{"cells":[{"metadata":{"_uuid":"a6dbbe6a-7010-42b5-89b2-689dc1ba261a","_cell_guid":"696bb9b0-3824-43c3-9590-eafeb4d04ddd","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:45:23.274004Z","iopub.status.busy":"2020-11-19T21:45:23.273154Z","iopub.status.idle":"2020-11-19T21:45:30.119096Z","shell.execute_reply":"2020-11-19T21:45:30.119725Z"},"papermill":{"duration":6.890298,"end_time":"2020-11-19T21:45:30.119979","exception":false,"start_time":"2020-11-19T21:45:23.229681","status":"completed"},"tags":[]},"cell_type":"code","source":"import math, re, os\nimport tensorflow as tf\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom kaggle_datasets import KaggleDatasets\nfrom tensorflow import keras\nfrom functools import partial\nfrom sklearn.model_selection import train_test_split\nimport tensorflow.keras.backend as K\nprint(\"Tensorflow version \" + tf.__version__)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"803b0995-ad12-4d80-b5b2-e5d0fef4b31c","_cell_guid":"911aba9c-c683-4d1c-a5c9-ee4635f84743","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:45:30.373218Z","iopub.status.busy":"2020-11-19T21:45:30.372403Z","iopub.status.idle":"2020-11-19T21:45:34.382672Z","shell.execute_reply":"2020-11-19T21:45:34.382035Z"},"papermill":{"duration":4.150374,"end_time":"2020-11-19T21:45:34.382816","exception":false,"start_time":"2020-11-19T21:45:30.232442","status":"completed"},"tags":[]},"cell_type":"code","source":"try:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print('Device:', tpu.master())\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nexcept:\n    strategy = tf.distribute.get_strategy()\nprint('Number of replicas:', strategy.num_replicas_in_sync)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d8de2719-a3ea-4989-a569-265184b61118","_cell_guid":"cfd5755f-fa54-4ebf-8090-9ace5776e99c","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:45:34.555293Z","iopub.status.busy":"2020-11-19T21:45:34.541822Z","iopub.status.idle":"2020-11-19T21:47:59.71579Z","shell.execute_reply":"2020-11-19T21:47:59.714961Z"},"papermill":{"duration":145.219568,"end_time":"2020-11-19T21:47:59.715925","exception":false,"start_time":"2020-11-19T21:45:34.496357","status":"completed"},"tags":[]},"cell_type":"code","source":"AUTOTUNE = tf.data.experimental.AUTOTUNE\nGCS_PATH = KaggleDatasets().get_gcs_path()\nBATCH_SIZE = 32 * strategy.num_replicas_in_sync\nIMAGE_SIZE = [512, 512]\nCLASSES = ['0', '1', '2', '3', '4']\nEPOCHS = 75","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b05038d7-9631-41ee-8dd1-02a85192072d","_cell_guid":"2c49c09d-a011-4e4c-93bb-20f3db6478ea","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:47:59.952622Z","iopub.status.busy":"2020-11-19T21:47:59.951868Z","iopub.status.idle":"2020-11-19T21:47:59.954997Z","shell.execute_reply":"2020-11-19T21:47:59.955558Z"},"papermill":{"duration":0.04859,"end_time":"2020-11-19T21:47:59.955731","exception":false,"start_time":"2020-11-19T21:47:59.907141","status":"completed"},"tags":[]},"cell_type":"code","source":"def decode_image(image):\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.cast(image, tf.float32) / 255.0\n    image = tf.reshape(image, [*IMAGE_SIZE, 3])\n    return image","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f0a139eb-62f3-488f-bf96-6794fe460f33","_cell_guid":"92c0d45d-41e8-4adf-9cd3-968021b5432b","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:00.123967Z","iopub.status.busy":"2020-11-19T21:48:00.123143Z","iopub.status.idle":"2020-11-19T21:48:00.126902Z","shell.execute_reply":"2020-11-19T21:48:00.126284Z"},"papermill":{"duration":0.052475,"end_time":"2020-11-19T21:48:00.127039","exception":false,"start_time":"2020-11-19T21:48:00.074564","status":"completed"},"tags":[]},"cell_type":"code","source":"def read_tfrecord(example, labeled):\n    tfrecord_format = {\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"target\": tf.io.FixedLenFeature([], tf.int64)\n    } if labeled else {\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"image_name\": tf.io.FixedLenFeature([], tf.string)\n    }\n    example = tf.io.parse_single_example(example, tfrecord_format)\n    image = decode_image(example['image'])\n    if labeled:\n        label = tf.cast(example['target'], tf.int32)\n        return image, label\n    idnum = example['image_name']\n    return image, idnum","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8767033d-a2e8-47f9-b683-9f099fcfd386","_cell_guid":"f4f40ea5-3f40-4e4c-a780-3bb1f7dba270","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:00.325942Z","iopub.status.busy":"2020-11-19T21:48:00.324875Z","iopub.status.idle":"2020-11-19T21:48:00.327502Z","shell.execute_reply":"2020-11-19T21:48:00.328493Z"},"papermill":{"duration":0.073623,"end_time":"2020-11-19T21:48:00.328703","exception":false,"start_time":"2020-11-19T21:48:00.25508","status":"completed"},"tags":[]},"cell_type":"code","source":"def load_dataset(filenames, labeled=True, ordered=False):\n    ignore_order = tf.data.Options()\n    if not ordered:\n        ignore_order.experimental_deterministic = False # disable order, increase speed\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE) # automatically interleaves reads from multiple files\n    dataset = dataset.with_options(ignore_order) # uses data as soon as it streams in, rather than in its original order\n    dataset = dataset.map(partial(read_tfrecord, labeled=labeled), num_parallel_calls=AUTOTUNE)\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2b437d82-fa02-4940-988e-d3cb05ceed57","_cell_guid":"9d915cdd-d1d6-4e7b-8573-4002da3a4f59","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:00.683596Z","iopub.status.busy":"2020-11-19T21:48:00.607588Z","iopub.status.idle":"2020-11-19T21:48:00.687244Z","shell.execute_reply":"2020-11-19T21:48:00.686445Z"},"papermill":{"duration":0.225941,"end_time":"2020-11-19T21:48:00.687385","exception":false,"start_time":"2020-11-19T21:48:00.461444","status":"completed"},"tags":[]},"cell_type":"code","source":"TRAINING_VALID_FILENAMES, TEST_FILENAMES = train_test_split(\n    tf.io.gfile.glob(GCS_PATH + '/train_tfrecords/ld_train*.tfrec'),\n    test_size=0.2, random_state=5\n)\n\nTRAINING_FILENAMES, VALID_FILENAMES = train_test_split(\n    TRAINING_VALID_FILENAMES,\n    test_size=0.2, random_state=5\n)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a94a027b-47e5-40e6-9a5b-ea93c8ea87c8","_cell_guid":"098f7b09-a5eb-47c2-bdb9-479786d7a6f0","trusted":true},"cell_type":"code","source":"def get_mat(rotation, shear, height_zoom, width_zoom, height_shift, width_shift):\n    # returns 3x3 transformmatrix which transforms indicies\n        \n    # CONVERT DEGREES TO RADIANS\n    rotation = math.pi * rotation / 180.\n    shear = math.pi * shear / 180.\n    \n    # ROTATION MATRIX\n    c1 = tf.math.cos(rotation)\n    s1 = tf.math.sin(rotation)\n    one = tf.constant([1],dtype='float32')\n    zero = tf.constant([0],dtype='float32')\n    rotation_matrix = tf.reshape( tf.concat([c1,s1,zero, -s1,c1,zero, zero,zero,one],axis=0),[3,3] )\n        \n    # SHEAR MATRIX\n    c2 = tf.math.cos(shear)\n    s2 = tf.math.sin(shear)\n    shear_matrix = tf.reshape( tf.concat([one,s2,zero, zero,c2,zero, zero,zero,one],axis=0),[3,3] )    \n    \n    # ZOOM MATRIX\n    zoom_matrix = tf.reshape( tf.concat([one/height_zoom,zero,zero, zero,one/width_zoom,zero, zero,zero,one],axis=0),[3,3] )\n    \n    # SHIFT MATRIX\n    shift_matrix = tf.reshape( tf.concat([one,zero,height_shift, zero,one,width_shift, zero,zero,one],axis=0),[3,3] )\n    \n    return K.dot(K.dot(rotation_matrix, shear_matrix), K.dot(zoom_matrix, shift_matrix))\n\ndef transform(image):\n    # input image - is one image of size [dim,dim,3] not a batch of [b,dim,dim,3]\n    # output - image randomly rotated, sheared, zoomed, and shifted\n    DIM = IMAGE_SIZE[0]\n    XDIM = DIM%2 #fix for size 331\n    \n    rot = 15. * tf.random.normal([1],dtype='float32')\n    shr = 5. * tf.random.normal([1],dtype='float32') \n    h_zoom = 1.0 + tf.random.normal([1],dtype='float32')/10.\n    w_zoom = 1.0 + tf.random.normal([1],dtype='float32')/10.\n    h_shift = 16. * tf.random.normal([1],dtype='float32') \n    w_shift = 16. * tf.random.normal([1],dtype='float32') \n  \n    # GET TRANSFORMATION MATRIX\n    m = get_mat(rot,shr,h_zoom,w_zoom,h_shift,w_shift) \n\n    # LIST DESTINATION PIXEL INDICES\n    x = tf.repeat( tf.range(DIM//2,-DIM//2,-1), DIM )\n    y = tf.tile( tf.range(-DIM//2,DIM//2),[DIM] )\n    z = tf.ones([DIM*DIM],dtype='int32')\n    idx = tf.stack( [x,y,z] )\n    \n    # ROTATE DESTINATION PIXELS ONTO ORIGIN PIXELS\n    idx2 = K.dot(m,tf.cast(idx,dtype='float32'))\n    idx2 = K.cast(idx2,dtype='int32')\n    idx2 = K.clip(idx2,-DIM//2+XDIM+1,DIM//2)\n    \n    # FIND ORIGIN PIXEL VALUES           \n    idx3 = tf.stack( [DIM//2-idx2[0,], DIM//2-1+idx2[1,]] )\n    d = tf.gather_nd(image,tf.transpose(idx3))\n        \n    return tf.reshape(d,[DIM,DIM,3])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"eb312495-a7ae-46fa-9b3d-fc78b8878130","_cell_guid":"f97427ba-9767-4913-ba87-262726739603","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:00.849827Z","iopub.status.busy":"2020-11-19T21:48:00.848867Z","iopub.status.idle":"2020-11-19T21:48:00.85179Z","shell.execute_reply":"2020-11-19T21:48:00.85115Z"},"papermill":{"duration":0.047715,"end_time":"2020-11-19T21:48:00.851918","exception":false,"start_time":"2020-11-19T21:48:00.804203","status":"completed"},"tags":[]},"cell_type":"code","source":"def gaussian_blur(image, kernel_size=23, padding='SAME'):\n    sigma = tf.random.uniform((1,))* 1.9 + 0.1\n\n    radius = tf.cast(kernel_size / 2, tf.int32)\n    kernel_size = radius * 2 + 1\n    x = tf.cast(tf.range(-radius, radius + 1), tf.float32)\n    blur_filter = tf.exp(\n        -tf.pow(x, 2.0) / (2.0 * tf.pow(tf.cast(sigma, tf.float32), 2.0)))\n    blur_filter /= tf.reduce_sum(blur_filter)\n    # One vertical and one horizontal filter.\n    blur_v = tf.reshape(blur_filter, [kernel_size, 1, 1, 1])\n    blur_h = tf.reshape(blur_filter, [1, kernel_size, 1, 1])\n    num_channels = tf.shape(image)[-1]\n    blur_h = tf.tile(blur_h, [1, 1, num_channels, 1])\n    blur_v = tf.tile(blur_v, [1, 1, num_channels, 1])\n    expand_batch_dim = image.shape.ndims == 3\n    if expand_batch_dim:\n        image = tf.expand_dims(image, axis=0)\n    blurred = tf.nn.depthwise_conv2d(\n        image, blur_h, strides=[1, 1, 1, 1], padding=padding)\n    blurred = tf.nn.depthwise_conv2d(\n    blurred, blur_v, strides=[1, 1, 1, 1], padding=padding)\n    if expand_batch_dim:\n        blurred = tf.squeeze(blurred, axis=0)\n    return blurred\n\ndef color_jitter(x, s=0.5):\n    x = tf.image.random_brightness(x, max_delta=0.8*s)\n    x = tf.image.random_contrast(x, lower=1-0.8*s, upper=1+0.8*s)\n    x = tf.image.random_saturation(x, lower=1-0.8*s, upper=1+0.8*s)\n    x = tf.image.random_hue(x, max_delta=0.2*s)\n    x = tf.clip_by_value(x, 0, 1)\n    return x\n\ndef random_apply(func, x, p):\n    return tf.cond( tf.less(tf.random.uniform([], minval=0, maxval=1, dtype=tf.float32),\n                            tf.cast(p, tf.float32)),\n                    lambda: func(x),\n                    lambda: x)\n\n\ndef data_augment(image, label):\n    image = random_apply(color_jitter, image, p=0.5)\n    \n    image = random_apply(transform, image, p=0.5)\n    \n    image = random_apply(gaussian_blur, image, p=0.5)\n    \n    image = random_apply(tf.image.flip_left_right, image, p=0.6)\n    \n    return image, label","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8416bda2-e9e9-4f92-929c-d828b4fc12c2","_cell_guid":"f3757bc5-2402-447e-9cb2-06a6486f814d","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:01.018921Z","iopub.status.busy":"2020-11-19T21:48:01.017912Z","iopub.status.idle":"2020-11-19T21:48:01.02164Z","shell.execute_reply":"2020-11-19T21:48:01.020852Z"},"papermill":{"duration":0.052326,"end_time":"2020-11-19T21:48:01.021791","exception":false,"start_time":"2020-11-19T21:48:00.969465","status":"completed"},"tags":[]},"cell_type":"code","source":"def get_training_dataset():\n    dataset = load_dataset(TRAINING_FILENAMES, labeled=True)  \n    dataset = dataset.map(data_augment, num_parallel_calls=AUTOTUNE)  \n    dataset = dataset.repeat()\n    dataset = dataset.shuffle(2048)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTOTUNE)\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f074f297-db54-40d1-ae40-8e2f20c60cf1","_cell_guid":"06b46a50-23d8-4962-9667-cccbff19b226","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:01.109616Z","iopub.status.busy":"2020-11-19T21:48:01.108559Z","iopub.status.idle":"2020-11-19T21:48:01.111418Z","shell.execute_reply":"2020-11-19T21:48:01.111986Z"},"papermill":{"duration":0.049787,"end_time":"2020-11-19T21:48:01.112145","exception":false,"start_time":"2020-11-19T21:48:01.062358","status":"completed"},"tags":[]},"cell_type":"code","source":"def get_validation_dataset(ordered=False):\n    dataset = load_dataset(VALID_FILENAMES, labeled=True, ordered=ordered) \n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.cache()\n    dataset = dataset.prefetch(AUTOTUNE)\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e00cd9c9-2a9c-48a8-9594-860710fa0685","_cell_guid":"02e374f6-7eac-454f-bc15-9a2fd867f012","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:01.204402Z","iopub.status.busy":"2020-11-19T21:48:01.203418Z","iopub.status.idle":"2020-11-19T21:48:01.207545Z","shell.execute_reply":"2020-11-19T21:48:01.20682Z"},"papermill":{"duration":0.050395,"end_time":"2020-11-19T21:48:01.207665","exception":false,"start_time":"2020-11-19T21:48:01.15727","status":"completed"},"tags":[]},"cell_type":"code","source":"def get_test_dataset(ordered=False):\n    dataset = load_dataset(TEST_FILENAMES, labeled=False, ordered=ordered)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTOTUNE)\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"376179a8-1302-4a96-8e02-4ee3c80e32e7","_cell_guid":"67c175f5-5e23-4f0f-9a7e-79f1ec93d34d","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:01.301631Z","iopub.status.busy":"2020-11-19T21:48:01.30084Z","iopub.status.idle":"2020-11-19T21:48:01.304479Z","shell.execute_reply":"2020-11-19T21:48:01.303807Z"},"papermill":{"duration":0.05422,"end_time":"2020-11-19T21:48:01.304611","exception":false,"start_time":"2020-11-19T21:48:01.250391","status":"completed"},"tags":[]},"cell_type":"code","source":"def count_data_items(filenames):\n    n = [int(re.compile(r\"-([0-9]*)\\.\").search(filename).group(1)) for filename in filenames]\n    return np.sum(n)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e7f431f1-60aa-40c6-8c31-859b45f8d4ec","_cell_guid":"6281da86-6b27-49d0-9f2a-bc330e9f61ad","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:01.39253Z","iopub.status.busy":"2020-11-19T21:48:01.391743Z","iopub.status.idle":"2020-11-19T21:48:01.395039Z","shell.execute_reply":"2020-11-19T21:48:01.395972Z"},"papermill":{"duration":0.051209,"end_time":"2020-11-19T21:48:01.396198","exception":false,"start_time":"2020-11-19T21:48:01.344989","status":"completed"},"tags":[]},"cell_type":"code","source":"NUM_TRAINING_IMAGES = count_data_items(TRAINING_FILENAMES)\nNUM_VALIDATION_IMAGES = count_data_items(VALID_FILENAMES)\nNUM_TEST_IMAGES = count_data_items(TEST_FILENAMES)\n\nprint('Dataset: {} training images, {} validation images, {} test images'.format(\n    NUM_TRAINING_IMAGES, NUM_VALIDATION_IMAGES, NUM_TEST_IMAGES))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"53bd4798-2c8e-4183-b854-4ed06baaadae","_cell_guid":"ad4a2d46-d133-4af5-b692-7f6f25c95585","trusted":true,"papermill":{"duration":0.044101,"end_time":"2020-11-19T21:48:18.6862","exception":false,"start_time":"2020-11-19T21:48:18.642099","status":"completed"},"tags":[]},"cell_type":"markdown","source":"The following code chunk sets up a series of functions that will print out a grid of images. The grid of images will contain images and their corresponding labels."},{"metadata":{"_uuid":"96f22d94-8f0a-4af8-ac2e-ae175ecc0ae0","_cell_guid":"a3a5369a-4979-4588-a97b-e538bf659b0e","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:18.782198Z","iopub.status.busy":"2020-11-19T21:48:18.781353Z","iopub.status.idle":"2020-11-19T21:48:18.808005Z","shell.execute_reply":"2020-11-19T21:48:18.807301Z"},"papermill":{"duration":0.077342,"end_time":"2020-11-19T21:48:18.808133","exception":false,"start_time":"2020-11-19T21:48:18.730791","status":"completed"},"tags":[]},"cell_type":"code","source":"# numpy and matplotlib defaults\nnp.set_printoptions(threshold=15, linewidth=80)\n\ndef batch_to_numpy_images_and_labels(data):\n    images, labels = data\n    numpy_images = images.numpy()\n    numpy_labels = labels.numpy()\n    if numpy_labels.dtype == object: # binary string in this case, these are image ID strings\n        numpy_labels = [None for _ in enumerate(numpy_images)]\n    # If no labels, only image IDs, return None for labels (this is the case for test data)\n    return numpy_images, numpy_labels\n\ndef title_from_label_and_target(label, correct_label):\n    if correct_label is None:\n        return CLASSES[label], True\n    correct = (label == correct_label)\n    return \"{} [{}{}{}]\".format(CLASSES[label], 'OK' if correct else 'NO', u\"\\u2192\" if not correct else '',\n                                CLASSES[correct_label] if not correct else ''), correct\n\ndef display_one_plant(image, title, subplot, red=False, titlesize=16):\n    plt.subplot(*subplot)\n    plt.axis('off')\n    plt.imshow(image)\n    if len(title) > 0:\n        plt.title(title, fontsize=int(titlesize) if not red else int(titlesize/1.2), color='red' if red else 'black', fontdict={'verticalalignment':'center'}, pad=int(titlesize/1.5))\n    return (subplot[0], subplot[1], subplot[2]+1)\n\ndef display_batch_of_images(databatch, predictions=None):\n    \"\"\"This will work with:\n    display_batch_of_images(images)\n    display_batch_of_images(images, predictions)\n    display_batch_of_images((images, labels))\n    display_batch_of_images((images, labels), predictions)\n    \"\"\"\n    # data\n    images, labels = batch_to_numpy_images_and_labels(databatch)\n    if labels is None:\n        labels = [None for _ in enumerate(images)]\n        \n    # auto-squaring: this will drop data that does not fit into square or square-ish rectangle\n    rows = int(math.sqrt(len(images)))\n    cols = len(images)//rows\n        \n    # size and spacing\n    FIGSIZE = 13.0\n    SPACING = 0.1\n    subplot=(rows,cols,1)\n    if rows < cols:\n        plt.figure(figsize=(FIGSIZE,FIGSIZE/cols*rows))\n    else:\n        plt.figure(figsize=(FIGSIZE/rows*cols,FIGSIZE))\n    \n    # display\n    for i, (image, label) in enumerate(zip(images[:rows*cols], labels[:rows*cols])):\n        title = '' if label is None else CLASSES[label]\n        correct = True\n        if predictions is not None:\n            title, correct = title_from_label_and_target(predictions[i], label)\n        dynamic_titlesize = FIGSIZE*SPACING/max(rows,cols)*40+3 # magic formula tested to work from 1x1 to 10x10 images\n        subplot = display_one_plant(image, title, subplot, not correct, titlesize=dynamic_titlesize)\n    \n    #layout\n    plt.tight_layout()\n    if label is None and predictions is None:\n        plt.subplots_adjust(wspace=0, hspace=0)\n    else:\n        plt.subplots_adjust(wspace=SPACING, hspace=SPACING)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"66fd932d-c594-4caf-8bf3-931999e5ced9","_cell_guid":"ef03e0cc-946c-4628-9f5b-294b5c700a3e","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:18.904519Z","iopub.status.busy":"2020-11-19T21:48:18.903424Z","iopub.status.idle":"2020-11-19T21:48:18.956871Z","shell.execute_reply":"2020-11-19T21:48:18.956219Z"},"papermill":{"duration":0.104176,"end_time":"2020-11-19T21:48:18.957003","exception":false,"start_time":"2020-11-19T21:48:18.852827","status":"completed"},"tags":[]},"cell_type":"code","source":"training_dataset = get_training_dataset()\ntraining_dataset = training_dataset.unbatch().batch(20)\ntrain_batch = iter(training_dataset)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ab1a9430-e4c3-42b8-b027-7709a81a42b3","_cell_guid":"443764b2-7634-47bf-894d-983644eaa9ce","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:20.176923Z","iopub.status.busy":"2020-11-19T21:48:20.175758Z","iopub.status.idle":"2020-11-19T21:48:22.374002Z","shell.execute_reply":"2020-11-19T21:48:22.374605Z"},"papermill":{"duration":3.371477,"end_time":"2020-11-19T21:48:22.374778","exception":false,"start_time":"2020-11-19T21:48:19.003301","status":"completed"},"tags":[]},"cell_type":"code","source":"display_batch_of_images(next(train_batch))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b386d533-b1c3-4107-9291-bf54dde297a0","_cell_guid":"6204868c-74a1-4d40-beee-d690233a5136","trusted":true},"cell_type":"code","source":"# Learning rate schedule for TPU, GPU and CPU.\n# Using an LR ramp up because fine-tuning a pre-trained model.\n# Starting with a high LR would break the pre-trained weights.\n\nLR_START = 0.00001\nLR_MAX = 0.00005 * strategy.num_replicas_in_sync\nLR_MIN = 0.00001\nLR_RAMPUP_EPOCHS = 5\nLR_SUSTAIN_EPOCHS = 0\nLR_EXP_DECAY = .8\n\ndef lrfn(epoch):\n    if epoch < LR_RAMPUP_EPOCHS:\n        lr = (LR_MAX - LR_START) / LR_RAMPUP_EPOCHS * epoch + LR_START\n    elif epoch < LR_RAMPUP_EPOCHS + LR_SUSTAIN_EPOCHS:\n        lr = LR_MAX\n    else:\n        lr = (LR_MAX - LR_MIN) * LR_EXP_DECAY**(epoch - LR_RAMPUP_EPOCHS - LR_SUSTAIN_EPOCHS) + LR_MIN\n    return lr\n    \nlr_callback = tf.keras.callbacks.LearningRateScheduler(lrfn, verbose = True)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"645af35e-4d2c-47d1-bc28-d214d272c0b5","_cell_guid":"31097893-7c1c-4ade-b7f8-b62c66b7e0c8","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:29.74622Z","iopub.status.busy":"2020-11-19T21:48:29.745069Z","iopub.status.idle":"2020-11-19T21:48:49.158244Z","shell.execute_reply":"2020-11-19T21:48:49.157378Z"},"papermill":{"duration":19.661572,"end_time":"2020-11-19T21:48:49.158413","exception":false,"start_time":"2020-11-19T21:48:29.496841","status":"completed"},"tags":[]},"cell_type":"code","source":"with strategy.scope():       \n    img_adjust_layer = tf.keras.layers.Lambda(tf.keras.applications.resnet_v2.preprocess_input, input_shape=[*IMAGE_SIZE, 3])\n    \n    base_model = tf.keras.applications.ResNet50V2(weights='imagenet', include_top=False)\n    base_model.trainable = True\n    \n    model = tf.keras.Sequential([\n        tf.keras.layers.BatchNormalization(renorm=True),\n        img_adjust_layer,\n        base_model,\n        tf.keras.layers.GlobalAveragePooling2D(),\n        tf.keras.layers.Dense(len(CLASSES), activation='softmax')  \n    ])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"829c1f2a-531d-428d-ad40-15dd3736f1f1","_cell_guid":"622320c2-73bc-4aab-b073-c7d6a74f4ea8","trusted":true},"cell_type":"code","source":"with strategy.scope():\n    model.compile(\n        optimizer='adam',\n        loss='sparse_categorical_crossentropy',  \n        metrics=['sparse_categorical_accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"68041f15-397b-43f1-9500-2c602975e4cb","_cell_guid":"e50f8701-6b2e-45ef-ad3b-7fa114d72068","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:49.868188Z","iopub.status.busy":"2020-11-19T21:48:49.867432Z","iopub.status.idle":"2020-11-19T21:48:49.93567Z","shell.execute_reply":"2020-11-19T21:48:49.936263Z"},"papermill":{"duration":0.249051,"end_time":"2020-11-19T21:48:49.936435","exception":false,"start_time":"2020-11-19T21:48:49.687384","status":"completed"},"tags":[]},"cell_type":"code","source":"# load data\ntrain_dataset = get_training_dataset()\nvalid_dataset = get_validation_dataset()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c2e326be-6bd5-4e21-8503-310db54bd5ad","_cell_guid":"e97bec5e-5a43-4f67-9502-6b44e21cf481","trusted":true},"cell_type":"code","source":"checkpoint_filepath = './checkpoint'\nmodel_checkpoint_callback = tf.keras.callbacks.ModelCheckpoint(\n    filepath=checkpoint_filepath,\n    save_weights_only=True,\n    monitor='val_sparse_categorical_accuracy',\n    mode='max',\n    save_best_only=True)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6ded5e70-9378-41f3-8132-3841f25b722b","_cell_guid":"798460a0-a3d0-4d35-89bc-3623c492dab6","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T21:48:50.304573Z","iopub.status.busy":"2020-11-19T21:48:50.303472Z","iopub.status.idle":"2020-11-19T22:04:46.794408Z","shell.execute_reply":"2020-11-19T22:04:46.795473Z"},"papermill":{"duration":956.681695,"end_time":"2020-11-19T22:04:46.795744","exception":false,"start_time":"2020-11-19T21:48:50.114049","status":"completed"},"tags":[]},"cell_type":"code","source":"STEPS_PER_EPOCH = NUM_TRAINING_IMAGES // BATCH_SIZE\nVALID_STEPS = NUM_VALIDATION_IMAGES // BATCH_SIZE\n\nhistory = model.fit(train_dataset, \n                    callbacks = [lr_callback],\n                    steps_per_epoch=STEPS_PER_EPOCH, \n                    epochs=40,\n                    validation_data=valid_dataset,\n                    validation_steps=VALID_STEPS)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"dd43661e-d343-42a2-942e-e0fc206c00f9","_cell_guid":"d0cfe2e2-a6d3-488c-9dbb-e00357cbf42a","trusted":true,"execution":{"iopub.execute_input":"2020-11-19T22:04:51.98529Z","iopub.status.busy":"2020-11-19T22:04:51.984414Z","iopub.status.idle":"2020-11-19T22:04:51.988629Z","shell.execute_reply":"2020-11-19T22:04:51.987853Z"},"papermill":{"duration":1.344562,"end_time":"2020-11-19T22:04:51.988755","exception":false,"start_time":"2020-11-19T22:04:50.644193","status":"completed"},"tags":[]},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9958acb5-a4a7-4f2e-95fd-2707a4387aa2","_cell_guid":"ecbcf7f6-a74e-4ce8-aa46-2e4b851d8cf3","trusted":true},"cell_type":"code","source":"# Konversi model.\nconverter = tf.lite.TFLiteConverter.from_keras_model(model)\ntflite_model = converter.convert()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c76ad22c-02b7-49a8-9ff3-0cd5fe7bc15d","_cell_guid":"8716479c-2d5f-4574-9c41-8cc8d6ed523d","trusted":true},"cell_type":"code","source":"with tf.io.gfile.GFile('model.tflite', 'wb') as f:\n  f.write(tflite_model)","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}