{"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":"# Trabajo Practico Nuevas Tecnologías\n\n**Grupo:** \n- La Torre, Gabriel (padrón 87796)\n- Pineda, Armando Facundo (padrón 85939)\n","metadata":{}},{"cell_type":"markdown","source":"## Competencia\nhttps://www.kaggle.com/competitions/histopathologic-cancer-detection\n\n## Link al dataset\n\nhttps://www.kaggle.com/competitions/histopathologic-cancer-detection/data\n\n## Link al notebook en Kaggle\nhttps://www.kaggle.com/code/fapifiuba/tecnologias-emergentes-detecci-n-de-c-ncer","metadata":{}},{"cell_type":"markdown","source":"# Link al notebook en kaggle","metadata":{}},{"cell_type":"markdown","source":"# Importando librerías","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport numpy as np\nimport tensorflow as tf\nfrom tensorflow import keras\n\nimport matplotlib.pyplot as plt\nfrom skimage.io import imread #read images from files\nimport matplotlib.patches as patches\nfrom PIL import Image\n\nimport cv2","metadata":{"collapsed":false,"pycharm":{"name":"#%%\n","is_executing":false},"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2022-12-23T18:39:52.707196Z","iopub.execute_input":"2022-12-23T18:39:52.708686Z","iopub.status.idle":"2022-12-23T18:39:52.716238Z","shell.execute_reply.started":"2022-12-23T18:39:52.708638Z","shell.execute_reply":"2022-12-23T18:39:52.715267Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Mostramos las versiones de las librerías que usamos","metadata":{"_kg_hide-input":true}},{"cell_type":"code","source":"print(f'Pandas Version: {pd.__version__}')\n#NUMPY\nnp.set_printoptions(suppress=True)\n# En produccion eliminar, se incluye por informacion\nprint(f'Numpy version: {np.__version__}')\n\nimport matplotlib\nprint(f'Matplotlib version: {matplotlib.__version__}')\n\nimport matplotlib.pyplot as plt\n%matplotlib inline\nplt.rcParams[\"figure.figsize\"] = (15,7)\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:39:52.718093Z","iopub.execute_input":"2022-12-23T18:39:52.718660Z","iopub.status.idle":"2022-12-23T18:39:52.739924Z","shell.execute_reply.started":"2022-12-23T18:39:52.718626Z","shell.execute_reply":"2022-12-23T18:39:52.738440Z"},"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Revisando los labels de train","metadata":{}},{"cell_type":"code","source":"df = pd.read_csv('../input/histopathologic-cancer-detection/train_labels.csv')\n\ndf['label'].value_counts()","metadata":{"collapsed":false,"pycharm":{"name":"#%%\n","is_executing":false},"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2022-12-23T18:39:52.742264Z","iopub.execute_input":"2022-12-23T18:39:52.743065Z","iopub.status.idle":"2022-12-23T18:39:53.048176Z","shell.execute_reply.started":"2022-12-23T18:39:52.743017Z","shell.execute_reply":"2022-12-23T18:39:53.046924Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.info()","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:39:53.051172Z","iopub.execute_input":"2022-12-23T18:39:53.051588Z","iopub.status.idle":"2022-12-23T18:39:53.078955Z","shell.execute_reply.started":"2022-12-23T18:39:53.051555Z","shell.execute_reply":"2022-12-23T18:39:53.077093Z"},"_kg_hide-input":false,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Set de datos\n\nMe quedo solo con 10000 filas para que el procesamiento de esto sea más rápido","metadata":{}},{"cell_type":"code","source":"df = df.sample(10000)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:39:53.080543Z","iopub.execute_input":"2022-12-23T18:39:53.080877Z","iopub.status.idle":"2022-12-23T18:39:53.099448Z","shell.execute_reply.started":"2022-12-23T18:39:53.080846Z","shell.execute_reply":"2022-12-23T18:39:53.098257Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## ¿Cuántos casos positivos y negativos me quedaron entonces?","metadata":{}},{"cell_type":"code","source":"df['label'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2022-12-23T20:48:59.847574Z","iopub.execute_input":"2022-12-23T20:48:59.848796Z","iopub.status.idle":"2022-12-23T20:48:59.858818Z","shell.execute_reply.started":"2022-12-23T20:48:59.848755Z","shell.execute_reply":"2022-12-23T20:48:59.857435Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cancer_positive = df[df[\"label\"] == 1].sample(5)['id']\n\n\ncancer_negative = df[df[\"label\"] == 0].sample(5)['id']\n","metadata":{"collapsed":false,"pycharm":{"name":"#%%\n","is_executing":false},"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2022-12-23T18:39:53.100975Z","iopub.execute_input":"2022-12-23T18:39:53.101355Z","iopub.status.idle":"2022-12-23T18:39:53.111962Z","shell.execute_reply.started":"2022-12-23T18:39:53.101323Z","shell.execute_reply":"2022-12-23T18:39:53.111009Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Manipulación de las imágenes:\nEs preciso manipular el nombre de las imágenes obtenidas para poderlas analizar, y aqui debajo comienzan distintos procesos:\n- adaptar el formato de su informacion a RGB,\n- adaptar el nombre para que el codigo las pueda encontrar,\n- realizar un muestreo por pantalla para comprobar que todo esta bien cargad.","metadata":{}},{"cell_type":"code","source":"def readImage(path):\n    # OpenCV reads the image in bgr format by default\n    bgr_img = cv2.imread(path)\n    # We flip it to rgb for visualization purposes\n    b,g,r = cv2.split(bgr_img)\n    rgb_img = cv2.merge([r,g,b])\n    return rgb_img\n\n","metadata":{"collapsed":false,"pycharm":{"name":"#%%\n","is_executing":false},"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2022-12-23T18:39:53.113488Z","iopub.execute_input":"2022-12-23T18:39:53.113840Z","iopub.status.idle":"2022-12-23T18:39:53.126969Z","shell.execute_reply.started":"2022-12-23T18:39:53.113808Z","shell.execute_reply":"2022-12-23T18:39:53.125501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Analizamos las imágenes","metadata":{}},{"cell_type":"code","source":"\nfig, ax = plt.subplots(2,5, figsize=(20,8))\nfig.suptitle('Exploraciones histopatológicas de secciones de ganglios linfáticos',fontsize=20)\npath_dir = '../input/histopathologic-cancer-detection'\n\n# Negatives\nfor i, idx in enumerate(cancer_negative):\n    path = os.path.join(path_dir, 'train', idx)\n    ax[0,i].imshow(readImage(path + '.tif'))\n    \nax[0,0].set_ylabel('Sin tumores', size='20')\n\n# Positives\nfor i, idx in enumerate(cancer_positive):\n    path = os.path.join(path_dir, 'train', idx)\n    ax[1,i].imshow(readImage(path + '.tif'))\n    \nax[1,0].set_ylabel('Muestras con tumores', size='20')","metadata":{"collapsed":false,"pycharm":{"name":"#%%\n","is_executing":false},"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2022-12-23T18:44:33.004782Z","iopub.execute_input":"2022-12-23T18:44:33.005460Z","iopub.status.idle":"2022-12-23T18:44:34.884554Z","shell.execute_reply.started":"2022-12-23T18:44:33.005404Z","shell.execute_reply":"2022-12-23T18:44:34.883179Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Agregamos los archivos de las imágenes al dataset","metadata":{}},{"cell_type":"code","source":"# Leyendo imágenes\ndf['image_path'] = path_dir + '/train/' + df['id'] + '.tif'\ndf.sample(3)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:39:54.986611Z","iopub.execute_input":"2022-12-23T18:39:54.987046Z","iopub.status.idle":"2022-12-23T18:39:55.006804Z","shell.execute_reply.started":"2022-12-23T18:39:54.987013Z","shell.execute_reply":"2022-12-23T18:39:55.005765Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['image'] = df['image_path'].map(imread)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:39:55.008026Z","iopub.execute_input":"2022-12-23T18:39:55.008392Z","iopub.status.idle":"2022-12-23T18:40:56.535939Z","shell.execute_reply.started":"2022-12-23T18:39:55.008361Z","shell.execute_reply":"2022-12-23T18:40:56.534680Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.sample(3)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:40:56.538000Z","iopub.execute_input":"2022-12-23T18:40:56.538525Z","iopub.status.idle":"2022-12-23T18:41:04.544784Z","shell.execute_reply.started":"2022-12-23T18:40:56.538481Z","shell.execute_reply":"2022-12-23T18:41:04.543658Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Un poco de explicación teórica\n\n## ¿Qué son las redes convolucionales?\n\nLas redes neuronales \"convencionales\" asocian features con una salida. Pero esto en imágenes, si bien funciona, no es tal útil. Porque si, suponiendo una imagen en blanco y negro, pensamos a cada pixel como un valor de 0 a 255 dependiendo su color, al analizar cada pixel como un features estamos perdiendo los patrones que forman las imágenes, es decir la relación entre un pixel y sus vecinos.\n\n![Redes convolucionales](https://i.postimg.cc/T1G1RQSg/Captura-de-pantalla-2022-12-23-165300.png)\n\nPara prevenir esto es que se utilizan las redes convolucionales, éstas tienen varios comportamientos que se pueden agrupar:\n- realizan rotaciones en las imágenes de entrada.\n- utilizan funciones de activación que apaguen neuronas de entrada de una capa.\n- realizan pooling entre los pixeles para resaltar patrones.\n\n![Max Pooling](https://i.postimg.cc/MTwqRHD8/Captura-de-pantalla-2022-12-23-165605.png)","metadata":{}},{"cell_type":"markdown","source":"# Baseline\n\nBasándonos en la documentación de Keras hacemos el primer modelo.\n\nReferencia: https://keras.io/getting_started/intro_to_keras_for_engineers/#training-models-with-fit\n\nMás info: https://www.tensorflow.org/api_docs/python/tf/keras/activations/relu","metadata":{"pycharm":{"name":"#%%\n"},"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2022-11-04T23:13:05.796904Z","iopub.execute_input":"2022-11-04T23:13:05.797349Z","iopub.status.idle":"2022-11-04T23:13:05.803509Z","shell.execute_reply.started":"2022-11-04T23:13:05.797316Z","shell.execute_reply":"2022-11-04T23:13:05.802178Z"}}},{"cell_type":"code","source":"# We know we have images from 96x96 in rgb\ninputs = keras.Input(shape=(96, 96, 3))\n\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.layers import CenterCrop\nfrom tensorflow.keras.layers import Rescaling\n\n# Center-crop images to 96x96 just in case\nx = CenterCrop(height=96, width=96)(inputs)\n# Rescale images to [0, 1]\nx = Rescaling(scale=1.0 / 255)(x)\n\n# See https://www.tensorflow.org/api_docs/python/tf/keras/activations/relu\n\n# Apply some convolution and pooling layers\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\nx = layers.MaxPooling2D(pool_size=(3, 3))(x)\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\nx = layers.MaxPooling2D(pool_size=(3, 3))(x)\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\n\n# Apply global average pooling to get flat feature vectors\nx = layers.GlobalAveragePooling2D()(x)\n\n# NORMALIZACION DE LOS DATOS de 0 a 1\n\n# Using Dense 1 because of binary prediction\noutputs = layers.Dense(1, kernel_initializer='normal', activation='sigmoid')(x)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:41:04.546265Z","iopub.execute_input":"2022-12-23T18:41:04.546605Z","iopub.status.idle":"2022-12-23T18:41:04.634905Z","shell.execute_reply.started":"2022-12-23T18:41:04.546573Z","shell.execute_reply":"2022-12-23T18:41:04.633703Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = keras.Model(inputs=inputs, outputs=outputs)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:41:04.636277Z","iopub.execute_input":"2022-12-23T18:41:04.636641Z","iopub.status.idle":"2022-12-23T18:41:04.645703Z","shell.execute_reply.started":"2022-12-23T18:41:04.636609Z","shell.execute_reply":"2022-12-23T18:41:04.644480Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Preparando el modelo","metadata":{}},{"cell_type":"markdown","source":"**rmsprop:** optimiza por cuadrados mninimos.\n\n**metrics:** nos informa ciertas estadisticas a lo largo de la ejecución.\n","metadata":{}},{"cell_type":"code","source":"model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=[tf.keras.metrics.BinaryAccuracy()],)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:41:04.647264Z","iopub.execute_input":"2022-12-23T18:41:04.647810Z","iopub.status.idle":"2022-12-23T18:41:04.666783Z","shell.execute_reply.started":"2022-12-23T18:41:04.647770Z","shell.execute_reply":"2022-12-23T18:41:04.665289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['image'].shape","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:41:04.671439Z","iopub.execute_input":"2022-12-23T18:41:04.672508Z","iopub.status.idle":"2022-12-23T18:41:04.681248Z","shell.execute_reply.started":"2022-12-23T18:41:04.672458Z","shell.execute_reply":"2022-12-23T18:41:04.679625Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"input_images = np.stack(list(df['image']), axis = 0)\ninput_images.shape","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:41:04.682809Z","iopub.execute_input":"2022-12-23T18:41:04.683320Z","iopub.status.idle":"2022-12-23T18:41:04.840049Z","shell.execute_reply.started":"2022-12-23T18:41:04.683282Z","shell.execute_reply":"2022-12-23T18:41:04.838680Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Train_test_split:** establece un porcentaje sin uso para luego probar el aprendizaje.","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nfrom sklearn.preprocessing import LabelBinarizer\n\nencoder = LabelBinarizer()\ny = encoder.fit_transform(df['label'])\n\nX_train, X_val, y_train, y_val = train_test_split(input_images, y, test_size=0.2, random_state=1)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:41:04.841900Z","iopub.execute_input":"2022-12-23T18:41:04.842397Z","iopub.status.idle":"2022-12-23T18:41:04.941124Z","shell.execute_reply.started":"2022-12-23T18:41:04.842353Z","shell.execute_reply":"2022-12-23T18:41:04.939873Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Probamos distintos valores de batch_size y epochs para encontrar un modelo óptimo.","metadata":{}},{"cell_type":"code","source":"epochs_n = 10\nmodel.fit(X_train, y_train, batch_size=20, epochs=epochs_n, \n          validation_data=(X_val, y_val),verbose=2,)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:41:04.942905Z","iopub.execute_input":"2022-12-23T18:41:04.943344Z","iopub.status.idle":"2022-12-23T18:44:00.921271Z","shell.execute_reply.started":"2022-12-23T18:41:04.943300Z","shell.execute_reply":"2022-12-23T18:44:00.919029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Mostramos el loss y el accuaracy","metadata":{}},{"cell_type":"code","source":"results = model.evaluate(X_val, y_val, verbose=0)\nprint(\"test loss, test acc:\", results)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:44:00.922975Z","iopub.execute_input":"2022-12-23T18:44:00.923592Z","iopub.status.idle":"2022-12-23T18:44:02.287202Z","shell.execute_reply.started":"2022-12-23T18:44:00.923556Z","shell.execute_reply":"2022-12-23T18:44:02.286281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Veamos las predicciones para 3 muestras\n","metadata":{}},{"cell_type":"code","source":"predictions = model.predict(X_val[:3])\nprint(\"predictions shape:\", predictions.shape)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:44:02.288681Z","iopub.execute_input":"2022-12-23T18:44:02.289018Z","iopub.status.idle":"2022-12-23T18:44:02.501360Z","shell.execute_reply.started":"2022-12-23T18:44:02.288986Z","shell.execute_reply":"2022-12-23T18:44:02.499804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:44:02.503238Z","iopub.execute_input":"2022-12-23T18:44:02.503721Z","iopub.status.idle":"2022-12-23T18:44:02.512518Z","shell.execute_reply.started":"2022-12-23T18:44:02.503640Z","shell.execute_reply":"2022-12-23T18:44:02.511456Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Vemos que keras hace predicciones entre 0 y 1. Somos nosotros los que tenemos que definir la condición de corte para la interpretación binaria.","metadata":{}},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:44:02.514052Z","iopub.execute_input":"2022-12-23T18:44:02.515128Z","iopub.status.idle":"2022-12-23T18:44:02.525780Z","shell.execute_reply.started":"2022-12-23T18:44:02.515088Z","shell.execute_reply":"2022-12-23T18:44:02.524008Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Analicemos los errores\n","metadata":{}},{"cell_type":"code","source":"from sklearn.metrics import classification_report\nbreak_condition = 0.5\n\nbinary_predictions = model.predict(X_val)\n\nbinary_predictions[binary_predictions <= break_condition] = 0.\nbinary_predictions[binary_predictions > break_condition] = 1\n\nprint(classification_report(y_val, binary_predictions))","metadata":{"execution":{"iopub.status.busy":"2022-12-23T18:44:02.528027Z","iopub.execute_input":"2022-12-23T18:44:02.528498Z","iopub.status.idle":"2022-12-23T18:44:03.617569Z","shell.execute_reply.started":"2022-12-23T18:44:02.528464Z","shell.execute_reply":"2022-12-23T18:44:03.615944Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Mejorando el modelo\n\nAgregamos 2 capas de Dropout que eliminan algunas neuronas entre capa y capa para que la red tenga que aprender de manera reduntante.","metadata":{}},{"cell_type":"code","source":"# We know we have images from 96x96 in rgb\ninputs = keras.Input(shape=(96, 96, 3))\n\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.layers import CenterCrop\nfrom tensorflow.keras.layers import Rescaling\n\n# Center-crop images to 96x96 just in case\nx = CenterCrop(height=96, width=96)(inputs)\n# Rescale images to [0, 1]\nx = Rescaling(scale=1.0 / 255)(x)\n\n# See https://www.tensorflow.org/api_docs/python/tf/keras/activations/relu\n\n# Apply some convolution and pooling layers\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\nx = layers.MaxPooling2D(pool_size=(3, 3))(x)\nx = layers.Dropout(0.2)(x)\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\nx = layers.MaxPooling2D(pool_size=(3, 3))(x)\nx = layers.Dropout(0.2)(x)\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\n\n# Apply global average pooling to get flat feature vectors\nx = layers.GlobalAveragePooling2D()(x)\n\n# NORMALIZACION DE LOS DATOS de 0 a 1\n\n# Using Dense 1 because of binary prediction\noutputs = layers.Dense(1, kernel_initializer='normal', activation='sigmoid')(x)\n\n","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:02:02.337489Z","iopub.execute_input":"2022-12-23T19:02:02.337902Z","iopub.status.idle":"2022-12-23T19:02:02.959877Z","shell.execute_reply.started":"2022-12-23T19:02:02.337869Z","shell.execute_reply":"2022-12-23T19:02:02.958609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = keras.Model(inputs=inputs, outputs=outputs)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:02:08.206993Z","iopub.execute_input":"2022-12-23T19:02:08.208125Z","iopub.status.idle":"2022-12-23T19:02:08.219049Z","shell.execute_reply.started":"2022-12-23T19:02:08.208086Z","shell.execute_reply":"2022-12-23T19:02:08.217097Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer='rmsprop', loss='binary_crossentropy', \n              metrics=[tf.keras.metrics.BinaryAccuracy()],)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:02:15.630758Z","iopub.execute_input":"2022-12-23T19:02:15.631233Z","iopub.status.idle":"2022-12-23T19:02:15.646595Z","shell.execute_reply.started":"2022-12-23T19:02:15.631188Z","shell.execute_reply":"2022-12-23T19:02:15.645533Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs_n = 10 # 250 es el que mejor valor dio\nmodel.fit(X_train, y_train, batch_size=20, epochs=epochs_n, \n          validation_data=(X_val, y_val),verbose=2,)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:02:15.648516Z","iopub.execute_input":"2022-12-23T19:02:15.649378Z","iopub.status.idle":"2022-12-23T19:05:27.746506Z","shell.execute_reply.started":"2022-12-23T19:02:15.649341Z","shell.execute_reply":"2022-12-23T19:05:27.745248Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"break_condition = 0.5\n\nbinary_predictions = model.predict(X_val)\n\nbinary_predictions[binary_predictions <= break_condition] = 0.\nbinary_predictions[binary_predictions > break_condition] = 1\n\nprint(classification_report(y_val, binary_predictions))","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:05:27.747857Z","iopub.execute_input":"2022-12-23T19:05:27.748237Z","iopub.status.idle":"2022-12-23T19:05:28.912715Z","shell.execute_reply.started":"2022-12-23T19:05:27.748202Z","shell.execute_reply":"2022-12-23T19:05:28.911247Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Conclusión de la mejora 2\n\nMejoramos el recall que quedó en 0.79 vs 0.69 en el caso anterior a cambio de perder solo 1 punto de precisión.","metadata":{}},{"cell_type":"markdown","source":"# Mejora 3\n\nAgregamos una capa más de dropout y de convolusión para que la red sea menos propensa a equivocarse al recibir una imagen rotada.","metadata":{}},{"cell_type":"code","source":"# We know we have images from 96x96 in rgb\ninputs = keras.Input(shape=(96, 96, 3))\n\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.layers import CenterCrop\nfrom tensorflow.keras.layers import Rescaling\n\n# Center-crop images to 96x96 just in case\nx = CenterCrop(height=96, width=96)(inputs)\n# Rescale images to [0, 1]\nx = Rescaling(scale=1.0 / 255)(x)\n\n# See https://www.tensorflow.org/api_docs/python/tf/keras/activations/relu\n\n# Apply some convolution and pooling layers\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\nx = layers.MaxPooling2D(pool_size=(3, 3))(x)\nx = layers.Dropout(0.2)(x)\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\nx = layers.MaxPooling2D(pool_size=(3, 3))(x)\nx = layers.Dropout(0.2)(x)\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\n# x = layers.MaxPooling2D(pool_size=(3, 3))(x)\nx = layers.Dropout(0.2)(x)\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\n\n# Apply global average pooling to get flat feature vectors\nx = layers.GlobalAveragePooling2D()(x)\n\n# NORMALIZACION DE LOS DATOS de 0 a 1\n\n# Using Dense 1 because of binary prediction\noutputs = layers.Dense(1, kernel_initializer='normal', activation='sigmoid')(x)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:13:10.610846Z","iopub.execute_input":"2022-12-23T19:13:10.611293Z","iopub.status.idle":"2022-12-23T19:13:10.718814Z","shell.execute_reply.started":"2022-12-23T19:13:10.611259Z","shell.execute_reply":"2022-12-23T19:13:10.717730Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = keras.Model(inputs=inputs, outputs=outputs)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:13:10.721343Z","iopub.execute_input":"2022-12-23T19:13:10.722247Z","iopub.status.idle":"2022-12-23T19:13:10.732945Z","shell.execute_reply.started":"2022-12-23T19:13:10.722193Z","shell.execute_reply":"2022-12-23T19:13:10.731284Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer='rmsprop', loss='binary_crossentropy', \n              metrics=[tf.keras.metrics.BinaryAccuracy()],)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:13:10.734404Z","iopub.execute_input":"2022-12-23T19:13:10.734842Z","iopub.status.idle":"2022-12-23T19:13:10.751700Z","shell.execute_reply.started":"2022-12-23T19:13:10.734804Z","shell.execute_reply":"2022-12-23T19:13:10.750388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs_n = 10 # 250 es el que mejor valor dio\nmodel.fit(X_train, y_train, batch_size=20, epochs=epochs_n, \n          validation_data=(X_val, y_val),verbose=2,)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:13:10.755118Z","iopub.execute_input":"2022-12-23T19:13:10.756160Z","iopub.status.idle":"2022-12-23T19:16:29.074953Z","shell.execute_reply.started":"2022-12-23T19:13:10.756094Z","shell.execute_reply":"2022-12-23T19:16:29.073485Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"break_condition = 0.5\n\nbinary_predictions = model.predict(X_val)\n\nbinary_predictions[binary_predictions <= break_condition] = 0.\nbinary_predictions[binary_predictions > break_condition] = 1\n\nprint(classification_report(y_val, binary_predictions))","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:16:29.076936Z","iopub.execute_input":"2022-12-23T19:16:29.077416Z","iopub.status.idle":"2022-12-23T19:16:30.341009Z","shell.execute_reply.started":"2022-12-23T19:16:29.077372Z","shell.execute_reply":"2022-12-23T19:16:30.339379Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Conclusión de la mejora 3\nMejoró considerablemente el recall, 0.73 a 0.77 y bajó un poco el accuracy, 0.02.","metadata":{}},{"cell_type":"markdown","source":"# Mejora 4\nHabíamos elegido el optimizador RMS (por errores de cuadrados mínimos) porque es uno de los mejores para problemas de clasificación binaria. De todas formas probamos otro optimizador recomendado en la documentación: Adam.","metadata":{}},{"cell_type":"code","source":"# We know we have images from 96x96 in rgb\ninputs = keras.Input(shape=(96, 96, 3))\n\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.layers import CenterCrop\nfrom tensorflow.keras.layers import Rescaling\n\n# Center-crop images to 96x96 just in case\nx = CenterCrop(height=96, width=96)(inputs)\n# Rescale images to [0, 1]\nx = Rescaling(scale=1.0 / 255)(x)\n\n# See https://www.tensorflow.org/api_docs/python/tf/keras/activations/relu\n\n# Apply some convolution and pooling layers\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\nx = layers.MaxPooling2D(pool_size=(3, 3))(x)\nx = layers.Dropout(0.2)(x)\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\nx = layers.MaxPooling2D(pool_size=(3, 3))(x)\nx = layers.Dropout(0.2)(x)\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\n# x = layers.MaxPooling2D(pool_size=(3, 3))(x)\nx = layers.Dropout(0.2)(x)\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\n\n# Apply global average pooling to get flat feature vectors\nx = layers.GlobalAveragePooling2D()(x)\n\n# NORMALIZACION DE LOS DATOS de 0 a 1\n\n# Using Dense 1 because of binary prediction\noutputs = layers.Dense(1, kernel_initializer='normal', activation='sigmoid')(x)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:21:02.642671Z","iopub.execute_input":"2022-12-23T19:21:02.643094Z","iopub.status.idle":"2022-12-23T19:21:02.753508Z","shell.execute_reply.started":"2022-12-23T19:21:02.643062Z","shell.execute_reply":"2022-12-23T19:21:02.752079Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = keras.Model(inputs=inputs, outputs=outputs)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:21:02.756232Z","iopub.execute_input":"2022-12-23T19:21:02.756960Z","iopub.status.idle":"2022-12-23T19:21:02.767965Z","shell.execute_reply.started":"2022-12-23T19:21:02.756922Z","shell.execute_reply":"2022-12-23T19:21:02.766481Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer='adam', loss='binary_crossentropy', \n              metrics=[tf.keras.metrics.BinaryAccuracy()],)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:21:02.769854Z","iopub.execute_input":"2022-12-23T19:21:02.770414Z","iopub.status.idle":"2022-12-23T19:21:02.789583Z","shell.execute_reply.started":"2022-12-23T19:21:02.770365Z","shell.execute_reply":"2022-12-23T19:21:02.788097Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs_n = 10 # 250 es el que mejor valor dio\nmodel.fit(X_train, y_train, batch_size=20, epochs=epochs_n, \n          validation_data=(X_val, y_val),verbose=2,)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:21:02.791637Z","iopub.execute_input":"2022-12-23T19:21:02.792153Z","iopub.status.idle":"2022-12-23T19:24:22.036789Z","shell.execute_reply.started":"2022-12-23T19:21:02.792105Z","shell.execute_reply":"2022-12-23T19:24:22.035971Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"break_condition = 0.5\n\nbinary_predictions = model.predict(X_val)\n\nbinary_predictions[binary_predictions <= break_condition] = 0.\nbinary_predictions[binary_predictions > break_condition] = 1\n\nprint(classification_report(y_val, binary_predictions))","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:24:22.038894Z","iopub.execute_input":"2022-12-23T19:24:22.039463Z","iopub.status.idle":"2022-12-23T19:24:23.298685Z","shell.execute_reply.started":"2022-12-23T19:24:22.039429Z","shell.execute_reply":"2022-12-23T19:24:23.297469Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Conclusión mejora 4\nNo mejoró ni el recall y la precisión bajó. Descartado","metadata":{}},{"cell_type":"markdown","source":"# Mejora 5\n\nVolvemos al optimizador rms y aumentamos los epochs.\n","metadata":{}},{"cell_type":"code","source":"# We know we have images from 96x96 in rgb\ninputs = keras.Input(shape=(96, 96, 3))\n\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.layers import CenterCrop\nfrom tensorflow.keras.layers import Rescaling\n\n# Center-crop images to 96x96 just in case\nx = CenterCrop(height=96, width=96)(inputs)\n# Rescale images to [0, 1]\nx = Rescaling(scale=1.0 / 255)(x)\n\n# See https://www.tensorflow.org/api_docs/python/tf/keras/activations/relu\n\n# Apply some convolution and pooling layers\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\nx = layers.MaxPooling2D(pool_size=(3, 3))(x)\nx = layers.Dropout(0.2)(x)\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\nx = layers.MaxPooling2D(pool_size=(3, 3))(x)\nx = layers.Dropout(0.2)(x)\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\n# x = layers.MaxPooling2D(pool_size=(3, 3))(x)\nx = layers.Dropout(0.2)(x)\nx = layers.Conv2D(filters=32, kernel_size=(3, 3), activation=\"relu\")(x)\n\n# Apply global average pooling to get flat feature vectors\nx = layers.GlobalAveragePooling2D()(x)\n\n# NORMALIZACION DE LOS DATOS de 0 a 1\n\n# Using Dense 1 because of binary prediction\noutputs = layers.Dense(1, kernel_initializer='normal', activation='sigmoid')(x)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:26:45.936571Z","iopub.execute_input":"2022-12-23T19:26:45.937116Z","iopub.status.idle":"2022-12-23T19:26:46.049001Z","shell.execute_reply.started":"2022-12-23T19:26:45.937073Z","shell.execute_reply":"2022-12-23T19:26:46.047648Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = keras.Model(inputs=inputs, outputs=outputs)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:26:46.051760Z","iopub.execute_input":"2022-12-23T19:26:46.052157Z","iopub.status.idle":"2022-12-23T19:26:46.062184Z","shell.execute_reply.started":"2022-12-23T19:26:46.052127Z","shell.execute_reply":"2022-12-23T19:26:46.060848Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer='rmsprop', loss='binary_crossentropy', \n              metrics=[tf.keras.metrics.BinaryAccuracy()],)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:26:46.063756Z","iopub.execute_input":"2022-12-23T19:26:46.064197Z","iopub.status.idle":"2022-12-23T19:26:46.081926Z","shell.execute_reply.started":"2022-12-23T19:26:46.064141Z","shell.execute_reply":"2022-12-23T19:26:46.080541Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs_n = 250\nmodel.fit(X_train, y_train, batch_size=20, epochs=epochs_n, \n          validation_data=(X_val, y_val),verbose=2,)","metadata":{"execution":{"iopub.status.busy":"2022-12-23T19:26:46.084628Z","iopub.execute_input":"2022-12-23T19:26:46.085005Z","iopub.status.idle":"2022-12-23T20:48:58.629012Z","shell.execute_reply.started":"2022-12-23T19:26:46.084971Z","shell.execute_reply":"2022-12-23T20:48:58.627943Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"break_condition = 0.5\n\nbinary_predictions = model.predict(X_val)\n\nbinary_predictions[binary_predictions <= break_condition] = 0.\nbinary_predictions[binary_predictions > break_condition] = 1\n\nprint(classification_report(y_val, binary_predictions))","metadata":{"execution":{"iopub.status.busy":"2022-12-23T20:48:58.630297Z","iopub.execute_input":"2022-12-23T20:48:58.631517Z","iopub.status.idle":"2022-12-23T20:48:59.845825Z","shell.execute_reply.started":"2022-12-23T20:48:58.631478Z","shell.execute_reply":"2022-12-23T20:48:59.844764Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Conclusión de la mejora 5\n\nMejoró muchísimo la precisión pero perdimos mucho recall. Para lo detallado en este trabajo práctico, el mejor modelo parece ser el modelo 3. ","metadata":{}},{"cell_type":"markdown","source":"# Conclusiones\n\nCon menos del 5% de las imágenes de las que disponemos logramos obtener un resultado útil. Aún un poco alejado de valores seguros para ser usados en producción, pero sin duda muy prometedores.\nAumentar los epochs mejora la precisión pero el recall se ve afectado, para nuestra prioridad, deberíamos aumentar la cantidad de imágenes que utilizamos en cada epoch para no tener falsos negativos.\n\n## Mejoras posibles\n\n- Mejorar el procesamiento de las imágenes realizando entrenamientos por batches que nos permitan utilizar todos los datos.\n- Invertir más tiempo en realizar epochs con muestras más batch sizes más grandes para mejorar el entrenamiento.\n- Analizar los datos de entrada, como vimos, tenemos muchas imágenes que no muestran metástasis, equilibrar los valores de entrada podría ayudar al modelo en su entrenamiento. Es decir, si tenemos 50% de los valores de entrada con label 0 y el otro 50% con label 1, la red podría verse obligada a mejorar.\n- Podemos cambiar la condición de corte en caso de ser necesario.","metadata":{}}]}