{"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":"# 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":{"execution":{"iopub.status.busy":"2022-07-29T07:43:14.032934Z","iopub.execute_input":"2022-07-29T07:43:14.033855Z","iopub.status.idle":"2022-07-29T07:43:14.066095Z","shell.execute_reply.started":"2022-07-29T07:43:14.033723Z","shell.execute_reply":"2022-07-29T07:43:14.064843Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ライブラリの読み込み\nimport random\nimport glob\nfrom PIL import Image\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.utils.data as data\nimport torchvision\nfrom tqdm import tqdm\nfrom torchvision import models, transforms\n\nfrom sklearn.model_selection import train_test_split\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:14.068230Z","iopub.execute_input":"2022-07-29T07:43:14.068657Z","iopub.status.idle":"2022-07-29T07:43:17.543032Z","shell.execute_reply.started":"2022-07-29T07:43:14.068614Z","shell.execute_reply":"2022-07-29T07:43:17.541867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 乱数のシードを設定する\nseed = 10\ntorch.manual_seed(seed)\nnp.random.seed(seed)\nrandom.seed(seed)","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:17.549970Z","iopub.execute_input":"2022-07-29T07:43:17.553535Z","iopub.status.idle":"2022-07-29T07:43:17.574699Z","shell.execute_reply.started":"2022-07-29T07:43:17.553478Z","shell.execute_reply":"2022-07-29T07:43:17.573179Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import zipfile\n\nzip_files = ['test', 'train']\n\ncrrnt_dir_files_list = glob.glob('*')\nprint(crrnt_dir_files_list)\n\n# zipファイルが解凍されていない時だけ解凍\nif zip_files[0] in crrnt_dir_files_list and zip_files[1] in crrnt_dir_files_list:\n    print('zip files already unziped !!')\nelse:\n    print('start unzip')\n    \n    for zip_file in zip_files:\n        with zipfile.ZipFile(\"../input/dogs-vs-cats-redux-kernels-edition/{}.zip\".format(zip_file),\"r\") as z:\n            z.extractall(\".\")\n            print(\"{} unzipped\".format(zip_file))\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:17.587905Z","iopub.execute_input":"2022-07-29T07:43:17.592015Z","iopub.status.idle":"2022-07-29T07:43:35.588854Z","shell.execute_reply.started":"2022-07-29T07:43:17.591954Z","shell.execute_reply":"2022-07-29T07:43:35.587765Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(os.listdir('../working'))","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:35.590846Z","iopub.execute_input":"2022-07-29T07:43:35.591784Z","iopub.status.idle":"2022-07-29T07:43:35.597821Z","shell.execute_reply.started":"2022-07-29T07:43:35.591743Z","shell.execute_reply":"2022-07-29T07:43:35.596778Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class ImageTransform():\n    def __init__(self, resize, mean, std):\n        self.data_transform = {\n            'train': transforms.Compose([\n                transforms.Resize((resize, resize)),\n                transforms.RandomHorizontalFlip(p=0.5),\n                transforms.RandomCrop(size =(150, 150), padding=18),\n                transforms.ToTensor(),\n                transforms.Normalize(mean,std)\n            ]),\n            'val': transforms.Compose([\n                transforms.Resize((resize,resize)),\n                transforms.ToTensor(),\n                transforms.transforms.Normalize(mean, std)\n            ]),\n            'test' : transforms.Compose([\n                transforms.Resize((resize,resize)),\n                transforms.ToTensor(),\n                transforms.transforms.Normalize(mean, std)\n            ])\n        }\n\n    def __call__(self, img, phase):\n        return self.data_transform[phase](img)\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:35.599653Z","iopub.execute_input":"2022-07-29T07:43:35.601184Z","iopub.status.idle":"2022-07-29T07:43:35.611142Z","shell.execute_reply.started":"2022-07-29T07:43:35.599898Z","shell.execute_reply":"2022-07-29T07:43:35.609962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DogCatDataset(data.Dataset):\n    def __init__(self, file_list, phase, transform = None):\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, index):\n        img_path = self.file_list[index]\n        img = Image.open(img_path)\n\n        img_trans = self.transform(\n            img, self.phase)\n\n        label = img_path.split('/')[-1].split('.')[0]\n\n        if label == 'cat':\n            label = 0\n        elif label == 'dog':\n            label = 1\n\n        return img_trans, label\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:35.612705Z","iopub.execute_input":"2022-07-29T07:43:35.613353Z","iopub.status.idle":"2022-07-29T07:43:35.625803Z","shell.execute_reply.started":"2022-07-29T07:43:35.613310Z","shell.execute_reply":"2022-07-29T07:43:35.624372Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# データを読み込み","metadata":{}},{"cell_type":"code","source":"import glob \ntrain_list = glob.glob('../working/train/*')\ntest_path_list = glob.glob('../working/test/*')","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:35.627502Z","iopub.execute_input":"2022-07-29T07:43:35.628362Z","iopub.status.idle":"2022-07-29T07:43:35.752588Z","shell.execute_reply.started":"2022-07-29T07:43:35.628315Z","shell.execute_reply":"2022-07-29T07:43:35.751603Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_idx, valid_idx = train_test_split(range(len(train_list)), test_size = 0.25, random_state = 46)\n\ntrain_path_list = []\nval_path_list = []\nfor index in train_idx:\n    i = train_list[index]\n    train_path_list.append(i)\n\nfor index in valid_idx:\n    i = train_list[index]\n    val_path_list.append(i)\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:35.754135Z","iopub.execute_input":"2022-07-29T07:43:35.754517Z","iopub.status.idle":"2022-07-29T07:43:35.779075Z","shell.execute_reply.started":"2022-07-29T07:43:35.754480Z","shell.execute_reply":"2022-07-29T07:43:35.778174Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 枚数の確認\nlen(train_path_list), len(val_path_list), len(test_path_list)\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:35.783988Z","iopub.execute_input":"2022-07-29T07:43:35.784320Z","iopub.status.idle":"2022-07-29T07:43:35.792097Z","shell.execute_reply.started":"2022-07-29T07:43:35.784292Z","shell.execute_reply":"2022-07-29T07:43:35.791107Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# データセットの作成","metadata":{}},{"cell_type":"code","source":"size = 150\nmean = (0.5,0.5,0.5)\nstd = (0.5,0.5,0.5)\n\ntrain_dataset = DogCatDataset(\n    file_list = train_path_list, transform = ImageTransform(size, mean, std), phase = 'train')\n\nval_dataset = DogCatDataset(\n    file_list = val_path_list, transform = ImageTransform(size, mean, std), phase = 'val')\n\ntest_dataset = DogCatDataset(\n    file_list = test_path_list, transform = ImageTransform(size, mean, std), phase = 'test')\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:35.793627Z","iopub.execute_input":"2022-07-29T07:43:35.794300Z","iopub.status.idle":"2022-07-29T07:43:35.807147Z","shell.execute_reply.started":"2022-07-29T07:43:35.794258Z","shell.execute_reply":"2022-07-29T07:43:35.806036Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# データローダーの作成","metadata":{}},{"cell_type":"code","source":"batch_size = 8\ntrain_dataloader = data.DataLoader(\n    train_dataset, batch_size=batch_size, shuffle = True)\n\nval_dataloader = data.DataLoader(\n    val_dataset, batch_size=batch_size, shuffle = False)\n\ntest_dataloader = data.DataLoader(\n    test_dataset, batch_size=batch_size, shuffle = False)\n\ndataloaders_dict = {'train': train_dataloader,\n                    'val': val_dataloader,\n                    'test': test_dataloader}\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:35.809851Z","iopub.execute_input":"2022-07-29T07:43:35.810223Z","iopub.status.idle":"2022-07-29T07:43:35.818882Z","shell.execute_reply.started":"2022-07-29T07:43:35.810184Z","shell.execute_reply":"2022-07-29T07:43:35.817672Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# efficientnetのダウンロード","metadata":{}},{"cell_type":"code","source":"!pip install efficientnet_pytorch","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:35.821054Z","iopub.execute_input":"2022-07-29T07:43:35.821701Z","iopub.status.idle":"2022-07-29T07:43:50.450668Z","shell.execute_reply.started":"2022-07-29T07:43:35.821656Z","shell.execute_reply":"2022-07-29T07:43:50.449461Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from efficientnet_pytorch import EfficientNet\n\nmodel = EfficientNet.from_pretrained('efficientnet-b7')\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:50.453786Z","iopub.execute_input":"2022-07-29T07:43:50.454295Z","iopub.status.idle":"2022-07-29T07:43:53.598812Z","shell.execute_reply.started":"2022-07-29T07:43:50.454242Z","shell.execute_reply":"2022-07-29T07:43:53.597630Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_ftrs = model._fc.in_features\nmodel._fc = nn.Linear(num_ftrs, 2)\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:53.600465Z","iopub.execute_input":"2022-07-29T07:43:53.602385Z","iopub.status.idle":"2022-07-29T07:43:53.609610Z","shell.execute_reply.started":"2022-07-29T07:43:53.602327Z","shell.execute_reply":"2022-07-29T07:43:53.608358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 学習の関数を設定","metadata":{}},{"cell_type":"code","source":"EPOCHS = 2\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:53.610966Z","iopub.execute_input":"2022-07-29T07:43:53.611640Z","iopub.status.idle":"2022-07-29T07:43:53.620481Z","shell.execute_reply.started":"2022-07-29T07:43:53.611591Z","shell.execute_reply":"2022-07-29T07:43:53.618842Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loss_fn = nn.CrossEntropyLoss()\n\noptimizer = optim.SGD(model.parameters(), lr = 0.1, momentum=0.9)\n\nscheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=EPOCHS)","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:53.622263Z","iopub.execute_input":"2022-07-29T07:43:53.623147Z","iopub.status.idle":"2022-07-29T07:43:53.636127Z","shell.execute_reply.started":"2022-07-29T07:43:53.623096Z","shell.execute_reply":"2022-07-29T07:43:53.634951Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_model(model, dataloaders_dict, loss_fn, optimizer, epochs, scheduler):\n    history = {'loss':[], 'acc':[], 'val_loss':[], 'val_acc':[]}\n    device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n    model = model.to(device)\n    for epoch in range(epochs):\n        print(f'{epoch + 1} start')\n        print('----------')\n\n        for phase in ['train', 'val']:\n            if phase == 'train':\n                model.train()\n            else:\n                model.eval()\n\n            epoch_loss = 0.0\n            epoch_corrects = 0.0\n\n            if (epoch == 0) and (phase == 'train'):\n                continue\n\n            for inputs, labels in tqdm(dataloaders_dict[phase]):\n                inputs = inputs.to(device)\n                labels = labels.to(device)\n\n                optimizer.zero_grad()\n\n                with torch.set_grad_enabled(phase == 'train'):\n                    outputs = model(inputs)\n                    loss = loss_fn(outputs, labels)\n                    pred_value, pred_label = torch.max(outputs, 1)\n\n                    if phase == 'train':\n                        loss.backward()\n                        optimizer.step()\n\n                    epoch_loss += loss.item() * inputs.size(0)\n                    epoch_corrects += torch.sum(pred_label == labels.data)\n\n            if phase == 'train':\n                scheduler.step()\n\n            epoch_loss /= len(dataloaders_dict[phase].dataset)*1.0\n            epoch_acc = epoch_corrects.double() / len(dataloaders_dict[phase].dataset)*1.0\n\n            print(f'{phase} Loss: {epoch_loss :.4f} Acc : {epoch_acc :.4f}')\n            if phase == 'train':\n                history['loss'].append(epoch_loss)\n                history['acc'].append(epoch_acc)\n            else:\n                history['val_loss'].append(epoch_loss)\n                history['val_acc'].append(epoch_acc)\n\n    # 学習結果を返す\n    return history","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:53.638034Z","iopub.execute_input":"2022-07-29T07:43:53.638763Z","iopub.status.idle":"2022-07-29T07:43:53.655034Z","shell.execute_reply.started":"2022-07-29T07:43:53.638713Z","shell.execute_reply":"2022-07-29T07:43:53.653833Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# gpuメモリのクリア\ntorch.cuda.empty_cache()\n\n# メモリの状態を表示 \ntorch.cuda.memory_summary(device=None, abbreviated=False)\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:53.657010Z","iopub.execute_input":"2022-07-29T07:43:53.657994Z","iopub.status.idle":"2022-07-29T07:43:53.734426Z","shell.execute_reply.started":"2022-07-29T07:43:53.657924Z","shell.execute_reply":"2022-07-29T07:43:53.733080Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 学習の実施","metadata":{}},{"cell_type":"code","source":"# モデルファイルの探索\nmodel_file_list = glob.glob('./*.pth')\n\n# 既存のモデルが存在するなら流用し，なければ学習する\nif(model_file_list):\n    print('find model file !!')\n    print(model_file_list)\n\n    # モデルの読み込み\n    model.load_state_dict(torch.load(model_file_list[0]))\n    device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n    model = model.to(device)\n    print('model loaded !!')\nelse:\n    print('not find model file...')\n    print('start learning')\n    \n    # 学習開始\n    train_history = train_model(model, dataloaders_dict, loss_fn, optimizer, EPOCHS, scheduler).copy()\n    \n    # モデルの保存\n    torch.save(model.state_dict(), 'model.pth')\n    print('model saved !!')\n\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:43:53.736691Z","iopub.execute_input":"2022-07-29T07:43:53.737590Z","iopub.status.idle":"2022-07-29T07:55:09.773601Z","shell.execute_reply.started":"2022-07-29T07:43:53.737541Z","shell.execute_reply":"2022-07-29T07:55:09.772448Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 学習結果をグラフに表示","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# グラフに表示する関数\ndef plot_graph(values1, values2, rng, label1, label2, save_name):\n    plt.plot(range(rng), values1, label=label1)\n    plt.plot(range(rng), values2, label=label2)\n    plt.legend()\n    plt.grid()\n    plt.show()\n    plt.savefig(save_name)","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:55:09.775260Z","iopub.execute_input":"2022-07-29T07:55:09.775959Z","iopub.status.idle":"2022-07-29T07:55:09.783300Z","shell.execute_reply.started":"2022-07-29T07:55:09.775910Z","shell.execute_reply":"2022-07-29T07:55:09.782020Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 学習結果の各値を確認\nprint(train_history)","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:55:09.784850Z","iopub.execute_input":"2022-07-29T07:55:09.785651Z","iopub.status.idle":"2022-07-29T07:55:09.811794Z","shell.execute_reply.started":"2022-07-29T07:55:09.785601Z","shell.execute_reply":"2022-07-29T07:55:09.810627Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# テンソルからリストを変換する関数\ndef TensorToList(target_history):\n    tmp_list = []\n    \n    for each_val in target_history:\n        # 勾配情報を無視してtensor -> numpy配列へ\n        acc_tmp_b = each_val.to(torch.device('cpu')) \n        acc_tmp_b = acc_tmp_b.detach().clone().numpy()\n        #print(type(acc_tmp_b))\n        #print(acc_tmp_b.shape)\n    \n        # numpy配列の1次元化\n        acc_tmp_b = np.atleast_1d(acc_tmp_b)\n        #print(type(acc_tmp_b))\n        #print(acc_tmp_b.shape)\n        #print(acc_tmp_b[0])\n        tmp_list.append(acc_tmp_b[0])\n    \n    return tmp_list","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:55:09.813889Z","iopub.execute_input":"2022-07-29T07:55:09.814319Z","iopub.status.idle":"2022-07-29T07:55:09.822496Z","shell.execute_reply.started":"2022-07-29T07:55:09.814277Z","shell.execute_reply":"2022-07-29T07:55:09.820917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 学習結果をグラフで表示\nif train_history:\n    # 学習結果の各値\n    t_losses = train_history['loss'].copy()\n    t_losses.insert(0, t_losses[0])\n    print(t_losses)\n    t_accus = TensorToList(train_history['acc']).copy()\n    t_accus.insert(0, t_accus[0])\n    print(t_accus)\n    \n    v_losses = train_history['val_loss'].copy()\n    print(v_losses)\n    v_accus = TensorToList(train_history['val_acc']).copy()\n    print(v_accus)\n\n    # 平均損失\n    plot_graph(t_losses, v_losses, EPOCHS, 'loss(train)', 'loss(validate)', 'loss_fig')\n    # 平均正解率\n    plot_graph(t_accus, v_accus, EPOCHS, 'accuracy(train)', 'accuracy(validate)', 'acc_fig')","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:55:09.824244Z","iopub.execute_input":"2022-07-29T07:55:09.825579Z","iopub.status.idle":"2022-07-29T07:55:10.247578Z","shell.execute_reply.started":"2022-07-29T07:55:09.825517Z","shell.execute_reply":"2022-07-29T07:55:10.246582Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# テストデータで推論","metadata":{}},{"cell_type":"code","source":"labels = []\nids = []\ncat_preds = []\ndog_preds = []\nwith torch.no_grad():\n    device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n\n    for image_path in tqdm(test_path_list):\n        img = Image.open(image_path)\n        test_transformer = ImageTransform(size, mean, std)\n        img = test_transformer(img, phase = 'test')\n        img = img.unsqueeze(0)\n        img = img.to(device)\n        model.eval()\n        output = model(img)\n        pred = nn.functional.softmax(output, dim = 1)[:].tolist()\n        cat_preds.append(pred[0][0])\n        dog_preds.append(pred[0][1])\n        ids.append(int(image_path.split('/')[-1].split('.')[0]))\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T07:55:10.249193Z","iopub.execute_input":"2022-07-29T07:55:10.249572Z","iopub.status.idle":"2022-07-29T08:04:34.385481Z","shell.execute_reply.started":"2022-07-29T07:55:10.249530Z","shell.execute_reply":"2022-07-29T08:04:34.384382Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 推論結果をcsvに出力","metadata":{}},{"cell_type":"code","source":"import pandas as pd\n\nsubmit = pd.DataFrame({'id': ids,\n                       'label': dog_preds})\n\n\nsubmit.sort_values(by='id', inplace=True)\n\nsubmit.reset_index(drop=True, inplace=True)\n\nsubmit.to_csv('./submission.csv', index=False)\n","metadata":{"execution":{"iopub.status.busy":"2022-07-29T08:04:34.387076Z","iopub.execute_input":"2022-07-29T08:04:34.387750Z","iopub.status.idle":"2022-07-29T08:04:34.451955Z","shell.execute_reply.started":"2022-07-29T08:04:34.387708Z","shell.execute_reply":"2022-07-29T08:04:34.450697Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}