{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "aGYwt_UjIrqp"
   },
   "source": [
    "# Rotated Object Detection\n",
    "\n",
    "In this tutorial, you will learn:\n",
    "- the basic structure of Oriented R-CNN.\n",
    "- to perform inference with a MMRotate detector.\n",
    "- to perform inference on huge image.\n",
    "\n",
    "Let's start!\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "tJxJHruNLb7Y"
   },
   "source": [
    "## Install MMRotate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Wi4LPmsR66sy",
    "outputId": "d1ce765a-c575-475a-d225-9b4af8fc9001"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "nvcc: NVIDIA (R) Cuda compiler driver\n",
      "Copyright (c) 2005-2020 NVIDIA Corporation\n",
      "Built on Mon_Oct_12_20:09:46_PDT_2020\n",
      "Cuda compilation tools, release 11.1, V11.1.105\n",
      "Build cuda_11.1.TC455_06.29190527_0\n",
      "gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0\n",
      "Copyright (C) 2017 Free Software Foundation, Inc.\n",
      "This is free software; see the source for copying conditions.  There is NO\n",
      "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# Check nvcc version\n",
    "!nvcc -V\n",
    "# Check GCC version\n",
    "!gcc --version"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "gkGnB9WyHSXB",
    "outputId": "a5fc82fb-03f5-43a7-f7a6-dff31e582b70"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Looking in links: https://download.pytorch.org/whl/torch_stable.html\n",
      "Collecting torch==1.9.0+cu111\n",
      "  Downloading https://download.pytorch.org/whl/cu111/torch-1.9.0%2Bcu111-cp37-cp37m-linux_x86_64.whl (2041.3 MB)\n",
      "\u001B[K     |█████████████                   | 834.1 MB 1.5 MB/s eta 0:13:16tcmalloc: large alloc 1147494400 bytes == 0x55fc26d26000 @  0x7f7753dc6615 0x55fbed75417c 0x55fbed83447a 0x55fbed756f9d 0x55fbed848d4d 0x55fbed7caec8 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7cad30 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c7719 0x55fbed849b76 0x55fbed7c6d95 0x55fbed849b76 0x55fbed7c6d95 0x55fbed849b76 0x55fbed7c6d95 0x55fbed758ce9 0x55fbed79c579 0x55fbed757902 0x55fbed7cac4d 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c7719 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c68f6 0x55fbed7587aa 0x55fbed7c6b4f 0x55fbed7c5a2e\n",
      "\u001B[K     |████████████████▌               | 1055.7 MB 1.4 MB/s eta 0:11:52tcmalloc: large alloc 1434370048 bytes == 0x55fc6b37c000 @  0x7f7753dc6615 0x55fbed75417c 0x55fbed83447a 0x55fbed756f9d 0x55fbed848d4d 0x55fbed7caec8 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7cad30 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c7719 0x55fbed849b76 0x55fbed7c6d95 0x55fbed849b76 0x55fbed7c6d95 0x55fbed849b76 0x55fbed7c6d95 0x55fbed758ce9 0x55fbed79c579 0x55fbed757902 0x55fbed7cac4d 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c7719 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c68f6 0x55fbed7587aa 0x55fbed7c6b4f 0x55fbed7c5a2e\n",
      "\u001B[K     |█████████████████████           | 1336.2 MB 1.4 MB/s eta 0:08:26tcmalloc: large alloc 1792966656 bytes == 0x55fbf01ae000 @  0x7f7753dc6615 0x55fbed75417c 0x55fbed83447a 0x55fbed756f9d 0x55fbed848d4d 0x55fbed7caec8 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7cad30 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c7719 0x55fbed849b76 0x55fbed7c6d95 0x55fbed849b76 0x55fbed7c6d95 0x55fbed849b76 0x55fbed7c6d95 0x55fbed758ce9 0x55fbed79c579 0x55fbed757902 0x55fbed7cac4d 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c7719 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c68f6 0x55fbed7587aa 0x55fbed7c6b4f 0x55fbed7c5a2e\n",
      "\u001B[K     |██████████████████████████▌     | 1691.1 MB 1.3 MB/s eta 0:04:23tcmalloc: large alloc 2241208320 bytes == 0x55fc5af96000 @  0x7f7753dc6615 0x55fbed75417c 0x55fbed83447a 0x55fbed756f9d 0x55fbed848d4d 0x55fbed7caec8 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7cad30 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c7719 0x55fbed849b76 0x55fbed7c6d95 0x55fbed849b76 0x55fbed7c6d95 0x55fbed849b76 0x55fbed7c6d95 0x55fbed758ce9 0x55fbed79c579 0x55fbed757902 0x55fbed7cac4d 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c7719 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c68f6 0x55fbed7587aa 0x55fbed7c6b4f 0x55fbed7c5a2e\n",
      "\u001B[K     |████████████████████████████████| 2041.3 MB 1.3 MB/s eta 0:00:01tcmalloc: large alloc 2041348096 bytes == 0x55fce08f8000 @  0x7f7753dc51e7 0x55fbed78a407 0x55fbed75417c 0x55fbed83447a 0x55fbed756f9d 0x55fbed848d4d 0x55fbed7caec8 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c6b4f 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c6b4f 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c6b4f 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c6b4f 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c6b4f 0x55fbed7587aa 0x55fbed7c6b4f 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c7719 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c7719 0x55fbed7c5a2e\n",
      "tcmalloc: large alloc 2551685120 bytes == 0x55fdce844000 @  0x7f7753dc6615 0x55fbed75417c 0x55fbed83447a 0x55fbed756f9d 0x55fbed848d4d 0x55fbed7caec8 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c6b4f 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c6b4f 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c6b4f 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c6b4f 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c6b4f 0x55fbed7587aa 0x55fbed7c6b4f 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c7719 0x55fbed7c5a2e 0x55fbed75888a 0x55fbed7c7719 0x55fbed7c5a2e 0x55fbed758f21\n",
      "\u001B[K     |████████████████████████████████| 2041.3 MB 7.2 kB/s \n",
      "\u001B[?25hCollecting torchvision==0.10.0+cu111\n",
      "  Downloading https://download.pytorch.org/whl/cu111/torchvision-0.10.0%2Bcu111-cp37-cp37m-linux_x86_64.whl (23.2 MB)\n",
      "\u001B[K     |████████████████████████████████| 23.2 MB 36.8 MB/s \n",
      "\u001B[?25hRequirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from torch==1.9.0+cu111) (3.10.0.2)\n",
      "Requirement already satisfied: pillow>=5.3.0 in /usr/local/lib/python3.7/dist-packages (from torchvision==0.10.0+cu111) (7.1.2)\n",
      "Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from torchvision==0.10.0+cu111) (1.21.5)\n",
      "Installing collected packages: torch, torchvision\n",
      "  Attempting uninstall: torch\n",
      "    Found existing installation: torch 1.10.0+cu111\n",
      "    Uninstalling torch-1.10.0+cu111:\n",
      "      Successfully uninstalled torch-1.10.0+cu111\n",
      "  Attempting uninstall: torchvision\n",
      "    Found existing installation: torchvision 0.11.1+cu111\n",
      "    Uninstalling torchvision-0.11.1+cu111:\n",
      "      Successfully uninstalled torchvision-0.11.1+cu111\n",
      "\u001B[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
      "torchtext 0.11.0 requires torch==1.10.0, but you have torch 1.9.0+cu111 which is incompatible.\n",
      "torchaudio 0.10.0+cu111 requires torch==1.10.0, but you have torch 1.9.0+cu111 which is incompatible.\u001B[0m\n",
      "Successfully installed torch-1.9.0+cu111 torchvision-0.10.0+cu111\n",
      "Looking in links: https://download.openmmlab.com/mmcv/dist/cu111/torch1.9.0/index.html\n",
      "Collecting mmcv-full\n",
      "  Downloading https://download.openmmlab.com/mmcv/dist/cu111/torch1.9.0/mmcv_full-1.4.8-cp37-cp37m-manylinux1_x86_64.whl (44.9 MB)\n",
      "\u001B[K     |████████████████████████████████| 44.9 MB 9.1 MB/s \n",
      "\u001B[?25hRequirement already satisfied: Pillow in /usr/local/lib/python3.7/dist-packages (from mmcv-full) (7.1.2)\n",
      "Requirement already satisfied: opencv-python>=3 in /usr/local/lib/python3.7/dist-packages (from mmcv-full) (4.1.2.30)\n",
      "Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from mmcv-full) (1.21.5)\n",
      "Requirement already satisfied: pyyaml in /usr/local/lib/python3.7/dist-packages (from mmcv-full) (3.13)\n",
      "Requirement already satisfied: packaging in /usr/local/lib/python3.7/dist-packages (from mmcv-full) (21.3)\n",
      "Collecting addict\n",
      "  Downloading addict-2.4.0-py3-none-any.whl (3.8 kB)\n",
      "Collecting yapf\n",
      "  Downloading yapf-0.32.0-py2.py3-none-any.whl (190 kB)\n",
      "\u001B[K     |████████████████████████████████| 190 kB 5.2 MB/s \n",
      "\u001B[?25hRequirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in /usr/local/lib/python3.7/dist-packages (from packaging->mmcv-full) (3.0.7)\n",
      "Installing collected packages: yapf, addict, mmcv-full\n",
      "Successfully installed addict-2.4.0 mmcv-full-1.4.8 yapf-0.32.0\n",
      "Collecting mmdet\n",
      "  Downloading mmdet-2.23.0-py3-none-any.whl (1.4 MB)\n",
      "\u001B[K     |████████████████████████████████| 1.4 MB 5.3 MB/s \n",
      "\u001B[?25hRequirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from mmdet) (1.15.0)\n",
      "Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from mmdet) (1.21.5)\n",
      "Requirement already satisfied: pycocotools in /usr/local/lib/python3.7/dist-packages (from mmdet) (2.0.4)\n",
      "Requirement already satisfied: matplotlib in /usr/local/lib/python3.7/dist-packages (from mmdet) (3.2.2)\n",
      "Collecting terminaltables\n",
      "  Downloading terminaltables-3.1.10-py2.py3-none-any.whl (15 kB)\n",
      "Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmdet) (2.8.2)\n",
      "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmdet) (1.4.0)\n",
      "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmdet) (0.11.0)\n",
      "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmdet) (3.0.7)\n",
      "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from kiwisolver>=1.0.1->matplotlib->mmdet) (3.10.0.2)\n",
      "Installing collected packages: terminaltables, mmdet\n",
      "Successfully installed mmdet-2.23.0 terminaltables-3.1.10\n",
      "Cloning into 'mmrotate'...\n",
      "remote: Enumerating objects: 1477, done.\u001B[K\n",
      "remote: Counting objects: 100% (238/238), done.\u001B[K\n",
      "remote: Compressing objects: 100% (190/190), done.\u001B[K\n",
      "remote: Total 1477 (delta 106), reused 102 (delta 47), pack-reused 1239\u001B[K\n",
      "Receiving objects: 100% (1477/1477), 19.97 MiB | 23.56 MiB/s, done.\n",
      "Resolving deltas: 100% (789/789), done.\n",
      "/content/mmrotate\n",
      "Obtaining file:///content/mmrotate\n",
      "Collecting e2cnn\n",
      "  Downloading e2cnn-0.2.1-py3-none-any.whl (224 kB)\n",
      "\u001B[K     |████████████████████████████████| 224 kB 5.3 MB/s \n",
      "\u001B[?25hRequirement already satisfied: matplotlib in /usr/local/lib/python3.7/dist-packages (from mmrotate==0.1.1) (3.2.2)\n",
      "Requirement already satisfied: mmcv-full in /usr/local/lib/python3.7/dist-packages (from mmrotate==0.1.1) (1.4.8)\n",
      "Requirement already satisfied: mmdet in /usr/local/lib/python3.7/dist-packages (from mmrotate==0.1.1) (2.23.0)\n",
      "Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from mmrotate==0.1.1) (1.21.5)\n",
      "Requirement already satisfied: pycocotools in /usr/local/lib/python3.7/dist-packages (from mmrotate==0.1.1) (2.0.4)\n",
      "Requirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from mmrotate==0.1.1) (1.15.0)\n",
      "Requirement already satisfied: terminaltables in /usr/local/lib/python3.7/dist-packages (from mmrotate==0.1.1) (3.1.10)\n",
      "Requirement already satisfied: torch in /usr/local/lib/python3.7/dist-packages (from mmrotate==0.1.1) (1.9.0+cu111)\n",
      "Requirement already satisfied: sympy in /usr/local/lib/python3.7/dist-packages (from e2cnn->mmrotate==0.1.1) (1.7.1)\n",
      "Requirement already satisfied: scipy in /usr/local/lib/python3.7/dist-packages (from e2cnn->mmrotate==0.1.1) (1.4.1)\n",
      "Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmrotate==0.1.1) (2.8.2)\n",
      "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmrotate==0.1.1) (1.4.0)\n",
      "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmrotate==0.1.1) (3.0.7)\n",
      "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmrotate==0.1.1) (0.11.0)\n",
      "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from kiwisolver>=1.0.1->matplotlib->mmrotate==0.1.1) (3.10.0.2)\n",
      "Requirement already satisfied: addict in /usr/local/lib/python3.7/dist-packages (from mmcv-full->mmrotate==0.1.1) (2.4.0)\n",
      "Requirement already satisfied: yapf in /usr/local/lib/python3.7/dist-packages (from mmcv-full->mmrotate==0.1.1) (0.32.0)\n",
      "Requirement already satisfied: pyyaml in /usr/local/lib/python3.7/dist-packages (from mmcv-full->mmrotate==0.1.1) (3.13)\n",
      "Requirement already satisfied: opencv-python>=3 in /usr/local/lib/python3.7/dist-packages (from mmcv-full->mmrotate==0.1.1) (4.1.2.30)\n",
      "Requirement already satisfied: packaging in /usr/local/lib/python3.7/dist-packages (from mmcv-full->mmrotate==0.1.1) (21.3)\n",
      "Requirement already satisfied: Pillow in /usr/local/lib/python3.7/dist-packages (from mmcv-full->mmrotate==0.1.1) (7.1.2)\n",
      "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.7/dist-packages (from sympy->e2cnn->mmrotate==0.1.1) (1.2.1)\n",
      "Installing collected packages: e2cnn, mmrotate\n",
      "  Running setup.py develop for mmrotate\n",
      "Successfully installed e2cnn-0.2.1 mmrotate-0.1.1\n",
      "Branch 'show_result' set up to track remote branch 'show_result' from 'origin'.\n",
      "Switched to a new branch 'show_result'\n",
      "  main\u001B[m\n",
      "* \u001B[32mshow_result\u001B[m\n",
      "  \u001B[31mremotes/origin/HEAD\u001B[m -> origin/main\n",
      "  \u001B[31mremotes/origin/csl\u001B[m\n",
      "  \u001B[31mremotes/origin/evalmap\u001B[m\n",
      "  \u001B[31mremotes/origin/fcos\u001B[m\n",
      "  \u001B[31mremotes/origin/get_flops\u001B[m\n",
      "  \u001B[31mremotes/origin/hrsc\u001B[m\n",
      "  \u001B[31mremotes/origin/hrsc2\u001B[m\n",
      "  \u001B[31mremotes/origin/init_cfg\u001B[m\n",
      "  \u001B[31mremotes/origin/main\u001B[m\n",
      "  \u001B[31mremotes/origin/show_result\u001B[m\n"
     ]
    }
   ],
   "source": [
    "# install dependencies: (use cu111 because colab has CUDA 11.1)\n",
    "!pip install torch==1.9.0+cu111 torchvision==0.10.0+cu111 -f https://download.pytorch.org/whl/torch_stable.html\n",
    "\n",
    "# install mmcv-full thus we could use CUDA operators\n",
    "!pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cu111/torch1.9.0/index.html\n",
    "\n",
    "# Install mmdetection\n",
    "!pip install mmdet\n",
    "\n",
    "# Install mmrotate\n",
    "!rm -rf mmrotate\n",
    "!git clone https://github.com/open-mmlab/mmrotate.git\n",
    "%cd mmrotate\n",
    "!pip install -e .\n",
    "\n",
    "# switch branch\n",
    "!git checkout dev\n",
    "!git branch -a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "_YeUiqAoCaoV",
    "outputId": "7c381baa-e322-490f-b4f3-9a46b71b3135"
   },
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "{'CUDA available': True,\n",
       " 'CUDA_HOME': '/usr/local/cuda',\n",
       " 'GCC': 'gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0',\n",
       " 'GPU 0': 'Tesla K80',\n",
       " 'MMCV': '1.4.8',\n",
       " 'MMCV CUDA Compiler': '11.1',\n",
       " 'MMCV Compiler': 'GCC 7.3',\n",
       " 'NVCC': 'Build cuda_11.1.TC455_06.29190527_0',\n",
       " 'OpenCV': '4.1.2',\n",
       " 'PyTorch': '1.9.0+cu111',\n",
       " 'PyTorch compiling details': 'PyTorch built with:\\n  - GCC 7.3\\n  - C++ Version: 201402\\n  - Intel(R) Math Kernel Library Version 2020.0.0 Product Build 20191122 for Intel(R) 64 architecture applications\\n  - Intel(R) MKL-DNN v2.1.2 (Git Hash 98be7e8afa711dc9b66c8ff3504129cb82013cdb)\\n  - OpenMP 201511 (a.k.a. OpenMP 4.5)\\n  - NNPACK is enabled\\n  - CPU capability usage: AVX2\\n  - CUDA Runtime 11.1\\n  - NVCC architecture flags: -gencode;arch=compute_37,code=sm_37;-gencode;arch=compute_50,code=sm_50;-gencode;arch=compute_60,code=sm_60;-gencode;arch=compute_70,code=sm_70;-gencode;arch=compute_75,code=sm_75;-gencode;arch=compute_80,code=sm_80;-gencode;arch=compute_86,code=sm_86\\n  - CuDNN 8.0.5\\n  - Magma 2.5.2\\n  - Build settings: BLAS_INFO=mkl, BUILD_TYPE=Release, CUDA_VERSION=11.1, CUDNN_VERSION=8.0.5, CXX_COMPILER=/opt/rh/devtoolset-7/root/usr/bin/c++, CXX_FLAGS= -Wno-deprecated -fvisibility-inlines-hidden -DUSE_PTHREADPOOL -fopenmp -DNDEBUG -DUSE_KINETO -DUSE_FBGEMM -DUSE_QNNPACK -DUSE_PYTORCH_QNNPACK -DUSE_XNNPACK -DSYMBOLICATE_MOBILE_DEBUG_HANDLE -O2 -fPIC -Wno-narrowing -Wall -Wextra -Werror=return-type -Wno-missing-field-initializers -Wno-type-limits -Wno-array-bounds -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-unused-result -Wno-unused-local-typedefs -Wno-strict-overflow -Wno-strict-aliasing -Wno-error=deprecated-declarations -Wno-stringop-overflow -Wno-psabi -Wno-error=pedantic -Wno-error=redundant-decls -Wno-error=old-style-cast -fdiagnostics-color=always -faligned-new -Wno-unused-but-set-variable -Wno-maybe-uninitialized -fno-math-errno -fno-trapping-math -Werror=format -Wno-stringop-overflow, LAPACK_INFO=mkl, PERF_WITH_AVX=1, PERF_WITH_AVX2=1, PERF_WITH_AVX512=1, TORCH_VERSION=1.9.0, USE_CUDA=ON, USE_CUDNN=ON, USE_EXCEPTION_PTR=1, USE_GFLAGS=OFF, USE_GLOG=OFF, USE_MKL=ON, USE_MKLDNN=ON, USE_MPI=OFF, USE_NCCL=ON, USE_NNPACK=ON, USE_OPENMP=ON, \\n',\n",
       " 'Python': '3.7.13 (default, Mar 16 2022, 17:37:17) [GCC 7.5.0]',\n",
       " 'TorchVision': '0.10.0+cu111',\n",
       " 'sys.platform': 'linux'}"
      ]
     },
     "metadata": {},
     "execution_count": 4
    }
   ],
   "source": [
    "from mmcv import collect_env\n",
    "collect_env()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "6hD0mmMixT0p",
    "outputId": "ec858f36-2065-45e3-910f-f982c390efbb"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "1.9.0+cu111 True\n",
      "0.2.0\n",
      "2.23.0\n",
      "11.1\n",
      "GCC 7.3\n"
     ]
    }
   ],
   "source": [
    "# Check Pytorch installation\n",
    "import torch, torchvision\n",
    "print(torch.__version__, torch.cuda.is_available())\n",
    "\n",
    "# Check MMRotate installation\n",
    "import mmrotate\n",
    "print(mmrotate.__version__)\n",
    "\n",
    "# Check MMDetection installation\n",
    "import mmdet\n",
    "print(mmdet.__version__)\n",
    "\n",
    "# Check mmcv installation\n",
    "from mmcv.ops import get_compiling_cuda_version, get_compiler_version\n",
    "print(get_compiling_cuda_version())\n",
    "print(get_compiler_version())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "gi9zw03oM4CH"
   },
   "source": [
    "## Perform Inference with An MMRotate detector\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "s99mDGBG1S1z"
   },
   "source": [
    "### A two-stage detector\n",
    "\n",
    "In this tutorial, we use Oriented R-CNN, a simple two-stage detector as an example.\n",
    "\n",
    "The high-level architecture of Oriented R-CNN is shown in the following picture. More details can be found in the [paper](https://openaccess.thecvf.com/content/ICCV2021/papers/Xie_Oriented_R-CNN_for_Object_Detection_ICCV_2021_paper.pdf).\n",
    "\n",
    "![oriented rcnn](https://raw.githubusercontent.com/zytx121/image-host/main/imgs/oriented_rcnn.png)\n",
    "\n",
    "\n",
    "Briefly, it uses a convolutional neural network (CNN) as backbone to extract features from an image. Then, it uses a region proposal network (RPN) to predict proposals, i.e., potential objects. After that, it uses `RoIAlignRotated` to crop rotated features for the region of interests (RoI), and uses a RoI Head to perform classification and bounding box prediction.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "j4doHX4exvS1",
    "outputId": "ddcaf58a-0342-4ac3-fccb-0fdcf34ba965"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "--2022-04-06 01:55:41--  https://download.openmmlab.com/mmrotate/v0.1.0/oriented_rcnn/oriented_rcnn_r50_fpn_1x_dota_le90/oriented_rcnn_r50_fpn_1x_dota_le90-6d2b2ce0.pth\n",
      "Resolving download.openmmlab.com (download.openmmlab.com)... 47.252.96.28\n",
      "Connecting to download.openmmlab.com (download.openmmlab.com)|47.252.96.28|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 165749436 (158M) [application/octet-stream]\n",
      "Saving to: ‘checkpoints/oriented_rcnn_r50_fpn_1x_dota_le90-6d2b2ce0.pth’\n",
      "\n",
      "checkpoints/oriente 100%[===================>] 158.07M  8.98MB/s    in 19s     \n",
      "\n",
      "2022-04-06 01:56:01 (8.18 MB/s) - ‘checkpoints/oriented_rcnn_r50_fpn_1x_dota_le90-6d2b2ce0.pth’ saved [165749436/165749436]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# We download the pre-trained checkpoints for inference and finetuning.\n",
    "!mkdir checkpoints\n",
    "!wget -c https://download.openmmlab.com/mmrotate/v0.1.0/oriented_rcnn/oriented_rcnn_r50_fpn_1x_dota_le90/oriented_rcnn_r50_fpn_1x_dota_le90-6d2b2ce0.pth \\\n",
    "      -O checkpoints/oriented_rcnn_r50_fpn_1x_dota_le90-6d2b2ce0.pth"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "8M5KUnX7Np3h",
    "outputId": "7032e171-00e6-4c08-e526-74ec9a063a40"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "/usr/local/lib/python3.7/dist-packages/mmdet/models/dense_heads/anchor_head.py:116: UserWarning: DeprecationWarning: `num_anchors` is deprecated, for consistency or also use `num_base_priors` instead\n",
      "  warnings.warn('DeprecationWarning: `num_anchors` is deprecated, '\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "load checkpoint from local path: checkpoints/oriented_rcnn_r50_fpn_1x_dota_le90-6d2b2ce0.pth\n"
     ]
    },
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "OrientedRCNN(\n",
       "  (backbone): ResNet(\n",
       "    (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)\n",
       "    (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "    (relu): ReLU(inplace=True)\n",
       "    (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)\n",
       "    (layer1): ResLayer(\n",
       "      (0): Bottleneck(\n",
       "        (conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "        (downsample): Sequential(\n",
       "          (0): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "          (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        )\n",
       "      )\n",
       "      (1): Bottleneck(\n",
       "        (conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "      )\n",
       "      (2): Bottleneck(\n",
       "        (conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "      )\n",
       "    )\n",
       "    (layer2): ResLayer(\n",
       "      (0): Bottleneck(\n",
       "        (conv1): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "        (downsample): Sequential(\n",
       "          (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)\n",
       "          (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        )\n",
       "      )\n",
       "      (1): Bottleneck(\n",
       "        (conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "      )\n",
       "      (2): Bottleneck(\n",
       "        (conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "      )\n",
       "      (3): Bottleneck(\n",
       "        (conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "      )\n",
       "    )\n",
       "    (layer3): ResLayer(\n",
       "      (0): Bottleneck(\n",
       "        (conv1): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "        (downsample): Sequential(\n",
       "          (0): Conv2d(512, 1024, kernel_size=(1, 1), stride=(2, 2), bias=False)\n",
       "          (1): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        )\n",
       "      )\n",
       "      (1): Bottleneck(\n",
       "        (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "      )\n",
       "      (2): Bottleneck(\n",
       "        (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "      )\n",
       "      (3): Bottleneck(\n",
       "        (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "      )\n",
       "      (4): Bottleneck(\n",
       "        (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "      )\n",
       "      (5): Bottleneck(\n",
       "        (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "      )\n",
       "    )\n",
       "    (layer4): ResLayer(\n",
       "      (0): Bottleneck(\n",
       "        (conv1): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "        (downsample): Sequential(\n",
       "          (0): Conv2d(1024, 2048, kernel_size=(1, 1), stride=(2, 2), bias=False)\n",
       "          (1): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        )\n",
       "      )\n",
       "      (1): Bottleneck(\n",
       "        (conv1): Conv2d(2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "      )\n",
       "      (2): Bottleneck(\n",
       "        (conv1): Conv2d(2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "        (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)\n",
       "        (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "        (relu): ReLU(inplace=True)\n",
       "      )\n",
       "    )\n",
       "  )\n",
       "  init_cfg={'type': 'Pretrained', 'checkpoint': 'torchvision://resnet50'}\n",
       "  (neck): FPN(\n",
       "    (lateral_convs): ModuleList(\n",
       "      (0): ConvModule(\n",
       "        (conv): Conv2d(256, 256, kernel_size=(1, 1), stride=(1, 1))\n",
       "      )\n",
       "      (1): ConvModule(\n",
       "        (conv): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1))\n",
       "      )\n",
       "      (2): ConvModule(\n",
       "        (conv): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))\n",
       "      )\n",
       "      (3): ConvModule(\n",
       "        (conv): Conv2d(2048, 256, kernel_size=(1, 1), stride=(1, 1))\n",
       "      )\n",
       "    )\n",
       "    (fpn_convs): ModuleList(\n",
       "      (0): ConvModule(\n",
       "        (conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
       "      )\n",
       "      (1): ConvModule(\n",
       "        (conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
       "      )\n",
       "      (2): ConvModule(\n",
       "        (conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
       "      )\n",
       "      (3): ConvModule(\n",
       "        (conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
       "      )\n",
       "    )\n",
       "  )\n",
       "  init_cfg={'type': 'Xavier', 'layer': 'Conv2d', 'distribution': 'uniform'}\n",
       "  (rpn_head): OrientedRPNHead(\n",
       "    (loss_cls): CrossEntropyLoss(avg_non_ignore=False)\n",
       "    (loss_bbox): SmoothL1Loss()\n",
       "    (rpn_conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
       "    (rpn_cls): Conv2d(256, 3, kernel_size=(1, 1), stride=(1, 1))\n",
       "    (rpn_reg): Conv2d(256, 18, kernel_size=(1, 1), stride=(1, 1))\n",
       "  )\n",
       "  init_cfg={'type': 'Normal', 'layer': 'Conv2d', 'std': 0.01}\n",
       "  (roi_head): OrientedStandardRoIHead(\n",
       "    (bbox_roi_extractor): RotatedSingleRoIExtractor(\n",
       "      (roi_layers): ModuleList(\n",
       "        (0): RoIAlignRotated(output_size=(7, 7), spatial_scale=0.25, sampling_ratio=2, aligned=True, clockwise=True)\n",
       "        (1): RoIAlignRotated(output_size=(7, 7), spatial_scale=0.125, sampling_ratio=2, aligned=True, clockwise=True)\n",
       "        (2): RoIAlignRotated(output_size=(7, 7), spatial_scale=0.0625, sampling_ratio=2, aligned=True, clockwise=True)\n",
       "        (3): RoIAlignRotated(output_size=(7, 7), spatial_scale=0.03125, sampling_ratio=2, aligned=True, clockwise=True)\n",
       "      )\n",
       "    )\n",
       "    (bbox_head): RotatedShared2FCBBoxHead(\n",
       "      (loss_cls): CrossEntropyLoss(avg_non_ignore=False)\n",
       "      (loss_bbox): SmoothL1Loss()\n",
       "      (fc_cls): Linear(in_features=1024, out_features=16, bias=True)\n",
       "      (fc_reg): Linear(in_features=1024, out_features=5, bias=True)\n",
       "      (shared_convs): ModuleList()\n",
       "      (shared_fcs): ModuleList(\n",
       "        (0): Linear(in_features=12544, out_features=1024, bias=True)\n",
       "        (1): Linear(in_features=1024, out_features=1024, bias=True)\n",
       "      )\n",
       "      (cls_convs): ModuleList()\n",
       "      (cls_fcs): ModuleList()\n",
       "      (reg_convs): ModuleList()\n",
       "      (reg_fcs): ModuleList()\n",
       "      (relu): ReLU(inplace=True)\n",
       "    )\n",
       "    init_cfg=[{'type': 'Normal', 'std': 0.01, 'override': {'name': 'fc_cls'}}, {'type': 'Normal', 'std': 0.001, 'override': {'name': 'fc_reg'}}, {'type': 'Xavier', 'layer': 'Linear', 'override': [{'name': 'shared_fcs'}, {'name': 'cls_fcs'}, {'name': 'reg_fcs'}]}]\n",
       "  )\n",
       ")"
      ]
     },
     "metadata": {},
     "execution_count": 7
    }
   ],
   "source": [
    "import mmcv\n",
    "from mmcv.runner import load_checkpoint\n",
    "\n",
    "from mmdet.apis import inference_detector, show_result_pyplot\n",
    "from mmrotate.models import build_detector\n",
    "\n",
    "# Choose to use a config and initialize the detector\n",
    "config = 'configs/oriented_rcnn/oriented_rcnn_r50_fpn_1x_dota_le90.py'\n",
    "# Setup a checkpoint file to load\n",
    "checkpoint = 'checkpoints/oriented_rcnn_r50_fpn_1x_dota_le90-6d2b2ce0.pth'\n",
    "\n",
    "# Set the device to be used for evaluation\n",
    "device='cuda:0'\n",
    "\n",
    "# Load the config\n",
    "config = mmcv.Config.fromfile(config)\n",
    "# Set pretrained to be None since we do not need pretrained model here\n",
    "config.model.pretrained = None\n",
    "\n",
    "# Initialize the detector\n",
    "model = build_detector(config.model)\n",
    "\n",
    "# Load checkpoint\n",
    "checkpoint = load_checkpoint(model, checkpoint, map_location=device)\n",
    "\n",
    "# Set the classes of models for inference\n",
    "model.CLASSES = checkpoint['meta']['CLASSES']\n",
    "\n",
    "# We need to set the model's cfg for inference\n",
    "model.cfg = config\n",
    "\n",
    "# Convert the model to GPU\n",
    "model.to(device)\n",
    "# Convert the model into evaluation mode\n",
    "model.eval()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "fLgFRMtP91ue"
   },
   "source": [
    "From the printed model, we will find that the model does consist of the components that we described earlier. It uses ResNet as its CNN backbone, and has a RPN head and RoI Head. In addition, the model has a neural network module, named neck, directly after the CNN backbone. It is a [feature pyramid network (FPN)](https://arxiv.org/abs/1612.03144) for enhancing the multi-scale features.\n",
    "\n",
    "\n",
    "### Inference the detector\n",
    "\n",
    "Since the model is successfully created and loaded, let's see how good it is. We use the high-level API `inference_detector` implemented in the MMDetection. This API is created to ease the inference process. The details of the codes can be found [here](https://github.com/open-mmlab/mmdetection/blob/master/mmdet/apis/inference.py#L15)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Wi6DRpsQPEmV",
    "outputId": "6fd94ce3-df8a-421e-db63-025ea52c8e37"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "/usr/local/lib/python3.7/dist-packages/torch/nn/functional.py:718: UserWarning: Named tensors and all their associated APIs are an experimental feature and subject to change. Please do not use them for anything important until they are released as stable. (Triggered internally at  /pytorch/c10/core/TensorImpl.h:1156.)\n",
      "  return torch.max_pool2d(input, kernel_size, stride, padding, dilation, ceil_mode)\n",
      "/usr/local/lib/python3.7/dist-packages/mmdet/models/dense_heads/anchor_head.py:123: UserWarning: DeprecationWarning: anchor_generator is deprecated, please use \"prior_generator\" instead\n",
      "  warnings.warn('DeprecationWarning: anchor_generator is deprecated, '\n"
     ]
    }
   ],
   "source": [
    "# Use the detector to do inference\n",
    "img = 'demo/demo.jpg'\n",
    "result = inference_detector(model, img)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 1000
    },
    "id": "UsJU5D-QPX8L",
    "outputId": "2494924d-5966-47c1-959d-2cc6afc24525"
   },
   "outputs": [
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<Figure size 1024.01x1024.01 with 1 Axes>"
      ],
      "image/png": "[encoded data, 2298532 characters]\n"
     },
     "metadata": {
      "needs_background": "light"
     }
    }
   ],
   "source": [
    "# Let's plot the result\n",
    "show_result_pyplot(model, img, result, score_thr=0.3, palette='dota')"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Inference on huge image\n",
    "Since small image can be successfully detected, what about huge images in remote sensing? We use the high-level API `inference_detector_by_patches` implemented in the MMRotate. This API is created to ease the inference process for huge image. The details of the codes can be found [here](https://github.com/open-mmlab/mmrotate/blob/dev/mmrotate/apis/inference.py)."
   ],
   "metadata": {
    "id": "CjtQeoaZTaRy"
   }
  },
  {
   "cell_type": "code",
   "source": [
    "# Use the detector to do inference\n",
    "from mmrotate.apis import inference_detector_by_patches\n",
    "img = 'demo/dota_demo.jpg'\n",
    "result = inference_detector_by_patches(model, img, [1024], [824], [1.0], 0.1)"
   ],
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "y6wcKulVTarC",
    "outputId": "092e00ae-6616-4581-d60d-a50809844881"
   },
   "execution_count": 10,
   "outputs": [
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "/usr/local/lib/python3.7/dist-packages/mmdet/models/dense_heads/anchor_head.py:123: UserWarning: DeprecationWarning: anchor_generator is deprecated, please use \"prior_generator\" instead\n",
      "  warnings.warn('DeprecationWarning: anchor_generator is deprecated, '\n"
     ]
    }
   ]
  },
  {
   "cell_type": "code",
   "source": [
    "# Let's plot the result\n",
    "show_result_pyplot(model, img, result, score_thr=0.3, palette='dota')"
   ],
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 1000
    },
    "id": "kepaXKQCUWoG",
    "outputId": "dbff10b2-bcbd-4b96-851d-35ec92e00f11"
   },
   "execution_count": 11,
   "outputs": [
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<Figure size 1616.01x1565.01 with 1 Axes>"
      ],
      "image/png": "[encoded data, 4143704 characters]\n"
     },
     "metadata": {
      "needs_background": "light"
     }
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "7GrWIJywLV-V"
   },
   "source": [
    "## Train a detector on customized dataset\n",
    "\n",
    "To train a new detector, there are usually three things to do:\n",
    "1. Support a new dataset\n",
    "2. Modify the config\n",
    "3. Train a new detector\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "E73y5Lru-wBx"
   },
   "source": [
    "### Support a new dataset\n",
    "\n",
    "There are three ways to support a new dataset in MMRotate: \n",
    "  1. reorganize the dataset into DOTA format.\n",
    "  2. reorganize the dataset into a middle format.\n",
    "  3. implement a new dataset.\n",
    "\n",
    "Usually we recommend to use the first two methods which are usually easier than the third.\n",
    "\n",
    "In this tutorial, we gives an example that converting the data into the format of existing datasets like DOTA, etc. Other methods and more advanced usages can be found in the [doc](https://mmrotate.readthedocs.io/en/latest/tutorials/customize_dataset.html).\n",
    "\n",
    "Firstly, let's download a SAR ship dataset obtained from [SSDD](https://github.com/TianwenZhang0825/Official-SSDD). We select the first 193 offshore images and their annotations from the dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "rHnw5Q_nARXq",
    "outputId": "1f18ba08-788b-46f4-e7af-7eeb8fea622f"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "--2022-04-06 01:57:57--  https://download.openmmlab.com/mmrotate/data/ssdd_tiny.zip\n",
      "Resolving download.openmmlab.com (download.openmmlab.com)... 47.252.96.28\n",
      "Connecting to download.openmmlab.com (download.openmmlab.com)|47.252.96.28|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 6741882 (6.4M) [application/zip]\n",
      "Saving to: ‘ssdd_tiny.zip’\n",
      "\n",
      "ssdd_tiny.zip       100%[===================>]   6.43M  8.17MB/s    in 0.8s    \n",
      "\n",
      "2022-04-06 01:57:59 (8.17 MB/s) - ‘ssdd_tiny.zip’ saved [6741882/6741882]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# download, decompress the data\n",
    "!wget https://download.openmmlab.com/mmrotate/data/ssdd_tiny.zip\n",
    "!unzip ssdd_tiny.zip > /dev/null"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Wuwxw1oZRtVZ",
    "outputId": "818e5c65-7b53-47f4-d8fa-f566fccc493d"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Reading package lists...\n",
      "Building dependency tree...\n",
      "Reading state information...\n",
      "The following NEW packages will be installed:\n",
      "  tree\n",
      "0 upgraded, 1 newly installed, 0 to remove and 39 not upgraded.\n",
      "Need to get 40.7 kB of archives.\n",
      "After this operation, 105 kB of additional disk space will be used.\n",
      "Get:1 http://archive.ubuntu.com/ubuntu bionic/universe amd64 tree amd64 1.7.0-5 [40.7 kB]\n",
      "Fetched 40.7 kB in 1s (79.9 kB/s)\n",
      "Selecting previously unselected package tree.\n",
      "(Reading database ... 156210 files and directories currently installed.)\n",
      "Preparing to unpack .../tree_1.7.0-5_amd64.deb ...\n",
      "Unpacking tree (1.7.0-5) ...\n",
      "Setting up tree (1.7.0-5) ...\n",
      "Processing triggers for man-db (2.8.3-2ubuntu0.1) ...\n",
      "ssdd_tiny\n",
      "├── images\n",
      "│   ├── 000001.png\n",
      "│   ├── 000009.png\n",
      "│   ├── 000011.png\n",
      "│   ├── 000029.png\n",
      "│   ├── 000041.png\n",
      "│   ├── 000049.png\n",
      "│   ├── 000051.png\n",
      "│   ├── 000059.png\n",
      "│   ├── 000061.png\n",
      "│   ├── 000071.png\n",
      "│   ├── 000079.png\n",
      "│   ├── 000081.png\n",
      "│   ├── 000089.png\n",
      "│   ├── 000091.png\n",
      "│   ├── 000099.png\n",
      "│   ├── 000101.png\n",
      "│   ├── 000109.png\n",
      "│   ├── 000111.png\n",
      "│   ├── 000119.png\n",
      "│   ├── 000121.png\n",
      "│   ├── 000129.png\n",
      "│   ├── 000131.png\n",
      "│   ├── 000139.png\n",
      "│   ├── 000141.png\n",
      "│   ├── 000149.png\n",
      "│   ├── 000151.png\n",
      "│   ├── 000159.png\n",
      "│   ├── 000161.png\n",
      "│   ├── 000169.png\n",
      "│   ├── 000171.png\n",
      "│   ├── 000179.png\n",
      "│   ├── 000181.png\n",
      "│   ├── 000189.png\n",
      "│   ├── 000191.png\n",
      "│   ├── 000199.png\n",
      "│   ├── 000201.png\n",
      "│   ├── 000209.png\n",
      "│   ├── 000211.png\n",
      "│   ├── 000259.png\n",
      "│   ├── 000261.png\n",
      "│   ├── 000269.png\n",
      "│   ├── 000271.png\n",
      "│   ├── 000279.png\n",
      "│   ├── 000281.png\n",
      "│   ├── 000289.png\n",
      "│   ├── 000291.png\n",
      "│   ├── 000299.png\n",
      "│   ├── 000301.png\n",
      "│   ├── 000309.png\n",
      "│   ├── 000311.png\n",
      "│   ├── 000319.png\n",
      "│   ├── 000321.png\n",
      "│   ├── 000329.png\n",
      "│   ├── 000331.png\n",
      "│   ├── 000339.png\n",
      "│   ├── 000341.png\n",
      "│   ├── 000361.png\n",
      "│   ├── 000369.png\n",
      "│   ├── 000371.png\n",
      "│   ├── 000379.png\n",
      "│   ├── 000381.png\n",
      "│   ├── 000389.png\n",
      "│   ├── 000391.png\n",
      "│   ├── 000399.png\n",
      "│   ├── 000401.png\n",
      "│   ├── 000411.png\n",
      "│   ├── 000419.png\n",
      "│   ├── 000421.png\n",
      "│   ├── 000429.png\n",
      "│   ├── 000431.png\n",
      "│   ├── 000439.png\n",
      "│   ├── 000441.png\n",
      "│   ├── 000449.png\n",
      "│   ├── 000451.png\n",
      "│   ├── 000459.png\n",
      "│   ├── 000461.png\n",
      "│   ├── 000469.png\n",
      "│   ├── 000471.png\n",
      "│   ├── 000479.png\n",
      "│   ├── 000481.png\n",
      "│   ├── 000489.png\n",
      "│   ├── 000491.png\n",
      "│   ├── 000499.png\n",
      "│   ├── 000501.png\n",
      "│   ├── 000509.png\n",
      "│   ├── 000511.png\n",
      "│   ├── 000519.png\n",
      "│   ├── 000521.png\n",
      "│   ├── 000529.png\n",
      "│   ├── 000531.png\n",
      "│   ├── 000539.png\n",
      "│   ├── 000541.png\n",
      "│   ├── 000549.png\n",
      "│   ├── 000551.png\n",
      "│   ├── 000559.png\n",
      "│   ├── 000561.png\n",
      "│   ├── 000569.png\n",
      "│   ├── 000571.png\n",
      "│   ├── 000579.png\n",
      "│   ├── 000581.png\n",
      "│   ├── 000589.png\n",
      "│   ├── 000591.png\n",
      "│   ├── 000599.png\n",
      "│   ├── 000601.png\n",
      "│   ├── 000609.png\n",
      "│   ├── 000611.png\n",
      "│   ├── 000619.png\n",
      "│   ├── 000621.png\n",
      "│   ├── 000629.png\n",
      "│   ├── 000631.png\n",
      "│   ├── 000639.png\n",
      "│   ├── 000649.png\n",
      "│   ├── 000651.png\n",
      "│   ├── 000659.png\n",
      "│   ├── 000661.png\n",
      "│   ├── 000669.png\n",
      "│   ├── 000671.png\n",
      "│   ├── 000679.png\n",
      "│   ├── 000681.png\n",
      "│   ├── 000689.png\n",
      "│   ├── 000691.png\n",
      "│   ├── 000699.png\n",
      "│   ├── 000701.png\n",
      "│   ├── 000709.png\n",
      "│   ├── 000711.png\n",
      "│   ├── 000719.png\n",
      "│   ├── 000721.png\n",
      "│   ├── 000731.png\n",
      "│   ├── 000739.png\n",
      "│   ├── 000769.png\n",
      "│   ├── 000771.png\n",
      "│   ├── 000779.png\n",
      "│   ├── 000781.png\n",
      "│   ├── 000789.png\n",
      "│   ├── 000791.png\n",
      "│   ├── 000799.png\n",
      "│   ├── 000801.png\n",
      "│   ├── 000809.png\n",
      "│   ├── 000811.png\n",
      "│   ├── 000819.png\n",
      "│   ├── 000821.png\n",
      "│   ├── 000829.png\n",
      "│   ├── 000831.png\n",
      "│   ├── 000839.png\n",
      "│   ├── 000841.png\n",
      "│   ├── 000849.png\n",
      "│   ├── 000851.png\n",
      "│   ├── 000859.png\n",
      "│   ├── 000861.png\n",
      "│   ├── 000869.png\n",
      "│   ├── 000871.png\n",
      "│   ├── 000879.png\n",
      "│   ├── 000881.png\n",
      "│   ├── 000889.png\n",
      "│   ├── 000891.png\n",
      "│   ├── 000899.png\n",
      "│   ├── 000901.png\n",
      "│   ├── 000909.png\n",
      "│   ├── 000911.png\n",
      "│   ├── 000919.png\n",
      "│   ├── 000921.png\n",
      "│   ├── 000929.png\n",
      "│   ├── 000931.png\n",
      "│   ├── 000939.png\n",
      "│   ├── 000941.png\n",
      "│   ├── 000949.png\n",
      "│   ├── 000951.png\n",
      "│   ├── 000959.png\n",
      "│   ├── 000961.png\n",
      "│   ├── 000969.png\n",
      "│   ├── 000971.png\n",
      "│   ├── 000979.png\n",
      "│   ├── 000981.png\n",
      "│   ├── 000989.png\n",
      "│   ├── 000991.png\n",
      "│   ├── 000999.png\n",
      "│   ├── 001001.png\n",
      "│   ├── 001009.png\n",
      "│   ├── 001011.png\n",
      "│   ├── 001021.png\n",
      "│   ├── 001051.png\n",
      "│   ├── 001061.png\n",
      "│   ├── 001099.png\n",
      "│   ├── 001101.png\n",
      "│   ├── 001109.png\n",
      "│   ├── 001111.png\n",
      "│   ├── 001119.png\n",
      "│   ├── 001121.png\n",
      "│   ├── 001129.png\n",
      "│   ├── 001131.png\n",
      "│   ├── 001139.png\n",
      "│   ├── 001141.png\n",
      "│   └── 001149.png\n",
      "├── train\n",
      "│   ├── 000029.txt\n",
      "│   ├── 000041.txt\n",
      "│   ├── 000049.txt\n",
      "│   ├── 000051.txt\n",
      "│   ├── 000079.txt\n",
      "│   ├── 000081.txt\n",
      "│   ├── 000089.txt\n",
      "│   ├── 000091.txt\n",
      "│   ├── 000111.txt\n",
      "│   ├── 000119.txt\n",
      "│   ├── 000121.txt\n",
      "│   ├── 000129.txt\n",
      "│   ├── 000149.txt\n",
      "│   ├── 000151.txt\n",
      "│   ├── 000159.txt\n",
      "│   ├── 000161.txt\n",
      "│   ├── 000181.txt\n",
      "│   ├── 000189.txt\n",
      "│   ├── 000191.txt\n",
      "│   ├── 000199.txt\n",
      "│   ├── 000259.txt\n",
      "│   ├── 000261.txt\n",
      "│   ├── 000269.txt\n",
      "│   ├── 000271.txt\n",
      "│   ├── 000291.txt\n",
      "│   ├── 000299.txt\n",
      "│   ├── 000301.txt\n",
      "│   ├── 000309.txt\n",
      "│   ├── 000329.txt\n",
      "│   ├── 000331.txt\n",
      "│   ├── 000339.txt\n",
      "│   ├── 000341.txt\n",
      "│   ├── 000379.txt\n",
      "│   ├── 000381.txt\n",
      "│   ├── 000389.txt\n",
      "│   ├── 000391.txt\n",
      "│   ├── 000419.txt\n",
      "│   ├── 000421.txt\n",
      "│   ├── 000429.txt\n",
      "│   ├── 000431.txt\n",
      "│   ├── 000451.txt\n",
      "│   ├── 000459.txt\n",
      "│   ├── 000461.txt\n",
      "│   ├── 000469.txt\n",
      "│   ├── 000489.txt\n",
      "│   ├── 000491.txt\n",
      "│   ├── 000499.txt\n",
      "│   ├── 000501.txt\n",
      "│   ├── 000521.txt\n",
      "│   ├── 000529.txt\n",
      "│   ├── 000531.txt\n",
      "│   ├── 000539.txt\n",
      "│   ├── 000559.txt\n",
      "│   ├── 000561.txt\n",
      "│   ├── 000569.txt\n",
      "│   ├── 000571.txt\n",
      "│   ├── 000591.txt\n",
      "│   ├── 000599.txt\n",
      "│   ├── 000601.txt\n",
      "│   ├── 000609.txt\n",
      "│   ├── 000629.txt\n",
      "│   ├── 000631.txt\n",
      "│   ├── 000639.txt\n",
      "│   ├── 000649.txt\n",
      "│   ├── 000669.txt\n",
      "│   ├── 000671.txt\n",
      "│   ├── 000679.txt\n",
      "│   ├── 000681.txt\n",
      "│   ├── 000701.txt\n",
      "│   ├── 000709.txt\n",
      "│   ├── 000711.txt\n",
      "│   ├── 000719.txt\n",
      "│   ├── 000769.txt\n",
      "│   ├── 000771.txt\n",
      "│   ├── 000779.txt\n",
      "│   ├── 000781.txt\n",
      "│   ├── 000801.txt\n",
      "│   ├── 000809.txt\n",
      "│   ├── 000811.txt\n",
      "│   ├── 000819.txt\n",
      "│   ├── 000839.txt\n",
      "│   ├── 000841.txt\n",
      "│   ├── 000849.txt\n",
      "│   ├── 000851.txt\n",
      "│   ├── 000871.txt\n",
      "│   ├── 000879.txt\n",
      "│   ├── 000881.txt\n",
      "│   ├── 000889.txt\n",
      "│   ├── 000909.txt\n",
      "│   ├── 000911.txt\n",
      "│   ├── 000919.txt\n",
      "│   ├── 000921.txt\n",
      "│   ├── 000941.txt\n",
      "│   ├── 000949.txt\n",
      "│   ├── 000951.txt\n",
      "│   ├── 000959.txt\n",
      "│   ├── 000979.txt\n",
      "│   ├── 000981.txt\n",
      "│   ├── 000989.txt\n",
      "│   ├── 000991.txt\n",
      "│   ├── 001011.txt\n",
      "│   ├── 001021.txt\n",
      "│   ├── 001051.txt\n",
      "│   ├── 001061.txt\n",
      "│   ├── 001111.txt\n",
      "│   ├── 001119.txt\n",
      "│   ├── 001121.txt\n",
      "│   ├── 001129.txt\n",
      "│   └── 001149.txt\n",
      "└── val\n",
      "    ├── 000001.txt\n",
      "    ├── 000009.txt\n",
      "    ├── 000011.txt\n",
      "    ├── 000059.txt\n",
      "    ├── 000061.txt\n",
      "    ├── 000071.txt\n",
      "    ├── 000099.txt\n",
      "    ├── 000101.txt\n",
      "    ├── 000109.txt\n",
      "    ├── 000131.txt\n",
      "    ├── 000139.txt\n",
      "    ├── 000141.txt\n",
      "    ├── 000169.txt\n",
      "    ├── 000171.txt\n",
      "    ├── 000179.txt\n",
      "    ├── 000201.txt\n",
      "    ├── 000209.txt\n",
      "    ├── 000211.txt\n",
      "    ├── 000279.txt\n",
      "    ├── 000281.txt\n",
      "    ├── 000289.txt\n",
      "    ├── 000311.txt\n",
      "    ├── 000319.txt\n",
      "    ├── 000321.txt\n",
      "    ├── 000361.txt\n",
      "    ├── 000369.txt\n",
      "    ├── 000371.txt\n",
      "    ├── 000399.txt\n",
      "    ├── 000401.txt\n",
      "    ├── 000411.txt\n",
      "    ├── 000439.txt\n",
      "    ├── 000441.txt\n",
      "    ├── 000449.txt\n",
      "    ├── 000471.txt\n",
      "    ├── 000479.txt\n",
      "    ├── 000481.txt\n",
      "    ├── 000509.txt\n",
      "    ├── 000511.txt\n",
      "    ├── 000519.txt\n",
      "    ├── 000541.txt\n",
      "    ├── 000549.txt\n",
      "    ├── 000551.txt\n",
      "    ├── 000579.txt\n",
      "    ├── 000581.txt\n",
      "    ├── 000589.txt\n",
      "    ├── 000611.txt\n",
      "    ├── 000619.txt\n",
      "    ├── 000621.txt\n",
      "    ├── 000651.txt\n",
      "    ├── 000659.txt\n",
      "    ├── 000661.txt\n",
      "    ├── 000689.txt\n",
      "    ├── 000691.txt\n",
      "    ├── 000699.txt\n",
      "    ├── 000721.txt\n",
      "    ├── 000731.txt\n",
      "    ├── 000739.txt\n",
      "    ├── 000789.txt\n",
      "    ├── 000791.txt\n",
      "    ├── 000799.txt\n",
      "    ├── 000821.txt\n",
      "    ├── 000829.txt\n",
      "    ├── 000831.txt\n",
      "    ├── 000859.txt\n",
      "    ├── 000861.txt\n",
      "    ├── 000869.txt\n",
      "    ├── 000891.txt\n",
      "    ├── 000899.txt\n",
      "    ├── 000901.txt\n",
      "    ├── 000929.txt\n",
      "    ├── 000931.txt\n",
      "    ├── 000939.txt\n",
      "    ├── 000961.txt\n",
      "    ├── 000969.txt\n",
      "    ├── 000971.txt\n",
      "    ├── 000999.txt\n",
      "    ├── 001001.txt\n",
      "    ├── 001009.txt\n",
      "    ├── 001099.txt\n",
      "    ├── 001101.txt\n",
      "    ├── 001109.txt\n",
      "    ├── 001131.txt\n",
      "    ├── 001139.txt\n",
      "    └── 001141.txt\n",
      "\n",
      "3 directories, 386 files\n"
     ]
    }
   ],
   "source": [
    "# Check the directory structure of the tiny data\n",
    "\n",
    "# Install tree first\n",
    "!apt-get -q install tree\n",
    "!tree ssdd_tiny"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 595
    },
    "id": "YnQQqzOWzE91",
    "outputId": "d72b1cbf-e588-4734-ff3c-b731b289dbf8"
   },
   "outputs": [
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<Figure size 1080x720 with 1 Axes>"
      ],
      "image/png": "[encoded data, 613964 characters]\n"
     },
     "metadata": {
      "needs_background": "light"
     }
    }
   ],
   "source": [
    "# Let's take a look at the dataset image\n",
    "import matplotlib.pyplot as plt\n",
    "img = mmcv.imread('ssdd_tiny/images/000631.png')\n",
    "plt.figure(figsize=(15, 10))\n",
    "plt.imshow(mmcv.bgr2rgb(img))\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "PMZvtSIl71qi"
   },
   "source": [
    "Let's take a look at the annotation txt file.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "n7rwalnPd6e1",
    "outputId": "7b402329-267d-4d6f-e529-983d499a1fcc"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "337 169 395 183 398 162 339 154 ship 0\n",
      "263 273 261 296 276 297 279 272 ship 0\n",
      "95 165 173 132 184 156 103 186 ship 0\n"
     ]
    }
   ],
   "source": [
    "# Check the label of a single image\n",
    "!cat ssdd_tiny/train/000631.txt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "id": "GdSaB2ad0EdX"
   },
   "outputs": [],
   "source": [
    "from mmrotate.datasets.builder import ROTATED_DATASETS\n",
    "from mmrotate.datasets.dota import DOTADataset\n",
    "\n",
    "\n",
    "@ROTATED_DATASETS.register_module()\n",
    "class TinyDataset(DOTADataset):\n",
    "    \"\"\"SAR ship dataset for detection.\"\"\"\n",
    "    CLASSES = ('ship',)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "PwqJOpBe-bMj"
   },
   "source": [
    "### Modify the config\n",
    "\n",
    "In the next step, we need to modify the config for the training.\n",
    "To accelerate the process, we finetune a detector using a pre-trained detector."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "id": "hamZrlnH-YDD"
   },
   "outputs": [],
   "source": [
    "from mmcv import Config\n",
    "cfg = Config.fromfile('./configs/oriented_rcnn/oriented_rcnn_r50_fpn_1x_dota_le90.py')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "HntziLGq-92Z"
   },
   "source": [
    "Given a config that trains a Oriented R-CNN on DOTA dataset, we need to modify some values to use it for training Oriented R-CNN on SSDD dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "pUbwD8uV0PR8",
    "outputId": "c3658c96-93fa-4ecc-fdcd-60e11af409fd"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Config:\n",
      "dataset_type = 'TinyDataset'\n",
      "data_root = 'ssdd_tiny/'\n",
      "img_norm_cfg = dict(\n",
      "    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)\n",
      "train_pipeline = [\n",
      "    dict(type='LoadImageFromFile'),\n",
      "    dict(type='LoadAnnotations', with_bbox=True),\n",
      "    dict(type='RResize', img_scale=(1024, 1024)),\n",
      "    dict(\n",
      "        type='RRandomFlip',\n",
      "        flip_ratio=[0.25, 0.25, 0.25],\n",
      "        direction=['horizontal', 'vertical', 'diagonal'],\n",
      "        version='le90'),\n",
      "    dict(\n",
      "        type='Normalize',\n",
      "        mean=[123.675, 116.28, 103.53],\n",
      "        std=[58.395, 57.12, 57.375],\n",
      "        to_rgb=True),\n",
      "    dict(type='Pad', size_divisor=32),\n",
      "    dict(type='DefaultFormatBundle'),\n",
      "    dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels'])\n",
      "]\n",
      "test_pipeline = [\n",
      "    dict(type='LoadImageFromFile'),\n",
      "    dict(\n",
      "        type='MultiScaleFlipAug',\n",
      "        img_scale=(1024, 1024),\n",
      "        flip=False,\n",
      "        transforms=[\n",
      "            dict(type='RResize'),\n",
      "            dict(\n",
      "                type='Normalize',\n",
      "                mean=[123.675, 116.28, 103.53],\n",
      "                std=[58.395, 57.12, 57.375],\n",
      "                to_rgb=True),\n",
      "            dict(type='Pad', size_divisor=32),\n",
      "            dict(type='DefaultFormatBundle'),\n",
      "            dict(type='Collect', keys=['img'])\n",
      "        ])\n",
      "]\n",
      "data = dict(\n",
      "    samples_per_gpu=2,\n",
      "    workers_per_gpu=2,\n",
      "    train=dict(\n",
      "        type='TinyDataset',\n",
      "        ann_file='train',\n",
      "        img_prefix='images',\n",
      "        pipeline=[\n",
      "            dict(type='LoadImageFromFile'),\n",
      "            dict(type='LoadAnnotations', with_bbox=True),\n",
      "            dict(type='RResize', img_scale=(1024, 1024)),\n",
      "            dict(\n",
      "                type='RRandomFlip',\n",
      "                flip_ratio=[0.25, 0.25, 0.25],\n",
      "                direction=['horizontal', 'vertical', 'diagonal'],\n",
      "                version='le90'),\n",
      "            dict(\n",
      "                type='Normalize',\n",
      "                mean=[123.675, 116.28, 103.53],\n",
      "                std=[58.395, 57.12, 57.375],\n",
      "                to_rgb=True),\n",
      "            dict(type='Pad', size_divisor=32),\n",
      "            dict(type='DefaultFormatBundle'),\n",
      "            dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels'])\n",
      "        ],\n",
      "        version='le90',\n",
      "        data_root='ssdd_tiny/'),\n",
      "    val=dict(\n",
      "        type='TinyDataset',\n",
      "        ann_file='val',\n",
      "        img_prefix='images',\n",
      "        pipeline=[\n",
      "            dict(type='LoadImageFromFile'),\n",
      "            dict(\n",
      "                type='MultiScaleFlipAug',\n",
      "                img_scale=(1024, 1024),\n",
      "                flip=False,\n",
      "                transforms=[\n",
      "                    dict(type='RResize'),\n",
      "                    dict(\n",
      "                        type='Normalize',\n",
      "                        mean=[123.675, 116.28, 103.53],\n",
      "                        std=[58.395, 57.12, 57.375],\n",
      "                        to_rgb=True),\n",
      "                    dict(type='Pad', size_divisor=32),\n",
      "                    dict(type='DefaultFormatBundle'),\n",
      "                    dict(type='Collect', keys=['img'])\n",
      "                ])\n",
      "        ],\n",
      "        version='le90',\n",
      "        data_root='ssdd_tiny/'),\n",
      "    test=dict(\n",
      "        type='TinyDataset',\n",
      "        ann_file='val',\n",
      "        img_prefix='images',\n",
      "        pipeline=[\n",
      "            dict(type='LoadImageFromFile'),\n",
      "            dict(\n",
      "                type='MultiScaleFlipAug',\n",
      "                img_scale=(1024, 1024),\n",
      "                flip=False,\n",
      "                transforms=[\n",
      "                    dict(type='RResize'),\n",
      "                    dict(\n",
      "                        type='Normalize',\n",
      "                        mean=[123.675, 116.28, 103.53],\n",
      "                        std=[58.395, 57.12, 57.375],\n",
      "                        to_rgb=True),\n",
      "                    dict(type='Pad', size_divisor=32),\n",
      "                    dict(type='DefaultFormatBundle'),\n",
      "                    dict(type='Collect', keys=['img'])\n",
      "                ])\n",
      "        ],\n",
      "        version='le90',\n",
      "        data_root='ssdd_tiny/'))\n",
      "evaluation = dict(interval=3, metric='mAP')\n",
      "optimizer = dict(type='SGD', lr=0.001, momentum=0.9, weight_decay=0.0001)\n",
      "optimizer_config = dict(grad_clip=dict(max_norm=35, norm_type=2))\n",
      "lr_config = dict(\n",
      "    policy='step',\n",
      "    warmup=None,\n",
      "    warmup_iters=500,\n",
      "    warmup_ratio=0.3333333333333333,\n",
      "    step=[8, 11])\n",
      "runner = dict(type='EpochBasedRunner', max_epochs=3)\n",
      "checkpoint_config = dict(interval=3)\n",
      "log_config = dict(\n",
      "    interval=10,\n",
      "    hooks=[dict(type='TextLoggerHook'),\n",
      "           dict(type='TensorboardLoggerHook')])\n",
      "dist_params = dict(backend='nccl')\n",
      "log_level = 'INFO'\n",
      "load_from = 'checkpoints/oriented_rcnn_r50_fpn_1x_dota_le90-6d2b2ce0.pth'\n",
      "resume_from = None\n",
      "workflow = [('train', 1)]\n",
      "angle_version = 'le90'\n",
      "model = dict(\n",
      "    type='OrientedRCNN',\n",
      "    backbone=dict(\n",
      "        type='ResNet',\n",
      "        depth=50,\n",
      "        num_stages=4,\n",
      "        out_indices=(0, 1, 2, 3),\n",
      "        frozen_stages=1,\n",
      "        norm_cfg=dict(type='BN', requires_grad=True),\n",
      "        norm_eval=True,\n",
      "        style='pytorch',\n",
      "        init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')),\n",
      "    neck=dict(\n",
      "        type='FPN',\n",
      "        in_channels=[256, 512, 1024, 2048],\n",
      "        out_channels=256,\n",
      "        num_outs=5),\n",
      "    rpn_head=dict(\n",
      "        type='OrientedRPNHead',\n",
      "        in_channels=256,\n",
      "        feat_channels=256,\n",
      "        version='le90',\n",
      "        anchor_generator=dict(\n",
      "            type='AnchorGenerator',\n",
      "            scales=[8],\n",
      "            ratios=[0.5, 1.0, 2.0],\n",
      "            strides=[4, 8, 16, 32, 64]),\n",
      "        bbox_coder=dict(\n",
      "            type='MidpointOffsetCoder',\n",
      "            angle_range='le90',\n",
      "            target_means=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0],\n",
      "            target_stds=[1.0, 1.0, 1.0, 1.0, 0.5, 0.5]),\n",
      "        loss_cls=dict(\n",
      "            type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),\n",
      "        loss_bbox=dict(\n",
      "            type='SmoothL1Loss', beta=0.1111111111111111, loss_weight=1.0)),\n",
      "    roi_head=dict(\n",
      "        type='OrientedStandardRoIHead',\n",
      "        bbox_roi_extractor=dict(\n",
      "            type='RotatedSingleRoIExtractor',\n",
      "            roi_layer=dict(\n",
      "                type='RoIAlignRotated',\n",
      "                out_size=7,\n",
      "                sample_num=2,\n",
      "                clockwise=True),\n",
      "            out_channels=256,\n",
      "            featmap_strides=[4, 8, 16, 32]),\n",
      "        bbox_head=dict(\n",
      "            type='RotatedShared2FCBBoxHead',\n",
      "            in_channels=256,\n",
      "            fc_out_channels=1024,\n",
      "            roi_feat_size=7,\n",
      "            num_classes=1,\n",
      "            bbox_coder=dict(\n",
      "                type='DeltaXYWHAOBBoxCoder',\n",
      "                angle_range='le90',\n",
      "                norm_factor=None,\n",
      "                edge_swap=True,\n",
      "                proj_xy=True,\n",
      "                target_means=(0.0, 0.0, 0.0, 0.0, 0.0),\n",
      "                target_stds=(0.1, 0.1, 0.2, 0.2, 0.1)),\n",
      "            reg_class_agnostic=True,\n",
      "            loss_cls=dict(\n",
      "                type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0),\n",
      "            loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))),\n",
      "    train_cfg=dict(\n",
      "        rpn=dict(\n",
      "            assigner=dict(\n",
      "                type='MaxIoUAssigner',\n",
      "                pos_iou_thr=0.7,\n",
      "                neg_iou_thr=0.3,\n",
      "                min_pos_iou=0.3,\n",
      "                match_low_quality=True,\n",
      "                ignore_iof_thr=-1),\n",
      "            sampler=dict(\n",
      "                type='RandomSampler',\n",
      "                num=256,\n",
      "                pos_fraction=0.5,\n",
      "                neg_pos_ub=-1,\n",
      "                add_gt_as_proposals=False),\n",
      "            allowed_border=0,\n",
      "            pos_weight=-1,\n",
      "            debug=False),\n",
      "        rpn_proposal=dict(\n",
      "            nms_pre=2000,\n",
      "            max_per_img=2000,\n",
      "            nms=dict(type='nms', iou_threshold=0.8),\n",
      "            min_bbox_size=0),\n",
      "        rcnn=dict(\n",
      "            assigner=dict(\n",
      "                type='MaxIoUAssigner',\n",
      "                pos_iou_thr=0.5,\n",
      "                neg_iou_thr=0.5,\n",
      "                min_pos_iou=0.5,\n",
      "                match_low_quality=False,\n",
      "                iou_calculator=dict(type='RBboxOverlaps2D'),\n",
      "                ignore_iof_thr=-1),\n",
      "            sampler=dict(\n",
      "                type='RRandomSampler',\n",
      "                num=512,\n",
      "                pos_fraction=0.25,\n",
      "                neg_pos_ub=-1,\n",
      "                add_gt_as_proposals=True),\n",
      "            pos_weight=-1,\n",
      "            debug=False)),\n",
      "    test_cfg=dict(\n",
      "        rpn=dict(\n",
      "            nms_pre=2000,\n",
      "            max_per_img=2000,\n",
      "            nms=dict(type='nms', iou_threshold=0.8),\n",
      "            min_bbox_size=0),\n",
      "        rcnn=dict(\n",
      "            nms_pre=2000,\n",
      "            min_bbox_size=0,\n",
      "            score_thr=0.05,\n",
      "            nms=dict(iou_thr=0.1),\n",
      "            max_per_img=2000)))\n",
      "work_dir = './tutorial_exps'\n",
      "seed = 0\n",
      "gpu_ids = range(0, 1)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "from mmdet.apis import set_random_seed\n",
    "\n",
    "# Modify dataset type and path\n",
    "cfg.dataset_type = 'TinyDataset'\n",
    "cfg.data_root = 'ssdd_tiny/'\n",
    "\n",
    "cfg.data.test.type = 'TinyDataset'\n",
    "cfg.data.test.data_root = 'ssdd_tiny/'\n",
    "cfg.data.test.ann_file = 'val'\n",
    "cfg.data.test.img_prefix = 'images'\n",
    "\n",
    "cfg.data.train.type = 'TinyDataset'\n",
    "cfg.data.train.data_root = 'ssdd_tiny/'\n",
    "cfg.data.train.ann_file = 'train'\n",
    "cfg.data.train.img_prefix = 'images'\n",
    "\n",
    "cfg.data.val.type = 'TinyDataset'\n",
    "cfg.data.val.data_root = 'ssdd_tiny/'\n",
    "cfg.data.val.ann_file = 'val'\n",
    "cfg.data.val.img_prefix = 'images'\n",
    "\n",
    "# modify num classes of the model in box head\n",
    "cfg.model.roi_head.bbox_head.num_classes = 1\n",
    "# We can still use the pre-trained Mask RCNN model though we do not need to\n",
    "# use the mask branch\n",
    "cfg.load_from = 'checkpoints/oriented_rcnn_r50_fpn_1x_dota_le90-6d2b2ce0.pth'\n",
    "\n",
    "# Set up working dir to save files and logs.\n",
    "cfg.work_dir = './tutorial_exps'\n",
    "\n",
    "cfg.optimizer.lr = 0.001\n",
    "cfg.lr_config.warmup = None\n",
    "cfg.runner.max_epochs = 3\n",
    "cfg.log_config.interval = 10\n",
    "\n",
    "# Change the evaluation metric since we use customized dataset.\n",
    "cfg.evaluation.metric = 'mAP'\n",
    "# We can set the evaluation interval to reduce the evaluation times\n",
    "cfg.evaluation.interval = 3\n",
    "# We can set the checkpoint saving interval to reduce the storage cost\n",
    "cfg.checkpoint_config.interval = 3\n",
    "\n",
    "# Set seed thus the results are more reproducible\n",
    "cfg.seed = 0\n",
    "set_random_seed(0, deterministic=False)\n",
    "cfg.gpu_ids = range(1)\n",
    "\n",
    "# We can also use tensorboard to log the training process\n",
    "cfg.log_config.hooks = [\n",
    "    dict(type='TextLoggerHook'),\n",
    "    dict(type='TensorboardLoggerHook')]\n",
    "\n",
    "# We can initialize the logger for training and have a look\n",
    "# at the final config used for training\n",
    "print(f'Config:\\n{cfg.pretty_text}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "111W_oZV_3wa"
   },
   "source": [
    "### Train a new detector\n",
    "\n",
    "Finally, lets initialize the dataset and detector, then train a new detector!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "7WBWHu010PN3",
    "outputId": "5be7243e-cab5-4f8a-a9c2-6d26848ea4e0"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "/usr/local/lib/python3.7/dist-packages/mmdet/models/dense_heads/anchor_head.py:116: UserWarning: DeprecationWarning: `num_anchors` is deprecated, for consistency or also use `num_base_priors` instead\n",
      "  warnings.warn('DeprecationWarning: `num_anchors` is deprecated, '\n",
      "2022-04-06 01:59:25,462 - mmdet - INFO - load checkpoint from local path: checkpoints/oriented_rcnn_r50_fpn_1x_dota_le90-6d2b2ce0.pth\n",
      "2022-04-06 01:59:25,597 - mmdet - WARNING - The model and loaded state dict do not match exactly\n",
      "\n",
      "size mismatch for roi_head.bbox_head.fc_cls.weight: copying a param with shape torch.Size([16, 1024]) from checkpoint, the shape in current model is torch.Size([2, 1024]).\n",
      "size mismatch for roi_head.bbox_head.fc_cls.bias: copying a param with shape torch.Size([16]) from checkpoint, the shape in current model is torch.Size([2]).\n",
      "2022-04-06 01:59:25,605 - mmdet - INFO - Start running, host: root@caaedfb32729, work_dir: /content/mmrotate/tutorial_exps\n",
      "2022-04-06 01:59:25,606 - mmdet - INFO - Hooks will be executed in the following order:\n",
      "before_run:\n",
      "(VERY_HIGH   ) StepLrUpdaterHook                  \n",
      "(NORMAL      ) CheckpointHook                     \n",
      "(LOW         ) EvalHook                           \n",
      "(VERY_LOW    ) TextLoggerHook                     \n",
      "(VERY_LOW    ) TensorboardLoggerHook              \n",
      " -------------------- \n",
      "before_train_epoch:\n",
      "(VERY_HIGH   ) StepLrUpdaterHook                  \n",
      "(LOW         ) IterTimerHook                      \n",
      "(LOW         ) EvalHook                           \n",
      "(VERY_LOW    ) TextLoggerHook                     \n",
      "(VERY_LOW    ) TensorboardLoggerHook              \n",
      " -------------------- \n",
      "before_train_iter:\n",
      "(VERY_HIGH   ) StepLrUpdaterHook                  \n",
      "(LOW         ) IterTimerHook                      \n",
      "(LOW         ) EvalHook                           \n",
      " -------------------- \n",
      "after_train_iter:\n",
      "(ABOVE_NORMAL) OptimizerHook                      \n",
      "(NORMAL      ) CheckpointHook                     \n",
      "(LOW         ) IterTimerHook                      \n",
      "(LOW         ) EvalHook                           \n",
      "(VERY_LOW    ) TextLoggerHook                     \n",
      "(VERY_LOW    ) TensorboardLoggerHook              \n",
      " -------------------- \n",
      "after_train_epoch:\n",
      "(NORMAL      ) CheckpointHook                     \n",
      "(LOW         ) EvalHook                           \n",
      "(VERY_LOW    ) TextLoggerHook                     \n",
      "(VERY_LOW    ) TensorboardLoggerHook              \n",
      " -------------------- \n",
      "before_val_epoch:\n",
      "(LOW         ) IterTimerHook                      \n",
      "(VERY_LOW    ) TextLoggerHook                     \n",
      "(VERY_LOW    ) TensorboardLoggerHook              \n",
      " -------------------- \n",
      "before_val_iter:\n",
      "(LOW         ) IterTimerHook                      \n",
      " -------------------- \n",
      "after_val_iter:\n",
      "(LOW         ) IterTimerHook                      \n",
      " -------------------- \n",
      "after_val_epoch:\n",
      "(VERY_LOW    ) TextLoggerHook                     \n",
      "(VERY_LOW    ) TensorboardLoggerHook              \n",
      " -------------------- \n",
      "after_run:\n",
      "(VERY_LOW    ) TextLoggerHook                     \n",
      "(VERY_LOW    ) TensorboardLoggerHook              \n",
      " -------------------- \n",
      "2022-04-06 01:59:25,607 - mmdet - INFO - workflow: [('train', 1)], max: 3 epochs\n",
      "2022-04-06 01:59:25,611 - mmdet - INFO - Checkpoints will be saved to /content/mmrotate/tutorial_exps by HardDiskBackend.\n",
      "/usr/local/lib/python3.7/dist-packages/mmdet/models/dense_heads/anchor_head.py:123: UserWarning: DeprecationWarning: anchor_generator is deprecated, please use \"prior_generator\" instead\n",
      "  warnings.warn('DeprecationWarning: anchor_generator is deprecated, '\n",
      "2022-04-06 01:59:51,026 - mmdet - INFO - Epoch [1][10/55]\tlr: 1.000e-03, eta: 0:04:51, time: 1.881, data_time: 0.241, memory: 3825, loss_rpn_cls: 0.2187, loss_rpn_bbox: 0.0519, loss_cls: 0.4219, acc: 90.3613, loss_bbox: 0.1330, loss: 0.8255, grad_norm: 8.1603\n",
      "2022-04-06 02:00:05,218 - mmdet - INFO - Epoch [1][20/55]\tlr: 1.000e-03, eta: 0:03:59, time: 1.419, data_time: 0.015, memory: 4016, loss_rpn_cls: 0.0354, loss_rpn_bbox: 0.0222, loss_cls: 0.1635, acc: 94.4531, loss_bbox: 0.0837, loss: 0.3048, grad_norm: 3.2388\n",
      "2022-04-06 02:00:18,658 - mmdet - INFO - Epoch [1][30/55]\tlr: 1.000e-03, eta: 0:03:28, time: 1.344, data_time: 0.011, memory: 4017, loss_rpn_cls: 0.0065, loss_rpn_bbox: 0.0172, loss_cls: 0.1568, acc: 93.5938, loss_bbox: 0.1275, loss: 0.3081, grad_norm: 2.6700\n",
      "2022-04-06 02:00:31,211 - mmdet - INFO - Epoch [1][40/55]\tlr: 1.000e-03, eta: 0:03:04, time: 1.255, data_time: 0.011, memory: 4017, loss_rpn_cls: 0.0067, loss_rpn_bbox: 0.0216, loss_cls: 0.1531, acc: 92.9688, loss_bbox: 0.1150, loss: 0.2964, grad_norm: 2.1666\n",
      "2022-04-06 02:00:44,373 - mmdet - INFO - Epoch [1][50/55]\tlr: 1.000e-03, eta: 0:02:45, time: 1.316, data_time: 0.012, memory: 4017, loss_rpn_cls: 0.0112, loss_rpn_bbox: 0.0188, loss_cls: 0.1429, acc: 93.4766, loss_bbox: 0.1018, loss: 0.2748, grad_norm: 2.2532\n",
      "2022-04-06 02:01:08,173 - mmdet - INFO - Epoch [2][10/55]\tlr: 1.000e-03, eta: 0:02:16, time: 1.686, data_time: 0.239, memory: 4017, loss_rpn_cls: 0.0035, loss_rpn_bbox: 0.0127, loss_cls: 0.1518, acc: 91.3965, loss_bbox: 0.1272, loss: 0.2953, grad_norm: 2.1427\n",
      "2022-04-06 02:01:20,879 - mmdet - INFO - Epoch [2][20/55]\tlr: 1.000e-03, eta: 0:02:02, time: 1.271, data_time: 0.013, memory: 4017, loss_rpn_cls: 0.0037, loss_rpn_bbox: 0.0154, loss_cls: 0.1167, acc: 93.5059, loss_bbox: 0.1006, loss: 0.2364, grad_norm: 1.7521\n",
      "2022-04-06 02:01:34,345 - mmdet - INFO - Epoch [2][30/55]\tlr: 1.000e-03, eta: 0:01:48, time: 1.347, data_time: 0.011, memory: 4017, loss_rpn_cls: 0.0022, loss_rpn_bbox: 0.0422, loss_cls: 0.1471, acc: 92.2754, loss_bbox: 0.1579, loss: 0.3493, grad_norm: 1.9944\n",
      "2022-04-06 02:01:47,409 - mmdet - INFO - Epoch [2][40/55]\tlr: 1.000e-03, eta: 0:01:34, time: 1.306, data_time: 0.012, memory: 4017, loss_rpn_cls: 0.0019, loss_rpn_bbox: 0.0263, loss_cls: 0.1333, acc: 93.5645, loss_bbox: 0.1112, loss: 0.2726, grad_norm: 1.8679\n",
      "2022-04-06 02:02:00,184 - mmdet - INFO - Epoch [2][50/55]\tlr: 1.000e-03, eta: 0:01:20, time: 1.278, data_time: 0.012, memory: 4017, loss_rpn_cls: 0.0058, loss_rpn_bbox: 0.0089, loss_cls: 0.1005, acc: 96.4551, loss_bbox: 0.0742, loss: 0.1894, grad_norm: 1.6071\n",
      "2022-04-06 02:02:23,231 - mmdet - INFO - Epoch [3][10/55]\tlr: 1.000e-03, eta: 0:00:58, time: 1.556, data_time: 0.233, memory: 4017, loss_rpn_cls: 0.0028, loss_rpn_bbox: 0.0150, loss_cls: 0.1119, acc: 95.4199, loss_bbox: 0.1039, loss: 0.2336, grad_norm: 2.1109\n",
      "2022-04-06 02:02:36,981 - mmdet - INFO - Epoch [3][20/55]\tlr: 1.000e-03, eta: 0:00:45, time: 1.375, data_time: 0.010, memory: 4017, loss_rpn_cls: 0.0039, loss_rpn_bbox: 0.0251, loss_cls: 0.1147, acc: 95.4883, loss_bbox: 0.1053, loss: 0.2490, grad_norm: 1.8938\n",
      "2022-04-06 02:02:50,715 - mmdet - INFO - Epoch [3][30/55]\tlr: 1.000e-03, eta: 0:00:32, time: 1.373, data_time: 0.011, memory: 4017, loss_rpn_cls: 0.0018, loss_rpn_bbox: 0.0102, loss_cls: 0.1044, acc: 96.6211, loss_bbox: 0.0987, loss: 0.2151, grad_norm: 2.0472\n",
      "2022-04-06 02:03:04,592 - mmdet - INFO - Epoch [3][40/55]\tlr: 1.000e-03, eta: 0:00:19, time: 1.388, data_time: 0.012, memory: 4017, loss_rpn_cls: 0.0008, loss_rpn_bbox: 0.0318, loss_cls: 0.1199, acc: 95.1953, loss_bbox: 0.1493, loss: 0.3017, grad_norm: 2.3279\n",
      "2022-04-06 02:03:18,135 - mmdet - INFO - Epoch [3][50/55]\tlr: 1.000e-03, eta: 0:00:06, time: 1.354, data_time: 0.011, memory: 4017, loss_rpn_cls: 0.0009, loss_rpn_bbox: 0.0119, loss_cls: 0.0972, acc: 97.2852, loss_bbox: 0.1043, loss: 0.2142, grad_norm: 1.8057\n",
      "2022-04-06 02:03:25,179 - mmdet - INFO - Saving checkpoint at 3 epochs\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] 84/84, 2.9 task/s, elapsed: 29s, ETA:     0s"
     ]
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "2022-04-06 02:04:17,380 - mmdet - INFO - \n",
      "+-------+-----+------+--------+-------+\n",
      "| class | gts | dets | recall | ap    |\n",
      "+-------+-----+------+--------+-------+\n",
      "| ship  | 176 | 2562 | 0.943  | 0.876 |\n",
      "+-------+-----+------+--------+-------+\n",
      "| mAP   |     |      |        | 0.876 |\n",
      "+-------+-----+------+--------+-------+\n",
      "2022-04-06 02:04:17,382 - mmdet - INFO - Epoch(val) [3][84]\tmAP: 0.8765\n"
     ]
    }
   ],
   "source": [
    "import os.path as osp\n",
    "\n",
    "from mmdet.datasets import build_dataset\n",
    "from mmdet.models import build_detector\n",
    "from mmdet.apis import train_detector\n",
    "\n",
    "# Build dataset\n",
    "datasets = [build_dataset(cfg.data.train)]\n",
    "\n",
    "# Build the detector\n",
    "model = build_detector(\n",
    "    cfg.model, train_cfg=cfg.get('train_cfg'), test_cfg=cfg.get('test_cfg'))\n",
    "# Add an attribute for visualization convenience\n",
    "model.CLASSES = datasets[0].CLASSES\n",
    "\n",
    "# Create work_dir\n",
    "mmcv.mkdir_or_exist(osp.abspath(cfg.work_dir))\n",
    "train_detector(model, datasets, cfg, distributed=False, validate=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "_vYQF5K2NqqI"
   },
   "source": [
    "### Understand the log\n",
    "From the log, we can have a basic understanding the training process and know how well the detector is trained.\n",
    "\n",
    "Firstly, the ResNet-50 backbone pre-trained on ImageNet is loaded, this is a common practice since training from scratch is more cost. The log shows that all the weights of the ResNet-50 backbone are loaded except the `conv1.bias`, which has been merged into `conv.weights`.\n",
    "\n",
    "Second, since the dataset we are using is small, we loaded a Oriented R-CNN model and finetune it for detection. \n",
    "The original Oriented R-CNN is trained on DOTA dataset which contains 15 classes but SSDD dataset only have 1 classes. Therefore, the last FC layer of the pre-trained Oriented R-CNN for classification has different weight shape and is not used.\n",
    "\n",
    "Third, after training, the detector is evaluated by the default evaluation. The results show that the detector achieves over 90 mAP on the val dataset,\n",
    " not bad!\n",
    "\n",
    "We can also check the tensorboard to see the curves."
   ]
  },
  {
   "cell_type": "code",
   "source": [
    "# load tensorboard in colab\n",
    "%load_ext tensorboard\n",
    "\n",
    "# see curves in tensorboard\n",
    "%tensorboard --logdir ./tutorial_exps"
   ],
   "metadata": {
    "colab": {
     "resources": {
      "https://localhost:6009/?tensorboardColab=true": {
       "data": "[encoded data, 252024 characters]",
       "ok": true,
       "headers": [
        [
         "content-type",
         "text/html; charset=utf-8"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/font-roboto/oMMgfZMQthOryQo9n22dcuvvDin1pK8aKteLpeZ5c0A.woff2": {
       "data": "[encoded data, 14332 characters]",
       "ok": true,
       "headers": [
        [
         "content-type",
         "font/woff2"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/index.js?_file_hash=4a366cbe": {
       "data": "[encoded data, 10228016 characters]",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/javascript; charset=utf-8"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/icon_bundle.svg": {
       "data": "[encoded data, 18556 characters]",
       "ok": true,
       "headers": [
        [
         "content-type",
         "image/svg+xml; charset=utf-8"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/font-roboto/RxZJdnzeo3R5zSexge8UUZBw1xU1rKptJj_0jans920.woff2": {
       "data": "[encoded data, 14384 characters]",
       "ok": true,
       "headers": [
        [
         "content-type",
         "font/woff2"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/data/plugins_listing": {
       "data": "eyJzY2FsYXJzIjogeyJkaXNhYmxlX3JlbG9hZCI6IGZhbHNlLCAiZW5hYmxlZCI6IHRydWUsICJyZW1vdmVfZG9tIjogZmFsc2UsICJ0YWJfbmFtZSI6ICJzY2FsYXJzIiwgImxvYWRpbmdfbWVjaGFuaXNtIjogeyJ0eXBlIjogIkNVU1RPTV9FTEVNRU5UIiwgImVsZW1lbnRfbmFtZSI6ICJ0Zi1zY2FsYXItZGFzaGJvYXJkIn19LCAiY3VzdG9tX3NjYWxhcnMiOiB7ImRpc2FibGVfcmVsb2FkIjogZmFsc2UsICJlbmFibGVkIjogZmFsc2UsICJyZW1vdmVfZG9tIjogZmFsc2UsICJ0YWJfbmFtZSI6ICJDdXN0b20gU2NhbGFycyIsICJsb2FkaW5nX21lY2hhbmlzbSI6IHsidHlwZSI6ICJDVVNUT01fRUxFTUVOVCIsICJlbGVtZW50X25hbWUiOiAidGYtY3VzdG9tLXNjYWxhci1kYXNoYm9hcmQifX0sICJpbWFnZXMiOiB7ImRpc2FibGVfcmVsb2FkIjogZmFsc2UsICJlbmFibGVkIjogZmFsc2UsICJyZW1vdmVfZG9tIjogZmFsc2UsICJ0YWJfbmFtZSI6ICJpbWFnZXMiLCAibG9hZGluZ19tZWNoYW5pc20iOiB7InR5cGUiOiAiQ1VTVE9NX0VMRU1FTlQiLCAiZWxlbWVudF9uYW1lIjogInRmLWltYWdlLWRhc2hib2FyZCJ9fSwgImF1ZGlvIjogeyJkaXNhYmxlX3JlbG9hZCI6IGZhbHNlLCAiZW5hYmxlZCI6IGZhbHNlLCAicmVtb3ZlX2RvbSI6IGZhbHNlLCAidGFiX25hbWUiOiAiYXVkaW8iLCAibG9hZGluZ19tZWNoYW5pc20iOiB7InR5cGUiOiAiQ1VTVE9NX0VMRU1FTlQiLCAiZWxlbWVudF9uYW1lIjogInRmLWF1ZGlvLWRhc2hib2FyZCJ9fSwgImRlYnVnZ2VyLXYyIjogeyJkaXNhYmxlX3JlbG9hZCI6IGZhbHNlLCAiZW5hYmxlZCI6IGZhbHNlLCAicmVtb3ZlX2RvbSI6IGZhbHNlLCAidGFiX25hbWUiOiAiRGVidWdnZXIgVjIiLCAibG9hZGluZ19tZWNoYW5pc20iOiB7InR5cGUiOiAiTkdfQ09NUE9ORU5UIn19LCAiZ3JhcGhzIjogeyJkaXNhYmxlX3JlbG9hZCI6IHRydWUsICJlbmFibGVkIjogZmFsc2UsICJyZW1vdmVfZG9tIjogZmFsc2UsICJ0YWJfbmFtZSI6ICJncmFwaHMiLCAibG9hZGluZ19tZWNoYW5pc20iOiB7InR5cGUiOiAiQ1VTVE9NX0VMRU1FTlQiLCAiZWxlbWVudF9uYW1lIjogInRmLWdyYXBoLWRhc2hib2FyZCJ9fSwgImRpc3RyaWJ1dGlvbnMiOiB7ImRpc2FibGVfcmVsb2FkIjogZmFsc2UsICJlbmFibGVkIjogZmFsc2UsICJyZW1vdmVfZG9tIjogZmFsc2UsICJ0YWJfbmFtZSI6ICJkaXN0cmlidXRpb25zIiwgImxvYWRpbmdfbWVjaGFuaXNtIjogeyJ0eXBlIjogIkNVU1RPTV9FTEVNRU5UIiwgImVsZW1lbnRfbmFtZSI6ICJ0Zi1kaXN0cmlidXRpb24tZGFzaGJvYXJkIn19LCAiaGlzdG9ncmFtcyI6IHsiZGlzYWJsZV9yZWxvYWQiOiBmYWxzZSwgImVuYWJsZWQiOiBmYWxzZSwgInJlbW92ZV9kb20iOiBmYWxzZSwgInRhYl9uYW1lIjogImhpc3RvZ3JhbXMiLCAibG9hZGluZ19tZWNoYW5pc20iOiB7InR5cGUiOiAiQ1VTVE9NX0VMRU1FTlQiLCAiZWxlbWVudF9uYW1lIjogInRmLWhpc3RvZ3JhbS1kYXNoYm9hcmQifX0sICJ0ZXh0IjogeyJkaXNhYmxlX3JlbG9hZCI6IGZhbHNlLCAiZW5hYmxlZCI6IGZhbHNlLCAicmVtb3ZlX2RvbSI6IGZhbHNlLCAidGFiX25hbWUiOiAidGV4dCIsICJsb2FkaW5nX21lY2hhbmlzbSI6IHsidHlwZSI6ICJDVVNUT01fRUxFTUVOVCIsICJlbGVtZW50X25hbWUiOiAidGYtdGV4dC1kYXNoYm9hcmQifX0sICJwcl9jdXJ2ZXMiOiB7ImRpc2FibGVfcmVsb2FkIjogZmFsc2UsICJlbmFibGVkIjogZmFsc2UsICJyZW1vdmVfZG9tIjogZmFsc2UsICJ0YWJfbmFtZSI6ICJQUiBDdXJ2ZXMiLCAibG9hZGluZ19tZWNoYW5pc20iOiB7InR5cGUiOiAiQ1VTVE9NX0VMRU1FTlQiLCAiZWxlbWVudF9uYW1lIjogInRmLXByLWN1cnZlLWRhc2hib2FyZCJ9fSwgInByb2ZpbGVfcmVkaXJlY3QiOiB7ImRpc2FibGVfcmVsb2FkIjogZmFsc2UsICJlbmFibGVkIjogZmFsc2UsICJyZW1vdmVfZG9tIjogZmFsc2UsICJ0YWJfbmFtZSI6ICJQcm9maWxlIiwgImxvYWRpbmdfbWVjaGFuaXNtIjogeyJ0eXBlIjogIkNVU1RPTV9FTEVNRU5UIiwgImVsZW1lbnRfbmFtZSI6ICJ0Zi1wcm9maWxlLXJlZGlyZWN0LWRhc2hib2FyZCJ9fSwgImhwYXJhbXMiOiB7ImRpc2FibGVfcmVsb2FkIjogZmFsc2UsICJlbmFibGVkIjogZmFsc2UsICJyZW1vdmVfZG9tIjogZmFsc2UsICJ0YWJfbmFtZSI6ICJocGFyYW1zIiwgImxvYWRpbmdfbWVjaGFuaXNtIjogeyJ0eXBlIjogIkNVU1RPTV9FTEVNRU5UIiwgImVsZW1lbnRfbmFtZSI6ICJ0Zi1ocGFyYW1zLWRhc2hib2FyZCJ9fSwgIm1lc2giOiB7ImRpc2FibGVfcmVsb2FkIjogZmFsc2UsICJlbmFibGVkIjogZmFsc2UsICJyZW1vdmVfZG9tIjogZmFsc2UsICJ0YWJfbmFtZSI6ICJtZXNoIiwgImxvYWRpbmdfbWVjaGFuaXNtIjogeyJ0eXBlIjogIkNVU1RPTV9FTEVNRU5UIiwgImVsZW1lbnRfbmFtZSI6ICJtZXNoLWRhc2hib2FyZCJ9fSwgInRpbWVzZXJpZXMiOiB7ImRpc2FibGVfcmVsb2FkIjogZmFsc2UsICJlbmFibGVkIjogdHJ1ZSwgInJlbW92ZV9kb20iOiBmYWxzZSwgInRhYl9uYW1lIjogIlRpbWUgU2VyaWVzIiwgImxvYWRpbmdfbWVjaGFuaXNtIjogeyJ0eXBlIjogIk5HX0NPTVBPTkVOVCJ9fSwgInByb2plY3RvciI6IHsiZGlzYWJsZV9yZWxvYWQiOiB0cnVlLCAiZW5hYmxlZCI6IGZhbHNlLCAicmVtb3ZlX2RvbSI6IGZhbHNlLCAidGFiX25hbWUiOiAicHJvamVjdG9yIiwgImxvYWRpbmdfbWVjaGFuaXNtIjogeyJ0eXBlIjogIklGUkFNRSIsICJtb2R1bGVfcGF0aCI6ICIvZGF0YS9wbHVnaW4vcHJvamVjdG9yL2luZGV4LmpzIn19LCAid2hhdGlmIjogeyJkaXNhYmxlX3JlbG9hZCI6IGZhbHNlLCAiZW5hYmxlZCI6IGZhbHNlLCAicmVtb3ZlX2RvbSI6IGZhbHNlLCAidGFiX25hbWUiOiAiV2hhdC1JZiBUb29sIiwgImxvYWRpbmdfbWVjaGFuaXNtIjogeyJ0eXBlIjogIklGUkFNRSIsICJtb2R1bGVfcGF0aCI6ICIvZGF0YS9wbHVnaW4vd2hhdGlmL2luZGV4LmpzIn19fQ==",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/json"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/data/environment": {
       "data": "eyJ2ZXJzaW9uIjogIjIuOC4wIiwgImRhdGFfbG9jYXRpb24iOiAiLi90dXRvcmlhbF9leHBzIiwgIndpbmRvd190aXRsZSI6ICIiLCAiZXhwZXJpbWVudF9uYW1lIjogIiIsICJleHBlcmltZW50X2Rlc2NyaXB0aW9uIjogIiIsICJjcmVhdGlvbl90aW1lIjogMC4wLCAiZGVidWciOiB7ImRhdGFfcHJvdmlkZXIiOiAiR3JwY0RhdGFQcm92aWRlcihhZGRyPSdsb2NhbGhvc3Q6Mzk5ODcnKSIsICJmbGFncyI6IHsibG9nZGlyIjogIi4vdHV0b3JpYWxfZXhwcyIsICJsb2dkaXJfc3BlYyI6ICIiLCAiaG9zdCI6IG51bGwsICJiaW5kX2FsbCI6IGZhbHNlLCAicG9ydCI6IDYwMDksICJyZXVzZV9wb3J0IjogZmFsc2UsICJsb2FkX2Zhc3QiOiAiYXV0byIsICJleHRyYV9kYXRhX3NlcnZlcl9mbGFncyI6ICIiLCAiZ3JwY19jcmVkc190eXBlIjogImxvY2FsIiwgImdycGNfZGF0YV9wcm92aWRlciI6ICIiLCAicHVyZ2Vfb3JwaGFuZWRfZGF0YSI6IHRydWUsICJkYiI6ICIiLCAiZGJfaW1wb3J0IjogZmFsc2UsICJpbnNwZWN0IjogZmFsc2UsICJ2ZXJzaW9uX3RiIjogZmFsc2UsICJ0YWciOiAiIiwgImV2ZW50X2ZpbGUiOiAiIiwgInBhdGhfcHJlZml4IjogIiIsICJ3aW5kb3dfdGl0bGUiOiAiIiwgIm1heF9yZWxvYWRfdGhyZWFkcyI6IDEsICJyZWxvYWRfaW50ZXJ2YWwiOiA1LjAsICJyZWxvYWRfdGFzayI6ICJhdXRvIiwgInJlbG9hZF9tdWx0aWZpbGUiOiBudWxsLCAicmVsb2FkX211bHRpZmlsZV9pbmFjdGl2ZV9zZWNzIjogODY0MDAsICJnZW5lcmljX2RhdGEiOiAiYXV0byIsICJzYW1wbGVzX3Blcl9wbHVnaW4iOiB7fSwgImN1c3RvbV9wcmVkaWN0X2ZuIjogIiIsICJ3aXRfZGF0YV9kaXIiOiAiIiwgIl9fdGVuc29yYm9hcmRfc3ViY29tbWFuZCI6ICJzZXJ2ZSJ9fX0=",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/json"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/data/runs": {
       "data": "WyJ0Zl9sb2dzIl0=",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/json"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/data/plugin/scalars/tags": {
       "data": "eyJ0Zl9sb2dzIjogeyJ0cmFpbi9sb3NzIjogeyJkaXNwbGF5TmFtZSI6ICIiLCAiZGVzY3JpcHRpb24iOiAiIn0sICJ0cmFpbi9sb3NzX3Jwbl9iYm94IjogeyJkaXNwbGF5TmFtZSI6ICIiLCAiZGVzY3JpcHRpb24iOiAiIn0sICJ0cmFpbi9hY2MiOiB7ImRpc3BsYXlOYW1lIjogIiIsICJkZXNjcmlwdGlvbiI6ICIifSwgImxlYXJuaW5nX3JhdGUiOiB7ImRpc3BsYXlOYW1lIjogIiIsICJkZXNjcmlwdGlvbiI6ICIifSwgIm1vbWVudHVtIjogeyJkaXNwbGF5TmFtZSI6ICIiLCAiZGVzY3JpcHRpb24iOiAiIn0sICJ0cmFpbi9ncmFkX25vcm0iOiB7ImRpc3BsYXlOYW1lIjogIiIsICJkZXNjcmlwdGlvbiI6ICIifSwgInZhbC9tQVAiOiB7ImRpc3BsYXlOYW1lIjogIiIsICJkZXNjcmlwdGlvbiI6ICIifSwgInRyYWluL2xvc3NfYmJveCI6IHsiZGlzcGxheU5hbWUiOiAiIiwgImRlc2NyaXB0aW9uIjogIiJ9LCAidHJhaW4vbG9zc19jbHMiOiB7ImRpc3BsYXlOYW1lIjogIiIsICJkZXNjcmlwdGlvbiI6ICIifSwgInRyYWluL2xvc3NfcnBuX2NscyI6IHsiZGlzcGxheU5hbWUiOiAiIiwgImRlc2NyaXB0aW9uIjogIiJ9fX0=",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/json"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/data/plugin/scalars/scalars?run=tf_logs&tag=learning_rate": {
       "data": "W1sxNjQ2NjEwMDk4LjQyNjg2MSwgMTAsIDAuMDAxMDAwMDAwMDQ3NDk3NDUxM10sIFsxNjQ2NjEwMTAzLjI1Mzc1ODQsIDIwLCAwLjAwMTAwMDAwMDA0NzQ5NzQ1MTNdLCBbMTY0NjYxMDEwNy45MDY3OTEyLCAzMCwgMC4wMDEwMDAwMDAwNDc0OTc0NTEzXSwgWzE2NDY2MTAxMTIuNjU2ODM0OCwgNDAsIDAuMDAxMDAwMDAwMDQ3NDk3NDUxM10sIFsxNjQ2NjEwMTE3LjUxMTAxNDcsIDUwLCAwLjAwMTAwMDAwMDA0NzQ5NzQ1MTNdLCBbMTY0NjYxMDEyOC4wMTU4NywgNjUsIDAuMDAxMDAwMDAwMDQ3NDk3NDUxM10sIFsxNjQ2NjEwMTMyLjg0MzQ0MTIsIDc1LCAwLjAwMTAwMDAwMDA0NzQ5NzQ1MTNdLCBbMTY0NjYxMDEzNy42MjkzMzY2LCA4NSwgMC4wMDEwMDAwMDAwNDc0OTc0NTEzXSwgWzE2NDY2MTAxNDIuMzE3NzA2NiwgOTUsIDAuMDAxMDAwMDAwMDQ3NDk3NDUxM10sIFsxNjQ2NjEwMTQ3LjA4OTU2NjUsIDEwNSwgMC4wMDEwMDAwMDAwNDc0OTc0NTEzXSwgWzE2NDY2MTAxNTYuNjk5Mjk2NywgMTIwLCAwLjAwMTAwMDAwMDA0NzQ5NzQ1MTNdLCBbMTY0NjYxMDE2MS40OTQwMzQ4LCAxMzAsIDAuMDAxMDAwMDAwMDQ3NDk3NDUxM10sIFsxNjQ2NjEwMTY2LjMzNTcyMiwgMTQwLCAwLjAwMTAwMDAwMDA0NzQ5NzQ1MTNdLCBbMTY0NjYxMDE3MS4yNDY4ODc0LCAxNTAsIDAuMDAxMDAwMDAwMDQ3NDk3NDUxM10sIFsxNjQ2NjEwMTc2LjA0MjMzMjYsIDE2MCwgMC4wMDEwMDAwMDAwNDc0OTc0NTEzXSwgWzE2NDY2MTAyMDcuOTA0Njc2NywgMTY2LCAwLjAwMTAwMDAwMDA0NzQ5NzQ1MTNdXQ==",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/json"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/data/plugin/scalars/scalars?run=tf_logs&tag=momentum": {
       "data": "W1sxNjQ2NjEwMDk4LjQyNjkxNzMsIDEwLCAwLjg5OTk5OTk3NjE1ODE0MjFdLCBbMTY0NjYxMDEwMy4yNTM3OTA0LCAyMCwgMC44OTk5OTk5NzYxNTgxNDIxXSwgWzE2NDY2MTAxMDcuOTA2ODE4NCwgMzAsIDAuODk5OTk5OTc2MTU4MTQyMV0sIFsxNjQ2NjEwMTEyLjY1Njg3NjMsIDQwLCAwLjg5OTk5OTk3NjE1ODE0MjFdLCBbMTY0NjYxMDExNy41MTEwNDQsIDUwLCAwLjg5OTk5OTk3NjE1ODE0MjFdLCBbMTY0NjYxMDEyOC4wMTU5MDk0LCA2NSwgMC44OTk5OTk5NzYxNTgxNDIxXSwgWzE2NDY2MTAxMzIuODQzNDcsIDc1LCAwLjg5OTk5OTk3NjE1ODE0MjFdLCBbMTY0NjYxMDEzNy42MjkzNzEsIDg1LCAwLjg5OTk5OTk3NjE1ODE0MjFdLCBbMTY0NjYxMDE0Mi4zMTc3NDEsIDk1LCAwLjg5OTk5OTk3NjE1ODE0MjFdLCBbMTY0NjYxMDE0Ny4wODk2MDA2LCAxMDUsIDAuODk5OTk5OTc2MTU4MTQyMV0sIFsxNjQ2NjEwMTU2LjY5OTMzOTYsIDEyMCwgMC44OTk5OTk5NzYxNTgxNDIxXSwgWzE2NDY2MTAxNjEuNDk0MDY4NCwgMTMwLCAwLjg5OTk5OTk3NjE1ODE0MjFdLCBbMTY0NjYxMDE2Ni4zMzU3NjE1LCAxNDAsIDAuODk5OTk5OTc2MTU4MTQyMV0sIFsxNjQ2NjEwMTcxLjI0NjkyMzQsIDE1MCwgMC44OTk5OTk5NzYxNTgxNDIxXSwgWzE2NDY2MTAxNzYuMDQyMzcyLCAxNjAsIDAuODk5OTk5OTc2MTU4MTQyMV0sIFsxNjQ2NjEwMjA3LjkwNDc1NSwgMTY2LCAwLjg5OTk5OTk3NjE1ODE0MjFdXQ==",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/json"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/font-roboto/Hgo13k-tfSpn0qi1SFdUfZBw1xU1rKptJj_0jans920.woff2": {
       "data": "[encoded data, 14504 characters]",
       "ok": true,
       "headers": [
        [
         "content-type",
         "font/woff2"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/font-roboto/d-6IYplOFocCacKzxwXSOJBw1xU1rKptJj_0jans920.woff2": {
       "data": "[encoded data, 14352 characters]",
       "ok": true,
       "headers": [
        [
         "content-type",
         "font/woff2"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/data/plugin/scalars/scalars?run=tf_logs&tag=train%2Facc": {
       "data": "W1sxNjQ2NjEwMDk4LjQyNjY1MTcsIDEwLCA5MS43ODcxMDkzNzVdLCBbMTY0NjYxMDEwMy4yNTM2MjA2LCAyMCwgOTIuOTk4MDQ2ODc1XSwgWzE2NDY2MTAxMDcuOTA2NjAyNCwgMzAsIDk0LjUxMTcxODc1XSwgWzE2NDY2MTAxMTIuNjU2NjU3LCA0MCwgOTIuNTQ4ODI4MTI1XSwgWzE2NDY2MTAxMTcuNTEwODg3MSwgNTAsIDkzLjQwODIwMzEyNV0sIFsxNjQ2NjEwMTI4LjAxNTcxNjMsIDY1LCA5My4yMDMxMjVdLCBbMTY0NjYxMDEzMi44NDMzMTIsIDc1LCA5MS42ODk0NTMxMjVdLCBbMTY0NjYxMDEzNy42MjkxNDU5LCA4NSwgOTQuMzE2NDA2MjVdLCBbMTY0NjYxMDE0Mi4zMTc1NTQyLCA5NSwgOTIuOTM5NDUzMTI1XSwgWzE2NDY2MTAxNDcuMDg5NDIxLCAxMDUsIDk0Ljg0Mzc1XSwgWzE2NDY2MTAxNTYuNjk5MTExLCAxMjAsIDk1Ljc0MjE4NzVdLCBbMTY0NjYxMDE2MS40OTM4OTI0LCAxMzAsIDk2LjA3NDIxODc1XSwgWzE2NDY2MTAxNjYuMzM1NTUyLCAxNDAsIDk1LjQyOTY4NzVdLCBbMTY0NjYxMDE3MS4yNDY3MjM3LCAxNTAsIDk1LjYwNTQ2ODc1XSwgWzE2NDY2MTAxNzYuMDQyMTI4OCwgMTYwLCA5Ni45MzM1OTM3NV1d",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/json"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/data/plugin/scalars/scalars?run=tf_logs&tag=train%2Floss_bbox": {
       "data": "W1sxNjQ2NjEwMDk4LjQyNjY5ODQsIDEwLCAwLjA1NzM4MjEyOTEzMjc0NzY1XSwgWzE2NDY2MTAxMDMuMjUzNjYwMiwgMjAsIDAuMTE2MDI5MzI5NTk3OTQ5OThdLCBbMTY0NjYxMDEwNy45MDY2NTcsIDMwLCAwLjEwMjU1NDExMjY3MjgwNTc5XSwgWzE2NDY2MTAxMTIuNjU2NzA3NSwgNDAsIDAuMTQzOTYxNzU3NDIxNDkzNTNdLCBbMTY0NjYxMDExNy41MTA5MjA1LCA1MCwgMC4xMjU0MzE5MjUwNTgzNjQ4N10sIFsxNjQ2NjEwMTI4LjAxNTc1MDYsIDY1LCAwLjA5OTUyMTE3NTAyNjg5MzYyXSwgWzE2NDY2MTAxMzIuODQzMzQ0NywgNzUsIDAuMTQ5NjA4NjQxODYyODY5MjZdLCBbMTY0NjYxMDEzNy42MjkxODU3LCA4NSwgMC4wOTg2MzAzNjg3MDk1NjQyMV0sIFsxNjQ2NjEwMTQyLjMxNzYwNywgOTUsIDAuMTA2NTMzMDk1MjQwNTkyOTZdLCBbMTY0NjYxMDE0Ny4wODk0NTksIDEwNSwgMC4xMDA0NTAxMDU5NjUxMzc0OF0sIFsxNjQ2NjEwMTU2LjY5OTE0NjMsIDEyMCwgMC4xMDE2MDQ3OTY5NDYwNDg3NF0sIFsxNjQ2NjEwMTYxLjQ5MzkyODIsIDEzMCwgMC4wODcwNjIxMDU1MzY0NjA4OF0sIFsxNjQ2NjEwMTY2LjMzNTYwMywgMTQwLCAwLjE3ODc0ODY5NzA0MjQ2NTJdLCBbMTY0NjYxMDE3MS4yNDY3NjA4LCAxNTAsIDAuMTE1OTY4NjE0ODE2NjY1NjVdLCBbMTY0NjYxMDE3Ni4wNDIxNjkzLCAxNjAsIDAuMTA1MjE5ODcwODA1NzQwMzZdXQ==",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/json"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/data/plugin/scalars/scalars?run=tf_logs&tag=train%2Floss": {
       "data": "W1sxNjQ2NjEwMDk4LjQyNjc0MywgMTAsIDAuNjIzMjM4ODAxOTU2MTc2OF0sIFsxNjQ2NjEwMTAzLjI1MzY5NDUsIDIwLCAwLjM2MjgxMTM4NjU4NTIzNTZdLCBbMTY0NjYxMDEwNy45MDY3MDM3LCAzMCwgMC4yODI1MjA1OTIyMTI2NzddLCBbMTY0NjYxMDExMi42NTY3NTE2LCA0MCwgMC4zMjU3MzE1NzU0ODkwNDQyXSwgWzE2NDY2MTAxMTcuNTEwOTUxNSwgNTAsIDAuMzAxOTI1ODY3Nzk1OTQ0Ml0sIFsxNjQ2NjEwMTI4LjAxNTc4MTYsIDY1LCAwLjI0ODI0OTU3NTQ5NTcxOTldLCBbMTY0NjYxMDEzMi44NDMzNzc2LCA3NSwgMC4zMzQ3NTg0MzA3MTkzNzU2XSwgWzE2NDY2MTAxMzcuNjI5MjYyNywgODUsIDAuMjU1MzUzMzMxNTY1ODU2OTNdLCBbMTY0NjYxMDE0Mi4zMTc2NDEsIDk1LCAwLjI1OTY3MjUyMjU0NDg2MDg0XSwgWzE2NDY2MTAxNDcuMDg5NDk2NCwgMTA1LCAwLjIzNTcwNjQxODc1MjY3MDNdLCBbMTY0NjYxMDE1Ni42OTkxNzk0LCAxMjAsIDAuMjQyNzU2NDQxMjM1NTQyM10sIFsxNjQ2NjEwMTYxLjQ5Mzk2MzcsIDEzMCwgMC4yMzIzNjEwNzgyNjIzMjkxXSwgWzE2NDY2MTAxNjYuMzM1NjQyLCAxNDAsIDAuMzM5NzUxODM5NjM3NzU2MzVdLCBbMTY0NjYxMDE3MS4yNDY4MTI2LCAxNTAsIDAuMjU3Njc0NDI1ODQwMzc3OF0sIFsxNjQ2NjEwMTc2LjA0MjIyOTQsIDE2MCwgMC4yMTkxMDI2MzU5Nzk2NTI0XV0=",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/json"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/data/plugin/scalars/scalars?run=tf_logs&tag=train%2Floss_rpn_cls": {
       "data": "W1sxNjQ2NjEwMDk4LjQyNjI5ODQsIDEwLCAwLjEyNjgwNTM3OTk4Njc2M10sIFsxNjQ2NjEwMTAzLjI1MzQyMiwgMjAsIDAuMDQxNjUzMzc2MDcyNjQ1MTldLCBbMTY0NjYxMDEwNy45MDYxMDY1LCAzMCwgMC4wMTc3MTEwMTM1NTU1MjY3MzNdLCBbMTY0NjYxMDExMi42NTYzOTQ1LCA0MCwgMC4wMTIwNDYxOTc0MjkyOTkzNTVdLCBbMTY0NjYxMDExNy41MTA3MTAyLCA1MCwgMC4wMDkyMDgzNjgxMzc0Nzg4MjhdLCBbMTY0NjYxMDEyOC4wMTU0MjQzLCA2NSwgMC4wMDUxOTQ4MTY3MzgzNjcwODFdLCBbMTY0NjYxMDEzMi44NDMwNzM0LCA3NSwgMC4wMDI5MDE1ODIyODAxNzM4OTc3XSwgWzE2NDY2MTAxMzcuNjI4OTE1OCwgODUsIDAuMDA1MjU3OTcwMTg3ODEzMDQ0XSwgWzE2NDY2MTAxNDIuMzE3Mzg5NywgOTUsIDAuMDAxNDMyNjAxMTI5NjM2MTY4NV0sIFsxNjQ2NjEwMTQ3LjA4OTE3NzQsIDEwNSwgMC4wMDM0ODUzMDMzNzIxNDQ2OTldLCBbMTY0NjYxMDE1Ni42OTg4MjIzLCAxMjAsIDAuMDAxNjIwNzM0NDU5NzIwNTUyXSwgWzE2NDY2MTAxNjEuNDkzNjg4OCwgMTMwLCAwLjAwMDc4OTY0MzE0ODg5MTYyNzhdLCBbMTY0NjYxMDE2Ni4zMzUzNjEyLCAxNDAsIDAuMDAzNDcyODU3ODc1NzQ5NDY5XSwgWzE2NDY2MTAxNzEuMjQ2NDk0NSwgMTUwLCAwLjAwMjY0NzE0MTkyNTk5MDU4MTVdLCBbMTY0NjYxMDE3Ni4wNDE5MjQyLCAxNjAsIDAuMDAwNTUwMTA3MjczNzM4ODMxM11d",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/json"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/data/plugin/scalars/scalars?run=tf_logs&tag=train%2Floss_cls": {
       "data": "W1sxNjQ2NjEwMDk4LjQyNjYwMDcsIDEwLCAwLjQwNzUxOTU0OTEzMTM5MzQzXSwgWzE2NDY2MTAxMDMuMjUzNTcxLCAyMCwgMC4xODI3Mjk3MzU5NzA0OTcxM10sIFsxNjQ2NjEwMTA3LjkwNjUxMTUsIDMwLCAwLjEzMDM2NTI5NzE5ODI5NTZdLCBbMTY0NjYxMDExMi42NTY2MDEyLCA0MCwgMC4xNDg1NjQxNTk4NzAxNDc3XSwgWzE2NDY2MTAxMTcuNTEwODUzLCA1MCwgMC4xNDE0ODExNzYwMTg3MTQ5XSwgWzE2NDY2MTAxMjguMDE1NjgxNSwgNjUsIDAuMTI5MjIxMjQ1NjQ2NDc2NzVdLCBbMTY0NjYxMDEzMi44NDMyNzUsIDc1LCAwLjE1MjQxMzM2ODIyNTA5NzY2XSwgWzE2NDY2MTAxMzcuNjI5MDg5OCwgODUsIDAuMTI1NDgyMzY1NDg5MDA2MDRdLCBbMTY0NjYxMDE0Mi4zMTc1MiwgOTUsIDAuMTM3NjY2OTg1MzkyNTcwNV0sIFsxNjQ2NjEwMTQ3LjA4OTM3ODgsIDEwNSwgMC4xMTI2MTA3NDk5MDAzNDEwM10sIFsxNjQ2NjEwMTU2LjY5OTA2MzUsIDEyMCwgMC4xMjIwOTE1NjE1NTU4NjI0M10sIFsxNjQ2NjEwMTYxLjQ5Mzg1NDMsIDEzMCwgMC4xMTgyNjAyNzE4NDcyNDgwOF0sIFsxNjQ2NjEwMTY2LjMzNTUxMiwgMTQwLCAwLjExNzkxMjEyODU2NzY5NTYyXSwgWzE2NDY2MTAxNzEuMjQ2Njc4LCAxNTAsIDAuMTE1NzM1NDE5MDk0NTYyNTNdLCBbMTY0NjYxMDE3Ni4wNDIwODU2LCAxNjAsIDAuMTAwNDczNDU2MDg0NzI4MjRdXQ==",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/json"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/data/plugin/scalars/scalars?run=tf_logs&tag=train%2Fgrad_norm": {
       "data": "W1sxNjQ2NjEwMDk4LjQyNjc4OSwgMTAsIDUuODM5NTY1NzUzOTM2NzY4XSwgWzE2NDY2MTAxMDMuMjUzNzI2MiwgMjAsIDMuNjk0NzY4MTkwMzgzOTExXSwgWzE2NDY2MTAxMDcuOTA2NzQ4NSwgMzAsIDIuNDg2NTI2NDg5MjU3ODEyNV0sIFsxNjQ2NjEwMTEyLjY1Njc5MjYsIDQwLCAyLjkwMjYzODY3Mzc4MjM0ODZdLCBbMTY0NjYxMDExNy41MTA5ODEsIDUwLCAyLjE4NzMzMjYzMDE1NzQ3MDddLCBbMTY0NjYxMDEyOC4wMTU4MTE0LCA2NSwgMi4wMDY4NjY2OTM0OTY3MDRdLCBbMTY0NjYxMDEzMi44NDM0MDksIDc1LCAyLjIyNzMyNzM0NjgwMTc1OF0sIFsxNjQ2NjEwMTM3LjYyOTI5OTYsIDg1LCAxLjc3MDM0MDIwNDIzODg5MTZdLCBbMTY0NjYxMDE0Mi4zMTc2NzIsIDk1LCAxLjg1MDA3MjAyNjI1Mjc0NjZdLCBbMTY0NjYxMDE0Ny4wODk1MzE3LCAxMDUsIDIuMTQ3NTczNDcxMDY5MzM2XSwgWzE2NDY2MTAxNTYuNjk5MjI5NSwgMTIwLCAyLjAzMzc2NzIyMzM1ODE1NDNdLCBbMTY0NjYxMDE2MS40OTM5OTgsIDEzMCwgMS44NjYyMjAxMTY2MTUyOTU0XSwgWzE2NDY2MTAxNjYuMzM1NjgxMiwgMTQwLCAyLjYwNjUzMTg1ODQ0NDIxNF0sIFsxNjQ2NjEwMTcxLjI0Njg0OSwgMTUwLCAyLjA2MDY3MzcxMzY4NDA4Ml0sIFsxNjQ2NjEwMTc2LjA0MjI3NzgsIDE2MCwgMS44MzA2MDUwMzAwNTk4MTQ1XV0=",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/json"
        ]
       ],
       "status": 200,
       "status_text": ""
      },
      "https://localhost:6009/data/plugin/scalars/scalars?run=tf_logs&tag=train%2Floss_rpn_bbox": {
       "data": "W1sxNjQ2NjEwMDk4LjQyNjUzNTYsIDEwLCAwLjAzMTUzMTcwNjQ1MjM2OTY5XSwgWzE2NDY2MTAxMDMuMjUzNTI2NCwgMjAsIDAuMDIyMzk4OTUyMzk0NzIzODkyXSwgWzE2NDY2MTAxMDcuOTA2MzM0LCAzMCwgMC4wMzE4OTAxNzI1MTEzMzkxOV0sIFsxNjQ2NjEwMTEyLjY1NjUzMDEsIDQwLCAwLjAyMTE1OTQ2NjM1NjAzOTA0N10sIFsxNjQ2NjEwMTE3LjUxMDgxNDIsIDUwLCAwLjAyNTgwNDM5MTEzMDgwNTAxNl0sIFsxNjQ2NjEwMTI4LjAxNTYzMzgsIDY1LCAwLjAxNDMxMjMzOTk0NjYyNzYxN10sIFsxNjQ2NjEwMTMyLjg0MzIwNTIsIDc1LCAwLjAyOTgzNDgzODU4NDA2NTQzN10sIFsxNjQ2NjEwMTM3LjYyOTAzOTMsIDg1LCAwLjAyNTk4MjYxNDYwNjYxODg4XSwgWzE2NDY2MTAxNDIuMzE3NDgwNiwgOTUsIDAuMDE0MDM5ODM1ODkyNjE3NzAyXSwgWzE2NDY2MTAxNDcuMDg5MzI4LCAxMDUsIDAuMDE5MTYwMjY2OTY1NjI3NjddLCBbMTY0NjYxMDE1Ni42OTkwMTU2LCAxMjAsIDAuMDE3NDM5MzQ4NjIzMTU2NTQ4XSwgWzE2NDY2MTAxNjEuNDkzODA1MiwgMTMwLCAwLjAyNjI0OTA1Mjk1NjcwMDMyNV0sIFsxNjQ2NjEwMTY2LjMzNTQ2NDUsIDE0MCwgMC4wMzk2MTgxNzU0NzY3ODk0NzRdLCBbMTY0NjYxMDE3MS4yNDY2MjA0LCAxNTAsIDAuMDIzMzIzMjQ3MjA5MTkxMzIyXSwgWzE2NDY2MTAxNzYuMDQyMDI0LCAxNjAsIDAuMDEyODU5MjAzODUyNzEzMTA4XV0=",
       "ok": true,
       "headers": [
        [
         "content-type",
         "application/json"
        ]
       ],
       "status": 200,
       "status_text": ""
      }
     },
     "base_uri": "https://localhost:8080/",
     "height": 856
    },
    "id": "0DcFrtBmgOID",
    "outputId": "b7700f03-c681-4495-9817-ea224b99cf32"
   },
   "execution_count": null,
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "The tensorboard extension is already loaded. To reload it, use:\n",
      "  %reload_ext tensorboard\n"
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "application/javascript": [
       "\n",
       "        (async () => {\n",
       "            const url = new URL(await google.colab.kernel.proxyPort(6009, {'cache': true}));\n",
       "            url.searchParams.set('tensorboardColab', 'true');\n",
       "            const iframe = document.createElement('iframe');\n",
       "            iframe.src = url;\n",
       "            iframe.setAttribute('width', '100%');\n",
       "            iframe.setAttribute('height', '800');\n",
       "            iframe.setAttribute('frameborder', 0);\n",
       "            document.body.appendChild(iframe);\n",
       "        })();\n",
       "    "
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {}
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "MfQ-yspZLuuI"
   },
   "source": [
    "From the tensorboard, we can observe that changes of loss and learning rate. We can see the losses of each branch gradually decrease as the training goes by.\n",
    "\n",
    "## Test the trained detector\n",
    "\n",
    "After finetuning the detector, let's visualize the prediction results!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 405
    },
    "id": "_MuZurfGLq0p",
    "outputId": "09e72fb0-3644-4f56-9acd-8b62d957ac0a"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "/usr/local/lib/python3.7/dist-packages/mmdet/models/dense_heads/anchor_head.py:123: UserWarning: DeprecationWarning: anchor_generator is deprecated, please use \"prior_generator\" instead\n",
      "  warnings.warn('DeprecationWarning: anchor_generator is deprecated, '\n"
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<Figure size 512.01x321.01 with 1 Axes>"
      ],
      "image/png": "[encoded data, 179296 characters]\n"
     },
     "metadata": {
      "needs_background": "light"
     }
    }
   ],
   "source": [
    "img = mmcv.imread('ssdd_tiny/images/001129.png')\n",
    "model.cfg = cfg\n",
    "result = inference_detector(model, img)\n",
    "show_result_pyplot(model, img, result, score_thr=0.3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "F1L8o3rtc37M"
   },
   "source": [
    "## What to Do Next?\n",
    "\n",
    "So far, we have learnt how to test a two-stage detector using MMRotate. To further explore MMRotate, you could do several other things as shown below:\n",
    "\n",
    "- Try single-stage detectors, e.g., [Rotated RetinaNet](https://github.com/open-mmlab/mmrotate/tree/dev/configs/rotated_retinanet) and [GWD](https://github.com/open-mmlab/mmrotate/tree/dev/configs/gwd) in [MMRotate model zoo](https://github.com/open-mmlab/mmrotate/blob/dev/docs/en/model_zoo.md). Single-stage detectors are more commonly used than two-stage detectors in industry.\n",
    "- Try anchor-free detectors, e.g., [Rotated RepPoints](https://github.com/open-mmlab/mmrotate/tree/dev/configs/rotated_reppoints) and [CFA](https://github.com/open-mmlab/mmrotate/tree/dev/configs/cfa) in [MMRotate model zoo](https://github.com/open-mmlab/mmrotate/blob/dev/docs/en/model_zoo.md). Anchor-free detector is a new trend in the object detection community.\n"
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "collapsed_sections": [],
   "name": "object_detection",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "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.6.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
