diff --git a/frontend/index.html b/frontend/index.html index a088c7a..3fe7076 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,6 +2,15 @@ + + + diff --git a/frontend/src/components/about.vue b/frontend/src/components/about.vue index cd4d6db..b386cf2 100644 --- a/frontend/src/components/about.vue +++ b/frontend/src/components/about.vue @@ -14,12 +14,10 @@ The Moore Institute for Plastic Pollution Research - and Walter Yu from CALTRANS. There - have also been - many contributors - to the code base. + and Walter Yu from CALTRANS. + + Steven Hollingsworth + is the lead developer and contributor to the code base.

To get started, visit the Upload Tab or @@ -68,6 +66,8 @@ >open a Github Issue in our repository. + If you would like to provide more general feedback, please fill out + our feedback form here .

  diff --git a/frontend/src/views/about.vue b/frontend/src/views/about.vue index 4e1b46e..bb91d38 100644 --- a/frontend/src/views/about.vue +++ b/frontend/src/views/about.vue @@ -14,12 +14,10 @@ The Moore Institute for Plastic Pollution Research - and Walter Yu from CALTRANS. There - have also been - - many contributors - - to the code base. + and Walter Yu from CALTRANS. + + Steven Hollingsworth + is the lead developer and contributor to the code base.

To get started, visit the Upload Tab or @@ -68,6 +66,8 @@ open a Github Issue in our repository. + If you would like to provide more general feedback, please fill out + our feedback form here .

