{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Deep Learning Models -- A collection of various deep learning architectures, models, and tips for TensorFlow and PyTorch in Jupyter Notebooks.\n", "- Author: Sebastian Raschka\n", "- GitHub Repository: https://github.com/rasbt/deeplearning-models" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Sebastian Raschka \n", "\n", "CPython 3.6.8\n", "IPython 7.2.0\n", "\n", "torch 1.0.0\n" ] } ], "source": [ "%load_ext watermark\n", "%watermark -a 'Sebastian Raschka' -v -p torch" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Runs on CPU or GPU (if available)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Model Zoo -- Autoencoder" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A simple, single-layer autoencoder that compresses 768-pixel MNIST images into 32-pixel vectors (32-times smaller representations)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Imports" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Device: cuda:0\n", "Image batch dimensions: torch.Size([256, 1, 28, 28])\n", "Image label dimensions: torch.Size([256])\n" ] } ], "source": [ "import time\n", "import numpy as np\n", "import torch\n", "import torch.nn.functional as F\n", "from torchvision import datasets\n", "from torchvision import transforms\n", "from torch.utils.data import DataLoader\n", "\n", "if torch.cuda.is_available():\n", " torch.backends.cudnn.deterministic = True\n", "\n", "\n", "##########################\n", "### SETTINGS\n", "##########################\n", "\n", "# Device\n", "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n", "print('Device:', device)\n", "\n", "# Hyperparameters\n", "random_seed = 123\n", "learning_rate = 0.005\n", "num_epochs = 5\n", "batch_size = 256\n", "\n", "# Architecture\n", "num_features = 784\n", "num_hidden_1 = 32\n", "\n", "\n", "##########################\n", "### MNIST DATASET\n", "##########################\n", "\n", "# Note transforms.ToTensor() scales input images\n", "# to 0-1 range\n", "train_dataset = datasets.MNIST(root='data', \n", " train=True, \n", " transform=transforms.ToTensor(),\n", " download=True)\n", "\n", "test_dataset = datasets.MNIST(root='data', \n", " train=False, \n", " transform=transforms.ToTensor())\n", "\n", "\n", "train_loader = DataLoader(dataset=train_dataset, \n", " batch_size=batch_size, \n", " shuffle=True)\n", "\n", "test_loader = DataLoader(dataset=test_dataset, \n", " batch_size=batch_size, \n", " shuffle=False)\n", "\n", "# Checking the dataset\n", "for images, labels in train_loader: \n", " print('Image batch dimensions:', images.shape)\n", " print('Image label dimensions:', labels.shape)\n", " break" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Model" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "##########################\n", "### MODEL\n", "##########################\n", "\n", "class Autoencoder(torch.nn.Module):\n", "\n", " def __init__(self, num_features):\n", " super(Autoencoder, self).__init__()\n", " \n", " ### ENCODER\n", " self.linear_1 = torch.nn.Linear(num_features, num_hidden_1)\n", " # The following to lones are not necessary, \n", " # but used here to demonstrate how to access the weights\n", " # and use a different weight initialization.\n", " # By default, PyTorch uses Xavier/Glorot initialization, which\n", " # should usually be preferred.\n", " self.linear_1.weight.detach().normal_(0.0, 0.1)\n", " self.linear_1.bias.detach().zero_()\n", " \n", " ### DECODER\n", " self.linear_2 = torch.nn.Linear(num_hidden_1, num_features)\n", " self.linear_1.weight.detach().normal_(0.0, 0.1)\n", " self.linear_1.bias.detach().zero_()\n", " \n", "\n", " def forward(self, x):\n", " \n", " ### ENCODER\n", " encoded = self.linear_1(x)\n", " encoded = F.leaky_relu(encoded)\n", " \n", " ### DECODER\n", " logits = self.linear_2(encoded)\n", " decoded = torch.sigmoid(logits)\n", " \n", " return decoded\n", "\n", " \n", "torch.manual_seed(random_seed)\n", "model = Autoencoder(num_features=num_features)\n", "model = model.to(device)\n", "\n", "optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate) " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "## Training" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch: 001/005 | Batch 000/235 | Cost: 0.7100\n", "Epoch: 001/005 | Batch 050/235 | Cost: 0.2028\n", "Epoch: 001/005 | Batch 100/235 | Cost: 0.1636\n", "Epoch: 001/005 | Batch 150/235 | Cost: 0.1349\n", "Epoch: 001/005 | Batch 200/235 | Cost: 0.1302\n", "Time elapsed: 0.10 min\n", "Epoch: 002/005 | Batch 000/235 | Cost: 0.1239\n", "Epoch: 002/005 | Batch 050/235 | Cost: 0.1130\n", "Epoch: 002/005 | Batch 100/235 | Cost: 0.1097\n", "Epoch: 002/005 | Batch 150/235 | Cost: 0.1061\n", "Epoch: 002/005 | Batch 200/235 | Cost: 0.1035\n", "Time elapsed: 0.21 min\n", "Epoch: 003/005 | Batch 000/235 | Cost: 0.1010\n", "Epoch: 003/005 | Batch 050/235 | Cost: 0.0975\n", "Epoch: 003/005 | Batch 100/235 | Cost: 0.0983\n", "Epoch: 003/005 | Batch 150/235 | Cost: 0.0975\n", "Epoch: 003/005 | Batch 200/235 | Cost: 0.0937\n", "Time elapsed: 0.31 min\n", "Epoch: 004/005 | Batch 000/235 | Cost: 0.0946\n", "Epoch: 004/005 | Batch 050/235 | Cost: 0.0961\n", "Epoch: 004/005 | Batch 100/235 | Cost: 0.0960\n", "Epoch: 004/005 | Batch 150/235 | Cost: 0.0971\n", "Epoch: 004/005 | Batch 200/235 | Cost: 0.0899\n", "Time elapsed: 0.42 min\n", "Epoch: 005/005 | Batch 000/235 | Cost: 0.0948\n", "Epoch: 005/005 | Batch 050/235 | Cost: 0.0927\n", "Epoch: 005/005 | Batch 100/235 | Cost: 0.0932\n", "Epoch: 005/005 | Batch 150/235 | Cost: 0.0938\n", "Epoch: 005/005 | Batch 200/235 | Cost: 0.0935\n", "Time elapsed: 0.52 min\n", "Total Training Time: 0.52 min\n" ] } ], "source": [ "start_time = time.time()\n", "for epoch in range(num_epochs):\n", " for batch_idx, (features, targets) in enumerate(train_loader):\n", " \n", " # don't need labels, only the images (features)\n", " features = features.view(-1, 28*28).to(device)\n", " \n", " ### FORWARD AND BACK PROP\n", " decoded = model(features)\n", " cost = F.binary_cross_entropy(decoded, features)\n", " optimizer.zero_grad()\n", " \n", " cost.backward()\n", " \n", " ### UPDATE MODEL PARAMETERS\n", " optimizer.step()\n", " \n", " ### LOGGING\n", " if not batch_idx % 50:\n", " print ('Epoch: %03d/%03d | Batch %03d/%03d | Cost: %.4f' \n", " %(epoch+1, num_epochs, batch_idx, \n", " len(train_loader), cost))\n", " \n", " print('Time elapsed: %.2f min' % ((time.time() - start_time)/60))\n", " \n", "print('Total Training Time: %.2f min' % ((time.time() - start_time)/60))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Evaluation" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAABIAAAACqCAYAAADV0DQZAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAIABJREFUeJzsnWegG8XVhp8NCQQIEMD0ZorBlIRmCC303nvvEFoIvdcPCL13MKGG3qspoZoONh2Hjk0JPSEJEBKKvh/2uzPaK+mu7pV0V7rv8+fqSqvV7NHM7GjOe85JSqUSxhhjjDHGGGOMMaZz+UlfN8AYY4wxxhhjjDHGNBdvABljjDHGGGOMMcZ0ON4AMsYYY4wxxhhjjOlwvAFkjDHGGGOMMcYY0+F4A8gYY4wxxhhjjDGmw/EGkDHGGGOMMcYYY0yH4w0gY4wxxhhjjDHGmA6nVxtASZKsmiTJ60mSvJUkyUGNapQxxhhjjDHGGGOMaRxJqVTq2RuTZDzgDWAl4APgWWCzUqk0qnHNM8YYY4wxxhhjjDG95ae9eO+iwFulUukdgCRJrgXWAapuAA0YMKA0cODAXnxkezJy5MjPS6XSVPW8x7bKj21VH/3RXqNHj+bzzz9P6n1ff7QVeBzWg22VH9sqP57f8+P5vT48DvNjW+XHc1Z+PGfVh8dhfvLaqjcbQDMA70f/fwD8JntQkiQ7ATsBzDzzzIwYMaIXH9meJEkyJudxtpVtlZu8thp3bL+215AhQ3If299tBR6H9WBb5ce2yo/n9/x4fq8Pj8P82Fb58ZyVH89Z9eFxmJ+8tmp6EuhSqTS0VCoNKZVKQ6aaqu6N4X6FbZUf26o+bK/82Fb5sa3yY1vlx7aqD9srP7ZVfmyr/NhW9WF75ce2yo9tlZ/ebAB9CMwU/T/juOeMMcYYY4wxxhhjTIHozQbQs8CgJElmTZJkfGBT4PbGNMsYY4wxxhhjjDHGNIoe5wAqlUrfJ0myO3AvMB5wSalUerVhLTPGGGOMMcYYY4wxDaE3SaAplUrDgGENaosxxhhjjDHGGGOMaQK92gAyxhhjjOkk/vrXvwJw1VVXAXDccccB8OOPP/ZZm4wxxhhjGkHTq4AZY4wxxhhjjDHGmL7FCiBjjDHG9CuGDh0KwC233JI+9/nnnwPw2muvAfD1118DkCQJAPvss0967CGHHALAgAEDmt9Y0/G8/vrr6eNlllkGgP/7v/8DYJdddumLJpmC8v3336eP//SnPwFw9NFHA/Dxxx8DUCqVAFhrrbXSY6VknG+++VrSziLzxRdfAHD44YcD8MorrwCw/fbbp8esv/76AEw66aQtbl2xOOuss4BwH7zwwgsBGDVqVHrMGWecUXbMZJNNBsDWW2/dsnaa+rACyBhjjDHGGGOMMabDaUsF0GmnnQbAMcccA8A///nPqsdqF3yBBRYAau9G7r333o1qYp8irxHAI488AsDDDz/c7fuWXXZZIHif9L/+mup89913QPAKA5xyyikAbLzxxgBcd911rW9YwYk9CPLAyG7PPvssALvuuisA5513Xotb13i+/PJLAG644QYA/vznP6evSX0wePBgIHh9V1555VY20ZiO4bPPPksf77zzzgDceuutQFgbyGNZ6Tn9L04//fT0sTyeurcuvfTSjWy66SdIzRHf3z755BMAllpqqT5pU1H497//DQQl3lFHHQXABRdcUPU9UnCsvvrqAGywwQbNbGKfsN5666WPhw0rr8MzwwwzAPDhhx8CcNddd6WvvfTSS0BYUx144IFNbWcRUX63NddcE4B33nmn7PVHH300ffzkk08CQfHSyei34pgxY9Lnjj32WADefPNNoPxemf1/r732Kntu/PHHL/t/q622akazTS+wAsgYY4wxxhhjjDGmw2lLBdB+++0HhJ3F7K5kJbTzrfdWQt495QZYddVVe9XOViEP5HLLLdeQ8+ivvC2xAujII4/s8pwJ3rtTTz01fU79UjHGJqhcTjzxRADOPffc9LVvv/0WgGmnnRaAySefHICbbrqp7D0Ak0wySfMb20Dkyf3qq6+AMB/FzDTTTEBQKGgcnnnmmQD8+te/7vZzJp54YgDmmGOO3jW4D5F3sh6vWyU1Rxb1qxNOOAHorNj0//73v0Dw3o0cOTJ9TV7MG2+8EYCPPvqox58z44wzpo9PPvlkADbddNMen69ZSPkjFQAEm9TyYlZ7rtYx++67LwB333030Lk5gTQ/a3xCqJKme9wWW2yR+3xTTDEFAL/85S8b1cS25OCDDwZCng0Ic/10003XJ23qC6TyATjiiCOAoPbPMx7FpZdeCsB//vMfAFZaaaX0tU7J5aL7PMCee+4JBKW5+ozm+Xj9+eCDDwJBqd5f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kO1UTOLNN9/scozSPnRySGtPuPjii9PHui90etiqwrmUtF/hXjFXX3112bEKOb/55ptb0cQ+R7+FFXqp+6NCoCCkaqinyI3Wutk+VvQ+pz0ChRn3dJ38t7/9DQhh5Ap5VtEIKM7vHyuAjDHGGGOMMcYYYzqcjlcAKQFavKuZRV6aaiXj2wUlWYw9unosFU6zExGqHHyMVEH6W+mYIiNVQcwuu+wC1JcUrL9w/PHHp4+VwHe//fYD4JRTTgGCZ2bVVVdtceuax2qrrQYEpckzzzyTviYl1AUXXADApJNO2pDPVGJjJemLy1QLeRvOOussoH1sLg9MHk+Mkh6rPKmSYUPwtGt+jBPTdiqyA4REumLIkCFAULvEKHGjvOhxmdN2pFKy2DyeyZ4ck8dzvP766wPtfd846aST0sexuiBG9wBdb0+Rwq/dePfddwG4/PLLqx6je+LEE0/ckja1I1IgaN1aSfmj9WR/UHbWg9Q+Sm4bM+ecc7a6OS1B93iVIP/2229zv1drsp///OcNb1cR0T1o++23L/vbUzQ2zznnnIqvTznllL06f7OZY445evX+oUOHAuH6pVa95JJLgGIq760AMsYYY4wxxhhjjOlwulUAJUkyE3AFMA1QAoaWSqUzkySZArgOGAiMBjYulUr/aF5Te8Y+++wDhF24/kCssMmqb5qtwlluueVytatdUZlll3/vyg033ACUK9DkkVlppZWAoACScqW/cO211wLw/PPPA+XlqXvC6NGjgVDu/aWXXip7fY011kgf77jjjgCss846vfrMInL//fcDsPbaawMh38+ee+6ZHqMS3hNNNFGLW9d6HnjgAQA+/fTTLq+tssoqANx6661AKOl61113pccoR9chhxwChDm76N67LFLjxPNMNn9PpXw+3R1T6T1SUo0cObLsmFghpDwvjz32GABXXHEFAMOHD0+PWXrppateTxF4/fXXgaAkhDDehK5z5513bl3DCsh3330HwL///e8ur8kzrDnLjEX5niDkXVS55KzaLl5LXnfddUB7q+qage77X3zxRZfXKuVCbVduvPHG9HFPlD9Cc3GsJDvssMOAkB9ovPHG63E7Ox0p37NjdaONNgI6q8+JF154IX183nnnAfD1118DQfU/cODAlrcrL3kUQN8D+5ZKpXmAxYDfJ0kyD3AQ8ECpVBoEPDDuf2OMMcYY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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "\n", "##########################\n", "### VISUALIZATION\n", "##########################\n", "\n", "n_images = 15\n", "image_width = 28\n", "\n", "fig, axes = plt.subplots(nrows=2, ncols=n_images, \n", " sharex=True, sharey=True, figsize=(20, 2.5))\n", "orig_images = features[:n_images]\n", "decoded_images = decoded[:n_images]\n", "\n", "for i in range(n_images):\n", " for ax, img in zip(axes, [orig_images, decoded_images]):\n", " curr_img = img[i].detach().to(torch.device('cpu'))\n", " ax[i].imshow(curr_img.view((image_width, image_width)), cmap='binary')" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "numpy 1.15.4\n", "torch 1.0.0\n", "\n" ] } ], "source": [ "%watermark -iv" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.7.1" }, "toc": { "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": true } }, "nbformat": 4, "nbformat_minor": 2 }