{"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":"&nbsp;\n&nbsp;\n&nbsp;\n\n# **IMPORTACIONES**","metadata":{}},{"cell_type":"code","source":"import numpy as np\n\nimport pandas as pd\n\nimport os\n\nimport tensorflow as tf\nimport tensorflow.keras as keras\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.layers.experimental import preprocessing\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom tensorflow.keras.callbacks import ReduceLROnPlateau\nfrom tensorflow.keras.callbacks import ModelCheckpoint\nfrom tensorflow.keras import regularizers\n\nimport matplotlib.pyplot as plt\n\nimport cv2\n\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix\n\nimport sys\n\nimport gc\n\nimport time\n\nimport seaborn as sns","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:08.569199Z","iopub.execute_input":"2022-08-21T20:22:08.570161Z","iopub.status.idle":"2022-08-21T20:22:15.394273Z","shell.execute_reply.started":"2022-08-21T20:22:08.570054Z","shell.execute_reply":"2022-08-21T20:22:15.393157Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"&nbsp;\n&nbsp;\n&nbsp;\n\n# **SEMILLA**","metadata":{}},{"cell_type":"code","source":"SEED = 42                  #Semilla para garantizar la reproducibilidad del programa (asignada a parámetros random_state y seed)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:15.396511Z","iopub.execute_input":"2022-08-21T20:22:15.397151Z","iopub.status.idle":"2022-08-21T20:22:15.406155Z","shell.execute_reply.started":"2022-08-21T20:22:15.397114Z","shell.execute_reply":"2022-08-21T20:22:15.404602Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"&nbsp;\n&nbsp;\n&nbsp;\n\n# **FUNCIONES**","metadata":{}},{"cell_type":"code","source":"# Carga y Ajuste del dataset de entrenamiento\ndef load_traindf():\n    \n    traindf = pd.read_csv('../input/landmark-recognition-2021/train.csv')\n    \n    #Añadir a train.csv la columna con la dirección de cada imagen para su posterior lectura\n    traindf['img_path'] = (traindf['id'].apply(lambda r: os.path.join\n                            ('../input/landmark-recognition-2021/train', r[0], r[1], r[2], r + '.jpg')))\n    \n    #Conversión de columna landmark_id de int64 a int32 para reducir consumo de memoria\n    traindf['landmark_id'] = traindf['landmark_id'].apply(lambda x: np.int32(x))\n    \n    return traindf\n\n\n\n# Lectura y Redimensionamiento imágenes a partir de su ruta (path)\ndef img_read_resize(img_path): \n    img = plt.imread(img_path)\n    img_redim = cv2.resize(img,(IMG_SIZE,IMG_SIZE))\n    return img_redim\n\n\n\n# Obtener la memoria de cualquier objeto en Bytes\ndef get_size(obj, seen=None):\n    \"\"\"Recursively finds size of objects\"\"\"\n    size = sys.getsizeof(obj)\n    if seen is None:\n        seen = set()\n    obj_id = id(obj)\n    if obj_id in seen:\n        return 0\n    # Important mark as seen *before* entering recursion to gracefully handle\n    # self-referential objects\n    seen.add(obj_id)\n    if isinstance(obj, dict):\n        size += sum([get_size(v, seen) for v in obj.values()])\n        size += sum([get_size(k, seen) for k in obj.keys()])\n    elif hasattr(obj, '__dict__'):\n        size += get_size(obj.__dict__, seen)\n    elif hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes, bytearray)):\n        size += sum([get_size(i, seen) for i in obj])\n    return size","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:15.408457Z","iopub.execute_input":"2022-08-21T20:22:15.409491Z","iopub.status.idle":"2022-08-21T20:22:15.423888Z","shell.execute_reply.started":"2022-08-21T20:22:15.409455Z","shell.execute_reply":"2022-08-21T20:22:15.422747Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"&nbsp;\n&nbsp;\n&nbsp;\n\n# **DATASET DE ENTRENAMIENTO**","metadata":{}},{"cell_type":"markdown","source":"### Carga del dataset de entrenamiento","metadata":{}},{"cell_type":"code","source":"traindf = load_traindf()        #Función previamente definida para cargar el dataset ajustado\n\nlandmark_unique = len(traindf['landmark_id'].unique())    #Clases totales del dataset \n\ntraindf","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:15.427250Z","iopub.execute_input":"2022-08-21T20:22:15.427588Z","iopub.status.idle":"2022-08-21T20:22:22.509138Z","shell.execute_reply.started":"2022-08-21T20:22:15.427555Z","shell.execute_reply":"2022-08-21T20:22:22.507903Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sys.getsizeof(traindf)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:22.510378Z","iopub.execute_input":"2022-08-21T20:22:22.511021Z","iopub.status.idle":"2022-08-21T20:22:22.778158Z","shell.execute_reply.started":"2022-08-21T20:22:22.510984Z","shell.execute_reply":"2022-08-21T20:22:22.777056Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"get_size(traindf)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:22.780026Z","iopub.execute_input":"2022-08-21T20:22:22.780451Z","iopub.status.idle":"2022-08-21T20:22:25.026900Z","shell.execute_reply.started":"2022-08-21T20:22:22.780411Z","shell.execute_reply":"2022-08-21T20:22:25.025958Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"traindf.info(memory_usage='deep')","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:25.028514Z","iopub.execute_input":"2022-08-21T20:22:25.028865Z","iopub.status.idle":"2022-08-21T20:22:25.435241Z","shell.execute_reply.started":"2022-08-21T20:22:25.028831Z","shell.execute_reply":"2022-08-21T20:22:25.434201Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Información numérica del dataset de entrenamiento","metadata":{}},{"cell_type":"code","source":"print('Datos del dataset de entrenamiento original \\n')\nprint('Número de imágenes en el dataset: ', traindf.shape[0])\nprint('Número de clases diferentes: ', landmark_unique)\nprint('Clase más baja: ', min(traindf['landmark_id']))\nprint('Clase más alta: ', max(traindf['landmark_id']))\nprint('\\nRepeticiones de elementos por clase:')\nprint(traindf['landmark_id'].value_counts())","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:25.436978Z","iopub.execute_input":"2022-08-21T20:22:25.437565Z","iopub.status.idle":"2022-08-21T20:22:25.728998Z","shell.execute_reply.started":"2022-08-21T20:22:25.437526Z","shell.execute_reply":"2022-08-21T20:22:25.727912Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(1, figsize = (22, 5))\n\nsns.distplot(traindf['landmark_id'], hist=True, kde=False, \n             bins=int(landmark_unique/10), color = 'blue',\n             hist_kws={'edgecolor':'blue'})\n\nplt.ylim([0,1.1*max(traindf['landmark_id'].value_counts())])","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:25.730303Z","iopub.execute_input":"2022-08-21T20:22:25.731333Z","iopub.status.idle":"2022-08-21T20:22:38.632448Z","shell.execute_reply.started":"2022-08-21T20:22:25.731296Z","shell.execute_reply":"2022-08-21T20:22:38.631360Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> Se puede observar que el dataset no está balanceado **(Imbalanced Classification)** por la diferencia entre las frecuencias de las clases. Es necesario realizar oversampling o undersampling. En este programa se realizará **undersampling** en el dataset antes de realizar el split datos entrenamiento-validación, pues es más conveniente disminuir la cantidad de datos de las clases con mayor frecuencia para ahorrar memoria que aumentar los datos de las clases con poca frecuencia dada a la limitación de memoria del sistema. Si esta no fuera un problema, sería recomendable realizar el oversampling, obteniendo así una mayor precisión del modelo.","metadata":{}},{"cell_type":"code","source":"#Mostrar imágenes aleatorias del set de datos inicial\n\nplt.figure(figsize=(25,7))\n\nfor i in range(12):\n    j = np.random.randint(0, traindf.shape[0])        \n    img = plt.imread((traindf['img_path'][j]))\n    plt.subplot(2 , 6, i+1)\n    plt.xticks([])\n    plt.yticks([])\n    plt.xlabel(str(img.shape[0])+'x'+str(img.shape[1]), \n               fontweight = \"bold\", fontsize=16)      #Resolución\n    plt.imshow(img)\n    \nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:38.636986Z","iopub.execute_input":"2022-08-21T20:22:38.637416Z","iopub.status.idle":"2022-08-21T20:22:40.103259Z","shell.execute_reply.started":"2022-08-21T20:22:38.637387Z","shell.execute_reply":"2022-08-21T20:22:40.102313Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Selección de una muestra y undersampling","metadata":{}},{"cell_type":"code","source":"'''\n#SELECCIONAR MUESTRA SEGÚN NÚMERO DE DATOS (PROBLEMA: una muestra puede acabar en mitad de los datos de una clase; la clase estaría dividida en varias muestras)\n\nIMG_SIZE = 160        #Tamaño/resolución de las imágenes que se empleará en todo el programa\nN_DATOS = 10000       #Número de filas del dataframe tras undersampling que se usarán en la muestra\n\ntraindf_s = traindf_s.iloc[:N_DATOS,:]             #Muestra del dataset de entrenamiento tras undersampling\n\n#Si se quieren barajar los datos :\n#traindf.sample(frac=N_DATOS/traindf_unders.shape[0], random_state=SEED).reset_index(drop=True)  #Se obtiene un [frac %]  de filas del dataframe original y se barajan\n\n'''","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:40.104206Z","iopub.execute_input":"2022-08-21T20:22:40.104506Z","iopub.status.idle":"2022-08-21T20:22:40.112830Z","shell.execute_reply.started":"2022-08-21T20:22:40.104479Z","shell.execute_reply":"2022-08-21T20:22:40.111634Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#SELECCIONAR MUESTRA SEGÚN CLASES MAX Y MIN (TODOS LOS DATOS COMPRENDIDOS ENTRE DICHAS CLASES Y DE DICHAS CLASES)\n\nIMG_SIZE = 128       #Tamaño/resolución de las imágenes que se empleará en todo el programa\n\n#MUESTRA\nCLASE_MIN = 0\nCLASE_MAX = 1500\n\n#Obtención de muestra traindf_s\ntraindf_s = traindf[(CLASE_MIN<traindf['landmark_id']) & (traindf['landmark_id']<=CLASE_MAX)]\n\n\nUMBRAL_UNDERSAMPLING = 80   \n\n#Undersampling en la muestra\ntraindf_s = (traindf_s.groupby('landmark_id', group_keys=False).\n           apply(lambda x: x.sample(n = min(len(x), UMBRAL_UNDERSAMPLING), random_state= SEED)))\ntraindf_s.reset_index(inplace=True, drop=True)  #Reiniciar índices. drop=True índices antiguos no sean nueva columna\ntraindf_s['landmark_id'].value_counts()            #Frecuencias de las clases tras undersampling\n\n#--------------------------------------------------------------------------------------------------------------------------------------------------------#\nN_DATOS = len(traindf_s['landmark_id'])\nclases = traindf_s['landmark_id'].unique()\nN_CLASES = len(clases)\n\nprint('Número de datos de la muestra, N_DATOS: '+str(N_DATOS))\nprint('\\nNúmero de clases de la muestra, N_CLASES: '+str(N_CLASES))\nprint('\\nClase más baja de la muestra: '+str(min(traindf_s['landmark_id'])))\nprint('\\nClase más alta de la muestra: '+str(max(traindf_s['landmark_id'])))\nprint('\\nRepeticiones de elementos por clase en la muestra tras Undersampling:')\nprint(traindf_s['landmark_id'].value_counts())","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:40.114732Z","iopub.execute_input":"2022-08-21T20:22:40.115602Z","iopub.status.idle":"2022-08-21T20:22:40.343120Z","shell.execute_reply.started":"2022-08-21T20:22:40.115570Z","shell.execute_reply":"2022-08-21T20:22:40.341996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"clases","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:40.344671Z","iopub.execute_input":"2022-08-21T20:22:40.345712Z","iopub.status.idle":"2022-08-21T20:22:40.354635Z","shell.execute_reply.started":"2022-08-21T20:22:40.345680Z","shell.execute_reply":"2022-08-21T20:22:40.353669Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"traindf_s","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:40.358024Z","iopub.execute_input":"2022-08-21T20:22:40.358710Z","iopub.status.idle":"2022-08-21T20:22:40.371834Z","shell.execute_reply.started":"2022-08-21T20:22:40.358675Z","shell.execute_reply":"2022-08-21T20:22:40.370903Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Comparación de datos en el mismo intervalo de clases [CLASE_MIN, CLASE_MAX]\n\n# Muestra del dataset SIN undersampling\ntraindf_no_unders = traindf[(CLASE_MIN<traindf['landmark_id']) & (traindf['landmark_id']<=CLASE_MAX)]\nplt.figure(1, figsize = (22, 5))\nplt.title('Histograma de landmark_id en muestra SIN undersampling: '+ str(len(traindf_no_unders))+' datos', fontweight =\"bold\")\nplt.hist(traindf_no_unders['landmark_id'], color = 'red', bins= CLASE_MAX - CLASE_MIN+1, histtype= 'stepfilled')\nplt.xlabel('landmark_id')\nplt.xlim([0,CLASE_MAX])\nplt.axhline(y=UMBRAL_UNDERSAMPLING, color='g', linestyle='--', label= 'Umbral Undersampling')      #Línea horizontal indicando umbral\nplt.legend()\nplt.show()\n\n\n# Muestra del dataset CON undersampling\nplt.figure(2, figsize = (22, 5))\nplt.title('Histograma de landmark_id en la muestra CON undersampling traindf_s: '+ str(N_DATOS)+' datos', fontweight = \"bold\")\nplt.hist(traindf_s['landmark_id'], color = 'blue', bins = CLASE_MAX - CLASE_MIN+1, histtype= 'stepfilled')\nplt.xlabel('landmark_id')\nplt.xlim([0,CLASE_MAX])\nplt.ylim([0,max(traindf_no_unders['landmark_id'].value_counts())])\nplt.axhline(y=UMBRAL_UNDERSAMPLING, color='g', linestyle='--', label= 'Umbral Undersampling')      #Línea horizontal indicando umbral\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:40.373114Z","iopub.execute_input":"2022-08-21T20:22:40.373542Z","iopub.status.idle":"2022-08-21T20:22:40.811557Z","shell.execute_reply.started":"2022-08-21T20:22:40.373509Z","shell.execute_reply":"2022-08-21T20:22:40.810684Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> Se ha conseguido equilibrar en cierta medida las frecuencias de las clases a costa de disminuir los datos.","metadata":{}},{"cell_type":"code","source":"traindf_s['landmark_id'].value_counts().describe()","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:40.812852Z","iopub.execute_input":"2022-08-21T20:22:40.813310Z","iopub.status.idle":"2022-08-21T20:22:40.826896Z","shell.execute_reply.started":"2022-08-21T20:22:40.813275Z","shell.execute_reply":"2022-08-21T20:22:40.826053Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Eliminar de memoria el dataset completo sin imágenes; solo se usará la muestra\nprint('ELIMINANDO ' + str(round((get_size(traindf)/(1024*1024)),4)) +' MB ocupados por traindf')\ndel traindf          #Elimina la relación entre la variable y el espacio de memoria al que apunta\ngc.collect();        #Elimina de memoria y devuelve los objetos a los que ya no se apunta","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:40.828505Z","iopub.execute_input":"2022-08-21T20:22:40.828855Z","iopub.status.idle":"2022-08-21T20:22:44.534209Z","shell.execute_reply.started":"2022-08-21T20:22:40.828821Z","shell.execute_reply":"2022-08-21T20:22:44.533178Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('ELIMINANDO ' + str(round((get_size(traindf_no_unders)/(1024*1024)),4)) +' MB ocupados por traindf_no_unders (muestra sin undersampling)')\ndel traindf_no_unders         #Elimina la relación entre la variable y el espacio de memoria al que apunta\ngc.collect();                 #Elimina de memoria y devuelve los objetos a los que ya no se apunta","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:44.535622Z","iopub.execute_input":"2022-08-21T20:22:44.536090Z","iopub.status.idle":"2022-08-21T20:22:44.698556Z","shell.execute_reply.started":"2022-08-21T20:22:44.536053Z","shell.execute_reply":"2022-08-21T20:22:44.697589Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Mostrar imágenes aleatorias de la muestra\n\nplt.figure(figsize=(25,7))\n\nfor i in range(12):\n    j = np.random.randint(0, N_DATOS)              #Cambiar j por i en las indexaciones si se quieren imágenes aleatorias de la muestra\n    img = img_read_resize(traindf_s['img_path'][j])     #Para que las imágenes tengan el mismo tamaño (= número de píxeles = neuronas de entrada)\n    plt.subplot(2 , 6, i+1)\n    plt.xticks([])\n    plt.yticks([])\n    plt.xlabel('landmark_id: '+ str(traindf_s['landmark_id'][j]), fontweight =\"bold\", fontsize=16)\n    plt.imshow(img)\n    \nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:44.700263Z","iopub.execute_input":"2022-08-21T20:22:44.700876Z","iopub.status.idle":"2022-08-21T20:22:45.657755Z","shell.execute_reply.started":"2022-08-21T20:22:44.700838Z","shell.execute_reply":"2022-08-21T20:22:45.656950Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Redimensionamiento de las imágenes del dataset de entrenamiento. Almacenamiento de las imágenes en una variable y de las etiquetas en otra","metadata":{}},{"cell_type":"code","source":"X = []   #Imágenes\ny = []   #Clases\n\nfor i in range(traindf_s.shape[0]):   \n    X.append(img_read_resize(traindf_s['img_path'][i])) \n    y.append(np.array(traindf_s['landmark_id'][i]))            #Cada etiqueta se convierte en numpy.ndarray (por compatibilidad con las imágenes en X, que son ndarrays)\n\nprint('Tipos de las variables: \\n')\nprint('X: ', type(X))\nprint('Elementos de X: ', type(X[0]))\nprint('\\ny: ', type(y))\nprint('Elementos de y: ', type(y[0]))","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:45.659178Z","iopub.execute_input":"2022-08-21T20:22:45.659736Z","iopub.status.idle":"2022-08-21T20:22:52.112985Z","shell.execute_reply.started":"2022-08-21T20:22:45.659702Z","shell.execute_reply":"2022-08-21T20:22:52.111964Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Label Encoding Etiquetas","metadata":{}},{"cell_type":"code","source":"#Label Encoding\n\nLE = LabelEncoder()\nLE.fit(clases)\ny_LE = LE.transform(y)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:52.114249Z","iopub.execute_input":"2022-08-21T20:22:52.115251Z","iopub.status.idle":"2022-08-21T20:22:52.121830Z","shell.execute_reply.started":"2022-08-21T20:22:52.115214Z","shell.execute_reply":"2022-08-21T20:22:52.120824Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(clases)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:52.123151Z","iopub.execute_input":"2022-08-21T20:22:52.123563Z","iopub.status.idle":"2022-08-21T20:22:52.131557Z","shell.execute_reply.started":"2022-08-21T20:22:52.123528Z","shell.execute_reply":"2022-08-21T20:22:52.130451Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"###print('ELIMINANDO ' + str(get_size(df_train)/(1024*1024)) +' MB ocupados por df_train')\n###del df_train         #Elimina la relación entre la variable y la memoria a la que apunta\n###gc.collect();        #Elimina de memoria y devuelve los objetos a los que ya no se apunta","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:52.133227Z","iopub.execute_input":"2022-08-21T20:22:52.133589Z","iopub.status.idle":"2022-08-21T20:22:52.139542Z","shell.execute_reply.started":"2022-08-21T20:22:52.133555Z","shell.execute_reply":"2022-08-21T20:22:52.138419Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('ELIMINANDO ' + str(round((get_size(traindf_s)/(1024*1024)),4)) +' MB ocupados por traindf_s')\ndel traindf_s         #Elimina la relación entre la variable y la memoria a la que apunta\ngc.collect();         #Elimina de memoria y devuelve los objetos a los que ya no se apunta","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:52.142122Z","iopub.execute_input":"2022-08-21T20:22:52.143400Z","iopub.status.idle":"2022-08-21T20:22:52.320554Z","shell.execute_reply.started":"2022-08-21T20:22:52.143283Z","shell.execute_reply":"2022-08-21T20:22:52.318954Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"whos","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:52.322120Z","iopub.execute_input":"2022-08-21T20:22:52.323409Z","iopub.status.idle":"2022-08-21T20:22:52.337684Z","shell.execute_reply.started":"2022-08-21T20:22:52.323304Z","shell.execute_reply":"2022-08-21T20:22:52.336728Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Ajustes a las variables","metadata":{}},{"cell_type":"markdown","source":"#Conversión de lista X a array + Normalización de las imágenes en X + Cambio de tipo de int8 a float16 para reducir memoria\nX = np.array(X).astype('float16')/255     #Se normalizan las imágenes para que los valores de los píxeles estén entre [0,1] en vez de [0,255]\n\n#Conversión de lista y a array\ny = np.array(y)","metadata":{"execution":{"iopub.status.busy":"2022-08-02T22:13:22.734325Z","iopub.status.idle":"2022-08-02T22:13:22.734815Z","shell.execute_reply.started":"2022-08-02T22:13:22.734549Z","shell.execute_reply":"2022-08-02T22:13:22.734586Z"}}},{"cell_type":"markdown","source":"### Obtención de los datos de validación y testeo","metadata":{}},{"cell_type":"code","source":"###### X = [n/255 for n in X]       #Escalado de los datos ---> DISMINUYE PRECISIÓN\n\nX = np.array(X)    #Conversión de lista a array necesaria\ny_LE = np.array(y_LE)\ny = np.array(y)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:52.340776Z","iopub.execute_input":"2022-08-21T20:22:52.341054Z","iopub.status.idle":"2022-08-21T20:22:52.350883Z","shell.execute_reply.started":"2022-08-21T20:22:52.341030Z","shell.execute_reply":"2022-08-21T20:22:52.349937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Separación de los datos en datos para entrenamiento, datos para validación y datos de testeo\n\n#Validación\nX_train, X_val, y_train, y_val = train_test_split(X, y_LE, test_size = 0.10, random_state=SEED, shuffle=True)\n        #Mismo tipo que X e y (ndarray formado por ndarrays o int64, respectivamente)\n\n#Testeo\nX_train, X_test, y_train, y_test = train_test_split(X_train, y_train, test_size = 0.05, random_state=SEED, shuffle=True)\n\nn_datos_entrenamiento = len(X_train)\n\nprint('Imágenes en X: ',len(X), ' y etiquetas en y: ', len(y_LE))\nprint('Entrenamiento. Imágenes en X_train: ',len(X_train), 'y etiquetas en y_train: ',len(y_train))\nprint('Validación. Imágenes en X_val: ',len(X_val), 'y etiquetas en y_val: ',len(y_val))\nprint('Testeo. Imágenes en X_test: ',len(X_test), 'y etiquetas en y_test: ',len(y_test))","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:52.354239Z","iopub.execute_input":"2022-08-21T20:22:52.354499Z","iopub.status.idle":"2022-08-21T20:22:52.371771Z","shell.execute_reply.started":"2022-08-21T20:22:52.354475Z","shell.execute_reply":"2022-08-21T20:22:52.370877Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.applications.resnet import preprocess_input\n\nX_train = preprocess_input(X_train)\nX_val = preprocess_input(X_val)\nX_test_orig = X_test                                     #Para representar al final las img testeo sin procesado\nX_test = preprocess_input(X_test)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:52.377791Z","iopub.execute_input":"2022-08-21T20:22:52.378172Z","iopub.status.idle":"2022-08-21T20:22:52.419824Z","shell.execute_reply.started":"2022-08-21T20:22:52.378128Z","shell.execute_reply":"2022-08-21T20:22:52.418821Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train.shape","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:52.421558Z","iopub.execute_input":"2022-08-21T20:22:52.421949Z","iopub.status.idle":"2022-08-21T20:22:52.428966Z","shell.execute_reply.started":"2022-08-21T20:22:52.421900Z","shell.execute_reply":"2022-08-21T20:22:52.427792Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"type(X)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:52.430422Z","iopub.execute_input":"2022-08-21T20:22:52.431430Z","iopub.status.idle":"2022-08-21T20:22:52.439229Z","shell.execute_reply.started":"2022-08-21T20:22:52.431396Z","shell.execute_reply":"2022-08-21T20:22:52.438102Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_augmentation = tf.keras.Sequential([\n    #preprocessing.RandomFlip('horizontal'),\n    preprocessing.RandomZoom(height_factor=(-0.2, 0.2)),\n    preprocessing.RandomContrast(0.4),\n    preprocessing.RandomTranslation(height_factor= (-0.2, 0.2), width_factor=(-0.2, 0.2)), \n    preprocessing.RandomRotation(factor= (-0.1, 0.1)),     #Giros entre -10%*2*pi y 10%*2*pi        \n    #preprocessing.RandomCrop(120, 120, seed=SEED)\n])\n\n#Se representa una imagen original de la muestra junto a algunas de sus posibles modificaciones\nplt.figure(figsize=(25,7))\nj = 1 #np.random.randint(0, N_DATOS)\nimg_orig = X[j]\nplt.subplot(2 , 6, 1)\nplt.xticks([])\nplt.yticks([])\nplt.xlabel('ORIGINAL. landmark_id: '+ str(y[j]), fontweight =\"bold\", fontsize=12)\nplt.imshow(img_orig)\n\nfor i in range(11):\n    img_mod = data_augmentation(img_orig)\n    plt.subplot(2 , 6, i+2)\n    plt.xticks([])\n    plt.yticks([])\n    plt.xlabel('Modificación '+str(i+1), fontweight =\"bold\", fontsize=12)\n    plt.imshow(img_mod)\n    \nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-08-21T20:22:52.441198Z","iopub.execute_input":"2022-08-21T20:22:52.441534Z","iopub.status.idle":"2022-08-21T20:22:56.274612Z","shell.execute_reply.started":"2022-08-21T20:22:52.441501Z","shell.execute_reply":"2022-08-21T20:22:56.273816Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.shape(y_train)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:56.276174Z","iopub.execute_input":"2022-08-21T20:22:56.276759Z","iopub.status.idle":"2022-08-21T20:22:56.283015Z","shell.execute_reply.started":"2022-08-21T20:22:56.276725Z","shell.execute_reply":"2022-08-21T20:22:56.282211Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.shape(X_train)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:56.284356Z","iopub.execute_input":"2022-08-21T20:22:56.285082Z","iopub.status.idle":"2022-08-21T20:22:56.293591Z","shell.execute_reply.started":"2022-08-21T20:22:56.285044Z","shell.execute_reply":"2022-08-21T20:22:56.292456Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### OVERSAMPLING de datos de entrenamiento","metadata":{}},{"cell_type":"code","source":"N_CLASES","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:56.295254Z","iopub.execute_input":"2022-08-21T20:22:56.295946Z","iopub.status.idle":"2022-08-21T20:22:56.302895Z","shell.execute_reply.started":"2022-08-21T20:22:56.295894Z","shell.execute_reply":"2022-08-21T20:22:56.301988Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"start_time = time.time()\n\nUMBRAL_OVERSAMPLING = 0.2 * UMBRAL_UNDERSAMPLING       #PORCENTAJE DEL UMBRAL_UNDERSAMPLING HASTA EL QUE SE AUMENTA\ni=0; n=0; k=0\n\nfor i in range(N_CLASES):     #Número de clases únicas\n    cont=0\n    for n in range(len(y_train)):\n        if y_train[n] == i:\n            cont = cont+1\n                  \n    if cont < UMBRAL_OVERSAMPLING:\n        img_clase_i = X_train[y_train==i]\n        for k in range(int(UMBRAL_OVERSAMPLING-cont)):\n            X_train = np.concatenate((X_train,np.array([(img_clase_i[np.random.randint(len(img_clase_i))])])),axis = 0)\n            y_train = np.append(y_train, i)\n\nprint('\\nDuración del oversampling: %s segundos' % (time.time() - start_time))\nn_datos_train_def = len(X_train)\nprint('\\nDatos de entrenamiento tras oversampling: '+str(n_datos_train_def)+' datos')\nprint('\\nLos datos de entrenamiento han pasado de: '+str(n_datos_entrenamiento)+' a:'+ str(n_datos_train_def))","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:22:56.304579Z","iopub.execute_input":"2022-08-21T20:22:56.305321Z","iopub.status.idle":"2022-08-21T20:23:17.839244Z","shell.execute_reply.started":"2022-08-21T20:22:56.305281Z","shell.execute_reply":"2022-08-21T20:23:17.837338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# X_train con oversampling\nplt.figure(2, figsize = (22, 5))\nplt.title('Histograma de X_train tras OVERSAMPLING', fontweight = \"bold\")\nplt.hist(LE.inverse_transform(y_train), color = 'blue', bins = CLASE_MAX - CLASE_MIN+1, histtype= 'stepfilled')\nplt.xlabel('X_train')\nplt.ylim([0,1.2*UMBRAL_UNDERSAMPLING])\nplt.axhline(y=UMBRAL_OVERSAMPLING, color='g', linestyle='--', label= 'Umbral Oversampling')      #Línea horizontal indicando umbral Oversampling\nplt.axhline(y=UMBRAL_UNDERSAMPLING, color='r', linestyle='--', label= 'Umbral Undersampling')      #Línea horizontal indicando umbral Undersampling\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:23:17.840620Z","iopub.execute_input":"2022-08-21T20:23:17.841083Z","iopub.status.idle":"2022-08-21T20:23:18.063359Z","shell.execute_reply.started":"2022-08-21T20:23:17.841046Z","shell.execute_reply":"2022-08-21T20:23:18.062455Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('ELIMINANDO ' + str(round((get_size(X)/(1024*1024)),4)) +' MB ocupados por X')\ndel X         #Elimina la relación entre la variable y la memoria a la que apunta\ngc.collect();        #Elimina de memoria y devuelve los objetos a los que ya no se apunta","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:23:18.064777Z","iopub.execute_input":"2022-08-21T20:23:18.065124Z","iopub.status.idle":"2022-08-21T20:23:18.241977Z","shell.execute_reply.started":"2022-08-21T20:23:18.065091Z","shell.execute_reply":"2022-08-21T20:23:18.240784Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('ELIMINANDO ' + str(round((get_size(y_LE)/(1024*1024)),4)) +' MB ocupados por y_LE')\ndel y_LE        #Elimina la relación entre la variable y la memoria a la que apunta\ngc.collect();       #Elimina de memoria y devuelve los objetos a los que ya no se apunta","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:23:18.243739Z","iopub.execute_input":"2022-08-21T20:23:18.244720Z","iopub.status.idle":"2022-08-21T20:23:18.403176Z","shell.execute_reply.started":"2022-08-21T20:23:18.244692Z","shell.execute_reply":"2022-08-21T20:23:18.402161Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('ELIMINANDO ' + str(round((get_size(y)/(1024*1024)),4)) +' MB ocupados por y')\ndel y        #Elimina la relación entre la variable y la memoria a la que apunta\ngc.collect();       #Elimina de memoria y devuelve los objetos a los que ya no se apunta","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:23:18.404625Z","iopub.execute_input":"2022-08-21T20:23:18.405169Z","iopub.status.idle":"2022-08-21T20:23:18.565974Z","shell.execute_reply.started":"2022-08-21T20:23:18.405133Z","shell.execute_reply":"2022-08-21T20:23:18.564568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"&nbsp;\n&nbsp;\n&nbsp;\n\n# **HIPERPARÁMETROS DEL MODELO**","metadata":{}},{"cell_type":"code","source":"#Hiperparámetros de la red neuronal convolucional\n\nkernelSize = (3,3)        #Tamaño de la plantilla de convolución\npaddingType = 'same'      #Cómo se procede en los bordes de las imágenes ('same' o 'valid')\nactivationF = 'relu'      #Función de activación\npoolSize = (2,2)          #Tamaño de la plantilla de maximum pooling\nstridesSize = (2,2)       #Desplazamiento de plantilla durante maximum pooling\ndropoutRate = 0.5         #Porcentaje de neuronas que se desactivan con la capa Dropout\nbatchSize = 256           #Cantidad de datos con los que se entrena en cada época\nepochsSize= 2000          #Número de épocas en las que se entrena\nlr = 0.01                 #Learning Rate\nweightDecay = regularizers.L2(0.01) #Regularización de pesos ---> L1: Suma pesos absolutos. \n                          #L2: Suma pesos cuadrados. L1L2: Suma pesos absolutos y cuadrados","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:23:18.568223Z","iopub.execute_input":"2022-08-21T20:23:18.568637Z","iopub.status.idle":"2022-08-21T20:23:18.576759Z","shell.execute_reply.started":"2022-08-21T20:23:18.568601Z","shell.execute_reply":"2022-08-21T20:23:18.575600Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"&nbsp;\n&nbsp;\n&nbsp;\n\n# **FUNCIÓN PARA CREACIÓN, COMPILACIÓN Y ENTRENAMIENTO DEL MODELO**","metadata":{}},{"cell_type":"code","source":"def crear_modelo():\n    \n    ResNet50 = (keras.applications.ResNet50(include_top=False, \n                weights='imagenet', input_shape=([IMG_SIZE, IMG_SIZE, 3])))\n    \n    ResNet50.trainable=False\n        \n    model = keras.Sequential()\n    \n    model.add(preprocessing.RandomZoom(height_factor=(-0.2, 0.2)))\n    model.add(preprocessing.RandomContrast(0.4))\n    model.add(preprocessing.RandomTranslation(height_factor= (-0.2, 0.2), width_factor=(-0.2, 0.2))) \n    model.add(preprocessing.RandomRotation(factor= (-0.1, 0.1)))\n    \n    model.add(ResNet50)\n                 \n    model.add(layers.Flatten())\n    model.add(layers.Dense(units = 512, activation=activationF, kernel_regularizer=weightDecay))\n    model.add(layers.Dropout(rate=dropoutRate,seed=SEED))\n    model.add(layers.BatchNormalization())\n    model.add(layers.Dense(units = 512, activation=activationF, kernel_regularizer=weightDecay))\n    model.add(layers.Dropout(rate=dropoutRate,seed=SEED))\n    model.add(layers.BatchNormalization())\n    model.add(layers.Dense(units = N_CLASES, activation='softmax'))\n    \n    \n    #OPTIMIZADORES\n    # A menor lr, menos cambios repentinos hay en las métricas como acuracy\n    opt1 = tf.keras.optimizers.RMSprop(learning_rate=lr, rho=0.9, momentum=0.5, epsilon=1e-07)   \n    opt2 = tf.keras.optimizers.Adam(learning_rate=lr, beta_1=0.9, beta_2=0.999, epsilon=1e-07)\n    opt3 = tf.keras.optimizers.SGD(learning_rate=lr, momentum=0.9, nesterov=False)                 #momentum--> acelera gradiente y amortigua oscilaciones\n    \n    #Compilación del modelo   \n    model.compile(\n        optimizer = opt3,\n        loss = 'sparse_categorical_crossentropy',\n        metrics = ['sparse_categorical_accuracy']\n    )\n    \n    #Callback 1\n    early_stopping = EarlyStopping(\n        monitor = \"val_loss\",\n        mode = \"auto\",\n        min_delta = 0.0001,         # minimium amount of change to count as an improvement\n        patience = 150,              # how many epochs to wait before stopping\n        restore_best_weights = True)\n    \n    #Callback 2\n    reduce_lr = ReduceLROnPlateau(\n        monitor='val_loss', factor=0.7, \n        patience=40, cooldown=1, min_lr=0.0005,\n        min_delta=0.001, verbose=1)\n    \n    #Callback 3\n    checkpoint = ModelCheckpoint(\n        'best-weights.h5', monitor='val_loss', \n        save_best_only=True, save_weights_only=True)\n    \n    \n    #Entrenamiento del modelo\n    history = model.fit(\n        X_train, y_train,\n        validation_data = (X_val, y_val),      #LAS ESTIQUETAS ESTÁN con CODIFICACIÓN LABEL ENCODING\n        class_weight = dic_class_weights,      #Para solucionar Imbalanced Data (similar a Oversampling)\n        shuffle = True,                        #Solo afecta a los datos de entrenamiento (1 vez al principio)\n        batch_size = batchSize,\n        steps_per_epoch = len(X_train)//batchSize,\n        epochs = epochsSize,\n        callbacks = [early_stopping, reduce_lr, checkpoint],\n        verbose=1,            # 0: silencio     1: barra de progreso + texto      2: solo texto\n        #use_multiprocessing=True,\n        #max_queue_size = 15,        #Default = 10\n        #workers = 32,\n    ) \n  \n    return model, history","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:23:18.578384Z","iopub.execute_input":"2022-08-21T20:23:18.579136Z","iopub.status.idle":"2022-08-21T20:23:18.604976Z","shell.execute_reply.started":"2022-08-21T20:23:18.579100Z","shell.execute_reply":"2022-08-21T20:23:18.603980Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"&nbsp;\n&nbsp;\n&nbsp;\n\n# **GRÁFICAS DE PÉRDIDA Y PRECISIÓN Y EVALUACIÓN DEL MODELO**","metadata":{}},{"cell_type":"code","source":"# Cálculo de pesos de cada clase de los datos para entrenamiento de la muestra\n_, freq = np.unique(y_train, return_counts=True)\nmax_freq = np.max(freq)\nprint ('Mayor frecuencia: '+str(np.max(freq)))\n\n##Método no funciona correctamente con este set debido a la numeración de landmark_id\n##from sklearn.utils import class_weight\n##classWeights = class_weight.compute_class_weight(class_weight ='balanced',classes = np.unique(y_train), y = y_train)\n##train_classWeights = dict(enumerate(classWeights))\n\n#Se realiza este procedimiento porque con el método compute_class_weight no funciona --> Las keys del diccionario deben coincidir con las etiquetas\ndic_class_weights ={}\ni=0\nfor i in range(max(y_train)+1):                   #Se va a crear un diccionario de max(y_train)+1 elementos, aunque el número de clases sea menor\n    dic_class_weights[i] = 0                      #Inicialmente todos los pesos (valores del diccionario) a 0\n    if i in y_train:                              #Si la clave coincide con el landmark_id (etiqueta) el peso no será 0\n        freq = len(y_train[y_train == i])          #Frecuencia de la etiqueta i\n        dic_class_weights[i] = max_freq/freq","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:23:18.607156Z","iopub.execute_input":"2022-08-21T20:23:18.608086Z","iopub.status.idle":"2022-08-21T20:23:18.622467Z","shell.execute_reply.started":"2022-08-21T20:23:18.608040Z","shell.execute_reply":"2022-08-21T20:23:18.621303Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"start_time = time.time()\n\nmodel, history = crear_modelo()\n    \nhistory_df = pd.DataFrame(history.history)    \n    \nprint('\\nbatchSize = '+str(batchSize))\n    \nplt.figure(figsize=(15,5))        #Anchura y Altura de las gráficas, respectivamente\n    \nplt.subplot(1,2,1)\n#history_df.loc[0:, ['loss', 'val_loss']].plot()             #Utilizar dataframe y su método plot dan problemas con plt.subplot\nplt.plot(history.history['loss'], label='train')        \nplt.plot(history.history['val_loss'], label='test')\nplt.legend()\nplt.title('Loss and Validation Loss')\nplt.xlabel('batchSize = '+str(batchSize))\nprint((\"Minimum Validation Loss: {:0.4f} in epoch {:0.0f} \").format(history_df['val_loss'].min(), history_df['val_loss'].idxmin()))            \n    \nplt.subplot(1,2,2)\n#history_df.loc[0:, ['accuracy', 'val_accuracy']].plot()\nplt.plot(history.history['sparse_categorical_accuracy'], label='train')\nplt.plot(history.history['val_sparse_categorical_accuracy'], label='test')\nplt.legend()\nplt.title('Accuracy and Validation Accuracy')\nplt.xlabel('batchSize = '+str(batchSize))\nprint((\"Maximum Validation Accuracy: {:0.4f} in epoch {:0.0f} \").format(history_df['val_sparse_categorical_accuracy'].max(), history_df['val_sparse_categorical_accuracy'].idxmax()))\n\nprint(\"\\nEvaluación del modelo con datos de entrenamiento\")\nscore = model.evaluate(X_train, y_train)\nprint(\"Test loss, Test accuracy:\", score[0], score[1])\n\nprint(\"\\nEvaluación del modelo con datos de validación\")\nscore = model.evaluate(X_val, y_val)\nprint(\"Test loss, Test accuracy:\", score[0], score[1])\n\nplt.show()    #Se muestran las gráficas\n    \nprint('\\nDuración del entrenamiento: %s minutos' % ((time.time() - start_time)/60))","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:23:18.624527Z","iopub.execute_input":"2022-08-21T20:23:18.625288Z","iopub.status.idle":"2022-08-21T20:32:00.288505Z","shell.execute_reply.started":"2022-08-21T20:23:18.625244Z","shell.execute_reply":"2022-08-21T20:32:00.287590Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:00.290054Z","iopub.execute_input":"2022-08-21T20:32:00.290404Z","iopub.status.idle":"2022-08-21T20:32:00.305399Z","shell.execute_reply.started":"2022-08-21T20:32:00.290370Z","shell.execute_reply":"2022-08-21T20:32:00.304298Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Cargar al modelo los mejores pesos (según val_loss)","metadata":{}},{"cell_type":"code","source":"model.load_weights('best-weights.h5')\nprint('Mejores pesos cargados al modelo')","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:00.306902Z","iopub.execute_input":"2022-08-21T20:32:00.307886Z","iopub.status.idle":"2022-08-21T20:32:00.703855Z","shell.execute_reply.started":"2022-08-21T20:32:00.307850Z","shell.execute_reply":"2022-08-21T20:32:00.702913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#model.get_weights()","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:00.705309Z","iopub.execute_input":"2022-08-21T20:32:00.705673Z","iopub.status.idle":"2022-08-21T20:32:00.711046Z","shell.execute_reply.started":"2022-08-21T20:32:00.705628Z","shell.execute_reply":"2022-08-21T20:32:00.709978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Guardado del modelo completo\n\n#-------model.save('./MyModel_h5',save_format='h5')  \n#model.save('./MyModel_tf',save_format='tf')\n\n#Guardado de pesos del modelo\n#-----model.save_weights('./Model_Weights_h5', save_format='h5')","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:00.712525Z","iopub.execute_input":"2022-08-21T20:32:00.713566Z","iopub.status.idle":"2022-08-21T20:32:00.719460Z","shell.execute_reply.started":"2022-08-21T20:32:00.713530Z","shell.execute_reply":"2022-08-21T20:32:00.718378Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Cargado de un modelo guardado\n\n#---model_cargado = tf.keras.models.load_model('./MyModel_h5')","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:00.721269Z","iopub.execute_input":"2022-08-21T20:32:00.721619Z","iopub.status.idle":"2022-08-21T20:32:00.731280Z","shell.execute_reply.started":"2022-08-21T20:32:00.721585Z","shell.execute_reply":"2022-08-21T20:32:00.730375Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"'''\n#En caso de que sea necesario borrar algún archivo en el directorio de salida\n\nfilename = ''\nimport os\nos.remove(filename)\n'''","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:00.733024Z","iopub.execute_input":"2022-08-21T20:32:00.733394Z","iopub.status.idle":"2022-08-21T20:32:00.743523Z","shell.execute_reply.started":"2022-08-21T20:32:00.733362Z","shell.execute_reply":"2022-08-21T20:32:00.742527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"'''\n#En caso de que sea necesario borrar algún directorio en el directorio de salida\ndirectory = ''\nimport shutil\nshutil.rmtree(directory)\n'''","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:00.745139Z","iopub.execute_input":"2022-08-21T20:32:00.745563Z","iopub.status.idle":"2022-08-21T20:32:00.753623Z","shell.execute_reply.started":"2022-08-21T20:32:00.745528Z","shell.execute_reply":"2022-08-21T20:32:00.752589Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#Reentrenar el modelo\n\nmodel_cargado.fit(\n        X_train, y_train,\n        validation_data= (X_val, y_val),\n        shuffle = True,\n        batch_size=batchSize,\n        epochs=epochsSize,\n        callbacks=[early_stopping],\n        verbose=1,    # 0: silencio     1: barra de progreso + texto      2: solo texto)\n)","metadata":{"execution":{"iopub.status.busy":"2022-04-26T15:31:16.797454Z","iopub.execute_input":"2022-04-26T15:31:16.798021Z","iopub.status.idle":"2022-04-26T15:31:16.930053Z","shell.execute_reply.started":"2022-04-26T15:31:16.797933Z","shell.execute_reply":"2022-04-26T15:31:16.927279Z"}}},{"cell_type":"markdown","source":"&nbsp;\n&nbsp;\n&nbsp;\n\n# **PREDICCIÓN DE LOS DATOS DE TESTEO DEL SPLIT**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(25,7))\n\nfor i in range(12):  \n    img = X_test[i]  #Ya se hizo el shuffle con el split\n    plt.subplot(2 , 6, i+1)\n    plt.xticks([])\n    plt.yticks([])\n    plt.xlabel('Clase: por determinar')\n    plt.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:00.755765Z","iopub.execute_input":"2022-08-21T20:32:00.756211Z","iopub.status.idle":"2022-08-21T20:32:01.326789Z","shell.execute_reply.started":"2022-08-21T20:32:00.756177Z","shell.execute_reply":"2022-08-21T20:32:01.325956Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.shape(X_test)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:01.328227Z","iopub.execute_input":"2022-08-21T20:32:01.328827Z","iopub.status.idle":"2022-08-21T20:32:01.335553Z","shell.execute_reply.started":"2022-08-21T20:32:01.328777Z","shell.execute_reply":"2022-08-21T20:32:01.334575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(25,7))\n\nfor i in range(12):  \n    img = X_test_orig[i]  #Ya se hizo el shuffle con el split\n    plt.subplot(2 , 6, i+1)\n    plt.xticks([])\n    plt.yticks([])\n    plt.xlabel('Clase: por determinar')\n    plt.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:01.337331Z","iopub.execute_input":"2022-08-21T20:32:01.337738Z","iopub.status.idle":"2022-08-21T20:32:02.020224Z","shell.execute_reply.started":"2022-08-21T20:32:01.337693Z","shell.execute_reply":"2022-08-21T20:32:02.019391Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predic = model.predict(X_test, verbose=1)       # batch_size=None,        #Se realiza la predicción","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:02.021472Z","iopub.execute_input":"2022-08-21T20:32:02.022565Z","iopub.status.idle":"2022-08-21T20:32:03.157898Z","shell.execute_reply.started":"2022-08-21T20:32:02.022511Z","shell.execute_reply":"2022-08-21T20:32:03.156814Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = []\nconfianza = []\n\nfor i in range(len(predic)):\n    y_pred.append(np.argmax(predic[i]))                 #Clase (landmark_id) con mayor probabilidad\n    confianza.append(predic[i][y_pred[i]].round(2))                            #Probabilidad de la clase con mayor probabilidad\n    \ny_pred = LE.inverse_transform(y_pred)\ny_pred","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:03.159463Z","iopub.execute_input":"2022-08-21T20:32:03.159907Z","iopub.status.idle":"2022-08-21T20:32:03.170305Z","shell.execute_reply.started":"2022-08-21T20:32:03.159872Z","shell.execute_reply":"2022-08-21T20:32:03.169217Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"\\nEvaluación del modelo con datos de testeo\")\nscore = model.evaluate(X_test, y_test)      #Al pasar X_test devuelve las etiquetas con Label Encoding\nprint(\"Test loss, Test accuracy:\", score[0], score[1])","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:03.171976Z","iopub.execute_input":"2022-08-21T20:32:03.172838Z","iopub.status.idle":"2022-08-21T20:32:03.250700Z","shell.execute_reply.started":"2022-08-21T20:32:03.172803Z","shell.execute_reply":"2022-08-21T20:32:03.249764Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_test = LE.inverse_transform(y_test)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:03.252149Z","iopub.execute_input":"2022-08-21T20:32:03.252477Z","iopub.status.idle":"2022-08-21T20:32:03.259056Z","shell.execute_reply.started":"2022-08-21T20:32:03.252442Z","shell.execute_reply":"2022-08-21T20:32:03.257015Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Leer de nuevo el dataset de entrenamiento pues se eliminó de la memoria\ntraindf = load_traindf()","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:03.261146Z","iopub.execute_input":"2022-08-21T20:32:03.261418Z","iopub.status.idle":"2022-08-21T20:32:10.167607Z","shell.execute_reply.started":"2022-08-21T20:32:03.261394Z","shell.execute_reply":"2022-08-21T20:32:10.166621Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"col = 5       #Número de columnas del subplot (teniendo en cuenta la propia imagen a predecir)\nn_pred_rep = 30       #Numero de predicciones a representar\n\nk=0\nfor k in range(n_pred_rep):\n    plt.figure(figsize=(16,7))\n    img_pred = X_test_orig[k]\n    plt.subplot(1, col, 1)\n    plt.xticks([])\n    plt.yticks([])\n    plt.title('Imagen a predecir nº '+ str(k))\n    str1 = 'Clase predicha: ' + str(y_pred[k])\n    str2 = 'Confianza: ' + str(confianza[k])\n    str3 = 'Clase real: ' + str(y_test[k])\n    plt.xlabel(str1 + '\\n' + str2 + '\\n' + str3, fontsize = 12, weight = 'bold')             #Para imprimir en 3 líneas distintas\n    plt.imshow(img_pred)\n    \n    i=0\n    img_clase_df = traindf[traindf['landmark_id']==y_pred[k]]            #Dataframe con imágenes de igual 'landmark_id' que la predicción\n    \n    for i in range(len(img_clase_df)):\n        if i < (col-1): \n            img_clase_path = img_clase_df.iloc[i,2] \n            img_clase = img_read_resize(img_clase_path)\n            plt.subplot(1, col, i+2)\n            plt.xticks([])\n            plt.yticks([])\n            plt.title('Imagen de la clase '+ str(y_pred[k]))\n            plt.xlabel(str())\n            plt.imshow(img_clase)\n        else:\n            break;","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:10.169020Z","iopub.execute_input":"2022-08-21T20:32:10.169395Z","iopub.status.idle":"2022-08-21T20:32:16.771346Z","shell.execute_reply.started":"2022-08-21T20:32:10.169360Z","shell.execute_reply":"2022-08-21T20:32:16.769996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"&nbsp;\n&nbsp;\n&nbsp;\n\n# **MATRIZ DE CONFUSIÓN**","metadata":{}},{"cell_type":"code","source":"clases_usadas = np.append(np.unique(y_test), np.unique(y_pred))    #Todas las clases usadas en predicción y testeo (algunas repetidas)\nclases_unicas_usadas = np.unique(clases_usadas)                    #Se eliminan las repetidas y se ordenan de menor a mayor\nclases_unicas_usadas","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:36:45.523031Z","iopub.execute_input":"2022-08-21T20:36:45.523742Z","iopub.status.idle":"2022-08-21T20:36:45.532482Z","shell.execute_reply.started":"2022-08-21T20:36:45.523708Z","shell.execute_reply":"2022-08-21T20:36:45.531245Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cm = confusion_matrix(y_test, y_pred)  #Número de filas y columnas = número de clases distintas usadas tanto en y_test como y_pred (orden menor a mayor)\n\ndf_mat_conf = pd.DataFrame(cm, columns=clases_unicas_usadas, index=clases_unicas_usadas)\ndf_mat_conf","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:36:47.025938Z","iopub.execute_input":"2022-08-21T20:36:47.026622Z","iopub.status.idle":"2022-08-21T20:36:47.045102Z","shell.execute_reply.started":"2022-08-21T20:36:47.026588Z","shell.execute_reply":"2022-08-21T20:36:47.043959Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"figure = plt.figure(figsize=(18, 13))\nplt.title(\"MATRIZ DE CONFUSIÓN\", fontsize=16, fontweight='bold')\n\ns=sns.heatmap(df_mat_conf, annot=True, cmap='Blues', fmt=\"d\")\n\nplt.tight_layout()\nplt.xlabel(\"Clase predicha\", fontsize=16, fontweight='bold')\nplt.ylabel(\"Clase real\", fontsize=16, fontweight='bold')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:36:48.708434Z","iopub.execute_input":"2022-08-21T20:36:48.708878Z","iopub.status.idle":"2022-08-21T20:36:49.614885Z","shell.execute_reply.started":"2022-08-21T20:36:48.708840Z","shell.execute_reply":"2022-08-21T20:36:49.613876Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"figure = plt.figure(figsize=(18, 13))\nplt.title(\"MATRIZ DE CONFUSIÓN\", fontsize=16, fontweight='bold')\n\ns=sns.heatmap(df_mat_conf, annot=False, cmap='Blues', fmt=\"d\")\n\nplt.tight_layout()\nplt.xlabel(\"Clase predicha\", fontsize=16, fontweight='bold')\nplt.ylabel(\"Clase real\", fontsize=16, fontweight='bold')\nplt.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"&nbsp;\n&nbsp;\n&nbsp;\n\n# **PREDICCIÓN DE LOS DATOS DE TESTEO de COMPETICIÓN**","metadata":{}},{"cell_type":"markdown","source":"### Carga del dataset de testeo y representación de su contenido","metadata":{}},{"cell_type":"code","source":"mainpath_test = '../input/landmark-recognition-2021/test'\n\nsample_subm = pd.read_csv('../input/landmark-recognition-2021/sample_submission.csv')         #Leer archivo .csv con imágenes a clasificar\n\nplt.figure(figsize=(25,7))\n\nfor i in range(12):\n    img_id = sample_subm['id'][i]\n    img_path = os.path.join(mainpath_test, img_id[0], img_id[1], img_id[2], img_id + '.jpg')\n    img = img_read_resize(img_path)  #Se usa la función previamente definida para lograr el mismo tamaño que las imágenes de entrenamiento\n    plt.subplot(2 , 6, i+1)\n    plt.xticks([])\n    plt.yticks([])\n    plt.xlabel('Clase: por determinar')\n    plt.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:16.779212Z","iopub.status.idle":"2022-08-21T20:32:16.780009Z","shell.execute_reply.started":"2022-08-21T20:32:16.779739Z","shell.execute_reply":"2022-08-21T20:32:16.779764Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Ajuste de datos y predicción","metadata":{}},{"cell_type":"code","source":"X_pred = []\nX_pred_copia = []\nconfianza = []\n\n#Se rellena una lista con las imágenes de testeo redimensionadas que se vayan a predecir\n\nelem_a_predecir = 30\n\nfor i in range(elem_a_predecir): \n    img_id = sample_subm['id'][i]\n    img_path = os.path.join(mainpath_test, img_id[0], img_id[1], img_id[2], img_id + '.jpg')\n    img = img_read_resize(img_path)               #Se usa la función previamente definida para lograr el mismo tamaño que las imágenes de entrenamiento\n    X_pred.append(img)                        \n\nX_pred_copia = X_pred                            #Copia de las imágenes de testeo redimensionadas y sin normalizar\nX_pred = np.array(X_pred)                        #/255   #Normalización de las imágenes de testeo redimensionadas\n\nX_pred = preprocess_input(X_pred)\n\npredic = model.predict(X_pred, verbose=1)       # batch_size=None,        #Se realiza la predicción","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:16.781403Z","iopub.status.idle":"2022-08-21T20:32:16.782218Z","shell.execute_reply.started":"2022-08-21T20:32:16.781905Z","shell.execute_reply":"2022-08-21T20:32:16.781946Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_subm.head()      #Archivo .csv antes de introducir resultados","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:16.783857Z","iopub.status.idle":"2022-08-21T20:32:16.784736Z","shell.execute_reply.started":"2022-08-21T20:32:16.784443Z","shell.execute_reply":"2022-08-21T20:32:16.784469Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = []\n\nfor i in range(len(predic)):\n    y_pred.append(np.argmax(predic[i]))                #Clase (landmark_id) con mayor probabilidad\n    confianza.append(predic[i][y_pred[i]].round(2))    #Probabilidad de la clase con mayor probabilidad\n    \ny_pred = LE.inverse_transform(y_pred)\n    \nfor i in range(len(predic)):\n    sample_subm['landmarks'][i] = str(y_pred[i]) +' '+ str(confianza[i])       #Se añaden los resultados al archivo .csv","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:16.786195Z","iopub.status.idle":"2022-08-21T20:32:16.786970Z","shell.execute_reply.started":"2022-08-21T20:32:16.786699Z","shell.execute_reply":"2022-08-21T20:32:16.786724Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(X_pred_copia[1])","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:16.788351Z","iopub.status.idle":"2022-08-21T20:32:16.789130Z","shell.execute_reply.started":"2022-08-21T20:32:16.788857Z","shell.execute_reply":"2022-08-21T20:32:16.788881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_subm.head()         #Archivo .csv después de introducir los resultados","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:16.790517Z","iopub.status.idle":"2022-08-21T20:32:16.791296Z","shell.execute_reply.started":"2022-08-21T20:32:16.791036Z","shell.execute_reply":"2022-08-21T20:32:16.791062Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Representación visual de los resultados","metadata":{}},{"cell_type":"code","source":"#Leer de nuevo el dataset de entrenamiento pues se eliminó de la memoria\ntraindf = load_traindf()","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:16.792703Z","iopub.status.idle":"2022-08-21T20:32:16.793504Z","shell.execute_reply.started":"2022-08-21T20:32:16.793216Z","shell.execute_reply":"2022-08-21T20:32:16.793240Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"col = 5       #Número de columnas del subplot (teniendo en cuenta la propia imagen a predecir)\n\nk=0\nfor k in range(elem_a_predecir):\n    plt.figure(figsize=(16,7))\n    img_pred = X_pred_copia[k]      #Cualquier imagen que se predijo anteriormente (ya está redimensionada)\n    plt.subplot(1, col, 1)\n    plt.xticks([])\n    plt.yticks([])\n    plt.title('Imagen a predecir nº '+ str(k))\n    str1 = 'Clase predicha: ' + str(y_pred[k]) \n    str2 = 'Confianza: ' + str(confianza[k])\n    plt.xlabel(str1 + '\\n' + str2, fontsize = 12, weight = 'bold')             #Para imprimir en 2 líneas distintas\n    plt.imshow(img_pred)\n    \n    i=0\n    img_clase_df = traindf[traindf['landmark_id']==y_pred[k]]            #Dataframe con imágenes de igual 'landmark_id' que la predicción\n    \n    for i in range(len(img_clase_df)):\n        if i < (col-1): \n            img_clase_path = img_clase_df.iloc[i,2] \n            img_clase = img_read_resize(img_clase_path)\n            plt.subplot(1, col, i+2)\n            plt.xticks([])\n            plt.yticks([])\n            plt.title('Imagen de la clase '+ str(y_pred[k]))\n            plt.xlabel(str())\n            plt.imshow(img_clase)\n        else:\n            break;","metadata":{"execution":{"iopub.status.busy":"2022-08-21T20:32:16.795082Z","iopub.status.idle":"2022-08-21T20:32:16.795857Z","shell.execute_reply.started":"2022-08-21T20:32:16.795588Z","shell.execute_reply":"2022-08-21T20:32:16.795612Z"},"trusted":true},"execution_count":null,"outputs":[]}]}