{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":3362,"databundleVersionId":31148,"sourceType":"competition"}],"dockerImageVersionId":30761,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 1- Importar librerías y visualizar los datos\n","metadata":{}},{"cell_type":"code","source":"# Librerías para leer los ficheros\nimport zipfile\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport io\n\n# Librerías para el modelo 1\nimport numpy as np\nfrom sklearn.model_selection import train_test_split\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout\n\n# Librerías para el modelo 2\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n# Ruta del fichero .zip de entrenamiento (cambia 'ruta/del/archivo' por la ruta correcta)\nzip_train_path = '/kaggle/input/dogs-vs-cats/train.zip'\n\n# Ruta del fichero .zip de prueba\nzip_test_path = '/kaggle/input/dogs-vs-cats/test1.zip'\n\n# Función para extraer y mostrar imágenes\ndef mostrar_imagenes_grises_zip(ruta_zip, num_imagenes=10):\n    with zipfile.ZipFile(ruta_zip, 'r') as archivo_zip:\n        # Listar todos los archivos contenidos en el zip\n        archivos = archivo_zip.namelist()\n        \n        # Filtrar archivos que sean imágenes (opcional)\n        imagenes = [archivo for archivo in archivos if archivo.endswith(('.png', '.jpg', '.jpeg'))]\n        \n        # Mostrar las primeras num_imagenes imágenes\n        for i, img_path in enumerate(imagenes[:num_imagenes]):\n            with archivo_zip.open(img_path) as imagen_zip:\n                # Leer la imagen \n                img = Image.open(io.BytesIO(imagen_zip.read()))\n                \n                # Mostrar la imagen\n                plt.subplot(1, num_imagenes, i + 1)\n                plt.imshow(img) \n                plt.axis('off')  # Quitar los ejes para visualizar solo la imagen\n\n        plt.show()\n\n# Llamar a la función para mostrar 10 imágenes del dataset de entrenamiento\nprint('Muestra de 10 imágenes del dataset de entrenamiento:')\nmostrar_imagenes_grises_zip(zip_train_path, num_imagenes=10)\n\n# Llamar a la función para mostrar 10 imágenes del dataset de test\nprint('Muestra de 10 imágenes del dataset de test:')\nmostrar_imagenes_grises_zip(zip_test_path, num_imagenes=10)","metadata":{"execution":{"iopub.status.busy":"2024-09-13T09:52:04.493025Z","iopub.execute_input":"2024-09-13T09:52:04.493587Z","iopub.status.idle":"2024-09-13T09:52:24.758658Z","shell.execute_reply.started":"2024-09-13T09:52:04.493540Z","shell.execute_reply":"2024-09-13T09:52:24.757295Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2- Mostrar 10 imágenes de los dataset, en escala de grises y redimensionadas a 128x128","metadata":{}},{"cell_type":"code","source":"# Definir el tamaño al que queremos redimensionar las imágenes (por ejemplo 128x128)\nnuevo_tamano = (128, 128)\n\n# Función para extraer, convertir a escala de grises y redimensionar las imágenes\ndef procesar_imagenes_zip(ruta_zip, num_imagenes=10, tamano=nuevo_tamano):\n    with zipfile.ZipFile(ruta_zip, 'r') as archivo_zip:\n        # Listar todos los archivos contenidos en el zip\n        archivos = archivo_zip.namelist()\n        \n        # Filtrar archivos que sean imágenes (opcional)\n        imagenes = [archivo for archivo in archivos if archivo.endswith(('.png', '.jpg', '.jpeg'))]\n        \n        # Mostrar las primeras num_imagenes imágenes\n        for i, img_path in enumerate(imagenes[:num_imagenes]):\n            with archivo_zip.open(img_path) as imagen_zip:\n                # Leer la imagen\n                img = Image.open(io.BytesIO(imagen_zip.read()))\n                \n                # Convertir a escala de grises\n                img = img.convert('L')\n                \n                # Redimensionar la imagen\n                img = img.resize(tamano)\n                \n                # Mostrar la imagen redimensionada en escala de grises\n                plt.subplot(1, num_imagenes, i + 1)\n                plt.imshow(img, cmap='gray')  # Mostrar en escala de grises\n                plt.axis('off')  # Quitar los ejes\n\n        plt.show()\n\n# Llamar a la función para procesar y mostrar 10 imágenes redimensionadas a 128x128\nprint('Muestra de 10 imágenes del dataset de entrenamiento, en escala de grises y redimensionadas a 128x128:')\nprocesar_imagenes_zip(zip_train_path, num_imagenes=10, tamano=(128, 128))\n\n# Llamar a la función para procesar y mostrar 10 imágenes redimensionadas a 128x128\nprint('Muestra de 10 imágenes del dataset de test, en escala de grises y redimensionadas a 128x128:')\nprocesar_imagenes_zip(zip_test_path, num_imagenes=10, tamano=(128, 128))","metadata":{"execution":{"iopub.status.busy":"2024-09-13T09:52:24.760841Z","iopub.execute_input":"2024-09-13T09:52:24.761526Z","iopub.status.idle":"2024-09-13T09:52:26.497807Z","shell.execute_reply.started":"2024-09-13T09:52:24.761481Z","shell.execute_reply":"2024-09-13T09:52:26.495850Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3- Contar el número de imágenes de cada dataset (entrenemiento y test)","metadata":{}},{"cell_type":"code","source":"# Función para contar el número de imágenes en el archivo zip\ndef contar_imagenes_zip(ruta_zip):\n    with zipfile.ZipFile(ruta_zip, 'r') as archivo_zip:\n        # Listar todos los archivos contenidos en el zip\n        archivos = archivo_zip.namelist()\n        \n        # Filtrar archivos que sean imágenes (con extensiones comunes)\n        imagenes = [archivo for archivo in archivos if archivo.endswith(('.png', '.jpg', '.jpeg'))]\n        \n        # Contar el número de imágenes\n        num_imagenes = len(imagenes)\n        print(f\"Número total de imágenes en {ruta_zip}: {num_imagenes}\")\n\n# Llamar a la función para contar el número total de imágenes en el zip de entrenamiento\ncontar_imagenes_zip(zip_train_path)\n\n# Llamar a la función para contar el número total de imágenes en el zip de entrenamiento\ncontar_imagenes_zip(zip_test_path)","metadata":{"execution":{"iopub.status.busy":"2024-09-13T09:52:26.500947Z","iopub.execute_input":"2024-09-13T09:52:26.501690Z","iopub.status.idle":"2024-09-13T09:52:27.012992Z","shell.execute_reply.started":"2024-09-13T09:52:26.501611Z","shell.execute_reply":"2024-09-13T09:52:27.011597Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4- Obtener los nuevos datasets a partir de los originales, con las imágenes en escala de grises y redimensionadas a 128x128 ","metadata":{"execution":{"iopub.status.busy":"2024-09-12T12:00:35.610325Z","iopub.execute_input":"2024-09-12T12:00:35.610843Z","iopub.status.idle":"2024-09-12T12:00:35.617491Z","shell.execute_reply.started":"2024-09-12T12:00:35.610800Z","shell.execute_reply":"2024-09-12T12:00:35.615832Z"}}},{"cell_type":"code","source":"# Definir el tamaño al que queremos redimensionar las imágenes (por ejemplo 128x128)\nnuevo_tamano = (128, 128)\n\n# Función para cargar y procesar todas las imágenes del zip\ndef cargar_dataset_grises_zip(ruta_zip, tamano=nuevo_tamano):\n    imagenes_procesadas = []\n    \n    with zipfile.ZipFile(ruta_zip, 'r') as archivo_zip:\n        # Listar todos los archivos contenidos en el zip\n        archivos = archivo_zip.namelist()\n        \n        # Filtrar archivos que sean imágenes (con extensiones comunes)\n        imagenes = [archivo for archivo in archivos if archivo.endswith(('.png', '.jpg', '.jpeg'))]\n        \n        # Procesar cada imagen\n        for img_path in imagenes:\n            with archivo_zip.open(img_path) as imagen_zip:\n                # Leer la imagen\n                img = Image.open(io.BytesIO(imagen_zip.read()))\n                \n                # Convertir a escala de grises\n                img = img.convert('L')\n                \n                # Redimensionar la imagen\n                img = img.resize(tamano)\n                \n                # Convertir la imagen a array NumPy y normalizar a [0, 1]\n                img_array = np.array(img) / 255.0\n                \n                # Agregar la imagen procesada al dataset\n                imagenes_procesadas.append(img_array)\n    \n    # Convertir la lista de imágenes procesadas a un array NumPy (para que funcione bien con el modelo)\n    dataset = np.array(imagenes_procesadas)\n    \n    print(f\"Dataset cargado con {len(dataset)} imágenes de tamaño {tamano}\")\n    \n    return dataset\n\n# Cargar el dataset de entrenamiento\ndataset_entrenamiento = cargar_dataset_grises_zip(zip_train_path, nuevo_tamano)\n\n# Cargar el dataset de prueba\ndataset_prueba = cargar_dataset_grises_zip(zip_test_path, nuevo_tamano)","metadata":{"execution":{"iopub.status.busy":"2024-09-13T09:52:27.016781Z","iopub.execute_input":"2024-09-13T09:52:27.017233Z","iopub.status.idle":"2024-09-13T09:52:49.801506Z","shell.execute_reply.started":"2024-09-13T09:52:27.017187Z","shell.execute_reply":"2024-09-13T09:52:49.799645Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Vemos qué pinta tiene el nuevo dataset\ndataset_entrenamiento","metadata":{"execution":{"iopub.status.busy":"2024-09-13T09:52:49.802522Z","iopub.status.idle":"2024-09-13T09:52:49.802981Z","shell.execute_reply.started":"2024-09-13T09:52:49.802762Z","shell.execute_reply":"2024-09-13T09:52:49.802785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 5- Extraer las etiquetas (en este caso van en el nombre de cada fichero .jpg)","metadata":{}},{"cell_type":"code","source":"# Función para extraer etiquetas de las imágenes en el archivo zip\ndef extraer_etiquetas_imagenes_zip(ruta_zip):\n    etiquetas = []\n    with zipfile.ZipFile(ruta_zip, 'r') as archivo_zip:\n        # Listar todos los archivos contenidos en el zip\n        archivos = archivo_zip.namelist()\n        \n        # Filtrar archivos que sean imágenes (con extensiones comunes)\n        imagenes = [archivo for archivo in archivos if archivo.endswith(('.png', '.jpg', '.jpeg'))]\n        \n        # Procesar cada imagen y extraer su etiqueta\n        for img_path in imagenes:\n            # Obtener el nombre del archivo o la carpeta donde está\n            if 'dog' in img_path.lower():\n                etiquetas.append(('dog', img_path))\n            elif 'cat' in img_path.lower():\n                etiquetas.append(('cat', img_path))\n            else:\n                etiquetas.append(('unknown', img_path))  # Si no es identificable\n        \n    return etiquetas\n\n# Llamar a la función para extraer etiquetas\netiquetas_imagenes = extraer_etiquetas_imagenes_zip(zip_train_path)\n\n# Mostrar las primeras 10 imágenes y sus etiquetas\nfor etiqueta, img_path in etiquetas_imagenes[:10]:\n    print(f\"Imagen: {img_path}, Etiqueta: {etiqueta}\")","metadata":{"execution":{"iopub.status.busy":"2024-09-13T09:52:49.804873Z","iopub.status.idle":"2024-09-13T09:52:49.805541Z","shell.execute_reply.started":"2024-09-13T09:52:49.805196Z","shell.execute_reply":"2024-09-13T09:52:49.805228Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 6- Creación y entrenamiento del modelo\n\nExplicación paso a paso:\n\n\t1.\tPreparación del dataset:\n\t•\tEtiquetas: Convertimos las etiquetas a valores binarios (0 para “gato” y 1 para “perro”).\n\t•\tCanal de escala de grises: Expandimos el dataset de imágenes para añadir el canal de color (en este caso, 1 canal, ya que son imágenes en escala de grises).\n\t•\tDivisión de datos: Usamos train_test_split para dividir el dataset en datos de entrenamiento (80%) y validación (20%).\n\t2.\tArquitectura de la CNN:\n\t•\tCapas convolucionales: Estas capas detectan características importantes como bordes, texturas, etc.\n\t•\tLa primera capa tiene 32 filtros, la segunda 64 filtros, y la tercera 128 filtros, cada uno con un tamaño de (3, 3).\n\t•\tCapas de MaxPooling: Estas capas reducen el tamaño de la imagen (downsampling), lo que ayuda a reducir la complejidad.\n\t•\tCapa de Flatten: Convierte la salida de las capas convolucionales en un vector unidimensional, para poder pasarla a las capas densas.\n\t•\tCapa Densa: Una capa completamente conectada con 128 neuronas.\n\t•\tCapa de salida: Utiliza una única neurona con activación sigmoid para hacer la clasificación binaria (perro o gato).\n\t3.\tCompilación:\n\t•\tUsamos el optimizador Adam (popular en tareas de clasificación).\n\t•\tLa función de pérdida es binary_crossentropy porque es un problema de clasificación binaria (perros y gatos).\n\t4.\tEntrenamiento:\n\t•\tEntrenamos el modelo con 10 épocas. Puedes ajustar este número para mejorar el rendimiento.\n\n¿Qué sigue?\n\n\t1.\tEvaluar el rendimiento:\n\t•\tUna vez entrenado el modelo, puedes evaluar su precisión tanto en el conjunto de validación como en el conjunto de prueba (que mencionaste tener en otro .zip).\n\t2.\tAjustar hiperparámetros:\n\t•\tPuedes modificar la arquitectura del modelo, ajustar el número de filtros, cambiar el optimizador, o modificar el tamaño del dataset para obtener mejores resultados.\n\t3.\tGuardar el modelo:\n\t•\tUna vez entrenado, puedes guardar el modelo con modelo.save('modelo_perro_vs_gato.h5').","metadata":{}},{"cell_type":"code","source":"# Supongamos que ya tienes el dataset de entrenamiento (imágenes y etiquetas) cargado:\n# dataset_entrenamiento -> Array de imágenes procesadas (grises y redimensionadas)\n# etiquetas_imagenes -> Lista de etiquetas ('dog' o 'cat')\n\n# Convertir las etiquetas a 0 (gato) o 1 (perro)\netiquetas_binarias = np.array([1 if etiqueta == 'dog' else 0 for etiqueta, _ in etiquetas_imagenes])\n\n# Redimensionar dataset_entrenamiento para añadir canal de escala de grises (1 canal)\ndataset_entrenamiento = np.expand_dims(dataset_entrenamiento, axis=-1)\n\n# Dividir el dataset en conjunto de entrenamiento y validación\nX_train, X_val, y_train, y_val = train_test_split(dataset_entrenamiento, etiquetas_binarias, test_size=0.2, random_state=42)\n\n# Crear el modelo CNN\nmodelo = Sequential()\n\n# Capa 1: Convolución + MaxPooling\nmodelo.add(Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 1)))\nmodelo.add(MaxPooling2D(pool_size=(2, 2)))\n\n# Capa 2: Convolución + MaxPooling\nmodelo.add(Conv2D(64, (3, 3), activation='relu'))\nmodelo.add(MaxPooling2D(pool_size=(2, 2)))\n\n# Capa 3: Convolución + MaxPooling\nmodelo.add(Conv2D(128, (3, 3), activation='relu'))\nmodelo.add(MaxPooling2D(pool_size=(2, 2)))\n\n# Aplanar las características 2D para convertirlas a un vector 1D\nmodelo.add(Flatten())\n\n# Capa Densa con 128 neuronas\nmodelo.add(Dense(128, activation='relu'))\n\n# Capa de salida (2 clases: perro o gato) con una única neurona (clasificación binaria)\nmodelo.add(Dense(1, activation='sigmoid'))\n\n# Compilar el modelo\nmodelo.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])\n\n# Entrenar el modelo\nmodelo.fit(X_train, y_train, epochs=10, validation_data=(X_val, y_val))","metadata":{"execution":{"iopub.status.busy":"2024-09-13T09:52:49.808385Z","iopub.status.idle":"2024-09-13T09:52:49.809157Z","shell.execute_reply.started":"2024-09-13T09:52:49.808750Z","shell.execute_reply":"2024-09-13T09:52:49.808784Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 7- Evaluación del modelo\n\n\t•\tVerifica cómo se desempeña el modelo en el conjunto de validación que separaste anteriormente.\n","metadata":{}},{"cell_type":"code","source":"# Evaluar el modelo en el conjunto de validación\npérdida, precisión = modelo.evaluate(X_val, y_val)\nprint(f'Precisión en el conjunto de validación: {precisión:.4f}')\nprint(f'Pérdida en el conjunto de validación: {pérdida:.4f}')","metadata":{"execution":{"iopub.status.busy":"2024-09-13T09:52:49.810616Z","iopub.status.idle":"2024-09-13T09:52:49.811419Z","shell.execute_reply.started":"2024-09-13T09:52:49.810957Z","shell.execute_reply":"2024-09-13T09:52:49.810989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 8- Probar en el conjunto de prueba\n\t•\tUsa el conjunto de prueba (del archivo test.zip) para una evaluación final, ya que debe ser independiente del conjunto de entrenamiento y validación.\n    \nExplicación:\n\n\t1.\tCargar imágenes de prueba:\n\t•\tEl código para cargar_imagenes_prueba_zip es similar al de entrenamiento, pero ahora estamos cargando el conjunto de prueba.\n\t2.\tHacer predicciones:\n\t•\tUtilizamos modelo.predict para obtener las predicciones del modelo. Las predicciones son probabilidades que convertimos a etiquetas binarias (0 o 1).\n\t3.\tMostrar predicciones:\n\t•\tImprimimos algunas de las predicciones junto con los nombres de los archivos para revisar los resultados.   \n    \nSiguientes pasos opcionales:\n\n\t•\tAjustar el modelo: Si el rendimiento no es el esperado, puedes ajustar la arquitectura, los hiperparámetros, o usar técnicas de data augmentation.\n\t•\tGuardar el modelo: Guarda el modelo entrenado para uso futuro.\n\n>modelo.save('modelo_perro_vs_gato.h5')\n\n\t•\tImplementar el modelo: Puedes usar el modelo para hacer predicciones en aplicaciones reales o integrarlo en una interfaz de usuario.","metadata":{}},{"cell_type":"code","source":"# Función para cargar y procesar las imágenes de prueba\ndef cargar_imagenes_prueba_zip(ruta_zip, tamano=nuevo_tamano):\n    imagenes_procesadas = []\n    nombres_imagenes = []\n    \n    with zipfile.ZipFile(ruta_zip, 'r') as archivo_zip:\n        archivos = archivo_zip.namelist()\n        imagenes = [archivo for archivo in archivos if archivo.endswith(('.png', '.jpg', '.jpeg'))]\n        \n        for img_path in imagenes:\n            with archivo_zip.open(img_path) as imagen_zip:\n                img = Image.open(io.BytesIO(imagen_zip.read()))\n                img = img.convert('L')\n                img = img.resize(tamano)\n                img_array = np.array(img) / 255.0\n                img_array = np.expand_dims(img_array, axis=-1)  # Añadir canal de escala de grises\n                imagenes_procesadas.append(img_array)\n                nombres_imagenes.append(img_path)\n    \n    return np.array(imagenes_procesadas), nombres_imagenes\n\n# Cargar las imágenes de prueba\nX_test, nombres_imagenes = cargar_imagenes_prueba_zip(zip_test_path, tamano=(128, 128))\n\n# Hacer predicciones\npredicciones = modelo.predict(X_test)\n\n# Convertir predicciones a etiquetas binarias\netiquetas_predichas = (predicciones > 0.5).astype(int).flatten()  # 0 para gato, 1 para perro\n\n# Función para mostrar imágenes y sus predicciones\ndef mostrar_imagenes_con_predicciones(imagenes, predicciones, nombres_imagenes, num_imagenes=10):\n    plt.figure(figsize=(15, 15))\n    \n    for i in range(min(num_imagenes, len(imagenes))):\n        plt.subplot(1, num_imagenes, i + 1)\n        plt.imshow(imagenes[i].squeeze(), cmap='gray')  # Mostrar imagen en escala de grises\n        plt.title(f'{\"perro\" if predicciones[i] == 1 else \"gato\"}')\n        plt.axis('off')\n    \n    plt.tight_layout()\n    plt.show()\n\n# Mostrar algunas imágenes y sus predicciones\nmostrar_imagenes_con_predicciones(X_test, etiquetas_predichas, nombres_imagenes)","metadata":{"execution":{"iopub.status.busy":"2024-09-13T09:52:49.813908Z","iopub.status.idle":"2024-09-13T09:52:49.814539Z","shell.execute_reply.started":"2024-09-13T09:52:49.814153Z","shell.execute_reply":"2024-09-13T09:52:49.814175Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Para mejorar el rendimiento del modelo de clasificación de imágenes, podemos probar varias estrategias. Algunas técnicas comunes para mejorar un modelo de red neuronal convolucional (CNN):\n\n\t1.\tAumentar el Dataset:\n\t•\tData Augmentation: Generar variaciones de las imágenes para aumentar la diversidad del dataset y prevenir el sobreajuste.\n\t2.\tAjustar la Arquitectura del Modelo:\n\t•\tAgregar Más Capas: Añadir más capas convolucionales o densas.\n\t•\tRegularización: Usar técnicas como Dropout para reducir el sobreajuste.\n\t3.\tModificar Hiperparámetros:\n\t•\tTasa de Aprendizaje: Ajustar la tasa de aprendizaje del optimizador.\n\t•\tNúmero de Épocas: Incrementar el número de épocas para mejorar el entrenamiento.\n\t4.\tNormalización:\n\t•\tNormalización de Datos: Asegurarse de que los datos estén correctamente normalizados.\n\nVamos a implementar data augmentation y regularización (con Dropout) para mejorar el modelo.","metadata":{}},{"cell_type":"markdown","source":"# 9- Modelo mejorado con data augmentation y regularización (con Dropout)\n\nExplicación:\n\n\t1.\tData Augmentation:\n\t•\tUtiliza ImageDataGenerator para aplicar rotaciones, desplazamientos, cambios de escala, y más. Esto ayuda a mejorar la capacidad de generalización del modelo.\n\t2.\tDropout:\n\t•\tAñade capas de Dropout después de las capas convolucionales y densas para prevenir el sobreajuste.\n\t3.\tAjustes en el Modelo:\n\t•\tNúmero de Épocas: Se ha incrementado el número de épocas a 20 para permitir un entrenamiento más prolongado.\n\t4.\tEntrenamiento:\n\t•\tSe usa datagen.flow para alimentar datos aumentados al modelo durante el entrenamiento.\n","metadata":{}},{"cell_type":"code","source":"# Definir el generador de datos para data augmentation\ndatagen = ImageDataGenerator(\n    rotation_range=20,\n    width_shift_range=0.2,\n    height_shift_range=0.2,\n    shear_range=0.2,\n    zoom_range=0.2,\n    horizontal_flip=True,\n    fill_mode='nearest'\n)\n\n# Crear el modelo CNN mejorado\nmodelo_mejorado = Sequential()\n\n# Capa 1: Convolución + MaxPooling\nmodelo_mejorado.add(Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 1)))\nmodelo_mejorado.add(MaxPooling2D(pool_size=(2, 2)))\nmodelo_mejorado.add(Dropout(0.25))  # Añadir Dropout\n\n# Capa 2: Convolución + MaxPooling\nmodelo_mejorado.add(Conv2D(64, (3, 3), activation='relu'))\nmodelo_mejorado.add(MaxPooling2D(pool_size=(2, 2)))\nmodelo_mejorado.add(Dropout(0.25))  # Añadir Dropout\n\n# Capa 3: Convolución + MaxPooling\nmodelo_mejorado.add(Conv2D(128, (3, 3), activation='relu'))\nmodelo_mejorado.add(MaxPooling2D(pool_size=(2, 2)))\nmodelo_mejorado.add(Dropout(0.25))  # Añadir Dropout\n\n# Aplanar las características 2D para convertirlas a un vector 1D\nmodelo_mejorado.add(Flatten())\n\n# Capa Densa con 128 neuronas\nmodelo_mejorado.add(Dense(128, activation='relu'))\nmodelo_mejorado.add(Dropout(0.5))  # Añadir Dropout\n\n# Capa de salida (clasificación binaria)\nmodelo_mejorado.add(Dense(1, activation='sigmoid'))\n\n# Compilar el modelo\nmodelo_mejorado.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])\n\n# Ajustar el modelo usando el generador de datos para data augmentation\nmodelo_mejorado.fit(datagen.flow(X_train, y_train, batch_size=32),\n                    epochs=20,  # Incrementar el número de épocas\n                    validation_data=(X_val, y_val))\n\n# Evaluar el modelo mejorado\npérdida_mejorada, precisión_mejorada = modelo_mejorado.evaluate(X_val, y_val)\nprint(f'Precisión en el conjunto de validación: {precisión_mejorada:.4f}')\nprint(f'Pérdida en el conjunto de validación: {pérdida_mejorada:.4f}')","metadata":{"execution":{"iopub.status.busy":"2024-09-13T09:52:49.816755Z","iopub.status.idle":"2024-09-13T09:52:49.817205Z","shell.execute_reply.started":"2024-09-13T09:52:49.816985Z","shell.execute_reply":"2024-09-13T09:52:49.817006Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Hacer predicciones con el modelo mejorado\npredicciones = modelo_mejorado.predict(X_test)\n\n# Convertir predicciones a etiquetas binarias\netiquetas_predichas = (predicciones > 0.5).astype(int).flatten()  # 0 para gato, 1 para perro\n\n# Mostrar algunas imágenes y sus predicciones\nmostrar_imagenes_con_predicciones(X_test, etiquetas_predichas, nombres_imagenes)","metadata":{"execution":{"iopub.status.busy":"2024-09-13T09:52:49.818530Z","iopub.status.idle":"2024-09-13T09:52:49.818953Z","shell.execute_reply.started":"2024-09-13T09:52:49.818746Z","shell.execute_reply":"2024-09-13T09:52:49.818767Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Todavía hay errores de clasificación, que podemos hacer?\n\n¡Me alegra saber que el modelo ha mejorado! Sin embargo, si sigue fallando en una de las imágenes, puedes aplicar varias estrategias adicionales para optimizar aún más el rendimiento. Aquí te dejo varias recomendaciones que puedes seguir para seguir afinando el modelo:\n\n### 1. **Aumentar el dataset** (si es posible)\n   - Si tienes acceso a más datos, añadir más imágenes de gatos y perros mejorará significativamente el rendimiento del modelo. Los modelos de deep learning se benefician mucho de grandes cantidades de datos para aprender mejor las características distintivas.\n\n### 2. **Ajustar Hiperparámetros**:\n   - **Tasa de aprendizaje**: Cambiar la tasa de aprendizaje puede tener un gran impacto en el rendimiento. Puedes utilizar un **scheduler** para reducir la tasa de aprendizaje durante el entrenamiento.\n   - **Optimización más avanzada**: En lugar de usar el optimizador `Adam` por defecto, puedes ajustar los parámetros o probar otros optimizadores como **RMSprop** o **SGD** con momento.\n\n#### Implementación:\n\n```python\nfrom tensorflow.keras.callbacks import ReduceLROnPlateau\n\n# Reducción de la tasa de aprendizaje si no hay mejoras\nreduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3, min_lr=1e-6)\n\n# Compilar el modelo con un optimizador más ajustado\nmodelo_mejorado.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001),\n                        loss='binary_crossentropy', metrics=['accuracy'])\n\n# Ajustar el modelo con reducción de la tasa de aprendizaje\nmodelo_mejorado.fit(datagen.flow(X_train, y_train, batch_size=32),\n                    epochs=20,\n                    validation_data=(X_val, y_val),\n                    callbacks=[reduce_lr])\n```\n\n- **`ReduceLROnPlateau`**: Reduce la tasa de aprendizaje en un factor de 0.5 si no se observa mejora en la pérdida del conjunto de validación durante 3 épocas consecutivas.\n- **`Adam(learning_rate=0.0001)`**: Reduce la tasa de aprendizaje inicial para que el modelo ajuste los pesos con más precisión.\n\n### 3. **Aumentar la complejidad del modelo**:\n   Si tu modelo está subentrenando (subfitting), es decir, que no está capturando bien las características del conjunto de datos, podrías aumentar la capacidad del modelo.\n\n#### Propuesta: Añadir más capas convolucionales y/o neuronas\n\n```python\n# Capa 4: Convolución + MaxPooling\nmodelo_mejorado.add(Conv2D(256, (3, 3), activation='relu'))\nmodelo_mejorado.add(MaxPooling2D(pool_size=(2, 2)))\nmodelo_mejorado.add(Dropout(0.25))\n\n# Añadir otra capa densa más grande\nmodelo_mejorado.add(Dense(256, activation='relu'))\nmodelo_mejorado.add(Dropout(0.5))\n```\n\n- **Añadir más filtros** en las capas convolucionales aumenta la capacidad del modelo para aprender características más complejas.\n- **Capa densa más grande**: Aumentar el número de neuronas en la capa densa a 256 permitirá que el modelo aprenda representaciones más ricas antes de la clasificación final.\n\n### 4. **Técnicas avanzadas de regularización**:\n   - **Batch Normalization**: Puede ayudar a estabilizar y acelerar el entrenamiento al normalizar las activaciones en cada capa. Esto puede hacer que el modelo sea más robusto y converja más rápido.\n\n#### Implementación:\n\n```python\nfrom tensorflow.keras.layers import BatchNormalization\n\n# Añadir Batch Normalization después de cada capa convolucional\nmodelo_mejorado.add(Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 1)))\nmodelo_mejorado.add(BatchNormalization())\nmodelo_mejorado.add(MaxPooling2D(pool_size=(2, 2)))\nmodelo_mejorado.add(Dropout(0.25))\n\n# Repetir el mismo patrón para otras capas\n```\n\n- **`BatchNormalization()`**: Alinea las activaciones en una capa a una distribución con media 0 y desviación estándar 1, lo que mejora la estabilidad del entrenamiento.\n\n### 5. **Data Augmentation más avanzado**:\n   Si el modelo sigue teniendo problemas para aprender ciertas características, podrías aplicar técnicas de augmentación más específicas como:\n   - **Aumentar más el rango de rotación, recortes o zoom**.\n   - **Gamma Correction**: Ajustar el brillo o contraste de las imágenes para entrenar al modelo a reconocer patrones en condiciones variadas.\n\n#### Ejemplo de cambios:\n\n```python\ndatagen = ImageDataGenerator(\n    rotation_range=40,  # Aumentar la rotación\n    width_shift_range=0.3,\n    height_shift_range=0.3,\n    shear_range=0.3,\n    zoom_range=0.3,\n    brightness_range=[0.5, 1.5],  # Cambiar el brillo\n    horizontal_flip=True,\n    fill_mode='nearest'\n)\n```\n\n### 6. **Aumentar el número de épocas**:\n   Aumentar el número de épocas puede ayudar si el modelo necesita más tiempo para aprender las características del dataset. Sin embargo, es importante monitorear el rendimiento para asegurarse de que no haya sobreajuste.\n\n#### Ajuste del código:\n\n```python\nmodelo_mejorado.fit(datagen.flow(X_train, y_train, batch_size=32),\n                    epochs=50,  # Aumentar las épocas a 50\n                    validation_data=(X_val, y_val),\n                    callbacks=[reduce_lr])\n```\n\n### 7. **Transfer Learning**:\n   Si sigues teniendo problemas con el rendimiento, puedes intentar usar un modelo preentrenado con **Transfer Learning**, como **VGG16**, **ResNet50**, etc. Estos modelos ya están preentrenados en grandes datasets (como ImageNet) y pueden ser ajustados para tu tarea específica.\n\n#### Ejemplo con Transfer Learning usando VGG16:\n\n```python\nfrom tensorflow.keras.applications import VGG16\n\n# Cargar el modelo preentrenado VGG16, sin la capa superior (clasificación)\nbase_model = VGG16(weights='imagenet', include_top=False, input_shape=(128, 128, 3))\n\n# Añadir capas adicionales de clasificación\nmodelo_transfer = Sequential()\nmodelo_transfer.add(base_model)\nmodelo_transfer.add(Flatten())\nmodelo_transfer.add(Dense(256, activation='relu'))\nmodelo_transfer.add(Dropout(0.5))\nmodelo_transfer.add(Dense(1, activation='sigmoid'))\n\n# Congelar las capas del modelo preentrenado\nfor layer in base_model.layers:\n    layer.trainable = False\n\n# Compilar el modelo\nmodelo_transfer.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])\n\n# Entrenar el modelo con las capas superiores\nmodelo_transfer.fit(datagen.flow(X_train, y_train, batch_size=32),\n                    epochs=20,\n                    validation_data=(X_val, y_val))\n```\n\nEn este caso, usas la red **VGG16** preentrenada para extraer características y solo entrenas las capas superiores, lo que puede mejorar mucho la precisión sin requerir un gran número de imágenes.\n\n---\n\n### Resumen de estrategias adicionales:\n\n1. **Ajustar la tasa de aprendizaje y usar un scheduler**.\n2. **Aumentar la complejidad del modelo** añadiendo más capas y neuronas.\n3. **Usar Batch Normalization** para estabilizar el entrenamiento.\n4. **Mejorar la augmentación de datos**.\n5. **Aumentar el número de épocas**.\n6. **Probar Transfer Learning** con modelos preentrenados como VGG16 o ResNet50.\n\nPrueba algunas de estas estrategias y ve si logras mejorar aún más el rendimiento. Si necesitas ayuda implementando alguna de estas técnicas o si tienes más dudas, ¡estaré aquí para ayudarte!","metadata":{}}]}