{"cells":[{"metadata":{},"cell_type":"markdown","source":"# SIIM-ISIC Melanoma Classification\n### Input","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# image size:\n# choose one between 256, 384, 512, 768\ntfrec_shape = 256\n\n# competition data:\n# choose between \"2020\" (only 2020 competition data) or \"2019-2020\" (2020 + 2019 competition data, including 2017 and 2018)\ncomp_data = \"2020\"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### 3rd place models:\n\n|  model      | tfrec_shape |   comp_data   |        model name                                      |\n|  :----:     |    :----:   |     :----:    |                     :----:                             |\n|    1        |   256       |     \"2020\"    | \"EfficientNetB6_256x256_2020_epoch13_auc_0.92.h5\"      |\n|    2        |   384       |     \"2020\"    | \"EfficientNetB6_384x384_2020_epoch15_auc_0.96.h5\"      |\n|    3        |   512       |     \"2020\"    | \"EfficientNetB6_512x512_2020_epoch15_auc_0.96.h5\"      |\n|    4        |   768       |     \"2020\"    | \"EfficientNetB6_768x768_2020_epoch15_auc_0.96.h5\"      |\n|    5        |   256       |  \"2019-2020\"  | \"EfficientNetB6_256x256_2019-2020_epoch25_auc_0.95.h5\" |\n|    6        |   384       |  \"2019-2020\"  | \"EfficientNetB6_384x384_2019-2020_epoch25_auc_0.97.h5\" |\n|    7        |   512       |  \"2019-2020\"  | \"EfficientNetB6_512x512_2019-2020_epoch12_auc_0.97.h5\" |\n|    8        |   768       |  \"2019-2020\"  | \"EfficientNetB6_768x768_2019-2020_epoch10_auc_0.97.h5\" |","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"### Parameters/Configuration Specification","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# random crop size for each original image size (256, 384, 512, 768):\ncrop_size = {256: 250, 384: 370, 512: 500, 768: 750}\n\n# net size for each original image size (in case you want to resize the images after the crop):\nif comp_data == \"2020\":\n    net_size = {256: 248, 384: 370, 512: 500, 768: 750}\nelif comp_data == \"2019-2020\":\n    net_size = {256: 250, 384: 370, 512: 500, 768: 750}\n\n# hair augmentation\nif comp_data == \"2020\":\n    hair_augm = {256: False, 384: False, 512: False, 768: False}\nelif comp_data == \"2019-2020\":\n    hair_augm = {256: True, 384: True, 512: True, 768: False}\n    \n# epochs\nif comp_data == \"2020\":\n    epochs_num = {256: 13, 384: 15, 512: 15, 768: 15}\nelif comp_data == \"2019-2020\":\n    epochs_num = {256: 25, 384: 25, 512: 12, 768: 10}\n\n# model weights\nmodel_weights = 'imagenet' # 'noisy-student'\n\n# device\nDEVICE = \"TPU\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# batch size for predictions\nbatch_size_predictions = {256: 256, 384: 100, 512: 75, 768: 50}\n\n# saved models\nif comp_data == \"2020\":\n    saved_models = {256: 'EfficientNetB6_256x256_2020_epoch13_auc_0.92.h5', \n                    384: 'EfficientNetB6_384x384_2020_epoch15_auc_0.96.h5', \n                    512: 'EfficientNetB6_512x512_2020_epoch15_auc_0.96.h5', \n                    768: 'EfficientNetB6_768x768_2020_epoch15_auc_0.96.h5'}\nelif comp_data == \"2019-2020\":\n    saved_models = {256: 'EfficientNetB6_256x256_2019-2020_epoch25_auc_0.95.h5',\n                    384: 'EfficientNetB6_384x384_2019-2020_epoch25_auc_0.97.h5', \n                    512: 'EfficientNetB6_512x512_2019-2020_epoch12_auc_0.97.h5', \n                    768: 'EfficientNetB6_768x768_2019-2020_epoch10_auc_0.97.h5'}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"CFG = dict(\n    \n    batch_size = 16,\n    \n    read_size = tfrec_shape,\n    crop_size = crop_size[tfrec_shape],\n    net_size = net_size[tfrec_shape],\n    \n    # LEARNING RATE\n    LR_START = 0.000003,\n    LR_MAX = 0.000020,\n    LR_MIN = 0.000001,\n    LR_RAMPUP_EPOCHS  = 5,\n    LR_SUSTAIN_EPOCHS = 0,\n    LR_EXP_DECAY = 0.8,\n    \n    # EPOCHS:\n    epochs = epochs_num[tfrec_shape],\n    \n    # DATA AUGMENTATION\n    rot = 180.0,\n    shr = 1.5,\n    hzoom = 6.0,\n    wzoom = 6.0,\n    hshift = 6.0,\n    wshift = 6.0,\n    \n    # COARSE DROPOUT\n    DROP_FREQ = 0, # Determines proportion of train images to apply coarse dropout to / Between 0 and 1.\n    DROP_CT = 0, # How many squares to remove from train images when applying dropout.\n    DROP_SIZE = 0, # The size of square side equals IMG_SIZE * DROP_SIZE / Between 0 and 1.  \n    \n    # HAIR AUGMENTATION:\n    hair_augm = hair_augm[tfrec_shape],\n    \n    optimizer = 'adam',\n    label_smooth_fac = 0.05,\n    tta_steps =  25\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Install EfficientNet","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"! /opt/conda/bin/python3.7 -m pip install -q --upgrade pip\n! pip install -q efficientnet","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Import required libraries","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import os, random, re, math, time\nrandom.seed(a=42)\n\nfrom glob import glob\nimport numpy as np\nimport pandas as pd\n\nimport tensorflow as tf\nimport tensorflow.keras.backend as K\nimport efficientnet.tfkeras as efn\n# from keras.callbacks import ModelCheckpoint\n# from sklearn.model_selection import KFold\n\nfrom kaggle_datasets import KaggleDatasets\nimport PIL","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Read the data","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"BASEPATH = \"../input/siim-isic-melanoma-classification\"\ndf_train = pd.read_csv(os.path.join(BASEPATH, 'train.csv'))\ndf_test  = pd.read_csv(os.path.join(BASEPATH, 'test.csv'))\ndf_sub   = pd.read_csv(os.path.join(BASEPATH, 'sample_submission.csv'))\n\n# 2020 TFRecords\nGCS_PATH = KaggleDatasets().get_gcs_path(f'melanoma-{tfrec_shape}x{tfrec_shape}')\n\n# 2019 TFRecords\nGCS_PATH_2019 = KaggleDatasets().get_gcs_path(f'isic2019-{tfrec_shape}x{tfrec_shape}')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# TRAIN\nif comp_data == \"2020\":\n    files_train = np.sort(np.array(tf.io.gfile.glob(GCS_PATH + '/train*.tfrec')))\nelif comp_data == \"2019-2020\":\n    ## 2020 + 2019 (all, including 2017+2018):\n    files_train = tf.io.gfile.glob(GCS_PATH + '/train*.tfrec')\n    files_train += tf.io.gfile.glob(GCS_PATH_2019 + '/train*.tfrec')\n    files_train = np.sort(np.array(files_train)) # np.random.shuffle(files_train)\n\n\n# TEST\nfiles_test = np.sort(np.array(tf.io.gfile.glob(GCS_PATH + '/test*.tfrec')))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### TPU configuration","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"if DEVICE == \"TPU\":\n    print(\"connecting to TPU...\")\n    try:\n        tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n        print('Running on TPU ', tpu.master())\n    except ValueError:\n        print(\"Could not connect to TPU\")\n        tpu = None\n\n    if tpu:\n        try:\n            print(\"initializing  TPU ...\")\n            tf.config.experimental_connect_to_cluster(tpu)\n            tf.tpu.experimental.initialize_tpu_system(tpu)\n            strategy = tf.distribute.experimental.TPUStrategy(tpu)\n            print(\"TPU initialized\")\n        except _:\n            print(\"failed to initialize TPU\")\n    else:\n        DEVICE = \"GPU\"\n\nif DEVICE != \"TPU\":\n    print(\"Using default strategy for CPU and single GPU\")\n    strategy = tf.distribute.get_strategy()\n\nif DEVICE == \"GPU\":\n    print(\"Num GPUs Available: \", len(tf.config.experimental.list_physical_devices('GPU')))\n\nAUTO = tf.data.experimental.AUTOTUNE\nREPLICAS = strategy.num_replicas_in_sync\nprint(f'REPLICAS: {REPLICAS}')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Functions","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# HAIR AUGMENTATION\n\n# loading hairs\nGCS_PATH_hair_images = KaggleDatasets().get_gcs_path('melanoma-hairs')\nhair_images = tf.io.gfile.glob(GCS_PATH_hair_images + '/*.png')\nhair_images_tf=tf.convert_to_tensor(hair_images)\n\n# the maximum number of hairs to augment:\nn_max= 20\n\n# The hair images were originally designed for the 256x256 size, so they need to be scaled to use with images of different sizes.\n# Scaling factor:\nif tfrec_shape != 256:\n    scale=tf.cast(CFG['crop_size']/256, dtype=tf.int32)\n\n    \ndef hair_aug_tf(input_img, augment=True):\n    \n    if augment:\n    \n        # Copy the input image, so it won't be changed\n        img = tf.identity(input_img)\n\n        # Unnormalize: Returning the image from 0-1 to 0-255:\n        img = tf.multiply(img, 255)\n\n        # Randomly choose the number of hairs to augment (up to n_max)\n        n_hairs = tf.random.uniform(shape=[], maxval=tf.constant(n_max)+1,dtype=tf.int32)\n\n        im_height = tf.shape(img)[0]\n        im_width = tf.shape(img)[1]\n\n        if n_hairs == 0:\n            # Normalize the image to [0,1]\n            img = tf.multiply(img, 1/255)\n            return img\n\n        for _ in tf.range(n_hairs):\n\n            # Read a random hair image\n            i = tf.random.uniform(shape=[], maxval=tf.shape(hair_images_tf)[0],dtype=tf.int32)\n            fname = hair_images_tf[i]\n            bits = tf.io.read_file(fname)\n            hair = tf.image.decode_jpeg(bits)\n\n            # Rescale the hair image to the right size\n            if tfrec_shape != 256:\n                # new_height, new_width, _  = scale*tf.shape(hair)\n                new_width = scale*tf.shape(hair)[1]\n                new_height = scale*tf.shape(hair)[0]\n                hair = tf.image.resize(hair, [new_height, new_width])\n\n            # Random flips of the hair image\n            hair = tf.image.random_flip_left_right(hair)\n            hair = tf.image.random_flip_up_down(hair)\n\n            # Random number of 90 degree rotations\n            n_rot = tf.random.uniform(shape=[], maxval=4,dtype=tf.int32)\n            hair = tf.image.rot90(hair, k=n_rot)\n\n            # The hair image height and width (ignore the number of color channels)\n            h_height = tf.shape(hair)[0]\n            h_width = tf.shape(hair)[1]\n\n            # The top left coord's of the region of interest (roi) where the augmentation will be performed\n            roi_h0 = tf.random.uniform(shape=[], maxval=im_height - h_height + 1, dtype=tf.int32)\n            roi_w0 = tf.random.uniform(shape=[], maxval=im_width - h_width + 1, dtype=tf.int32)\n\n            # The region of interest\n            roi = img[roi_h0:(roi_h0 + h_height), roi_w0:(roi_w0 + h_width)]  \n\n            # Convert the hair image to grayscale (slice to remove the trainsparency channel)\n            hair2gray = tf.image.rgb_to_grayscale(hair[:, :, :3])\n\n            # Threshold:\n            mask = hair2gray>10\n\n            img_bg = tf.multiply(roi, tf.cast(tf.image.grayscale_to_rgb(~mask), dtype=tf.float32))\n            hair_fg = tf.multiply(tf.cast(hair[:, :, :3], dtype=tf.int32), tf.cast(tf.image.grayscale_to_rgb(mask), dtype=tf.int32))\n\n            dst = tf.add(img_bg, tf.cast(hair_fg, dtype=tf.float32))\n\n            paddings = tf.stack([[roi_h0, im_height-(roi_h0 + h_height)], [roi_w0, im_width-(roi_w0 + h_width)],[0, 0]])\n            # Pad dst with zeros to make it the same shape as image.\n            dst_padded=tf.pad(dst, paddings, \"CONSTANT\")\n\n            # Create a boolean mask with zeros at the pixels of the augmentation segment and ones everywhere else\n            mask_img=tf.pad(tf.ones_like(dst), paddings, \"CONSTANT\")\n            mask_img=~tf.cast(mask_img, dtype=tf.bool)\n\n            # Make a hole in the original image at the location of the augmentation segment\n            img_hole=tf.multiply(img, tf.cast(mask_img, dtype=tf.float32))\n\n            # Inserting the augmentation segment in place of the hole\n            img = tf.add(img_hole, dst_padded)\n\n        # Normalize the image to [0,1]\n        img = tf.multiply(img, 1/255)\n        \n        return img\n    else:\n        return input_img","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# COARSE DROPOUT\n\ndef dropout(image, DIM=256, PROBABILITY = 0.75, CT = 8, SZ = 0.2):\n    # input image - is one image of size [dim,dim,3] not a batch of [b,dim,dim,3]\n    # output - image with CT squares of side size SZ*DIM removed\n    \n    # DO DROPOUT WITH PROBABILITY DEFINED ABOVE\n    P = tf.cast( tf.random.uniform([],0,1)<PROBABILITY, tf.int32)\n    if (P==0)|(CT==0)|(SZ==0): return image\n    \n    for k in range(CT):\n        # CHOOSE RANDOM LOCATION\n        x = tf.cast( tf.random.uniform([],0,DIM),tf.int32)\n        y = tf.cast( tf.random.uniform([],0,DIM),tf.int32)\n        # COMPUTE SQUARE\n        WIDTH = tf.cast( SZ*DIM,tf.int32) * P\n        ya = tf.math.maximum(0,y-WIDTH//2)\n        yb = tf.math.minimum(DIM,y+WIDTH//2)\n        xa = tf.math.maximum(0,x-WIDTH//2)\n        xb = tf.math.minimum(DIM,x+WIDTH//2)\n        # DROPOUT IMAGE\n        one = image[ya:yb,0:xa,:]\n        two = tf.zeros([yb-ya,xb-xa,3]) \n        three = image[ya:yb,xb:DIM,:]\n        middle = tf.concat([one,two,three],axis=1)\n        image = tf.concat([image[0:ya,:,:],middle,image[yb:DIM,:,:]],axis=0)\n            \n    # RESHAPE HACK SO TPU COMPILER KNOWS SHAPE OF OUTPUT TENSOR\n    image = tf.reshape(image,[DIM,DIM,3])\n    return image","execution_count":null,"outputs":[]},{"metadata":{"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    def get_3x3_mat(lst):\n        return tf.reshape(tf.concat([lst],axis=0), [3,3])\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    \n    rotation_matrix = get_3x3_mat([c1,   s1,   zero, \n                                   -s1,  c1,   zero, \n                                   zero, zero, one])    \n    # SHEAR MATRIX\n    c2 = tf.math.cos(shear)\n    s2 = tf.math.sin(shear)    \n    \n    shear_matrix = get_3x3_mat([one,  s2,   zero, \n                                zero, c2,   zero, \n                                zero, zero, one])        \n    # ZOOM MATRIX\n    zoom_matrix = get_3x3_mat([one/height_zoom, zero,           zero, \n                               zero,            one/width_zoom, zero, \n                               zero,            zero,           one])    \n    # SHIFT MATRIX\n    shift_matrix = get_3x3_mat([one,  zero, height_shift, \n                                zero, one,  width_shift, \n                                zero, zero, one])\n    \n    return K.dot(K.dot(rotation_matrix, shear_matrix), \n                 K.dot(zoom_matrix,     shift_matrix))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def transform(image, cfg):    \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 = cfg[\"read_size\"]\n    XDIM = DIM%2 #fix for size 331\n    \n    rot = cfg['rot'] * tf.random.normal([1], dtype='float32')\n    shr = cfg['shr'] * tf.random.normal([1], dtype='float32') \n    h_zoom = 1.0 + tf.random.normal([1], dtype='float32') / cfg['hzoom']\n    w_zoom = 1.0 + tf.random.normal([1], dtype='float32') / cfg['wzoom']\n    h_shift = cfg['hshift'] * tf.random.normal([1], dtype='float32') \n    w_shift = cfg['wshift'] * 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":{"trusted":true},"cell_type":"code","source":"def read_labeled_tfrecord(example):\n    tfrec_format = {\n        'image'                        : tf.io.FixedLenFeature([], tf.string),\n        'image_name'                   : tf.io.FixedLenFeature([], tf.string),\n        'patient_id'                   : tf.io.FixedLenFeature([], tf.int64),\n        'sex'                          : tf.io.FixedLenFeature([], tf.int64),\n        'age_approx'                   : tf.io.FixedLenFeature([], tf.int64),\n        'anatom_site_general_challenge': tf.io.FixedLenFeature([], tf.int64),\n        'diagnosis'                    : tf.io.FixedLenFeature([], tf.int64),\n        'target'                       : tf.io.FixedLenFeature([], tf.int64)\n    }           \n    example = tf.io.parse_single_example(example, tfrec_format)\n    return example['image'], example['target']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def read_unlabeled_tfrecord(example, return_image_name):\n    tfrec_format = {\n        'image'                        : tf.io.FixedLenFeature([], tf.string),\n        'image_name'                   : tf.io.FixedLenFeature([], tf.string),\n    }\n    example = tf.io.parse_single_example(example, tfrec_format)\n    return example['image'], example['image_name'] if return_image_name else 0","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def prepare_image(img, cfg=None, augment=True):\n    \n    img = tf.image.decode_jpeg(img, channels=3)\n    img = tf.image.resize(img, [cfg['read_size'], cfg['read_size']])\n    img = tf.cast(img, tf.float32) / 255.0 # # Cast and normalize the image to [0,1]\n    \n    if augment:\n        \n        # Data augmentation\n        img = transform(img, cfg)\n        img = tf.image.random_crop(img, [cfg['crop_size'], cfg['crop_size'], 3]) \n        # Coarse dropout\n        # img = dropout(img, DIM=cfg['crop_size'], PROBABILITY=cfg['DROP_FREQ'], CT=cfg['DROP_CT'], SZ=cfg['DROP_SIZE'])\n        # Other augmentations\n        img = tf.image.random_flip_left_right(img)\n        img = tf.image.random_hue(img, 0.01)\n        img = tf.image.random_saturation(img, 0.7, 1.3)\n        img = tf.image.random_contrast(img, 0.8, 1.2)\n        img = tf.image.random_brightness(img, 0.1)\n        # Hair augmentation\n        img = hair_aug_tf(img, augment=cfg['hair_augm'])\n    else:\n        img = tf.image.central_crop(img, cfg['crop_size'] / cfg['read_size'])\n                                   \n    img = tf.image.resize(img, [cfg['net_size'], cfg['net_size']])\n    img = tf.reshape(img, [cfg['net_size'], cfg['net_size'], 3])        \n    return img","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# function to count how many photos we have in\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},"cell_type":"code","source":"def get_dataset(files, cfg, augment = False, shuffle = False, repeat = False, labeled=True, return_image_names=True):\n    \n    ds = tf.data.TFRecordDataset(files, num_parallel_reads=AUTO)\n    ds = ds.cache()\n    \n    if repeat:\n        ds = ds.repeat()\n    \n    if shuffle: \n        ds = ds.shuffle(1024*8)\n        opt = tf.data.Options()\n        opt.experimental_deterministic = False\n        ds = ds.with_options(opt)\n        \n    if labeled: \n        ds = ds.map(read_labeled_tfrecord, num_parallel_calls=AUTO)\n    else:\n        ds = ds.map(lambda example: read_unlabeled_tfrecord(example, return_image_names), num_parallel_calls=AUTO)      \n    \n    ds = ds.map(lambda img, imgname_or_label: (prepare_image(img, augment=augment, cfg=cfg),imgname_or_label), num_parallel_calls=AUTO)\n    \n    ds = ds.batch(cfg['batch_size'] * REPLICAS)\n    ds = ds.prefetch(AUTO)\n    return ds","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def show_dataset(thumb_size, cols, rows, ds):\n    mosaic = PIL.Image.new(mode='RGB', size=(thumb_size*cols + (cols-1), thumb_size*rows + (rows-1)))\n   \n    for idx, data in enumerate(iter(ds)):\n        img, target_or_imgid = data\n        ix  = idx % cols\n        iy  = idx // cols\n        img = np.clip(img.numpy() * 255, 0, 255).astype(np.uint8)\n        img = PIL.Image.fromarray(img)\n        img = img.resize((thumb_size, thumb_size), resample=PIL.Image.BILINEAR)\n        mosaic.paste(img, (ix*thumb_size + ix, \n                           iy*thumb_size + iy))\n\n    display(mosaic)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Train & Test datasets -> Image examples","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"num_training_images = int(count_data_items(files_train))\nnum_test_images = count_data_items(files_test)\nprint('Dataset: {} training images, {} unlabeled test images'.format(num_training_images, num_test_images))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Train Data\nds = get_dataset(files_train, CFG).unbatch().take(12*5) # augment = False\nshow_dataset(64, 12, 5, ds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Image Augmentation\nds = tf.data.TFRecordDataset(files_train, num_parallel_reads=AUTO)\nds = ds.take(1).cache().repeat()\nds = ds.map(read_labeled_tfrecord, num_parallel_calls=AUTO)\nds = ds.map(lambda img, target: (prepare_image(img, cfg=CFG, augment=True), target), num_parallel_calls=AUTO)\nds = ds.take(12*5)\nds = ds.prefetch(AUTO)\nshow_dataset(64, 12, 5, ds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Test Data\nds = get_dataset(files_test, CFG, labeled=False).unbatch().take(12*5)\nshow_dataset(64, 12, 5, ds)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Load model","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"with strategy.scope():\n    model_B6 = tf.keras.models.load_model(f'../input/melanoma-classification-3rd-place-models/{saved_models[tfrec_shape]}')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Predict","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"CFG['batch_size'] = batch_size_predictions[tfrec_shape]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cnt_test = count_data_items(files_test)\nsteps = cnt_test / (CFG['batch_size'] * REPLICAS) * CFG['tta_steps']\nds_testAug = get_dataset(files_test, CFG, augment=True, repeat=True, labeled=False, return_image_names=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds_B6 = model_B6.predict(ds_testAug, verbose=1, steps=steps)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Test shape :\",df_sub.shape)\nprint(\"Preds shape :\",preds_B6.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds = np.stack(preds_B6)\npreds = preds[:,:cnt_test* CFG['tta_steps']]\npreds = preds[:df_test.shape[0]*CFG['tta_steps']]\npreds = np.stack(np.split(preds, CFG['tta_steps']),axis=1)\npreds = np.mean(preds, axis=1)\npreds_B6 = preds.reshape(-1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Make Submission","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"ds = get_dataset(files_test, CFG, augment=False, repeat=False, labeled=False, return_image_names=True)\nimage_names = np.array([img_name.numpy().decode(\"utf-8\") for img, img_name in iter(ds.unbatch())])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_B6 = pd.DataFrame(dict(image_name = image_names,target = preds_B6))\n\nsubmission_B6 = submission_B6.sort_values('image_name')\nsubmission_B6.to_csv(f'submission_EfficientNetB6_{tfrec_shape}x{tfrec_shape}_{comp_data}.csv', index=False)\n\nsubmission_B6.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Acknowledgements & Inspiration:\n* https://www.kaggle.com/vbhargav875/efficientnet-b5-b6-b7-tf-keras\n* https://www.kaggle.com/agentauers/incredible-tpus-finetune-effnetb0-b6-at-once\n* https://www.kaggle.com/nroman/melanoma-pytorch-starter-efficientnet?scriptVersionId=40165150\n* https://www.kaggle.com/graf10a/siim-data-augmentation-in-tf-hair-batch-affine\n* https://www.kaggle.com/cdeotte/triple-stratified-kfold-with-tfrecords","execution_count":null}],"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}