{"cells":[{"metadata":{},"cell_type":"markdown","source":"## One Cycle Scheduler vs TPU Scheduler\n\nThis notebook compares two different learning rate schedulers. The One Cycler Scheduler used in the fastai [module](https://docs.fast.ai/callbacks.one_cycle.html#Training-with-the-1cycle-policy) and the scheduler implemented in this [notebook](https://www.kaggle.com/mgornergoogle/five-flowers-with-keras-and-xception-on-tpu) for TPU (I decided to name it TPU Scheduler in this notebook). I compare both of them using the same settings in model and data settings.\n\nThe data augmentation techniques used in this notebook is taken from the following amazing notebooks.\n1. [flower-with-tpus-advanced-augmentation](http://www.kaggle.com/dimitreoliveira/flower-with-tpus-advanced-augmentation)\n2. [rotation-augmentation-gpu-tpu-0-96](https://www.kaggle.com/cdeotte/rotation-augmentation-gpu-tpu-0-96)\n3. [make-chris-deotte-s-data-augmentation-faster](https://www.kaggle.com/yihdarshieh/make-chris-deotte-s-data-augmentation-faster)\n\n![Capture.PNG](attachment:Capture.PNG)","attachments":{"Capture.PNG":{"image/png":"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"}},"execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport re\nimport math\nimport warnings\nimport numpy as np\nimport pandas as pd\n\nimport seaborn as sns\nfrom matplotlib import pyplot as plt\nfrom kaggle_datasets import KaggleDatasets\n\nfrom sklearn.metrics import f1_score, precision_score, recall_score, confusion_matrix\n\nimport tensorflow as tf\nimport tensorflow.keras.backend as K\nprint(tf.__version__)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def seed_everything(seed=0):\n    np.random.seed(seed)\n    tf.random.set_seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    os.environ['TF_DETERMINISTIC_OPS'] = '1'\n    \nsns.set()\nSEED = 17\nseed_everything(SEED)\nwarnings.filterwarnings(\"ignore\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Configurations","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# TPU or GPU detection\n# Detect hardware, return appropriate distribution strategy\ntry:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print('Running on TPU ', tpu.master())\nexcept ValueError:\n    tpu = None\n\nif tpu:\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nelse:\n    strategy = tf.distribute.get_strategy()\n\nprint(\"REPLICAS: \", strategy.num_replicas_in_sync)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"HEIGHT, WIDTH = (512, 512)\nCHANNELS = 3\nN_CLASSES = 104\n\n#Get datatset from google cloud services\nGCS_PATH = KaggleDatasets().get_gcs_path('tpu-getting-started') + '/tfrecords-jpeg-%sx%s' % (HEIGHT, WIDTH)\n\nTRAINING_FILENAMES = tf.io.gfile.glob(GCS_PATH + '/train/*.tfrec')\nVALIDATION_FILENAMES = tf.io.gfile.glob(GCS_PATH + '/val/*.tfrec')\nTEST_FILENAMES = tf.io.gfile.glob(GCS_PATH + '/test/*.tfrec')\n\nCLASSES = [\n    'pink primrose', 'hard-leaved pocket orchid', 'canterbury bells', 'sweet pea', \n    'wild geranium', 'tiger lily', 'moon orchid', 'bird of paradise', 'monkshood', \n    'globe thistle', 'snapdragon', \"colt's foot\", 'king protea', 'spear thistle', \n    'yellow iris', 'globe-flower', 'purple coneflower', 'peruvian lily', \n    'balloon flower', 'giant white arum lily', 'fire lily', 'pincushion flower', \n    'fritillary', 'red ginger', 'grape hyacinth', 'corn poppy', \n    'prince of wales feathers', 'stemless gentian', 'artichoke', 'sweet william', \n    'carnation', 'garden phlox', 'love in the mist', 'cosmos',  'alpine sea holly', \n    'ruby-lipped cattleya', 'cape flower', 'great masterwort',  'siam tulip', \n    'lenten rose', 'barberton daisy', 'daffodil',  'sword lily', 'poinsettia', \n    'bolero deep blue',  'wallflower', 'marigold', 'buttercup', 'daisy', \n    'common dandelion', 'petunia', 'wild pansy', 'primula',  'sunflower', \n    'lilac hibiscus', 'bishop of llandaff', 'gaura',  'geranium', 'orange dahlia', \n    'pink-yellow dahlia', 'cautleya spicata',  'japanese anemone', 'black-eyed susan', \n    'silverbush', 'californian poppy',  'osteospermum', 'spring crocus', 'iris', \n    'windflower',  'tree poppy', 'gazania', 'azalea', 'water lily',  'rose', \n    'thorn apple', 'morning glory', 'passion flower',  'lotus', 'toad lily', \n    'anthurium', 'frangipani',  'clematis', 'hibiscus', 'columbine', 'desert-rose', \n    'tree mallow', 'magnolia', 'cyclamen ', 'watercress',  'canna lily', \n    'hippeastrum ', 'bee balm', 'pink quill',  'foxglove', 'bougainvillea', \n    'camellia', 'mallow',  'mexican petunia',  'bromelia', 'blanket flower', \n    'trumpet creeper',  'blackberry lily', 'common tulip', 'wild rose']","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Helper and Augmentation functions","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def transform_rotation(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\n    DIM = HEIGHT\n    XDIM = DIM%2 #fix for size 331\n    \n    rotation = 15. * tf.random.normal([1],dtype='float32')\n    # CONVERT DEGREES TO RADIANS\n    rotation = math.pi * rotation / 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    # 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(rotation_matrix,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])\n\ndef transform_shear(image):\n    # input image - is one image of size [dim,dim,3] not a batch of [b,dim,dim,3]\n    # output - image randomly sheared\n    DIM = HEIGHT\n    XDIM = DIM%2 #fix for size 331\n    \n    shear = 5. * tf.random.normal([1],dtype='float32')\n    shear = math.pi * shear / 180.\n        \n    # SHEAR MATRIX\n    one = tf.constant([1],dtype='float32')\n    zero = tf.constant([0],dtype='float32')\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    # 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(shear_matrix,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])\n\ndef transform_shift(image):\n    # input image - is one image of size [dim,dim,3] not a batch of [b,dim,dim,3]\n    # output - image randomly shifted\n    DIM = HEIGHT\n    XDIM = DIM%2 #fix for size 331\n    \n    height_shift = 16. * tf.random.normal([1],dtype='float32') \n    width_shift = 16. * tf.random.normal([1],dtype='float32') \n    one = tf.constant([1],dtype='float32')\n    zero = tf.constant([0],dtype='float32')\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    # 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(shift_matrix,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])\n\ndef transform_zoom(image):\n    # input image - is one image of size [dim,dim,3] not a batch of [b,dim,dim,3]\n    # output - image randomly zoomed\n    DIM = HEIGHT\n    XDIM = DIM%2 #fix for size 331\n    \n    height_zoom = 1.0 + tf.random.normal([1],dtype='float32')/10.\n    width_zoom = 1.0 + tf.random.normal([1],dtype='float32')/10.\n    one = tf.constant([1],dtype='float32')\n    zero = tf.constant([0],dtype='float32')\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    # 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(zoom_matrix,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":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# Datasets utility functions\nAUTO = tf.data.experimental.AUTOTUNE # instructs the API to read from multiple files if available.\n\ndef decode_image(image_data):\n    image = tf.image.decode_jpeg(image_data, channels=3)\n    image = tf.cast(image, tf.float32) / 255.0\n    image = tf.reshape(image, [HEIGHT, WIDTH, 3])\n    return image\n\ndef read_labeled_tfrecord(example):\n    LABELED_TFREC_FORMAT = {\n        \"image\": tf.io.FixedLenFeature([], tf.string), # tf.string means bytestring\n        \"class\": tf.io.FixedLenFeature([], tf.int64),  # shape [] means single element\n    }\n    example = tf.io.parse_single_example(example, LABELED_TFREC_FORMAT)\n    image = decode_image(example['image'])\n    label = tf.cast(example['class'], tf.int32)\n    return image, label\n\ndef read_unlabeled_tfrecord(example):\n    UNLABELED_TFREC_FORMAT = {\n        \"image\": tf.io.FixedLenFeature([], tf.string), # tf.string means bytestring\n        \"id\": tf.io.FixedLenFeature([], tf.string),  # shape [] means single element\n        # class is missing, this competitions's challenge is to predict flower classes for the test dataset\n    }\n    example = tf.io.parse_single_example(example, UNLABELED_TFREC_FORMAT)\n    image = decode_image(example['image'])\n    idnum = example['id']\n    return image, idnum # returns a dataset of image(s)\n\ndef 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\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTO) # 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(read_labeled_tfrecord if labeled else read_unlabeled_tfrecord, num_parallel_calls=AUTO)\n    # returns a dataset of (image, label) pairs if labeled=True or (image, id) pairs if labeled=False\n    return dataset\n\ndef data_augment(image, label):\n    p_spatial = tf.random.uniform([1], minval=0, maxval=1, dtype='float32', seed=SEED)\n    p_spatial2 = tf.random.uniform([1], minval=0, maxval=1, dtype='float32', seed=SEED)\n    p_pixel = tf.random.uniform([1], minval=0, maxval=1, dtype='float32', seed=SEED)\n    p_crop = tf.random.uniform([1], minval=0, maxval=1, dtype='float32', seed=SEED)\n    \n    ### Spatial-level transforms\n    if p_spatial >= .2:\n        image = tf.image.random_flip_left_right(image, seed=SEED)\n        image = tf.image.random_flip_up_down(image, seed=SEED)\n        \n    if p_crop >= .7:\n        if p_crop >= .95:\n            image = tf.image.random_crop(image, size=[int(HEIGHT*.6), int(WIDTH*.6), CHANNELS], seed=SEED)\n        elif p_crop >= .85:\n            image = tf.image.random_crop(image, size=[int(HEIGHT*.7), int(WIDTH*.7), CHANNELS], seed=SEED)\n        elif p_crop >= .8:\n            image = tf.image.random_crop(image, size=[int(HEIGHT*.8), int(WIDTH*.8), CHANNELS], seed=SEED)\n        else:\n            image = tf.image.random_crop(image, size=[int(HEIGHT*.9), int(WIDTH*.9), CHANNELS], seed=SEED)\n        image = tf.image.resize(image, size=[HEIGHT, WIDTH])\n\n    if p_spatial2 >= .6:\n        if p_spatial2 >= .9:\n            image = transform_rotation(image)\n        elif p_spatial2 >= .8:\n            image = transform_zoom(image)\n        elif p_spatial2 >= .7:\n            image = transform_shift(image)\n        else:\n            image = transform_shear(image)\n        \n    ## Pixel-level transforms\n    if p_pixel >= .4:\n        if p_pixel >= .85:\n            image = tf.image.random_saturation(image, lower=0, upper=2, seed=SEED)\n        elif p_pixel >= .65:\n            image = tf.image.random_contrast(image, lower=.8, upper=2, seed=SEED)\n        elif p_pixel >= .5:\n            image = tf.image.random_brightness(image, max_delta=.2, seed=SEED)\n        else:\n            image = tf.image.adjust_gamma(image, gamma=.6)\n\n    return image, label\n\ndef get_training_dataset(do_aug=True):\n    dataset = load_dataset(TRAINING_FILENAMES, labeled=True)\n    dataset = dataset.map(data_augment, num_parallel_calls=AUTO)\n    dataset = dataset.repeat() # the training dataset must repeat for several epochs\n    dataset = dataset.shuffle(2048)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO) # prefetch next batch while training (autotune prefetch buffer size)\n    return dataset\n\ndef get_validation_dataset(ordered=False):\n    dataset = load_dataset(VALIDATION_FILENAMES, labeled=True, ordered=ordered)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.cache()\n    dataset = dataset.prefetch(AUTO)\n    return dataset\n\ndef get_train_valid_datasets():\n    dataset = load_dataset(TRAINING_FILENAMES + VALIDATION_FILENAMES, labeled=True)\n    dataset = dataset.map(data_augment, num_parallel_calls=AUTO)\n    dataset = dataset.repeat() # the training dataset must repeat for several epochs\n    dataset = dataset.shuffle(2048)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO) # prefetch next batch while training (autotune prefetch buffer size)\n    return dataset\n\ndef 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(AUTO)\n    return dataset\n\ndef count_data_items(filenames):\n    # the number of data items is written in the name of the .tfrec files, i.e. flowers00-230.tfrec = 230 data items\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":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# Visualization utility functions\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_flower(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_flower(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":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def display_training_curves(training, validation, title, subplot):\n    if subplot%10==1: # set up the subplots on the first call\n        plt.subplots(figsize=(15,10), facecolor='#F0F0F0')\n        plt.tight_layout()\n    ax = plt.subplot(subplot)\n    ax.set_facecolor('#F8F8F8')\n    ax.plot(training)\n    ax.plot(validation)\n    ax.set_title(title)\n    ax.set_ylabel(title.split(\" \")[-1])\n    #ax.set_ylim(0.28,1.05)\n    ax.set_xlabel('epoch')\n    ax.legend(['train', 'valid.'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Count train, val and test data\nNUM_TRAINING_IMAGES = count_data_items(TRAINING_FILENAMES)\nNUM_VALIDATION_IMAGES = count_data_items(VALIDATION_FILENAMES)\nNUM_TEST_IMAGES = count_data_items(TEST_FILENAMES)\n\nprint('Number of training images %d' % NUM_TRAINING_IMAGES)\nprint('Number of validation images %d' % NUM_VALIDATION_IMAGES)\nprint('Number of test images %d' % NUM_TEST_IMAGES)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Augmentation Visualization","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH_SIZE = 16 * strategy.num_replicas_in_sync\nall_elements = get_training_dataset().unbatch()\none_element = tf.data.Dataset.from_tensors( next(iter(all_elements)) )\naugmented_element = one_element.repeat().map(data_augment).batch(25)\n\ndisplay_batch_of_images(next(iter(augmented_element)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model function and schedulers callback","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def create_model(input_shape, N_CLASSES):\n    \n    base_model = tf.keras.applications.DenseNet201(\n        weights='imagenet', include_top=False, input_shape=input_shape)\n    \n    model = tf.keras.Sequential([\n        base_model,\n        tf.keras.layers.GlobalAveragePooling2D(),\n        tf.keras.layers.Dense(N_CLASSES, activation='softmax')\n    ])\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Used this implementation https://www.avanwyk.com/tensorflow-2-super-convergence-with-the-1cycle-policy/\n\nfrom tensorflow.keras.callbacks import Callback\n\nclass CosineAnnealer:\n    \n    def __init__(self, start, end, steps):\n        self.start = start\n        self.end = end\n        self.steps = steps\n        self.n = 0\n        \n    def step(self):\n        self.n += 1\n        cos = np.cos(np.pi * (self.n / self.steps)) + 1\n        return self.end + (self.start - self.end) / 2. * cos\n\n\nclass OneCycleScheduler(Callback):\n    \"\"\" \nCallback that schedules the learning rate on a 1cycle policy as per Leslie Smith's \npaper(https://arxiv.org/pdf/1803.09820.pdf). If the model supports a momentum parameter, it will also be adapted by \nthe schedule. The implementation adopts additional improvements as per the fastai \nlibrary: https://docs.fast.ai/callbacks.one_cycle.html, where only two phases are used and the adaptation is done \nusing cosine annealing. \n\nIn phase 1 the LR increases from lr_max / div_factor to lr_max and momentum decreases from mom_max to mom_min.\nIn the second phase the LR decreases from lr_max to lr_max / (div_factor * 1e4) and momemtum from mom_max to mom_min.\nBy default the phases are not of equal length, with the phase 1 percentage controlled by the parameter phase1_pct.\n\"\"\"\n\n    def __init__(self, lr_max, steps, mom_min=0.85, mom_max=0.95, phase_1_pct=0.3, div_factor=25.):\n        super(OneCycleScheduler, self).__init__()\n        lr_min = lr_max / div_factor\n        final_lr = lr_max / (div_factor * 1e4)\n        phase_1_steps = steps * phase_1_pct\n        phase_2_steps = steps - phase_1_steps\n        \n        self.phase_1_steps = phase_1_steps\n        self.phase_2_steps = phase_2_steps\n        self.phase = 0\n        self.step = 0\n        \n        self.phases = [[CosineAnnealer(lr_min, lr_max, phase_1_steps), CosineAnnealer(mom_max, mom_min, phase_1_steps)], \n                 [CosineAnnealer(lr_max, final_lr, phase_2_steps), CosineAnnealer(mom_min, mom_max, phase_2_steps)]]\n        \n        self.lrs = []\n        self.moms = []\n\n    def on_train_begin(self, logs=None):\n        self.phase = 0\n        self.step = 0\n\n        self.set_lr(self.lr_schedule().start)\n        self.set_momentum(self.mom_schedule().start)\n        \n    def on_train_batch_begin(self, batch, logs=None):\n        self.lrs.append(self.get_lr())\n        self.moms.append(self.get_momentum())\n\n    def on_train_batch_end(self, batch, logs=None):\n        self.step += 1\n        if self.step >= self.phase_1_steps:\n            self.phase = 1\n            \n        self.set_lr(self.lr_schedule().step())\n        self.set_momentum(self.mom_schedule().step())\n        \n    def get_lr(self):\n        try:\n            return tf.keras.backend.get_value(self.model.optimizer.lr)\n        except AttributeError:\n            return None\n        \n    def get_momentum(self):\n        try:\n            return tf.keras.backend.get_value(self.model.optimizer.momentum)\n        except AttributeError:\n            return None\n        \n    def set_lr(self, lr):\n        try:\n            tf.keras.backend.set_value(self.model.optimizer.lr, lr)\n        except AttributeError:\n            pass # ignore\n        \n    def set_momentum(self, mom):\n        try:\n            tf.keras.backend.set_value(self.model.optimizer.momentum, mom)\n        except AttributeError:\n            pass # ignore\n\n    def lr_schedule(self):\n        return self.phases[self.phase][0]\n    \n    def mom_schedule(self):\n        return self.phases[self.phase][1]\n    \n    def plot(self):\n        ax = plt.subplot(1, 2, 1)\n        ax.plot(self.lrs)\n        ax.set_title('Learning Rate')\n        ax = plt.subplot(1, 2, 2)\n        ax.plot(self.moms)\n        ax.set_title('Momentum')","execution_count":null,"outputs":[]},{"metadata":{"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","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Training configurations","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"EPOCHS = 20\nBATCH_SIZE = 16 * strategy.num_replicas_in_sync\n\nTRAIN_VALID = False\n\nif TRAIN_VALID:\n    STEPS_PER_EPOCH = (NUM_TRAINING_IMAGES + NUM_VALIDATION_IMAGES) // BATCH_SIZE\nelse:\n    STEPS_PER_EPOCH = NUM_TRAINING_IMAGES // BATCH_SIZE\n\nLR = 1e-3\nsteps = STEPS_PER_EPOCH * EPOCHS","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Visualization of schedulers","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"phase_1_pct=0.3\ndiv_factor=25.\nlr_max = LR\n\nlr_min = lr_max / div_factor\nfinal_lr = lr_max / (div_factor * 1e4)\nphase_1_steps = int(steps * phase_1_pct)\nphase_2_steps = int(steps - phase_1_steps)\n\nphase1 = CosineAnnealer(lr_min, lr_max, phase_1_steps)\nphase2 = CosineAnnealer(lr_max, final_lr, phase_2_steps)\n\nlrs1 = []\nfor step in range(phase_1_steps):\n    lrs1.append(phase1.step())\n    \nfor step in range(phase_2_steps):\n    lrs1.append(phase2.step())\n\nrng1 = [i for i in range(phase_1_steps + phase_2_steps)]\n\nrng2 = [i for i in range(EPOCHS)]\nlrs2 = [lrfn(x) for x in rng2]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"fig, axes = plt.subplots(1, 2, figsize=(12, 5))\n\naxes[0].plot(rng1, lrs1)\naxes[0].set_title(\"One Cycle Scheduler Learning rates: {:.3g} to {:.3g} to {:.3g}\".format(lrs2[0], max(lrs2), lrs2[-1]))\n\naxes[1].plot(rng2, lrs2)\naxes[1].set_title(\"TPU Scheduler Learning rates: {:.3g} to {:.3g} to {:.3g}\".format(lr_min, lr_max, final_lr));","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"val_ds = get_validation_dataset(ordered=True) # since we are splitting the dataset and iterating separately on images and labels, order matters.\nval_images_ds = val_ds.map(lambda image, label: image)\nval_labels_ds = val_ds.map(lambda image, label: label).unbatch()\nval_correct_labels = next(iter(val_labels_ds.batch(NUM_VALIDATION_IMAGES))).numpy() # get everything as one batch\n\ntest_ds = get_test_dataset(ordered=True) # since we are splitting the dataset and iterating separately on images and ids, order matters.\ntest_images_ds = test_ds.map(lambda image, idnum: image)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with strategy.scope():\n    model = create_model((None, None, CHANNELS), N_CLASSES)\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## One Cycle Scheduler experiment","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"lr_schedule = OneCycleScheduler(LR, steps)\n\nmodel.compile(\n    optimizer='adam',\n    loss = 'sparse_categorical_crossentropy',\n    metrics=['sparse_categorical_accuracy']\n)\n\nhistory1 = model.fit(x=get_training_dataset() if TRAIN_VALID == False else get_train_valid_datasets(),\n                    steps_per_epoch=STEPS_PER_EPOCH,\n                    validation_data=get_validation_dataset() if TRAIN_VALID == False else None,\n                    epochs=EPOCHS, callbacks=[lr_schedule],\n                    verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"val_probabilities = model.predict(val_images_ds)\nval_predictions = np.argmax(val_probabilities, axis=-1)\n\nscore_sch1 = f1_score(val_correct_labels, val_predictions, labels=range(len(CLASSES)), average='macro')\nprecision_sch1 = precision_score(val_correct_labels, val_predictions, labels=range(len(CLASSES)), average='macro')\nrecall_sch1 = recall_score(val_correct_labels, val_predictions, labels=range(len(CLASSES)), average='macro')\n\ntest_probabilities1 = model.predict(test_images_ds)\n\nprint('f1 score: {:.3f}, precision: {:.3f}, recall: {:.3f}'.format(score_sch1, precision_sch1, recall_sch1))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## TPU Scheduler experiment","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"with strategy.scope():\n    model = create_model((None, None, CHANNELS), N_CLASSES)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"lr_schedule = tf.keras.callbacks.LearningRateScheduler(lrfn, verbose=1)\n\nmodel.compile(\n    optimizer='adam',\n    loss = 'sparse_categorical_crossentropy',\n    metrics=['sparse_categorical_accuracy']\n)\n\nhistory2 = model.fit(x=get_training_dataset() if TRAIN_VALID == False else get_train_valid_datasets(),\n                    steps_per_epoch=STEPS_PER_EPOCH,\n                    validation_data=get_validation_dataset() if TRAIN_VALID == False else None,\n                    epochs=EPOCHS, callbacks=[lr_schedule],\n                    verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"val_probabilities = model.predict(val_images_ds)\nval_predictions = np.argmax(val_probabilities, axis=-1)\n\nscore_sch2 = f1_score(val_correct_labels, val_predictions, labels=range(len(CLASSES)), average='macro')\nprecision_sch2 = precision_score(val_correct_labels, val_predictions, labels=range(len(CLASSES)), average='macro')\nrecall_sch2 = recall_score(val_correct_labels, val_predictions, labels=range(len(CLASSES)), average='macro')\n\ntest_probabilities2 = model.predict(test_images_ds)\n\nprint('f1 score: {:.3f}, precision: {:.3f}, recall: {:.3f}'.format(score_sch2, precision_sch2, recall_sch2))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Comparing each sheduler train/validation loss and accuracy","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"if TRAIN_VALID == False:\n    display_training_curves(history1.history['loss'], history1.history['val_loss'], 'One Cycle Scheduler loss', 221)\n    display_training_curves(history2.history['loss'], history2.history['val_loss'], 'TPU Scheduler loss', 222)\n    display_training_curves(history1.history['sparse_categorical_accuracy'], history1.history['val_sparse_categorical_accuracy'], 'One Cycle Scheduler accuracy', 223)\n    display_training_curves(history2.history['sparse_categorical_accuracy'], history2.history['val_sparse_categorical_accuracy'], 'TPU Scheduler accuracy', 224)\n\nelse:\n    display_training_curves(history1.history['loss'], history1.history['loss'], 'One Cycle Scheduler loss', 221)\n    display_training_curves(history2.history['loss'], history2.history['loss'], 'TPU Scheduler loss', 222)\n    display_training_curves(history1.history['sparse_categorical_accuracy'], history1.history['sparse_categorical_accuracy'], 'One Cycle Scheduler accuracy', 223)\n    display_training_curves(history2.history['sparse_categorical_accuracy'], history2.history['sparse_categorical_accuracy'], 'TPU Scheduler accuracy', 224)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Validation score comparison for each scheduler","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.DataFrame([[score_sch1, precision_sch1, recall_sch1], [score_sch2, precision_sch2, recall_sch2]], \n                columns=['Precision', 'Recall', 'F1 Score'], \n                index=['One Cycle Scheduler', 'TPU Scheduler'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Submitting a blend of both schedulers","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"print('[INFO] Computing predictions...')\n\nprobabilities = (test_probabilities1 + test_probabilities2) / 2\npredictions = np.argmax(probabilities, axis=-1)\n\nprint('[INFO] Generating submission.csv file...')\ntest_ids_ds = test_ds.map(lambda image, idnum: idnum).unbatch()\ntest_ids = next(iter(test_ids_ds.batch(NUM_TEST_IMAGES))).numpy().astype('U') # all in one batch\nnp.savetxt('submission.csv', np.rec.fromarrays([test_ids, predictions]), fmt=['%s', '%d'], delimiter=',', header='id,label', comments='')","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}