DHafez commited on
Commit
f4b1fcb
Β·
verified Β·
1 Parent(s): b0dc2a2

Upload dr-diaa-mm.ipynb

Browse files
Files changed (1) hide show
  1. dr-diaa-mm.ipynb +1 -0
dr-diaa-mm.ipynb ADDED
@@ -0,0 +1 @@
 
 
1
+ {"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceType":"datasetVersion","sourceId":15336154,"datasetId":9809411,"databundleVersionId":16244328}],"dockerImageVersionId":31328,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# **Setup & Imports**","metadata":{}},{"cell_type":"code","source":"import os\nimport cv2\nimport kagglehub\nfrom tqdm import tqdm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-04-21T21:13:54.212799Z","iopub.execute_input":"2026-04-21T21:13:54.213068Z","iopub.status.idle":"2026-04-21T21:14:57.063429Z","shell.execute_reply.started":"2026-04-21T21:13:54.213040Z","shell.execute_reply":"2026-04-21T21:14:57.062470Z"}},"outputs":[{"name":"stdout","text":"Mounting files to /kaggle/input/datasets/anashikforu/ucf101-official...\nPath to dataset files: /kaggle/input/datasets/anashikforu/ucf101-official\n","output_type":"stream"}],"execution_count":1},{"cell_type":"markdown","source":"## Download Dataset","metadata":{}},{"cell_type":"code","source":"path = kagglehub.dataset_download(\"anashikforu/ucf101-official\")\nprint(path)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Setup Paths","metadata":{}},{"cell_type":"code","source":"ROOT = \"/kaggle/input/datasets/anashikforu/ucf101-official\"\n\nVIDEO_PATH = os.path.join(ROOT, \"UCF-101\")\nSPLIT_PATH = os.path.join(ROOT, \"UCFTrainTestlist\")\n\nFRAME_PATH = \"/kaggle/working/ucf5_frames\"\nLIST_PATH = \"/kaggle/working/ucf5_lists\"\n\nos.makedirs(FRAME_PATH, exist_ok=True)\nos.makedirs(LIST_PATH, exist_ok=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-21T21:15:18.173701Z","iopub.execute_input":"2026-04-21T21:15:18.174094Z","iopub.status.idle":"2026-04-21T21:15:18.178994Z","shell.execute_reply.started":"2026-04-21T21:15:18.174058Z","shell.execute_reply":"2026-04-21T21:15:18.177816Z"}},"outputs":[],"execution_count":4},{"cell_type":"markdown","source":"### 5 Classes to work on","metadata":{}},{"cell_type":"code","source":"SELECTED_CLASSES = [\n \"ApplyEyeMakeup\",\n \"Basketball\",\n \"Biking\",\n \"CliffDiving\",\n \"CricketBowling\"\n]","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Extract Frames to build Model","metadata":{}},{"cell_type":"code","source":"def extract_video(video_file, save_folder):\n os.makedirs(save_folder, exist_ok=True)\n\n cap = cv2.VideoCapture(video_file)\n count = 1\n\n while True:\n ret, frame = cap.read()\n if not ret:\n break\n\n cv2.imwrite(\n os.path.join(save_folder, f\"img_{count:05d}.jpg\"),\n frame\n )\n count += 1\n\n cap.release()\n return count - 1","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for class_name in tqdm(SELECTED_CLASSES):\n\n class_folder = os.path.join(VIDEO_PATH, class_name)\n\n for video in os.listdir(class_folder):\n\n if video.endswith(\".avi\"):\n\n video_path = os.path.join(class_folder, video)\n\n video_name = video.replace(\".avi\", \"\")\n\n save_path = os.path.join(\n FRAME_PATH,\n class_name,\n video_name\n )\n\n extract_video(video_path, save_path)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class_map = {\n name: idx for idx, name in enumerate(SELECTED_CLASSES)\n}\n\nprint(class_map)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_file = os.path.join(SPLIT_PATH, \"trainlist01.txt\")\ntest_file = os.path.join(SPLIT_PATH, \"testlist01.txt\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def count_frames(folder):\n return len(os.listdir(folder))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_lines = []\n\nwith open(train_file) as f:\n for line in f:\n\n parts = line.strip().split()\n\n video_rel = parts[0]\n class_name = video_rel.split(\"/\")[0]\n\n if class_name not in SELECTED_CLASSES:\n continue\n\n video_name = os.path.basename(video_rel).replace(\".avi\", \"\")\n\n label = class_map[class_name]\n\n frame_folder = os.path.join(\n FRAME_PATH,\n class_name,\n video_name\n )\n\n n_frames = count_frames(frame_folder)\n\n train_lines.append(\n f\"{class_name}/{video_name} {n_frames} {label}\"\n )\n\nwith open(f\"{LIST_PATH}/train_split1.txt\", \"w\") as f:\n f.write(\"\\n\".join(train_lines))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"val_lines = []\n\nwith open(test_file) as f:\n for line in f:\n\n video_rel = line.strip()\n\n class_name = video_rel.split(\"/\")[0]\n\n if class_name not in SELECTED_CLASSES:\n continue\n\n video_name = os.path.basename(video_rel).replace(\".avi\", \"\")\n\n label = class_map[class_name]\n\n frame_folder = os.path.join(\n FRAME_PATH,\n class_name,\n video_name\n )\n\n n_frames = count_frames(frame_folder)\n\n val_lines.append(\n f\"{class_name}/{video_name} {n_frames} {label}\"\n )\n\nwith open(f\"{LIST_PATH}/val_split1.txt\", \"w\") as f:\n f.write(\"\\n\".join(val_lines))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(train_lines[:5])\nprint(val_lines[:5])","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Model**","metadata":{}},{"cell_type":"code","source":"# Install required packages\n!pip install torch torchvision torchaudio --quiet\n!pip install tensorboardX --quiet\n!pip install scikit-learn --quiet\n!pip install tqdm --quiet\n!pip install opencv-python --quiet\n!pip install pillow --quiet\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torchvision\nimport numpy as np\nimport os\nimport time\nimport shutil\nfrom PIL import Image\nfrom tqdm import tqdm\nimport random\nfrom torch.nn.utils import clip_grad_norm_\nfrom sklearn.metrics import confusion_matrix\n\nprint(f\"PyTorch version: {torch.__version__}\")\nprint(f\"CUDA available: {torch.cuda.is_available()}\")\nif torch.cuda.is_available():\n print(f\"CUDA device: {torch.cuda.get_device_name(0)}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TemporalShift(nn.Module):\n \"\"\"Temporal Shift Module\n\n Shifts part of the channels along temporal dimension to enable\n information exchange between neighboring frames.\n\n Args:\n net: The wrapped module (e.g., Conv2d)\n n_segment: Number of frames in the input\n n_div: Divisor for number of channels to shift (fold_div)\n inplace: Whether to use inplace shifting (not recommended)\n \"\"\"\n\n def __init__(self, net, n_segment=3, n_div=8, inplace=False):\n super(TemporalShift, self).__init__()\n self.net = net\n self.n_segment = n_segment\n self.fold_div = n_div\n self.inplace = inplace\n if inplace:\n print(\"=> Using in-place shift...\")\n print(\"=> Using fold div: {}\".format(self.fold_div))\n\n def forward(self, x):\n x = self.shift(x, self.n_segment, fold_div=self.fold_div, inplace=self.inplace)\n return self.net(x)\n\n @staticmethod\n def shift(x, n_segment, fold_div=3, inplace=False):\n \"\"\"Perform temporal shift operation\n\n Args:\n x: Input tensor [N*T, C, H, W]\n n_segment: Number of temporal segments (T)\n fold_div: How many folds for shifting (default: 8)\n 1/fold_div of channels shift left\n 1/fold_div of channels shift right\n remaining channels don't shift\n \"\"\"\n nt, c, h, w = x.size()\n n_batch = nt // n_segment\n x = x.view(n_batch, n_segment, c, h, w)\n\n fold = c // fold_div\n if inplace:\n raise NotImplementedError(\"Inplace shift not implemented for stability\")\n else:\n out = torch.zeros_like(x)\n out[:, :-1, :fold] = x[:, 1:, :fold] # shift left\n out[:, 1:, fold : 2 * fold] = x[:, :-1, fold : 2 * fold] # shift right\n out[:, :, 2 * fold :] = x[:, :, 2 * fold :] # not shift\n\n return out.view(nt, c, h, w)\n\n\ndef make_temporal_shift(net, n_segment, n_div=8, place=\"blockres\", temporal_pool=False):\n \"\"\"Insert temporal shift modules into ResNet\n\n Args:\n net: ResNet model\n n_segment: Number of frames\n n_div: Divisor for channel shifting\n place: Where to insert TSM ('block' or 'blockres')\n temporal_pool: Whether to use temporal pooling\n \"\"\"\n if temporal_pool:\n n_segment_list = [n_segment, n_segment // 2, n_segment // 2, n_segment // 2]\n else:\n n_segment_list = [n_segment] * 4\n\n assert n_segment_list[-1] > 0\n print(\"=> n_segment per stage: {}\".format(n_segment_list))\n\n if isinstance(net, torchvision.models.ResNet):\n if place == \"block\":\n\n def make_block_temporal(stage, this_segment):\n blocks = list(stage.children())\n print(\"=> Processing stage with {} blocks\".format(len(blocks)))\n for i, b in enumerate(blocks):\n blocks[i] = TemporalShift(b, n_segment=this_segment, n_div=n_div)\n return nn.Sequential(*blocks)\n\n net.layer1 = make_block_temporal(net.layer1, n_segment_list[0])\n net.layer2 = make_block_temporal(net.layer2, n_segment_list[1])\n net.layer3 = make_block_temporal(net.layer3, n_segment_list[2])\n net.layer4 = make_block_temporal(net.layer4, n_segment_list[3])\n\n elif \"blockres\" in place:\n n_round = 1\n if len(list(net.layer3.children())) >= 23:\n n_round = 2\n print(\"=> Using n_round {} to insert temporal shift\".format(n_round))\n\n def make_block_temporal(stage, this_segment):\n blocks = list(stage.children())\n print(\"=> Processing stage with {} blocks residual\".format(len(blocks)))\n for i, b in enumerate(blocks):\n if i % n_round == 0:\n blocks[i].conv1 = TemporalShift(\n b.conv1, n_segment=this_segment, n_div=n_div\n )\n return nn.Sequential(*blocks)\n\n net.layer1 = make_block_temporal(net.layer1, n_segment_list[0])\n net.layer2 = make_block_temporal(net.layer2, n_segment_list[1])\n net.layer3 = make_block_temporal(net.layer3, n_segment_list[2])\n net.layer4 = make_block_temporal(net.layer4, n_segment_list[3])\n else:\n raise NotImplementedError(place)\n\n\nprint(\"βœ“ Temporal Shift Module implementation loaded\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SegmentConsensus(nn.Module):\n \"\"\"Segment consensus module for aggregating frame-level predictions\"\"\"\n\n def __init__(self, consensus_type, dim=1):\n super(SegmentConsensus, self).__init__()\n self.consensus_type = consensus_type\n self.dim = dim\n self.shape = None\n\n def forward(self, input_tensor):\n self.shape = input_tensor.size()\n if self.consensus_type == \"avg\":\n output = input_tensor.mean(dim=self.dim, keepdim=True)\n elif self.consensus_type == \"identity\":\n output = input_tensor\n else:\n output = None\n return output\n\n\nclass ConsensusModule(nn.Module):\n def __init__(self, consensus_type, dim=1):\n super(ConsensusModule, self).__init__()\n self.consensus_type = consensus_type if consensus_type != \"rnn\" else \"identity\"\n self.dim = dim\n\n def forward(self, input):\n return SegmentConsensus(self.consensus_type, self.dim)(input)\n\n\nprint(\"βœ“ Consensus Module loaded\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TSN(nn.Module):\n \"\"\"Temporal Segment Networks / Temporal Shift Module Model\n\n Args:\n num_class: Number of classes\n num_segments: Number of frames to sample\n modality: 'RGB' or 'Flow'\n base_model: Backbone architecture (e.g., 'resnet50')\n consensus_type: How to aggregate frame predictions ('avg')\n dropout: Dropout ratio\n partial_bn: Use partial batch normalization\n is_shift: Whether to use temporal shift\n shift_div: Division factor for shifting\n shift_place: Where to place shift ('blockres')\n \"\"\"\n\n def __init__(\n self,\n num_class,\n num_segments,\n modality,\n base_model=\"resnet50\",\n new_length=None,\n consensus_type=\"avg\",\n before_softmax=True,\n dropout=0.8,\n img_feature_dim=256,\n crop_num=1,\n partial_bn=True,\n print_spec=True,\n pretrain=\"imagenet\",\n is_shift=False,\n shift_div=8,\n shift_place=\"blockres\",\n fc_lr5=False,\n temporal_pool=False,\n non_local=False,\n ):\n super(TSN, self).__init__()\n self.modality = modality\n self.num_segments = num_segments\n self.reshape = True\n self.before_softmax = before_softmax\n self.dropout = dropout\n self.crop_num = crop_num\n self.consensus_type = consensus_type\n self.img_feature_dim = img_feature_dim\n self.pretrain = pretrain\n\n self.is_shift = is_shift\n self.shift_div = shift_div\n self.shift_place = shift_place\n self.base_model_name = base_model\n self.fc_lr5 = fc_lr5\n self.temporal_pool = temporal_pool\n self.non_local = non_local\n\n if not before_softmax and consensus_type != \"avg\":\n raise ValueError(\"Only avg consensus can be used after Softmax\")\n\n if new_length is None:\n self.new_length = 1 if modality == \"RGB\" else 5\n else:\n self.new_length = new_length\n\n if print_spec:\n print(\n (\n f\"\"\"\n Initializing TSN with base model: {base_model}.\n TSN Configurations:\n input_modality: {self.modality}\n num_segments: {self.num_segments}\n new_length: {self.new_length}\n consensus_module: {consensus_type}\n dropout_ratio: {self.dropout}\n img_feature_dim: {self.img_feature_dim}\n \"\"\"\n )\n )\n\n self._prepare_base_model(base_model)\n feature_dim = self._prepare_tsn(num_class)\n\n self.consensus = ConsensusModule(consensus_type)\n\n if not self.before_softmax:\n self.softmax = nn.Softmax()\n\n self._enable_pbn = partial_bn\n if partial_bn:\n self.partialBN(True)\n\n def _prepare_tsn(self, num_class):\n feature_dim = getattr(\n self.base_model, self.base_model.last_layer_name\n ).in_features\n if self.dropout == 0:\n setattr(\n self.base_model,\n self.base_model.last_layer_name,\n nn.Linear(feature_dim, num_class),\n )\n self.new_fc = None\n else:\n setattr(\n self.base_model,\n self.base_model.last_layer_name,\n nn.Dropout(p=self.dropout),\n )\n self.new_fc = nn.Linear(feature_dim, num_class)\n\n std = 0.001\n if self.new_fc is None:\n nn.init.normal_(\n getattr(self.base_model, self.base_model.last_layer_name).weight, 0, std\n )\n nn.init.constant_(\n getattr(self.base_model, self.base_model.last_layer_name).bias, 0\n )\n else:\n if hasattr(self.new_fc, \"weight\"):\n nn.init.normal_(self.new_fc.weight, 0, std)\n nn.init.constant_(self.new_fc.bias, 0)\n return feature_dim\n\n def _prepare_base_model(self, base_model):\n print(\"=> base model: {}\".format(base_model))\n\n if \"resnet\" in base_model:\n self.base_model = getattr(torchvision.models, base_model)(\n True if self.pretrain == \"imagenet\" else False\n )\n\n if self.is_shift:\n print(\"Adding temporal shift...\")\n make_temporal_shift(\n self.base_model,\n self.num_segments,\n n_div=self.shift_div,\n place=self.shift_place,\n temporal_pool=self.temporal_pool,\n )\n\n self.base_model.last_layer_name = \"fc\"\n self.input_size = 224\n self.input_mean = [0.485, 0.456, 0.406]\n self.input_std = [0.229, 0.224, 0.225]\n self.base_model.avgpool = nn.AdaptiveAvgPool2d(1)\n\n if self.modality == \"Flow\":\n self.input_mean = [0.5]\n self.input_std = [np.mean(self.input_std)]\n else:\n raise ValueError(\"Unknown base model: {}\".format(base_model))\n\n def train(self, mode=True):\n \"\"\"Override train to freeze BN parameters\"\"\"\n super(TSN, self).train(mode)\n count = 0\n if self._enable_pbn and mode:\n print(\"Freezing BatchNorm2D except the first one.\")\n for m in self.base_model.modules():\n if isinstance(m, nn.BatchNorm2d):\n count += 1\n if count >= (2 if self._enable_pbn else 1):\n m.eval()\n m.weight.requires_grad = False\n m.bias.requires_grad = False\n\n def partialBN(self, enable):\n self._enable_pbn = enable\n\n def get_optim_policies(self):\n \"\"\"Get parameter groups with different learning rates\"\"\"\n first_conv_weight = []\n first_conv_bias = []\n normal_weight = []\n normal_bias = []\n lr5_weight = []\n lr10_bias = []\n bn = []\n\n conv_cnt = 0\n bn_cnt = 0\n for m in self.modules():\n if isinstance(m, (torch.nn.Conv2d, torch.nn.Conv1d, torch.nn.Conv3d)):\n ps = list(m.parameters())\n conv_cnt += 1\n if conv_cnt == 1:\n first_conv_weight.append(ps[0])\n if len(ps) == 2:\n first_conv_bias.append(ps[1])\n else:\n normal_weight.append(ps[0])\n if len(ps) == 2:\n normal_bias.append(ps[1])\n elif isinstance(m, torch.nn.Linear):\n ps = list(m.parameters())\n if self.fc_lr5:\n lr5_weight.append(ps[0])\n else:\n normal_weight.append(ps[0])\n if len(ps) == 2:\n if self.fc_lr5:\n lr10_bias.append(ps[1])\n else:\n normal_bias.append(ps[1])\n elif isinstance(m, (torch.nn.BatchNorm2d, torch.nn.BatchNorm3d)):\n bn_cnt += 1\n if not self._enable_pbn or bn_cnt == 1:\n bn.extend(list(m.parameters()))\n elif len(m._modules) == 0:\n if len(list(m.parameters())) > 0:\n raise ValueError(\n f\"New atomic module type: {type(m)}. Need to give it a learning policy\"\n )\n\n return [\n {\n \"params\": first_conv_weight,\n \"lr_mult\": 5 if self.modality == \"Flow\" else 1,\n \"decay_mult\": 1,\n \"name\": \"first_conv_weight\",\n },\n {\n \"params\": first_conv_bias,\n \"lr_mult\": 10 if self.modality == \"Flow\" else 2,\n \"decay_mult\": 0,\n \"name\": \"first_conv_bias\",\n },\n {\n \"params\": normal_weight,\n \"lr_mult\": 1,\n \"decay_mult\": 1,\n \"name\": \"normal_weight\",\n },\n {\n \"params\": normal_bias,\n \"lr_mult\": 2,\n \"decay_mult\": 0,\n \"name\": \"normal_bias\",\n },\n {\"params\": bn, \"lr_mult\": 1, \"decay_mult\": 0, \"name\": \"BN scale/shift\"},\n {\"params\": lr5_weight, \"lr_mult\": 5, \"decay_mult\": 1, \"name\": \"lr5_weight\"},\n {\"params\": lr10_bias, \"lr_mult\": 10, \"decay_mult\": 0, \"name\": \"lr10_bias\"},\n ]\n\n def forward(self, input, no_reshape=False):\n if not no_reshape:\n sample_len = (3 if self.modality == \"RGB\" else 2) * self.new_length\n base_out = self.base_model(input.view((-1, sample_len) + input.size()[-2:]))\n else:\n base_out = self.base_model(input)\n\n if self.dropout > 0:\n base_out = self.new_fc(base_out)\n\n if not self.before_softmax:\n base_out = self.softmax(base_out)\n\n if self.reshape:\n if self.is_shift and self.temporal_pool:\n base_out = base_out.view(\n (-1, self.num_segments // 2) + base_out.size()[1:]\n )\n else:\n base_out = base_out.view((-1, self.num_segments) + base_out.size()[1:])\n output = self.consensus(base_out)\n return output.squeeze(1)\n\n @property\n def crop_size(self):\n return self.input_size\n\n @property\n def scale_size(self):\n return self.input_size * 256 // 224\n\n\nprint(\"βœ“ TSN/TSM Model Architecture loaded\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class GroupRandomCrop:\n def __init__(self, size):\n self.size = (int(size), int(size)) if isinstance(size, int) else size\n\n def __call__(self, img_group):\n w, h = img_group[0].size\n th, tw = self.size\n out_images = []\n x1 = random.randint(0, w - tw) if w > tw else 0\n y1 = random.randint(0, h - th) if h > th else 0\n\n for img in img_group:\n if w == tw and h == th:\n out_images.append(img)\n else:\n out_images.append(img.crop((x1, y1, x1 + tw, y1 + th)))\n return out_images\n\n\nclass GroupCenterCrop:\n def __init__(self, size):\n self.worker = torchvision.transforms.CenterCrop(size)\n\n def __call__(self, img_group):\n return [self.worker(img) for img in img_group]\n\n\nclass GroupScale:\n def __init__(self, size, interpolation=Image.BILINEAR):\n self.worker = torchvision.transforms.Resize(size, interpolation)\n\n def __call__(self, img_group):\n return [self.worker(img) for img in img_group]\n\n\nclass GroupNormalize:\n def __init__(self, mean, std):\n self.mean = mean\n self.std = std\n\n def __call__(self, tensor):\n rep_mean = self.mean * (tensor.size()[0] // len(self.mean))\n rep_std = self.std * (tensor.size()[0] // len(self.std))\n for t, m, s in zip(tensor, rep_mean, rep_std):\n t.sub_(m).div_(s)\n return tensor\n\n\nclass Stack:\n def __init__(self, roll=False):\n self.roll = roll\n\n def __call__(self, img_group):\n if img_group[0].mode == \"L\":\n return np.concatenate([np.expand_dims(x, 2) for x in img_group], axis=2)\n elif img_group[0].mode == \"RGB\":\n if self.roll:\n return np.concatenate(\n [np.array(x)[:, :, ::-1] for x in img_group], axis=2\n )\n else:\n return np.concatenate(img_group, axis=2)\n\n\nclass ToTorchFormatTensor:\n def __init__(self, div=True):\n self.div = div\n\n def __call__(self, pic):\n if isinstance(pic, np.ndarray):\n img = torch.from_numpy(pic).permute(2, 0, 1).contiguous()\n else:\n img = torch.ByteTensor(torch.ByteStorage.from_buffer(pic.tobytes()))\n img = img.view(pic.size[1], pic.size[0], len(pic.mode))\n img = img.transpose(0, 1).transpose(0, 2).contiguous()\n return img.float().div(255) if self.div else img.float()\n\n\nclass GroupMultiScaleCrop:\n def __init__(\n self, input_size, scales=None, max_distort=1, fix_crop=True, more_fix_crop=True\n ):\n self.scales = scales if scales is not None else [1, 0.875, 0.75, 0.66]\n self.max_distort = max_distort\n self.fix_crop = fix_crop\n self.more_fix_crop = more_fix_crop\n self.input_size = (\n [input_size, input_size] if isinstance(input_size, int) else input_size\n )\n self.interpolation = Image.BILINEAR\n\n def __call__(self, img_group):\n im_size = img_group[0].size\n crop_w, crop_h, offset_w, offset_h = self._sample_crop_size(im_size)\n crop_img_group = [\n img.crop((offset_w, offset_h, offset_w + crop_w, offset_h + crop_h))\n for img in img_group\n ]\n ret_img_group = [\n img.resize((self.input_size[0], self.input_size[1]), self.interpolation)\n for img in crop_img_group\n ]\n return ret_img_group\n\n def _sample_crop_size(self, im_size):\n image_w, image_h = im_size[0], im_size[1]\n base_size = min(image_w, image_h)\n crop_sizes = [int(base_size * x) for x in self.scales]\n crop_h = [\n self.input_size[1] if abs(x - self.input_size[1]) < 3 else x\n for x in crop_sizes\n ]\n crop_w = [\n self.input_size[0] if abs(x - self.input_size[0]) < 3 else x\n for x in crop_sizes\n ]\n\n pairs = []\n for i, h in enumerate(crop_h):\n for j, w in enumerate(crop_w):\n if abs(i - j) <= self.max_distort:\n pairs.append((w, h))\n\n crop_pair = random.choice(pairs)\n if not self.fix_crop:\n w_offset = random.randint(0, image_w - crop_pair[0])\n h_offset = random.randint(0, image_h - crop_pair[1])\n else:\n w_offset, h_offset = self._sample_fix_offset(\n image_w, image_h, crop_pair[0], crop_pair[1]\n )\n\n return crop_pair[0], crop_pair[1], w_offset, h_offset\n\n def _sample_fix_offset(self, image_w, image_h, crop_w, crop_h):\n offsets = self.fill_fix_offset(\n self.more_fix_crop, image_w, image_h, crop_w, crop_h\n )\n return random.choice(offsets)\n\n @staticmethod\n def fill_fix_offset(more_fix_crop, image_w, image_h, crop_w, crop_h):\n w_step = (image_w - crop_w) // 4\n h_step = (image_h - crop_h) // 4\n\n ret = []\n ret.append((0, 0)) # upper left\n ret.append((4 * w_step, 0)) # upper right\n ret.append((0, 4 * h_step)) # lower left\n ret.append((4 * w_step, 4 * h_step)) # lower right\n ret.append((2 * w_step, 2 * h_step)) # center\n\n if more_fix_crop:\n ret.append((0, 2 * h_step)) # center left\n ret.append((4 * w_step, 2 * h_step)) # center right\n ret.append((2 * w_step, 4 * h_step)) # lower center\n ret.append((2 * w_step, 0 * h_step)) # upper center\n ret.append((1 * w_step, 1 * h_step)) # upper left quarter\n ret.append((3 * w_step, 1 * h_step)) # upper right quarter\n ret.append((1 * w_step, 3 * h_step)) # lower left quarter\n ret.append((3 * w_step, 3 * h_step)) # lower right quarter\n return ret\n\n\nclass GroupRandomHorizontalFlip:\n \"\"\"Randomly horizontally flips the given PIL.Image with a probability of 0.5\"\"\"\n\n def __init__(self, is_flow=False):\n self.is_flow = is_flow\n\n def __call__(self, img_group, is_flow=False):\n v = random.random()\n if v < 0.5:\n ret = [img.transpose(Image.FLIP_LEFT_RIGHT) for img in img_group]\n if self.is_flow:\n for i in range(0, len(ret), 2):\n from PIL import ImageOps\n\n ret[i] = ImageOps.invert(ret[i])\n return ret\n else:\n return img_group\n\n\nprint(\"βœ“ Data transforms loaded\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AverageMeter:\n \"\"\"Computes and stores the average and current value\"\"\"\n\n def __init__(self):\n self.reset()\n\n def reset(self):\n self.val = 0\n self.avg = 0\n self.sum = 0\n self.count = 0\n\n def update(self, val, n=1):\n self.val = val\n self.sum += val * n\n self.count += n\n self.avg = self.sum / self.count\n\n\ndef accuracy(output, target, topk=(1,)):\n \"\"\"Computes the precision@k for the specified values of k\"\"\"\n maxk = max(topk)\n batch_size = target.size(0)\n\n _, pred = output.topk(maxk, 1, True, True)\n pred = pred.t()\n correct = pred.eq(target.view(1, -1).expand_as(pred))\n\n res = []\n for k in topk:\n correct_k = correct[:k].reshape(-1).float().sum(0)\n res.append(correct_k.mul_(100.0 / batch_size))\n return res\n\n\ndef adjust_learning_rate(optimizer, epoch, lr_type, lr_steps, base_lr):\n \"\"\"Sets the learning rate to the initial LR decayed by 10 every step\"\"\"\n if lr_type == \"step\":\n decay = 0.1 ** (sum(epoch >= np.array(lr_steps)))\n lr = base_lr * decay\n elif lr_type == \"cos\":\n import math\n\n total_epochs = lr_steps[-1] if lr_steps else 50\n lr = 0.5 * base_lr * (1 + math.cos(math.pi * epoch / total_epochs))\n else:\n raise NotImplementedError\n\n for param_group in optimizer.param_groups:\n param_group[\"lr\"] = lr * param_group[\"lr_mult\"]\n\n return lr\n\n\nprint(\"βœ“ Training utilities loaded\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Configuration\nclass Config:\n # Dataset\n dataset = \"ucf101\" # or 'ucf101', 'hmdb51', 'something', 'somethingv2'\n num_class = 5 # Update based on your dataset\n modality = \"RGB\"\n\n # Model architecture\n arch = \"resnet50\" # Base model\n num_segments = 8 # Number of frames\n consensus_type = \"avg\"\n dropout = 0.5\n\n # TSM specific\n shift = True # Enable temporal shift\n shift_div = 8 # Shift 1/8 channels\n shift_place = \"blockres\" # Where to insert shift\n temporal_pool = False\n non_local = False\n\n # Training\n epochs = 20 # For Kinetics from ImageNet pretrain\n batch_size = 8 # Adjust based on your GPU memory (original: 128)\n lr = 0.01 # Base learning rate (original: 0.02 for batch_size 128)\n lr_type = \"step\"\n lr_steps = [20, 40] # Decay at these epochs\n momentum = 0.9\n weight_decay = 1e-4\n clip_gradient = 20 # Gradient clipping\n\n # Evaluation\n eval_freq = 1 # Evaluate every N epochs\n\n # Data augmentation\n no_partialbn = False # Use partial BN\n dense_sample = False # Use dense sampling (I3D style)\n\n # Paths (Update these for your data)\n root_path = \"/kaggle/working/ucf5_frames\"\n train_list = \"/kaggle/working/ucf5_lists/train_split1.txt\"\n val_list = \"/kaggle/working/ucf5_lists/val_split1.txt\"\n\n # Output\n root_log = \"./logs\"\n root_model = \"./checkpoints\"\n\n # Device\n gpus = [0] # GPU IDs\n workers = 2 # Data loading workers\n print_freq = 20 # Print frequency\n\n # Pretrain\n pretrain = \"imagenet\" # or path to checkpoint\n tune_from = None # Fine-tune from checkpoint\n\n\nconfig = Config()\n\n# Create directories\nos.makedirs(config.root_log, exist_ok=True)\nos.makedirs(config.root_model, exist_ok=True)\n\nprint(\"βœ“ Configuration set\")\nprint(f\"Model: TSM-{config.arch}\")\nprint(f\"Shift enabled: {config.shift}\")\nprint(f\"Num segments: {config.num_segments}\")\nprint(f\"Batch size: {config.batch_size}\")\nprint(f\"Learning rate: {config.lr}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create model\nprint(\"Creating model...\")\nmodel = TSN(\n num_class=config.num_class,\n num_segments=config.num_segments,\n modality=config.modality,\n base_model=config.arch,\n consensus_type=config.consensus_type,\n dropout=config.dropout,\n partial_bn=not config.no_partialbn,\n pretrain=config.pretrain,\n is_shift=config.shift,\n shift_div=config.shift_div,\n shift_place=config.shift_place,\n fc_lr5=(\n not (config.tune_from and config.dataset in config.tune_from)\n if config.tune_from\n else False\n ),\n temporal_pool=config.temporal_pool,\n non_local=config.non_local,\n)\n\n# Get crop and scale sizes\ncrop_size = model.crop_size\nscale_size = model.scale_size\ninput_mean = model.input_mean\ninput_std = model.input_std\n\n# Move to GPU\nif torch.cuda.is_available():\n model = torch.nn.DataParallel(model, device_ids=config.gpus).cuda()\nelse:\n print(\"WARNING: Running on CPU. Training will be very slow!\")\n\n# Get optimization policies\npolicies = (\n model.module.get_optim_policies()\n if hasattr(model, \"module\")\n else model.get_optim_policies()\n)\n\n# Create optimizer\noptimizer = torch.optim.SGD(\n policies, config.lr, momentum=config.momentum, weight_decay=config.weight_decay\n)\n\n# Loss function\ncriterion = (\n nn.CrossEntropyLoss().cuda() if torch.cuda.is_available() else nn.CrossEntropyLoss()\n)\n\nprint(\"βœ“ Model created successfully\")\nprint(f\"Total parameters: {sum(p.numel() for p in model.parameters()):,}\")\nprint(\n f\"Trainable parameters: {sum(p.numel() for p in model.parameters() if p.requires_grad):,}\"\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Data augmentation for training\ntrain_augmentation = GroupMultiScaleCrop(crop_size, [1, 0.875, 0.75, 0.66])\nif \"something\" not in config.dataset and \"jester\" not in config.dataset:\n # Add horizontal flip for datasets other than Something-Something\n pass # Flip will be applied in transform composition\n\n# Note: You'll need to implement or adapt the dataset loader\n# For demonstration, here's a template dataset class\n\n\nclass VideoRecord:\n def __init__(self, row):\n self._data = row\n\n @property\n def path(self):\n return self._data[0]\n\n @property\n def num_frames(self):\n return int(self._data[1])\n\n @property\n def label(self):\n return int(self._data[2])\n\n\nclass TSNDataSet(torch.utils.data.Dataset):\n \"\"\"Video dataset for TSM/TSN\n\n Expected list file format (one line per video):\n video_folder_path num_frames class_index\n\n Example:\n basketball/video_001 250 0\n soccer/video_002 180 1\n \"\"\"\n\n def __init__(\n self,\n root_path,\n list_file,\n num_segments=3,\n new_length=1,\n modality=\"RGB\",\n image_tmpl=\"img_{:05d}.jpg\",\n transform=None,\n random_shift=True,\n test_mode=False,\n dense_sample=False,\n ):\n\n self.root_path = root_path\n self.list_file = list_file\n self.num_segments = num_segments\n self.new_length = new_length\n self.modality = modality\n self.image_tmpl = image_tmpl\n self.transform = transform\n self.random_shift = random_shift\n self.test_mode = test_mode\n self.dense_sample = dense_sample\n\n self._parse_list()\n\n def _load_image(self, directory, idx):\n if self.modality == \"RGB\":\n try:\n return [\n Image.open(\n os.path.join(\n self.root_path, directory, self.image_tmpl.format(idx)\n )\n ).convert(\"RGB\")\n ]\n except Exception:\n print(\n f\"Error loading image: {os.path.join(self.root_path, directory, self.image_tmpl.format(idx))}\"\n )\n return [\n Image.open(\n os.path.join(\n self.root_path, directory, self.image_tmpl.format(1)\n )\n ).convert(\"RGB\")\n ]\n\n def _parse_list(self):\n tmp = [x.strip().split(\" \") for x in open(self.list_file)]\n if not self.test_mode:\n tmp = [item for item in tmp if int(item[1]) >= 3]\n self.video_list = [VideoRecord(item) for item in tmp]\n print(f\"Video number: {len(self.video_list)}\")\n\n def _sample_indices(self, record):\n \"\"\"Sample frame indices for training\"\"\"\n if self.dense_sample:\n sample_pos = max(1, 1 + record.num_frames - 64)\n t_stride = 64 // self.num_segments\n start_idx = 0 if sample_pos == 1 else np.random.randint(0, sample_pos - 1)\n offsets = [\n (idx * t_stride + start_idx) % record.num_frames\n for idx in range(self.num_segments)\n ]\n return np.array(offsets) + 1\n else:\n average_duration = (\n record.num_frames - self.new_length + 1\n ) // self.num_segments\n if average_duration > 0:\n offsets = np.multiply(\n list(range(self.num_segments)), average_duration\n ) + np.random.randint(average_duration, size=self.num_segments)\n elif record.num_frames > self.num_segments:\n offsets = np.sort(\n np.random.randint(\n record.num_frames - self.new_length + 1, size=self.num_segments\n )\n )\n else:\n offsets = np.zeros((self.num_segments,))\n return offsets + 1\n\n def _get_val_indices(self, record):\n \"\"\"Sample frame indices for validation (deterministic)\"\"\"\n if self.dense_sample:\n sample_pos = max(1, 1 + record.num_frames - 64)\n t_stride = 64 // self.num_segments\n start_idx = 0 if sample_pos == 1 else np.random.randint(0, sample_pos - 1)\n offsets = [\n (idx * t_stride + start_idx) % record.num_frames\n for idx in range(self.num_segments)\n ]\n return np.array(offsets) + 1\n else:\n if record.num_frames > self.num_segments + self.new_length - 1:\n tick = (record.num_frames - self.new_length + 1) / float(\n self.num_segments\n )\n offsets = np.array(\n [int(tick / 2.0 + tick * x) for x in range(self.num_segments)]\n )\n else:\n offsets = np.zeros((self.num_segments,))\n return offsets + 1\n\n def __getitem__(self, index):\n record = self.video_list[index]\n\n if not self.test_mode:\n segment_indices = (\n self._sample_indices(record)\n if self.random_shift\n else self._get_val_indices(record)\n )\n else:\n segment_indices = self._get_val_indices(record)\n\n return self.get(record, segment_indices)\n\n def get(self, record, indices):\n images = []\n for seg_ind in indices:\n p = int(seg_ind)\n for i in range(self.new_length):\n seg_imgs = self._load_image(record.path, p)\n images.extend(seg_imgs)\n if p < record.num_frames:\n p += 1\n\n process_data = self.transform(images)\n return process_data, record.label\n\n def __len__(self):\n return len(self.video_list)\n\n\nprint(\"βœ“ Dataset class defined\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define data transforms\nnormalize = GroupNormalize(input_mean, input_std)\n\n# Training transform\ntrain_transform = torchvision.transforms.Compose(\n [\n train_augmentation,\n GroupRandomHorizontalFlip(is_flow=False),\n Stack(roll=(config.arch in [\"BNInception\", \"InceptionV3\"])),\n ToTorchFormatTensor(div=(config.arch not in [\"BNInception\", \"InceptionV3\"])),\n normalize,\n ]\n)\n\n# Validation transform\nval_transform = torchvision.transforms.Compose(\n [\n GroupScale(int(scale_size)),\n GroupCenterCrop(crop_size),\n Stack(roll=(config.arch in [\"BNInception\", \"InceptionV3\"])),\n ToTorchFormatTensor(div=(config.arch not in [\"BNInception\", \"InceptionV3\"])),\n normalize,\n ]\n)\n\n# Create datasets\n# NOTE: Update config.root_path, config.train_list, config.val_list with your data\ntry:\n train_dataset = TSNDataSet(\n config.root_path,\n config.train_list,\n num_segments=config.num_segments,\n new_length=1,\n modality=config.modality,\n image_tmpl=\"img_{:05d}.jpg\",\n transform=train_transform,\n dense_sample=config.dense_sample,\n )\n\n val_dataset = TSNDataSet(\n config.root_path,\n config.val_list,\n num_segments=config.num_segments,\n new_length=1,\n modality=config.modality,\n image_tmpl=\"img_{:05d}.jpg\",\n random_shift=False,\n transform=val_transform,\n dense_sample=config.dense_sample,\n )\n\n # Create data loaders\n train_loader = torch.utils.data.DataLoader(\n train_dataset,\n batch_size=config.batch_size,\n shuffle=True,\n num_workers=config.workers,\n pin_memory=True,\n drop_last=True,\n )\n\n val_loader = torch.utils.data.DataLoader(\n val_dataset,\n batch_size=config.batch_size,\n shuffle=False,\n num_workers=config.workers,\n pin_memory=True,\n )\n\n print(f\"βœ“ Data loaders created\")\n print(f\"Training samples: {len(train_dataset)}\")\n print(f\"Validation samples: {len(val_dataset)}\")\n print(f\"Training batches: {len(train_loader)}\")\n print(f\"Validation batches: {len(val_loader)}\")\n\nexcept FileNotFoundError as e:\n print(f\"⚠️ Warning: Data files not found: {e}\")\n print(\n \"Please update config.root_path, config.train_list, and config.val_list with your dataset paths\"\n )\n print(\"For now, we'll create dummy loaders for demonstration\")\n train_loader = None\n val_loader = None","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_epoch(train_loader, model, criterion, optimizer, epoch, config):\n \"\"\"Train for one epoch\"\"\"\n batch_time = AverageMeter()\n data_time = AverageMeter()\n losses = AverageMeter()\n top1 = AverageMeter()\n top5 = AverageMeter()\n\n # Switch to train mode\n model.train()\n\n # Partial BN\n if hasattr(model, \"module\"):\n if not config.no_partialbn:\n model.module.partialBN(True)\n else:\n model.module.partialBN(False)\n\n end = time.time()\n for i, (input, target) in enumerate(tqdm(train_loader, desc=f\"Epoch {epoch}\")):\n # Measure data loading time\n data_time.update(time.time() - end)\n\n if torch.cuda.is_available():\n target = target.cuda()\n input = input.cuda()\n\n # Compute output\n output = model(input)\n loss = criterion(output, target)\n\n # Measure accuracy and record loss\n prec1, prec5 = accuracy(output.data, target, topk=(1, 5))\n losses.update(loss.item(), input.size(0))\n top1.update(prec1.item(), input.size(0))\n top5.update(prec5.item(), input.size(0))\n\n # Compute gradient and do SGD step\n optimizer.zero_grad()\n loss.backward()\n\n if config.clip_gradient is not None:\n total_norm = clip_grad_norm_(model.parameters(), config.clip_gradient)\n\n optimizer.step()\n\n # Measure elapsed time\n batch_time.update(time.time() - end)\n end = time.time()\n\n if i % config.print_freq == 0:\n print(\n f\"Epoch: [{epoch}][{i}/{len(train_loader)}]\\t\"\n f\"Time {batch_time.val:.3f} ({batch_time.avg:.3f})\\t\"\n f\"Data {data_time.val:.3f} ({data_time.avg:.3f})\\t\"\n f\"Loss {losses.val:.4f} ({losses.avg:.4f})\\t\"\n f\"Prec@1 {top1.val:.3f} ({top1.avg:.3f})\\t\"\n f\"Prec@5 {top5.val:.3f} ({top5.avg:.3f})\"\n )\n\n return top1.avg, top5.avg, losses.avg\n\n\ndef validate(val_loader, model, criterion, epoch, config):\n \"\"\"Validate the model\"\"\"\n batch_time = AverageMeter()\n losses = AverageMeter()\n top1 = AverageMeter()\n top5 = AverageMeter()\n\n # Switch to evaluate mode\n model.eval()\n\n end = time.time()\n with torch.no_grad():\n for i, (input, target) in enumerate(tqdm(val_loader, desc=\"Validation\")):\n if torch.cuda.is_available():\n target = target.cuda()\n input = input.cuda()\n\n # Compute output\n output = model(input)\n loss = criterion(output, target)\n\n # Measure accuracy and record loss\n prec1, prec5 = accuracy(output.data, target, topk=(1, 5))\n losses.update(loss.item(), input.size(0))\n top1.update(prec1.item(), input.size(0))\n top5.update(prec5.item(), input.size(0))\n\n # Measure elapsed time\n batch_time.update(time.time() - end)\n end = time.time()\n\n if i % config.print_freq == 0:\n print(\n f\"Test: [{i}/{len(val_loader)}]\\t\"\n f\"Time {batch_time.val:.3f} ({batch_time.avg:.3f})\\t\"\n f\"Loss {losses.val:.4f} ({losses.avg:.4f})\\t\"\n f\"Prec@1 {top1.val:.3f} ({top1.avg:.3f})\\t\"\n f\"Prec@5 {top5.val:.3f} ({top5.avg:.3f})\"\n )\n\n print(\n f\"Testing Results: Prec@1 {top1.avg:.3f} Prec@5 {top5.avg:.3f} Loss {losses.avg:.5f}\"\n )\n\n return top1.avg, top5.avg, losses.avg\n\n\ndef save_checkpoint(state, is_best, filename=\"checkpoint.pth.tar\"):\n \"\"\"Save checkpoint\"\"\"\n filepath = os.path.join(config.root_model, filename)\n torch.save(state, filepath)\n if is_best:\n shutil.copyfile(filepath, filepath.replace(\".pth.tar\", \"_best.pth.tar\"))\n\n\nprint(\"βœ“ Training functions defined\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def main():\n # Training loop\n if train_loader is not None and val_loader is not None:\n print(\"Starting training...\")\n best_prec1 = 0\n \n for epoch in range(config.epochs):\n # Adjust learning rate\n lr = adjust_learning_rate(\n optimizer, epoch, config.lr_type, config.lr_steps, config.lr\n )\n print(f\"\\n{'='*50}\")\n print(f\"Epoch {epoch+1}/{config.epochs} - Learning Rate: {lr:.6f}\")\n print(f\"{'='*50}\")\n \n # Train for one epoch\n train_top1, train_top5, train_loss = train_epoch(\n train_loader, model, criterion, optimizer, epoch, config\n )\n \n # Evaluate on validation set\n if (epoch + 1) % config.eval_freq == 0 or epoch == config.epochs - 1:\n val_top1, val_top5, val_loss = validate(\n val_loader, model, criterion, epoch, config\n )\n \n # Remember best prec@1 and save checkpoint\n is_best = val_top1 > best_prec1\n best_prec1 = max(val_top1, best_prec1)\n \n print(f\"\\nBest Prec@1: {best_prec1:.3f}\")\n \n # Save checkpoint\n save_checkpoint(\n {\n \"epoch\": epoch + 1,\n \"arch\": config.arch,\n \"state_dict\": model.state_dict(),\n \"optimizer\": optimizer.state_dict(),\n \"best_prec1\": best_prec1,\n },\n is_best,\n filename=f\"checkpoint_epoch_{epoch+1}.pth.tar\",\n )\n \n print(f\"Checkpoint saved: checkpoint_epoch_{epoch+1}.pth.tar\")\n if is_best:\n print(\"βœ“ New best model saved!\")\n \n print(\"\\n\" + \"=\" * 50)\n print(f\"Training completed!\")\n print(f\"Best validation Prec@1: {best_prec1:.3f}\")\n print(\"=\" * 50)\n else:\n print(\"⚠️ Skipping training - data loaders not available\")\n print(\"Please set up your dataset and update the configuration\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"main()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"\\n\" + \"=\" * 70)\nprint(\"TSM TRAINING PIPELINE COMPLETE\")\nprint(\"=\" * 70)\n\nprint(\"\\nπŸ“Š Model Architecture Summary:\")\nprint(f\" - Base Model: {config.arch}\")\nprint(f\" - Temporal Shift: {config.shift}\")\nprint(f\" - Shift Division: 1/{config.shift_div} channels\")\nprint(f\" - Number of Segments: {config.num_segments}\")\nprint(f\" - Input Resolution: {crop_size}x{crop_size}\")\nprint(f\" - Number of Classes: {config.num_class}\")\n\nprint(\"\\n🎯 Next Steps for Your PhD Research:\")\nprint(\" 1. Prepare your video dataset:\")\nprint(\" - Extract frames from videos (use ffmpeg)\")\nprint(\" - Create train/val split files\")\nprint(\" - Update config.root_path, config.train_list, config.val_list\")\n\nprint(\"\\n 2. Train baseline TSM model:\")\nprint(\" - Start with ImageNet pretrained weights\")\nprint(\" - Train on your dataset\")\nprint(\" - Reproduce paper results\")\n\nprint(\"\\n 3. Implement your improvements:\")\nprint(\" - Modify temporal_shift.py for enhanced shifting\")\nprint(\" - Add new modules/components\")\nprint(\" - Experiment with different architectures\")\n\nprint(\"\\n 4. Fine-tuning strategies:\")\nprint(\" - Use config.tune_from to load pretrained checkpoint\")\nprint(\" - Adjust learning rate and epochs\")\nprint(\" - Try different augmentation strategies\")\n\nprint(\"\\nπŸ“š Paper Reference:\")\nprint(\" Lin, Ji, Chuang Gan, and Song Han.\")\nprint(\" 'TSM: Temporal Shift Module for Efficient Video Understanding.'\")\nprint(\" Proceedings of the IEEE ICCV, 2019.\")\nprint(\" arXiv: https://arxiv.org/abs/1811.08383\")\n\nprint(\"\\n\" + \"=\" * 70)\nprint(\"Good luck with your PhD research! πŸŽ“\")\nprint(\"=\" * 70)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Testing","metadata":{}},{"cell_type":"code","source":"# Test model with dummy data to verify it works\nprint(\"Testing model with dummy data...\")\n\n# Create dummy input (batch_size, channels, height, width)\n# For num_segments=8: input is [batch, 3*8, 224, 224]\ndummy_input = torch.randn(2, 3 * config.num_segments, 224, 224)\n\nif torch.cuda.is_available():\n dummy_input = dummy_input.cuda()\n\n# Forward pass\nmodel.eval()\nwith torch.no_grad():\n output = model(dummy_input)\n\nprint(f\"\\nβœ“ Model test successful!\")\nprint(f\"Input shape: {dummy_input.shape}\")\nprint(f\"Output shape: {output.shape}\")\nprint(f\"Expected output shape: [batch_size={2}, num_classes={config.num_class}]\")\n\n# Verify temporal shift is working\nprint(f\"\\nπŸ” Verifying Temporal Shift Module:\")\nhas_temporal_shift = False\nfor name, module in model.named_modules():\n if isinstance(module, TemporalShift):\n has_temporal_shift = True\n print(f\" Found TSM in: {name}\")\n break\n\nif has_temporal_shift:\n print(\" βœ“ Temporal Shift Module is active!\")\nelse:\n print(\" ⚠️ No Temporal Shift found - model is baseline TSN\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}