├── README.md ├── TrafficSignsWebApp ├── Figure_0.png ├── Figure_1.png ├── Traffic_app.py ├── main.py ├── my_model.h5 ├── static │ ├── css │ │ └── main.css │ └── js │ │ └── main.js └── templates │ ├── base.html │ └── index.html ├── classes.png ├── model.pt ├── sample_train_images.png ├── trafficsign.jpeg ├── train.ipynb ├── tsrpytorch.ipynb └── visualize.ipynb /README.md: -------------------------------------------------------------------------------- 1 | # TrafficSignRecognition_PyTorch 2 | 3 |
4 | Logo 5 |
6 | 7 | Traffic Sign Recognition on GTSRB dataset using PyTorch 8 | 9 | Dataset link: https://www.kaggle.com/meowmeowmeowmeowmeow/gtsrb-german-traffic-sign 10 | 11 | The model achieved 95.70% accuracy 12 | 13 | [![built with love](https://forthebadge.com/images/badges/built-with-love.svg)](https://github.com/debamitr1012/TrafficSignRecognition_PyTorch) 14 | -------------------------------------------------------------------------------- /TrafficSignsWebApp/Figure_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/debamitr1012/TrafficSignRecognition_PyTorch/e3caa0f6c96f60a9deca79212170d6bedc84b58a/TrafficSignsWebApp/Figure_0.png -------------------------------------------------------------------------------- /TrafficSignsWebApp/Figure_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/debamitr1012/TrafficSignRecognition_PyTorch/e3caa0f6c96f60a9deca79212170d6bedc84b58a/TrafficSignsWebApp/Figure_1.png -------------------------------------------------------------------------------- /TrafficSignsWebApp/Traffic_app.py: -------------------------------------------------------------------------------- 1 | from flask import * 2 | import os 3 | from werkzeug.utils import secure_filename 4 | from keras.models import load_model 5 | import numpy as np 6 | from PIL import Image 7 | app = Flask(__name__) 8 | # Classes of trafic signs 9 | classes = { 0:'Speed limit (20km/h)', 10 | 1:'Speed limit (30km/h)', 11 | 2:'Speed limit (50km/h)', 12 | 3:'Speed limit (60km/h)', 13 | 4:'Speed limit (70km/h)', 14 | 5:'Speed limit (80km/h)', 15 | 6:'End of speed limit (80km/h)', 16 | 7:'Speed limit (100km/h)', 17 | 8:'Speed limit (120km/h)', 18 | 9:'No passing', 19 | 10:'No passing veh over 3.5 tons', 20 | 11:'Right-of-way at intersection', 21 | 12:'Priority road', 22 | 13:'Yield', 23 | 14:'Stop', 24 | 15:'No vehicles', 25 | 16:'Vehicle > 3.5 tons prohibited', 26 | 17:'No entry', 27 | 18:'General caution', 28 | 19:'Dangerous curve left', 29 | 20:'Dangerous curve right', 30 | 21:'Double curve', 31 | 22:'Bumpy road', 32 | 23:'Slippery road', 33 | 24:'Road narrows on the right', 34 | 25:'Road work', 35 | 26:'Traffic signals', 36 | 27:'Pedestrians', 37 | 28:'Children crossing', 38 | 29:'Bicycles crossing', 39 | 30:'Beware of ice/snow', 40 | 31:'Wild animals crossing', 41 | 32:'End speed + passing limits', 42 | 33:'Turn right ahead', 43 | 34:'Turn left ahead', 44 | 35:'Ahead only', 45 | 36:'Go straight or right', 46 | 37:'Go straight or left', 47 | 38:'Keep right', 48 | 39:'Keep left', 49 | 40:'Roundabout mandatory', 50 | 41:'End of no passing', 51 | 42:'End no passing vehicle > 3.5 tons' } 52 | def image_processing(img): 53 | model = load_model('./model/TSR.h5') 54 | data=[] 55 | image = Image.open(img) 56 | image = image.resize((30,30)) 57 | data.append(np.array(image)) 58 | X_test=np.array(data) 59 | Y_pred = model.predict_classes(X_test) 60 | return Y_pred 61 | @app.route('/') 62 | def index(): 63 | return render_template('index.html') 64 | @app.route('/predict', methods=['GET', 'POST']) 65 | def upload(): 66 | if request.method == 'POST': 67 | # Get the file from post request 68 | f = request.files['file'] 69 | file_path = secure_filename(f.filename) 70 | f.save(file_path) 71 | # Make prediction 72 | result = image_processing(file_path) 73 | s = [str(i) for i in result] 74 | a = int("".join(s)) 75 | result = "Predicted Traffic🚦Sign is: " +classes[a] 76 | os.remove(file_path) 77 | return result 78 | return None 79 | if __name__ == '__main__': 80 | app.run(debug=True) -------------------------------------------------------------------------------- /TrafficSignsWebApp/main.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import matplotlib.pyplot as plt 4 | import cv2 5 | import tensorflow as tf 6 | from PIL import Image 7 | import os 8 | os.chdir('C:/Users/91983/TrafficSignsWebApp/TrafficSignRecognition') 9 | from sklearn.model_selection import train_test_split 10 | from keras.utils import to_categorical 11 | from keras.models import Sequential, load_model 12 | from keras.layers import Conv2D, MaxPool2D, Dense, Flatten, Dropout 13 | data = [] 14 | labels = [] 15 | classes = 43 16 | cur_path = os.getcwd() 17 | #Retrieving the images and their labels 18 | for i in range(classes): 19 | path = os.path.join(cur_path,'train',str(i)) 20 | images = os.listdir(path) 21 | for a in images: 22 | try: 23 | image = Image.open(path + '\\'+ a) 24 | image = image.resize((30,30)) 25 | image = np.array(image) 26 | #sim = Image.fromarray(image) 27 | data.append(image) 28 | labels.append(i) 29 | except: 30 | print("Error loading image") 31 | #Converting lists into numpy arrays 32 | data = np.array(data) 33 | labels = np.array(labels) 34 | print(data.shape, labels.shape) 35 | #Splitting training and testing dataset 36 | X_train, X_test, y_train, y_test = train_test_split(data, labels, test_size=0.2, random_state=42) 37 | print(X_train.shape, X_test.shape, y_train.shape, y_test.shape) 38 | #Converting the labels into one hot encoding 39 | y_train = to_categorical(y_train, 43) 40 | y_test = to_categorical(y_test, 43) 41 | #Building the model 42 | model = Sequential() 43 | model.add(Conv2D(filters=32, kernel_size=(5,5), activation='relu', input_shape=X_train.shape[1:])) 44 | model.add(Conv2D(filters=32, kernel_size=(5,5), activation='relu')) 45 | model.add(MaxPool2D(pool_size=(2, 2))) 46 | model.add(Dropout(rate=0.25)) 47 | model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu')) 48 | model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu')) 49 | model.add(MaxPool2D(pool_size=(2, 2))) 50 | model.add(Dropout(rate=0.25)) 51 | model.add(Flatten()) 52 | model.add(Dense(256, activation='relu')) 53 | model.add(Dropout(rate=0.5)) 54 | model.add(Dense(43, activation='softmax')) 55 | #Compilation of the model 56 | model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) 57 | epochs = 15 58 | history = model.fit(X_train, y_train, batch_size=32, epochs=epochs, validation_data=(X_test, y_test)) 59 | model.save("my_model.h5") 60 | #plotting graphs for accuracy 61 | plt.figure(0) 62 | plt.plot(history.history['accuracy'], label='training accuracy') 63 | plt.plot(history.history['val_accuracy'], label='val accuracy') 64 | plt.title('Accuracy') 65 | plt.xlabel('epochs') 66 | plt.ylabel('accuracy') 67 | plt.legend() 68 | plt.show() 69 | plt.figure(1) 70 | plt.plot(history.history['loss'], label='training loss') 71 | plt.plot(history.history['val_loss'], label='val loss') 72 | plt.title('Loss') 73 | plt.xlabel('epochs') 74 | plt.ylabel('loss') 75 | plt.legend() 76 | plt.show() 77 | #testing accuracy on test dataset 78 | from sklearn.metrics import accuracy_score 79 | y_test = pd.read_csv('C:/Users/91983/TrafficSignsWebApp/TrafficSignRecognition/Test.csv') 80 | labels = y_test["ClassId"].values 81 | imgs = y_test["Path"].values 82 | data=[] 83 | for img in imgs: 84 | image = Image.open(img) 85 | image = image.resize((30,30)) 86 | data.append(np.array(image)) 87 | X_test=np.array(data) 88 | #pred = model.predict_classes(X_test) 89 | #pred = (model.predict(X_test) > 0.5).astype("int32") 90 | pred=model.predict(X_test) 91 | classes_x=np.argmax(pred,axis=1) 92 | #Accuracy with the test data 93 | from sklearn.metrics import accuracy_score 94 | print(accuracy_score(labels, pred)) 95 | model.save('traffic_classifier.h5') -------------------------------------------------------------------------------- /TrafficSignsWebApp/my_model.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/debamitr1012/TrafficSignRecognition_PyTorch/e3caa0f6c96f60a9deca79212170d6bedc84b58a/TrafficSignsWebApp/my_model.h5 -------------------------------------------------------------------------------- /TrafficSignsWebApp/static/css/main.css: -------------------------------------------------------------------------------- 1 | 2 | .img-preview { 3 | width: 256px; 4 | height: 256px; 5 | position: relative; 6 | border: 5px solid #F8F8F8; 7 | box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.1); 8 | margin-top: 1em; 9 | margin-bottom: 1em; 10 | } 11 | 12 | .img-preview>div { 13 | width: 100%; 14 | height: 100%; 15 | background-size: 256px 256px; 16 | background-repeat: no-repeat; 17 | background-position: center; 18 | } 19 | 20 | input[type="file"] { 21 | display: none; 22 | } 23 | 24 | .upload-label{ 25 | display: inline-block; 26 | padding: 12px 30px; 27 | background: #39D2B4; 28 | color: #fff; 29 | font-size: 1em; 30 | transition: all .4s; 31 | cursor: pointer; 32 | } 33 | 34 | .upload-label:hover{ 35 | background: #34495E; 36 | color: #39D2B4; 37 | } 38 | 39 | .loader { 40 | border: 8px solid #f3f3f3; /* Light grey */ 41 | border-top: 8px solid #3498db; /* Blue */ 42 | border-radius: 50%; 43 | width: 50px; 44 | height: 50px; 45 | animation: spin 1s linear infinite; 46 | } 47 | 48 | @keyframes spin { 49 | 0% { transform: rotate(0deg); } 50 | 100% { transform: rotate(360deg); } 51 | } -------------------------------------------------------------------------------- /TrafficSignsWebApp/static/js/main.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | // Init 3 | $('.image-section').hide(); 4 | $('.loader').hide(); 5 | $('#result').hide(); 6 | 7 | // Upload Preview 8 | function readURL(input) { 9 | if (input.files && input.files[0]) { 10 | var reader = new FileReader(); 11 | reader.onload = function (e) { 12 | $('#imagePreview').css('background-image', 'url(' + e.target.result + ')'); 13 | $('#imagePreview').hide(); 14 | $('#imagePreview').fadeIn(650); 15 | } 16 | reader.readAsDataURL(input.files[0]); 17 | } 18 | } 19 | $("#imageUpload").change(function () { 20 | $('.image-section').show(); 21 | $('#btn-predict').show(); 22 | $('#result').text(''); 23 | $('#result').hide(); 24 | readURL(this); 25 | }); 26 | 27 | // Predict 28 | $('#btn-predict').click(function () { 29 | var form_data = new FormData($('#upload-file')[0]); 30 | 31 | // Show loading animation 32 | $(this).hide(); 33 | $('.loader').show(); 34 | 35 | // Make prediction by calling api /predict 36 | $.ajax({ 37 | type: 'POST', 38 | url: '/predict', 39 | data: form_data, 40 | contentType: false, 41 | cache: false, 42 | processData: false, 43 | async: true, 44 | success: function (data) { 45 | // Get and display the result 46 | $('.loader').hide(); 47 | $('#result').fadeIn(600); 48 | $('#result').text(data); 49 | console.log('Success!'); 50 | }, 51 | }); 52 | }); 53 | 54 | }); -------------------------------------------------------------------------------- /TrafficSignsWebApp/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Traffic Signs🚦 Classification 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 22 |
23 |
{% block content %}{% endblock %}
24 |
25 | 26 | 27 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /TrafficSignsWebApp/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} {% block content %} 2 | 3 |

