{"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":30762,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 1- Import Libraries\n","metadata":{}},{"cell_type":"code","source":"import os              # Permite interactuar con el sistema de archivos.\nimport numpy as np      # Trabaja con arrays y operaciones matemáticas eficientes.\nimport pandas as pd     # Maneja y analiza grandes conjuntos de datos estructurados.\nimport random as rnd    # Genera números aleatorios para simulaciones o muestreo.\nimport matplotlib.pyplot as plt  # Crea gráficos y visualizaciones de datos.\n%matplotlib inline      \n# Muestra gráficos dentro de notebooks.\n\nfrom sklearn.model_selection import train_test_split  # Divide datos en conjuntos de entrenamiento y prueba.\n\nimport keras                          # Biblioteca para construir redes neuronales.\nfrom keras.models import Sequential   # Construye modelos de redes neuronales secuenciales.\nfrom keras.utils import to_categorical  # Convierte etiquetas a formato categórico.\nfrom keras.preprocessing.image import load_img  # Carga imágenes para su procesamiento.\nfrom keras.layers import Flatten, Dense, Dropout  # Define capas de redes neuronales.\nfrom keras.layers import Conv2D, MaxPool2D, BatchNormalization, Activation  # Capas para redes neuronales convolucionales.\n\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator  # Aumenta y prepara imágenes para el entrenamiento.\n\nprint(os.listdir(\"/kaggle/input/dogs-vs-cats\"))  # Muestra los archivos en la carpeta especificada.","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:38:51.645569Z","iopub.execute_input":"2024-09-07T12:38:51.645953Z","iopub.status.idle":"2024-09-07T12:39:04.921242Z","shell.execute_reply.started":"2024-09-07T12:38:51.645915Z","shell.execute_reply":"2024-09-07T12:39:04.920244Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2- Data-Constants","metadata":{}},{"cell_type":"code","source":"FAST_RUN = False  # Opción para entrenar más rápido o más completo (se usa mas tarde).\nIMAGE_WIDTH = 128  # El ancho de cada imagen que vamos a usar.\nIMAGE_HEIGHT = 128  # La altura de cada imagen que vamos a usar.\nIMAGE_CHANNELS = 3  # Indica que las imágenes son a color (3 colores: rojo, verde, azul).\nIMAGE_SIZE = (IMAGE_WIDTH, IMAGE_HEIGHT)  # Establece el tamaño final de las imágenes que usaremos.","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:04.922831Z","iopub.execute_input":"2024-09-07T12:39:04.923364Z","iopub.status.idle":"2024-09-07T12:39:04.928300Z","shell.execute_reply.started":"2024-09-07T12:39:04.923330Z","shell.execute_reply":"2024-09-07T12:39:04.927453Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3- Load DataSet","metadata":{}},{"cell_type":"code","source":"# import zipfile\n\n# zip_files = ['test1', 'train']\n\n# for zip_file in zip_files:\n#     with zipfile.ZipFile(f\"../input/dogs-vs-cats/{zip_file}.zip\", \"r\") as z:\n#         z.extractall(\".\")\n#         print(f\"{zip_file} unzipped\")","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:04.929496Z","iopub.execute_input":"2024-09-07T12:39:04.929814Z","iopub.status.idle":"2024-09-07T12:39:04.965624Z","shell.execute_reply.started":"2024-09-07T12:39:04.929777Z","shell.execute_reply":"2024-09-07T12:39:04.964808Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ## Extract Compressed Files","metadata":{}},{"cell_type":"code","source":"import zipfile  # Sirve para abrir y descomprimir archivos comprimidos (.zip)\n\npath = \"/kaggle/input/dogs-vs-cats\"  # Ubicación de los archivos comprimidos.(es un dataset disponible en kaggle)\nfor zip_file in os.listdir(path)[:2]:  # Recorre los primeros 2 archivos en esa ubicación.\n    zipfile.ZipFile(f\"{path}/{zip_file}\", 'r').extractall(\".\")  # Abre y descomprime los archivos.\n#     print(f\"{path}/{zip_file}\")  # (opcional) Muestra la ruta completa de cada archivo.\n    print(f\"{zip_file} unzipped\")  # Muestra que el archivo ha sido descomprimido.","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:04.968197Z","iopub.execute_input":"2024-09-07T12:39:04.969162Z","iopub.status.idle":"2024-09-07T12:39:21.967633Z","shell.execute_reply.started":"2024-09-07T12:39:04.969116Z","shell.execute_reply":"2024-09-07T12:39:21.966714Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4- Data Preprocessing","metadata":{}},{"cell_type":"markdown","source":"> ## Label Encoding","metadata":{}},{"cell_type":"code","source":"train_images = os.listdir(\"/kaggle/working/train\")  # Lista los nombres de las imágenes en la carpeta \"train\".\nCATEGORIES = []  # Aquí guardaremos las categorías (0 o 1) de cada imagen.\n\nfor image_name in train_images:  # Recorre cada imagen en la carpeta \"train\".\n    class_name = image_name.split('.')[0]  # Toma el nombre antes del punto, por ejemplo: \"cat\" de \"cat.588.jpg\".\n    CATEGORIES.append(0 if class_name == 'cat' else 1)  # Si es \"cat\", asigna 0; si no, asigna 1.\n\ndf = pd.DataFrame({\"train_images\": train_images, \"CATEGORIES\": CATEGORIES})  # Crea una tabla con las imágenes y sus categorías.\n","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:21.968689Z","iopub.execute_input":"2024-09-07T12:39:21.968999Z","iopub.status.idle":"2024-09-07T12:39:22.016534Z","shell.execute_reply.started":"2024-09-07T12:39:21.968968Z","shell.execute_reply":"2024-09-07T12:39:22.015779Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ## Show DataFrame","metadata":{}},{"cell_type":"code","source":"df.head() #nos muestra las primeras filas del dataframe categorizado","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:22.017914Z","iopub.execute_input":"2024-09-07T12:39:22.018193Z","iopub.status.idle":"2024-09-07T12:39:22.035450Z","shell.execute_reply.started":"2024-09-07T12:39:22.018163Z","shell.execute_reply":"2024-09-07T12:39:22.034532Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.tail() #nos muestra las últimas filas del dataframe","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:22.036613Z","iopub.execute_input":"2024-09-07T12:39:22.036923Z","iopub.status.idle":"2024-09-07T12:39:22.045582Z","shell.execute_reply.started":"2024-09-07T12:39:22.036892Z","shell.execute_reply":"2024-09-07T12:39:22.044613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### df.describe()\n¿Qué hace?\nEste comando proporciona información como:\n\n- Conteo (count): Número total de elementos en cada columna.\n- Promedio (mean): Promedio de los valores en las columnas numéricas.\n- Desviación estándar (std): Mide la variación o dispersión de los datos.\n- Valores mínimos (min) y máximos (max): El valor más bajo y más alto en cada columna.\n- Percentiles: Valores que dividen el conjunto de datos en partes (25%, 50%, 75%).","metadata":{}},{"cell_type":"code","source":"df.describe()  # Genera un resumen estadístico de los datos numéricos.","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:22.046725Z","iopub.execute_input":"2024-09-07T12:39:22.047063Z","iopub.status.idle":"2024-09-07T12:39:22.067526Z","shell.execute_reply.started":"2024-09-07T12:39:22.047031Z","shell.execute_reply":"2024-09-07T12:39:22.066690Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df[\"CATEGORIES\"].value_counts() #cuenta todos los resultados de cada categoría, tendremos 12500 gatos (0) y 12500 perros (1) en nuestra data","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:22.068713Z","iopub.execute_input":"2024-09-07T12:39:22.069368Z","iopub.status.idle":"2024-09-07T12:39:22.080277Z","shell.execute_reply.started":"2024-09-07T12:39:22.069324Z","shell.execute_reply":"2024-09-07T12:39:22.079385Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ## Visualize The Data","metadata":{}},{"cell_type":"code","source":"df[\"CATEGORIES\"].value_counts().plot.bar() #muestra el gráfico\n# Cambiamos las etiquetas del eje x, así sale cats/dogs en lugar de solo 0 y 1\nplt.xticks([0, 1], ['cats (0)', 'dogs (1)'])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:22.084512Z","iopub.execute_input":"2024-09-07T12:39:22.084831Z","iopub.status.idle":"2024-09-07T12:39:22.317087Z","shell.execute_reply.started":"2024-09-07T12:39:22.084797Z","shell.execute_reply":"2024-09-07T12:39:22.316165Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ## *From our data we have 12500 cats and 12500 dogs*","metadata":{}},{"cell_type":"markdown","source":"> ## Show Dimensions Of Images","metadata":{}},{"cell_type":"code","source":"shapes = []  # Lista para almacenar las dimensiones de cada imagen.\n\nfor image in df[\"train_images\"]:  # Recorre cada imagen en el DataFrame.\n    path = os.path.join(\"/kaggle/working/train\", image)  # Crea la ruta completa para cada imagen.\n    image_array = plt.imread(path)  # Lee la imagen y la convierte a un formato que el programa pueda entender.\n    shapes.append(image_array.shape)  # Guarda las dimensiones (alto, ancho, canales) de la imagen.\n\n# Muestra cuántas imágenes tienen las mismas dimensiones.\nprint(pd.Series(shapes).value_counts())  \n\n# Encuentra el índice de la imagen con la dimensión más pequeña.\nindex = np.argmin(shapes)  \nprint(f\"\\nThe Minimum Dimension is ==> {shapes[index]}\\n\")  # Muestra las dimensiones más pequeñas encontradas.\nprint(\"*El número 3 al final representa los canales (R,G,B)\")\n","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:22.318338Z","iopub.execute_input":"2024-09-07T12:39:22.318723Z","iopub.status.idle":"2024-09-07T12:39:51.519644Z","shell.execute_reply.started":"2024-09-07T12:39:22.318670Z","shell.execute_reply":"2024-09-07T12:39:51.518790Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ## **See sample image**\n","metadata":{}},{"cell_type":"code","source":"sample = rnd.choice(train_images)  # Selecciona una imagen al azar de la lista \"train_images\".\nimage = load_img(os.path.join(\"/kaggle/working/train\", sample))  # Carga la imagen seleccionada desde su ubicación.\nprint(type(image))  # Muestra el tipo de objeto de la imagen (normalmente, será una imagen en formato PIL).\n\nplt.imshow(image)  # Muestra la imagen seleccionada en pantalla.\nplt.axis(\"off\")  # Oculta los ejes de la imagen (no queremos ver números alrededor).\nplt.show()  # Muestra la imagen final sin ejes.\n","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:51.520831Z","iopub.execute_input":"2024-09-07T12:39:51.521157Z","iopub.status.idle":"2024-09-07T12:39:51.784513Z","shell.execute_reply.started":"2024-09-07T12:39:51.521125Z","shell.execute_reply":"2024-09-07T12:39:51.783584Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # Prepare data","metadata":{}},{"cell_type":"code","source":"df[\"CATEGORIES\"] = df[\"CATEGORIES\"].replace({0: 'cat', 1: 'dog'})  # Reemplaza 0 por \"cat\" y 1 por \"dog\" en la columna CATEGORIES. (igual que hemos hecho antes con el gráfico)","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:51.785665Z","iopub.execute_input":"2024-09-07T12:39:51.785989Z","iopub.status.idle":"2024-09-07T12:39:51.793678Z","shell.execute_reply.started":"2024-09-07T12:39:51.785953Z","shell.execute_reply":"2024-09-07T12:39:51.792813Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # Split Data\nTenemos que dividir la data para tener una parte para entrenar y otra para validar si el modelo funciona","metadata":{}},{"cell_type":"code","source":"train_df, valid_df = train_test_split(df, test_size=0.20, random_state=42)  \n# Divide los datos en dos partes: 80% para entrenar y 20% para validar. train_test_split proviene de la librería sklearn.\n\ntrain_df = train_df.reset_index(drop=True)  \n# Resetea los índices del conjunto de entrenamiento, eliminando los números originales.\n\nvalid_df = valid_df.reset_index(drop=True)  \n# Resetea los índices del conjunto de validación, eliminando los números originales.","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:51.795169Z","iopub.execute_input":"2024-09-07T12:39:51.795604Z","iopub.status.idle":"2024-09-07T12:39:51.810790Z","shell.execute_reply.started":"2024-09-07T12:39:51.795561Z","shell.execute_reply":"2024-09-07T12:39:51.809871Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"> # Show train DataFrame","metadata":{}},{"cell_type":"code","source":"train_df['CATEGORIES'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:51.811913Z","iopub.execute_input":"2024-09-07T12:39:51.812209Z","iopub.status.idle":"2024-09-07T12:39:51.822197Z","shell.execute_reply.started":"2024-09-07T12:39:51.812177Z","shell.execute_reply":"2024-09-07T12:39:51.821340Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df['CATEGORIES'].value_counts().plot.bar()","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:51.823386Z","iopub.execute_input":"2024-09-07T12:39:51.823688Z","iopub.status.idle":"2024-09-07T12:39:52.044866Z","shell.execute_reply.started":"2024-09-07T12:39:51.823655Z","shell.execute_reply":"2024-09-07T12:39:52.044002Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # Show valid DataFrame","metadata":{}},{"cell_type":"code","source":"valid_df['CATEGORIES'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:52.046191Z","iopub.execute_input":"2024-09-07T12:39:52.046567Z","iopub.status.idle":"2024-09-07T12:39:52.055357Z","shell.execute_reply.started":"2024-09-07T12:39:52.046522Z","shell.execute_reply":"2024-09-07T12:39:52.054328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"valid_df['CATEGORIES'].value_counts().plot.bar()","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:52.057416Z","iopub.execute_input":"2024-09-07T12:39:52.057722Z","iopub.status.idle":"2024-09-07T12:39:52.267657Z","shell.execute_reply.started":"2024-09-07T12:39:52.057689Z","shell.execute_reply":"2024-09-07T12:39:52.266738Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # Data Augmentation","metadata":{}},{"cell_type":"code","source":"total_train = train_df.shape[0]  # Cuenta el número total de imágenes en el conjunto de entrenamiento.\ntotal_validate = valid_df.shape[0]  # Cuenta el número total de imágenes en el conjunto de validación.\nbatch_size = 15  # Define el número de imágenes que procesamos a la vez durante el entrenamiento.\n\nprint(f'TOTAL TRAIN: {total_train}')\nprint(f'TOTAL VALIDATE: {total_validate}')","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:52.269591Z","iopub.execute_input":"2024-09-07T12:39:52.270329Z","iopub.status.idle":"2024-09-07T12:39:52.275693Z","shell.execute_reply.started":"2024-09-07T12:39:52.270281Z","shell.execute_reply":"2024-09-07T12:39:52.274801Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ## Train Generator","metadata":{}},{"cell_type":"code","source":"df.head()","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:52.276891Z","iopub.execute_input":"2024-09-07T12:39:52.277173Z","iopub.status.idle":"2024-09-07T12:39:52.289479Z","shell.execute_reply.started":"2024-09-07T12:39:52.277143Z","shell.execute_reply":"2024-09-07T12:39:52.288510Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Procesamiento de Imágenes para el Entrenamiento\n\n`ImageDataGenerator` aplica transformaciones como rotaciones y zoom para mejorar los datos de entrenamiento. `flow_from_dataframe` carga imágenes y categorías de un archivo. El modo `categorical` clasifica las imágenes como gato o perro. `batch_size` define cuántas imágenes se procesan juntas.\n\nAumentar y transformar imágenes durante el entrenamiento mejora la capacidad del modelo para generalizar y reconocer patrones, incluso en situaciones nuevas. Al procesar las imágenes en pequeños lotes y etiquetarlas correctamente, optimizamos el uso de recursos computacionales y mejoramos la precisión del modelo en la clasificación.\n\n","metadata":{}},{"cell_type":"code","source":"train_datagen = ImageDataGenerator(  # Crea un generador que transforma las imágenes de varias maneras.\n    rotation_range=15,  # Gira las imágenes hasta 15 grados al azar.\n    rescale=1./255,  # Normaliza los valores de los píxeles para que estén entre 0 y 1.\n    shear_range=0.1,  # Aplica un efecto de corte o \"cisallamiento\" en las imágenes.\n    zoom_range=0.2,  # Realiza un zoom al azar en las imágenes hasta un 20%.\n    horizontal_flip=True,  # Gira las imágenes horizontalmente (de izquierda a derecha).\n    width_shift_range=0.1,  # Desplaza las imágenes horizontalmente hasta un 10%.\n    height_shift_range=0.1  # Desplaza las imágenes verticalmente hasta un 10%.\n)\n\ntrain_generator = train_datagen.flow_from_dataframe(  # Genera imágenes modificadas a partir del DataFrame.\n    train_df,  # Usa el conjunto de entrenamiento.\n    \"/kaggle/working/train\",  # Ruta donde están almacenadas las imágenes.\n    x_col='train_images',  # Columna que contiene los nombres de las imágenes.\n    y_col='CATEGORIES',  # Columna que contiene las categorías (gato o perro).\n    target_size=IMAGE_SIZE,  # Tamaño al que se redimensionarán las imágenes.\n    class_mode='categorical',  # Las etiquetas de las imágenes estarán en formato categórico (una para gato, otra para perro).\n    batch_size=batch_size  # Número de imágenes procesadas juntas en cada lote.\n)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:52.290696Z","iopub.execute_input":"2024-09-07T12:39:52.291012Z","iopub.status.idle":"2024-09-07T12:39:52.548259Z","shell.execute_reply.started":"2024-09-07T12:39:52.290981Z","shell.execute_reply":"2024-09-07T12:39:52.547302Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # Valid Generator\n\nAún no estamos entrenando el modelo. Lo que estamos haciendo es preparar el conjunto de validación con valid_generator. Esto será usado más adelante durante el entrenamiento para evaluar el rendimiento del modelo. Es decir, una vez que entrenemos el modelo con los datos de entrenamiento, el conjunto de validación se usará para ver qué tan bien el modelo generaliza a datos que no ha visto antes.","metadata":{}},{"cell_type":"code","source":"valid_datagen = ImageDataGenerator(rescale=1./255)  \n# Normaliza los valores de los píxeles de las imágenes de validación, convirtiéndolos en un rango de 0 a 1.\n\nvalid_generator = valid_datagen.flow_from_dataframe(  \n    valid_df,  # Utiliza el conjunto de datos de validación.\n    \"/kaggle/working/train\",  # Ruta donde están almacenadas las imágenes.\n    x_col='train_images',  # Columna que contiene los nombres de las imágenes.\n    y_col='CATEGORIES',  # Columna que contiene las categorías (gato o perro).\n    target_size=IMAGE_SIZE,  # Redimensiona las imágenes al tamaño especificado.\n    class_mode='categorical',  # Las etiquetas están en formato categórico (gato/perro).\n    batch_size=batch_size  # Procesa las imágenes en lotes pequeños, de tamaño batch_size.\n)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:52.549536Z","iopub.execute_input":"2024-09-07T12:39:52.549949Z","iopub.status.idle":"2024-09-07T12:39:52.619453Z","shell.execute_reply.started":"2024-09-07T12:39:52.549901Z","shell.execute_reply":"2024-09-07T12:39:52.618585Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"># Example Generator\n\nLo que estamos haciendo ahora es seleccionar una imagen de ejemplo del conjunto de entrenamiento y prepararla con el `example_generator`. Esto se usa para ver cómo se procesará una imagen antes de aplicar el modelo completo. Este generador realiza las transformaciones necesarias (como redimensionado y normalización) y ayuda a visualizar cómo se manejan las imágenes individuales en el flujo de datos.\n","metadata":{}},{"cell_type":"code","source":"example_df = train_df.sample(n=1)  # Toma una muestra aleatoria de 1 imagen del conjunto de entrenamiento.\nprint(example_df, \"\\n\")  # Muestra la información de esa imagen seleccionada.\n\nexample_df = example_df.reset_index(drop=True)  # Reinicia los índices de la muestra seleccionada para que empiece desde 0.\nprint(example_df, \"\\n\")  # Muestra la información con el nuevo índice.\n\nexample_generator = train_datagen.flow_from_dataframe(\n    example_df,  # Utiliza la muestra de 1 imagen que seleccionamos.\n    \"/kaggle/working/train\",  # Ruta donde están las imágenes.\n    x_col='train_images',  # Columna con los nombres de las imágenes.\n    y_col='CATEGORIES',  # Columna con las categorías (gato o perro).\n    target_size=IMAGE_SIZE,  # Redimensiona la imagen al tamaño deseado.\n    class_mode='categorical'  # Define que las categorías son en formato categórico (gato o perro).\n)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:52.620448Z","iopub.execute_input":"2024-09-07T12:39:52.620781Z","iopub.status.idle":"2024-09-07T12:39:52.635989Z","shell.execute_reply.started":"2024-09-07T12:39:52.620736Z","shell.execute_reply":"2024-09-07T12:39:52.634950Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # Show Generated Images from One-Image\n\nEn esta parte, estamos usando el `example_generator` para visualizar cómo las imágenes seleccionadas aleatoriamente del conjunto de entrenamiento se procesan antes del entrenamiento completo. Mostramos varias imágenes transformadas (como redimensionado o volteo) para verificar que las modificaciones realizadas por el generador sean correctas. Esta visualización nos permite comprobar que el flujo de datos funciona como se espera antes de pasar al proceso de entrenamiento.\n","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(12, 12))  # Crea una figura de tamaño 12x12 para mostrar varias imágenes.\nfor i in range(0, 15):  # Repite el proceso 15 veces para mostrar 15 imágenes.\n    plt.subplot(5, 3, i+1)  # Divide el área de la figura en una cuadrícula de 5 filas y 3 columnas.\n    for X_batch, Y_batch in example_generator:  # Obtiene un lote de imágenes y sus categorías del generador.\n        image = X_batch[0]  # Toma la primera imagen del lote.\n        plt.imshow(image)  # Muestra la imagen.\n        plt.axis('off')  # Oculta los ejes alrededor de la imagen.\n        break  # Sale del bucle después de mostrar la imagen para evitar mostrar el mismo lote varias veces.\nplt.tight_layout()  # Ajusta el diseño para que las imágenes no se superpongan.\nplt.show()  # Muestra la figura con todas las imágenes.","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:52.637312Z","iopub.execute_input":"2024-09-07T12:39:52.637646Z","iopub.status.idle":"2024-09-07T12:39:53.810114Z","shell.execute_reply.started":"2024-09-07T12:39:52.637613Z","shell.execute_reply":"2024-09-07T12:39:53.809111Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 5- Build The Model","metadata":{}},{"cell_type":"markdown","source":"![image](https://i.imgur.com/ebkMGGu.jpg)","metadata":{}},{"cell_type":"markdown","source":"> * **Input Layer**: It represent input image data. It will reshape image into single diminsion array. Example your image is 64x64 = 4096, it will convert to (4096,1) array.\n> * **Conv Layer**: This layer will extract features from image.\n> * **Pooling Layer**: This layerreduce the spatial volume of input image after convolution.\n> * **Fully Connected Layer**: It connect the network from a layer to another layer\n> * **Output Layer**: It is the predicted values layer.","metadata":{}},{"cell_type":"markdown","source":"> # Fit Model\nEn esta fase, estamos construyendo la estructura del modelo. Definimos las capas que utilizará para procesar y clasificar las imágenes, como capas convolucionales, de agrupación y densas. Además, lo configuramos para que pueda ser entrenado más adelante, especificando la función de pérdida, el optimizador y las métricas que evaluaremos. Aún no estamos entrenando el modelo; simplemente lo estamos preparando para el siguiente paso.","metadata":{}},{"cell_type":"code","source":"model = Sequential([  # Creamos un modelo secuencial, donde las capas se apilan una tras otra.\n    Conv2D(32, (3, 3), activation='relu', input_shape=(IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_CHANNELS)),  \n    # Capa convolucional que aplica 32 filtros de tamaño 3x3 a las imágenes. Ayuda a detectar patrones como bordes.\n    \n    MaxPool2D(pool_size=(4,4)),  # Reduce el tamaño de la imagen, manteniendo solo la información importante.\n    Dropout(rate=0.25),  # Apaga aleatoriamente el 25% de las neuronas para evitar sobreajuste.\n\n    Conv2D(64, (3, 3), activation='relu'),  # Segunda capa convolucional con 64 filtros.\n    BatchNormalization(),  # Normaliza los valores de salida para mejorar la estabilidad y acelerar el entrenamiento.\n    MaxPool2D(pool_size=(4,4)),  # Segunda reducción del tamaño de la imagen.\n    Dropout(rate=0.25),  # Apaga el 25% de las neuronas.\n\n    Conv2D(128, (3, 3), activation='relu'),  # Tercera capa convolucional con 128 filtros.\n    BatchNormalization(),  # Normaliza las salidas.\n    MaxPool2D(pool_size=(4,4)),  # Tercera reducción de tamaño de la imagen.\n    Dropout(rate=0.25),  # Apaga el 25% de las neuronas.\n\n    Flatten(),  # Aplana la imagen en un vector para que pueda ser usada en las capas densas.\n\n    Dense(512, activation='relu'),  # Capa densa totalmente conectada con 512 neuronas.\n    Dropout(rate=0.5),  # Apaga el 50% de las neuronas para evitar sobreajuste.\n\n    Dense(2, activation='softmax')  # Capa de salida con 2 neuronas (gato o perro) usando softmax para clasificación.\n])\n\n# Compilación del modelo\nmodel.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])  \n# Configura el modelo con la función de pérdida, el optimizador y la métrica que mediremos (exactitud).\n\n# Resumen del Modelo\nmodel.summary()  # Muestra un resumen de las capas y parámetros del modelo.\n","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:53.811394Z","iopub.execute_input":"2024-09-07T12:39:53.811711Z","iopub.status.idle":"2024-09-07T12:39:54.580446Z","shell.execute_reply.started":"2024-09-07T12:39:53.811678Z","shell.execute_reply":"2024-09-07T12:39:54.579496Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ## Callbacks","metadata":{}},{"cell_type":"code","source":"from keras.callbacks import EarlyStopping, ReduceLROnPlateau","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:54.581469Z","iopub.execute_input":"2024-09-07T12:39:54.581787Z","iopub.status.idle":"2024-09-07T12:39:54.587107Z","shell.execute_reply.started":"2024-09-07T12:39:54.581727Z","shell.execute_reply":"2024-09-07T12:39:54.586064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ### Early Stop\n> To prevent over fitting we will stop the learning after 10 epochs and val_loss value not decreased","metadata":{}},{"cell_type":"code","source":"earlystop = EarlyStopping(patience=5)","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:54.588475Z","iopub.execute_input":"2024-09-07T12:39:54.589366Z","iopub.status.idle":"2024-09-07T12:39:54.595416Z","shell.execute_reply.started":"2024-09-07T12:39:54.589321Z","shell.execute_reply":"2024-09-07T12:39:54.594516Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ### Learning Rate Reduction\n> We will reduce the learning rate when then accuracy not increase for 2 steps","metadata":{}},{"cell_type":"code","source":"learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc',  # Monitorea la exactitud en los datos de validación.\n                                            patience=2,  # Si no mejora en 2 épocas, reduce la tasa de aprendizaje.\n                                            verbose=1,  # Muestra mensajes sobre el cambio de la tasa de aprendizaje.\n                                            factor=0.5,  # Reduce la tasa de aprendizaje a la mitad.\n                                            min_lr=0.00001)  # Define la tasa de aprendizaje mínima.\n\ncallbacks = [earlystop, learning_rate_reduction]  # Lista de funciones especiales que ejecutamos durante el entrenamiento.\n","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:54.601977Z","iopub.execute_input":"2024-09-07T12:39:54.602271Z","iopub.status.idle":"2024-09-07T12:39:54.607349Z","shell.execute_reply.started":"2024-09-07T12:39:54.602240Z","shell.execute_reply":"2024-09-07T12:39:54.606474Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs = 3 if FAST_RUN else 10  # Si FAST_RUN es True, entrenamos por 3 épocas; de lo contrario, 10 épocas.\n\nhistory = model.fit(train_generator,  # Utiliza el conjunto de imágenes de entrenamiento.\n                    epochs=epochs,  # Entrena por 3 o 10 repeticiones, según FAST_RUN.\n                    validation_data=valid_generator,  # Usa el conjunto de validación para evaluar el rendimiento.\n#                     validation_steps=total_validate//batch_size, # Opcional: número de pasos en validación.\n#                     steps_per_epoch=total_train//batch_size,     # Opcional: número de pasos por época.\n                    callbacks=callbacks)  # Usa las funciones especiales (como reducción de tasa de aprendizaje y early stopping).\n","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:39:54.608450Z","iopub.execute_input":"2024-09-07T12:39:54.608727Z","iopub.status.idle":"2024-09-07T12:57:19.901617Z","shell.execute_reply.started":"2024-09-07T12:39:54.608697Z","shell.execute_reply":"2024-09-07T12:57:19.900834Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # Visualización de Resultados\n\nEn esta fase, estamos visualizando el rendimiento del modelo a lo largo del entrenamiento. Graficamos la **precisión** y la **pérdida** tanto para el conjunto de entrenamiento como para el conjunto de validación. Esto nos permite ver cómo el modelo ha mejorado (o no) con cada época. Un buen modelo mostrará que la precisión aumenta y la pérdida disminuye tanto en los datos de entrenamiento como en los de validación.\n","metadata":{}},{"cell_type":"code","source":"accuracy = history.history[\"accuracy\"]  # Guarda los valores de precisión del entrenamiento.\nval_accuracy = history.history[\"val_accuracy\"]  # Guarda los valores de precisión en los datos de validación.\n\nloss = history.history[\"loss\"]  # Guarda los valores de pérdida del entrenamiento.\nval_loss = history.history[\"val_loss\"]  # Guarda los valores de pérdida en los datos de validación.\n\nepochs = range(len(accuracy))  # Crea una lista de números de épocas (ciclos de entrenamiento).\n\nplt.figure(figsize=(12,6))  # Crea un gráfico de tamaño 12x6 pulgadas.\n\nplt.subplot(1,2,1)  # Crea el primer gráfico en una cuadrícula de 1 fila y 2 columnas.\nplt.plot(epochs, accuracy, 'bo', label=\"Train_Acc\")  # Grafica la precisión de entrenamiento.\nplt.plot(epochs, val_accuracy, 'r', label=\"val_Acc\")  # Grafica la precisión de validación.\nplt.legend(loc='best', shadow=True)  # Muestra una leyenda explicando qué es cada línea.\n\nplt.subplot(1,2,2)  # Crea el segundo gráfico.\nplt.plot(epochs, loss, 'bo', label=\"Train_Loss\")  # Grafica la pérdida de entrenamiento.\nplt.plot(epochs, val_loss, 'r', label=\"val_Loss\")  # Grafica la pérdida de validación.\nplt.legend(loc='best', shadow=True)  # Muestra una leyenda explicando qué es cada línea.\n\nplt.show()  # Muestra los dos gráficos.\n","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:57:19.903281Z","iopub.execute_input":"2024-09-07T12:57:19.903676Z","iopub.status.idle":"2024-09-07T12:57:20.336303Z","shell.execute_reply.started":"2024-09-07T12:57:19.903627Z","shell.execute_reply":"2024-09-07T12:57:20.335334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # The Epochs = 10 Only. We Can Increase The number of Epochs to Reach Suitable Accuracy.","metadata":{}},{"cell_type":"markdown","source":"> # Preparación de Datos de Prueba\n\nEn esta fase, estamos preparando el conjunto de imágenes de prueba. Cargamos los nombres de los archivos de prueba desde la carpeta correspondiente y creamos un DataFrame que almacena esa información. También calculamos cuántas imágenes de prueba tenemos en total. Esto es el primer paso para hacer predicciones usando el modelo entrenado.\n","metadata":{}},{"cell_type":"code","source":"test_file_names = os.listdir(\"/kaggle/working/test1\")  # Lista los nombres de los archivos de prueba en la carpeta \"test1\".\ntest_df = pd.DataFrame({'file_name': test_file_names})  # Crea un DataFrame con los nombres de los archivos de prueba.\n\ntotal_testing = test_df.shape[0]  # Cuenta el número total de archivos de prueba.\n","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:57:20.337882Z","iopub.execute_input":"2024-09-07T12:57:20.338196Z","iopub.status.idle":"2024-09-07T12:57:20.352339Z","shell.execute_reply.started":"2024-09-07T12:57:20.338163Z","shell.execute_reply":"2024-09-07T12:57:20.351402Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # Test The Model","metadata":{}},{"cell_type":"markdown","source":"> # Create Testing Generator","metadata":{}},{"cell_type":"code","source":"test_gen = ImageDataGenerator(rescale=1./255)  # Normaliza los valores de los píxeles de las imágenes de prueba.\n\ntest_generator = test_gen.flow_from_dataframe(\n    test_df,  # Utiliza el DataFrame que contiene los nombres de los archivos de prueba.\n    \"/kaggle/working/test1\",  # Ruta donde están las imágenes de prueba.\n    x_col='file_name',  # Columna que contiene los nombres de las imágenes.\n    y_col=None,  # No tenemos etiquetas (categorías) porque son imágenes para probar.\n    class_mode=None,  # No se necesitan etiquetas ya que solo queremos hacer predicciones.\n    target_size=IMAGE_SIZE,  # Redimensiona las imágenes al tamaño deseado.\n    batch_size=batch_size,  # Procesa las imágenes en lotes pequeños.\n    shuffle=False  # No mezclamos las imágenes para que las predicciones sigan el mismo orden que los nombres.\n)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:57:20.353586Z","iopub.execute_input":"2024-09-07T12:57:20.353910Z","iopub.status.idle":"2024-09-07T12:57:20.485874Z","shell.execute_reply.started":"2024-09-07T12:57:20.353877Z","shell.execute_reply":"2024-09-07T12:57:20.485116Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # Predict","metadata":{}},{"cell_type":"code","source":"predictions = model.predict(test_generator)  # Utiliza el modelo entrenado para hacer predicciones en las imágenes de prueba.","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:57:20.487001Z","iopub.execute_input":"2024-09-07T12:57:20.487361Z","iopub.status.idle":"2024-09-07T12:57:38.709880Z","shell.execute_reply.started":"2024-09-07T12:57:20.487320Z","shell.execute_reply":"2024-09-07T12:57:38.709038Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> For categoral classication the prediction will come with probability of each category. So we will pick the category that have the highest probability with numpy average max","metadata":{}},{"cell_type":"code","source":"test_df[\"CATEGORIES\"] = np.argmax(predictions, axis=1)  # Asigna la categoría (gato o perro) con la mayor probabilidad a cada imagen.","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:57:38.711065Z","iopub.execute_input":"2024-09-07T12:57:38.711348Z","iopub.status.idle":"2024-09-07T12:57:38.717099Z","shell.execute_reply.started":"2024-09-07T12:57:38.711317Z","shell.execute_reply":"2024-09-07T12:57:38.716078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> We will convert the predict category back into our generator classes by using train_generator.class_indices. It is the classes that image generator map while converting data into computer vision","metadata":{}},{"cell_type":"code","source":"label_map = dict((v,k) for k,v in train_generator.class_indices.items())  # Crea un diccionario para mapear 0 a \"cat\" y 1 a \"dog\".\ntest_df['CATEGORIES'] = test_df['CATEGORIES'].replace(label_map)  # Reemplaza los valores 0 y 1 en la columna CATEGORIES con \"cat\" o \"dog\".","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:57:38.718155Z","iopub.execute_input":"2024-09-07T12:57:38.718511Z","iopub.status.idle":"2024-09-07T12:57:38.730698Z","shell.execute_reply.started":"2024-09-07T12:57:38.718479Z","shell.execute_reply":"2024-09-07T12:57:38.729867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> From our prepare data part. We map data with {1: 'dog', 0: 'cat'}. Now we will map the result back to dog is 1 and cat is 0\n\n","metadata":{}},{"cell_type":"code","source":"test_df['CATEGORIES'] = test_df['CATEGORIES'].replace({ 'dog': 1, 'cat': 0 })  # Reemplaza las etiquetas de texto \"dog\" por 1 y \"cat\" por 0.","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:58:17.402064Z","iopub.execute_input":"2024-09-07T12:58:17.402448Z","iopub.status.idle":"2024-09-07T12:58:17.408195Z","shell.execute_reply.started":"2024-09-07T12:58:17.402412Z","shell.execute_reply":"2024-09-07T12:58:17.407332Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 6- Visualize The Result","metadata":{}},{"cell_type":"code","source":"test_df[\"CATEGORIES\"].value_counts().plot.bar()  # Cuenta cuántas veces aparece cada categoría y crea un gráfico de barras.","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:58:25.928642Z","iopub.execute_input":"2024-09-07T12:58:25.929474Z","iopub.status.idle":"2024-09-07T12:58:26.134485Z","shell.execute_reply.started":"2024-09-07T12:58:25.929433Z","shell.execute_reply":"2024-09-07T12:58:26.133547Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # Show Predicted Images","metadata":{}},{"cell_type":"code","source":"sample_test = test_df.head(36)  # Selecciona las primeras 36 imágenes del DataFrame de prueba.\n\nplt.figure(figsize=(15,15))  # Crea una figura de 15x15 pulgadas para mostrar las imágenes.\n\nfor index, row in sample_test.iterrows():  # Recorre cada fila (imagen) en la muestra de prueba.\n    file_name = row['file_name']  # Obtiene el nombre del archivo de la imagen.\n    category = row['CATEGORIES']  # Obtiene la categoría predicha (0 para gato, 1 para perro).\n    path = os.path.join(\"/kaggle/working/test1\", file_name)  # Crea la ruta completa a la imagen.\n    img = load_img(path, target_size=IMAGE_SIZE)  # Carga la imagen y la redimensiona al tamaño especificado.\n    \n    plt.subplot(6, 6, index + 1)  # Crea un área de visualización de 6 filas por 6 columnas.\n    plt.imshow(img)  # Muestra la imagen.\n    plt.title(f\"{file_name}\\n is ==> {'cat' if category==0 else 'dog'}\")  # Establece el título, indicando si es un gato o un perro.\n    plt.axis('off')  # Oculta los ejes para una visualización más limpia.\n\nplt.tight_layout()  # Ajusta el espacio entre las imágenes para evitar que se superpongan.\nplt.show()  # Muestra todas las imágenes en la cuadrícula.\n","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:58:29.605904Z","iopub.execute_input":"2024-09-07T12:58:29.606584Z","iopub.status.idle":"2024-09-07T12:58:33.545237Z","shell.execute_reply.started":"2024-09-07T12:58:29.606543Z","shell.execute_reply":"2024-09-07T12:58:33.544253Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 7- Save The Model","metadata":{}},{"cell_type":"code","source":"model.save(\"CNN.h5\")  # Guarda todo el modelo, incluyendo la arquitectura, los pesos y la configuración de entrenamiento en un archivo.\nmodel.save_weights(\"CNN.weights.h5\")  # Guarda solo los pesos del modelo en un archivo separado.","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:59:08.370243Z","iopub.execute_input":"2024-09-07T12:59:08.370603Z","iopub.status.idle":"2024-09-07T12:59:08.457717Z","shell.execute_reply.started":"2024-09-07T12:59:08.370570Z","shell.execute_reply":"2024-09-07T12:59:08.456757Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 8- Submission","metadata":{}},{"cell_type":"code","source":"submission_df = test_df.copy()  # Crea una copia del DataFrame de prueba para preparar el archivo de envío.\n\nsubmission_df['id'] = submission_df['file_name'].str.split('.').str[0]  \n# Crea una nueva columna 'id' tomando el nombre del archivo y eliminando la extensión.\n\nsubmission_df['label'] = submission_df['CATEGORIES']  \n# Crea una nueva columna 'label' con los valores de la categoría predicha (gato o perro).\n\nsubmission_df.drop(['file_name', 'CATEGORIES'], axis=1, inplace=True)  \n# Elimina las columnas 'file_name' y 'CATEGORIES' del DataFrame, ya no son necesarias.\n\nsubmission_df.to_csv(\"submission.csv\", index=False)  \n# Guarda el DataFrame como un archivo CSV llamado 'submission.csv' sin el índice.","metadata":{"execution":{"iopub.status.busy":"2024-09-07T12:59:11.891412Z","iopub.execute_input":"2024-09-07T12:59:11.892220Z","iopub.status.idle":"2024-09-07T12:59:11.933462Z","shell.execute_reply.started":"2024-09-07T12:59:11.892179Z","shell.execute_reply":"2024-09-07T12:59:11.932703Z"},"trusted":true},"execution_count":null,"outputs":[]}]}