diff --git a/notebooks/Evaluation_Accuracy.ipynb b/notebooks/Evaluation_Accuracy.ipynb new file mode 100644 index 0000000..4d78b3b --- /dev/null +++ b/notebooks/Evaluation_Accuracy.ipynb @@ -0,0 +1,1354 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# This notebook: Build evaluation method\n", + "* Aim at >.90 accuracy\n", + "\n", + "Currently it is tested with yolov5 prediction results. But it is compatible for all prediction outputs as long as they are in the form of `.pandas().xywh`. (see section `1.3` for examples)\n", + "\n", + "Using `Google Colab` to view this notebook is highly recommended." + ], + "metadata": { + "id": "qN8V989HzHDT" + } + }, + { + "cell_type": "markdown", + "source": [ + "### Questions:\n", + "* Want the **big TACO**? i.e. the **unofficial TACO** that contains 5,000+ images. It's much larger a dataset, but the label quality of the big TACO might be poor. \n", + "\n", + "* **Reduce target classes**? There are 60 categories and 28 super-categories. Currently we predict 60 classes, which might be too many considering that we only have less than 1500 training images. Should we use the 28 super-categories as classes to be predicted? Or one step further, 5~10 classes of plastic, metal, glass, etc. based on the material of trash objects.\n", + "\n", + "* Better **Train/Test split**? Currently I do a non-stratified 1300/100/100 split for train/val/test. This is not the best choice. Classes(categories)'s distribution in training and testing set will be different which might be a problem. Inputs are greatly welcomed!" + ], + "metadata": { + "id": "mS4ry1DRFSes" + } + }, + { + "cell_type": "code", + "source": [ + "mount_drive = True # set to true only if you have weights and images in your own google drive\n", + "reduced = True #True if using reduced classes (28 categories)\n", + "\n", + "\n", + "model_choice = 2 ## keys: 1: 'Yolo on original TACO', 2: 'Yolo on reduced TACO', 3: 'Yolo on reduced big TACO'" + ], + "metadata": { + "id": "R_Dc3-3xaTwr" + }, + "execution_count": 1, + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "id": "0D7J191IYwp8", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "a3ddbdc1-7c41-43ec-ca8e-16cd829d8579" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Sun Oct 23 14:17:50 2022 \n", + "+-----------------------------------------------------------------------------+\n", + "| NVIDIA-SMI 460.32.03 Driver Version: 460.32.03 CUDA Version: 11.2 |\n", + "|-------------------------------+----------------------+----------------------+\n", + "| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |\n", + "| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |\n", + "| | | MIG M. |\n", + "|===============================+======================+======================|\n", + "| 0 A100-SXM4-40GB Off | 00000000:00:04.0 Off | 0 |\n", + "| N/A 29C P0 43W / 400W | 0MiB / 40536MiB | 0% Default |\n", + "| | | Disabled |\n", + "+-------------------------------+----------------------+----------------------+\n", + " \n", + "+-----------------------------------------------------------------------------+\n", + "| Processes: |\n", + "| GPU GI CI PID Type Process name GPU Memory |\n", + "| ID ID Usage |\n", + "|=============================================================================|\n", + "| No running processes found |\n", + "+-----------------------------------------------------------------------------+\n" + ] + } + ], + "source": [ + "!nvidia-smi" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# 0. Prep works, install yolov5, download and partition datasets" + ], + "metadata": { + "id": "_9jgRJYlL_-H" + } + }, + { + "cell_type": "code", + "source": [ + "%cd /content/" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ucAYkRiCIxFW", + "outputId": "27839e27-1d53-4653-d151-3832b18e10be" + }, + "execution_count": 3, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "/content\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "%%bash\n", + "#rm -rf /content/*\n", + "find . \\! -name 'rotated2.zip' -delete" + ], + "metadata": { + "id": "cJDeErmxIuY8" + }, + "execution_count": 4, + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "id": "2TTOdqkAk_Ad" + }, + "outputs": [], + "source": [ + "%%capture\n", + "!git clone https://github.com/ultralytics/yolov5 \n", + "%cd yolov5\n", + "!pip install -r requirements.txt #wandb\n", + "%cd .." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "FBHHieZsCbGS" + }, + "outputs": [], + "source": [ + "%%capture\n", + "!wget https://raw.githubusercontent.com/scikit-multilearn/scikit-multilearn/master/skmultilearn/model_selection/iterative_stratification.py\n", + "from iterative_stratification import *\n", + "from collections import Counter\n", + "\n", + "from PIL import Image, ExifTags\n", + "from pycocotools.coco import COCO\n", + "from matplotlib.patches import Polygon, Rectangle\n", + "from matplotlib.collections import PatchCollection\n", + "import colorsys\n", + "import random\n", + "import pylab\n", + "\n", + "import json\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns; sns.set()\n", + "from tqdm import tqdm\n", + "\n", + "import shutil\n", + "import os\n", + "import re\n", + "\n", + "import torch\n", + "from torch.utils.data import Dataset, DataLoader\n", + "from torchvision import transforms, utils" + ] + }, + { + "cell_type": "code", + "source": [ + "if not mount_drive:\n", + " # gdown a gdrive file too frequently triggers google's control and makes the file un-gdown-able\n", + " # You can download them manually by adding this prefix: https://drive.google.com/file/d/ to the below codes after !gdown\n", + "\n", + " !gdown 106n90SCtJz3GsNqJbP0ZGUZaZkDKOSLL # download best trained yolov5x6 weights at https://drive.google.com/file/d/106n90SCtJz3GsNqJbP0ZGUZaZkDKOSLL\n", + " !gdown 1X3O2v3GIPveq3ylWF6o1qHI5uzbN1vWA # download organized TACO images (TACO itself, 1500 images) at https://drive.google.com/file/d/1X3O2v3GIPveq3ylWF6o1qHI5uzbN1vWA\n", + "\n", + "if mount_drive:\n", + " from google.colab import drive\n", + " drive.mount('/gdrive')\n", + " if model_choice ==1:\n", + " %cp /gdrive/MyDrive/trash_ai_trained_weights/yolov5x6_best_weights_og.pt /content/yolov5x6_best_weights.pt #get trained weights\n", + " elif model_choice ==2:\n", + " %cp /gdrive/MyDrive/yolo_og_reduced/exp/weights/best.pt /content/yolov5x6_best_weights.pt\n", + " elif model_choice ==3:\n", + " %cp /gdrive/MyDrive/best_yolov5_bigTACO/exp/weights/best.pt /content/yolov5x6_best_weights.pt \n", + "\n", + " \n", + " if not os.path.isfile('/content/rotated2.zip'):\n", + " if not reduced:\n", + " %cp /gdrive/MyDrive/rotated2_og.zip /content/rotated2.zip #get images\n", + " else:\n", + " %cp /gdrive/MyDrive/rotated2_reduced.zip /content/rotated2.zip #get images\n", + "\n", + " \n" + ], + "metadata": { + "id": "M0nSxY0wdrr2", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "c78d1453-2583-4fd6-871e-4afe77b4f08f" + }, + "execution_count": 7, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Mounted at /gdrive\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "!unzip -qq /content/rotated2.zip \n", + "%mv /content/content/* /content/" + ], + "metadata": { + "id": "Pfvddv2pS_ZX" + }, + "execution_count": 8, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "%%capture\n", + "!wget https://raw.githubusercontent.com/pedropro/TACO/master/data/annotations.json\n", + "!wget https://raw.githubusercontent.com/pedropro/TACO/master/data/annotations_unofficial.json" + ], + "metadata": { + "id": "nbwKD15fKpfa" + }, + "execution_count": 9, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "%pwd" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 36 + }, + "id": "V4v7BSn2dT2R", + "outputId": "0b5b01cb-0c34-4319-d8ca-1a6af31d1a2a" + }, + "execution_count": 10, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "'/content'" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + } + }, + "metadata": {}, + "execution_count": 10 + } + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "CPFCzX31IGBq", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "9fb1e013-357d-484f-9758-b20bee9d208b" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Number of all images:\n", + "1500\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + " 10%|▉ | 149/1500 [00:01<00:07, 182.50it/s]" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "image id number 101 skipped due to no label found\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "100%|██████████| 1500/1500 [00:06<00:00, 239.88it/s]\n" + ] + } + ], + "source": [ + "nr_imgs=None\n", + "for root, dirnames, filenames in os.walk('./yoloTACO/labels/'):\n", + " nr_imgs = len(filenames)\n", + " break\n", + "print('Number of all images:\\n'+str(nr_imgs))\n", + "\n", + "if reduced: \n", + " nr_class = 28\n", + "else: nr_class = 60\n", + "\n", + "xy = {}\n", + "for i in tqdm([i for i in range(nr_imgs)]):\n", + " try: \n", + " X = pd.read_csv('./yoloTACO/labels/'+str(i)+'.txt',header = None,delimiter = ' ')\n", + " x = pd.DataFrame([Counter(X[0].tolist())],columns=[*range(nr_class)]).fillna(0).astype(int).iloc[[0]].squeeze().tolist()\n", + " y=i\n", + " xy[y]=x\n", + " except: \n", + " print('image id number '+str(i)+' skipped due to no label found')\n", + " pass\n", + "X = pd.DataFrame.from_dict(xy, orient='index')\n", + "\n", + "y = xy.keys()\n", + "one_hot_y = pd.get_dummies(y)\n", + "\n", + "## train test split\n", + "'''\n", + "train: images/train\n", + "val: images/val\n", + "test: images/test\n", + "'''\n", + "\n", + "np.random.seed(5) # sk-multilearn is based on sk, sk uses np random state. \n", + " # so, setting np random seed will clamp the results of iterative_train_test_split\n", + "\n", + "X_train, y_train, X_temp, y_temp = iterative_train_test_split(X.values, one_hot_y.values, test_size = 0.5)\n", + "X_train1, y_train1, X_val, y_val = iterative_train_test_split(X_temp, y_temp, test_size = 0.5)\n", + "X_val, y_val,X_test,y_test = iterative_train_test_split(X_val, y_val, test_size = 0.5)\n", + "\n", + "# ISSUE: in this environment, any test_size!= 0.5 results in nothing in testing set. \n", + "# therefore train/val/test split is roughly .75, .125, .125\n", + "\n", + "y_train = np.vstack((y_train,y_train1))\n", + "train_ids,val_ids,test_ids = pd.DataFrame(y_train,columns = y).idxmax(axis=1).tolist(),\\\n", + " pd.DataFrame(y_val,columns = y).idxmax(axis=1).tolist(),\\\n", + " pd.DataFrame(y_test,columns = y).idxmax(axis=1).tolist()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "id": "kwCWClsrSD4z" + }, + "outputs": [], + "source": [ + "%%capture\n", + "\n", + "def move_helper(ids, desti):\n", + " for id in ids:\n", + " img_name = os.path.join( './yoloTACO/images', str(id)+'.jpg' )\n", + " lbl_name = os.path.join( './yoloTACO/labels', str(id)+'.txt' )\n", + " print(img_name)\n", + " if os.path.isfile(img_name):\n", + " shutil.copy( img_name, './yoloTACO/images/'+desti)\n", + " shutil.copy( lbl_name, './yoloTACO/labels/'+desti)\n", + " else :\n", + " print('file does not exist', img_name)\n", + "\n", + "!mkdir yoloTACO/images/train\n", + "!mkdir yoloTACO/images/val\n", + "!mkdir yoloTACO/images/test\n", + "!mkdir yoloTACO/labels/train\n", + "!mkdir yoloTACO/labels/val\n", + "!mkdir yoloTACO/labels/test\n", + "move_helper(test_ids,'test')\n", + "move_helper(train_ids,'train')\n", + "move_helper(val_ids,'val')" + ] + }, + { + "cell_type": "code", + "source": [ + "%%bash\n", + "mkdir ./datasets\n", + "mv yoloTACO datasets/" + ], + "metadata": { + "id": "gHyjxWAW7DF0" + }, + "execution_count": 13, + "outputs": [] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "S96FWSElHY9d" + }, + "execution_count": 13, + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "id": "evH7jgs5Dnj7", + "cellView": "form" + }, + "outputs": [], + "source": [ + "#@title yml\n", + "\n", + "if reduced == True:\n", + "\n", + " with open('/content/yolov5/data/yoloTACO.yaml', mode='w') as fp:\n", + " lines = '''path: ../datasets/yoloTACO # dataset root dir\n", + "train: images/train # train images \n", + "val: images/val # val images \n", + "test: images/test # test images (optional)\n", + "\n", + "# Classes\n", + "names:\n", + " 0: Aluminium foil\n", + " 1: Battery\n", + " 2: Blister pack\n", + " 3: Bottle\n", + " 4: Bottle cap\n", + " 5: Broken glass\n", + " 6: Can\n", + " 7: Carton\n", + " 8: Cup\n", + " 9: Food waste\n", + " 10: Glass jar\n", + " 11: Lid\n", + " 12: Other plastic\n", + " 13: Paper\n", + " 14: Paper bag\n", + " 15: Plastic bag & wrapper\n", + " 16: Plastic container\n", + " 17: Plastic glooves\n", + " 18: Plastic utensils\n", + " 19: Pop tab\n", + " 20: Rope & strings\n", + " 21: Scrap metal\n", + " 22: Shoe\n", + " 23: Squeezable tube\n", + " 24: Straw\n", + " 25: Styrofoam piece\n", + " 26: Unlabeled litter\n", + " 27: Cigarette'''\n", + " fp.writelines(lines)\n", + "\n", + "else: \n", + " with open('/content/yolov5/data/yoloTACO.yaml', mode='w') as fp:\n", + " lines = '''path: ../datasets/yoloTACO # dataset root dir\n", + "train: images/train # train images (relative to 'path') 128 images\n", + "val: images/val # val images (relative to 'path') 128 images\n", + "test: images/test # test images (optional)\n", + "\n", + "# Classes\n", + "names:\n", + " 0: Aluminium foil\n", + " 1: Battery\n", + " 2: Aluminium blister pack\n", + " 3: Carded blister pack\n", + " 4: Other plastic bottle\n", + " 5: Clear plastic bottle\n", + " 6: Glass bottle\n", + " 7: Plastic bottle cap\n", + " 8: Metal bottle cap\n", + " 9: Broken glass\n", + " 10: Food Can\n", + " 11: Aerosol\n", + " 12: Drink can\n", + " 13: Toilet tube\n", + " 14: Other carton\n", + " 15: Egg carton\n", + " 16: Drink carton\n", + " 17: Corrugated carton\n", + " 18: Meal carton\n", + " 19: Pizza box\n", + " 20: Paper cup\n", + " 21: Disposable plastic cup\n", + " 22: Foam cup\n", + " 23: Glass cup\n", + " 24: Other plastic cup\n", + " 25: Food waste\n", + " 26: Glass jar\n", + " 27: Plastic lid\n", + " 28: Metal lid\n", + " 29: Other plastic\n", + " 30: Magazine paper\n", + " 31: Tissues\n", + " 32: Wrapping paper\n", + " 33: Normal paper\n", + " 34: Paper bag\n", + " 35: Plastified paper bag\n", + " 36: Plastic film\n", + " 37: Six pack rings\n", + " 38: Garbage bag\n", + " 39: Other plastic wrapper\n", + " 40: Single-use carrier bag\n", + " 41: Polypropylene bag\n", + " 42: Crisp packet\n", + " 43: Spread tub\n", + " 44: Tupperware\n", + " 45: Disposable food container\n", + " 46: Foam food container\n", + " 47: Other plastic container\n", + " 48: Plastic glooves\n", + " 49: Plastic utensils\n", + " 50: Pop tab\n", + " 51: Rope & strings\n", + " 52: Scrap metal\n", + " 53: Shoe\n", + " 54: Squeezable tube\n", + " 55: Plastic straw\n", + " 56: Paper straw\n", + " 57: Styrofoam piece\n", + " 58: Unlabeled litter\n", + " 59: Cigarette'''\n", + " fp.writelines(lines)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "id": "CdMrwEgnB9C4", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "7889b2bc-7032-4700-e827-99db1d1e3750" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "/content/yolov5\n", + "benchmarks.py\t detect.py models\t setup.cfg val.py\n", + "classify\t export.py README.md\t train.py\n", + "CONTRIBUTING.md hubconf.py requirements.txt tutorial.ipynb\n", + "data\t\t LICENSE segment\t utils\n" + ] + } + ], + "source": [ + "%cd ./yolov5\n", + "!ls" + ] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "67Xa-feZH9q5" + }, + "execution_count": 15, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# 1. Evaluate with our best trained weights so far" + ], + "metadata": { + "id": "C37qgWyEMLpj" + } + }, + { + "cell_type": "markdown", + "source": [ + "## 1.1 eval with yolo default scripts" + ], + "metadata": { + "id": "fHmO_QRlN4bQ" + } + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "id": "DoLh0BGlXQMC" + }, + "outputs": [], + "source": [ + "#!python val.py --data yoloTACO.yaml --task test --weights /content/yolov5x6_best_weights.pt\n", + "#!python detect.py --weights /content/yolov5x6_best_weights.pt --source /content/datasets/yoloTACO/images/test" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Note that the default `MAP` is not the \"wanted\" metrics for our project, as our sponsor specifically requested a metrics under the name \"accuracy\" and a target score of >.90." + ], + "metadata": { + "id": "4of5Qufu1Pd_" + } + }, + { + "cell_type": "markdown", + "source": [ + "## 1.2 detect with torch framework manually\n", + "\n", + "This is a necessary step to use our accuracy evaluator." + ], + "metadata": { + "id": "5Ay3MOsDN90j" + } + }, + { + "cell_type": "code", + "source": [ + "model = torch.hub.load('ultralytics/yolov5', 'custom', path='/content/yolov5x6_best_weights.pt',force_reload=True) # load our local model" + ], + "metadata": { + "id": "30QWyk7yiMsk", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "bc4c3b4d-638a-4663-c0b6-40e8ea059fb8" + }, + "execution_count": 17, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.7/dist-packages/torch/hub.py:267: UserWarning: You are about to download and run code from an untrusted repository. In a future release, this won't be allowed. To add the repository to your trusted list, change the command to {calling_fn}(..., trust_repo=False) and a command prompt will appear asking for an explicit confirmation of trust, or load(..., trust_repo=True), which will assume that the prompt is to be answered with 'yes'. You can also use load(..., trust_repo='check') which will only prompt for confirmation if the repo is not already trusted. This will eventually be the default behaviour\n", + " \"You are about to download and run code from an untrusted repository. In a future release, this won't \"\n", + "Downloading: \"https://github.com/ultralytics/yolov5/zipball/master\" to /root/.cache/torch/hub/master.zip\n", + "YOLOv5 🚀 2022-10-23 Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n", + "\n", + "Fusing layers... \n", + "Model summary: 416 layers, 140230396 parameters, 0 gradients, 208.5 GFLOPs\n", + "Adding AutoShape... \n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# Load test imgs\n", + "test_dir = '/content/datasets/yoloTACO/images/test/'\n", + "test_list = test_ids # [i[2] for i in os.walk(test_dir)][0] # or alternatively read from files # test_list = [re.findall(r'\\d+',i)[0] for i in test_list]\n", + "\n", + "test_read_img_list = [Image.open(test_dir+str(i)+'.jpg') for i in test_list] # alternatively use cv2: cv2.imread('target_path')[..., ::-1] # OpenCV image (BGR to RGB)" + ], + "metadata": { + "id": "GUjCnveZk2sf" + }, + "execution_count": 18, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Inference\n", + "results = model(test_read_img_list) # batch of images\n", + "pred_pd = results.pandas().xywh\n", + "\n", + "for j,i in enumerate(pred_pd):\n", + " i=i.assign(image_id=[test_list[j]]*i.shape[0])\n", + " pred_pd[j]=i" + ], + "metadata": { + "id": "RKr_CupeiMvD" + }, + "execution_count": 19, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# clear GPU mem\n", + "def free_memory(to_delete: list, debug=False):\n", + " import gc\n", + " import inspect\n", + " calling_namespace = inspect.currentframe().f_back\n", + " if debug:\n", + " print('Before:')\n", + " torch.get_less_used_gpu(debug=True)\n", + "\n", + " for _var in to_delete:\n", + " calling_namespace.f_locals.pop(_var, None)\n", + " gc.collect()\n", + " torch.cuda.empty_cache()\n", + " if debug:\n", + " print('After:')\n", + " torch.get_less_used_gpu(debug=True)\n", + "\n", + "free_memory([model])" + ], + "metadata": { + "id": "HvwZN3vzHB5u" + }, + "execution_count": 20, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "%%capture\n", + "!wget -O data/annotations.json https://raw.githubusercontent.com/pedropro/TACO/master/data/annotations.json\n", + "anno_path = './data/annotations.json'\n", + "annos = COCO(annotation_file=anno_path)\n", + "with open(anno_path, 'r') as f:\n", + " annos_json = json.loads(f.read())\n", + "no_to_clname = {i:j for i,j in enumerate([i['name'] for i in annos_json['categories']])}\n" + ], + "metadata": { + "id": "QRj9_Dk_iMxG" + }, + "execution_count": 21, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "truth_pd = []\n", + "for i in test_list:\n", + " img_info = annos.loadImgs(i)[0] \n", + " img_height = img_info['height']\n", + " img_width = img_info['width']\n", + "\n", + " cache = pd.read_csv('/content/datasets/yoloTACO/labels/'+str(i)+'.txt',header=None,\n", + " names = ['class','xcenter','ycenter','width','height'],delimiter=' ')\n", + " cache[\"xcenter\"] = img_width * cache[\"xcenter\"]\n", + " cache[\"ycenter\"] = img_height * cache[\"ycenter\"]\n", + " cache[\"width\"] = img_width * cache[\"width\"]\n", + " cache[\"height\"] = img_height * cache[\"height\"]\n", + "\n", + " cache = cache.assign(confidence = [1]*cache.shape[0])\n", + " cache = cache.reindex(columns=['xcenter','ycenter','width','height','confidence','class'])\n", + " cache = cache.assign(image_id = [i]*cache.shape[0])\n", + "\n", + " # cache = cache.assign(img_width = [width]*cache.shape[0])\n", + " # cache = cache.assign(img_height = [height]*cache.shape[0])\n", + "\n", + " truth_pd.append(cache)" + ], + "metadata": { + "id": "o6dfoDEzdV-1" + }, + "execution_count": 22, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## 1.3 example prediction and truth" + ], + "metadata": { + "id": "QNrQCtxcBiw0" + } + }, + { + "cell_type": "code", + "source": [ + "pred_pd[:2] \n", + "# predictions for first two images\n", + "# there will be a list of two dataframes" + ], + "metadata": { + "id": "WuvboCQRLUvU", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "b6b7cefd-d665-456a-e4f8-42c525d94f12" + }, + "execution_count": 23, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "[Empty DataFrame\n", + " Columns: [xcenter, ycenter, width, height, confidence, class, name, image_id]\n", + " Index: [],\n", + " xcenter ycenter width height confidence class \\\n", + " 0 869.249634 673.73645 92.600647 255.507812 0.751637 16 \n", + " \n", + " name image_id \n", + " 0 Plastic container 8 ]" + ] + }, + "metadata": {}, + "execution_count": 23 + } + ] + }, + { + "cell_type": "code", + "source": [ + "pred_pd[3]" + ], + "metadata": { + "id": "WFbRwGhdR0o5", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 49 + }, + "outputId": "f7d84397-a973-4b0c-e730-69a6fb6e4b93" + }, + "execution_count": 24, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "Empty DataFrame\n", + "Columns: [xcenter, ycenter, width, height, confidence, class, name, image_id]\n", + "Index: []" + ], + "text/html": [ + "\n", + "
\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
xcenterycenterwidthheightconfidenceclassnameimage_id
\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + " \n", + "
\n", + "
\n", + " " + ] + }, + "metadata": {}, + "execution_count": 24 + } + ] + }, + { + "cell_type": "code", + "source": [ + "truth_pd[3]" + ], + "metadata": { + "id": "qwJA0H4QrHYC", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 81 + }, + "outputId": "f987f1f4-8a1a-4d76-b499-9a8778ad1aaf" + }, + "execution_count": 25, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " xcenter ycenter width height confidence class image_id\n", + "0 775.499498 934.99968 713.000467 1854.000768 1 3 14" + ], + "text/html": [ + "\n", + "
\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
xcenterycenterwidthheightconfidenceclassimage_id
0775.499498934.99968713.0004671854.0007681314
\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + " \n", + "
\n", + "
\n", + " " + ] + }, + "metadata": {}, + "execution_count": 25 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# 2. Accuracy evaluation\n", + "\n", + "Usually, `Object Detection` tasks are measured by mAP, which is also the default metrics YoloV5 uses. You can also check Yolo's Precision and Recall metrics. \n", + "\n", + "However, if an `accuracy` metric is specifically needed, the following codes will do it.\n", + "\n", + "For each object with a truth bounding box in each image, if there is a prediction bounding box that has an IOU > threshold with that truth bounding box, it is counted as `detected`.\n", + "\n", + "For overall model `accuracy`, we count total number of `detected` of all images over total number of `predictions` of all images." + ], + "metadata": { + "id": "TyiyfCEAODQI" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Definition of `Accuracy`:**\n", + "\n", + "$$\\text{Accuracy} = \\frac{\\text{Number of correct predictions}}{\\text{Total number of predictions}}$$\n", + "\n", + "A comparison of `Accuracy, Precision, Recall`:\n", + "$$\n", + "\\text{Accuracy} = \\frac{TP+TN}{TP+TN+FP+FN}\n", + "$$\n", + "\n", + "$$\\text{Precision} = \\frac{TP}{TP+FP}\n", + "$$\n", + "\n", + "$$\\text{Recall} = \\frac{TP}{TP+FN}\n", + "$$\n", + "CC: https://developers.google.com/machine-learning/crash-course/classification/accuracy" + ], + "metadata": { + "id": "Ff6hBppj1SjL" + } + }, + { + "cell_type": "code", + "source": [ + "def bbox_iou(box1, box2, eps=1e-7):\n", + " \"\"\"\n", + " CITATION: adapted from YOLOV5 utils, author, cr: ultralytics\n", + " Returns Intersection over Union (IoU) of box1(1,4) to box2(n,4)\n", + " Get the coordinates of bounding boxes, transform from xywh to xyxy\n", + " \"\"\"\n", + " (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, 1), box2.chunk(4, 1)\n", + " w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2\n", + " b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_\n", + " b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_\n", + "\n", + " inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \\\n", + " (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0)\n", + " union = w1 * h1 + w2 * h2 - inter + eps\n", + " return inter / union # return IoU\n", + " \n", + "def each_pic(pred_df,truth_df,iou_th,must_class):\n", + " \"\"\"\n", + " returns number of objects (truth) and number of detection\n", + " e.g. if there are 5 pieces of trash in an image and we predicted 2, it will return 5,2\n", + " \"\"\"\n", + " pred_df_ = pred_df.assign(matched=[0]*pred_df.shape[0])\n", + " nr_preds = pred_df.shape[0]\n", + " nr_dets = 0\n", + " for i in truth_df.iterrows():\n", + " tbox_tensor = torch.tensor([i[1].tolist()[:4]])\n", + " tlabel = i[1].tolist()[5]\n", + " \n", + " row_counter=0\n", + " for j in pred_df_.iterrows():\n", + " pbox_tensor = torch.tensor([j[1].tolist()[:4]])\n", + " plabel = j[1].tolist()[5]\n", + " matched = j[1].tolist()[-1]\n", + " if must_class==True: # if the detection has to assign a correct class name. \n", + " if bbox_iou(tbox_tensor,pbox_tensor)>iou_th and matched==0 and tlabel==plabel:\n", + " nr_dets+=1\n", + " pred_df_.iat[row_counter,-1]=1 # mark matched bbox, so one prediction bbox wont be counted as \"detected\" for two different objects\n", + " continue\n", + " else: \n", + " if bbox_iou(tbox_tensor,pbox_tensor)>iou_th and matched==0:\n", + " nr_dets+=1\n", + " pred_df_.iat[row_counter,-1]=1\n", + " continue\n", + " row_counter+=1\n", + " return nr_preds,nr_dets\n", + "\n", + "def get_accuracy(pred,truth,iou_th=0.5,must_class=False):\n", + " \"\"\"\n", + " pred: prediction list of dataframe\n", + " truth: truth list of dataframe\n", + " iou_th IOU threshold you define suitable\n", + " must_class: controls whether the category need to be predicted correctly\n", + " when set to false, only consider whether predicted bbox bounded objects correctly, \n", + " without considering if the correct class is identified\n", + " \"\"\"\n", + " preds,dets=0,0\n", + " for i in tqdm(range(len(truth))):\n", + " p,d=each_pic(pred_pd[i],truth_pd[i],iou_th,must_class)\n", + " preds+=p\n", + " dets+=d\n", + " return np.round(dets/preds,6)" + ], + "metadata": { + "id": "LkQgO9T5OHzs" + }, + "execution_count": 26, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "**Accuracy**" + ], + "metadata": { + "id": "t1nk9VlW3KZT" + } + }, + { + "cell_type": "code", + "source": [ + "accuracy = get_accuracy(pred_pd,truth_pd,iou_th=0.5,must_class=True)\n", + "print('\\nOur trained model has an accuracy of: '+str(accuracy*100)+'%')" + ], + "metadata": { + "id": "p8E9EsAMOH1d", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "f4dd210c-1d73-4db9-9c9f-94df15053601" + }, + "execution_count": 27, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "100%|██████████| 194/194 [00:00<00:00, 385.69it/s]" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n", + "Our trained model has an accuracy of: 82.6923%\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "**Box-Accuracy**\n", + "\n", + "Some detection tasks care only about \"having a bounding box over the target object,\" they do not care about if the model then label the object with a correct class. If you want such accuracy, it can be obtained by setting `must_class` to `False`. \n", + "\n", + "Below is an example:" + ], + "metadata": { + "id": "fZWitSXb3EHh" + } + }, + { + "cell_type": "code", + "source": [ + "accuracy = get_accuracy(pred_pd,truth_pd,iou_th=0.5,must_class=False)\n", + "print('\\nOur trained model has an accuracy of: '+str(accuracy*100)+'%')" + ], + "metadata": { + "id": "28BGyq9g3Bwc", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "11c6e9c4-f652-470f-8959-abba4626e830" + }, + "execution_count": 28, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "100%|██████████| 194/194 [00:00<00:00, 430.77it/s]" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n", + "Our trained model has an accuracy of: 92.3077%\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "\n" + ] + } + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "collapsed_sections": [], + "provenance": [] + }, + "gpuClass": "premium", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/notebooks/stratified_splitter.ipynb b/notebooks/stratified_splitter.ipynb new file mode 100644 index 0000000..fea141c --- /dev/null +++ b/notebooks/stratified_splitter.ipynb @@ -0,0 +1,368 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "RJQb7ylX2vHr" + }, + "outputs": [], + "source": [ + "# stratified_splitter" + ] + }, + { + "cell_type": "code", + "source": [ + "mount_drive=True\n", + "reduced=False" + ], + "metadata": { + "id": "eLwlGJnd03WG" + }, + "execution_count": 2, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "%%bash\n", + "find . \\! -name 'rotated2.zip' -delete" + ], + "metadata": { + "id": "BOatsR0Ayvf9" + }, + "execution_count": 3, + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "id": "FBHHieZsCbGS" + }, + "outputs": [], + "source": [ + "from PIL import Image, ExifTags\n", + "from pycocotools.coco import COCO\n", + "from matplotlib.patches import Polygon, Rectangle\n", + "from matplotlib.collections import PatchCollection\n", + "import colorsys\n", + "import random\n", + "import pylab\n", + "from collections import Counter\n", + "\n", + "\n", + "import json\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns; sns.set()\n", + "from tqdm import tqdm\n", + "\n", + "import shutil\n", + "import os\n", + "\n", + "import torch\n", + "from torch.utils.data import Dataset, DataLoader\n", + "from torchvision import transforms, utils" + ] + }, + { + "cell_type": "code", + "source": [ + "%%capture\n", + "!wget https://raw.githubusercontent.com/scikit-multilearn/scikit-multilearn/master/skmultilearn/model_selection/iterative_stratification.py\n", + "from iterative_stratification import *" + ], + "metadata": { + "id": "9a-vq9oV09zD" + }, + "execution_count": 5, + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "hL6YKD-F6UG3", + "outputId": "c0cea04d-dc0d-48bf-cdd6-f64939b27ac9" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Drive already mounted at /gdrive; to attempt to forcibly remount, call drive.mount(\"/gdrive\", force_remount=True).\n" + ] + } + ], + "source": [ + "if not mount_drive:\n", + " !gdown 1X3O2v3GIPveq3ylWF6o1qHI5uzbN1vWA # download organized TACO images (TACO itself, 1500 images, without unofficial images)\n", + "\n", + "if mount_drive:\n", + " from google.colab import drive\n", + " drive.mount('/gdrive')\n", + " if not os.path.isfile('/content/rotated2.zip'):\n", + " %cp /gdrive/MyDrive/rotated2_og.zip /content/rotated2.zip" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "UMKb-KDK3kta" + }, + "outputs": [], + "source": [ + "!unzip -qq rotated2.zip\n", + "%mv /content/content/* /content" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "fzhrp4RiHKiW", + "outputId": "260ad9c8-304b-4716-87e0-8e1883615f8f" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "/content\n" + ] + } + ], + "source": [ + "!pwd" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "CPFCzX31IGBq", + "outputId": "8d1df5b7-b028-449e-bfb2-e693cadf952c" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Number of all images:\n", + "1500\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + " 8%|▊ | 120/1500 [00:00<00:07, 190.93it/s]" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "image id number 101 skipped due to no label found\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "100%|██████████| 1500/1500 [00:08<00:00, 171.55it/s]\n" + ] + } + ], + "source": [ + "nr_imgs=None\n", + "for root, dirnames, filenames in os.walk('./yoloTACO/labels/'):\n", + " nr_imgs = len(filenames)\n", + " break\n", + "print('Number of all images:\\n'+str(nr_imgs))\n", + "\n", + "if reduced: nr_class = 28\n", + "else: nr_class = 60\n", + "\n", + "xy = {}\n", + "for i in tqdm([i for i in range(nr_imgs)]):\n", + " try: \n", + " X = pd.read_csv('./yoloTACO/labels/'+str(i)+'.txt',header = None,delimiter = ' ')\n", + " x = pd.DataFrame([Counter(X[0].tolist())],columns=[*range(nr_class)]).fillna(0).astype(int).iloc[[0]].squeeze().tolist()\n", + " y=i\n", + " xy[y]=x\n", + " except: \n", + " print('image id number '+str(i)+' skipped due to no label found')\n", + " pass\n", + "X = pd.DataFrame.from_dict(xy, orient='index')\n", + "\n", + "y = xy.keys()\n", + "one_hot_y = pd.get_dummies(y)\n", + "\n", + "## train test split\n", + "'''\n", + "train: images/train\n", + "val: images/val\n", + "test: images/test\n", + "'''\n", + "\n", + "np.random.seed(5) # sk-multilearn is based on sk, sk uses np random state. \n", + " # so, setting np random seed will clamp the results of iterative_train_test_split\n", + "\n", + "X_train, y_train, X_temp, y_temp = iterative_train_test_split(X.values, one_hot_y.values, test_size = 0.5)\n", + "X_train1, y_train1, X_val, y_val = iterative_train_test_split(X_temp, y_temp, test_size = 0.5)\n", + "X_val, y_val,X_test,y_test = iterative_train_test_split(X_val, y_val, test_size = 0.5)\n", + "\n", + "# ISSUE: in this environment, any test_size!= 0.5 results in nothing in testing set. \n", + "# therefore train/val/test split is roughly .75, .125, .125\n", + "\n", + "y_train = np.vstack((y_train,y_train1))\n", + "train_ids,val_ids,test_ids = pd.DataFrame(y_train,columns = y).idxmax(axis=1).tolist(),\\\n", + " pd.DataFrame(y_val,columns = y).idxmax(axis=1).tolist(),\\\n", + " pd.DataFrame(y_test,columns = y).idxmax(axis=1).tolist()\n" + ] + }, + { + "cell_type": "code", + "source": [ + "# check no intersection\n", + "set(train_ids).intersection(set(val_ids)), set(train_ids).intersection(set(test_ids)), set(val_ids).intersection(set(test_ids)), " + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "DCGDYZ1DOF5H", + "outputId": "0b3bc29f-2f00-47f1-f3b1-6906f3635bc1" + }, + "execution_count": 10, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "(set(), set(), set())" + ] + }, + "metadata": {}, + "execution_count": 10 + } + ] + }, + { + "cell_type": "code", + "source": [ + "# check total number of img_ids\n", + "# should be 1499, recall that id 101 was skipped due to no label in it\n", + "len(set(train_ids).union(set(val_ids)).union(set(test_ids)))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "nyApvAiVOVDq", + "outputId": "13194727-bd0f-4638-972a-bc137d393305" + }, + "execution_count": 11, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "1499" + ] + }, + "metadata": {}, + "execution_count": 11 + } + ] + }, + { + "cell_type": "code", + "source": [ + "def list_add(list1, list2): return [sum(x) for x in zip(list1, list2)]\n", + "def vis(img_id_list):\n", + " vis=[0]*nr_class\n", + " for i in img_id_list:\n", + " X = pd.read_csv('./yoloTACO/labels/'+str(i)+'.txt',header = None,delimiter = ' ')\n", + " x_ = pd.DataFrame([Counter(X[0].tolist())],columns=[*range(nr_class)]).fillna(0).astype(int).iloc[[0]].squeeze().tolist()\n", + " vis=list_add(vis,x_)\n", + " return vis" + ], + "metadata": { + "id": "Rhwaw94mFR5L" + }, + "execution_count": 12, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "from matplotlib.pyplot import figure\n", + "figure(figsize=(12, 8), dpi=80)\n", + "\n", + "plt.bar([*range(nr_class)],vis(train_ids), width = 1, label = 'Train')\n", + "plt.bar([*range(nr_class)],vis(val_ids), width = 1, label = 'Val',alpha = 0.5)\n", + "plt.bar([*range(nr_class)],vis(test_ids), width = 1, label = 'Test',alpha = 0.5)\n", + "\n", + "plt.xticks([*range(nr_class)],rotation = 75)\n", + "plt.xlabel(\"Class_id\")\n", + "plt.ylabel(\"Number of occurrence\")\n", + "plt.title(\"Class distribution in Train/Val/Test sets\")\n", + "plt.legend()\n", + "plt.show()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 579 + }, + "id": "Y7nSVWT5Jo_-", + "outputId": "f8e89de7-019e-481b-f0ec-dbdbd619552e" + }, + "execution_count": 14, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAysAAAIyCAYAAADL+VW7AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAMTQAADE0B0s6tTgAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nOzdeVhWdeL//9d93wgKigvmhlPOmJBbikuEuaRp5PpNRHOyktTUSQszf6UlOmppqzVq6ZSZmS1qaloaWs7UZ8oty7aRxLHcl3Bnh5v7/P5wvMc7Ac+N3HDwfj6ui+viPud9znlxA8XLc97n2AzDMAQAAAAAFmMv7wAAAAAAUBjKCgAAAABLoqwAAAAAsCTKCgAAAABLoqwAAAAAsCTKCgAAAABLoqwAAAAAsCTKCgAAAABLoqwAuKqtWrVKnTt3Lu8YkqQJEyZo4sSJ7te9e/fW6tWrS/UYO3bsUFRUlAoKCiRJc+fO1Z///OdSPYYkHTlyRFFRUTp48GCp7/uCtWvXKjY21mf7L4kRI0bolVdeKdcMEydO1IQJE8o1AwCUlYDyDgAAV2L37t1asGCBvv76a2VmZqpmzZpq3bq1hg8frubNm5d3vGKtW7fO1Lht27bpvvvu07///W8FBBT/n+127dpp586dpRHPbe7cudq8ebPee+8997IGDRqU+nF+r1+/furXr1+Jtj1y5Ih69+7tfp2XlydJCgwMdC9bt26dGjRo4NV+Fy5cWKI8L730ks6ePauNGzdq5MiRSkhIuGTMoEGD1LRpU02bNs3r/RuGoS5duqhRo0b68ccf3cuys7NVpUoV2Ww2SVLfvn01ffp0r/fvzc9gSRX2cwYAlBUAFda2bdv0wAMPaNCgQXr//fcVHh6u9PR0bdy4UcnJyZYvK6UtPz9flSpVKu8YlvD7MjVhwgQFBATomWeeKXR8Xl6eR5EpbRs2bNDUqVMVGhqqZcuWXVJWdu3ape+//14zZswo0f6///572e12vfXWW+5isn//ft1+++36+OOP1bBhwyv9EgCgXHAZGIAKa8qUKYqNjdXkyZPVsGFD2Ww2hYaGKj4+Xo8++mih23zyySeKi4tT+/btFR0drdGjR3tcyvTzzz/rnnvuUbt27dS+fXvFxcXpl19+kSRt3bpVcXFxatu2raKjozV48GCdPXu2yHwLFy7Urbfeqnbt2unJJ59Ufn6+x/pu3bppxYoVkqRz587pkUceUXR0tNq0aaPY2FglJyfryJEjeuCBByRJ7du3V1RUlBYsWODefs6cORo+fLiioqL05ptvatu2bYqMjJTT6fQ41osvvqiYmBjdcsstevbZZ91ZDh06pMjISO3fv9899uJ9rF27Vn//+9/13XffKSoqSlFRUdqxY0eh261atUp9+vRRmzZt1KdPH49L3C6MX716tfr166eoqCgNGjRI//nPf4p8/35/Cd/EiRP1yCOPaPr06YqOjlaHDh308ssvF7l9cSZOnKjExERNnTpVN998sx588EFJUlJSkrp166aoqCj3++tyudzb3XvvvXrppZfcryMjI/X2229r8ODBioqKUt++fbVjxw6PY+3Zs0enT59W+/btddddd2nfvn3aunWrx5j33ntPbdu2VWRkpP72t78pNjZWUVFR6tKli2bMmKHs7Oxiv54NGzaoe/fu7qJSlC+++EIDBw5U+/btdfvtt2vJkiXudSX5Gfy99evXq3fv3mrTpo2io6M9Sllubq5mz56t7t27q3379hoyZIh27dolSUX+nBWVCYAfMQCgAvr111+NiIgI48svvyx23MqVK41OnTq5X3/xxRdGSkqK4XQ6jZMnTxqjRo0yBg0a5F5/1113GXPnzjXy8/ON/Px8Y9euXUZaWpphGIbRsWNH44MPPjBcLpeRm5trfPvtt0ZmZmahx127dq3Rrl0745tvvjHy8vKM999/32jWrJnx+OOPu8d07drVWL58uWEYhjF79mzjgQceMNLT0w2Xy2UcOnTI2LNnj2EYhrF161YjIiLCyM/P9zhG165djQ4dOhjffvut4XK5jKysrEvGzpkzx2jWrJnx0ksvGbm5ucZ//vMfo1u3bsarr75qGIZhHDx40IiIiDD27dvn3m9h+xg8eLDHsX+/XXJyshEVFWVs3rzZcDqdxldffWW0bt3a+PTTTz3GDx061Dh+/LiRk5NjPPTQQ8aQIUNMf+8ef/xxo3nz5sbHH39sOJ1O49tvvzWaNWtmbNmypch9XPDoo496vPePP/640axZM2PFihVGXl6ekZWVZRiGYSxfvtxIS0szXC6XsXPnTuOmm24y3nvvPfd299xzjzF79mz364iICKNv377Gvn37jPz8fOOpp54ybr31Vo9jz5s3z5g4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\n" + }, + "metadata": {} + } + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "machine_shape": "hm", + "provenance": [] + }, + "gpuClass": "standard", + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file