├── Cats_vs_Dogs_Without_Data_Augmentation.ipynb
├── Cats_vs_Dogs_with_Data_Augmentation.ipynb
├── Celsius_to_Fahrenheit.ipynb
├── Classifying_Images_of_Clothing.ipynb
├── Common_Patterns(Time_Series_Forecasting).ipynb
├── Flowers_with_data_augmentation.ipynb
├── Flowers_with_transfer_learning.ipynb
├── Image_Classification_with_CNNs.ipynb
├── Moving_Average_(Time_Series_Forecasting).ipynb
├── Naive_Forecasting_(Time_Series_Forecasting).ipynb
├── README.md
├── Saving_and_Loading_Models.ipynb
└── Transfer_Learning_with_TensorFlow_Hub.ipynb
/Cats_vs_Dogs_Without_Data_Augmentation.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "accelerator": "GPU",
6 | "colab": {
7 | "name": "Cats vs Dogs Without Data Augmentation.ipynb",
8 | "provenance": [],
9 | "private_outputs": true,
10 | "collapsed_sections": [],
11 | "toc_visible": true,
12 | "include_colab_link": true
13 | },
14 | "kernelspec": {
15 | "display_name": "Python 3",
16 | "name": "python3"
17 | }
18 | },
19 | "cells": [
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {
23 | "id": "view-in-github",
24 | "colab_type": "text"
25 | },
26 | "source": [
27 | "
"
28 | ]
29 | },
30 | {
31 | "cell_type": "markdown",
32 | "metadata": {
33 | "colab_type": "text",
34 | "id": "TBFXQGKYUc4X"
35 | },
36 | "source": [
37 | "##### Copyright 2019 The TensorFlow Authors."
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "metadata": {
43 | "cellView": "form",
44 | "colab_type": "code",
45 | "id": "1z4xy2gTUc4a",
46 | "colab": {}
47 | },
48 | "source": [
49 | "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
50 | "# you may not use this file except in compliance with the License.\n",
51 | "# You may obtain a copy of the License at\n",
52 | "#\n",
53 | "# https://www.apache.org/licenses/LICENSE-2.0\n",
54 | "#\n",
55 | "# Unless required by applicable law or agreed to in writing, software\n",
56 | "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
57 | "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
58 | "# See the License for the specific language governing permissions and\n",
59 | "# limitations under the License."
60 | ],
61 | "execution_count": 0,
62 | "outputs": []
63 | },
64 | {
65 | "cell_type": "code",
66 | "metadata": {
67 | "id": "bSwWhN9TGh7p",
68 | "colab_type": "code",
69 | "colab": {}
70 | },
71 | "source": [
72 | "from google.colab import drive\n",
73 | "drive.mount('/content/drive')"
74 | ],
75 | "execution_count": 0,
76 | "outputs": []
77 | },
78 | {
79 | "cell_type": "markdown",
80 | "metadata": {
81 | "colab_type": "text",
82 | "id": "FE7KNzPPVrVV"
83 | },
84 | "source": [
85 | "# Dogs vs Cats Image Classification Without Image Augmentation"
86 | ]
87 | },
88 | {
89 | "cell_type": "markdown",
90 | "metadata": {
91 | "colab_type": "text",
92 | "id": "gN7G9GFmVrVY"
93 | },
94 | "source": [
95 | "\n",
96 | "\n",
97 | "In this tutorial, we will discuss how to classify images into pictures of cats or pictures of dogs. We'll build an image classifier using `tf.keras.Sequential` model and load data using `tf.keras.preprocessing.image.ImageDataGenerator`.\n",
98 | "\n",
99 | "## Specific concepts that will be covered:\n",
100 | "In the process, we will build practical experience and develop intuition around the following concepts\n",
101 | "\n",
102 | "* Building _data input pipelines_ using the `tf.keras.preprocessing.image.ImageDataGenerator` class — How can we efficiently work with data on disk to interface with our model?\n",
103 | "* _Overfitting_ - what is it, how to identify it?\n",
104 | "\n",
105 | "
\n",
106 | "\n",
107 | "\n",
108 | "**Before you begin**\n",
109 | "\n",
110 | "Before running the code in this notebook, reset the runtime by going to **Runtime -> Reset all runtimes** in the menu above. If you have been working through several notebooks, this will help you avoid reaching Colab's memory limits.\n"
111 | ]
112 | },
113 | {
114 | "cell_type": "markdown",
115 | "metadata": {
116 | "colab_type": "text",
117 | "id": "zF9uvbXNVrVY"
118 | },
119 | "source": [
120 | "# Importing packages"
121 | ]
122 | },
123 | {
124 | "cell_type": "markdown",
125 | "metadata": {
126 | "colab_type": "text",
127 | "id": "VddxeYBEVrVZ"
128 | },
129 | "source": [
130 | "Let's start by importing required packages:\n",
131 | "\n",
132 | "* os — to read files and directory structure\n",
133 | "* numpy — for some matrix math outside of TensorFlow\n",
134 | "* matplotlib.pyplot — to plot the graph and display images in our training and validation data\n",
135 | "\n",
136 | "\n",
137 | "\n",
138 | "\n"
139 | ]
140 | },
141 | {
142 | "cell_type": "code",
143 | "metadata": {
144 | "colab_type": "code",
145 | "id": "qyHrknvL0pOu",
146 | "colab": {}
147 | },
148 | "source": [
149 | "from __future__ import absolute_import, division, print_function, unicode_literals"
150 | ],
151 | "execution_count": 0,
152 | "outputs": []
153 | },
154 | {
155 | "cell_type": "code",
156 | "metadata": {
157 | "colab_type": "code",
158 | "id": "oSdjGwVWGshH",
159 | "colab": {}
160 | },
161 | "source": [
162 | "try:\n",
163 | " # Use the %tensorflow_version magic if in colab.\n",
164 | " %tensorflow_version 2.x\n",
165 | "except Exception:\n",
166 | " pass\n",
167 | "\n",
168 | "import tensorflow as tf"
169 | ],
170 | "execution_count": 0,
171 | "outputs": []
172 | },
173 | {
174 | "cell_type": "code",
175 | "metadata": {
176 | "colab_type": "code",
177 | "id": "nlORkUyFGxWH",
178 | "colab": {}
179 | },
180 | "source": [
181 | "from tensorflow.keras.preprocessing.image import ImageDataGenerator"
182 | ],
183 | "execution_count": 0,
184 | "outputs": []
185 | },
186 | {
187 | "cell_type": "code",
188 | "metadata": {
189 | "colab_type": "code",
190 | "id": "wqtiIPRbG4FA",
191 | "colab": {}
192 | },
193 | "source": [
194 | "import os\n",
195 | "import matplotlib.pyplot as plt\n",
196 | "import numpy as np"
197 | ],
198 | "execution_count": 0,
199 | "outputs": []
200 | },
201 | {
202 | "cell_type": "code",
203 | "metadata": {
204 | "colab_type": "code",
205 | "id": "GHHqtPisG3R1",
206 | "colab": {}
207 | },
208 | "source": [
209 | "import logging\n",
210 | "logger = tf.get_logger()\n",
211 | "logger.setLevel(logging.ERROR)"
212 | ],
213 | "execution_count": 0,
214 | "outputs": []
215 | },
216 | {
217 | "cell_type": "markdown",
218 | "metadata": {
219 | "colab_type": "text",
220 | "id": "UZZI6lNkVrVm"
221 | },
222 | "source": [
223 | "# Data Loading"
224 | ]
225 | },
226 | {
227 | "cell_type": "markdown",
228 | "metadata": {
229 | "colab_type": "text",
230 | "id": "DPHx8-t-VrVo"
231 | },
232 | "source": [
233 | "To build our image classifier, we begin by downloading the dataset. The dataset we are using is a filtered version of Dogs vs. Cats dataset from Kaggle (ultimately, this dataset is provided by Microsoft Research).\n",
234 | "\n",
235 | "In previous Colabs, we've used TensorFlow Datasets, which is a very easy and convenient way to use datasets. In this Colab however, we will make use of the class `tf.keras.preprocessing.image.ImageDataGenerator` which will read data from disk. We therefore need to directly download *Dogs vs. Cats* from a URL and unzip it to the Colab filesystem."
236 | ]
237 | },
238 | {
239 | "cell_type": "code",
240 | "metadata": {
241 | "colab_type": "code",
242 | "id": "rpUSoFjuVrVp",
243 | "colab": {}
244 | },
245 | "source": [
246 | "_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'\n",
247 | "zip_dir = tf.keras.utils.get_file('cats_and_dogs_filterted.zip', origin=_URL, extract=True)"
248 | ],
249 | "execution_count": 0,
250 | "outputs": []
251 | },
252 | {
253 | "cell_type": "markdown",
254 | "metadata": {
255 | "colab_type": "text",
256 | "id": "Giv0wMQzVrVw"
257 | },
258 | "source": [
259 | "The dataset we have downloaded has the following directory structure.\n",
260 | "\n",
261 | "\n",
262 | "cats_and_dogs_filtered\n",
263 | "|__ train\n",
264 | " |______ cats: [cat.0.jpg, cat.1.jpg, cat.2.jpg ...]\n",
265 | " |______ dogs: [dog.0.jpg, dog.1.jpg, dog.2.jpg ...]\n",
266 | "|__ validation\n",
267 | " |______ cats: [cat.2000.jpg, cat.2001.jpg, cat.2002.jpg ...]\n",
268 | " |______ dogs: [dog.2000.jpg, dog.2001.jpg, dog.2002.jpg ...]\n",
269 | "
\n",
270 | "\n",
271 | "We can list the directories with the following terminal command:"
272 | ]
273 | },
274 | {
275 | "cell_type": "code",
276 | "metadata": {
277 | "colab_type": "code",
278 | "id": "ssD23VbTZeVA",
279 | "colab": {}
280 | },
281 | "source": [
282 | "zip_dir_base = os.path.dirname(zip_dir)\n",
283 | "!find $zip_dir_base -type d -print"
284 | ],
285 | "execution_count": 0,
286 | "outputs": []
287 | },
288 | {
289 | "cell_type": "markdown",
290 | "metadata": {
291 | "colab_type": "text",
292 | "id": "VpmywIlsVrVx"
293 | },
294 | "source": [
295 | "We'll now assign variables with the proper file path for the training and validation sets."
296 | ]
297 | },
298 | {
299 | "cell_type": "code",
300 | "metadata": {
301 | "colab_type": "code",
302 | "id": "sRucI3QqVrVy",
303 | "colab": {}
304 | },
305 | "source": [
306 | "base_dir = os.path.join(os.path.dirname(zip_dir), 'cats_and_dogs_filtered')\n",
307 | "train_dir = os.path.join(base_dir, 'train')\n",
308 | "validation_dir = os.path.join(base_dir, 'validation')\n",
309 | "\n",
310 | "train_cats_dir = os.path.join(train_dir, 'cats') # directory with our training cat pictures\n",
311 | "train_dogs_dir = os.path.join(train_dir, 'dogs') # directory with our training dog pictures\n",
312 | "validation_cats_dir = os.path.join(validation_dir, 'cats') # directory with our validation cat pictures\n",
313 | "validation_dogs_dir = os.path.join(validation_dir, 'dogs') # directory with our validation dog pictures"
314 | ],
315 | "execution_count": 0,
316 | "outputs": []
317 | },
318 | {
319 | "cell_type": "markdown",
320 | "metadata": {
321 | "colab_type": "text",
322 | "id": "ZdrHHTy2VrV3"
323 | },
324 | "source": [
325 | "### Understanding our data"
326 | ]
327 | },
328 | {
329 | "cell_type": "markdown",
330 | "metadata": {
331 | "colab_type": "text",
332 | "id": "LblUYjl-VrV3"
333 | },
334 | "source": [
335 | "Let's look at how many cats and dogs images we have in our training and validation directory"
336 | ]
337 | },
338 | {
339 | "cell_type": "code",
340 | "metadata": {
341 | "colab_type": "code",
342 | "id": "vc4u8e9hVrV4",
343 | "colab": {}
344 | },
345 | "source": [
346 | "num_cats_tr = len(os.listdir(train_cats_dir))\n",
347 | "num_dogs_tr = len(os.listdir(train_dogs_dir))\n",
348 | "\n",
349 | "num_cats_val = len(os.listdir(validation_cats_dir))\n",
350 | "num_dogs_val = len(os.listdir(validation_dogs_dir))\n",
351 | "\n",
352 | "total_train = num_cats_tr + num_dogs_tr\n",
353 | "total_val = num_cats_val + num_dogs_val"
354 | ],
355 | "execution_count": 0,
356 | "outputs": []
357 | },
358 | {
359 | "cell_type": "code",
360 | "metadata": {
361 | "colab_type": "code",
362 | "id": "g4GGzGt0VrV7",
363 | "colab": {}
364 | },
365 | "source": [
366 | "print('total training cat images:', num_cats_tr)\n",
367 | "print('total training dog images:', num_dogs_tr)\n",
368 | "\n",
369 | "print('total validation cat images:', num_cats_val)\n",
370 | "print('total validation dog images:', num_dogs_val)\n",
371 | "print(\"--\")\n",
372 | "print(\"Total training images:\", total_train)\n",
373 | "print(\"Total validation images:\", total_val)"
374 | ],
375 | "execution_count": 0,
376 | "outputs": []
377 | },
378 | {
379 | "cell_type": "markdown",
380 | "metadata": {
381 | "colab_type": "text",
382 | "id": "tdsI_L-NVrV_"
383 | },
384 | "source": [
385 | "# Setting Model Parameters"
386 | ]
387 | },
388 | {
389 | "cell_type": "markdown",
390 | "metadata": {
391 | "colab_type": "text",
392 | "id": "8Lp-0ejxOtP1"
393 | },
394 | "source": [
395 | "For convenience, we'll set up variables that will be used later while pre-processing our dataset and training our network."
396 | ]
397 | },
398 | {
399 | "cell_type": "code",
400 | "metadata": {
401 | "colab_type": "code",
402 | "id": "3NqNselLVrWA",
403 | "colab": {}
404 | },
405 | "source": [
406 | "BATCH_SIZE = 100 # Number of training examples to process before updating our models variables\n",
407 | "IMG_SHAPE = 150 # Our training data consists of images with width of 150 pixels and height of 150 pixels"
408 | ],
409 | "execution_count": 0,
410 | "outputs": []
411 | },
412 | {
413 | "cell_type": "markdown",
414 | "metadata": {
415 | "colab_type": "text",
416 | "id": "INn-cOn1VrWC"
417 | },
418 | "source": [
419 | "# Data Preparation "
420 | ]
421 | },
422 | {
423 | "cell_type": "markdown",
424 | "metadata": {
425 | "colab_type": "text",
426 | "id": "5Jfk6aSAVrWD"
427 | },
428 | "source": [
429 | "Images must be formatted into appropriately pre-processed floating point tensors before being fed into the network. The steps involved in preparing these images are:\n",
430 | "\n",
431 | "1. Read images from the disk\n",
432 | "2. Decode contents of these images and convert it into proper grid format as per their RGB content\n",
433 | "3. Convert them into floating point tensors\n",
434 | "4. Rescale the tensors from values between 0 and 255 to values between 0 and 1, as neural networks prefer to deal with small input values.\n",
435 | "\n",
436 | "Fortunately, all these tasks can be done using the class **tf.keras.preprocessing.image.ImageDataGenerator**.\n",
437 | "\n",
438 | "We can set this up in a couple of lines of code."
439 | ]
440 | },
441 | {
442 | "cell_type": "code",
443 | "metadata": {
444 | "colab_type": "code",
445 | "id": "syDdF_LWVrWE",
446 | "colab": {}
447 | },
448 | "source": [
449 | "train_image_generator = ImageDataGenerator(rescale=1./255) # Generator for our training data\n",
450 | "validation_image_generator = ImageDataGenerator(rescale=1./255) # Generator for our validation data"
451 | ],
452 | "execution_count": 0,
453 | "outputs": []
454 | },
455 | {
456 | "cell_type": "markdown",
457 | "metadata": {
458 | "colab_type": "text",
459 | "id": "RLciCR_FVrWH"
460 | },
461 | "source": [
462 | "After defining our generators for training and validation images, **flow_from_directory** method will load images from the disk, apply rescaling, and resize them using single line of code."
463 | ]
464 | },
465 | {
466 | "cell_type": "code",
467 | "metadata": {
468 | "colab_type": "code",
469 | "id": "Pw94ajOOVrWI",
470 | "colab": {}
471 | },
472 | "source": [
473 | "train_data_gen = train_image_generator.flow_from_directory(batch_size=BATCH_SIZE,\n",
474 | " directory=train_dir,\n",
475 | " shuffle=True,\n",
476 | " target_size=(IMG_SHAPE,IMG_SHAPE), #(150,150)\n",
477 | " class_mode='binary')"
478 | ],
479 | "execution_count": 0,
480 | "outputs": []
481 | },
482 | {
483 | "cell_type": "code",
484 | "metadata": {
485 | "colab_type": "code",
486 | "id": "2oUoKUzRVrWM",
487 | "colab": {}
488 | },
489 | "source": [
490 | "val_data_gen = validation_image_generator.flow_from_directory(batch_size=BATCH_SIZE,\n",
491 | " directory=validation_dir,\n",
492 | " shuffle=False,\n",
493 | " target_size=(IMG_SHAPE,IMG_SHAPE), #(150,150)\n",
494 | " class_mode='binary')"
495 | ],
496 | "execution_count": 0,
497 | "outputs": []
498 | },
499 | {
500 | "cell_type": "markdown",
501 | "metadata": {
502 | "colab_type": "text",
503 | "id": "hyexPJ8CVrWP"
504 | },
505 | "source": [
506 | "### Visualizing Training images"
507 | ]
508 | },
509 | {
510 | "cell_type": "markdown",
511 | "metadata": {
512 | "colab_type": "text",
513 | "id": "60CnhEL4VrWQ"
514 | },
515 | "source": [
516 | "We can visualize our training images by getting a batch of images from the training generator, and then plotting a few of them using `matplotlib`."
517 | ]
518 | },
519 | {
520 | "cell_type": "code",
521 | "metadata": {
522 | "colab_type": "code",
523 | "id": "3f0Z7NZgVrWQ",
524 | "colab": {}
525 | },
526 | "source": [
527 | "sample_training_images, _ = next(train_data_gen) "
528 | ],
529 | "execution_count": 0,
530 | "outputs": []
531 | },
532 | {
533 | "cell_type": "markdown",
534 | "metadata": {
535 | "colab_type": "text",
536 | "id": "49weMt5YVrWT"
537 | },
538 | "source": [
539 | "The `next` function returns a batch from the dataset. One batch is a tuple of (*many images*, *many labels*). For right now, we're discarding the labels because we just want to look at the images."
540 | ]
541 | },
542 | {
543 | "cell_type": "code",
544 | "metadata": {
545 | "colab_type": "code",
546 | "id": "JMt2RES_VrWU",
547 | "colab": {}
548 | },
549 | "source": [
550 | "# This function will plot images in the form of a grid with 1 row and 5 columns where images are placed in each column.\n",
551 | "def plotImages(images_arr):\n",
552 | " fig, axes = plt.subplots(1, 5, figsize=(20,20))\n",
553 | " axes = axes.flatten()\n",
554 | " for img, ax in zip(images_arr, axes):\n",
555 | " ax.imshow(img)\n",
556 | " plt.tight_layout()\n",
557 | " plt.show()"
558 | ],
559 | "execution_count": 0,
560 | "outputs": []
561 | },
562 | {
563 | "cell_type": "code",
564 | "metadata": {
565 | "colab_type": "code",
566 | "id": "d_VVg_gEVrWW",
567 | "colab": {}
568 | },
569 | "source": [
570 | "plotImages(sample_training_images[:5]) # Plot images 0-4"
571 | ],
572 | "execution_count": 0,
573 | "outputs": []
574 | },
575 | {
576 | "cell_type": "markdown",
577 | "metadata": {
578 | "colab_type": "text",
579 | "id": "b5Ej-HLGVrWZ"
580 | },
581 | "source": [
582 | "# Model Creation"
583 | ]
584 | },
585 | {
586 | "cell_type": "markdown",
587 | "metadata": {
588 | "colab_type": "text",
589 | "id": "wEgW4i18VrWZ"
590 | },
591 | "source": [
592 | "## Define the model\n",
593 | "\n",
594 | "The model consists of four convolution blocks with a max pool layer in each of them. Then we have a fully connected layer with 512 units, with a `relu` activation function. The model will output class probabilities for two classes — dogs and cats — using `softmax`. "
595 | ]
596 | },
597 | {
598 | "cell_type": "code",
599 | "metadata": {
600 | "colab_type": "code",
601 | "id": "F15-uwLPVrWa",
602 | "colab": {}
603 | },
604 | "source": [
605 | "model = tf.keras.models.Sequential([\n",
606 | " tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(150, 150, 3)),\n",
607 | " tf.keras.layers.MaxPooling2D(2, 2),\n",
608 | "\n",
609 | " tf.keras.layers.Conv2D(64, (3,3), activation='relu'),\n",
610 | " tf.keras.layers.MaxPooling2D(2,2),\n",
611 | " \n",
612 | " tf.keras.layers.Conv2D(128, (3,3), activation='relu'),\n",
613 | " tf.keras.layers.MaxPooling2D(2,2),\n",
614 | " \n",
615 | " tf.keras.layers.Conv2D(128, (3,3), activation='relu'),\n",
616 | " tf.keras.layers.MaxPooling2D(2,2),\n",
617 | " \n",
618 | " tf.keras.layers.Flatten(),\n",
619 | " tf.keras.layers.Dense(512, activation='relu'),\n",
620 | " tf.keras.layers.Dense(2, activation='softmax')\n",
621 | "])"
622 | ],
623 | "execution_count": 0,
624 | "outputs": []
625 | },
626 | {
627 | "cell_type": "markdown",
628 | "metadata": {
629 | "colab_type": "text",
630 | "id": "PI5cdkMQVrWc"
631 | },
632 | "source": [
633 | "### Compile the model\n",
634 | "\n",
635 | "As usual, we will use the `adam` optimizer. Since we output a softmax categorization, we'll use `sparse_categorical_crossentropy` as the loss function. We would also like to look at training and validation accuracy on each epoch as we train our network, so we are passing in the metrics argument."
636 | ]
637 | },
638 | {
639 | "cell_type": "code",
640 | "metadata": {
641 | "colab_type": "code",
642 | "id": "6Mg7_TXOVrWd",
643 | "colab": {}
644 | },
645 | "source": [
646 | "model.compile(optimizer='adam',\n",
647 | " loss='sparse_categorical_crossentropy',\n",
648 | " metrics=['accuracy'])"
649 | ],
650 | "execution_count": 0,
651 | "outputs": []
652 | },
653 | {
654 | "cell_type": "markdown",
655 | "metadata": {
656 | "colab_type": "text",
657 | "id": "2YmQZ3TAVrWg"
658 | },
659 | "source": [
660 | "### Model Summary\n",
661 | "\n",
662 | "Let's look at all the layers of our network using **summary** method."
663 | ]
664 | },
665 | {
666 | "cell_type": "code",
667 | "metadata": {
668 | "colab_type": "code",
669 | "id": "Vtny8hmBVrWh",
670 | "colab": {}
671 | },
672 | "source": [
673 | "model.summary()"
674 | ],
675 | "execution_count": 0,
676 | "outputs": []
677 | },
678 | {
679 | "cell_type": "markdown",
680 | "metadata": {
681 | "colab_type": "text",
682 | "id": "N06iqE8VVrWj"
683 | },
684 | "source": [
685 | "### Train the model"
686 | ]
687 | },
688 | {
689 | "cell_type": "markdown",
690 | "metadata": {
691 | "colab_type": "text",
692 | "id": "oub9RtoFVrWk"
693 | },
694 | "source": [
695 | "It's time we train our network.\n",
696 | "\n",
697 | "Since our batches are coming from a generator (`ImageDataGenerator`), we'll use `fit_generator` instead of `fit`."
698 | ]
699 | },
700 | {
701 | "cell_type": "code",
702 | "metadata": {
703 | "colab_type": "code",
704 | "id": "KSF2HqhDVrWk",
705 | "colab": {}
706 | },
707 | "source": [
708 | "EPOCHS = 100\n",
709 | "history = model.fit_generator(\n",
710 | " train_data_gen,\n",
711 | " steps_per_epoch=int(np.ceil(total_train / float(BATCH_SIZE))),\n",
712 | " epochs=EPOCHS,\n",
713 | " validation_data=val_data_gen,\n",
714 | " validation_steps=int(np.ceil(total_val / float(BATCH_SIZE)))\n",
715 | ")"
716 | ],
717 | "execution_count": 0,
718 | "outputs": []
719 | },
720 | {
721 | "cell_type": "markdown",
722 | "metadata": {
723 | "colab_type": "text",
724 | "id": "ojJNteAGVrWo"
725 | },
726 | "source": [
727 | "### Visualizing results of the training"
728 | ]
729 | },
730 | {
731 | "cell_type": "markdown",
732 | "metadata": {
733 | "colab_type": "text",
734 | "id": "LZPYT-EmVrWo"
735 | },
736 | "source": [
737 | "We'll now visualize the results we get after training our network."
738 | ]
739 | },
740 | {
741 | "cell_type": "code",
742 | "metadata": {
743 | "colab_type": "code",
744 | "id": "K6oA77ADVrWp",
745 | "colab": {}
746 | },
747 | "source": [
748 | "acc = history.history['accuracy']\n",
749 | "val_acc = history.history['val_accuracy']\n",
750 | "\n",
751 | "loss = history.history['loss']\n",
752 | "val_loss = history.history['val_loss']\n",
753 | "\n",
754 | "epochs_range = range(EPOCHS)\n",
755 | "\n",
756 | "plt.figure(figsize=(8, 8))\n",
757 | "plt.subplot(1, 2, 1)\n",
758 | "plt.plot(epochs_range, acc, label='Training Accuracy')\n",
759 | "plt.plot(epochs_range, val_acc, label='Validation Accuracy')\n",
760 | "plt.legend(loc='lower right')\n",
761 | "plt.title('Training and Validation Accuracy')\n",
762 | "\n",
763 | "plt.subplot(1, 2, 2)\n",
764 | "plt.plot(epochs_range, loss, label='Training Loss')\n",
765 | "plt.plot(epochs_range, val_loss, label='Validation Loss')\n",
766 | "plt.legend(loc='upper right')\n",
767 | "plt.title('Training and Validation Loss')\n",
768 | "plt.savefig('./foo.png')\n",
769 | "plt.show()"
770 | ],
771 | "execution_count": 0,
772 | "outputs": []
773 | },
774 | {
775 | "cell_type": "markdown",
776 | "metadata": {
777 | "colab_type": "text",
778 | "id": "kDnr50l2VrWu"
779 | },
780 | "source": [
781 | "As we can see from the plots, training accuracy and validation accuracy are off by large margin and our model has achieved only around **70%** accuracy on the validation set (depending on the number of epochs you trained for).\n",
782 | "\n",
783 | "This is a clear indication of overfitting. Once the training and validation curves start to diverge, our model has started to memorize the training data and is unable to perform well on the validation data."
784 | ]
785 | }
786 | ]
787 | }
--------------------------------------------------------------------------------
/Cats_vs_Dogs_with_Data_Augmentation.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "accelerator": "GPU",
6 | "colab": {
7 | "name": "Cats vs Dogs with Data Augmentation.ipynb",
8 | "provenance": [],
9 | "private_outputs": true,
10 | "collapsed_sections": [],
11 | "toc_visible": true,
12 | "include_colab_link": true
13 | },
14 | "kernelspec": {
15 | "display_name": "Python 3",
16 | "name": "python3"
17 | }
18 | },
19 | "cells": [
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {
23 | "id": "view-in-github",
24 | "colab_type": "text"
25 | },
26 | "source": [
27 | "
"
28 | ]
29 | },
30 | {
31 | "cell_type": "markdown",
32 | "metadata": {
33 | "colab_type": "text",
34 | "id": "TBFXQGKYUc4X"
35 | },
36 | "source": [
37 | "##### Copyright 2019 The TensorFlow Authors."
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "metadata": {
43 | "cellView": "form",
44 | "colab_type": "code",
45 | "id": "1z4xy2gTUc4a",
46 | "colab": {}
47 | },
48 | "source": [
49 | "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
50 | "# you may not use this file except in compliance with the License.\n",
51 | "# You may obtain a copy of the License at\n",
52 | "#\n",
53 | "# https://www.apache.org/licenses/LICENSE-2.0\n",
54 | "#\n",
55 | "# Unless required by applicable law or agreed to in writing, software\n",
56 | "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
57 | "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
58 | "# See the License for the specific language governing permissions and\n",
59 | "# limitations under the License."
60 | ],
61 | "execution_count": 0,
62 | "outputs": []
63 | },
64 | {
65 | "cell_type": "markdown",
66 | "metadata": {
67 | "colab_type": "text",
68 | "id": "FE7KNzPPVrVV"
69 | },
70 | "source": [
71 | "# Dogs vs Cats Image Classification With Image Augmentation"
72 | ]
73 | },
74 | {
75 | "cell_type": "markdown",
76 | "metadata": {
77 | "colab_type": "text",
78 | "id": "gN7G9GFmVrVY"
79 | },
80 | "source": [
81 | "In this tutorial, we will discuss how to classify images into pictures of cats or pictures of dogs. We'll build an image classifier using `tf.keras.Sequential` model and load data using `tf.keras.preprocessing.image.ImageDataGenerator`.\n",
82 | "\n",
83 | "## Specific concepts that will be covered:\n",
84 | "In the process, we will build practical experience and develop intuition around the following concepts\n",
85 | "\n",
86 | "* Building _data input pipelines_ using the `tf.keras.preprocessing.image.ImageDataGenerator` class — How can we efficiently work with data on disk to interface with our model?\n",
87 | "* _Overfitting_ - what is it, how to identify it, and how can we prevent it?\n",
88 | "* _Data Augmentation_ and _Dropout_ - Key techniques to fight overfitting in computer vision tasks that we will incorporate into our data pipeline and image classifier model.\n",
89 | "\n",
90 | "## We will follow the general machine learning workflow:\n",
91 | "\n",
92 | "1. Examine and understand data\n",
93 | "2. Build an input pipeline\n",
94 | "3. Build our model\n",
95 | "4. Train our model\n",
96 | "5. Test our model\n",
97 | "6. Improve our model/Repeat the process\n",
98 | "\n",
99 | "
\n",
100 | "\n",
101 | "**Before you begin**\n",
102 | "\n",
103 | "Before running the code in this notebook, reset the runtime by going to **Runtime -> Reset all runtimes** in the menu above. If you have been working through several notebooks, this will help you avoid reaching Colab's memory limits.\n"
104 | ]
105 | },
106 | {
107 | "cell_type": "markdown",
108 | "metadata": {
109 | "colab_type": "text",
110 | "id": "zF9uvbXNVrVY"
111 | },
112 | "source": [
113 | "# Importing packages"
114 | ]
115 | },
116 | {
117 | "cell_type": "markdown",
118 | "metadata": {
119 | "colab_type": "text",
120 | "id": "VddxeYBEVrVZ"
121 | },
122 | "source": [
123 | "Let's start by importing required packages:\n",
124 | "\n",
125 | "* os — to read files and directory structure\n",
126 | "* numpy — for some matrix math outside of TensorFlow\n",
127 | "* matplotlib.pyplot — to plot the graph and display images in our training and validation data"
128 | ]
129 | },
130 | {
131 | "cell_type": "code",
132 | "metadata": {
133 | "colab_type": "code",
134 | "id": "rtPGh2MAVrVa",
135 | "colab": {}
136 | },
137 | "source": [
138 | "from __future__ import absolute_import, division, print_function, unicode_literals"
139 | ],
140 | "execution_count": 0,
141 | "outputs": []
142 | },
143 | {
144 | "cell_type": "code",
145 | "metadata": {
146 | "colab_type": "code",
147 | "id": "in3OdvpUG_9_",
148 | "colab": {}
149 | },
150 | "source": [
151 | "try:\n",
152 | " # Use the %tensorflow_version magic if in colab.\n",
153 | " %tensorflow_version 2.x\n",
154 | "except Exception:\n",
155 | " pass\n",
156 | "\n",
157 | "import tensorflow as tf"
158 | ],
159 | "execution_count": 0,
160 | "outputs": []
161 | },
162 | {
163 | "cell_type": "code",
164 | "metadata": {
165 | "colab_type": "code",
166 | "id": "L1WtoaOHVrVh",
167 | "colab": {}
168 | },
169 | "source": [
170 | "from tensorflow.keras.preprocessing.image import ImageDataGenerator"
171 | ],
172 | "execution_count": 0,
173 | "outputs": []
174 | },
175 | {
176 | "cell_type": "code",
177 | "metadata": {
178 | "colab_type": "code",
179 | "id": "ede3_kbeHOjR",
180 | "colab": {}
181 | },
182 | "source": [
183 | "import os\n",
184 | "import numpy as np\n",
185 | "import matplotlib.pyplot as plt"
186 | ],
187 | "execution_count": 0,
188 | "outputs": []
189 | },
190 | {
191 | "cell_type": "markdown",
192 | "metadata": {
193 | "colab_type": "text",
194 | "id": "UZZI6lNkVrVm"
195 | },
196 | "source": [
197 | "# Data Loading"
198 | ]
199 | },
200 | {
201 | "cell_type": "markdown",
202 | "metadata": {
203 | "colab_type": "text",
204 | "id": "DPHx8-t-VrVo"
205 | },
206 | "source": [
207 | "To build our image classifier, we begin by downloading the dataset. The dataset we are using is a filtered version of Dogs vs. Cats dataset from Kaggle (ultimately, this dataset is provided by Microsoft Research).\n",
208 | "\n",
209 | "In previous Colabs, we've used TensorFlow Datasets, which is a very easy and convenient way to use datasets. In this Colab however, we will make use of the class `tf.keras.preprocessing.image.ImageDataGenerator` which will read data from disk. We therefore need to directly download *Dogs vs. Cats* from a URL and unzip it to the Colab filesystem."
210 | ]
211 | },
212 | {
213 | "cell_type": "code",
214 | "metadata": {
215 | "colab_type": "code",
216 | "id": "OYmOylPlVrVt",
217 | "colab": {}
218 | },
219 | "source": [
220 | "_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'\n",
221 | "\n",
222 | "zip_dir = tf.keras.utils.get_file('cats_and_dogs_filterted.zip', origin=_URL, extract=True)"
223 | ],
224 | "execution_count": 0,
225 | "outputs": []
226 | },
227 | {
228 | "cell_type": "markdown",
229 | "metadata": {
230 | "colab_type": "text",
231 | "id": "Giv0wMQzVrVw"
232 | },
233 | "source": [
234 | "The dataset we have downloaded has following directory structure.\n",
235 | "\n",
236 | "\n",
237 | "cats_and_dogs_filtered\n",
238 | "|__ train\n",
239 | " |______ cats: [cat.0.jpg, cat.1.jpg, cat.2.jpg ....]\n",
240 | " |______ dogs: [dog.0.jpg, dog.1.jpg, dog.2.jpg ...]\n",
241 | "|__ validation\n",
242 | " |______ cats: [cat.2000.jpg, cat.2001.jpg, cat.2002.jpg ....]\n",
243 | " |______ dogs: [dog.2000.jpg, dog.2001.jpg, dog.2002.jpg ...]\n",
244 | "
"
245 | ]
246 | },
247 | {
248 | "cell_type": "markdown",
249 | "metadata": {
250 | "colab_type": "text",
251 | "id": "VpmywIlsVrVx"
252 | },
253 | "source": [
254 | "We'll now assign variables with the proper file path for the training and validation sets."
255 | ]
256 | },
257 | {
258 | "cell_type": "code",
259 | "metadata": {
260 | "colab_type": "code",
261 | "id": "sRucI3QqVrVy",
262 | "colab": {}
263 | },
264 | "source": [
265 | "base_dir = os.path.join(os.path.dirname(zip_dir), 'cats_and_dogs_filtered')\n",
266 | "train_dir = os.path.join(base_dir, 'train')\n",
267 | "validation_dir = os.path.join(base_dir, 'validation')"
268 | ],
269 | "execution_count": 0,
270 | "outputs": []
271 | },
272 | {
273 | "cell_type": "code",
274 | "metadata": {
275 | "colab_type": "code",
276 | "id": "Utv3nryxVrV0",
277 | "colab": {}
278 | },
279 | "source": [
280 | "train_cats_dir = os.path.join(train_dir, 'cats') # directory with our training cat pictures\n",
281 | "train_dogs_dir = os.path.join(train_dir, 'dogs') # directory with our training dog pictures\n",
282 | "validation_cats_dir = os.path.join(validation_dir, 'cats') # directory with our validation cat pictures\n",
283 | "validation_dogs_dir = os.path.join(validation_dir, 'dogs') # directory with our validation dog pictures"
284 | ],
285 | "execution_count": 0,
286 | "outputs": []
287 | },
288 | {
289 | "cell_type": "markdown",
290 | "metadata": {
291 | "colab_type": "text",
292 | "id": "ZdrHHTy2VrV3"
293 | },
294 | "source": [
295 | "### Understanding our data"
296 | ]
297 | },
298 | {
299 | "cell_type": "markdown",
300 | "metadata": {
301 | "colab_type": "text",
302 | "id": "LblUYjl-VrV3"
303 | },
304 | "source": [
305 | "Let's look at how many cats and dogs images we have in our training and validation directory"
306 | ]
307 | },
308 | {
309 | "cell_type": "code",
310 | "metadata": {
311 | "colab_type": "code",
312 | "id": "vc4u8e9hVrV4",
313 | "colab": {}
314 | },
315 | "source": [
316 | "num_cats_tr = len(os.listdir(train_cats_dir))\n",
317 | "num_dogs_tr = len(os.listdir(train_dogs_dir))\n",
318 | "\n",
319 | "num_cats_val = len(os.listdir(validation_cats_dir))\n",
320 | "num_dogs_val = len(os.listdir(validation_dogs_dir))\n",
321 | "\n",
322 | "total_train = num_cats_tr + num_dogs_tr\n",
323 | "total_val = num_cats_val + num_dogs_val"
324 | ],
325 | "execution_count": 0,
326 | "outputs": []
327 | },
328 | {
329 | "cell_type": "code",
330 | "metadata": {
331 | "colab_type": "code",
332 | "id": "g4GGzGt0VrV7",
333 | "colab": {}
334 | },
335 | "source": [
336 | "print('total training cat images:', num_cats_tr)\n",
337 | "print('total training dog images:', num_dogs_tr)\n",
338 | "\n",
339 | "print('total validation cat images:', num_cats_val)\n",
340 | "print('total validation dog images:', num_dogs_val)\n",
341 | "print(\"--\")\n",
342 | "print(\"Total training images:\", total_train)\n",
343 | "print(\"Total validation images:\", total_val)"
344 | ],
345 | "execution_count": 0,
346 | "outputs": []
347 | },
348 | {
349 | "cell_type": "markdown",
350 | "metadata": {
351 | "colab_type": "text",
352 | "id": "tdsI_L-NVrV_"
353 | },
354 | "source": [
355 | "# Setting Model Parameters"
356 | ]
357 | },
358 | {
359 | "cell_type": "markdown",
360 | "metadata": {
361 | "colab_type": "text",
362 | "id": "8Lp-0ejxOtP1"
363 | },
364 | "source": [
365 | "For convenience, let us set up variables that will be used later while pre-processing our dataset and training our network."
366 | ]
367 | },
368 | {
369 | "cell_type": "code",
370 | "metadata": {
371 | "colab_type": "code",
372 | "id": "3NqNselLVrWA",
373 | "colab": {}
374 | },
375 | "source": [
376 | "BATCH_SIZE = 100\n",
377 | "IMG_SHAPE = 150 # Our training data consists of images with width of 150 pixels and height of 150 pixels"
378 | ],
379 | "execution_count": 0,
380 | "outputs": []
381 | },
382 | {
383 | "cell_type": "markdown",
384 | "metadata": {
385 | "colab_type": "text",
386 | "id": "RLciCR_FVrWH"
387 | },
388 | "source": [
389 | "After defining our generators for training and validation images, **flow_from_directory** method will load images from the disk and will apply rescaling and will resize them into required dimensions using single line of code."
390 | ]
391 | },
392 | {
393 | "cell_type": "markdown",
394 | "metadata": {
395 | "colab_type": "text",
396 | "id": "UOoVpxFwVrWy"
397 | },
398 | "source": [
399 | "# Data Augmentation"
400 | ]
401 | },
402 | {
403 | "cell_type": "markdown",
404 | "metadata": {
405 | "colab_type": "text",
406 | "id": "Wn_QLciWVrWy"
407 | },
408 | "source": [
409 | "Overfitting often occurs when we have a small number of training examples. One way to fix this problem is to augment our dataset so that it has sufficient number and variety of training examples. Data augmentation takes the approach of generating more training data from existing training samples, by augmenting the samples through random transformations that yield believable-looking images. The goal is that at training time, your model will never see the exact same picture twice. This exposes the model to more aspects of the data, allowing it to generalize better.\n",
410 | "\n",
411 | "In **tf.keras** we can implement this using the same **ImageDataGenerator** class we used before. We can simply pass different transformations we would want to our dataset as a form of arguments and it will take care of applying it to the dataset during our training process.\n",
412 | "\n",
413 | "To start off, let's define a function that can display an image, so we can see the type of augmentation that has been performed. Then, we'll look at specific augmentations that we'll use during training."
414 | ]
415 | },
416 | {
417 | "cell_type": "code",
418 | "metadata": {
419 | "colab_type": "code",
420 | "id": "GBYLOFgOXPJ9",
421 | "colab": {}
422 | },
423 | "source": [
424 | "# This function will plot images in the form of a grid with 1 row and 5 columns where images are placed in each column.\n",
425 | "def plotImages(images_arr):\n",
426 | " fig, axes = plt.subplots(1, 5, figsize=(20,20))\n",
427 | " axes = axes.flatten()\n",
428 | " for img, ax in zip(images_arr, axes):\n",
429 | " ax.imshow(img)\n",
430 | " plt.tight_layout()\n",
431 | " plt.show()"
432 | ],
433 | "execution_count": 0,
434 | "outputs": []
435 | },
436 | {
437 | "cell_type": "markdown",
438 | "metadata": {
439 | "colab_type": "text",
440 | "id": "rlVj6VqaVrW0"
441 | },
442 | "source": [
443 | "### Flipping the image horizontally"
444 | ]
445 | },
446 | {
447 | "cell_type": "markdown",
448 | "metadata": {
449 | "colab_type": "text",
450 | "id": "xcdvx4TVVrW1"
451 | },
452 | "source": [
453 | "We can begin by randomly applying horizontal flip augmentation to our dataset and seeing how individual images will look after the transformation. This is achieved by passing `horizontal_flip=True` as an argument to the `ImageDataGenerator` class."
454 | ]
455 | },
456 | {
457 | "cell_type": "code",
458 | "metadata": {
459 | "colab_type": "code",
460 | "id": "Bi1_vHyBVrW2",
461 | "colab": {}
462 | },
463 | "source": [
464 | "image_gen = ImageDataGenerator(rescale=1./255, horizontal_flip=True)\n",
465 | "\n",
466 | "train_data_gen = image_gen.flow_from_directory(batch_size=BATCH_SIZE,\n",
467 | " directory=train_dir,\n",
468 | " shuffle=True,\n",
469 | " target_size=(IMG_SHAPE,IMG_SHAPE))"
470 | ],
471 | "execution_count": 0,
472 | "outputs": []
473 | },
474 | {
475 | "cell_type": "markdown",
476 | "metadata": {
477 | "colab_type": "text",
478 | "id": "zJpRSxJ-VrW7"
479 | },
480 | "source": [
481 | "To see the transformation in action, let's take one sample image from our training set and repeat it five times. The augmentation will be randomly applied (or not) to each repetition."
482 | ]
483 | },
484 | {
485 | "cell_type": "code",
486 | "metadata": {
487 | "colab_type": "code",
488 | "id": "RrKGd_jjVrW7",
489 | "colab": {}
490 | },
491 | "source": [
492 | "augmented_images = [train_data_gen[0][0][0] for i in range(5)]\n",
493 | "plotImages(augmented_images)"
494 | ],
495 | "execution_count": 0,
496 | "outputs": []
497 | },
498 | {
499 | "cell_type": "markdown",
500 | "metadata": {
501 | "colab_type": "text",
502 | "id": "i7n9xcqCVrXB"
503 | },
504 | "source": [
505 | "### Rotating the image"
506 | ]
507 | },
508 | {
509 | "cell_type": "markdown",
510 | "metadata": {
511 | "colab_type": "text",
512 | "id": "qXnwkzFuVrXB"
513 | },
514 | "source": [
515 | "The rotation augmentation will randomly rotate the image up to a specified number of degrees. Here, we'll set it to 45."
516 | ]
517 | },
518 | {
519 | "cell_type": "code",
520 | "metadata": {
521 | "colab_type": "code",
522 | "id": "1zip35pDVrXB",
523 | "colab": {}
524 | },
525 | "source": [
526 | "image_gen = ImageDataGenerator(rescale=1./255, rotation_range=45)\n",
527 | "\n",
528 | "train_data_gen = image_gen.flow_from_directory(batch_size=BATCH_SIZE,\n",
529 | " directory=train_dir,\n",
530 | " shuffle=True,\n",
531 | " target_size=(IMG_SHAPE, IMG_SHAPE))"
532 | ],
533 | "execution_count": 0,
534 | "outputs": []
535 | },
536 | {
537 | "cell_type": "markdown",
538 | "metadata": {
539 | "colab_type": "text",
540 | "id": "deaqZLsfcZ15"
541 | },
542 | "source": [
543 | "To see the transformation in action, let's once again take a sample image from our training set and repeat it. The augmentation will be randomly applied (or not) to each repetition."
544 | ]
545 | },
546 | {
547 | "cell_type": "code",
548 | "metadata": {
549 | "colab_type": "code",
550 | "id": "kVoWh4OIVrXD",
551 | "colab": {}
552 | },
553 | "source": [
554 | "augmented_images = [train_data_gen[0][0][0] for i in range(5)]\n",
555 | "plotImages(augmented_images)"
556 | ],
557 | "execution_count": 0,
558 | "outputs": []
559 | },
560 | {
561 | "cell_type": "markdown",
562 | "metadata": {
563 | "colab_type": "text",
564 | "id": "FOqGPL76VrXM"
565 | },
566 | "source": [
567 | "### Applying Zoom"
568 | ]
569 | },
570 | {
571 | "cell_type": "markdown",
572 | "metadata": {
573 | "colab_type": "text",
574 | "id": "NvqXaD8BVrXN"
575 | },
576 | "source": [
577 | "We can also apply Zoom augmentation to our dataset, zooming images up to 50% randomly."
578 | ]
579 | },
580 | {
581 | "cell_type": "code",
582 | "metadata": {
583 | "colab_type": "code",
584 | "id": "tGNKLa_YVrXR",
585 | "colab": {}
586 | },
587 | "source": [
588 | "image_gen = ImageDataGenerator(rescale=1./255, zoom_range=0.5)\n",
589 | "\n",
590 | "train_data_gen = image_gen.flow_from_directory(batch_size=BATCH_SIZE,\n",
591 | " directory=train_dir,\n",
592 | " shuffle=True,\n",
593 | " target_size=(IMG_SHAPE, IMG_SHAPE))\n"
594 | ],
595 | "execution_count": 0,
596 | "outputs": []
597 | },
598 | {
599 | "cell_type": "markdown",
600 | "metadata": {
601 | "colab_type": "text",
602 | "id": "WgPWieSZcctO"
603 | },
604 | "source": [
605 | "One more time, take a sample image from our training set and repeat it. The augmentation will be randomly applied (or not) to each repetition."
606 | ]
607 | },
608 | {
609 | "cell_type": "code",
610 | "metadata": {
611 | "colab_type": "code",
612 | "id": "VOvTs32FVrXU",
613 | "colab": {}
614 | },
615 | "source": [
616 | "augmented_images = [train_data_gen[0][0][0] for i in range(5)]\n",
617 | "plotImages(augmented_images)"
618 | ],
619 | "execution_count": 0,
620 | "outputs": []
621 | },
622 | {
623 | "cell_type": "markdown",
624 | "metadata": {
625 | "colab_type": "text",
626 | "id": "usS13KCNVrXd"
627 | },
628 | "source": [
629 | "### Putting it all together"
630 | ]
631 | },
632 | {
633 | "cell_type": "markdown",
634 | "metadata": {
635 | "colab_type": "text",
636 | "id": "OC8fIsalVrXd"
637 | },
638 | "source": [
639 | "We can apply all these augmentations, and even others, with just one line of code, by passing the augmentations as arguments with proper values.\n",
640 | "\n",
641 | "Here, we have applied rescale, rotation of 45 degrees, width shift, height shift, horizontal flip, and zoom augmentation to our training images."
642 | ]
643 | },
644 | {
645 | "cell_type": "code",
646 | "metadata": {
647 | "colab_type": "code",
648 | "id": "gnr2xujaVrXe",
649 | "colab": {}
650 | },
651 | "source": [
652 | "image_gen_train = ImageDataGenerator(\n",
653 | " rescale=1./255,\n",
654 | " rotation_range=40,\n",
655 | " width_shift_range=0.2,\n",
656 | " height_shift_range=0.2,\n",
657 | " shear_range=0.2,\n",
658 | " zoom_range=0.2,\n",
659 | " horizontal_flip=True,\n",
660 | " fill_mode='nearest')\n",
661 | "\n",
662 | "train_data_gen = image_gen_train.flow_from_directory(batch_size=BATCH_SIZE,\n",
663 | " directory=train_dir,\n",
664 | " shuffle=True,\n",
665 | " target_size=(IMG_SHAPE,IMG_SHAPE),\n",
666 | " class_mode='binary')"
667 | ],
668 | "execution_count": 0,
669 | "outputs": []
670 | },
671 | {
672 | "cell_type": "markdown",
673 | "metadata": {
674 | "colab_type": "text",
675 | "id": "AW-pV5awVrXl"
676 | },
677 | "source": [
678 | "Let's visualize how a single image would look like five different times, when we pass these augmentations randomly to our dataset. "
679 | ]
680 | },
681 | {
682 | "cell_type": "code",
683 | "metadata": {
684 | "colab_type": "code",
685 | "id": "z2m68eMhVrXm",
686 | "colab": {}
687 | },
688 | "source": [
689 | "augmented_images = [train_data_gen[0][0][0] for i in range(5)]\n",
690 | "plotImages(augmented_images)"
691 | ],
692 | "execution_count": 0,
693 | "outputs": []
694 | },
695 | {
696 | "cell_type": "markdown",
697 | "metadata": {
698 | "colab_type": "text",
699 | "id": "J8cUd7FXVrXq"
700 | },
701 | "source": [
702 | "### Creating Validation Data generator"
703 | ]
704 | },
705 | {
706 | "cell_type": "markdown",
707 | "metadata": {
708 | "colab_type": "text",
709 | "id": "a99fDBt7VrXr"
710 | },
711 | "source": [
712 | "Generally, we only apply data augmentation to our training examples, since the original images should be representative of what our model needs to manage. So, in this case we are only rescaling our validation images and converting them into batches using ImageDataGenerator."
713 | ]
714 | },
715 | {
716 | "cell_type": "code",
717 | "metadata": {
718 | "colab_type": "code",
719 | "id": "54x0aNbKVrXr",
720 | "colab": {}
721 | },
722 | "source": [
723 | "image_gen_val = ImageDataGenerator(rescale=1./255)\n",
724 | "\n",
725 | "val_data_gen = image_gen_val.flow_from_directory(batch_size=BATCH_SIZE,\n",
726 | " directory=validation_dir,\n",
727 | " target_size=(IMG_SHAPE, IMG_SHAPE),\n",
728 | " class_mode='binary')"
729 | ],
730 | "execution_count": 0,
731 | "outputs": []
732 | },
733 | {
734 | "cell_type": "markdown",
735 | "metadata": {
736 | "colab_type": "text",
737 | "id": "b5Ej-HLGVrWZ"
738 | },
739 | "source": [
740 | "# Model Creation"
741 | ]
742 | },
743 | {
744 | "cell_type": "markdown",
745 | "metadata": {
746 | "colab_type": "text",
747 | "id": "wEgW4i18VrWZ"
748 | },
749 | "source": [
750 | "## Define the model\n",
751 | "\n",
752 | "The model consists of four convolution blocks with a max pool layer in each of them.\n",
753 | "\n",
754 | "Before the final Dense layers, we're also applying a Dropout probability of 0.5. It means that 50% of the values coming into the Dropout layer will be set to zero. This helps to prevent overfitting.\n",
755 | "\n",
756 | "Then we have a fully connected layer with 512 units, with a `relu` activation function. The model will output class probabilities for two classes — dogs and cats — using `softmax`. "
757 | ]
758 | },
759 | {
760 | "cell_type": "code",
761 | "metadata": {
762 | "cellView": "both",
763 | "colab_type": "code",
764 | "id": "Evjf8jZk2zi-",
765 | "colab": {}
766 | },
767 | "source": [
768 | "model = tf.keras.models.Sequential([\n",
769 | " tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(150, 150, 3)),\n",
770 | " tf.keras.layers.MaxPooling2D(2, 2),\n",
771 | "\n",
772 | " tf.keras.layers.Conv2D(64, (3,3), activation='relu'),\n",
773 | " tf.keras.layers.MaxPooling2D(2,2),\n",
774 | "\n",
775 | " tf.keras.layers.Conv2D(128, (3,3), activation='relu'),\n",
776 | " tf.keras.layers.MaxPooling2D(2,2),\n",
777 | "\n",
778 | " tf.keras.layers.Conv2D(128, (3,3), activation='relu'),\n",
779 | " tf.keras.layers.MaxPooling2D(2,2),\n",
780 | "\n",
781 | " tf.keras.layers.Dropout(0.5),\n",
782 | " tf.keras.layers.Flatten(),\n",
783 | " tf.keras.layers.Dense(512, activation='relu'),\n",
784 | " tf.keras.layers.Dense(2, activation='softmax')\n",
785 | "])"
786 | ],
787 | "execution_count": 0,
788 | "outputs": []
789 | },
790 | {
791 | "cell_type": "markdown",
792 | "metadata": {
793 | "colab_type": "text",
794 | "id": "DADWLqMSJcH3"
795 | },
796 | "source": [
797 | "### Compiling the model\n",
798 | "\n",
799 | "As usual, we will use the `adam` optimizer. Since we output a softmax categorization, we'll use `sparse_categorical_crossentropy` as the loss function. We would also like to look at training and validation accuracy on each epoch as we train our network, so we are passing in the metrics argument."
800 | ]
801 | },
802 | {
803 | "cell_type": "code",
804 | "metadata": {
805 | "colab_type": "code",
806 | "id": "08rRJ0sn3Tb1",
807 | "colab": {}
808 | },
809 | "source": [
810 | "model.compile(optimizer='adam',\n",
811 | " loss='sparse_categorical_crossentropy',\n",
812 | " metrics=['accuracy'])"
813 | ],
814 | "execution_count": 0,
815 | "outputs": []
816 | },
817 | {
818 | "cell_type": "markdown",
819 | "metadata": {
820 | "colab_type": "text",
821 | "id": "uurnCp_H4Hj9"
822 | },
823 | "source": [
824 | "### Model Summary\n",
825 | "\n",
826 | "Let's look at all the layers of our network using **summary** method."
827 | ]
828 | },
829 | {
830 | "cell_type": "code",
831 | "metadata": {
832 | "colab_type": "code",
833 | "id": "b66qAJF_4Jnw",
834 | "colab": {}
835 | },
836 | "source": [
837 | "model.summary()"
838 | ],
839 | "execution_count": 0,
840 | "outputs": []
841 | },
842 | {
843 | "cell_type": "markdown",
844 | "metadata": {
845 | "colab_type": "text",
846 | "id": "N06iqE8VVrWj"
847 | },
848 | "source": [
849 | "### Train the model"
850 | ]
851 | },
852 | {
853 | "cell_type": "markdown",
854 | "metadata": {
855 | "colab_type": "text",
856 | "id": "oub9RtoFVrWk"
857 | },
858 | "source": [
859 | "It's time we train our network.\n",
860 | "\n",
861 | "Since our batches are coming from a generator (`ImageDataGenerator`), we'll use `fit_generator` instead of `fit`."
862 | ]
863 | },
864 | {
865 | "cell_type": "code",
866 | "metadata": {
867 | "colab_type": "code",
868 | "id": "tk5NT1PW3j_P",
869 | "colab": {}
870 | },
871 | "source": [
872 | "epochs=100\n",
873 | "history = model.fit_generator(\n",
874 | " train_data_gen,\n",
875 | " steps_per_epoch=int(np.ceil(total_train / float(BATCH_SIZE))),\n",
876 | " epochs=epochs,\n",
877 | " validation_data=val_data_gen,\n",
878 | " validation_steps=int(np.ceil(total_val / float(BATCH_SIZE)))\n",
879 | ")"
880 | ],
881 | "execution_count": 0,
882 | "outputs": []
883 | },
884 | {
885 | "cell_type": "markdown",
886 | "metadata": {
887 | "colab_type": "text",
888 | "id": "ojJNteAGVrWo"
889 | },
890 | "source": [
891 | "### Visualizing results of the training"
892 | ]
893 | },
894 | {
895 | "cell_type": "markdown",
896 | "metadata": {
897 | "colab_type": "text",
898 | "id": "LZPYT-EmVrWo"
899 | },
900 | "source": [
901 | "We'll now visualize the results we get after training our network."
902 | ]
903 | },
904 | {
905 | "cell_type": "code",
906 | "metadata": {
907 | "colab_type": "code",
908 | "id": "8CfngybnFHQR",
909 | "colab": {}
910 | },
911 | "source": [
912 | "acc = history.history['accuracy']\n",
913 | "val_acc = history.history['val_accuracy']\n",
914 | "\n",
915 | "loss = history.history['loss']\n",
916 | "val_loss = history.history['val_loss']\n",
917 | "\n",
918 | "epochs_range = range(epochs)\n",
919 | "\n",
920 | "plt.figure(figsize=(8, 8))\n",
921 | "plt.subplot(1, 2, 1)\n",
922 | "plt.plot(epochs_range, acc, label='Training Accuracy')\n",
923 | "plt.plot(epochs_range, val_acc, label='Validation Accuracy')\n",
924 | "plt.legend(loc='lower right')\n",
925 | "plt.title('Training and Validation Accuracy')\n",
926 | "\n",
927 | "plt.subplot(1, 2, 2)\n",
928 | "plt.plot(epochs_range, loss, label='Training Loss')\n",
929 | "plt.plot(epochs_range, val_loss, label='Validation Loss')\n",
930 | "plt.legend(loc='upper right')\n",
931 | "plt.title('Training and Validation Loss')\n",
932 | "plt.show()"
933 | ],
934 | "execution_count": 0,
935 | "outputs": []
936 | }
937 | ]
938 | }
--------------------------------------------------------------------------------
/Celsius_to_Fahrenheit.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "Celsius to Fahrenheit.ipynb",
7 | "provenance": [],
8 | "private_outputs": true,
9 | "collapsed_sections": [],
10 | "toc_visible": true,
11 | "include_colab_link": true
12 | },
13 | "kernelspec": {
14 | "name": "python3",
15 | "display_name": "Python 3"
16 | },
17 | "accelerator": "GPU"
18 | },
19 | "cells": [
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {
23 | "id": "view-in-github",
24 | "colab_type": "text"
25 | },
26 | "source": [
27 | "
"
28 | ]
29 | },
30 | {
31 | "cell_type": "markdown",
32 | "metadata": {
33 | "colab_type": "text",
34 | "id": "HnKx50tv5aZD"
35 | },
36 | "source": [
37 | "##### Copyright 2018 The TensorFlow Authors."
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "metadata": {
43 | "id": "WTv4rxgLLTpa",
44 | "colab_type": "code",
45 | "colab": {}
46 | },
47 | "source": [
48 | "from google.colab import drive\n",
49 | "drive.mount('/content/drive')"
50 | ],
51 | "execution_count": 0,
52 | "outputs": []
53 | },
54 | {
55 | "cell_type": "code",
56 | "metadata": {
57 | "cellView": "form",
58 | "colab_type": "code",
59 | "id": "IwtS_OXU5cWG",
60 | "colab": {}
61 | },
62 | "source": [
63 | "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
64 | "# you may not use this file except in compliance with the License.\n",
65 | "# You may obtain a copy of the License at\n",
66 | "#\n",
67 | "# https://www.apache.org/licenses/LICENSE-2.0\n",
68 | "#\n",
69 | "# Unless required by applicable law or agreed to in writing, software\n",
70 | "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
71 | "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
72 | "# See the License for the specific language governing permissions and\n",
73 | "# limitations under the License."
74 | ],
75 | "execution_count": 0,
76 | "outputs": []
77 | },
78 | {
79 | "cell_type": "markdown",
80 | "metadata": {
81 | "colab_type": "text",
82 | "id": "YHI3vyhv5p85"
83 | },
84 | "source": [
85 | "# The Basics: Training Your First Model"
86 | ]
87 | },
88 | {
89 | "cell_type": "markdown",
90 | "metadata": {
91 | "colab_type": "text",
92 | "id": "F8YVA_634OFk"
93 | },
94 | "source": [
95 | "Welcome to this Colab where you will train your first Machine Learning model!\n",
96 | "\n",
97 | "We'll try to keep things simple here, and only introduce basic concepts. Later Colabs will cover more advanced problems.\n",
98 | "\n",
99 | "The problem we will solve is to convert from Celsius to Fahrenheit, where the approximate formula is:\n",
100 | "\n",
101 | "$$ f = c \\times 1.8 + 32 $$\n",
102 | "\n",
103 | "\n",
104 | "Of course, it would be simple enough to create a conventional Python function that directly performs this calculation, but that wouldn't be machine learning.\n",
105 | "\n",
106 | "\n",
107 | "Instead, we will give TensorFlow some sample Celsius values (0, 8, 15, 22, 38) and their corresponding Fahrenheit values (32, 46, 59, 72, 100).\n",
108 | "Then, we will train a model that figures out the above formula through the training process."
109 | ]
110 | },
111 | {
112 | "cell_type": "markdown",
113 | "metadata": {
114 | "colab_type": "text",
115 | "id": "fA93WUy1zzWf"
116 | },
117 | "source": [
118 | "## Import dependencies\n",
119 | "\n",
120 | "First, import TensorFlow. Here, we're calling it `tf` for ease of use. We also tell it to only display errors.\n",
121 | "\n",
122 | "Next, import [NumPy](http://www.numpy.org/) as `np`. Numpy helps us to represent our data as highly performant lists."
123 | ]
124 | },
125 | {
126 | "cell_type": "code",
127 | "metadata": {
128 | "colab_type": "code",
129 | "id": "X9uIpOS2zx7k",
130 | "colab": {}
131 | },
132 | "source": [
133 | "from __future__ import absolute_import, division, print_function, unicode_literals"
134 | ],
135 | "execution_count": 0,
136 | "outputs": []
137 | },
138 | {
139 | "cell_type": "code",
140 | "metadata": {
141 | "colab_type": "code",
142 | "id": "-ZMgCvSRFqxE",
143 | "colab": {}
144 | },
145 | "source": [
146 | "try:\n",
147 | " # Use the %tensorflow_version magic if in colab.\n",
148 | " %tensorflow_version 2.x\n",
149 | "except Exception:\n",
150 | " pass\n",
151 | "\n",
152 | "import tensorflow as tf"
153 | ],
154 | "execution_count": 0,
155 | "outputs": []
156 | },
157 | {
158 | "cell_type": "code",
159 | "metadata": {
160 | "colab_type": "code",
161 | "id": "y_WQEM5MGmg3",
162 | "colab": {}
163 | },
164 | "source": [
165 | "import numpy as np\n",
166 | "import logging\n",
167 | "logger = tf.get_logger()\n",
168 | "logger.setLevel(logging.ERROR)"
169 | ],
170 | "execution_count": 0,
171 | "outputs": []
172 | },
173 | {
174 | "cell_type": "markdown",
175 | "metadata": {
176 | "colab_type": "text",
177 | "id": "AC3EQFi20buB"
178 | },
179 | "source": [
180 | "## Set up training data\n",
181 | "\n",
182 | "As we saw before, supervised Machine Learning is all about figuring out an algorithm given a set of inputs and outputs. Since the task in this Codelab is to create a model that can give the temperature in Fahrenheit when given the degrees in Celsius, we create two lists `celsius_q` and `fahrenheit_a` that we can use to train our model."
183 | ]
184 | },
185 | {
186 | "cell_type": "code",
187 | "metadata": {
188 | "colab_type": "code",
189 | "id": "gg4pn6aI1vms",
190 | "colab": {}
191 | },
192 | "source": [
193 | "celsius_q = np.array([-40, -10, 0, 8, 15, 22, 38], dtype=float)\n",
194 | "fahrenheit_a = np.array([-40, 14, 32, 46, 59, 72, 100], dtype=float)\n",
195 | "\n",
196 | "for i,c in enumerate(celsius_q):\n",
197 | " print(\"{} degrees Celsius = {} degrees Fahrenheit\".format(c, fahrenheit_a[i]))"
198 | ],
199 | "execution_count": 0,
200 | "outputs": []
201 | },
202 | {
203 | "cell_type": "markdown",
204 | "metadata": {
205 | "colab_type": "text",
206 | "id": "wwJGmDrQ0EoB"
207 | },
208 | "source": [
209 | "### Some Machine Learning terminology\n",
210 | "\n",
211 | " - **Feature** — The input(s) to our model. In this case, a single value — the degrees in Celsius.\n",
212 | "\n",
213 | " - **Labels** — The output our model predicts. In this case, a single value — the degrees in Fahrenheit.\n",
214 | "\n",
215 | " - **Example** — A pair of inputs/outputs used during training. In our case a pair of values from `celsius_q` and `fahrenheit_a` at a specific index, such as `(22,72)`.\n",
216 | "\n"
217 | ]
218 | },
219 | {
220 | "cell_type": "markdown",
221 | "metadata": {
222 | "colab_type": "text",
223 | "id": "VM7_9Klvq7MO"
224 | },
225 | "source": [
226 | "## Create the model\n",
227 | "\n",
228 | "Next create the model. We will use simplest possible model we can, a Dense network. Since the problem is straightforward, this network will require only a single layer, with a single neuron.\n",
229 | "\n",
230 | "### Build a layer\n",
231 | "\n",
232 | "We'll call the layer `l0` and create it by instantiating `tf.keras.layers.Dense` with the following configuration:\n",
233 | "\n",
234 | "* `input_shape=[1]` — This specifies that the input to this layer is a single value. That is, the shape is a one-dimensional array with one member. Since this is the first (and only) layer, that input shape is the input shape of the entire model. The single value is a floating point number, representing degrees Celsius.\n",
235 | "\n",
236 | "* `units=1` — This specifies the number of neurons in the layer. The number of neurons defines how many internal variables the layer has to try to learn how to solve the problem (more later). Since this is the final layer, it is also the size of the model's output — a single float value representing degrees Fahrenheit. (In a multi-layered network, the size and shape of the layer would need to match the `input_shape` of the next layer.)\n"
237 | ]
238 | },
239 | {
240 | "cell_type": "code",
241 | "metadata": {
242 | "colab_type": "code",
243 | "id": "pRllo2HLfXiu",
244 | "colab": {}
245 | },
246 | "source": [
247 | "l0 = tf.keras.layers.Dense(units=1, input_shape=[1])"
248 | ],
249 | "execution_count": 0,
250 | "outputs": []
251 | },
252 | {
253 | "cell_type": "markdown",
254 | "metadata": {
255 | "colab_type": "text",
256 | "id": "_F00_J9duLBD"
257 | },
258 | "source": [
259 | "### Assemble layers into the model\n",
260 | "\n",
261 | "Once layers are defined, they need to be assembled into a model. The Sequential model definition takes a list of layers as argument, specifying the calculation order from the input to the output.\n",
262 | "\n",
263 | "This model has just a single layer, l0."
264 | ]
265 | },
266 | {
267 | "cell_type": "code",
268 | "metadata": {
269 | "colab_type": "code",
270 | "id": "cSp-GpLSuMRq",
271 | "colab": {}
272 | },
273 | "source": [
274 | "mod\n",
275 | "el = tf.keras.Sequential([l0])"
276 | ],
277 | "execution_count": 0,
278 | "outputs": []
279 | },
280 | {
281 | "cell_type": "markdown",
282 | "metadata": {
283 | "colab_type": "text",
284 | "id": "t7pfHfWxust0"
285 | },
286 | "source": [
287 | "**Note**\n",
288 | "\n",
289 | "You will often see the layers defined inside the model definition, rather than beforehand:\n",
290 | "\n",
291 | "```python\n",
292 | "model = tf.keras.Sequential([\n",
293 | " tf.keras.layers.Dense(units=1, input_shape=[1])\n",
294 | "])\n",
295 | "```"
296 | ]
297 | },
298 | {
299 | "cell_type": "markdown",
300 | "metadata": {
301 | "colab_type": "text",
302 | "id": "kiZG7uhm8qCF"
303 | },
304 | "source": [
305 | "## Compile the model, with loss and optimizer functions\n",
306 | "\n",
307 | "Before training, the model has to be compiled. When compiled for training, the model is given:\n",
308 | "\n",
309 | "- **Loss function** — A way of measuring how far off predictions are from the desired outcome. (The measured difference is called the \"loss\".)\n",
310 | "\n",
311 | "- **Optimizer function** — A way of adjusting internal values in order to reduce the loss.\n"
312 | ]
313 | },
314 | {
315 | "cell_type": "code",
316 | "metadata": {
317 | "colab_type": "code",
318 | "id": "m8YQN1H41L-Y",
319 | "colab": {}
320 | },
321 | "source": [
322 | "model.compile(loss='mean_squared_error',\n",
323 | " optimizer=tf.keras.optimizers.Adam(0.1))"
324 | ],
325 | "execution_count": 0,
326 | "outputs": []
327 | },
328 | {
329 | "cell_type": "markdown",
330 | "metadata": {
331 | "colab_type": "text",
332 | "id": "17M3Pqv4P52R"
333 | },
334 | "source": [
335 | "These are used during training (`model.fit()`, below) to first calculate the loss at each point, and then improve it. In fact, the act of calculating the current loss of a model and then improving it is precisely what training is.\n",
336 | "\n",
337 | "During training, the optimizer function is used to calculate adjustments to the model's internal variables. The goal is to adjust the internal variables until the model (which is really a math function) mirrors the actual equation for converting Celsius to Fahrenheit.\n",
338 | "\n",
339 | "TensorFlow uses numerical analysis to perform this tuning, and all this complexity is hidden from you so we will not go into the details here. What is useful to know about these parameters are:\n",
340 | "\n",
341 | "The loss function ([mean squared error](https://en.wikipedia.org/wiki/Mean_squared_error)) and the optimizer ([Adam](https://machinelearningmastery.com/adam-optimization-algorithm-for-deep-learning/)) used here are standard for simple models like this one, but many others are available. It is not important to know how these specific functions work at this point.\n",
342 | "\n",
343 | "One part of the Optimizer you may need to think about when building your own models is the learning rate (`0.1` in the code above). This is the step size taken when adjusting values in the model. If the value is too small, it will take too many iterations to train the model. Too large, and accuracy goes down. Finding a good value often involves some trial and error, but the range is usually within 0.001 (default), and 0.1"
344 | ]
345 | },
346 | {
347 | "cell_type": "markdown",
348 | "metadata": {
349 | "colab_type": "text",
350 | "id": "c-Jk4dG91dvD"
351 | },
352 | "source": [
353 | "## Train the model\n",
354 | "\n",
355 | "Train the model by calling the `fit` method.\n",
356 | "\n",
357 | "During training, the model takes in Celsius values, performs a calculation using the current internal variables (called \"weights\") and outputs values which are meant to be the Fahrenheit equivalent. Since the weights are initially set randomly, the output will not be close to the correct value. The difference between the actual output and the desired output is calculated using the loss function, and the optimizer function directs how the weights should be adjusted.\n",
358 | "\n",
359 | "This cycle of calculate, compare, adjust is controlled by the `fit` method. The first argument is the inputs, the second argument is the desired outputs. The `epochs` argument specifies how many times this cycle should be run, and the `verbose` argument controls how much output the method produces."
360 | ]
361 | },
362 | {
363 | "cell_type": "code",
364 | "metadata": {
365 | "colab_type": "code",
366 | "id": "lpRrl7WK10Pq",
367 | "colab": {}
368 | },
369 | "source": [
370 | "history = model.fit(celsius_q, fahrenheit_a, epochs=500, verbose=False)\n",
371 | "print(\"Finished training the model\")"
372 | ],
373 | "execution_count": 0,
374 | "outputs": []
375 | },
376 | {
377 | "cell_type": "markdown",
378 | "metadata": {
379 | "colab_type": "text",
380 | "id": "GFcIU2-SdCrI"
381 | },
382 | "source": [
383 | "In later videos, we will go into more details on what actually happens here and how a Dense layer actually works internally."
384 | ]
385 | },
386 | {
387 | "cell_type": "markdown",
388 | "metadata": {
389 | "colab_type": "text",
390 | "id": "0-QsNCLD4MJZ"
391 | },
392 | "source": [
393 | "## Display training statistics\n",
394 | "\n",
395 | "The `fit` method returns a history object. We can use this object to plot how the loss of our model goes down after each training epoch. A high loss means that the Fahrenheit degrees the model predicts is far from the corresponding value in `fahrenheit_a`.\n",
396 | "\n",
397 | "We'll use [Matplotlib](https://matplotlib.org/) to visualize this (you could use another tool). As you can see, our model improves very quickly at first, and then has a steady, slow improvement until it is very near \"perfect\" towards the end.\n",
398 | "\n"
399 | ]
400 | },
401 | {
402 | "cell_type": "code",
403 | "metadata": {
404 | "colab_type": "code",
405 | "id": "IeK6BzfbdO6_",
406 | "colab": {}
407 | },
408 | "source": [
409 | "import matplotlib.pyplot as plt\n",
410 | "plt.xlabel('Epoch Number')\n",
411 | "plt.ylabel(\"Loss Magnitude\")\n",
412 | "plt.plot(history.history['loss'])"
413 | ],
414 | "execution_count": 0,
415 | "outputs": []
416 | },
417 | {
418 | "cell_type": "markdown",
419 | "metadata": {
420 | "colab_type": "text",
421 | "id": "LtQGDMob5LOD"
422 | },
423 | "source": [
424 | "## Use the model to predict values\n",
425 | "\n",
426 | "Now you have a model that has been trained to learn the relationship between `celsius_q` and `fahrenheit_a`. You can use the predict method to have it calculate the Fahrenheit degrees for a previously unknown Celsius degrees.\n",
427 | "\n",
428 | "So, for example, if the Celsius value is 100, what do you think the Fahrenheit result will be? Take a guess before you run this code."
429 | ]
430 | },
431 | {
432 | "cell_type": "code",
433 | "metadata": {
434 | "colab_type": "code",
435 | "id": "oxNzL4lS2Gui",
436 | "colab": {}
437 | },
438 | "source": [
439 | "print(model.predict([200.0]))"
440 | ],
441 | "execution_count": 0,
442 | "outputs": []
443 | },
444 | {
445 | "cell_type": "markdown",
446 | "metadata": {
447 | "colab_type": "text",
448 | "id": "jApk6tZ1fBg1"
449 | },
450 | "source": [
451 | "The correct answer is $100 \\times 1.8 + 32 = 212$, so our model is doing really well.\n",
452 | "\n",
453 | "### To review\n",
454 | "\n",
455 | "\n",
456 | "* We created a model with a Dense layer\n",
457 | "* We trained it with 3500 examples (7 pairs, over 500 epochs).\n",
458 | "\n",
459 | "Our model tuned the variables (weights) in the Dense layer until it was able to return the correct Fahrenheit value for any Celsius value. (Remember, 100 Celsius was not part of our training data.)\n",
460 | "\n",
461 | "\n"
462 | ]
463 | },
464 | {
465 | "cell_type": "markdown",
466 | "metadata": {
467 | "colab_type": "text",
468 | "id": "zRrOky5gm20Z"
469 | },
470 | "source": [
471 | "## Looking at the layer weights\n",
472 | "\n",
473 | "Finally, let's print the internal variables of the Dense layer. "
474 | ]
475 | },
476 | {
477 | "cell_type": "code",
478 | "metadata": {
479 | "colab_type": "code",
480 | "id": "kmIkVdkbnZJI",
481 | "colab": {}
482 | },
483 | "source": [
484 | "print(\"These are the layer variables: {}\".format(l0.get_weights()))"
485 | ],
486 | "execution_count": 0,
487 | "outputs": []
488 | },
489 | {
490 | "cell_type": "markdown",
491 | "metadata": {
492 | "colab_type": "text",
493 | "id": "RSplSnMvnWC-"
494 | },
495 | "source": [
496 | "The first variable is close to ~1.8 and the second to ~32. These values (1.8 and 32) are the actual variables in the real conversion formula.\n",
497 | "\n",
498 | "This is really close to the values in the conversion formula. We'll explain this in an upcoming video where we show how a Dense layer works, but for a single neuron with a single input and a single output, the internal math looks the same as [the equation for a line](https://en.wikipedia.org/wiki/Linear_equation#Slope%E2%80%93intercept_form), $y = mx + b$, which has the same form as the conversion equation, $f = 1.8c + 32$.\n",
499 | "\n",
500 | "Since the form is the same, the variables should converge on the standard values of 1.8 and 32, which is exactly what happened.\n",
501 | "\n",
502 | "With additional neurons, additional inputs, and additional outputs, the formula becomes much more complex, but the idea is the same.\n",
503 | "\n",
504 | "### A little experiment\n",
505 | "\n",
506 | "Just for fun, what if we created more Dense layers with different units, which therefore also has more variables?"
507 | ]
508 | },
509 | {
510 | "cell_type": "code",
511 | "metadata": {
512 | "colab_type": "code",
513 | "id": "Y2zTA-rDS5Xk",
514 | "colab": {}
515 | },
516 | "source": [
517 | "l0 = tf.keras.layers.Dense(units=4, input_shape=[1])\n",
518 | "l1 = tf.keras.layers.Dense(units=4)\n",
519 | "l2 = tf.keras.layers.Dense(units=1)\n",
520 | "model = tf.keras.Sequential([l0, l1, l2])\n",
521 | "model.compile(loss='mean_squared_error', optimizer=tf.keras.optimizers.Adam(0.1))\n",
522 | "model.fit(celsius_q, fahrenheit_a, epochs=500, verbose=False)\n",
523 | "print(\"Finished training the model\")\n",
524 | "print(model.predict([100.0]))\n",
525 | "print(\"Model predicts that 100 degrees Celsius is: {} degrees Fahrenheit\".format(model.predict([100.0])))\n",
526 | "print(\"These are the l0 variables: {}\".format(l0.get_weights()))\n",
527 | "print(\"These are the l1 variables: {}\".format(l1.get_weights()))\n",
528 | "print(\"These are the l2 variables: {}\".format(l2.get_weights()))"
529 | ],
530 | "execution_count": 0,
531 | "outputs": []
532 | },
533 | {
534 | "cell_type": "markdown",
535 | "metadata": {
536 | "colab_type": "text",
537 | "id": "xrpFFlgYhCty"
538 | },
539 | "source": [
540 | "As you can see, this model is also able to predict the corresponding Fahrenheit value really well. But when you look at the variables (weights) in the `l0` and `l1` layers, they are nothing even close to ~1.8 and ~32. The added complexity hides the \"simple\" form of the conversion equation."
541 | ]
542 | }
543 | ]
544 | }
--------------------------------------------------------------------------------
/Common_Patterns(Time_Series_Forecasting).ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "Common Patterns(Time Series Forecasting).ipynb",
7 | "provenance": [],
8 | "private_outputs": true,
9 | "collapsed_sections": [],
10 | "toc_visible": true,
11 | "include_colab_link": true
12 | },
13 | "kernelspec": {
14 | "display_name": "Python 3",
15 | "name": "python3"
16 | }
17 | },
18 | "cells": [
19 | {
20 | "cell_type": "markdown",
21 | "metadata": {
22 | "id": "view-in-github",
23 | "colab_type": "text"
24 | },
25 | "source": [
26 | "
"
27 | ]
28 | },
29 | {
30 | "cell_type": "markdown",
31 | "metadata": {
32 | "colab_type": "text",
33 | "id": "Za8-Nr5k11fh"
34 | },
35 | "source": [
36 | "##### Copyright 2018 The TensorFlow Authors."
37 | ]
38 | },
39 | {
40 | "cell_type": "code",
41 | "metadata": {
42 | "cellView": "form",
43 | "colab_type": "code",
44 | "id": "Eq10uEbw0E4l",
45 | "colab": {}
46 | },
47 | "source": [
48 | "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
49 | "# you may not use this file except in compliance with the License.\n",
50 | "# You may obtain a copy of the License at\n",
51 | "#\n",
52 | "# https://www.apache.org/licenses/LICENSE-2.0\n",
53 | "#\n",
54 | "# Unless required by applicable law or agreed to in writing, software\n",
55 | "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
56 | "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
57 | "# See the License for the specific language governing permissions and\n",
58 | "# limitations under the License."
59 | ],
60 | "execution_count": 0,
61 | "outputs": []
62 | },
63 | {
64 | "cell_type": "markdown",
65 | "metadata": {
66 | "colab_type": "text",
67 | "id": "Ivi7Bm7thgCT"
68 | },
69 | "source": [
70 | "# Common patterns"
71 | ]
72 | },
73 | {
74 | "cell_type": "markdown",
75 | "metadata": {
76 | "colab_type": "text",
77 | "id": "vidayERjaO5q"
78 | },
79 | "source": [
80 | "## Setup"
81 | ]
82 | },
83 | {
84 | "cell_type": "code",
85 | "metadata": {
86 | "colab_type": "code",
87 | "id": "LVQoKzvQvaci",
88 | "colab": {}
89 | },
90 | "source": [
91 | "from __future__ import absolute_import, division, print_function, unicode_literals"
92 | ],
93 | "execution_count": 0,
94 | "outputs": []
95 | },
96 | {
97 | "cell_type": "code",
98 | "metadata": {
99 | "colab_type": "code",
100 | "id": "gqWabzlJ63nL",
101 | "colab": {}
102 | },
103 | "source": [
104 | "import numpy as np\n",
105 | "import matplotlib.pyplot as plt"
106 | ],
107 | "execution_count": 0,
108 | "outputs": []
109 | },
110 | {
111 | "cell_type": "code",
112 | "metadata": {
113 | "colab_type": "code",
114 | "id": "sJwA96JU00pW",
115 | "colab": {}
116 | },
117 | "source": [
118 | "def plot_series(time, series, format=\"-\", start=0, end=None, label=None):\n",
119 | " plt.plot(time[start:end], series[start:end], format, label=label)\n",
120 | " plt.xlabel(\"Time\")\n",
121 | " plt.ylabel(\"Value\")\n",
122 | " if label:\n",
123 | " plt.legend(fontsize=14)\n",
124 | " plt.grid(True)"
125 | ],
126 | "execution_count": 0,
127 | "outputs": []
128 | },
129 | {
130 | "cell_type": "markdown",
131 | "metadata": {
132 | "colab_type": "text",
133 | "id": "yVo6CcpRaW7u"
134 | },
135 | "source": [
136 | "## Trend and Seasonality"
137 | ]
138 | },
139 | {
140 | "cell_type": "code",
141 | "metadata": {
142 | "colab_type": "code",
143 | "id": "t30Ts2KjiOIY",
144 | "colab": {}
145 | },
146 | "source": [
147 | "def trend(time, slope=0):\n",
148 | " return slope * time"
149 | ],
150 | "execution_count": 0,
151 | "outputs": []
152 | },
153 | {
154 | "cell_type": "markdown",
155 | "metadata": {
156 | "colab_type": "text",
157 | "id": "iJjc3G1Maefn"
158 | },
159 | "source": [
160 | "Let's create a time series that just trends upward:"
161 | ]
162 | },
163 | {
164 | "cell_type": "code",
165 | "metadata": {
166 | "colab_type": "code",
167 | "id": "BLt-pLiZ0nfB",
168 | "colab": {}
169 | },
170 | "source": [
171 | "time = np.arange(4 * 365 + 1)\n",
172 | "baseline = 10\n",
173 | "series = baseline + trend(time, 0.1)\n",
174 | "\n",
175 | "plt.figure(figsize=(10, 6))\n",
176 | "plot_series(time, series)\n",
177 | "plt.show()"
178 | ],
179 | "execution_count": 0,
180 | "outputs": []
181 | },
182 | {
183 | "cell_type": "code",
184 | "metadata": {
185 | "colab_type": "code",
186 | "id": "3-4hV2WHTC_F",
187 | "colab": {}
188 | },
189 | "source": [
190 | "time"
191 | ],
192 | "execution_count": 0,
193 | "outputs": []
194 | },
195 | {
196 | "cell_type": "code",
197 | "metadata": {
198 | "colab_type": "code",
199 | "id": "eOK7NnaOTGa7",
200 | "colab": {}
201 | },
202 | "source": [
203 | "series"
204 | ],
205 | "execution_count": 0,
206 | "outputs": []
207 | },
208 | {
209 | "cell_type": "markdown",
210 | "metadata": {
211 | "colab_type": "text",
212 | "id": "WKD4nh9sauBf"
213 | },
214 | "source": [
215 | "Now let's generate a time series with a seasonal pattern:"
216 | ]
217 | },
218 | {
219 | "cell_type": "code",
220 | "metadata": {
221 | "colab_type": "code",
222 | "id": "89gdEnPY1Niy",
223 | "colab": {}
224 | },
225 | "source": [
226 | "def seasonal_pattern(season_time):\n",
227 | " \"\"\"Just an arbitrary pattern, you can change it if you wish\"\"\"\n",
228 | " return np.where(season_time < 0.4,\n",
229 | " np.cos(season_time * 2 * np.pi),\n",
230 | " 1 / np.exp(3 * season_time))\n",
231 | "\n",
232 | "def seasonality(time, period, amplitude=1, phase=0):\n",
233 | " \"\"\"Repeats the same pattern at each period\"\"\"\n",
234 | " season_time = ((time + phase) % period) / period\n",
235 | " return amplitude * seasonal_pattern(season_time)"
236 | ],
237 | "execution_count": 0,
238 | "outputs": []
239 | },
240 | {
241 | "cell_type": "code",
242 | "metadata": {
243 | "colab_type": "code",
244 | "id": "7kaNezUk1S9l",
245 | "colab": {}
246 | },
247 | "source": [
248 | "amplitude = 40\n",
249 | "series = seasonality(time, period=365, amplitude=amplitude)\n",
250 | "\n",
251 | "plt.figure(figsize=(10, 6))\n",
252 | "plot_series(time, series)\n",
253 | "plt.show()"
254 | ],
255 | "execution_count": 0,
256 | "outputs": []
257 | },
258 | {
259 | "cell_type": "markdown",
260 | "metadata": {
261 | "colab_type": "text",
262 | "id": "-Vo433h0bDLD"
263 | },
264 | "source": [
265 | "Now let's create a time series with both trend and seasonality:"
266 | ]
267 | },
268 | {
269 | "cell_type": "code",
270 | "metadata": {
271 | "colab_type": "code",
272 | "id": "AyqFdaIN1oy5",
273 | "colab": {}
274 | },
275 | "source": [
276 | "slope = 0.05\n",
277 | "series = baseline + trend(time, slope) + seasonality(time, period=365, amplitude=amplitude)\n",
278 | "\n",
279 | "plt.figure(figsize=(10, 6))\n",
280 | "plot_series(time, series)\n",
281 | "plt.show()"
282 | ],
283 | "execution_count": 0,
284 | "outputs": []
285 | },
286 | {
287 | "cell_type": "markdown",
288 | "metadata": {
289 | "colab_type": "text",
290 | "id": "YVdJ2jNN8OHk"
291 | },
292 | "source": [
293 | "## Noise"
294 | ]
295 | },
296 | {
297 | "cell_type": "markdown",
298 | "metadata": {
299 | "colab_type": "text",
300 | "id": "V4taP424sces"
301 | },
302 | "source": [
303 | "In practice few real-life time series have such a smooth signal. They usually have some noise, and the signal-to-noise ratio can sometimes be very low. Let's generate some white noise:"
304 | ]
305 | },
306 | {
307 | "cell_type": "code",
308 | "metadata": {
309 | "colab_type": "code",
310 | "id": "3kD3_zjVscBH",
311 | "colab": {}
312 | },
313 | "source": [
314 | "def white_noise(time, noise_level=1, seed=None):\n",
315 | " rnd = np.random.RandomState(seed)\n",
316 | " return rnd.randn(len(time)) * noise_level"
317 | ],
318 | "execution_count": 0,
319 | "outputs": []
320 | },
321 | {
322 | "cell_type": "code",
323 | "metadata": {
324 | "colab_type": "code",
325 | "id": "aLvBwrKrtDzo",
326 | "colab": {}
327 | },
328 | "source": [
329 | "noise_level = 5\n",
330 | "noise = white_noise(time, noise_level, seed=42)\n",
331 | "\n",
332 | "plt.figure(figsize=(10, 6))\n",
333 | "plot_series(time, noise)\n",
334 | "plt.show()"
335 | ],
336 | "execution_count": 0,
337 | "outputs": []
338 | },
339 | {
340 | "cell_type": "markdown",
341 | "metadata": {
342 | "colab_type": "text",
343 | "id": "GHa6gicgbL74"
344 | },
345 | "source": [
346 | "Now let's add this white noise to the time series:"
347 | ]
348 | },
349 | {
350 | "cell_type": "code",
351 | "metadata": {
352 | "colab_type": "code",
353 | "id": "2bRDx8K816N9",
354 | "colab": {}
355 | },
356 | "source": [
357 | "series += noise\n",
358 | "\n",
359 | "plt.figure(figsize=(10, 6))\n",
360 | "plot_series(time, series)\n",
361 | "plt.show()"
362 | ],
363 | "execution_count": 0,
364 | "outputs": []
365 | },
366 | {
367 | "cell_type": "code",
368 | "metadata": {
369 | "colab_type": "code",
370 | "id": "Hn9MwfC9YtEd",
371 | "colab": {}
372 | },
373 | "source": [
374 | ""
375 | ],
376 | "execution_count": 0,
377 | "outputs": []
378 | }
379 | ]
380 | }
--------------------------------------------------------------------------------
/Flowers_with_transfer_learning.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "accelerator": "GPU",
6 | "colab": {
7 | "name": "Flowers_with_transfer_learning.ipynb",
8 | "provenance": [],
9 | "private_outputs": true,
10 | "collapsed_sections": [],
11 | "toc_visible": true,
12 | "include_colab_link": true
13 | },
14 | "kernelspec": {
15 | "display_name": "Python 3",
16 | "name": "python3"
17 | }
18 | },
19 | "cells": [
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {
23 | "id": "view-in-github",
24 | "colab_type": "text"
25 | },
26 | "source": [
27 | "
"
28 | ]
29 | },
30 | {
31 | "cell_type": "markdown",
32 | "metadata": {
33 | "colab_type": "text",
34 | "id": "W_tvPdyfA-BL"
35 | },
36 | "source": [
37 | "##### Copyright 2019 The TensorFlow Authors."
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "metadata": {
43 | "cellView": "form",
44 | "colab_type": "code",
45 | "id": "0O_LFhwSBCjm",
46 | "colab": {}
47 | },
48 | "source": [
49 | "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
50 | "# you may not use this file except in compliance with the License.\n",
51 | "# You may obtain a copy of the License at\n",
52 | "#\n",
53 | "# https://www.apache.org/licenses/LICENSE-2.0\n",
54 | "#\n",
55 | "# Unless required by applicable law or agreed to in writing, software\n",
56 | "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
57 | "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
58 | "# See the License for the specific language governing permissions and\n",
59 | "# limitations under the License."
60 | ],
61 | "execution_count": 0,
62 | "outputs": []
63 | },
64 | {
65 | "cell_type": "markdown",
66 | "metadata": {
67 | "colab_type": "text",
68 | "id": "NxjpzKTvg_dd"
69 | },
70 | "source": [
71 | "# TensorFlow Hub"
72 | ]
73 | },
74 | {
75 | "cell_type": "markdown",
76 | "metadata": {
77 | "colab_type": "text",
78 | "id": "crU-iluJIEzw"
79 | },
80 | "source": [
81 | "[TensorFlow Hub](http://tensorflow.org/hub) is an online repository of already trained TensorFlow models that you can use.\n",
82 | "These models can either be used as is, or they can be used for Transfer Learning.\n",
83 | "\n",
84 | "Transfer learning is a process where you take an existing trained model, and extend it to do additional work. This involves leaving the bulk of the model unchanged, while adding and retraining the final layers, in order to get a different set of possible outputs.\n",
85 | "\n",
86 | "Here, you can see all the models available in [TensorFlow Module Hub](https://tfhub.dev/).\n",
87 | "\n",
88 | "Before starting this Colab, you should reset the Colab environment by selecting `Runtime -> Reset all runtimes...` from menu above."
89 | ]
90 | },
91 | {
92 | "cell_type": "markdown",
93 | "metadata": {
94 | "colab_type": "text",
95 | "id": "7RVsYZLEpEWs"
96 | },
97 | "source": [
98 | "# Imports\n",
99 | "\n"
100 | ]
101 | },
102 | {
103 | "cell_type": "markdown",
104 | "metadata": {
105 | "colab_type": "text",
106 | "id": "ZUCEcRdhnyWn"
107 | },
108 | "source": [
109 | "Some normal imports we've seen before. The new one is importing tensorflow_hub which this Colab will make heavy use of."
110 | ]
111 | },
112 | {
113 | "cell_type": "code",
114 | "metadata": {
115 | "colab_type": "code",
116 | "id": "OGNpmn43C0O6",
117 | "colab": {}
118 | },
119 | "source": [
120 | "from __future__ import absolute_import, division, print_function, unicode_literals"
121 | ],
122 | "execution_count": 0,
123 | "outputs": []
124 | },
125 | {
126 | "cell_type": "code",
127 | "metadata": {
128 | "colab_type": "code",
129 | "id": "zIuDCLW_IAG_",
130 | "colab": {}
131 | },
132 | "source": [
133 | "try:\n",
134 | " # Use the %tensorflow_version magic if in colab.\n",
135 | " %tensorflow_version 2.x\n",
136 | "except Exception:\n",
137 | " pass\n",
138 | "\n",
139 | "import tensorflow as tf"
140 | ],
141 | "execution_count": 0,
142 | "outputs": []
143 | },
144 | {
145 | "cell_type": "code",
146 | "metadata": {
147 | "colab_type": "code",
148 | "id": "dHenfza_ICJL",
149 | "colab": {}
150 | },
151 | "source": [
152 | "import numpy as np\n",
153 | "import matplotlib.pyplot as plt\n",
154 | "\n",
155 | "import tensorflow_hub as hub\n",
156 | "import tensorflow_datasets as tfds\n",
157 | "\n",
158 | "from tensorflow.keras import layers"
159 | ],
160 | "execution_count": 0,
161 | "outputs": []
162 | },
163 | {
164 | "cell_type": "code",
165 | "metadata": {
166 | "colab_type": "code",
167 | "id": "gEsgwsqbHFn2",
168 | "colab": {}
169 | },
170 | "source": [
171 | "import logging\n",
172 | "logger = tf.get_logger()\n",
173 | "logger.setLevel(logging.ERROR)"
174 | ],
175 | "execution_count": 0,
176 | "outputs": []
177 | },
178 | {
179 | "cell_type": "markdown",
180 | "metadata": {
181 | "colab_type": "text",
182 | "id": "amfzqn1Oo7Om"
183 | },
184 | "source": [
185 | "# Download the Flowers Dataset using TensorFlow Datasets"
186 | ]
187 | },
188 | {
189 | "cell_type": "markdown",
190 | "metadata": {
191 | "colab_type": "text",
192 | "id": "Z93vvAdGxDMD"
193 | },
194 | "source": [
195 | "In the cell below you will download the Flowers dataset using TensorFlow Datasets. If you look at the [TensorFlow Datasets documentation](https://www.tensorflow.org/datasets/datasets#tf_flowers) you will see that the name of the Flowers dataset is `tf_flowers`. You can also see that this dataset is only split into a TRAINING set. You will therefore have to use `tfds.splits` to split this training set into to a `training_set` and a `validation_set`. Do a `[70, 30]` split such that 70 corresponds to the `training_set` and 30 to the `validation_set`. Then load the `tf_flowers` dataset using `tfds.load`. Make sure the `tfds.load` function uses the all the parameters you need, and also make sure it returns the dataset info, so we can retrieve information about the datasets.\n",
196 | "\n",
197 | "\n"
198 | ]
199 | },
200 | {
201 | "cell_type": "code",
202 | "metadata": {
203 | "colab_type": "code",
204 | "id": "oXiJjX0jfx1o",
205 | "colab": {}
206 | },
207 | "source": [
208 | "splits = tfds.Split.TRAIN.subsplit([70, 30])\n",
209 | "\n",
210 | "(training_set, validation_set), dataset_info = tfds.load('tf_flowers', with_info=True, as_supervised=True, split=splits)"
211 | ],
212 | "execution_count": 0,
213 | "outputs": []
214 | },
215 | {
216 | "cell_type": "markdown",
217 | "metadata": {
218 | "colab_type": "text",
219 | "id": "X0p1sOEHf0JF"
220 | },
221 | "source": [
222 | "# Print Information about the Flowers Dataset\n",
223 | "\n",
224 | "Now that you have downloaded the dataset, use the dataset info to print the number of classes in the dataset, and also write some code that counts how many images we have in the training and validation sets. "
225 | ]
226 | },
227 | {
228 | "cell_type": "code",
229 | "metadata": {
230 | "colab_type": "code",
231 | "id": "DrIUV3V0xDL_",
232 | "colab": {}
233 | },
234 | "source": [
235 | "num_classes = dataset_info.features['label'].num_classes\n",
236 | "\n",
237 | "num_training_examples = 0\n",
238 | "num_validation_examples = 0\n",
239 | "\n",
240 | "for example in training_set:\n",
241 | " num_training_examples += 1\n",
242 | "\n",
243 | "for example in validation_set:\n",
244 | " num_validation_examples += 1\n",
245 | "\n",
246 | "print('Total Number of Classes: {}'.format(num_classes))\n",
247 | "print('Total Number of Training Images: {}'.format(num_training_examples))\n",
248 | "print('Total Number of Validation Images: {} \\n'.format(num_validation_examples))"
249 | ],
250 | "execution_count": 0,
251 | "outputs": []
252 | },
253 | {
254 | "cell_type": "markdown",
255 | "metadata": {
256 | "colab_type": "text",
257 | "id": "UlFZ_hwjCLgS"
258 | },
259 | "source": [
260 | "The images in the Flowers dataset are not all the same size."
261 | ]
262 | },
263 | {
264 | "cell_type": "code",
265 | "metadata": {
266 | "colab_type": "code",
267 | "id": "W4lDPkn2cpWZ",
268 | "colab": {}
269 | },
270 | "source": [
271 | "for i, example in enumerate(training_set.take(5)):\n",
272 | " print('Image {} shape: {} label: {}'.format(i+1, example[0].shape, example[1]))"
273 | ],
274 | "execution_count": 0,
275 | "outputs": []
276 | },
277 | {
278 | "cell_type": "markdown",
279 | "metadata": {
280 | "colab_type": "text",
281 | "id": "mbgpD3E6gM2P"
282 | },
283 | "source": [
284 | "# Reformat Images and Create Batches\n",
285 | "\n",
286 | "In the cell below create a function that reformats all images to the resolution expected by MobileNet v2 (224, 224) and normalizes them. The function should take in an `image` and a `label` as arguments and should return the new `image` and corresponding `label`. Then create training and validation batches of size `32`."
287 | ]
288 | },
289 | {
290 | "cell_type": "code",
291 | "metadata": {
292 | "colab_type": "code",
293 | "id": "we_ftzQxNf7e",
294 | "colab": {}
295 | },
296 | "source": [
297 | "IMAGE_RES = 224\n",
298 | "\n",
299 | "def format_image(image, label):\n",
300 | " image = tf.image.resize(image, (IMAGE_RES, IMAGE_RES)) / 255.0\n",
301 | " return image, label\n",
302 | "\n",
303 | "BATCH_SIZE = 32\n",
304 | "\n",
305 | "train_batches = training_set.shuffle(num_training_examples//4).map(format_image).batch(BATCH_SIZE).prefetch(1) \n",
306 | "\n",
307 | "validation_batches = validation_set.map(format_image).batch(BATCH_SIZE).prefetch(1)"
308 | ],
309 | "execution_count": 0,
310 | "outputs": []
311 | },
312 | {
313 | "cell_type": "markdown",
314 | "metadata": {
315 | "colab_type": "text",
316 | "id": "JzV457OXreQP"
317 | },
318 | "source": [
319 | "# Do Simple Transfer Learning with TensorFlow Hub\n",
320 | "\n",
321 | "Let's now use TensorFlow Hub to do Transfer Learning. Remember, in transfer learning we reuse parts of an already trained model and change the final layer, or several layers, of the model, and then retrain those layers on our own dataset.\n",
322 | "\n",
323 | "### Create a Feature Extractor\n",
324 | "In the cell below create a `feature_extractor` using MobileNet v2. Remember that the partial model from TensorFlow Hub (without the final classification layer) is called a feature vector. Go to the [TensorFlow Hub documentation](https://tfhub.dev/s?module-type=image-feature-vector&q=tf2) to see a list of available feature vectors. Click on the `tf2-preview/mobilenet_v2/feature_vector`. Read the documentation and get the corresponding `URL` to get the MobileNet v2 feature vector. Finally, create a `feature_extractor` by using `hub.KerasLayer` with the correct `input_shape` parameter."
325 | ]
326 | },
327 | {
328 | "cell_type": "code",
329 | "metadata": {
330 | "colab_type": "code",
331 | "id": "5wB030nezBwI",
332 | "colab": {}
333 | },
334 | "source": [
335 | "URL = \"https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4\"\n",
336 | "feature_extractor = hub.KerasLayer(URL, input_shape=(IMAGE_RES, IMAGE_RES, 3))"
337 | ],
338 | "execution_count": 0,
339 | "outputs": []
340 | },
341 | {
342 | "cell_type": "markdown",
343 | "metadata": {
344 | "colab_type": "text",
345 | "id": "CtFmF7A5E4tk"
346 | },
347 | "source": [
348 | "### Freeze the Pre-Trained Model\n",
349 | "\n",
350 | "In the cell below freeze the variables in the feature extractor layer, so that the training only modifies the final classifier layer."
351 | ]
352 | },
353 | {
354 | "cell_type": "code",
355 | "metadata": {
356 | "colab_type": "code",
357 | "id": "Jg5ar6rcE4H-",
358 | "colab": {}
359 | },
360 | "source": [
361 | "feature_extractor.trainable = False"
362 | ],
363 | "execution_count": 0,
364 | "outputs": []
365 | },
366 | {
367 | "cell_type": "markdown",
368 | "metadata": {
369 | "colab_type": "text",
370 | "id": "RPVeouTksO9q"
371 | },
372 | "source": [
373 | "### Attach a classification head\n",
374 | "\n",
375 | "In the cell below create a `tf.keras.Sequential` model, and add the pre-trained model and the new classification layer. Remember that the classification layer must have the same number of classes as our Flowers dataset. Finally print a summary of the Sequential model."
376 | ]
377 | },
378 | {
379 | "cell_type": "code",
380 | "metadata": {
381 | "colab_type": "code",
382 | "id": "mGcY27fY1q3Q",
383 | "colab": {}
384 | },
385 | "source": [
386 | "model = tf.keras.Sequential([\n",
387 | " feature_extractor,\n",
388 | " layers.Dense(num_classes, activation = 'softmax')\n",
389 | "])\n",
390 | "\n",
391 | "model.summary()"
392 | ],
393 | "execution_count": 0,
394 | "outputs": []
395 | },
396 | {
397 | "cell_type": "markdown",
398 | "metadata": {
399 | "colab_type": "text",
400 | "id": "OHbXQqIquFxQ"
401 | },
402 | "source": [
403 | "### Train the model\n",
404 | "\n",
405 | "In the cell bellow train this model like any other, by first calling `compile` and then followed by `fit`. Make sure you use the proper parameters when applying both methods. Train the model for only 6 epochs."
406 | ]
407 | },
408 | {
409 | "cell_type": "code",
410 | "metadata": {
411 | "colab_type": "code",
412 | "id": "3n0Wb9ylKd8R",
413 | "colab": {}
414 | },
415 | "source": [
416 | "model.compile(\n",
417 | " optimizer = 'adam',\n",
418 | " loss = 'sparse_categorical_crossentropy',\n",
419 | " metrics = ['accuracy']\n",
420 | ")\n",
421 | "\n",
422 | "EPOCHS = 6\n",
423 | "\n",
424 | "history = model.fit(\n",
425 | " train_batches,\n",
426 | " epochs = EPOCHS,\n",
427 | " validation_data = validation_batches\n",
428 | ")"
429 | ],
430 | "execution_count": 0,
431 | "outputs": []
432 | },
433 | {
434 | "cell_type": "markdown",
435 | "metadata": {
436 | "colab_type": "text",
437 | "id": "76as-K8-vFQJ"
438 | },
439 | "source": [
440 | "You can see we get ~88% validation accuracy with only 6 epochs of training, which is absolutely awesome. This is a huge improvement over the model we created in the previous lesson, where we were able to get ~76% accuracy with 80 epochs of training. The reason for this difference is that MobileNet v2 was carefully designed over a long time by experts, then trained on a massive dataset (ImageNet)."
441 | ]
442 | },
443 | {
444 | "cell_type": "markdown",
445 | "metadata": {
446 | "colab_type": "text",
447 | "id": "SLxTcprUqJaq"
448 | },
449 | "source": [
450 | "# Plot Training and Validation Graphs\n",
451 | "\n",
452 | "In the cell below, plot the training and validation accuracy/loss graphs."
453 | ]
454 | },
455 | {
456 | "cell_type": "code",
457 | "metadata": {
458 | "colab_type": "code",
459 | "id": "d28dhbFpr98b",
460 | "colab": {}
461 | },
462 | "source": [
463 | "acc = history.history['accuracy']\n",
464 | "val_acc = history.history['val_accuracy']\n",
465 | "\n",
466 | "loss = history.history['loss']\n",
467 | "val_loss = history.history['val_loss']\n",
468 | "\n",
469 | "epochs_range = range(EPOCHS)\n",
470 | "\n",
471 | "plt.figure(figsize = (8, 8))\n",
472 | "\n",
473 | "plt.subplot(1, 2, 1)\n",
474 | "plt.plot(epochs_range, acc, label = 'Training Accuracy')\n",
475 | "plt.plot(epochs_range, val_acc, label = 'Validation Accuracy')\n",
476 | "plt.legend(loc = 'lower right')\n",
477 | "plt.title('Training and Validation Accuracy')\n",
478 | "\n",
479 | "plt.subplot(1, 2, 2)\n",
480 | "plt.plot(epochs_range, loss, label = 'Training Loss')\n",
481 | "plt.plot(epochs_range, val_loss, label = 'Validation Loss')\n",
482 | "plt.legend(loc = 'upper right')\n",
483 | "plt.title('Training and Validation Loss')\n",
484 | "\n",
485 | "plt.show()"
486 | ],
487 | "execution_count": 0,
488 | "outputs": []
489 | },
490 | {
491 | "cell_type": "markdown",
492 | "metadata": {
493 | "colab_type": "text",
494 | "id": "5zmoDisGvNye"
495 | },
496 | "source": [
497 | "What is a bit curious here is that validation performance is better than training performance, right from the start to the end of execution.\n",
498 | "\n",
499 | "One reason for this is that validation performance is measured at the end of the epoch, but training performance is the average values across the epoch.\n",
500 | "\n",
501 | "The bigger reason though is that we're reusing a large part of MobileNet which is already trained on Flower images. "
502 | ]
503 | },
504 | {
505 | "cell_type": "markdown",
506 | "metadata": {
507 | "colab_type": "text",
508 | "id": "kb__ZN8uFn-D"
509 | },
510 | "source": [
511 | "# Check Predictions\n",
512 | "\n",
513 | "In the cell below get the label names from the dataset info and convert them into a NumPy array. Print the array to make sure you have the correct label names."
514 | ]
515 | },
516 | {
517 | "cell_type": "code",
518 | "metadata": {
519 | "colab_type": "code",
520 | "id": "W_Zvg2i0fzJu",
521 | "colab": {}
522 | },
523 | "source": [
524 | "class_names = np.array(dataset_info.features['label'].names)\n",
525 | "\n",
526 | "print(class_names)"
527 | ],
528 | "execution_count": 0,
529 | "outputs": []
530 | },
531 | {
532 | "cell_type": "markdown",
533 | "metadata": {
534 | "colab_type": "text",
535 | "id": "4Olg6MsNGJTL"
536 | },
537 | "source": [
538 | "### Create an Image Batch and Make Predictions\n",
539 | "\n",
540 | "In the cell below, use the `next()` function to create an `image_batch` and its corresponding `label_batch`. Convert both the `image_batch` and `label_batch` to numpy arrays using the `.numpy()` method. Then use the `.predict()` method to run the image batch through your model and make predictions. Then use the `np.argmax()` function to get the indices of the best prediction for each image. Finally convert the indices of the best predictions to class names."
541 | ]
542 | },
543 | {
544 | "cell_type": "code",
545 | "metadata": {
546 | "colab_type": "code",
547 | "id": "fCLVCpEjJ_VP",
548 | "colab": {}
549 | },
550 | "source": [
551 | "image_batch, label_batch = next(iter(train_batches))\n",
552 | "\n",
553 | "image_batch = image_batch.numpy()\n",
554 | "label_batch = label_batch.numpy()\n",
555 | "\n",
556 | "predicted_batch = model.predict(image_batch)\n",
557 | "predicted_batch = tf.squeeze(predicted_batch).numpy()\n",
558 | "\n",
559 | "predicted_ids = np.argmax(predicted_batch, axis = -1)\n",
560 | "predicted_class_names = class_names[predicted_ids]\n",
561 | "\n",
562 | "print(predicted_class_names)\n",
563 | "\n"
564 | ],
565 | "execution_count": 0,
566 | "outputs": []
567 | },
568 | {
569 | "cell_type": "markdown",
570 | "metadata": {
571 | "colab_type": "text",
572 | "id": "CkGbZxl9GZs-"
573 | },
574 | "source": [
575 | "### Print True Labels and Predicted Indices\n",
576 | "\n",
577 | "In the cell below, print the true labels and the indices of predicted labels."
578 | ]
579 | },
580 | {
581 | "cell_type": "code",
582 | "metadata": {
583 | "colab_type": "code",
584 | "id": "nL9IhOmGI5dJ",
585 | "colab": {}
586 | },
587 | "source": [
588 | "print(\"Labels: \", label_batch)\n",
589 | "print(\"Predicted labels: \", predicted_ids)"
590 | ],
591 | "execution_count": 0,
592 | "outputs": []
593 | },
594 | {
595 | "cell_type": "markdown",
596 | "metadata": {
597 | "colab_type": "text",
598 | "id": "gJDyzEfYuFcW"
599 | },
600 | "source": [
601 | "# Plot Model Predictions"
602 | ]
603 | },
604 | {
605 | "cell_type": "code",
606 | "metadata": {
607 | "colab_type": "code",
608 | "id": "wC_AYRJU9NQe",
609 | "colab": {}
610 | },
611 | "source": [
612 | "plt.figure(figsize=(10,9))\n",
613 | "for n in range(30):\n",
614 | " plt.subplot(6,5,n+1)\n",
615 | " plt.subplots_adjust(hspace = 0.3)\n",
616 | " plt.imshow(image_batch[n])\n",
617 | " color = \"blue\" if predicted_ids[n] == label_batch[n] else \"red\"\n",
618 | " plt.title(predicted_class_names[n].title(), color=color)\n",
619 | " plt.axis('off')\n",
620 | "_ = plt.suptitle(\"Model predictions (blue: correct, red: incorrect)\")"
621 | ],
622 | "execution_count": 0,
623 | "outputs": []
624 | },
625 | {
626 | "cell_type": "markdown",
627 | "metadata": {
628 | "colab_type": "text",
629 | "id": "7QBKxS5CuKhc"
630 | },
631 | "source": [
632 | "# Perform Transfer Learning with the Inception Model\n",
633 | "\n",
634 | "Go to the [TensorFlow Hub documentation](https://tfhub.dev/s?module-type=image-feature-vector&q=tf2) and click on `tf2-preview/inception_v3/feature_vector`. This feature vector corresponds to the Inception v3 model. In the cells below, use transfer learning to create a CNN that uses Inception v3 as the pretrained model to classify the images from the Flowers dataset. Note that Inception, takes as input, images that are 299 x 299 pixels. Compare the accuracy you get with Inception v3 to the accuracy you got with MobileNet v2."
635 | ]
636 | },
637 | {
638 | "cell_type": "code",
639 | "metadata": {
640 | "colab_type": "code",
641 | "id": "14lmpJhpwLgd",
642 | "colab": {}
643 | },
644 | "source": [
645 | "IMAGE_RES = 299\n",
646 | "\n",
647 | "(training_set, validation_set), dataset_info = tfds.load('tf_flowers', with_info=True, as_supervised=True, split=splits)\n",
648 | "\n",
649 | "train_batches = training_set.shuffle(num_training_examples//4).map(format_image).batch(BATCH_SIZE).prefetch(1)\n",
650 | "validation_batches = validation_set.map(format_image).batch(BATCH_SIZE).prefetch(1)\n",
651 | "\n",
652 | "URL = \"https://tfhub.dev/google/tf2-preview/inception_v3/feature_vector/4\"\n",
653 | "feature_extractor = hub.KerasLayer(URL,\n",
654 | " input_shape=(IMAGE_RES, IMAGE_RES, 3),\n",
655 | " trainable=False)\n",
656 | "\n",
657 | "model_inception = tf.keras.Sequential([\n",
658 | " feature_extractor,\n",
659 | " tf.keras.layers.Dense(num_classes, activation='softmax')\n",
660 | "])\n",
661 | "\n",
662 | "model_inception.summary()"
663 | ],
664 | "execution_count": 0,
665 | "outputs": []
666 | },
667 | {
668 | "cell_type": "code",
669 | "metadata": {
670 | "id": "NfRADYIM-cuR",
671 | "colab_type": "code",
672 | "colab": {}
673 | },
674 | "source": [
675 | "model_inception.compile(\n",
676 | " optimizer='adam', \n",
677 | " loss='sparse_categorical_crossentropy',\n",
678 | " metrics=['accuracy'])\n",
679 | "\n",
680 | "EPOCHS = 6\n",
681 | "\n",
682 | "history = model_inception.fit(train_batches,\n",
683 | " epochs=EPOCHS,\n",
684 | " validation_data=validation_batches)"
685 | ],
686 | "execution_count": 0,
687 | "outputs": []
688 | }
689 | ]
690 | }
--------------------------------------------------------------------------------
/Moving_Average_(Time_Series_Forecasting).ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "Moving Average (Time Series Forecasting).ipynb",
7 | "provenance": [],
8 | "private_outputs": true,
9 | "collapsed_sections": [],
10 | "toc_visible": true,
11 | "include_colab_link": true
12 | },
13 | "kernelspec": {
14 | "display_name": "Python 3",
15 | "name": "python3"
16 | }
17 | },
18 | "cells": [
19 | {
20 | "cell_type": "markdown",
21 | "metadata": {
22 | "id": "view-in-github",
23 | "colab_type": "text"
24 | },
25 | "source": [
26 | "
"
27 | ]
28 | },
29 | {
30 | "cell_type": "markdown",
31 | "metadata": {
32 | "colab_type": "text",
33 | "id": "Za8-Nr5k11fh"
34 | },
35 | "source": [
36 | "##### Copyright 2018 The TensorFlow Authors."
37 | ]
38 | },
39 | {
40 | "cell_type": "code",
41 | "metadata": {
42 | "cellView": "form",
43 | "colab_type": "code",
44 | "id": "Eq10uEbw0E4l",
45 | "colab": {}
46 | },
47 | "source": [
48 | "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
49 | "# you may not use this file except in compliance with the License.\n",
50 | "# You may obtain a copy of the License at\n",
51 | "#\n",
52 | "# https://www.apache.org/licenses/LICENSE-2.0\n",
53 | "#\n",
54 | "# Unless required by applicable law or agreed to in writing, software\n",
55 | "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
56 | "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
57 | "# See the License for the specific language governing permissions and\n",
58 | "# limitations under the License."
59 | ],
60 | "execution_count": 0,
61 | "outputs": []
62 | },
63 | {
64 | "cell_type": "markdown",
65 | "metadata": {
66 | "colab_type": "text",
67 | "id": "Nm71sonIiJjH"
68 | },
69 | "source": [
70 | "# Moving average"
71 | ]
72 | },
73 | {
74 | "cell_type": "markdown",
75 | "metadata": {
76 | "colab_type": "text",
77 | "id": "vidayERjaO5q"
78 | },
79 | "source": [
80 | "## Setup"
81 | ]
82 | },
83 | {
84 | "cell_type": "code",
85 | "metadata": {
86 | "colab_type": "code",
87 | "id": "G0954hNkvkXk",
88 | "colab": {}
89 | },
90 | "source": [
91 | "from __future__ import absolute_import, division, print_function, unicode_literals"
92 | ],
93 | "execution_count": 0,
94 | "outputs": []
95 | },
96 | {
97 | "cell_type": "code",
98 | "metadata": {
99 | "colab_type": "code",
100 | "id": "_nkdPmYn2hFS",
101 | "colab": {}
102 | },
103 | "source": [
104 | "try:\n",
105 | " # Use the %tensorflow_version magic if in colab.\n",
106 | " %tensorflow_version 2.x\n",
107 | "except Exception:\n",
108 | " pass"
109 | ],
110 | "execution_count": 0,
111 | "outputs": []
112 | },
113 | {
114 | "cell_type": "code",
115 | "metadata": {
116 | "colab_type": "code",
117 | "id": "gqWabzlJ63nL",
118 | "colab": {}
119 | },
120 | "source": [
121 | "import numpy as np\n",
122 | "import matplotlib.pyplot as plt\n",
123 | "import tensorflow as tf\n",
124 | "\n",
125 | "keras = tf.keras"
126 | ],
127 | "execution_count": 0,
128 | "outputs": []
129 | },
130 | {
131 | "cell_type": "code",
132 | "metadata": {
133 | "colab_type": "code",
134 | "id": "sJwA96JU00pW",
135 | "colab": {}
136 | },
137 | "source": [
138 | "def plot_series(time, series, format=\"-\", start=0, end=None, label=None):\n",
139 | " plt.plot(time[start:end], series[start:end], format, label=label)\n",
140 | " plt.xlabel(\"Time\")\n",
141 | " plt.ylabel(\"Value\")\n",
142 | " if label:\n",
143 | " plt.legend(fontsize=14)\n",
144 | " plt.grid(True)\n",
145 | " \n",
146 | "def trend(time, slope=0):\n",
147 | " return slope * time\n",
148 | "\n",
149 | "def seasonal_pattern(season_time):\n",
150 | " \"\"\"Just an arbitrary pattern, you can change it if you wish\"\"\"\n",
151 | " return np.where(season_time < 0.4,\n",
152 | " np.cos(season_time * 2 * np.pi),\n",
153 | " 1 / np.exp(3 * season_time))\n",
154 | "\n",
155 | "def seasonality(time, period, amplitude=1, phase=0):\n",
156 | " \"\"\"Repeats the same pattern at each period\"\"\"\n",
157 | " season_time = ((time + phase) % period) / period\n",
158 | " return amplitude * seasonal_pattern(season_time)\n",
159 | "\n",
160 | "def white_noise(time, noise_level=1, seed=None):\n",
161 | " rnd = np.random.RandomState(seed)\n",
162 | " return rnd.randn(len(time)) * noise_level"
163 | ],
164 | "execution_count": 0,
165 | "outputs": []
166 | },
167 | {
168 | "cell_type": "markdown",
169 | "metadata": {
170 | "colab_type": "text",
171 | "id": "yVo6CcpRaW7u"
172 | },
173 | "source": [
174 | "## Trend and Seasonality"
175 | ]
176 | },
177 | {
178 | "cell_type": "code",
179 | "metadata": {
180 | "colab_type": "code",
181 | "id": "BLt-pLiZ0nfB",
182 | "colab": {}
183 | },
184 | "source": [
185 | "time = np.arange(4 * 365 + 1)\n",
186 | "\n",
187 | "slope = 0.05\n",
188 | "baseline = 10\n",
189 | "amplitude = 40\n",
190 | "series = baseline + trend(time, slope) + seasonality(time, period=365, amplitude=amplitude)\n",
191 | "\n",
192 | "noise_level = 5\n",
193 | "noise = white_noise(time, noise_level, seed=42)\n",
194 | "\n",
195 | "series += noise\n",
196 | "\n",
197 | "plt.figure(figsize=(10, 6))\n",
198 | "plot_series(time, series)\n",
199 | "plt.show()"
200 | ],
201 | "execution_count": 0,
202 | "outputs": []
203 | },
204 | {
205 | "cell_type": "markdown",
206 | "metadata": {
207 | "colab_type": "text",
208 | "id": "bjD8ncEZbjEW"
209 | },
210 | "source": [
211 | "## Naive Forecast"
212 | ]
213 | },
214 | {
215 | "cell_type": "code",
216 | "metadata": {
217 | "colab_type": "code",
218 | "id": "Pj_-uCeYxcAb",
219 | "colab": {}
220 | },
221 | "source": [
222 | "split_time = 1000\n",
223 | "time_train = time[:split_time]\n",
224 | "x_train = series[:split_time]\n",
225 | "time_valid = time[split_time:]\n",
226 | "x_valid = series[split_time:]\n",
227 | "\n",
228 | "naive_forecast = series[split_time - 1:-1]\n",
229 | "\n",
230 | "plt.figure(figsize=(10, 6))\n",
231 | "plot_series(time_valid, x_valid, start=0, end=150, label=\"Series\")\n",
232 | "plot_series(time_valid, naive_forecast, start=1, end=151, label=\"Forecast\")"
233 | ],
234 | "execution_count": 0,
235 | "outputs": []
236 | },
237 | {
238 | "cell_type": "markdown",
239 | "metadata": {
240 | "colab_type": "text",
241 | "id": "Uh_7244Gsxfx"
242 | },
243 | "source": [
244 | "Now let's compute the mean squared error between the forecasts and the predictions in the validation period:"
245 | ]
246 | },
247 | {
248 | "cell_type": "code",
249 | "metadata": {
250 | "colab_type": "code",
251 | "id": "byNnC7IbsnMZ",
252 | "colab": {}
253 | },
254 | "source": [
255 | "keras.metrics.mean_absolute_error(x_valid, naive_forecast).numpy()"
256 | ],
257 | "execution_count": 0,
258 | "outputs": []
259 | },
260 | {
261 | "cell_type": "markdown",
262 | "metadata": {
263 | "colab_type": "text",
264 | "id": "WGPBC9QttI1u"
265 | },
266 | "source": [
267 | "That's our baseline, now let's try a moving average."
268 | ]
269 | },
270 | {
271 | "cell_type": "markdown",
272 | "metadata": {
273 | "colab_type": "text",
274 | "id": "MLtZbFoU8OH-"
275 | },
276 | "source": [
277 | "## Moving Average"
278 | ]
279 | },
280 | {
281 | "cell_type": "code",
282 | "metadata": {
283 | "colab_type": "code",
284 | "id": "YGz5UsUdf2tV",
285 | "colab": {}
286 | },
287 | "source": [
288 | "def moving_average_forecast(series, window_size):\n",
289 | " \"\"\"Forecasts the mean of the last few values.\n",
290 | " If window_size=1, then this is equivalent to naive forecast\"\"\"\n",
291 | " forecast = []\n",
292 | " for time in range(len(series) - window_size):\n",
293 | " forecast.append(series[time:time + window_size].mean())\n",
294 | " return np.array(forecast)"
295 | ],
296 | "execution_count": 0,
297 | "outputs": []
298 | },
299 | {
300 | "cell_type": "code",
301 | "metadata": {
302 | "colab_type": "code",
303 | "id": "Le2gNBthBWPN",
304 | "colab": {}
305 | },
306 | "source": [
307 | "def moving_average_forecast(series, window_size):\n",
308 | " \"\"\"Forecasts the mean of the last few values.\n",
309 | " If window_size=1, then this is equivalent to naive forecast\n",
310 | " This implementation is *much* faster than the previous one\"\"\"\n",
311 | " mov = np.cumsum(series)\n",
312 | " mov[window_size:] = mov[window_size:] - mov[:-window_size]\n",
313 | " return mov[window_size - 1:-1] / window_size"
314 | ],
315 | "execution_count": 0,
316 | "outputs": []
317 | },
318 | {
319 | "cell_type": "code",
320 | "metadata": {
321 | "colab_type": "code",
322 | "id": "F50zyJGoDNJl",
323 | "colab": {}
324 | },
325 | "source": [
326 | "moving_avg = moving_average_forecast(series, 30)[split_time - 30:]\n",
327 | "\n",
328 | "plt.figure(figsize=(10, 6))\n",
329 | "plot_series(time_valid, x_valid, label=\"Series\")\n",
330 | "plot_series(time_valid, moving_avg, label=\"Moving average (30 days)\")"
331 | ],
332 | "execution_count": 0,
333 | "outputs": []
334 | },
335 | {
336 | "cell_type": "code",
337 | "metadata": {
338 | "colab_type": "code",
339 | "id": "wG7pTAd7z0e8",
340 | "colab": {}
341 | },
342 | "source": [
343 | "keras.metrics.mean_absolute_error(x_valid, moving_avg).numpy()"
344 | ],
345 | "execution_count": 0,
346 | "outputs": []
347 | },
348 | {
349 | "cell_type": "markdown",
350 | "metadata": {
351 | "colab_type": "text",
352 | "id": "JMYPnJqwz8nS"
353 | },
354 | "source": [
355 | "That's worse than naive forecast! The moving average does not anticipate trend or seasonality, so let's try to remove them by using differencing. Since the seasonality period is 365 days, we will subtract the value at time *t* – 365 from the value at time *t*."
356 | ]
357 | },
358 | {
359 | "cell_type": "code",
360 | "metadata": {
361 | "colab_type": "code",
362 | "id": "5pqySF7-rJR4",
363 | "colab": {}
364 | },
365 | "source": [
366 | "diff_series = (series[365:] - series[:-365])\n",
367 | "diff_time = time[365:]\n",
368 | "\n",
369 | "plt.figure(figsize=(10, 6))\n",
370 | "plot_series(diff_time, diff_series, label=\"Series(t) – Series(t–365)\")\n",
371 | "plt.show()"
372 | ],
373 | "execution_count": 0,
374 | "outputs": []
375 | },
376 | {
377 | "cell_type": "markdown",
378 | "metadata": {
379 | "colab_type": "text",
380 | "id": "WDNer84g8OIF"
381 | },
382 | "source": [
383 | "Focusing on the validation period:"
384 | ]
385 | },
386 | {
387 | "cell_type": "code",
388 | "metadata": {
389 | "colab_type": "code",
390 | "id": "-O21jlnA8OIG",
391 | "colab": {}
392 | },
393 | "source": [
394 | "plt.figure(figsize=(10, 6))\n",
395 | "plot_series(time_valid, diff_series[split_time - 365:], label=\"Series(t) – Series(t–365)\")\n",
396 | "plt.show()"
397 | ],
398 | "execution_count": 0,
399 | "outputs": []
400 | },
401 | {
402 | "cell_type": "markdown",
403 | "metadata": {
404 | "colab_type": "text",
405 | "id": "xPlPlS7DskWg"
406 | },
407 | "source": [
408 | "Great, the trend and seasonality seem to be gone, so now we can use the moving average:"
409 | ]
410 | },
411 | {
412 | "cell_type": "code",
413 | "metadata": {
414 | "colab_type": "code",
415 | "id": "QmZpz7arsjbb",
416 | "colab": {}
417 | },
418 | "source": [
419 | "diff_moving_avg = moving_average_forecast(diff_series, 50)[split_time - 365 - 50:]\n",
420 | "\n",
421 | "plt.figure(figsize=(10, 6))\n",
422 | "plot_series(time_valid, diff_series[split_time - 365:], label=\"Series(t) – Series(t–365)\")\n",
423 | "plot_series(time_valid, diff_moving_avg, label=\"Moving Average of Diff\")\n",
424 | "plt.show()"
425 | ],
426 | "execution_count": 0,
427 | "outputs": []
428 | },
429 | {
430 | "cell_type": "markdown",
431 | "metadata": {
432 | "colab_type": "text",
433 | "id": "Gno9S2lyecnc"
434 | },
435 | "source": [
436 | "Now let's bring back the trend and seasonality by adding the past values from t – 365:"
437 | ]
438 | },
439 | {
440 | "cell_type": "code",
441 | "metadata": {
442 | "colab_type": "code",
443 | "id": "Dv6RWFq7TFGB",
444 | "colab": {}
445 | },
446 | "source": [
447 | "diff_moving_avg_plus_past = series[split_time - 365:-365] + diff_moving_avg\n",
448 | "\n",
449 | "plt.figure(figsize=(10, 6))\n",
450 | "plot_series(time_valid, x_valid, label=\"Series\")\n",
451 | "plot_series(time_valid, diff_moving_avg_plus_past, label=\"Forecasts\")\n",
452 | "plt.show()"
453 | ],
454 | "execution_count": 0,
455 | "outputs": []
456 | },
457 | {
458 | "cell_type": "code",
459 | "metadata": {
460 | "colab_type": "code",
461 | "id": "59jmBrwcTFCx",
462 | "colab": {}
463 | },
464 | "source": [
465 | "keras.metrics.mean_absolute_error(x_valid, diff_moving_avg_plus_past).numpy()"
466 | ],
467 | "execution_count": 0,
468 | "outputs": []
469 | },
470 | {
471 | "cell_type": "markdown",
472 | "metadata": {
473 | "colab_type": "text",
474 | "id": "vx9Et1Hkeusl"
475 | },
476 | "source": [
477 | "Better than naive forecast, good. However the forecasts look a bit too random, because we're just adding past values, which were noisy. Let's use a moving averaging on past values to remove some of the noise:"
478 | ]
479 | },
480 | {
481 | "cell_type": "code",
482 | "metadata": {
483 | "colab_type": "code",
484 | "id": "K81dtROoTE_r",
485 | "colab": {}
486 | },
487 | "source": [
488 | "diff_moving_avg_plus_smooth_past = moving_average_forecast(series[split_time - 370:-359], 11) + diff_moving_avg\n",
489 | "\n",
490 | "plt.figure(figsize=(10, 6))\n",
491 | "plot_series(time_valid, x_valid, label=\"Series\")\n",
492 | "plot_series(time_valid, diff_moving_avg_plus_smooth_past, label=\"Forecasts\")\n",
493 | "plt.show()"
494 | ],
495 | "execution_count": 0,
496 | "outputs": []
497 | },
498 | {
499 | "cell_type": "code",
500 | "metadata": {
501 | "colab_type": "code",
502 | "id": "iN2MsBxWTE3m",
503 | "colab": {}
504 | },
505 | "source": [
506 | "keras.metrics.mean_absolute_error(x_valid, diff_moving_avg_plus_smooth_past).numpy()"
507 | ],
508 | "execution_count": 0,
509 | "outputs": []
510 | },
511 | {
512 | "cell_type": "markdown",
513 | "metadata": {
514 | "colab_type": "text",
515 | "id": "WKnmJisHcvTW"
516 | },
517 | "source": [
518 | "That's starting to look pretty good! Let's see if we can do better with a Machine Learning model."
519 | ]
520 | }
521 | ]
522 | }
--------------------------------------------------------------------------------
/Naive_Forecasting_(Time_Series_Forecasting).ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "Naive Forecasting (Time Series Forecasting).ipynb",
7 | "provenance": [],
8 | "private_outputs": true,
9 | "collapsed_sections": [],
10 | "toc_visible": true,
11 | "include_colab_link": true
12 | },
13 | "kernelspec": {
14 | "display_name": "Python 3",
15 | "name": "python3"
16 | }
17 | },
18 | "cells": [
19 | {
20 | "cell_type": "markdown",
21 | "metadata": {
22 | "id": "view-in-github",
23 | "colab_type": "text"
24 | },
25 | "source": [
26 | "
"
27 | ]
28 | },
29 | {
30 | "cell_type": "markdown",
31 | "metadata": {
32 | "colab_type": "text",
33 | "id": "Za8-Nr5k11fh"
34 | },
35 | "source": [
36 | "##### Copyright 2018 The TensorFlow Authors."
37 | ]
38 | },
39 | {
40 | "cell_type": "code",
41 | "metadata": {
42 | "cellView": "form",
43 | "colab_type": "code",
44 | "id": "Eq10uEbw0E4l",
45 | "colab": {}
46 | },
47 | "source": [
48 | "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
49 | "# you may not use this file except in compliance with the License.\n",
50 | "# You may obtain a copy of the License at\n",
51 | "#\n",
52 | "# https://www.apache.org/licenses/LICENSE-2.0\n",
53 | "#\n",
54 | "# Unless required by applicable law or agreed to in writing, software\n",
55 | "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
56 | "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
57 | "# See the License for the specific language governing permissions and\n",
58 | "# limitations under the License."
59 | ],
60 | "execution_count": 0,
61 | "outputs": []
62 | },
63 | {
64 | "cell_type": "markdown",
65 | "metadata": {
66 | "colab_type": "text",
67 | "id": "_3bi1D2IiCyW"
68 | },
69 | "source": [
70 | "# Naive forecasting"
71 | ]
72 | },
73 | {
74 | "cell_type": "markdown",
75 | "metadata": {
76 | "colab_type": "text",
77 | "id": "vidayERjaO5q"
78 | },
79 | "source": [
80 | "## Setup"
81 | ]
82 | },
83 | {
84 | "cell_type": "code",
85 | "metadata": {
86 | "colab_type": "code",
87 | "id": "VemY5RD7vefi",
88 | "colab": {}
89 | },
90 | "source": [
91 | "from __future__ import absolute_import, division, print_function, unicode_literals"
92 | ],
93 | "execution_count": 0,
94 | "outputs": []
95 | },
96 | {
97 | "cell_type": "code",
98 | "metadata": {
99 | "colab_type": "code",
100 | "id": "gqWabzlJ63nL",
101 | "colab": {}
102 | },
103 | "source": [
104 | "import numpy as np\n",
105 | "import matplotlib.pyplot as plt"
106 | ],
107 | "execution_count": 0,
108 | "outputs": []
109 | },
110 | {
111 | "cell_type": "code",
112 | "metadata": {
113 | "colab_type": "code",
114 | "id": "sJwA96JU00pW",
115 | "colab": {}
116 | },
117 | "source": [
118 | "def plot_series(time, series, format=\"-\", start=0, end=None, label=None):\n",
119 | " plt.plot(time[start:end], series[start:end], format, label=label)\n",
120 | " plt.xlabel(\"Time\")\n",
121 | " plt.ylabel(\"Value\")\n",
122 | " if label:\n",
123 | " plt.legend(fontsize=14)\n",
124 | " plt.grid(True)\n",
125 | " \n",
126 | "def trend(time, slope=0):\n",
127 | " return slope * time\n",
128 | "\n",
129 | "def seasonal_pattern(season_time):\n",
130 | " \"\"\"Just an arbitrary pattern, you can change it if you wish\"\"\"\n",
131 | " return np.where(season_time < 0.4,\n",
132 | " np.cos(season_time * 2 * np.pi),\n",
133 | " 1 / np.exp(3 * season_time))\n",
134 | " \n",
135 | "def seasonality(time, period, amplitude=1, phase=0):\n",
136 | " \"\"\"Repeats the same pattern at each period\"\"\"\n",
137 | " season_time = ((time + phase) % period) / period\n",
138 | " return amplitude * seasonal_pattern(season_time)\n",
139 | " \n",
140 | "def white_noise(time, noise_level=1, seed=None):\n",
141 | " rnd = np.random.RandomState(seed)\n",
142 | " return rnd.randn(len(time)) * noise_level"
143 | ],
144 | "execution_count": 0,
145 | "outputs": []
146 | },
147 | {
148 | "cell_type": "markdown",
149 | "metadata": {
150 | "colab_type": "text",
151 | "id": "yVo6CcpRaW7u"
152 | },
153 | "source": [
154 | "## Trend and Seasonality"
155 | ]
156 | },
157 | {
158 | "cell_type": "code",
159 | "metadata": {
160 | "colab_type": "code",
161 | "id": "BLt-pLiZ0nfB",
162 | "colab": {}
163 | },
164 | "source": [
165 | "time = np.arange(4 * 365 + 1)\n",
166 | "\n",
167 | "slope = 0.05\n",
168 | "baseline = 10\n",
169 | "amplitude = 40\n",
170 | "series = baseline + trend(time, slope) + seasonality(time, period=365, amplitude=amplitude)\n",
171 | "\n",
172 | "noise_level = 5\n",
173 | "noise = white_noise(time, noise_level, seed=42)\n",
174 | "\n",
175 | "series += noise\n",
176 | "\n",
177 | "plt.figure(figsize=(10, 6))\n",
178 | "plot_series(time, series)\n",
179 | "plt.show()"
180 | ],
181 | "execution_count": 0,
182 | "outputs": []
183 | },
184 | {
185 | "cell_type": "markdown",
186 | "metadata": {
187 | "colab_type": "text",
188 | "id": "a1sQpPjhtj0G"
189 | },
190 | "source": [
191 | "All right, this looks realistic enough for now. Let's try to forecast it. We will split it into two periods: the training period and the validation period (in many cases, you would also want to have a test period). The split will be at time step 1000."
192 | ]
193 | },
194 | {
195 | "cell_type": "code",
196 | "metadata": {
197 | "colab_type": "code",
198 | "id": "_w0eKap5uFNP",
199 | "colab": {}
200 | },
201 | "source": [
202 | "split_time = 1000\n",
203 | "time_train = time[:split_time]\n",
204 | "x_train = series[:split_time]\n",
205 | "time_valid = time[split_time:]\n",
206 | "x_valid = series[split_time:]"
207 | ],
208 | "execution_count": 0,
209 | "outputs": []
210 | },
211 | {
212 | "cell_type": "markdown",
213 | "metadata": {
214 | "colab_type": "text",
215 | "id": "bjD8ncEZbjEW"
216 | },
217 | "source": [
218 | "## Naive Forecast"
219 | ]
220 | },
221 | {
222 | "cell_type": "code",
223 | "metadata": {
224 | "colab_type": "code",
225 | "id": "Pj_-uCeYxcAb",
226 | "colab": {}
227 | },
228 | "source": [
229 | "naive_forecast = series[split_time - 1:-1]"
230 | ],
231 | "execution_count": 0,
232 | "outputs": []
233 | },
234 | {
235 | "cell_type": "code",
236 | "metadata": {
237 | "colab_type": "code",
238 | "id": "JtxwHj9Ig0jT",
239 | "colab": {}
240 | },
241 | "source": [
242 | "plt.figure(figsize=(10, 6))\n",
243 | "plot_series(time_valid, x_valid, label=\"Series\")\n",
244 | "plot_series(time_valid, naive_forecast, label=\"Forecast\")"
245 | ],
246 | "execution_count": 0,
247 | "outputs": []
248 | },
249 | {
250 | "cell_type": "markdown",
251 | "metadata": {
252 | "colab_type": "text",
253 | "id": "fw1SP5WeuixH"
254 | },
255 | "source": [
256 | "Let's zoom in on the start of the validation period:"
257 | ]
258 | },
259 | {
260 | "cell_type": "code",
261 | "metadata": {
262 | "colab_type": "code",
263 | "id": "D0MKg7FNug9V",
264 | "colab": {}
265 | },
266 | "source": [
267 | "plt.figure(figsize=(10, 6))\n",
268 | "plot_series(time_valid, x_valid, start=0, end=150, label=\"Series\")\n",
269 | "plot_series(time_valid, naive_forecast, start=1, end=151, label=\"Forecast\")"
270 | ],
271 | "execution_count": 0,
272 | "outputs": []
273 | },
274 | {
275 | "cell_type": "markdown",
276 | "metadata": {
277 | "colab_type": "text",
278 | "id": "35gIlQLfu0TT"
279 | },
280 | "source": [
281 | "You can see that the naive forecast lags 1 step behind the time series."
282 | ]
283 | },
284 | {
285 | "cell_type": "markdown",
286 | "metadata": {
287 | "colab_type": "text",
288 | "id": "Uh_7244Gsxfx"
289 | },
290 | "source": [
291 | "Now let's compute the mean absolute error between the forecasts and the predictions in the validation period:"
292 | ]
293 | },
294 | {
295 | "cell_type": "code",
296 | "metadata": {
297 | "colab_type": "code",
298 | "id": "LjpLQeWY11H8",
299 | "colab": {}
300 | },
301 | "source": [
302 | "errors = naive_forecast - x_valid\n",
303 | "abs_errors = np.abs(errors)\n",
304 | "mae = abs_errors.mean()\n",
305 | "mae"
306 | ],
307 | "execution_count": 0,
308 | "outputs": []
309 | },
310 | {
311 | "cell_type": "markdown",
312 | "metadata": {
313 | "colab_type": "text",
314 | "id": "WGPBC9QttI1u"
315 | },
316 | "source": [
317 | "That's our baseline, now let's try a moving average."
318 | ]
319 | }
320 | ]
321 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Intro to Tensorflow for Deep Learning Udacity
2 |
3 | Algorithms implemented in Google Colab from the course.
4 |
--------------------------------------------------------------------------------
/Saving_and_Loading_Models.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "accelerator": "GPU",
6 | "colab": {
7 | "name": "Saving and Loading Models.ipynb",
8 | "provenance": [],
9 | "private_outputs": true,
10 | "collapsed_sections": [],
11 | "toc_visible": true,
12 | "machine_shape": "hm",
13 | "include_colab_link": true
14 | },
15 | "kernelspec": {
16 | "display_name": "Python 3",
17 | "name": "python3"
18 | }
19 | },
20 | "cells": [
21 | {
22 | "cell_type": "markdown",
23 | "metadata": {
24 | "id": "view-in-github",
25 | "colab_type": "text"
26 | },
27 | "source": [
28 | "
"
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {
34 | "colab_type": "text",
35 | "id": "W_tvPdyfA-BL"
36 | },
37 | "source": [
38 | "##### Copyright 2019 The TensorFlow Authors."
39 | ]
40 | },
41 | {
42 | "cell_type": "code",
43 | "metadata": {
44 | "cellView": "form",
45 | "colab_type": "code",
46 | "id": "0O_LFhwSBCjm",
47 | "colab": {}
48 | },
49 | "source": [
50 | "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
51 | "# you may not use this file except in compliance with the License.\n",
52 | "# You may obtain a copy of the License at\n",
53 | "#\n",
54 | "# https://www.apache.org/licenses/LICENSE-2.0\n",
55 | "#\n",
56 | "# Unless required by applicable law or agreed to in writing, software\n",
57 | "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
58 | "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
59 | "# See the License for the specific language governing permissions and\n",
60 | "# limitations under the License."
61 | ],
62 | "execution_count": 0,
63 | "outputs": []
64 | },
65 | {
66 | "cell_type": "markdown",
67 | "metadata": {
68 | "colab_type": "text",
69 | "id": "NxjpzKTvg_dd"
70 | },
71 | "source": [
72 | "# Saving and Loading Models\n",
73 | "\n",
74 | "In this tutorial we will learn how we can take a trained model, save it, and then load it back to keep training it or use it to perform inference. In particular, we will use transfer learning to train a classifier to classify images of cats and dogs, just like we did in the previous lesson. We will then take our trained model and save it as an HDF5 file, which is the format used by Keras. We will then load this model, use it to perform predictions, and then continue to train the model. Finally, we will save our trained model as a TensorFlow SavedModel and then we will download it to a local disk, so that it can later be used for deployment in different platforms."
75 | ]
76 | },
77 | {
78 | "cell_type": "markdown",
79 | "metadata": {
80 | "colab_type": "text",
81 | "id": "crU-iluJIEzw"
82 | },
83 | "source": [
84 | "\n",
85 | "\n",
86 | "## Concepts that will be covered in this Colab\n",
87 | "\n",
88 | "1. Saving models in HDF5 format for Keras\n",
89 | "2. Saving models in the TensorFlow SavedModel format\n",
90 | "3. Loading models\n",
91 | "4. Download models to Local Disk\n",
92 | "\n",
93 | "Before starting this Colab, you should reset the Colab environment by selecting `Runtime -> Reset all runtimes...` from menu above."
94 | ]
95 | },
96 | {
97 | "cell_type": "markdown",
98 | "metadata": {
99 | "colab_type": "text",
100 | "id": "7RVsYZLEpEWs"
101 | },
102 | "source": [
103 | "# Imports\n",
104 | "\n",
105 | "In this Colab we will use the TensorFlow 2.0 Beta version. "
106 | ]
107 | },
108 | {
109 | "cell_type": "code",
110 | "metadata": {
111 | "colab_type": "code",
112 | "id": "TEBj4fbVsL5u",
113 | "colab": {}
114 | },
115 | "source": [
116 | "try:\n",
117 | " # Use the %tensorflow_version magic if in colab.\n",
118 | " %tensorflow_version 2.x\n",
119 | "except Exception:\n",
120 | " !pip install -q -U \"tensorflow-gpu==2.0.0rc0\" "
121 | ],
122 | "execution_count": 0,
123 | "outputs": []
124 | },
125 | {
126 | "cell_type": "code",
127 | "metadata": {
128 | "colab_type": "code",
129 | "id": "e3BXzUGabcI9",
130 | "colab": {}
131 | },
132 | "source": [
133 | "!pip install -q -U tensorflow_hub\n",
134 | "!pip install -q -U tensorflow_datasets"
135 | ],
136 | "execution_count": 0,
137 | "outputs": []
138 | },
139 | {
140 | "cell_type": "markdown",
141 | "metadata": {
142 | "colab_type": "text",
143 | "id": "a28UtPNlizGI"
144 | },
145 | "source": [
146 | "Some normal imports we've seen before. "
147 | ]
148 | },
149 | {
150 | "cell_type": "code",
151 | "metadata": {
152 | "colab_type": "code",
153 | "id": "Hj4tWLi9riAK",
154 | "colab": {}
155 | },
156 | "source": [
157 | "from __future__ import absolute_import, division, print_function, unicode_literals"
158 | ],
159 | "execution_count": 0,
160 | "outputs": []
161 | },
162 | {
163 | "cell_type": "code",
164 | "metadata": {
165 | "colab_type": "code",
166 | "id": "OGNpmn43C0O6",
167 | "colab": {}
168 | },
169 | "source": [
170 | "import time\n",
171 | "import numpy as np\n",
172 | "import matplotlib.pylab as plt\n",
173 | "\n",
174 | "import tensorflow as tf\n",
175 | "import tensorflow_hub as hub\n",
176 | "import tensorflow_datasets as tfds\n",
177 | "tfds.disable_progress_bar()\n",
178 | "\n",
179 | "from tensorflow.keras import layers"
180 | ],
181 | "execution_count": 0,
182 | "outputs": []
183 | },
184 | {
185 | "cell_type": "markdown",
186 | "metadata": {
187 | "colab_type": "text",
188 | "id": "amfzqn1Oo7Om"
189 | },
190 | "source": [
191 | "# Part 1: Load the Cats vs. Dogs Dataset"
192 | ]
193 | },
194 | {
195 | "cell_type": "markdown",
196 | "metadata": {
197 | "colab_type": "text",
198 | "id": "Z93vvAdGxDMD"
199 | },
200 | "source": [
201 | "We will use TensorFlow Datasets to load the Dogs vs Cats dataset. "
202 | ]
203 | },
204 | {
205 | "cell_type": "code",
206 | "metadata": {
207 | "colab_type": "code",
208 | "id": "DrIUV3V0xDL_",
209 | "colab": {}
210 | },
211 | "source": [
212 | "splits = tfds.Split.ALL.subsplit(weighted=(80, 20))\n",
213 | "\n",
214 | "splits, info = tfds.load('cats_vs_dogs', with_info=True, as_supervised=True, split = splits)\n",
215 | "\n",
216 | "(train_examples, validation_examples) = splits"
217 | ],
218 | "execution_count": 0,
219 | "outputs": []
220 | },
221 | {
222 | "cell_type": "markdown",
223 | "metadata": {
224 | "colab_type": "text",
225 | "id": "mbgpD3E6gM2P"
226 | },
227 | "source": [
228 | "The images in the Dogs vs. Cats dataset are not all the same size. So, we need to reformat all images to the resolution expected by MobileNet (224, 224)"
229 | ]
230 | },
231 | {
232 | "cell_type": "code",
233 | "metadata": {
234 | "colab_type": "code",
235 | "id": "we_ftzQxNf7e",
236 | "colab": {}
237 | },
238 | "source": [
239 | "def format_image(image, label):\n",
240 | " # `hub` image modules exepct their data normalized to the [0,1] range.\n",
241 | " image = tf.image.resize(image, (IMAGE_RES, IMAGE_RES))/255.0\n",
242 | " return image, label\n",
243 | "\n",
244 | "num_examples = info.splits['train'].num_examples\n",
245 | "\n",
246 | "BATCH_SIZE = 32\n",
247 | "IMAGE_RES = 224\n",
248 | "\n",
249 | "train_batches = train_examples.cache().shuffle(num_examples//4).map(format_image).batch(BATCH_SIZE).prefetch(1)\n",
250 | "validation_batches = validation_examples.cache().map(format_image).batch(BATCH_SIZE).prefetch(1)"
251 | ],
252 | "execution_count": 0,
253 | "outputs": []
254 | },
255 | {
256 | "cell_type": "markdown",
257 | "metadata": {
258 | "colab_type": "text",
259 | "id": "JzV457OXreQP"
260 | },
261 | "source": [
262 | "# Part 2: Transfer Learning with TensorFlow Hub\n",
263 | "\n",
264 | "We will now use TensorFlow Hub to do Transfer Learning."
265 | ]
266 | },
267 | {
268 | "cell_type": "code",
269 | "metadata": {
270 | "colab_type": "code",
271 | "id": "5wB030nezBwI",
272 | "colab": {}
273 | },
274 | "source": [
275 | "URL = \"https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4\"\n",
276 | "feature_extractor = hub.KerasLayer(URL,\n",
277 | " input_shape=(IMAGE_RES, IMAGE_RES,3))"
278 | ],
279 | "execution_count": 0,
280 | "outputs": []
281 | },
282 | {
283 | "cell_type": "markdown",
284 | "metadata": {
285 | "colab_type": "text",
286 | "id": "CtFmF7A5E4tk"
287 | },
288 | "source": [
289 | "Freeze the variables in the feature extractor layer, so that the training only modifies the final classifier layer."
290 | ]
291 | },
292 | {
293 | "cell_type": "code",
294 | "metadata": {
295 | "colab_type": "code",
296 | "id": "Jg5ar6rcE4H-",
297 | "colab": {}
298 | },
299 | "source": [
300 | "feature_extractor.trainable = False"
301 | ],
302 | "execution_count": 0,
303 | "outputs": []
304 | },
305 | {
306 | "cell_type": "markdown",
307 | "metadata": {
308 | "colab_type": "text",
309 | "id": "RPVeouTksO9q"
310 | },
311 | "source": [
312 | "## Attach a classification head\n",
313 | "\n",
314 | "Now wrap the hub layer in a `tf.keras.Sequential` model, and add a new classification layer."
315 | ]
316 | },
317 | {
318 | "cell_type": "code",
319 | "metadata": {
320 | "colab_type": "code",
321 | "id": "mGcY27fY1q3Q",
322 | "colab": {}
323 | },
324 | "source": [
325 | "model = tf.keras.Sequential([\n",
326 | " feature_extractor,\n",
327 | " layers.Dense(2, activation='softmax')\n",
328 | "])\n",
329 | "\n",
330 | "model.summary()"
331 | ],
332 | "execution_count": 0,
333 | "outputs": []
334 | },
335 | {
336 | "cell_type": "markdown",
337 | "metadata": {
338 | "colab_type": "text",
339 | "id": "OHbXQqIquFxQ"
340 | },
341 | "source": [
342 | "## Train the model\n",
343 | "\n",
344 | "We now train this model like any other, by first calling `compile` followed by `fit`."
345 | ]
346 | },
347 | {
348 | "cell_type": "code",
349 | "metadata": {
350 | "colab_type": "code",
351 | "id": "3n0Wb9ylKd8R",
352 | "colab": {}
353 | },
354 | "source": [
355 | "model.compile(\n",
356 | " optimizer='adam', \n",
357 | " loss=tf.losses.SparseCategoricalCrossentropy(),\n",
358 | " metrics=['accuracy'])\n",
359 | "\n",
360 | "EPOCHS = 3\n",
361 | "history = model.fit(train_batches,\n",
362 | " epochs=EPOCHS,\n",
363 | " validation_data=validation_batches)"
364 | ],
365 | "execution_count": 0,
366 | "outputs": []
367 | },
368 | {
369 | "cell_type": "markdown",
370 | "metadata": {
371 | "colab_type": "text",
372 | "id": "kb__ZN8uFn-D"
373 | },
374 | "source": [
375 | "## Check the predictions\n",
376 | "\n",
377 | "Get the ordered list of class names."
378 | ]
379 | },
380 | {
381 | "cell_type": "code",
382 | "metadata": {
383 | "colab_type": "code",
384 | "id": "W_Zvg2i0fzJu",
385 | "colab": {}
386 | },
387 | "source": [
388 | "class_names = np.array(info.features['label'].names)\n",
389 | "class_names"
390 | ],
391 | "execution_count": 0,
392 | "outputs": []
393 | },
394 | {
395 | "cell_type": "markdown",
396 | "metadata": {
397 | "colab_type": "text",
398 | "id": "4Olg6MsNGJTL"
399 | },
400 | "source": [
401 | "Run an image batch through the model and convert the indices to class names."
402 | ]
403 | },
404 | {
405 | "cell_type": "code",
406 | "metadata": {
407 | "colab_type": "code",
408 | "id": "fCLVCpEjJ_VP",
409 | "colab": {}
410 | },
411 | "source": [
412 | "image_batch, label_batch = next(iter(train_batches.take(1)))\n",
413 | "image_batch = image_batch.numpy()\n",
414 | "label_batch = label_batch.numpy()\n",
415 | "\n",
416 | "predicted_batch = model.predict(image_batch)\n",
417 | "predicted_batch = tf.squeeze(predicted_batch).numpy()\n",
418 | "predicted_ids = np.argmax(predicted_batch, axis=-1)\n",
419 | "predicted_class_names = class_names[predicted_ids]\n",
420 | "predicted_class_names"
421 | ],
422 | "execution_count": 0,
423 | "outputs": []
424 | },
425 | {
426 | "cell_type": "markdown",
427 | "metadata": {
428 | "colab_type": "text",
429 | "id": "CkGbZxl9GZs-"
430 | },
431 | "source": [
432 | "Let's look at the true labels and predicted ones."
433 | ]
434 | },
435 | {
436 | "cell_type": "code",
437 | "metadata": {
438 | "colab_type": "code",
439 | "id": "nL9IhOmGI5dJ",
440 | "colab": {}
441 | },
442 | "source": [
443 | "print(\"Labels: \", label_batch)\n",
444 | "print(\"Predicted labels: \", predicted_ids)"
445 | ],
446 | "execution_count": 0,
447 | "outputs": []
448 | },
449 | {
450 | "cell_type": "code",
451 | "metadata": {
452 | "colab_type": "code",
453 | "id": "wC_AYRJU9NQe",
454 | "colab": {}
455 | },
456 | "source": [
457 | "plt.figure(figsize=(10,9))\n",
458 | "for n in range(30):\n",
459 | " plt.subplot(6,5,n+1)\n",
460 | " plt.imshow(image_batch[n])\n",
461 | " color = \"blue\" if predicted_ids[n] == label_batch[n] else \"red\"\n",
462 | " plt.title(predicted_class_names[n].title(), color=color)\n",
463 | " plt.axis('off')\n",
464 | "_ = plt.suptitle(\"Model predictions (blue: correct, red: incorrect)\")"
465 | ],
466 | "execution_count": 0,
467 | "outputs": []
468 | },
469 | {
470 | "cell_type": "markdown",
471 | "metadata": {
472 | "colab_type": "text",
473 | "id": "mmPQYQLx3cYq"
474 | },
475 | "source": [
476 | "# Part 3: Save as Keras `.h5` model\n",
477 | "\n",
478 | "Now that we've trained the model, we can save it as an HDF5 file, which is the format used by Keras. Our HDF5 file will have the extension '.h5', and it's name will correpond to the current time stamp."
479 | ]
480 | },
481 | {
482 | "cell_type": "code",
483 | "metadata": {
484 | "colab_type": "code",
485 | "id": "tCnNWTkZ3Ckz",
486 | "colab": {}
487 | },
488 | "source": [
489 | "t = time.time()\n",
490 | "\n",
491 | "export_path_keras = \"./{}.h5\".format(int(t))\n",
492 | "print(export_path_keras)\n",
493 | "\n",
494 | "model.save(export_path_keras)"
495 | ],
496 | "execution_count": 0,
497 | "outputs": []
498 | },
499 | {
500 | "cell_type": "code",
501 | "metadata": {
502 | "colab_type": "code",
503 | "id": "9tdJWVHmnKxJ",
504 | "colab": {}
505 | },
506 | "source": [
507 | "!ls"
508 | ],
509 | "execution_count": 0,
510 | "outputs": []
511 | },
512 | {
513 | "cell_type": "markdown",
514 | "metadata": {
515 | "colab_type": "text",
516 | "id": "JgqmH1WVUKli"
517 | },
518 | "source": [
519 | " You can later recreate the same model from this file, even if you no longer have access to the code that created the model.\n",
520 | "\n",
521 | "This file includes:\n",
522 | "\n",
523 | "- The model's architecture\n",
524 | "- The model's weight values (which were learned during training)\n",
525 | "- The model's training config (what you passed to `compile`), if any\n",
526 | "- The optimizer and its state, if any (this enables you to restart training where you left off)"
527 | ]
528 | },
529 | {
530 | "cell_type": "markdown",
531 | "metadata": {
532 | "colab_type": "text",
533 | "id": "yXole25Z799G"
534 | },
535 | "source": [
536 | "# Part 4: Load the Keras `.h5` Model\n",
537 | "\n",
538 | "We will now load the model we just saved into a new model called `reloaded`. We will need to provide the file path and the `custom_objects` parameter. This parameter tells keras how to load the `hub.KerasLayer` from the `feature_extractor` we used for transfer learning."
539 | ]
540 | },
541 | {
542 | "cell_type": "code",
543 | "metadata": {
544 | "colab_type": "code",
545 | "id": "Rx-z3Qwx5RnB",
546 | "colab": {}
547 | },
548 | "source": [
549 | "reloaded = tf.keras.models.load_model(\n",
550 | " export_path_keras, \n",
551 | " # `custom_objects` tells keras how to load a `hub.KerasLayer`\n",
552 | " custom_objects={'KerasLayer': hub.KerasLayer})\n",
553 | "\n",
554 | "reloaded.summary()"
555 | ],
556 | "execution_count": 0,
557 | "outputs": []
558 | },
559 | {
560 | "cell_type": "markdown",
561 | "metadata": {
562 | "colab_type": "text",
563 | "id": "XxDl2vPkf2ST"
564 | },
565 | "source": [
566 | "We can check that the reloaded model and the previous model give the same result"
567 | ]
568 | },
569 | {
570 | "cell_type": "code",
571 | "metadata": {
572 | "colab_type": "code",
573 | "id": "MFljA-Hd85Tu",
574 | "colab": {}
575 | },
576 | "source": [
577 | "result_batch = model.predict(image_batch)\n",
578 | "reloaded_result_batch = reloaded.predict(image_batch)"
579 | ],
580 | "execution_count": 0,
581 | "outputs": []
582 | },
583 | {
584 | "cell_type": "markdown",
585 | "metadata": {
586 | "colab_type": "text",
587 | "id": "YeCZUUJK9Svv"
588 | },
589 | "source": [
590 | "The differnece in output should be zero:"
591 | ]
592 | },
593 | {
594 | "cell_type": "code",
595 | "metadata": {
596 | "colab_type": "code",
597 | "id": "S3p5-uD39PC1",
598 | "colab": {}
599 | },
600 | "source": [
601 | "(abs(result_batch - reloaded_result_batch)).max()"
602 | ],
603 | "execution_count": 0,
604 | "outputs": []
605 | },
606 | {
607 | "cell_type": "markdown",
608 | "metadata": {
609 | "colab_type": "text",
610 | "id": "KqU79kKFo7S2"
611 | },
612 | "source": [
613 | "As we can see, the reult is 0.0, which indicates that both models made the same predictions on the same batch of images."
614 | ]
615 | },
616 | {
617 | "cell_type": "markdown",
618 | "metadata": {
619 | "colab_type": "text",
620 | "id": "nKunO4soA4Dm"
621 | },
622 | "source": [
623 | "# Keep Training\n",
624 | "\n",
625 | "Besides making predictions, we can also take our `reloaded` model and keep training it. To do this, you can just train the `realoaded` as usual, using the `.fit` method."
626 | ]
627 | },
628 | {
629 | "cell_type": "code",
630 | "metadata": {
631 | "colab_type": "code",
632 | "id": "NEv-fnHEAplx",
633 | "colab": {}
634 | },
635 | "source": [
636 | "EPOCHS = 2\n",
637 | "history = reloaded.fit(train_batches,\n",
638 | " epochs=EPOCHS,\n",
639 | " validation_data=validation_batches)"
640 | ],
641 | "execution_count": 0,
642 | "outputs": []
643 | },
644 | {
645 | "cell_type": "markdown",
646 | "metadata": {
647 | "colab_type": "text",
648 | "id": "5OKoZaAHFH_s"
649 | },
650 | "source": [
651 | "# Part 5: Export as SavedModel\n",
652 | "\n"
653 | ]
654 | },
655 | {
656 | "cell_type": "markdown",
657 | "metadata": {
658 | "colab_type": "text",
659 | "id": "3V47IwQbFTYT"
660 | },
661 | "source": [
662 | "You can also export a whole model to the TensorFlow SavedModel format. SavedModel is a standalone serialization format for Tensorflow objects, supported by TensorFlow serving as well as TensorFlow implementations other than Python. A SavedModel contains a complete TensorFlow program, including weights and computation. It does not require the original model building code to run, which makes it useful for sharing or deploying (with TFLite, TensorFlow.js, TensorFlow Serving, or TFHub).\n",
663 | "\n",
664 | "The SavedModel files that were created contain:\n",
665 | "\n",
666 | "* A TensorFlow checkpoint containing the model weights.\n",
667 | "* A SavedModel proto containing the underlying Tensorflow graph. Separate graphs are saved for prediction (serving), train, and evaluation. If the model wasn't compiled before, then only the inference graph gets exported.\n",
668 | "* The model's architecture config, if available.\n",
669 | "\n",
670 | "\n",
671 | "Let's save our original `model` as a TensorFlow SavedModel. To do this we will use the `tf.saved_model.save()` function. This functions takes in the model we want to save and the path to the folder where we want to save our model. \n",
672 | "\n",
673 | "This function will create a folder where you will find an `assets` folder, a `variables` folder, and the `saved_model.pb` file. "
674 | ]
675 | },
676 | {
677 | "cell_type": "code",
678 | "metadata": {
679 | "colab_type": "code",
680 | "id": "LtpeKMfoGXrj",
681 | "colab": {}
682 | },
683 | "source": [
684 | "t = time.time()\n",
685 | "\n",
686 | "export_path_sm = \"./{}\".format(int(t))\n",
687 | "print(export_path_sm)\n",
688 | "\n",
689 | "tf.saved_model.save(model, export_path_sm)"
690 | ],
691 | "execution_count": 0,
692 | "outputs": []
693 | },
694 | {
695 | "cell_type": "code",
696 | "metadata": {
697 | "colab_type": "code",
698 | "id": "5h6B1wITlu-9",
699 | "colab": {}
700 | },
701 | "source": [
702 | "!ls {export_path_sm}"
703 | ],
704 | "execution_count": 0,
705 | "outputs": []
706 | },
707 | {
708 | "cell_type": "markdown",
709 | "metadata": {
710 | "colab_type": "text",
711 | "id": "ktpsqHxJPIQW"
712 | },
713 | "source": [
714 | "# Part 6: Load SavedModel"
715 | ]
716 | },
717 | {
718 | "cell_type": "markdown",
719 | "metadata": {
720 | "colab_type": "text",
721 | "id": "v0FDcCn9ncDb"
722 | },
723 | "source": [
724 | "Now, let's load our SavedModel and use it to make predictions. We use the `tf.saved_model.load()` function to load our SavedModels. The object returned by `tf.saved_model.load` is 100% independent of the code that created it."
725 | ]
726 | },
727 | {
728 | "cell_type": "code",
729 | "metadata": {
730 | "colab_type": "code",
731 | "id": "c7_PM7lofG2V",
732 | "colab": {}
733 | },
734 | "source": [
735 | "reloaded_sm = tf.saved_model.load(export_path_sm)"
736 | ],
737 | "execution_count": 0,
738 | "outputs": []
739 | },
740 | {
741 | "cell_type": "markdown",
742 | "metadata": {
743 | "colab_type": "text",
744 | "id": "esEODdtM0kHB"
745 | },
746 | "source": [
747 | "Now, let's use the `reloaded_sm` (reloaded SavedModel) to make predictions on a batch of images."
748 | ]
749 | },
750 | {
751 | "cell_type": "code",
752 | "metadata": {
753 | "colab_type": "code",
754 | "id": "lpQldy_bm3Ty",
755 | "colab": {}
756 | },
757 | "source": [
758 | "reload_sm_result_batch = reloaded_sm(image_batch, training=False).numpy()"
759 | ],
760 | "execution_count": 0,
761 | "outputs": []
762 | },
763 | {
764 | "cell_type": "markdown",
765 | "metadata": {
766 | "colab_type": "text",
767 | "id": "65upCyVN0u3Q"
768 | },
769 | "source": [
770 | "We can check that the reloaded SavedModel and the previous model give the same result."
771 | ]
772 | },
773 | {
774 | "cell_type": "code",
775 | "metadata": {
776 | "colab_type": "code",
777 | "id": "hoCwmkGznR_0",
778 | "colab": {}
779 | },
780 | "source": [
781 | "(abs(result_batch - reload_sm_result_batch)).max()"
782 | ],
783 | "execution_count": 0,
784 | "outputs": []
785 | },
786 | {
787 | "cell_type": "markdown",
788 | "metadata": {
789 | "colab_type": "text",
790 | "id": "wxuETjjs01pL"
791 | },
792 | "source": [
793 | "As we can see, the result is 0.0, which indicates that both models made the same predictions on the same batch of images."
794 | ]
795 | },
796 | {
797 | "cell_type": "markdown",
798 | "metadata": {
799 | "colab_type": "text",
800 | "id": "7Nom-ka0yuqB"
801 | },
802 | "source": [
803 | "# Part 7: Loading the SavedModel as a Keras Model\n",
804 | "\n",
805 | "The object returned by `tf.saved_model.load` is not a Keras object (i.e. doesn't have `.fit`, `.predict`, `.summary`, etc. methods). Therefore, you can't simply take your `reloaded_sm` model and keep training it by running `.fit`. To be able to get back a full keras model from the Tensorflow SavedModel format we must use the `tf.keras.models.load_model` function. This function will work the same as before, except now we pass the path to the folder containing our SavedModel."
806 | ]
807 | },
808 | {
809 | "cell_type": "code",
810 | "metadata": {
811 | "colab_type": "code",
812 | "id": "Vi1jaqh8yvt6",
813 | "colab": {}
814 | },
815 | "source": [
816 | "t = time.time()\n",
817 | "\n",
818 | "export_path_sm = \"./{}\".format(int(t))\n",
819 | "print(export_path_sm)\n",
820 | "tf.saved_model.save(model, export_path_sm)"
821 | ],
822 | "execution_count": 0,
823 | "outputs": []
824 | },
825 | {
826 | "cell_type": "code",
827 | "metadata": {
828 | "colab_type": "code",
829 | "id": "1VPE2_QQGmAP",
830 | "colab": {}
831 | },
832 | "source": [
833 | "reload_sm_keras = tf.keras.models.load_model(\n",
834 | " export_path_sm,\n",
835 | " custom_objects={'KerasLayer': hub.KerasLayer})\n",
836 | "\n",
837 | "reload_sm_keras.summary()"
838 | ],
839 | "execution_count": 0,
840 | "outputs": []
841 | },
842 | {
843 | "cell_type": "markdown",
844 | "metadata": {
845 | "colab_type": "text",
846 | "id": "thTbiHE72GL4"
847 | },
848 | "source": [
849 | "Now, let's use the `reloaded_sm)keras` (reloaded Keras model from our SavedModel) to make predictions on a batch of images."
850 | ]
851 | },
852 | {
853 | "cell_type": "code",
854 | "metadata": {
855 | "colab_type": "code",
856 | "id": "-0oCJrNLKdKj",
857 | "colab": {}
858 | },
859 | "source": [
860 | "result_batch = model.predict(image_batch)\n",
861 | "reload_sm_keras_result_batch = reload_sm_keras.predict(image_batch)"
862 | ],
863 | "execution_count": 0,
864 | "outputs": []
865 | },
866 | {
867 | "cell_type": "markdown",
868 | "metadata": {
869 | "colab_type": "text",
870 | "id": "jUQaxzFj2Q8k"
871 | },
872 | "source": [
873 | "We can check that the reloaded Keras model and the previous model give the same result."
874 | ]
875 | },
876 | {
877 | "cell_type": "code",
878 | "metadata": {
879 | "colab_type": "code",
880 | "id": "DJCD9JJxKg9F",
881 | "colab": {}
882 | },
883 | "source": [
884 | "(abs(result_batch - reload_sm_keras_result_batch)).max()"
885 | ],
886 | "execution_count": 0,
887 | "outputs": []
888 | },
889 | {
890 | "cell_type": "markdown",
891 | "metadata": {
892 | "colab_type": "text",
893 | "id": "NFa6jNc4PW9F"
894 | },
895 | "source": [
896 | "# Part 8: Download your model"
897 | ]
898 | },
899 | {
900 | "cell_type": "markdown",
901 | "metadata": {
902 | "colab_type": "text",
903 | "id": "2W_y1qMVQeCm"
904 | },
905 | "source": [
906 | "You can download the SavedModel to your local disk by creating a zip file. We wil use the `-r` (recursice) option to zip all subfolders. "
907 | ]
908 | },
909 | {
910 | "cell_type": "code",
911 | "metadata": {
912 | "colab_type": "code",
913 | "id": "WPRFoU1xPCGF",
914 | "colab": {}
915 | },
916 | "source": [
917 | "!zip -r model.zip {export_path_sm}"
918 | ],
919 | "execution_count": 0,
920 | "outputs": []
921 | },
922 | {
923 | "cell_type": "markdown",
924 | "metadata": {
925 | "colab_type": "text",
926 | "id": "MBZL85RsQBTj"
927 | },
928 | "source": [
929 | "The zip file is saved in the current working directory. You can see what the current working directory is by running:"
930 | ]
931 | },
932 | {
933 | "cell_type": "code",
934 | "metadata": {
935 | "colab_type": "code",
936 | "id": "ALP-DfwSQRL8",
937 | "colab": {}
938 | },
939 | "source": [
940 | "!ls"
941 | ],
942 | "execution_count": 0,
943 | "outputs": []
944 | },
945 | {
946 | "cell_type": "markdown",
947 | "metadata": {
948 | "colab_type": "text",
949 | "id": "IR89aU-SRmsL"
950 | },
951 | "source": [
952 | "Once the file is zipped, you can download it to your local disk. "
953 | ]
954 | },
955 | {
956 | "cell_type": "code",
957 | "metadata": {
958 | "colab_type": "code",
959 | "id": "lOXYrlDkNjKQ",
960 | "colab": {}
961 | },
962 | "source": [
963 | "try:\n",
964 | " from google.colab import files\n",
965 | " files.download('./model.zip')\n",
966 | "except ImportError:\n",
967 | " pass"
968 | ],
969 | "execution_count": 0,
970 | "outputs": []
971 | },
972 | {
973 | "cell_type": "markdown",
974 | "metadata": {
975 | "colab_type": "text",
976 | "id": "RzLutxq_SeLQ"
977 | },
978 | "source": [
979 | "The `files.download` command will search for files in your current working directory. If the file you want to download is in a directory other than the current working directory, you have to include the path to the directory where the file is located."
980 | ]
981 | }
982 | ]
983 | }
--------------------------------------------------------------------------------
/Transfer_Learning_with_TensorFlow_Hub.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "accelerator": "GPU",
6 | "colab": {
7 | "name": "Transfer Learning with TensorFlow Hub.ipynb",
8 | "provenance": [],
9 | "collapsed_sections": [],
10 | "toc_visible": true,
11 | "include_colab_link": true
12 | },
13 | "kernelspec": {
14 | "name": "python3",
15 | "display_name": "Python 3"
16 | }
17 | },
18 | "cells": [
19 | {
20 | "cell_type": "markdown",
21 | "metadata": {
22 | "id": "view-in-github",
23 | "colab_type": "text"
24 | },
25 | "source": [
26 | "
"
27 | ]
28 | },
29 | {
30 | "cell_type": "markdown",
31 | "metadata": {
32 | "colab_type": "text",
33 | "id": "W_tvPdyfA-BL"
34 | },
35 | "source": [
36 | "##### Copyright 2019 The TensorFlow Authors."
37 | ]
38 | },
39 | {
40 | "cell_type": "code",
41 | "metadata": {
42 | "cellView": "form",
43 | "colab_type": "code",
44 | "id": "0O_LFhwSBCjm",
45 | "colab": {}
46 | },
47 | "source": [
48 | "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
49 | "# you may not use this file except in compliance with the License.\n",
50 | "# You may obtain a copy of the License at\n",
51 | "#\n",
52 | "# https://www.apache.org/licenses/LICENSE-2.0\n",
53 | "#\n",
54 | "# Unless required by applicable law or agreed to in writing, software\n",
55 | "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
56 | "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
57 | "# See the License for the specific language governing permissions and\n",
58 | "# limitations under the License."
59 | ],
60 | "execution_count": 0,
61 | "outputs": []
62 | },
63 | {
64 | "cell_type": "markdown",
65 | "metadata": {
66 | "colab_type": "text",
67 | "id": "NxjpzKTvg_dd"
68 | },
69 | "source": [
70 | "# TensorFlow Hub and Transfer Learning"
71 | ]
72 | },
73 | {
74 | "cell_type": "markdown",
75 | "metadata": {
76 | "colab_type": "text",
77 | "id": "crU-iluJIEzw"
78 | },
79 | "source": [
80 | "[TensorFlow Hub](http://tensorflow.org/hub) is an online repository of already trained TensorFlow models that you can use.\n",
81 | "These models can either be used as is, or they can be used for Transfer Learning.\n",
82 | "\n",
83 | "Transfer learning is a process where you take an existing trained model, and extend it to do additional work. This involves leaving the bulk of the model unchanged, while adding and retraining the final layers, in order to get a different set of possible outputs.\n",
84 | "\n",
85 | "In this Colab we will do both.\n",
86 | "\n",
87 | "Here, you can see all the models available in [TensorFlow Module Hub](https://tfhub.dev/).\n",
88 | "\n",
89 | "## Concepts that will be covered in this Colab\n",
90 | "\n",
91 | "1. Use a TensorFlow Hub model for prediction.\n",
92 | "2. Use a TensorFlow Hub model for Dogs vs. Cats dataset.\n",
93 | "3. Do simple transfer learning with TensorFlow Hub.\n",
94 | "\n",
95 | "Before starting this Colab, you should reset the Colab environment by selecting `Runtime -> Reset all runtimes...` from menu above."
96 | ]
97 | },
98 | {
99 | "cell_type": "markdown",
100 | "metadata": {
101 | "colab_type": "text",
102 | "id": "7RVsYZLEpEWs"
103 | },
104 | "source": [
105 | "# Imports\n",
106 | "\n"
107 | ]
108 | },
109 | {
110 | "cell_type": "markdown",
111 | "metadata": {
112 | "colab_type": "text",
113 | "id": "fL7DqCwbmfwi"
114 | },
115 | "source": [
116 | "This Colab will require us to use some things which are not yet in official releases of TensorFlow. So below, we're first installing a nightly version of TensorFlow as well as TensorFlow Hub.\n",
117 | "\n",
118 | "This will switch your installation of TensorFlow in Colab to this TensorFlow version. Once you are finished with this Colab, you should switch batch to the latest stable release of TensorFlow by selecting `Runtime -> Reset all runtimes...` in the menus above. This will reset the Colab environment to its original state."
119 | ]
120 | },
121 | {
122 | "cell_type": "markdown",
123 | "metadata": {
124 | "colab_type": "text",
125 | "id": "ZUCEcRdhnyWn"
126 | },
127 | "source": [
128 | "Some normal imports we've seen before. The new one is importing tensorflow_hub which was installed above, and which this Colab will make heavy use of."
129 | ]
130 | },
131 | {
132 | "cell_type": "code",
133 | "metadata": {
134 | "colab_type": "code",
135 | "id": "OGNpmn43C0O6",
136 | "colab": {}
137 | },
138 | "source": [
139 | "from __future__ import absolute_import, division, print_function, unicode_literals"
140 | ],
141 | "execution_count": 0,
142 | "outputs": []
143 | },
144 | {
145 | "cell_type": "code",
146 | "metadata": {
147 | "colab_type": "code",
148 | "id": "8z5hqr0hHtLv",
149 | "colab": {}
150 | },
151 | "source": [
152 | "try:\n",
153 | " # Use the %tensorflow_version magic if in colab.\n",
154 | " %tensorflow_version 2.x\n",
155 | "except Exception:\n",
156 | " pass\n",
157 | "\n",
158 | "import tensorflow as tf"
159 | ],
160 | "execution_count": 0,
161 | "outputs": []
162 | },
163 | {
164 | "cell_type": "code",
165 | "metadata": {
166 | "colab_type": "code",
167 | "id": "WZnAHGETHu7e",
168 | "colab": {}
169 | },
170 | "source": [
171 | "import matplotlib.pylab as plt\n",
172 | "\n",
173 | "import tensorflow_hub as hub\n",
174 | "import tensorflow_datasets as tfds\n",
175 | "\n",
176 | "from tensorflow.keras import layers"
177 | ],
178 | "execution_count": 0,
179 | "outputs": []
180 | },
181 | {
182 | "cell_type": "code",
183 | "metadata": {
184 | "colab_type": "code",
185 | "id": "FVM2fKGEHIJN",
186 | "colab": {}
187 | },
188 | "source": [
189 | "import logging\n",
190 | "logger = tf.get_logger()\n",
191 | "logger.setLevel(logging.ERROR)"
192 | ],
193 | "execution_count": 0,
194 | "outputs": []
195 | },
196 | {
197 | "cell_type": "markdown",
198 | "metadata": {
199 | "colab_type": "text",
200 | "id": "s4YuF5HvpM1W"
201 | },
202 | "source": [
203 | "# Part 1: Use a TensorFlow Hub MobileNet for prediction"
204 | ]
205 | },
206 | {
207 | "cell_type": "markdown",
208 | "metadata": {
209 | "colab_type": "text",
210 | "id": "4Sh2sPc10V0b"
211 | },
212 | "source": [
213 | "In this part of the Colab, we'll take a trained model, load it into to Keras, and try it out.\n",
214 | "\n",
215 | "The model that we'll use is MobileNet v2 (but any model from [tf2 compatible image classifier URL from tfhub.dev](https://tfhub.dev/s?q=tf2&module-type=image-classification) would work)."
216 | ]
217 | },
218 | {
219 | "cell_type": "markdown",
220 | "metadata": {
221 | "colab_type": "text",
222 | "id": "xEY_Ow5loN6q"
223 | },
224 | "source": [
225 | "## Download the classifier\n",
226 | "\n",
227 | "Download the MobileNet model and create a Keras model from it.\n",
228 | "MobileNet is expecting images of 224 $\\times$ 224 pixels, in 3 color channels (RGB)."
229 | ]
230 | },
231 | {
232 | "cell_type": "code",
233 | "metadata": {
234 | "colab_type": "code",
235 | "id": "y_6bGjoPtzau",
236 | "colab": {}
237 | },
238 | "source": [
239 | "CLASSIFIER_URL =\"https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/2\"\n",
240 | "IMAGE_RES = 224\n",
241 | "\n",
242 | "model = tf.keras.Sequential([\n",
243 | " hub.KerasLayer(CLASSIFIER_URL, input_shape=(IMAGE_RES, IMAGE_RES, 3))\n",
244 | "])"
245 | ],
246 | "execution_count": 0,
247 | "outputs": []
248 | },
249 | {
250 | "cell_type": "markdown",
251 | "metadata": {
252 | "colab_type": "text",
253 | "id": "pwZXaoV0uXp2"
254 | },
255 | "source": [
256 | "## Run it on a single image"
257 | ]
258 | },
259 | {
260 | "cell_type": "markdown",
261 | "metadata": {
262 | "colab_type": "text",
263 | "id": "TQItP1i55-di"
264 | },
265 | "source": [
266 | "MobileNet has been trained on the ImageNet dataset. ImageNet has 1000 different output classes, and one of them is military uniforms.\n",
267 | "Let's get an image containing a military uniform that is not part of ImageNet, and see if our model can predict that it is a military uniform."
268 | ]
269 | },
270 | {
271 | "cell_type": "code",
272 | "metadata": {
273 | "colab_type": "code",
274 | "id": "w5wDjXNjuXGD",
275 | "colab": {}
276 | },
277 | "source": [
278 | "import numpy as np\n",
279 | "import PIL.Image as Image\n",
280 | "\n",
281 | "grace_hopper = tf.keras.utils.get_file('image.jpg','https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg')\n",
282 | "grace_hopper = Image.open(grace_hopper).resize((IMAGE_RES, IMAGE_RES))\n",
283 | "grace_hopper "
284 | ],
285 | "execution_count": 0,
286 | "outputs": []
287 | },
288 | {
289 | "cell_type": "code",
290 | "metadata": {
291 | "colab_type": "code",
292 | "id": "BEmmBnGbLxPp",
293 | "colab": {}
294 | },
295 | "source": [
296 | "grace_hopper = np.array(grace_hopper)/255.0\n",
297 | "grace_hopper.shape"
298 | ],
299 | "execution_count": 0,
300 | "outputs": []
301 | },
302 | {
303 | "cell_type": "markdown",
304 | "metadata": {
305 | "colab_type": "text",
306 | "id": "0Ic8OEEo2b73"
307 | },
308 | "source": [
309 | "Remember, models always want a batch of images to process. So here, we add a batch dimension, and pass the image to the model for prediction."
310 | ]
311 | },
312 | {
313 | "cell_type": "code",
314 | "metadata": {
315 | "colab_type": "code",
316 | "id": "EMquyn29v8q3",
317 | "colab": {}
318 | },
319 | "source": [
320 | "result = model.predict(grace_hopper[np.newaxis, ...])\n",
321 | "result.shape"
322 | ],
323 | "execution_count": 0,
324 | "outputs": []
325 | },
326 | {
327 | "cell_type": "markdown",
328 | "metadata": {
329 | "colab_type": "text",
330 | "id": "NKzjqENF6jDF"
331 | },
332 | "source": [
333 | "The result is a 1001 element vector of logits, rating the probability of each class for the image.\n",
334 | "\n",
335 | "So the top class ID can be found with argmax. But how can we know what class this actually is and in particular if that class ID in the ImageNet dataset denotes a military uniform or something else?"
336 | ]
337 | },
338 | {
339 | "cell_type": "code",
340 | "metadata": {
341 | "colab_type": "code",
342 | "id": "rgXb44vt6goJ",
343 | "colab": {}
344 | },
345 | "source": [
346 | "predicted_class = np.argmax(result[0], axis=-1)\n",
347 | "predicted_class"
348 | ],
349 | "execution_count": 0,
350 | "outputs": []
351 | },
352 | {
353 | "cell_type": "markdown",
354 | "metadata": {
355 | "colab_type": "text",
356 | "id": "YrxLMajMoxkf"
357 | },
358 | "source": [
359 | "## Decode the predictions\n",
360 | "\n",
361 | "To see what our predicted_class is in the ImageNet dataset, download the ImageNet labels and fetch the row that the model predicted."
362 | ]
363 | },
364 | {
365 | "cell_type": "code",
366 | "metadata": {
367 | "colab_type": "code",
368 | "id": "ij6SrDxcxzry",
369 | "colab": {}
370 | },
371 | "source": [
372 | "labels_path = tf.keras.utils.get_file('ImageNetLabels.txt','https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')\n",
373 | "imagenet_labels = np.array(open(labels_path).read().splitlines())\n",
374 | "\n",
375 | "plt.imshow(grace_hopper)\n",
376 | "plt.axis('off')\n",
377 | "predicted_class_name = imagenet_labels[predicted_class]\n",
378 | "_ = plt.title(\"Prediction: \" + predicted_class_name.title())"
379 | ],
380 | "execution_count": 0,
381 | "outputs": []
382 | },
383 | {
384 | "cell_type": "markdown",
385 | "metadata": {
386 | "colab_type": "text",
387 | "id": "a6TNYYAM4u2-"
388 | },
389 | "source": [
390 | "Bingo. Our model correctly predicted military uniform!"
391 | ]
392 | },
393 | {
394 | "cell_type": "markdown",
395 | "metadata": {
396 | "colab_type": "text",
397 | "id": "amfzqn1Oo7Om"
398 | },
399 | "source": [
400 | "# Part 2: Use a TensorFlow Hub models for the Cats vs. Dogs dataset"
401 | ]
402 | },
403 | {
404 | "cell_type": "markdown",
405 | "metadata": {
406 | "colab_type": "text",
407 | "id": "K-nIpVJ94xrw"
408 | },
409 | "source": [
410 | "Now we'll use the full MobileNet model and see how it can perform on the Dogs vs. Cats dataset."
411 | ]
412 | },
413 | {
414 | "cell_type": "markdown",
415 | "metadata": {
416 | "colab_type": "text",
417 | "id": "Z93vvAdGxDMD"
418 | },
419 | "source": [
420 | "## Dataset\n",
421 | "\n",
422 | "We can use TensorFlow Datasets to load the Dogs vs Cats dataset."
423 | ]
424 | },
425 | {
426 | "cell_type": "code",
427 | "metadata": {
428 | "colab_type": "code",
429 | "id": "DrIUV3V0xDL_",
430 | "colab": {}
431 | },
432 | "source": [
433 | "splits = tfds.Split.ALL.subsplit(weighted=(80, 20))\n",
434 | "\n",
435 | "splits, info = tfds.load('cats_vs_dogs', with_info=True, as_supervised=True, split = splits)\n",
436 | "\n",
437 | "(train_examples, validation_examples) = splits\n",
438 | "\n",
439 | "num_examples = info.splits['train'].num_examples\n",
440 | "num_classes = info.features['label'].num_classes"
441 | ],
442 | "execution_count": 0,
443 | "outputs": []
444 | },
445 | {
446 | "cell_type": "markdown",
447 | "metadata": {
448 | "colab_type": "text",
449 | "id": "UlFZ_hwjCLgS"
450 | },
451 | "source": [
452 | "The images in the Dogs vs. Cats dataset are not all the same size."
453 | ]
454 | },
455 | {
456 | "cell_type": "code",
457 | "metadata": {
458 | "colab_type": "code",
459 | "id": "W4lDPkn2cpWZ",
460 | "colab": {}
461 | },
462 | "source": [
463 | "for i, example_image in enumerate(train_examples.take(3)):\n",
464 | " print(\"Image {} shape: {}\".format(i+1, example_image[0].shape))"
465 | ],
466 | "execution_count": 0,
467 | "outputs": []
468 | },
469 | {
470 | "cell_type": "markdown",
471 | "metadata": {
472 | "colab_type": "text",
473 | "id": "mbgpD3E6gM2P"
474 | },
475 | "source": [
476 | "So we need to reformat all images to the resolution expected by MobileNet (224, 224).\n",
477 | "\n",
478 | "The `.repeat()` and `steps_per_epoch` here is not required, but saves ~15s per epoch, since the shuffle-buffer only has to cold-start once."
479 | ]
480 | },
481 | {
482 | "cell_type": "code",
483 | "metadata": {
484 | "colab_type": "code",
485 | "id": "we_ftzQxNf7e",
486 | "colab": {}
487 | },
488 | "source": [
489 | "def format_image(image, label):\n",
490 | " image = tf.image.resize(image, (IMAGE_RES, IMAGE_RES))/255.0\n",
491 | " return image, label\n",
492 | "\n",
493 | "BATCH_SIZE = 32\n",
494 | "\n",
495 | "train_batches = train_examples.shuffle(num_examples//4).map(format_image).batch(BATCH_SIZE).prefetch(1)\n",
496 | "validation_batches = validation_examples.map(format_image).batch(BATCH_SIZE).prefetch(1)"
497 | ],
498 | "execution_count": 0,
499 | "outputs": []
500 | },
501 | {
502 | "cell_type": "markdown",
503 | "metadata": {
504 | "colab_type": "text",
505 | "id": "0gTN7M_GxDLx"
506 | },
507 | "source": [
508 | "## Run the classifier on a batch of images"
509 | ]
510 | },
511 | {
512 | "cell_type": "markdown",
513 | "metadata": {
514 | "colab_type": "text",
515 | "id": "O3fvrZR8xDLv"
516 | },
517 | "source": [
518 | "Remember our `model` object is still the full MobileNet model trained on ImageNet, so it has 1000 possible output classes.\n",
519 | "ImageNet has a lot of dogs and cats in it, so let's see if it can predict the images in our Dogs vs. Cats dataset.\n"
520 | ]
521 | },
522 | {
523 | "cell_type": "code",
524 | "metadata": {
525 | "colab_type": "code",
526 | "id": "kii_jWZYOn0B",
527 | "colab": {}
528 | },
529 | "source": [
530 | "image_batch, label_batch = next(iter(train_batches.take(1)))\n",
531 | "image_batch = image_batch.numpy()\n",
532 | "label_batch = label_batch.numpy()\n",
533 | "\n",
534 | "result_batch = model.predict(image_batch)\n",
535 | "\n",
536 | "predicted_class_names = imagenet_labels[np.argmax(result_batch, axis=-1)]\n",
537 | "predicted_class_names"
538 | ],
539 | "execution_count": 0,
540 | "outputs": []
541 | },
542 | {
543 | "cell_type": "markdown",
544 | "metadata": {
545 | "colab_type": "text",
546 | "id": "QmvSWg9nxDLa"
547 | },
548 | "source": [
549 | "The labels seem to match names of Dogs and Cats. Let's now plot the images from our Dogs vs Cats dataset and put the ImageNet labels next to them."
550 | ]
551 | },
552 | {
553 | "cell_type": "code",
554 | "metadata": {
555 | "colab_type": "code",
556 | "id": "IXTB22SpxDLP",
557 | "colab": {}
558 | },
559 | "source": [
560 | "plt.figure(figsize=(10,9))\n",
561 | "for n in range(30):\n",
562 | " plt.subplot(6,5,n+1)\n",
563 | " plt.subplots_adjust(hspace = 0.3)\n",
564 | " plt.imshow(image_batch[n])\n",
565 | " plt.title(predicted_class_names[n])\n",
566 | " plt.axis('off')\n",
567 | "_ = plt.suptitle(\"ImageNet predictions\")"
568 | ],
569 | "execution_count": 0,
570 | "outputs": []
571 | },
572 | {
573 | "cell_type": "markdown",
574 | "metadata": {
575 | "colab_type": "text",
576 | "id": "JzV457OXreQP"
577 | },
578 | "source": [
579 | "# Part 3: Do simple transfer learning with TensorFlow Hub\n",
580 | "\n",
581 | "Let's now use TensorFlow Hub to do Transfer Learning.\n",
582 | "\n",
583 | "With transfer learning we reuse parts of an already trained model and change the final layer, or several layers, of the model, and then retrain those layers on our own dataset.\n",
584 | "\n",
585 | "In addition to complete models, TensorFlow Hub also distributes models without the last classification layer. These can be used to easily do transfer learning. We will continue using MobileNet v2 because in later parts of this course, we will take this model and deploy it on a mobile device using [TensorFlow Lite](https://www.tensorflow.org/lite). Any [image feature vector URL from tfhub.dev](https://tfhub.dev/s?module-type=image-feature-vector&q=tf2) would work here.\n",
586 | "\n",
587 | "We'll also continue to use the Dogs vs Cats dataset, so we will be able to compare the performance of this model against the ones we created from scratch earlier.\n",
588 | "\n",
589 | "Note that we're calling the partial model from TensorFlow Hub (without the final classification layer) a `feature_extractor`. The reasoning for this term is that it will take the input all the way to a layer containing a number of features. So it has done the bulk of the work in identifying the content of an image, except for creating the final probability distribution. That is, it has extracted the features of the image."
590 | ]
591 | },
592 | {
593 | "cell_type": "code",
594 | "metadata": {
595 | "colab_type": "code",
596 | "id": "5wB030nezBwI",
597 | "colab": {}
598 | },
599 | "source": [
600 | "URL = \"https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/2\"\n",
601 | "feature_extractor = hub.KerasLayer(URL,\n",
602 | " input_shape=(IMAGE_RES, IMAGE_RES,3))"
603 | ],
604 | "execution_count": 0,
605 | "outputs": []
606 | },
607 | {
608 | "cell_type": "markdown",
609 | "metadata": {
610 | "colab_type": "text",
611 | "id": "pkSvAPvKOWg2"
612 | },
613 | "source": [
614 | "Let's run a batch of images through this, and see the final shape. 32 is the number of images, and 1280 is the number of neurons in the last layer of the partial model from TensorFlow Hub."
615 | ]
616 | },
617 | {
618 | "cell_type": "code",
619 | "metadata": {
620 | "colab_type": "code",
621 | "id": "Of7i-35F09ls",
622 | "colab": {}
623 | },
624 | "source": [
625 | "feature_batch = feature_extractor(image_batch)\n",
626 | "print(feature_batch.shape)"
627 | ],
628 | "execution_count": 0,
629 | "outputs": []
630 | },
631 | {
632 | "cell_type": "markdown",
633 | "metadata": {
634 | "colab_type": "text",
635 | "id": "CtFmF7A5E4tk"
636 | },
637 | "source": [
638 | "Freeze the variables in the feature extractor layer, so that the training only modifies the final classifier layer."
639 | ]
640 | },
641 | {
642 | "cell_type": "code",
643 | "metadata": {
644 | "colab_type": "code",
645 | "id": "Jg5ar6rcE4H-",
646 | "colab": {}
647 | },
648 | "source": [
649 | "feature_extractor.trainable = False"
650 | ],
651 | "execution_count": 0,
652 | "outputs": []
653 | },
654 | {
655 | "cell_type": "markdown",
656 | "metadata": {
657 | "colab_type": "text",
658 | "id": "RPVeouTksO9q"
659 | },
660 | "source": [
661 | "## Attach a classification head\n",
662 | "\n",
663 | "Now wrap the hub layer in a `tf.keras.Sequential` model, and add a new classification layer."
664 | ]
665 | },
666 | {
667 | "cell_type": "code",
668 | "metadata": {
669 | "colab_type": "code",
670 | "id": "mGcY27fY1q3Q",
671 | "colab": {}
672 | },
673 | "source": [
674 | "model = tf.keras.Sequential([\n",
675 | " feature_extractor,\n",
676 | " layers.Dense(2, activation='softmax')\n",
677 | "])\n",
678 | "\n",
679 | "model.summary()"
680 | ],
681 | "execution_count": 0,
682 | "outputs": []
683 | },
684 | {
685 | "cell_type": "markdown",
686 | "metadata": {
687 | "colab_type": "text",
688 | "id": "OHbXQqIquFxQ"
689 | },
690 | "source": [
691 | "## Train the model\n",
692 | "\n",
693 | "We now train this model like any other, by first calling `compile` followed by `fit`."
694 | ]
695 | },
696 | {
697 | "cell_type": "code",
698 | "metadata": {
699 | "colab_type": "code",
700 | "id": "3n0Wb9ylKd8R",
701 | "colab": {}
702 | },
703 | "source": [
704 | "model.compile(\n",
705 | " optimizer='adam',\n",
706 | " loss='sparse_categorical_crossentropy',\n",
707 | " metrics=['accuracy'])\n",
708 | "\n",
709 | "EPOCHS = 10\n",
710 | "history = model.fit(train_batches,\n",
711 | " epochs=EPOCHS,\n",
712 | " validation_data=validation_batches)"
713 | ],
714 | "execution_count": 0,
715 | "outputs": []
716 | },
717 | {
718 | "cell_type": "markdown",
719 | "metadata": {
720 | "colab_type": "text",
721 | "id": "76as-K8-vFQJ"
722 | },
723 | "source": [
724 | "You can see we get ~97% validation accuracy, which is absolutely awesome. This is a huge improvement over the model we created in the previous lesson, where we were able to get ~83% accuracy. The reason for this difference is that MobileNet was carefully designed over a long time by experts, then trained on a massive dataset (ImageNet).\n",
725 | "\n",
726 | "Although not equivalent to TensorFlow Hub, you can check out how to create MobileNet in Keras [here](https://github.com/keras-team/keras-applications/blob/master/keras_applications/mobilenet.py).\n",
727 | "\n",
728 | "Let's plot the training and validation accuracy/loss graphs."
729 | ]
730 | },
731 | {
732 | "cell_type": "code",
733 | "metadata": {
734 | "colab_type": "code",
735 | "id": "d28dhbFpr98b",
736 | "colab": {}
737 | },
738 | "source": [
739 | "acc = history.history['accuracy']\n",
740 | "val_acc = history.history['val_accuracy']\n",
741 | "\n",
742 | "loss = history.history['loss']\n",
743 | "val_loss = history.history['val_loss']\n",
744 | "\n",
745 | "epochs_range = range(EPOCHS)\n",
746 | "\n",
747 | "plt.figure(figsize=(8, 8))\n",
748 | "plt.subplot(1, 2, 1)\n",
749 | "plt.plot(epochs_range, acc, label='Training Accuracy')\n",
750 | "plt.plot(epochs_range, val_acc, label='Validation Accuracy')\n",
751 | "plt.legend(loc='lower right')\n",
752 | "plt.title('Training and Validation Accuracy')\n",
753 | "\n",
754 | "plt.subplot(1, 2, 2)\n",
755 | "plt.plot(epochs_range, loss, label='Training Loss')\n",
756 | "plt.plot(epochs_range, val_loss, label='Validation Loss')\n",
757 | "plt.legend(loc='upper right')\n",
758 | "plt.title('Training and Validation Loss')\n",
759 | "plt.show()"
760 | ],
761 | "execution_count": 0,
762 | "outputs": []
763 | },
764 | {
765 | "cell_type": "markdown",
766 | "metadata": {
767 | "colab_type": "text",
768 | "id": "5zmoDisGvNye"
769 | },
770 | "source": [
771 | "What is a bit curious here is that validation performance is better than training performance, right from the start to the end of execution.\n",
772 | "\n",
773 | "One reason for this is that validation performance is measured at the end of the epoch, but training performance is the average values across the epoch.\n",
774 | "\n",
775 | "The bigger reason though is that we're reusing a large part of MobileNet which is already trained on Dogs and Cats images. While doing training, the network is still performing image augmentation on the training images, but not on the validation dataset. This means the training images may be harder to classify compared to the normal images in the validation dataset."
776 | ]
777 | },
778 | {
779 | "cell_type": "markdown",
780 | "metadata": {
781 | "colab_type": "text",
782 | "id": "kb__ZN8uFn-D"
783 | },
784 | "source": [
785 | "## Check the predictions\n",
786 | "\n",
787 | "To redo the plot from before, first get the ordered list of class names."
788 | ]
789 | },
790 | {
791 | "cell_type": "code",
792 | "metadata": {
793 | "colab_type": "code",
794 | "id": "W_Zvg2i0fzJu",
795 | "colab": {}
796 | },
797 | "source": [
798 | "class_names = np.array(info.features['label'].names)\n",
799 | "class_names"
800 | ],
801 | "execution_count": 0,
802 | "outputs": []
803 | },
804 | {
805 | "cell_type": "markdown",
806 | "metadata": {
807 | "colab_type": "text",
808 | "id": "4Olg6MsNGJTL"
809 | },
810 | "source": [
811 | "Run the image batch through the model and convert the indices to class names."
812 | ]
813 | },
814 | {
815 | "cell_type": "code",
816 | "metadata": {
817 | "colab_type": "code",
818 | "id": "fCLVCpEjJ_VP",
819 | "colab": {}
820 | },
821 | "source": [
822 | "predicted_batch = model.predict(image_batch)\n",
823 | "predicted_batch = tf.squeeze(predicted_batch).numpy()\n",
824 | "predicted_ids = np.argmax(predicted_batch, axis=-1)\n",
825 | "predicted_class_names = class_names[predicted_ids]\n",
826 | "predicted_class_names"
827 | ],
828 | "execution_count": 0,
829 | "outputs": []
830 | },
831 | {
832 | "cell_type": "markdown",
833 | "metadata": {
834 | "colab_type": "text",
835 | "id": "CkGbZxl9GZs-"
836 | },
837 | "source": [
838 | "Let's look at the true labels and predicted ones."
839 | ]
840 | },
841 | {
842 | "cell_type": "code",
843 | "metadata": {
844 | "colab_type": "code",
845 | "id": "nL9IhOmGI5dJ",
846 | "colab": {}
847 | },
848 | "source": [
849 | "print(\"Labels: \", label_batch)\n",
850 | "print(\"Predicted labels: \", predicted_ids)"
851 | ],
852 | "execution_count": 0,
853 | "outputs": []
854 | },
855 | {
856 | "cell_type": "code",
857 | "metadata": {
858 | "colab_type": "code",
859 | "id": "wC_AYRJU9NQe",
860 | "colab": {}
861 | },
862 | "source": [
863 | "plt.figure(figsize=(10,9))\n",
864 | "for n in range(30):\n",
865 | " plt.subplot(6,5,n+1)\n",
866 | " plt.subplots_adjust(hspace = 0.3)\n",
867 | " plt.imshow(image_batch[n])\n",
868 | " color = \"blue\" if predicted_ids[n] == label_batch[n] else \"red\"\n",
869 | " plt.title(predicted_class_names[n].title(), color=color)\n",
870 | " plt.axis('off')\n",
871 | "_ = plt.suptitle(\"Model predictions (blue: correct, red: incorrect)\")"
872 | ],
873 | "execution_count": 0,
874 | "outputs": []
875 | }
876 | ]
877 | }
--------------------------------------------------------------------------------