{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "cc633225-bd1f-44fe-be1a-b1e0fa634b2d",
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide\n",
    "! [ -e /content ] && pip install -Uqq fastbook\n",
    "import fastbook\n",
    "fastbook.setup_book()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a3ef801f-c3c8-4bd1-ab8f-9432549a3337",
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide\n",
    "from fastbook import *\n",
    "from fastai.vision.widgets import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "5fc6d94e-b54d-4cdf-876b-c81cacda385f",
   "metadata": {},
   "outputs": [],
   "source": [
    "key = os.environ.get('AZURE_SEARCH_KEY', '7abaad513db84a0ba26d2064d5494231')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "de64e2de-1e56-48dd-9dd4-680d07468547",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function fastbook.search_images_bing(key, term, min_sz=128, max_images=150)>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "search_images_bing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "b50e9a3a-00c1-49ef-b2e7-cefdbaea9d77",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "150"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "results = search_images_bing(key, 'grizzly bear')\n",
    "ims = results.attrgot('contentUrl')\n",
    "len(ims)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "59aa1157-3234-409a-b62c-559283a4f275",
   "metadata": {
    "hide_input": true
   },
   "outputs": [],
   "source": [
    "#hide\n",
    "ims = ['http://3.bp.blogspot.com/-S1scRCkI3vY/UHzV2kucsPI/AAAAAAAAA-k/YQ5UzHEm9Ss/s1600/Grizzly%2BBear%2BWildlife.jpg']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "ba8bf2c1-46ef-48fb-b03d-5dcf46197aa2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "    /* Turns off some styling */\n",
       "    progress {\n",
       "        /* gets rid of default border in Firefox and Opera. */\n",
       "        border: none;\n",
       "        /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
       "        background-size: auto;\n",
       "    }\n",
       "    progress:not([value]), progress:not([value])::-webkit-progress-bar {\n",
       "        background: repeating-linear-gradient(45deg, #7e7e7e, #7e7e7e 10px, #5c5c5c 10px, #5c5c5c 20px);\n",
       "    }\n",
       "    .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
       "        background: #F44336;\n",
       "    }\n",
       "</style>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "\n",
       "    <div>\n",
       "      <progress value='704512' class='' max='697626' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
       "      100.99% [704512/697626 00:00&lt;00:00]\n",
       "    </div>\n",
       "    "
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "Path('images/grizzly.jpg')"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dest = 'images/grizzly.jpg'\n",
    "download_url(ims[0], dest)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "8b4381d0-884c-4836-94d1-8dfc08e95f86",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/jpeg": "[encoded data, 5016 characters]",
      "image/png": "[encoded data, 39660 characters]",
      "text/plain": [
       "<PIL.Image.Image image mode=RGB size=108x128>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "im = Image.open(dest)\n",
    "im.to_thumb(128,128)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "7d8da2c0-d4fa-4096-aecd-2f153798f8a8",
   "metadata": {},
   "outputs": [],
   "source": [
    "bear_types = 'grizzly','black','teddy'\n",
    "path = Path('bears')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "3ab052df-0615-410f-a338-c4c5b1fac5af",
   "metadata": {},
   "outputs": [],
   "source": [
    "if not path.exists():\n",
    "    path.mkdir()\n",
    "    for o in bear_types:\n",
    "        dest = (path/o)\n",
    "        dest.mkdir(exist_ok=True)\n",
    "        results = search_images_bing(key, f'{o} bear')\n",
    "        download_images(dest, urls=results.attrgot('contentUrl'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "75457a53-45c7-45b2-a523-5f54d40adba6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "412"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fns = get_image_files(path)\n",
    "len(fns)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "bcd84a8d-e8cc-4fd4-b1e7-cb973bfb53a0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "failed = verify_images(fns)\n",
    "len(failed)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "115d00d3-f3b3-423f-b2ce-dec9e4b2f8d1",
   "metadata": {},
   "outputs": [],
   "source": [
    "failed.map(Path.unlink);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "d5ff7b3e-6999-4bee-b3cb-d635575de1a5",
   "metadata": {},
   "outputs": [],
   "source": [
    "bears = DataBlock(\n",
    "    blocks=(ImageBlock, CategoryBlock), \n",
    "    get_items=get_image_files, \n",
    "    splitter=RandomSplitter(valid_pct=0.2, seed=42),\n",
    "    get_y=parent_label,\n",
    "    item_tfms=Resize(128))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "72b1a022-add5-4ef0-93b3-ba83e4c23fba",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<fastai.data.core.DataLoaders at 0x7f4489753760>"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dls = bears.dataloaders(path)\n",
    "dls"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "88ed710f-61d4-49c2-b75f-52cf1b13d2dc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 1094100 characters]",
      "text/plain": [
       "<Figure size 1200x900 with 12 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "dls.valid.show_batch(max_n=12, nrows=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "bbe5eed3-dafb-45e2-9781-f51a0405cc51",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 383416 characters]",
      "text/plain": [
       "<Figure size 1200x300 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "bears = bears.new(item_tfms=Resize(128, ResizeMethod.Squish))\n",
    "dls = bears.dataloaders(path)\n",
    "dls.valid.show_batch(max_n=4, nrows=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "0cdd838f-2567-49a1-943d-dd5b1b775a87",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 288136 characters]",
      "text/plain": [
       "<Figure size 1200x300 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "bears = bears.new(item_tfms=Resize(128, ResizeMethod.Pad, pad_mode='zeros'))\n",
    "dls = bears.dataloaders(path)\n",
    "dls.valid.show_batch(max_n=4, nrows=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "95d13af7-7483-439e-86fa-f27055e6ad39",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 371748 characters]",
      "text/plain": [
       "<Figure size 1200x300 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "bears = bears.new(item_tfms=RandomResizedCrop(128, min_scale=0.3))\n",
    "dls = bears.dataloaders(path)\n",
    "dls.train.show_batch(max_n=4, nrows=1, unique=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "66a6ffa3-b73d-427a-aa27-0cddeab3e601",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 731448 characters]",
      "text/plain": [
       "<Figure size 1200x600 with 8 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "bears = bears.new(item_tfms=Resize(128), batch_tfms=aug_transforms(mult=2))\n",
    "dls = bears.dataloaders(path)\n",
    "dls.train.show_batch(max_n=8, nrows=2, unique=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "eb7d23ec-32b7-4ec1-8f30-1c29d4dc20d3",
   "metadata": {},
   "outputs": [],
   "source": [
    "bears = bears.new(\n",
    "    item_tfms=RandomResizedCrop(224, min_scale=0.5),\n",
    "    batch_tfms=aug_transforms())\n",
    "dls = bears.dataloaders(path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "4b9b06af-721e-467f-b3e7-8aa135a1e717",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Downloading: \"https://download.pytorch.org/models/resnet18-f37072fd.pth\" to /root/.cache/torch/hub/checkpoints/resnet18-f37072fd.pth\n",
      "100%|██████████| 44.7M/44.7M [00:00<00:00, 101MB/s] \n",
      "[W NNPACK.cpp:64] Could not initialize NNPACK! Reason: Unsupported hardware.\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "    /* Turns off some styling */\n",
       "    progress {\n",
       "        /* gets rid of default border in Firefox and Opera. */\n",
       "        border: none;\n",
       "        /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
       "        background-size: auto;\n",
       "    }\n",
       "    progress:not([value]), progress:not([value])::-webkit-progress-bar {\n",
       "        background: repeating-linear-gradient(45deg, #7e7e7e, #7e7e7e 10px, #5c5c5c 10px, #5c5c5c 20px);\n",
       "    }\n",
       "    .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
       "        background: #F44336;\n",
       "    }\n",
       "</style>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: left;\">\n",
       "      <th>epoch</th>\n",
       "      <th>train_loss</th>\n",
       "      <th>valid_loss</th>\n",
       "      <th>error_rate</th>\n",
       "      <th>time</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>1.060724</td>\n",
       "      <td>0.174752</td>\n",
       "      <td>0.048780</td>\n",
       "      <td>00:11</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "    /* Turns off some styling */\n",
       "    progress {\n",
       "        /* gets rid of default border in Firefox and Opera. */\n",
       "        border: none;\n",
       "        /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
       "        background-size: auto;\n",
       "    }\n",
       "    progress:not([value]), progress:not([value])::-webkit-progress-bar {\n",
       "        background: repeating-linear-gradient(45deg, #7e7e7e, #7e7e7e 10px, #5c5c5c 10px, #5c5c5c 20px);\n",
       "    }\n",
       "    .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
       "        background: #F44336;\n",
       "    }\n",
       "</style>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: left;\">\n",
       "      <th>epoch</th>\n",
       "      <th>train_loss</th>\n",
       "      <th>valid_loss</th>\n",
       "      <th>error_rate</th>\n",
       "      <th>time</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>0.202916</td>\n",
       "      <td>0.096295</td>\n",
       "      <td>0.036585</td>\n",
       "      <td>00:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>0.155526</td>\n",
       "      <td>0.065877</td>\n",
       "      <td>0.012195</td>\n",
       "      <td>00:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>0.124621</td>\n",
       "      <td>0.062025</td>\n",
       "      <td>0.012195</td>\n",
       "      <td>00:10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>0.104887</td>\n",
       "      <td>0.063404</td>\n",
       "      <td>0.012195</td>\n",
       "      <td>00:10</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "learn = vision_learner(dls, resnet18, metrics=error_rate)\n",
    "learn.fine_tune(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "afdef2fc-c5e6-45db-942a-c49e4b676458",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "    /* Turns off some styling */\n",
       "    progress {\n",
       "        /* gets rid of default border in Firefox and Opera. */\n",
       "        border: none;\n",
       "        /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
       "        background-size: auto;\n",
       "    }\n",
       "    progress:not([value]), progress:not([value])::-webkit-progress-bar {\n",
       "        background: repeating-linear-gradient(45deg, #7e7e7e, #7e7e7e 10px, #5c5c5c 10px, #5c5c5c 20px);\n",
       "    }\n",
       "    .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
       "        background: #F44336;\n",
       "    }\n",
       "</style>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "    /* Turns off some styling */\n",
       "    progress {\n",
       "        /* gets rid of default border in Firefox and Opera. */\n",
       "        border: none;\n",
       "        /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
       "        background-size: auto;\n",
       "    }\n",
       "    progress:not([value]), progress:not([value])::-webkit-progress-bar {\n",
       "        background: repeating-linear-gradient(45deg, #7e7e7e, #7e7e7e 10px, #5c5c5c 10px, #5c5c5c 20px);\n",
       "    }\n",
       "    .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
       "        background: #F44336;\n",
       "    }\n",
       "</style>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 24936 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "interp = ClassificationInterpretation.from_learner(learn)\n",
    "interp.plot_confusion_matrix()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "db469df3-27b7-4de1-b4c0-f8e2ec5d58e4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "    /* Turns off some styling */\n",
       "    progress {\n",
       "        /* gets rid of default border in Firefox and Opera. */\n",
       "        border: none;\n",
       "        /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
       "        background-size: auto;\n",
       "    }\n",
       "    progress:not([value]), progress:not([value])::-webkit-progress-bar {\n",
       "        background: repeating-linear-gradient(45deg, #7e7e7e, #7e7e7e 10px, #5c5c5c 10px, #5c5c5c 20px);\n",
       "    }\n",
       "    .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
       "        background: #F44336;\n",
       "    }\n",
       "</style>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 608140 characters]",
      "text/plain": [
       "<Figure size 1500x300 with 5 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "interp.plot_top_losses(5, nrows=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "9487672d-860c-41a9-9cd6-2ff19d7520fa",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "    /* Turns off some styling */\n",
       "    progress {\n",
       "        /* gets rid of default border in Firefox and Opera. */\n",
       "        border: none;\n",
       "        /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
       "        background-size: auto;\n",
       "    }\n",
       "    progress:not([value]), progress:not([value])::-webkit-progress-bar {\n",
       "        background: repeating-linear-gradient(45deg, #7e7e7e, #7e7e7e 10px, #5c5c5c 10px, #5c5c5c 20px);\n",
       "    }\n",
       "    .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
       "        background: #F44336;\n",
       "    }\n",
       "</style>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "    /* Turns off some styling */\n",
       "    progress {\n",
       "        /* gets rid of default border in Firefox and Opera. */\n",
       "        border: none;\n",
       "        /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
       "        background-size: auto;\n",
       "    }\n",
       "    progress:not([value]), progress:not([value])::-webkit-progress-bar {\n",
       "        background: repeating-linear-gradient(45deg, #7e7e7e, #7e7e7e 10px, #5c5c5c 10px, #5c5c5c 20px);\n",
       "    }\n",
       "    .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
       "        background: #F44336;\n",
       "    }\n",
       "</style>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "7a3818f77ece45518ccb54d923c98ce7",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "VBox(children=(Dropdown(options=('black', 'grizzly', 'teddy'), value='black'), Dropdown(options=('Train', 'Val…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#hide_output\n",
    "cleaner = ImageClassifierCleaner(learn)\n",
    "cleaner"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "dbfaba70-9ca9-451f-b2da-28531729a0c9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "04f60e81d7b74c8bb4d897a30b6a1829",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(IntSlider(value=5, description='x', max=10), Output()), _dom_classes=('widget-interact',…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<function __main__.f(x)>"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import ipywidgets\n",
    "from ipywidgets import interact, IntSlider\n",
    "def f(x):\n",
    "    return x\n",
    "\n",
    "interact(f, x=IntSlider(min=0, max=10, step=1, value=5))\n",
    "#hide\n",
    "# for idx in cleaner.delete(): cleaner.fns[idx].unlink()\n",
    "# for idx,cat in cleaner.change(): shutil.move(str(cleaner.fns[idx]), path/cat)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b867ffcc-2119-4ca6-8a9e-aa5d93d5aa46",
   "metadata": {},
   "outputs": [],
   "source": [
    "learn.export()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "70c7a92e-f527-4c46-afba-0f8f3a327153",
   "metadata": {},
   "outputs": [],
   "source": [
    "path = Path()\n",
    "path.ls(file_exts='.pkl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bd66f2c2-adc4-489e-b434-5805e96deda4",
   "metadata": {},
   "outputs": [],
   "source": [
    "learn_inf = load_learner(path/'export.pkl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f6fec006-9ece-4bbb-9ee6-e3b401a36fba",
   "metadata": {},
   "outputs": [],
   "source": [
    "learn_inf.predict('images/grizzly.jpg')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "253c2517-8175-4ebb-b43b-506e36d27407",
   "metadata": {},
   "outputs": [],
   "source": [
    "learn_inf.dls.vocab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1da0a6b5-416b-4c6a-b707-de03a0addd78",
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide_output\n",
    "btn_upload = widgets.FileUpload()\n",
    "btn_upload"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e660413f-169d-4599-8016-ae215db16e32",
   "metadata": {
    "hide_input": true
   },
   "outputs": [],
   "source": [
    "#hide\n",
    "# For the book, we can't actually click an upload button, so we fake it\n",
    "btn_upload = SimpleNamespace(data = ['images/grizzly.jpg'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c08fc992-f4be-4a08-90c5-b8b2f8bd2c01",
   "metadata": {},
   "outputs": [],
   "source": [
    "img = PILImage.create(btn_upload.data[-1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "947b4b4b-56e2-46eb-8358-bc34022e1256",
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide_output\n",
    "out_pl = widgets.Output()\n",
    "out_pl.clear_output()\n",
    "with out_pl: display(img.to_thumb(128,128))\n",
    "out_pl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "56998404-f13e-45bd-b404-d0ef865cd6c3",
   "metadata": {},
   "outputs": [],
   "source": [
    "pred,pred_idx,probs = learn_inf.predict(img)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b0b4365a-f3fa-424c-b1c6-af8c5eb05bf0",
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide_output\n",
    "lbl_pred = widgets.Label()\n",
    "lbl_pred.value = f'Prediction: {pred}; Probability: {probs[pred_idx]:.04f}'\n",
    "lbl_pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0f36264c-b305-4e82-8914-e534752472dd",
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide_output\n",
    "btn_run = widgets.Button(description='Classify')\n",
    "btn_run"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c597e678-c2a9-4f5f-b311-0a9fb7965513",
   "metadata": {},
   "outputs": [],
   "source": [
    "def on_click_classify(change):\n",
    "    img = PILImage.create(btn_upload.data[-1])\n",
    "    out_pl.clear_output()\n",
    "    with out_pl: display(img.to_thumb(128,128))\n",
    "    pred,pred_idx,probs = learn_inf.predict(img)\n",
    "    lbl_pred.value = f'Prediction: {pred}; Probability: {probs[pred_idx]:.04f}'\n",
    "\n",
    "btn_run.on_click(on_click_classify)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "32ba7f7c-665d-4883-b66c-5c22f9fcab57",
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide\n",
    "#Putting back btn_upload to a widget for next cell\n",
    "btn_upload = widgets.FileUpload()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "de07e1d1-8a97-4091-a36a-e96d7a8630f6",
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide_output\n",
    "VBox([widgets.Label('Select your bear!'), \n",
    "      btn_upload, btn_run, out_pl, lbl_pred])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "58839c49-1436-435e-9d66-6cdabc8a3107",
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide\n",
    "# !pip install voila\n",
    "# !jupyter serverextension enable --sys-prefix voila "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
