Skip to content

Instantly share code, notes, and snippets.

@georgehc
Last active April 18, 2022 20:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save georgehc/9369b7af1df2e60502b663bccc389def to your computer and use it in GitHub Desktop.
Save georgehc/9369b7af1df2e60502b663bccc389def to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 94-775/95-865: Handwritten Digit Recognition with Neural Nets\n",
"\n",
"Author: George H. Chen (georgechen [at symbol] cmu.edu)\n",
"\n",
"This demo shows how to train and evaluate four neural net models using PyTorch:\n",
"\n",
"1. Flatten -> fully connected -> softmax activation*\n",
"\n",
"2. Flatten -> fully connected -> ReLU -> fully connected -> softmax activation*\n",
"\n",
"3. Conv2d -> ReLU -> MaxPool2d -> flatten -> fully connected -> softmax activation*\n",
"\n",
"4. Conv2d -> ReLU -> MaxPool2d -> Conv2d -> ReLU -> MaxPool2d -> flatten -> fully connected -> softmax activation*\n",
"\n",
"*In PyTorch, softmax activation is automatically done as part of using the cross entropy loss."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import random\n",
"\n",
"# the next two lines are needed on my Intel-based MacBook Air to get the code to run; you likely don't need these two lines...\n",
"# (in fact I used to not need these two lines)\n",
"import os\n",
"os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'\n",
"\n",
"import torch\n",
"torch.use_deterministic_algorithms(True)\n",
"torch.backends.cudnn.benchmark = False\n",
"import torch.nn as nn\n",
"import torchvision\n",
"import torchvision.transforms as transforms\n",
"from torchsummaryX import summary\n",
"\n",
"from UDA_pytorch_utils import UDA_pytorch_classifier_fit, \\\n",
" UDA_plot_train_val_accuracy_vs_epoch, UDA_pytorch_classifier_predict, \\\n",
" UDA_compute_accuracy\n",
"\n",
"np.random.seed(0)\n",
"torch.manual_seed(0)\n",
"random.seed(0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Loading in the data and a quick data inspection¶"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"train_dataset = torchvision.datasets.MNIST(root='data/',\n",
" train=True,\n",
" transform=transforms.ToTensor(),\n",
" download=True)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"train_images = torch.tensor(np.array([image.numpy() for image, label in train_dataset]))"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"train_labels = torch.tensor([label for image, label in train_dataset])"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"torch.Size([60000, 1, 28, 28])"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"train_images.shape"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"torch.Size([60000])"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"train_labels.shape"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We first take a look at the data."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.image.AxesImage at 0x7f8834e5ec70>"
]
},
"execution_count": 7,
"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": [
"plt.imshow(train_images[13][0], cmap='gray')"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"tensor(6)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"train_labels[13]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Basics of working with neural nets"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"simple_model = nn.Sequential(nn.Flatten(),\n",
" nn.Linear(in_features=784, out_features=10))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"==================================================\n",
" Kernel Shape Output Shape Params Mult-Adds\n",
"Layer \n",
"0_0 - [5, 784] - -\n",
"1_1 [784, 10] [5, 10] 7.85k 7.84k\n",
"--------------------------------------------------\n",
" Totals\n",
"Total params 7.85k\n",
"Trainable params 7.85k\n",
"Non-trainable params 0.0\n",
"Mult-Adds 7.84k\n",
"==================================================\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/georgehc/opt/anaconda3/lib/python3.9/site-packages/torchsummaryX/torchsummaryX.py:101: FutureWarning: Dropping of nuisance columns in DataFrame reductions (with 'numeric_only=None') is deprecated; in a future version this will raise TypeError. Select only valid columns before calling the reduction.\n",
" df_sum = df.sum()\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Kernel Shape</th>\n",
" <th>Output Shape</th>\n",
" <th>Params</th>\n",
" <th>Mult-Adds</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Layer</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0_0</th>\n",
" <td>-</td>\n",
" <td>[5, 784]</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1_1</th>\n",
" <td>[784, 10]</td>\n",
" <td>[5, 10]</td>\n",
" <td>7850.0</td>\n",
" <td>7840.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Kernel Shape Output Shape Params Mult-Adds\n",
"Layer \n",
"0_0 - [5, 784] NaN NaN\n",
"1_1 [784, 10] [5, 10] 7850.0 7840.0"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"summary(simple_model, torch.zeros((5, 1, 28, 28))) # (batch size, num channels, height, width)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"proper_train_size = int(0.8 * len(train_dataset))\n",
"val_size = len(train_dataset) - proper_train_size\n",
"proper_train_dataset, val_dataset = torch.utils.data.random_split(train_dataset,\n",
" [proper_train_size,\n",
" val_size])"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1 [==================================================] 48000/48000\n",
" Train accuracy: 0.8913\n",
" Validation accuracy: 0.8873\n",
"Epoch 2 [==================================================] 48000/48000\n",
" Train accuracy: 0.9075\n",
" Validation accuracy: 0.9046\n",
"Epoch 3 [==================================================] 48000/48000\n",
" Train accuracy: 0.9125\n",
" Validation accuracy: 0.9107\n",
"Epoch 4 [==================================================] 48000/48000\n",
" Train accuracy: 0.9179\n",
" Validation accuracy: 0.9127\n",
"Epoch 5 [==================================================] 48000/48000\n",
" Train accuracy: 0.9194\n",
" Validation accuracy: 0.9147\n",
"Epoch 6 [==================================================] 48000/48000\n",
" Train accuracy: 0.9229\n",
" Validation accuracy: 0.9166\n",
"Epoch 7 [==================================================] 48000/48000\n",
" Train accuracy: 0.9254\n",
" Validation accuracy: 0.9178\n",
"Epoch 8 [==================================================] 48000/48000\n",
" Train accuracy: 0.9266\n",
" Validation accuracy: 0.9188\n",
"Epoch 9 [==================================================] 48000/48000\n",
" Train accuracy: 0.9278\n",
" Validation accuracy: 0.9197\n",
"Epoch 10 [==================================================] 48000/48000\n",
" Train accuracy: 0.9278\n",
" Validation accuracy: 0.9187\n"
]
}
],
"source": [
"num_epochs = 10 # during optimization, how many times we look at training data\n",
"batch_size = 128 # during optimization, how many training data to use at each step\n",
"learning_rate = 0.001 # during optimization, how much we nudge our solution at each step\n",
"\n",
"train_accuracies, val_accuracies = \\\n",
" UDA_pytorch_classifier_fit(simple_model,\n",
" torch.optim.Adam(simple_model.parameters(),\n",
" lr=learning_rate),\n",
" nn.CrossEntropyLoss(), # includes softmax\n",
" proper_train_dataset, val_dataset,\n",
" num_epochs, batch_size)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"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": [
"UDA_plot_train_val_accuracy_vs_epoch(train_accuracies, val_accuracies)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"====================================================\n",
" Kernel Shape Output Shape Params Mult-Adds\n",
"Layer \n",
"0_0 - [1, 784] - -\n",
"1_1 [784, 512] [1, 512] 401.92k 401.408k\n",
"2_2 - [1, 512] - -\n",
"3_3 [512, 10] [1, 10] 5.13k 5.12k\n",
"----------------------------------------------------\n",
" Totals\n",
"Total params 407.05k\n",
"Trainable params 407.05k\n",
"Non-trainable params 0.0\n",
"Mult-Adds 406.528k\n",
"====================================================\n",
"Epoch 1 [= ] 1024/48000"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/georgehc/opt/anaconda3/lib/python3.9/site-packages/torchsummaryX/torchsummaryX.py:101: FutureWarning: Dropping of nuisance columns in DataFrame reductions (with 'numeric_only=None') is deprecated; in a future version this will raise TypeError. Select only valid columns before calling the reduction.\n",
" df_sum = df.sum()\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1 [==================================================] 48000/48000\n",
" Train accuracy: 0.9521\n",
" Validation accuracy: 0.9438\n",
"Epoch 2 [==================================================] 48000/48000\n",
" Train accuracy: 0.9719\n",
" Validation accuracy: 0.9650\n",
"Epoch 3 [==================================================] 48000/48000\n",
" Train accuracy: 0.9805\n",
" Validation accuracy: 0.9706\n",
"Epoch 4 [==================================================] 48000/48000\n",
" Train accuracy: 0.9864\n",
" Validation accuracy: 0.9748\n",
"Epoch 5 [==================================================] 48000/48000\n",
" Train accuracy: 0.9902\n",
" Validation accuracy: 0.9765\n",
"Epoch 6 [==================================================] 48000/48000\n",
" Train accuracy: 0.9921\n",
" Validation accuracy: 0.9754\n",
"Epoch 7 [==================================================] 48000/48000\n",
" Train accuracy: 0.9943\n",
" Validation accuracy: 0.9779\n",
"Epoch 8 [==================================================] 48000/48000\n",
" Train accuracy: 0.9943\n",
" Validation accuracy: 0.9762\n",
"Epoch 9 [==================================================] 48000/48000\n",
" Train accuracy: 0.9959\n",
" Validation accuracy: 0.9771\n",
"Epoch 10 [==================================================] 48000/48000\n",
" Train accuracy: 0.9961\n",
" Validation accuracy: 0.9775\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": [
"deeper_model = nn.Sequential(nn.Flatten(),\n",
" nn.Linear(in_features=784, out_features=512),\n",
" nn.ReLU(),\n",
" nn.Linear(in_features=512, out_features=10))\n",
"summary(deeper_model, torch.zeros((1, 1, 28, 28))) # (batch size, num channels, height, width)\n",
"\n",
"train_accuracies, val_accuracies = \\\n",
" UDA_pytorch_classifier_fit(deeper_model,\n",
" torch.optim.Adam(deeper_model.parameters(),\n",
" lr=learning_rate),\n",
" nn.CrossEntropyLoss(), # includes softmax\n",
" proper_train_dataset, val_dataset,\n",
" num_epochs, batch_size)\n",
"\n",
"UDA_plot_train_val_accuracy_vs_epoch(train_accuracies, val_accuracies)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Convnets"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"=========================================================\n",
" Kernel Shape Output Shape Params Mult-Adds\n",
"Layer \n",
"0_0 [1, 32, 3, 3] [1, 32, 26, 26] 320.0 194.688k\n",
"1_1 - [1, 32, 26, 26] - -\n",
"2_2 - [1, 32, 13, 13] - -\n",
"3_3 - [1, 5408] - -\n",
"4_4 [5408, 10] [1, 10] 54.09k 54.08k\n",
"---------------------------------------------------------\n",
" Totals\n",
"Total params 54.41k\n",
"Trainable params 54.41k\n",
"Non-trainable params 0.0\n",
"Mult-Adds 248.768k\n",
"=========================================================\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/georgehc/opt/anaconda3/lib/python3.9/site-packages/torchsummaryX/torchsummaryX.py:101: FutureWarning: Dropping of nuisance columns in DataFrame reductions (with 'numeric_only=None') is deprecated; in a future version this will raise TypeError. Select only valid columns before calling the reduction.\n",
" df_sum = df.sum()\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Kernel Shape</th>\n",
" <th>Output Shape</th>\n",
" <th>Params</th>\n",
" <th>Mult-Adds</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Layer</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0_0</th>\n",
" <td>[1, 32, 3, 3]</td>\n",
" <td>[1, 32, 26, 26]</td>\n",
" <td>320.0</td>\n",
" <td>194688.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1_1</th>\n",
" <td>-</td>\n",
" <td>[1, 32, 26, 26]</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2_2</th>\n",
" <td>-</td>\n",
" <td>[1, 32, 13, 13]</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3_3</th>\n",
" <td>-</td>\n",
" <td>[1, 5408]</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4_4</th>\n",
" <td>[5408, 10]</td>\n",
" <td>[1, 10]</td>\n",
" <td>54090.0</td>\n",
" <td>54080.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Kernel Shape Output Shape Params Mult-Adds\n",
"Layer \n",
"0_0 [1, 32, 3, 3] [1, 32, 26, 26] 320.0 194688.0\n",
"1_1 - [1, 32, 26, 26] NaN NaN\n",
"2_2 - [1, 32, 13, 13] NaN NaN\n",
"3_3 - [1, 5408] NaN NaN\n",
"4_4 [5408, 10] [1, 10] 54090.0 54080.0"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"simple_convnet = nn.Sequential(nn.Conv2d(1, 32, 3),\n",
" nn.ReLU(),\n",
" nn.MaxPool2d(2),\n",
" nn.Flatten(),\n",
" nn.Linear(in_features=5408, out_features=10))\n",
"summary(simple_convnet, torch.zeros((1, 1, 28, 28))) # (batch size, num channels, height, width)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1 [==================================================] 48000/48000\n",
" Train accuracy: 0.9540\n",
" Validation accuracy: 0.9507\n",
"Epoch 2 [==================================================] 48000/48000\n",
" Train accuracy: 0.9722\n",
" Validation accuracy: 0.9683\n",
"Epoch 3 [==================================================] 48000/48000\n",
" Train accuracy: 0.9797\n",
" Validation accuracy: 0.9758\n",
"Epoch 4 [==================================================] 48000/48000\n",
" Train accuracy: 0.9847\n",
" Validation accuracy: 0.9802\n",
"Epoch 5 [==================================================] 48000/48000\n",
" Train accuracy: 0.9872\n",
" Validation accuracy: 0.9816\n",
"Epoch 6 [==================================================] 48000/48000\n",
" Train accuracy: 0.9880\n",
" Validation accuracy: 0.9816\n",
"Epoch 7 [==================================================] 48000/48000\n",
" Train accuracy: 0.9896\n",
" Validation accuracy: 0.9822\n",
"Epoch 8 [==================================================] 48000/48000\n",
" Train accuracy: 0.9911\n",
" Validation accuracy: 0.9828\n",
"Epoch 9 [==================================================] 48000/48000\n",
" Train accuracy: 0.9921\n",
" Validation accuracy: 0.9825\n",
"Epoch 10 [==================================================] 48000/48000\n",
" Train accuracy: 0.9918\n",
" Validation accuracy: 0.9822\n"
]
},
{
"data": {
"image/png": "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UYKYP38+zz777DHf++GHHx5zn5YsWbKEiRMn1ieIP/zhD60+lmk/9pdUNKoqWpV3iIpqZyyx3l2jOevkREb3SWBUnwQG9uhEWGiIx8e220uDjyWIlnzzjFcSxHXXXcfjjz9ORUUFkZGRbN++nfz8fN58800eeOABysrKuO6663jiiSeavbdv375kZGSQlJTEU089xdy5c+nduzfdunVj9OjRgNPHYdasWVRWVnLqqafyxhtvkJ2dzdKlS/nmm2948skneeedd/jjH//IxIkTue666/jiiy946KGHqK6u5owzzuDFF18kMjKSvn37cvPNN/P+++9TVVXF22+/zaBBg074OzAnpqX+B7W1yua9RxqTV+QcrL/VNCI0hKHJnbnprD5OQkhNoHvnqAB/EtPeBFeC+OhR2L3a8/3nXHHsfU46HS57psXNiYmJjBkzho8//pirr76a+fPnM3nyZKZPn07Xrl2pqalhwoQJrFq1imHDhrk9RmZmJvPnzycrK4vq6mpGjRpVnyAmTZrEHXfcAcDjjz/Oq6++yr333stVV11VnxAaKi8vZ9q0aXzxxRcMGDCAm266iRdffJH7778fgKSkJFasWMHf/vY3Zs6cySuvvOLBF2V8xV3/g4feXsmL3/xIfmEZxa6G46Q4pzF5yhm9Gd0ngaHJXbw+gqkJPsGVII6lcAccatC3b8e3znOX3hDfp9WHratmqksQs2fPZuHChcyaNYvq6mp27drFunXrWkwQ//znP7n22muJiYkB4KqrrqrftmbNGh5//HEKCwspKSlpVJXlzsaNG+nXrx8DBgwA4Oabb+aFF16oTxCTJk0CYPTo0bz77rut/szm+JVV1pB/qIxdheXkF5aRf6iMWcu2Nut/UF2r/Li3hMmuZDC6j3VEM74RXAniKL/0m5nRBWYc8sppr7nmGh588EFWrFhBWVkZCQkJzJw5k/T0dBISEpg2bRrl5e7vM6/T0n/+adOmsWTJEoYPH85rr73G119/fdTjHGvsrbohw1saUty0TnVNLXuKK5wLf2EZ+YXl7DrkPOcXlrHrUBkHm0xjKQIt/XPV1CpPXXu6HyI3wSy4EkSAxMXFcf7553PrrbcydepUioqKiI2NpUuXLuzZs4ePPvqoxXkgAM4991ymTZvGo48+SnV1Ne+//379eErFxcX07NmTqqoq5s2bVz90eKdO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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"train_accuracies, val_accuracies = \\\n",
" UDA_pytorch_classifier_fit(simple_convnet,\n",
" torch.optim.Adam(simple_convnet.parameters(),\n",
" lr=learning_rate),\n",
" nn.CrossEntropyLoss(), # includes softmax\n",
" proper_train_dataset, val_dataset,\n",
" num_epochs, batch_size)\n",
"\n",
"UDA_plot_train_val_accuracy_vs_epoch(train_accuracies, val_accuracies)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"=========================================================\n",
" Kernel Shape Output Shape Params Mult-Adds\n",
"Layer \n",
"0_0 [1, 32, 3, 3] [1, 32, 26, 26] 320.0 194.688k\n",
"1_1 - [1, 32, 26, 26] - -\n",
"2_2 - [1, 32, 13, 13] - -\n",
"3_3 [32, 16, 3, 3] [1, 16, 11, 11] 4.624k 557.568k\n",
"4_4 - [1, 16, 11, 11] - -\n",
"5_5 - [1, 16, 5, 5] - -\n",
"6_6 - [1, 400] - -\n",
"7_7 [400, 10] [1, 10] 4.01k 4.0k\n",
"---------------------------------------------------------\n",
" Totals\n",
"Total params 8.954k\n",
"Trainable params 8.954k\n",
"Non-trainable params 0.0\n",
"Mult-Adds 756.256k\n",
"=========================================================\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/georgehc/opt/anaconda3/lib/python3.9/site-packages/torchsummaryX/torchsummaryX.py:101: FutureWarning: Dropping of nuisance columns in DataFrame reductions (with 'numeric_only=None') is deprecated; in a future version this will raise TypeError. Select only valid columns before calling the reduction.\n",
" df_sum = df.sum()\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Kernel Shape</th>\n",
" <th>Output Shape</th>\n",
" <th>Params</th>\n",
" <th>Mult-Adds</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Layer</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0_0</th>\n",
" <td>[1, 32, 3, 3]</td>\n",
" <td>[1, 32, 26, 26]</td>\n",
" <td>320.0</td>\n",
" <td>194688.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1_1</th>\n",
" <td>-</td>\n",
" <td>[1, 32, 26, 26]</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2_2</th>\n",
" <td>-</td>\n",
" <td>[1, 32, 13, 13]</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3_3</th>\n",
" <td>[32, 16, 3, 3]</td>\n",
" <td>[1, 16, 11, 11]</td>\n",
" <td>4624.0</td>\n",
" <td>557568.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4_4</th>\n",
" <td>-</td>\n",
" <td>[1, 16, 11, 11]</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5_5</th>\n",
" <td>-</td>\n",
" <td>[1, 16, 5, 5]</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6_6</th>\n",
" <td>-</td>\n",
" <td>[1, 400]</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7_7</th>\n",
" <td>[400, 10]</td>\n",
" <td>[1, 10]</td>\n",
" <td>4010.0</td>\n",
" <td>4000.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Kernel Shape Output Shape Params Mult-Adds\n",
"Layer \n",
"0_0 [1, 32, 3, 3] [1, 32, 26, 26] 320.0 194688.0\n",
"1_1 - [1, 32, 26, 26] NaN NaN\n",
"2_2 - [1, 32, 13, 13] NaN NaN\n",
"3_3 [32, 16, 3, 3] [1, 16, 11, 11] 4624.0 557568.0\n",
"4_4 - [1, 16, 11, 11] NaN NaN\n",
"5_5 - [1, 16, 5, 5] NaN NaN\n",
"6_6 - [1, 400] NaN NaN\n",
"7_7 [400, 10] [1, 10] 4010.0 4000.0"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"deeper_convnet = nn.Sequential(nn.Conv2d(1, 32, 3),\n",
" nn.ReLU(),\n",
" nn.MaxPool2d(2),\n",
" nn.Conv2d(32, 16, 3),\n",
" nn.ReLU(),\n",
" nn.MaxPool2d(2),\n",
" nn.Flatten(),\n",
" nn.Linear(in_features=400, out_features=10))\n",
"summary(deeper_convnet, torch.zeros((1, 1, 28, 28))) # (batch size, num channels, height, width)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1 [==================================================] 48000/48000\n",
" Train accuracy: 0.9564\n",
" Validation accuracy: 0.9556\n",
"Epoch 2 [==================================================] 48000/48000\n",
" Train accuracy: 0.9711\n",
" Validation accuracy: 0.9712\n",
"Epoch 3 [==================================================] 48000/48000\n",
" Train accuracy: 0.9771\n",
" Validation accuracy: 0.9754\n",
"Epoch 4 [==================================================] 48000/48000\n",
" Train accuracy: 0.9810\n",
" Validation accuracy: 0.9802\n",
"Epoch 5 [==================================================] 48000/48000\n",
" Train accuracy: 0.9829\n",
" Validation accuracy: 0.9820\n",
"Epoch 6 [==================================================] 48000/48000\n",
" Train accuracy: 0.9843\n",
" Validation accuracy: 0.9822\n",
"Epoch 7 [==================================================] 48000/48000\n",
" Train accuracy: 0.9841\n",
" Validation accuracy: 0.9827\n",
"Epoch 8 [==================================================] 48000/48000\n",
" Train accuracy: 0.9873\n",
" Validation accuracy: 0.9847\n",
"Epoch 9 [==================================================] 48000/48000\n",
" Train accuracy: 0.9880\n",
" Validation accuracy: 0.9852\n",
"Epoch 10 [==================================================] 48000/48000\n",
" Train accuracy: 0.9868\n",
" Validation accuracy: 0.9843\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": [
"train_accuracies, val_accuracies = \\\n",
" UDA_pytorch_classifier_fit(deeper_convnet,\n",
" torch.optim.Adam(deeper_convnet.parameters(),\n",
" lr=learning_rate),\n",
" nn.CrossEntropyLoss(), # includes softmax\n",
" proper_train_dataset, val_dataset,\n",
" num_epochs, batch_size)\n",
"\n",
"UDA_plot_train_val_accuracy_vs_epoch(train_accuracies, val_accuracies)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Finally evaluate on test data"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [],
"source": [
"test_dataset = torchvision.datasets.MNIST(root='data/',\n",
" train=False,\n",
" transform=transforms.ToTensor(),\n",
" download=True)\n",
"test_images = torch.tensor(np.array([image.numpy() for image, label in test_dataset]))"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Test accuracy: 0.9241\n"
]
}
],
"source": [
"predicted_test_labels = UDA_pytorch_classifier_predict(simple_model, test_images)\n",
"print('Test accuracy:', UDA_compute_accuracy(predicted_test_labels, test_dataset.targets))"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Test accuracy: 0.9767\n"
]
}
],
"source": [
"predicted_test_labels = UDA_pytorch_classifier_predict(deeper_model, test_images)\n",
"print('Test accuracy:', UDA_compute_accuracy(predicted_test_labels, test_dataset.targets))"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Test accuracy: 0.9816\n"
]
}
],
"source": [
"predicted_test_labels = UDA_pytorch_classifier_predict(simple_convnet, test_images)\n",
"print('Test accuracy:', UDA_compute_accuracy(predicted_test_labels, test_dataset.targets))"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Test accuracy: 0.9838\n"
]
}
],
"source": [
"predicted_test_labels = UDA_pytorch_classifier_predict(deeper_convnet, test_images)\n",
"print('Test accuracy:', UDA_compute_accuracy(predicted_test_labels, test_dataset.targets))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
"""
Helper code for Carnegie Mellon University's Unstructured Data Analytics course
Author: George H. Chen (georgechen [at symbol] cmu.edu)
I wrote this code for my class to make teaching how to use PyTorch as simple as
using Keras. Note that this code only has been tested using categorical cross
entropy loss.
"""
import matplotlib.pyplot as plt
import numpy as np
import sys
import torch
import torch.nn as nn
from matplotlib.ticker import MaxNLocator
from torchnlp.encoders.text import stack_and_pad_tensors
from torchnlp.samplers import BucketBatchSampler
from torchnlp.utils import collate_tensors
def UDA_pytorch_classifier_fit(model, optimizer, loss,
proper_train_dataset, val_dataset,
num_epochs, batch_size, device=None,
sequence=False,
save_epoch_checkpoint_prefix=None):
"""
Trains a neural net classifier `model` using an `optimizer` such as Adam or
stochastic gradient descent. We specifically minimize the given `loss`
using the data given by `proper_train_dataset` using the number of epochs
given by `num_epochs` and a batch size given by `batch_size`.
Accuracies on the (proper) training data (`proper_train_dataset`) and
validation data (`val_dataset`) are computed at the end of each epoch;
`val_dataset` can be set to None if you don't want to use a validation set.
The function outputs the training and validation accuracies.
You can manually set which device (CPU or GPU) to use with the optional
`device` argument (e.g., setting `device=torch.device('cpu')` or
`device=torch.device('cuda')`). By default, the code tries to use a GPU if
it is available.
The boolean argument `sequence` says whether we are looking at time series
data (set this True for working with recurrent neural nets).
Lastly, if `save_epoch_checkpoint_prefix` is a string prefix, then each
epoch's model is saved to a filename with format
'<save_epoch_checkpoint_prefix>_epoch<epoch number>.pt'.
"""
if device is None:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
if loss._get_name() != 'CrossEntropyLoss':
raise Exception('Unsupported loss: ' + loss._get_name())
if not sequence:
# PyTorch uses DataLoader to load data in batches
proper_train_loader = \
torch.utils.data.DataLoader(dataset=proper_train_dataset,
batch_size=batch_size,
shuffle=True)
if val_dataset is not None:
val_loader = torch.utils.data.DataLoader(dataset=val_dataset,
batch_size=batch_size,
shuffle=False)
else:
proper_train_loader = \
UDA_get_batches_sequence(proper_train_dataset,
batch_size,
shuffle=True,
device=device)
if val_dataset is not None:
val_loader = \
UDA_get_batches_sequence(val_dataset,
batch_size,
shuffle=False,
device=device)
proper_train_size = len(proper_train_dataset)
val_size = len(val_dataset)
train_accuracies = np.zeros(num_epochs)
val_accuracies = np.zeros(num_epochs)
for epoch_idx in range(num_epochs):
# go through training data
num_training_examples_so_far = 0
for batch_idx, (batch_features, batch_labels) \
in enumerate(proper_train_loader):
# make sure the data are stored on the right device
batch_features = batch_features.to(device)
batch_labels = batch_labels.to(device)
# make predictions for current batch and compute loss
batch_outputs = model(batch_features)
batch_loss = loss(batch_outputs, batch_labels)
# update model parameters
optimizer.zero_grad() # reset which direction optimizer is going
batch_loss.backward() # compute new direction optimizer should go
optimizer.step() # move the optimizer
# draw fancy progress bar
num_training_examples_so_far += batch_features.shape[0]
sys.stdout.write('\r')
sys.stdout.write("Epoch %d [%-50s] %d/%d"
% (epoch_idx + 1,
'=' * int(num_training_examples_so_far
/ proper_train_size * 50),
num_training_examples_so_far,
proper_train_size))
sys.stdout.flush()
# draw fancy progress bar at 100%
sys.stdout.write('\r')
sys.stdout.write("Epoch %d [%-50s] %d/%d"
% (epoch_idx + 1,
'=' * 50,
num_training_examples_so_far, proper_train_size))
sys.stdout.flush()
sys.stdout.write('\n')
sys.stdout.flush()
# compute proper training and validation set raw accuracies
model.eval() # turn on evaluation mode
train_accuracy = \
UDA_pytorch_classifier_evaluate(model,
proper_train_dataset,
device=device,
batch_size=batch_size,
sequence=sequence)
print(' Train accuracy: %.4f' % train_accuracy, flush=True)
train_accuracies[epoch_idx] = train_accuracy
if val_dataset is not None:
val_accuracy = \
UDA_pytorch_classifier_evaluate(model,
val_dataset,
device=device,
batch_size=batch_size,
sequence=sequence)
print(' Validation accuracy: %.4f' % val_accuracy, flush=True)
val_accuracies[epoch_idx] = val_accuracy
model.train() # turn off evaluation mode
if save_epoch_checkpoint_prefix is not None:
torch.save(model.state_dict(),
'%s_epoch%d.pt'
% (save_epoch_checkpoint_prefix, epoch_idx + 1))
return train_accuracies, val_accuracies
def UDA_pytorch_model_transform(model, inputs, device=None, batch_size=128,
sequence=False):
"""
Given a neural net `model`, evaluate the model given `inputs`, which should
*not* be already batched. This helper function automatically batches the
data, feeds each batch through the neural net, and then unbatches the
outputs. The outputs are stored as a PyTorch tensor.
You can manually set which device (CPU or GPU) to use with the optional
`device` argument (e.g., setting `device=torch.device('cpu')` or
`device=torch.device('cuda')`). By default, the code tries to use a GPU if
it is available.
You can also manually set `batch_size`; this is less critical than in
training since we are, at this point, just evaluating the model without
updating its parameters.
Lastly, the boolean argument `sequence` says whether we are looking at time
series data (set this True for working with recurrent neural nets).
"""
if device is None:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
# batch the inputs
if not sequence:
feature_loader = torch.utils.data.DataLoader(dataset=inputs,
batch_size=batch_size,
shuffle=False)
else:
feature_loader = \
UDA_get_batches_from_encoded_text(inputs,
None,
batch_size,
shuffle=False,
device=device)
outputs = []
with torch.no_grad():
idx = 0
for batch_features in feature_loader:
batch_features = batch_features.to(device)
batch_outputs = model(batch_features)
outputs.append(batch_outputs)
return torch.cat(outputs, 0)
def UDA_pytorch_classifier_predict(model, inputs, device=None, batch_size=128,
sequence=False):
"""
Given a neural net classifier `model`, predict labels for the given
`inputs`, which should *not* be already batched. This helper function
automatically batches the data, feeds each batch through the neural net,
and then computes predicted labels by looking at the argmax. The output
predicted labels are stored as a PyTorch tensor.
You can manually set which device (CPU or GPU) to use with the optional
`device` argument (e.g., setting `device=torch.device('cpu')` or
`device=torch.device('cuda')`). By default, the code tries to use a GPU if
it is available.
You can also manually set `batch_size`; this is less critical than in
training since we are, at this point, just evaluating the model without
updating its parameters.
Lastly, the boolean argument `sequence` says whether we are looking at time
series data (set this True for working with recurrent neural nets).
"""
outputs = UDA_pytorch_model_transform(model,
inputs,
device=device,
batch_size=batch_size,
sequence=sequence)
with torch.no_grad():
return outputs.argmax(axis=1).view(-1)
def UDA_pytorch_classifier_evaluate(model, dataset, device=None,
batch_size=128, sequence=False):
"""
Evaluate the raw accuracy of a neural net classifier `model` for a
`dataset`, which should be a list of pairs of the format (input, label).
You can manually set which device (CPU or GPU) to use with the optional
`device` argument (e.g., setting `device=torch.device('cpu')` or
`device=torch.device('cuda')`). By default, the code tries to use a GPU if
it is available.
You can also manually set `batch_size`; this is less critical than in
training since we are, at this point, just evaluating the model without
updating its parameters.
Lastly, the boolean argument `sequence` says whether we are looking at time
series data (set this True for working with recurrent neural nets).
"""
if device is None:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
if not sequence:
loader = torch.utils.data.DataLoader(dataset=dataset,
batch_size=batch_size,
shuffle=False)
else:
loader = UDA_get_batches_sequence(dataset,
batch_size,
shuffle=False,
device=device)
with torch.no_grad():
num_correct = 0.
for batch_features, batch_labels in loader:
batch_features = batch_features.to(device)
batch_outputs = model(batch_features)
batch_predicted_labels = batch_outputs.argmax(axis=1)
if type(batch_labels) == np.ndarray:
batch_predicted_labels = \
batch_predicted_labels.view(-1).cpu().numpy()
num_correct += (batch_predicted_labels == batch_labels).sum()
else:
num_correct += \
(batch_predicted_labels.view(-1)
== batch_labels.to(device).view(-1)).sum().item()
return num_correct / len(dataset)
def UDA_plot_train_val_accuracy_vs_epoch(train_accuracies, val_accuracies):
"""
Helper function for plotting (proper) training and validation accuracies
across epochs; `train_accuracies` and `val_accuracies` should be the same
length, which should equal the number of epochs.
"""
ax = plt.figure().gca()
num_epochs = len(train_accuracies)
plt.plot(np.arange(1, num_epochs + 1), train_accuracies, '-o',
label='Training')
plt.plot(np.arange(1, num_epochs + 1), val_accuracies, '-+',
label='Validation')
plt.legend()
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
ax.xaxis.set_major_locator(MaxNLocator(integer=True))
def UDA_compute_accuracy(labels1, labels2):
"""
Computes the raw accuracy of two label sequences `labels1` and `labels2`
agreeing. This helper function coerces both label sequences to be on the
CPU, flattened, and stored as 1D NumPy arrays before computing the average
agreement.
"""
if type(labels1) == torch.Tensor:
labels1 = labels1.detach().view(-1).cpu().numpy()
elif type(labels1) != np.ndarray:
labels1 = np.array(labels1).flatten()
else:
labels1 = labels1.flatten()
if type(labels2) == torch.Tensor:
labels2 = labels2.detach().view(-1).cpu().numpy()
elif type(labels2) != np.ndarray:
labels2 = np.array(labels2).flatten()
else:
labels2 = labels2.flatten()
return np.mean(labels1 == labels2)
class UDA_LSTMforSequential(nn.Module):
"""
This helper class allows for an LSTM to be used with nn.Sequential().
"""
def __init__(self, input_size, hidden_size, return_sequences=False):
super().__init__()
self.return_sequences = return_sequences
self.model = nn.LSTM(input_size=input_size,
hidden_size=hidden_size,
batch_first=True) # axis 0 indexes data in batch
def forward(self, x):
# x should be of shape (batch size, sequence length, feature dimension)
outputs, _ = self.model(x)
if self.return_sequences:
return outputs
else:
return outputs[:, -1, :] # take last time step's output
def UDA_get_batches_sequence(dataset, batch_size, shuffle=True, device=None):
"""
Helper function that does the same thing as
`UDA_get_batches_from_encoded_text()` except that the input dataset is a
list of pairs of the format (encoded text, label). This function
basically converts the input format to be what is expected by
`UDA_get_batches_from_encoded_text()` and then runs that function. See
the documentation for that function to understand what the arguments are.
"""
text_encoded = []
labels = []
for text, label in dataset:
text_encoded.append(text)
labels.append(label)
return UDA_get_batches_from_encoded_text(text_encoded, labels,
batch_size, shuffle, device)
def UDA_get_batches_from_encoded_text(text_encoded, labels, batch_size,
shuffle=True, device=None):
"""
Batches sequence data, where sequences within the same batch could have
unequal lengths, so padding is needed to get their lengths to be the same
for feeding to the neural net. The input text `text_encoded` should already
be encoded so that each text sequence consists of word indices to represent
indices into a vocabulary. The i-th element of `text_encoded` should have a
label given by the i-th entry in `labels` (which will be converted to a
PyTorch tensor). The batch size is specified by `batch_size`.
If `shuffle` is set to True, a bucket sampling strategy is used that reduces
how much padding is needed in different batches while injecting some
randomness.
You can manually set which device (CPU or GPU) to use with the optional
`device` argument (e.g., setting `device=torch.device('cpu')` or
`device=torch.device('cuda')`). By default, the code tries to use a GPU if
it is available.
"""
if device is None:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
if shuffle:
# use bucket sampling strategy to reduce the amount of padding needed
sampler = torch.utils.data.sampler.SequentialSampler(text_encoded)
loader = BucketBatchSampler(
sampler, batch_size=batch_size, drop_last=False,
sort_key=lambda i: text_encoded[i].shape[0])
else:
indices = list(range(len(text_encoded)))
loader = torch.utils.data.DataLoader(dataset=indices,
batch_size=batch_size,
shuffle=False)
if labels is None:
batches = [collate_tensors([text_encoded[i] for i in batch],
stack_tensors=stack_and_pad_tensors
).tensor.to(device)
for batch in loader]
else:
batches = [(collate_tensors([text_encoded[i] for i in batch],
stack_tensors=stack_and_pad_tensors
).tensor.to(device),
torch.tensor([labels[i] for i in batch],
dtype=torch.long).to(device).view(-1))
for batch in loader]
return batches
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment