{"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":"nvidiaTeslaT4","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":30762,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# 1.  Importar Librerías Necesarias\n\nimport tensorflow as tf\nfrom tensorflow.keras import layers\nfrom glob import glob\nimport matplotlib.pyplot as plt\nimport time\nimport os\nfrom PIL import Image","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-09-13T18:56:12.318305Z","iopub.execute_input":"2024-09-13T18:56:12.318741Z","iopub.status.idle":"2024-09-13T18:56:12.324781Z","shell.execute_reply.started":"2024-09-13T18:56:12.318696Z","shell.execute_reply":"2024-09-13T18:56:12.323747Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 2. Carga de Datos\n\n#Usaremos los archivos TFRecord (una recomendación de la competición) para leer las imágenes del dataset.\n\n# Ruta a los archivos TFRecord\nmonet_tfrec_files = tf.io.gfile.glob('/kaggle/input/gan-getting-started/monet_tfrec/*.tfrec')\nphoto_tfrec_files = tf.io.gfile.glob('/kaggle/input/gan-getting-started/photo_tfrec/*.tfrec')\n\ndef decode_image(image):\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.image.resize(image, [256, 256])\n    image = (image / 127.5) - 1  # Normalize to [-1, 1]\n    return image\n\ndef load_tfrecord(filenames, labeled=False):\n    raw_image_dataset = tf.data.TFRecordDataset(filenames)\n    \n    image_feature_description = {\n        'image': tf.io.FixedLenFeature([], tf.string),\n    }\n    \n    def _parse_image_function(example_proto):\n        content = tf.io.parse_single_example(example_proto, image_feature_description)\n        image = decode_image(content['image'])\n        return image\n    \n    return raw_image_dataset.map(_parse_image_function)\n\n# Cargar datasets\nmonet_dataset = load_tfrecord(monet_tfrec_files)\nphoto_dataset = load_tfrecord(photo_tfrec_files)","metadata":{"execution":{"iopub.status.busy":"2024-09-13T18:11:47.893299Z","iopub.execute_input":"2024-09-13T18:11:47.894153Z","iopub.status.idle":"2024-09-13T18:11:48.021210Z","shell.execute_reply.started":"2024-09-13T18:11:47.894109Z","shell.execute_reply":"2024-09-13T18:11:48.020292Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 3. Visualización de los datos, en forma de muestra de imágenes\n\n# Función para mostrar imágenes\ndef display_sample_images(dataset, num_images):\n    plt.figure(figsize=(10, 10))\n    for i, image in enumerate(dataset.take(num_images)):\n        plt.subplot(1, num_images, i + 1)\n        plt.imshow(image.numpy())\n        plt.axis(\"off\")\n    plt.show()\n\n# Mostrar 5 imágenes del dataset de Monet\nprint(\"Muestra de imágenes de Monet:\")\ndisplay_sample_images(monet_dataset, 5)\n\n# Mostrar 5 imágenes del dataset de fotos\nprint(\"Muestra de imágenes de fotos:\")\ndisplay_sample_images(photo_dataset, 5)","metadata":{"execution":{"iopub.status.busy":"2024-09-13T18:11:48.022748Z","iopub.execute_input":"2024-09-13T18:11:48.023095Z","iopub.status.idle":"2024-09-13T18:11:48.695144Z","shell.execute_reply.started":"2024-09-13T18:11:48.023063Z","shell.execute_reply":"2024-09-13T18:11:48.694139Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 4. Preprocesamiento del Dataset\n\n# Necesitamos ajustar el preprocesamiento para que las imágenes estén en el rango adecuado para el entrenamiento de la GAN. \n# Esto incluye normalizar las imágenes a un rango de [-1, 1].\n\n# Definir la función de preprocesamiento\ndef preprocess_image(image):\n    # Normalizar las imágenes entre [-1, 1]\n    image = tf.image.convert_image_dtype(image, tf.float32)\n    image = (image - 0.5) * 2\n    return image\n\ndef preprocess_dataset(dataset):\n    dataset = dataset.map(lambda x: preprocess_image(x))\n    dataset = dataset.shuffle(buffer_size=1000).batch(1)  # Tamaño del batch 1 para generar imágenes una por una\n    return dataset\n\n# Aplicar preprocesamiento a los datasets de Monet y fotos\nmonet_dataset = preprocess_dataset(monet_dataset)\nphoto_dataset = preprocess_dataset(photo_dataset)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-13T18:11:48.696309Z","iopub.execute_input":"2024-09-13T18:11:48.696609Z","iopub.status.idle":"2024-09-13T18:11:48.762153Z","shell.execute_reply.started":"2024-09-13T18:11:48.696575Z","shell.execute_reply":"2024-09-13T18:11:48.761233Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 5. Definir la Arquitectura de la GAN\n\n# Vamos a definir las arquitecturas del generador y el discriminador.\n\ndef build_generator():\n    model = tf.keras.Sequential()\n\n    # Capa de entrada\n    model.add(layers.Input(shape=(256, 256, 3)))\n\n    # Bloque Conv2D + Activación\n    model.add(layers.Conv2D(64, kernel_size=7, strides=1, padding='same'))\n    model.add(layers.LeakyReLU(negative_slope=0.2))\n    \n    # Bloques adicionales de Conv2D\n    model.add(layers.Conv2D(128, kernel_size=4, strides=2, padding='same'))\n    model.add(layers.BatchNormalization())\n    model.add(layers.LeakyReLU(negative_slope=0.2))\n    \n    model.add(layers.Conv2D(256, kernel_size=4, strides=2, padding='same'))\n    model.add(layers.BatchNormalization())\n    model.add(layers.LeakyReLU(negative_slope=0.2))\n\n    # Capa de salida\n    model.add(layers.Conv2D(3, kernel_size=7, strides=1, padding='same', activation='tanh'))\n\n    return model\n\n\ndef build_discriminator():\n    model = tf.keras.Sequential()\n\n    # Capa de entrada\n    model.add(layers.Input(shape=(256, 256, 3)))\n\n    # Bloques Conv2D para discriminar\n    model.add(layers.Conv2D(64, kernel_size=4, strides=2, padding='same'))\n    model.add(layers.LeakyReLU(negative_slope=0.2))\n\n    model.add(layers.Conv2D(128, kernel_size=4, strides=2, padding='same'))\n    model.add(layers.BatchNormalization())\n    model.add(layers.LeakyReLU(negative_slope=0.2))\n\n    model.add(layers.Conv2D(256, kernel_size=4, strides=2, padding='same'))\n    model.add(layers.BatchNormalization())\n    model.add(layers.LeakyReLU(negative_slope=0.2))\n\n    # Capa final para clasificar real o falso\n    model.add(layers.Conv2D(1, kernel_size=4, strides=1, padding='same'))\n\n    return model\n\n# Creación de los modelos\ngenerator_g = build_generator()  # Convierte fotos a Monet\ngenerator_f = build_generator()  # Convierte Monet a fotos\ndiscriminator_x = build_discriminator()  # Discriminador de Monet\ndiscriminator_y = build_discriminator()  # Discriminador de fotos","metadata":{"execution":{"iopub.status.busy":"2024-09-13T18:11:48.764618Z","iopub.execute_input":"2024-09-13T18:11:48.765095Z","iopub.status.idle":"2024-09-13T18:11:49.096586Z","shell.execute_reply.started":"2024-09-13T18:11:48.765050Z","shell.execute_reply":"2024-09-13T18:11:49.095861Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 6. Definir la Función de Entrenamiento\n\nloss_obj = tf.keras.losses.BinaryCrossentropy(from_logits=True)\n\ndef discriminator_loss(real, generated):\n    real_loss = loss_obj(tf.ones_like(real), real)\n    generated_loss = loss_obj(tf.zeros_like(generated), generated)\n    return real_loss + generated_loss\n\ndef generator_loss(generated):\n    return loss_obj(tf.ones_like(generated), generated)\n\ndef cycle_consistency_loss(real_image, cycled_image):\n    # Redimensionar cycled_image a la misma forma que real_image\n    cycled_image_resized = tf.image.resize(cycled_image, [256, 256])\n    \n    loss = tf.reduce_mean(tf.abs(real_image - cycled_image_resized))\n    return loss\n\n# Optimizers\ngenerator_g_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\ngenerator_f_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\ndiscriminator_x_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\ndiscriminator_y_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n\n@tf.function\ndef train_step(real_x, real_y):\n    \n    # Asegúrate de que real_x y real_y tengan la forma correcta (batch_size, 256, 256, 3)\n    if len(real_x.shape) == 3:  # Si es (256, 256, 3), expande a (1, 256, 256, 3)\n        real_x = tf.expand_dims(real_x, axis=0)\n        \n    if len(real_y.shape) == 3:  # Si es (256, 256, 3), expande a (1, 256, 256, 3)\n        real_y = tf.expand_dims(real_y, axis=0)\n    \n    with tf.GradientTape(persistent=True) as tape:\n        # Photo -> Monet\n        fake_y = generator_g(real_x, training=True)\n        cycled_x = generator_f(fake_y, training=True)\n\n        # Monet -> Photo\n        fake_x = generator_f(real_y, training=True)\n        cycled_y = generator_g(fake_x, training=True)\n\n        # Discriminators\n        disc_real_x = discriminator_x(real_y, training=True)\n        disc_fake_x = discriminator_x(fake_y, training=True)\n\n        disc_real_y = discriminator_y(real_x, training=True)\n        disc_fake_y = discriminator_y(fake_x, training=True)\n\n        # Generator losses\n        gen_g_loss = generator_loss(disc_fake_x)\n        gen_f_loss = generator_loss(disc_fake_y)\n\n        # Cycle losses\n        cycle_loss_g = cycle_consistency_loss(real_x, cycled_x)\n        cycle_loss_f = cycle_consistency_loss(real_y, cycled_y)\n\n        # Total generator loss\n        total_gen_g_loss = gen_g_loss + 10 * cycle_loss_g\n        total_gen_f_loss = gen_f_loss + 10 * cycle_loss_f\n\n        # Discriminator losses\n        disc_x_loss = discriminator_loss(disc_real_x, disc_fake_x)\n        disc_y_loss = discriminator_loss(disc_real_y, disc_fake_y)\n\n    # Calculate the gradients\n    generator_g_gradients = tape.gradient(total_gen_g_loss, generator_g.trainable_variables)\n    generator_f_gradients = tape.gradient(total_gen_f_loss, generator_f.trainable_variables)\n\n    discriminator_x_gradients = tape.gradient(disc_x_loss, discriminator_x.trainable_variables)\n    discriminator_y_gradients = tape.gradient(disc_y_loss, discriminator_y.trainable_variables)\n\n    # Apply the gradients\n    generator_g_optimizer.apply_gradients(zip(generator_g_gradients, generator_g.trainable_variables))\n    generator_f_optimizer.apply_gradients(zip(generator_f_gradients, generator_f.trainable_variables))\n    discriminator_x_optimizer.apply_gradients(zip(discriminator_x_gradients, discriminator_x.trainable_variables))\n    discriminator_y_optimizer.apply_gradients(zip(discriminator_y_gradients, discriminator_y.trainable_variables))","metadata":{"execution":{"iopub.status.busy":"2024-09-13T18:44:35.652442Z","iopub.execute_input":"2024-09-13T18:44:35.652782Z","iopub.status.idle":"2024-09-13T18:44:35.710551Z","shell.execute_reply.started":"2024-09-13T18:44:35.652742Z","shell.execute_reply":"2024-09-13T18:44:35.709425Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 7. Entrenamiento de la GAN\n\nEPOCHS = 100\n\nfor epoch in range(EPOCHS):\n    start = time.time()\n\n    for image_x, image_y in tf.data.Dataset.zip((photo_dataset, monet_dataset)):\n        train_step(image_x, image_y)\n\n    print(f'Time for epoch {epoch+1} is {time.time()-start} sec')","metadata":{"execution":{"iopub.status.busy":"2024-09-13T18:11:49.186136Z","iopub.execute_input":"2024-09-13T18:11:49.186455Z","iopub.status.idle":"2024-09-13T18:36:15.476873Z","shell.execute_reply.started":"2024-09-13T18:11:49.186415Z","shell.execute_reply":"2024-09-13T18:36:15.475835Z"},"trusted":true},"execution_count":null,"outputs":[]}]}