{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Import Library" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "import mnist" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "import mlx.core as mx\n", "import mlx.nn as nn\n", "import mlx.optimizers as optim\n", "\n", "from tqdm import tqdm\n", "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# GAN Architecture" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Generator 👨🏻‍🎨" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "def GenBlock(in_dim:int,out_dim:int):\n", " \n", " return nn.Sequential(\n", " nn.Linear(in_dim,out_dim),\n", " nn.BatchNorm(out_dim),\n", " nn.ReLU()\n", " )" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "class Generator(nn.Module):\n", "\n", " def __init__(self, z_dim:int = 10, im_dim:int = 784, hidden_dim: int =128):\n", " super(Generator, self).__init__()\n", " # Build the neural network\n", " self.gen = nn.Sequential(\n", " GenBlock(z_dim, hidden_dim),\n", " GenBlock(hidden_dim, hidden_dim * 2),\n", " GenBlock(hidden_dim * 2, hidden_dim * 4),\n", " GenBlock(hidden_dim * 4, hidden_dim * 8),\n", "\n", "\n", " nn.Linear(hidden_dim * 8,im_dim),\n", " nn.Sigmoid()\n", " )\n", " \n", " def __call__(self, noise):\n", "\n", " return self.gen(noise)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Generator(\n", " (gen): Sequential(\n", " (layers.0): Sequential(\n", " (layers.0): Linear(input_dims=100, output_dims=128, bias=True)\n", " (layers.1): BatchNorm(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (layers.2): ReLU()\n", " )\n", " (layers.1): Sequential(\n", " (layers.0): Linear(input_dims=128, output_dims=256, bias=True)\n", " (layers.1): BatchNorm(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (layers.2): ReLU()\n", " )\n", " (layers.2): Sequential(\n", " (layers.0): Linear(input_dims=256, output_dims=512, bias=True)\n", " (layers.1): BatchNorm(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (layers.2): ReLU()\n", " )\n", " (layers.3): Sequential(\n", " (layers.0): Linear(input_dims=512, output_dims=1024, bias=True)\n", " (layers.1): BatchNorm(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (layers.2): ReLU()\n", " )\n", " (layers.4): Linear(input_dims=1024, output_dims=784, bias=True)\n", " (layers.5): Sigmoid()\n", " )\n", ")" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gen = Generator(100)\n", "gen" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "def get_noise(n_samples, z_dim):\n", "\n", " return np.random.randn(n_samples,z_dim)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Discriminator 🕵🏻‍♂️" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "def DisBlock(in_dim:int,out_dim:int):\n", " \n", " return nn.Sequential(\n", " nn.Linear(in_dim,out_dim),\n", " nn.LeakyReLU(negative_slope=0.2)\n", " )" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "class Discriminator(nn.Module):\n", "\n", " def __init__(self,im_dim:int = 784, hidden_dim:int = 128):\n", " super(Discriminator, self).__init__()\n", "\n", " self.disc = nn.Sequential(\n", " DisBlock(im_dim, hidden_dim * 4),\n", " DisBlock(hidden_dim * 4, hidden_dim * 2),\n", " DisBlock(hidden_dim * 2, hidden_dim),\n", "\n", " nn.Linear(hidden_dim,1),\n", " )\n", " \n", " def __call__(self, noise):\n", "\n", " return self.disc(noise)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Discriminator(\n", " (disc): Sequential(\n", " (layers.0): Sequential(\n", " (layers.0): Linear(input_dims=784, output_dims=512, bias=True)\n", " (layers.1): LeakyReLU()\n", " )\n", " (layers.1): Sequential(\n", " (layers.0): Linear(input_dims=512, output_dims=256, bias=True)\n", " (layers.1): LeakyReLU()\n", " )\n", " (layers.2): Sequential(\n", " (layers.0): Linear(input_dims=256, output_dims=128, bias=True)\n", " (layers.1): LeakyReLU()\n", " )\n", " (layers.3): Linear(input_dims=128, output_dims=1, bias=True)\n", " )\n", ")" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "disc = Discriminator()\n", "disc" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Model Training 🏋🏻‍♂️" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "# Set your parameters\n", "criterion = nn.losses.binary_cross_entropy\n", "n_epochs = 200\n", "z_dim = 64\n", "display_step = 500\n", "batch_size = 128\n", "lr = 0.00001" ] }, { "cell_type": "code", "execution_count": 197, "metadata": {}, "outputs": [], "source": [ "gen = Generator(z_dim)\n", "mx.eval(gen.parameters())\n", "gen_opt = optim.Adam(learning_rate=lr)\n", "\n", "disc = Discriminator()\n", "mx.eval(disc.parameters())\n", "disc_opt = optim.Adam(learning_rate=lr)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Losses" ] }, { "cell_type": "code", "execution_count": 198, "metadata": {}, "outputs": [], "source": [ "def disc_loss(gen, disc, real, num_images, z_dim):\n", " noise = mx.array(get_noise(num_images, z_dim))\n", " fake_images = gen(noise)\n", " \n", " fake_disc = disc(fake_images)\n", " \n", " fake_labels = mx.zeros((len(fake_images),1))\n", " fake_loss = nn.losses.binary_cross_entropy(fake_disc,fake_labels,with_logits=True)\n", " \n", " real_disc = disc(real)\n", " real_labels = mx.ones((len(real),1))\n", " real_loss = nn.losses.binary_cross_entropy(real_disc,real_labels,with_logits=True)\n", "\n", " disc_loss = (fake_loss + real_loss) / 2\n", "\n", " return disc_loss" ] }, { "cell_type": "code", "execution_count": 204, "metadata": {}, "outputs": [], "source": [ "def gen_loss(gen, disc, num_images, z_dim):\n", "\n", " noise = mx.array(get_noise(num_images, z_dim))\n", " fake_images = gen(noise)\n", " \n", " fake_disc = disc(fake_images)\n", "\n", " fake_labels = mx.ones((len(fake_images),1))\n", " \n", " gen_loss = nn.losses.binary_cross_entropy(fake_disc,fake_labels,with_logits=True)\n", "\n", " return gen_loss" ] }, { "cell_type": "code", "execution_count": 205, "metadata": {}, "outputs": [], "source": [ "train_images, _, test_images, _ = map(\n", " mx.array, getattr(mnist, 'mnist')()\n", ")" ] }, { "cell_type": "code", "execution_count": 206, "metadata": {}, "outputs": [], "source": [ "def batch_iterate(batch_size:int, ipt:list):\n", " perm = mx.array(np.random.permutation(len(ipt)))\n", " for s in range(0, ipt.size, batch_size):\n", " ids = perm[s : s + batch_size]\n", " yield ipt[ids]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### show batch of images" ] }, { "cell_type": "code", "execution_count": 207, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for X in batch_iterate(16, train_images):\n", " fig,axes = plt.subplots(4, 4, figsize=(4, 4))\n", "\n", " for i, ax in enumerate(axes.flat):\n", " img = mx.array(X[i]).reshape(28,28)\n", " ax.imshow(img,cmap='gray')\n", " ax.axis('off')\n", " break" ] }, { "cell_type": "code", "execution_count": 208, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "0it [00:00, ?it/s]\n" ] }, { "ename": "TypeError", "evalue": "'bool' object is not callable", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[208], line 28\u001b[0m\n\u001b[1;32m 23\u001b[0m disc_opt\u001b[38;5;241m.\u001b[39mupdate(disc, D_grads)\n\u001b[1;32m 25\u001b[0m \u001b[38;5;66;03m# Update gradients\u001b[39;00m\n\u001b[0;32m---> 28\u001b[0m G_loss,G_grads \u001b[38;5;241m=\u001b[39m \u001b[43mG_loss_grad\u001b[49m\u001b[43m(\u001b[49m\u001b[43mgen\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdisc\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbatch_size\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mz_dim\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 30\u001b[0m \u001b[38;5;66;03m# Update optimizer\u001b[39;00m\n\u001b[1;32m 31\u001b[0m gen_opt\u001b[38;5;241m.\u001b[39mupdate(gen, G_grads)\n", "File \u001b[0;32m~/miniforge3/lib/python3.10/site-packages/mlx/nn/utils.py:34\u001b[0m, in \u001b[0;36mvalue_and_grad..wrapped_value_grad_fn\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 32\u001b[0m \u001b[38;5;129m@wraps\u001b[39m(fn)\n\u001b[1;32m 33\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mwrapped_value_grad_fn\u001b[39m(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[0;32m---> 34\u001b[0m value, grad \u001b[38;5;241m=\u001b[39m \u001b[43mvalue_grad_fn\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmodel\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtrainable_parameters\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 35\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m value, grad\n", "File \u001b[0;32m~/miniforge3/lib/python3.10/site-packages/mlx/nn/utils.py:28\u001b[0m, in \u001b[0;36mvalue_and_grad..inner_fn\u001b[0;34m(params, *args, **kwargs)\u001b[0m\n\u001b[1;32m 26\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minner_fn\u001b[39m(params, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[1;32m 27\u001b[0m model\u001b[38;5;241m.\u001b[39mupdate(params)\n\u001b[0;32m---> 28\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", "\u001b[0;31mTypeError\u001b[0m: 'bool' object is not callable" ] } ], "source": [ "batch_size = 8\n", "cur_step = 0\n", "mean_generator_loss = 0\n", "mean_discriminator_loss = 0\n", "test_generator = True # Whether the generator should be tested\n", "gen_loss = False\n", "error = False\n", "\n", "D_loss_grad = nn.value_and_grad(disc, disc_loss)\n", "G_loss_grad = nn.value_and_grad(gen, gen_loss)\n", "\n", "\n", "for epoch in range(n_epochs):\n", " \n", " # Dataloader returns the batches\n", " for real in tqdm(batch_iterate(batch_size, train_images)):\n", "\n", " # Flatten the batch of real images from the dataset\n", " \n", " D_loss,D_grads = D_loss_grad(gen, disc, real, batch_size, z_dim)\n", "\n", " # Update optimizer\n", " disc_opt.update(disc, D_grads)\n", " \n", " # Update gradients\n", " \n", " \n", " G_loss,G_grads = G_loss_grad(gen, disc, batch_size, z_dim)\n", " \n", " # Update optimizer\n", " gen_opt.update(gen, G_grads)\n", " \n", " # Update gradients\n", "\n", " \n", "\n", " # # Keep track of the average discriminator loss\n", " # mean_discriminator_loss += disc_loss.item() / display_step\n", "\n", " # # Keep track of the average generator loss\n", " # mean_generator_loss += gen_loss.item() / display_step\n", "\n", " # ### Visualization code ###\n", " # if cur_step % display_step == 0 and cur_step > 0:\n", " # print(f\"Step {cur_step}: Generator loss: {mean_generator_loss}, discriminator loss: {mean_discriminator_loss}\")\n", " # fake_noise = get_noise(cur_batch_size, z_dim, device=device)\n", " # fake = gen(fake_noise)\n", " # show_tensor_images(fake)\n", " # show_tensor_images(real)\n", " # mean_generator_loss = 0\n", " # mean_discriminator_loss = 0\n", " # cur_step += 1\n" ] } ], "metadata": { "kernelspec": { "display_name": "base", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.10" } }, "nbformat": 4, "nbformat_minor": 2 }