{"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":"none","dataSources":[{"sourceId":3004,"databundleVersionId":861823,"sourceType":"competition"}],"dockerImageVersionId":30698,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\npd.set_option('display.max_columns', None)\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"a72748f5-c8c5-4f28-904a-fe7b2e601b34","_cell_guid":"138c41e3-c328-4287-a181-168b6213f20f","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-09T10:53:53.469295Z","iopub.execute_input":"2024-05-09T10:53:53.469777Z","iopub.status.idle":"2024-05-09T10:53:53.985133Z","shell.execute_reply.started":"2024-05-09T10:53:53.469739Z","shell.execute_reply":"2024-05-09T10:53:53.983903Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n<font style=\"font-size:18px;color:blue;font-style: italic;\" > \n<ul>\n<li>The MNIST dataset was created by Yann LeCun, Corinna Cortes, and Christopher J.C. Burges for evaluating machine learning models on the specific task of recognizing handwritten digits. \n    \n<li>Content: The dataset contains grayscale images of handwritten digits (from 0 to 9). \n<li>Image Size: Each image is 28 x 28 pixels, typically represented in a flattened form as a 784-dimensional vector of pixel intensity values.\n<li>Labeling: Each image is labeled with the digit it represents.\n</ul>\n</font>","metadata":{}},{"cell_type":"code","source":"df_train = pd.read_csv('/kaggle/input/digit-recognizer/train.csv')\ndf_train.head()","metadata":{"_uuid":"8cd6a5b9-da29-492c-a865-63f5b8adf343","_cell_guid":"b8274fc0-9ccb-400b-924e-fd82557f2537","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-09T10:53:56.647924Z","iopub.execute_input":"2024-05-09T10:53:56.648485Z","iopub.status.idle":"2024-05-09T10:54:01.663044Z","shell.execute_reply.started":"2024-05-09T10:53:56.648443Z","shell.execute_reply":"2024-05-09T10:54:01.661587Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train.shape","metadata":{"_uuid":"a70c5647-6bcd-4c30-8739-be0813675281","_cell_guid":"26a8d226-91fc-41f3-abeb-8fe73339eec4","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-09T10:54:01.665601Z","iopub.execute_input":"2024-05-09T10:54:01.666003Z","iopub.status.idle":"2024-05-09T10:54:01.674424Z","shell.execute_reply.started":"2024-05-09T10:54:01.665971Z","shell.execute_reply":"2024-05-09T10:54:01.672890Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Remove label column\ndata_matrix = np.array(df_train.loc[:, df_train.columns != 'label'])\ndata_matrix = data_matrix.astype(np.float64)\n\n\n#Converting the flattened 784-dimensional vector of pixel intensity values back to its original square dimension of 28x28 pixels.\ndata_matrix = data_matrix.reshape(df_train.shape[0],28,28)","metadata":{"_uuid":"4945a2e1-5bf9-4942-8875-c8c88ac9d766","_cell_guid":"9b6413ef-fb08-4cbd-ae79-b212cd4e174d","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-09T10:54:01.676221Z","iopub.execute_input":"2024-05-09T10:54:01.676678Z","iopub.status.idle":"2024-05-09T10:54:02.006939Z","shell.execute_reply.started":"2024-05-09T10:54:01.676643Z","shell.execute_reply":"2024-05-09T10:54:02.005399Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_matrix.shape","metadata":{"execution":{"iopub.status.busy":"2024-05-09T10:54:02.010143Z","iopub.execute_input":"2024-05-09T10:54:02.011048Z","iopub.status.idle":"2024-05-09T10:54:02.019489Z","shell.execute_reply.started":"2024-05-09T10:54:02.011003Z","shell.execute_reply":"2024-05-09T10:54:02.018173Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<font style=\"font-size:18px;color:blue;font-style: italic;\" > \nA look into the Dataset\n</font>","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\n\ndef display_images_grid(data_matrix, indices, rows, cols):\n    if any(i >= data_matrix.shape[0] or i < 0 for i in indices):\n        print(\"One or more indices are out of range.\")\n        return\n\n    fig, axes = plt.subplots(rows, cols, figsize=(cols * 2, rows * 2))\n    fig.subplots_adjust(hspace=0.5, wspace=0.1)\n\n    for ax, index in zip(axes.flatten(), indices):\n        # Check if the current index exists in the indices list\n        if index < len(indices):\n            # Reshape the 1D array (row of the data matrix) back to 2D (assuming 100x100)\n            image = data_matrix[index].reshape(28,28)\n            ax.imshow(image, cmap='gray')\n            ax.set_title(f\"Image at index {index}\")\n            ax.axis('off')  # Turn off axis numbers and ticks\n        else:\n            ax.axis('off')  # Hide empty subplots\n    \n    plt.show()\n\n# Example usage\n# Assuming `data_matrix` is already loaded with image data\n# Display the first 10 images in a 2x5 grid\nindices_to_display = list(range(20))  # You can specify any range of indices here\ndisplay_images_grid(data_matrix, indices_to_display, 4, 5)\n","metadata":{"execution":{"iopub.status.busy":"2024-05-09T10:54:02.021139Z","iopub.execute_input":"2024-05-09T10:54:02.022627Z","iopub.status.idle":"2024-05-09T10:54:03.421167Z","shell.execute_reply.started":"2024-05-09T10:54:02.022581Z","shell.execute_reply":"2024-05-09T10:54:03.420159Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<font style=\"font-size:18px;color:blue;font-style: italic;\" > \n<ul>\n\n<li> In every iteration, both the discriminator and generator are trained alternately, freezing the weights of the other.\n    \n<li>In the first part of the iteration, the discriminator learns to classify between real and fake images. \n\n<li>In the second part of the iteration, the generator learns to modify the fake image in a way that makes it tough for the discriminator to classify. \n\n<li>This is repeated for many iterations.\n\n\n<li>Since CNNs (Convolutional Neural Networks) work well with images due to their use of filters and pooling layers, both generators and discriminators in GANs (Generative Adversarial Networks) typically employ CNN-based architectures. \n\n<li>Filters in CNNs are effective at detecting similar attributes within close neighborhoods, allowing the network to recognize and process visual patterns efficiently. This capability is crucial for both generating new images and distinguishing between real and generated images, making CNNs an ideal choice for the discriminator and generator components in GAN frameworks.\n</ul>\n    \n</font>","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nfrom tensorflow.keras import layers, models, optimizers, Model\nfrom keras.layers import Input, Dense, Reshape, Flatten, Conv2D, Conv2DTranspose, LeakyReLU, BatchNormalization\nfrom tensorflow.keras.optimizers import Adam\n\n# Setting up pandas to display all columns\npd.set_option('display.max_columns', None)\n\n# Load dataset\ndef load_data():\n    df_train = pd.read_csv('/kaggle/input/digit-recognizer/train.csv')\n    data_matrix = df_train.drop('label', axis=1).values\n    data_matrix = data_matrix.reshape(df_train.shape[0],28,28,1)\n    data_matrix = ((data_matrix.astype(np.float32) / 255.0) * 2 - 1.0)\n    return data_matrix, df_train['label']\n\ndata_matrix, labels = load_data()\n\n\n# 100*1 -> 256 * 7 * 7 (Dense laye) -> 7 * 7 * 256 (Reshape) -> 14 * 14 * 128 (upsample (Conv2DTranspose) + 128 filters) -> 28 * 28 * 1 (upsample (Conv2DTranspose) + 1 filter)\ndef build_generator(input_dim_noise = 100, output_shape = (28,28,1)):\n    inputs = Input(shape=(input_dim_noise,))\n    # Start with a Dense layer to expand the dimensions\n    x = Dense(256 * (output_shape[0] // 4) * (output_shape[1] // 4))(inputs)\n    x = LeakyReLU(alpha=0.2)(x)\n    x = BatchNormalization(momentum=0.8)(x)\n    \n    # Reshape into a feature map\n    x = Reshape((output_shape[0] // 4, output_shape[1] // 4, 256))(x)\n    \n    # Upsample to the next stage\n    x = Conv2DTranspose(128, kernel_size=4, strides=2, padding='same')(x)\n    x = LeakyReLU(alpha=0.2)(x)\n    x = BatchNormalization(momentum=0.8)(x)\n    \n    # Upsample to the final image size\n    x = Conv2DTranspose(output_shape[2], kernel_size=4, strides=2, padding='same', activation='tanh')(x)  # Output channels is the last element of output_shape\n\n    model = Model(inputs, x)\n    return model\n\n#28 * 28 * 1 (Noise) -> 14 * 14 * 64 (Downsample (Conv2D) + 64 filters) - > 7 * 7 * 128 (Downsample (Conv2D) + 128 filters) -> 6272 (flatten) -> 1 (Sigmoid)\ndef build_discriminator(input_shape=(28,28,1)):\n    inputs = Input(shape=input_shape)\n    # Downsample\n    x = Conv2D(64, kernel_size=4, strides=2, padding='same')(inputs)\n    x = LeakyReLU(alpha=0.2)(x)\n    \n    # Downsample further\n    x = Conv2D(128, kernel_size=4, strides=2, padding='same')(x)\n    x = LeakyReLU(alpha=0.2)(x)\n    \n    # Flatten and output classification\n    x = Flatten()(x)\n    x = Dense(1, activation='sigmoid')(x)\n    \n    model = Model(inputs, x)\n    model.compile(loss='binary_crossentropy', optimizer=Adam(0.0002, 0.5), metrics=['accuracy'])\n    return model\n\n# Define the GAN\ndef build_gan(generator, discriminator):\n    discriminator.trainable = False\n    model = models.Sequential([generator, discriminator])\n    model.compile(loss='binary_crossentropy', optimizer=optimizers.Adam(0.005, 0.5), metrics=['accuracy'])\n    return model\n\n# Instantiate the models\ngenerator = build_generator()\ndiscriminator = build_discriminator()\ngan = build_gan(generator, discriminator)\n\n# Display models\ngenerator.summary()\ndiscriminator.summary()\ngan.summary()\n\n# Training function\ndef train_gan(generator, discriminator, gan, data_matrix, iterations=20, batch_size=128):\n    for iteration in range(iterations):\n        idx = np.random.randint(0, data_matrix.shape[0], batch_size)\n        real_images = data_matrix[idx]\n        \n        noise = np.random.normal(0, 1, (batch_size, 100))\n        generated_images = generator.predict(noise)\n        \n        # Train Discriminator\n        discriminator.trainable = True\n        d_loss_real = discriminator.train_on_batch(real_images, np.ones((batch_size, 1)))\n        d_loss_fake = discriminator.train_on_batch(generated_images, np.zeros((batch_size, 1)))\n        d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)\n        \n        # Train Generator\n        discriminator.trainable = False\n        noise = np.random.normal(0, 1, (batch_size, 100))\n        g_loss = gan.train_on_batch(noise, np.ones((batch_size, 1)))\n\n        # Print progress\n        print(f\"Iteration {iteration + 1}/{iterations} - D Loss: {d_loss[0]}, D Accuracy: {d_loss[1]}, G Loss: {g_loss[0]}, G Accuracy: {g_loss[1]}\")\n        if iteration % 20 == 0:\n            display_generated_images(generator)\n        \n\n# Display generated images\ndef display_generated_images(generator, num_examples=10):\n    noise = np.random.normal(0, 1, (num_examples, 100))\n    generated_images = generator.predict(noise)\n    plt.figure(figsize=(10, 1))\n    for i in range(num_examples):\n        plt.subplot(1, 10, i+1)\n        plt.imshow(generated_images[i].reshape(28, 28), cmap='gray')\n        plt.axis('off')\n    plt.show()\n\n# Training the GAN\ntrain_gan(generator, discriminator, gan, data_matrix, iterations=800, batch_size=128)\n\n# Displaying generated images\ndisplay_generated_images(generator)\n","metadata":{"_uuid":"7d221225-b338-4806-8b97-fc3aff5fa7e7","_cell_guid":"5e6c6c0e-b92c-4a08-b1fd-a618290da1c0","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-09T10:54:03.422623Z","iopub.execute_input":"2024-05-09T10:54:03.423045Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<font style=\"font-size:18px;color:blue;font-style: italic;\" > \n<ul>\n<li> Taking noise as input, the generator has started creating images that look like digits, which is confusing the discriminator in classifying between true digits and generated digits.\n<li> CNN converges faster and generates more cleaner image\n</ul> \n</font>","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}