{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Preprocess the dogs and cats dataset\nCheck out [Dogs-vs-cats](https://thedatafrog.com/en/articles/dogs-vs-cats/)"},{"metadata":{},"cell_type":"markdown","source":"The files in zip are extracted to the directories created in the root: ***/train*** and ***/test1***"},{"metadata":{"trusted":true},"cell_type":"code","source":"datasetdir = '/'\nos.chdir(datasetdir)\nif os.path.exists('train/train/cat.0.jpg'):\n    print(\"train already unzipped\")\nelse:\n    !unzip kaggle/input/dogs-vs-cats/train.zip -d train","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"datasetdir = '/'\nos.chdir(datasetdir)\nif os.path.exists('test/test1/1.jpg'):\n    print(\"test1 already unzipped\")\nelse:\n    !unzip kaggle/input/dogs-vs-cats/test1.zip -d test","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Make directories under **/kaggle/working** : **/cats** and **/dogs**, and from **train**, we will put all dog images in **dogs** , and all cat images in **cats**"},{"metadata":{"trusted":true},"cell_type":"code","source":"datasetdir = '/kaggle/working'\nimport os\nimport shutil\nos.chdir(datasetdir)\n\nif os.path.exists(\"cats\"):\n    print('cats exists')\nelse:\n    os.mkdir('cats')\nif os.path.exists(\"cats/cat.0.jpg\"):\n    print('cat images are moved')\nelse:\n    source_dir = '/train/train'\n    target_dir = '/kaggle/working/cats/'\n    file_names = os.listdir(source_dir)\n    for filename in file_names:\n        if filename.startswith(\"cat\"):\n            shutil.move(os.path.join(source_dir,filename),target_dir)\n    \n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"if os.path.exists('dogs'):\n    print('dogs exists')\nelse:\n    os.mkdir('dogs') \n\nif os.path.exists(\"dogs/dog.0.jpg\"):\n    print('dogs images are moved')\nelse:\n    source_dir = '/train/train'\n    target_dir = '/kaggle/working/dogs'\n    file_names = os.listdir(source_dir)\n    for filename in file_names:\n        if filename.startswith(\"dog\"):\n            shutil.move(os.path.join(source_dir,filename),target_dir)\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"if os.path.exists('test1'):\n    print('test exists')  \nelse:\n    os.mkdir('test1')\n\nif os.path.exists(\"test1/1.jpg\"):\n    print('test images are moved')\nelse:\n    source_dir = '/test/test1'\n    target_dir = '/kaggle/working/test1/'\n    file_names = os.listdir(source_dir)\n    for filename in file_names:\n        shutil.move(os.path.join(source_dir,filename),target_dir)\n    \n#test dataset is in the format of XXX(ind).jpg","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Enter in the cell below the location of your dataset directory, the one that contains the **dogs** and **cats** subdirectories, and execute it:"},{"metadata":{"trusted":true},"cell_type":"code","source":"# define and move to dataset directory\ndatasetdir = '/kaggle/working'\nimport os\nos.chdir(datasetdir)\n\n# import the needed packages\nimport matplotlib.pyplot as plt\nimport matplotlib.image as img\nfrom tensorflow import keras\n# shortcut to the ImageDataGenerator class\nImageDataGenerator = keras.preprocessing.image.ImageDataGenerator","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"First let's start investigating the dataset by plotting the first picture in each category:"},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.subplot(1,2,1)\nplt.imshow(img.imread('cats/cat.0.jpg'))\nplt.subplot(1,2,2)\nplt.imshow(img.imread('dogs/dog.0.jpg'))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Improve the dataset quality"},{"metadata":{},"cell_type":"markdown","source":"First, here are the indices for the bad images"},{"metadata":{"trusted":true},"cell_type":"code","source":"bad_dog_ids = [5604, 6413, 8736, 8898, 9188, 9517, 10161, \n               10190, 10237, 10401, 10797, 11186]\n\nbad_cat_ids = [2939, 3216, 4688, 4833, 5418, 6215, 7377, \n               8456, 8470, 11565, 12272]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Try to retrieve the images with these ids from the `cats` and `dogs` directories:"},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_images(ids, categ):\n    #return the images corresponding to a list of ids'''\n    images = []\n    dirname = categ+'s' # dog -> dogs\n    for theid in ids: \n        fname = '{dirname}/{categ}.{theid}.jpg'.format(\n        dirname=dirname,\n        categ=categ, \n        theid=theid\n    )\n        im = img.imread(fname)\n        images.append(im)\n    \n    return images","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_images(images, ids):\n    ncols, nrows = 4, 3\n    fig = plt.figure( figsize=(ncols*3, nrows*3), dpi=90)\n    for i, (img, theid) in enumerate(zip(images,ids)):\n        plt.subplot(nrows, ncols, i+1)\n        plt.imshow(img)\n        plt.title(str(theid))\n        plt.axis('off')\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Cleanup the dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"import glob\nimport re\nimport shutil\n# matches any string with the substring \".<digits>.\"\n# such as dog.666.jpg\npattern = re.compile(r'.*\\.(\\d+)\\..*')\n\ndef trash_path(dirname):\n    '''return the path of the Trash directory, \n    where the bad dog and bad cat images will be moved.\n    Note that the Trash directory should not be within the dogs/ \n    or the cats/ directory, or Keras will still find these pictures.\n    '''\n    return os.path.join('../Trash', dirname)\n\ndef cleanup(ids, dirname): \n    '''move away images with these ids in dirname\n    '''\n    os.chdir(datasetdir)\n    # keep track of current directory\n    oldpwd = os.getcwd()\n    # go to either cats/ or dogs/\n    os.chdir(dirname)\n    # create the trash directory. \n    # if it exists, it is first removed\n    trash = trash_path(dirname)\n    if os.path.isdir(trash):\n        shutil.rmtree(trash)\n    os.makedirs(trash, exist_ok=True)\n    # loop on all cat or dog files\n    fnames = os.listdir()\n    for fname in fnames:\n        m = pattern.match(fname)\n        if m: \n            # extract the id\n            the_id = int(m.group(1))\n            if the_id in ids:\n                # this id is in the list of ids to be trashed\n                print('moving to {}: {}'.format(trash, fname))\n                shutil.move(fname, trash)\n    # going back to root directory\n    os.chdir(oldpwd)\n\ndef restore(dirname):\n    '''restores files in the trash\n    I will need this to restore this tutorial to initial state for you \n    and you might need it if you want to try training the network\n    without the cleaning of bad images\n    '''\n    os.chdir(datasetdir)\n    oldpwd = os.getcwd()\n    os.chdir(dirname)\n    trash = trash_path(dirname)\n    print(trash)\n    for fname in os.listdir(trash):\n        fname = os.path.join(trash,fname)\n        print('restoring', fname)\n        print(os.getcwd())\n        shutil.move(fname, os.getcwd())\n    os.chdir(oldpwd)\n    \n    #i.g. restore('dogs')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"datasetdir = '/kaggle/working'\nos.chdir(datasetdir)\nif not os.path.exists(\"dogs/dog.5604.jpg\"):\n    print(\"Dog trash is moved\")\nelse:\n    bad_dogs = load_images(bad_dog_ids, 'dog')\n    plot_images(bad_dogs, bad_dog_ids)\n    cleanup(bad_dog_ids, 'dogs')\nif not os.path.exists(\"cats/cat.2939.jpg\"):\n    print(\"Cat trash is moved\")\nelse:    \n    bad_cats = load_images(bad_cat_ids, 'cat')\n    plot_images(bad_cats, bad_cat_ids)\n    cleanup(bad_cat_ids,'cats')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Load the dogs and cats image dataset with Keras"},{"metadata":{},"cell_type":"markdown","source":"Neural networks are trained by presenting them with batches of images, each of them with a label identifying the true nature of the image (either cat or dog in our case). A batch may contain of the order of a few tenths to a couple hundred images.\n\nFor each image, the prediction of the network is compared with the corresponding label, and the distance between the predictions of the network and the truth is evaluated for the whole batch. Then, after the processing of the batch, the network parameters are changed in a way to minimize this distance, therefore improving the prediction capability of the network. The training then proceeds iteratively, batch after batch.\n\nSo we need a way to turn our images, now files on disk, into batches of data arrays in memory that can be fed to the network during training.\n\nThe ImageDataGenerator can readily be used for this purpose. "},{"metadata":{"trusted":true},"cell_type":"code","source":"gen = ImageDataGenerator()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now, we will use the  [flow_from_directory](https://keras.io/preprocessing/image/#flow_from_directory) method of the `gen` object to start generating batches. \n\nThis method will return an iterator that returns a batch everytime it's iterated on. To see how the data is organized, we can simply create this iterator, and get a first batch to look at it: "},{"metadata":{"trusted":true},"cell_type":"code","source":"datasetdir = '/kaggle/working'\nimport os\nos.chdir(datasetdir)\niterator = gen.flow_from_directory(\n    os.getcwd(), \n    target_size=(256,256), \n    classes=('dogs','cats')\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# we can guess that the iterator has a next function, \n# because all python iterators have one. \nbatch = iterator.next()\nlen(batch) #number of elements in the batch\n#their types are numpy array\n#print(type(batch[0]))\n#print(type(batch[1]))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"[ImageDataGenerator](https://keras.io/preprocessing/image/#imagedatagenerator-class) automatically produced a label for each image depending on the directory in which it was found. One-hot encoding is used for the labels, and this is precisely what we need for the classification task we are up to. If you want to know more about one-hot encoding, check my post about a [First Neural Network with Keras](https://thedatafrog.com/first-neural-network-keras/#Preparing-the-dataset). \n\nWe can also guess that the label `[0., 1.]` corresponds to a true cat, and `[1.,0.]` to a true dog. The prediction of the network for a given image will lie somewhere in between, like `[0.6,0.4]` for a dog. Still, that's only a guess, and a guess is not enough! we need to be sure, or we take the risk to feed our network with mislabeled images (and garbage in, garbage out). "},{"metadata":{},"cell_type":"markdown","source":"# Pet plotting for label validation\n\nTo validate the dataset labels, we want to check that, for a few batches, the labels are correctly set. So we need a function that can plot a fairly large number of images and label them. Here it is: "},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\ndef plot_images(batch):\n    imgs = batch[0]\n    labels = batch[1]\n    ncols, nrows = 4,8\n    fig = plt.figure( figsize=(ncols*3, nrows*3), dpi=90)\n    for i, (img,label) in enumerate(zip(imgs,labels)):\n        plt.subplot(nrows, ncols, i+1)\n        plt.imshow(img.astype(np.int))\n        assert(label[0]+label[1]==1.)\n        categ = 'dog' if label[0]>0.5 else 'cat'\n        plt.title( '{} {}'.format(str(label), categ))\n        plt.axis('off')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_images(iterator.next())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Split the training and validation samples with ImageDataGenerator\n\nWe will train our neural network on a subset of the dog and cat images called the *training dataset*. \n\nIf a network is complex enough (if it has enough parameters), it can start [overfitting](https://thedatafrog.com/overfitting-illustrated/), which means that it is able to learn the specific features of the images in the training dataset. In other words, the network looses its generality, and its ability to classify an arbitrary image as a dog or cat image. \n\nTo make sure that overfitting does not occur, we will evaluate the performance of the network on a *validation dataset*, disjoint from the training dataset. \n\nLet's first create a new `ImageDataGenerator`. With respect to the previous one, we request to: \n\n* rescale all color levels to be in the range 0-1. We're doing this because neural nets behave better on input variables of the order of unity. \n* use 20% of the images for validation, and thus 80% for the training. "},{"metadata":{"trusted":true},"cell_type":"code","source":"imgdatagen = ImageDataGenerator(\n    rescale = 1/255., \n    validation_split = 0.2,\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Next, define our iterators for the training and validation datasets. \nWe use a batch size of 30 because, typically, networks are not able to learn if the batch size is too large or too small. And the images are forced to 256x256 pixels.\n\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"datasetdir = '/kaggle/working'\nimport os\nos.chdir(datasetdir)\n\nbatch_size = 30\nheight, width = (256,256)\n#train_generator\ntrain_dataset = imgdatagen.flow_from_directory(\n    os.getcwd(),\n    target_size = (height, width), \n    classes = ('dogs','cats'),\n    batch_size = batch_size,\n    subset = 'training'\n)\n#validation_generator\nval_dataset = imgdatagen.flow_from_directory(\n    os.getcwd(),\n    target_size = (height, width), \n    classes = ('dogs','cats'),\n    batch_size = batch_size,\n    subset = 'validation'\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Convolutional Neural Network- ResNet50"},{"metadata":{},"cell_type":"markdown","source":"Check out \n[學習基於Keras框架的ResNet網路及實踐筆記](https://itw01.com/U468XEP.html), \n[ResNet50](https://github.com/priya-dwivedi/Deep-Learning/blob/master/resnet_keras/Residual_Networks_yourself.ipynb), [kera-Resnet50](https://github.com/keras-team/keras-applications/blob/master/keras_applications/resnet50.py)"},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nfrom keras import layers\nfrom keras.layers import Input, Add, Dense, Activation, ZeroPadding2D, BatchNormalization, Flatten, Conv2D, AveragePooling2D, MaxPooling2D, GlobalMaxPooling2D\nfrom keras.models import Model, load_model\nfrom keras.preprocessing import image\nfrom keras.utils import layer_utils\nfrom keras.utils.data_utils import get_file\nfrom keras.applications.imagenet_utils import preprocess_input\nimport pydot\nfrom IPython.display import SVG\nfrom keras.utils.vis_utils import model_to_dot\nfrom keras.utils import plot_model\n#from resnets_utils import *\nfrom keras.initializers import glorot_uniform\nimport scipy.misc\nfrom matplotlib.pyplot import imshow\n%matplotlib inline\n\nimport keras.backend as K\nK.set_image_data_format('channels_last')\nK.set_learning_phase(1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def identity_block(X, f, filters, stage, block): \n    conv_name_base = 'res' + str(stage) + block + '_branch' \n    bn_name_base = 'bn' + str(stage) + block + '_branch' \n    F1, F2, F3 = filters \n    X_shortcut = X \n    X = Conv2D(filters = F1, kernel_size = (1,1), strides = (1,1), padding = 'valid', name = conv_name_base + '2a', kernel_initializer = glorot_uniform(seed = 0))(X) \n    X = BatchNormalization(axis = 3, name = bn_name_base + '2a')(X) \n    X = Activation('relu')(X) \n   \n    X = Conv2D(filters = F2, kernel_size = (f,f), strides = (1,1), padding = 'same', name = conv_name_base + '2b', kernel_initializer = glorot_uniform(seed = 0))(X) \n    X = BatchNormalization(axis = 3, name = bn_name_base + '2b')(X) \n    X = Activation('relu')(X) \n    \n    X = Conv2D(filters = F3, kernel_size = (1,1), strides = (1,1), padding = 'valid', name = conv_name_base + '2c', kernel_initializer = glorot_uniform(seed = 0))(X) \n    X = BatchNormalization(axis = 3, name = bn_name_base + '2c')(X) \n    \n    X = Add()([X, X_shortcut]) \n    X = Activation('relu')(X) \n    return X ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def convolutional_block(X, f, filters, stage, block, s=2):\n    \n    conv_name_base = 'res' + str(stage) + block + '_branch' \n    bn_name_base = 'bn' + str(stage) + block + '_branch' \n    F1, F2, F3 = filters \n    \n    X_shortcut = X \n    \n    X = Conv2D(filters = F1, kernel_size = (1,1), strides = (s,s), name = conv_name_base + '2a', kernel_initializer = glorot_uniform(seed = 0))(X) \n    X = BatchNormalization(axis = 3, name = bn_name_base + '2a')(X) \n    X = Activation('relu')(X) \n    \n    X = Conv2D(filters = F2, kernel_size = (f,f), strides = (1,1), padding = 'same', name = conv_name_base + '2b', kernel_initializer = glorot_uniform(seed = 0))(X) \n    X = BatchNormalization(axis = 3, name = bn_name_base + '2b')(X) \n    X = Activation('relu')(X) \n    \n    X = Conv2D(filters = F3, kernel_size = (1,1), strides = (1,1), name = conv_name_base + '2c', kernel_initializer = glorot_uniform(seed = 0))(X) \n    X = BatchNormalization(axis = 3, name = bn_name_base + '2c')(X) \n    \n    X_shortcut = Conv2D(F3, (1,1), strides = (s,s), name = conv_name_base + '1', kernel_initializer = glorot_uniform(seed=0))(X_shortcut) \n    X_shortcut = BatchNormalization(axis = 3, name=bn_name_base + '1')(X_shortcut) \n    \n    X = Add()([X, X_shortcut])\n    X = Activation('relu')(X) \n    return X","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def ResNet50(input_shape=(64, 64, 3), classes=6):\n\n    # Define the input as a tensor with shape input_shape\n    X_input = Input(input_shape)\n\n    # Zero-Padding\n    X = ZeroPadding2D((3, 3))(X_input)\n\n    # Stage 1\n    X = Conv2D(64, (7, 7), strides=(2, 2), name='conv1', kernel_initializer=glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis=3, name='bn_conv1')(X)\n    X = Activation('relu')(X)\n    X = MaxPooling2D((3, 3), strides=(2, 2))(X)\n\n    # Stage 2\n    X = convolutional_block(X, f=3, filters=[64, 64, 256], stage=2, block='a', s=1)\n    X = identity_block(X, 3, [64, 64, 256], stage=2, block='b')\n    X = identity_block(X, 3, [64, 64, 256], stage=2, block='c')\n\n    ### START CODE HERE ###\n\n    # Stage 3 (≈4 lines)\n    X = convolutional_block(X, f = 3, filters = [128, 128, 512], stage = 3, block='a', s = 2)\n    X = identity_block(X, 3, [128, 128, 512], stage=3, block='b')\n    X = identity_block(X, 3, [128, 128, 512], stage=3, block='c')\n    X = identity_block(X, 3, [128, 128, 512], stage=3, block='d')\n\n    # Stage 4 (≈6 lines)\n    X = convolutional_block(X, f = 3, filters = [256, 256, 1024], stage = 4, block='a', s = 2)\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='b')\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='c')\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='d')\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='e')\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='f')\n\n    # Stage 5 (≈3 lines)\n    X = convolutional_block(X, f = 3, filters = [512, 512, 2048], stage = 5, block='a', s = 2)\n    X = identity_block(X, 3, [512, 512, 2048], stage=5, block='b')\n    X = identity_block(X, 3, [512, 512, 2048], stage=5, block='c')\n\n    # AVGPOOL (≈1 line). Use \"X = AveragePooling2D(...)(X)\"\n    X = AveragePooling2D((2,2), name=\"avg_pool\")(X)\n\n    ### END CODE HERE ###\n\n    # output layer\n    X = Flatten()(X)\n    X = Dense(classes, activation='softmax', name='fc' + str(classes), kernel_initializer = glorot_uniform(seed=0))(X)\n    \n    \n    # Create model\n    model = Model(inputs = X_input, outputs = X, name='ResNet50')\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = ResNet50(input_shape = (256, 256, 3), classes = 2)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''This is not Resnet50\nmodel = keras.models.Sequential()\n\n\ninitializers = {\n    \n}\nmodel.add( \n    keras.layers.Conv2D(\n        24, 5, input_shape=(256,256,3), \n        activation='relu', \n    )\n)\nmodel.add( keras.layers.MaxPooling2D(2) )\nmodel.add( \n    keras.layers.Conv2D(\n        48, 5, activation='relu', \n    )\n)\nmodel.add( keras.layers.MaxPooling2D(2) )\nmodel.add( \n    keras.layers.Conv2D(\n        96, 5, activation='relu', \n    )\n)\nmodel.add( keras.layers.Flatten() )\nmodel.add( keras.layers.Dropout(0.9) )\n\nmodel.add( keras.layers.Dense(\n    2, activation='softmax',\n    )\n)\n\nmodel.summary()\n'''","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## TensorBoard"},{"metadata":{},"cell_type":"markdown","source":"[tensorboard](https://www.tensorflow.org/tensorboard/get_started)"},{"metadata":{"trusted":true},"cell_type":"code","source":"%load_ext tensorboard","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import tensorflow as tf \nfrom tensorflow.keras.callbacks import TensorBoard\nimport time\n\n# Clear any logs from previous runs\n!rm -rf ./logs/ \n#!mkdir ./logs/\n'''\n# Download Ngrok to tunnel the tensorboard port to an external port\n!wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip\n!unzip ngrok-stable-linux-amd64.zip\n\n# Run tensorboard as well as Ngrox (for tunneling as non-blocking processes)\nimport os\nimport multiprocessing\n\n\npool = multiprocessing.Pool(processes = 10)\nresults_of_processes = [pool.apply_async(os.system, args=(cmd, ), callback = None )\n                        for cmd in [\n                        f\"tensorboard --logdir ./logs/ --host 0.0.0.0 --port 6006 &\",\n                        \"./ngrok http 6006 &\"\n                        ]]\n! curl -s http://localhost:4040/api/tunnels | python3 -c \\\n    \"import sys, json; print(json.load(sys.stdin)['tunnels'][0]['public_url'])\"\n'''\nimport datetime\nlog_dir = \"logs/fit/\" + datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\")\n\ntensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\nhistory = model.fit_generator(\n    train_dataset,\n    epochs=20,#20 \n    callbacks=[tensorboard_callback],\n    validation_data = val_dataset,\n    workers=10\n)\n'''\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"load tensorboard"},{"metadata":{"trusted":true},"cell_type":"code","source":"#%tensorboard --logdir logs","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"plot accuracy and loss"},{"metadata":{},"cell_type":"markdown","source":"## Reload the saved model and history "},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nos.chdir('/kaggle/input/traineddata')\n\nimport numpy\nimport tensorflow as tf\nimport keras.backend as backend\nfrom tensorflow.keras.models import load_model\nmodel = tf.keras.models.load_model('kera_resnet50_12-21_15_20.h5')\n\nimport json\nwith open('kera_resnet50_history_12-21_15_20.json') as file:\n    history = json.load(file)\n    \n    #kera_resnet50_history_12-25_15_08 weird high accuracy\n    #kera_resnet50_history_aug_12-25_13_31 augmented data","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_history(hist):\n    import matplotlib.pyplot as plt\n    fig = plt.figure('Accuracy')\n    plt.clf()\n    plt.subplot(2, 1, 1)\n    plt.plot(hist['accuracy'])\n    plt.plot(hist['val_accuracy'])\n    plt.legend(['Training', 'Testing'])\n    plt.xlabel('Epoch')\n    plt.ylabel('accuracy')\n    plt.title('Accuracy')\n    plt.tight_layout()\n    plt.subplot(2, 1, 2)\n    plt.plot(hist['loss'])\n    plt.plot(hist['val_loss'])\n    plt.xlabel('Epoch')\n    plt.ylabel('loss')\n    plt.title('Loss')\n    plt.legend(['Training', 'Testing'])\n    plt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_history(history)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Save model and history"},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\n# Create a time stamp\nimport pytz\nfrom datetime import datetime\ntimezone = pytz.timezone(\"Asia/Taipei\")\nos_time = datetime.now()\nlocal_time = timezone.localize(os_time)\ntime_stamp = local_time.strftime(\"%m-%d_%H_%M\")\n\n# Save the model\nmodel_filename = 'kera_resnet50_'+time_stamp+'.h5'\nmodel.save(model_filename)\nprint('Successfully save \\'' + model_filename + '\\'')\n\n# Save Training history as json file\nimport json\nmerge_hist = {**history.history, **history.params}\nj = json.dumps(merge_hist)\nhist_filename = 'kera_resnet50_history_'+time_stamp+'.json'\nwith open(hist_filename, 'w') as file:\n    file.write(j)\n    print('Successfully write \\'' + hist_filename + '\\'')\n'''","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Print the accuracy and loss of the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"from datetime import datetime\n\ndef evaluate_model(model, generator):\n    score = model.evaluate_generator(generator=generator,           # Generator yielding tuples\n                                     steps=generator.samples//batch_size)   # number of steps (batches of samples) to yield from generator before stopping\n\n    print(\"%s: Model evaluated:\"\n          \"\\n\\t\\t\\t\\t\\t\\t Loss: %.3f\"\n          \"\\n\\t\\t\\t\\t\\t\\t Accuracy: %.3f\" %\n          (datetime.now().strftime('%Y-%m-%d_%H-%M-%S'),\n           score[0], score[1]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"evaluate_model(model,val_dataset)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Prediction on test data "},{"metadata":{},"cell_type":"markdown","source":"create a result.csv file"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_datagen = ImageDataGenerator(rescale=1. / 255)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\ndatasetdir = '/kaggle/working'\nos.chdir(datasetdir)\n\ntest_generator = test_datagen.flow_from_directory(\n    '/test',\n    target_size = (height, width), \n    color_mode=\"rgb\",\n    batch_size=1,\n    class_mode='categorical',\n    shuffle=False\n)\n'''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\nimport cv2\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport matplotlib.image as img\nfrom keras.preprocessing import image\nfrom keras.applications.resnet50 import preprocess_input, decode_predictions\n\npath, dirs, files = next(os.walk(\"test\"))\nfile_count = len(files)\ntest_steps = file_count / test_generator.batch_size\ntest_generator.reset()\npred=model.predict_generator(test_generator,test_steps,verbose=1)\n'''\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#predicted_class_indices=np.argmax(pred,axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\nlabels = (train_dataset.class_indices)\nlabels = dict((v,k) for k,v in labels.items())\npredictions = [labels[k] for k in predicted_class_indices]\n'''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\nfilenames=test_generator.filenames\nresults=pd.DataFrame({\"Filename\":filenames,\n                      \"Predictions\":predictions})\nresults.to_csv(\"results.csv\",index=False)\n'''","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"predict the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"datasetdir = '/kaggle/input/traineddata'\nos.chdir(datasetdir)\nfile=pd.read_csv(\"results.csv\")\nans=file['Predictions'].values\nname=file['Filename'].values","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import cv2\ndatasetdir = '/kaggle/working'\nos.chdir(datasetdir)\n\ndef class_prediction(test_ind):\n    # plot image\n    plt.axis('off')\n    print('Index:'+name[test_ind])\n    plt.title('Class: '+ans[test_ind])\n    img = cv2.imread(name[test_ind], 0)\n    if not os.path.isfile(name[test_ind]):\n        print (\"The file \" + name[test_ind] + \" does not exist.\")\n    else:\n        plt.imshow(img)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#choose inference[0~12499]\nimport random\ndatasetdir = '/kaggle/working'\nos.chdir(datasetdir)\nindex=random.randint(0,12499)\nclass_prediction(index)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data augmentation"},{"metadata":{"trusted":true},"cell_type":"code","source":"imgdatagen_aug = ImageDataGenerator(\n    rescale = 1/255., \n    horizontal_flip = True, \n    zoom_range = 0.3, \n    rotation_range = 15.,\n    validation_split = 0.1,\n)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size = 30\nheight, width = (256,256)\n\ndatasetdir = '/kaggle/working'\nos.chdir(datasetdir)\n\ntrain_dataset_aug = imgdatagen_aug.flow_from_directory(\n    os.getcwd(),\n    target_size = (height, width), \n    classes = ('dogs','cats'),\n    batch_size = batch_size,\n    subset = 'training'\n)\n\nval_dataset_aug = imgdatagen_aug.flow_from_directory(\n    os.getcwd(),\n    target_size = (height, width), \n    classes = ('dogs','cats'),\n    batch_size = batch_size,\n    subset = 'validation'\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Go up to build resnet50 model"},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\nhistory_augm = model.fit_generator(\n    train_dataset_aug,\n    epochs=20, \n    callbacks=[tensorboard_callback],\n    validation_data = val_dataset_aug,\n    workers=10\n)\n'''","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Save the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\n# Create a time stamp\nimport pytz\nfrom datetime import datetime\ntimezone = pytz.timezone(\"Asia/Taipei\")\nos_time = datetime.now()\nlocal_time = timezone.localize(os_time)\ntime_stamp = local_time.strftime(\"%m-%d_%H_%M\")\n\n# Save the model\nmodel_filename = 'kera_resnet50_aug_'+time_stamp+'.h5'\nmodel.save(model_filename)\nprint('Successfully save \\'' + model_filename + '\\'')\n\n# Save Training history as json file\nimport json\nmerge_hist = {**history_augm.history, **history_augm.params}\nj = json.dumps(merge_hist)\nhist_filename = 'kera_resnet50_history_aug_'+time_stamp+'.json'\nwith open(hist_filename, 'w') as file:\n  file.write(j)\n  print('Successfully write \\'' + hist_filename + '\\'')\n'''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nos.chdir('/kaggle/input/traineddata')\n\nimport numpy\nimport tensorflow as tf\nimport keras.backend as backend\nfrom tensorflow.keras.models import load_model\nmodel_aug = tf.keras.models.load_model('kera_resnet50_aug_12-25_13_31.h5')\n\nimport json\nwith open('kera_resnet50_history_aug_12-25_13_31.json') as file:\n    history_augm = json.load(file)\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_history(history_augm)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"evaluate_model(model_aug,val_dataset_aug)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## **Resize augmentation comparison**"},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\nfig = plt.figure()\nax = fig.add_axes([0,0,1,1])\nax.set_title('Resize augmentation comparison')\nax.grid()\nx = ['Before Resize', 'After Resize']\ny = [86.2,87.8]\nax.bar(x,y)\nplt.show()","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}