{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1 align=\"center\">TensorFlow Neural Network Lab</h1>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"image/notmnist.png\">\n",
    "In this lab, you'll use all the tools you learned from *Introduction to TensorFlow* to label images of English letters! The data you are using, <a href=\"http://yaroslavvb.blogspot.com/2011/09/notmnist-dataset.html\">notMNIST</a>, consists of images of a letter from A to J in differents font.\n",
    "\n",
    "The above images are a few examples of the data you'll be training on. After training the network, you will compare your prediction model against test data. Your goal, by the end of this lab, is to make predictions against that test set with at least an 80% accuracy. Let's jump in!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To start this lab, you first need to import all the necessary modules. Run the code below. If it runs successfully, it will print \"`All modules imported`\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "All modules imported.\n"
     ]
    }
   ],
   "source": [
    "import hashlib\n",
    "import os\n",
    "import pickle\n",
    "from urllib.request import urlretrieve\n",
    "\n",
    "import numpy as np\n",
    "from PIL import Image\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.preprocessing import LabelBinarizer\n",
    "from sklearn.utils import resample\n",
    "from tqdm import tqdm\n",
    "from zipfile import ZipFile\n",
    "\n",
    "print('All modules imported.')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The notMNIST dataset is too large for many computers to handle.  It contains 500,000 images for just training.  You'll be using a subset of this data, 15,000 images for each label (A-J)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading notMNIST_train.zip...\n",
      "Download Finished\n",
      "Downloading notMNIST_test.zip...\n",
      "Download Finished\n",
      "All files downloaded.\n"
     ]
    }
   ],
   "source": [
    "def download(url, file):\n",
    "    \"\"\"\n",
    "    Download file from <url>\n",
    "    :param url: URL to file\n",
    "    :param file: Local file path\n",
    "    \"\"\"\n",
    "    if not os.path.isfile(file):\n",
    "        print('Downloading ' + file + '...')\n",
    "        urlretrieve(url, file)\n",
    "        print('Download Finished')\n",
    "\n",
    "# Download the training and test dataset.\n",
    "download('https://s3.amazonaws.com/udacity-sdc/notMNIST_train.zip', 'notMNIST_train.zip')\n",
    "download('https://s3.amazonaws.com/udacity-sdc/notMNIST_test.zip', 'notMNIST_test.zip')\n",
    "\n",
    "# Make sure the files aren't corrupted\n",
    "assert hashlib.md5(open('notMNIST_train.zip', 'rb').read()).hexdigest() == 'c8673b3f28f489e9cdf3a3d74e2ac8fa',\\\n",
    "        'notMNIST_train.zip file is corrupted.  Remove the file and try again.'\n",
    "assert hashlib.md5(open('notMNIST_test.zip', 'rb').read()).hexdigest() == '5d3c7e653e63471c88df796156a9dfa9',\\\n",
    "        'notMNIST_test.zip file is corrupted.  Remove the file and try again.'\n",
    "\n",
    "# Wait until you see that all files have been downloaded.\n",
    "print('All files downloaded.')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 210001/210001 [00:26<00:00, 7964.58files/s]\n",
      "100%|██████████| 10001/10001 [00:01<00:00, 8404.50files/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "All features and labels uncompressed.\n"
     ]
    }
   ],
   "source": [
    "def uncompress_features_labels(file):\n",
    "    \"\"\"\n",
    "    Uncompress features and labels from a zip file\n",
    "    :param file: The zip file to extract the data from\n",
    "    \"\"\"\n",
    "    features = []\n",
    "    labels = []\n",
    "\n",
    "    with ZipFile(file) as zipf:\n",
    "        # Progress Bar\n",
    "        filenames_pbar = tqdm(zipf.namelist(), unit='files')\n",
    "        \n",
    "        # Get features and labels from all files\n",
    "        for filename in filenames_pbar:\n",
    "            # Check if the file is a directory\n",
    "            if not filename.endswith('/'):\n",
    "                with zipf.open(filename) as image_file:\n",
    "                    image = Image.open(image_file)\n",
    "                    image.load()\n",
    "                    # Load image data as 1 dimensional array\n",
    "                    # We're using float32 to save on memory space\n",
    "                    feature = np.array(image, dtype=np.float32).flatten()\n",
    "\n",
    "                # Get the the letter from the filename.  This is the letter of the image.\n",
    "                label = os.path.split(filename)[1][0]\n",
    "\n",
    "                features.append(feature)\n",
    "                labels.append(label)\n",
    "    return np.array(features), np.array(labels)\n",
    "\n",
    "# Get the features and labels from the zip files\n",
    "train_features, train_labels = uncompress_features_labels('notMNIST_train.zip')\n",
    "test_features, test_labels = uncompress_features_labels('notMNIST_test.zip')\n",
    "\n",
    "# Limit the amount of data to work with a docker container\n",
    "docker_size_limit = 150000\n",
    "train_features, train_labels = resample(train_features, train_labels, n_samples=docker_size_limit)\n",
    "\n",
    "# Set flags for feature engineering.  This will prevent you from skipping an important step.\n",
    "is_features_normal = False\n",
    "is_labels_encod = False\n",
    "\n",
    "# Wait until you see that all features and labels have been uncompressed.\n",
    "print('All features and labels uncompressed.')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"image/Mean Variance - Image.png\" style=\"height: 75%;width: 75%; position: relative; right: 5%\">\n",
    "## Problem 1\n",
    "The first problem involves normalizing the features for your training and test data.\n",
    "\n",
    "Implement Min-Max scaling in the `normalize()` function to a range of `a=0.1` and `b=0.9`. After scaling, the values of the pixels in the input data should range from 0.1 to 0.9.\n",
    "\n",
    "Since the raw notMNIST image data is in [grayscale](https://en.wikipedia.org/wiki/Grayscale), the current values range from a min of 0 to a max of 255.\n",
    "\n",
    "Min-Max Scaling:\n",
    "$\n",
    "X'=a+{\\frac {\\left(X-X_{\\min }\\right)\\left(b-a\\right)}{X_{\\max }-X_{\\min }}}\n",
    "$\n",
    "\n",
    "*If you're having trouble solving problem 1, you can view the solution [here](https://github.com/udacity/deep-learning/blob/master/intro-to-tensorFlow/intro_to_tensorflow_solution.ipynb).*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t = train_features[0]\n",
    "t_ = 0.1 + ((t-t.min())*(0.9 - 0.1))/(t.max()-t.min())\n",
    "0.1 + (255*0.8/255)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tests Passed!\n"
     ]
    }
   ],
   "source": [
    "# Problem 1 - Implement Min-Max scaling for grayscale image data\n",
    "def normalize_grayscale(image_data):\n",
    "    \"\"\"\n",
    "    Normalize the image data with Min-Max scaling to a range of [0.1, 0.9]\n",
    "    :param image_data: The image data to be normalized\n",
    "    :return: Normalized image data\n",
    "    \"\"\"\n",
    "    t = image_data\n",
    "    # TODO: Implement Min-Max scaling for grayscale image data\n",
    "    return 0.1 + ((t-t.min())*(0.9 - 0.1))/(t.max()-t.min())\n",
    "\n",
    "\n",
    "### DON'T MODIFY ANYTHING BELOW ###\n",
    "# Test Cases\n",
    "np.testing.assert_array_almost_equal(\n",
    "    normalize_grayscale(np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 255])),\n",
    "    [0.1, 0.103137254902, 0.106274509804, 0.109411764706, 0.112549019608, 0.11568627451, 0.118823529412, 0.121960784314,\n",
    "     0.125098039216, 0.128235294118, 0.13137254902, 0.9],\n",
    "    decimal=3)\n",
    "np.testing.assert_array_almost_equal(\n",
    "    normalize_grayscale(np.array([0, 1, 10, 20, 30, 40, 233, 244, 254,255])),\n",
    "    [0.1, 0.103137254902, 0.13137254902, 0.162745098039, 0.194117647059, 0.225490196078, 0.830980392157, 0.865490196078,\n",
    "     0.896862745098, 0.9])\n",
    "\n",
    "if not is_features_normal:\n",
    "    train_features = normalize_grayscale(train_features)\n",
    "    test_features = normalize_grayscale(test_features)\n",
    "    is_features_normal = True\n",
    "\n",
    "print('Tests Passed!')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Labels One-Hot Encoded\n"
     ]
    }
   ],
   "source": [
    "if not is_labels_encod:\n",
    "    # Turn labels into numbers and apply One-Hot Encoding\n",
    "    encoder = LabelBinarizer()\n",
    "    encoder.fit(train_labels)\n",
    "    train_labels = encoder.transform(train_labels)\n",
    "    test_labels = encoder.transform(test_labels)\n",
    "\n",
    "    # Change to float32, so it can be multiplied against the features in TensorFlow, which are float32\n",
    "    train_labels = train_labels.astype(np.float32)\n",
    "    test_labels = test_labels.astype(np.float32)\n",
    "    is_labels_encod = True\n",
    "\n",
    "print('Labels One-Hot Encoded')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Training features and labels randomized and split.\n"
     ]
    }
   ],
   "source": [
    "assert is_features_normal, 'You skipped the step to normalize the features'\n",
    "assert is_labels_encod, 'You skipped the step to One-Hot Encode the labels'\n",
    "\n",
    "# Get randomized datasets for training and validation\n",
    "train_features, valid_features, train_labels, valid_labels = train_test_split(\n",
    "    train_features,\n",
    "    train_labels,\n",
    "    test_size=0.05,\n",
    "    random_state=832289)\n",
    "\n",
    "print('Training features and labels randomized and split.')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Saving data to pickle file...\n",
      "Data cached in pickle file.\n"
     ]
    }
   ],
   "source": [
    "# Save the data for easy access\n",
    "pickle_file = 'notMNIST.pickle'\n",
    "if not os.path.isfile(pickle_file):\n",
    "    print('Saving data to pickle file...')\n",
    "    try:\n",
    "        with open('notMNIST.pickle', 'wb') as pfile:\n",
    "            pickle.dump(\n",
    "                {\n",
    "                    'train_dataset': train_features,\n",
    "                    'train_labels': train_labels,\n",
    "                    'valid_dataset': valid_features,\n",
    "                    'valid_labels': valid_labels,\n",
    "                    'test_dataset': test_features,\n",
    "                    'test_labels': test_labels,\n",
    "                },\n",
    "                pfile, pickle.HIGHEST_PROTOCOL)\n",
    "    except Exception as e:\n",
    "        print('Unable to save data to', pickle_file, ':', e)\n",
    "        raise\n",
    "\n",
    "print('Data cached in pickle file.')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Checkpoint\n",
    "All your progress is now saved to the pickle file.  If you need to leave and comeback to this lab, you no longer have to start from the beginning.  Just run the code block below and it will load all the data and modules required to proceed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Data and modules loaded.\n"
     ]
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "\n",
    "# Load the modules\n",
    "import pickle\n",
    "import math\n",
    "\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "from tqdm import tqdm\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Reload the data\n",
    "pickle_file = 'notMNIST.pickle'\n",
    "with open(pickle_file, 'rb') as f:\n",
    "  pickle_data = pickle.load(f)\n",
    "  train_features = pickle_data['train_dataset']\n",
    "  train_labels = pickle_data['train_labels']\n",
    "  valid_features = pickle_data['valid_dataset']\n",
    "  valid_labels = pickle_data['valid_labels']\n",
    "  test_features = pickle_data['test_dataset']\n",
    "  test_labels = pickle_data['test_labels']\n",
    "  del pickle_data  # Free up memory\n",
    "\n",
    "print('Data and modules loaded.')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## Problem 2\n",
    "\n",
    "Now it's time to build a simple neural network using TensorFlow. Here, your network will be just an input layer and an output layer.\n",
    "\n",
    "<img src=\"image/network_diagram.png\" style=\"height: 40%;width: 40%; position: relative; right: 10%\">\n",
    "\n",
    "For the input here the images have been flattened into a vector of $28 \\times 28 = 784$ features. Then, we're trying to predict the image digit so there are 10 output units, one for each label. Of course, feel free to add hidden layers if you want, but this notebook is built to guide you through a single layer network. \n",
    "\n",
    "For the neural network to train on your data, you need the following <a href=\"https://www.tensorflow.org/resources/dims_types.html#data-types\">float32</a> tensors:\n",
    " - `features`\n",
    "  - Placeholder tensor for feature data (`train_features`/`valid_features`/`test_features`)\n",
    " - `labels`\n",
    "  - Placeholder tensor for label data (`train_labels`/`valid_labels`/`test_labels`)\n",
    " - `weights`\n",
    "  - Variable Tensor with random numbers from a truncated normal distribution.\n",
    "    - See <a href=\"https://www.tensorflow.org/api_docs/python/constant_op.html#truncated_normal\">`tf.truncated_normal()` documentation</a> for help.\n",
    " - `biases`\n",
    "  - Variable Tensor with all zeros.\n",
    "    - See <a href=\"https://www.tensorflow.org/api_docs/python/constant_op.html#zeros\"> `tf.zeros()` documentation</a> for help.\n",
    "\n",
    "*If you're having trouble solving problem 2, review \"TensorFlow Linear Function\" section of the class.  If that doesn't help, the solution for this problem is available [here](intro_to_tensorflow_solution.ipynb).*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 159,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tests Passed!\n"
     ]
    }
   ],
   "source": [
    "# All the pixels in the image (28 * 28 = 784)\n",
    "features_count = 784\n",
    "# All the labels\n",
    "labels_count = 10\n",
    "\n",
    "# TODO: Set the features and labels tensors\n",
    "features = tf.placeholder(tf.float32, [None, features_count])\n",
    "labels = tf.placeholder(tf.float32, [None, labels_count])\n",
    "\n",
    "# TODO: Set the weights and biases tensors\n",
    "weights = tf.Variable(tf.truncated_normal([features_count, labels_count]))\n",
    "biases = tf.Variable(tf.zeros([labels_count]))\n",
    "\n",
    "\n",
    "\n",
    "### DON'T MODIFY ANYTHING BELOW ###\n",
    "\n",
    "#Test Cases\n",
    "from tensorflow.python.ops.variables import Variable\n",
    "\n",
    "assert features._op.name.startswith('Placeholder'), 'features must be a placeholder'\n",
    "assert labels._op.name.startswith('Placeholder'), 'labels must be a placeholder'\n",
    "assert isinstance(weights, Variable), 'weights must be a TensorFlow variable'\n",
    "assert isinstance(biases, Variable), 'biases must be a TensorFlow variable'\n",
    "\n",
    "assert features._shape == None or (\\\n",
    "    features._shape.dims[0].value is None and\\\n",
    "    features._shape.dims[1].value in [None, 784]), 'The shape of features is incorrect'\n",
    "assert labels._shape  == None or (\\\n",
    "    labels._shape.dims[0].value is None and\\\n",
    "    labels._shape.dims[1].value in [None, 10]), 'The shape of labels is incorrect'\n",
    "assert weights._variable._shape == (784, 10), 'The shape of weights is incorrect'\n",
    "assert biases._variable._shape == (10), 'The shape of biases is incorrect'\n",
    "\n",
    "assert features._dtype == tf.float32, 'features must be type float32'\n",
    "assert labels._dtype == tf.float32, 'labels must be type float32'\n",
    "\n",
    "# Feed dicts for training, validation, and test session\n",
    "train_feed_dict = {features: train_features, labels: train_labels}\n",
    "valid_feed_dict = {features: valid_features, labels: valid_labels}\n",
    "test_feed_dict = {features: test_features, labels: test_labels}\n",
    "\n",
    "# Linear Function WX + b\n",
    "logits = tf.matmul(features, weights) + biases\n",
    "\n",
    "prediction = tf.nn.softmax(logits)\n",
    "\n",
    "# Cross entropy\n",
    "cross_entropy = -tf.reduce_sum(labels * tf.log(prediction), reduction_indices=1)\n",
    "\n",
    "# Training loss\n",
    "loss = tf.reduce_mean(cross_entropy)\n",
    "\n",
    "\n",
    "optimizer = tf.train.AdamOptimizer(0.003).minimize(loss)    \n",
    "\n",
    "# Create an operation that initializes all variables\n",
    "init = tf.global_variables_initializer()\n",
    "\n",
    "# Test Cases\n",
    "with tf.Session() as session:\n",
    "    session.run(init)\n",
    "    session.run(loss, feed_dict=train_feed_dict)\n",
    "    session.run(loss, feed_dict=valid_feed_dict)\n",
    "    session.run(loss, feed_dict=test_feed_dict)\n",
    "    biases_data = session.run(biases)\n",
    "\n",
    "assert not np.count_nonzero(biases_data), 'biases must be zeros'\n",
    "\n",
    "print('Tests Passed!')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 160,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy function created.\n"
     ]
    }
   ],
   "source": [
    "# Determine if the predictions are correct\n",
    "is_correct_prediction = tf.equal(tf.argmax(prediction, 1), tf.argmax(labels, 1))\n",
    "# Calculate the accuracy of the predictions\n",
    "accuracy = tf.reduce_mean(tf.cast(is_correct_prediction, tf.float32))\n",
    "\n",
    "print('Accuracy function created.')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"image/Learn Rate Tune - Image.png\" style=\"height: 70%;width: 70%\">\n",
    "## Problem 3\n",
    "Below are 2 parameter configurations for training the neural network. In each configuration, one of the parameters has multiple options. For each configuration, choose the option that gives the best acccuracy.\n",
    "\n",
    "Parameter configurations:\n",
    "\n",
    "Configuration 1\n",
    "* **Epochs:** 1\n",
    "* **Learning Rate:**\n",
    "  * 0.8\n",
    "  * 0.5\n",
    "  * 0.1\n",
    "  * 0.05\n",
    "  * 0.01\n",
    "\n",
    "Configuration 2\n",
    "* **Epochs:**\n",
    "  * 1\n",
    "  * 2\n",
    "  * 3\n",
    "  * 4\n",
    "  * 5\n",
    "* **Learning Rate:** 0.2\n",
    "\n",
    "The code will print out a Loss and Accuracy graph, so you can see how well the neural network performed.\n",
    "\n",
    "*If you're having trouble solving problem 3, you can view the solution [here](intro_to_tensorflow_solution.ipynb).*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 161,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Epoch  1/5: 100%|██████████| 557/557 [00:02<00:00, 246.49batches/s]\n",
      "Epoch  2/5: 100%|██████████| 557/557 [00:02<00:00, 256.03batches/s]\n",
      "Epoch  3/5: 100%|██████████| 557/557 [00:02<00:00, 252.19batches/s]\n",
      "Epoch  4/5: 100%|██████████| 557/557 [00:02<00:00, 241.44batches/s]\n",
      "Epoch  5/5: 100%|██████████| 557/557 [00:02<00:00, 238.71batches/s]\n"
     ]
    },
    {
     "data": {
      "image/png": "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\nP/ww9evX58UXX6RDhw7069ePo0ePOuU7ffo0b731Ft26deOFF17g6aef5tixY/To0YMffrB+ldSp\nU4fXXnsNYwyDBg0iKSmJpKQk7rnnHnvZecu///77SUxMpF27dvz1r3+lc+fO/OUvf2H48OH56r13\n717i4uLo1asXL7/8MlWrVmXUqFHs27ev0OsGSE5Oplq1avTu3ZsOHToQHh7ustdp3bp1xMbG8uOP\nP/LYY4/x8ssvExsby5o1a+x5vvnmG9q3b8+WLVsYN24cr776KnfffbdTHlfXW1D6hg0bmDJlCkOH\nDuWVV16hQYMGgOe/76eeeor777+fwMBAnnnmGZ5++mnq1avHpk2bABg5ciS//fYbqanON5qOHj3K\nli1bGDFihEftCJCSkkL//v2dXhMnTvT4+GJhjPHqBXwO/M1hW7A+KTe5gGMmA6eA2zwsIxowaWlp\nxqSkGAPG/PSTUUqpay0tLc3YP4/c+OknY+6444+PqbzbV6ukzp+Tk2Pq1q1rbr/9dqf0+fPnG4vF\nYlJTU53SL1686LSdlZVlIiMjTa9evZzS69WrZx566CH7dmpqqrFYLGbr1q3GGGMuX75swsLCTNu2\nbU12drZTuSJiunfv7lTHrKwsp/OfPn3a1KxZ04wdO9aeduzYMSMi5tlnn813ndOnTzf+/v727bS0\nNCMiZvz48U75Jk6caCwWi/nss8+crsVisZjPP//cqayAgAAzbdq0fGW5EhkZaR544AH79pQpU8wN\nN9xgrly5Yk/Lzs42DRo0ME2bNjW///6723N17NjRhIaGmqNHj7rNM3z4cNO0adN86XnbITs724iI\n8ff3N/v27cuX35Pf9969e43FYjFDhgxxW5/c99mIESOc0l944QXj5+dnDh8+7PZYT/7/5eYBoo2X\nMU1RXkW5VfcykCAiI0WkBTAfCALeAhCRxSIyOzeziDwOPIP1qbtDIlLb9qqc/9QurFgBMTG6GJ1S\nqtTKXWx89GjrguOjR9sWJY8o3ee3WCzExcWxfft2Dh48aE9fsmQJtWvX5s4773TK79j7dPr0aU6f\nPk2nTp1IT0/3qtwvvviCEydOMG7cOPz8/Ozpo0ePJiQkJF8dK1SwLqtqjOHUqVNkZWXRpk0br8vN\ntXbtWkSESZMmOaU/9thjGGOcem8AWrVqRbt27ezbtWvXpmnTphw4cKDQstLT09m9ezdDhw61p8XH\nx3P8+HGnHpgdO3Zw+PBhJk6cSHBwsMtzHT9+nO3bt/PQQw9xQzEOXenWrRtNmjTJl+7J7/u9994D\ncLpVmJfFYmHo0KGsXLmSCxcu2NOXLFlCly5dqFevXnFcxjXjdeBkjFkOPAbMAr4GWgE9jTG/2bLU\nw3mg+DisT9H9Czjq8Hqs0MIuXIC1a/VpOqVUqRcRATNnQmys9Wdx/61XUucfNmwYxhj7MIgjR47w\n2WefER8fn++2zocffkj79u0JDAykevXq1KpVi3/+85+cOXPGqzIPHjyIiOT7svb39yfCxYW9+eab\ntGrVikqVKlGjRg1q1arFunXrvC7XsfwKFSrQuHFjp/Qbb7yRkJAQpyASsN+6chQaGurRNA1JSUmE\nhIRQv3599u/fz/79+6lcuTL16tVzul23f/9+RISoqCi358qdxqCgPEXhqs3Bs9/3gQMH8PPzo3nz\n5gWWMWrUKM6ePcsHH3wAwA8//MC3337LyJEji+06rpUiDQ43xswzxkQYYwKNMR2MMTsc9t1pjBnt\nsN3QGOPn4jWr0IK2b4fz5zVwUkqVehkZkJgIn3xi/eluQHdpO390dDQtWrSwD3bO/enYQwKwadMm\n7r33XkJCQpg/fz4fffQRqampDBkyxOWg34IY2xNwrsbb5O7L9dZbb/Hggw/SokUL3nzzTdavX09q\naipdu3b1ulx3ZRS2z7FXzNPz5O5ftmwZZ8+epWXLljRt2pSmTZvSrFkzfv75Z95//30uXrzo0bk8\nzQPu58LKyclxmR4YGJgvzdPftzHGo7m3brrpJm655RaSkpIAa0AZGBjIwDL4/V7B1xUo0Mcfw003\nQbNmvq6JUkq5lTtQO/f2We5tteK6XVfS5x82bBgzZszg+++/JyUlhaZNmxITE+OU57333qNy5cqs\nW7fOKZBYsGCB1+VFRERgjOHHH3/k9ttvt6dnZWVx8OBB6tT546bFihUraN68eb4B7E888YTTtjcT\nZ0ZERJCdnc3+/fudep2OHj3K2bNnCQ8P9/aSXNq4cSO//PILzz33XL6n3DIzMxk3bhwffvghgwcP\npkmTJhhj2LlzJ126dHF5vtweup07dxZYbmhoKKdPn86XnuFFtO3p77tJkyZkZ2ezZ88eIiMjCzzn\nyJEjmTp1Kr/++itLly6lf//++W7NlgWle5HfLVu0t0kpVarlDWrAObi52p6hkj4//HG7bsaMGXzz\nzTf5niwDa6+LxWJx6rU4cOAAq1at8rq8du3aUb16debPn+90voULF/L777/nKzevrVu38tVXxg1c\nNgAADcdJREFUXzmlVa5sHTbrKmDIq0+fPhhjeOWVV5zSX3rpJUSEu+66y+NrKUhSUhJVqlThscce\nY8CAAU6vhIQEGjZsaL9dd9ttt9GgQQP++te/8t///tfl+WrXrk3Hjh1ZuHAhR44ccVtu48aNOXHi\nBLt377anHTlyxKvflae/73tt8ysmJiYW2iM2dOhQrly5woQJEzh06JDL91lZULp7nM6d00V9lVKl\n2ubNrnt+coObzZuvrleopM9vPVcEHTt25IMPPkBE8t2mA+jbty+vvvoqPXv2JD4+nl9++YV58+bR\nvHlz+7QABXH8UvX39+eZZ57hkUce4Y477mDIkCH85z//YfHixTRs2DBfuR9++CEDBgygd+/e7N+/\nnzfeeIPIyEiniRorV65Ms2bNSElJoVGjRoSGhtKqVStatmyZry7R0dEMGzaMefPmceLECTp37sz2\n7dtJSkpi8ODBTr1gRZU7K3vv3r3tg9vz6tevH6+//jonT56kevXqzJs3j3vvvZdbb72VBx54gDp1\n6rBnzx727t3L6tWrAfj73/9O165dad26NQkJCURERHDgwAE2bNhgnxtq6NChPPHEE/Tv358JEyZw\n9uxZ5s+fT4sWLfj22289qr+nv+9mzZoxdepU5syZQ9euXbnnnnsICAjgq6++Ijw8nFmz/hiVU7t2\nbbp37867775LWFgYvXr1Kmrz+ta1eHTP2xe50xHUq2eMw+OaSil1rXnyOHR5MG/ePGOxWEyHDh3c\n5lm4cKFp1qyZCQwMNFFRUeadd97J94i7McbUr1/fJCQk2LfzTkfgWGajRo1MYGCg6dChg9m2bZvp\n3Lmz6dGjh1O+Z5991kRERJigoCDTpk0bs27dOjN8+HDTrFkzp3xbt241bdq0MZUqVTIWi8U+NcH0\n6dNNQECAU97s7GyTmJhoGjVqZCpWrGgiIiLMjBkz8k19UL9+fTNgwIB8bdGpU6d89XS0fPlyY7FY\nTFJSkts8GzduNBaLxbz++uv2tM8++8x0797dVKlSxYSEhJjWrVubBQsWOB23c+dOc++995rq1aub\nypUrm8jISDNr1iynPOvXrzc33XSTqVixoomMjDTLli1zOR2BxWIxkyZNclk/T3/fxhizaNEiEx0d\n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\nLR/zc9RFAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fe0bd505e10>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Validation accuracy at 0.7875999808311462\n"
     ]
    }
   ],
   "source": [
    "# Change if you have memory restrictions\n",
    "batch_size = 256\n",
    "\n",
    "# TODO: Find the best parameters for each configuration\n",
    "epochs = 5\n",
    "#learning_rate = 0.01\n",
    "    \n",
    "\n",
    "### DON'T MODIFY ANYTHING BELOW ###\n",
    "# Gradient Descent\n",
    "#optimizer = tf.train.AdamOptimizer().minimize(loss)    \n",
    "#with tf.Session() as sess:\n",
    "#    sess.run(init)\n",
    "\n",
    "# The accuracy measured against the validation set\n",
    "validation_accuracy = 0.0\n",
    "\n",
    "# Measurements use for graphing loss and accuracy\n",
    "log_batch_step = 50\n",
    "batches = []\n",
    "loss_batch = []\n",
    "train_acc_batch = []\n",
    "valid_acc_batch = []\n",
    "\n",
    "with tf.Session() as session:\n",
    "    session.run(init)\n",
    "    batch_count = int(math.ceil(len(train_features)/batch_size))\n",
    "\n",
    "    for epoch_i in range(epochs):\n",
    "        \n",
    "        # Progress bar\n",
    "        batches_pbar = tqdm(range(batch_count), desc='Epoch {:>2}/{}'.format(epoch_i+1, epochs), unit='batches')\n",
    "        \n",
    "        # The training cycle\n",
    "        for batch_i in batches_pbar:\n",
    "            # Get a batch of training features and labels\n",
    "            batch_start = batch_i*batch_size\n",
    "            batch_features = train_features[batch_start:batch_start + batch_size]\n",
    "            batch_labels = train_labels[batch_start:batch_start + batch_size]\n",
    "\n",
    "            # Run optimizer and get loss\n",
    "            _, l = session.run(\n",
    "                [optimizer, loss],\n",
    "                feed_dict={features: batch_features, labels: batch_labels})\n",
    "\n",
    "            # Log every 50 batches\n",
    "            if not batch_i % log_batch_step:\n",
    "                # Calculate Training and Validation accuracy\n",
    "                training_accuracy = session.run(accuracy, feed_dict=train_feed_dict)\n",
    "                validation_accuracy = session.run(accuracy, feed_dict=valid_feed_dict)\n",
    "\n",
    "                # Log batches\n",
    "                previous_batch = batches[-1] if batches else 0\n",
    "                batches.append(log_batch_step + previous_batch)\n",
    "                loss_batch.append(l)\n",
    "                train_acc_batch.append(training_accuracy)\n",
    "                valid_acc_batch.append(validation_accuracy)\n",
    "\n",
    "        # Check accuracy against Validation data\n",
    "        validation_accuracy = session.run(accuracy, feed_dict=valid_feed_dict)\n",
    "\n",
    "loss_plot = plt.subplot(211)\n",
    "loss_plot.set_title('Loss')\n",
    "loss_plot.plot(batches, loss_batch, 'g')\n",
    "loss_plot.set_xlim([batches[0], batches[-1]])\n",
    "acc_plot = plt.subplot(212)\n",
    "acc_plot.set_title('Accuracy')\n",
    "acc_plot.plot(batches, train_acc_batch, 'r', label='Training Accuracy')\n",
    "acc_plot.plot(batches, valid_acc_batch, 'x', label='Validation Accuracy')\n",
    "acc_plot.set_ylim([0, 1.0])\n",
    "acc_plot.set_xlim([batches[0], batches[-1]])\n",
    "acc_plot.legend(loc=4)\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print('Validation accuracy at {}'.format(validation_accuracy))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Test\n",
    "You're going to test your model against your hold out dataset/testing data.  This will give you a good indicator of how well the model will do in the real world.  You should have a test accuracy of at least 80%."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 162,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Epoch  1/5: 100%|██████████| 557/557 [00:00<00:00, 1103.36batches/s]\n",
      "Epoch  2/5: 100%|██████████| 557/557 [00:00<00:00, 1257.45batches/s]\n",
      "Epoch  3/5: 100%|██████████| 557/557 [00:00<00:00, 1494.07batches/s]\n",
      "Epoch  4/5: 100%|██████████| 557/557 [00:00<00:00, 1577.33batches/s]\n",
      "Epoch  5/5: 100%|██████████| 557/557 [00:00<00:00, 1609.31batches/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Nice Job! Test Accuracy is 0.855400025844574\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "### DON'T MODIFY ANYTHING BELOW ###\n",
    "# The accuracy measured against the test set\n",
    "test_accuracy = 0.0\n",
    "\n",
    "with tf.Session() as session:\n",
    "    \n",
    "    session.run(init)\n",
    "    batch_count = int(math.ceil(len(train_features)/batch_size))\n",
    "\n",
    "    for epoch_i in range(epochs):\n",
    "        e\n",
    "        # Progress bar\n",
    "        batches_pbar = tqdm(range(batch_count), desc='Epoch {:>2}/{}'.format(epoch_i+1, epochs), unit='batches')\n",
    "        \n",
    "        # The training cycle\n",
    "        for batch_i in batches_pbar:\n",
    "            # Get a batch of training features and labels\n",
    "            batch_start = batch_i*batch_size\n",
    "            batch_features = train_features[batch_start:batch_start + batch_size]\n",
    "            batch_labels = train_labels[batch_start:batch_start + batch_size]\n",
    "\n",
    "            # Run optimizer\n",
    "            _ = session.run(optimizer, feed_dict={features: batch_features, labels: batch_labels})\n",
    "\n",
    "        # Check accuracy against Test data\n",
    "        test_accuracy = session.run(accuracy, feed_dict=test_feed_dict)\n",
    "\n",
    "\n",
    "assert test_accuracy >= 0.80, 'Test accuracy at {}, should be equal to or greater than 0.80'.format(test_accuracy)\n",
    "print('Nice Job! Test Accuracy is {}'.format(test_accuracy))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Multiple layers\n",
    "Good job!  You built a one layer TensorFlow network!  However, you might want to build more than one layer.  This is deep learning after all!  In the next section, you will start to satisfy your need for more layers."
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "hide_input": false,
  "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.5.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
