{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Melanoma Classification\n\nKaggle Competition Page: www.kaggle.com/c/siim-isic-melanoma-classification/overview\n\n\n## What is Melanoma?\nMelanoma, the most severe type of skin cancer, develops in the cells (melanocytes) that produce melanin — the pigment that gives your skin its color. Melanoma can also form in your eyes and, rarely, inside your body, such as in your nose or throat.\n\nThe exact cause of all melanomas isn't clear, but exposure to ultraviolet (UV) radiation from sunlight or tanning lamps and beds increases your risk of developing melanoma.\n\nThe risk of melanoma seems to be increasing in people under 40, especially women. Knowing the warning signs of skin cancer can help ensure that cancerous changes are detected and treated before the cancer has spread. We can treat melanoma successfully if it is detected early.","metadata":{"id":"XvBDTao8djYJ"}},{"cell_type":"markdown","source":"<img src=\"https://github.com/SaschaMet/melanoma-classification/blob/master/images/melanoma.jpg?raw=1\" alt=\"Drawing\" style=\"width: 600px;\"/>","metadata":{"id":"PQIr6OLjdjYs"}},{"cell_type":"markdown","source":"## Symptoms & Diagnosis\nMelanomas can develop anywhere on your body. They most often develop in areas with exposure to the sun, such as your back, legs, arms, and face.\nMelanomas can also occur in areas that don't receive much sun exposure, such as the soles of your feet, palms of your hands, and fingernail beds. These hidden melanomas are more common in people with darker skin.\n\nTo help you identify characteristics of melanomas or other skin cancers, think of the letters ABCDE:\n- A is for asymmetrical shape. Look for moles with irregular shapes, such as two very different-looking halves.\n- B is for irregular border. Look for moles with rough, notched, or scalloped edges — characteristics of melanomas.\n- C is for color changes. Look for growths that have many colors or an uneven distribution of color.\n- D is for diameter. Look for new growth in a mole larger than 1/4 inch (about 6 millimeters).\n- E is for evolving. Look for changes over time, such as a mole that grows in size or changes color or shape.\n","metadata":{"id":"wR5V4LGwdjYs"}},{"cell_type":"markdown","source":"![ABCDE Melanoma](https://github.com/SaschaMet/melanoma-classification/blob/master/images/abcde-melanoma.jpg?raw=1)\n\nSource: https://www.health.harvard.edu/cancer/melanoma-overview","metadata":{"id":"3_Vl79qwdjYw"}},{"cell_type":"markdown","source":"The facts about Melanoma:\n- Melanoma is the most severe form of skin cancer\n- It makes up 2% of skin cancers but is responsible for 75% of skin cancer deaths\n- Australia and New Zealand have the highest melanoma rates in the world\n- 1 in 17 Australians will be diagnosed with melanoma before the age of 85\n- More than 90% of melanoma can be successfully treated with surgery if detected early\n\nSource: https://melanomapatients.org.au/about-melanoma/melanoma-facts/","metadata":{"id":"Bm8mD1YSdjYx"}},{"cell_type":"markdown","source":"<img src=\"https://github.com/SaschaMet/melanoma-classification/blob/master/images/melanoma-impact.jpg?raw=1\" alt=\"Drawing\" style=\"width: 600px;\"/>\n\nSource: https://impactmelanoma.org/wp-content/uploads/2018/11/Standard-Infographic_0.jpg","metadata":{"id":"si5Twho8djYx"}},{"cell_type":"markdown","source":"## Setup","metadata":{"id":"e-AFobcxdjYx"}},{"cell_type":"code","source":"import os\nimport json\nimport random\nimport warnings\nimport itertools\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nimport tensorflow as tf\nfrom pathlib import Path\nfrom tensorflow import keras\nimport matplotlib.pyplot as plt\nfrom keras.optimizers import Adam, RMSprop\nfrom datetime import datetime, date\nfrom tensorflow.keras import layers\nimport tensorflow.keras.backend as K\nfrom keras.applications.vgg16 import VGG16\nfrom pandas_profiling import ProfileReport\nfrom sklearn.model_selection import train_test_split\nfrom tensorflow.keras.models import Sequential, Model\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import ModelCheckpoint, EarlyStopping\nfrom sklearn.metrics import roc_curve, auc, precision_recall_curve, plot_precision_recall_curve, confusion_matrix","metadata":{"id":"E06dG0gndjYy","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"SEED = 1\nEPOCHS = 100\nBATCH_SIZE = 32\nNUM_CLASSES = 2\nVERBOSE_LEVEL = 1\nSAVE_OUTPUT = True\nIMG_SIZE = (224, 224)\nINPUT_SHAPE = (224, 224, 3)\n\nCWD = os.getcwd()\nwarnings.filterwarnings('ignore')\n","metadata":{"id":"JnvR9SrjdjYy","outputId":"1bc1ff6f-760d-4cff-bfd8-9885ae28ebb7","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BASE_PATH = '/kaggle/input/siim-isic-melanoma-classification'\nPATH_TO_IMAGES = '/kaggle/input/siim-isic-melanoma-classification/jpeg' \nIMAGE_TYPE = \".jpg\"","metadata":{"id":"7QrMRrKjdjYz","outputId":"10df2198-94f3-462f-e656-f1d18fe28bd3","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Loading the data","metadata":{"id":"E7Vq9jDVdjY3"}},{"cell_type":"code","source":"\"\"\" Helper function to validate the image paths\n\n    Parameters:\n        file_path (string): Path to the image \n\n    Returns:\n        The file path if the file exists, otherwise false if the file does not exist\n\n\"\"\"\ndef check_image(file_path):\n    img_file = Path(file_path)\n    if img_file.is_file():\n        return file_path\n    return False","metadata":{"id":"mvQWw7NtdjY3","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\" Helper function to get the train dataset\n\"\"\"\ndef get_train_data():\n    # read the data from the train.csv file\n    train = pd.read_csv(os.path.join(BASE_PATH, 'train.csv'))\n    # add the image_path to the train set\n    train['image_path'] = train['image_name'].apply(lambda x: PATH_TO_IMAGES + \"/train/\" + x + IMAGE_TYPE)\n    # check if the we have an image \n    train['image_path'] = train.apply(lambda row : check_image(row['image_path']), axis = 1)\n    # if we do not have an image we will not include the data\n    train = train[train['image_path'] != False]\n    print(\"valid rows in train\", train.shape[0])\n    return train\n\n","metadata":{"id":"kA5weeYJdjY4","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = get_train_data()","metadata":{"id":"kdk3Ha_rdjY4","outputId":"5ccae5ce-4f94-4c08-ab80-b69aee63b62e","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.dtypes","metadata":{"id":"SAukZCdpdjY4","outputId":"60aea1cf-1c86-403f-ea29-b727710daea1","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Train Dataset:\n- image name: the filename for the specific image\n- patient_id: unique patient id\n- sex: gender of the patient\n- age_approx: age of the patient\n- anatom_site_general_challenge: location of the scan site\n- diagnosis: information about the diagnosis\n- benign_malignant: indicates if the scan result is malignant or benign\n- target: 0 for benign and 1 for malignant\n- image_path: path to the image","metadata":{"id":"-xS3V7IedjY5"}},{"cell_type":"markdown","source":"### Check for missing values","metadata":{"id":"ezInl9iUdjZu"}},{"cell_type":"code","source":"\"\"\" Helper function check a dataframe for missing values\n\n    Parameters:\n        df (dataframe): The dataframe to check\n\n    Returns:\n        A dataframe with the number of missing and zero values for each column in percent\n\n\"\"\"\ndef check_for_missing_and_null(df):\n    null_df = pd.DataFrame({'columns': df.columns, \n                            'percent_null': df.isnull().sum() * 100 / len(df), \n                            'percent_zero': df.isin([0]).sum() * 100 / len(df),\n                            'total_zero': df.isnull().sum() * 100 / len(df) + df.isin([0]).sum() * 100 / len(df),\n                           })\n    return null_df\n\ncheck_for_missing_and_null(train)","metadata":{"id":"C7CSiXIbdjZu","outputId":"fe3c2689-44e2-445b-9ed9-bd2fd581c09c","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There is a small portion of missing values for age and sex, as well as for the anatom_site_general_challenge column. \n\nThe target column consists of 98 % zero values. This means we have a highly imbalanced dataset.","metadata":{"id":"5yaIn2dQdjZu"}},{"cell_type":"markdown","source":"### Removing missing values\n\nTo do the EDA, I will remove the dataset's missing values because we will not lose much information. Later, when we prepare the dataset for training, I will add these missing values again.","metadata":{"id":"gCB_FFkYdjZx"}},{"cell_type":"code","source":"train = train.dropna()","metadata":{"id":"TuszpnbgdjZy","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Target distribution","metadata":{"id":"Dpro3gGYdjZy"}},{"cell_type":"code","source":"plt.figure(figsize = (8,6))\nx = plt.bar([\"Melanoma\",\"Benign\"],[len(train[train.target==1]), len(train[train.target==0])])","metadata":{"id":"UowDHn02djZy","outputId":"fd60d213-4ecf-4df7-c646-2d7f91273f60","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"benign_cases = train[train.target == 0]\nmelanoma_cases = train[train.target == 1]\n\nprint(\"Benign Cases\", len(benign_cases))\nprint(\"Melanoma Cases\", len(melanoma_cases))\nprint(\" \")\nprint(\"There are only\", len(melanoma_cases), \"malignant cases in the dataset. This is very important to know, because this has implications on how to perpare the dataset for training the machine learning model.\")","metadata":{"id":"LnZ0oqxvgKL8","outputId":"dc6ceac8-bbe9-4418-cb95-7aa56c1c137f","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Gender distribution","metadata":{"id":"65LkV7UQdjZz"}},{"cell_type":"code","source":"female = train[train.sex == \"female\"]\nmale = train[train.sex == \"male\"]\nplt.figure(figsize = (8,6))\nx = plt.bar(\n    [\"Female\",\"Male\"],\n    [len(female), len(male)]\n)\nprint('There are', len(female), 'female patients in the dataset and', len(male), 'male patients.')","metadata":{"id":"bsBh6hYpdjZz","outputId":"d5d968d4-554e-4c97-85af-b6e4bf631cb8","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"benign_cases_female = train[train.target==0][train.sex == \"female\"]\nmalignant_cases_female = train[train.target==1][train.sex == \"female\"]\n\nbenign_cases_male = train[train.target==0][train.sex == \"male\"]\nmalignant_cases_male = train[train.target==1][train.sex == \"male\"]\n\nplt.figure(figsize = (8,6))\nx = plt.bar(\n    [\"Benign & Female\",\"Malignant & Female\", \"Benign & Male\",\"Malignant & Male\"],\n    [len(benign_cases_female), len(malignant_cases_female), len(benign_cases_male), len(malignant_cases_male)]\n)","metadata":{"id":"A-pyTo-R0_fz","outputId":"7b8e46e2-b651-4235-af94-e0be8e2e9b13","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"grouped_df_by_sex = train.groupby(['target','sex'])['benign_malignant'].count().to_frame().reset_index()\ngrouped_df_by_sex","metadata":{"id":"prEJvzLwdjZ1","outputId":"ab58980f-18ca-42f1-a152-275dce1e745b","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"f_m = train[train.target == 1][train.sex == \"female\"]\nm_m = train[train.target == 1][train.sex == \"male\"]\n\nprint(\"There are\", len(m_m) ,\"malignant male cases in the dataset compared to\", len(f_m) ,\"female cases.\")","metadata":{"id":"Su2PnvF6ixFI","outputId":"9ac244ed-1308-4b3b-a8c4-9029150205e5","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Age distribution","metadata":{"id":"noATRLdYdjZ7"}},{"cell_type":"code","source":"# create ten age bins, from 0 to 100\nage_bins = np.arange(0, 100, 10)\n\n\"\"\" Helper function to return the age bin for a specific age\n\n    Parameters:\n        age (int)\n\n    Returns:\n        age bin (int)\n\"\"\"\ndef add_age_bin(age):\n    for idx, val in enumerate(age_bins):\n        if age < val:\n            return idx\n\n# add the age bins to the train df\ntrain['age_bin'] = train.apply(lambda row : add_age_bin(row['age_approx']), axis = 1)","metadata":{"id":"VJ947xNOdjZ7","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(8,6))\nplt.hist( train.age_bin, bins = 20)\nplt.show()","metadata":{"id":"eDLo_EZYdjZ7","outputId":"1de61ad8-6271-4d42-b302-1c21ed924f9f","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"The mean age of a patient in the dataset is\", round(np.mean(train.age_approx, 0)))","metadata":{"id":"_nkOM4msdjZ8","outputId":"0748bc5a-ba7e-49b7-a9d2-96532f8d4330","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(8,6))\nplt.hist( train[train.target==1].age_bin, bins = 20)\nplt.show()","metadata":{"id":"836oCQZodjZ8","outputId":"95909d95-a70a-4c8c-9ba0-9feeaf6a9b19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The age distributions follows a normal distribution. If we look only at the malignant cases however we can see, that the distribution seems to be wider. ","metadata":{"id":"iXKLO5frdjZ9"}},{"cell_type":"code","source":"def get_ratio_by_age_bin(age_bin):\n    total = train[train['age_bin'] == age_bin]\n    malignant = train[train['age_bin'] == age_bin][train['target'] == 1]\n    return round((len(malignant) / len(total)) * 100, 2)\n    \nfor age_bin in [2,3,4,5,6,7,8]:\n    print(\"Ratio malignant / total cases for age_bin\", age_bin, \"=\" , get_ratio_by_age_bin(age_bin))\n","metadata":{"id":"7UBG-TCVdjZ9","outputId":"30240b1d-8462-4ea3-a744-92b065f9dd59","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There are indeed more malignant cases at the ends of the age distribution.","metadata":{"id":"6H3jKX8sdjZ-"}},{"cell_type":"markdown","source":"### Anatom Site General Challenge distribution","metadata":{"id":"QIsSW6Z7djZ-"}},{"cell_type":"code","source":"anatom_site = list(train.anatom_site_general_challenge.unique())\nanatom_site = [x for x in anatom_site if str(x) != 'nan']\n\nanatom_site_value_counts = []\nfor x in anatom_site:\n    y = train[train['anatom_site_general_challenge'] == x]\n    anatom_site_value_counts.append(len(y))\n\ny_pos = np.arange(len(anatom_site))\nplt.figure(figsize=(8,6))\nplt.bar(y_pos, anatom_site_value_counts, align='center')\nplt.xticks(y_pos, anatom_site)\nplt.ylabel('# of rows')\nplt.title('Anatom Site General Challenge')\n\nplt.show()","metadata":{"id":"ubTnh6V-djZ-","outputId":"87831388-f508-444d-b098-e71fb2600f30","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Most often a lesion was found in the torso area, followed by the lower and upper extremity.","metadata":{}},{"cell_type":"markdown","source":"### Diagnosis distribution","metadata":{"id":"8bR7V1xWdjZ_"}},{"cell_type":"code","source":"diagnosis = list(train.diagnosis.unique())\ndiagnosis = [x for x in diagnosis if str(x) != 'unknown']\n\ndiagnosis_value_counts = []\nfor x in diagnosis:\n    y = train[train['diagnosis'] == x]\n    diagnosis_value_counts.append(len(y))","metadata":{"id":"hdhrURJ0djZ_","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels = diagnosis\nsizes = diagnosis_value_counts\nplt.figure(figsize=(8,6))\npatches, texts = plt.pie(sizes, shadow=True, startangle=90)\nplt.legend(patches, labels, loc=\"best\")\nplt.axis('equal')\nplt.show()","metadata":{"id":"CDNIXujZdjZ_","outputId":"c1b0fe99-7314-4b38-fa86-0b18f64c0399","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The main finding in the dataset is \"nevus\". Nevus is a nonspecific medical term for a visible, circumscribed, chronic lesion of the skin (e.g. a \"birthmark\"). The second most common finding was melanoma.\n\n\nSource: https://en.wikipedia.org/wiki/Nevus","metadata":{"id":"FW-F5CQIdjZ_"}},{"cell_type":"markdown","source":"## Images from the dataset","metadata":{"id":"XrP2muWNdjZ_"}},{"cell_type":"code","source":"plt.figure(figsize=(16, 16))\nfor i in range(9):\n    plt.subplot(3, 3, i + 1)\n    img_path = train.iloc[i].image_path\n    img = plt.imread(img_path)\n    plt.imshow(img, cmap='gray')\n    plt.axis('off')\nplt.tight_layout()   ","metadata":{"id":"MBHUu1ITdjaA","outputId":"b9f73fd6-4a13-48ec-d0a5-c50bb5576bf2","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data preparation\n\nBecause we removed some values from the dataset for the EDA, we load the train and test set again.","metadata":{"id":"NTOLu_PxdjaE"}},{"cell_type":"code","source":"train = get_train_data()","metadata":{"id":"DP1lSkATdjaE","outputId":"f2ea5e6c-9ce5-4ced-d522-883f5f7aa5b3","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# getting dummy variables for gender\nsex_dummies = pd.get_dummies(train['sex'], prefix='sex', dtype=\"int\")\ntrain = pd.concat([train, sex_dummies], axis=1)\n\n# getting dummy variables for anatom_site_general_challenge\nanatom_dummies = pd.get_dummies(train['anatom_site_general_challenge'], prefix='anatom', dtype=\"int\")\ntrain = pd.concat([train, anatom_dummies], axis=1)\n\n# getting dummy variables for target column\n#target_dummies = pd.get_dummies(train['target'], prefix='target', dtype=\"int\")\n#train = pd.concat([train, target_dummies], axis=1)\n\n# dropping not useful columns\ntrain.drop(['sex','diagnosis','benign_malignant','anatom_site_general_challenge'], axis=1, inplace=True)\n\n# replace missing age values wiht the mean age\ntrain['age_approx'] = train['age_approx'].fillna(int(np.mean(train['age_approx'])))\n\n# convert age to int\ntrain['age_approx'] = train['age_approx'].astype('int')\n\nprint(\"rows in train\", train.shape[0])","metadata":{"id":"tG54suCTdjaF","outputId":"ad62324d-efa0-4ed9-9813-f9b1edc473ab","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.dtypes","metadata":{"id":"jBNW9t1MdjaI","outputId":"b18733b1-ae80-4491-bcc9-9f386f3652eb","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Balance the dataset\n\nBecause we have a highly imbalanced dataset we need to balance it.","metadata":{"id":"bamRcA-xdjaJ"}},{"cell_type":"code","source":"# 1 means 50 / 50 => equal amount of positive and negative cases in Training\n# 4 = 20%; 8 = ~11%; 12 = ~8%\nbalance = 1\np_inds = train[train.target == 1].index.tolist()\nnp_inds = train[train.target == 0].index.tolist()\n\nnp_sample = random.sample(np_inds, balance * len(p_inds))\ntrain = train.loc[p_inds + np_sample]\nprint(\"Samples in train\", train['target'].sum()/len(train))\nprint(\"Remaining rows in train set\", len(train))","metadata":{"id":"3Ayqx5OTdjaJ","outputId":"4deb5bc6-f858-4c91-fb14-9c33f3a05d66","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\" Helper function to create a train and a validation dataset\n\n    Parameters:\n    df (dataframe): The dataframe to split\n    test_size (int): Size of the validation set\n    classToPredict: The target column\n\n    Returns:\n    train_data (dataframe)\n    val_data (dataframe)\n\"\"\"\ndef create_splits(df, test_size, classToPredict):\n    train_data, val_data = train_test_split(df,  test_size = test_size, random_state = 1, stratify = df[classToPredict])\n    train_data, test_data = train_test_split(df,  test_size = 0.16, random_state = 1, stratify = df[classToPredict])\n    return train_data, val_data, test_data","metadata":{"id":"bIdtddiJdjaL","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\" Helper function to plot the history of a tensorflow model\n\n    Parameters:\n        history (history object): The history from a tf model\n        timestamp (string): The timestamp of the function execution\n\n    Returns:\n        Null\n\"\"\"\ndef save_history(history, timestamp):\n    f = plt.figure()\n    f.set_figwidth(15)\n\n    f.add_subplot(1, 2, 1)\n    plt.plot(history['val_loss'], label='val loss')\n    plt.plot(history['loss'], label='train loss')\n    plt.legend()\n    plt.title(\"Modell Loss\")\n\n    f.add_subplot(1, 2, 2)\n    plt.plot(history['val_accuracy'], label='val accuracy')\n    plt.plot(history['accuracy'], label='train accuracy')\n    plt.legend()\n    plt.title(\"Modell Accuracy\")\n","metadata":{"id":"wdrJ0CbSdjaN","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\" Helper function to plot the auc curve\n\n    Parameters:\n        t_y (array): True binary labels\n        p_y (array): Target scores\n\n    Returns:\n        Null\n\"\"\"\ndef plot_auc(t_y, p_y):\n    fpr, tpr, thresholds = roc_curve(t_y, p_y, pos_label=1)\n    fig, c_ax = plt.subplots(1,1, figsize = (8, 8))\n    c_ax.plot(fpr, tpr, label = '%s (AUC:%0.2f)'  % ('Target', auc(fpr, tpr)))\n    c_ax.plot([0, 1], [0, 1], color='navy', lw=1, linestyle='--')\n    c_ax.legend()\n    c_ax.set_xlabel('False Positive Rate')\n    c_ax.set_ylabel('True Positive Rate')","metadata":{"id":"VUFWVx4hdjaN","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data augmentation","metadata":{}},{"cell_type":"code","source":"\"\"\" Factory function to create a training image data generator\n\nParameters:\n    df (dataframe): Training dataframe \n\nReturns:\n    Image Data Generator function\n\"\"\"\ndef get_training_gen(df):\n    ## prepare images for training\n    train_idg = ImageDataGenerator(\n        rescale = 1 / 255.0,\n        horizontal_flip = True, \n        vertical_flip = True, \n        height_shift_range = 0.15, \n        width_shift_range = 0.15,\n        shear_range=0.15,\n        rotation_range = 90, \n        zoom_range = 0.20,\n        fill_mode='nearest'\n    )\n\n    train_gen = train_idg.flow_from_dataframe(\n        seed=SEED,\n        dataframe=df,\n        directory=None,\n        x_col='image_path',\n        y_col='target',\n        class_mode='raw',\n        shuffle=True,\n        target_size=IMG_SIZE,\n        #batch_size=BATCH_SIZE,\n        validate_filenames = False\n    )\n\n    return train_gen","metadata":{"id":"0DkseDQSdjaN","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\" Factory function to create a validation image data generator\n\nParameters:\n    df (dataframe): Validation dataframe \n\nReturns:\n    Image Data Generator function\n\"\"\"\ndef get_validation_gen(df):\n    ## prepare images for validation\n    val_idg = ImageDataGenerator(rescale=1. / 255.0)\n    val_gen = val_idg.flow_from_dataframe(\n        seed=SEED,\n        dataframe=df,\n        directory=None,\n        x_col='image_path',\n        y_col='target',\n        class_mode='raw',\n        shuffle=False,\n        target_size=IMG_SIZE,\n        #batch_size=BATCH_SIZE,\n        validate_filenames = False\n    )\n\n    return val_gen","metadata":{"id":"IoYfVIj1djaN","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\" Factory function to create a test image data generator\n\nParameters:\n    df (dataframe): Test dataframe \n\nReturns:\n    Image Data Generator function\n\"\"\"\ndef get_test_gen(df):\n    ## prepare images for validation\n    test_idg = ImageDataGenerator(rescale=1. / 255.0)\n    test_gen = test_idg.flow_from_dataframe(\n        seed=SEED,\n        dataframe=df,\n        directory=None,\n        x_col='image_path',\n        y_col='target',\n        class_mode='raw',\n        shuffle=False,\n        target_size=IMG_SIZE,\n        #batch_size=BATCH_SIZE,\n        validate_filenames = False\n    )\n\n    return test_gen","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Images returned from the ImageDataGenerator","metadata":{"id":"Y_EECRkFdjaN"}},{"cell_type":"code","source":"train_gen = get_training_gen(train)","metadata":{"tags":[],"id":"GeRvqJ-qdjaO","outputId":"08f1a46e-540f-46b4-de53-07d7fe435219","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The Image Data Generator function returns these transformed images.\n\nThe Keras ImageDataGenerator class works by:\n- Accepting a batch of images used for training.\n- Taking this batch and applying a series of random transformations to each image in the batch (including random rotation, resizing, shearing, etc.).\n- Replacing and returning the original batch with the new, randomly transformed batch.\n\nSource: https://www.pyimagesearch.com/2019/07/08/keras-imagedatagenerator-and-data-augmentation/","metadata":{}},{"cell_type":"markdown","source":"## Transfer Learning\n\nConventional machine learning and deep learning algorithms, so far, have been traditionally designed to work in isolation. These algorithms are trained to solve specific tasks. The models have to be rebuilt from scratch once the feature-space distribution changes. Transfer learning is the idea of overcoming the isolated learning paradigm and utilizing knowledge acquired for one task to solve related ones. ","metadata":{"id":"67EjcGWPdjaO"}},{"cell_type":"markdown","source":"\n![Transfer Learning](https://github.com/SaschaMet/melanoma-classification/blob/master/images/transfer-learning.png?raw=1)\n ","metadata":{"id":"fkqvRu-0djaO"}},{"cell_type":"markdown","source":"Traditional learning is isolated and occurs purely based on specific tasks, datasets, and training separate isolated models on them. No knowledge is retained, which can be transferred from one model to another. In transfer learning, you can leverage knowledge (features, weights, etc.) from previously trained models for training newer models and even tackle problems like having less data for the more recent task.","metadata":{"id":"g-vCqePSD4iI"}},{"cell_type":"markdown","source":"**Fine Tuning Off-the-shelf Pre-trained Models**\n\nThis is a more involved technique, where we do not just replace the final layer (for classification/regression), but we also selectively retrain some of the previous layers. \n\n\n![Transfer Learning](https://miro.medium.com/max/700/1*BBZGHtI_vhDBeqsIbgMj1w.png)\n \n\n","metadata":{"id":"oLBLoI_mEp3q"}},{"cell_type":"markdown","source":"Source: https://towardsdatascience.com/a-comprehensive-hands-on-guide-to-transfer-learning-with-real-world-applications-in-deep-learning-212bf3b2f27a","metadata":{"id":"TXTzfRx8EmSV"}},{"cell_type":"code","source":"\"\"\" Helper function which returns a VGG16 model\n\"\"\"\nfrom keras.preprocessing import image\nfrom keras.applications.vgg16 import preprocess_input\nimport numpy as np\n\ndef load_pretrained_model():\n    base_model = VGG16(\n        input_shape=INPUT_SHAPE,\n        include_top=False,\n        weights='imagenet'\n    )\n\n    return base_model\n","metadata":{"id":"5aWRaNHUdjaO","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = load_pretrained_model()\nmodel.summary()","metadata":{"id":"4tiogvTddjaO","outputId":"6e60b24b-a310-44b6-d066-eac8e234a19f","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"last_layer_shape = model.layers[-1].output_shape\nlast_layer_shape","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create a training and validation dataset from the train df\ntrain_df, val_df, test_df = create_splits(train, 0.2, 'target')\n\nprint(\"rows in train_df\", train_df.shape[0])\nprint(\"rows in val_df\", val_df.shape[0])\nprint(\"rows in test_df\", test_df.shape[0])\n\n# call the generator functions\ntrain_gen = get_training_gen(train_df)\nval_gen = get_validation_gen(val_df)\ntest_gen = get_test_gen(test_df)\nvalX, valY = val_gen.next()","metadata":{"id":"zxj3bFJPdjaR","outputId":"fbc3976a-1fbb-40fc-90a2-dd521dc63d7f","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_len = train_df.shape[0]\nval_len = val_df.shape[0]\ntest_len = test_df.shape[0]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\" Helper function for feature extraction\n\"\"\"\n\ndef extract_features(df):\n\n    features = []\n    labels = []\n    for img_path in df['image_path']:\n        img = image.load_img(img_path, target_size=INPUT_SHAPE)\n        img_data = image.img_to_array(img)\n        img_data = np.expand_dims(img_data, axis=0)\n        img_data = preprocess_input(img_data)\n\n        feature = model.predict(img_data)\n        feature_np = np.array(feature)\n        features.append(feature_np.flatten())\n        labels.append(df.loc[df['image_path'] == img_path, 'target'].iloc[0])\n        \n    feature_list_np = np.array(features)\n    labels_list_np = np.array(labels)\n    \n    return feature_list_np, labels_list_np","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_features, train_labels = extract_features(train_df)\nval_features, val_labels = extract_features(val_df)\ntest_features, test_labels = extract_features(test_df)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train, y_train = train_features, train_labels\nX_val, y_val = val_features, val_labels\nX_test, y_test = test_features, test_labels","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# SVM","metadata":{}},{"cell_type":"code","source":"from sklearn.svm import SVC\nclassifier_SVM = SVC(kernel = 'rbf', random_state = 0)\nclassifier_SVM.fit(X_train, y_train)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_acc_SVM = classifier_SVM.score(X_train, y_train)\nval_acc_SVM = classifier_SVM.score(X_val, y_val)\ntest_acc_SVM = classifier_SVM.score(X_test, y_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(train_acc_SVM)\nprint(val_acc_SVM)\nprint(test_acc_SVM)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_SVM = classifier_SVM.predict(X_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn import metrics\ndef print_performance_metrics(test_labels,predict):\n    print('Accuracy:', np.round(metrics.accuracy_score(test_labels, predict),4))\n    print('ROC Area:', np.round(metrics.roc_auc_score(test_labels, predict),4))\n    print('Precision:', np.round(metrics.precision_score(test_labels, predict,average='weighted'),4))\n    print('Recall:', np.round(metrics.recall_score(test_labels, predict,\n                                               average='weighted'),4))\n    print('F1 Score:', np.round(metrics.f1_score(test_labels, predict,\n                                               average='weighted'),4))\n    print('Cohen Kappa Score:', np.round(metrics.cohen_kappa_score(test_labels, predict),4))\n    print('Matthews Corrcoef:', np.round(metrics.matthews_corrcoef(test_labels, predict),4)) \n    print('\\t\\tClassification Report:\\n', metrics.classification_report(test_labels, predict))\n\nprint_performance_metrics(y_test,y_pred_SVM)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create a confusion matrix\ncm_SVM =  confusion_matrix(y_test,y_pred_SVM)\ncm_SVM","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\" Helper function to plot a confusion matrix\n\n    Parameters:\n        cm (confusion matrix)\n\n    Returns:\n        Null\n\"\"\"\ndef plot_confusion_matrix(cm, labels):\n    plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)\n    plt.title('Confusion Matrix')\n    plt.colorbar()\n    tick_marks = np.arange(len(labels))\n    plt.xticks(tick_marks, labels, rotation=55)\n    plt.yticks(tick_marks, labels)\n\n    thresh = cm.max() / 2.\n    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n        plt.text(j, i, format(cm[i, j], 'd'), horizontalalignment=\"center\", color=\"white\" if cm[i, j] > thresh else \"black\")\n\n    plt.ylabel('True label')\n    plt.xlabel('Predicted label')\n    plt.tight_layout()\n\ncm_plot_label =['benign', 'malignant']\nplot_confusion_matrix(cm_SVM, cm_plot_label)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# RANDOM FOREST","metadata":{}},{"cell_type":"code","source":"from sklearn.ensemble import RandomForestClassifier\nclassifier_RF = RandomForestClassifier(n_estimators = 800, criterion = 'entropy', random_state = 0)\nclassifier_RF.fit(X_train,y_train)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_acc_RF = classifier_RF.score(X_train, y_train)\nval_acc_RF = classifier_RF.score(X_val, y_val)\ntest_acc_RF = classifier_RF.score(X_test, y_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(train_acc_RF)\nprint(val_acc_RF)\nprint(test_acc_RF)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_RF = classifier_RF.predict(X_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_performance_metrics(y_test,y_pred_RF)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create a confusion matrix\ncm_RF =  confusion_matrix(y_test,y_pred_RF)\ncm_RF","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_confusion_matrix(cm_RF, cm_plot_label)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ADABOOST","metadata":{}},{"cell_type":"code","source":"from sklearn.ensemble import AdaBoostClassifier\nclassifier_AdaBoost = AdaBoostClassifier(n_estimators = 100)\nclassifier_AdaBoost.fit(X_train, y_train)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_acc_AdaBoost = classifier_AdaBoost.score(X_train, y_train)\nval_acc_AdaBoost = classifier_AdaBoost.score(X_val, y_val)\ntest_acc_AdaBoost = classifier_AdaBoost.score(X_test, y_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(train_acc_AdaBoost)\nprint(val_acc_AdaBoost)\nprint(test_acc_AdaBoost)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_AdaBoost = classifier_AdaBoost.predict(X_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_performance_metrics(y_test,y_pred_AdaBoost)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create a confusion matrix\ncm_AdaBoost =  confusion_matrix(y_test,y_pred_AdaBoost)\ncm_AdaBoost","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_confusion_matrix(cm_AdaBoost, cm_plot_label)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# KNN","metadata":{}},{"cell_type":"code","source":"from sklearn.neighbors import KNeighborsClassifier\nclassifier_kNN = KNeighborsClassifier(n_neighbors = 5, algorithm='ball_tree', leaf_size=30)\nclassifier_kNN.fit(X_train, y_train)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_acc_kNN = classifier_kNN.score(X_train, y_train)\nval_acc_kNN = classifier_kNN.score(X_val, y_val)\ntest_acc_kNN = classifier_kNN.score(X_test, y_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(train_acc_kNN)\nprint(val_acc_kNN)\nprint(test_acc_kNN)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_kNN = classifier_kNN.predict(X_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_performance_metrics(y_test,y_pred_kNN)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create a confusion matrix\ncm_kNN =  confusion_matrix(y_test,y_pred_kNN)\ncm_kNN","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_confusion_matrix(cm_kNN, cm_plot_label)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# XGBOOST","metadata":{}},{"cell_type":"code","source":"import xgboost as xgb\nclassifier_xgb = xgb.XGBClassifier(n_estimators = 300)\nclassifier_xgb.fit(X_train, y_train)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_acc_xgb = classifier_xgb.score(X_train, y_train)\nval_acc_xgb = classifier_xgb.score(X_val, y_val)\ntest_acc_xgb = classifier_xgb.score(X_test, y_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(train_acc_xgb)\nprint(val_acc_xgb)\nprint(test_acc_xgb)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_xgb = classifier_xgb.predict(X_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_performance_metrics(y_test,y_pred_xgb)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create a confusion matrix\ncm_xgb =  confusion_matrix(y_test,y_pred_xgb)\ncm_xgb","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_confusion_matrix(cm_xgb, cm_plot_label)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# BAGGING","metadata":{}},{"cell_type":"code","source":"from sklearn.ensemble import BaggingClassifier\nclassifier_Bagging = BaggingClassifier(n_estimators=100)\nclassifier_Bagging.fit(X_train,y_train)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_acc_Bagging = classifier_Bagging.score(X_train, y_train)\nval_acc_Bagging = classifier_Bagging.score(X_val, y_val)\ntest_acc_Bagging = classifier_Bagging.score(X_test, y_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(train_acc_Bagging)\nprint(val_acc_Bagging)\nprint(test_acc_Bagging)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_Bagging = classifier_Bagging.predict(X_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_performance_metrics(y_test,y_pred_Bagging)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create a confusion matrix\ncm_Bagging =  confusion_matrix(y_test,y_pred_Bagging)\ncm_Bagging","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_confusion_matrix(cm_Bagging, cm_plot_label)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ANN","metadata":{}},{"cell_type":"code","source":"model_ANN = tf.keras.models.Sequential([\n    tf.keras.Input(shape=(last_layer_shape[1],last_layer_shape[2],last_layer_shape[3])),\n    tf.keras.layers.Flatten(),\n    #tf.keras.layers.Dense(64, activation = 'relu'),\n    #tf.keras.layers.Dropout(0.4),\n    tf.keras.layers.Dense(32, activation = 'relu'),\n    tf.keras.layers.Dense(1, activation = 'sigmoid')\n])\n\nLEARNING_RATE = 1e-4\nOPTIMIZER = RMSprop(lr=LEARNING_RATE,decay=1e-2)\nLOSS = 'binary_crossentropy'\nMETRICS = [\n    'accuracy', \n    'AUC'\n] \n\nmodel_ANN.compile(\n    loss=LOSS,\n    metrics=METRICS,\n    optimizer=OPTIMIZER,\n)\n\nprint(\"fit model on gpu\")\nhistory_ANN = model_ANN.fit(\n    train_features, train_labels, \n    epochs=EPOCHS, \n    verbose=VERBOSE_LEVEL, \n    validation_data=(val_features,val_labels)\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# get the current timestamp. This timestamp is used to save the model data with a unique name\nnow = datetime.now()\ntoday = date.today()\ncurrent_time = now.strftime(\"%H:%M:%S\")\ntimestamp = str(today) + \"_\" + str(current_time)\n\n# plot model history\nsave_history(history_ANN.history, timestamp)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_ANN = model_ANN.predict(X_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\" Helper function turn the model predictions into a binary (0,1) format\n\n    Parameters:\n        pred (float): Model prediction\n\n    Returns:\n        binary prediction (int)\n\"\"\"\n\ndef pred_to_binary(pred):\n    if pred < 0.5:\n        return 0\n    else:\n        return 1\n\ny_pred_ANN = [pred_to_binary(x) for x in y_pred_ANN]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_performance_metrics(y_test,y_pred_ANN)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create a confusion matrix\ncm_ANN =  confusion_matrix(y_test,y_pred_ANN)\ncm_ANN","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_confusion_matrix(cm_ANN, cm_plot_label)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# LSTM","metadata":{}},{"cell_type":"code","source":"#For LSTMs\n\ntrain_features_2d = np.zeros((train_len,last_layer_shape[1],last_layer_shape[2]*last_layer_shape[3]))\nfor i in range(len(train_labels)):\n    train_features_2d[i] = train_features[i].reshape(last_layer_shape[1],\n                                                     last_layer_shape[2]*last_layer_shape[3])\n    \nval_features_2d = np.zeros((val_len,last_layer_shape[1],last_layer_shape[2]*last_layer_shape[3]))\nfor i in range(len(val_labels)):\n    val_features_2d[i] = val_features[i].reshape(last_layer_shape[1],\n                                                     last_layer_shape[2]*last_layer_shape[3])\n    \ntest_features_2d = np.zeros((test_len,last_layer_shape[1],last_layer_shape[2]*last_layer_shape[3]))\nfor i in range(len(test_labels)):\n    test_features_2d[i] = test_features[i].reshape(last_layer_shape[1],\n                                                     last_layer_shape[2]*last_layer_shape[3])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_LSTM = tf.keras.models.Sequential([\n    tf.keras.Input(shape=(last_layer_shape[1], last_layer_shape[2]*last_layer_shape[3])),\n    tf.keras.layers.LSTM(100, return_sequences=True),\n    #tf.keras.layers.LSTM(32, return_sequences=True),\n    tf.keras.layers.LSTM(32),\n    tf.keras.layers.Dense(1, activation = 'sigmoid')\n])\n\nLEARNING_RATE = 1e-4\nOPTIMIZER = Adam(lr=LEARNING_RATE,decay=1e-2)\nLOSS = 'binary_crossentropy'\nMETRICS = [\n    'accuracy', \n    'AUC'\n] \n\nmodel_LSTM.compile(\n    loss=LOSS,\n    metrics=METRICS,\n    optimizer=OPTIMIZER,\n)\n\nprint(\"fit model on gpu\")\nhistory_LSTM = model_LSTM.fit(\n    train_features_2d, train_labels, \n    epochs=EPOCHS, \n    verbose=VERBOSE_LEVEL,\n    validation_data=(val_features_2d,val_labels)\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# plot model history\nsave_history(history_LSTM.history, timestamp)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_LSTM = model_LSTM.predict(test_features_2d)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_LSTM = [pred_to_binary(x) for x in y_pred_LSTM]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_performance_metrics(y_test,y_pred_LSTM)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create a confusion matrix\ncm_LSTM =  confusion_matrix(y_test,y_pred_LSTM)\ncm_LSTM","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_confusion_matrix(cm_LSTM, cm_plot_label)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# BIDIRECTIONAL LSTM","metadata":{}},{"cell_type":"code","source":"model_Bi_LSTM = tf.keras.models.Sequential([\n    tf.keras.Input(shape=(last_layer_shape[1], last_layer_shape[2]*last_layer_shape[3])),\n    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(100, return_sequences=True)),\n    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(100)),\n    #tf.keras.layers.Dropout(0.3),\n    #tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(128)),\n    tf.keras.layers.Dense(1, activation = 'sigmoid')\n])\n\nLEARNING_RATE = 1e-4\nOPTIMIZER = Adam(lr=LEARNING_RATE,decay=1e-2)\nLOSS = 'binary_crossentropy'\nMETRICS = [\n    'accuracy', \n    'AUC'\n] \n\nmodel_Bi_LSTM.compile(\n    loss=LOSS,\n    metrics=METRICS,\n    optimizer=OPTIMIZER,\n)\n\nprint(\"fit model on gpu\")\nhistory_Bi_LSTM = model_Bi_LSTM.fit(\n    train_features_2d, train_labels, \n    epochs=EPOCHS, \n    verbose=VERBOSE_LEVEL, \n    validation_data=(val_features_2d,val_labels)\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# plot model history\nsave_history(history_Bi_LSTM.history, timestamp)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_Bi_LSTM = model_Bi_LSTM.predict(test_features_2d)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_Bi_LSTM = [pred_to_binary(x) for x in y_pred_Bi_LSTM]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_performance_metrics(y_test,y_pred_Bi_LSTM)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create a confusion matrix\ncm_Bi_LSTM =  confusion_matrix(y_test,y_pred_Bi_LSTM)\ncm_Bi_LSTM","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_confusion_matrix(cm_Bi_LSTM, cm_plot_label)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}