{"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":"# [Tensorflow - Help Protect the Great Barrier Reef](https://www.kaggle.com/c/tensorflow-great-barrier-reef)\n> Detect crown-of-thorns starfish in underwater image data\n\n<img src=\"https://storage.googleapis.com/kaggle-competitions/kaggle/31703/logos/header.png?t=2021-10-29-00-30-04\">","metadata":{}},{"cell_type":"markdown","source":"## 当たり前にやられていること\n- [ ] Dataの修正・追加\n    - [ ] サイズが大きすぎる・小さすぎるbboxを無視（実装）\n    - [ ] 手作業でbboxを追加（解説）\n- [ ] Data Augmentation\n    - [ ] Albumentationsライブラリを使ったaugmentation（RandomSizedCrop, HueSaturationValue, RandomBrightnessContrast, ToGray, HorizontalFlip, VerticalFlip, Cutout, etc）\n    - [ ] mixup（画像の合成。実装）\n    - [ ] cutmix（cutout+mixup: cutoutした部分に別画像を合成。実装 ）\n    - [ ] ジグソーパズルによる画像生成（既述）\n- [ ] アーキテクチャの選択\n    - [ ] YOLO（コンペ参加直後に触っていた。v5はライセンスの問題で使用禁止に。単独ではおそらく最高精度が出せるモデルだった）\n    - [ ] EfficientDet（YOLOv5が禁止になってからはひたすらD5を中心にEfficientDetで実験していた。EfficientNetの考え方を取り入れた物体検出モデル。実装）\n    - [ ] 他は試してないが、DetectorRSやUniverseNetが良いなどの報告あり\n- [ ] 高解像度で学習\n    - [ ] リサイズを行わず1024 x 1024の画像で学習（Colab Proではbatch size 1でギリギリCUDA out of memoryを回避できる）\n- [x] TTA（テストデータもaugmentation。実装）\n- [ ] Pseudo Labeling (テーブルデータでもお馴染み、テストデータを予測し確信度の高いラベルのみ訓練データに取り入れて再予測。実装)\n- [ ] Ensemble (精度を求めるKaggleではWBFが強い場合が多そう。実装, 解説)\n    - [ ] NMS（IoUがある閾値を超えて重なっているbboxの集合から、スコアが最大のbboxを残して、それ以外を除去）\n    - [ ] SoftNMS（IoU閾値を超えたbboxを残しつつ、スコアが最大のbbox以外も除去せず、スコアを割り引いて残す）\n    - [ ] NMW (重なりあったbboxをスコアとIoUで重み付けして足し合わせることで、1つの新たなbboxを作り出す)\n    - [ ] WBF（検出されたモデルの数が少ないbboxほどスコアを下げることで、少数のモデルだけで検出されたbboxをスコアで足切りする）","metadata":{}},{"cell_type":"markdown","source":"アイデア\n\n- ヒトデが映ってない画像も学習データにしたらダメか？\n    - 全部使うとほとんどヒトデが映ってない、と判定しそう\n        - 同じ枚数(5k)だったらいいかも？\n- モデルを変える\n    - YoloX\n    - EfficientDet\n    - FasterRCNN\n    - DETR\n- nofair tracking\n- コントラスト均等化する\n- Augmentationをしない\n    - メモリ節約のため\n- Adamを使う","metadata":{}},{"cell_type":"markdown","source":"わかったこと\n- yolov5について\n    - 学習にはtrain.pyという元々あるコードを使っている\n    - それに引数として学習データのパスやハイパーパラメータの情報が記述された.yamlファイルを与えている","metadata":{}},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"やる事\n- yolov5とは何か調査\n    - 何を学習するのか？\n    - 精度とかはどうやって出すのか？\n    - 見つけたいものが映ってないデータは学習に含めてよいのか？\n- いらない部分を削ってシンプルにする\n- W&Bにログインして学習経過のグラフなどを見る\n    - ~というか、細かい処理とかwandbに登録してこっちでやってそう~\n- クロスバリデーションするモデル5個作ってアンサンブル","metadata":{}},{"cell_type":"markdown","source":"## ファイル構造\n\nworking/labels/以下にすべてのファイルのlabel.txtが入っている\n\nimagesを同じ","metadata":{}},{"cell_type":"markdown","source":"# 🛠 Install Libraries","metadata":{}},{"cell_type":"code","source":"!pip install -qU wandb\n!pip install -qU bbox-utility # check https://github.com/awsaf49/bbox for source code","metadata":{"_kg_hide-output":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-02-03T12:22:47.906495Z","iopub.execute_input":"2022-02-03T12:22:47.906966Z","iopub.status.idle":"2022-02-03T12:23:08.793093Z","shell.execute_reply.started":"2022-02-03T12:22:47.906852Z","shell.execute_reply":"2022-02-03T12:23:08.792117Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📚 Import Libraries","metadata":{}},{"cell_type":"code","source":"import numpy as np\nfrom tqdm.notebook import tqdm\ntqdm.pandas()\nimport pandas as pd\nimport os\nimport cv2\nimport matplotlib.pyplot as plt\nimport glob\n\nimport shutil\nimport sys\nsys.path.append('../input/tensorflow-great-barrier-reef')\n\nfrom joblib import Parallel, delayed\n\nfrom IPython.display import display, HTML\n\nfrom matplotlib import animation, rc\nrc('animation', html='jshtml')\n\n# for DA\nfrom torch.utils.data import DataLoader, Dataset\nimport torch.utils.data as Data\nimport ast #?\nfrom fastprogress.fastprogress import master_bar, progress_bar #?","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-02-03T12:23:08.79951Z","iopub.execute_input":"2022-02-03T12:23:08.801189Z","iopub.status.idle":"2022-02-03T12:23:10.813715Z","shell.execute_reply.started":"2022-02-03T12:23:08.801145Z","shell.execute_reply":"2022-02-03T12:23:10.812994Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📌 Key-Points\n* 提供されているpython時系列APIを使用して予測を送信する必要があります。これにより、このコンテストは以前のオブジェクト検出コンテストとは異なります。\n* 各予測行には、画像のすべての境界ボックスを含める必要があります。提出はフォーマットもCOCOのようです。これは`[x_min、y_min、幅、高さ]`を意味します\n* CopmetitionメトリックF2は、ヒトデを見逃すことがほとんどないことを保証するために、いくつかの誤検知（FP）を許容します。つまり、誤検知（FN）は、誤検知（FP）よりも重要です。\n$$F2 = 5 \\cdot \\frac{precision \\cdot recall}{4\\cdot precision + recall}$$","metadata":{}},{"cell_type":"markdown","source":"# ⭐ WandB","metadata":{}},{"cell_type":"code","source":"import wandb\n\ntry:\n    from kaggle_secrets import UserSecretsClient\n    user_secrets = UserSecretsClient()\n    api_key = user_secrets.get_secret(\"wandb_team_iforine\")\n    wandb.login(key=api_key)\n    anonymous = None\nexcept:\n    wandb.login(anonymous='must')\n    print('To use your W&B account,\\nGo to Add-ons -> Secrets and provide your W&B access token. Use the Label name as WANDB. \\nGet your W&B access token from here: https://wandb.ai/authorize')","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:10.814839Z","iopub.execute_input":"2022-02-03T12:23:10.815072Z","iopub.status.idle":"2022-02-03T12:23:13.145894Z","shell.execute_reply.started":"2022-02-03T12:23:10.815039Z","shell.execute_reply":"2022-02-03T12:23:13.145118Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📖 Meta Data\n* `train_images/` - Folder containing training set photos of the form `video_{video_id}/{video_frame}.jpg`.\n\n* `[train/test].csv` - 画像のメタデータです。他のテストファイルと同様に、テストのメタデータデータのほとんどは、提出時にしかノートブックに表示されません。ダウンロードできるのは最初の数行だけです。\n\n* `video_id` - 画像が含まれるビデオのID番号。ビデオIDは意味のある順序ではありません。\n* `video_frame` - 映像内の画像のフレーム番号です。ダイバーが浮上したときからフレーム番号にずれが生じることがあります。\n* `sequence` - ID of a gap-free subset of a given video. The sequence ids are not meaningfully ordered.指定されたビデオのギャップフリー部分集合のID。シーケンスIDは意味のある順序ではありません。\n* `sequence_frame` - 指定されたシーケンス内のフレーム番号。\n* `image_id` - ID code for the image, in the format `{video_id}-{video_frame}`\n* `annotations` - The bounding boxes of any starfish detections in a string format that can be evaluated directly with Python. Does not use the same format as the predictions you will submit. Not available in test.csv. A bounding box is described by the pixel coordinate `(x_min, y_min)` of its lower left corner within the image together with its `width` and `height` in pixels --> (COCO format).Pythonで直接評価可能な文字列形式のヒトデ検出のバウンディングボックス。提出する予測値と同じフォーマットではありません。test.csvでは利用できません。バウンディングボックスは、画像内の左下隅のピクセル座標 `(x_min, y_min)` と、ピクセル単位の `width` と `height` で記述される --> (COCO 形式)。","metadata":{}},{"cell_type":"code","source":"FOLD      = 4 # which fold to train\nDIM       = 2016\nMODEL     = 'yolov5s'\nBATCH     = 4\nEPOCHS    = 10\nOPTIM     = 'Adam'\nAUG       = 'HE'\n\nPROJECT   = 'iforine/great-barrier-reef-public' # w&b in yolov5\nNAME      = f'{MODEL}-dim{DIM}-fold{FOLD}-bat{BATCH}-opt{OPTIM}-aug{AUG}-epch{EPOCHS}-addNoCot' # w&b for yolov5\n\nREMOVE_NOBBOX = False # remove images with no bbox\nADD_NOBBOX = True # bboxのある画像と同じ枚数分bboxの無い画像を学習データに加える\nROOT_DIR  = '/kaggle/input/tensorflow-great-barrier-reef/'\nIMAGE_DIR = '/kaggle/working/images' # directory to save images\nLABEL_DIR = '/kaggle/working/labels' # directory to save labels\n\nWORKER = 4 # よくわかってない。スレッドの数とか？\n\nnp.random.seed(42)","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:13.147475Z","iopub.execute_input":"2022-02-03T12:23:13.148445Z","iopub.status.idle":"2022-02-03T12:23:13.155912Z","shell.execute_reply.started":"2022-02-03T12:23:13.148401Z","shell.execute_reply":"2022-02-03T12:23:13.155246Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Create Directories","metadata":{}},{"cell_type":"code","source":"!mkdir -p {IMAGE_DIR}\n!mkdir -p {LABEL_DIR}","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:13.159112Z","iopub.execute_input":"2022-02-03T12:23:13.159665Z","iopub.status.idle":"2022-02-03T12:23:14.477984Z","shell.execute_reply.started":"2022-02-03T12:23:13.159636Z","shell.execute_reply":"2022-02-03T12:23:14.477058Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Get Paths","metadata":{}},{"cell_type":"code","source":"pd.set_option('display.max_columns', 10)","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:14.480137Z","iopub.execute_input":"2022-02-03T12:23:14.480387Z","iopub.status.idle":"2022-02-03T12:23:14.486042Z","shell.execute_reply.started":"2022-02-03T12:23:14.480359Z","shell.execute_reply":"2022-02-03T12:23:14.485276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"pandas.eval()\n\n様々なバックエンドを使用して、Python式を文字列として評価します。","metadata":{}},{"cell_type":"code","source":"# Train Data\ndf = pd.read_csv(f'{ROOT_DIR}/train.csv')\ndf['old_image_path'] = f'{ROOT_DIR}/train_images/video_'+df.video_id.astype(str)+'/'+df.video_frame.astype(str)+'.jpg'\ndf['image_path']  = f'{IMAGE_DIR}/'+df.image_id+'.jpg' # '/kaggle/working/images'\ndf['label_path']  = f'{LABEL_DIR}/'+df.image_id+'.txt' # '/kaggle/working/labels'\ndf['annotations'] = df['annotations'].progress_apply(eval) # apply(各要素に関数を適用する)の進捗を表示する。evalは何？\ndisplay(df.head(100))","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:14.48773Z","iopub.execute_input":"2022-02-03T12:23:14.488296Z","iopub.status.idle":"2022-02-03T12:23:15.063406Z","shell.execute_reply.started":"2022-02-03T12:23:14.48826Z","shell.execute_reply":"2022-02-03T12:23:15.062616Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Number of BBoxes\n> Nearly 80% images are without any bbox.","metadata":{}},{"cell_type":"code","source":"df['num_bbox'] = df['annotations'].progress_apply(lambda x: len(x))\ndata = (df.num_bbox>0).value_counts(normalize=True)*100 # ユニークな要素の出現頻度を算出。normalize=Trueにすると合計が1になるように正規化される(割合になる)\nprint(f\"No BBox: {data[0]:0.2f}% | With BBox: {data[1]:0.2f}%\")","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:15.064874Z","iopub.execute_input":"2022-02-03T12:23:15.065134Z","iopub.status.idle":"2022-02-03T12:23:15.163444Z","shell.execute_reply.started":"2022-02-03T12:23:15.065097Z","shell.execute_reply":"2022-02-03T12:23:15.159608Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"`Error displaying widget: model not found`\n\n何らかの原因でprogressを出せないのかも。モデルがない、とはどういうこと？","metadata":{}},{"cell_type":"markdown","source":"実際にbboxの存在する画像を見てみる","metadata":{}},{"cell_type":"markdown","source":"# 🧹 Clean Data\n* In this notebook, we use only **bboxed-images** (`~5k`). We can use all `~23K` images for train but most of them don't have any labels. So it would be easier to carry out experiments using only **bboxed images**.\n* このノートブックでは、bboxed-images（〜5k）のみを使用します。trainには約23Kの画像をすべて使用できますが、ほとんどの画像にはラベルがありません。したがって、bboxed画像のみを使用して実験を実行する方が簡単です","metadata":{}},{"cell_type":"code","source":"if REMOVE_NOBBOX:\n    df = df.query(\"num_bbox>0\") # df[df['num_bbox'] > 0]と同等。直観的で便利だ・・・","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:15.164541Z","iopub.execute_input":"2022-02-03T12:23:15.164934Z","iopub.status.idle":"2022-02-03T12:23:15.169313Z","shell.execute_reply.started":"2022-02-03T12:23:15.164895Z","shell.execute_reply":"2022-02-03T12:23:15.168461Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 背景画像を全体の10%含める\nif ADD_NOBBOX:\n    df = pd.concat([df.query(\"num_bbox>0\"), df.query(\"num_bbox==0\").sample(int(len(df.query(\"num_bbox>0\")) * 0.1))])","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:15.170638Z","iopub.execute_input":"2022-02-03T12:23:15.171465Z","iopub.status.idle":"2022-02-03T12:23:15.201889Z","shell.execute_reply.started":"2022-02-03T12:23:15.171427Z","shell.execute_reply":"2022-02-03T12:23:15.201164Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ✏️ Write Images\n* We need to copy the Images to Current Directory(`/kaggle/working`) as `/kaggle/input` doesn't have **write access** which is needed for **YOLOv5**.\n* We can make this process faster using **Joblib** which uses **Parallel** computing.\n\n* / kaggle / inputにはYOLOv5に必要な書き込みアクセス権がないため、イメージを現在のディレクトリ（/ kaggle / working）にコピーする必要があります。\n* この処理を高速化するには、**並列**計算を利用する**Joblib**を使用します。","metadata":{}},{"cell_type":"markdown","source":"shutil.copyfile(src, dst, *, follow_symlinks=True)\n\nsrc という名前のファイルの内容 (メタデータを含まない) を dst という名前のファイルにコピーし、最も効率的な方法で dst を返します。 src と dst は path-like object または文字列でパス名を指定します。","metadata":{}},{"cell_type":"code","source":"def make_copy(row):\n    shutil.copyfile(row.old_image_path, row.image_path)\n    return","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:15.204028Z","iopub.execute_input":"2022-02-03T12:23:15.20446Z","iopub.status.idle":"2022-02-03T12:23:15.208881Z","shell.execute_reply.started":"2022-02-03T12:23:15.204423Z","shell.execute_reply":"2022-02-03T12:23:15.20811Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"並列処理\n\n```\njoblib.Parallel(<Parallelへの引数>)(\n    joblib.delayed(<実行する関数>)(<関数への引数>) for 変数名 in イテラブル\n)\n```","metadata":{}},{"cell_type":"markdown","source":"iterrows()メソッドを使うと、1行ずつ、インデックス名（行名）とその行のデータ（pandas.Series型）のタプル(index, Series)を取得できる。","metadata":{}},{"cell_type":"code","source":"image_paths = df.old_image_path.tolist()\n_ = Parallel(n_jobs=-1, backend='threading')(delayed(make_copy)(row) for _, row in tqdm(df.iterrows(), total=len(df)))","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:15.210201Z","iopub.execute_input":"2022-02-03T12:23:15.210642Z","iopub.status.idle":"2022-02-03T12:23:47.548148Z","shell.execute_reply.started":"2022-02-03T12:23:15.210604Z","shell.execute_reply":"2022-02-03T12:23:47.547506Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🔨 Helper","metadata":{}},{"cell_type":"code","source":"# check https://github.com/awsaf49/bbox for source code of following utility functions\n# 作者が作ったヘルパー関数\nfrom bbox.utils import coco2yolo, coco2voc, voc2yolo\nfrom bbox.utils import draw_bboxes, load_image\nfrom bbox.utils import clip_bbox, str2annot, annot2str\n\n# bboxをリストにして返す\ndef get_bbox(annots):\n    bboxes = [list(annot.values()) for annot in annots]\n    return bboxes\n\n# rowに幅と高さの列を追加する\ndef get_imgsize(row):\n    row['width'], row['height'] = imagesize.get(row['image_path']) # このimagesizeって何？\n    return row\n\nnp.random.seed(32)\ncolors = [(np.random.randint(255), np.random.randint(255), np.random.randint(255))\\\n          for idx in range(1)]","metadata":{"_kg_hide-input":false,"execution":{"iopub.status.busy":"2022-02-03T12:23:47.54924Z","iopub.execute_input":"2022-02-03T12:23:47.549434Z","iopub.status.idle":"2022-02-03T12:23:48.177477Z","shell.execute_reply.started":"2022-02-03T12:23:47.549409Z","shell.execute_reply":"2022-02-03T12:23:48.176769Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Create BBox","metadata":{}},{"cell_type":"code","source":"# annotionsからbboxes列を作成\ndf['bboxes'] = df.annotations.progress_apply(get_bbox)\ndf.head(2)","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:48.181172Z","iopub.execute_input":"2022-02-03T12:23:48.181406Z","iopub.status.idle":"2022-02-03T12:23:49.823586Z","shell.execute_reply.started":"2022-02-03T12:23:48.18138Z","shell.execute_reply":"2022-02-03T12:23:49.8229Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Get Image-Size\n> All Images have same dimension, [Width, Height] =  `[1280, 720]`","metadata":{}},{"cell_type":"code","source":"df['width']  = 1280\ndf['height'] = 720\ndisplay(df.head(2))","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:49.824893Z","iopub.execute_input":"2022-02-03T12:23:49.825291Z","iopub.status.idle":"2022-02-03T12:23:49.843354Z","shell.execute_reply.started":"2022-02-03T12:23:49.825254Z","shell.execute_reply":"2022-02-03T12:23:49.842622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🏷️ Create Labels\nWe need to export our labels to **YOLO** format, with one `*.txt` file per image (if no objects in image, no `*.txt` file is required). The *.txt file specifications are:\n\n* One row per object\n* Each row is class `[x_center, y_center, width, height]` format.\n* Box coordinates must be in **normalized** `xywh` format (from `0 - 1`). If your boxes are in pixels, divide `x_center` and `width` by `image width`, and `y_center` and `height` by `image height`.\n* Class numbers are **zero-indexed** (start from `0`).\n\n> Competition bbox format is **COCO** hence `[x_min, y_min, width, height]`. So, we need to convert form **COCO** to **YOLO** format.\n\n各画像に対して.txtファイルを作ってYOLOに対応する形式にする\n\n* オブジェクト一つにつき1行\n* 各行以下のフォーマット`[x_center, y_center, width, height]`\n* box座標は**0-1で正規化された**xywhフォーマット。ピクセル単位の場合は、 `x_center` と `width` を `image width` で割って、 `y_center` と `height` を `image height` で割ってください。\n* クラス番号は **0から始まるゼロ・インデックス** です。\n\n> コンペのbbox形式はCOCOであるため、[x_min、y_min、width、height]です。したがって、フォームCOCOをYOLO形式に変換する必要があります。","metadata":{}},{"cell_type":"code","source":"pd.set_option('display.max_columns', 100) # 列が多いと省略されるのを防ぐ","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:49.84488Z","iopub.execute_input":"2022-02-03T12:23:49.845369Z","iopub.status.idle":"2022-02-03T12:23:49.851906Z","shell.execute_reply.started":"2022-02-03T12:23:49.845331Z","shell.execute_reply":"2022-02-03T12:23:49.851253Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"これがラベル？3のとこにはbboxの数が入る","metadata":{}},{"cell_type":"markdown","source":"coco => **[xmin, ymin, w, h]**\n\nvoc  => **[xmin, ymin, xmax, ymax]**\n\nyolo => **[xmid, ymid, w, h]** (normalized)\n\n```\ndef clip_bbox(bboxes_voc, height=720, width=1280):\n\n    Clip bounding boxes to image boundaries.\n    Args:\n        bboxes_voc (np.ndarray): bboxes in [xmin, ymin, xmax, ymax] format.\n        height (int, optional): height of bbox. Defaults to 720.\n        width (int, optional): width of bbox. Defaults to 1280.\n    Returns:\n        np.ndarray : clipped bboxes in [xmin, ymin, xmax, ymax] format.\n```","metadata":{}},{"cell_type":"markdown","source":"## label.txtを作成","metadata":{}},{"cell_type":"code","source":"cnt = 0\nall_bboxes = []\nbboxes_info = []\nfor row_idx in tqdm(range(df.shape[0])):\n    row = df.iloc[row_idx]\n    image_height = row.height\n    image_width  = row.width\n    bboxes_coco  = np.array(row.bboxes).astype(np.float32).copy() #bboxesをnumpy形式に変換\n    num_bbox     = len(bboxes_coco)\n    names        = ['cots']*num_bbox\n    labels       = np.array([0]*num_bbox)[..., None].astype(str) # 次元を++(リストからshape:(N, 1)の行列へ)\n    ## Create Annotation(YOLO)\n    with open(row.label_path, 'w') as f:\n        if num_bbox<1:\n            annot = ''\n            f.write(annot)\n            cnt+=1\n            continue\n        bboxes_voc  = coco2voc(bboxes_coco, image_height, image_width)\n        bboxes_voc  = clip_bbox(bboxes_voc, image_height, image_width)\n        bboxes_yolo = voc2yolo(bboxes_voc, image_height, image_width).astype(str)\n        all_bboxes.extend(bboxes_yolo.astype(float)) # all_bboxesにbboxes_yoloを追加\n        bboxes_info.extend([[row.image_id, row.video_id, row.sequence]]*len(bboxes_yolo)) # bboxes_infoにbboxの数だけ[image_id, video_id, sequence]を追加\n        annots = np.concatenate([labels, bboxes_yolo], axis=1) # labelsの横にbboxes_yoloをくっつける(bboxの数だけ行ができる)\n        string = annot2str(annots) # annotationをstrにしてる\n        f.write(string)\nprint('Missing:',cnt)","metadata":{"_kg_hide-input":false,"execution":{"iopub.status.busy":"2022-02-03T12:23:49.853375Z","iopub.execute_input":"2022-02-03T12:23:49.853931Z","iopub.status.idle":"2022-02-03T12:23:54.691956Z","shell.execute_reply.started":"2022-02-03T12:23:49.853893Z","shell.execute_reply":"2022-02-03T12:23:54.69119Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"指定した場所`kaggle/imageとかlabel`にファイルができないぞ？？？","metadata":{}},{"cell_type":"markdown","source":"# 📁 Create Folds\n> Number of samples aren't same in each fold which can create large variance in **Cross-Validation**.\n\n> 各フォールドのサンプル数が同じでないため、クロスバリデーションで大きなばらつきが生じる可能性があります。\n\nGroupKFold: 同じグループが異なる分割パターンに出現しないようにデータセットを分割する。\n参考：https://upura.hatenablog.com/entry/2018/12/04/224436\n\n> クラスとは別の概念として、データセット全体は均等な10グループに分割されています。グループはなかなかイメージが付きづらいかもしれませんが、例えば「同じユーザのデータを一つのグループにまとめておく」といった使い方が想定できます。**同じユーザのデータがtrainのデータセットとvalidationのデータセットの両者に存在すると、不当に精度が高くなる恐れがある**ためです。\n\n今回は動画の数(`len(df['sequence'].unique())`の事)","metadata":{}},{"cell_type":"markdown","source":"https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GroupKFold.html#sklearn.model_selection.GroupKFold\n\n> class sklearn.model_selection.GroupKFold(n_splits=5)[source]\n>\n> オーバーラップしないグループを持つK-foldイテレータの変形。\n>\n> 同じグループが2つの異なるフォールドに現れることはありません（異なるグループの数は、少なくともフォールドの数と同じでなければなりません）。\n>\n> 各フォールドは、それぞれのフォールドで異なるグループの数がほぼ同じという意味で、ほぼバランスが取れています。","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import GroupKFold\nkf = GroupKFold(n_splits = 5) # n_split: train,valのパターンの数。元データを5パターンのtrain,valに分ける\ndf = df.reset_index(drop=True)\ndf['fold'] = -1\nfor fold, (train_idx, val_idx) in enumerate(kf.split(df, y = df.video_id.tolist(), groups=df.sequence)): # sequence: 動画のサブセットID(同じIDの画僧は同じ動画)\n    df.loc[val_idx, 'fold'] = fold\ndisplay(df.fold.value_counts())","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:54.693614Z","iopub.execute_input":"2022-02-03T12:23:54.694126Z","iopub.status.idle":"2022-02-03T12:23:55.216792Z","shell.execute_reply.started":"2022-02-03T12:23:54.694084Z","shell.execute_reply":"2022-02-03T12:23:55.216052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ⚙️ Configuration\nThe dataset config file requires\n1. The dataset root directory path and relative paths to `train / val / test` image directories (or *.txt files with image paths)\n2. The number of classes `nc` and \n3. A list of class `names`:`['cots']`\n\nデータセット設定ファイルには、以下のものが必要です。\n1. 1. データセットのルートディレクトリのパスと，`train / val / test` 画像ディレクトリの相対パス (または画像パスを含む *.txt ファイル)\n2. クラス数 `nc` と \n3. クラス名`:`['cots']`のリスト。","metadata":{}},{"cell_type":"code","source":"train_files = []\nval_files   = []\ntrain_df = df.query(\"fold!=@FOLD\")\nvalid_df = df.query(\"fold==@FOLD\")\ntrain_files += list(train_df.image_path.unique())\nval_files += list(valid_df.image_path.unique())\nlen(train_files), len(val_files)","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:55.21797Z","iopub.execute_input":"2022-02-03T12:23:55.2183Z","iopub.status.idle":"2022-02-03T12:23:55.237717Z","shell.execute_reply.started":"2022-02-03T12:23:55.218263Z","shell.execute_reply":"2022-02-03T12:23:55.236713Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Data Augmentation**","metadata":{"execution":{"iopub.status.busy":"2022-01-31T13:27:35.106346Z","iopub.execute_input":"2022-01-31T13:27:35.106754Z","iopub.status.idle":"2022-01-31T13:27:35.145508Z","shell.execute_reply.started":"2022-01-31T13:27:35.106708Z","shell.execute_reply":"2022-01-31T13:27:35.144592Z"}}},{"cell_type":"markdown","source":"train_dfに対してDAをかける\n\n今回はbboxの位置が変わる処理はしない(label.txtを流用したいため)\n\nできた画像は`working/images/{video_id}-{video_frame}-aug.jpg`に入れる。\n\nその画像に対するラベルは元画像のlabel.txtから流用`working/labels/{video_id}-{video_frame}-aug.txt`に入れる。\n\ntrain_dfに行を追加。(元画像の行をコピー。image_path, label_pathを↑のものに変えればOKのはず)","metadata":{}},{"cell_type":"code","source":"import albumentations as A","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:55.238985Z","iopub.execute_input":"2022-02-03T12:23:55.239447Z","iopub.status.idle":"2022-02-03T12:23:56.344226Z","shell.execute_reply.started":"2022-02-03T12:23:55.239412Z","shell.execute_reply":"2022-02-03T12:23:56.343413Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class HE_HSV(A.ImageOnlyTransform):\n    def __init__(self, p: float = 0.5, always_apply=False):\n        super().__init__(always_apply, p)\n        \n    def apply(self, image,**params):\n        img_hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)\n\n        # Histogram equalisation on the V-channel\n        img_hsv[:, :, 2] = cv2.equalizeHist(img_hsv[:, :, 2])\n\n        # convert image back from HSV to RGB\n        image_hsv = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2RGB)\n\n        return image_hsv","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:56.345693Z","iopub.execute_input":"2022-02-03T12:23:56.34597Z","iopub.status.idle":"2022-02-03T12:23:56.352854Z","shell.execute_reply.started":"2022-02-03T12:23:56.345932Z","shell.execute_reply":"2022-02-03T12:23:56.351452Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class AUG_DATASET(Dataset):\n    \n    def __init__(self, df, transform=None):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        \n    def coco2yolo(self, bboxes, image_height=720, image_width=1280):\n        \"\"\"\n        coco => [xmin, ymin, w, h]\n        yolo => [xmid, ymid, w, h] (normalized)\n        \"\"\"\n        bboxes = np.array(bboxes)\n        bboxes = bboxes.copy().astype(float) # otherwise all value will be 0 as voc_pascal dtype is np.int\n\n        # normolizinig\n        bboxes[..., [0, 2]]= bboxes[..., [0, 2]]/ image_width\n        bboxes[..., [1, 3]]= bboxes[..., [1, 3]]/ image_height\n\n        # converstion (xmin, ymin) => (xmid, ymid)\n        bboxes[..., [0, 1]] = bboxes[..., [0, 1]] + bboxes[..., [2, 3]]/2\n\n        return bboxes\n    \n    def coord_to_box(self, bouding_box, image):\n        box_yolo_format = []\n        height, width = image.shape[0], image.shape[1]\n        \n        if False: # CFG.use_coco2yolo\n            box_yolo_format = self.coco2yolo(bouding_box)\n            box_yolo_format = np.clip(box_yolo_format,0,1)\n            label = np.repeat([0],box_yolo_format.shape[0]).reshape(-1,1)\n            box_yolo_format = np.append(box_yolo_format,label, axis=1)\n        else:\n            for bb in bouding_box:\n                label = [max(0,bb[0]), max(0,bb[1]), min(bb[0]+bb[2], 1280), min(720,bb[1]+bb[3]), '0']\n                bbox_albu = A.convert_bbox_to_albumentations(label, source_format='pascal_voc', rows=height, cols=width)\n                bbox_yolo = A.convert_bbox_from_albumentations(bbox_albu, target_format='yolo', rows=height, cols=width, check_validity=True)\n                clip_box = [np.clip(value,0,1) for value in bbox_yolo[:-1]] + [bbox_yolo[-1]]\n                box_yolo_format.append(clip_box)\n        return box_yolo_format\n\n    def bbox_to_txt(self, bboxes):\n        \"\"\"\n        Convert a list of bbox into a string in YOLO format (to write a file).\n        @bboxes : numpy array of bounding boxes \n        return : a string for each object in new line: <object-class> <x> <y> <width> <height>\n        \"\"\"\n        txt=''\n        for index,l in enumerate(bboxes):\n            l = [str(x) for x in l[:4]]\n            l = ' '.join(l)\n            txt +=  '0' +' ' + l + '\\n'\n        return txt\n\n    def __len__(self):\n        return self.df.shape[0]\n    \n    def __getitem__(self,index):\n        row = self.df.iloc[index]\n        path = row['image_path']\n        img = cv2.imread(path)\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        #aug_index = row['aug_index']\n        list_info = path.split('/')\n        image_name = list_info[-2] + '_' + list_info[-1].split('.')[0]\n        box = row['bboxes']\n        bounding_box = self.coord_to_box(box, img)\n\n        if self.transform is not None:\n            res = self.transform(image=img, bboxes=bounding_box)\n            img = res['image']\n            bounding_box = res['bboxes']\n            \n        box_yolo_format = self.bbox_to_txt(bounding_box)\n        return img, box_yolo_format, image_name","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:56.354162Z","iopub.execute_input":"2022-02-03T12:23:56.354614Z","iopub.status.idle":"2022-02-03T12:23:57.409139Z","shell.execute_reply.started":"2022-02-03T12:23:56.354579Z","shell.execute_reply":"2022-02-03T12:23:57.408243Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_transforms():\n    return A.Compose([\n            HE_HSV(always_apply=True) # 現在は全データに対してDAかけた前提でtrain_dfの行を追加している\n            ], bbox_params=A.BboxParams(format='yolo' , min_visibility=0.4,min_area=500))","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:57.411024Z","iopub.execute_input":"2022-02-03T12:23:57.411587Z","iopub.status.idle":"2022-02-03T12:23:57.443381Z","shell.execute_reply.started":"2022-02-03T12:23:57.411543Z","shell.execute_reply":"2022-02-03T12:23:57.442472Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"class AUGDATA　のimage_path周りの設定いじる必要あり","metadata":{}},{"cell_type":"markdown","source":"できた画像は`working/images/{video_id}-{video_frame}-aug.jpg`に入れる。\n\nその画像に対するラベルは元画像のlabel.txtから流用`working/labels/{video_id}-{video_frame}-aug.txt`に入れる。\n\ntrain_dfに行を追加。(元画像の行をコピー。image_path, label_pathを↑のものに変えればOKのはず)\n\n---\n\n最初からtrain_dfをコピーする。=tran_aug_df\n\ntrain_aug_dfに対してDAをかける\n\n同じtrainディレクトリに保存すればok","metadata":{}},{"cell_type":"code","source":"train_df","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:57.444839Z","iopub.execute_input":"2022-02-03T12:23:57.454692Z","iopub.status.idle":"2022-02-03T12:23:58.086109Z","shell.execute_reply.started":"2022-02-03T12:23:57.454648Z","shell.execute_reply":"2022-02-03T12:23:58.085333Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if AUG is not None:\n    \n    train_df_he = train_df.copy(deep=True)\n    \n    # dataloaderを使ってデータ拡張\n    dataset = AUG_DATASET(train_df_he, transform = get_transforms())\n    dataloader = Data.DataLoader(dataset=dataset, num_workers=WORKER, batch_size=BATCH, shuffle=False, drop_last=False,\\\n                               pin_memory = False)\n    \n    for aug_img, aug_box, image_name in progress_bar(dataloader):\n        for idx, image in enumerate(aug_img):\n            name = image_name[idx]\n            new_name = \"{}_HE\".format(name)\n            image = aug_img[idx]\n            box = aug_box[idx]\n            \n            path_txt = LABEL_DIR + \"/\" + new_name + \".txt\"\n            path_jpg = IMAGE_DIR + \"/\" + new_name + \".jpg\"\n            is_path = os.path.exists(path_jpg)\n            image = image.numpy()\n            cv2.imwrite(path_jpg, image[...,::-1])\n            txt_file = open(path_txt, \"w\")\n            txt_file.write(box)\n            txt_file.close()\n        break\n    \n    # train_dfにDAした行を追加\n    func_he_path = lambda x: '{}_HE'.format(x)\n    train_df_he.image_path = train_df_he.image_path.map(func_he_path) # image_pathを更新\n    train_df_he.label_path = train_df_he.label_path.map(func_he_path) # label_pathを更新\n    train_df = pd.concat([train_df, train_df_he], axis=0, ignore_index=True) #index再度降り直し","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:58.09462Z","iopub.execute_input":"2022-02-03T12:23:58.102573Z","iopub.status.idle":"2022-02-03T12:23:59.570004Z","shell.execute_reply.started":"2022-02-03T12:23:58.102526Z","shell.execute_reply":"2022-02-03T12:23:59.569143Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(train_df.image_path.unique())","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:59.571871Z","iopub.execute_input":"2022-02-03T12:23:59.57214Z","iopub.status.idle":"2022-02-03T12:23:59.581864Z","shell.execute_reply.started":"2022-02-03T12:23:59.572102Z","shell.execute_reply":"2022-02-03T12:23:59.580969Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## train.txt, val.txtを作る(学習と検証データのパスが記述されている)","metadata":{}},{"cell_type":"code","source":"import yaml\n\ncwd = '/kaggle/working/'\n\nwith open(os.path.join( cwd , 'train.txt'), 'w') as f:\n    for path in train_df.image_path.tolist():\n        f.write(path+'\\n')\n            \nwith open(os.path.join(cwd , 'val.txt'), 'w') as f:\n    for path in valid_df.image_path.tolist():\n        f.write(path+'\\n')\n\ndata = dict(\n    path  = '/kaggle/working',\n    train =  os.path.join( cwd , 'train.txt') ,\n    val   =  os.path.join( cwd , 'val.txt' ),\n    nc    = 1,\n    names = ['cots'],\n    )\n\nwith open(os.path.join( cwd , 'gbr.yaml'), 'w') as outfile:\n    yaml.dump(data, outfile, default_flow_style=False)\n\nf = open(os.path.join( cwd , 'gbr.yaml'), 'r')\nprint('\\nyaml:')\nprint(f.read())","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-02-03T12:23:59.583114Z","iopub.execute_input":"2022-02-03T12:23:59.583614Z","iopub.status.idle":"2022-02-03T12:23:59.600709Z","shell.execute_reply.started":"2022-02-03T12:23:59.583579Z","shell.execute_reply":"2022-02-03T12:23:59.599851Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%writefile /kaggle/working/hyp.yaml\nlr0: 0.01  # initial learning rate (SGD=1E-2, Adam=1E-3)\nlrf: 0.1  # final OneCycleLR learning rate (lr0 * lrf)\nmomentum: 0.937  # SGD momentum/Adam beta1\nweight_decay: 0.0005  # optimizer weight decay 5e-4\nwarmup_epochs: 3.0  # warmup epochs (fractions ok)\nwarmup_momentum: 0.8  # warmup initial momentum\nwarmup_bias_lr: 0.1  # warmup initial bias lr\nbox: 0.05  # box loss gain\ncls: 0.5  # cls loss gain\ncls_pw: 1.0  # cls BCELoss positive_weight\nobj: 1.0  # obj loss gain (scale with pixels)\nobj_pw: 1.0  # obj BCELoss positive_weight\niou_t: 0.20  # IoU training threshold\nanchor_t: 4.0  # anchor-multiple threshold\n# anchors: 3  # anchors per output layer (0 to ignore)\nfl_gamma: 0.0  # focal loss gamma (efficientDet default gamma=1.5)\nhsv_h: 0.015  # image HSV-Hue augmentation (fraction)\nhsv_s: 0.7  # image HSV-Saturation augmentation (fraction)\nhsv_v: 0.4  # image HSV-Value augmentation (fraction)\ndegrees: 0.0  # image rotation (+/- deg)\ntranslate: 0.10  # image translation (+/- fraction)\nscale: 0.5  # image scale (+/- gain)\nshear: 0.0  # image shear (+/- deg)\nperspective: 0.0  # image perspective (+/- fraction), range 0-0.001\nflipud: 0.5  # image flip up-down (probability)\nfliplr: 0.5  # image flip left-right (probability)\nmosaic: 0.5  # image mosaic (probability)\nmixup: 0.5 # image mixup (probability)\ncopy_paste: 0.0  # segment copy-paste (probability)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-02-03T12:23:59.602822Z","iopub.execute_input":"2022-02-03T12:23:59.603311Z","iopub.status.idle":"2022-02-03T12:23:59.610246Z","shell.execute_reply.started":"2022-02-03T12:23:59.603276Z","shell.execute_reply":"2022-02-03T12:23:59.609483Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📦 [YOLOv5](https://github.com/ultralytics/yolov5/)","metadata":{}},{"cell_type":"code","source":"%cd /kaggle/working\n!rm -r /kaggle/working/yolov5\n# !git clone https://github.com/ultralytics/yolov5 # clone\n!cp -r /kaggle/input/yolov5-lib-ds /kaggle/working/yolov5\n%cd yolov5\n%pip install -qr requirements.txt  # install\n\nfrom yolov5 import utils\ndisplay = utils.notebook_init()  # check","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:23:59.611601Z","iopub.execute_input":"2022-02-03T12:23:59.612073Z","iopub.status.idle":"2022-02-03T12:24:12.291077Z","shell.execute_reply.started":"2022-02-03T12:23:59.612038Z","shell.execute_reply":"2022-02-03T12:24:12.290195Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🚅 Training","metadata":{}},{"cell_type":"code","source":"!python train.py --img {DIM}\\\n--batch {BATCH}\\\n--epochs {EPOCHS}\\\n--data /kaggle/working/gbr.yaml\\\n--hyp /kaggle/working/hyp.yaml\\\n--weights {MODEL}.pt\\\n--optimizer {OPTIM}\\\n--project {PROJECT} --name {NAME}\\\n--exist-ok","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-02-03T12:24:12.292782Z","iopub.execute_input":"2022-02-03T12:24:12.293699Z","iopub.status.idle":"2022-02-03T12:27:53.010773Z","shell.execute_reply.started":"2022-02-03T12:24:12.29365Z","shell.execute_reply":"2022-02-03T12:27:53.009887Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ✨ Overview","metadata":{}},{"cell_type":"markdown","source":"## Output Files","metadata":{}},{"cell_type":"code","source":"OUTPUT_DIR = '{}/{}'.format(PROJECT, NAME)\n!ls {OUTPUT_DIR}","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-02-03T12:27:53.014875Z","iopub.execute_input":"2022-02-03T12:27:53.015386Z","iopub.status.idle":"2022-02-03T12:27:53.778407Z","shell.execute_reply.started":"2022-02-03T12:27:53.015347Z","shell.execute_reply":"2022-02-03T12:27:53.777615Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📈 Class Distribution","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (10,10))\nplt.axis('off')\nplt.imshow(plt.imread(f'{OUTPUT_DIR}/labels_correlogram.jpg'));","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-02-03T12:27:53.781368Z","iopub.execute_input":"2022-02-03T12:27:53.781593Z","iopub.status.idle":"2022-02-03T12:27:54.602482Z","shell.execute_reply.started":"2022-02-03T12:27:53.781564Z","shell.execute_reply":"2022-02-03T12:27:54.601553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize = (10,10))\nplt.axis('off')\nplt.imshow(plt.imread(f'{OUTPUT_DIR}/labels.jpg'));","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-02-03T12:27:54.604338Z","iopub.execute_input":"2022-02-03T12:27:54.605045Z","iopub.status.idle":"2022-02-03T12:27:55.31483Z","shell.execute_reply.started":"2022-02-03T12:27:54.605003Z","shell.execute_reply":"2022-02-03T12:27:55.314145Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🔭 Batch Image","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nplt.figure(figsize = (10, 10))\nplt.imshow(plt.imread(f'{OUTPUT_DIR}/train_batch0.jpg'))\n\nplt.figure(figsize = (10, 10))\nplt.imshow(plt.imread(f'{OUTPUT_DIR}/train_batch1.jpg'))\n\nplt.figure(figsize = (10, 10))\nplt.imshow(plt.imread(f'{OUTPUT_DIR}/train_batch2.jpg'))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-02-03T12:27:55.316108Z","iopub.execute_input":"2022-02-03T12:27:55.316497Z","iopub.status.idle":"2022-02-03T12:27:57.813941Z","shell.execute_reply.started":"2022-02-03T12:27:55.316461Z","shell.execute_reply":"2022-02-03T12:27:57.813289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## GT Vs Pred","metadata":{}},{"cell_type":"code","source":"fig, ax = plt.subplots(3, 2, figsize = (2*9,3*5), constrained_layout = True)\nfor row in range(3):\n    ax[row][0].imshow(plt.imread(f'{OUTPUT_DIR}/val_batch{row}_labels.jpg'))\n    ax[row][0].set_xticks([])\n    ax[row][0].set_yticks([])\n    ax[row][0].set_title(f'{OUTPUT_DIR}/val_batch{row}_labels.jpg', fontsize = 12)\n    \n    ax[row][1].imshow(plt.imread(f'{OUTPUT_DIR}/val_batch{row}_pred.jpg'))\n    ax[row][1].set_xticks([])\n    ax[row][1].set_yticks([])\n    ax[row][1].set_title(f'{OUTPUT_DIR}/val_batch{row}_pred.jpg', fontsize = 12)\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-02-03T12:27:57.815155Z","iopub.execute_input":"2022-02-03T12:27:57.815699Z","iopub.status.idle":"2022-02-03T12:27:58.923098Z","shell.execute_reply.started":"2022-02-03T12:27:57.81566Z","shell.execute_reply":"2022-02-03T12:27:58.921183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🔍 Result","metadata":{}},{"cell_type":"markdown","source":"## Score Vs Epoch","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(30,15))\nplt.axis('off')\nplt.imshow(plt.imread(f'{OUTPUT_DIR}/results.png'));","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-02-03T12:27:58.925154Z","iopub.status.idle":"2022-02-03T12:27:58.925502Z","shell.execute_reply.started":"2022-02-03T12:27:58.92533Z","shell.execute_reply":"2022-02-03T12:27:58.925352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Confusion Matrix","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(12,10))\nplt.axis('off')\nplt.imshow(plt.imread(f'{OUTPUT_DIR}/confusion_matrix.png'));","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-02-03T12:27:58.929393Z","iopub.status.idle":"2022-02-03T12:27:58.929686Z","shell.execute_reply.started":"2022-02-03T12:27:58.929532Z","shell.execute_reply":"2022-02-03T12:27:58.929553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Metrics","metadata":{}},{"cell_type":"code","source":"for metric in ['F1', 'PR', 'P', 'R']:\n    print(f'Metric: {metric}')\n    plt.figure(figsize=(12,10))\n    plt.axis('off')\n    plt.imshow(plt.imread(f'{OUTPUT_DIR}/{metric}_curve.png'));\n    plt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-02-03T12:27:58.931083Z","iopub.status.idle":"2022-02-03T12:27:58.93149Z","shell.execute_reply.started":"2022-02-03T12:27:58.931267Z","shell.execute_reply":"2022-02-03T12:27:58.931289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Please Upvote if you find this Helpful","metadata":{}},{"cell_type":"markdown","source":"# ✂️ Remove Files","metadata":{}},{"cell_type":"code","source":"!rm -r {IMAGE_DIR}\n!rm -r {LABEL_DIR}","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:27:58.93316Z","iopub.status.idle":"2022-02-03T12:27:58.933588Z","shell.execute_reply.started":"2022-02-03T12:27:58.933364Z","shell.execute_reply":"2022-02-03T12:27:58.933388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<img src=\"https://www.pngall.com/wp-content/uploads/2018/04/Under-Construction-PNG-File.png\">","metadata":{}}]}