└── Traffic_sign_classification_with_keras.ipynb /Traffic_sign_classification_with_keras.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "HmRAX2GJiWL9" 8 | }, 9 | "source": [ 10 | "# Traffic Sign Classification with Keras\n", 11 | "\n" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 1, 17 | "metadata": { 18 | "colab": { 19 | "base_uri": "https://localhost:8080/", 20 | "height": 70 21 | }, 22 | "colab_type": "code", 23 | "executionInfo": { 24 | "elapsed": 9633, 25 | "status": "ok", 26 | "timestamp": 1554301404602, 27 | "user": { 28 | "displayName": "Prashant Sahu", 29 | "photoUrl": "https://lh3.googleusercontent.com/-ompx6lyKrkc/AAAAAAAAAAI/AAAAAAAAALk/kbQk9IjXg44/s64/photo.jpg", 30 | "userId": "17861245123904241513" 31 | }, 32 | "user_tz": -330 33 | }, 34 | "id": "yYOwSaC6iWMK", 35 | "outputId": "81aa55dd-3cb5-42b0-c41b-94e72bbb0866" 36 | }, 37 | "outputs": [ 38 | { 39 | "name": "stderr", 40 | "output_type": "stream", 41 | "text": [ 42 | "Train Dataset: 120MB [00:06, 17.2MB/s] \n", 43 | "Test Dataset: 38.8MB [00:01, 30.4MB/s] " 44 | ] 45 | }, 46 | { 47 | "name": "stdout", 48 | "output_type": "stream", 49 | "text": [ 50 | "Training and Test data downloaded.\n" 51 | ] 52 | }, 53 | { 54 | "name": "stderr", 55 | "output_type": "stream", 56 | "text": [ 57 | "\n" 58 | ] 59 | } 60 | ], 61 | "source": [ 62 | "from urllib.request import urlretrieve\n", 63 | "from os.path import isfile\n", 64 | "from tqdm import tqdm\n", 65 | "\n", 66 | "class DLProgress(tqdm):\n", 67 | " last_block = 0\n", 68 | "\n", 69 | " def hook(self, block_num=1, block_size=1, total_size=None):\n", 70 | " self.total = total_size\n", 71 | " self.update((block_num - self.last_block) * block_size)\n", 72 | " self.last_block = block_num\n", 73 | "\n", 74 | "if not isfile('train.p'):\n", 75 | " with DLProgress(unit='B', unit_scale=True, miniters=1, desc='Train Dataset') as pbar:\n", 76 | " urlretrieve(\n", 77 | " 'https://s3.amazonaws.com/udacity-sdc/datasets/german_traffic_sign_benchmark/train.p',\n", 78 | " 'train.p',\n", 79 | " pbar.hook)\n", 80 | "\n", 81 | "if not isfile('test.p'):\n", 82 | " with DLProgress(unit='B', unit_scale=True, miniters=1, desc='Test Dataset') as pbar:\n", 83 | " urlretrieve(\n", 84 | " 'https://s3.amazonaws.com/udacity-sdc/datasets/german_traffic_sign_benchmark/test.p',\n", 85 | " 'test.p',\n", 86 | " pbar.hook)\n", 87 | "\n", 88 | "print('Training and Test data downloaded.')" 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": { 94 | "colab_type": "text", 95 | "id": "6VOF9K3-iWM9" 96 | }, 97 | "source": [ 98 | "## Overview\n", 99 | "\n", 100 | "Here are the steps you'll take to build the network:\n", 101 | "\n", 102 | "1. Load the training data.\n", 103 | "2. Preprocess the data.\n", 104 | "3. Build a feedforward neural network to classify traffic signs.\n", 105 | "4. Build a convolutional neural network to classify traffic signs.\n", 106 | "5. Evaluate the final neural network on testing data.\n" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": 0, 112 | "metadata": { 113 | "colab": {}, 114 | "colab_type": "code", 115 | "id": "ucpK74jfiWNA" 116 | }, 117 | "outputs": [], 118 | "source": [ 119 | "import pickle\n", 120 | "import numpy as np\n", 121 | "import math" 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "metadata": { 127 | "colab_type": "text", 128 | "id": "RKYG2116iWNm" 129 | }, 130 | "source": [ 131 | "## Load the Data\n", 132 | "\n", 133 | "Start by importing the data from the pickle file." 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": 16, 139 | "metadata": { 140 | "colab": { 141 | "base_uri": "https://localhost:8080/", 142 | "height": 34 143 | }, 144 | "colab_type": "code", 145 | "executionInfo": { 146 | "elapsed": 1758, 147 | "status": "ok", 148 | "timestamp": 1554306601315, 149 | "user": { 150 | "displayName": "Prashant Sahu", 151 | "photoUrl": "https://lh3.googleusercontent.com/-ompx6lyKrkc/AAAAAAAAAAI/AAAAAAAAALk/kbQk9IjXg44/s64/photo.jpg", 152 | "userId": "17861245123904241513" 153 | }, 154 | "user_tz": -330 155 | }, 156 | "id": "JRNls9WhiWNo", 157 | "outputId": "7d30d97a-9189-40f5-8d41-70dbe2efcc9f" 158 | }, 159 | "outputs": [ 160 | { 161 | "data": { 162 | "text/plain": [ 163 | "dict" 164 | ] 165 | }, 166 | "execution_count": 16, 167 | "metadata": { 168 | "tags": [] 169 | }, 170 | "output_type": "execute_result" 171 | } 172 | ], 173 | "source": [ 174 | "with open('train.p', 'rb') as f:\n", 175 | " data = pickle.load(f)\n", 176 | "\n", 177 | "type(data)" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 17, 183 | "metadata": { 184 | "colab": { 185 | "base_uri": "https://localhost:8080/", 186 | "height": 34 187 | }, 188 | "colab_type": "code", 189 | "executionInfo": { 190 | "elapsed": 2748, 191 | "status": "ok", 192 | "timestamp": 1554306654781, 193 | "user": { 194 | "displayName": "Prashant Sahu", 195 | "photoUrl": "https://lh3.googleusercontent.com/-ompx6lyKrkc/AAAAAAAAAAI/AAAAAAAAALk/kbQk9IjXg44/s64/photo.jpg", 196 | "userId": "17861245123904241513" 197 | }, 198 | "user_tz": -330 199 | }, 200 | "id": "3jvvZfXS5ChS", 201 | "outputId": "c4e1e5b4-e856-40de-c2ca-ee089a561b65" 202 | }, 203 | "outputs": [ 204 | { 205 | "name": "stdout", 206 | "output_type": "stream", 207 | "text": [ 208 | "dict_keys(['features', 'labels'])\n" 209 | ] 210 | } 211 | ], 212 | "source": [ 213 | "print(data.keys())\n", 214 | "\n" 215 | ] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "execution_count": 28, 220 | "metadata": { 221 | "colab": { 222 | "base_uri": "https://localhost:8080/", 223 | "height": 87 224 | }, 225 | "colab_type": "code", 226 | "executionInfo": { 227 | "elapsed": 3479, 228 | "status": "ok", 229 | "timestamp": 1554306993006, 230 | "user": { 231 | "displayName": "Prashant Sahu", 232 | "photoUrl": "https://lh3.googleusercontent.com/-ompx6lyKrkc/AAAAAAAAAAI/AAAAAAAAALk/kbQk9IjXg44/s64/photo.jpg", 233 | "userId": "17861245123904241513" 234 | }, 235 | "user_tz": -330 236 | }, 237 | "id": "yzspuoof5Njs", 238 | "outputId": "dc36535c-ad64-4b00-de27-a6b56c520d45" 239 | }, 240 | "outputs": [ 241 | { 242 | "name": "stdout", 243 | "output_type": "stream", 244 | "text": [ 245 | "(39209, 32, 32, 3)\n", 246 | "(39209,)\n", 247 | "42\n" 248 | ] 249 | }, 250 | { 251 | "data": { 252 | "text/plain": [ 253 | "numpy.ndarray" 254 | ] 255 | }, 256 | "execution_count": 28, 257 | "metadata": { 258 | "tags": [] 259 | }, 260 | "output_type": "execute_result" 261 | } 262 | ], 263 | "source": [ 264 | "# TODO: Load the feature data to the variable X_train\n", 265 | "X_train = data['features']\n", 266 | "# TODO: Load the label data to the variable y_train\n", 267 | "y_train = data['labels']\n", 268 | "\n", 269 | "print(X_train.shape)\n", 270 | "print(y_train.shape)\n", 271 | "print(y_train[-1])\n", 272 | "type(X_train)" 273 | ] 274 | }, 275 | { 276 | "cell_type": "markdown", 277 | "metadata": { 278 | "colab_type": "text", 279 | "id": "ipKB7hRxiWOM" 280 | }, 281 | "source": [ 282 | "## Preprocess the Data\n", 283 | "\n", 284 | "1. Shuffle the data\n", 285 | "2. Normalize the features using Min-Max scaling between -0.5 and 0.5\n", 286 | "3. One-Hot Encode the labels\n", 287 | "\n", 288 | "### Shuffle the data\n", 289 | "Hint: You can use the [scikit-learn shuffle](http://scikit-learn.org/stable/modules/generated/sklearn.utils.shuffle.html) function to shuffle the data." 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": 0, 295 | "metadata": { 296 | "colab": {}, 297 | "colab_type": "code", 298 | "id": "mvDsurqQiWOQ" 299 | }, 300 | "outputs": [], 301 | "source": [ 302 | "# TODO: Shuffle the data\n", 303 | "from sklearn.utils import shuffle\n", 304 | "X_train, y_train = shuffle(X_train, y_train)" 305 | ] 306 | }, 307 | { 308 | "cell_type": "code", 309 | "execution_count": 32, 310 | "metadata": { 311 | "colab": { 312 | "base_uri": "https://localhost:8080/", 313 | "height": 52 314 | }, 315 | "colab_type": "code", 316 | "executionInfo": { 317 | "elapsed": 1128, 318 | "status": "ok", 319 | "timestamp": 1554307202198, 320 | "user": { 321 | "displayName": "Prashant Sahu", 322 | "photoUrl": "https://lh3.googleusercontent.com/-ompx6lyKrkc/AAAAAAAAAAI/AAAAAAAAALk/kbQk9IjXg44/s64/photo.jpg", 323 | "userId": "17861245123904241513" 324 | }, 325 | "user_tz": -330 326 | }, 327 | "id": "jmWzxc5W7JvV", 328 | "outputId": "939773c7-e69e-46d2-fd93-09801a385d37" 329 | }, 330 | "outputs": [ 331 | { 332 | "name": "stdout", 333 | "output_type": "stream", 334 | "text": [ 335 | "5\n", 336 | "1\n" 337 | ] 338 | } 339 | ], 340 | "source": [ 341 | "print(y_train[0]) # label for the 1st image\n", 342 | "print(y_train[-1]) # label for the last image" 343 | ] 344 | }, 345 | { 346 | "cell_type": "markdown", 347 | "metadata": { 348 | "colab_type": "text", 349 | "id": "TK-uxRWYiWPA" 350 | }, 351 | "source": [ 352 | "### Normalize the features\n" 353 | ] 354 | }, 355 | { 356 | "cell_type": "code", 357 | "execution_count": 0, 358 | "metadata": { 359 | "colab": {}, 360 | "colab_type": "code", 361 | "id": "bUxhfrIpiWPC" 362 | }, 363 | "outputs": [], 364 | "source": [ 365 | "# TODO: Normalize the data features to the variable X_normalized\n", 366 | "X_min = 0\n", 367 | "X_max = 255\n", 368 | "a = -0.5\n", 369 | "b = 0.5\n", 370 | "X_normalized = a + ((X_train - X_min)*(b-a)/ (X_max - X_min))\n" 371 | ] 372 | }, 373 | { 374 | "cell_type": "code", 375 | "execution_count": 34, 376 | "metadata": { 377 | "colab": { 378 | "base_uri": "https://localhost:8080/", 379 | "height": 879 380 | }, 381 | "colab_type": "code", 382 | "executionInfo": { 383 | "elapsed": 1364, 384 | "status": "ok", 385 | "timestamp": 1554307441319, 386 | "user": { 387 | "displayName": "Prashant Sahu", 388 | "photoUrl": "https://lh3.googleusercontent.com/-ompx6lyKrkc/AAAAAAAAAAI/AAAAAAAAALk/kbQk9IjXg44/s64/photo.jpg", 389 | "userId": "17861245123904241513" 390 | }, 391 | "user_tz": -330 392 | }, 393 | "id": "uvgfwSmK8Rym", 394 | "outputId": "b85b9fc6-5609-413b-9ad8-82e688f169bb" 395 | }, 396 | "outputs": [ 397 | { 398 | "name": "stdout", 399 | "output_type": "stream", 400 | "text": [ 401 | "[[[-0.40980392 -0.4254902 -0.42941176]\n", 402 | " [-0.39803922 -0.41372549 -0.40980392]\n", 403 | " [-0.37843137 -0.39411765 -0.39803922]\n", 404 | " ...\n", 405 | " [-0.34313725 -0.37843137 -0.39019608]\n", 406 | " [-0.34313725 -0.37058824 -0.39019608]\n", 407 | " [-0.33921569 -0.3627451 -0.38627451]]\n", 408 | "\n", 409 | " [[-0.40980392 -0.4254902 -0.42941176]\n", 410 | " [-0.40196078 -0.41372549 -0.40588235]\n", 411 | " [-0.38627451 -0.39803922 -0.39803922]\n", 412 | " ...\n", 413 | " [-0.34313725 -0.3745098 -0.38627451]\n", 414 | " [-0.33921569 -0.36666667 -0.38627451]\n", 415 | " [-0.32745098 -0.35490196 -0.38235294]]\n", 416 | "\n", 417 | " [[-0.40588235 -0.4254902 -0.42941176]\n", 418 | " [-0.40980392 -0.42156863 -0.41764706]\n", 419 | " [-0.39019608 -0.39803922 -0.40196078]\n", 420 | " ...\n", 421 | " [-0.33921569 -0.37058824 -0.38627451]\n", 422 | " [-0.32745098 -0.35490196 -0.3745098 ]\n", 423 | " [-0.30392157 -0.33921569 -0.36666667]]\n", 424 | "\n", 425 | " ...\n", 426 | "\n", 427 | " [[-0.32352941 -0.37058824 -0.39803922]\n", 428 | " [-0.34313725 -0.3745098 -0.39803922]\n", 429 | " [-0.35882353 -0.3745098 -0.39411765]\n", 430 | " ...\n", 431 | " [-0.30392157 -0.33921569 -0.3627451 ]\n", 432 | " [-0.3 -0.33921569 -0.36666667]\n", 433 | " [-0.30392157 -0.34313725 -0.37843137]]\n", 434 | "\n", 435 | " [[-0.31960784 -0.36666667 -0.39019608]\n", 436 | " [-0.34705882 -0.37843137 -0.40196078]\n", 437 | " [-0.3627451 -0.38235294 -0.40196078]\n", 438 | " ...\n", 439 | " [-0.31176471 -0.34313725 -0.37058824]\n", 440 | " [-0.30784314 -0.34313725 -0.37058824]\n", 441 | " [-0.30392157 -0.33921569 -0.36666667]]\n", 442 | "\n", 443 | " [[-0.32745098 -0.36666667 -0.39019608]\n", 444 | " [-0.34313725 -0.3745098 -0.39803922]\n", 445 | " [-0.3627451 -0.39019608 -0.41372549]\n", 446 | " ...\n", 447 | " [-0.31176471 -0.34705882 -0.38235294]\n", 448 | " [-0.31176471 -0.34313725 -0.37058824]\n", 449 | " [-0.31960784 -0.35098039 -0.37058824]]]\n" 450 | ] 451 | } 452 | ], 453 | "source": [ 454 | "print(X_normalized[0])" 455 | ] 456 | }, 457 | { 458 | "cell_type": "markdown", 459 | "metadata": { 460 | "colab_type": "text", 461 | "id": "jaKe_6y6iWP3" 462 | }, 463 | "source": [ 464 | "### One-Hot Encode the labels\n", 465 | "Hint: You can use the [scikit-learn LabelBinarizer](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.LabelBinarizer.html) function to one-hot encode the labels." 466 | ] 467 | }, 468 | { 469 | "cell_type": "code", 470 | "execution_count": 0, 471 | "metadata": { 472 | "colab": {}, 473 | "colab_type": "code", 474 | "id": "I-Pg60_hiWP_" 475 | }, 476 | "outputs": [], 477 | "source": [ 478 | "# TODO: One Hot encode the labels to the variable y_one_hot\n", 479 | "from sklearn import preprocessing \n", 480 | "lb = preprocessing.LabelBinarizer()\n", 481 | "lb.fit(y_train)\n", 482 | "y_one_hot =lb.transform(y_train)" 483 | ] 484 | }, 485 | { 486 | "cell_type": "code", 487 | "execution_count": 38, 488 | "metadata": { 489 | "colab": { 490 | "base_uri": "https://localhost:8080/", 491 | "height": 52 492 | }, 493 | "colab_type": "code", 494 | "executionInfo": { 495 | "elapsed": 1272, 496 | "status": "ok", 497 | "timestamp": 1554307890173, 498 | "user": { 499 | "displayName": "Prashant Sahu", 500 | "photoUrl": "https://lh3.googleusercontent.com/-ompx6lyKrkc/AAAAAAAAAAI/AAAAAAAAALk/kbQk9IjXg44/s64/photo.jpg", 501 | "userId": "17861245123904241513" 502 | }, 503 | "user_tz": -330 504 | }, 505 | "id": "4c9JtSfr90Zq", 506 | "outputId": "f410fe10-9652-4f8c-d157-e37b2a86bdab" 507 | }, 508 | "outputs": [ 509 | { 510 | "data": { 511 | "text/plain": [ 512 | "array([0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", 513 | " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])" 514 | ] 515 | }, 516 | "execution_count": 38, 517 | "metadata": { 518 | "tags": [] 519 | }, 520 | "output_type": "execute_result" 521 | } 522 | ], 523 | "source": [ 524 | "y_one_hot[-1]" 525 | ] 526 | }, 527 | { 528 | "cell_type": "markdown", 529 | "metadata": { 530 | "colab_type": "text", 531 | "id": "Y4JUdA05iWQX" 532 | }, 533 | "source": [ 534 | "## Keras Sequential Model\n", 535 | "```python\n", 536 | "from keras.models import Sequential\n", 537 | "\n", 538 | "# Create the Sequential model\n", 539 | "model = Sequential()\n", 540 | "```\n", 541 | "The `keras.models.Sequential` class is a wrapper for the neural network model. Just like many of the class models in scikit-learn, it provides common functions like `fit()`, `evaluate()`, and `compile()`. We'll cover these functions as we get to them. Let's start looking at the layers of the model.\n", 542 | "\n", 543 | "## Keras Layer\n", 544 | "A Keras layer is just like a neural network layer. It can be fully connected, max pool, activation, etc. You can add a layer to the model using the model's `add()` function. For example, a simple model would look like this:\n", 545 | "```python\n", 546 | "from keras.models import Sequential\n", 547 | "from keras.layers.core import Dense, Activation, Flatten\n", 548 | "\n", 549 | "# Create the Sequential model\n", 550 | "model = Sequential()\n", 551 | "\n", 552 | "# 1st Layer - Add a flatten layer\n", 553 | "model.add(Flatten(input_shape=(32, 32, 3)))\n", 554 | "\n", 555 | "# 2nd Layer - Add a fully connected layer\n", 556 | "model.add(Dense(100))\n", 557 | "\n", 558 | "# 3rd Layer - Add a ReLU activation layer\n", 559 | "model.add(Activation('relu'))\n", 560 | "\n", 561 | "# 4th Layer - Add a fully connected layer\n", 562 | "model.add(Dense(60))\n", 563 | "\n", 564 | "# 5th Layer - Add a ReLU activation layer\n", 565 | "model.add(Activation('relu'))\n", 566 | "```\n", 567 | "Keras will automatically infer the shape of all layers after the first layer. This means you only have to set the input dimensions for the first layer.\n", 568 | "\n", 569 | "The first layer from above, `model.add(Flatten(input_shape=(32, 32, 3)))`, sets the input dimension to (32, 32, 3) and output dimension to (3072=32\\*32\\*3). The second layer takes in the output of the first layer and sets the output dimenions to (100). This chain of passing output to the next layer continues until the last layer, which is the output of the model." 570 | ] 571 | }, 572 | { 573 | "cell_type": "markdown", 574 | "metadata": { 575 | "colab_type": "text", 576 | "id": "FrrWu3t1iWQY" 577 | }, 578 | "source": [ 579 | "## Build a Multi-Layer Feedforward Network\n", 580 | "\n", 581 | "Build a multi-layer feedforward neural network to classify the traffic sign images.\n", 582 | "\n", 583 | "1. Set the first layer to a `Flatten` layer with the `input_shape` set to (32, 32, 3)\n", 584 | "2. Set the second layer to `Dense` layer width to 128 output. \n", 585 | "3. Use a ReLU activation function after the second layer.\n", 586 | "4. Set the output layer width to 43, since there are 43 classes in the dataset.\n", 587 | "5. Use a softmax activation function after the output layer.\n", 588 | "\n", 589 | "To get started, review the Keras documentation about [models](https://keras.io/models/sequential/) and [layers](https://keras.io/layers/core/).\n", 590 | "\n", 591 | "The Keras example of a [Multi-Layer Perceptron](https://github.com/fchollet/keras/blob/master/examples/mnist_mlp.py) network is similar to what you need to do here. Use that as a guide, but keep in mind that there are a number of differences." 592 | ] 593 | }, 594 | { 595 | "cell_type": "code", 596 | "execution_count": 0, 597 | "metadata": { 598 | "colab": {}, 599 | "colab_type": "code", 600 | "id": "MsYGHqXbiWQZ" 601 | }, 602 | "outputs": [], 603 | "source": [ 604 | "# TODO: Build a Multi-layer feedforward neural network with Keras here.\n", 605 | "from keras.models import Sequential\n", 606 | "from keras.layers.core import Dense, Activation, Flatten \n", 607 | "model = Sequential()\n", 608 | "model.add(Flatten(input_shape = (32,32,3))) # This is the input layer\n", 609 | "model.add(Dense(128)) # This is the hidden layer with 128 neurons\n", 610 | "model.add(Activation('relu'))\n", 611 | "model.add(Dense(43)) # This is the output layer\n", 612 | "model.add(Activation('softmax'))" 613 | ] 614 | }, 615 | { 616 | "cell_type": "markdown", 617 | "metadata": { 618 | "colab_type": "text", 619 | "id": "FI0oetxSiWQn" 620 | }, 621 | "source": [ 622 | ",## Training a Sequential Model\n", 623 | "You built a multi-layer neural network in Keras, now let's look at training a neural network.\n", 624 | "```python\n", 625 | "from keras.models import Sequential\n", 626 | "from keras.layers.core import Dense, Activation\n", 627 | "\n", 628 | "model = Sequential()\n", 629 | "...\n", 630 | "\n", 631 | "# Configures the learning process and metrics\n", 632 | "model.compile('sgd', 'mean_squared_error', ['accuracy'])\n", 633 | "\n", 634 | "# Train the model\n", 635 | "# History is a record of training loss and metrics\n", 636 | "history = model.fit(x_train_data, Y_train_data, batch_size=128, nb_epoch=2, validation_split=0.2)\n", 637 | "\n", 638 | "# Calculate test score\n", 639 | "test_score = model.evaluate(x_test_data, Y_test_data)\n", 640 | "```\n", 641 | "The code above configures, trains, and tests the model. The line `model.compile('sgd', 'mean_squared_error', ['accuracy'])` configures the model's optimizer to `'sgd'`(stochastic gradient descent), the loss to `'mean_squared_error'`, and the metric to `'accuracy'`. \n", 642 | "\n", 643 | "You can find more optimizers [here](https://keras.io/optimizers/), loss functions [here](https://keras.io/objectives/#available-objectives), and more metrics [here](https://keras.io/metrics/#available-metrics).\n", 644 | "\n", 645 | "To train the model, use the `fit()` function as shown in `model.fit(x_train_data, Y_train_data, batch_size=128, nb_epoch=2, validation_split=0.2)`. The `validation_split` parameter will split a percentage of the training dataset to be used to validate the model. The model can be further tested with the test dataset using the `evaluate()` function as shown in the last line." 646 | ] 647 | }, 648 | { 649 | "cell_type": "markdown", 650 | "metadata": { 651 | "colab_type": "text", 652 | "id": "RIziY98OiWQo" 653 | }, 654 | "source": [ 655 | "## Train the Network\n", 656 | "\n", 657 | "1. Compile the network using adam optimizer and categorical_crossentropy loss function.\n", 658 | "2. Train the network for ten epochs and validate with 20% of the training data." 659 | ] 660 | }, 661 | { 662 | "cell_type": "code", 663 | "execution_count": 40, 664 | "metadata": { 665 | "colab": { 666 | "base_uri": "https://localhost:8080/", 667 | "height": 442 668 | }, 669 | "colab_type": "code", 670 | "executionInfo": { 671 | "elapsed": 44331, 672 | "status": "ok", 673 | "timestamp": 1554308205516, 674 | "user": { 675 | "displayName": "Prashant Sahu", 676 | "photoUrl": "https://lh3.googleusercontent.com/-ompx6lyKrkc/AAAAAAAAAAI/AAAAAAAAALk/kbQk9IjXg44/s64/photo.jpg", 677 | "userId": "17861245123904241513" 678 | }, 679 | "user_tz": -330 680 | }, 681 | "id": "KtrjxlghiWQp", 682 | "outputId": "6ccbad51-e273-4d35-b359-6d7f03dfab39" 683 | }, 684 | "outputs": [ 685 | { 686 | "name": "stderr", 687 | "output_type": "stream", 688 | "text": [ 689 | "/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:3: UserWarning: The `nb_epoch` argument in `fit` has been renamed `epochs`.\n", 690 | " This is separate from the ipykernel package so we can avoid doing imports until\n" 691 | ] 692 | }, 693 | { 694 | "name": "stdout", 695 | "output_type": "stream", 696 | "text": [ 697 | "Train on 31367 samples, validate on 7842 samples\n", 698 | "Epoch 1/10\n", 699 | "31367/31367 [==============================] - 5s 168us/step - loss: 1.7498 - acc: 0.5430 - val_loss: 1.0329 - val_acc: 0.7313\n", 700 | "Epoch 2/10\n", 701 | "31367/31367 [==============================] - 5s 145us/step - loss: 0.8184 - acc: 0.7877 - val_loss: 0.7510 - val_acc: 0.7830\n", 702 | "Epoch 3/10\n", 703 | "31367/31367 [==============================] - 4s 129us/step - loss: 0.5884 - acc: 0.8483 - val_loss: 0.5309 - val_acc: 0.8628\n", 704 | "Epoch 4/10\n", 705 | "31367/31367 [==============================] - 4s 129us/step - loss: 0.4665 - acc: 0.8800 - val_loss: 0.4400 - val_acc: 0.8777\n", 706 | "Epoch 5/10\n", 707 | "31367/31367 [==============================] - 4s 130us/step - loss: 0.3907 - acc: 0.8968 - val_loss: 0.4481 - val_acc: 0.8676\n", 708 | "Epoch 6/10\n", 709 | "31367/31367 [==============================] - 4s 131us/step - loss: 0.3509 - acc: 0.9078 - val_loss: 0.3376 - val_acc: 0.9208\n", 710 | "Epoch 7/10\n", 711 | "31367/31367 [==============================] - 4s 131us/step - loss: 0.3004 - acc: 0.9214 - val_loss: 0.4242 - val_acc: 0.8734\n", 712 | "Epoch 8/10\n", 713 | "31367/31367 [==============================] - 4s 129us/step - loss: 0.2842 - acc: 0.9241 - val_loss: 0.3239 - val_acc: 0.9095\n", 714 | "Epoch 9/10\n", 715 | "31367/31367 [==============================] - 4s 128us/step - loss: 0.2608 - acc: 0.9296 - val_loss: 0.3550 - val_acc: 0.9042\n", 716 | "Epoch 10/10\n", 717 | "31367/31367 [==============================] - 4s 126us/step - loss: 0.2334 - acc: 0.9394 - val_loss: 0.3004 - val_acc: 0.9092\n" 718 | ] 719 | } 720 | ], 721 | "source": [ 722 | "# TODO: Compile and train the model here.\n", 723 | "\n", 724 | "model.compile('adam', 'categorical_crossentropy', ['accuracy'])\n", 725 | "history = model.fit(X_normalized, y_one_hot, batch_size=120, nb_epoch=10, validation_split= 0.2)" 726 | ] 727 | }, 728 | { 729 | "cell_type": "markdown", 730 | "metadata": { 731 | "colab_type": "text", 732 | "id": "K6mSlJm8iWQ9" 733 | }, 734 | "source": [ 735 | "## Convolutions\n", 736 | "1. Re-construct the previous network\n", 737 | "2. Add a [convolutional layer](https://keras.io/layers/convolutional/#convolution2d) with 32 filters, a 3x3 kernel, and valid padding before the flatten layer.\n", 738 | "3. Add a ReLU activation after the convolutional layer.\n", 739 | "\n", 740 | "Hint 1: The Keras example of a [convolutional neural network](https://github.com/fchollet/keras/blob/master/examples/mnist_cnn.py) for MNIST would be a good example to review." 741 | ] 742 | }, 743 | { 744 | "cell_type": "code", 745 | "execution_count": 41, 746 | "metadata": { 747 | "colab": { 748 | "base_uri": "https://localhost:8080/", 749 | "height": 72 750 | }, 751 | "colab_type": "code", 752 | "executionInfo": { 753 | "elapsed": 1747, 754 | "status": "ok", 755 | "timestamp": 1554308615586, 756 | "user": { 757 | "displayName": "Prashant Sahu", 758 | "photoUrl": "https://lh3.googleusercontent.com/-ompx6lyKrkc/AAAAAAAAAAI/AAAAAAAAALk/kbQk9IjXg44/s64/photo.jpg", 759 | "userId": "17861245123904241513" 760 | }, 761 | "user_tz": -330 762 | }, 763 | "id": "chgFNaUviWRF", 764 | "outputId": "2224cb6f-9c03-4609-cf9b-d305bf0666b5" 765 | }, 766 | "outputs": [ 767 | { 768 | "name": "stderr", 769 | "output_type": "stream", 770 | "text": [ 771 | "/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:5: UserWarning: Update your `Conv2D` call to the Keras 2 API: `Conv2D(32, (3, 3), input_shape=(32, 32, 3..., padding=\"valid\")`\n", 772 | " \"\"\"\n" 773 | ] 774 | } 775 | ], 776 | "source": [ 777 | "# TODO: Re-construct the network and add a convolutional layer before the flatten layer.\n", 778 | "from keras.models import Sequential\n", 779 | "from keras.layers.core import Dense, Flatten, Activation\n", 780 | "from keras.layers import Convolution2D\n", 781 | "model = Sequential()\n", 782 | "model.add(Convolution2D(32, 3, 3, border_mode='valid', input_shape=(32,32,3)))\n", 783 | "model.add(Activation('relu'))\n", 784 | "model.add(Flatten()) # the convoluted image if flattened to a single vector\n", 785 | "model.add(Dense(128)) # The flattened image is fed to the hidden layer (fully-connected layer)\n", 786 | "model.add(Activation('relu'))\n", 787 | "model.add(Dense(43)) # final output layer\n", 788 | "model.add(Activation('softmax'))\n" 789 | ] 790 | }, 791 | { 792 | "cell_type": "markdown", 793 | "metadata": { 794 | "colab_type": "text", 795 | "id": "Kkv5QW84iWRW" 796 | }, 797 | "source": [ 798 | "## Pooling\n", 799 | "1. Re-construct the network\n", 800 | "2. Add a 2x2 [max pooling layer](https://keras.io/layers/pooling/#maxpooling2d) immediately following your convolutional layer." 801 | ] 802 | }, 803 | { 804 | "cell_type": "code", 805 | "execution_count": 42, 806 | "metadata": { 807 | "colab": { 808 | "base_uri": "https://localhost:8080/", 809 | "height": 72 810 | }, 811 | "colab_type": "code", 812 | "executionInfo": { 813 | "elapsed": 1229, 814 | "status": "ok", 815 | "timestamp": 1554308913648, 816 | "user": { 817 | "displayName": "Prashant Sahu", 818 | "photoUrl": "https://lh3.googleusercontent.com/-ompx6lyKrkc/AAAAAAAAAAI/AAAAAAAAALk/kbQk9IjXg44/s64/photo.jpg", 819 | "userId": "17861245123904241513" 820 | }, 821 | "user_tz": -330 822 | }, 823 | "id": "KWwUUjweiWRY", 824 | "outputId": "3cf7cb8d-42e0-4423-ac19-9fd44bccd66f" 825 | }, 826 | "outputs": [ 827 | { 828 | "name": "stderr", 829 | "output_type": "stream", 830 | "text": [ 831 | "/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:5: UserWarning: Update your `Conv2D` call to the Keras 2 API: `Conv2D(32, (3, 3), input_shape=(32, 32, 3..., padding=\"valid\")`\n", 832 | " \"\"\"\n" 833 | ] 834 | } 835 | ], 836 | "source": [ 837 | "# TODO: Re-construct the network and add a pooling layer after the convolutional layer.\n", 838 | "from keras.models import Sequential\n", 839 | "from keras.layers.core import Dense, Flatten, Activation\n", 840 | "from keras.layers import Convolution2D, pooling\n", 841 | "model = Sequential()\n", 842 | "model.add(Convolution2D(32, 3, 3, border_mode='valid', input_shape=(32,32,3))) \n", 843 | "# output convulted image has size (30,30,32)\n", 844 | "model.add(pooling.MaxPooling2D(pool_size=(2, 2))) \n", 845 | "model.add(Activation('relu'))\n", 846 | "model.add(Flatten()) # is to convert the outout of the MaxPoling LAyer into a single row of pixels >> 1-D\n", 847 | "model.add(Dense(128)) # H.L. with 128 neurons >> fully-connected layer\n", 848 | "model.add(Activation('relu'))\n", 849 | "model.add(Dense(43)) # output layer with 43 neurons are there as 43 classes\n", 850 | "model.add(Activation('softmax'))" 851 | ] 852 | }, 853 | { 854 | "cell_type": "markdown", 855 | "metadata": { 856 | "colab_type": "text", 857 | "id": "wbmUl02siWRi" 858 | }, 859 | "source": [ 860 | "## Dropout\n", 861 | "1. Re-construct the network\n", 862 | "2. Add a [dropout](https://keras.io/layers/core/#dropout) layer after the pooling layer. Set the dropout rate to 50%." 863 | ] 864 | }, 865 | { 866 | "cell_type": "code", 867 | "execution_count": 43, 868 | "metadata": { 869 | "colab": { 870 | "base_uri": "https://localhost:8080/", 871 | "height": 72 872 | }, 873 | "colab_type": "code", 874 | "executionInfo": { 875 | "elapsed": 1322, 876 | "status": "ok", 877 | "timestamp": 1554308983472, 878 | "user": { 879 | "displayName": "Prashant Sahu", 880 | "photoUrl": "https://lh3.googleusercontent.com/-ompx6lyKrkc/AAAAAAAAAAI/AAAAAAAAALk/kbQk9IjXg44/s64/photo.jpg", 881 | "userId": "17861245123904241513" 882 | }, 883 | "user_tz": -330 884 | }, 885 | "id": "3oH6BohWiWRj", 886 | "outputId": "8454e67f-a027-4641-f058-ce173fafe10c" 887 | }, 888 | "outputs": [ 889 | { 890 | "name": "stderr", 891 | "output_type": "stream", 892 | "text": [ 893 | "/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:5: UserWarning: Update your `Conv2D` call to the Keras 2 API: `Conv2D(32, (3, 3), input_shape=(32, 32, 3..., padding=\"valid\")`\n", 894 | " \"\"\"\n" 895 | ] 896 | } 897 | ], 898 | "source": [ 899 | "# TODO: Re-construct the network and add dropout after the pooling layer.\n", 900 | "from keras.models import Sequential\n", 901 | "from keras.layers.core import Dense, Flatten, Activation, Dropout\n", 902 | "from keras.layers import Convolution2D, pooling\n", 903 | "model = Sequential()\n", 904 | "model.add(Convolution2D(32, 3, 3, border_mode='valid', input_shape=(32,32,3)))\n", 905 | "model.add(pooling.MaxPooling2D(pool_size=(2, 2)))\n", 906 | "model.add(Dropout(0.5))\n", 907 | "model.add(Activation('relu'))\n", 908 | "model.add(Flatten()) \n", 909 | "model.add(Dense(128))\n", 910 | "model.add(Activation('relu'))\n", 911 | "model.add(Dense(43))\n", 912 | "model.add(Activation('softmax'))" 913 | ] 914 | }, 915 | { 916 | "cell_type": "markdown", 917 | "metadata": { 918 | "colab_type": "text", 919 | "id": "gH_sBlEJiWR3" 920 | }, 921 | "source": [ 922 | "## Optimization\n", 923 | "Congratulations! You've built a neural network with convolutions, pooling, dropout, and fully-connected layers, all in just a few lines of code.\n", 924 | "\n", 925 | "Have fun with the model and see how well you can do! Add more layers, or regularization, or different padding, or batches, or more training epochs.\n", 926 | "\n", 927 | "What is the best validation accuracy you can achieve?" 928 | ] 929 | }, 930 | { 931 | "cell_type": "code", 932 | "execution_count": 44, 933 | "metadata": { 934 | "colab": { 935 | "base_uri": "https://localhost:8080/", 936 | "height": 459 937 | }, 938 | "colab_type": "code", 939 | "executionInfo": { 940 | "elapsed": 396194, 941 | "status": "ok", 942 | "timestamp": 1554309440474, 943 | "user": { 944 | "displayName": "Prashant Sahu", 945 | "photoUrl": "https://lh3.googleusercontent.com/-ompx6lyKrkc/AAAAAAAAAAI/AAAAAAAAALk/kbQk9IjXg44/s64/photo.jpg", 946 | "userId": "17861245123904241513" 947 | }, 948 | "user_tz": -330 949 | }, 950 | "id": "KrNwE3wsiWSC", 951 | "outputId": "ccc556a5-a6e6-4fad-a4cd-65e5b29500b6" 952 | }, 953 | "outputs": [ 954 | { 955 | "name": "stderr", 956 | "output_type": "stream", 957 | "text": [ 958 | "/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:5: UserWarning: Update your `Conv2D` call to the Keras 2 API: `Conv2D(32, (3, 3), input_shape=(32, 32, 3..., padding=\"valid\")`\n", 959 | " \"\"\"\n", 960 | "/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:17: UserWarning: The `nb_epoch` argument in `fit` has been renamed `epochs`.\n" 961 | ] 962 | }, 963 | { 964 | "name": "stdout", 965 | "output_type": "stream", 966 | "text": [ 967 | "Train on 31367 samples, validate on 7842 samples\n", 968 | "Epoch 1/10\n", 969 | "31367/31367 [==============================] - 40s 1ms/step - loss: 1.6369 - acc: 0.5692 - val_loss: 0.7254 - val_acc: 0.7979\n", 970 | "Epoch 2/10\n", 971 | "31367/31367 [==============================] - 40s 1ms/step - loss: 0.5086 - acc: 0.8677 - val_loss: 0.3277 - val_acc: 0.9263\n", 972 | "Epoch 3/10\n", 973 | "31367/31367 [==============================] - 40s 1ms/step - loss: 0.3077 - acc: 0.9211 - val_loss: 0.2222 - val_acc: 0.9473\n", 974 | "Epoch 4/10\n", 975 | "31367/31367 [==============================] - 39s 1ms/step - loss: 0.2237 - acc: 0.9421 - val_loss: 0.1730 - val_acc: 0.9612\n", 976 | "Epoch 5/10\n", 977 | "31367/31367 [==============================] - 39s 1ms/step - loss: 0.1791 - acc: 0.9538 - val_loss: 0.1444 - val_acc: 0.9672\n", 978 | "Epoch 6/10\n", 979 | "31367/31367 [==============================] - 39s 1ms/step - loss: 0.1525 - acc: 0.9592 - val_loss: 0.1361 - val_acc: 0.9685\n", 980 | "Epoch 7/10\n", 981 | "31367/31367 [==============================] - 39s 1ms/step - loss: 0.1344 - acc: 0.9643 - val_loss: 0.1235 - val_acc: 0.9695\n", 982 | "Epoch 8/10\n", 983 | "31367/31367 [==============================] - 39s 1ms/step - loss: 0.1164 - acc: 0.9683 - val_loss: 0.1125 - val_acc: 0.9704\n", 984 | "Epoch 9/10\n", 985 | "31367/31367 [==============================] - 39s 1ms/step - loss: 0.1049 - acc: 0.9720 - val_loss: 0.1120 - val_acc: 0.9719\n", 986 | "Epoch 10/10\n", 987 | "31367/31367 [==============================] - 40s 1ms/step - loss: 0.0986 - acc: 0.9730 - val_loss: 0.0956 - val_acc: 0.9800\n" 988 | ] 989 | } 990 | ], 991 | "source": [ 992 | "# TODO: Build a model\n", 993 | "from keras.models import Sequential\n", 994 | "from keras.layers.core import Dense, Flatten, Activation, Dropout\n", 995 | "from keras.layers import Convolution2D, pooling\n", 996 | "model = Sequential()\n", 997 | "model.add(Convolution2D(32, 3, 3, border_mode='valid', input_shape=(32,32,3)))\n", 998 | "model.add(pooling.MaxPooling2D(pool_size=(2, 2)))\n", 999 | "model.add(Dropout(0.5))\n", 1000 | "model.add(Activation('relu'))\n", 1001 | "model.add(Flatten()) \n", 1002 | "model.add(Dense(128))\n", 1003 | "model.add(Activation('relu'))\n", 1004 | "model.add(Dense(43))\n", 1005 | "model.add(Activation('softmax'))\n", 1006 | "\n", 1007 | "# TODO: Compile and train the model\n", 1008 | "model.compile('adam', 'categorical_crossentropy', ['accuracy'])\n", 1009 | "history = model.fit(X_normalized, y_one_hot, batch_size=128, nb_epoch=10, validation_split=0.2)\n" 1010 | ] 1011 | }, 1012 | { 1013 | "cell_type": "markdown", 1014 | "metadata": { 1015 | "colab_type": "text", 1016 | "id": "dtbr0R-piWSI" 1017 | }, 1018 | "source": [ 1019 | "**Best Validation Accuracy:** 98.07%" 1020 | ] 1021 | }, 1022 | { 1023 | "cell_type": "markdown", 1024 | "metadata": { 1025 | "colab_type": "text", 1026 | "id": "5fOVgo94iWSJ" 1027 | }, 1028 | "source": [ 1029 | "## Testing\n", 1030 | "Once you've picked out your best model, it's time to test it.\n", 1031 | "\n", 1032 | "Load up the test data and use the [`evaluate()` method](https://keras.io/models/model/#evaluate) to see how well it does.\n", 1033 | "\n", 1034 | "Hint 1: The `evaluate()` method should return an array of numbers. Use the [`metrics_names`](https://keras.io/models/model/) property to get the labels." 1035 | ] 1036 | }, 1037 | { 1038 | "cell_type": "code", 1039 | "execution_count": 45, 1040 | "metadata": { 1041 | "colab": { 1042 | "base_uri": "https://localhost:8080/", 1043 | "height": 70 1044 | }, 1045 | "colab_type": "code", 1046 | "executionInfo": { 1047 | "elapsed": 8187, 1048 | "status": "ok", 1049 | "timestamp": 1554309510625, 1050 | "user": { 1051 | "displayName": "Prashant Sahu", 1052 | "photoUrl": "https://lh3.googleusercontent.com/-ompx6lyKrkc/AAAAAAAAAAI/AAAAAAAAALk/kbQk9IjXg44/s64/photo.jpg", 1053 | "userId": "17861245123904241513" 1054 | }, 1055 | "user_tz": -330 1056 | }, 1057 | "id": "aRydySRQiWSJ", 1058 | "outputId": "bcfb5c3f-e446-4170-a375-46058b738f9c" 1059 | }, 1060 | "outputs": [ 1061 | { 1062 | "name": "stdout", 1063 | "output_type": "stream", 1064 | "text": [ 1065 | "12630/12630 [==============================] - 6s 483us/step\n", 1066 | "loss: 0.4715543721983193\n", 1067 | "acc: 0.8998416468630871\n" 1068 | ] 1069 | } 1070 | ], 1071 | "source": [ 1072 | "# TODO: Load test data\n", 1073 | "with open('test.p', 'rb') as f:\n", 1074 | " data = pickle.load(f)\n", 1075 | "X_test = data['features']\n", 1076 | "y_test = data['labels']\n", 1077 | "\n", 1078 | "# TODO: Normalize the data features to the variable X_normalized\n", 1079 | "X_min = 0\n", 1080 | "X_max = 255\n", 1081 | "a = -0.5\n", 1082 | "b = 0.5\n", 1083 | "X_test_normalized = a + ((X_test - X_min)*(b-a)/ (X_max - X_min))\n", 1084 | "\n", 1085 | "# TODO: Preprocess data & one-hot encode the labels\n", 1086 | "from sklearn import preprocessing \n", 1087 | "lb = preprocessing.LabelBinarizer()\n", 1088 | "lb.fit(y_test)\n", 1089 | "y_test_one_hot =lb.transform(y_test)\n", 1090 | "\n", 1091 | "# TODO: Evaluate model on test data\n", 1092 | "metrics = model.evaluate(X_test_normalized, y_test_one_hot)\n", 1093 | "for metric_i in range(len(model.metrics_names)):\n", 1094 | " metric_name = model.metrics_names[metric_i]\n", 1095 | " metric_value = metrics[metric_i]\n", 1096 | " print('{}: {}'.format(metric_name, metric_value))" 1097 | ] 1098 | }, 1099 | { 1100 | "cell_type": "markdown", 1101 | "metadata": { 1102 | "colab_type": "text", 1103 | "id": "f138guYGiWSM" 1104 | }, 1105 | "source": [] 1106 | }, 1107 | { 1108 | "cell_type": "markdown", 1109 | "metadata": { 1110 | "colab_type": "text", 1111 | "id": "JW71LiY9iWSN" 1112 | }, 1113 | "source": [] 1114 | } 1115 | ], 1116 | "metadata": { 1117 | "accelerator": "TPU", 1118 | "colab": { 1119 | "collapsed_sections": [], 1120 | "name": "traffic_sign_classification_with_keras (1).ipynb", 1121 | "provenance": [], 1122 | "version": "0.3.2" 1123 | }, 1124 | "kernelspec": { 1125 | "display_name": "Python 3", 1126 | "language": "python", 1127 | "name": "python3" 1128 | }, 1129 | "language_info": { 1130 | "codemirror_mode": { 1131 | "name": "ipython", 1132 | "version": 3 1133 | }, 1134 | "file_extension": ".py", 1135 | "mimetype": "text/x-python", 1136 | "name": "python", 1137 | "nbconvert_exporter": "python", 1138 | "pygments_lexer": "ipython3", 1139 | "version": "3.6.4" 1140 | } 1141 | }, 1142 | "nbformat": 4, 1143 | "nbformat_minor": 1 1144 | } 1145 | --------------------------------------------------------------------------------