├── 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 |

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 | [](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 |
24 |
25 |
26 |
30 |
31 |
32 |
33 |
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 |
--------------------------------------------------------------------------------