{"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":"# Herbarium 2021 - Half-Earth Challenge - FGVC8 - ResNet\n\n**Author:** Ricardo B. Sousa (ORCID: [0000-0003-4537-5095](https://orcid.org/0000-0003-4537-5095))\n\n**Affilitation:**: Faculty of Engineering of the University of Porto, INESC TEC - Instituto de Engenharia de Sistemas e Computadores, Tecnologia e Ciência\n\n**Scope of this work:** Project of the curricular unit Computacional Vision of PDEEC@FEUP (Doctoral Program in Electrical and Computer Engineering)","metadata":{}},{"cell_type":"markdown","source":"## Setup\n\n### Load libraries","metadata":{}},{"cell_type":"code","source":"# Math and Image\nimport numpy as np               # Math\nimport matplotlib.pyplot as plt  # Plot\nimport cv2                       # OpenCV\nimport PIL                       # Data Augmentation\nimport albumentations            # Data Augmentation\nfrom albumentations.pytorch import ToTensorV2\n# Operating System\nimport os\nimport time\nimport copy\n# Utilities\nimport pandas as pd  # Handling CSV files\nimport random\nimport json\nimport tqdm          # Testing\nimport sklearn       # label encoding and metrics\nfrom sklearn import preprocessing\n# Torch\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torchvision\n# TensorFlow\nimport tensorflow as tf\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)\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets\n# 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\n# outside of the current session will list all files under the input directory\n\nprint(\"PyTorch Version: \",torch.__version__)\nprint(\"Torchvision Version: \",torchvision.__version__)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-05-23T00:13:07.841141Z","iopub.execute_input":"2021-05-23T00:13:07.841521Z","iopub.status.idle":"2021-05-23T00:13:15.918595Z","shell.execute_reply.started":"2021-05-23T00:13:07.841435Z","shell.execute_reply":"2021-05-23T00:13:15.917688Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### PC Configuration","metadata":{}},{"cell_type":"code","source":"# CPU Details - Number & Model\n!lscpu | grep \"CPU(s):\"\n!lscpu | grep Hz\n# Total Memory\n!cat /proc/meminfo | grep MemTotal\n# CUDA Check\nprint(\"Is CUDA Available?\",\n      torch.cuda.is_available())\nif torch.cuda.is_available() == True: \n    print(\"Current CUDA device:\",\n        torch.cuda.get_device_name(0))\n\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(\"Device: \",DEVICE)","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:15.922214Z","iopub.execute_input":"2021-05-23T00:13:15.922521Z","iopub.status.idle":"2021-05-23T00:13:17.917688Z","shell.execute_reply.started":"2021-05-23T00:13:15.922492Z","shell.execute_reply":"2021-05-23T00:13:17.916392Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Random Seed\n\n**Note:** change the type of the next cell from Code to Markdown when using data augmentation (if you train 1 epoch per session with seed fixed, the same images would be augmented in all epochs; the purpose is augmenting online all the images if possible, and not only a subset and always the same subset).","metadata":{}},{"cell_type":"code","source":"def seed_fix(seed=42):\n    random.seed(seed)\n    os.environ[\"PYTHONHASHSEED\"] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n\nseed_fix()\nprint(\"Seed fixed\")","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:17.91928Z","iopub.execute_input":"2021-05-23T00:13:17.919668Z","iopub.status.idle":"2021-05-23T00:13:17.928264Z","shell.execute_reply.started":"2021-05-23T00:13:17.91963Z","shell.execute_reply":"2021-05-23T00:13:17.926655Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Configuration","metadata":{}},{"cell_type":"code","source":"ROOT_DATA   = \"/kaggle/input/herbarium-2021-fgvc8/\"\nDATA_TRAIN  = ROOT_DATA + \"train/\"\nDATA_TEST   = ROOT_DATA + \"test/\"\nROOT_OUTPUT = \"/kaggle/working/\"\nMETA        = \"metadata.json\"\nBATCH_SIZE  = 128    # number of training examples utilized in one iteration\nBATCH_EVAL  = 128\nSHUFFLE     = True\nEPOCHS      = 1\nLEARN_RATE  = 4e-4\nIMG_HEIGHT  = 224\nIMG_WIDTH   = 224\nNUM_CLASSES = None   # define below\nNUM_WORKERS = 4\nPRE_TRAINED = False\n\nPATH_SAVE_MODEL = \"/kaggle/working/ResNet50_da_run-09.pth\"\n\nESTIMATED_MAX_TRAINING_TIME = 480 # hours (8h * 60 = 480min, leaving 1h to the test time)\n\nprint(ROOT_DATA)","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:17.92958Z","iopub.execute_input":"2021-05-23T00:13:17.930254Z","iopub.status.idle":"2021-05-23T00:13:17.93706Z","shell.execute_reply.started":"2021-05-23T00:13:17.93017Z","shell.execute_reply":"2021-05-23T00:13:17.936181Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Create dataset","metadata":{}},{"cell_type":"markdown","source":"### Generic information","metadata":{}},{"cell_type":"code","source":"# Training dataset\nwith open(os.path.join(DATA_TRAIN,META),\"r\",encoding=\"ISO-8859-1\") as file:\n    meta_train = json.load(file)\n    print(\"Number of images (training dataset): \",\n          len(meta_train[\"images\"]),)\n    for i in list(meta_train.keys()):\n        print(\"  - sample and number of elements in category {}: \".format(i),\n              len(list(meta_train[i])),)\n        print(\"\\t[0] \",\n              list(meta_train[i])[0], end=\"\\n\")\n\nNUM_CLASSES   = len(meta_train[\"categories\"])\nNUM_IMG_TRAIN = len(meta_train[\"annotations\"])\n\n# Validation dataset\nwith open(os.path.join(DATA_TEST,META),\"r\",encoding=\"ISO-8859-1\") as file:\n    meta_test = json.load(file)\n    print(\"\\nNumber of images (training dataset): \",\n          len(meta_test[\"images\"]),)\n    for i in list(meta_test.keys()):\n        print(\"  - sample and number of elements in category {}: \".format(i),\n              len(list(meta_test[i])),)\n        print(\"\\t[0] \",\n              list(meta_test[i])[0], end=\"\\n\")\n\nNUM_IMG_TEST  = len(meta_test[\"images\"]) \n\n# Print variables\nprint(\"\\n\\n\"\n      \"Number of images for training: \",NUM_IMG_TRAIN)\nprint(\"Number of images for testing : \",NUM_IMG_TEST)\nprint(\"Number of classes            : \",NUM_CLASSES)","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:17.941356Z","iopub.execute_input":"2021-05-23T00:13:17.941893Z","iopub.status.idle":"2021-05-23T00:13:29.751804Z","shell.execute_reply.started":"2021-05-23T00:13:17.941855Z","shell.execute_reply":"2021-05-23T00:13:29.7509Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Process training and evaluation metadata\n\nMerge training images and annotations as a dataframe. The database-based joint operation merge is performed on the ids \"image_id\" (from images dataframe) and \"id\" (from annotations dataframe).\n\nThe problem with the validation data is that the `.json` does not provide the labels to check if the model is classifying correctly or not the validation images.","metadata":{}},{"cell_type":"code","source":"# Process metadata json for training images into a DataFrame\ntrain_img = pd.DataFrame(meta_train[\"images\"])\ntrain_ann = pd.DataFrame(meta_train[\"annotations\"]).drop(columns=\"image_id\")\ntrain_df  = train_img.merge(train_ann,on=\"id\") # Performs a database-style joint\n\n# Check number of classes\nprint(\"Number of classes (expected): \",NUM_CLASSES)\nprint(\"Number of classes (computed): \",\n      train_df[\"category_id\"].max() - train_df[\"category_id\"].min()+1)\nprint(\"\\nShape training dataframe    :\",train_df.shape)\n\n# Process metadata json for test images into a DataFrame\ntest_df = pd.DataFrame(meta_test[\"images\"])","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:29.755473Z","iopub.execute_input":"2021-05-23T00:13:29.755732Z","iopub.status.idle":"2021-05-23T00:13:40.406951Z","shell.execute_reply.started":"2021-05-23T00:13:29.755705Z","shell.execute_reply":"2021-05-23T00:13:40.406158Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Prepare Submission","metadata":{}},{"cell_type":"code","source":"sample_submission = pd.read_csv(ROOT_DATA + \"sample_submission.csv\")","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:40.408274Z","iopub.execute_input":"2021-05-23T00:13:40.408648Z","iopub.status.idle":"2021-05-23T00:13:40.485884Z","shell.execute_reply.started":"2021-05-23T00:13:40.40861Z","shell.execute_reply":"2021-05-23T00:13:40.485141Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Label Encoder","metadata":{}},{"cell_type":"code","source":"# Fit the label encoder instance\nlabel_encoder = preprocessing.LabelEncoder()\nlabel_encoder.fit(train_df[\"category_id\"])\n\n# Transform labels to normalized encoding\ntrain_df[\"category_id_le\"] = label_encoder.transform(train_df[\"category_id\"])\nclass_map = dict(sorted(train_df[[\"category_id_le\",\"category_id\"]].values.tolist()))\n\nprint(\"Labels converted to normalized encoding\")","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:40.487228Z","iopub.execute_input":"2021-05-23T00:13:40.487699Z","iopub.status.idle":"2021-05-23T00:13:50.431289Z","shell.execute_reply.started":"2021-05-23T00:13:40.487661Z","shell.execute_reply":"2021-05-23T00:13:50.429615Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Dataloaders","metadata":{}},{"cell_type":"code","source":"class TrainDataset(torch.utils.data.Dataset):\n    def __init__(self, df, labels, transform=None):\n        self.df = df\n        self.labels = labels\n        self.transform = transform\n        \n    def __len__(self) -> int:\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        file_name = self.df[\"file_name\"].values[idx]\n        file_path = DATA_TRAIN + file_name\n        img = cv2.imread(file_path)\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        label = self.labels.values[idx]\n        \n        if self.transform:\n            img = self.transform(image=img)[\"image\"]\n        \n        return img, label","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:50.432638Z","iopub.execute_input":"2021-05-23T00:13:50.432967Z","iopub.status.idle":"2021-05-23T00:13:50.440993Z","shell.execute_reply.started":"2021-05-23T00:13:50.43293Z","shell.execute_reply":"2021-05-23T00:13:50.439816Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class TestDataset(torch.utils.data.Dataset):\n    def __init__(self, df, transform=None):\n        self.df = df\n        self.transform = transform\n        \n    def __len__(self) -> int:\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        file_name = self.df[\"file_name\"].values[idx]\n        file_path = DATA_TEST + file_name\n        img = cv2.imread(file_path)\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        \n        if self.transform:\n            img = self.transform(image=img)[\"image\"]\n        \n        return img","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:50.442413Z","iopub.execute_input":"2021-05-23T00:13:50.442861Z","iopub.status.idle":"2021-05-23T00:13:50.45228Z","shell.execute_reply.started":"2021-05-23T00:13:50.442825Z","shell.execute_reply":"2021-05-23T00:13:50.451355Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Image Augmentation\n\n**Note:** uncomment the `albumentations.HorizontalFlip` + `albumentations.VerticalFlip` + `albumentations.Rotate` to have data augmentation with geometric transformations.","metadata":{}},{"cell_type":"code","source":"def get_transforms(*, data: str):\n    assert data in (\"train\",\"test\")\n    \n    if data == \"train\":\n        return albumentations.Compose([\n            albumentations.Resize(IMG_HEIGHT,IMG_WIDTH),\n            albumentations.Normalize(\n                mean=[0.485, 0.456, 0.406],\n                std=[0.229, 0.224, 0.225],\n            ),\n            #albumentations.HorizontalFlip(p=0.25),\n            #albumentations.VerticalFlip(p=0.25),\n            #albumentations.Rotate(limit=10,p=0.05),\n            ToTensorV2(),\n        ])\n\n    elif data == \"test\":\n        return albumentations.Compose([\n            albumentations.Resize(IMG_HEIGHT,IMG_WIDTH),\n            albumentations.Normalize(\n                mean=[0.485, 0.456, 0.406],\n                std=[0.229, 0.224, 0.225],\n            ),\n            ToTensorV2(),\n        ])","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:50.453564Z","iopub.execute_input":"2021-05-23T00:13:50.453959Z","iopub.status.idle":"2021-05-23T00:13:50.466708Z","shell.execute_reply.started":"2021-05-23T00:13:50.453923Z","shell.execute_reply":"2021-05-23T00:13:50.465726Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Check One Sample\n\n**Note:** change the type of the next cell from Markdown to Code to have an example of the data augmentation techniquies used in this work.","metadata":{}},{"cell_type":"markdown","source":"im = PIL.Image.open(DATA_TRAIN + train_df.file_name[0])\nnewsize=(IMG_HEIGHT,IMG_WIDTH)\nim=im.resize(newsize)\nim=im.transpose(PIL.Image.FLIP_LEFT_RIGHT)\nim=im.transpose(PIL.Image.FLIP_TOP_BOTTOM)\nim=im.rotate(10)\nim.save(\"original-image_left_2right_top2bottom_rotate-10.png\")\nim","metadata":{}},{"cell_type":"markdown","source":"## Datasets\n\n### Training Dataset","metadata":{}},{"cell_type":"code","source":"train_dataset = TrainDataset(\n    train_df,train_df[\"category_id_le\"],\n    transform=get_transforms(data=\"train\"))\ntrain_loader = torch.utils.data.DataLoader(\n    train_dataset,\n    batch_size=BATCH_SIZE,shuffle=SHUFFLE,num_workers=NUM_WORKERS)\nprint(\"Train data loader created\")","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:50.46921Z","iopub.execute_input":"2021-05-23T00:13:50.469881Z","iopub.status.idle":"2021-05-23T00:13:50.477491Z","shell.execute_reply.started":"2021-05-23T00:13:50.469844Z","shell.execute_reply":"2021-05-23T00:13:50.476454Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Test Dataset","metadata":{}},{"cell_type":"code","source":"test_df.head(n=5)","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:50.478982Z","iopub.execute_input":"2021-05-23T00:13:50.479406Z","iopub.status.idle":"2021-05-23T00:13:50.496693Z","shell.execute_reply.started":"2021-05-23T00:13:50.479359Z","shell.execute_reply":"2021-05-23T00:13:50.495534Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_dataset = TestDataset(\n    test_df,\n    transform=get_transforms(data=\"test\"))\ntest_loader = torch.utils.data.DataLoader(\n    test_dataset,\n    batch_size=BATCH_EVAL,shuffle=False,num_workers=NUM_WORKERS)\nprint(\"Test data loader created\")","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:50.498045Z","iopub.execute_input":"2021-05-23T00:13:50.498493Z","iopub.status.idle":"2021-05-23T00:13:50.504042Z","shell.execute_reply.started":"2021-05-23T00:13:50.498458Z","shell.execute_reply":"2021-05-23T00:13:50.503158Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model","metadata":{}},{"cell_type":"code","source":"def train_model(model,dataloader,criterion,optimizer,num_epochs=1):\n    since = time.time()\n    \n    for epoch in range(num_epochs):\n        print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n        print('-' * 10)\n        \n        model.train()\n        \n        running_loss = 0.0\n        running_corrects = 0\n        \n        #for inputs, labels in tqdm.tqdm(enumerate(dataloader)):\n        i = 0\n        len_dataset = len(dataloader.dataset)\n        for inputs, labels in dataloader:\n            since_tmp = time.time()\n            \n            inputs = inputs.to(DEVICE)\n            labels = labels.to(DEVICE)\n            \n            optimizer.zero_grad()\n            \n            with torch.set_grad_enabled(True):\n                outputs = model(inputs)\n                loss = criterion(outputs,labels)\n                \n                _,preds = torch.max(outputs,1)\n                \n                loss.backward()\n                optimizer.step()\n              \n            loss_tmp = loss.item()\n            pred_tmp = torch.sum(preds == labels.data)\n            \n            running_loss += loss_tmp * inputs.size(0)\n            running_corrects += pred_tmp\n            \n            time_elapsed_tmp = time.time() - since_tmp\n            \n            print('  loss: {:.04f} corr: {:d} ({:d}/{:d}) completed in {:.0f}m {:.03f}s'.format(\n                loss_tmp, pred_tmp,(i+1)*BATCH_SIZE,len_dataset,\n                time_elapsed_tmp // 60, time_elapsed_tmp % 60))\n            \n            if ((time.time() - since) // 60 > ESTIMATED_MAX_TRAINING_TIME):\n                break;\n            \n            i += 1\n            \n        epoch_loss = running_loss / len_dataset\n        epoch_acc = running_corrects.double() / len_dataset\n        \n        torch.save(model.state_dict(),PATH_SAVE_MODEL)\n        print(PATH_SAVE_MODEL)\n        print('Loss: {:.04f} Acc: {:.04f}'.format(epoch_loss, epoch_acc))\n        \n        print()\n            \n        if ((time.time() - since) // 60 > ESTIMATED_MAX_TRAINING_TIME):\n            break;\n        \n    time_elapsed = time.time() - since\n    print('Loss: {:.04f} Acc: {:.04f}'.format(epoch_loss, epoch_acc))\n    print('Training complete in {:.0f}m {:.03f}s'.format(time_elapsed // 60, time_elapsed % 60))\n    \n    #model.load_state_dict(best_model_wts)\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:50.505313Z","iopub.execute_input":"2021-05-23T00:13:50.505914Z","iopub.status.idle":"2021-05-23T00:13:50.519517Z","shell.execute_reply.started":"2021-05-23T00:13:50.505877Z","shell.execute_reply":"2021-05-23T00:13:50.518738Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Construct model","metadata":{}},{"cell_type":"code","source":"model = torchvision.models.resnet50(pretrained=PRE_TRAINED)\nmodel.avgpool = torch.nn.AdaptiveAvgPool2d(1)\nmodel.fc = torch.nn.Linear(model.fc.in_features,NUM_CLASSES)","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:50.520923Z","iopub.execute_input":"2021-05-23T00:13:50.521289Z","iopub.status.idle":"2021-05-23T00:13:50.985442Z","shell.execute_reply.started":"2021-05-23T00:13:50.521252Z","shell.execute_reply":"2021-05-23T00:13:50.984587Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Use existent trained model","metadata":{}},{"cell_type":"code","source":"model.load_state_dict(torch.load(\"../input/herbarium-2021-rbs/ResNet50_da_run-08.pth\"))","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:50.986923Z","iopub.execute_input":"2021-05-23T00:13:50.987287Z","iopub.status.idle":"2021-05-23T00:13:59.506414Z","shell.execute_reply.started":"2021-05-23T00:13:50.987251Z","shell.execute_reply":"2021-05-23T00:13:59.505705Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Train","metadata":{}},{"cell_type":"code","source":"model.to(DEVICE)\n\noptimizer = torch.optim.Adam(model.parameters(), lr=LEARN_RATE, amsgrad=False)\nscheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(\n    optimizer, 'min', factor=0.75, patience=5, verbose=True, eps=1e-6)\n\ncriterion = torch.nn.CrossEntropyLoss()","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:59.50782Z","iopub.execute_input":"2021-05-23T00:13:59.508157Z","iopub.status.idle":"2021-05-23T00:13:59.565552Z","shell.execute_reply.started":"2021-05-23T00:13:59.508122Z","shell.execute_reply":"2021-05-23T00:13:59.564822Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = train_model(model,train_loader,criterion,optimizer,EPOCHS)","metadata":{"execution":{"iopub.status.busy":"2021-05-23T00:13:59.566986Z","iopub.execute_input":"2021-05-23T00:13:59.567334Z","iopub.status.idle":"2021-05-23T06:12:44.719288Z","shell.execute_reply.started":"2021-05-23T00:13:59.567296Z","shell.execute_reply":"2021-05-23T06:12:44.717558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Inference","metadata":{}},{"cell_type":"code","source":"model.eval()\nmodel.to(DEVICE)\n\npredictions = np.zeros((len(test_dataset)))\n\nfor i,images in tqdm.tqdm(enumerate(test_loader)):\n    images = images.to(DEVICE)\n    with torch.no_grad():\n        y_predictions = model(images)\n\n    predictions[i*BATCH_EVAL:(i+1)*BATCH_EVAL] = y_predictions.to(DEVICE).cpu().numpy().argmax(1)","metadata":{"execution":{"iopub.status.busy":"2021-05-23T06:12:44.720985Z","iopub.execute_input":"2021-05-23T06:12:44.721344Z","iopub.status.idle":"2021-05-23T06:52:01.089305Z","shell.execute_reply.started":"2021-05-23T06:12:44.721302Z","shell.execute_reply":"2021-05-23T06:52:01.088046Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Submit","metadata":{}},{"cell_type":"code","source":"test_df[\"preds\"] = predictions.astype(int)\nsubmission = sample_submission.merge(\n    test_df.rename(columns = {\"id\":\"Id\"})[[\"Id\",\"preds\"]],on=\"Id\"\n).drop(columns=\"Predicted\")\nsubmission[\"Predicted\"] = submission[\"preds\"].map(class_map)\nsubmission = submission.drop(columns=\"preds\")\nsubmission.to_csv(\"submission.csv\",index=False)\nsubmission.head()","metadata":{"execution":{"iopub.status.busy":"2021-05-23T06:52:01.091129Z","iopub.execute_input":"2021-05-23T06:52:01.091546Z","iopub.status.idle":"2021-05-23T06:52:02.448028Z","shell.execute_reply.started":"2021-05-23T06:52:01.091503Z","shell.execute_reply":"2021-05-23T06:52:02.447286Z"},"trusted":true},"execution_count":null,"outputs":[]}]}