{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"tpu1vmV38","dataSources":[{"sourceId":886249,"sourceType":"datasetVersion","datasetId":472549},{"sourceId":4272422,"sourceType":"datasetVersion","datasetId":2517288},{"sourceId":8050050,"sourceType":"datasetVersion","datasetId":4747199},{"sourceId":9090405,"sourceType":"datasetVersion","datasetId":5485449},{"sourceId":9293099,"sourceType":"datasetVersion","datasetId":5626147},{"sourceId":9420510,"sourceType":"datasetVersion","datasetId":5721816},{"sourceId":9919562,"sourceType":"datasetVersion","datasetId":6096282},{"sourceId":9921427,"sourceType":"datasetVersion","datasetId":6097585},{"sourceId":9945613,"sourceType":"datasetVersion","datasetId":6115629},{"sourceId":9945769,"sourceType":"datasetVersion","datasetId":6115758},{"sourceId":9946405,"sourceType":"datasetVersion","datasetId":6116187},{"sourceId":9947235,"sourceType":"datasetVersion","datasetId":6116735},{"sourceId":10053605,"sourceType":"datasetVersion","datasetId":6194768},{"sourceId":10105100,"sourceType":"datasetVersion","datasetId":6233164},{"sourceId":10143851,"sourceType":"datasetVersion","datasetId":6261224},{"sourceId":10210432,"sourceType":"datasetVersion","datasetId":6310579},{"sourceId":10212764,"sourceType":"datasetVersion","datasetId":6312204},{"sourceId":10248898,"sourceType":"datasetVersion","datasetId":6339021},{"sourceId":10250044,"sourceType":"datasetVersion","datasetId":6339868},{"sourceId":10262628,"sourceType":"datasetVersion","datasetId":6348670},{"sourceId":10276136,"sourceType":"datasetVersion","datasetId":6358452},{"sourceId":10280802,"sourceType":"datasetVersion","datasetId":6361884}],"dockerImageVersionId":30588,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"##### import os, random, json, PIL, shutil, re\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport tensorflow.keras.layers as L\nimport tensorflow_addons as tfa\nfrom tensorflow.keras import Model, losses, optimizers\nprint(\"si\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:47:23.898922Z","iopub.execute_input":"2024-12-23T07:47:23.899880Z","iopub.status.idle":"2024-12-23T07:47:23.905473Z","shell.execute_reply.started":"2024-12-23T07:47:23.899839Z","shell.execute_reply":"2024-12-23T07:47:23.904549Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"HEIGHT = 1024\nWIDTH = 1024 \nCHANNELS = 3\nEPOCHS = 200\nBATCH_SIZE = 16","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:47:23.906883Z","iopub.execute_input":"2024-12-23T07:47:23.907167Z","iopub.status.idle":"2024-12-23T07:47:23.928106Z","shell.execute_reply.started":"2024-12-23T07:47:23.907138Z","shell.execute_reply":"2024-12-23T07:47:23.927362Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"try:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print(f'Running on TPU {tpu.master()}')\nexcept ValueError:\n    tpu = None\n\nif tpu:\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nelse:\n    strategy = tf.distribute.get_strategy()\n\n\nREPLICAS = strategy.num_replicas_in_sync\nprint(f'REPLICAS: {REPLICAS}')\nAUTO = tf.data.experimental.AUTOTUNE","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:47:23.929375Z","iopub.execute_input":"2024-12-23T07:47:23.929613Z","iopub.status.idle":"2024-12-23T07:47:29.260801Z","shell.execute_reply.started":"2024-12-23T07:47:23.929588Z","shell.execute_reply":"2024-12-23T07:47:29.259905Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport tensorflow as tf\nfrom PIL import Image\n\ndef get_filenames_from_folder(folder_path, extensions, limit=None):\n    filenames = []\n    for root, dirs, files in os.walk(folder_path):\n        for file in files:\n            if file.endswith(extensions):\n                file_path = os.path.join(root, file)\n                # Verificación opcional para asegurarse de que la imagen no esté corrupta\n                try:\n                    img = Image.open(file_path)\n                    img.verify()  # Verifica si la imagen está corrupta\n                    filenames.append(file_path)\n                    if limit and len(filenames) >= limit:\n                        return filenames\n                except (IOError, SyntaxError) as e:\n                    print(f\"Imagen corrupta detectada: {file_path}\")\n                    continue  # Ignora la imagen corrupta\n    return filenames\n\n# Aplica la función para obtener los nombres de archivo de la Clase 1\nclass_1_filenamesaptos = get_filenames_from_folder(\"/kaggle/input/stargan-retinas/stargan_retina/normal_fundus\", ('.jpg', '.jpeg', '.png', '.tif'), 5000)\nclass_1_filenamesodir = get_filenames_from_folder(\"/kaggle/input/dataset-normal-1024/normal\", ('.jpg', '.jpeg', '.png', '.tif'), 6000)\nclass_1_filenames = class_1_filenamesodir \n#class_1_filenames_train = get_filenames_from_folder(\"/kaggle/input/indian-diabetic-retinopathy-image-dataset/A.%20Segmentation/A. Segmentation/1. Original Images/a. Training Set\", ('.jpg', '.jpeg', '.png', '.tif'), 81)\n#class_1_filenames_test = get_filenames_from_folder(\"/kaggle/input/indian-diabetic-retinopathy-image-dataset/A.%20Segmentation/A. Segmentation/1. Original Images/b. Testing Set\", ('.jpg', '.jpeg', '.png', '.tif'), 81)\nclass_2_filenames = get_filenames_from_folder(\"/kaggle/input/dataset-diffuse-myopia-1024/diffuse_chorioretinal_atrophyrotation1024\", ('.jpg', '.jpeg', '.png', '.tif'), 10000)\n\n\n# Función para contar los elementos\ndef count_data_items(filenames):\n    return len(filenames)\n\n# Combinar las listas de archivos de la clase 2\n\nn_class_1_samples = count_data_items(class_1_filenames)\nn_class_2_samples = count_data_items(class_2_filenames)\nprint(f'Número de archivos Clase normal fundus: {n_class_1_samples}')\nprint(f'Número de archivos Clase diabetic: {n_class_2_samples}')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T15:08:28.800494Z","iopub.execute_input":"2024-12-23T15:08:28.800876Z","iopub.status.idle":"2024-12-23T15:11:32.769144Z","shell.execute_reply.started":"2024-12-23T15:08:28.800846Z","shell.execute_reply":"2024-12-23T15:11:32.767910Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def _bytes_feature(value):\n    \"\"\"Retorna una bytes_list de un string/byte.\"\"\"\n    return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))\n\ndef image_example(image_string):\n    feature = {\n        'image': _bytes_feature(image_string),\n    }\n    return tf.train.Example(features=tf.train.Features(feature=feature))\n\ndef write_tfrecord(image_paths, output_file):\n    with tf.io.TFRecordWriter(output_file) as writer:\n        for image_path in image_paths:\n            try:\n                with open(image_path, 'rb') as f:\n                    image_string = f.read()\n                if not image_string:\n                    print(f\"Imagen vacía: {image_path}\")\n                    continue\n                tf_example = image_example(image_string)\n                writer.write(tf_example.SerializeToString())\n            except Exception as e:\n                print(f\"Error al procesar {image_path}: {e}\")\n                continue\n\n# Convertir class_1_filenames a TFRecords\nwrite_tfrecord(class_1_filenames, 'class_1.tfrecord')\n# Convertir class_2_filenames a TFRecords\nwrite_tfrecord(class_2_filenames, 'class_2.tfrecord')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T15:19:35.053246Z","iopub.execute_input":"2024-12-23T15:19:35.054303Z","iopub.status.idle":"2024-12-23T15:20:04.319045Z","shell.execute_reply.started":"2024-12-23T15:19:35.054262Z","shell.execute_reply":"2024-12-23T15:20:04.317561Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\n\n# Define AUTO para el uso en llamadas paralelas\nAUTO = tf.data.AUTOTUNE","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:48:50.169022Z","iopub.execute_input":"2024-12-23T07:48:50.169276Z","iopub.status.idle":"2024-12-23T07:48:50.172937Z","shell.execute_reply.started":"2024-12-23T07:48:50.169251Z","shell.execute_reply":"2024-12-23T07:48:50.172278Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def decode_image(image):\n    image = tf.image.decode_png(image, channels=CHANNELS)\n    image = tf.image.resize(image, [HEIGHT, WIDTH])  # Redimensionar la imagen\n    image = (tf.cast(image, tf.float32) / 127.5) - 1\n    return image\n\n\ndef load_image(filename):\n    image = tf.io.read_file(filename)\n    image = decode_image(image)\n    return image\n\n\ndef parse_tfrecord(example_proto):\n    image_feature_description = {\n        'image': tf.io.FixedLenFeature([], tf.string),\n    }\n    parsed_features = tf.io.parse_single_example(example_proto, image_feature_description)\n    image = tf.io.decode_image(parsed_features['image'], channels=CHANNELS, expand_animations=False)\n    image.set_shape([None, None, CHANNELS])  # Establecer explícitamente la forma\n    image = tf.image.resize(image, [HEIGHT, WIDTH])\n    image = (tf.cast(image, tf.float32) / 127.5) - 1\n    return image\n\n\ndef load_dataset(tfrecord_file):\n    raw_dataset = tf.data.TFRecordDataset(tfrecord_file)\n    dataset = raw_dataset.map(parse_tfrecord, num_parallel_calls=AUTO)\n    return dataset\n\n\ndef display_samples(ds, row, col):\n    ds_iter = iter(ds)\n    plt.figure(figsize=(15, int(15*row/col)))\n    for j in range(row*col):\n        example_batch = next(ds_iter)\n        example_sample = example_batch  # Como estamos en batch(1), tomamos el único elemento\n        plt.subplot(row, col, j+1)\n        plt.axis('off')\n        # Normaliza y muestra la imagen\n        plt.imshow((example_sample.numpy() * 0.5 + 0.5))\n    plt.show()\n\n    \ndef get_gan_dataset(monet_tfrecord, photo_tfrecord, batch_size=1):\n    monet_ds = load_dataset(monet_tfrecord)\n    photo_ds = load_dataset(photo_tfrecord)\n\n    monet_ds = monet_ds.cache().shuffle(1024).repeat()\n    photo_ds = photo_ds.cache().shuffle(1024).repeat()\n\n    monet_ds = monet_ds.batch(batch_size, drop_remainder=True)\n    photo_ds = photo_ds.batch(batch_size, drop_remainder=True)\n\n    monet_ds = monet_ds.prefetch(AUTO)\n    photo_ds = photo_ds.prefetch(AUTO)\n\n    gan_ds = tf.data.Dataset.zip((monet_ds, photo_ds))\n    return gan_ds\n\n\n\ndef display_generated_samples(ds, model, n_samples):\n    ds_iter = iter(ds)\n    for n_sample in range(n_samples):\n        example_sample = next(ds_iter)\n        generated_sample = model.predict(example_sample)\n        \n        plt.subplot(121)\n        plt.title(\"input image\")\n        plt.imshow(example_sample[0] * 0.5 + 0.5)\n        plt.axis('off')\n        \n        plt.subplot(122)\n        plt.title(\"Generated image\")\n        plt.imshow(generated_sample[0] * 0.5 + 0.5)\n        plt.axis('off')\n        plt.show()\n        \ndef predict_and_save(input_ds, model, output_path, domain_labels):\n    i = 1\n    for img, label in input_ds:\n        # Asumiendo que el modelo StarGAN puede tomar tanto la imagen como la etiqueta de dominio como entrada\n        prediction = model([img, label], training=False)[0].numpy()\n        prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n        im = PIL.Image.fromarray(prediction)\n        im.save(f'{output_path}{str(i)}.jpg')\n        i += 1\n\n                \nimport tensorflow as tf\nimport tensorflow.keras.layers as L\n\nclass SEBlock(L.Layer):\n    def __init__(self, reduction=16, **kwargs):\n        super(SEBlock, self).__init__(**kwargs)\n        self.reduction = reduction\n\n    def build(self, input_shape):\n        filters = input_shape[-1]\n        # Crear capas Dense aquí, ya que ahora estamos en build y las variables se crearán con el layer\n        self.dense1 = L.Dense(filters // self.reduction, activation='relu', use_bias=False)\n        self.dense2 = L.Dense(filters, activation='sigmoid', use_bias=False)\n        super(SEBlock, self).build(input_shape)\n\n    def call(self, x):\n        # Computar el bloque SE\n        se = tf.reduce_mean(x, axis=[1,2], keepdims=True)  # GlobalAveragePooling2D manual\n        se = self.dense1(se)\n        se = self.dense2(se)\n        return x * se\n\ndef downsample(filters, size, apply_instancenorm=True):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    result = tf.keras.Sequential()\n    result.add(L.Conv2D(filters, size, strides=2, padding='same',\n                        kernel_initializer=initializer, use_bias=False))\n    if apply_instancenorm:\n        result.add(tfa.layers.InstanceNormalization())\n    # Insertamos la capa SE\n    #result.add(SEBlock())\n    result.add(L.LeakyReLU())\n    return result\n\ndef upsample(filters, size, apply_dropout=False):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    result = tf.keras.Sequential()\n    result.add(L.Conv2DTranspose(filters, size, strides=2,\n                                 padding='same',\n                                 kernel_initializer=initializer,\n                                 use_bias=False))\n    result.add(tfa.layers.InstanceNormalization())\n    # Insertamos la capa SE\n    #result.add(SEBlock())\n    result.add(L.ReLU())\n    if apply_dropout:\n        result.add(L.Dropout(0.5))\n    return result","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T15:27:14.599648Z","iopub.execute_input":"2024-12-23T15:27:14.600031Z","iopub.status.idle":"2024-12-23T15:27:14.622492Z","shell.execute_reply.started":"2024-12-23T15:27:14.600001Z","shell.execute_reply":"2024-12-23T15:27:14.621524Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"OUTPUT_CHANNELS = 3\n# Asumiendo que HEIGHT, WIDTH, y CHANNELS están definidos\n# Ejemplo: HEIGHT = 256, WIDTH = 256, CHANNELS = 3\n\n\ndef generator_fn():\n    inputs = L.Input(shape=[HEIGHT, WIDTH, CHANNELS])\n\n    down_stack = [\n        downsample(64, 4, apply_instancenorm=False),\n        downsample(128, 4),\n        downsample(256, 4),\n        downsample(512, 4),\n        downsample(512, 4),\n        downsample(512, 4),\n        downsample(512, 4),\n        downsample(512, 4),\n    ]\n\n    up_stack = [\n        upsample(512, 4, apply_dropout=True),\n        upsample(512, 4, apply_dropout=True),\n        upsample(512, 4),\n        upsample(512, 4),\n        upsample(256, 4),\n        upsample(128, 4),\n        upsample(64, 4),\n    ]\n\n    initializer = tf.random_normal_initializer(0., 0.02)\n    last = L.Conv2DTranspose(OUTPUT_CHANNELS, 4, strides=2, padding='same',\n                             kernel_initializer=initializer, activation='tanh')\n\n    x = inputs\n    skips = []\n    for down in down_stack:\n        x = down(x)\n        skips.append(x)\n    skips = list(reversed(skips[:-1]))\n\n    for up, skip in zip(up_stack, skips):\n        x = up(x)\n        if x.shape[1] != skip.shape[1] or x.shape[2] != skip.shape[2]:\n            x = tf.image.resize(x, (skip.shape[1], skip.shape[2]), method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)\n        x = L.Concatenate()([x, skip])\n\n    x = last(x)\n    return tf.keras.Model(inputs=inputs, outputs=x)\n\ndef discriminator_fn():\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = tf.keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    inp = L.Input(shape=[HEIGHT, WIDTH, CHANNELS], name='input_image')\n\n    x = inp\n    down1 = downsample(64, 4, False)(x)\n    down2 = downsample(128, 4)(down1)\n    down3 = downsample(256, 4)(down2)\n    down4 = downsample(512, 4)(down3)\n\n    zero_pad1 = L.ZeroPadding2D()(down4)\n    conv = L.Conv2D(512, 3, strides=1, kernel_initializer=initializer, use_bias=False)(zero_pad1)\n    norm1 = tfa.layers.InstanceNormalization(gamma_initializer=gamma_init)(conv)\n    leaky_relu = L.LeakyReLU()(norm1)\n    zero_pad2 = L.ZeroPadding2D()(leaky_relu)\n    last = L.Conv2D(1, 3, strides=1, kernel_initializer=initializer)(zero_pad2)\n\n    return Model(inputs=inp, outputs=last)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:48:50.196760Z","iopub.execute_input":"2024-12-23T07:48:50.197047Z","iopub.status.idle":"2024-12-23T07:48:50.209700Z","shell.execute_reply.started":"2024-12-23T07:48:50.197019Z","shell.execute_reply":"2024-12-23T07:48:50.209002Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with strategy.scope():\n    def discriminator_loss(real, generated):\n        real_loss = losses.BinaryCrossentropy(from_logits=True, reduction=losses.Reduction.NONE)(tf.ones_like(real), real)\n        generated_loss = losses.BinaryCrossentropy(from_logits=True, reduction=losses.Reduction.NONE)(tf.zeros_like(generated), generated)\n        total_disc_loss = real_loss + generated_loss\n        return total_disc_loss * 0.5\n\n    def generator_loss(generated):\n        return losses.BinaryCrossentropy(from_logits=True, reduction=losses.Reduction.NONE)(tf.ones_like(generated), generated)\n    \n    with strategy.scope():\n        def calc_cycle_loss(real_image, cycled_image, LAMBDA):\n            loss1 = tf.reduce_mean(tf.abs(real_image - cycled_image))\n            return LAMBDA * loss1\n\n    with strategy.scope():\n        def identity_loss(real_image, same_image, LAMBDA):\n            loss = tf.reduce_mean(tf.abs(real_image - same_image))\n            return LAMBDA * 0.5 * loss\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:48:50.210567Z","iopub.execute_input":"2024-12-23T07:48:50.210806Z","iopub.status.idle":"2024-12-23T07:48:50.222771Z","shell.execute_reply.started":"2024-12-23T07:48:50.210781Z","shell.execute_reply":"2024-12-23T07:48:50.222106Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.applications import VGG19\nfrom tensorflow.keras import layers\n\ndef model_build(image_size, num_classes):\n    inputs = tf.keras.Input(shape=(image_size, image_size, 3))\n    base_model = VGG19(weights='imagenet', include_top=False, input_tensor=inputs)\n    base_model.trainable = False\n    \n    x = base_model.output\n    x = layers.GlobalAveragePooling2D()(x)\n    x = layers.Dense(64, activation='relu')(x)\n    x = layers.BatchNormalization()(x)\n    outputs = layers.Dense(num_classes, activation='softmax')(x)\n    \n    model = tf.keras.Model(inputs=inputs, outputs=outputs)\n    return model\n\ncnn_model = model_build(224, 2)\ncnn_model.load_weights('/kaggle/input/modelo-myopia-vgg19/model_myopia_vgg19.h5')\ncnn_model.trainable = False\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:48:50.223661Z","iopub.execute_input":"2024-12-23T07:48:50.223895Z","iopub.status.idle":"2024-12-23T07:48:51.516190Z","shell.execute_reply.started":"2024-12-23T07:48:50.223870Z","shell.execute_reply":"2024-12-23T07:48:51.515140Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cnn_model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:48:51.519113Z","iopub.execute_input":"2024-12-23T07:48:51.519772Z","iopub.status.idle":"2024-12-23T07:48:51.559642Z","shell.execute_reply.started":"2024-12-23T07:48:51.519739Z","shell.execute_reply":"2024-12-23T07:48:51.558932Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"layers_dict = {'0': 'conv1_1',\n               '5': 'conv2_1', \n               '10': 'conv3_1', \n               '19': 'conv4_1',\n               '21': 'conv4_2', \n               '28': 'conv5_1'}\n\nstyle_weights = {'conv1_1': 1.0,\n                 'conv2_1': 0.75,\n                 'conv3_1': 0.2,\n                 'conv4_1': 0.2,\n                 'conv5_1': 0.2}\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:48:51.560395Z","iopub.execute_input":"2024-12-23T07:48:51.560637Z","iopub.status.idle":"2024-12-23T07:48:54.586956Z","shell.execute_reply.started":"2024-12-23T07:48:51.560612Z","shell.execute_reply":"2024-12-23T07:48:54.586017Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"layers_dict = {\n    'block1_conv2': 'conv1_1',\n    'block2_conv1': 'conv2_1',\n    'block3_conv1': 'conv3_1',\n    'block4_conv1': 'conv4_1',\n    'block4_conv2': 'conv4_2',\n    'block5_conv1': 'conv5_1'\n}\nstyle_weights = {\n    'conv1_1': 1.0,\n    'conv2_1': 0.75,\n    'conv3_1': 0.2,\n    'conv4_1': 0.2,\n    'conv4_2': 0.2,  # Agregar esta línea si quieres usar conv4_2\n    'conv5_1': 0.2\n}\n\ndef get_feature_extractor(cnn_model, layer_dict):\n    outputs = []\n    for layer_name in layer_dict.keys():\n        layer = cnn_model.get_layer(name=layer_name)\n        outputs.append(layer.output)\n    model = tf.keras.Model(inputs=cnn_model.input, outputs=outputs)\n    model.trainable = False\n    return model\n\nfeature_extractor = get_feature_extractor(cnn_model, layers_dict)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:48:54.588022Z","iopub.execute_input":"2024-12-23T07:48:54.588279Z","iopub.status.idle":"2024-12-23T07:48:57.901132Z","shell.execute_reply.started":"2024-12-23T07:48:54.588252Z","shell.execute_reply":"2024-12-23T07:48:57.900236Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def perceptual_loss(real_images, generated_images, feature_extractor, layers_dict, style_weights):\n    real_images = (real_images + 1.0)/2.0\n    generated_images = (generated_images + 1.0)/2.0\n\n    mean = tf.constant([0.485, 0.456, 0.406], shape=(1,1,1,3))\n    std = tf.constant([0.229, 0.224, 0.225], shape=(1,1,1,3))\n\n    real_images = (real_images - mean)/std\n    generated_images = (generated_images - mean)/std\n\n    real_images = tf.image.resize(real_images, (224,224))\n    generated_images = tf.image.resize(generated_images, (224,224))\n\n    real_features = feature_extractor(real_images, training=False)\n    generated_features = feature_extractor(generated_images, training=False)\n\n    feature_names = list(layers_dict.values())\n    loss = 0.0\n    for real_f, gen_f, name in zip(real_features, generated_features, feature_names):\n        C = tf.cast(tf.shape(real_f)[-1], tf.float32)\n        H = tf.cast(tf.shape(real_f)[1], tf.float32)\n        W = tf.cast(tf.shape(real_f)[2], tf.float32)\n\n        layer_loss = tf.reduce_mean((real_f - gen_f)**2)\n        layer_loss = layer_loss / (C * H * W)\n        layer_loss *= style_weights[name]\n        loss += layer_loss\n    return loss\n\nlog_dir = './logs/gradient_logs'\nif not os.path.exists(log_dir):\n    os.makedirs(log_dir)\nfile_writer = tf.summary.create_file_writer(log_dir)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:48:57.902186Z","iopub.execute_input":"2024-12-23T07:48:57.902841Z","iopub.status.idle":"2024-12-23T07:48:59.396896Z","shell.execute_reply.started":"2024-12-23T07:48:57.902808Z","shell.execute_reply":"2024-12-23T07:48:59.395881Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import csv\nimport os\nimport tensorflow as tf\n\nimport datetime\n\nimport datetime\n\nclass GradientLoggingCallback(tf.keras.callbacks.Callback):\n    def __init__(self, log_dir='./gradients_log'):\n        super().__init__()\n        self.log_dir = log_dir\n        if not os.path.exists(self.log_dir):\n            os.makedirs(self.log_dir)\n        current_time = datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\")\n        self.file_writer = tf.summary.create_file_writer(os.path.join(self.log_dir, current_time))\n    \n    def on_train_batch_end(self, batch, logs=None):\n        if hasattr(self.model, 'last_gradients') and self.model.last_gradients is not None:\n            with self.file_writer.as_default():\n                for var_name, grad_value in self.model.last_gradients.items():\n                    grad_mean = tf.reduce_mean(grad_value)\n                    grad_std = tf.math.reduce_std(tf.cast(grad_value, tf.float32))\n                    grad_min = tf.reduce_min(grad_value)\n                    grad_max = tf.reduce_max(grad_value)\n                    \n                    prefix = f\"{var_name}/epoch_{self.model.current_epoch}_batch_{batch}\"\n                    tf.summary.scalar(f\"{prefix}_grad_mean\", grad_mean, step=self.model.current_epoch)\n                    tf.summary.scalar(f\"{prefix}_grad_std\", grad_std, step=self.model.current_epoch)\n                    tf.summary.scalar(f\"{prefix}_grad_min\", grad_min, step=self.model.current_epoch)\n                    tf.summary.scalar(f\"{prefix}_grad_max\", grad_max, step=self.model.current_epoch)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:48:59.397956Z","iopub.execute_input":"2024-12-23T07:48:59.398247Z","iopub.status.idle":"2024-12-23T07:48:59.407570Z","shell.execute_reply.started":"2024-12-23T07:48:59.398219Z","shell.execute_reply":"2024-12-23T07:48:59.406757Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with strategy.scope():\n    monet_generator = generator_fn() # transforms photos to Monet-esque paintings\n    photo_generator = generator_fn() # transforms Monet paintings to be more like photos\n\n    monet_discriminator = discriminator_fn() # differentiates real Monet paintings and generated Monet paintings\n    photo_discriminator = discriminator_fn() # differentiates real photos and generated photos\n\n\n\nclass CycleGan(Model):\n    def __init__(\n        self,\n        monet_generator,\n        photo_generator,\n        monet_discriminator,\n        photo_discriminator,\n        lambda_cycle=10,\n    ):\n        super(CycleGan, self).__init__()\n        self.m_gen = monet_generator\n        self.p_gen = photo_generator\n        self.m_disc = monet_discriminator\n        self.p_disc = photo_discriminator\n        self.lambda_cycle = lambda_cycle\n        self.current_epoch = 0\n        self.global_step = tf.Variable(0, trainable=False, dtype=tf.int64)\n        self.summary_writer = file_writer\n\n    def compile(\n        self,\n        m_gen_optimizer,\n        p_gen_optimizer,\n        m_disc_optimizer,\n        p_disc_optimizer,\n        gen_loss_fn,\n        disc_loss_fn,\n        cycle_loss_fn,\n        identity_loss_fn,\n        perceptual_loss_fn=None,\n        layers_dict=None,\n        style_weights=None,\n        perceptual_lambda=0.1\n    ):\n        super(CycleGan, self).compile()\n        self.m_gen_optimizer = m_gen_optimizer\n        self.p_gen_optimizer = p_gen_optimizer\n        self.m_disc_optimizer = m_disc_optimizer\n        self.p_disc_optimizer = p_disc_optimizer\n        self.gen_loss_fn = gen_loss_fn\n        self.disc_loss_fn = disc_loss_fn\n        self.cycle_loss_fn = cycle_loss_fn\n        self.identity_loss_fn = identity_loss_fn\n        self.perceptual_loss_fn = perceptual_loss_fn\n        self.layers_dict = layers_dict\n        self.style_weights = style_weights\n        self.perceptual_lambda = perceptual_lambda\n\n    def train_step(self, batch_data):\n        real_monet, real_photo = batch_data\n    \n        with tf.GradientTape(persistent=True) as tape:\n            fake_monet = self.m_gen(real_photo, training=True)\n            cycled_photo = self.p_gen(fake_monet, training=True)\n            fake_photo = self.p_gen(real_monet, training=True)\n            cycled_monet = self.m_gen(fake_photo, training=True)\n    \n            same_monet = self.m_gen(real_monet, training=True)\n            same_photo = self.p_gen(real_photo, training=True)\n    \n            disc_real_monet = self.m_disc(real_monet, training=True)\n            disc_real_photo = self.p_disc(real_photo, training=True)\n            disc_fake_monet = self.m_disc(fake_monet, training=True)\n            disc_fake_photo = self.p_disc(fake_photo, training=True)\n    \n            monet_gen_loss = self.gen_loss_fn(disc_fake_monet)\n            photo_gen_loss = self.gen_loss_fn(disc_fake_photo)\n            total_cycle_loss = self.cycle_loss_fn(real_monet, cycled_monet, self.lambda_cycle) + \\\n                               self.cycle_loss_fn(real_photo, cycled_photo, self.lambda_cycle)\n            monet_id_loss = self.identity_loss_fn(real_monet, same_monet, self.lambda_cycle)\n            photo_id_loss = self.identity_loss_fn(real_photo, same_photo, self.lambda_cycle)\n    \n            total_monet_gen_loss = monet_gen_loss + total_cycle_loss + monet_id_loss\n            total_photo_gen_loss = photo_gen_loss + total_cycle_loss + photo_id_loss\n    \n            if self.perceptual_loss_fn is not None:\n                perc_loss_monet = self.perceptual_loss_fn(real_monet, fake_monet, feature_extractor, self.layers_dict, self.style_weights)\n                perc_loss_photo = self.perceptual_loss_fn(real_photo, fake_photo, feature_extractor, self.layers_dict, self.style_weights)\n                total_monet_gen_loss += self.perceptual_lambda * perc_loss_monet\n                total_photo_gen_loss += self.perceptual_lambda * perc_loss_photo\n    \n            monet_disc_loss = self.disc_loss_fn(disc_real_monet, disc_fake_monet)\n            photo_disc_loss = self.disc_loss_fn(disc_real_photo, disc_fake_photo)\n    \n        monet_generator_gradients = tape.gradient(total_monet_gen_loss, self.m_gen.trainable_variables)\n        photo_generator_gradients = tape.gradient(total_photo_gen_loss, self.p_gen.trainable_variables)\n        monet_discriminator_gradients = tape.gradient(monet_disc_loss, self.m_disc.trainable_variables)\n        photo_discriminator_gradients = tape.gradient(photo_disc_loss, self.p_disc.trainable_variables)\n    \n        self.m_gen_optimizer.apply_gradients(zip(monet_generator_gradients, self.m_gen.trainable_variables))\n        self.p_gen_optimizer.apply_gradients(zip(photo_generator_gradients, self.p_gen.trainable_variables))\n        self.m_disc_optimizer.apply_gradients(zip(monet_discriminator_gradients, self.m_disc.trainable_variables))\n        self.p_disc_optimizer.apply_gradients(zip(photo_discriminator_gradients, self.p_disc.trainable_variables))\n    \n        self.global_step.assign_add(1)\n    \n        # Asegúrate que las métricas retornadas sean escalares (usamos tf.reduce_mean)\n        return {\n            'monet_gen_loss': tf.reduce_mean(total_monet_gen_loss),\n            'photo_gen_loss': tf.reduce_mean(total_photo_gen_loss),\n            'monet_disc_loss': tf.reduce_mean(monet_disc_loss),\n            'photo_disc_loss': tf.reduce_mean(photo_disc_loss)\n        }\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:48:59.408820Z","iopub.execute_input":"2024-12-23T07:48:59.409107Z","iopub.status.idle":"2024-12-23T07:49:05.847628Z","shell.execute_reply.started":"2024-12-23T07:48:59.409078Z","shell.execute_reply":"2024-12-23T07:49:05.846504Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nn_class_2_samples//128\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:05.848724Z","iopub.execute_input":"2024-12-23T07:49:05.848981Z","iopub.status.idle":"2024-12-23T07:49:05.854044Z","shell.execute_reply.started":"2024-12-23T07:49:05.848935Z","shell.execute_reply":"2024-12-23T07:49:05.853328Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport os\n\n\nclass DisplaySampleCallback(tf.keras.callbacks.Callback):\n    def __init__(self, dataset, monet_generator, output_dir='./sample_epochs', freq=1):\n        super().__init__()\n        self.dataset = dataset\n        self.monet_generator = monet_generator\n        self.freq = freq\n        self.output_dir = output_dir\n        if not os.path.exists(self.output_dir):\n            os.makedirs(self.output_dir)\n        \n        ds_iter = iter(self.dataset)\n        self.sample_photo = next(ds_iter)[1]\n\n    def on_epoch_begin(self, epoch, logs=None):\n        self.model.current_epoch = epoch\n\n    def on_epoch_end(self, epoch, logs=None):\n        print(epoch)\n        generated_monet = self.monet_generator(self.sample_photo, training=False)\n        gen_img = (generated_monet[0].numpy() * 0.5) + 0.5\n\n        plt.figure(figsize=(6,6))\n        plt.imshow(gen_img)\n        plt.axis('off')\n        plt.title(f\"Epoch {epoch+1}\")\n        plt.savefig(os.path.join(self.output_dir, f\"epoch_{epoch+1}.png\"))\n        plt.close()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:05.854942Z","iopub.execute_input":"2024-12-23T07:49:05.855189Z","iopub.status.idle":"2024-12-23T07:49:05.865581Z","shell.execute_reply.started":"2024-12-23T07:49:05.855157Z","shell.execute_reply":"2024-12-23T07:49:05.864792Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nclass LearningRateLoggerCallback(tf.keras.callbacks.Callback):\n    def __init__(self, csv_file='lr_log.csv', monitor='monet_gen_loss'):\n        super().__init__()\n        self.csv_file = csv_file\n        self.monitor = monitor\n        self.prev_lrs = None\n        self.file_initialized = False\n\n    def on_train_begin(self, logs=None):\n        # Crear o sobreescribir el archivo CSV con encabezados\n        with open(self.csv_file, 'w') as f:\n            f.write(\"epoch,\"+self.monitor+\",m_gen_lr,p_gen_lr,m_disc_lr,p_disc_lr\\n\")\n\n    def on_epoch_end(self, epoch, logs=None):\n        logs = logs or {}\n        metric_value = logs.get(self.monitor, None)\n\n        # Obtener los LR actuales\n        m_gen_lr = float(tf.keras.backend.get_value(self.model.m_gen_optimizer.lr))\n        p_gen_lr = float(tf.keras.backend.get_value(self.model.p_gen_optimizer.lr))\n        m_disc_lr = float(tf.keras.backend.get_value(self.model.m_disc_optimizer.lr))\n        p_disc_lr = float(tf.keras.backend.get_value(self.model.p_disc_optimizer.lr))\n\n        # Escribir en el CSV\n        with open(self.csv_file, 'a') as f:\n            f.write(f\"{epoch},{metric_value},{m_gen_lr},{p_gen_lr},{m_disc_lr},{p_disc_lr}\\n\")\n\n        # Comparar con LR previos para ver si cambiaron\n        current_lrs = (m_gen_lr, p_gen_lr, m_disc_lr, p_disc_lr)\n        if self.prev_lrs is not None:\n            # Si algún LR cambió, imprimir mensaje\n            if current_lrs != self.prev_lrs:\n                print(f\"Epoch {epoch}: ¡Los learning rates han cambiado!\")\n                print(f\"Antes: {self.prev_lrs}, Ahora: {current_lrs}\")\n        self.prev_lrs = current_lrs\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:05.866508Z","iopub.execute_input":"2024-12-23T07:49:05.866759Z","iopub.status.idle":"2024-12-23T07:49:05.878354Z","shell.execute_reply.started":"2024-12-23T07:49:05.866732Z","shell.execute_reply":"2024-12-23T07:49:05.877624Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ========== CALLBACKS para mostrar y guardar checkpoints ==========\nclass DisplaySampleCallback(tf.keras.callbacks.Callback):\n    def __init__(self, dataset, monet_generator, output_dir='./sample_epochs', freq=1):\n        super().__init__()\n        self.dataset = dataset\n        self.monet_generator = monet_generator\n        self.freq = freq\n        self.output_dir = output_dir\n        if not os.path.exists(self.output_dir):\n            os.makedirs(self.output_dir)\n        \n        ds_iter = iter(self.dataset)\n        # batch_data = (real_monet, real_photo)\n        self.sample_photo = next(ds_iter)[1]  # index=1 => real_photo\n\n    def on_epoch_end(self, epoch, logs=None):\n        if (epoch + 1) % self.freq == 0:\n            generated_monet = self.monet_generator(self.sample_photo, training=False)\n            gen_img = (generated_monet[0].numpy() * 0.5) + 0.5\n\n            plt.figure(figsize=(6,6))\n            plt.imshow(gen_img)\n            plt.axis('off')\n            plt.title(f\"Epoch {epoch+1}\")\n            plt.savefig(os.path.join(self.output_dir, f\"epoch_{epoch+1}.png\"))\n            plt.close()\n\n\nclass CustomTrainCheckpoints(tf.keras.callbacks.Callback):\n    \"\"\"\n    Callback que guarda checkpoints completos (generadores, discriminadores y optimizadores)\n    usando tf.train.Checkpoint, de modo que se pueda reanudar el entrenamiento\n    exactamente con el mismo estado.\n    \"\"\"\n    def __init__(self, checkpoint_dir='checkpoints', save_freq=5):\n        \"\"\"\n        :param checkpoint_dir: carpeta donde se guardarán los checkpoints.\n        :param save_freq: cada cuántas épocas guardar.\n        \"\"\"\n        super().__init__()\n        self.checkpoint_dir = checkpoint_dir\n        self.save_freq = save_freq\n        if not os.path.exists(self.checkpoint_dir):\n            os.makedirs(self.checkpoint_dir)\n\n    def on_epoch_end(self, epoch, logs=None):\n        if (epoch + 1) % self.save_freq == 0:\n            # Build a tf.train.Checkpoint\n            ckpt = tf.train.Checkpoint(\n                monet_generator=self.model.m_gen,\n                photo_generator=self.model.p_gen,\n                monet_discriminator=self.model.m_disc,\n                photo_discriminator=self.model.p_disc,\n                monet_gen_optimizer=self.model.m_gen_optimizer,\n                photo_gen_optimizer=self.model.p_gen_optimizer,\n                monet_disc_optimizer=self.model.m_disc_optimizer,\n                photo_disc_optimizer=self.model.p_disc_optimizer\n            )\n            ckpt_path = os.path.join(self.checkpoint_dir, f'ckpt_epoch_{epoch+1}')\n            ckpt.save(file_prefix=ckpt_path)\n            print(f\"Checkpoint guardado: {ckpt_path}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:05.879469Z","iopub.execute_input":"2024-12-23T07:49:05.879697Z","iopub.status.idle":"2024-12-23T07:49:05.891530Z","shell.execute_reply.started":"2024-12-23T07:49:05.879674Z","shell.execute_reply":"2024-12-23T07:49:05.890804Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"gan_ds = get_gan_dataset('class_2.tfrecord', 'class_1.tfrecord', batch_size=BATCH_SIZE)\nsteps_per_epoch = n_class_2_samples // BATCH_SIZE","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:05.892443Z","iopub.execute_input":"2024-12-23T07:49:05.892670Z","iopub.status.idle":"2024-12-23T07:49:05.956407Z","shell.execute_reply.started":"2024-12-23T07:49:05.892646Z","shell.execute_reply":"2024-12-23T07:49:05.955563Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.callbacks import ReduceLROnPlateau\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:52:23.066010Z","iopub.execute_input":"2024-12-23T07:52:23.067162Z","iopub.status.idle":"2024-12-23T07:52:23.071353Z","shell.execute_reply.started":"2024-12-23T07:52:23.067118Z","shell.execute_reply":"2024-12-23T07:52:23.070441Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# Celda 6: ENTRENAMIENTO INICIAL\n# ============================================\n\"\"\"\nfrom tensorflow.keras.callbacks import ReduceLROnPlateau\n\nwith strategy.scope():\n    # 1. Instanciar generadores y discriminadores\n    monet_generator = generator_fn()\n    photo_generator = generator_fn()\n    monet_discriminator = discriminator_fn()\n    photo_discriminator = discriminator_fn()\n\n    # 2. Definir optimizadores (pueden ser tf.keras.optimizers o legacy)\n    monet_generator_optimizer = optimizers.Adam(2e-4, beta_1=0.5)\n    photo_generator_optimizer = optimizers.Adam(2e-4, beta_1=0.5)\n    monet_discriminator_optimizer = optimizers.Adam(2e-4, beta_1=0.5)\n    photo_discriminator_optimizer = optimizers.Adam(2e-4, beta_1=0.5)\n\n    # 3. Instanciar y compilar el modelo CycleGan\n    gan_model = CycleGan(\n        monet_generator, \n        photo_generator,\n        monet_discriminator, \n        photo_discriminator,\n        lambda_cycle=10\n    )\n    gan_model.compile(\n        m_gen_optimizer=monet_generator_optimizer,\n        p_gen_optimizer=photo_generator_optimizer,\n        m_disc_optimizer=monet_discriminator_optimizer,\n        p_disc_optimizer=photo_discriminator_optimizer,\n        gen_loss_fn=generator_loss,\n        disc_loss_fn=discriminator_loss,\n        cycle_loss_fn=calc_cycle_loss,\n        identity_loss_fn=identity_loss,\n        perceptual_loss_fn=perceptual_loss,\n        layers_dict=layers_dict,\n        style_weights=style_weights,\n        perceptual_lambda=0.1\n    )\n\n    # 4. Callbacks\n    display_callback = DisplaySampleCallback(\n        dataset=gan_ds,\n        monet_generator=gan_model.m_gen,\n        output_dir='./sample_epochs',\n        freq=1\n    )\n    reduce_lr_callback = ReduceLROnPlateau(\n        monitor='monet_gen_loss',\n        factor=0.5,\n        patience=5,\n        verbose=1,\n        mode='min'\n    )\n    # Este callback guardará un checkpoint completo cada 5 épocas (ajusta a tu gusto)\n    checkpoint_callback = CustomTrainCheckpoints(\n        checkpoint_dir='checkpoints',\n        save_freq=5\n    )\n\n    # 5. Entrenar, por ejemplo, 30 épocas\n    history = gan_model.fit(\n        gan_ds,\n        steps_per_epoch=steps_per_epoch,\n        epochs=200,\n        verbose=2,\n        callbacks=[display_callback, reduce_lr_callback, checkpoint_callback]\n    )\"\"\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:05.957469Z","iopub.execute_input":"2024-12-23T07:49:05.957729Z","iopub.status.idle":"2024-12-23T07:49:05.964121Z","shell.execute_reply.started":"2024-12-23T07:49:05.957705Z","shell.execute_reply":"2024-12-23T07:49:05.963340Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =====================================\n# Celda 3: REANUDAR ENTRENAMIENTO\n# =====================================\n\n# Volvemos a usar las mismas definiciones de generator_fn(), discriminator_fn(), etc.\n\nwith strategy.scope():\n    # 1. Crear redes con la misma arquitectura\n    monet_generator_resumed = generator_fn()\n    photo_generator_resumed = generator_fn()\n    monet_discriminator_resumed = discriminator_fn()\n    photo_discriminator_resumed = discriminator_fn()\n\n    # 2. Crear los mismos optimizadores\n    monet_generator_optimizer_resumed = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n    photo_generator_optimizer_resumed = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n    monet_discriminator_optimizer_resumed = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n    photo_discriminator_optimizer_resumed = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n\n    # 3. Instanciar un nuevo CycleGAN\n    gan_model_resumed = CycleGan(\n        monet_generator_resumed,\n        photo_generator_resumed,\n        monet_discriminator_resumed,\n        photo_discriminator_resumed,\n        lambda_cycle=10\n    )\n    gan_model_resumed.compile(\n        m_gen_optimizer=monet_generator_optimizer_resumed,\n        p_gen_optimizer=photo_generator_optimizer_resumed,\n        m_disc_optimizer=monet_discriminator_optimizer_resumed,\n        p_disc_optimizer=photo_discriminator_optimizer_resumed,\n        gen_loss_fn=generator_loss,\n        disc_loss_fn=discriminator_loss,\n        cycle_loss_fn=calc_cycle_loss,\n        identity_loss_fn=identity_loss,\n        perceptual_loss_fn=perceptual_loss,\n        layers_dict=layers_dict,\n        style_weights=style_weights,\n        perceptual_lambda=0.1\n    )\n\n    # 4. Crear un tf.train.Checkpoint para restaurar estado (G, D y Opts)\n    ckpt_resumed = tf.train.Checkpoint(\n        monet_generator=gan_model_resumed.m_gen,\n        photo_generator=gan_model_resumed.p_gen,\n        monet_discriminator=gan_model_resumed.m_disc,\n        photo_discriminator=gan_model_resumed.p_disc,\n        monet_gen_optimizer=gan_model_resumed.m_gen_optimizer,\n        photo_gen_optimizer=gan_model_resumed.p_gen_optimizer,\n        monet_disc_optimizer=gan_model_resumed.m_disc_optimizer,\n        photo_disc_optimizer=gan_model_resumed.p_disc_optimizer\n    )\n\n    # 5. Indica el checkpoint a cargar (ej. el de la época 30)\n    #    asumiendo que lo guardó como: checkpoints/ckpt_epoch_30-1\n    #    (o similar, usa tf.train.latest_checkpoint para encontrarlo)\n    checkpoint_dir = '/kaggle/input/checkpoint30-diffusse-myopia' \n    latest_ckpt = tf.train.latest_checkpoint(checkpoint_dir)\n    if latest_ckpt:\n        ckpt_resumed.restore(latest_ckpt).expect_partial()\n        print(f\"Checkpoint restaurado desde {latest_ckpt}\")\n    else:\n        print(\"No se encontró checkpoint en la carpeta:\", checkpoint_dir)\n\n    # 6. Callbacks para seguir entrenando\n    display_callback_resumed = DisplaySampleCallback(\n        dataset=gan_ds,\n        monet_generator=gan_model_resumed.m_gen,\n        output_dir='./sample_epochs_resumed',\n        freq=1\n    )\n    reduce_lr_callback_resumed = ReduceLROnPlateau(\n        monitor='monet_gen_loss',\n        factor=0.5,\n        patience=5,\n        verbose=1,\n        mode='min'\n    )\n    checkpoint_callback_resumed = CustomTrainCheckpoints(\n        checkpoint_dir='checkpoints_resumed',  # carpeta distinta o la misma\n        save_freq=10\n    )\n\n    # 7. Reanudar entrenamiento: si lo dejaste en la 30, pon initial_epoch=30\n    #    para que la siguiente sea la 31\n    history_resumed = gan_model_resumed.fit(\n        gan_ds,\n        steps_per_epoch=steps_per_epoch,\n        epochs=60,         # entrenar otras 30 epocas, por ejemplo\n        initial_epoch=30,  # arranca contaje en 30\n        verbose=2,\n        callbacks=[display_callback_resumed, reduce_lr_callback_resumed, checkpoint_callback_resumed]\n    )\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:52:28.697288Z","iopub.execute_input":"2024-12-23T07:52:28.698096Z","iopub.status.idle":"2024-12-23T14:59:39.404771Z","shell.execute_reply.started":"2024-12-23T07:52:28.698052Z","shell.execute_reply":"2024-12-23T14:59:39.403493Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\np_gen_checkpoint = '/kaggle/input/modelos-epoca38-myopia/gan_model_myopiaNoAttention_epoch_38.h5'\nm_gen_checkpoint = '/kaggle/working/model_checkpoints/gan_model_myopiaNoAttention_epoch_38.h5'\n\nprint(f\"¿Existe {p_gen_checkpoint}? {os.path.exists(p_gen_checkpoint)}\")\nprint(f\"¿Existe {m_gen_checkpoint}? {os.path.exists(m_gen_checkpoint)}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T15:01:54.715592Z","iopub.execute_input":"2024-12-23T15:01:54.716739Z","iopub.status.idle":"2024-12-23T15:01:54.736646Z","shell.execute_reply.started":"2024-12-23T15:01:54.716700Z","shell.execute_reply":"2024-12-23T15:01:54.735519Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"gan_model.p_gen.save('gan_model_normal_myopiaNoAttention66.h5')  # Guarda el generador que transforma fotos en Monet","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:19.295333Z","iopub.status.idle":"2024-12-23T07:49:19.295674Z","shell.execute_reply.started":"2024-12-23T07:49:19.295511Z","shell.execute_reply":"2024-12-23T07:49:19.295528Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"gan_model.m_gen.save('gan_model_myopiaNoAttention66.h5')  # Guarda el generador que transforma fotos en Monet","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:19.296573Z","iopub.status.idle":"2024-12-23T07:49:19.296901Z","shell.execute_reply.started":"2024-12-23T07:49:19.296745Z","shell.execute_reply":"2024-12-23T07:49:19.296762Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport zipfile\n\ndef folder_to_zip(folder_path, output_zip_path):\n    # Crear un archivo .zip\n    with zipfile.ZipFile(output_zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:\n        # Recorrer todos los archivos en el directorio\n        for root, dirs, files in os.walk(folder_path):\n            for file in files:\n                # Crear la ruta completa del archivo\n                full_path = os.path.join(root, file)\n                # Agregar el archivo al zip, eliminando el prefijo de la carpeta original\n                zipf.write(full_path, os.path.relpath(full_path, folder_path))\n\n    print(f\"Carpeta {folder_path} comprimida en {output_zip_path}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T15:02:21.072774Z","iopub.execute_input":"2024-12-23T15:02:21.073134Z","iopub.status.idle":"2024-12-23T15:02:21.078914Z","shell.execute_reply.started":"2024-12-23T15:02:21.073105Z","shell.execute_reply":"2024-12-23T15:02:21.077940Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"folder_to_zip('/kaggle/working/checkpoints_resumed', 'checkpointsdiffuse60.zip')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T15:02:23.921378Z","iopub.execute_input":"2024-12-23T15:02:23.921746Z","iopub.status.idle":"2024-12-23T15:05:50.659214Z","shell.execute_reply.started":"2024-12-23T15:02:23.921715Z","shell.execute_reply":"2024-12-23T15:05:50.658016Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"folder_to_zip('/kaggle/working/sample_epochs_resumed', 'sample_epochs_resumed60.zip')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T15:06:43.952289Z","iopub.execute_input":"2024-12-23T15:06:43.953139Z","iopub.status.idle":"2024-12-23T15:06:44.188780Z","shell.execute_reply.started":"2024-12-23T15:06:43.953083Z","shell.execute_reply":"2024-12-23T15:06:44.187663Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history.keys()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:19.302021Z","iopub.status.idle":"2024-12-23T07:49:19.302326Z","shell.execute_reply.started":"2024-12-23T07:49:19.302174Z","shell.execute_reply":"2024-12-23T07:49:19.302190Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Suponiendo que tienes un objeto de historial que contiene los datos de entrenamiento\nfor key in history.keys():\n    data = np.array(history[key])  # Asegúrate de que 'history[key]' tiene la forma correcta\n    # Verificar la forma de los datos\n    print(key, data.shape)\n\n    # Si los datos son de alta dimensión, podríamos promediarlos\n    # Asegúrate de que este enfoque tiene sentido para tus datos específicos\n    if data.ndim > 2:\n        data = data.mean(axis=tuple(range(1, data.ndim)))\n\n    plt.plot(data, label=key)\n    \n\nplt.title('Curvas de Pérdida durante el Entrenamiento')\nplt.xlabel('Épocas')\nplt.ylabel('Pérdida')\nplt.legend()\nplt.show() ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:19.303456Z","iopub.status.idle":"2024-12-23T07:49:19.303769Z","shell.execute_reply.started":"2024-12-23T07:49:19.303615Z","shell.execute_reply":"2024-12-23T07:49:19.303631Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# Suponiendo que tienes un objeto de historial que contiene los datos de entrenamiento\nfor key in history.keys():\n    data = np.array(history[key])  # Asegúrate de que 'history[key]' tiene la forma correcta\n    # Verificar la forma de los datos\n    print(key, data.shape)\n\n    # Si los datos son de alta dimensión, podríamos promediarlos\n    # Asegúrate de que este enfoque tiene sentido para tus datos específicos\n    if data.ndim > 2:\n        data = data.mean(axis=tuple(range(1, data.ndim)))\n\n    plt.plot(data, label=key)\n\nplt.title('Curvas de Pérdida durante el Entrenamiento')\nplt.xlabel('Épocas')\nplt.ylabel('Pérdida')\nplt.legend()\nplt.show()\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:19.304698Z","iopub.status.idle":"2024-12-23T07:49:19.305023Z","shell.execute_reply.started":"2024-12-23T07:49:19.304852Z","shell.execute_reply":"2024-12-23T07:49:19.304868Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"display_generated_samples(load_dataset('class_1.tfrecord').batch(1), monet_generator, 25)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:19.306105Z","iopub.status.idle":"2024-12-23T07:49:19.306439Z","shell.execute_reply.started":"2024-12-23T07:49:19.306265Z","shell.execute_reply":"2024-12-23T07:49:19.306281Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"display_generated_samples(load_dataset('class_2.tfrecord').batch(1), photo_generator, 25)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:19.307388Z","iopub.status.idle":"2024-12-23T07:49:19.307719Z","shell.execute_reply.started":"2024-12-23T07:49:19.307558Z","shell.execute_reply":"2024-12-23T07:49:19.307575Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"os.makedirs('../images/') # Create folder to save generated images\n\npredict_and_save(load_dataset(class_normal_filenames).batch(1), monet_generator, '../images/')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:19.308705Z","iopub.status.idle":"2024-12-23T07:49:19.309044Z","shell.execute_reply.started":"2024-12-23T07:49:19.308871Z","shell.execute_reply":"2024-12-23T07:49:19.308886Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"shutil.make_archive('/kaggle/working/images/', 'zip', '../images')\n\nprint(f\"Generated samples: {len([name for name in os.listdir('../images/') if os.path.isfile(os.path.join('../images/', name))])}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:19.310178Z","iopub.status.idle":"2024-12-23T07:49:19.310487Z","shell.execute_reply.started":"2024-12-23T07:49:19.310325Z","shell.execute_reply":"2024-12-23T07:49:19.310340Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport PIL\nfrom PIL import Image\n# Definiciones globales\nHEIGHT = 512\nWIDTH = 512\nCHANNELS = 3\nAUTO = tf.data.experimental.AUTOTUNE\n\n# Función para decodificar y preprocesar imágenes\ndef decode_image(image):\n    image = tf.image.decode_png(image, channels=CHANNELS)\n    image = tf.image.resize(image, [HEIGHT, WIDTH])\n    image = (tf.cast(image, tf.float32) / 127.5) - 1\n    return image\n\ndef load_image(filename):\n    image = tf.io.read_file(filename)\n    image = decode_image(image)\n    return image\n\ndef load_dataset(filenames):\n    dataset = tf.data.Dataset.from_tensor_slices(filenames)\n    dataset = dataset.map(load_image, num_parallel_calls=AUTO)\n    return dataset\n\nimport tensorflow as tf\nimport tensorflow_addons as tfa  # Importa tensorflow_addons\n\n\n\n# Función para hacer predicciones\ndef predict_image(model, image_path):\n    image = load_image(image_path)\n    image = tf.expand_dims(image, axis=0)  # Añadir la dimensión de batch\n    prediction = model.predict(image)\n    prediction = (prediction + 1) * 0.5  # Transformar de [-1, 1] a [0, 1]\n    return prediction\n# helper function for un-normalizing an image \n# and converting it from a Tensor image to a NumPy image for display\ndef im_convert(tensor):\n    \"\"\" Display a tensor as an image. \"\"\"\n    \n    image = tensor.to(\"cpu\").clone().detach()\n    image = image.numpy().squeeze()\n    image = image.transpose(1,2,0)\n    image = image * np.array((0.229, 0.224, 0.225)) + np.array((0.485, 0.456, 0.406))\n    image = image.clip(0, 1)\n\n    return image\n# Visualización de una imagen de predicción\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom PIL import Image\n\ndef display_prediction(image_path):\n    plt.figure(figsize=(6, 6))\n    prediction = predict_image(gan_model.m_gen, image_path)\n    \n    # Remove batch dimension if necessary\n    prediction = prediction.squeeze()  # Remove batch dimension\n\n    # Clip values to the expected range [0, 1] if not already\n    prediction = np.clip(prediction, 0, 1)\n\n    # Convert to 8-bit per channel format for image representation\n    prediction = (prediction * 255).astype(np.uint8)\n\n    # Display using matplotlib\n    plt.imshow(prediction)\n    plt.axis('off')\n    plt.show()\n\n    # Save using PIL\n    img = Image.fromarray(prediction)\n    img.save(\"reconstruccion2.png\")  # Saving as PNG\n\n# Use the function with an appropriate image path\nimage_path = '/kaggle/input/aptos-crop/train_images_crop/0c917c372572.png'\ndisplay_prediction(image_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:19.311419Z","iopub.status.idle":"2024-12-23T07:49:19.311736Z","shell.execute_reply.started":"2024-12-23T07:49:19.311582Z","shell.execute_reply":"2024-12-23T07:49:19.311599Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_path = '/kaggle/input/aptos-crop/train_images_crop/0e0fc1d9810c.png'\ndisplay_prediction(image_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:19.312840Z","iopub.status.idle":"2024-12-23T07:49:19.313182Z","shell.execute_reply.started":"2024-12-23T07:49:19.313022Z","shell.execute_reply":"2024-12-23T07:49:19.313039Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_path = '/kaggle/input/aptos-crop/train_images_crop/0a4e1a29ffff.png'\ndisplay_prediction(image_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:19.314203Z","iopub.status.idle":"2024-12-23T07:49:19.314504Z","shell.execute_reply.started":"2024-12-23T07:49:19.314350Z","shell.execute_reply":"2024-12-23T07:49:19.314365Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_path = '/kaggle/input/aptos-crop/train_images_crop/1409ab48175a.png'\ndisplay_prediction(image_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-23T07:49:19.315556Z","iopub.status.idle":"2024-12-23T07:49:19.315852Z","shell.execute_reply.started":"2024-12-23T07:49:19.315705Z","shell.execute_reply":"2024-12-23T07:49:19.315721Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### Use the function with an appropriate image path\nimage_path = '/kaggle/input/aptos-crop/train_images_crop/02da652c74b8.png'\ndisplay_prediction(image_path)\n","metadata":{}}]}