{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Introduction\n\nWelcome to join the competition, '<a href=\"https://www.kaggle.com/c/herbarium-2021-fgvc8/overview  \">Herbarium 2021 - Half-Earth Challenge - FGVC8</a>'  \nThis notebook provides the easy way to complete the submission.  \nAll of the code blocks contain the comments.  "},{"metadata":{},"cell_type":"markdown","source":"# Ready\n\nThis section presents environmental setting for experiment."},{"metadata":{},"cell_type":"markdown","source":"## Python Packages"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n1. General Purpose\nThe following packages are called for accessing the filesystem and handling the each file.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nimport os, json, random\nfrom PIL import Image\n\n\n\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n2. Data Handling\nThe packages called as below help to handle the array, constructed with number, and tabular data.\nThese packages accelerates result derivation because, numpy supports broadcasting at calculation.\nAlso, pandas, the numpy dependency package, supports accelerated calculation.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nimport numpy as np \nimport pandas as pd \n\n\n\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n3. Machine / Deep Learning\nThis source code uses PyTorch for derivating the results.\nRefer that *PyTorch is one of the deep learning framework like TensorFlow, Keras, or MXNet.\n* https://pytorch.org\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nimport torch\nimport torch.nn as nn\nimport torchvision\nimport torchvision.transforms as transforms\nfrom torch.utils.data import Dataset, DataLoader\n\n\n\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n4. Device Setting\nWhen using the deep learning framework, GPU acceleration is highly useful for getting result faster.\nIn this source code, using GPU is the default option.\nHowever, when you turn off the 'Accelerator', as 'None' option, the CPU will be used.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nDEVICE = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Functions"},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\nFixing the random seed\nFor making the environment statically, fixing the random seed is needed.\nAlso, it is essential to reproduce the experimental results.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\ndef 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()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Global Variables\nSet the global variables for proceed overall source code."},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n1. Hyperparameters for training the deep learning model.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nBATCH = 16\nEPOCHS = 2\nLR = 0.01\n\n\n\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n# 2. For handling large size data. The original image is lager than 64 x 64.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nIM_SIZE = 64 \nNUM_CLASS = None # set in the below block\n\n\n\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n# 3. Set the path for loading the training and test data.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nTRAIN_DIR = '../input/herbarium-2021-fgvc8/train/'\nTEST_DIR = '../input/herbarium-2021-fgvc8/test/'","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"with open(TRAIN_DIR + 'metadata.json', \"r\", encoding=\"ISO-8859-1\") as file:\n    train = json.load(file)   ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n# 1. Parsing the image and annotations (labels) from the 'train' dictionary.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\ntrain_img = pd.DataFrame(train['images'])\ntrain_ann = pd.DataFrame(train['annotations']).drop(columns='image_id')\n\n\n\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n# 2. Merge the images and annotations as a dataframe.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\ntr_df = train_img.merge(train_ann, on='id')\n\n\n\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n# 3. Confirmation of the training dataset.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nprint(tr_df.shape)\ntr_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n1, Set number of the class using the training set.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nNUM_CLASS = tr_df['category_id'].max() - tr_df['category_id'].min() + 1\nNUM_CLASS\n\n\n\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n2. Split the input and target from the training set.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nX_Train, Y_Train = tr_df['file_name'].values, tr_df['category_id'].values\n\n\n\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n3. Define the dataset composer\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nTransform = transforms.Compose(\n    [transforms.ToTensor(),\n    transforms.Resize((IM_SIZE, IM_SIZE)),\n    transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))])\n\n\n\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n4. The class object for using dataset on training process.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nclass GetData(Dataset):\n    def __init__(self, Dir, FNames, Labels, Transform):\n        self.dir = Dir\n        self.fnames = FNames\n        self.transform = Transform\n        self.labels = Labels         \n        \n    def __len__(self):\n        return len(self.fnames)\n\n    def __getitem__(self, index):       \n        x = Image.open(os.path.join(self.dir, self.fnames[index]))\n    \n        if \"train\" in self.dir:             \n            return self.transform(x), self.labels[index]\n        elif \"test\" in self.dir:            \n            return self.transform(x), self.fnames[index]\n        \n\n\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n5. Define the training set via the class 'GetData' and trainloader via the 'DataLoader'.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\ntrainset = GetData(TRAIN_DIR, X_Train, Y_Train, Transform)\ntrainloader = DataLoader(trainset, batch_size=BATCH, shuffle=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model"},{"metadata":{},"cell_type":"markdown","source":"## Model Preparing"},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n1. Download the pre-defined model, well known as ResNet-18.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nmodel = torchvision.models.resnet18()\n\n\n\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n2. Set the final layer, as used as classifier, for using the dataset in this task.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\nmodel.fc = nn.Linear(512, NUM_CLASS, bias=True)\nmodel = model.to(DEVICE)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=LR)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model Training"},{"metadata":{"trusted":true},"cell_type":"code","source":"for epoch in range(EPOCHS):\n    tr_loss = 0.0\n\n    model = model.train()\n\n    for i, (images, labels) in enumerate(trainloader):        \n        images = images.to(DEVICE)\n        labels = labels.to(DEVICE)       \n        logits = model(images.float())       \n        loss = criterion(logits, labels)\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        tr_loss += loss.detach().item()\n    \n    model.eval()\n    print('Epoch: %d | Loss: %.4f'%(epoch, tr_loss / i))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Test Procedure"},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n1. Preparing the test set.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\n%%time\nwith open(TEST_DIR + 'metadata.json', \"r\", encoding=\"ISO-8859-1\") as file:\n    test = json.load(file)\n\ntest_df = pd.DataFrame(test['images'])\nprint(len(test_df))\ntest_df.head()\n\nX_Test = test_df['file_name'].values\n\ntestset = GetData(TEST_DIR, X_Test, None, Transform)\ntestloader = DataLoader(testset, batch_size=1, shuffle=False)\n\n\n\"\"\" -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-\n2. Inference the ID of the test set.\n-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*- \"\"\"\n%%time\n\ns_ls = []\n\nwith torch.no_grad():\n    model.eval()\n    for image, fname in testloader: \n        image = image.to(DEVICE)\n        \n        logits = model(image)        \n        ps = torch.exp(logits)        \n        _, top_class = ps.topk(1, dim=1)\n        \n        for pred in top_class:\n            s_ls.append([fname[0].split('/')[-1][:-4], pred.item()])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Make Submission"},{"metadata":{"trusted":true},"cell_type":"code","source":"sub = pd.DataFrame.from_records(s_ls, columns=['Id', 'Predicted'])\nsub.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub.to_csv(\"submission.csv\", index=False)","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}