{"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":"markdown","source":"# State farm distracted driver detection","metadata":{}},{"cell_type":"code","source":"# 使用するモジュールのインポート\nimport os.path as osp\nfrom glob import glob\nimport random\nimport time\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport plotly.express as px\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.metrics import accuracy_score\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.utils.data as data\nimport torch.optim as optim\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-12-02T09:16:25.911400Z","iopub.execute_input":"2021-12-02T09:16:25.912249Z","iopub.status.idle":"2021-12-02T09:16:25.919052Z","shell.execute_reply.started":"2021-12-02T09:16:25.912206Z","shell.execute_reply":"2021-12-02T09:16:25.918232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def fix_seed(seed):\n    # random\n    random.seed(seed)\n    # Numpy\n    np.random.seed(seed)\n    # Pytorch\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed_all(seed)\n    torch.backends.cudnn.deterministic = True","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:26.950612Z","iopub.execute_input":"2021-12-02T09:16:26.951113Z","iopub.status.idle":"2021-12-02T09:16:26.955408Z","shell.execute_reply.started":"2021-12-02T09:16:26.951073Z","shell.execute_reply":"2021-12-02T09:16:26.954728Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Seed値の固定\nSEED = 42\nfix_seed(SEED)\n\n# 各クラスの説明の定義\nactivity_map = {\n    'c0': 'Safe driving', \n    'c1': 'Texting - right', \n    'c2': 'Talking on the phone - right', \n    'c3': 'Texting - left', \n    'c4': 'Talking on the phone - left', \n    'c5': 'Operating the radio', \n    'c6': 'Drinking', \n    'c7': 'Reaching behind', \n    'c8': 'Hair and makeup', \n    'c9': 'Talking to passenger'\n}\n\n# パスの定義\ndata_dir = '../input/state-farm-distracted-driver-detection'\ncsv_file_path = osp.join(data_dir, 'driver_imgs_list.csv')","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:27.310154Z","iopub.execute_input":"2021-12-02T09:16:27.310563Z","iopub.status.idle":"2021-12-02T09:16:27.317672Z","shell.execute_reply.started":"2021-12-02T09:16:27.310529Z","shell.execute_reply":"2021-12-02T09:16:27.316763Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(csv_file_path) # csvファイルの読み込み\ndf.head(5) # 最初の5行を表示","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:27.529986Z","iopub.execute_input":"2021-12-02T09:16:27.530380Z","iopub.status.idle":"2021-12-02T09:16:27.556003Z","shell.execute_reply.started":"2021-12-02T09:16:27.530349Z","shell.execute_reply":"2021-12-02T09:16:27.555243Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# EDA","metadata":{}},{"cell_type":"code","source":"by_drivers = df.groupby('subject') # ドライバーでグループ化\nunique_drivers = by_drivers.groups.keys() # ドライバー名のリスト\n\n# データセットに含まれるドライバーの数\nprint('unique drivers: ',len(unique_drivers)) \n# ドライバー1人当たりの画像の数の平均\nprint('mean of images: ', round(df.groupby('subject').count()['classname'].mean()))","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:27.917497Z","iopub.execute_input":"2021-12-02T09:16:27.917749Z","iopub.status.idle":"2021-12-02T09:16:27.938114Z","shell.execute_reply.started":"2021-12-02T09:16:27.917715Z","shell.execute_reply":"2021-12-02T09:16:27.937399Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_file_num = len(glob(osp.join(data_dir, 'imgs/train/*/*.jpg'))) # 訓練データの数\ntest_file_num = len(glob(osp.join(data_dir, 'imgs/test/*.jpg'))) # テストデータの数\ncategory_num = len(df['classname'].unique()) # カテゴリの数\nprint('train_file_num: ', train_file_num)\nprint('test_file_num: ', test_file_num)\nprint('category_num: ', category_num)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:28.119255Z","iopub.execute_input":"2021-12-02T09:16:28.119585Z","iopub.status.idle":"2021-12-02T09:16:28.475521Z","shell.execute_reply.started":"2021-12-02T09:16:28.119554Z","shell.execute_reply":"2021-12-02T09:16:28.474759Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# クラスごとのデータ数\npx.histogram(df, x=\"classname\", color=\"classname\", title=\"Number of images by categories \")","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:28.477216Z","iopub.execute_input":"2021-12-02T09:16:28.477482Z","iopub.status.idle":"2021-12-02T09:16:28.986785Z","shell.execute_reply.started":"2021-12-02T09:16:28.477448Z","shell.execute_reply":"2021-12-02T09:16:28.986124Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"drivers_id = pd.DataFrame((df['subject'].value_counts()).reset_index())\ndrivers_id.columns = ['driver_id', 'Counts']\npx.histogram(drivers_id, x=\"driver_id\",y=\"Counts\" ,color=\"driver_id\", title=\"Number of images by subjects \")","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:28.988537Z","iopub.execute_input":"2021-12-02T09:16:28.989096Z","iopub.status.idle":"2021-12-02T09:16:29.150815Z","shell.execute_reply.started":"2021-12-02T09:16:28.989058Z","shell.execute_reply":"2021-12-02T09:16:29.150093Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ドライバーごとの画像の数のヒストグラム\n# 自分で実装\npx.histogram(df, x='subject', color='subject', title='Number of images by subjects')","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:29.151930Z","iopub.execute_input":"2021-12-02T09:16:29.152631Z","iopub.status.idle":"2021-12-02T09:16:29.448322Z","shell.execute_reply.started":"2021-12-02T09:16:29.152579Z","shell.execute_reply":"2021-12-02T09:16:29.447529Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 各クラスのデータを描画\n# 自分で実装\nplt.figure(figsize=(12, 20))\nfor i, (key, value) in enumerate(activity_map.items()):\n    image_dir = osp.join(data_dir, 'imgs/train', key, '*.jpg')\n    image_path = glob(image_dir)[0]\n    image = cv2.imread(image_path)[:, :, (2, 1, 0)]\n    plt.subplot(5, 2, i+1)\n    plt.imshow(image)\n    plt.title(value)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:29.450362Z","iopub.execute_input":"2021-12-02T09:16:29.450614Z","iopub.status.idle":"2021-12-02T09:16:31.533755Z","shell.execute_reply.started":"2021-12-02T09:16:29.450581Z","shell.execute_reply":"2021-12-02T09:16:31.533104Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 前処理","metadata":{}},{"cell_type":"code","source":"# ファイルパスの列を追加\n# 自分で実装\ndf['file_path'] = df.apply(lambda x: osp.join(data_dir, 'imgs/train', x.classname, x.img), axis=1)\n\n# 正解ラベルを数値に変換して列を追加\n# 自分で実装\ndf['class_num'] = df['classname'].map(lambda x: int(x[1]))\ndf.head(5)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:31.534782Z","iopub.execute_input":"2021-12-02T09:16:31.535121Z","iopub.status.idle":"2021-12-02T09:16:32.393190Z","shell.execute_reply.started":"2021-12-02T09:16:31.535090Z","shell.execute_reply":"2021-12-02T09:16:32.392481Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Datasetの作成","metadata":{}},{"cell_type":"code","source":"class DataTransform():\n    \"\"\"\n    画像とアノテーションの前処理クラス。訓練時と検証時で異なる動作をする。\n    画像のサイズをinput_size x input_sizeにする。\n    訓練時はデータオーギュメンテーションする。\n\n\n    Attributes\n    ----------\n    input_size : int\n        リサイズ先の画像の大きさ。\n    color_mean : (R, G, B)\n        各色チャネルの平均値。\n    color_std : (R, G, B)\n        各色チャネルの標準偏差。\n    \"\"\"\n\n    def __init__(self, input_size, color_mean, color_std):\n        self.data_transform = {\n            # trainだけ自分で実装\n            'train': A.Compose([\n                A.HorizontalFlip(p=0.5),\n                A.Rotate(-10, 10),\n                A.Resize(input_size, input_size),  # リサイズ(input_size)\n                A.Normalize(color_mean, color_std),  # 色情報の標準化\n                ToTensorV2() # テンソル化\n            ]),\n            'val': A.Compose([\n                A.Resize(input_size, input_size),  # リサイズ(input_size)\n                A.Normalize(color_mean, color_std),  # 色情報の標準化\n                ToTensorV2() # テンソル化\n            ])\n        }\n\n    def __call__(self, phase, image):\n        \"\"\"\n        Parameters\n        ----------\n        phase : 'train' or 'val'\n            前処理のモードを指定。\n        \"\"\"\n        transformed = self.data_transform[phase](image=image)\n        return transformed['image']","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:32.395002Z","iopub.execute_input":"2021-12-02T09:16:32.395651Z","iopub.status.idle":"2021-12-02T09:16:32.405178Z","shell.execute_reply.started":"2021-12-02T09:16:32.395613Z","shell.execute_reply":"2021-12-02T09:16:32.404283Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Dataset(data.Dataset):\n    \"\"\"\n    Attributes\n    ----------\n    df : DataFrame\n        class_num, file_pathのカラムがあるデータフレーム\n    phase : 'train' or 'val'\n        学習か訓練かを設定する。\n    transform : object\n        前処理クラスのインスタンス\n    \"\"\"\n    def __init__(self, df, phase, transform):\n        self.df = df\n        self.phase = phase\n        self.transform = transform\n\n    def __len__(self):\n        '''画像の枚数を返す'''\n        return len(self.df)\n\n    def __getitem__(self, index):\n        '''前処理をした画像のTensor形式のデータを取得'''\n        image = self.pull_item(index)\n        return image, self.df.iloc[index]['class_num']\n\n    def pull_item(self, index):\n        '''画像のTensor形式のデータを取得する'''\n        \n        # 自分で実装\n        # 1. 画像読み込み\n        image_path = self.df.iloc[index]['file_path']\n        image = cv2.imread(image_path)[:, :, (2, 1, 0)]\n\n        # 2. 前処理を実施\n        return self.transform(self.phase, image)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:32.406364Z","iopub.execute_input":"2021-12-02T09:16:32.406911Z","iopub.status.idle":"2021-12-02T09:16:32.420677Z","shell.execute_reply.started":"2021-12-02T09:16:32.406866Z","shell.execute_reply":"2021-12-02T09:16:32.419760Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 動作確認\n\n# (RGB)の色の平均値と標準偏差\ncolor_mean = (0.485, 0.456, 0.406)\ncolor_std = (0.229, 0.224, 0.225)\ninput_size = 256\n\n# データ分割\ndf_train, df_val = train_test_split(df, stratify=df['subject'], random_state=SEED)\n\n# 自分で実装\n# データセット作成\ntrain_dataset = Dataset(df_train, phase=\"train\", transform=DataTransform(\n    input_size=input_size, color_mean=color_mean, color_std=color_std))\n\nval_dataset = Dataset(df_val, phase=\"val\", transform=DataTransform(\n    input_size=input_size, color_mean=color_mean, color_std=color_std))\n\n# 自分で実装\n# データの取り出し例\nimage, label = train_dataset[0]\nplt.imshow(image.permute(1, 2, 0))\nplt.title(label)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:32.421998Z","iopub.execute_input":"2021-12-02T09:16:32.422515Z","iopub.status.idle":"2021-12-02T09:16:32.704588Z","shell.execute_reply.started":"2021-12-02T09:16:32.422480Z","shell.execute_reply":"2021-12-02T09:16:32.703916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# DataLoaderの作成","metadata":{}},{"cell_type":"code","source":"# データローダーの作成\nbatch_size = 64\n\n# 自分で実装\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\n# 辞書オブジェクトにまとめる\ndataloaders_dict = {\"train\": train_dataloader, \"val\": val_dataloader}\n\n# 自分で実装\n# 動作の確認\nbatch_iterator = iter(dataloaders_dict[\"val\"])  # イタレータに変換\nimages, labels = next(batch_iterator)  # 1番目の要素を取り出す\nprint(images.size())  # torch.Size([8, 3, 256, 256])\nprint(labels.size())  # torch.Size([8])","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:32.705655Z","iopub.execute_input":"2021-12-02T09:16:32.706024Z","iopub.status.idle":"2021-12-02T09:16:33.263744Z","shell.execute_reply.started":"2021-12-02T09:16:32.705991Z","shell.execute_reply":"2021-12-02T09:16:33.262193Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# モデルの作成","metadata":{}},{"cell_type":"code","source":"!pip install efficientnet_pytorch\nfrom efficientnet_pytorch import EfficientNet\nmodel = EfficientNet.from_pretrained('efficientnet-b0', num_classes=10)\n\n# 自分で実装(練習)\n# class Model(nn.Module):\n#     def __init__(self, num_classes=10):\n#         super(Model, self).__init__()\n#         self.net = nn.Sequential(\n#             nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=2, padding=1),\n#             nn.BatchNorm2d(num_features=64),\n#             nn.ReLU(),\n#             nn.Conv2d(in_channels=64, out_channels=16, kernel_size=3, stride=2, padding=1),\n#             nn.BatchNorm2d(num_features=16),\n#             nn.ReLU(),\n#             nn.Flatten(),\n#             nn.Linear(in_features=65536, out_features=num_classes)\n#         )\n    \n#     def forward(self, x):\n#         output = self.net(x)\n#         return output\n# \n# model = Model(num_classes=10)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:33.265033Z","iopub.execute_input":"2021-12-02T09:16:33.265286Z","iopub.status.idle":"2021-12-02T09:16:40.472340Z","shell.execute_reply.started":"2021-12-02T09:16:33.265251Z","shell.execute_reply":"2021-12-02T09:16:40.471528Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 学習","metadata":{}},{"cell_type":"code","source":"# 自分で実装(練習)\n# train_dataset = Dataset(df_train.iloc[:1000], phase=\"train\", transform=DataTransform(\n#     input_size=input_size, color_mean=color_mean, color_std=color_std))\n\n# val_dataset = Dataset(df_val.iloc[:1000], phase=\"val\", transform=DataTransform(\n#     input_size=input_size, color_mean=color_mean, color_std=color_std))\n\n# train_dataloader = data.DataLoader(\n#     train_dataset, batch_size=batch_size, shuffle=True)\n\n# val_dataloader = data.DataLoader(\n#     val_dataset, batch_size=batch_size, shuffle=False)\n\n# # 辞書オブジェクトにまとめる\n# dataloaders_dict = {\"train\": train_dataloader, \"val\": val_dataloader}\n\n# device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n# optimizer = optim.Adam(model.parameters(), lr=1e-3)\n# criterion = nn.CrossEntropyLoss()\n\n# model = model.to(device)\n# for epoch in range(5):\n#     print(f'epoch: {epoch+1}')\n#     print('-'*50)\n    \n#     # train\n#     model.train()\n#     train_loss = 0\n#     for images, labels in train_dataloader:\n#         images = images.to(device)\n#         labels = labels.to(device)\n        \n#         optimizer.zero_grad()\n#         outputs = model(images)\n#         loss = criterion(outputs, labels)\n        \n#         loss.backward()\n#         optimizer.step()\n        \n#         train_loss += loss.item() / len(images)\n        \n#     print(f'epoch train loss: {train_loss: .4f}')\n\n#     # valid\n#     model.eval()\n#     valid_loss = 0\n#     preds = []\n#     trues = []\n#     for images, labels in val_dataloader:\n#         images = images.to(device)\n#         labels = labels.to(device)\n        \n#         with torch.no_grad():\n#             outputs = model(images)\n#             loss = criterion(outputs, labels)\n#             valid_loss = loss.item() / len(images)\n            \n#             trues += list(labels.cpu().numpy())\n#             preds += list(outputs.argmax(axis=1).cpu().numpy())\n    \n#     accuracy = accuracy_score(trues, preds)\n#     print(f'epoch valid loss: {valid_loss: .4f} accuracy: {accuracy: .4f}\\n')","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:40.475500Z","iopub.execute_input":"2021-12-02T09:16:40.475713Z","iopub.status.idle":"2021-12-02T09:16:40.482477Z","shell.execute_reply.started":"2021-12-02T09:16:40.475676Z","shell.execute_reply":"2021-12-02T09:16:40.481610Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# チェックポイントの保存\ndef save_checkpoint(model, optimizer, scheduler, epoch, path):\n    torch.save(\n        {'epoch': epoch,\n                'model': model.state_dict(),\n                'optimizer': optimizer.state_dict(),\n                'scheduler': scheduler.state_dict(), \n        }, path)\n\n# チェックポイントの読み込み\ndef load_checkpoint(model, optimizer, scheduler, path):\n    checkpoint = torch.load(path)\n    model.load_state_dict(checkpoint['model'])\n    optimizer.load_state_dict(checkpoint['optimizer'])\n    scheduler.load_state_dict(checkpoint['scheduler'])\n\n# モデルを学習させる関数\ndef train_model(model, dataloaders_dict, criterion, scheduler, optimizer, device, num_epochs, save_path):\n    # ネットワークをGPUへ\n    model.to(device)\n\n    best_val_loss = float('inf')\n    best_preds = None\n    \n    # epochのループ\n    for epoch in range(num_epochs):\n\n        # 開始時刻を保存\n        t_epoch_start = time.time()\n        epoch_train_loss = 0.0  # epochの損失和\n        epoch_val_loss = 0.0  # epochの損失和\n        preds = []\n        trues = []\n\n        print('-------------')\n        print(f'Epoch {epoch+1}/{num_epochs}')\n        print('-------------')\n\n        # epochごとの訓練と検証のループ\n        for phase in ['train', 'val']:\n            if phase == 'train':\n                model.train()  # モデルを訓練モードに\n            else:\n                model.eval()   # モデルを検証モードに\n                print('-------------')\n                \n            # イテレーターループ\n            for i, (images, labels) in enumerate(dataloaders_dict[phase]):\n\n                # GPUが使えるならGPUにデータを送る\n                images = images.to(device)\n                labels = labels.to(device)\n\n                # 順伝搬（forward）計算\n                with torch.set_grad_enabled(phase == 'train'):\n                    outputs = model(images)\n                    loss = criterion(outputs, labels)\n                    \n                    # 訓練時はバックプロパゲーション\n                    if phase == 'train':\n                        loss.backward()  # 勾配の計算\n                        optimizer.step()\n                        optimizer.zero_grad() # 勾配の初期化\n                        epoch_train_loss += loss.item()/len(dataloaders_dict[phase].dataset)\n                    # 検証時\n                    else:\n                        preds += [outputs.detach().cpu().softmax(dim=1).numpy()]\n                        trues += [labels.detach().cpu()]\n                        epoch_val_loss += loss.item()/len(dataloaders_dict[phase].dataset)\n                    \n                    # 途中経過を表示\n                    if i%10 == 0:\n                        print(f'[{phase}][{i+1}/{len(dataloaders_dict[phase])}] loss: {loss.item()/images.size(0): .4f}')\n        \n        if phase == 'train':\n            scheduler.step()  # 最適化schedulerの更新\n            \n        # epochのphaseごとのlossと正解率\n        t_epoch_finish = time.time()\n        print('-------------')\n        print(f'epoch {epoch+1} epoch_train_Loss:{epoch_train_loss:.4f} epoch_val_loss:{epoch_val_loss:.4f} time: {t_epoch_finish - t_epoch_start:.4f} sec.')\n        print(f'epoch_val_acc: {accuracy_score(np.concatenate(trues), np.concatenate(preds).argmax(axis=1))}')\n        \n        # validation lossが一番低いエポックのモデルを保存\n        if best_val_loss > epoch_val_loss:\n            best_preds = np.concatenate(preds)\n            best_val_loss = epoch_val_loss\n            save_checkpoint(model, optimizer, scheduler, epoch, save_path)\n            print(\"save model\")\n    return best_val_loss, best_preds\n\n# 1foldの学習を行う関数\ndef run_one_fold(df_train, df_val, fold, device):\n    # データセット作成\n    train_dataset = Dataset(df_train, phase=\"train\", transform=DataTransform(\n        input_size=args.input_size, color_mean=args.color_mean, color_std=args.color_std))\n\n    val_dataset = Dataset(df_val, phase=\"val\", transform=DataTransform(\n        input_size=args.input_size, color_mean=args.color_mean, color_std=args.color_std))\n    \n    # データローダーの作成\n    train_dataloader = data.DataLoader(\n        train_dataset, batch_size=args.batch_size, shuffle=True)\n\n    val_dataloader = data.DataLoader(\n        val_dataset, batch_size=args.batch_size, shuffle=False)\n\n    # 辞書オブジェクトにまとめる\n    dataloaders_dict = {\"train\": train_dataloader, \"val\": val_dataloader}\n\n    # モデル定義\n    model = EfficientNet.from_pretrained(args.model_name, num_classes=args.num_classes)\n    optimizer = optim.Adam(model.parameters(), lr=args.lr) # 最適化手法\n    criterion = nn.CrossEntropyLoss() # 損失関数\n    scheduler = optim.lr_scheduler.ExponentialLR(optimizer, gamma=args.gamma) # スケジューラ―\n    \n    save_path = f\"{args.model_name}_fold_{fold}.pth\"\n    best_val_loss, best_preds = train_model(model, dataloaders_dict, criterion, scheduler, optimizer, device, num_epochs=args.epochs, save_path=save_path)\n    return best_val_loss, best_preds\n\n# kfoldの学習を行う関数\ndef run_k_fold(df):\n    # GPUが使えるかを確認\n    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n    print(\"使用デバイス：\", device)\n    \n    # 層化K分割交差検証\n    skf = StratifiedKFold(n_splits=args.folds, shuffle=True, random_state=SEED)\n    oof = pd.DataFrame(index=df.index)\n    for fold, (train_index, val_index) in enumerate(skf.split(df, df['subject'])):\n        print(f'\\n\\nFOLD: {fold}')\n        print('-'*50)\n        df_train, df_val = df.loc[train_index], df.loc[val_index]\n        best_val_loss, best_preds = run_one_fold(df_train, df_val, fold, device)\n        oof.loc[val_index, activity_map.keys()] = best_preds\n    return oof","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:40.483896Z","iopub.execute_input":"2021-12-02T09:16:40.484358Z","iopub.status.idle":"2021-12-02T09:16:40.512573Z","shell.execute_reply.started":"2021-12-02T09:16:40.484320Z","shell.execute_reply":"2021-12-02T09:16:40.511636Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 学習パラメータ\nclass args:\n    model_name = 'efficientnet-b3'\n    color_mean = (0.485, 0.456, 0.406)\n    color_std = (0.229, 0.224, 0.225)\n    input_size = 256\n    num_classes = 10\n    batch_size = 64\n    epochs = 10\n    folds = 5\n    lr = 1e-3\n    gamma = 0.98\n    debug = True\n    train = False","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:40.513787Z","iopub.execute_input":"2021-12-02T09:16:40.514314Z","iopub.status.idle":"2021-12-02T09:16:40.525066Z","shell.execute_reply.started":"2021-12-02T09:16:40.514228Z","shell.execute_reply":"2021-12-02T09:16:40.524113Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if args.debug:\n    df_train = df.iloc[:1000]\nelse:\n    df_train = df.copy()\n\nif args.train:\n    oof = run_k_fold(df_train)\n    accuracy = accuracy_score(df_train['class_num'], oof.values.argmax(axis=1))\n    print(f'\\n\\naccuracy: {accuracy}')","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:40.526030Z","iopub.execute_input":"2021-12-02T09:16:40.528470Z","iopub.status.idle":"2021-12-02T09:16:40.538174Z","shell.execute_reply.started":"2021-12-02T09:16:40.528384Z","shell.execute_reply":"2021-12-02T09:16:40.537442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Testデータの予測","metadata":{}},{"cell_type":"code","source":"# 自分で実装\n# テストデータの推論を行う関数\ndef inference(model, dataloader, device):\n    model.to(device)\n    model.eval()\n    preds = []\n    for i, (images, labels) in enumerate(dataloader):\n        images = images.to(device)\n        with torch.no_grad():\n            outputs = model(images)\n        preds += [outputs.detach().cpu().softmax(dim=1).numpy()]\n        \n        if i%10 == 0:\n            print(f'[test][{i+1}/{len(dataloader)}]')\n        \n    preds = np.concatenate(preds)\n    return preds\n\n# k個のモデルに対して推論を行い，アンサンブル\ndef inference_k_fold(df_test):\n    test_dataset = Dataset(df_test, phase=\"val\", transform=DataTransform(\n        input_size=args.input_size, color_mean=args.color_mean, color_std=args.color_std))\n    test_dataloader = data.DataLoader(\n        test_dataset, batch_size=args.batch_size, shuffle=False)\n\n    model = EfficientNet.from_pretrained(args.model_name, num_classes=args.num_classes)\n    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n    for fold in range(args.folds):\n        print(f'\\n\\nFOLD: {fold}')\n        print('-'*50)\n        model.load_state_dict(torch.load(f\"{args.model_name}_fold_{fold}.pth\")['model'])\n        df_test.loc[:, activity_map.keys()] += (inference(model, test_dataloader, device) / args.folds)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:16:40.540639Z","iopub.execute_input":"2021-12-02T09:16:40.541268Z","iopub.status.idle":"2021-12-02T09:16:40.552090Z","shell.execute_reply.started":"2021-12-02T09:16:40.541231Z","shell.execute_reply":"2021-12-02T09:16:40.551267Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if args.debug:\n    results = pd.read_csv('../input/statefarmdistracteddriverdetectionpretrain/result.csv')\n    results.to_csv('result.csv', index=False)\nelse:\n    # テストデータの読み込み\n    df_test = pd.read_csv(osp.join(data_dir, 'sample_submission.csv'))\n\n    # 前処理\n    df_test['file_path'] = df_test.apply(lambda row: osp.join(data_dir, f'imgs/test/{row.img}'), axis=1)\n    df_test['class_num'] = 0\n    df_test.loc[:, activity_map.keys()] = 0\n    \n    # k個分の推論結果を平均し，resultsに格納\n    inference_k_fold(df_test)\n    results = df_test.drop(['file_path', 'class_num'], axis=1)\n    results.iloc[:, 1:] = results.iloc[:, 1:].clip(0, 1)\n    results.to_csv('result.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T09:17:48.367927Z","iopub.execute_input":"2021-12-02T09:17:48.368199Z","iopub.status.idle":"2021-12-02T09:17:50.590025Z","shell.execute_reply.started":"2021-12-02T09:17:48.368169Z","shell.execute_reply":"2021-12-02T09:17:50.589233Z"},"trusted":true},"execution_count":null,"outputs":[]}]}