From 5f11bd055415c4849cbf1164665acbe533c095b0 Mon Sep 17 00:00:00 2001 From: A Farzat Date: Tue, 4 Nov 2025 17:57:32 +0300 Subject: Add Monet CycleGAN project blog --- content/blog/csca5642-w5/index.md | 84 + content/blog/csca5642-w5/notebook.html | 9812 ++++++++++++++++++++++++++++++++ 2 files changed, 9896 insertions(+) create mode 100644 content/blog/csca5642-w5/index.md create mode 100644 content/blog/csca5642-w5/notebook.html (limited to 'content') diff --git a/content/blog/csca5642-w5/index.md b/content/blog/csca5642-w5/index.md new file mode 100644 index 0000000..fe04748 --- /dev/null +++ b/content/blog/csca5642-w5/index.md @@ -0,0 +1,84 @@ ++++ +title = "🎨 From Photos to Monet: CycleGAN and Styled CycleGAN for Artistic Style Transfer" +description = "Exploring GAN-based architectures to transform real-world photos into Monet-inspired paintings, with custom enhancements for better style fidelity." +date = 2025-11-04 +[taxonomies] +tags = ["machine_learning"] +[extra] +styles = ["notebooks.css", ] ++++ + +## Project Overview + +Art and AI intersect in this project, which tackles the Kaggle challenge *“I’m +Something of a Painter Myself.”* The goal: generate Monet-style images. Instead +of creating paintings from scratch, I focused on **style +transfer**—transforming real-world photos into Monet-inspired artworks using +**CycleGAN**, and later improving the approach with a custom **Styled +CycleGAN**. + +The dataset includes: + +* **Monet paintings:** 300 images +* **Photos:** 7,038 images + +All images are 256×256 RGB, stored as TFRecords. + +The challenge lies in preserving content while transferring style—a delicate +balance between realism and artistry. + +## Approach + +The workflow began with **CycleGAN**, an architecture designed for unpaired +image-to-image translation. It uses two generators and two discriminators to +ensure that style transfer happens without losing the original content. Think +of it like translating English to French and back to English—the round trip +should preserve meaning. + +Key steps: + +* **Data Analysis:** Pixel intensity distributions, structural similarity +metrics, and visualizations. +* **CycleGAN Implementation:** Built with TensorFlow and Keras using UNet-based +generators and PatchGAN discriminators. +* **Loss Functions:** Adversarial, cycle-consistency, and identity losses. +* **Styled CycleGAN:** Introduced **style loss** and **content loss** using +VGG19 for perceptual features, improving artistic fidelity. +* **Hyperparameter Tuning:** Experimented with dropout rates and epochs to +balance clarity and style. + +## Key Findings + +* **Plain CycleGAN struggled** to produce noticeable style changes even after +50 epochs. +* **Styled CycleGAN introduced strong Monet-like patterns early (10 epochs)**, +but required tuning to reduce distortions. +* Best configuration: **Styled CycleGAN, 50 epochs, dropout=0.5**, achieving a +MiFID score of **59.90** (better than CycleGAN’s 70.76). +* Increasing dropout to 0.7 improved clarity but reduced artistic feel; +lowering it to 0.3 worsened results. + +## Reflections + +Styled CycleGAN clearly outperformed the baseline, showing that perceptual +losses (style and content) are critical for artistic tasks. However: + +* Balancing style transfer with content preservation remains tricky. +* GPU limitations restricted deeper experiments—reducing cycle and identity +loss weights might improve results. + +Future improvements could include: + +* Exploring alternative architectures (e.g., Diffusion Models). +* Reducing cycle-consistency weight for more freedom in style transfer. +* Ignoring original photos entirely, as Kaggle rules allow. + +*** + +If you're curious about the details, the full notebook is embedded below 👇 + + + + +You can also view the notebook in [a separate page](notebook.html), or check it +on [GitHub](https://github.com/Farzat07/Kaggle-Mini-Project-Monet-Painting-Dataset). diff --git a/content/blog/csca5642-w5/notebook.html b/content/blog/csca5642-w5/notebook.html new file mode 100644 index 0000000..ae4d62a --- /dev/null +++ b/content/blog/csca5642-w5/notebook.html @@ -0,0 +1,9812 @@ + + + + + +cours3w5submission + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +# Create and train Styled CycleGAN +with strategy.scope(): + styled_cyclegan = StyledCycleGAN( + Generator(), Generator(), + Discriminator(), Discriminator(), + lambda_cycle=10, + lambda_style=1.0, + lambda_content=0.5 + ) + + styled_cyclegan.compile( + m_gen_optimizer=tf.keras.optimizers.Adam(2e-4, beta_1=0.5), + p_gen_optimizer=tf.keras.optimizers.Adam(2e-4, beta_1=0.5), + m_disc_optimizer=tf.keras.optimizers.Adam(2e-4, beta_1=0.5), + p_disc_optimizer=tf.keras.optimizers.Adam(2e-4, beta_1=0.5), + gen_loss_fn=generator_loss, + disc_loss_fn=discriminator_loss, + cycle_loss_fn=calc_cycle_loss, + identity_loss_fn=identity_loss + ) + +# Build styled model +_ = styled_cyclegan(sample_input, training=False) + +# Train styled model +styled_cyclegan.fit( + tf.data.Dataset.zip((monet_ds, photo_ds)), + epochs=10 +) + +#styled_cyclegan.m_gen.save("models/style_high_dropout50.keras") + +# Create and train Styled CycleGAN with a dropout of 0.3 or 0.7 +with strategy.scope(): + styled_cyclegan = StyledCycleGAN( + Generator(dropout=.7), Generator(dropout=.7), + Discriminator(), Discriminator(), + lambda_cycle=10, + lambda_style=1.0, + lambda_content=0.5 + ) + + styled_cyclegan.compile( + m_gen_optimizer=tf.keras.optimizers.Adam(2e-4, beta_1=0.5), + p_gen_optimizer=tf.keras.optimizers.Adam(2e-4, beta_1=0.5), + m_disc_optimizer=tf.keras.optimizers.Adam(2e-4, beta_1=0.5), + p_disc_optimizer=tf.keras.optimizers.Adam(2e-4, beta_1=0.5), + gen_loss_fn=generator_loss, + disc_loss_fn=discriminator_loss, + cycle_loss_fn=calc_cycle_loss, + identity_loss_fn=identity_loss + ) + +# Build the styled model +_ = styled_cyclegan(sample_input, training=False) + +# Train the styled model +styled_cyclegan.fit( + tf.data.Dataset.zip((monet_ds, photo_ds)), + epochs=50 +) + +#styled_cyclegan.m_gen.save("models/style_high_dropout50.keras") + + +i = 1 +for img in photo_ds: + prediction = styled_cyclegan(img, training=False)[0].numpy() + prediction = (prediction * 127.5 + 127.5).astype(np.uint8) + im = Image.fromarray(prediction) + im.save(path.join(IMG_PATH, str(i) + ".jpg")) + i += 1shutil.make_archive(ZIP_NAME, 'zip', IMG_PATH) + + + +
+ + -- cgit v1.2.3-70-g09d2