{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":34426,"databundleVersionId":3218632,"sourceType":"competition"}],"dockerImageVersionId":30665,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# # This Python 3 environment comes with many helpful analytics libraries installed\n# # It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# # For example, here's several helpful packages to load\n\n# import numpy as np # linear algebra\n# import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# # Input data files are available in the read-only \"../input/\" directory\n# # For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\n# import os\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n#         print(os.path.join(dirname, filename))\n\n# # You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# # You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-03-20T09:55:54.096868Z","iopub.execute_input":"2024-03-20T09:55:54.097219Z","iopub.status.idle":"2024-03-20T09:55:54.101940Z","shell.execute_reply.started":"2024-03-20T09:55:54.097191Z","shell.execute_reply":"2024-03-20T09:55:54.100965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## コードの実行の仕方\n* Kaggleのアカウントを作成してください。\n* このノートブックをご自身のアカウントにコピーしてください。  \n右上のcopy&editタグからcopyできます。\n* AcceleratorをGUP T4 x 2に設定してください。  \nAcceleratorは右上の設定メニュー(点3つのタグ)から変更できます。  \n* ライブラリとフレームワークのインポートを行った後、Acceleratorの確認を行ってください。  \n出力がcudaであれば、GPUを使用してすべてのセルを実行することができます。  \n* ツールバーのRun Allをクリックしてください。","metadata":{}},{"cell_type":"markdown","source":"## ライブラリのインポート","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader, Dataset, random_split\nfrom torchvision.datasets.folder import default_loader\nfrom torchvision import datasets, models, transforms\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport os\n%matplotlib inline","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:55:54.103460Z","iopub.execute_input":"2024-03-20T09:55:54.103710Z","iopub.status.idle":"2024-03-20T09:55:54.121653Z","shell.execute_reply.started":"2024-03-20T09:55:54.103688Z","shell.execute_reply":"2024-03-20T09:55:54.120807Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Acceleratorの確認","metadata":{}},{"cell_type":"code","source":"# Acceleratorの確認\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nprint(device)","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:55:54.123432Z","iopub.execute_input":"2024-03-20T09:55:54.123841Z","iopub.status.idle":"2024-03-20T09:55:54.133376Z","shell.execute_reply.started":"2024-03-20T09:55:54.123810Z","shell.execute_reply":"2024-03-20T09:55:54.132552Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 訓練データの読み込みと前処理","metadata":{}},{"cell_type":"code","source":"# 前処理の条件\ntrain_transform = transforms.Compose([\n    transforms.Resize((32, 32)),\n    # ランダムに左右を入れ替える\n    transforms.RandomHorizontalFlip(),\n    # ランダムに画像の色調を変更する\n    transforms.ColorJitter(),\n    # ランダムに画像を±10°で回転\n    transforms.RandomRotation(10),\n    # 画像をtensorクラスに変換してchannel_firstにしてくれる\n    transforms.ToTensor(), \n    # channelごとに(rgbごとに)画像全体の平均値を0.5, 標準偏差を0.5になるように正規化を行う\n    transforms.Normalize((0.5, ), (0.5, ))\n])\n\ntest_transform = transforms.Compose([\n    transforms.Resize((32, 32)),\n    transforms.ToTensor(), \n    # channelごとに(rgbごとに)画像全体の平均値を0.5, 標準偏差を0.5になるように正規化を行う\n    transforms.Normalize((0.5, ), (0.5, ))\n])","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:55:54.134379Z","iopub.execute_input":"2024-03-20T09:55:54.134642Z","iopub.status.idle":"2024-03-20T09:55:54.144840Z","shell.execute_reply.started":"2024-03-20T09:55:54.134612Z","shell.execute_reply":"2024-03-20T09:55:54.144001Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 訓練データとテストデータのpath\ntrain_path = \"./../input/dog-vs-cat-classification/train/train/\"\ntest_path = \"./../input/dog-vs-cat-classification/test/test/\"","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:55:54.146554Z","iopub.execute_input":"2024-03-20T09:55:54.146828Z","iopub.status.idle":"2024-03-20T09:55:54.159473Z","shell.execute_reply.started":"2024-03-20T09:55:54.146806Z","shell.execute_reply":"2024-03-20T09:55:54.158600Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# データセットの作成\ndataset = datasets.ImageFolder(train_path, transform=train_transform)","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:55:54.160552Z","iopub.execute_input":"2024-03-20T09:55:54.160950Z","iopub.status.idle":"2024-03-20T09:58:39.884135Z","shell.execute_reply.started":"2024-03-20T09:55:54.160921Z","shell.execute_reply":"2024-03-20T09:58:39.883241Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## データセットを学習用と検証用に分割する","metadata":{}},{"cell_type":"code","source":"# データセットを学習用と検証用に分割\ntrain_size = int(0.8 * len(dataset))  # 80%を学習用とする\nval_size = len(dataset) - train_size\ntrain_dataset, val_dataset = random_split(dataset, [train_size, val_size])\n\nprint(\"train images:\", len(train_dataset))\nprint(\"val images:\", len(val_dataset))","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:58:39.885381Z","iopub.execute_input":"2024-03-20T09:58:39.885723Z","iopub.status.idle":"2024-03-20T09:58:39.925451Z","shell.execute_reply.started":"2024-03-20T09:58:39.885685Z","shell.execute_reply":"2024-03-20T09:58:39.924558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ラベルに対応する名前をclassesとして定義する\nclasses = dataset.classes\nprint(classes)","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:58:39.927936Z","iopub.execute_input":"2024-03-20T09:58:39.928205Z","iopub.status.idle":"2024-03-20T09:58:39.933245Z","shell.execute_reply.started":"2024-03-20T09:58:39.928182Z","shell.execute_reply":"2024-03-20T09:58:39.932176Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 学習用のデータローダーと検証用のデータローダーを作成","metadata":{}},{"cell_type":"code","source":"# バッチサイズ\nbatch_size = 64\n# データローダー\ntrain_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)\nval_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:58:39.934569Z","iopub.execute_input":"2024-03-20T09:58:39.934892Z","iopub.status.idle":"2024-03-20T09:58:39.943710Z","shell.execute_reply.started":"2024-03-20T09:58:39.934868Z","shell.execute_reply":"2024-03-20T09:58:39.942791Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# dataloaderからimgsとlabelsを取り出す\ntrain_iter = iter(train_loader)\nimgs, labels = next(train_iter)","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:58:39.944907Z","iopub.execute_input":"2024-03-20T09:58:39.945208Z","iopub.status.idle":"2024-03-20T09:58:40.590986Z","shell.execute_reply.started":"2024-03-20T09:58:39.945184Z","shell.execute_reply":"2024-03-20T09:58:40.589965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 学習する画像を確認","metadata":{}},{"cell_type":"code","source":"# 画像の確認\nplt.style.use(\"dark_background\")\nplt.figure(figsize=(15, 15))\nfor i in range(36):\n    ax = plt.subplot(6, 6, i+1, xticks=[], yticks=[])\n    # 範囲外のものを0or1にする\n    imgs[i] = np.clip(imgs[i], 0, 1)\n    # チャンネルラストに\n    ax.imshow(imgs[i].permute(1, 2, 0))\n    # 画像名の取得\n    label = classes[labels[i]]\n    ax.set_title(label, fontsize=12)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:58:40.592429Z","iopub.execute_input":"2024-03-20T09:58:40.592708Z","iopub.status.idle":"2024-03-20T09:58:42.512849Z","shell.execute_reply.started":"2024-03-20T09:58:40.592684Z","shell.execute_reply":"2024-03-20T09:58:42.511912Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 畳み込みニューラルネットワークを定義する","metadata":{}},{"cell_type":"code","source":"# 全結合層への入力を確かめるネット\nclass Net(nn.Module):\n    def __init__(self):\n        super().__init__()\n        # 畳み込み層\n        self.feature = nn.Sequential(\n            nn.Conv2d(in_channels=3, out_channels=6, kernel_size=5),\n            nn.ReLU(inplace=True),\n            # nn.MaxPool2dは、kernel_size=2, stride=2だとサイズは半分になる\n            nn.MaxPool2d(kernel_size=2, stride=2),\n            nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d(kernel_size=2, stride=2),\n\n        )\n\n    def forward(self, x):\n        x = self.feature(x)\n        x = x.view(x.size(0), -1)\n        return x","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:58:42.514037Z","iopub.execute_input":"2024-03-20T09:58:42.514330Z","iopub.status.idle":"2024-03-20T09:58:42.521203Z","shell.execute_reply.started":"2024-03-20T09:58:42.514305Z","shell.execute_reply":"2024-03-20T09:58:42.520299Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 全結合層への入力を確かめるためのfakedata\n# バッチサイズ・チャンネル数・画像高さ・画像幅を入力する画像と合わせたfake_dataを作る\nfake_data = torch.FloatTensor(64, 3, 32, 32)\n\n# fake_dataを流すためのnetのインスタンスを生成\nfakenet = Net()\n\n# fake_dataをfakenetに渡して出力のsizeを確認\ncheck = fakenet(fake_data).size()\n\nprint(f\"(batch_size, in_features) = {check}\")\n# 全結合層への入力が400だとわかる","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:58:42.522572Z","iopub.execute_input":"2024-03-20T09:58:42.522995Z","iopub.status.idle":"2024-03-20T09:58:42.631090Z","shell.execute_reply.started":"2024-03-20T09:58:42.522962Z","shell.execute_reply":"2024-03-20T09:58:42.630179Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 全結合層への入力を確かめるネット\nclass Net(nn.Module):\n    def __init__(self):\n        super().__init__()\n        # 畳み込み層\n        self.feature = nn.Sequential(\n            nn.Conv2d(in_channels=3, out_channels=6, kernel_size=5),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d(kernel_size=2, stride=2),\n            nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d(kernel_size=2, stride=2),\n\n        )\n\n        # 全結合層\n        self.classifier = nn.Sequential(\n            nn.Linear(in_features=400, out_features=256),\n            nn.ReLU(inplace=True),\n            nn.Dropout(p=0.5),\n            nn.Linear(in_features=256, out_features=2),\n        )\n\n    def forward(self, x):\n        x = self.feature(x)\n#         畳み込み層の出力を一次元(batch_size, チャンネル数x画像高x画像幅)のベクトルにする\n        x = x.view(x.size(0), -1)\n        x = self.classifier(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:58:42.632447Z","iopub.execute_input":"2024-03-20T09:58:42.632985Z","iopub.status.idle":"2024-03-20T09:58:42.641713Z","shell.execute_reply.started":"2024-03-20T09:58:42.632948Z","shell.execute_reply":"2024-03-20T09:58:42.640803Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# モデルが作用するか確認\n# imgsの0番目の画像を使用\nimg = imgs[0]\n# unsqueeze(0)でbatchの次元を追加\nimg = img.unsqueeze(0)\nimg.size()\nnet = Net()\nprint(net(img))\n# モデルが作用していることが確認できた","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:58:42.642925Z","iopub.execute_input":"2024-03-20T09:58:42.643221Z","iopub.status.idle":"2024-03-20T09:58:42.744868Z","shell.execute_reply.started":"2024-03-20T09:58:42.643197Z","shell.execute_reply":"2024-03-20T09:58:42.743962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## モデルの訓練","metadata":{}},{"cell_type":"code","source":"# インスタンスの生成\nnet = Net()\n# netをgpuに渡す\nnet.cuda()","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:58:42.748465Z","iopub.execute_input":"2024-03-20T09:58:42.748778Z","iopub.status.idle":"2024-03-20T09:58:42.955147Z","shell.execute_reply.started":"2024-03-20T09:58:42.748740Z","shell.execute_reply":"2024-03-20T09:58:42.954240Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 損失関数の定義\ncriterion = nn.CrossEntropyLoss()\n\n# 最適化アルゴリズム\noptimizer = optim.Adam(net.parameters(), lr=0.001)","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:58:42.956155Z","iopub.execute_input":"2024-03-20T09:58:42.956429Z","iopub.status.idle":"2024-03-20T09:58:42.961658Z","shell.execute_reply.started":"2024-03-20T09:58:42.956407Z","shell.execute_reply":"2024-03-20T09:58:42.960754Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 学習\nnum_epochs = 20\n\n# ミニバッチごとのlossやaccuracyを格納するリスト\nlosses = []\naccs = []\nt_losses = []\nt_accs = []\n\nfor epoch in range(num_epochs):\n    # 訓練モード\n    net.train()\n    running_loss = 0.0\n    running_acc = 0.0\n    for i, (imgs, labels) in enumerate(train_loader):\n        # cudaにデータを渡す\n        imgs, labels = imgs.cuda(), labels.cuda()\n        # 最適化アルゴリズムの初期化\n        optimizer.zero_grad()\n        # 分類\n        outputs = net(imgs)\n        # 損失の計算\n        loss = criterion(outputs, labels)\n        running_loss += loss.item()\n        # 精度の計算\n        acc = torch.argmax(outputs, dim=1)\n        running_acc += torch.mean(acc.eq(labels).float())\n        # 誤差逆伝播\n        loss.backward()\n        # 重みの更新\n        optimizer.step()\n    # lossの平均化とリストに格納\n    running_loss /= i+1\n    losses.append(running_loss)\n    # accの平均化とリストに格納\n    running_acc /= i+1\n    accs.append(running_acc.cpu())\n\n    # 評価モード\n    net.eval()\n    t_running_loss = 0.0\n    t_running_acc = 0.0\n    with torch.no_grad():\n        for j, (t_imgs, t_labels) in enumerate(val_loader):\n            t_imgs, t_labels = t_imgs.cuda(), t_labels.cuda()\n            t_outputs = net(t_imgs)\n            t_loss = criterion(t_outputs, t_labels)\n            t_running_loss += t_loss.item()\n            t_acc = torch.argmax(t_outputs, dim=1)\n            t_running_acc += torch.mean(t_acc.eq(t_labels).float())\n        t_running_loss /= j+1\n        t_losses.append(t_running_loss)\n        t_running_acc /= j+1\n        t_accs.append(t_running_acc.cpu())\n    \n    # 損失や精度の表示\n    print(f\"epoch: {epoch}, train loss: {running_loss:.4f}, train acc: {running_acc:.4f}\")\n    print(f\"epoch: {epoch}, val loss: {t_running_loss:.4f}, val acc: {t_running_acc:.4f}\")\n    print(\"=\"*100)","metadata":{"execution":{"iopub.status.busy":"2024-03-20T09:58:42.963121Z","iopub.execute_input":"2024-03-20T09:58:42.963904Z","iopub.status.idle":"2024-03-20T10:26:24.380233Z","shell.execute_reply.started":"2024-03-20T09:58:42.963877Z","shell.execute_reply":"2024-03-20T10:26:24.379275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 誤差と精度の推移","metadata":{}},{"cell_type":"code","source":"# 誤差の推移\nplt.style.use(\"ggplot\")\nplt.plot(losses, label=\"train\")\nplt.plot(t_losses, label=\"test\")\nplt.legend()\nplt.xlabel(\"epochs\")\nplt.ylabel(\"loss\")\nplt.title(\"Loss vs Epoch\")\nplt.xticks(torch.arange(0, 21, 1))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-03-20T10:31:28.879074Z","iopub.execute_input":"2024-03-20T10:31:28.879816Z","iopub.status.idle":"2024-03-20T10:31:29.172329Z","shell.execute_reply.started":"2024-03-20T10:31:28.879784Z","shell.execute_reply":"2024-03-20T10:31:29.171202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 精度の推移\nplt.plot(accs, label=\"train\")\nplt.plot(t_accs, label=\"test\")\nplt.legend()\nplt.xlabel(\"epochs\")\nplt.ylabel(\"acuracy\")\nplt.title(\"Accuracy vs Epoch\")\nplt.xticks(torch.arange(0, 21, 1))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-03-20T10:31:34.299852Z","iopub.execute_input":"2024-03-20T10:31:34.300816Z","iopub.status.idle":"2024-03-20T10:31:34.621676Z","shell.execute_reply.started":"2024-03-20T10:31:34.300744Z","shell.execute_reply":"2024-03-20T10:31:34.620739Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 検証データの正解率を計算","metadata":{}},{"cell_type":"code","source":"# 正解の数\ncorrect = 0\n# 総数\ntotal = 0\n\n# 評価モード\nnet.eval()\nfor j, (t_imgs, t_labels) in enumerate(val_loader):\n    # t_imgs, t_labelsをcudaに渡す\n    t_imgs, t_labels = t_imgs.cuda(), t_labels.cuda()\n\n    # 分類\n    t_outputs = net(t_imgs)\n    t_preds = torch.argmax(t_outputs, dim=1)\n    correct += t_preds.eq(t_labels).sum().item()\n    total += len(t_imgs)\nprint(f\"正解率: {correct/total*100}%\")","metadata":{"execution":{"iopub.status.idle":"2024-03-20T10:26:39.686813Z","shell.execute_reply.started":"2024-03-20T10:26:25.178980Z","shell.execute_reply":"2024-03-20T10:26:39.685769Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 訓練したモデルで検証データの推論","metadata":{}},{"cell_type":"code","source":"# 検証用のデータセットから16バッチだけのloaderを作る\nbatch_size=16\nval_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=True)\nval_iter = iter(val_loader)\nt_imgs, t_labels = next(val_iter)\n# 評価モード\nnet.eval()\n\n# 推論を行うために画像とラベルをcudaに渡す\nt_imgs, t_labels = t_imgs.cuda(), t_labels.cuda()\n# 推論\nt_outputs = net(t_imgs)\nplt.style.use(\"dark_background\")\nplt.figure(figsize=(12, 12))\nfor i in range(batch_size):\n    # 描画するために画像とラベルをcpuにわたす\n    t_imgs, t_labels = t_imgs.cpu(), t_labels.cpu()\n    plt.subplot(4, 4, i+1)\n    # 0~1の範囲外の要素を0または1にする\n    t_imgs[i] = np.clip(t_imgs[i], 0, 1)\n    # imshow関数に入力するためにpermuteでchannel_lastにする\n    plt.imshow(t_imgs[i].permute(1, 2, 0))\n    # メモリとラベルを非表示にする\n    plt.tick_params(labelbottom=False, labelleft=False, bottom=False, left=False)\n#     タイトルに正解ラベルと予想結果を表示する\n    plt.title(f\"true: {classes[t_labels[i]]}, predict: {classes[torch.argmax(t_outputs[i], dim=0).item()]}\")\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-03-20T10:32:01.654946Z","iopub.execute_input":"2024-03-20T10:32:01.655568Z","iopub.status.idle":"2024-03-20T10:32:04.917649Z","shell.execute_reply.started":"2024-03-20T10:32:01.655534Z","shell.execute_reply":"2024-03-20T10:32:04.916702Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## テストデータの分類","metadata":{}},{"cell_type":"code","source":"# testデータが入っているフォルダからデータセットを作成するためのクラスを定義する\nclass TestDataset(Dataset):\n    \n    def __init__(self, root, transforms=None):\n        self.transforms = transforms\n        # 指定されたpathにあるすべてのjpgファイルを取得してリストに保存する\n        # img_pathsはリスト\n        self.img_paths = sorted(os.path.join(root, x) for x in os.listdir(root) if x.endswith('.jpg'))\n\n        \n    def __len__(self):\n        # データセット内の画像の個数\n        return len(self.img_paths)\n    \n    # 画像に通し番号(idx)を振って、順番にアクセスして前処理する\n    def __getitem__(self, idx):\n        # img_pathに対応する画像ファイル対応するパスをimg_pathsから取得\n        img_path = self.img_paths[idx]\n        # default_loader関数はimg_pathから画像を読み込んでtensorで返す\n        img = default_loader(img_path)\n        # もし前処理が指定されていれば、前処理を行う\n        if self.transforms is not None:\n            img = self.transforms(img)\n        # 画像と画像ファイルの名前のタプルを返す\n        return img, img_path.split('/')[-1]","metadata":{"execution":{"iopub.status.busy":"2024-03-20T10:26:43.032976Z","iopub.execute_input":"2024-03-20T10:26:43.033276Z","iopub.status.idle":"2024-03-20T10:26:43.041544Z","shell.execute_reply.started":"2024-03-20T10:26:43.033249Z","shell.execute_reply":"2024-03-20T10:26:43.040449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# テスト用のデータセットを作成\ntest_dataset = TestDataset(root=test_path, transforms=test_transform)\n# テスト用のデータローダーを作成\ntest_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=True)","metadata":{"execution":{"iopub.status.busy":"2024-03-20T10:26:43.042698Z","iopub.execute_input":"2024-03-20T10:26:43.043090Z","iopub.status.idle":"2024-03-20T10:26:46.160240Z","shell.execute_reply.started":"2024-03-20T10:26:43.043066Z","shell.execute_reply":"2024-03-20T10:26:46.159460Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# モデルを検証モードにする\nnet.eval()\n\n# 予測したlabelを格納するarray\nt_preds_arr = np.array([])\n\n# 予測した画像のpathを格納するarray\nt_img_paths = np.array([])\n\nwith torch.no_grad():\n    for j, (t_imgs, t_img_path) in enumerate(test_loader):\n        # 画像をgpuに渡す\n        t_imgs = t_imgs.cuda()\n        # モデルにt_imgsを渡して推論結果を取得\n        t_outputs = net(t_imgs)\n        # モデルの出力(t_outputs)から予想されたlabelを取得\n        t_preds = torch.argmax(t_outputs, dim=1)\n        # 予測されたlabelをt_result_arrに格納\n        # その際にcpuに移して勾配を外して、numpyにする\n        t_preds_arr = np.append(t_preds_arr, t_preds.cpu().detach().numpy())\n        # テストデータの各画像のpathをt_img_pathsに格納\n        t_img_paths = np.append(t_img_paths, t_img_path)","metadata":{"execution":{"iopub.status.busy":"2024-03-20T10:26:46.161409Z","iopub.execute_input":"2024-03-20T10:26:46.161708Z","iopub.status.idle":"2024-03-20T10:29:12.143368Z","shell.execute_reply.started":"2024-03-20T10:26:46.161683Z","shell.execute_reply":"2024-03-20T10:29:12.142494Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 前述したdogsとcatsが格納されているリスト\nprint(classes)","metadata":{"execution":{"iopub.status.busy":"2024-03-20T10:29:12.144605Z","iopub.execute_input":"2024-03-20T10:29:12.145031Z","iopub.status.idle":"2024-03-20T10:29:12.150147Z","shell.execute_reply.started":"2024-03-20T10:29:12.144992Z","shell.execute_reply":"2024-03-20T10:29:12.149124Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 予測結果を可視化\nplt.style.use(\"dark_background\")\nplt.figure(figsize=(12, 12))\nfor i in range(16):\n    plt.subplot(4, 4, i+1)\n    t_img = plt.imread(os.path.join(test_path, t_img_paths[i]))\n    plt.imshow(t_img)\n    plt.tick_params(labelbottom=False, labelleft=False, bottom=False, left=False)\n#     t_preds_arrをインデックスとして使用して、classesリストからdogsまたはcatsを取り出す\n    title = classes[int(t_preds_arr[i])]\n    plt.title(f\"predict: {title}\")","metadata":{"execution":{"iopub.status.busy":"2024-03-20T10:29:12.151329Z","iopub.execute_input":"2024-03-20T10:29:12.151602Z","iopub.status.idle":"2024-03-20T10:29:16.016995Z","shell.execute_reply.started":"2024-03-20T10:29:12.151572Z","shell.execute_reply":"2024-03-20T10:29:16.016030Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}