367 lines
32 KiB
Plaintext
367 lines
32 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 83,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import tensorflow as tf\n",
|
|
"from tensorflow.keras import layers, models\n",
|
|
"import numpy as np\n",
|
|
"from matplotlib import pyplot as plt\n",
|
|
"from sklearn.model_selection import train_test_split\n",
|
|
"%matplotlib inline"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Exercise 9\n",
|
|
"Create CNN from scratch and apply to MNIST dataset to get best accuracy possible"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 84,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Load in the data\n",
|
|
"(X_train_full, y_train_full), (X_test, y_test) = tf.keras.datasets.mnist.load_data(\n",
|
|
" path='mnist.npz'\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 85,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"(60000, 28, 28)\n",
|
|
"(60000,)\n",
|
|
"(10000, 28, 28)\n",
|
|
"(10000,)\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# Check out our dimensions\n",
|
|
"print(X_train_full.shape)\n",
|
|
"print(y_train_full.shape)\n",
|
|
"print(X_test.shape)\n",
|
|
"print(y_test.shape)\n",
|
|
"\n",
|
|
"# Scale the data\n",
|
|
"X_train_full = X_train_full / 255.0\n",
|
|
"X_test = X_test / 255.0"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 86,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"6\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"image/png": "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\n",
|
|
"text/plain": [
|
|
"<Figure size 432x288 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {
|
|
"needs_background": "light"
|
|
},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"# Check out random samples of the data\n",
|
|
"import random\n",
|
|
"idx = random.randint(0, 60000)\n",
|
|
"plt.imshow(X_train_full[idx])\n",
|
|
"print(y_train_full[idx])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 87,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Split training set into training and validation sets\n",
|
|
"X_train, X_valid, y_train, y_valid = train_test_split(\n",
|
|
" X_train_full, y_train_full, test_size=10000)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 88,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"(50000, 28, 28)\n",
|
|
"(50000,)\n",
|
|
"(10000, 28, 28)\n",
|
|
"(10000,)\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# Check the shapes\n",
|
|
"print(X_train.shape)\n",
|
|
"print(y_train.shape)\n",
|
|
"print(X_valid.shape)\n",
|
|
"print(y_valid.shape)\n",
|
|
"\n",
|
|
"# Reshape to form single channel\n",
|
|
"X_train = X_train.reshape(X_train.shape[0], 28, 28, 1)\n",
|
|
"X_valid = X_valid.reshape(X_valid.shape[0], 28, 28, 1)\n",
|
|
"X_test = X_test.reshape(X_test.shape[0], 28, 28, 1)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 89,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"model = models.Sequential()\n",
|
|
"model.add(layers.Conv2D(32, (3,3), activation='relu', input_shape = (28, 28, 1)))\n",
|
|
"model.add(layers.MaxPooling2D((2,2)))\n",
|
|
"model.add(layers.Conv2D(64, (3,3), activation='relu'))\n",
|
|
"model.add(layers.MaxPooling2D((2,2)))\n",
|
|
"model.add(layers.Conv2D(64, (3,3), activation='relu'))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 90,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Model: \"sequential_11\"\n",
|
|
"_________________________________________________________________\n",
|
|
"Layer (type) Output Shape Param # \n",
|
|
"=================================================================\n",
|
|
"conv2d_21 (Conv2D) (None, 26, 26, 32) 320 \n",
|
|
"_________________________________________________________________\n",
|
|
"max_pooling2d_11 (MaxPooling (None, 13, 13, 32) 0 \n",
|
|
"_________________________________________________________________\n",
|
|
"conv2d_22 (Conv2D) (None, 11, 11, 64) 18496 \n",
|
|
"_________________________________________________________________\n",
|
|
"max_pooling2d_12 (MaxPooling (None, 5, 5, 64) 0 \n",
|
|
"_________________________________________________________________\n",
|
|
"conv2d_23 (Conv2D) (None, 3, 3, 64) 36928 \n",
|
|
"=================================================================\n",
|
|
"Total params: 55,744\n",
|
|
"Trainable params: 55,744\n",
|
|
"Non-trainable params: 0\n",
|
|
"_________________________________________________________________\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"model.summary()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 91,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"model.add(layers.Flatten())\n",
|
|
"model.add(layers.Dense(64, activation='relu'))\n",
|
|
"model.add(layers.Dense(10))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 92,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Model: \"sequential_11\"\n",
|
|
"_________________________________________________________________\n",
|
|
"Layer (type) Output Shape Param # \n",
|
|
"=================================================================\n",
|
|
"conv2d_21 (Conv2D) (None, 26, 26, 32) 320 \n",
|
|
"_________________________________________________________________\n",
|
|
"max_pooling2d_11 (MaxPooling (None, 13, 13, 32) 0 \n",
|
|
"_________________________________________________________________\n",
|
|
"conv2d_22 (Conv2D) (None, 11, 11, 64) 18496 \n",
|
|
"_________________________________________________________________\n",
|
|
"max_pooling2d_12 (MaxPooling (None, 5, 5, 64) 0 \n",
|
|
"_________________________________________________________________\n",
|
|
"conv2d_23 (Conv2D) (None, 3, 3, 64) 36928 \n",
|
|
"_________________________________________________________________\n",
|
|
"flatten_5 (Flatten) (None, 576) 0 \n",
|
|
"_________________________________________________________________\n",
|
|
"dense_10 (Dense) (None, 64) 36928 \n",
|
|
"_________________________________________________________________\n",
|
|
"dense_11 (Dense) (None, 10) 650 \n",
|
|
"=================================================================\n",
|
|
"Total params: 93,322\n",
|
|
"Trainable params: 93,322\n",
|
|
"Non-trainable params: 0\n",
|
|
"_________________________________________________________________\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"model.summary()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 93,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Train on 50000 samples, validate on 10000 samples\n",
|
|
"Epoch 1/10\n",
|
|
"50000/50000 [==============================] - 41s 825us/sample - loss: 0.1628 - acc: 0.9500 - val_loss: 0.0811 - val_acc: 0.9761\n",
|
|
"Epoch 2/10\n",
|
|
"50000/50000 [==============================] - 44s 880us/sample - loss: 0.0522 - acc: 0.9837 - val_loss: 0.0459 - val_acc: 0.9861\n",
|
|
"Epoch 3/10\n",
|
|
"50000/50000 [==============================] - 42s 850us/sample - loss: 0.0381 - acc: 0.9876 - val_loss: 0.0530 - val_acc: 0.9842\n",
|
|
"Epoch 4/10\n",
|
|
"50000/50000 [==============================] - 42s 839us/sample - loss: 0.0277 - acc: 0.9916 - val_loss: 0.0397 - val_acc: 0.9889\n",
|
|
"Epoch 5/10\n",
|
|
"50000/50000 [==============================] - 41s 817us/sample - loss: 0.0219 - acc: 0.9930 - val_loss: 0.0418 - val_acc: 0.9884\n",
|
|
"Epoch 6/10\n",
|
|
"50000/50000 [==============================] - 41s 820us/sample - loss: 0.0172 - acc: 0.9945 - val_loss: 0.0471 - val_acc: 0.9875\n",
|
|
"Epoch 7/10\n",
|
|
"50000/50000 [==============================] - 40s 797us/sample - loss: 0.0158 - acc: 0.9947 - val_loss: 0.0458 - val_acc: 0.9884\n",
|
|
"Epoch 8/10\n",
|
|
"50000/50000 [==============================] - 41s 817us/sample - loss: 0.0127 - acc: 0.9961 - val_loss: 0.0473 - val_acc: 0.9880\n",
|
|
"Epoch 9/10\n",
|
|
"50000/50000 [==============================] - 42s 841us/sample - loss: 0.0106 - acc: 0.9964 - val_loss: 0.0497 - val_acc: 0.9892\n",
|
|
"Epoch 10/10\n",
|
|
"50000/50000 [==============================] - 42s 837us/sample - loss: 0.0118 - acc: 0.9962 - val_loss: 0.0583 - val_acc: 0.9884 0.0118\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# Compile and fit our model to the data\n",
|
|
"model.compile(optimizer='adam',\n",
|
|
" loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n",
|
|
" metrics=['accuracy'])\n",
|
|
"\n",
|
|
"history = model.fit(X_train, y_train, epochs=10,\n",
|
|
" validation_data = (X_valid, y_valid))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 94,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"<matplotlib.legend.Legend at 0x17fa3926708>"
|
|
]
|
|
},
|
|
"execution_count": 94,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
},
|
|
{
|
|
"data": {
|
|
"image/png": "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\n",
|
|
"text/plain": [
|
|
"<Figure size 432x288 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {
|
|
"needs_background": "light"
|
|
},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"# Plot accuracy over epochs\n",
|
|
"plt.plot(history.history['acc'], label='train_accuracy')\n",
|
|
"plt.plot(history.history['val_acc'], label = 'val_accuracy')\n",
|
|
"plt.xlabel('Epoch')\n",
|
|
"plt.ylabel('Accuracy')\n",
|
|
"plt.legend(loc='lower right')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 95,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"10000/10000 - 3s - loss: 0.0421 - acc: 0.9900\n",
|
|
"0.99\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# Get final test accuracy\n",
|
|
"test_loss, test_accuracy = model.evaluate(X_test, y_test, verbose=2)\n",
|
|
"print(test_accuracy)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": []
|
|
}
|
|
],
|
|
"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.6"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 2
|
|
}
|