{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":20270,"databundleVersionId":1222630,"sourceType":"competition"},{"sourceId":1322485,"sourceType":"datasetVersion","datasetId":758225},{"sourceId":1322494,"sourceType":"datasetVersion","datasetId":688574},{"sourceId":1322517,"sourceType":"datasetVersion","datasetId":689329},{"sourceId":1322552,"sourceType":"datasetVersion","datasetId":688719},{"sourceId":1322612,"sourceType":"datasetVersion","datasetId":689578},{"sourceId":1324333,"sourceType":"datasetVersion","datasetId":762256},{"sourceId":1324349,"sourceType":"datasetVersion","datasetId":762108},{"sourceId":1324366,"sourceType":"datasetVersion","datasetId":762176},{"sourceId":1324385,"sourceType":"datasetVersion","datasetId":762138},{"sourceId":1324412,"sourceType":"datasetVersion","datasetId":762168},{"sourceId":1324430,"sourceType":"datasetVersion","datasetId":768238},{"sourceId":1324483,"sourceType":"datasetVersion","datasetId":758409},{"sourceId":1339671,"sourceType":"datasetVersion","datasetId":758489},{"sourceId":1362814,"sourceType":"datasetVersion","datasetId":791650},{"sourceId":1362826,"sourceType":"datasetVersion","datasetId":791647},{"sourceId":1362834,"sourceType":"datasetVersion","datasetId":791645},{"sourceId":1362843,"sourceType":"datasetVersion","datasetId":791643},{"sourceId":1362855,"sourceType":"datasetVersion","datasetId":791638},{"sourceId":1362877,"sourceType":"datasetVersion","datasetId":791635}],"dockerImageVersionId":30648,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# **Imports**","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport glob\nimport cv2\nimport matplotlib.pyplot as plt\nimport matplotlib.cm as cm\nimport seaborn as sns\nimport PIL\nimport time\nimport os\nimport torch\nimport tensorflow as tf, re, math\nimport random\n\nfrom tensorflow import keras\nfrom IPython.display import Image\nimport tensorflow.keras.backend as K\nfrom keras.losses import binary_crossentropy\nfrom tensorflow.keras.applications import ResNet50, ResNet101, ResNet152 \nfrom tensorflow.keras.losses import BinaryCrossentropy, BinaryFocalCrossentropy\nfrom sklearn.metrics import roc_auc_score\nfrom sklearn.model_selection import train_test_split, KFold\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array, array_to_img\nfrom tensorflow.keras.layers import Flatten, Dense, Dropout\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras import optimizers\nimport tensorflow as tf, re, math\nfrom functools import partial\nfrom kaggle_datasets import KaggleDatasets\nimport tempfile\n\nimport pandas as pd, numpy as np, gc\nfrom kaggle_datasets import KaggleDatasets\nimport tensorflow.keras.backend as K\nfrom sklearn.model_selection import KFold\nfrom sklearn.metrics import roc_auc_score\nimport matplotlib.pyplot as plt","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-06-16T22:33:01.789589Z","iopub.execute_input":"2024-06-16T22:33:01.790601Z","iopub.status.idle":"2024-06-16T22:33:25.690593Z","shell.execute_reply.started":"2024-06-16T22:33:01.790562Z","shell.execute_reply":"2024-06-16T22:33:25.689234Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Versión de TensorFlow:\", tf.__version__)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(dir(tf.keras.applications))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nimport keras\nimport sys\nimport os\n\n# Verificar la versión de TensorFlow\nprint(\"Versión de TensorFlow:\", tf.__version__)\n\n# Verificar la versión de Keras\nprint(\"Versión de Keras:\", keras.__version__)\n\n# Verificar la versión de CUDA\ncuda_version = os.popen('nvcc --version').read()\nprint(\"Versión de CUDA:\", cuda_version)\n\n# Verificar la versión de Python\nprint(\"Versión de Python:\", sys.version)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def set_seed(seed=42):\n    \"\"\"Sets the seed of the entire notebook so results are the same every time we run. This is for reproducibility\"\"\"\n    np.random.seed(seed)\n    random.seed(seed)\n    tf.random.set_seed(seed)\n\n    # Disable GPU parallelism to ensure reproducibility on GPU\n    tf.config.threading.set_inter_op_parallelism_threads(1)\n    tf.config.threading.set_intra_op_parallelism_threads(1)\n\n    # Disable CuDNN auto-tuning to ensure reproducibility on GPU\n    tf.config.set_soft_device_placement(True)\n    tf.config.optimizer.set_experimental_options({\"auto_mixed_precision\": False})\n\n    print('SEEDING DONE')\n\nset_seed(42)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Kaggle's SIIM-ISIC Melanoma Classification**","metadata":{}},{"cell_type":"code","source":"train_csv = pd.read_csv('../input/siim-isic-melanoma-classification/train.csv')\ntest_csv  = pd.read_csv('../input/siim-isic-melanoma-classification/test.csv')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"total_img = train_csv['target'].size\nmalignant = np.count_nonzero(train_csv['target'])\nbenign    = total_img - malignant\n\nprint('Total      {}  {:.2f}%   \\nBenign     {}  {:.2f}%   \\nMalignant  {}    {:.2f}%'.format(total_img,100 * total_img / total_img, benign, 100 * benign / total_img, malignant, 100 * malignant / total_img))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"weight_for_0 = 1.02  #(1 / (benign    / total_img))\nweight_for_1 = 85.08 #(1 / (malignant / total_img))\nclass_weight = {0: weight_for_0, 1: weight_for_1}\n\nprint('Weight for class 0: {}'.format(weight_for_0))\nprint('Weight for class 1: {}'.format(weight_for_1))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2, pandas as pd, matplotlib.pyplot as plt\n\ntrain = pd.read_csv('../input/siim-isic-melanoma-classification/train.csv')\n\nprint('Images with Melanoma')\nimgs = train.loc[train.target==1].sample(10).image_name.values\nplt.figure(figsize=(20,8))\nfor i,k in enumerate(imgs):\n    img = cv2.imread('../input/jpeg-melanoma-128x128/train/%s.jpg'%k)\n    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)\n    plt.subplot(1,10,i+1); plt.axis('off')\n    plt.imshow(img)\nplt.show()\n\nprint('Images without Melanoma')\nimgs = train.loc[train.target==0].sample(10).image_name.values\nplt.figure(figsize=(20,8))\nfor i,k in enumerate(imgs):\n    img = cv2.imread('../input/jpeg-melanoma-128x128/train/%s.jpg'%k)\n    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)\n    plt.subplot(1,10,i+1); plt.axis('off')\n    plt.imshow(img)\nplt.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Parameters**\nIn order to be a proper cross validation with a meaningful overall CV score (aligned with LB score), **you need to choose the same** `IMG_SIZES`, `INC2019`, `INC2018`, and `EFF_NETS` **for each fold**. If your goal is to just run lots of experiments, then you can choose to have a different experiment in each fold. Then each fold is like a holdout validation experiment. When you find a configuration you like, you can use that configuration for all folds. \n\nFirst we choose a number of `EXPERIMENTS`. Then this notebook will perform that many experiments on the same KFold fold. Afterward we can compare validation scores. Or you can repeat the same experiment many times and assess validation score variability. If you have read my previous notebook [here][1], you are familar with most of these configuration variables. We will list the new parameters first:\n[1]: https://www.kaggle.com/cdeotte/triple-stratified-kfold-with-tfrecords\n\n<table>\n  <tr>\n    <td><b>DEVICE</b></td>\n    <td>is GPU or TPU.</td>\n  </tr>\n  <tr>\n    <td><b>SEED</b></td>\n    <td>a different seed produces a different triple stratified kfold split.</td>\n  </tr>\n  <tr>\n    <td><b>FOLDS</b></td>\n    <td>number of folds. Best set to 3, 5, or 15 but can be any number between 2 and 15.</td>\n  </tr>\n  <tr>\n    <td><b>IMG_SIZES</b></td>\n    <td>is a Python list of length FOLDS. These are the image sizes to use each fold.</td>\n  </tr>\n  <tr>\n    <td><b>INC2019</b></td>\n    <td>This includes the new half of the 2019 competition data.</td>\n  </tr>\n  <tr>\n    <td><b>INC2018</b></td>\n    <td>This includes the second half of the 2019 competition data.</td>\n  </tr>\n  <tr>\n    <td><b>BATCH_SIZES</b></td>\n    <td>is a list of length FOLDS. These are batch sizes for each fold.</td>\n  </tr>\n  <tr>\n    <td><b>EPOCHS</b></td>\n    <td>is a list of length FOLDS. These are maximum epochs.</td>\n  </tr>\n  <tr>\n    <td><b>EFF_NETS</b></td>\n    <td>is a list of length FOLDS. These are the ConvNeXt to use each fold.</td>\n  </tr>\n  <tr>\n    <td><b>EFF_NETS_NUM</b></td>\n    <td>is a list of length FOLDS. These are the index for each item of EFF_NETS.</td>\n  </tr>\n  <tr>\n    <td><b>WGTS</b></td>\n    <td>this should be `1/FOLDS` for each fold.</td>\n  </tr>\n  <tr>\n    <td><b>TTA</b></td>\n    <td>test time augmentation.</td>\n  </tr>\n    <tr>\n    <td><b>EXPERIMENTS</b></td>\n    <td>number of experiments to perform</td>\n  </tr>\n  <tr>\n    <td><b>FNUMBER</b></td>\n    <td>which of the KFolds to repeatedly perform experiments on.</td>\n  </tr>\n  <tr>\n    <td><b>M1</b></td>\n    <td>is a list. Adds copies of malignant images from this year's comp data</td>\n  </tr>\n  <tr>\n    <td><b>M2</b></td>\n    <td>is a list. Adds copies of malignant images from ISIC archive that are not in 2020, 2019, 2018, 2017 comp data</td>\n  </tr>\n  <tr>\n    <td><b>M3</b></td>\n    <td>is a list. Adds copies of malignant images from 2019 comp data.</td>\n  </tr>\n  <tr>\n    <td><b>M4</b></td>\n    <td>is a list. Adds copies of malignant images from 2017 and 2018 data.</td>\n  </tr>\n  <tr>\n    <td><b>DROP_FREQ</b></td>\n    <td>a list of floats between 0 and 1. Determines the proportion of train images to apply coarse dropout to</td>\n  </tr>\n  <tr>\n    <td><b>DROP_CT</b></td>\n    <td>a list of ints. Determines how many squares to remove from train images when applying dropout</td>\n  </tr>\n  <tr>\n    <td><b>DROP_SIZE</b></td>\n    <td>a list of floats between 0 and 1. Determines the size of square side equals IMG_SIZE * DROP_SIZE</td>\n  </tr>\n  <tr>\n    <td><b>INFER_TEST</b></td>\n    <td>whether to predict test images each experiment</td>\n  </tr>\n</table>\n","metadata":{}},{"cell_type":"markdown","source":"With this code I will perform 3 different experiments based on class-imbalance:\nCLASS_WEIGHT\nBINARYFOCALCROSSLOSS\nAUGMENTATIONS","metadata":{}},{"cell_type":"code","source":"DEVICE = \"GPU\"\n\n# USE DIFFERENT SEED FOR DIFFERENT STRATIFIED KFOLD\nSEED = 42\n\n# NUMBER OF FOLDS: 3,5,15 (1-15)\nFOLDS = 5\n\n# WHICH FOLD TO PERFORM EXPERIMENTS ON: (1-15)\n# NUMBER OF EXPERIMENTS FOR THE SELECTED FOLD\nFNUMBER = 1\nEXPERIMENTS = 1\n\n# WHICH IMAGE SIZES TO LOAD EACH FOLD: 128, 192, 256, 384, 512, 768 \nIMG_SIZES = [256]*EXPERIMENTS\n\n# INCLUDE OLD COMP DATA? YES=1 NO=0\nINC2019 = [1]*EXPERIMENTS\nINC2018 = [1]*EXPERIMENTS\n\n# UPSAMPLE MALIGNANT COUNT TIMES\nM1 = [0]*EXPERIMENTS #2020 malig\nM2 = [0]*EXPERIMENTS #ISIC malig\nM3 = [0]*EXPERIMENTS #2019 good malig\nM4 = [0]*EXPERIMENTS #2018 2017 malig\n\n# COARSE DROPOUT\nDROP_FREQ = [0.75,0.75,0.75] # between 0 and 1\nDROP_CT   = [8,8,8]          # may slow training if CT>16\nDROP_SIZE = [0.2,0.2,0.2]    # between 0 and 1\n\n# BATCH SIZE AND EPOCHS\nBATCH_SIZES = [16]*EXPERIMENTS\nEPOCHS = [25]*EXPERIMENTS\n\n# WHICH CONVNET NAME TO USE\nEFF_NETS = ['ResNet101']*FOLDS\n\nEFF_NETS_NUMS = [0,1,2,3,4]\n\n# WEIGHTS FOR FOLD MODELS WHEN PREDICTING TEST\nWGTS = [1/EXPERIMENTS]*EXPERIMENTS\n\n# TEST TIME AUGMENTATION STEPS\nTTA = 11\nINFER_TEST = True","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"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    \n\nAUTO     = tf.data.experimental.AUTOTUNE\nREPLICAS = strategy.num_replicas_in_sync\nprint(f'REPLICAS: {REPLICAS}')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Step 1: Preprocess Data**\nPreprocess has already been done and saved to TFRecords. Here we choose which size to load. We can use either 128x128, 192x192, 256x256, 384x384, 512x512, 768x768 by changing the `IMG_SIZES` variable in the preceeding code section. These TFRecords are discussed [here][1]. The advantage of using different input sizes is discussed [here][2]\n\n[1]: https://www.kaggle.com/c/siim-isic-melanoma-classification/discussion/155579\n[2]: https://www.kaggle.com/c/siim-isic-melanoma-classification/discussion/160147","metadata":{}},{"cell_type":"code","source":"GCS_PATH  = [None]*FOLDS\nGCS_PATH2 = [None]*FOLDS\nGCS_PATH3 = [None]*FOLDS\n\nfor i,k in enumerate(IMG_SIZES[:FOLDS]):\n    GCS_PATH[i] = KaggleDatasets().get_gcs_path('melanoma-%ix%i'%(k,k))\n    GCS_PATH2[i] = KaggleDatasets().get_gcs_path('isic2019-%ix%i'%(k,k))\n    GCS_PATH3[i] = KaggleDatasets().get_gcs_path('malignant-v2-%ix%i'%(k,k))\nfiles_train = np.sort(np.array(tf.io.gfile.glob(GCS_PATH[0] + '/train*.tfrec')))\nfiles_test  = np.sort(np.array(tf.io.gfile.glob(GCS_PATH[0] + '/test*.tfrec')))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Step 2: Data Augmentation**\nThis notebook uses rotation, sheer, zoom, shift augmentation first shown in this notebook [here][1] and successfully used in Melanoma comp by AgentAuers [here][2]. This notebook also uses horizontal flip, hue, saturation, contrast, brightness augmentation similar to last years winner and also similar to AgentAuers' notebook.\n\nAdditionally we can decide to use external data by changing the variables `INC2019` and `INC2018` in the preceeding code section. These variables respectively indicate whether to load last year 2019 data and/or year 2018 + 2017 data. These datasets are discussed [here][3]\n\nConsider experimenting with different augmenation and/or external data. The code to load TFRecords is taken from AgentAuers' notebook [here][2]. Thank you AgentAuers, this is great work.\n\n[1]: https://www.kaggle.com/cdeotte/rotation-augmentation-gpu-tpu-0-96\n[2]: https://www.kaggle.com/agentauers/incredible-tpus-finetune-effnetb0-b6-at-once\n[3]: https://www.kaggle.com/c/siim-isic-melanoma-classification/discussion/164910","metadata":{}},{"cell_type":"markdown","source":"### **Geometric Augmentations**","metadata":{}},{"cell_type":"code","source":"ROT_    = 180.0\nSHR_    = 2.0\nHZOOM_  = 8.0\nWZOOM_  = 8.0\nHSHIFT_ = 8.0\nWSHIFT_ = 8.0","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"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    \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))\n\n\ndef transform(image, DIM=256):    \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    XDIM = DIM%2 #fix for size 331\n    \n    rot     = ROT_ * tf.random.normal([1], dtype='float32')\n    shr     = SHR_ * tf.random.normal([1], dtype='float32') \n    h_zoom  = 1.0 + tf.random.normal([1], dtype='float32') / HZOOM_\n    w_zoom  = 1.0 + tf.random.normal([1], dtype='float32') / WZOOM_\n    h_shift = HSHIFT_ * tf.random.normal([1], dtype='float32') \n    w_shift = 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])","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Dropout Augmentations**","metadata":{}},{"cell_type":"code","source":"RATE = 0.75; CT = 8; SIZE = 0.2\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        \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","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Microscope Augmentations**","metadata":{}},{"cell_type":"code","source":"def dropout_circle(image, DIM=256, PROBABILITY=0.75, RADIUS=0.9):\n    # input image - is one image of size [dim,dim,3] not a batch of [b,dim,dim,3]\n    # output - image with a circle of radius RADIUS*DIM centered and filled with black, simulating a microscope view\n    \n    # DO DROPOUT WITH PROBABILITY DEFINED ABOVE\n    P = tf.cast(tf.random.uniform([], 0, 1) < PROBABILITY, tf.int32)\n    if P == 0 or RADIUS == 0:\n        return image\n    \n    # CALCULATE CENTER OF THE CIRCLE (CENTER OF THE IMAGE)\n    x_center = tf.cast(DIM / 2, tf.float32)\n    y_center = tf.cast(DIM / 2, tf.float32)\n    \n    # CREATE MESHGRID TO CALCULATE DISTANCE FROM CENTER FOR EACH PIXEL\n    X, Y = tf.meshgrid(tf.range(DIM), tf.range(DIM), indexing='ij')\n    X = tf.cast(X, tf.float32)\n    Y = tf.cast(Y, tf.float32)\n    \n    # CALCULATE DISTANCE OF EACH PIXEL FROM CENTER\n    distances = tf.sqrt(tf.square(X - x_center) + tf.square(Y - y_center))\n    \n    # CREATE MASK FOR THE CIRCLE\n    circle_mask = tf.cast(distances < RADIUS * DIM / 2, tf.float32)\n    \n    # CREATE BLACK IMAGE\n    black_image = tf.zeros_like(image)\n    \n    # FILL INSIDE OF CIRCLE WITH ORIGINAL IMAGE VALUES\n    masked_image = black_image + image * circle_mask[:, :, tf.newaxis]\n    \n    return masked_image","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Prepare_image**","metadata":{}},{"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']\n\n\ndef read_unlabeled_tfrecord(example, return_image_name=True):\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\n\n \ndef prepare_image(img, augment=True, dim=256, droprate=0, dropct=0, dropsize=0, radius=0):    \n    img = tf.image.decode_jpeg(img, channels=3)\n    img = tf.cast(img, tf.float32) / 255.0\n    \n    if augment:\n        \n        # Geometric Augmentations Part1\n        img = transform(img,DIM=dim)\n        \n        # Dropout Augmentations\n        #if (droprate!=0)&(dropct!=0)&(dropsize!=0): \n            #img = dropout(img, DIM=dim, PROBABILITY=droprate, CT=dropct, SZ=dropsize)\n        \n        # Microscope Augmentations\n        if (droprate!=0)&(radius!=0): \n            img = dropout_circle(img, DIM=dim, PROBABILITY=droprate, RADIUS=radius)\n        \n        # Geometric Augmentations Part2\n        img = tf.image.flip_left_right(img)\n        img = tf.image.flip_left_right(img)\n        img = tf.image.flip_up_down(img)\n        img = tf.image.rot90(img, k=1)\n        img = tf.image.rot90(img, k=2)\n        img = tf.image.rot90(img, k=3)\n        \n        # Color distortion Augmentations\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                      \n        img = tf.reshape(img, [dim,dim, 3])\n            \n    return img\n\n    \ndef show_image(img, augment=True, dim=256, droprate=0.75, dropct=8, dropsize=0.2):    \n    img = tf.image.decode_jpeg(img, channels=3)\n    img_og = tf.cast(img, tf.float32) / 255.0\n    \n    augmented_images = []\n    lst_augmented = []\n    \n    # Geometric and Color distortion Augmentations \n    if augment:\n        lst_augmented.append('Original');\n        img_dro = dropout(img_og, DIM=dim, PROBABILITY=0.75, CT=8, SZ=0.2);       lst_augmented.append('■');\n        img_cir = dropout_circle(img_og, DIM=dim, PROBABILITY=0.75, RADIUS=0.9);  lst_augmented.append('𒊹');\n        img_flipped_lr  = tf.image.flip_left_right(img_og);      lst_augmented.append('⇄');\n        img_flipped_ud  = tf.image.flip_up_down(img_og);         lst_augmented.append('⇅');\n        img_rotated_90  = tf.image.rot90(img_og, k=1);           lst_augmented.append('⟲90');\n        img_rotated_180 = tf.image.rot90(img_og, k=2);           lst_augmented.append('⟲180');\n        img_rotated_270 = tf.image.rot90(img_og, k=3);           lst_augmented.append('⟲270');\n        img_hue = tf.image.random_hue(img_og, 0.01);             lst_augmented.append('hue');\n        img_sat = tf.image.random_saturation(img_og, 0.7, 1.3);  lst_augmented.append('saturation');\n        img_con = tf.image.random_contrast(img_og, 0.8, 1.2);    lst_augmented.append('contrast');\n        img_bri = tf.image.random_brightness(img_og, 0.1);       lst_augmented.append('brightness');\n        \n        \n        augmented_images.extend([img_og, img_dro, img_cir, img_flipped_lr, img_flipped_ud, img_rotated_90, img_rotated_180, img_rotated_270,img_hue,img_sat,img_con,img_bri])\n    augmented_images = [tf.reshape(img, [dim, dim, 3]) for img in augmented_images]\n    img = tf.reshape(img, [dim, dim, 3])\n            \n    return augmented_images, lst_augmented\n\n\ndef count_data_items(filenames):\n    n = [int(re.compile(r\"-([0-9]*)\\.\").search(filename).group(1)) \n         for filename in filenames]\n    return np.sum(n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_dataset(files, augment = False, shuffle = False, repeat = False, \n                labeled=True, return_image_names=True, batch_size=16, dim=256,\n                droprate=0, dropct=0, dropsize=0):\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*2) #if too large causes OOM in GPU CPU\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), \n                    num_parallel_calls=AUTO)      \n    \n    ds = ds.map(lambda img, imgname_or_label: (prepare_image(img, \n                                                             augment=True, \n                                                             dim=dim, \n                                                             droprate=droprate,\n                                                             dropct=dropct, \n                                                             dropsize=dropsize,\n                                                             radius=0.9), imgname_or_label), num_parallel_calls=AUTO)\n    \n    ds = ds.batch(batch_size * REPLICAS)\n    ds = ds.prefetch(AUTO)\n    return ds","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Display Data Augmentation**\n","metadata":{}},{"cell_type":"code","source":"import PIL, cv2\n\ndef show_dataset(thumb_size, cols, rows, ds):\n    mosaic = PIL.Image.new(mode='RGB', size=(thumb_size*cols + (cols-1), \n                                             thumb_size*rows + (rows-1)))\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        nn = target_or_imgid.numpy().decode(\"utf-8\")\n\n    display(mosaic)\n    return nn\n\nPATH9 =  '../input/jpeg-melanoma-128x128/train/'\nfiles_train = tf.io.gfile.glob(GCS_PATH[0] + '/train*.tfrec')\n\n# DROPOUT parameters to display\nRATE = 0.75; CT = 8; SIZE = 0.2\n\n# LOAD DATA AND APPLY AUGMENTATIONS\nds = tf.data.TFRecordDataset(files_train, num_parallel_reads=AUTO).shuffle(1024)\nds = ds.take(1).cache().repeat()\n\nds = ds.map(read_unlabeled_tfrecord, num_parallel_calls=AUTO)\n","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# LOAD DATA AND APPLY DROPOUT AUGMENTATIONS (COMENTAR EN prepare_image QUE SE QUIERE VER Y QUE NO)\nds = ds.map(lambda img, target: (prepare_image(img,\n                                               augment=True, \n                                               dim=IMG_SIZES[0],\n                                               droprate = RATE, \n                                               dropct = CT, \n                                               dropsize = SIZE,\n                                               radius=0.9), target), num_parallel_calls=AUTO)\nds = ds.take(12*5); \nds = ds.prefetch(AUTO)\n\n# DISPLAY IMAGE WITH AND WITHOUT AUGMENTATIONS\nprint('WITH DROPOUT AUGMENTATION - dropout_freq=%.2f count=%i size=%.3f'%(RATE,CT,SIZE))\nname = show_dataset(128, 8, 2, ds)\nimg = cv2.imread(PATH9+name+'.jpg')\nimg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\nplt.imshow(img)\n\nprint('WITHOUT AUGMENTATION - Original Image')\nplt.title('%s'%name,size=16); plt.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# LOAD DATA AND APPLY GEOMETRIC AND COLOR DISTORSION AUGMENTATIONS\nds = tf.data.TFRecordDataset(files_train, num_parallel_reads=AUTO).shuffle(1024)\nds = ds.take(1).cache().repeat()\n\nds = ds.map(read_unlabeled_tfrecord, num_parallel_calls=AUTO)\nds = ds.map(lambda img, target: show_image(img,\n                                           augment=True, \n                                           dim=IMG_SIZES[0],\n                                           droprate=0.75, \n                                           dropct=8, \n                                           dropsize=0.1), num_parallel_calls=AUTO)\n\nds = ds.take(12*5); \nds = ds.prefetch(AUTO)\n\n# DISPLAY IMAGE WITH AND WITHOUT AUGMENTATIONS\nfor augmented_images, lst_augmented in ds.take(1):\n    plt.figure(figsize=(15, 15))\n    for i, augmented_img in enumerate(augmented_images):\n        plt.subplot(1, len(augmented_images), i + 1)\n        plt.imshow(augmented_img.numpy())\n        augmented_label = lst_augmented[i].numpy().decode(\"utf-8\")\n        plt.title(augmented_label)\n        plt.axis('off')\n    plt.subplots_adjust(wspace=1, hspace=1)\n    plt.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Step 3: Build Model**\nThis is a common model architecute. Consider experimenting with different backbones, custom heads, losses, and optimizers. Also consider inputing meta features into your CNN.","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nimport keras.backend as K\n\ndef tp(y_true, y_pred):\n    y_pred = K.round(y_pred)\n    tp = K.sum(K.cast(y_true * y_pred, 'float'), axis=0)\n    \n    return K.mean(tp)\n\ndef tn(y_true, y_pred):\n    y_pred = K.round(y_pred)\n    tn = K.sum(K.cast((1 - y_true) * (1 - y_pred), 'float'), axis=0)\n    \n    return K.mean(tn)\n\ndef fp(y_true, y_pred):\n    y_pred = K.round(y_pred)\n    fp = K.sum(K.cast((1 - y_true) * y_pred, 'float'), axis=0)\n    \n    return K.mean(fp)\n\ndef fn(y_true, y_pred):\n    y_pred = K.round(y_pred)\n    fn = K.sum(K.cast(y_true * (1 - y_pred), 'float'), axis=0)\n    \n    return K.mean(fn)\n\n\ndef f1score_1(y_true, y_pred):\n    y_pred = K.round(y_pred)\n    tp = K.sum(K.cast(y_true * y_pred, 'float'), axis=0)\n    tn = K.sum(K.cast((1 - y_true) * (1 - y_pred), 'float'), axis=0)\n    fp = K.sum(K.cast((1 - y_true) * y_pred, 'float'), axis=0)\n    fn = K.sum(K.cast(y_true * (1 - y_pred), 'float'), axis=0)\n\n    p = tp / (tp + fp + K.epsilon())\n    r = tp / (tp + fn + K.epsilon())\n\n    f1 = 2 * p * r / (p + r + K.epsilon())\n    f1 = tf.where(tf.math.is_nan(f1), tf.zeros_like(f1), f1)\n    return K.mean(f1)\n\ndef f1score_0(y_true, y_pred):\n    y_pred = K.round(y_pred)\n    tp = K.sum(K.cast(y_true * y_pred, 'float'), axis=0)\n    tn = K.sum(K.cast((1 - y_true) * (1 - y_pred), 'float'), axis=0)\n    fp = K.sum(K.cast((1 - y_true) * y_pred, 'float'), axis=0)\n    fn = K.sum(K.cast(y_true * (1 - y_pred), 'float'), axis=0)\n\n    p = tn / (tn + fn + K.epsilon())\n    r = tn / (tn + fp + K.epsilon())\n\n    f1 = 2 * p * r / (p + r + K.epsilon())\n    f1 = tf.where(tf.math.is_nan(f1), tf.zeros_like(f1), f1)\n    return K.mean(f1)\n\ndef f1score(y_true, y_pred):\n    f1class1 = f1score_1(y_true, y_pred)\n    f1class0 = f1score_0(y_true, y_pred)\n    f1 = (f1class1+f1class0)/2\n    f1 = tf.where(tf.math.is_nan(f1), tf.zeros_like(f1), f1)\n    return K.mean(f1)\n\ndef precision_1(y_true, y_pred):\n    y_pred = K.round(y_pred)\n    tp = K.sum(K.cast(y_true * y_pred, 'float'), axis=0)\n    tn = K.sum(K.cast((1 - y_true) * (1 - y_pred), 'float'), axis=0)\n    fp = K.sum(K.cast((1 - y_true) * y_pred, 'float'), axis=0)\n    fn = K.sum(K.cast(y_true * (1 - y_pred), 'float'), axis=0)\n\n    p = tp / (tp + fp + K.epsilon())\n    p = tf.where(tf.math.is_nan(p), tf.zeros_like(p), p)\n    return K.mean(p)\n\ndef precision_0(y_true, y_pred):\n    y_pred = K.round(y_pred)\n    tp = K.sum(K.cast(y_true * y_pred, 'float'), axis=0)\n    tn = K.sum(K.cast((1 - y_true) * (1 - y_pred), 'float'), axis=0)\n    fp = K.sum(K.cast((1 - y_true) * y_pred, 'float'), axis=0)\n    fn = K.sum(K.cast(y_true * (1 - y_pred), 'float'), axis=0)\n\n    p = tn / (tn + fn + K.epsilon())\n    p = tf.where(tf.math.is_nan(p), tf.zeros_like(p), p)\n    return K.mean(p)\n\ndef precision(y_true, y_pred):\n    precisionclass1 = precision_1(y_true, y_pred)\n    precisionclass0 = precision_0(y_true, y_pred)\n    p = (precisionclass1+precisionclass0)/2\n    p = tf.where(tf.math.is_nan(p), tf.zeros_like(p), p)\n    return K.mean(p)\n\ndef recall_1(y_true, y_pred):\n    y_pred = K.round(y_pred)\n    tp = K.sum(K.cast(y_true * y_pred, 'float'), axis=0)\n    tn = K.sum(K.cast((1 - y_true) * (1 - y_pred), 'float'), axis=0)\n    fp = K.sum(K.cast((1 - y_true) * y_pred, 'float'), axis=0)\n    fn = K.sum(K.cast(y_true * (1 - y_pred), 'float'), axis=0)\n\n    r = tp / (tp + fn + K.epsilon())\n    r = tf.where(tf.math.is_nan(r), tf.zeros_like(r), r)\n    return K.mean(r)\n\ndef recall_0(y_true, y_pred):\n    y_pred = K.round(y_pred)\n    tp = K.sum(K.cast(y_true * y_pred, 'float'), axis=0)\n    tn = K.sum(K.cast((1 - y_true) * (1 - y_pred), 'float'), axis=0)\n    fp = K.sum(K.cast((1 - y_true) * y_pred, 'float'), axis=0)\n    fn = K.sum(K.cast(y_true * (1 - y_pred), 'float'), axis=0)\n\n    r = tn / (tn + fp + K.epsilon())\n    r = tf.where(tf.math.is_nan(r), tf.zeros_like(r), r)\n    return K.mean(r)\n\ndef recall(y_true, y_pred):\n    recallclass1 = recall_1(y_true, y_pred)\n    recallclass0 = recall_0(y_true, y_pred)\n    r = (recallclass1+recallclass0)/2\n    r = tf.where(tf.math.is_nan(r), tf.zeros_like(r), r)\n    return K.mean(r)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"EFNS = [ResNet101,ResNet101,ResNet101,ResNet101,ResNet101]\nalpha=0.99\ngamma=4.99\n\ndef build_model(dim=128, ef=0):\n    inp  = tf.keras.layers.Input(shape=(dim,dim,3))\n    base = EFNS[ef](input_shape=(dim,dim,3),weights='imagenet',include_top=False)\n    \n    x = base(inp)\n    x = tf.keras.layers.GlobalAveragePooling2D()(x)\n    x = tf.keras.layers.Dense(1,activation='sigmoid')(x)\n    model = tf.keras.Model(inputs=inp,outputs=x)\n    \n    opt  = tf.keras.optimizers.Adam(learning_rate=0.001)\n    '''\n    loss = tf.keras.losses.BinaryCrossentropy(label_smoothing=0.05) \n    '''\n    loss = tf.keras.losses.BinaryFocalCrossentropy(apply_class_balancing=True,\n                                                   alpha=alpha,\n                                                   gamma=gamma,\n                                                   from_logits=False,\n                                                   label_smoothing=0.05,\n                                                   axis=-1,\n                                                   reduction='sum_over_batch_size',\n                                                   name='binary_focal_crossentropy'\n                                                   )\n    \n    model.compile(optimizer=opt,loss=loss,metrics=['accuracy','AUC', f1score, f1score_1, f1score_0, precision, precision_1, precision_0, recall, recall_1, recall_0, tp, tn, fp, fn])\n    \n    return model","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Step 4: Train Schedule**\nThis is a common train schedule for transfer learning. The learning rate starts near zero, then increases to a maximum, then decays over time. Consider changing the schedule and/or learning rates. Note how the learning rate max is larger with larger batches sizes. This is a good practice to follow.","metadata":{}},{"cell_type":"code","source":"def get_lr_callback(batch_size=8):\n    lr_start   = 0.000005\n    lr_max     = 0.00000125 * REPLICAS * batch_size\n    lr_min     = 0.000001\n    lr_ramp_ep = 5\n    lr_sus_ep  = 0\n    lr_decay   = 0.8\n   \n    def lrfn(epoch):\n        if epoch < lr_ramp_ep:\n            lr = (lr_max - lr_start) / lr_ramp_ep * epoch + lr_start\n            \n        elif epoch < lr_ramp_ep + lr_sus_ep:\n            lr = lr_max\n            \n        else:\n            lr = (lr_max - lr_min) * lr_decay**(epoch - lr_ramp_ep - lr_sus_ep) + lr_min\n            \n        return lr\n\n    lr_callback = tf.keras.callbacks.LearningRateScheduler(lrfn, verbose=False)\n    return lr_callback","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train Experiments\nThis note book will repeatedly run experiments on the same KFold fold. Each experiment will be trained for the number of EPOCHS you chose in the configuration above. Each experiment the model with lowest validation loss will be saved and used to predict OOF and test. Adjust the variables `VERBOSE` and `DISPLOY_PLOT` below to determine what output you want displayed. The variable `VERBOSE=1 or 2` will display the training and validation loss and auc for each epoch as text. The variable `DISPLAY_PLOT` shows this information as a plot. ","metadata":{}},{"cell_type":"code","source":"skf = KFold(n_splits=FOLDS,shuffle=True,random_state=SEED)\nfor fold,(idxT,idxV) in enumerate(skf.split(np.arange(15))):\n    if fold==(FNUMBER-1):\n        idxTT = idxT; idxVV = idxV\n        print('### Using fold',fold,'for experiments')\n    print('Fold',fold,'has TRAIN:',idxT,'VALID:',idxV)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import time\n\n# USE VERBOSE=0 for silent, VERBOSE=1 for interactive, VERBOSE=2 for commit\nVERBOSE = 2\nDISPLAY_PLOT = True\ntime_lst = []\n\noof_pred = []; oof_tar = []; oof_val = []; oof_names = []; oof_folds = [] \npreds = np.zeros((count_data_items(files_test),1))\n\nfor fold in range(EXPERIMENTS):\n    '''\n    if fold == 3:\n        break\n    '''\n    # REPEAT SAME FOLD OVER AND OVER\n    idxT = idxTT\n    idxV = idxVV\n    \n    # DISPLAY FOLD INFO\n    if DEVICE=='TPU':\n        if tpu: tf.tpu.experimental.initialize_tpu_system(tpu)\n    print('#'*25); print('#### EXPERIMENT',fold+1)\n    print('#### %s - Image Size %i'%(EFF_NETS[fold],IMG_SIZES[fold]))\n    \n    # CREATE TRAIN AND VALIDATION SUBSETS\n    files_train = tf.io.gfile.glob([GCS_PATH[fold] + '/train%.2i*.tfrec'%x for x in idxT])\n    if INC2019[fold]:\n        files_train += tf.io.gfile.glob([GCS_PATH2[fold] + '/train%.2i*.tfrec'%x for x in idxT*2+1])\n        print('#### Using 2019 external data')\n    if INC2018[fold]:\n        files_train += tf.io.gfile.glob([GCS_PATH2[fold] + '/train%.2i*.tfrec'%x for x in idxT*2])\n        print('#### Using 2018+2017 external data')\n    for k in range(M1[fold]):\n        files_train += tf.io.gfile.glob([GCS_PATH3[fold] + '/train%.2i*.tfrec'%x for x in idxT])\n        print('#### Upsample MALIG-1 data (2020 comp)')\n    for k in range(M2[fold]):\n        files_train += tf.io.gfile.glob([GCS_PATH3[fold] + '/train%.2i*.tfrec'%x for x in idxT+15])\n        print('#### Upsample MALIG-2 data (ISIC website)')\n    for k in range(M3[fold]):\n        files_train += tf.io.gfile.glob([GCS_PATH3[fold] + '/train%.2i*.tfrec'%x for x in idxT*2+1+30])\n        print('#### Upsample MALIG-3 data (2019 comp)')\n    for k in range(M4[fold]):\n        files_train += tf.io.gfile.glob([GCS_PATH3[fold] + '/train%.2i*.tfrec'%x for x in idxT*2+30])\n        print('#### Upsample MALIG-4 data (2018 2017 comp)')\n    np.random.shuffle(files_train); print('#'*25)\n    files_valid = tf.io.gfile.glob([GCS_PATH[fold] + '/train%.2i*.tfrec'%x for x in idxV])\n    files_test = np.sort(np.array(tf.io.gfile.glob(GCS_PATH[fold] + '/test*.tfrec')))\n    \n    # BUILD MODEL\n    K.clear_session()\n    with strategy.scope():\n        model = build_model(dim=IMG_SIZES[fold],ef=EFF_NETS_NUMS[fold])\n        \n    # SAVE BEST MODEL EACH FOLD\n    sv = tf.keras.callbacks.ModelCheckpoint(\n        'fold-%i.h5'%fold, monitor='val_f1score', verbose=0, save_best_only=True,\n        save_weights_only=True, mode='min', save_freq='epoch')\n   \n    # TRAIN\n    print('Training...')\n    \n    t1 = time.time()\n    \n    history = model.fit(get_dataset(files_train, \n                                    augment=True, \n                                    shuffle=True, \n                                    repeat=True,\n                                    dim=IMG_SIZES[fold], \n                                    batch_size = BATCH_SIZES[fold],\n                                    droprate=DROP_FREQ[fold], \n                                    dropct=DROP_CT[fold], \n                                    dropsize=DROP_SIZE[fold]), \n                        epochs=EPOCHS[fold], \n                        callbacks = [sv,get_lr_callback(BATCH_SIZES[fold])], \n                        steps_per_epoch=count_data_items(files_train)/BATCH_SIZES[fold]//REPLICAS,\n                        validation_data=get_dataset(files_valid,augment=False,shuffle=False,repeat=False,dim=IMG_SIZES[fold]), \n                        #class_weight = class_weight,\n                        verbose=VERBOSE\n                        )\n    \n    t2 = time.time()\n    time_lst.append(t2-t1)  \n    \n    print('Loading best model...')\n    model.load_weights('fold-%i.h5'%fold)\n    \n    # PREDICT OOF USING TTA\n    print('Predicting OOF with TTA...')\n    ds_valid = get_dataset(files_valid,labeled=False,return_image_names=False,augment=True,\n            repeat=True,shuffle=False,dim=IMG_SIZES[fold],batch_size=BATCH_SIZES[fold]*2,\n            droprate=DROP_FREQ[fold], dropct=DROP_CT[fold], dropsize=DROP_SIZE[fold])\n    ct_valid = count_data_items(files_valid); STEPS = TTA * ct_valid/BATCH_SIZES[fold]/2/REPLICAS\n    pred = model.predict(ds_valid,steps=STEPS,verbose=VERBOSE)[:TTA*ct_valid,] \n    oof_pred.append( np.mean(pred.reshape((ct_valid,TTA),order='F'),axis=1) )                 \n    \n    # GET OOF TARGETS AND NAMES\n    ds_valid = get_dataset(files_valid, augment=False, repeat=False, dim=IMG_SIZES[fold],\n            labeled=True, return_image_names=True)\n    oof_tar.append( np.array([target.numpy() for img, target in iter(ds_valid.unbatch())]) )\n    oof_folds.append( np.ones_like(oof_tar[-1],dtype='int8')*fold )\n    ds = get_dataset(files_valid, augment=False, repeat=False, dim=IMG_SIZES[fold],\n                labeled=False, return_image_names=True)\n    oof_names.append( np.array([img_name.numpy().decode(\"utf-8\") for img, img_name in iter(ds.unbatch())]))\n    \n    # PREDICT TEST USING TTA\n    if INFER_TEST:\n        print('Predicting Test with TTA...')\n        ds_test = get_dataset(files_test,labeled=False,return_image_names=False,augment=True,\n            repeat=True,shuffle=False,dim=IMG_SIZES[fold],batch_size=BATCH_SIZES[fold]*2,\n            droprate=DROP_FREQ[fold], dropct=DROP_CT[fold], dropsize=DROP_SIZE[fold])\n        ct_test = count_data_items(files_test); STEPS = TTA * ct_test/BATCH_SIZES[fold]/2/REPLICAS\n        pred = model.predict(ds_test,steps=STEPS,verbose=VERBOSE)[:TTA*ct_test,] \n        preds[:,0] += np.mean(pred.reshape((ct_test,TTA),order='F'),axis=1) * WGTS[fold]\n    \n    # REPORT RESULTS\n    auc = roc_auc_score(oof_tar[-1],oof_pred[-1])\n    oof_val.append(np.max( history.history['val_auc'] ))\n    print('#### EXPERIMENT %i OOF AUC without TTA = %.3f, with TTA = %.3f'%(fold+1,oof_val[-1],auc))\n    \n    # PLOT TRAINING\n    if DISPLAY_PLOT:\n        plt.figure(figsize=(15,5))\n        plt.plot(np.arange(EPOCHS[fold]),history.history['auc'],'-o',label='Train AUC',color='#ff7f0e')\n        plt.plot(np.arange(EPOCHS[fold]),history.history['val_auc'],'-o',label='Val AUC',color='#1f77b4')\n        x = np.argmax( history.history['val_auc'] ); y = np.max( history.history['val_auc'] )\n        xdist = plt.xlim()[1] - plt.xlim()[0]; ydist = plt.ylim()[1] - plt.ylim()[0]\n        plt.scatter(x,y,s=200,color='#1f77b4'); plt.text(x-0.03*xdist,y-0.13*ydist,'max auc\\n%.2f'%y,size=14)\n        plt.ylabel('AUC',size=14); plt.xlabel('Epoch',size=14)\n        plt.legend(loc=2)\n        plt2 = plt.gca().twinx()\n        plt2.plot(np.arange(EPOCHS[fold]),history.history['loss'],'-o',label='Train Loss',color='#2ca02c')\n        plt2.plot(np.arange(EPOCHS[fold]),history.history['val_loss'],'-o',label='Val Loss',color='#d62728')\n        x = np.argmin( history.history['val_loss'] ); y = np.min( history.history['val_loss'] )\n        ydist = plt.ylim()[1] - plt.ylim()[0]\n        plt.scatter(x,y,s=200,color='#d62728'); plt.text(x-0.03*xdist,y+0.05*ydist,'min loss',size=14)\n        plt.ylabel('Loss',size=14)\n        plt.title('%s - Image Size %i, inc2019=%i, inc2018=%i, M1=%i, M2=%i, M3=%i, M4=%i\\n\\\n        batch_size %i, dropout_freq=%.2f count=%i size=%.3f'%\n                (EFF_NETS[fold],IMG_SIZES[fold],INC2019[fold],INC2018[fold],M1[fold],M2[fold],M3[fold],\n                 M4[fold],BATCH_SIZES[fold]*REPLICAS,DROP_FREQ[fold],DROP_CT[fold],DROP_SIZE[fold]),size=18)\n        plt.legend(loc=3)\n        plt.show()  \n        \n    for metric_name in history.history.keys():\n        values = history.history[metric_name]\n        values_str = \"[\" + \", \".join([str(value) for value in values]) + \"]\"\n        print(f\"{metric_name} = {values_str}\")\n        \n    del model; z = gc.collect()\n\nprint(f\"Time: {time_lst}\")","metadata":{"_kg_hide-input":false,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history.history.keys()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loss = history.history['loss']\naccuracy = history.history['accuracy'] \nauc = history.history['auc']\nf1score = history.history['f1score']\nf1score_1 = history.history['f1score_1']\nf1score_0 = history.history['f1score_0']\nprecision = history.history['precision']\nprecision_1 = history.history['precision_1']\nprecision_0 = history.history['precision_0']\nrecall = history.history['recall']\nrecall_1 = history.history['recall_1']\nrecall_0 = history.history['recall_0']\ntp = history.history['tp']\ntn = history.history['tn']\nfp = history.history['fp']\nfn = history.history['fn']\n\nval_loss = history.history['val_loss']\nval_accuracy = history.history['val_accuracy']\nval_auc = history.history['val_auc']\nval_f1score = history.history['val_f1score']\nval_f1score_1 = history.history['val_f1score_1']\nval_f1score_0 = history.history['val_f1score_0']\nval_precision = history.history['val_precision']\nval_precision_1 = history.history['val_precision_1']\nval_precision_0 = history.history['val_precision_0']\nval_recall = history.history['val_recall']\nval_recall_1 = history.history['val_recall_1']\nval_recall_0 = history.history['val_recall_0']\nval_tp = history.history['val_tp']\nval_tn = history.history['val_tn']\nval_fp = history.history['val_fp']\nval_fn = history.history['val_fn']\n\nlr = history.history['lr'] ","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import seaborn as sns\nimport matplotlib.pyplot as plt\n\n# Establecer el estilo de seaborn\nsns.set_style(\"dark\")\n\n# Lista para el número de épocas\nepochs_list = list(range(1, EPOCHS[fold] + 1))\n\nfig, axs = plt.subplots(2, 2, figsize=(20, 12))\n\n# Función para añadir leyenda debajo\ndef add_legend_below(ax1, ax2):\n    lines = ax1.get_lines() + ax2.get_lines()\n    labels = [line.get_label() for line in lines]\n    ax1.legend(lines, labels, loc='upper center', bbox_to_anchor=(0.5, -0.2), ncol=2)\n\n# Gráfica arriba izquierda\nax1 = axs[0, 0]\nax1.set_xlabel('Epoch', size=14, labelpad=10)\nax1.set_ylabel('AUC', size=14, labelpad=10)\nline1, = ax1.plot(epochs_list, auc, '-', label='Trn AUC', color='#79b6e2', alpha=0.5, linewidth=3)\nline2, = ax1.plot(epochs_list, val_auc, '--', label='Val AUC', color='#F43545', alpha=0.5, linewidth=3)\nax1.tick_params(axis='both', labelcolor='black', colors='black', which='both')\nax1.set_xticks(epochs_list)\nax1.set_ylim(-0.1, 1.1)\nax2 = ax1.twinx()\nax2.set_ylabel('Loss', size=14, labelpad=10)\nline3, = ax2.plot(epochs_list, loss, '-', label='Trn Loss', color='#5FBB68', alpha=0.5, linewidth=3)\nline4, = ax2.plot(epochs_list, val_loss, '--', label='Val Loss', color='#F9A729', alpha=0.5, linewidth=3)\nax2.tick_params(axis='both', labelcolor='black', colors='black', which='both')\nax2.set_ylim(-0.1, 1.1)\nax1.set_title('AUC and Loss by Epoch', size=16, color='black')\n\nadd_legend_below(ax1, ax2)\n\n# Gráfica arriba derecha\nax1 = axs[0, 1]\nax1.set_xlabel('Epoch', size=14, labelpad=10)\nax1.set_ylabel('ACC', size=14, labelpad=10)\nline1, = ax1.plot(epochs_list, accuracy, '-', label='Trn ACC', color='#79b6e2', alpha=0.5, linewidth=3)\nline2, = ax1.plot(epochs_list, val_accuracy, '--', label='Val ACC', color='#F43545', alpha=0.5, linewidth=3)\nax1.tick_params(axis='both', labelcolor='black', colors='black', which='both')\nax1.set_xticks(epochs_list)\nax1.set_ylim(-0.1, 1.1)\nax2 = ax1.twinx()\nax2.set_ylabel('Loss', size=14, labelpad=10)\nline3, = ax2.plot(epochs_list, loss, '-', label='Trn Loss', color='#5FBB68', alpha=0.5, linewidth=3)\nline4, = ax2.plot(epochs_list, val_loss, '--', label='Val Loss', color='#F9A729', alpha=0.5, linewidth=3)\nax2.tick_params(axis='both', labelcolor='black', colors='black', which='both')\nax2.set_ylim(-0.1, 1.1)\nax1.set_title('ACC and Loss by Epoch', size=16, color='black')\n\nadd_legend_below(ax1, ax2)\n\n# Gráfica abajo izquierda\nax1 = axs[1, 0]\nax1.set_xlabel('Epoch', size=14, labelpad=10)\nax1.set_ylabel('F1-score', size=14, labelpad=10)\nline1, = ax1.plot(epochs_list, f1score, '-', label='Trn F1-score', color='#5FBB68', alpha=0.5, linewidth=3)\nline2, = ax1.plot(epochs_list, val_f1score, '--', label='Val F1-score', color='#F9A729', alpha=0.5, linewidth=3)\nax1.tick_params(axis='both', labelcolor='black', colors='black', which='both')\nax1.set_xticks(epochs_list)\nax1.set_ylim(-0.1, 1.1)\nax2 = ax1.twinx()\nax2.set_ylabel('Loss', size=14, labelpad=10)\nline3, = ax2.plot(epochs_list, loss, '-', label='Trn Loss', color='#79b6e2', alpha=0.5, linewidth=3)\nline4, = ax2.plot(epochs_list, val_loss, '--', label='Val Loss', color='#F43545', alpha=0.5, linewidth=3)\nax2.tick_params(axis='both', labelcolor='black', colors='black', which='both')\nax2.set_ylim(-0.1, 1.1)\nax1.set_title('F1-score and Loss by Epoch', size=16, color='black')\n\nadd_legend_below(ax1, ax2)\n\n# Gráfica abajo derecha\nax1 = axs[1, 1]\nax1.set_xlabel('Epoch', size=14, labelpad=10)\nax1.set_ylabel('F1-score Class 0', size=14, labelpad=10)\nline1, = ax1.plot(epochs_list, f1score_0, '-', label='Trn F1-score Class 0', color='#79b6e2', alpha=0.5, linewidth=3)\nline2, = ax1.plot(epochs_list, val_f1score_0, '--', label='Val F1-score Class 0', color='#F43545', alpha=0.5, linewidth=3)\nax1.tick_params(axis='both', labelcolor='black', colors='black', which='both')\nax1.set_xticks(epochs_list)\nax1.set_ylim(-0.1, 1.1)\nax2 = ax1.twinx()\nax2.set_ylabel('F1-score Class 1', size=14, labelpad=10)\nline3, = ax2.plot(epochs_list, f1score_1, '-', label='Trn F1-score Class 1', color='#5FBB68', alpha=0.5, linewidth=3)\nline4, = ax2.plot(epochs_list, val_f1score_1, '--', label='Val F1-score Class 1', color='#F9A729', alpha=0.5, linewidth=3)\nax2.tick_params(axis='both', labelcolor='black', colors='black', which='both')\nax2.set_ylim(-0.1, 1.1)\nax1.set_title('F1-score for Class 0 and 1 by Epoch', size=16, color='black')\n\nadd_legend_below(ax1, ax2)\n\n# Ajustar el espaciado vertical\nfig.tight_layout(pad=5.0, h_pad=3.0)\n\nplt.show()\n","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_f1score_max   = max(val_f1score)\nval_f1score_index = val_f1score.index(val_f1score_max)\n\nindex = val_f1score_index\n\nprint('Best f1score epoch:',index+1)\nprint('')\n\n# Sacar el valor del \"index\" hallado en el paso 2 de todas estas listas \nf1_auc = auc[index]\nf1_val_auc = val_auc[index]\n\nf1_loss = loss[index]\nf1_val_loss = val_loss[index]\n\nf1_accuracy = accuracy[index]\nf1_val_accuracy = val_accuracy[index]\n\nf1score = f1score[index]\nval_f1score = val_f1score[index]\n\nf1_precision = precision[index]\nf1_val_precision = val_precision[index]\n\nf1_recall = recall[index]\nf1_val_recall = val_recall[index]\n\nprint('METRICAS')\nprint('-------------------------------------')\nprint(round(f1_auc,4))\nprint(round(f1_val_auc,4))\nprint('')\nprint(round(f1_loss,4))\nprint(round(f1_val_loss,4))\nprint('')\nprint(round(f1_accuracy,4))\nprint(round(f1_val_accuracy,4))\nprint('')\nprint(round(f1score,4))\nprint(round(val_f1score,4))\nprint('')\nprint(round(f1_precision,4))\nprint(round(f1_val_precision,4))\nprint('')\nprint(round(f1_recall,4))\nprint(round(f1_val_recall,4))\nprint('-------------------------------------\\n')\n\nf1score_0 = f1score_0[index]\nval_f1score_0 = val_f1score_0[index]\n\nf1score_1 = f1score_1[index]\nval_f1score_1 = val_f1score_1[index]\n\nprint('F1SCORE POR CLASE')\nprint('-------------------------------------')\nprint(round(f1score_0,4))\nprint(round(val_f1score_0,4))\nprint(round(f1score_1,4))\nprint(round(val_f1score_1,4))\nprint('-------------------------------------\\n')\n\ntp = tp[index]\ntn = tn[index]\nfp = fp[index]\nfn = fn[index]\nval_tp = val_tp[index]\nval_tn = val_tn[index]\nval_fp = val_fp[index]\nval_fn = val_fn[index]\n\nprint('CONFUSSION MATRIX')\nprint('-------------------------------------')\nprint(round(tp))\nprint(round(val_tp))\nprint(round(tn))\nprint(round(val_tn))\nprint(round(fp))\nprint(round(val_fp))\nprint(round(fn))\nprint(round(val_fn))\nprint('-------------------------------------\\n')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## import numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom matplotlib.colors import ListedColormap\n\ntp = round(tp)\ntn = round(val_tp)\nfp = round(tn)\nfn = round(val_tn)\nval_tp = round(fp)\nval_tn = round(val_fp)\nval_fp = round(fn)\nval_fn = round(val_fn)\n\n# Crear matrices de confusión\nconf_matrix_trn = np.array([[tp, fp],\n                            [fn, tn]])\n\nconf_matrix_val = np.array([[val_tp, val_fp],\n                            [val_fn, val_tn]])\n\n# Crear un colormap con transparencia\nbase_cmap = sns.color_palette(\"Spectral\", as_cmap=True)\ncmap_alpha = base_cmap(np.arange(base_cmap.N))\ncmap_alpha[:, -1] = 0.6  \ncmap_alpha = ListedColormap(cmap_alpha)\n\ndef plot_confusion_matrices(cm_train, cm_val):\n    fig, axs = plt.subplots(1, 2, figsize=(14, 5))\n\n    sns.heatmap(cm_train, annot=True, cmap=cmap_alpha, ax=axs[0], annot_kws={\"size\": 18})\n    axs[0].set_title('Train Confusion Matrix', fontsize=20)\n    axs[0].set_xlabel('Predicted Values', fontsize=18)\n    axs[0].set_ylabel('Real Values', fontsize=18)\n    axs[0].tick_params(axis='both', which='major', labelsize=18)\n\n    sns.heatmap(cm_val, annot=True, cmap=cmap_alpha, ax=axs[1], vmin=0, annot_kws={\"size\": 18})\n    axs[1].set_title('Validation Confusion Matrix', fontsize=20)\n    axs[1].set_xlabel('Predicted Values', fontsize=18)\n    axs[1].set_ylabel('Real Values', fontsize=18)\n    axs[1].tick_params(axis='both', which='major', labelsize=18)\n\n    plt.tight_layout()\n    plt.show()\n\n# Plotear matrices de confusión\nplot_confusion_matrices(conf_matrix_trn, conf_matrix_val)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Calculate OOF Preds**\nThe OOF (out of fold) predictions are saved to disk. If you wish to ensemble multiple models, use the OOF to determine what are the best weights to blend your models with. Choose weights that maximize OOF CV score when used to blend OOF. Then use those same weights to blend your test predictions.","metadata":{}},{"cell_type":"code","source":"# COMPUTE OVERALL OOF AUC\noof = np.concatenate(oof_pred); true = np.concatenate(oof_tar);\nnames = np.concatenate(oof_names); folds = np.concatenate(oof_folds)\n\n# SAVE OOF TO DISK\ndf_oof = pd.DataFrame(dict(\n    image_name = names, target=true, pred = oof, fold=folds))\ndf_oof.to_csv('oof.csv',index=False)\ndf_oof.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Submit To Kaggle**\nIf we chose to predict by setting `INFER_TEST = True` above, then we create `submission.csv` here.","metadata":{}},{"cell_type":"code","source":"if INFER_TEST:\n    ds = get_dataset(files_test, augment=False, repeat=False, dim=IMG_SIZES[fold],\n                 labeled=False, return_image_names=True)\n\n    image_names = np.array([img_name.numpy().decode(\"utf-8\") \n                        for img, img_name in iter(ds.unbatch())])\n\n    submission = pd.DataFrame(dict(image_name=image_names, target=preds[:,0]))\n    submission = submission.sort_values('image_name') \n    submission.to_csv('submission.csv', index=False)\n    submission.head()\n\n    plt.hist(submission.target,bins=100)\n    plt.show()\nelse:\n    print('We did not predict test set')","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}