{"metadata":{"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":30746,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.10.13"},"papermill":{"default_parameters":{},"duration":2178.451466,"end_time":"2024-07-14T11:02:54.055227","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2024-07-14T10:26:35.603761","version":"2.5.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## 各種モジュールをインポート","metadata":{"papermill":{"duration":0.006175,"end_time":"2024-07-14T10:26:38.326236","exception":false,"start_time":"2024-07-14T10:26:38.320061","status":"completed"},"tags":[]}},{"cell_type":"code","source":"import pandas as pd\nimport os, glob, time, copy, zipfile\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split\nfrom tqdm import tqdm\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.utils.data as data\nimport torch.nn.functional as F\nfrom torchvision import models, transforms","metadata":{"papermill":{"duration":7.022572,"end_time":"2024-07-14T10:26:45.354547","exception":false,"start_time":"2024-07-14T10:26:38.331975","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-07-26T08:01:50.384920Z","iopub.execute_input":"2024-07-26T08:01:50.385540Z","iopub.status.idle":"2024-07-26T08:01:56.388669Z","shell.execute_reply.started":"2024-07-26T08:01:50.385500Z","shell.execute_reply":"2024-07-26T08:01:56.387885Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 各種パラメータの設定","metadata":{"papermill":{"duration":0.00541,"end_time":"2024-07-14T10:26:45.365757","exception":false,"start_time":"2024-07-14T10:26:45.360347","status":"completed"},"tags":[]}},{"cell_type":"code","source":"size = 224\nmean = (0.485, 0.456, 0.406)\nstd = (0.229, 0.224, 0.225)\nbatch_size = 64 #バッチサイズ\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nnum_epoch = 10","metadata":{"papermill":{"duration":0.088571,"end_time":"2024-07-14T10:26:45.459829","exception":false,"start_time":"2024-07-14T10:26:45.371258","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-07-26T08:01:56.390319Z","iopub.execute_input":"2024-07-26T08:01:56.390951Z","iopub.status.idle":"2024-07-26T08:01:56.451625Z","shell.execute_reply.started":"2024-07-26T08:01:56.390923Z","shell.execute_reply":"2024-07-26T08:01:56.450625Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 初期化","metadata":{"papermill":{"duration":0.005847,"end_time":"2024-07-14T10:26:45.471847","exception":false,"start_time":"2024-07-14T10:26:45.466","status":"completed"},"tags":[]}},{"cell_type":"code","source":"!rm -rf ../data","metadata":{"papermill":{"duration":1.005648,"end_time":"2024-07-14T10:26:46.483288","exception":false,"start_time":"2024-07-14T10:26:45.47764","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-07-26T08:01:56.453008Z","iopub.execute_input":"2024-07-26T08:01:56.453413Z","iopub.status.idle":"2024-07-26T08:01:57.524907Z","shell.execute_reply.started":"2024-07-26T08:01:56.453377Z","shell.execute_reply":"2024-07-26T08:01:57.523661Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 解凍","metadata":{"papermill":{"duration":0.005658,"end_time":"2024-07-14T10:26:46.494717","exception":false,"start_time":"2024-07-14T10:26:46.489059","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# ディレクトリを設定\nbase_dir = '../input/dogs-vs-cats-redux-kernels-edition'\ntrain_dir = '../data/train'\ntest_dir = '../data/test'\n\nos.makedirs('../data', exist_ok=True)\n\n# train dataの解凍\nwith zipfile.ZipFile(os.path.join(base_dir, 'train.zip')) as train_zip:\n    train_zip.extractall('../data')\n    \n# test dataの解凍\nwith zipfile.ZipFile(os.path.join(base_dir, 'test.zip')) as test_zip:\n    test_zip.extractall('../data')\n\ntrain_list = glob.glob(os.path.join(train_dir, '*.jpg'))\ntest_list = glob.glob(os.path.join(test_dir, '*.jpg'))\n\n# train dataとvalidation dataを8:2に分割\ntrain_list, val_list = train_test_split(train_list, test_size=0.2)","metadata":{"papermill":{"duration":15.347723,"end_time":"2024-07-14T10:27:01.847998","exception":false,"start_time":"2024-07-14T10:26:46.500275","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-07-26T08:01:57.526532Z","iopub.execute_input":"2024-07-26T08:01:57.526979Z","iopub.status.idle":"2024-07-26T08:02:14.320180Z","shell.execute_reply.started":"2024-07-26T08:01:57.526938Z","shell.execute_reply":"2024-07-26T08:02:14.319353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# クラスの定義","metadata":{}},{"cell_type":"code","source":"class ImageTransform():\n    \n    def __init__(self, resize, mean, std):\n        self.data_transform = {\n            'train': transforms.Compose([\n                transforms.Resize((resize, resize)),  # 画像サイズを224にリサイズ\n                transforms.RandomAffine(degrees=0, shear=0.2), # Affine変換\n                transforms.RandomHorizontalFlip(),    # ランダム水平反転\n                transforms.RandomVerticalFlip(),      # ランダム垂直反転\n                transforms.ToTensor(),                # テンソルに変換\n                transforms.Normalize(mean, std)       # 正規化\n            ]),\n            'val': transforms.Compose([\n                transforms.Resize((resize, resize)),  # 画像サイズを224にリサイズ\n                transforms.ToTensor(),                # テンソルに変換\n                transforms.Normalize(mean, std)       # 正規化\n            ])\n        }\n        \n    def __call__(self, img, phase):\n        return self.data_transform[phase](img)","metadata":{"papermill":{"duration":0.015791,"end_time":"2024-07-14T10:27:01.870477","exception":false,"start_time":"2024-07-14T10:27:01.854686","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-07-26T08:02:14.322485Z","iopub.execute_input":"2024-07-26T08:02:14.323310Z","iopub.status.idle":"2024-07-26T08:02:14.331360Z","shell.execute_reply.started":"2024-07-26T08:02:14.323284Z","shell.execute_reply":"2024-07-26T08:02:14.330486Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class ImageDataset(data.Dataset):\n    \n    def __init__(self, file_list, transform=None, phase='train'):    \n        self.file_list = file_list\n        self.transform = transform\n        self.phase = phase\n        \n    def __len__(self):\n        return len(self.file_list)\n    \n    def __getitem__(self, idx):\n        \n        img_path = self.file_list[idx]\n        img = Image.open(img_path)\n        \n        img_transformed = self.transform(img, self.phase)\n        \n        # ファイル名からラベルを取得\n        label = img_path.split('/')[-1].split('.')[0]\n        if label == 'dog':\n            label = 1\n        elif label == 'cat':\n            label = 0\n\n        return img_transformed, label","metadata":{"papermill":{"duration":0.014851,"end_time":"2024-07-14T10:27:01.890755","exception":false,"start_time":"2024-07-14T10:27:01.875904","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-07-26T08:02:14.332400Z","iopub.execute_input":"2024-07-26T08:02:14.332675Z","iopub.status.idle":"2024-07-26T08:02:14.354114Z","shell.execute_reply.started":"2024-07-26T08:02:14.332651Z","shell.execute_reply":"2024-07-26T08:02:14.353254Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 前処理\ntrain_dataset = ImageDataset(train_list, transform=ImageTransform(size, mean, std), phase='train')\nval_dataset = ImageDataset(val_list, transform=ImageTransform(size, mean, std), phase='val')\n\n# データの読み込み\ntrain_dataloader = data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\nval_dataloader = data.DataLoader(val_dataset, batch_size=batch_size, shuffle=False)\n\ndataloader_dict = {'train': train_dataloader, 'val': val_dataloader}","metadata":{"papermill":{"duration":0.014821,"end_time":"2024-07-14T10:27:01.911054","exception":false,"start_time":"2024-07-14T10:27:01.896233","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-07-26T08:02:14.355188Z","iopub.execute_input":"2024-07-26T08:02:14.355479Z","iopub.status.idle":"2024-07-26T08:02:14.365062Z","shell.execute_reply.started":"2024-07-26T08:02:14.355456Z","shell.execute_reply":"2024-07-26T08:02:14.364204Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## モデルの定義","metadata":{"papermill":{"duration":0.005298,"end_time":"2024-07-14T10:27:01.921836","exception":false,"start_time":"2024-07-14T10:27:01.916538","status":"completed"},"tags":[]}},{"cell_type":"code","source":"use_pretrained = True\n# 事前学習済みのvgg16\nnet = models.vgg16(pretrained=use_pretrained)\n# 線形層の置き換え\nnet.classifier[6] = nn.Linear(in_features=4096, out_features=2)\n\nparams_to_update = [] # 学習パラメータの初期化\n\nupdate_params_name = ['classifier.6.weight', 'classifier.6.bias'] #更新するパラメータの指定\n\nfor name, param in net.named_parameters():\n    if name in update_params_name: # 更新するパラメータ\n        param.requires_grad = True\n        params_to_update.append(param) # 更新するパラメータの追加\n    else: # 更新しないパラメータ\n        param.requires_grad = False","metadata":{"papermill":{"duration":5.027967,"end_time":"2024-07-14T10:27:06.956184","exception":false,"start_time":"2024-07-14T10:27:01.928217","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-07-26T08:02:14.366314Z","iopub.execute_input":"2024-07-26T08:02:14.366715Z","iopub.status.idle":"2024-07-26T08:02:19.781401Z","shell.execute_reply.started":"2024-07-26T08:02:14.366684Z","shell.execute_reply":"2024-07-26T08:02:19.780623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 学習の定義","metadata":{"papermill":{"duration":0.008849,"end_time":"2024-07-14T10:27:06.973648","exception":false,"start_time":"2024-07-14T10:27:06.964799","status":"completed"},"tags":[]}},{"cell_type":"code","source":"criterion = nn.CrossEntropyLoss() #損失関数\noptimizer = optim.Adam(params=params_to_update, lr=0.0001)\n\ndef train_model(net, dataloader_dict, criterion, optimizer, num_epoch):\n    \n    since = time.time() #学習開始時刻を記録\n    best_model_wts = copy.deepcopy(net.state_dict()) #最良モデルの初期化\n    best_acc = 0.0 #最良精度の初期化\n    \n     # 損失と精度の履歴\n    history = {'train_loss': [], 'val_loss': [], 'train_acc': [], 'val_acc': []}\n    \n    net = net.to(device) #モデルをGPUに転送\n    print('training started')\n    for epoch in range(num_epoch): #各エポックの進捗\n        print('Epoch {}/{}'.format(epoch + 1, num_epoch))\n        print('-'*20)\n        \n        for phase in ['train', 'val']:\n            #学習と検証を交互に行う\n            if phase == 'train':\n                net.train() #学習フェーズ\n            else:\n                net.eval() #検証フェーズ\n                \n            epoch_loss = 0.0\n            epoch_corrects = 0\n            \n            for inputs, labels in tqdm(dataloader_dict[phase]):\n                inputs = inputs.to(device)\n                labels = labels.to(device)\n                optimizer.zero_grad()\n                \n                with torch.set_grad_enabled(phase == 'train'):\n                    outputs = net(inputs) #出力を算出\n                    _, preds = torch.max(outputs, 1) #予測値の取得\n                    loss = criterion(outputs, labels) #損失の計算\n                    \n                    if phase == 'train':\n                        loss.backward() #逆伝播で学習\n                        optimizer.step()\n                        \n                    #バッチごとの損失と精度を累積    \n                    epoch_loss += loss.item() * inputs.size(0) \n                    epoch_corrects += torch.sum(preds == labels.data)\n            \n            #エポックごとの損失と精度の計算\n            epoch_loss = epoch_loss / len(dataloader_dict[phase].dataset)\n            epoch_acc = epoch_corrects.double() / len(dataloader_dict[phase].dataset)\n            \n            print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))\n            \n            # 履歴に保存\n            history[f'{phase}_loss'].append(epoch_loss)\n            history[f'{phase}_acc'].append(epoch_acc.cpu().numpy())\n            \n            # 最良モデルの保存\n            if phase == 'val' and epoch_acc > best_acc:\n                best_acc = epoch_acc\n                best_model_wts = copy.deepcopy(net.state_dict())\n                \n    time_elapsed = time.time() - since #学習の総時間を計算\n    print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))\n    print('Best val Acc: {:4f}'.format(best_acc))\n\n    # 最良の重みを読み込む\n    net.load_state_dict(best_model_wts)\n    return net, history","metadata":{"papermill":{"duration":0.025806,"end_time":"2024-07-14T10:27:07.007637","exception":false,"start_time":"2024-07-14T10:27:06.981831","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-07-26T08:02:19.782586Z","iopub.execute_input":"2024-07-26T08:02:19.782873Z","iopub.status.idle":"2024-07-26T08:02:19.800018Z","shell.execute_reply.started":"2024-07-26T08:02:19.782849Z","shell.execute_reply":"2024-07-26T08:02:19.798948Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## モデルの学習","metadata":{"papermill":{"duration":0.008072,"end_time":"2024-07-14T10:27:07.023857","exception":false,"start_time":"2024-07-14T10:27:07.015785","status":"completed"},"tags":[]}},{"cell_type":"code","source":"net, history = train_model(net, dataloader_dict, criterion, optimizer, num_epoch)","metadata":{"papermill":{"duration":1988.200157,"end_time":"2024-07-14T11:00:15.232574","exception":false,"start_time":"2024-07-14T10:27:07.032417","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-07-26T08:02:19.801466Z","iopub.execute_input":"2024-07-26T08:02:19.801959Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 損失の可視化","metadata":{"papermill":{"duration":0.616454,"end_time":"2024-07-14T11:00:16.511355","exception":false,"start_time":"2024-07-14T11:00:15.894901","status":"completed"},"tags":[]}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n# 損失のプロット\nplt.figure(figsize=(12, 5))\nplt.subplot(1, 2, 1)\nplt.plot(history['train_loss'], label='Train Loss')\nplt.plot(history['val_loss'], label='Val Loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.title('Loss over epochs')\nplt.legend()\n\n# 精度のプロット\nplt.subplot(1, 2, 2)\nplt.plot(history['train_acc'], label='Train Accuracy')\nplt.plot(history['val_acc'], label='Val Accuracy')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\nplt.title('Accuracy over epochs')\nplt.legend()\n\nplt.show()","metadata":{"papermill":{"duration":1.185905,"end_time":"2024-07-14T11:00:18.323463","exception":false,"start_time":"2024-07-14T11:00:17.137558","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 推論","metadata":{"papermill":{"duration":0.620276,"end_time":"2024-07-14T11:00:19.561038","exception":false,"start_time":"2024-07-14T11:00:18.940762","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# 変数の初期化\nid_list = []\npred_list = []\n\nwith torch.no_grad():\n    for test_path in tqdm(test_list):\n        img = Image.open(test_path) #画像読み込み\n        _id = int(test_path.split('/')[-1].split('.')[0]) #ID抽出\n\n        transform = ImageTransform(size, mean, std)\n        img = transform(img, phase='val') #画像変換\n        img = img.unsqueeze(0) #バッチ次元の追加\n        img = img.to(device) #画像をGPUに転送\n\n        net.eval() #モデルを評価モードに設定\n\n        outputs = net(img) #モデルによる推論\n        preds = F.softmax(outputs, dim=1)[:, 1].tolist() #クラス1(dog)の確率を算出\n        \n        id_list.append(_id) #IDをリストに追加\n        pred_list.append(preds[0]) #予測値をリストに追加\n    \n    \nres = pd.DataFrame({'id': id_list, 'label': pred_list}) #IDと予測値からデータフレームを作成\n\n\nres.sort_values(by='id', inplace=True) #ID順に並び替え\nres.reset_index(drop=True, inplace=True)\n\nres.to_csv('/kaggle/working/submission.csv', index=False) #データフレームをCSVファイルに保存\n\n# print(res) #データフレームの表示\n","metadata":{"papermill":{"duration":150.606935,"end_time":"2024-07-14T11:02:50.828113","exception":false,"start_time":"2024-07-14T11:00:20.221178","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]}]}