{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# TFM - Deep Learning y Blue Economy","metadata":{}},{"cell_type":"markdown","source":"## Importación de paquetes","metadata":{}},{"cell_type":"code","source":"#Importamos los paquetes necesarios\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport random as rnd\nfrom PIL import Image\nfrom tqdm import tqdm\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.applications.imagenet_utils import preprocess_input\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nfrom sklearn.model_selection import train_test_split\nimport time\nfrom tensorflow.keras.utils import plot_model\nfrom sklearn.metrics import confusion_matrix, classification_report\nimport pickle","metadata":{"execution":{"iopub.status.busy":"2023-03-01T18:57:07.035954Z","iopub.execute_input":"2023-03-01T18:57:07.036370Z","iopub.status.idle":"2023-03-01T18:57:15.704153Z","shell.execute_reply.started":"2023-03-01T18:57:07.036338Z","shell.execute_reply":"2023-03-01T18:57:15.702873Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Carga de datos","metadata":{}},{"cell_type":"code","source":"#Cargamos nuestro conjuntos de train y de test\ntrain_csv = pd.read_csv('/kaggle/input/happy-whale-and-dolphin/train.csv')\nsample_submission = pd.read_csv('/kaggle/input/happy-whale-and-dolphin/sample_submission.csv')","metadata":{"execution":{"iopub.status.busy":"2023-03-01T18:57:15.894097Z","iopub.execute_input":"2023-03-01T18:57:15.894440Z","iopub.status.idle":"2023-03-01T18:57:16.004999Z","shell.execute_reply.started":"2023-03-01T18:57:15.894408Z","shell.execute_reply":"2023-03-01T18:57:16.003809Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## EDA","metadata":{}},{"cell_type":"markdown","source":"Preparamos una paleta de colores acorde a nuestro tema para realizar unos gráficos más adecuados","metadata":{}},{"cell_type":"code","source":"my_colors = [\"#2FC7B5\", \"#2AB3A3\", \"#259387\", \"#218379\", \"#08696A\", \"#0A7375\", \"#0D898C\", \"#0E9599\"]\nsns.palplot(sns.color_palette(my_colors))","metadata":{"execution":{"iopub.status.busy":"2023-03-01T17:44:31.137549Z","iopub.execute_input":"2023-03-01T17:44:31.137969Z","iopub.status.idle":"2023-03-01T17:44:31.284531Z","shell.execute_reply.started":"2023-03-01T17:44:31.137936Z","shell.execute_reply":"2023-03-01T17:44:31.282199Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Exploración del dataset\n\n#### Train VS Test\nProcedemos a profundizar más en el conjunto de datos que tenemos disponible a través de nuestro dataset. Primero comenzaremos analizando el número de datos que contienen los archivos proporcionados.\n\n\nVeremos ahora el número de imágenes que tienen nuestro conjunto de train y test.\n\n- Total de imágenes en Train: 51.033\n- Total de imágenes en Test: 27.956\n","metadata":{}},{"cell_type":"code","source":"plt.clf()\nplt.figure(figsize=(10, 5))\n\nnumber_images = [len(train_csv), len(sample_submission)]\ndata = {'Datasets': ['Train', 'Test'], 'Cantidad de imágenes': number_images}\ndf = pd.DataFrame(data)\n\ncolors = [my_colors[1], my_colors[4]]\n\nsns.barplot(x='Cantidad de imágenes', y='Datasets', data=df, palette=\"PuBuGn_r\", alpha=0.65)\n\nplt.title('Imágenes Train VS Test', size=13, color=my_colors[6], weight='bold')\nplt.xlabel('Imágenes', size=10, color=my_colors[6], weight='bold')\nplt.ylabel('Datasets', size=10, color=my_colors[6], weight='bold')\nplt.yticks(fontsize=8, color=my_colors[6], weight='bold')\n\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:18:11.283907Z","iopub.execute_input":"2023-03-01T16:18:11.284354Z","iopub.status.idle":"2023-03-01T16:18:11.537052Z","shell.execute_reply.started":"2023-03-01T16:18:11.284318Z","shell.execute_reply":"2023-03-01T16:18:11.536143Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Mientras que nuestro conjunto de train tiene 3 columnas:\n\n- Nombre de la imágen\n- Especie a la que pertenece\n- ID de cada individuo\n\nNuestro conjunto de test tiene solo 2 columnas:\n\n- Nombre de la imágen\n- Posibles predicciones","metadata":{}},{"cell_type":"code","source":"train_csv.columns\n","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:18:18.429126Z","iopub.execute_input":"2023-03-01T16:18:18.429660Z","iopub.status.idle":"2023-03-01T16:18:18.437996Z","shell.execute_reply.started":"2023-03-01T16:18:18.429612Z","shell.execute_reply":"2023-03-01T16:18:18.436765Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_submission.columns","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:18:20.880456Z","iopub.execute_input":"2023-03-01T16:18:20.880895Z","iopub.status.idle":"2023-03-01T16:18:20.888517Z","shell.execute_reply.started":"2023-03-01T16:18:20.880859Z","shell.execute_reply":"2023-03-01T16:18:20.887328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Duplicados y valores nulos\n\nProcedemos ahora a chequear si tenemos valores nulos o duplicados en nuestro conjunto de train que tengamos que tener en cuenta antes de empezar a entrenar nuestro modelo.","metadata":{}},{"cell_type":"code","source":"duplicates = train_csv.duplicated()\nprint ('En nuestro conjunto de train tenemos ', train_csv['individual_id'].isna().sum(), 'valores nulos y', duplicates.sum(), 'valores duplicados' )\n","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:18:23.566727Z","iopub.execute_input":"2023-03-01T16:18:23.567142Z","iopub.status.idle":"2023-03-01T16:18:23.602388Z","shell.execute_reply.started":"2023-03-01T16:18:23.567109Z","shell.execute_reply":"2023-03-01T16:18:23.601207Z"},"_kg_hide-input":false,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Transformaciones y Distribución\n\n##### Especies\n\nTras habernos cerciorado de que no tenemos valores nulos ni valores duplicados en nuestro conjunto, procedemos a analizar en mayor profundidad nuestro conjunto de datos para visualizar cuántas especies distintas tenemos.\n","metadata":{}},{"cell_type":"code","source":"print(' En nuestros datos aparecen un total de', len(train_csv.species.value_counts()), 'especies distintas')","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:18:28.429137Z","iopub.execute_input":"2023-03-01T16:18:28.429560Z","iopub.status.idle":"2023-03-01T16:18:28.438497Z","shell.execute_reply.started":"2023-03-01T16:18:28.429524Z","shell.execute_reply":"2023-03-01T16:18:28.437280Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Contamos con **30 especies** distintas en los datos proporcionados, pero vamos a visualizar en una tabla el nombre de cada una de las especies para analizar si contamos con algún error de sintaxis en sus denominaciones o si tenemos algún valor repetido que no se esté detectando de manera automática.","metadata":{}},{"cell_type":"code","source":"# Creamos un dataframe con los datos\nspecies = pd.DataFrame({'species': sorted(train_csv.species.unique())})\n\n#Le damos un formato para destacar los cambios que vamos a realizar\nspecies.style.applymap(lambda x: 'background-color: #0E9599', subset=pd.IndexSlice[[0,2,3,12,15,16], :])\n","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:18:34.341471Z","iopub.execute_input":"2023-03-01T16:18:34.342693Z","iopub.status.idle":"2023-03-01T16:18:34.417068Z","shell.execute_reply.started":"2023-03-01T16:18:34.342635Z","shell.execute_reply":"2023-03-01T16:18:34.415919Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Como podemos apreciar tras revisar nuestros datos, algunas de las especies están duplicadas por errores de sintáxis.\n\nAsí mismo, tras unas comprobaciones realizadas a través de la Oficina Nacional de Administración Oceánica y Atmosférica (NOAA), una de las organizaciones que han proporcionado los datos para el concurso, se comprueba que la especie [\"globis\" se refiere al genero \"Globicephala\" que recoge a las ballenas pilotos (pilot whale)](https://www.fisheries.noaa.gov/species/long-finned-pilot-whale).\n\nAdemás, se decide agrupar **short finned pilot whale** y **long finned pilot whale** en una misma especie de **pilot whale** por su dificultad para diferenciarlas, y añadir a la especie **beluga** el término **whale**, para mantener la homogenenidad en las denominaciones de las especies, ya que pertenece al grupo de las ballenas, y se trata de la única especie que no viene detallada de esta forma.\n","metadata":{}},{"cell_type":"code","source":"train_csv.species.replace({\n    \"globis\" : \"pilot_whale\",\n    \"long_finned_pilot_whale\" : \"pilot_whale\",\n    \"short_finned_pilot_whale\" : \"pilot_whale\",\n    \"kiler_whale\" : \"killer_whale\",\n    \"bottlenose_dolpin\": \"bottlenose_dolphin\",\n    \"beluga\": \"beluga_whale\"\n}, inplace=True)","metadata":{"execution":{"iopub.status.busy":"2023-03-01T18:57:23.467029Z","iopub.execute_input":"2023-03-01T18:57:23.467481Z","iopub.status.idle":"2023-03-01T18:57:23.494846Z","shell.execute_reply.started":"2023-03-01T18:57:23.467443Z","shell.execute_reply":"2023-03-01T18:57:23.493508Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Por tanto, se han realizado los siguientes cambios:\n\n- Se han agrupado: **globis, long_fined_pilot_whale y short_fined_pilot_whale** en **pilot_whale**.\n\n- Se ha corregido el nombre de **kiler_whale** conviertiendolo en **killer_whale** y el de bottlenose_dolpin en **bottlenose_dolphin**.\n\n- Se ha añadido al nombre **beluga** su categoría para homogeneizarlo con la estructura de la denominación del resto de especies, quedando así **beluga_whale**\n\nUna vez hechas las correcciones podemos afirmar que en nuestros datos aparecen un total de **25 especies** distintas. Procedemos a ver como se distribuyen:","metadata":{}},{"cell_type":"code","source":"# Creamos un dataframe con los datos\nnumber_species = pd.DataFrame(train_csv.species.value_counts())\n\n#Generamos un gráfico con los datos creados para conseguir una mejor visualización\nplt.clf()\n\nplt.figure(figsize=(10, 5))\nsns.barplot(x=number_species.species, y=number_species.index, orient='h', palette=\"PuBuGn_r\", alpha=0.65)\nplt.xlabel(\"Número de especies\", color=my_colors[6], weight='bold')\nplt.ylabel(\"Especie\", color=my_colors[6], weight='bold')\nplt.title(\"Distribución de las especies\", size=15, color=my_colors[6], weight='bold')\n\nsns.despine(left=True, bottom=True)\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:18:41.266196Z","iopub.execute_input":"2023-03-01T16:18:41.266581Z","iopub.status.idle":"2023-03-01T16:18:41.617782Z","shell.execute_reply.started":"2023-03-01T16:18:41.266550Z","shell.execute_reply":"2023-03-01T16:18:41.616455Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"A través del gráfico de barras se aprecia que la especie **bottlenose dolphin** o **delfín mular** predomina en nuestro conjunto de datos, seguido por la **beluga** y las **ballenas jorobadas**. Por otro lado, las especies que menos aparecen en las imágenes de nuestros datos son la **orca pigmea**, los **delfines de dientes rugosos** y los **delfines de Fraser**.\n\nSiguiendo con nuestro análisis, se decide añadir una nueva variable que permita categorizar las especies entre los dos grupos de cetáceos principales (ballenas y delfines).\n\nEn general, para realizar la categorización, nos centraremos en sus denominaciones en la variable especie. Es decir, todas aquellas especies que contienen \"_dolphin\" en su nombre perteneceran a la categoría de delfines, y todas aquellas que contienen \"_whale\" en su nombre perteneceran a las ballenas.\n\nNo obstante, contamos con dos excepciones: [las orcas y las ballenas piloto que pertenecen a la categoría de los delfines](https://www.fisheries.noaa.gov/species/killer-whale), a pesar de contener en su nombre de especie la palabra ballena.","metadata":{}},{"cell_type":"code","source":"category = train_csv[\"species\"].str.contains(\"dolphin|killer_whale|pilot_whale\", case=False)\ntrain_csv['species_category'] = np.where(category, 'dolphin', 'whale')","metadata":{"execution":{"iopub.status.busy":"2023-03-01T18:57:26.105126Z","iopub.execute_input":"2023-03-01T18:57:26.105584Z","iopub.status.idle":"2023-03-01T18:57:26.176439Z","shell.execute_reply.started":"2023-03-01T18:57:26.105544Z","shell.execute_reply":"2023-03-01T18:57:26.175445Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"number_category = pd.DataFrame(train_csv.species_category.value_counts())\n\nplt.clf()\n\nfig, ax = plt.subplots(1, 2, figsize=(20, 7.5))\nfig.suptitle('- Categorias -', size=26, color=my_colors[7], weight='bold')\n\n#Generamos un gráfico de tarta para ver el porcentaje\nlabels = number_category.index\nsizes = number_category['species_category']\n\ncolors = [my_colors[1], my_colors[4]]\n\nax[0].pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%',\nshadow=False, startangle=90, textprops={'fontweight':'bold', 'color': 'black'})\nax[0].axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle\nax[0].set_title(\"% por categoría\", size = 15, color = my_colors[6], weight='bold')\n\nsns.barplot(data=number_category, y= sizes, x=labels , ax=ax[1], palette=\"PuBu_r\", alpha = 0.85)\n\nfor i in range(len(labels)):\n    ax[1].text(i, sizes[i]+100, str(sizes[i]), ha='center', va='bottom', fontsize=12, weight='bold')\n\nax[1].set_title(\"Frecuencia de categoría\",size = 15, color = my_colors[6], weight='bold')\nax[1].set_ylabel(\"Frecuencia\", size = 13, color = my_colors[6], weight='bold')\nax[1].set_xlabel(\"Categoría\", size = 13, color = my_colors[6], weight='bold')\n\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:18:50.242734Z","iopub.execute_input":"2023-03-01T16:18:50.243138Z","iopub.status.idle":"2023-03-01T16:18:50.571770Z","shell.execute_reply.started":"2023-03-01T16:18:50.243100Z","shell.execute_reply":"2023-03-01T16:18:50.570473Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"El análisis de la distribución de las imágenes por categoría es un paso importante en el análisis exploratorio de los datos, ya que nos permite entender la composición del dataset y detectar posibles desequilibrios entre las diferentes clases.\n\nEn este caso, al utilizar un gráfico de pastel, podemos visualizar claramente que la distribución de las imágenes en las categorías de ballenas y delfines es casi igual. Además a través del gráfico de barras vemos con mayor detalle las cifras. Contamos con un total de **27.198 imágenes de ballenas** y **23.835 imágenes de delfines.**\n\nA continuación profundizaremos en la distribución de las especies dentro de cada categoría.","metadata":{}},{"cell_type":"code","source":"plt.clf()\n\nfig, ax = plt.subplots(1, 2, figsize=(10, 5))\n\nwhales = train_csv[train_csv['species_category']=='whale']\ndolphins = train_csv[train_csv['species_category']!='whale']\n\nspecies_counts_whales = whales.species.value_counts().sort_values(ascending=True)\nspecies_counts_dolphins = dolphins.species.value_counts().sort_values(ascending=True)\n\nax[0].barh(species_counts_whales.index, species_counts_whales.values, color=my_colors[2])\nax[0].set_title('Especies ballenas', size = 15, color = my_colors[6], weight='bold')\nax[0].set_ylabel(None)\n\n\n\nax[1].barh(species_counts_dolphins.index, species_counts_dolphins.values, color=my_colors[0])\nax[1].set_title('Especies delfines', size = 15, color = my_colors[6], weight='bold')\nax[1].set_ylabel(None)\n\nplt.tight_layout()\nplt.ioff()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:18:55.484899Z","iopub.execute_input":"2023-03-01T16:18:55.485294Z","iopub.status.idle":"2023-03-01T16:18:55.990278Z","shell.execute_reply.started":"2023-03-01T16:18:55.485263Z","shell.execute_reply":"2023-03-01T16:18:55.989132Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Como podemos apreciar a través de los dos gráficos de barras, la distribución de las especies que forman parte de la categoría de las ballenas, está mucho más repartida que la de los delfines. En el caso de los delfines la mayor parte se concentra en las cuatro primeras especies, siendo muy pocas las imagenes recogidas para las últimas cuatro.\n\n##### Individuos\n\nPara realizar este análisis, es preciso conocer el número de imágenes que tenemos por cada individuo. De esta manera, podremos darnos cuenta de si existen algunos cetáceos que tienen un número inusualmente alto o bajo de imágenes en comparación con el resto de los individuos en el conjunto de datos.\n\nAdemás, al contar el número de imágenes para cada ID individual, podremos tener una idea más precisa del número total de individuos incluidos en el conjunto de datos. Es posible que algunos individuos estén representados por un gran número de imágenes, mientras que otros solo tienen unas pocas imágenes. Este análisis nos permitirá tener una comprensión más detallada de la distribución de imágenes en el conjunto de datos y podremos tomar decisiones más informadas en cuanto a cómo seleccionar las imágenes de entrenamiento y prueba para nuestros modelos.\n\nDe nuestro conjunto de entrenamiento de 51.033 imágenes, el número de diferentes individuos recogidos en las imágenes son **15.587**. Es decir, de media contamos con apróximadamente 3 fotos por individuo. No obstante, vamos a visualizar cómo se distribuyen:\n","metadata":{}},{"cell_type":"code","source":"number_individual = pd.DataFrame(train_csv.individual_id.value_counts())\nnumber_individual_grouped = number_individual.groupby('individual_id').size().reset_index(name='counts')","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:19:11.277710Z","iopub.execute_input":"2023-03-01T16:19:11.278162Z","iopub.status.idle":"2023-03-01T16:19:11.308113Z","shell.execute_reply.started":"2023-03-01T16:19:11.278126Z","shell.execute_reply":"2023-03-01T16:19:11.306770Z"},"jupyter":{"source_hidden":true,"outputs_hidden":true},"_kg_hide-input":true,"collapsed":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"all_indivs = train_csv[\"individual_id\"].value_counts().reset_index()\nindividuals = train_csv[\"individual_id\"].value_counts().reset_index().head(1000)\ntop50_individuals = train_csv[\"individual_id\"].value_counts().reset_index().head(50)\n\nplt.clf()\n\n# Plots\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))\nfig.suptitle('Análisis de Individuos', size = 26, weight='bold', color=my_colors[6])\naxs = [ax1, ax2]\n\nsns.barplot(data=top50_individuals, x=\"individual_id\", y='index', ax=ax1, palette=\"PuBuGn_r\", alpha=0.65)\nax1.set_title(\"Top 50 individuos\", size=15, color=my_colors[6], weight='bold')\nax1.set_ylabel(\"Código Identificación\", size=13, color=my_colors[6], weight='bold')\nax1.set_xlabel(\"Número Imágenes\", size=13, color=my_colors[6], weight='bold')\nax1.yaxis.set_tick_params(labelsize=12)\n\n\nsns.barplot(data=number_individual_grouped.head(20), x=\"individual_id\", y=\"counts\", ax=ax2,palette=\"PuBuGn_r\", alpha=0.65)\nax2.set_title(\"Apariciones por individuo - Bottom 20\", size=15, color=my_colors[6], weight='bold')\nax2.set_xlabel(\"Número Apariciones\", size = 13, weight='bold', color=my_colors[6])\nax2.set_ylabel(\"Número Individuos\", size = 13, weight='bold', color=my_colors[6])\n\n\nsns.despine(left=True, bottom=True)\nplt.tight_layout()\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:19:16.376954Z","iopub.execute_input":"2023-03-01T16:19:16.377374Z","iopub.status.idle":"2023-03-01T16:19:17.848651Z","shell.execute_reply.started":"2023-03-01T16:19:16.377336Z","shell.execute_reply":"2023-03-01T16:19:17.847394Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Podemos apreciar que contamos con una distribución de imágenes por individuo bastante desproporcionada. Por un lado, tenemos más de **8.000 individuos que tienen una única imagen**, y por otro, contamos con **un individuo** que tiene **400 fotografías**, por lo que podría ser un **outlier**. Vamos a ver a qué especie pertenece el individuo que tiene tantas imágenes.","metadata":{}},{"cell_type":"code","source":"filtered_df = train_csv[train_csv.individual_id == '37c7aba965a5']\nfiltered_df[['species','species_category']].head(1)\n\n\nprint (filtered_df['species'].head(1))","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:19:22.708405Z","iopub.execute_input":"2023-03-01T16:19:22.708803Z","iopub.status.idle":"2023-03-01T16:19:22.722473Z","shell.execute_reply.started":"2023-03-01T16:19:22.708771Z","shell.execute_reply":"2023-03-01T16:19:22.721306Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"species_simple = train_csv[\"species\"].value_counts().reset_index()\nspecies = train_csv.groupby(by=[\"individual_id\", \"species\"]).count()\\\n                .reset_index()[\"species\"].value_counts().reset_index()","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:19:51.103693Z","iopub.execute_input":"2023-03-01T16:19:51.104092Z","iopub.status.idle":"2023-03-01T16:19:51.156698Z","shell.execute_reply.started":"2023-03-01T16:19:51.104060Z","shell.execute_reply":"2023-03-01T16:19:51.155702Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"individual_speciesgroup = train_csv.groupby('species').agg({'individual_id':'nunique'})\nindividual_speciesgroup = individual_speciesgroup.sort_values(by='individual_id', ascending=False)","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:19:56.452825Z","iopub.execute_input":"2023-03-01T16:19:56.453216Z","iopub.status.idle":"2023-03-01T16:19:56.481912Z","shell.execute_reply.started":"2023-03-01T16:19:56.453179Z","shell.execute_reply":"2023-03-01T16:19:56.480739Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"En este punto, realizamos una reflexión, ¿si tenemos en cuenta unicamente una imágen por cada individuo, cambiará la distribución de especies que tenóamos anteriormente?\n\nPara contesar a nuestra cuestión, realizaremos una comparativa del gráfico *distribución de especies* anterior y crearemos uno teniendo aguprando las imágenes por el ID del inviduo.\n","metadata":{}},{"cell_type":"code","source":"plt.clf()\n\nfig, ax = plt.subplots(1, 2, figsize=(20, 7.5))\nfig.suptitle('- Análisis de las especies -', size=26, color=my_colors[7], weight='bold')\n\nsns.barplot(data=individual_speciesgroup, x=\"individual_id\", y=individual_speciesgroup.index, ax=ax[0], palette=\"PuBu_r\", alpha=0.6)\nax[0].set_title(\"Especie por Individuo\", size=15, color=my_colors[6], weight='bold')\nax[0].set_xlabel(\"Frecuencia\", size=13, color=my_colors[6], weight='bold')\nax[0].set_ylabel(\"Especie\", size=13, color=my_colors[6], weight='bold')\n\nsns.barplot(data=species_simple, x=\"species\", y=\"index\", ax=ax[1], palette=\"PuBuGn_r\", alpha=0.65)\nax[1].set_title(\"Distribución de las especies\", size=15, color=my_colors[6], weight='bold')\nax[1].set_ylabel(\"Especies\", size=13, color=my_colors[6], weight='bold')\nax[1].set_xlabel(\"\", size=13, color=my_colors[6], weight='bold')\nax[1].yaxis.set_tick_params(labelsize=12)\n\nsns.despine(left=True, bottom=True)\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:19:58.435730Z","iopub.execute_input":"2023-03-01T16:19:58.436146Z","iopub.status.idle":"2023-03-01T16:19:59.409821Z","shell.execute_reply.started":"2023-03-01T16:19:58.436110Z","shell.execute_reply":"2023-03-01T16:19:59.408645Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Al contrario de lo que apreciabamos anteriormente, tenemos un mayor número de individuos de las especies **dusky dolphin**, **humpback whale** y **blue_whale**, mientras que en la distribución del número de imágenes en cada una de las especies se encontraban en primer lugar las siguientes especies, **bottlenose**, **beluga** y **humpback**. Lo cual nos lleva a concluir, que el número de imágenes que contienen ciertas especies es totalmente determinante en la distribución de las fotografías.","metadata":{}},{"cell_type":"markdown","source":"### Análisis de imágenes\n\nEn este punto realizaremos un análisis de las imágenes. Para ello, vamos a añadir algunas columnas más a nuestros conjuntos de train y de test.\nAñadiremos la ruta a la imágen, para poder extraer ciertas carácteristicas de la imágen como el ancho y el alto.\n","metadata":{}},{"cell_type":"code","source":"train_csv['path'] = '/kaggle/input/happy-whale-and-dolphin/train_images/' + train_csv['image']\nsample_submission['path'] = '/kaggle/input/happy-whale-and-dolphin/test_images/' + sample_submission['image']","metadata":{"execution":{"iopub.status.busy":"2023-03-01T18:57:30.801050Z","iopub.execute_input":"2023-03-01T18:57:30.801457Z","iopub.status.idle":"2023-03-01T18:57:30.825081Z","shell.execute_reply.started":"2023-03-01T18:57:30.801424Z","shell.execute_reply":"2023-03-01T18:57:30.823893Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"widths, heights = [], []\n\nfor path in tqdm(train_csv[\"path\"]):\n    width, height = Image.open(path).size\n    widths.append(width)\n    heights.append(height)\n    \ntrain_csv[\"width\"] = widths\ntrain_csv[\"height\"] = heights\ntrain_csv[\"dimension\"] = train_csv[\"width\"] * train_csv[\"height\"]","metadata":{"execution":{"iopub.status.busy":"2023-03-01T18:57:47.143089Z","iopub.execute_input":"2023-03-01T18:57:47.143554Z","iopub.status.idle":"2023-03-01T19:12:46.701820Z","shell.execute_reply.started":"2023-03-01T18:57:47.143521Z","shell.execute_reply":"2023-03-01T19:12:46.699306Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"widths, heights = [], []\n\nfor path in tqdm(sample_submission[\"path\"]):\n    width, height = Image.open(path).size\n    widths.append(width)\n    heights.append(height)\n    \nsample_submission[\"width\"] = widths\nsample_submission[\"height\"] = heights\nsample_submission[\"dimension\"] = sample_submission[\"width\"] * sample_submission[\"height\"]","metadata":{"execution":{"iopub.status.busy":"2023-03-01T19:12:46.705778Z","iopub.execute_input":"2023-03-01T19:12:46.706217Z","iopub.status.idle":"2023-03-01T19:20:11.144880Z","shell.execute_reply.started":"2023-03-01T19:12:46.706182Z","shell.execute_reply":"2023-03-01T19:20:11.142907Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Visualización de Imágenes\n\nAhora es momento de explorar el conjunto de datos a nivel visual. Para ello, seleccionaremos una imagen de cada especie de manera aleatoria. Esta estrategia nos permitirá familiarizarnos con las imágenes y obtener una idea general de los tipos de fotografías que se nos proporcionan en el conjunto de datos. Este análisis visual nos brindará información valiosa y complementaria a los análisis estadísticos previos que hemos realizado y nos permitirá tener una comprensión más completa de nuestro conjunto de datos.\n","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (15,12))\nfor idx,i in enumerate(train_csv.species.unique()):\n    plt.subplot(4,7,idx+1)\n    df = train_csv[train_csv['species'] ==i].reset_index(drop = True)\n    image_path = train_csv.loc[rnd.randint(0, len(train_csv))-1,'path']\n    img = Image.open(image_path)\n    img = img.resize((224,224))\n    plt.imshow(img)\n    plt.axis('off')\n    plt.title(i)\nplt.tight_layout()\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:37:03.306983Z","iopub.execute_input":"2023-03-01T16:37:03.307419Z","iopub.status.idle":"2023-03-01T16:37:09.284519Z","shell.execute_reply.started":"2023-03-01T16:37:03.307383Z","shell.execute_reply":"2023-03-01T16:37:09.283687Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"En términos generales, las imágenes del conjunto de datos se centran en mostrar las aletas de los cetáceos, aunque se pueden apreciar variaciones en cuanto al ángulo de la toma y la calidad de la imagen, siendo algunas más nítidas que otras. Además, algunas imágenes muestran más claramente el paisaje alrededor del animal que el propio cetáceo.\n\n#### Dimensiones de las imágenes\n\nAhora bien, es importante realizar diversas comparaciones para obtener una mejor comprensión del conjunto de datos. En este sentido, una primera comparación que realizamos es el tamaño de las imágenes en los conjuntos de entrenamiento y validación, con el objetivo de determinar si hay alguna diferencia significativa en este aspecto entre los dos conjuntos. Además, se realiza en escala logaritmica para tener un mayor detalle.","metadata":{}},{"cell_type":"code","source":"train_csv['split'] = 'train'\ntrain_csv.columns","metadata":{"execution":{"iopub.status.busy":"2023-03-01T19:30:55.032568Z","iopub.execute_input":"2023-03-01T19:30:55.033016Z","iopub.status.idle":"2023-03-01T19:30:55.049911Z","shell.execute_reply.started":"2023-03-01T19:30:55.032983Z","shell.execute_reply":"2023-03-01T19:30:55.048702Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_submission['split'] = 'test'\nsample_submission.columns","metadata":{"execution":{"iopub.status.busy":"2023-03-01T19:30:56.416114Z","iopub.execute_input":"2023-03-01T19:30:56.416506Z","iopub.status.idle":"2023-03-01T19:30:56.425718Z","shell.execute_reply.started":"2023-03-01T19:30:56.416475Z","shell.execute_reply":"2023-03-01T19:30:56.424519Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Procedemos a realizar un análisis más detallado de las dimensiones de las imágenes en relación con las especies, mediante el uso de un gráfico de dispersión.","metadata":{}},{"cell_type":"code","source":"plt.clf()\n\nfig, axes = plt.subplots(ncols=1, figsize=(12, 9))\nsns.scatterplot(data=train_csv, x='width', y='height', hue='species')\naxes.set_title(f'Ancho y alto de imagen por especies')\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-01T19:37:05.607785Z","iopub.execute_input":"2023-03-01T19:37:05.608212Z","iopub.status.idle":"2023-03-01T19:37:08.168593Z","shell.execute_reply.started":"2023-03-01T19:37:05.608179Z","shell.execute_reply":"2023-03-01T19:37:08.167577Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"A través del grafico de dispersión se aprecia que la anchura de las imágenes varían según la especie de cetáceo. Por ejemplo, las especies **killer, pilot whale y dusky dolphin** tienden a ser imágenes más estrechas, mientras que **fin_whale o blue_whale** suelen presentar imágenes más anchas. En cuanto a la altura de las imágenes, se observa una distribución similar en todas las especies.\n\nCon el fin de simplificar el análisis, se procede a mostrar el gráfico de dispersión agrupando las imágenes por las categorías de delfines y ballenas.\n","metadata":{}},{"cell_type":"code","source":"plt.clf()\n\nfig, axes = plt.subplots(ncols=1, figsize=(12, 6))\nsns.scatterplot(data=train_csv, x='width', y='height', hue='species_category', palette =  \"PuBuGn_r\", alpha=0.65)\naxes.set_title(f'Ancho y alto de imagen por categoría de especie')\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-01T19:37:20.839368Z","iopub.execute_input":"2023-03-01T19:37:20.840089Z","iopub.status.idle":"2023-03-01T19:37:22.712894Z","shell.execute_reply.started":"2023-03-01T19:37:20.840048Z","shell.execute_reply":"2023-03-01T19:37:22.712056Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"A partir de este segundo gráfico de dispersión, se puede concluir que, en cuanto a la anchura de las imágenes, las fotografías de **ballenas** tienden a ser más anchas, mientras que las de **delfines** suelen ser más estrechas. Sin embargo, en lo que respecta a la altura de las imágenes, se aprecia una distribución similar en ambas categorías, aunque se pueden encontrar algunas imágenes con una altura atípica en comparación con otras en ambas categorías.","metadata":{}},{"cell_type":"markdown","source":"## Inicio del entrenamiento","metadata":{}},{"cell_type":"markdown","source":"### Separación en train y test","metadata":{}},{"cell_type":"code","source":"train_df , test_df = train_test_split(train_csv, test_size = 0.30, shuffle = True, random_state = 1)","metadata":{"execution":{"iopub.status.busy":"2023-03-01T19:35:55.977553Z","iopub.execute_input":"2023-03-01T19:35:55.978027Z","iopub.status.idle":"2023-03-01T19:35:56.014019Z","shell.execute_reply.started":"2023-03-01T19:35:55.977991Z","shell.execute_reply":"2023-03-01T19:35:56.012882Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Modelo MobileVNet2 con regularización\n\n### Generación de Datos con MobileVNet2","metadata":{}},{"cell_type":"code","source":"#Preprocesamiento de imagenes a través de la aplicación MobileNetV2\ntrain_gen = tf.keras.preprocessing.image.ImageDataGenerator(preprocessing_function = tf.keras.applications.mobilenet_v2.preprocess_input,validation_split = 0.2)\n\ntest_gen = tf.keras.preprocessing.image.ImageDataGenerator(preprocessing_function = tf.keras.applications.mobilenet_v2.preprocess_input)\n\n\n#Cargar las imagenes de train y de validation\ntrain_generator = train_gen.flow_from_dataframe(dataframe=train_df.loc[:,train_df.columns!=\"split\"],\n                        directory=\"/kaggle/input/happy-whale-and-dolphin/train_images\",\n                        x_col = 'image',\n                        y_col = 'species',\n                        target_size = (224, 224),\n                        class_mode = 'categorical',\n                        batch_size = 32,\n                        shuffle = True,\n                        subset = 'training')\n\nval_generator = train_gen.flow_from_dataframe(dataframe=train_df.loc[:,train_df.columns!=\"split\"],\n                        directory=\"/kaggle/input/happy-whale-and-dolphin/train_images\",\n                        x_col = 'image',\n                        y_col = 'species',\n                        target_size = (224, 224),\n                        class_mode = 'categorical',\n                        batch_size = 32,\n                        shuffle = True,\n                        subset = 'validation')\n\n\ntest_generator = test_gen.flow_from_dataframe(dataframe=test_df.loc[:,test_df.columns!=\"split\"],\n                        directory=\"/kaggle/input/happy-whale-and-dolphin/train_images\",\n                        x_col = 'image',\n                        y_col = 'species',\n                        target_size = (224, 224),\n                        class_mode = 'categorical',\n                        batch_size = 32,\n                        shuffle = False)\n","metadata":{"execution":{"iopub.status.busy":"2023-03-01T19:35:59.136410Z","iopub.execute_input":"2023-03-01T19:35:59.137367Z","iopub.status.idle":"2023-03-01T19:36:38.261636Z","shell.execute_reply.started":"2023-03-01T19:35:59.137321Z","shell.execute_reply":"2023-03-01T19:36:38.260394Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Callback","metadata":{}},{"cell_type":"code","source":"es_callback = keras.callbacks.EarlyStopping(\n    monitor='val_loss',\n    patience=3,  # si durante 3 epocas no hay ninguna mejora, la ejecución parará\n    verbose=1)","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:40:06.443166Z","iopub.execute_input":"2023-03-01T16:40:06.443612Z","iopub.status.idle":"2023-03-01T16:40:06.449335Z","shell.execute_reply.started":"2023-03-01T16:40:06.443561Z","shell.execute_reply":"2023-03-01T16:40:06.448101Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Premodelo","metadata":{}},{"cell_type":"code","source":"pretrained_model = tf.keras.applications.MobileNetV2(\n    input_shape=(224, 224, 3),\n    include_top=False\n    )\n    \npretrained_model.trainable = False","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:40:08.724529Z","iopub.execute_input":"2023-03-01T16:40:08.724972Z","iopub.status.idle":"2023-03-01T16:40:09.835015Z","shell.execute_reply.started":"2023-03-01T16:40:08.724938Z","shell.execute_reply":"2023-03-01T16:40:09.833894Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Juntar modelos","metadata":{}},{"cell_type":"markdown","source":"Añadimos una nueva capa de regularización","metadata":{}},{"cell_type":"code","source":"inputs = pretrained_model.input\n\n# pre-trained model\nx = pretrained_model(inputs)\n\n# classifier\nflat = tf.keras.layers.Flatten()(x)\nflat = tf.keras.layers.Dropout(0.5)(flat)\nl_1 = layers.Dense(256, activation='relu', name='layer_1')(flat)\nl_1 = layers.Dropout(0.5, name='dropout_l1')(l_1)\noutputs = tf.keras.layers.Dense(25, activation='softmax')(l_1)\n\nmodel_tlv2 = tf.keras.Model(inputs, outputs)\nmodel_tlv2.summary()","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:40:14.706586Z","iopub.execute_input":"2023-03-01T16:40:14.707048Z","iopub.status.idle":"2023-03-01T16:40:15.266571Z","shell.execute_reply.started":"2023-03-01T16:40:14.707015Z","shell.execute_reply":"2023-03-01T16:40:15.265651Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Compilacion","metadata":{}},{"cell_type":"code","source":"model_tlv2.compile(\n    optimizer='adam',\n    loss='categorical_crossentropy',\n    metrics=['accuracy']\n)","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:40:19.389422Z","iopub.execute_input":"2023-03-01T16:40:19.389872Z","iopub.status.idle":"2023-03-01T16:40:19.408666Z","shell.execute_reply.started":"2023-03-01T16:40:19.389835Z","shell.execute_reply":"2023-03-01T16:40:19.407196Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Historia","metadata":{}},{"cell_type":"markdown","source":"En este punto debido a la gran duración del proceso de entrenamiento, se ha dejado el fichero de predicción y de resultado del modelo que se guardaron previamente para poder cargarlo directamente y no tener que entrenarlo de nuevo","metadata":{}},{"cell_type":"code","source":"seed = 7\nnp.random.seed(seed)\n\n#history = model_tlv2.fit(\n#    train_generator,\n#    validation_data=val_generator,\n#    epochs=100,\n#    callbacks=[es_callback]\n#)\n\n#model_tlv2.save_weights(\"model_tlv2.h5\")","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#results = model_tlv2.evaluate(test_generator, verbose = 0)\n\n#Guardar resultados del modelo\n#with open(\"results_model_overfit.pkl\", \"wb\") as f:\n#    pickle.dump(results, f)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open(\"/kaggle/input/result/results_model_overfit.pkl\", \"rb\") as f:\n    results_model_tlv2 = pickle.load(f)","metadata":{"execution":{"iopub.status.busy":"2023-03-01T18:12:33.829873Z","iopub.execute_input":"2023-03-01T18:12:33.830310Z","iopub.status.idle":"2023-03-01T18:12:33.842999Z","shell.execute_reply.started":"2023-03-01T18:12:33.830278Z","shell.execute_reply":"2023-03-01T18:12:33.841933Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'\\nTest Accuracy : {round(results_model_tlv2[1], 4)*100}%\\n') ","metadata":{"execution":{"iopub.status.busy":"2023-03-01T18:12:38.003547Z","iopub.execute_input":"2023-03-01T18:12:38.004069Z","iopub.status.idle":"2023-03-01T18:12:38.011750Z","shell.execute_reply.started":"2023-03-01T18:12:38.004034Z","shell.execute_reply":"2023-03-01T18:12:38.010406Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Predicción del modelo","metadata":{}},{"cell_type":"code","source":"#pred = np.argmax(model_tlv2.predict(test_generator), axis = 1)\n\n#Guardar la predicción\n#with open(\"prediction_model_tlv2.pkl\", \"wb\") as f:\n#    pickle.dump(pred, f)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Cargar predicción\nwith open(\"/kaggle/input/prediction/prediction_model_tlv2.pkl\", \"rb\") as f:\n    pred = pickle.load(f)","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:51:53.554664Z","iopub.execute_input":"2023-03-01T16:51:53.556280Z","iopub.status.idle":"2023-03-01T16:51:53.572009Z","shell.execute_reply.started":"2023-03-01T16:51:53.556217Z","shell.execute_reply":"2023-03-01T16:51:53.570881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix, classification_report\n\nclass_names = list(test_generator.class_indices.keys())\ncm = confusion_matrix(test_generator.labels, pred, labels = np.arange(25))\nclr = classification_report(test_generator.labels, pred, labels = np.arange(25),target_names = class_names)\nplt.figure(figsize = (10,10))\nsns.heatmap(cm, annot = True, fmt = 'g', vmin = 0, cbar = False)\nplt.xticks(ticks = np.arange(25) + 0.5, labels = class_names, rotation = 90)\nplt.yticks(ticks = np.arange(25) + 0.5, labels = class_names, rotation = 0)\nplt.xlabel('Predicted')\nplt.ylabel('Actual')\nplt.show()\nprint(f'classification Report------------>\\n{clr}')","metadata":{"execution":{"iopub.status.busy":"2023-03-01T18:12:52.552119Z","iopub.execute_input":"2023-03-01T18:12:52.552653Z","iopub.status.idle":"2023-03-01T18:12:55.006320Z","shell.execute_reply.started":"2023-03-01T18:12:52.552617Z","shell.execute_reply":"2023-03-01T18:12:55.004698Z"},"_kg_hide-input":false,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.clf()\n\ndef show_loss_accuracy_evolution(history):\n    \n    hist = pd.DataFrame(history.history)\n    hist['epoch'] = history.epoch\n    \n    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6))\n\n    ax1.set_xlabel('Epoch')\n    ax1.set_ylabel('Categorical Crossentropy')\n    ax1.plot(hist['epoch'], hist['loss'], label='Train Error')\n    ax1.plot(hist['epoch'], hist['val_loss'], label = 'Val Error')\n    ax1.grid()\n    ax1.legend()\n\n    ax2.set_xlabel('Epoch')\n    ax2.set_ylabel('Accuracy')\n    ax2.plot(hist['epoch'], hist['accuracy'], label='Train Accuracy')\n    ax2.plot(hist['epoch'], hist['val_accuracy'], label = 'Val Accuracy')\n    ax2.grid()\n    ax2.legend()\n\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:52:39.356347Z","iopub.execute_input":"2023-03-01T16:52:39.356785Z","iopub.status.idle":"2023-03-01T16:52:39.372050Z","shell.execute_reply.started":"2023-03-01T16:52:39.356751Z","shell.execute_reply":"2023-03-01T16:52:39.370617Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Se facilita la imágen de la evolución de precisión y del error en train y validation para que no tenga que volver a ejecutarse el entrenamiento","metadata":{}},{"cell_type":"markdown","source":"<img src=\"https://i.imgur.com/1lrkZGE.png\" width=800>\n\n","metadata":{}},{"cell_type":"code","source":"#show_loss_accuracy_evolution(history)","metadata":{"execution":{"iopub.status.busy":"2023-03-01T16:52:42.726614Z","iopub.execute_input":"2023-03-01T16:52:42.727059Z","iopub.status.idle":"2023-03-01T16:52:42.767755Z","shell.execute_reply.started":"2023-03-01T16:52:42.727026Z","shell.execute_reply":"2023-03-01T16:52:42.766203Z"},"_kg_hide-input":true,"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_errors(val_ds, model, class_names, n_images=5):\n    n_plots = 0\n    fig = plt.figure(figsize=(15,15))\n    labels = val_ds.classes\n    preds = model.predict(val_ds)\n    preds = np.argmax(preds, axis=1)\n    bad_pred_inds = np.where(labels != preds)[0]\n    for ind in bad_pred_inds:\n        if n_plots >= n_images:\n            break\n        n_plots += 1\n        real_class = class_names[int(labels[ind])]\n        pred_class = class_names[preds[ind]]\n        ax = fig.add_subplot(n_images, 1, n_plots)\n        ax.imshow(val_ds[ind][0][0], cmap='gray')\n        ax.set_title(\"Real class: \" + real_class + \", Pred class: \" + pred_class)\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-01T18:15:05.934796Z","iopub.execute_input":"2023-03-01T18:15:05.935414Z","iopub.status.idle":"2023-03-01T18:15:05.946500Z","shell.execute_reply.started":"2023-03-01T18:15:05.935376Z","shell.execute_reply":"2023-03-01T18:15:05.945489Z"},"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_errors(val_generator, model_tlv2, class_names, n_images=5)","metadata":{"execution":{"iopub.status.busy":"2023-03-01T18:15:10.311431Z","iopub.execute_input":"2023-03-01T18:15:10.311954Z","iopub.status.idle":"2023-03-01T18:27:49.033220Z","shell.execute_reply.started":"2023-03-01T18:15:10.311916Z","shell.execute_reply":"2023-03-01T18:27:49.030857Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Como podemos apreciar las imagenes que aparecen para los errores están bastante distorsionadas al haberles aplicado unas transformaciones acorde al modelo seleccionado, pero se pueden visualizar algunos errores realizados por nuestro modelo.","metadata":{}}]}