{"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":"\n# import package\n\nimport numpy as np \nimport pandas as pd\n\n# model\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch import optim\n!from torchsummary import summary\n\n\n# dataset and transformation\nfrom torchvision import datasets\nimport torchvision.transforms as transforms\nfrom torch.utils.data import DataLoader\nfrom torchvision import models\nimport os\n\n# display images\nfrom torchvision import utils\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\n# utils\nimport numpy as np\nimport time\nimport copy\n\n#OpenCV-Python\nimport cv2","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:21.035832Z","iopub.execute_input":"2021-11-30T05:52:21.036938Z","iopub.status.idle":"2021-11-30T05:52:21.855794Z","shell.execute_reply.started":"2021-11-30T05:52:21.036876Z","shell.execute_reply":"2021-11-30T05:52:21.854826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#데이터셋\ntrain_image_path = '../input/plant-pathology-2021-fgvc8/train_images'\ntest_image_path = '../input/plant-pathology-2021-fgvc8/test_images'\ntrain_df_path = '../input/plant-pathology-2021-fgvc8/train.csv'\ntest_df_path = '../input/plant-pathology-2021-fgvc8/sample_submission.csv'\n","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:21.857874Z","iopub.execute_input":"2021-11-30T05:52:21.858233Z","iopub.status.idle":"2021-11-30T05:52:21.862243Z","shell.execute_reply.started":"2021-11-30T05:52:21.858204Z","shell.execute_reply":"2021-11-30T05:52:21.861609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_ds = train_df_path\ntest_ds = test_df_path","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:21.863514Z","iopub.execute_input":"2021-11-30T05:52:21.863900Z","iopub.status.idle":"2021-11-30T05:52:21.878419Z","shell.execute_reply.started":"2021-11-30T05:52:21.863853Z","shell.execute_reply":"2021-11-30T05:52:21.877684Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train = pd.read_csv(train_df_path)","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:21.879780Z","iopub.execute_input":"2021-11-30T05:52:21.880059Z","iopub.status.idle":"2021-11-30T05:52:21.913544Z","shell.execute_reply.started":"2021-11-30T05:52:21.880020Z","shell.execute_reply":"2021-11-30T05:52:21.912381Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train.head()","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:21.915963Z","iopub.execute_input":"2021-11-30T05:52:21.916192Z","iopub.status.idle":"2021-11-30T05:52:21.927406Z","shell.execute_reply.started":"2021-11-30T05:52:21.916163Z","shell.execute_reply":"2021-11-30T05:52:21.926386Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_test = pd.read_csv(test_df_path)","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:21.928635Z","iopub.execute_input":"2021-11-30T05:52:21.929392Z","iopub.status.idle":"2021-11-30T05:52:21.944176Z","shell.execute_reply.started":"2021-11-30T05:52:21.929355Z","shell.execute_reply":"2021-11-30T05:52:21.943455Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#데이터 로드?\n\ntrain_dl = DataLoader(train_ds, batch_size=32, shuffle=True)\ntest_dl = DataLoader(test_ds, batch_size=32, shuffle=True)","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:21.945263Z","iopub.execute_input":"2021-11-30T05:52:21.946108Z","iopub.status.idle":"2021-11-30T05:52:21.953477Z","shell.execute_reply.started":"2021-11-30T05:52:21.946069Z","shell.execute_reply":"2021-11-30T05:52:21.952786Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#모델 구축","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:21.954733Z","iopub.execute_input":"2021-11-30T05:52:21.955759Z","iopub.status.idle":"2021-11-30T05:52:21.966057Z","shell.execute_reply.started":"2021-11-30T05:52:21.955708Z","shell.execute_reply":"2021-11-30T05:52:21.965488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Swish activation function\nclass Swish(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        return x * self.sigmoid(x)\n\n# check\nif __name__ == '__main__':\n    x = torch.randn(3, 3, 224, 224)\n    model = Swish()\n    output = model(x)\n    print('output size:', output.size())","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:21.967209Z","iopub.execute_input":"2021-11-30T05:52:21.967734Z","iopub.status.idle":"2021-11-30T05:52:21.990555Z","shell.execute_reply.started":"2021-11-30T05:52:21.967684Z","shell.execute_reply":"2021-11-30T05:52:21.989819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#in channels 연산수정\n# SE Block\nclass SEBlock(nn.Module):\n    def __init__(self, in_channels, r=4):\n        super().__init__()\n\n        self.squeeze = nn.AdaptiveAvgPool2d((1,1))\n        self.excitation = nn.Sequential(\n            nn.Linear(in_channels, in_channels // r),\n            Swish(),\n            nn.Linear(in_channels // r, in_channels),\n            nn.Sigmoid()\n        )\n\n    def forward(self, x):\n        x = self.squeeze(x)\n        x = x.view(x.size(0), -1)\n        x = self.excitation(x)\n        x = x.view(x.size(0), x.size(1), 1, 1)\n        return x\n\n# check\nif __name__ == '__main__':\n    x = torch.randn(3, 56, 17, 17)\n    model = SEBlock(x.size(1))\n    output = model(x)\n    print('output size:', output.size())","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:21.992265Z","iopub.execute_input":"2021-11-30T05:52:21.992951Z","iopub.status.idle":"2021-11-30T05:52:22.005732Z","shell.execute_reply.started":"2021-11-30T05:52:21.992912Z","shell.execute_reply":"2021-11-30T05:52:22.004776Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MBConv(nn.Module):\n    expand = 6\n    def __init__(self, in_channels, out_channels, kernel_size, stride=1, se_scale=4, p=0.5):\n        super().__init__()\n        # first MBConv is not using stochastic depth\n        self.p = torch.tensor(p).float() if (in_channels == out_channels) else torch.tensor(1).float()\n\n        self.residual = nn.Sequential(\n            nn.Conv2d(in_channels, in_channels * MBConv.expand, 1, stride=stride, padding=0, bias=False),\n            nn.BatchNorm2d(in_channels * MBConv.expand, momentum=0.99, eps=1e-3),\n            Swish(),\n            nn.Conv2d(in_channels * MBConv.expand, in_channels * MBConv.expand, kernel_size=kernel_size,\n                      stride=1, padding=kernel_size//2, bias=False, groups=in_channels*MBConv.expand),\n            nn.BatchNorm2d(in_channels * MBConv.expand, momentum=0.99, eps=1e-3),\n            Swish()\n        )\n\n        self.se = SEBlock(in_channels * MBConv.expand, se_scale)\n\n        self.project = nn.Sequential(\n            nn.Conv2d(in_channels*MBConv.expand, out_channels, kernel_size=1, stride=1, padding=0, bias=False),\n            nn.BatchNorm2d(out_channels, momentum=0.99, eps=1e-3)\n        )\n\n        self.shortcut = (stride == 1) and (in_channels == out_channels)\n\n    def forward(self, x):\n        # stochastic depth\n        if self.training:\n            if not torch.bernoulli(self.p):\n                return x\n\n        x_shortcut = x\n        x_residual = self.residual(x)\n        x_se = self.se(x_residual)\n\n        x = x_se * x_residual\n        x = self.project(x)\n\n        if self.shortcut:\n            x= x_shortcut + x\n\n        return x\n\n# check\nif __name__ == '__main__':\n    x = torch.randn(3, 16, 24, 24)\n    model = MBConv(x.size(1), x.size(1), 3, stride=1, p=1)\n    model.train()\n    output = model(x)\n    x = (output == x)\n    print('output size:', output.size(), 'Stochastic depth:', x[1,0,0,0])\n","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:22.007671Z","iopub.execute_input":"2021-11-30T05:52:22.007927Z","iopub.status.idle":"2021-11-30T05:52:22.038219Z","shell.execute_reply.started":"2021-11-30T05:52:22.007898Z","shell.execute_reply":"2021-11-30T05:52:22.036842Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class SepConv(nn.Module):\n    expand = 1\n    def __init__(self, in_channels, out_channels, kernel_size, stride=1, se_scale=4, p=0.5):\n        super().__init__()\n        # first SepConv is not using stochastic depth\n        self.p = torch.tensor(p).float() if (in_channels == out_channels) else torch.tensor(1).float()\n\n        self.residual = nn.Sequential(\n            nn.Conv2d(in_channels * SepConv.expand, in_channels * SepConv.expand, kernel_size=kernel_size,\n                      stride=1, padding=kernel_size//2, bias=False, groups=in_channels*SepConv.expand),\n            nn.BatchNorm2d(in_channels * SepConv.expand, momentum=0.99, eps=1e-3),\n            Swish()\n        )\n\n        self.se = SEBlock(in_channels * SepConv.expand, se_scale)\n\n        self.project = nn.Sequential(\n            nn.Conv2d(in_channels*SepConv.expand, out_channels, kernel_size=1, stride=1, padding=0, bias=False),\n            nn.BatchNorm2d(out_channels, momentum=0.99, eps=1e-3)\n        )\n\n        self.shortcut = (stride == 1) and (in_channels == out_channels)\n\n    def forward(self, x):\n        # stochastic depth\n        if self.training:\n            if not torch.bernoulli(self.p):\n                return x\n\n        x_shortcut = x\n        x_residual = self.residual(x)\n        x_se = self.se(x_residual)\n\n        x = x_se * x_residual\n        x = self.project(x)\n\n        if self.shortcut:\n            x= x_shortcut + x\n\n        return x\n\n# check\nif __name__ == '__main__':\n    x = torch.randn(3, 16, 24, 24)\n    model = SepConv(x.size(1), x.size(1), 3, stride=1, p=1)\n    model.train()\n    output = model(x)\n    # stochastic depth check\n    x = (output == x)\n    print('output size:', output.size(), 'Stochastic depth:', x[1,0,0,0])","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:22.039810Z","iopub.execute_input":"2021-11-30T05:52:22.040623Z","iopub.status.idle":"2021-11-30T05:52:22.062917Z","shell.execute_reply.started":"2021-11-30T05:52:22.040571Z","shell.execute_reply":"2021-11-30T05:52:22.061916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class EfficientNet(nn.Module):\n    def __init__(self, num_classes=10, width_coef=1., depth_coef=1., scale=1., dropout=0.2, se_scale=4, stochastic_depth=False, p=0.5):\n        super().__init__()\n        channels = [32, 16, 24, 40, 80, 112, 192, 320, 1280]\n        repeats = [1, 2, 2, 3, 3, 4, 1]\n        strides = [1, 2, 2, 2, 1, 2, 1]\n        kernel_size = [3, 3, 5, 3, 5, 5, 3]\n        depth = depth_coef\n        width = width_coef\n\n        channels = [int(x*width) for x in channels]\n        repeats = [int(x*depth) for x in repeats]\n\n        # stochastic depth\n        if stochastic_depth:\n            self.p = p\n            self.step = (1 - 0.5) / (sum(repeats) - 1)\n        else:\n            self.p = 1\n            self.step = 0\n\n\n        # efficient net\n        self.upsample = nn.Upsample(scale_factor=scale, mode='bilinear', align_corners=False)\n\n        self.stage1 = nn.Sequential(\n            nn.Conv2d(3, channels[0],3, stride=2, padding=1, bias=False),\n            nn.BatchNorm2d(channels[0], momentum=0.99, eps=1e-3)\n        )\n\n        self.stage2 = self._make_Block(SepConv, repeats[0], channels[0], channels[1], kernel_size[0], strides[0], se_scale)\n\n        self.stage3 = self._make_Block(MBConv, repeats[1], channels[1], channels[2], kernel_size[1], strides[1], se_scale)\n\n        self.stage4 = self._make_Block(MBConv, repeats[2], channels[2], channels[3], kernel_size[2], strides[2], se_scale)\n\n        self.stage5 = self._make_Block(MBConv, repeats[3], channels[3], channels[4], kernel_size[3], strides[3], se_scale)\n\n        self.stage6 = self._make_Block(MBConv, repeats[4], channels[4], channels[5], kernel_size[4], strides[4], se_scale)\n\n        self.stage7 = self._make_Block(MBConv, repeats[5], channels[5], channels[6], kernel_size[5], strides[5], se_scale)\n\n        self.stage8 = self._make_Block(MBConv, repeats[6], channels[6], channels[7], kernel_size[6], strides[6], se_scale)\n\n        self.stage9 = nn.Sequential(\n            nn.Conv2d(channels[7], channels[8], 1, stride=1, bias=False),\n            nn.BatchNorm2d(channels[8], momentum=0.99, eps=1e-3),\n            Swish()\n        ) \n\n        self.avgpool = nn.AdaptiveAvgPool2d((1,1))\n        self.dropout = nn.Dropout(p=dropout)\n        self.linear = nn.Linear(channels[8], num_classes)\n\n    def forward(self, x):\n        x = self.upsample(x)\n        x = self.stage1(x)\n        x = self.stage2(x)\n        x = self.stage3(x)\n        x = self.stage4(x)\n        x = self.stage5(x)\n        x = self.stage6(x)\n        x = self.stage7(x)\n        x = self.stage8(x)\n        x = self.stage9(x)\n        x = self.avgpool(x)\n        x = x.view(x.size(0), -1)\n        x = self.dropout(x)\n        x = self.linear(x)\n        return x\n\n\n    def _make_Block(self, block, repeats, in_channels, out_channels, kernel_size, stride, se_scale):\n        strides = [stride] + [1] * (repeats - 1)\n        layers = []\n        for stride in strides:\n            layers.append(block(in_channels, out_channels, kernel_size, stride, se_scale, self.p))\n            in_channels = out_channels\n            self.p -= self.step\n\n        return nn.Sequential(*layers)\n\n\ndef efficientnet_b0(num_classes=10):\n    return EfficientNet(num_classes=num_classes, width_coef=1.0, depth_coef=1.0, scale=1.0,dropout=0.2, se_scale=4)\n\ndef efficientnet_b1(num_classes=10):\n    return EfficientNet(num_classes=num_classes, width_coef=1.0, depth_coef=1.1, scale=240/224, dropout=0.2, se_scale=4)\n\ndef efficientnet_b2(num_classes=10):\n    return EfficientNet(num_classes=num_classes, width_coef=1.1, depth_coef=1.2, scale=260/224., dropout=0.3, se_scale=4)\n\ndef efficientnet_b3(num_classes=10):\n    return EfficientNet(num_classes=num_classes, width_coef=1.2, depth_coef=1.4, scale=300/224, dropout=0.3, se_scale=4)\n\ndef efficientnet_b4(num_classes=10):\n    return EfficientNet(num_classes=num_classes, width_coef=1.4, depth_coef=1.8, scale=380/224, dropout=0.4, se_scale=4)\n\ndef efficientnet_b5(num_classes=10):\n    return EfficientNet(num_classes=num_classes, width_coef=1.6, depth_coef=2.2, scale=456/224, dropout=0.4, se_scale=4)\n\ndef efficientnet_b6(num_classes=10):\n    return EfficientNet(num_classes=num_classes, width_coef=1.8, depth_coef=2.6, scale=528/224, dropout=0.5, se_scale=4)\n\ndef efficientnet_b7(num_classes=10):\n    return EfficientNet(num_classes=num_classes, width_coef=2.0, depth_coef=3.1, scale=600/224, dropout=0.5, se_scale=4)\n\n\n# check\nif __name__ == '__main__':\n    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n    x = torch.randn(3, 3, 224, 224).to(device)\n    model = efficientnet_b0().to(device)\n    output = model(x)\n    print('output size:', output.size())","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:22.064752Z","iopub.execute_input":"2021-11-30T05:52:22.065183Z","iopub.status.idle":"2021-11-30T05:52:22.392465Z","shell.execute_reply.started":"2021-11-30T05:52:22.065144Z","shell.execute_reply":"2021-11-30T05:52:22.391098Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#모델 써머리 출력 \n#작동오류발생\n#model = efficientnet_b0().to(device)\n#summary(model, (3,224,224), device=device.type)","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:22.395343Z","iopub.execute_input":"2021-11-30T05:52:22.395810Z","iopub.status.idle":"2021-11-30T05:52:22.399573Z","shell.execute_reply.started":"2021-11-30T05:52:22.395770Z","shell.execute_reply":"2021-11-30T05:52:22.398519Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#학습하기","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:22.401196Z","iopub.execute_input":"2021-11-30T05:52:22.401665Z","iopub.status.idle":"2021-11-30T05:52:22.411017Z","shell.execute_reply.started":"2021-11-30T05:52:22.401622Z","shell.execute_reply":"2021-11-30T05:52:22.410195Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# define loss function, optimizer, lr_scheduler\nloss_func = nn.CrossEntropyLoss(reduction='sum')\nopt = optim.Adam(model.parameters(), lr=0.01)\n\nfrom torch.optim.lr_scheduler import ReduceLROnPlateau\nlr_scheduler = ReduceLROnPlateau(opt, mode='min', factor=0.1, patience=10)\n\n\n# get current lr\ndef get_lr(opt):\n    for param_group in opt.param_groups:\n        return param_group['lr']\n\n\n# calculate the metric per mini-batch\ndef metric_batch(output, target):\n    pred = output.argmax(1, keepdim=True)\n    corrects = pred.eq(target.view_as(pred)).sum().item()\n    return corrects\n\n\n# calculate the loss per mini-batch\ndef loss_batch(loss_func, output, target, opt=None):\n    loss_b = loss_func(output, target)\n    metric_b = metric_batch(output, target)\n\n    if opt is not None:\n        opt.zero_grad()\n        loss_b.backward()\n        opt.step()\n    \n    return loss_b.item(), metric_b\n\n\n# calculate the loss per epochs\ndef loss_epoch(model, loss_func, df_train, sanity_check=False, opt=None):\n    running_loss = 0.0\n    running_metric = 0.0\n    len_data = len(df_train)\n\n    #for xb, yb in df_train:\n        #xb = xb.to(device)\n        #yb = yb.to(device)\n        #output = model(xb)\n\n        #loss_b, metric_b = loss_batch(loss_func, output, yb, opt)\n\n        #running_loss += loss_b\n        \n        #if metric_b is not None:\n            #running_metric += metric_b\n\n        #if sanity_check is True:\n            #break\n\n    loss = running_loss / len_data\n    metric = running_metric / len_data\n    return loss, metric\n\n\n# function to start training\ndef train_test(model, params):\n    num_epochs=params['num_epochs']\n    loss_func=params['loss_func']\n    opt=params['optimizer']\n    train_dl=params['train_dl']\n    test_dl=params['test_dl']\n    sanity_check=params['sanity_check']\n    lr_scheduler=params['lr_scheduler']\n    path2weights=params['path2weights']\n\n    loss_history = {'train': [], 'test': []}\n    metric_history = {'train': [], 'test': []}\n\n    best_loss = float('inf')\n    best_model_wts = copy.deepcopy(model.state_dict())\n    start_time = time.time()\n\n    for epoch in range(num_epochs):\n        current_lr = get_lr(opt)\n        print('Epoch {}/{}, current lr= {}'.format(epoch, num_epochs-1, current_lr))\n\n        model.train()\n        train_loss, train_metric = loss_epoch(model, loss_func, train_dl, sanity_check, opt)\n        loss_history['train'].append(train_loss)\n        metric_history['train'].append(train_metric)\n\n        model.eval()\n        with torch.no_grad():\n            test_loss, test_metric = loss_epoch(model, loss_func, test_dl, sanity_check)\n        loss_history['test'].append(test_loss)\n        metric_history['test'].append(test_metric)\n\n        if test_loss < best_loss:\n            best_loss = test_loss\n            best_model_wts = copy.deepcopy(model.state_dict())\n            torch.save(model.state_dict(), path2weights)\n            print('Copied best model weights!')\n\n        lr_scheduler.step(test_loss)\n        if current_lr != get_lr(opt):\n            print('Loading best model weights!')\n            model.load_state_dict(best_model_wts)\n\n        print('train loss: %.6f, test loss: %.6f, accuracy: %.2f, time: %.4f min' %(train_loss, test_loss, 100*test_metric, (time.time()-start_time)/60))\n        print('-'*10)\n\n    model.load_state_dict(best_model_wts)\n    return model, loss_history, metric_history","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:22.412710Z","iopub.execute_input":"2021-11-30T05:52:22.413215Z","iopub.status.idle":"2021-11-30T05:52:22.440983Z","shell.execute_reply.started":"2021-11-30T05:52:22.413169Z","shell.execute_reply":"2021-11-30T05:52:22.439905Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# define the training parameters\nparams_train = {\n    'num_epochs':100,\n    'optimizer':opt,\n    'loss_func':loss_func,\n    'train_dl':train_dl,\n    'test_dl':test_dl,\n    'sanity_check':False,\n    'lr_scheduler':lr_scheduler,\n    'path2weights':'./models/weights.pt'}\n\n# check the directory to save weights.pt\ndef createFolder(directory):\n    try:\n        if not os.path.exists(directory):\n            os.makedirs(directory)\n    except OSerror:\n        print('Error')\ncreateFolder('./models')","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:22.442635Z","iopub.execute_input":"2021-11-30T05:52:22.443406Z","iopub.status.idle":"2021-11-30T05:52:22.456315Z","shell.execute_reply.started":"2021-11-30T05:52:22.443359Z","shell.execute_reply":"2021-11-30T05:52:22.455524Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#too many values to unpack 발생지점 \n\nmodel, loss_hist, metric_hist = train_test(model, params_train)","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:22.457846Z","iopub.execute_input":"2021-11-30T05:52:22.458317Z","iopub.status.idle":"2021-11-30T05:52:23.227846Z","shell.execute_reply.started":"2021-11-30T05:52:22.458249Z","shell.execute_reply":"2021-11-30T05:52:23.226922Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_epochs = params_train['num_epochs']\n\n# Plot train-test loss\nplt.title('Train-Test Loss')\nplt.plot(range(1, num_epochs+1), loss_hist['train'], label='train')\nplt.plot(range(1, num_epochs+1), loss_hist['test'], label='test')\nplt.ylabel('Loss')\nplt.xlabel('Training Epochs')\nplt.legend()\nplt.show()\n\n# plot train-test accuracy\nplt.title('Train-Test Accuracy')\nplt.plot(range(1, num_epochs+1), metric_hist['train'], label='train')\nplt.plot(range(1, num_epochs+1), metric_hist['test'], label='test')\nplt.ylabel('Accuracy')\nplt.xlabel('Training Epochs')\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-30T05:52:23.229297Z","iopub.execute_input":"2021-11-30T05:52:23.229628Z","iopub.status.idle":"2021-11-30T05:52:23.725160Z","shell.execute_reply.started":"2021-11-30T05:52:23.229578Z","shell.execute_reply":"2021-11-30T05:52:23.724156Z"},"trusted":true},"execution_count":null,"outputs":[]}]}