1
+ {
2
+ "cells" : [
3
+ {
4
+ "cell_type" : " markdown" ,
5
+ "metadata" : {
6
+ "id" : " QmRAEtvJ_6OT"
7
+ },
8
+ "source" : [
9
+ " # **Deep Learning With Python - CHAPTER 12**"
10
+ ]
11
+ },
12
+ {
13
+ "cell_type" : " markdown" ,
14
+ "metadata" : {
15
+ "id" : " 8HE2uMKK_7Qp"
16
+ },
17
+ "source" : [
18
+ " - This code implements a **Generative Adversarial Network (GAN)** to generate realistic face images using the **CelebA dataset**.\n " ,
19
+ " \n " ,
20
+ " - It is structured into several classes for better modularity:\n " ,
21
+ " \n " ,
22
+ " `CelebAGANDataLoader` handles dataset downloading and preprocessing, `Discriminator` and `Generator` define the two neural networks, `GAN` encapsulates the training logic, and `GANMonitor` saves generated images during training.\n " ,
23
+ " \n " ,
24
+ " - The model is trained using **binary cross-entropy loss**, and the generator learns to create increasingly realistic images by competing with the discriminator. The training loop runs for **100 epochs**, generating images at the end of each epoch."
25
+ ]
26
+ },
27
+ {
28
+ "cell_type" : " code" ,
29
+ "execution_count" : 2 ,
30
+ "metadata" : {
31
+ "id" : " oqNg9frRCBgk"
32
+ },
33
+ "outputs" : [],
34
+ "source" : [
35
+ " import os\n " ,
36
+ " import pathlib\n " ,
37
+ " import random\n " ,
38
+ " import tensorflow as tf\n " ,
39
+ " from tensorflow import keras\n " ,
40
+ " import matplotlib.pyplot as plt\n " ,
41
+ " from tensorflow.keras import layers"
42
+ ]
43
+ },
44
+ {
45
+ "cell_type" : " code" ,
46
+ "execution_count" : 3 ,
47
+ "metadata" : {
48
+ "id" : " 7HHCQEtlu8Pg"
49
+ },
50
+ "outputs" : [],
51
+ "source" : [
52
+ " class CelebAGANDataLoader:\n " ,
53
+ " def __init__(self, dataset_path=\" celeba_gan\" , image_size=(64, 64), batch_size=32):\n " ,
54
+ " self.dataset_path = dataset_path\n " ,
55
+ " self.image_size = image_size\n " ,
56
+ " self.batch_size = batch_size\n " ,
57
+ " \n " ,
58
+ " def download_and_extract_data(self):\n " ,
59
+ " os.makedirs(self.dataset_path, exist_ok=True)\n " ,
60
+ " !gdown --id 1O7m1010EJjLE5QxLZiM9Fpjs7Oj6e684 -O {self.dataset_path}/data.zip\n " ,
61
+ " !unzip -qq {self.dataset_path}/data.zip -d {self.dataset_path}\n " ,
62
+ " \n " ,
63
+ " def load_dataset(self):\n " ,
64
+ " dataset = keras.utils.image_dataset_from_directory(\n " ,
65
+ " self.dataset_path,\n " ,
66
+ " label_mode=None,\n " ,
67
+ " image_size=self.image_size,\n " ,
68
+ " batch_size=self.batch_size,\n " ,
69
+ " smart_resize=True\n " ,
70
+ " )\n " ,
71
+ " return dataset.map(lambda x: x / 255.0)"
72
+ ]
73
+ },
74
+ {
75
+ "cell_type" : " code" ,
76
+ "source" : [
77
+ " class Discriminator(keras.Model):\n " ,
78
+ " def __init__(self, input_shape=(64, 64, 3)):\n " ,
79
+ " super().__init__()\n " ,
80
+ " self.model = keras.Sequential([\n " ,
81
+ " layers.Conv2D(64, kernel_size=4, strides=2, padding=\" same\" ),\n " ,
82
+ " layers.LeakyReLU(alpha=0.2),\n " ,
83
+ " layers.Conv2D(128, kernel_size=4, strides=2, padding=\" same\" ),\n " ,
84
+ " layers.LeakyReLU(alpha=0.2),\n " ,
85
+ " layers.Conv2D(128, kernel_size=4, strides=2, padding=\" same\" ),\n " ,
86
+ " layers.LeakyReLU(alpha=0.2),\n " ,
87
+ " layers.Flatten(),\n " ,
88
+ " layers.Dropout(0.2),\n " ,
89
+ " layers.Dense(1, activation=\" sigmoid\" ),\n " ,
90
+ " ], name=\" discriminator\" )\n " ,
91
+ " \n " ,
92
+ " def call(self, inputs):\n " ,
93
+ " return self.model(inputs)"
94
+ ],
95
+ "metadata" : {
96
+ "id" : " 6mitfoIAJY0r"
97
+ },
98
+ "execution_count" : 4 ,
99
+ "outputs" : []
100
+ },
101
+ {
102
+ "cell_type" : " code" ,
103
+ "source" : [
104
+ " class Generator(keras.Model):\n " ,
105
+ " def __init__(self, latent_dim=128):\n " ,
106
+ " super().__init__()\n " ,
107
+ " self.model = keras.Sequential([\n " ,
108
+ " layers.Dense(8 * 8 * 128, input_shape=(latent_dim,)),\n " ,
109
+ " layers.Reshape((8, 8, 128)),\n " ,
110
+ " layers.Conv2DTranspose(128, kernel_size=4, strides=2, padding=\" same\" ),\n " ,
111
+ " layers.LeakyReLU(alpha=0.2),\n " ,
112
+ " layers.Conv2DTranspose(256, kernel_size=4, strides=2, padding=\" same\" ),\n " ,
113
+ " layers.LeakyReLU(alpha=0.2),\n " ,
114
+ " layers.Conv2DTranspose(512, kernel_size=4, strides=2, padding=\" same\" ),\n " ,
115
+ " layers.LeakyReLU(alpha=0.2),\n " ,
116
+ " layers.Conv2D(3, kernel_size=5, padding=\" same\" , activation=\" sigmoid\" ),\n " ,
117
+ " ], name=\" generator\" )\n " ,
118
+ " \n " ,
119
+ " def call(self, inputs):\n " ,
120
+ " return self.model(inputs)"
121
+ ],
122
+ "metadata" : {
123
+ "id" : " qr8jz4GeLVbT"
124
+ },
125
+ "execution_count" : 5 ,
126
+ "outputs" : []
127
+ },
128
+ {
129
+ "cell_type" : " code" ,
130
+ "source" : [
131
+ " class GAN(keras.Model):\n " ,
132
+ " def __init__(self, discriminator, generator, latent_dim):\n " ,
133
+ " super().__init__()\n " ,
134
+ " self.discriminator = discriminator\n " ,
135
+ " self.generator = generator\n " ,
136
+ " self.latent_dim = latent_dim\n " ,
137
+ " self.d_loss_metric = keras.metrics.Mean(name=\" d_loss\" )\n " ,
138
+ " self.g_loss_metric = keras.metrics.Mean(name=\" g_loss\" )\n " ,
139
+ " \n " ,
140
+ " def compile(self, d_optimizer, g_optimizer, loss_fn):\n " ,
141
+ " super().compile()\n " ,
142
+ " self.d_optimizer = d_optimizer\n " ,
143
+ " self.g_optimizer = g_optimizer\n " ,
144
+ " self.loss_fn = loss_fn\n " ,
145
+ " \n " ,
146
+ " @property\n " ,
147
+ " def metrics(self):\n " ,
148
+ " return [self.d_loss_metric, self.g_loss_metric]\n " ,
149
+ " \n " ,
150
+ " def train_step(self, real_images):\n " ,
151
+ " batch_size = tf.shape(real_images)[0]\n " ,
152
+ " random_latent_vectors = tf.random.normal(shape=(batch_size, self.latent_dim))\n " ,
153
+ " generated_images = self.generator(random_latent_vectors)\n " ,
154
+ " combined_images = tf.concat([generated_images, real_images], axis=0)\n " ,
155
+ " \n " ,
156
+ " labels = tf.concat([tf.ones((batch_size, 1)), tf.zeros((batch_size, 1))], axis=0)\n " ,
157
+ " labels += 0.05 * tf.random.uniform(tf.shape(labels))\n " ,
158
+ " \n " ,
159
+ " with tf.GradientTape() as tape:\n " ,
160
+ " predictions = self.discriminator(combined_images)\n " ,
161
+ " d_loss = self.loss_fn(labels, predictions)\n " ,
162
+ " grads = tape.gradient(d_loss, self.discriminator.trainable_weights)\n " ,
163
+ " self.d_optimizer.apply_gradients(zip(grads, self.discriminator.trainable_weights))\n " ,
164
+ " \n " ,
165
+ " random_latent_vectors = tf.random.normal(shape=(batch_size, self.latent_dim))\n " ,
166
+ " misleading_labels = tf.zeros((batch_size, 1))\n " ,
167
+ " \n " ,
168
+ " with tf.GradientTape() as tape:\n " ,
169
+ " predictions = self.discriminator(self.generator(random_latent_vectors))\n " ,
170
+ " g_loss = self.loss_fn(misleading_labels, predictions)\n " ,
171
+ " grads = tape.gradient(g_loss, self.generator.trainable_weights)\n " ,
172
+ " self.g_optimizer.apply_gradients(zip(grads, self.generator.trainable_weights))\n " ,
173
+ " \n " ,
174
+ " self.d_loss_metric.update_state(d_loss)\n " ,
175
+ " self.g_loss_metric.update_state(g_loss)\n " ,
176
+ " return {\" d_loss\" : self.d_loss_metric.result(), \" g_loss\" : self.g_loss_metric.result()}"
177
+ ],
178
+ "metadata" : {
179
+ "id" : " 5KU0n2MpLXsb"
180
+ },
181
+ "execution_count" : 6 ,
182
+ "outputs" : []
183
+ },
184
+ {
185
+ "cell_type" : " code" ,
186
+ "source" : [
187
+ " class GANMonitor(keras.callbacks.Callback):\n " ,
188
+ " def __init__(self, num_img=3, latent_dim=128):\n " ,
189
+ " self.num_img = num_img\n " ,
190
+ " self.latent_dim = latent_dim\n " ,
191
+ " \n " ,
192
+ " def on_epoch_end(self, epoch, logs=None):\n " ,
193
+ " random_latent_vectors = tf.random.normal(shape=(self.num_img, self.latent_dim))\n " ,
194
+ " generated_images = self.model.generator(random_latent_vectors)\n " ,
195
+ " generated_images *= 255\n " ,
196
+ " generated_images = generated_images.numpy()\n " ,
197
+ " \n " ,
198
+ " for i in range(self.num_img):\n " ,
199
+ " img = keras.utils.array_to_img(generated_images[i])\n " ,
200
+ " img.save(f\" generated_img_{epoch:03d}_{i}.png\" )"
201
+ ],
202
+ "metadata" : {
203
+ "id" : " DkfZR6EULaJ6"
204
+ },
205
+ "execution_count" : 7 ,
206
+ "outputs" : []
207
+ },
208
+ {
209
+ "cell_type" : " code" ,
210
+ "source" : [
211
+ " if __name__ == \" __main__\" :\n " ,
212
+ " data_loader = CelebAGANDataLoader()\n " ,
213
+ " dataset = data_loader.load_dataset()\n " ,
214
+ " \n " ,
215
+ " discriminator = Discriminator()\n " ,
216
+ " generator = Generator(latent_dim=128)\n " ,
217
+ " \n " ,
218
+ " gan = GAN(discriminator=discriminator, generator=generator, latent_dim=128)\n " ,
219
+ " gan.compile(\n " ,
220
+ " d_optimizer=keras.optimizers.Adam(learning_rate=0.0001),\n " ,
221
+ " g_optimizer=keras.optimizers.Adam(learning_rate=0.0001),\n " ,
222
+ " loss_fn=keras.losses.BinaryCrossentropy(),\n " ,
223
+ " )\n " ,
224
+ " \n " ,
225
+ " gan.fit(dataset, epochs=100, callbacks=[GANMonitor(num_img=10, latent_dim=128)])"
226
+ ],
227
+ "metadata" : {
228
+ "id" : " 8J0DSS30O0uZ"
229
+ },
230
+ "execution_count" : null ,
231
+ "outputs" : []
232
+ }
233
+ ],
234
+ "metadata" : {
235
+ "colab" : {
236
+ "provenance" : []
237
+ },
238
+ "kernelspec" : {
239
+ "display_name" : " Python 3" ,
240
+ "name" : " python3"
241
+ },
242
+ "language_info" : {
243
+ "name" : " python"
244
+ }
245
+ },
246
+ "nbformat" : 4 ,
247
+ "nbformat_minor" : 0
248
+ }
0 commit comments