{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# early stopping\nimport numpy as np\nimport torch\n \nclass EarlyStopping:\n    \"\"\"Early stops the training if validation loss doesn't improve after a given patience.\"\"\"\n    def __init__(self, patience=7, verbose=False, delta=0):\n        \"\"\"\n        Args:\n            patience (int): How long to wait after last time validation loss improved.\n                            上次验证集损失值改善后等待几个epoch\n                            Default: 7\n            verbose (bool): If True, prints a message for each validation loss improvement.\n                            如果是True，为每个验证集损失值改善打印一条信息\n                            Default: False\n            delta (float): Minimum change in the monitored quantity to qualify as an improvement.\n                            监测数量的最小变化，以符合改进的要求\n                            Default: 0\n        \"\"\"\n        self.patience = patience\n        self.verbose = verbose\n        self.counter = 0\n        self.best_score = None\n        self.early_stop = False\n        self.val_loss_min = np.Inf\n        self.delta = delta\n \n    def __call__(self, val_loss, model):\n \n        score = -val_loss\n \n        if self.best_score is None:\n            self.best_score = score\n            self.save_checkpoint(val_loss, model)\n        elif score < self.best_score + self.delta:\n            self.counter += 1\n            # print(f'EarlyStopping counter: {self.counter} out of {self.patience}')\n            if self.counter >= self.patience:\n                self.early_stop = True\n        else:\n            self.best_score = score\n            self.save_checkpoint(val_loss, model)\n            self.counter = 0\n \n    def save_checkpoint(self, val_loss, model):\n        '''\n        Saves model when validation loss decrease.\n        验证损失减少时保存模型。\n        '''\n        if self.verbose:\n            print(f'Validation loss decreased ({self.val_loss_min:.6f} --> {val_loss:.6f}).  Saving model ...')\n        torch.save(model.state_dict(), 'checkpoint.pth') # 这里会存储迄今最优模型的参数\n        # torch.save(model, 'finish_model.pkl') # 这里会存储迄今最优的模型\n","metadata":{"execution":{"iopub.status.busy":"2023-03-24T04:52:26.926489Z","iopub.execute_input":"2023-03-24T04:52:26.926948Z","iopub.status.idle":"2023-03-24T04:52:39.539403Z","shell.execute_reply.started":"2023-03-24T04:52:26.926904Z","shell.execute_reply":"2023-03-24T04:52:39.537852Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport pandas as pd\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\nimport os\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split\nimport time","metadata":{"execution":{"iopub.status.busy":"2023-03-23T15:31:42.441292Z","iopub.execute_input":"2023-03-23T15:31:42.441847Z","iopub.status.idle":"2023-03-23T15:31:42.449561Z","shell.execute_reply.started":"2023-03-23T15:31:42.441804Z","shell.execute_reply":"2023-03-23T15:31:42.448515Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# vgg-based\nclass Net(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.features = nn.Sequential(\n            nn.Conv2d(3, 64, kernel_size=3, padding=1),\n            nn.BatchNorm2d(64),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(64, 64, kernel_size=3, padding=1),\n            nn.BatchNorm2d(64),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d(kernel_size=2, stride=2),  # 224 / 2 = 112\n\n            nn.Conv2d(64, 128, kernel_size=3, padding=1),\n            nn.BatchNorm2d(128),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(128, 128, kernel_size=3, padding=1),\n            nn.BatchNorm2d(128),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d(kernel_size=2, stride=2),  # 112 /2 = 56\n\n            nn.Conv2d(128, 256, kernel_size=3, padding=1),\n            nn.BatchNorm2d(256),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(256, 256, kernel_size=3, padding=1),\n            nn.BatchNorm2d(256),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(256, 256, kernel_size=3, padding=1),\n            nn.BatchNorm2d(256),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d(kernel_size=2, stride=2),  # 56 /2 =28\n\n            nn.Conv2d(256, 512, kernel_size=3, padding=1),\n            nn.BatchNorm2d(512),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(512, 512, kernel_size=3, padding=1),\n            nn.BatchNorm2d(512),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(512, 512, kernel_size=3, padding=1),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d(kernel_size=2, stride=2),  # 28 /2 = 14\n\n            nn.Conv2d(512, 512, kernel_size=3, padding=1),\n            nn.BatchNorm2d(512),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(512, 512, kernel_size=3, padding=1),\n            nn.BatchNorm2d(512),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(512, 512, kernel_size=3, padding=1),\n            nn.BatchNorm2d(512),\n            nn.ReLU(inplace=True),\n\n            nn.MaxPool2d(kernel_size=2, stride=2)  # 14 - 2 / 2 + 1 = 7\n        )\n\n        self.classifier = nn.Sequential(\n            nn.Linear(512 * 7 * 7, 4096),\n            nn.ReLU(inplace=True),\n            nn.Dropout(0.5),\n\n            nn.Linear(4096, 4096),\n            nn.ReLU(True),\n            nn.Dropout(0.5),\n\n            nn.Linear(4096, 10)\n        )\n\n    def forward(self, x):\n        x = self.features(x)\n        x = x.view(x.size(0), -1)\n        x = self.classifier(x)\n        return x\n    # add initialization to against underfitting\n    def initialize_weights(self):\n        for m in self.modules():\n            if isinstance(m, nn.Conv2d):\n                init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')\n                if m.bias is not None:\n                    init.constant_(m.bias, 0)\n            elif isinstance(m, nn.BatchNorm2d):\n                init.constant_(m.weight, 1)\n                init.constant_(m.bias, 0)\n            elif isinstance(m, nn.Linear):\n                init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')\n                init.constant_(m.bias, 0)\n","metadata":{"execution":{"iopub.status.busy":"2023-03-23T15:31:42.451598Z","iopub.execute_input":"2023-03-23T15:31:42.452250Z","iopub.status.idle":"2023-03-23T15:31:42.481826Z","shell.execute_reply.started":"2023-03-23T15:31:42.452211Z","shell.execute_reply":"2023-03-23T15:31:42.480537Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 1.only normalize image get a validation accuracy around 47% --> without overfitting problems\n# 2.with many image augmentation, the results for trian and validation are all 40%, no overfitting\n# 3.change learning rate 0.1, 0.01(40%), 0.001(best)\n# try adam... still not good validation are 41; add batches, best validation acc is 50%\n\n\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport pandas as pd\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\nimport os\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split\nimport time\npatience = 40 # 当验证集损失在连续20次训练周期中都没有得到降低时，停止模型训练，以防止模型过拟合\nearly_stopping = EarlyStopping(patience, verbose=True)\n\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n    \nclass MyDataset(Dataset):\n    def __init__(self, root, csv_file, transform=None):\n        self.root = root\n        self.transforms = transform\n        self.df = pd.read_csv(csv_file, header=None, skiprows=1)\n        self.classes = sorted(self.df[1].unique())\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, index):\n        vid, label = self.df.iloc[index, :]\n        img_list = os.listdir(os.path.join(self.root, f\"{vid}\"))\n        img_list = sorted(img_list)\n        img_path = os.path.join(self.root, f\"{vid}\", img_list[int(len(img_list)/2)])\n \n        img = Image.open(img_path).convert('RGB')\n        if self.transforms is not None:\n            img = self.transforms(img)\n\n        label = self.classes.index(label)\n        return img, label\n\n# You can add data augmentation here\n# transform = transforms.Compose([\n#             transforms.Resize((224, 224)),\n#             transforms.ToTensor()\n# ])\n\n\n# color jitter because there is some brightness for this...\n# gaussianblur for the robust\ntransform = transforms.Compose([\n            transforms.Resize((224, 224)),\n            transforms.GaussianBlur(kernel_size=7, sigma=(0.1, 2.0)),\n            transforms.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0.1),\n            transforms.RandomHorizontalFlip(p=0.2),\n            transforms.ToTensor(),\n            transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # Normalize the tensor with ImageNet mean and standard deviation\n        ])\n\n#\n# transform = transforms.Compose([\n#     transforms.Resize((224, 224)),  # Resize the image to 256x256\n#     transforms.RandomHorizontalFlip(p=0.5),  # Horizontally flip the image with a 50% probability\n#     transforms.RandomAffine(degrees=15, translate=(0.1, 0.1), scale=(0.9, 1.1)),  # Apply random rotation, translation, and scaling\n#     transforms.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0.1),  # Apply random color changes\n#     transforms.ToTensor(),  # Convert the image to a tensor\n#     transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # Normalize the tensor with ImageNet mean and standard deviation\n# ])\n\n\ntrainval_dataset = MyDataset(\"/kaggle/input/aiaa-5032-hw2/video_frames_30fpv_320p/video_frames_30fpv_320p\", \"/kaggle/input/aiaa-5032-hw2/trainval.csv\", transform)\ntrain_data, val_data = train_test_split(trainval_dataset, test_size=0.2, random_state=0)\n\ntrain_loader = DataLoader(train_data, batch_size=32, shuffle=True)\nval_loader = DataLoader(val_data, batch_size=32, shuffle=False)\n\nnet = Net().to(device)\n\noptimizer = torch.optim.SGD(net.parameters(), lr=1e-3, momentum=0.9, weight_decay=0.01) # sgd\n# optimizer = torch.optim.Adam(net.parameters(), lr=0.001, betas=(0.9, 0.99), weight_decay=0.01) # adam\ncriterion = nn.CrossEntropyLoss()\n\n\nfor epoch in range(100):\n    # Metrics here ...\n    running_loss = 0.0\n    correct = 0\n    total = 0\n    \n    for i, (inputs, labels) in enumerate(train_loader, 0):\n        # Training code ...\n        inputs, labels = inputs.to(device), labels.to(device)\n        optimizer.zero_grad()\n\n        outputs = net(inputs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item()\n        _, predicted = outputs.max(1)\n        total += labels.size(0)\n        correct += predicted.eq(labels).sum().item()\n\n    train_loss = running_loss / (i + 1)\n    train_acc = 100 * correct / total\n\n    val_loss = 0.0\n    val_correct = 0\n    val_total = 0\n    best_accuracy = 0\n    with torch.no_grad():\n        for val_inputs, val_labels in val_loader:\n            # Validation code ...\n            val_inputs, val_labels = val_inputs.to(device), val_labels.to(device)\n            val_outputs = net(val_inputs)\n            loss = criterion(val_outputs, val_labels)\n\n            val_loss += loss.item()\n            _, val_predicted = val_outputs.max(1)\n            val_total += val_labels.size(0)\n            val_correct += val_predicted.eq(val_labels).sum().item()\n\n        val_loss /= len(val_loader)\n        val_acc = 100 * val_correct / val_total\n        early_stopping(val_loss, net)\n    if early_stopping.early_stop:\n        print(\"Early stopping\")\n        break\n    if val_acc > best_accuracy:\n        best_accuracy = val_acc\n        torch.save(net.state_dict(), 'model_best.pth')\n    print(f\"Epoch {epoch + 1}/{50}, Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.2f}%, Val Loss: {val_loss:.4f}, Val Acc: {val_acc:.2f}%\")\n    \n","metadata":{"execution":{"iopub.status.busy":"2023-03-23T15:31:42.483810Z","iopub.execute_input":"2023-03-23T15:31:42.484535Z","iopub.status.idle":"2023-03-23T15:50:52.697052Z","shell.execute_reply.started":"2023-03-23T15:31:42.484497Z","shell.execute_reply":"2023-03-23T15:50:52.695053Z"},"trusted":true},"execution_count":null,"outputs":[]}]}