{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":31153,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport glob\nimport math\nimport time\nimport zipfile\nfrom tqdm import tqdm\nfrom PIL import Image\n\nimport numpy as np\nimport matplotlib.pyplot as plt\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\n\nINPUT_ROOT = '/kaggle/input/gan-getting-started'\nMONET_DIR = os.path.join(INPUT_ROOT, 'monet_jpg')\nOUTPUT_DIR = '/kaggle/working'\nIMAGES_OUT = os.path.join(OUTPUT_DIR, 'images')\nSAMPLES_DIR = os.path.join(OUTPUT_DIR, 'samples')\nCKPT_DIR = os.path.join(OUTPUT_DIR, 'dcgan_checkpoints')\n\nos.makedirs(IMAGES_OUT, exist_ok=True)\nos.makedirs(SAMPLES_DIR, exist_ok=True)\nos.makedirs(CKPT_DIR, exist_ok=True)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-13T23:58:18.428503Z","iopub.execute_input":"2025-10-13T23:58:18.428786Z","iopub.status.idle":"2025-10-13T23:58:37.609769Z","shell.execute_reply.started":"2025-10-13T23:58:18.428765Z","shell.execute_reply":"2025-10-13T23:58:37.608821Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Quick EDA\n\npaths = sorted(glob.glob(os.path.join(MONET_DIR, '*.jpg')))\n# show a few samples\ndef show_samples(paths, n=6):\n    fig, axs = plt.subplots(1, n, figsize=(15, 4))\n    for i, p in enumerate(paths[:n]):\n        img = Image.open(p).convert('RGB')\n        axs[i].imshow(img)\n        axs[i].axis('off')\n    plt.show()\n\nshow_samples(paths, n=6)\n\n# quick metadata\nsample = Image.open(paths[0]).convert('RGB')\nprint(\"Sample image size:\", sample.size, \"mode:\", sample.mode)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-13T22:43:13.931535Z","iopub.execute_input":"2025-10-13T22:43:13.931914Z","iopub.status.idle":"2025-10-13T22:43:14.392513Z","shell.execute_reply.started":"2025-10-13T22:43:13.931885Z","shell.execute_reply":"2025-10-13T22:43:14.391413Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# parameters\nIMG_LR = 128        \nOUT_SIZE = 256      \nBATCH_SIZE = 32\nEPOCHS = 20        \nNOISE_DIM = 100\nNUM_SAMPLES = 7028  \nBUFFER_SIZE = len(paths)\nSEED = 42","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-13T22:43:23.603590Z","iopub.execute_input":"2025-10-13T22:43:23.603900Z","iopub.status.idle":"2025-10-13T22:43:23.608969Z","shell.execute_reply.started":"2025-10-13T22:43:23.603877Z","shell.execute_reply":"2025-10-13T22:43:23.608102Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# dataset loader\ndef load_and_preprocess(path):\n    img = tf.io.read_file(path)\n    img = tf.image.decode_jpeg(img, channels=3)\n    img = tf.image.resize(img, [IMG_LR, IMG_LR])\n    img = tf.cast(img, tf.float32) / 127.5 - 1.0   \n    return img\n\nds_paths = sorted(paths)\ndataset = tf.data.Dataset.from_tensor_slices(ds_paths)\ndataset = dataset.shuffle(BUFFER_SIZE, seed=SEED)\ndataset = dataset.map(load_and_preprocess, num_parallel_calls=tf.data.AUTOTUNE)\ndataset = dataset.repeat().batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)\n\nsteps_per_epoch = max(1, len(ds_paths) // BATCH_SIZE)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-13T22:43:25.536416Z","iopub.execute_input":"2025-10-13T22:43:25.536711Z","iopub.status.idle":"2025-10-13T22:43:25.666134Z","shell.execute_reply.started":"2025-10-13T22:43:25.536692Z","shell.execute_reply":"2025-10-13T22:43:25.665096Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Model building — DCGAN \n\ndef build_generator(noise_dim=NOISE_DIM, out_channels=3):\n    model = keras.Sequential(name='generator')\n    # reshape\n    n_nodes = 8 * 8 * 512\n    model.add(layers.Dense(n_nodes, use_bias=False, input_shape=(noise_dim,)))\n    model.add(layers.BatchNormalization())\n    model.add(layers.ReLU())\n    model.add(layers.Reshape((8, 8, 512)))  # 8x8\n\n    # 16x16\n    model.add(layers.Conv2DTranspose(256, kernel_size=5, strides=2, padding='same', use_bias=False))\n    model.add(layers.BatchNormalization())\n    model.add(layers.ReLU())\n\n    # 32x32\n    model.add(layers.Conv2DTranspose(128, 5, strides=2, padding='same', use_bias=False))\n    model.add(layers.BatchNormalization())\n    model.add(layers.ReLU())\n\n    # 64x64\n    model.add(layers.Conv2DTranspose(64, 5, strides=2, padding='same', use_bias=False))\n    model.add(layers.BatchNormalization())\n    model.add(layers.ReLU())\n\n    # 128x128\n    model.add(layers.Conv2DTranspose(32, 5, strides=2, padding='same', use_bias=False))\n    model.add(layers.BatchNormalization())\n    model.add(layers.ReLU())\n\n    model.add(layers.Conv2D(out_channels, kernel_size=7, padding='same', activation='tanh'))\n    return model\n\ndef build_discriminator(in_shape=(IMG_LR, IMG_LR, 3)):\n    model = keras.Sequential(name='discriminator')\n    model.add(layers.Conv2D(64, 5, strides=2, padding='same', input_shape=in_shape))\n    model.add(layers.LeakyReLU(0.2))\n    model.add(layers.Dropout(0.3))\n\n    model.add(layers.Conv2D(128, 5, strides=2, padding='same'))\n    model.add(layers.LeakyReLU(0.2))\n    model.add(layers.Dropout(0.3))\n\n    model.add(layers.Conv2D(256, 5, strides=2, padding='same'))\n    model.add(layers.LeakyReLU(0.2))\n    model.add(layers.Dropout(0.3))\n\n    model.add(layers.Conv2D(512, 5, strides=2, padding='same'))\n    model.add(layers.LeakyReLU(0.2))\n    model.add(layers.Dropout(0.3))\n\n    model.add(layers.Flatten())\n    model.add(layers.Dense(1, activation='sigmoid'))\n    return model\n\ngenerator = build_generator()\ndiscriminator = build_discriminator()\n\ngenerator.summary()\ndiscriminator.summary()\n\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-13T22:43:36.663091Z","iopub.execute_input":"2025-10-13T22:43:36.663558Z","iopub.status.idle":"2025-10-13T22:43:37.126731Z","shell.execute_reply.started":"2025-10-13T22:43:36.663529Z","shell.execute_reply":"2025-10-13T22:43:37.125810Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Losses and optimizers\n\ncross_entropy = keras.losses.BinaryCrossentropy(from_logits=False)\n\ngen_optimizer = keras.optimizers.Adam(1e-4)\ndisc_optimizer = keras.optimizers.Adam(1e-4)\n\nckpt = tf.train.Checkpoint(generator=generator,\n                           discriminator=discriminator,\n                           gen_opt=gen_optimizer,\n                           disc_opt=disc_optimizer)\nmanager = tf.train.CheckpointManager(ckpt, CKPT_DIR, max_to_keep=3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-13T22:43:49.775804Z","iopub.execute_input":"2025-10-13T22:43:49.776095Z","iopub.status.idle":"2025-10-13T22:43:49.787357Z","shell.execute_reply.started":"2025-10-13T22:43:49.776076Z","shell.execute_reply":"2025-10-13T22:43:49.786513Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Training step\n\n@tf.function\ndef train_step(real_images):\n    noise = tf.random.normal([tf.shape(real_images)[0], NOISE_DIM])\n\n    # train discriminator\n    with tf.GradientTape() as disc_tape:\n        fake_images = generator(noise, training=True)\n        real_out = discriminator(real_images, training=True)\n        fake_out = discriminator(fake_images, training=True)\n\n        real_labels = tf.ones_like(real_out) * 0.9  # smoothing (neccesary?)\n        fake_labels = tf.zeros_like(fake_out)\n\n        d_loss_real = cross_entropy(real_labels, real_out)\n        d_loss_fake = cross_entropy(fake_labels, fake_out)\n        d_loss = d_loss_real + d_loss_fake\n\n    grads_d = disc_tape.gradient(d_loss, discriminator.trainable_variables)\n    disc_optimizer.apply_gradients(zip(grads_d, discriminator.trainable_variables))\n\n    # train generator\n    noise2 = tf.random.normal([tf.shape(real_images)[0], NOISE_DIM])\n    with tf.GradientTape() as gen_tape:\n        generated = generator(noise2, training=True)\n        fake_out = discriminator(generated, training=True)\n        g_loss = cross_entropy(tf.ones_like(fake_out), fake_out)\n\n    grads_g = gen_tape.gradient(g_loss, generator.trainable_variables)\n    gen_optimizer.apply_gradients(zip(grads_g, generator.trainable_variables))\n\n    return d_loss, g_loss","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-13T22:43:52.138807Z","iopub.execute_input":"2025-10-13T22:43:52.139135Z","iopub.status.idle":"2025-10-13T22:43:52.147643Z","shell.execute_reply.started":"2025-10-13T22:43:52.139109Z","shell.execute_reply":"2025-10-13T22:43:52.146676Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Training loop \n\nds_iter = iter(dataset)\nsample_noise = tf.random.normal([16, NOISE_DIM])\n\nfor epoch in range(1, EPOCHS + 1):\n    start = time.time()\n    d_loss_avg = 0.0\n    g_loss_avg = 0.0\n    for step in range(steps_per_epoch):\n        real_batch = next(ds_iter)\n        d_loss, g_loss = train_step(real_batch)\n        d_loss_avg += float(d_loss)\n        g_loss_avg += float(g_loss)\n    d_loss_avg /= steps_per_epoch\n    g_loss_avg /= steps_per_epoch\n\n    # every 5 epochs save\n    if epoch % 5 == 0 or epoch == 1 or epoch == EPOCHS:\n        fake = generator(sample_noise, training=False)\n        fake = (fake + 1.0) * 127.5\n        fake = tf.clip_by_value(fake, 0, 255).numpy().astype('uint8')\n\n        # create grid 4x4\n        grid = Image.new('RGB', (IMG_LR * 4, IMG_LR * 4))\n        idx = 0\n        for i in range(4):\n            for j in range(4):\n                im = Image.fromarray(fake[idx])\n                grid.paste(im, (j*IMG_LR, i*IMG_LR))\n                idx += 1\n        sample_path = os.path.join(SAMPLES_DIR, f'epoch_{epoch:03d}.jpg')\n        grid.save(sample_path)\n        manager.save()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-13T22:43:57.424584Z","iopub.execute_input":"2025-10-13T22:43:57.425277Z","iopub.status.idle":"2025-10-13T23:09:49.695140Z","shell.execute_reply.started":"2025-10-13T22:43:57.425214Z","shell.execute_reply":"2025-10-13T23:09:49.694160Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Visualize final samples\nsample_files = sorted(glob.glob(os.path.join(SAMPLES_DIR, 'epoch_*.jpg')))\nif sample_files:\n    display(Image.open(sample_files[-1]))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-13T23:09:49.696661Z","iopub.execute_input":"2025-10-13T23:09:49.697110Z","iopub.status.idle":"2025-10-13T23:09:49.755786Z","shell.execute_reply.started":"2025-10-13T23:09:49.697083Z","shell.execute_reply":"2025-10-13T23:09:49.754823Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# upscale to 256×256, and save\nif manager.latest_checkpoint:\n    ckpt.restore(manager.latest_checkpoint)\nos.makedirs(IMAGES_OUT, exist_ok=True)\n\nbatch_size_gen = 64\nbatches = math.ceil(NUM_SAMPLES / batch_size_gen)\nimg_count = 0\nfor b in tqdm(range(batches)):\n    cur = min(batch_size_gen, NUM_SAMPLES - img_count)\n    noise = tf.random.normal([cur, NOISE_DIM])\n    fake = generator(noise, training=False)\n    fake = (fake + 1.0) / 2.0  # [0,1]\n    fake_np = (fake.numpy() * 255).astype('uint8')\n\n    for i in range(cur):\n        im = Image.fromarray(fake_np[i])\n        # upscale to 256x256 (bilinear)\n        im = im.resize((OUT_SIZE, OUT_SIZE), resample=Image.BILINEAR)\n        fname = os.path.join(IMAGES_OUT, f'image_{img_count:05d}.jpg')\n        im.save(fname, quality=95)\n        img_count += 1\n\nprint(\"put images to\", IMAGES_OUT, \"count:\", img_count)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-13T23:09:49.756774Z","iopub.execute_input":"2025-10-13T23:09:49.756983Z","iopub.status.idle":"2025-10-13T23:14:20.327869Z","shell.execute_reply.started":"2025-10-13T23:09:49.756967Z","shell.execute_reply":"2025-10-13T23:14:20.327075Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Zip images into `images.zip`\n\nzipf = os.path.join(OUTPUT_DIR, 'images.zip')\nwith zipfile.ZipFile(zipf, 'w', zipfile.ZIP_DEFLATED) as z:\n    for root, _, files in os.walk(IMAGES_OUT):\n        for file in files:\n            z.write(os.path.join(root, file), arcname=file)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-13T23:58:37.863661Z","iopub.execute_input":"2025-10-13T23:58:37.863989Z","iopub.status.idle":"2025-10-13T23:58:37.869744Z","shell.execute_reply.started":"2025-10-13T23:58:37.863959Z","shell.execute_reply":"2025-10-13T23:58:37.868728Z"}},"outputs":[],"execution_count":null}]}