Upload Traffic Signs🚦

4 | 15 | 16 |
17 | 18 |
19 | 22 | 23 |
24 | 25 | 34 | 35 | 36 | 37 |

38 | 39 |

40 | 41 |
42 | 43 | {% endblock %} -------------------------------------------------------------------------------- /classes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/debamitr1012/TrafficSignRecognition_PyTorch/e3caa0f6c96f60a9deca79212170d6bedc84b58a/classes.png -------------------------------------------------------------------------------- /model.pt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/debamitr1012/TrafficSignRecognition_PyTorch/e3caa0f6c96f60a9deca79212170d6bedc84b58a/model.pt -------------------------------------------------------------------------------- /sample_train_images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/debamitr1012/TrafficSignRecognition_PyTorch/e3caa0f6c96f60a9deca79212170d6bedc84b58a/sample_train_images.png -------------------------------------------------------------------------------- /trafficsign.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/debamitr1012/TrafficSignRecognition_PyTorch/e3caa0f6c96f60a9deca79212170d6bedc84b58a/trafficsign.jpeg -------------------------------------------------------------------------------- /tsrpytorch.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import numpy as np\n", 10 | "import matplotlib.pyplot as plt\n", 11 | "import os\n", 12 | "import time\n", 13 | "from PIL import Image" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 5, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "X = [] \n", 23 | "y = [] \n", 24 | "classes = 43\n", 25 | "current_path = os.getcwd()\n", 26 | "for i in range(classes):\n", 27 | " path = os.path.join(current_path, 'TrafficSignRecognition', 'Train', str(i))\n", 28 | " images = os.listdir(path)\n", 29 | " for img_name in images:\n", 30 | " image = Image.open(path + '\\\\' + img_name)\n", 31 | " image = image.resize((30, 30))\n", 32 | " image = np.array(image)\n", 33 | " X.append(image)\n", 34 | " y.append(i)\n", 35 | "X = np.array(X)\n", 36 | "y = np.array(y)" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 6, 42 | "metadata": {}, 43 | "outputs": [ 44 | { 45 | "data": { 46 | "text/plain": [ 47 | "(39209, 30, 30, 3)" 48 | ] 49 | }, 50 | "execution_count": 6, 51 | "metadata": {}, 52 | "output_type": "execute_result" 53 | } 54 | ], 55 | "source": [ 56 | "X.shape" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": 7, 62 | "metadata": {}, 63 | "outputs": [], 64 | "source": [ 65 | "def train_test_split(data, labels, test_size=0.2, random_state=0):\n", 66 | " np.random.seed(random_state)\n", 67 | " N = labels.shape[0]\n", 68 | " idx = np.random.permutation(N)\n", 69 | " train_size = int(np.ceil((1-test_size)*N))\n", 70 | " X_train = data[idx[:train_size]]\n", 71 | " y_train = labels[idx[:train_size]]\n", 72 | " X_test = data[idx[train_size:]]\n", 73 | " y_test = labels[idx[train_size:]]\n", 74 | " return X_train, X_test, y_train, y_test" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 8, 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "name": "stdout", 84 | "output_type": "stream", 85 | "text": [ 86 | "X_train shape: (31368, 30, 30, 3)\n", 87 | "X_test shape: (7841, 30, 30, 3)\n", 88 | "y_train shape: (31368,)\n", 89 | "y_test shape: (7841,)\n" 90 | ] 91 | } 92 | ], 93 | "source": [ 94 | "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=113)\n", 95 | "print(f\"X_train shape: {X_train.shape}\")\n", 96 | "print(f\"X_test shape: {X_test.shape}\")\n", 97 | "print(f\"y_train shape: {y_train.shape}\")\n", 98 | "print(f\"y_test shape: {y_test.shape}\")" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": 9, 104 | "metadata": {}, 105 | "outputs": [], 106 | "source": [ 107 | "import torch\n", 108 | "import torch.nn as nn\n", 109 | "import torch.nn.functional as F\n", 110 | "import torch.optim as optim\n", 111 | "from torch.utils.data import TensorDataset\n", 112 | "from torch.utils.data import DataLoader" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 11, 118 | "metadata": {}, 119 | "outputs": [], 120 | "source": [ 121 | "class Net(nn.Module):\n", 122 | " def __init__(self):\n", 123 | " super(Net, self).__init__()\n", 124 | " self.conv1 = nn.Conv2d(3, 32, 5) \n", 125 | " self.conv2 = nn.Conv2d(32, 32, 5) \n", 126 | " self.pool1 = nn.MaxPool2d(2,2) \n", 127 | " self.dropout1 = nn.Dropout(0.25) \n", 128 | " self.conv3 = nn.Conv2d(32, 64, 3) \n", 129 | " self.conv4 = nn.Conv2d(64, 64, 3) \n", 130 | " self.pool2 = nn.MaxPool2d(2,2) \n", 131 | " self.dropout2 = nn.Dropout(0.25) \n", 132 | " self.fc1 = nn.Linear(3*3*64,256)\n", 133 | " self.dropout3 = nn.Dropout(0.5) \n", 134 | " self.fc2 = nn.Linear(256, 43) \n", 135 | " def forward(self, x):\n", 136 | " x = F.relu(self.conv1(x))\n", 137 | " x = F.relu(self.conv2(x))\n", 138 | " x = self.pool1(x)\n", 139 | " x = self.dropout1(x)\n", 140 | " x = F.relu(self.conv3(x))\n", 141 | " x = F.relu(self.conv4(x))\n", 142 | " x = self.pool2(x)\n", 143 | " x = self.dropout2(x)\n", 144 | " x = x.view(-1, 3*3*64)\n", 145 | " x = F.relu(self.fc1(x))\n", 146 | " x = self.dropout3(x)\n", 147 | " x = self.fc2(x)\n", 148 | " return x" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": 12, 154 | "metadata": {}, 155 | "outputs": [ 156 | { 157 | "data": { 158 | "text/plain": [ 159 | "Net(\n", 160 | " (conv1): Conv2d(3, 32, kernel_size=(5, 5), stride=(1, 1))\n", 161 | " (conv2): Conv2d(32, 32, kernel_size=(5, 5), stride=(1, 1))\n", 162 | " (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n", 163 | " (dropout1): Dropout(p=0.25, inplace=False)\n", 164 | " (conv3): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1))\n", 165 | " (conv4): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1))\n", 166 | " (pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n", 167 | " (dropout2): Dropout(p=0.25, inplace=False)\n", 168 | " (fc1): Linear(in_features=576, out_features=256, bias=True)\n", 169 | " (dropout3): Dropout(p=0.5, inplace=False)\n", 170 | " (fc2): Linear(in_features=256, out_features=43, bias=True)\n", 171 | ")" 172 | ] 173 | }, 174 | "execution_count": 12, 175 | "metadata": {}, 176 | "output_type": "execute_result" 177 | } 178 | ], 179 | "source": [ 180 | "model = Net()\n", 181 | "model" 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": 13, 187 | "metadata": {}, 188 | "outputs": [], 189 | "source": [ 190 | "criterion = nn.CrossEntropyLoss()\n", 191 | "optimizer = optim.Adam(model.parameters())" 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": 14, 197 | "metadata": {}, 198 | "outputs": [], 199 | "source": [ 200 | "X_train_tensor = torch.from_numpy(np.transpose(X_train, (0, 3, 1, 2))).float()\n", 201 | "y_train_tensor = torch.from_numpy(y_train).long()\n", 202 | "X_val_tensor = torch.from_numpy(np.transpose(X_test, (0, 3, 1, 2))).float()\n", 203 | "y_val_tensor = torch.from_numpy(y_test).long()\n", 204 | "train_data = TensorDataset(X_train_tensor, y_train_tensor)\n", 205 | "val_data = TensorDataset(X_val_tensor, y_val_tensor)\n", 206 | "train_dataloader = DataLoader(dataset=train_data, batch_size=64)\n", 207 | "val_dataloader = DataLoader(dataset=val_data, batch_size=64)\n", 208 | "dataloaders = {'train': train_dataloader, 'val':val_dataloader}\n", 209 | "dataset_sizes = {'train': len(X_train), 'val': len(X_test)}" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": 15, 215 | "metadata": {}, 216 | "outputs": [], 217 | "source": [ 218 | "def train_model(model, criterion, optimizer, dataset_sizes, num_epochs=15):\n", 219 | " since = time.time()\n", 220 | " epoch_loss = []\n", 221 | " epoch_acc = []\n", 222 | " for epoch in range(num_epochs):\n", 223 | " print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n", 224 | " print('-' * 10)\n", 225 | " for phase in ['train', 'val']:\n", 226 | " if phase == 'train':\n", 227 | " model.train() \n", 228 | " else:\n", 229 | " model.eval() \n", 230 | " i = 0\n", 231 | " running_loss = 0.0\n", 232 | " running_corrects = 0\n", 233 | " if phase == 'train':\n", 234 | " print(f'\\rProgress:',end='')\n", 235 | " for inputs, labels in dataloaders[phase]:\n", 236 | " optimizer.zero_grad()\n", 237 | " with torch.set_grad_enabled(phase == 'train'):\n", 238 | " outputs = model(inputs)\n", 239 | " _, preds = torch.max(outputs, 1)\n", 240 | " loss = criterion(outputs, labels)\n", 241 | " if phase == 'train':\n", 242 | " loss.backward()\n", 243 | " optimizer.step()\n", 244 | " running_loss += loss.item()\n", 245 | " running_corrects += torch.sum(preds == labels.data)\n", 246 | " if phase == 'train' and i % 50 == 49:\n", 247 | " print(f\"\\rProgress: [{'='*((i+1)//50)}] \",end='')\n", 248 | " i += 1 \n", 249 | " epoch_loss.append(running_loss / dataset_sizes[phase])\n", 250 | " epoch_acc.append(running_corrects.numpy() / dataset_sizes[phase])\n", 251 | " print('{} Loss: {:.4f} Acc: {:.4f}'.format(\n", 252 | " phase, epoch_loss[-1], epoch_acc[-1]))\n", 253 | " print()\n", 254 | " time_elapsed = time.time() - since\n", 255 | " print('Training complete in {:.0f}m {:.0f}s'.format(\n", 256 | " time_elapsed // 60, time_elapsed % 60))\n", 257 | " return epoch_loss, epoch_acc" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": 16, 263 | "metadata": {}, 264 | "outputs": [ 265 | { 266 | "name": "stdout", 267 | "output_type": "stream", 268 | "text": [ 269 | "Epoch 0/14\n", 270 | "----------\n", 271 | "Progress: [=========] train Loss: 0.0293 Acc: 0.4941\n", 272 | "val Loss: 0.0067 Acc: 0.9066\n", 273 | "\n", 274 | "Epoch 1/14\n", 275 | "----------\n", 276 | "Progress: [=========] train Loss: 0.0088 Acc: 0.8394\n", 277 | "val Loss: 0.0031 Acc: 0.9597\n", 278 | "\n", 279 | "Epoch 2/14\n", 280 | "----------\n", 281 | "Progress: [=========] train Loss: 0.0056 Acc: 0.8991\n", 282 | "val Loss: 0.0020 Acc: 0.9699\n", 283 | "\n", 284 | "Epoch 3/14\n", 285 | "----------\n", 286 | "Progress: [=========] train Loss: 0.0043 Acc: 0.9242\n", 287 | "val Loss: 0.0017 Acc: 0.9774\n", 288 | "\n", 289 | "Epoch 4/14\n", 290 | "----------\n", 291 | "Progress: [=========] train Loss: 0.0036 Acc: 0.9362\n", 292 | "val Loss: 0.0013 Acc: 0.9779\n", 293 | "\n", 294 | "Epoch 5/14\n", 295 | "----------\n", 296 | "Progress: [=========] train Loss: 0.0031 Acc: 0.9426\n", 297 | "val Loss: 0.0008 Acc: 0.9889\n", 298 | "\n", 299 | "Epoch 6/14\n", 300 | "----------\n", 301 | "Progress: [=========] train Loss: 0.0029 Acc: 0.9477\n", 302 | "val Loss: 0.0007 Acc: 0.9904\n", 303 | "\n", 304 | "Epoch 7/14\n", 305 | "----------\n", 306 | "Progress: [=========] train Loss: 0.0031 Acc: 0.9453\n", 307 | "val Loss: 0.0008 Acc: 0.9879\n", 308 | "\n", 309 | "Epoch 8/14\n", 310 | "----------\n", 311 | "Progress: [=========] train Loss: 0.0029 Acc: 0.9483\n", 312 | "val Loss: 0.0007 Acc: 0.9898\n", 313 | "\n", 314 | "Epoch 9/14\n", 315 | "----------\n", 316 | "Progress: [=========] train Loss: 0.0025 Acc: 0.9545\n", 317 | "val Loss: 0.0009 Acc: 0.9870\n", 318 | "\n", 319 | "Epoch 10/14\n", 320 | "----------\n", 321 | "Progress: [=========] train Loss: 0.0025 Acc: 0.9565\n", 322 | "val Loss: 0.0008 Acc: 0.9867\n", 323 | "\n", 324 | "Epoch 11/14\n", 325 | "----------\n", 326 | "Progress: [=========] train Loss: 0.0025 Acc: 0.9558\n", 327 | "val Loss: 0.0008 Acc: 0.9875\n", 328 | "\n", 329 | "Epoch 12/14\n", 330 | "----------\n", 331 | "Progress: [=========] train Loss: 0.0025 Acc: 0.9566\n", 332 | "val Loss: 0.0006 Acc: 0.9893\n", 333 | "\n", 334 | "Epoch 13/14\n", 335 | "----------\n", 336 | "Progress: [=========] train Loss: 0.0026 Acc: 0.9555\n", 337 | "val Loss: 0.0006 Acc: 0.9909\n", 338 | "\n", 339 | "Epoch 14/14\n", 340 | "----------\n", 341 | "Progress: [=========] train Loss: 0.0022 Acc: 0.9611\n", 342 | "val Loss: 0.0006 Acc: 0.9889\n", 343 | "\n", 344 | "Training complete in 13m 32s\n" 345 | ] 346 | } 347 | ], 348 | "source": [ 349 | "epoch_loss, epoch_acc = train_model(model, criterion, optimizer, dataset_sizes, num_epochs=15)" 350 | ] 351 | }, 352 | { 353 | "cell_type": "code", 354 | "execution_count": 17, 355 | "metadata": {}, 356 | "outputs": [], 357 | "source": [ 358 | "accuracy = epoch_acc[::2]\n", 359 | "val_accuracy = epoch_acc[1::2]\n", 360 | "loss = epoch_loss[::2]\n", 361 | "val_loss = epoch_loss[1::2]" 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "execution_count": 18, 367 | "metadata": {}, 368 | "outputs": [ 369 | { 370 | "data": { 371 | "text/plain": [ 372 | "" 373 | ] 374 | }, 375 | "execution_count": 18, 376 | "metadata": {}, 377 | "output_type": "execute_result" 378 | }, 379 | { 380 | "data": { 381 | "image/png": "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57zzziM9PZ309HT69evHrl27GDJkSKttpk2bFimbNGkSmzdvJicnh5EjR0Yq39mzZzNv3ryDjt/Y2MiSJUv4wx/+QG5uLieffDJLly7l/PPP56233mL+/PkA+Hw+evfuzfz587nkkksoKCgAoE+fPof9uadNm9aq7/4DDzzAokWLANi6dStffvklgUCAM844I7Jdy3GvvvpqZs2axa233srjjz/Oj370o8N+X1fyZCIorQgysiCHFJue0pgul519oBPGr3/9a84++2wWLVrE5s2bOeuss9rdJz09PbLs8/kIhUJHtU1Hli5dSlVVFRMmTACgtraWzMxMzj///E4fA8Dv90camsPhcKtG8eif+5133uGNN97gww8/JCsri7POOuuQffuHDh1K//79eeutt/j444959tlnjyiuY+XJXkNlNj2lMd2iurqawYMHA/Dkk092+fHHjh3Lxo0b2bx5MwDPPfdcu9stWLCARx99lM2bN7N582Y2bdrE66+/Tm1tLeeccw4PPfQQAM3NzVRXV/P1r3+dF154gcrKSoDIraHhw4ezYsUKABYvXtzhFU51dTX5+flkZWWxYcMGPvroIwBOOeUU3n33XTZt2tTquADXXHMNV1xxRasrqu7iuURQ19jMtiqbntKY7vDzn/+cX/ziF0yePPmIzuA7KzMzkz/96U/MmDGDqVOnkpubS+/evVttU1tby2uvvcZ5550XKcvOzua0007jlVde4f777+ftt99mwoQJTJ06lfXr1zN+/Hh++ctfcuaZZ1JUVMTtt98OwLXXXsuyZcsoKiriww8/bHUVEG3GjBmEQiFOPPFE7rjjDk455RQACgsLmTdvHt/73vcoKiri0ksvjewzc+ZMgsFgt98WAhBV7fYvPRbFxcVaUlJy1Puv217NeQ+8z4OXT+G8iQO7MDJjutdnn33GiSeeGO8w4i4YDJKTk4OqcuONNzJ69Ghuu+22eId1xEpKSrjtttt47733jvlY7f1uiMgKVW23z67nrghaegzZw2TG9AyPPPIIkyZNYvz48VRXV3P99dfHO6Qjdu+993LRRRfxu9/9Li7f77nG4rLAflIEhve1RGBMT3Dbbbcl5RVAtDvuuIM77rgjbt/vuSuCsoogQ/tk2fSUxhjj8lwisMHmjDGmNU8lgsj0lNZ11BhjIjyVCLbuqaWxOWxXBMYYE8VT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", 382 | "text/plain": [ 383 | "
" 384 | ] 385 | }, 386 | "metadata": { 387 | "needs_background": "light" 388 | }, 389 | "output_type": "display_data" 390 | } 391 | ], 392 | "source": [ 393 | "plt.figure()\n", 394 | "plt.plot(accuracy, label = 'Training Accuracy')\n", 395 | "plt.plot(val_accuracy, label = 'Validation Accuracy')\n", 396 | "plt.title('Accuray')\n", 397 | "plt.xlabel('epochs')\n", 398 | "plt.ylabel('accuracy')\n", 399 | "plt.legend()" 400 | ] 401 | }, 402 | { 403 | "cell_type": "code", 404 | "execution_count": 19, 405 | "metadata": {}, 406 | "outputs": [ 407 | { 408 | "data": { 409 | "text/plain": [ 410 | "" 411 | ] 412 | }, 413 | "execution_count": 19, 414 | "metadata": {}, 415 | "output_type": "execute_result" 416 | }, 417 | { 418 | "data": { 419 | "image/png": "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2W+b2bNnU1paSkZGBtOnT2fDhg289tprlJeXtz8T0ZvgWL58OSeffDKxWIxoNMq5557LM888Q3l5OevWreMLX/gCv//97yksDH6RPfroozn33HO56667ujwFlwxqcXSjvCRokq6r2p3iSkTST19aBsmSl5fXPv3d736XOXPm8OCDD7JhwwZOPvnkTvfJzs5un45EIjQ3N/dpm/4watQoXnjhBR577DF+/vOfc99993Hrrbfy8MMP88wzz/Db3/6Wa6+9lpdeemlAAkQtjm6MyIowbuQItThEhpCamhrGjRsHwG233dbvxz/iiCNYt24dGzZsAODee+9NeN/Zs2fzpz/9ia1bt9LS0sI999zDSSedxNatW2ltbeXMM8/kmmuuYdWqVbS2trJx40bmzJnD9ddfT01NDbt2Dcx3lVocPSiP5anFITKEfOMb3+CCCy7gmmuu4dRTT+33448YMYKf/vSnzJs3j7y8PGbNmtXltk888QSlpaXt87/+9a+57rrrmDNnDu7Oqaeeyvz583nhhRf49Kc/TWtrKwA/+MEPaGlp4bzzzqOmpgZ354tf/CIjR47s98/TGWu7C2Aomzlzpvd1IKerlq7h1ys28vL3/4+eiBXpwauvvsp73vOeVJeRcrt27SI/Px9353Of+xyTJk3isssuS3VZ3ers787MVrr7fvco61RVDypieexubGHLzoZUlyIiaeLmm29m+vTpHHXUUdTU1PCZz3wm1SX1K52q6kF5LLhA/kbVLg4uyklxNSKSDi677LJB38I4EGpx9KAiLjhERETB0aODCrPJy4roArmISEjB0QMzozyWrxaHiEhIwZGACt2SKyLSTsGRgPJYPpt27KGuMTlPhYpI/5gzZw6PPfbYPst+9KMfcemll3a5z8knn0zb7fof/ehHO+3z6aqrruKGG27o9mc/9NBDvPLKK+3zV155JY8//ngvqu9cfOeLg4WCIwFtF8jXb1WrQ2QwW7RoEUuWLNln2ZIlSxLuL+qRRx7p80N0HYPj6quv5kMf+lCfjjXYKTgSsLezQwWHyGC2YMECHn74YRobGwHYsGEDmzdv5sQTT+TSSy9l5syZHHXUUXzve9/rdP+ysjK2bt0KwLXXXsvhhx/O+9///vau1yF4RmPWrFlMmzaNM888k7q6Op599lmWLl3K17/+daZPn84bb7zB4sWLuf/+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", 420 | "text/plain": [ 421 | "
" 422 | ] 423 | }, 424 | "metadata": { 425 | "needs_background": "light" 426 | }, 427 | "output_type": "display_data" 428 | } 429 | ], 430 | "source": [ 431 | "plt.figure()\n", 432 | "plt.plot(loss, label = 'Training Loss')\n", 433 | "plt.plot(val_loss, label = 'Validation Loss')\n", 434 | "plt.title('Loss')\n", 435 | "plt.xlabel('epochs')\n", 436 | "plt.ylabel('loss')\n", 437 | "plt.legend()" 438 | ] 439 | }, 440 | { 441 | "cell_type": "code", 442 | "execution_count": 26, 443 | "metadata": {}, 444 | "outputs": [], 445 | "source": [ 446 | "torch.save(model.state_dict(), 'model.pt')" 447 | ] 448 | }, 449 | { 450 | "cell_type": "code", 451 | "execution_count": 22, 452 | "metadata": {}, 453 | "outputs": [], 454 | "source": [ 455 | "N = 5000\n", 456 | "import pandas as pd\n", 457 | "current_path = os.getcwd()\n", 458 | "test_model_data = pd.read_csv(open(os.path.join(current_path, 'TrafficSignRecognition', 'Test.csv'), \"rb\"))\n", 459 | "y_test_labels = test_model_data['ClassId'][:N]\n", 460 | "img_paths = test_model_data['Path'][:N]\n", 461 | "x_test_labels = []\n", 462 | "for img in img_paths:\n", 463 | " image = Image.open(os.path.join(current_path, 'TrafficSignRecognition',img))\n", 464 | " image = image.resize((30,30))\n", 465 | " x_test_labels.append(np.array(image))\n", 466 | "x_test_labels = np.array(x_test_labels)" 467 | ] 468 | }, 469 | { 470 | "cell_type": "code", 471 | "execution_count": 23, 472 | "metadata": {}, 473 | "outputs": [], 474 | "source": [ 475 | "X_test_labels_tensor = torch.from_numpy(np.transpose(x_test_labels, (0, 3, 1, 2))).float()\n", 476 | "y_test_labels_tensor = torch.from_numpy(y_test_labels.values).long()" 477 | ] 478 | }, 479 | { 480 | "cell_type": "code", 481 | "execution_count": 24, 482 | "metadata": {}, 483 | "outputs": [ 484 | { 485 | "name": "stdout", 486 | "output_type": "stream", 487 | "text": [ 488 | "95.70%\n" 489 | ] 490 | } 491 | ], 492 | "source": [ 493 | "model.eval()\n", 494 | "y_test_outputs = model(X_test_labels_tensor)\n", 495 | "_, y_test_preds = torch.max(y_test_outputs, 1)\n", 496 | "acc = torch.sum(y_test_preds == y_test_labels_tensor.data).float()/len(y_test_labels)\n", 497 | "print(f\"{acc:.2%}\")" 498 | ] 499 | } 500 | ], 501 | "metadata": { 502 | "interpreter": { 503 | "hash": "b529c6bed313b112a2bdc274fe95ed48478553dddbcd7bb656e7813927f6331f" 504 | }, 505 | "kernelspec": { 506 | "display_name": "Python 3.9.0 64-bit", 507 | "language": "python", 508 | "name": "python3" 509 | }, 510 | "language_info": { 511 | "codemirror_mode": { 512 | "name": "ipython", 513 | "version": 3 514 | }, 515 | "file_extension": ".py", 516 | "mimetype": "text/x-python", 517 | "name": "python", 518 | "nbconvert_exporter": "python", 519 | "pygments_lexer": "ipython3", 520 | "version": "3.9.0" 521 | }, 522 | "orig_nbformat": 4 523 | }, 524 | "nbformat": 4, 525 | "nbformat_minor": 2 526 | } 527 | --------------------------------------------------------------------------------