{ "cells": [ { "cell_type": "markdown", "id": "saved-jonathan", "metadata": { "id": "saved-jonathan" }, "source": [ "#
Taller de Aprendizaje Automático
\n", "##
Taller 7: Gatos y Perros
" ] }, { "cell_type": "markdown", "id": "primary-ministry", "metadata": { "id": "primary-ministry" }, "source": [ "Con el resurgimiento de las redes convolucionales en 2012, entre otras cosas gracias a la viabilidad de entrenar con millones de imágenes, una serie de problemas considerados muy difíciles o inabordables hasta entonces debido a la necesidad de generar algoritmos muy específicos para cada tarea pasaron a estar al alcance de cualquier desarrollador. Un ejemplo emblemático es el de distinguir entre imágenes de perros y gatos. Debido a la gran variabilidad intra clase de estos animales, es realmente dificil generar características que permitan separar bien las clases y probablemente el esfuerzo que conlleva generar características específicas, no esté justificado por la relevancia del problema. En este taller se verá el procedimiento para entrenar un clasificador a partir de un número no muy grande de imágenes, sin necesidad de diseñar características.\n", "\n", "## Objetivos\n", "\n", " - Familiarizarse con la estructura *Dataset* de tensorflow \n", " - Aprender a utilizar modelos de clasificación de imágenes preentrenados en *tensorflow* con imágenes de *Imagenet* \n", " - Conocer las opciones para realizar *aumento de datos* y aplicárselo a las imágenes de perros y gatos\n", " - Realizar *transferencia de aprendizaje* del modelo preentrenado con *Imagenet* al problema de clasificar perros y gatos\n", " - Explicar en base a qué regiones de una imagen el clasificador toma la decisión " ] }, { "cell_type": "markdown", "id": "amazing-chicken", "metadata": {}, "source": [ "\n", " \n", "
\n", " Ejecutar en Google Colab\n", "
" ] }, { "cell_type": "code", "execution_count": null, "id": "built-garlic", "metadata": { "executionInfo": { "elapsed": 1735, "status": "ok", "timestamp": 1622499113030, "user": { "displayName": "Guillermo Carbajal", "photoUrl": "", "userId": "12547730654968608614" }, "user_tz": 180 }, "id": "built-garlic" }, "outputs": [], "source": [ "import tensorflow as tf\n", "from tensorflow import keras\n", "from tensorflow.keras import layers\n", "import os\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "id": "expired-warning", "metadata": { "id": "expired-warning" }, "source": [ "## Parte 0 - Utilización de GPU" ] }, { "cell_type": "markdown", "id": "touched-chemical", "metadata": { "id": "touched-chemical" }, "source": [ "El entrenamiento de redes convolucionales en general es más rápido cuando se utiliza GPU (Graphic Processor Unit). Correr la siguiente celda y verificar que se está utilizando una. Debería observar un mensaje similar al siguiente:\n", "\n", "[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]\n", "\n", "En caso de no observar dicho mensaje y estar trabajando en Colab, verifique que el entorno de ejecución es el correcto, vaya a: \n", "Entorno de ejecuccióón-->Cambiar tipo de entorno de ejecución-->GPU" ] }, { "cell_type": "code", "execution_count": null, "id": "lined-judges", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 430, "status": "ok", "timestamp": 1622499115918, "user": { "displayName": "Guillermo Carbajal", "photoUrl": "", "userId": "12547730654968608614" }, "user_tz": 180 }, "id": "lined-judges", "outputId": "f3918ff9-cdc9-457d-b99b-143686c864b1" }, "outputs": [], "source": [ "tf.config.list_physical_devices('GPU')" ] }, { "cell_type": "markdown", "id": "exempt-rescue", "metadata": { "id": "exempt-rescue" }, "source": [ "## Parte 1 - Levantar los datos" ] }, { "cell_type": "markdown", "id": "treated-interpretation", "metadata": { "id": "treated-interpretation" }, "source": [ "Se trabajará con los datos disponibles en [Kaggle](https://www.kaggle.com/c/dogs-vs-cats/overview). En caso de estar trabajando en Colab seguir los siguientes pasos:" ] }, { "cell_type": "markdown", "id": "racial-twelve", "metadata": { "id": "racial-twelve" }, "source": [ "a) Installar el paquete *kaggle* para acceder a los datos " ] }, { "cell_type": "code", "execution_count": null, "id": "metropolitan-honolulu", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 2939, "status": "ok", "timestamp": 1622499119301, "user": { "displayName": "Guillermo Carbajal", "photoUrl": "", "userId": "12547730654968608614" }, "user_tz": 180 }, "id": "metropolitan-honolulu", "outputId": "73c35cac-5967-4861-b10c-e1a8402cd675" }, "outputs": [], "source": [ "!pip install kaggle" ] }, { "cell_type": "markdown", "id": "impaired-stupid", "metadata": { "id": "impaired-stupid" }, "source": [ "b) Realizar la configuración necesaria para obtener datos desde la plataforma Kaggle." ] }, { "cell_type": "markdown", "id": "c0064671-ca2b-475b-9193-9531c898132c", "metadata": {}, "source": [ "### Configuración para trabajar en Colab" ] }, { "cell_type": "markdown", "id": "16349f1e-8802-48a2-90e2-8d0117bd3060", "metadata": {}, "source": [ "Ir a la página de la competencia y en la sección *data* aceptar los términos. Luego ejecutar la siguiente celda y pasarle el *token* de su usuario (ver comentario en celda)." ] }, { "cell_type": "code", "execution_count": null, "id": "computational-garden", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 102, "resources": { "http://localhost:8080/nbextensions/google.colab/files.js": { "data": "Ly8gQ29weXJpZ2h0IDIwMTcgR29vZ2xlIExMQwovLwovLyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKLy8geW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLgovLyBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKLy8KLy8gICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKLy8KLy8gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQovLyBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAovLyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KLy8gU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAovLyBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCi8qKgogKiBAZmlsZW92ZXJ2aWV3IEhlbHBlcnMgZm9yIGdvb2dsZS5jb2xhYiBQeXRob24gbW9kdWxlLgogKi8KKGZ1bmN0aW9uKHNjb3BlKSB7CmZ1bmN0aW9uIHNwYW4odGV4dCwgc3R5bGVBdHRyaWJ1dGVzID0ge30pIHsKICBjb25zdCBlbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpOwogIGVsZW1lbnQudGV4dENvbnRlbnQgPSB0ZXh0OwogIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHN0eWxlQXR0cmlidXRlcykpIHsKICAgIGVsZW1lbnQuc3R5bGVba2V5XSA9IHN0eWxlQXR0cmlidXRlc1trZXldOwogIH0KICByZXR1cm4gZWxlbWVudDsKfQoKLy8gTWF4IG51bWJlciBvZiBieXRlcyB3aGljaCB3aWxsIGJlIHVwbG9hZGVkIGF0IGEgdGltZS4KY29uc3QgTUFYX1BBWUxPQURfU0laRSA9IDEwMCAqIDEwMjQ7CgpmdW5jdGlvbiBfdXBsb2FkRmlsZXMoaW5wdXRJZCwgb3V0cHV0SWQpIHsKICBjb25zdCBzdGVwcyA9IHVwbG9hZEZpbGVzU3RlcChpbnB1dElkLCBvdXRwdXRJZCk7CiAgY29uc3Qgb3V0cHV0RWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKG91dHB1dElkKTsKICAvLyBDYWNoZSBzdGVwcyBvbiB0aGUgb3V0cHV0RWxlbWVudCB0byBtYWtlIGl0IGF2YWlsYWJsZSBmb3IgdGhlIG5leHQgY2FsbAogIC8vIHRvIHVwbG9hZEZpbGVzQ29udGludWUgZnJvbSBQeXRob24uCiAgb3V0cHV0RWxlbWVudC5zdGVwcyA9IHN0ZXBzOwoKICByZXR1cm4gX3VwbG9hZEZpbGVzQ29udGludWUob3V0cHV0SWQpOwp9CgovLyBUaGlzIGlzIHJvdWdobHkgYW4gYXN5bmMgZ2VuZXJhdG9yIChub3Qgc3VwcG9ydGVkIGluIHRoZSBicm93c2VyIHlldCksCi8vIHdoZXJlIHRoZXJlIGFyZSBtdWx0aXBsZSBhc3luY2hyb25vdXMgc3RlcHMgYW5kIHRoZSBQeXRob24gc2lkZSBpcyBnb2luZwovLyB0byBwb2xsIGZvciBjb21wbGV0aW9uIG9mIGVhY2ggc3RlcC4KLy8gVGhpcyB1c2VzIGEgUHJvbWlzZSB0byBibG9jayB0aGUgcHl0aG9uIHNpZGUgb24gY29tcGxldGlvbiBvZiBlYWNoIHN0ZXAsCi8vIHRoZW4gcGFzc2VzIHRoZSByZXN1bHQgb2YgdGhlIHByZXZpb3VzIHN0ZXAgYXMgdGhlIGlucHV0IHRvIHRoZSBuZXh0IHN0ZXAuCmZ1bmN0aW9uIF91cGxvYWRGaWxlc0NvbnRpbnVlKG91dHB1dElkKSB7CiAgY29uc3Qgb3V0cHV0RWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKG91dHB1dElkKTsKICBjb25zdCBzdGVwcyA9IG91dHB1dEVsZW1lbnQuc3RlcHM7CgogIGNvbnN0IG5leHQgPSBzdGVwcy5uZXh0KG91dHB1dEVsZW1lbnQubGFzdFByb21pc2VWYWx1ZSk7CiAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShuZXh0LnZhbHVlLnByb21pc2UpLnRoZW4oKHZhbHVlKSA9PiB7CiAgICAvLyBDYWNoZSB0aGUgbGFzdCBwcm9taXNlIHZhbHVlIHRvIG1ha2UgaXQgYXZhaWxhYmxlIHRvIHRoZSBuZXh0CiAgICAvLyBzdGVwIG9mIHRoZSBnZW5lcmF0b3IuCiAgICBvdXRwdXRFbGVtZW50Lmxhc3RQcm9taXNlVmFsdWUgPSB2YWx1ZTsKICAgIHJldHVybiBuZXh0LnZhbHVlLnJlc3BvbnNlOwogIH0pOwp9CgovKioKICogR2VuZXJhdG9yIGZ1bmN0aW9uIHdoaWNoIGlzIGNhbGxlZCBiZXR3ZWVuIGVhY2ggYXN5bmMgc3RlcCBvZiB0aGUgdXBsb2FkCiAqIHByb2Nlc3MuCiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dElkIEVsZW1lbnQgSUQgb2YgdGhlIGlucHV0IGZpbGUgcGlja2VyIGVsZW1lbnQuCiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRwdXRJZCBFbGVtZW50IElEIG9mIHRoZSBvdXRwdXQgZGlzcGxheS4KICogQHJldHVybiB7IUl0ZXJhYmxlPCFPYmplY3Q+fSBJdGVyYWJsZSBvZiBuZXh0IHN0ZXBzLgogKi8KZnVuY3Rpb24qIHVwbG9hZEZpbGVzU3RlcChpbnB1dElkLCBvdXRwdXRJZCkgewogIGNvbnN0IGlucHV0RWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGlucHV0SWQpOwogIGlucHV0RWxlbWVudC5kaXNhYmxlZCA9IGZhbHNlOwoKICBjb25zdCBvdXRwdXRFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQob3V0cHV0SWQpOwogIG91dHB1dEVsZW1lbnQuaW5uZXJIVE1MID0gJyc7CgogIGNvbnN0IHBpY2tlZFByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gewogICAgaW5wdXRFbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIChlKSA9PiB7CiAgICAgIHJlc29sdmUoZS50YXJnZXQuZmlsZXMpOwogICAgfSk7CiAgfSk7CgogIGNvbnN0IGNhbmNlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2J1dHRvbicpOwogIGlucHV0RWxlbWVudC5wYXJlbnRFbGVtZW50LmFwcGVuZENoaWxkKGNhbmNlbCk7CiAgY2FuY2VsLnRleHRDb250ZW50ID0gJ0NhbmNlbCB1cGxvYWQnOwogIGNvbnN0IGNhbmNlbFByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gewogICAgY2FuY2VsLm9uY2xpY2sgPSAoKSA9PiB7CiAgICAgIHJlc29sdmUobnVsbCk7CiAgICB9OwogIH0pOwoKICAvLyBXYWl0IGZvciB0aGUgdXNlciB0byBwaWNrIHRoZSBmaWxlcy4KICBjb25zdCBmaWxlcyA9IHlpZWxkIHsKICAgIHByb21pc2U6IFByb21pc2UucmFjZShbcGlja2VkUHJvbWlzZSwgY2FuY2VsUHJvbWlzZV0pLAogICAgcmVzcG9uc2U6IHsKICAgICAgYWN0aW9uOiAnc3RhcnRpbmcnLAogICAgfQogIH07CgogIGNhbmNlbC5yZW1vdmUoKTsKCiAgLy8gRGlzYWJsZSB0aGUgaW5wdXQgZWxlbWVudCBzaW5jZSBmdXJ0aGVyIHBpY2tzIGFyZSBub3QgYWxsb3dlZC4KICBpbnB1dEVsZW1lbnQuZGlzYWJsZWQgPSB0cnVlOwoKICBpZiAoIWZpbGVzKSB7CiAgICByZXR1cm4gewogICAgICByZXNwb25zZTogewogICAgICAgIGFjdGlvbjogJ2NvbXBsZXRlJywKICAgICAgfQogICAgfTsKICB9CgogIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykgewogICAgY29uc3QgbGkgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsaScpOwogICAgbGkuYXBwZW5kKHNwYW4oZmlsZS5uYW1lLCB7Zm9udFdlaWdodDogJ2JvbGQnfSkpOwogICAgbGkuYXBwZW5kKHNwYW4oCiAgICAgICAgYCgke2ZpbGUudHlwZSB8fCAnbi9hJ30pIC0gJHtmaWxlLnNpemV9IGJ5dGVzLCBgICsKICAgICAgICBgbGFzdCBtb2RpZmllZDogJHsKICAgICAgICAgICAgZmlsZS5sYXN0TW9kaWZpZWREYXRlID8gZmlsZS5sYXN0TW9kaWZpZWREYXRlLnRvTG9jYWxlRGF0ZVN0cmluZygpIDoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ24vYSd9IC0gYCkpOwogICAgY29uc3QgcGVyY2VudCA9IHNwYW4oJzAlIGRvbmUnKTsKICAgIGxpLmFwcGVuZENoaWxkKHBlcmNlbnQpOwoKICAgIG91dHB1dEVsZW1lbnQuYXBwZW5kQ2hpbGQobGkpOwoKICAgIGNvbnN0IGZpbGVEYXRhUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7CiAgICAgIGNvbnN0IHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7CiAgICAgIHJlYWRlci5vbmxvYWQgPSAoZSkgPT4gewogICAgICAgIHJlc29sdmUoZS50YXJnZXQucmVzdWx0KTsKICAgICAgfTsKICAgICAgcmVhZGVyLnJlYWRBc0FycmF5QnVmZmVyKGZpbGUpOwogICAgfSk7CiAgICAvLyBXYWl0IGZvciB0aGUgZGF0YSB0byBiZSByZWFkeS4KICAgIGxldCBmaWxlRGF0YSA9IHlpZWxkIHsKICAgICAgcHJvbWlzZTogZmlsZURhdGFQcm9taXNlLAogICAgICByZXNwb25zZTogewogICAgICAgIGFjdGlvbjogJ2NvbnRpbnVlJywKICAgICAgfQogICAgfTsKCiAgICAvLyBVc2UgYSBjaHVua2VkIHNlbmRpbmcgdG8gYXZvaWQgbWVzc2FnZSBzaXplIGxpbWl0cy4gU2VlIGIvNjIxMTU2NjAuCiAgICBsZXQgcG9zaXRpb24gPSAwOwogICAgd2hpbGUgKHBvc2l0aW9uIDwgZmlsZURhdGEuYnl0ZUxlbmd0aCkgewogICAgICBjb25zdCBsZW5ndGggPSBNYXRoLm1pbihmaWxlRGF0YS5ieXRlTGVuZ3RoIC0gcG9zaXRpb24sIE1BWF9QQVlMT0FEX1NJWkUpOwogICAgICBjb25zdCBjaHVuayA9IG5ldyBVaW50OEFycmF5KGZpbGVEYXRhLCBwb3NpdGlvbiwgbGVuZ3RoKTsKICAgICAgcG9zaXRpb24gKz0gbGVuZ3RoOwoKICAgICAgY29uc3QgYmFzZTY0ID0gYnRvYShTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KG51bGwsIGNodW5rKSk7CiAgICAgIHlpZWxkIHsKICAgICAgICByZXNwb25zZTogewogICAgICAgICAgYWN0aW9uOiAnYXBwZW5kJywKICAgICAgICAgIGZpbGU6IGZpbGUubmFtZSwKICAgICAgICAgIGRhdGE6IGJhc2U2NCwKICAgICAgICB9LAogICAgICB9OwogICAgICBwZXJjZW50LnRleHRDb250ZW50ID0KICAgICAgICAgIGAke01hdGgucm91bmQoKHBvc2l0aW9uIC8gZmlsZURhdGEuYnl0ZUxlbmd0aCkgKiAxMDApfSUgZG9uZWA7CiAgICB9CiAgfQoKICAvLyBBbGwgZG9uZS4KICB5aWVsZCB7CiAgICByZXNwb25zZTogewogICAgICBhY3Rpb246ICdjb21wbGV0ZScsCiAgICB9CiAgfTsKfQoKc2NvcGUuZ29vZ2xlID0gc2NvcGUuZ29vZ2xlIHx8IHt9OwpzY29wZS5nb29nbGUuY29sYWIgPSBzY29wZS5nb29nbGUuY29sYWIgfHwge307CnNjb3BlLmdvb2dsZS5jb2xhYi5fZmlsZXMgPSB7CiAgX3VwbG9hZEZpbGVzLAogIF91cGxvYWRGaWxlc0NvbnRpbnVlLAp9Owp9KShzZWxmKTsK", "headers": [ [ "content-type", "application/javascript" ] ], "ok": true, "status": 200, "status_text": "OK" } } }, "executionInfo": { "elapsed": 8941, "status": "ok", "timestamp": 1622499128222, "user": { "displayName": "Guillermo Carbajal", "photoUrl": "", "userId": "12547730654968608614" }, "user_tz": 180 }, "id": "computational-garden", "outputId": "b746899e-0cfb-41c8-9ece-dde99fff6fd3", "scrolled": true }, "outputs": [], "source": [ "import warnings\n", "warnings.filterwarnings('ignore')\n", "from google.colab import files\n", "\n", "# El archivo solicitado es para habilitar la API de Kaggle en el entorno que está trabajando.\n", "# Este archivo se descarga entrando a su perfíl de Kaggle, en la sección API, presionando donde dice: Create New API Token\n", "\n", "uploaded = files.upload()\n", "\n", "for fn in uploaded.keys():\n", " print('User uploaded file \"{name}\" with length {length} bytes'.format(\n", " name=fn, length=len(uploaded[fn])))\n", " \n", "#Then move kaggle.json into the folder where the API expects to find it.\n", "!mkdir -p ~/.kaggle/ && mv kaggle.json ~/.kaggle/ && chmod 600 ~/.kaggle/kaggle.json" ] }, { "cell_type": "markdown", "id": "bridal-prague", "metadata": { "id": "bridal-prague" }, "source": [ "Una vez guardado el *token* se pueden descargar los datos." ] }, { "cell_type": "code", "execution_count": null, "id": "entertaining-respect", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 19047, "status": "ok", "timestamp": 1622499151725, "user": { "displayName": "Guillermo Carbajal", "photoUrl": "", "userId": "12547730654968608614" }, "user_tz": 180 }, "id": "entertaining-respect", "outputId": "9a047d56-fca7-4d53-8ca4-0e3b556a109e" }, "outputs": [], "source": [ "# celda para bajar los datos desde colab\n", "!kaggle competitions download -c dogs-vs-cats\n", "!unzip /content/dogs-vs-cats.zip\n", "!unzip /content/train.zip\n", "!unzip /content/test1.zip" ] }, { "cell_type": "markdown", "id": "f3354324-d0f4-42e1-8315-4c005e60b4fb", "metadata": {}, "source": [ "### Configuración para trabajar local" ] }, { "cell_type": "markdown", "id": "4c0e37ef-69e2-4fce-be69-11a53aea9b93", "metadata": {}, "source": [ "En caso de estar trabajando localmente ejecutar la siguiente celda." ] }, { "cell_type": "code", "execution_count": null, "id": "4738c817-8d27-4394-a427-b839d13a4dd1", "metadata": {}, "outputs": [], "source": [ "# celda para bajar los datos localmente\n", "!kaggle competitions download -c dogs-vs-cats\n", "!unzip dogs-vs-cats.zip\n", "!unzip train.zip\n", "!unzip test1.zip" ] }, { "cell_type": "markdown", "id": "SJ8H6_kYY8Oo", "metadata": { "id": "SJ8H6_kYY8Oo" }, "source": [ "## Parte 2 - Preparar los datos" ] }, { "cell_type": "markdown", "id": "initial-shoulder", "metadata": { "id": "initial-shoulder" }, "source": [ "En este taller en vez de almacenar los datos en un arreglo de numpy como en talleres anteriores, los almacenaremos en un *Dataset* de Tensorflow. Para ello se utilizará la función `tf.keras.preprocessing.image_dataset_from_directory()`. Dicha función asume que en el directorio que se pasa como parámetro hay tantos subdirectorios como clases hay en el problema y que dentro de cada subdirectorio están las imágenes correspondientes a esa clase. Los datos originalmente no están almacenados siguiendo esta estructura. Utilizar la función `preparar_datos_entrenamiento()` para generar una estructura de archivos adecuada para `tf.keras.preprocessing.image_dataset_from_directory()`. Luego utilizar esta última para generar un Dataset de entrenamiento y uno de validación con las siguientes características.\n", "\n", "* 80% de entrenamiento y 20% de validación\n", "* Batch size 32\n", "* Tamaño de imagen 180\n", "\n", "[Aquí](https://keras.io/examples/vision/image_classification_from_scratch/) un ejemplo de keras que muestra cómo hacerlo.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "ranking-observer", "metadata": { "ExecuteTime": { "end_time": "2022-05-21T20:40:12.818330Z", "start_time": "2022-05-21T20:40:12.803990Z" }, "executionInfo": { "elapsed": 7, "status": "ok", "timestamp": 1622499153338, "user": { "displayName": "Guillermo Carbajal", "photoUrl": "", "userId": "12547730654968608614" }, "user_tz": 180 }, "id": "ranking-observer" }, "outputs": [], "source": [ "def preparar_datos_entrenamiento(data_folder, output_folder):\n", " \n", " '''\n", " Genera una estructura de directorios adecuada para la función image_dataset_from_directory()\n", " Entrada: \n", " data_folder: directorio raíz en que se encuentran los datos descargados desde kaggle\n", " output_folder: directorio en que se guardaran los datos reorganizados\n", " '''\n", " \n", " classes = ['cat','dog']\n", " if not os.path.exists(output_folder):\n", " os.makedirs(output_folder)\n", " for clase in classes:\n", " class_folder = os.path.join(output_folder, clase)\n", " if not os.path.exists(class_folder):\n", " os.makedirs(class_folder)\n", " \n", " train_folder = os.path.join(data_folder, 'train')\n", " imgs_paths = os.listdir(train_folder)\n", " print('Hay %d imágenes de entrenamiento' % len(imgs_paths))\n", " for img_name in imgs_paths:\n", " img_class = 'cat' if img_name.startswith('cat') else 'dog'\n", " \n", " source_img_path = os.path.join(train_folder, img_name)\n", " dst_img_path = os.path.join(output_folder,img_class, img_name)\n", " if os.path.exists(dst_img_path):\n", " os.unlink(dst_img_path)\n", " \n", " os.symlink(source_img_path, dst_img_path)\n", " \n", " return \n", " " ] }, { "cell_type": "code", "execution_count": null, "id": "considered-master", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "transsexual-aerospace", "metadata": { "id": "transsexual-aerospace" }, "source": [ "## Parte 3 - Exploración de datos" ] }, { "cell_type": "markdown", "id": "aging-summer", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 545, "status": "ok", "timestamp": 1622499172239, "user": { "displayName": "Guillermo Carbajal", "photoUrl": "", "userId": "12547730654968608614" }, "user_tz": 180 }, "id": "NcV5QtDVfhEv", "outputId": "0b9d04ee-2948-41d2-e25b-af98022c889d" }, "source": [ "Mostrar algunos ejemplos de los datos de entrenamiento (un batch por ejemplo). ¿En qué formato se encuentran almacenados los datos? ¿Son adecuados para entrenar una red neuronal?" ] }, { "cell_type": "markdown", "id": "southeast-webmaster", "metadata": { "id": "southeast-webmaster" }, "source": [ "## Parte 4 - Aumento de datos" ] }, { "cell_type": "markdown", "id": "7NFWfpQHgJfw", "metadata": { "id": "7NFWfpQHgJfw" }, "source": [ "**4a)** Siguiendo con el ejemplo de keras, realizar aumento de datos a la primer imagen del dataset y mostrar los resultados. \n", "**4b)** Además de las opciones que se muestan el ejemplo ¿Qué otras opciones de aumento de datos brinda Keras? Muestre alguna que no aparezca en el ejemplo. \n", "**4c)** Asegúrese de entender por qué en algún caso puede tener sentido realizar el aumento de datos en el modelo y en otros sobre el dataset. " ] }, { "cell_type": "markdown", "id": "honest-context", "metadata": { "id": "honest-context" }, "source": [ "## Parte 5 - Entrenando con aumento de datos en el modelo" ] }, { "cell_type": "markdown", "id": "hqF6UxOYkqjb", "metadata": { "id": "hqF6UxOYkqjb" }, "source": [ "Copie el modelo del ejemplo y entrene durante 10 épocas utilizando dicho modelo." ] }, { "cell_type": "markdown", "id": "PwpCM7xvmBcG", "metadata": { "id": "PwpCM7xvmBcG" }, "source": [ "**5a)** Asegúrese que entiende cómo fue construída la red y cada uno de los bloques que se utilizan \n", "**5b)** Modifique la salida de la red para que la salida tenga *num_classes* unidades independientemente de cuál sea el número de clases. \n", "**5c)** Entrene la red durante 10 épocas " ] }, { "cell_type": "markdown", "id": "native-costs", "metadata": { "id": "native-costs" }, "source": [ "## Parte 6 - Utilizando Modelos Preentrenados" ] }, { "cell_type": "markdown", "id": "XDQnqp8koNyz", "metadata": { "id": "XDQnqp8koNyz" }, "source": [ "En esta parte en vez de entrenar un modelo desde cero vamos a utilizar un modelo preentrenado en otro problema y adaptarlo al de clasificar entre perros y gatos. Se evaluarán dos modelos: Resnet50 y Xception.\n", "\n", "**6a)** Levantar ambos modelos con los pesos preentrenados con la base *Imagenet*. Ver un ejemplo en la sección *Using Pretrained Models from Keras* del *Capíítulo 14* del libro del curso. \n", "**6b)** Adaptar el ejemplo del libro para mostrar, para cada una de los modelos cargados, cuáles son las *top3* clases de un *batch* de imágenes del dataset de entrenamiento. ¿Qué observa? " ] }, { "cell_type": "markdown", "id": "major-verification", "metadata": { "id": "major-verification" }, "source": [ "## Parte 7 - Visualización de filtros" ] }, { "cell_type": "markdown", "id": "DyBBJ-CAz8jd", "metadata": { "id": "DyBBJ-CAz8jd" }, "source": [ "En el caso del modelo *Resnet50* mostrar los filtros aprendidos en la primera capa de convolución. Explique con algún ejemplo por qué puede ser razonable utilizar estos mismos filtros en otro problema." ] }, { "cell_type": "markdown", "id": "civilian-villa", "metadata": { "id": "civilian-villa" }, "source": [ "## Parte 8 - Transferencia de aprendizaje" ] }, { "cell_type": "markdown", "id": "9Fo8kI6A3QKI", "metadata": { "id": "9Fo8kI6A3QKI" }, "source": [ "Tomando como referencia la sección *Pretrained Models for Transfer Learning* del *Capíítulo 14* del libro y el ejemplo [Transfer Learning](https://keras.io/guides/transfer_learning/) de keras, realizar transferencia de aprendizaje utilizando ambos modelos. " ] }, { "cell_type": "markdown", "id": "speaking-symbol", "metadata": { "id": "speaking-symbol" }, "source": [ "## Parte 9 - Grad Cam" ] }, { "cell_type": "markdown", "id": "extended-longitude", "metadata": { "id": "extended-longitude" }, "source": [ "Una vez que se entrena una red convolucional es muy útil entender en qué basa la red sus predicciones. Uno de los métodos propuestos en ese sentido es [GradCAM](https://arxiv.org/pdf/1610.02391.pdf). \n", "\n", "**9a)** ¿Para qué puede ser útil un método que explique los resultados obtenidos? \n", "**9b)** Adaptar el [ejemplo](https://keras.io/examples/vision/grad_cam/) de keras y mostrar sobre algunas imágenes de validación las predicciones realizadas y los mapas de activación superpuestos a la imagen. Para eso utilizar (o adaptar) las funciones `make_gradcam_heatmap()` y `save_and_display_gradcam()`." ] }, { "cell_type": "markdown", "id": "JdUui-c28YIW", "metadata": { "id": "JdUui-c28YIW" }, "source": [ "## Parte 10 - Evauar con el conjunto de Test" ] }, { "cell_type": "markdown", "id": "zZpY4JAH9QUG", "metadata": { "id": "zZpY4JAH9QUG" }, "source": [ "Evaluar el modelo con que haya obtenido mejores resultados con el conjunto de validación con el conjunto de test. En este taller el foco no está puesto en optimizar los clasificadores, sin embargo verifique que los resultados obtenidos con el conjunto de test son del orden de los obtenidos con el conjunto de valdiación." ] } ], "metadata": { "accelerator": "GPU", "colab": { "collapsed_sections": [], "name": "Copia de taller7_gatos_y_perros.ipynb", "provenance": [ { "file_id": "1AUMuKih4oHPf0F9W67NuS5lezWaVWu4x", "timestamp": 1622480139138 } ], "toc_visible": true }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.19" }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 5 }