{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Thank to https://www.kaggle.com/c/siim-isic-melanoma-classification/discussion/160147\n\nI tried to ensemble use https://www.kaggle.com/truonghoang/stacking-ensemble-on-my-submissions?scriptVersionId=37760143 and got **LB 0.914**\n\nHope that I get some improves from this notebook\n\nGood luck to all !!!","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"!pip install -q efficientnet","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os, random\nimport re\nimport numpy as np\nimport pandas as pd\nimport math\n\nimport tensorflow as tf\nimport tensorflow.keras.layers as L\nfrom tensorflow.keras.models import Sequential, Model, load_model\nfrom tensorflow.keras import backend as K\n\nimport efficientnet.tfkeras as efn\n\nfrom kaggle_datasets import KaggleDatasets","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"try:\n    # TPU detection. No parameters necessary if TPU_NAME environment variable is\n    # set: this is always the case on Kaggle.\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    # Default distribution strategy in Tensorflow. Works on CPU and single GPU.\n    strategy = tf.distribute.get_strategy()\n\nprint(\"REPLICAS: \", strategy.num_replicas_in_sync)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# For tf.dataset\nAUTO = tf.data.experimental.AUTOTUNE\n\n# Data access\nGCS_PATH = KaggleDatasets().get_gcs_path('siim-isic-melanoma-classification')\n\n# Configuration\nEPOCHS = 12\nSEED = 2048\nBATCH_SIZE = 16 * strategy.num_replicas_in_sync","execution_count":null,"outputs":[]},{"metadata":{"trusted":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    random.seed(SEED)\n\nseed_everything(SEED)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub = pd.read_csv('/kaggle/input/siim-isic-melanoma-classification/sample_submission.csv')\ntrain = pd.read_csv('/kaggle/input/siim-isic-melanoma-classification/train.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def decode_image(image_data):\n    image = tf.image.decode_jpeg(image_data, channels=3)\n    image = tf.cast(image, tf.float32) / 255.0  # convert image to floats in [0, 1] range\n    image = tf.reshape(image, [IMAGE_SIZE, IMAGE_SIZE, 3]) # explicit size needed for TPU\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        \"target\": 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['target'], tf.int32)\n    return image, label # returns a dataset of (image, label) pairs\n\ndef read_unlabeled_tfrecord(example):\n    UNLABELED_TFREC_FORMAT = {\n        \"image\": tf.io.FixedLenFeature([], tf.string), # tf.string means bytestring\n        \"image_name\": tf.io.FixedLenFeature([], tf.string),  # shape [] means single element\n    }\n    example = tf.io.parse_single_example(example, UNLABELED_TFREC_FORMAT)\n    image = decode_image(example['image'])\n    idnum = example['image_name']\n    return image, idnum # returns a dataset of image(s)\n\ndef load_dataset(filenames, labeled=True, ordered=False):\n    # Read from TFRecords. For optimal performance, reading from multiple files at once and\n    # disregarding data order. Order does not matter since we will be shuffling the data anyway.\n\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    if labeled: \n        dataset = dataset.map(read_labeled_tfrecord, num_parallel_calls=AUTO)\n    else:\n        dataset = dataset.map(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    # data augmentation. Thanks to the dataset.prefetch(AUTO) statement in the next function (below),\n    # this happens essentially for free on TPU. Data pipeline code is executed on the \"CPU\" part\n    # of the TPU while the TPU itself is computing gradients.\n    image = tf.image.random_flip_left_right(image)\n    image = tf.image.random_flip_up_down(image)\n    return image, label   \n\ndef get_training_dataset(files):\n    dataset = load_dataset(files, 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(files, ordered=False):\n    dataset = load_dataset(files, labeled=True, ordered=ordered)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.cache()\n    dataset = dataset.prefetch(AUTO) # prefetch next batch while training (autotune prefetch buffer size)\n    return dataset\n\ndef get_test_dataset(filenames, labeled = False, aug=False, ordered = True):\n    dataset = load_dataset(filenames, labeled = labeled, ordered = ordered)\n    if aug:\n        dataset = dataset.map(data_augment, num_parallel_calls=AUTO)\n    dataset = dataset.batch(BATCH_SIZE)\n    # prefetch next batch while training (autotune prefetch buffer size)\n    dataset = dataset.prefetch(AUTO) \n    return dataset\n\ndef count_data_items(filenames):\n    n = [int(re.compile(r\"-([0-9]*)\\.\").search(filename).group(1)) for filename in filenames]\n    return np.sum(n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def build_lrfn(lr_start=0.00001, lr_max=0.0001, \n               lr_min=0.000001, lr_rampup_epochs=20, \n               lr_sustain_epochs=0, lr_exp_decay=.8):\n    lr_max = lr_max * strategy.num_replicas_in_sync\n\n    def lrfn(epoch):\n        if epoch < lr_rampup_epochs:\n            lr = (lr_max - lr_start) / lr_rampup_epochs * epoch + lr_start\n        elif epoch < lr_rampup_epochs + lr_sustain_epochs:\n            lr = lr_max\n        else:\n            lr = (lr_max - lr_min) * lr_exp_decay**(epoch - lr_rampup_epochs - lr_sustain_epochs) + lr_min\n        return lr\n    \n    return lrfn","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"GCS_PATH_SELECT = {\n    '256': KaggleDatasets().get_gcs_path('melanoma-256x256'),\n    '384': KaggleDatasets().get_gcs_path('melanoma-384x384'),\n    '512': KaggleDatasets().get_gcs_path('melanoma-512x512'),\n    '768': KaggleDatasets().get_gcs_path('melanoma-768x768'),\n    '512x': KaggleDatasets().get_gcs_path('512x512-melanoma-tfrecords-70k-images'),\n}\n\nlr_schedule = tf.keras.callbacks.LearningRateScheduler(build_lrfn(), verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"probs = []\nprobs_tta = []\n\nfor size, path in GCS_PATH_SELECT.items():\n    if size == '512x':\n        IMAGE_SIZE = 512\n    else:\n        IMAGE_SIZE = int(size)\n    TRAINING_FILENAMES = tf.io.gfile.glob(path + '/train*.tfrec')\n    STEPS_PER_EPOCH = count_data_items(TRAINING_FILENAMES) / BATCH_SIZE\n\n    with strategy.scope():\n        base_model = efn.EfficientNetB3(weights='imagenet', include_top=False, input_shape=(None, None, 3))\n        x = base_model.output\n        x = L.GlobalAveragePooling2D()(x)\n        x = L.Dense(1, activation='sigmoid')(x)\n\n        model = Model(inputs=base_model.input, outputs=x)\n\n        model.compile(\n            optimizer='adam',\n            loss = 'binary_crossentropy',\n            metrics=['accuracy', tf.keras.metrics.AUC()]\n        )\n    \n    model.fit(\n        get_training_dataset(TRAINING_FILENAMES), \n        epochs=EPOCHS, \n        callbacks=[lr_schedule],\n        steps_per_epoch=STEPS_PER_EPOCH\n    )\n\n    model.save(\"model_\" + size + \".h5\")\n\n    print('Generating submission.csv file...')\n    TEST_FILENAMES = tf.io.gfile.glob(path + '/test*.tfrec')\n    test_ds = get_test_dataset(TEST_FILENAMES, ordered=True)\n    test_images_ds = test_ds.map(lambda image, image_name: image)\n    prob = model.predict(test_images_ds)\n\n    test_ids_ds = test_ds.map(lambda image, image_name: image_name).unbatch()\n    test_ids = next(iter(test_ids_ds.batch(count_data_items(TEST_FILENAMES)))).numpy().astype('U') # all in one batch\n    pred_df = pd.DataFrame({'image_name': test_ids, 'target': prob[:, 0]})\n    sub.drop('target', inplace = True, axis = 1)\n    sub = sub.merge(pred_df, on='image_name')\n    sub.to_csv('submission_' + size + '.csv', index = False)\n    probs.append(sub['target'])\n    \n    K.clear_session()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub['target'] = np.mean(probs, 0)\nsub.to_csv('submission.csv', index=False)","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}