{"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":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":30746,"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\nimport numpy as np # linear algebra\nimport 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\nimport os\nfor 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-07-26T08:59:18.217250Z","iopub.execute_input":"2024-07-26T08:59:18.218099Z","iopub.status.idle":"2024-07-26T08:59:18.603263Z","shell.execute_reply.started":"2024-07-26T08:59:18.218064Z","shell.execute_reply":"2024-07-26T08:59:18.602294Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'\nprint(\"device:\", device)","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:18.605242Z","iopub.execute_input":"2024-07-26T08:59:18.605907Z","iopub.status.idle":"2024-07-26T08:59:20.518746Z","shell.execute_reply.started":"2024-07-26T08:59:18.605874Z","shell.execute_reply":"2024-07-26T08:59:20.517636Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## データの読込み\n/kaggle/inputのデータを、/kaggle/workingに読み込む。","metadata":{}},{"cell_type":"code","source":"# /kaggle/input/ に入っているファイルを確認\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:20.520086Z","iopub.execute_input":"2024-07-26T08:59:20.520604Z","iopub.status.idle":"2024-07-26T08:59:20.528834Z","shell.execute_reply.started":"2024-07-26T08:59:20.520566Z","shell.execute_reply":"2024-07-26T08:59:20.527748Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\n# /kaggle/input/ のcsvファイルを/kaggle/workingにコピーする\nshutil.copyfile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/sample_submission.csv', '/kaggle/working/sample_submission.csv')","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:20.532920Z","iopub.execute_input":"2024-07-26T08:59:20.533292Z","iopub.status.idle":"2024-07-26T08:59:20.543538Z","shell.execute_reply.started":"2024-07-26T08:59:20.533256Z","shell.execute_reply":"2024-07-26T08:59:20.542602Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import zipfile\n# /kaggle/input/ のzipファイルを、/kaggle/working/に保存\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip') as existing_zip:\n    existing_zip.extractall()\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip') as existing_zip:\n    existing_zip.extractall()","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:20.545072Z","iopub.execute_input":"2024-07-26T08:59:20.545656Z","iopub.status.idle":"2024-07-26T08:59:31.937112Z","shell.execute_reply.started":"2024-07-26T08:59:20.545628Z","shell.execute_reply":"2024-07-26T08:59:31.936107Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import glob\n# '/kaggle/working/' に入っているファイルを確認\nfiles = glob.glob('/kaggle/working/*')\nfor file in files: \n    print(file)","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:31.939183Z","iopub.execute_input":"2024-07-26T08:59:31.939581Z","iopub.status.idle":"2024-07-26T08:59:31.945628Z","shell.execute_reply.started":"2024-07-26T08:59:31.939529Z","shell.execute_reply":"2024-07-26T08:59:31.944675Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 犬と猫の画像を別々のフォルダに保存する","metadata":{}},{"cell_type":"code","source":"# 検証用フォルダの作成\nd_dir = '/kaggle/working/train/dog/'\nc_dir = '/kaggle/working/train/cat/'\n\nif os.path.isdir(d_dir) == False:\n    os.mkdir(d_dir)\nif os.path.isdir(c_dir) == False:\n    os.mkdir(c_dir)","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:31.947253Z","iopub.execute_input":"2024-07-26T08:59:31.947607Z","iopub.status.idle":"2024-07-26T08:59:32.940501Z","shell.execute_reply.started":"2024-07-26T08:59:31.947549Z","shell.execute_reply":"2024-07-26T08:59:32.939639Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 犬と猫の画像をそれぞれのフォルダに移動する\nfiles = glob.glob('/kaggle/working/train/*.jpg') # trainfフォルダの全.jpgパスを取得\n\nfor file in files: \n    file_name = os.path.basename(file)\n    if 'cat' in file: \n        shutil.move(file, '/kaggle/working/train/cat/' + file_name)\n    else:\n        shutil.move(file, '/kaggle/working/train/dog/' + file_name)","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:32.941748Z","iopub.execute_input":"2024-07-26T08:59:32.942041Z","iopub.status.idle":"2024-07-26T08:59:34.144246Z","shell.execute_reply.started":"2024-07-26T08:59:32.942017Z","shell.execute_reply":"2024-07-26T08:59:34.143396Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## trainフォルダの犬と猫の画像を2500枚ずつ検証用フォルダに移動","metadata":{}},{"cell_type":"code","source":"# 検証用フォルダの作成\nvalid = '/kaggle/working/valid/'\nd_valid = '/kaggle/working/valid/dog/'\nc_valid = '/kaggle/working/valid/cat/'\n\nif os.path.isdir(valid) == False:\n    os.mkdir(valid)\nif os.path.isdir(d_valid) == False:\n    os.mkdir(d_valid)\nif os.path.isdir(c_valid) == False:\n    os.mkdir(c_valid)","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:34.145429Z","iopub.execute_input":"2024-07-26T08:59:34.146035Z","iopub.status.idle":"2024-07-26T08:59:34.151795Z","shell.execute_reply.started":"2024-07-26T08:59:34.145988Z","shell.execute_reply":"2024-07-26T08:59:34.150726Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n# /train/dog/フォルダ内から，検証用フォルダに移動する2500枚を選ぶ\nd_files = glob.glob('/kaggle/working/train/dog/*.jpg')\nprint(len(d_files))\nd_train, d_valid = train_test_split(d_files, test_size = 0.2, random_state = 100)\nprint(len(d_valid))\ncount = 0\n# 選んだ2500枚を検証用フォルダに移動する\nfor file in d_valid:\n    count += 1 \n    d_name = os.path.basename(file)\n    name = d_name.split('/')[0]\n    shutil.move(file, '/kaggle/working/valid/dog/' + str(name))\n\nprint(count)","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:34.155852Z","iopub.execute_input":"2024-07-26T08:59:34.156154Z","iopub.status.idle":"2024-07-26T08:59:34.918380Z","shell.execute_reply.started":"2024-07-26T08:59:34.156119Z","shell.execute_reply":"2024-07-26T08:59:34.917432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# /train/cat/フォルダ内から，検証用フォルダに移動する2500枚を選ぶ\nc_files = glob.glob('/kaggle/working/train/cat/*.jpg')\nprint(len(c_files))\nc_train, c_valid = train_test_split(c_files, test_size = 0.2, random_state = 100)\nprint(len(c_valid))\ncount = 0\n# 選んだ2500枚を検証用フォルダに移動する\nfor file in c_valid:\n    count += 1 \n    c_name = os.path.basename(file)\n    name = c_name.split('/')[0]\n    shutil.move(file, '/kaggle/working/valid/cat/' + str(name))\n\nprint(count)","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:34.919802Z","iopub.execute_input":"2024-07-26T08:59:34.920126Z","iopub.status.idle":"2024-07-26T08:59:35.095595Z","shell.execute_reply.started":"2024-07-26T08:59:34.920101Z","shell.execute_reply":"2024-07-26T08:59:35.094670Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 学習モデルを構築する","metadata":{}},{"cell_type":"code","source":"# パッケージをインポートする\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nimport torch.nn as nn\nimport time","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:35.096796Z","iopub.execute_input":"2024-07-26T08:59:35.097097Z","iopub.status.idle":"2024-07-26T08:59:36.189906Z","shell.execute_reply.started":"2024-07-26T08:59:35.097071Z","shell.execute_reply":"2024-07-26T08:59:36.189106Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#畳み込みニューラルネットワーク（CNN）モデル\nclass Model(nn.Module):\n    def __init__(self, kernel_size=3, dropout_rate=0.5):\n        super(Model, self).__init__()\n        \n        self.kernel_size = kernel_size\n        self.padding = (kernel_size - 1) // 2\n        self.dropout_rate = dropout_rate\n        \n        self.layer1 = nn.Sequential(\n            nn.Conv2d(in_channels = 3, out_channels = 32, kernel_size = self.kernel_size, padding = self.padding),\n            nn.BatchNorm2d(32),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size = 2),\n            nn.Dropout(p = self.dropout_rate)\n        )\n        self.layer2 = nn.Sequential(\n            nn.Conv2d(in_channels = 32, out_channels = 64, kernel_size = self.kernel_size, padding = self.padding),\n            nn.BatchNorm2d(64),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size = 2),\n            nn.Dropout(p = self.dropout_rate)\n        )\n        self.layer3 = nn.Sequential(\n            nn.Conv2d(in_channels = 64, out_channels = 128, kernel_size = self.kernel_size, padding = self.padding),\n            nn.BatchNorm2d(128),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size = 2),\n            nn.Dropout(p = self.dropout_rate)\n        )\n        self.layer4 = nn.Sequential(\n            nn.Conv2d(in_channels = 128, out_channels = 256, kernel_size = self.kernel_size, padding = self.padding),\n            nn.BatchNorm2d(256),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size = 2),\n            nn.Dropout(p = self.dropout_rate)\n        )\n        self.layer5 = nn.Sequential(\n            nn.Conv2d(in_channels = 256, out_channels = 512, kernel_size = self.kernel_size, padding = self.padding),\n            nn.BatchNorm2d(512),\n            nn.ReLU(),\n            nn.AvgPool2d(kernel_size = 16),\n            nn.Dropout(p = self.dropout_rate),\n            nn.Flatten(),\n            nn.Linear(512,1),\n            nn.Sigmoid()\n        )\n    def forward(self,x):\n        x = self.layer1(x)\n        x = self.layer2(x)\n        x = self.layer3(x)\n        x = self.layer4(x)\n        x = self.layer5(x)\n\n        return x\n        ","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:36.191001Z","iopub.execute_input":"2024-07-26T08:59:36.191412Z","iopub.status.idle":"2024-07-26T08:59:36.204724Z","shell.execute_reply.started":"2024-07-26T08:59:36.191386Z","shell.execute_reply":"2024-07-26T08:59:36.203851Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#オプティマイザはAdam（適応モーメント推定）を使用\ncnn = Model()\nopt = torch.optim.Adam(cnn.parameters(), lr=0.001)\nloss_fn = nn.BCELoss()","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:36.205735Z","iopub.execute_input":"2024-07-26T08:59:36.205971Z","iopub.status.idle":"2024-07-26T08:59:36.240080Z","shell.execute_reply.started":"2024-07-26T08:59:36.205951Z","shell.execute_reply":"2024-07-26T08:59:36.239247Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 訓練データの前処理","metadata":{}},{"cell_type":"code","source":"#データセットの定義\nclass Dataset(Dataset):\n    def __init__(self, file_list, transform=None):\n        self.file_list = file_list\n        self.transform = transform\n        \n    def __len__(self):\n        return len(self.file_list)\n    \n      #ファイル名に基づいてラベルを設定します（ファイル名に「cat」が含まれていれば0、それ以外は1）\n    def __getitem__(self, index):\n        image_path = self.file_list[index]\n        image = Image.open(image_path)\n        if self.transform is not None:\n            image = self.transform(image)\n        if 'cat' in image_path:\n            label = 0\n        else:\n            label = 1\n            \n        return image, label","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:36.241134Z","iopub.execute_input":"2024-07-26T08:59:36.241452Z","iopub.status.idle":"2024-07-26T08:59:36.247892Z","shell.execute_reply.started":"2024-07-26T08:59:36.241429Z","shell.execute_reply":"2024-07-26T08:59:36.246980Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#訓練データと検証データの取得\ndog_train = glob.glob('/kaggle/working/train/dog/*.jpg')\ncat_train = glob.glob('/kaggle/working/train/cat/*.jpg')\ndog_valid = glob.glob('/kaggle/working/valid/dog/*.jpg')\ncat_valid = glob.glob('/kaggle/working/valid/cat/*.jpg')\n\n#訓練データと検証データの前処理\ntrain_data = Dataset(dog_train+cat_train, transform=transforms.Compose([transforms.Resize([256, 256]), transforms.ToTensor()]))\nvalid_data = Dataset(dog_valid+cat_valid, transform=transforms.Compose([transforms.Resize([256, 256]), transforms.ToTensor()]))\n\n#訓練データと検証データの読み込み\ntrain_dl = DataLoader(train_data, batch_size=64, shuffle=True, num_workers=1, pin_memory=True)\nvalid_dl = DataLoader(valid_data, batch_size=64, shuffle=False, num_workers=1, pin_memory=True)","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:36.248948Z","iopub.execute_input":"2024-07-26T08:59:36.249212Z","iopub.status.idle":"2024-07-26T08:59:36.351462Z","shell.execute_reply.started":"2024-07-26T08:59:36.249189Z","shell.execute_reply":"2024-07-26T08:59:36.350604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 深層学習モデルの学習","metadata":{}},{"cell_type":"code","source":"def train(model, epochs, train_dl, valid_dl):\n    model.to(device)\n    loss_hist_train = np.zeros(epochs)\n    accuracy_hist_train = [0] * epochs\n    loss_hist_valid = np.zeros(epochs)\n    accuracy_hist_valid = [0] * epochs\n    start_time = time.time() \n    \n    for epoch in range(epochs):\n        \n        #Train\n        model.train()\n        train_loss = 0.0\n        train_correct = 0\n        train_total = 0\n        \n        for batch_idx, (x_batch, y_batch) in enumerate(train_dl):\n            x_batch = x_batch.to(device)\n            y_batch = y_batch.to(device)\n            pred = model(x_batch)[:, 0]\n            loss = loss_fn(pred, y_batch.float())\n            opt.zero_grad()\n            loss.backward()\n            opt.step()\n            train_loss += loss.item() * y_batch.size(0)\n            train_correct += ((pred >= 0.5).float() == y_batch).sum()\n            train_total += y_batch.size(0)\n        \n        loss_hist_train[epoch] = train_loss / train_total\n        accuracy_hist_train[epoch] = train_correct / train_total\n        \n        #Valid\n        model.eval()\n        valid_loss = 0.0\n        valid_correct = 0\n        valid_total = 0\n        \n        with torch.no_grad():\n            for x_batch, y_batch in valid_dl:\n                x_batch = x_batch.to(device)\n                y_batch = y_batch.to(device)\n                pred = model(x_batch)[:, 0]\n                loss = loss_fn(pred, y_batch.float())\n                valid_loss += loss.item() * y_batch.size(0)\n                valid_correct += ((pred >= 0.5).float() == y_batch).sum()\n                valid_total += y_batch.size(0)\n        \n        loss_hist_valid[epoch] = valid_loss / valid_total\n        accuracy_hist_valid[epoch] = valid_correct / valid_total\n        \n        #結果の表示\n        print(f'Epoch {epoch+1} train_accuracy: {accuracy_hist_train[epoch]:.4f} val_accuracy: {accuracy_hist_valid[epoch]:.4f}')\n        print('Time elapsed: %.2f min' % ((time.time() - start_time) / 60))\n    \n    print('Total Training Time: %.2f min' % ((time.time() - start_time) / 60))\n    \n    return loss_hist_train, loss_hist_valid, accuracy_hist_train, accuracy_hist_valid","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:36.352890Z","iopub.execute_input":"2024-07-26T08:59:36.353216Z","iopub.status.idle":"2024-07-26T08:59:36.371688Z","shell.execute_reply.started":"2024-07-26T08:59:36.353187Z","shell.execute_reply":"2024-07-26T08:59:36.370489Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from PIL import Image\n\n#学習と学習済みモデルの保存\nepochs = 100\nhistory = train(cnn, epochs, train_dl, valid_dl)\ntorch.save(cnn, 'model_weight.pth')","metadata":{"execution":{"iopub.status.busy":"2024-07-26T08:59:36.373187Z","iopub.execute_input":"2024-07-26T08:59:36.373519Z","iopub.status.idle":"2024-07-26T09:00:39.370206Z","shell.execute_reply.started":"2024-07-26T08:59:36.373485Z","shell.execute_reply":"2024-07-26T09:00:39.368842Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 深層学習モデルの学習結果\n訓練データとテストデータのロスを表示","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n#訓練データとテストデータのロスをグラフ表示\ndpi = 100\nfig, ax = plt.subplots(nrows=2, ncols=1, figsize=(5.4, 7.2), dpi=dpi)\nax[0].plot(history[0], lw=2, label='train-loss')\nax[0].plot(history[1], lw=2, label='valid-loss')\nax[0].legend(fontsize=12)\nax[0].set_xlabel('Epochs', fontsize=12)\n\n#訓練データとテストデータのaccuracy(正解率)をグラフ表示\nax[1].plot([i.cpu() for i in history[2]], lw=2, label='train-acc.')\nax[1].plot([i.cpu() for i in history[3]], lw=2, label='valid-acc.')\nax[1].legend(fontsize=12)\nax[1].set_xlabel('Epochs', fontsize=12)\n\nplt.savefig('history.png', dpi=dpi)","metadata":{"execution":{"iopub.status.busy":"2024-07-26T09:00:39.371492Z","iopub.status.idle":"2024-07-26T09:00:39.371905Z","shell.execute_reply.started":"2024-07-26T09:00:39.371716Z","shell.execute_reply":"2024-07-26T09:00:39.371732Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## テストデータの前処理","metadata":{}},{"cell_type":"code","source":"#テストデータの取得\ntest_id = []\nt_files = glob.glob('/kaggle/working/test/*.jpg')\nfor no in range(len(t_files)):\n    t_id = int(t_files[no].split('/')[-1].split('.')[0])\n    test_id.append(t_id)\n\n#テストデータの前処理と読み込み\ntest_data = Dataset(t_files, transform=transforms.Compose([transforms.Resize([256, 256]), transforms.ToTensor()]))\ntest_dl = DataLoader(test_data, batch_size=64, shuffle=False, num_workers=1, pin_memory=True)","metadata":{"execution":{"iopub.status.busy":"2024-07-26T09:00:39.373667Z","iopub.status.idle":"2024-07-26T09:00:39.374062Z","shell.execute_reply.started":"2024-07-26T09:00:39.373883Z","shell.execute_reply":"2024-07-26T09:00:39.373899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 推論\n学習した深層学習モデルを使用して、テストデータを推論する","metadata":{}},{"cell_type":"code","source":"import csv\n\n# VGG16モデルの読み込み\nVGG16 = torch.load('model_weight.pth')\n\nVGG16.eval()\n\n# 推論結果を保存するリストを初期化\npredictions = []\n\n#推論を行う\nwith torch.no_grad():\n    for x_batch, _ in test_dl:\n        x_batch = x_batch.to(device)\n        pred = VGG16(x_batch)[:, 0]\n        predictions.extend(pred.tolist())\n\n# 予測結果をCSVファイルに保存\nsubmission_file = 'submission.csv'\nwith open(submission_file, 'w', newline='') as file:\n    writer = csv.writer(file)\n    writer.writerow(['id', 'label'])\n    for i, pred in enumerate(predictions):\n        write_id = test_id[i]\n        writer.writerow([write_id, pred])","metadata":{"execution":{"iopub.status.busy":"2024-07-26T09:00:39.376075Z","iopub.status.idle":"2024-07-26T09:00:39.376438Z","shell.execute_reply.started":"2024-07-26T09:00:39.376260Z","shell.execute_reply":"2024-07-26T09:00:39.376275Z"},"trusted":true},"execution_count":null,"outputs":[]}]}