{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install -q efficientnet_pytorch    ","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import re\nimport os\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, Flatten\nfrom functools import partial\nfrom sklearn.model_selection import train_test_split\nimport tempfile\nimport matplotlib.pyplot as plt\nimport pydicom \nfrom skimage.transform import resize\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.preprocessing import OneHotEncoder\nimport seaborn as sns\nimport cv2\n\nsns.set_style(\"whitegrid\")\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# System\nimport cv2\nimport os, os.path\nfrom PIL import Image              # from RBG to YCbCr\nimport gc\nimport time\nimport datetime\n\n# Basics\nimport pandas as pd\nimport numpy as np\nimport random\nimport seaborn as sns\nimport matplotlib\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg    # to check images\n# %matplotlib inline\nfrom tqdm.notebook import tqdm      # beautiful progression bar\n\n# SKlearn\nfrom sklearn.model_selection import StratifiedKFold, GroupKFold\nfrom sklearn.metrics import accuracy_score, roc_auc_score, confusion_matrix\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn import preprocessing\n\n# PyTorch\nimport torch\nimport torchvision\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch import FloatTensor, LongTensor\nfrom torch.utils.data import Dataset, DataLoader, Subset\nfrom torch.optim.lr_scheduler import ReduceLROnPlateau\n\n# Data Augmentation for Image Preprocessing\nfrom albumentations import (ToFloat, Normalize, VerticalFlip, HorizontalFlip, Compose, Resize,\n                            RandomBrightnessContrast, HueSaturationValue, Blur, GaussNoise,\n                            Rotate, RandomResizedCrop, Cutout, ShiftScaleRotate)\nfrom albumentations.pytorch import ToTensorV2, ToTensor\n\nfrom efficientnet_pytorch import EfficientNet\nfrom torchvision.models import resnet34, resnet50\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Data Exploration"},{"metadata":{"trusted":true},"cell_type":"code","source":"list(os.listdir('../input/siim-isic-melanoma-classification'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"directory = '../input/siim-isic-melanoma-classification'\n\ntrain_df = pd.read_csv(directory + '/train.csv')\ntest_df = pd.read_csv(directory + '/test.csv')\n\nprint('Train has {:,} rows and Test has {:,} rows.'.format(len(train_df), len(test_df)))\n\nnew_names = ['image_name', 'ID', 'sex', 'age', 'anatomy', 'diagnosis', 'benign_malignant', 'target']\ntrain_df.columns = new_names\ntest_df.columns = new_names[:5]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.isnull().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df.isnull().sum()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"In the training dataset there are 65 missing values for sex, 68 missing values for age, and 527 missing values for anatomy. For the test dataset there are 351 values missing for anatomy. This number of missing values is not too bad since the datasets are pretty large. "},{"metadata":{"trusted":true},"cell_type":"code","source":"nan_sex = train_df[train_df['sex'].isna() == True]\nis_sex = train_df[train_df['sex'].isna() == False]\n\nf, (ax1, ax2) = plt.subplots(1, 2, figsize = (16, 6))\n\na = sns.countplot(nan_sex['anatomy'], ax = ax1)\nb = sns.countplot(is_sex['anatomy'], ax = ax2)\nax1.set_title('NAN Gender: Anatomy', fontsize=16)\nax2.set_title('Rest Gender: Anatomy', fontsize=16)\n\na.set_xticklabels(a.get_xticklabels(), rotation=35, ha=\"right\")\nb.set_xticklabels(b.get_xticklabels(), rotation=35, ha=\"right\")\nsns.despine(left=True, bottom=True);\n\nprint('Out of 65 NAN values, {} are benign and 0 malignant.'.format(nan_sex['benign_malignant'].value_counts()[0]))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Since the torso is by far the most common location for melanomas based on the graph on the right and is the second most common location for melanomas based on the graph on the left, this is the location I will use to fill in missing location values. "},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df['anatomy'].fillna('torso', inplace = True) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.isnull().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15,8))\nsns.countplot(test_df['anatomy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df['anatomy'].fillna('torso', inplace = True) \ntest_df.isnull().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df['age'].mean()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df['age'].median()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df['age'].fillna(50, inplace = True) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.isnull().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15,8))\nsns.countplot(train_df['sex'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df['sex'].fillna('male', inplace = True) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.isnull().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df.isnull().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15,8))\nsns.countplot(train_df['benign_malignant'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The classes of benign and malignant samples are extremely unbalanced, an issue that will need to be addressed before a model can be accurately fit to the data. "},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15,8))\nsns.countplot(train_df['age'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.to_csv('train_clean.csv', index=False)\ntest_df.to_csv('test_clean.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15,8))\nsns.distplot(a = train_df[train_df['target']==0]['age'], hist=False, rug=True, kde_kws=dict(linewidth=4), \n             label='Benign')\nsns.distplot(a = train_df[train_df['target']==1]['age'], hist=False, rug=True, kde_kws=dict(linewidth=4), \n             label='Malignant')\nplt.title('Age Distribution by Target Types', fontsize=16)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(16, 6))\nsns.countplot(data=train_df, x='benign_malignant', hue='sex')\nplt.title('Gender Split by Target Variable', fontsize=16)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(16, 6))\nsns.countplot(data=train_df, x='benign_malignant', hue='anatomy')\nplt.title('Anatomy Split by Target Variable', fontsize=16)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"f, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize = (16, 6))\n\na = sns.countplot(test_df['sex'], ax=ax1)\nb = sns.countplot(test_df['anatomy'], ax=ax2)\nc = sns.distplot(a = test_df['age'], ax=ax3, hist=False, rug=True, kde_kws=dict(linewidth=4))\n\n\nax1.set_title('Test: Gender Frequencies', fontsize=16)\nax2.set_title('Test: Anatomy Frequencies', fontsize=16)\nax3.set_title('Test: Age Distribution', fontsize=16)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"patients_count_train = train_df.groupby(by='ID')['image_name'].count().reset_index()\npatients_count_test = test_df.groupby(by='ID')['image_name'].count().reset_index()\n\nf, (ax1, ax2) = plt.subplots(1, 2, figsize = (16, 6))\n\na = sns.distplot(patients_count_train['image_name'], kde=False, bins=50, \n                 ax=ax1, hist_kws={'alpha': 1})\nb = sns.distplot(patients_count_test['image_name'], kde=False, bins=50, \n                 ax=ax2, hist_kws={'alpha': 1})\n    \nax1.set_title('Train: Images per Patient Distribution', fontsize=16)\nax2.set_title('Test: Images per Patient Distribution', fontsize=16)\nsns.despine(left=True, bottom=True);","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"You can see that there are patients with multiple images taken in both the test and training datasets. "},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.to_csv('train_clean.csv', index=False)\ntest_df.to_csv('test_clean.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Next we will create image paths to allow us to access image features for the images as dicoms and as jpegs. "},{"metadata":{"trusted":true},"cell_type":"code","source":"path_train = directory + '/train/' + train_df['image_name'] + '.dcm'\npath_test = directory + '/test/' + test_df['image_name'] + '.dcm'\n\n# Append to the original dataframes\ntrain_df['path_dicom'] = path_train\ntest_df['path_dicom'] = path_test\n\n# === JPEG ===\n# Create the paths\npath_train = directory + '/jpeg/train/' + train_df['image_name'] + '.jpg'\npath_test = directory + '/jpeg/test/' + test_df['image_name'] + '.jpg'\n\n# Append to the original dataframes\ntrain_df['path_jpeg'] = path_train\ntest_df['path_jpeg'] = path_test","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The categorical features will need to be converted to numerical features through one-hot encoding. "},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.drop(['benign_malignant'], axis=1, inplace=True)\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"to_encode = ['sex', 'anatomy', 'diagnosis']\nencoded_all = []\n\nlabel_encoder = LabelEncoder()\n\nfor column in to_encode:\n    encoded = label_encoder.fit_transform(train_df[column])\n    encoded_all.append(encoded)\n    \ntrain_df['sex'] = encoded_all[0]\ntrain_df['anatomy'] = encoded_all[1]\ntrain_df['diagnosis'] = encoded_all[2]\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"to_encode = ['sex', 'anatomy']\nencoded_all = []\n\nlabel_encoder = LabelEncoder()\n\nfor column in to_encode:\n    encoded = label_encoder.fit_transform(test_df[column])\n    encoded_all.append(encoded)\n    \ntest_df['sex'] = encoded_all[0]\ntest_df['anatomy'] = encoded_all[1]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.to_csv('train_clean.csv', index=False)\ntest_df.to_csv('test_clean.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from PIL import Image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"shapes_train = []\n\nfor k, path in enumerate(train_df['path_jpeg']):\n    image = Image.open(path)\n    shapes_train.append(image.size)\n    \n    if k >= 100: break\n        \nshapes_train = pd.DataFrame(data = shapes_train, columns = ['H', 'W'], dtype='object')\nshapes_train['Size'] = '[' + shapes_train['H'].astype(str) + ', ' + shapes_train['W'].astype(str) + ']'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize = (16, 6))\nsns.countplot(shapes_train['Size'])\nplt.title('100 Images Shapes', fontsize=16)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Next we will view some of the benign and some of the malignant melanoma images from the dataset. "},{"metadata":{"trusted":true},"cell_type":"code","source":"def show_images(data, n = 5, rows=1, cols=5, title='Default'):\n    plt.figure(figsize=(16,4))\n\n    for k, path in enumerate(data['path_dicom'][:n]):\n        image = pydicom.read_file(path)\n        image = image.pixel_array\n        \n        # image = resize(image, (200, 200), anti_aliasing=True)\n\n        plt.suptitle(title, fontsize = 16)\n        plt.subplot(rows, cols, k+1)\n        plt.imshow(image)\n        plt.axis('off')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"show_images(train_df[train_df['target'] == 0], n=10, rows=2, cols=5, title='Benign Sample')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"show_images(train_df[train_df['target'] == 1], n=10, rows=2, cols=5, title='Malignant Sample')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, axes = plt.subplots(nrows=2, ncols=6, figsize=(16,6))\nplt.suptitle(\"B&W\", fontsize = 16)\n\nfor i in range(0, 2*6):\n    data = pydicom.read_file(train_df['path_dicom'][i])\n    image = data.pixel_array\n    \n    # Transform to B&W\n    # The function converts an input image from one color space to another.\n    image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)\n    image = cv2.resize(image, (200,200))\n    \n    x = i // 6\n    y = i % 6\n    axes[x, y].imshow(image, cmap=plt.cm.bone) \n    axes[x, y].axis('off')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, axes = plt.subplots(nrows=2, ncols=6, figsize=(16,6))\nplt.suptitle(\"Without Gaussian Blur\", fontsize = 16)\n\nfor i in range(0, 2*6):\n    data = pydicom.read_file(train_df['path_dicom'][i])\n    image = data.pixel_array\n    \n    # Transform to B&W\n    # The function converts an input image from one color space to another.\n    image = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)\n    image = cv2.resize(image, (200,200))\n    \n    x = i // 6\n    y = i % 6\n    axes[x, y].imshow(image, cmap=plt.cm.bone) \n    axes[x, y].axis('off')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, axes = plt.subplots(nrows=2, ncols=6, figsize=(16,6))\nplt.suptitle(\"With Gaussian Blur\", fontsize = 16)\n\nfor i in range(0, 2*6):\n    data = pydicom.read_file(train_df['path_dicom'][i])\n    image = data.pixel_array\n    \n    image = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)\n    image = cv2.resize(image, (200,200))\n    image=cv2.addWeighted(image, 4, cv2.GaussianBlur(image, (0,0) ,256/10), -4, 128)\n    \n    x = i // 6\n    y = i % 6\n    axes[x, y].imshow(image, cmap=plt.cm.bone) \n    axes[x, y].axis('off')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, axes = plt.subplots(nrows=2, ncols=6, figsize=(16,6))\nplt.suptitle(\"Hue, Saturation, Brightness\", fontsize = 16)\n\nfor i in range(0, 2*6):\n    data = pydicom.read_file(train_df['path_dicom'][i])\n    image = data.pixel_array\n    \n    image = cv2.cvtColor(image, cv2.COLOR_RGB2HLS)\n    image = cv2.resize(image, (200,200))\n    \n    x = i // 6\n    y = i % 6\n    axes[x, y].imshow(image, cmap=plt.cm.bone) \n    axes[x, y].axis('off')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, axes = plt.subplots(nrows=2, ncols=6, figsize=(16,6))\nplt.suptitle(\"LUV Color Space\", fontsize = 16)\n\nfor i in range(0, 2*6):\n    data = pydicom.read_file(train_df['path_dicom'][i])\n    image = data.pixel_array\n\n    image = cv2.cvtColor(image, cv2.COLOR_RGB2LUV)\n    image = cv2.resize(image, (200,200))\n    \n    x = i // 6\n    y = i % 6\n    axes[x, y].imshow(image, cmap=plt.cm.bone) \n    axes[x, y].axis('off')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from torch.utils.data import DataLoader, Dataset\nimport torchvision.transforms as transforms \nimport torch \nimport torchvision","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image_list = train_df.sample(12)['path_jpeg']\nimage_list = image_list.reset_index()['path_jpeg']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class DatasetExample(Dataset):\n    def __init__(self, image_list, transforms=None):\n        self.image_list = image_list\n        self.transforms = transforms\n    \n    # To get item's length\n    def __len__(self):\n        return (len(self.image_list))\n    \n    # For indexing\n    def __getitem__(self, i):\n        # Read in image\n        image = plt.imread(self.image_list[i])\n        image = Image.fromarray(image).convert('RGB')        \n        image = np.asarray(image).astype(np.uint8)\n        if self.transforms is not None:\n            image = self.transforms(image)\n            \n        return torch.tensor(image, dtype=torch.float)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def show_transform(image, title=\"Default\"):\n    plt.figure(figsize=(16,6))\n    plt.suptitle(title, fontsize = 16)\n    \n    # Unnormalize\n    image = image / 2 + 0.5  \n    npimg = image.numpy()\n    npimg = np.clip(npimg, 0., 1.)\n    plt.imshow(np.transpose(npimg, (1, 2, 0)))\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"transform = transforms.Compose([\n     transforms.ToPILImage(),\n     transforms.Resize((300, 300)),\n     transforms.CenterCrop((100, 100)),\n     transforms.ToTensor(),\n     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),\n     ])\n\n# Create the dataset\npytorch_dataset = DatasetExample(image_list=image_list, transforms=transform)\npytorch_dataloader = DataLoader(dataset=pytorch_dataset, batch_size=12, shuffle=True)\n\n# Select the data\nimages = next(iter(pytorch_dataloader))\n \n# show images\nshow_transform(torchvision.utils.make_grid(images, nrow=6), title=\"Crop\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"transform = transforms.Compose([\n     transforms.ToPILImage(),\n     transforms.Resize((300, 300)),\n     transforms.ColorJitter(brightness=0.7, contrast=0.7, saturation=0.7, hue=0.5),\n     transforms.ToTensor(),\n     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),\n     ])\n\n# Create the dataset\npytorch_dataset = DatasetExample(image_list=image_list, transforms=transform)\npytorch_dataloader = DataLoader(dataset=pytorch_dataset, batch_size=12, shuffle=True)\n\n# Select the data\nimages = next(iter(pytorch_dataloader))\n \n# show images\nshow_transform(torchvision.utils.make_grid(images, nrow=6), title=\"Color Jitter\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"transform = transforms.Compose([\n     transforms.ToPILImage(),\n     transforms.Resize((300, 300)),\n     transforms.RandomGrayscale(p=0.7),\n     transforms.ToTensor(),\n     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),\n     ])\n\n# Create the dataset\npytorch_dataset = DatasetExample(image_list=image_list, transforms=transform)\npytorch_dataloader = DataLoader(dataset=pytorch_dataset, batch_size=12, shuffle=True)\n\n# Select the data\nimages = next(iter(pytorch_dataloader))\n \n# show images\nshow_transform(torchvision.utils.make_grid(images, nrow=6), title=\"Random Greyscale\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"transform = transforms.Compose([\n     transforms.ToPILImage(),\n     transforms.Resize((300, 300)),\n     transforms.RandomVerticalFlip(p=0.7),\n     transforms.ToTensor(),\n     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),\n     ])\n\n# Create the dataset\npytorch_dataset = DatasetExample(image_list=image_list, transforms=transform)\npytorch_dataloader = DataLoader(dataset=pytorch_dataset, batch_size=12, shuffle=True)\n\n# Select the data\nimages = next(iter(pytorch_dataloader))\n \n# show images\nshow_transform(torchvision.utils.make_grid(images, nrow=6), title=\"Random Vertical Flip\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def hair_remove(image):\n    # convert image to grayScale\n    grayScale = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)\n\n    # kernel for morphologyEx\n    kernel = cv2.getStructuringElement(1,(17,17))\n\n    # apply MORPH_BLACKHAT to grayScale image\n    blackhat = cv2.morphologyEx(grayScale, cv2.MORPH_BLACKHAT, kernel)\n\n    # apply thresholding to blackhat\n    _,threshold = cv2.threshold(blackhat,10,255,cv2.THRESH_BINARY)\n\n    # inpaint with original image and threshold image\n    final_image = cv2.inpaint(image,threshold,1,cv2.INPAINT_TELEA)\n\n    return final_image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"output_size =1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# My Train: with imputed missing values + OHE\nmy_train = pd.read_csv('train_clean.csv')\n\n# Drop path columns and Diagnosis (it won't be available during TEST)\n# We'll rewrite them once the data is concatenated\nto_drop = ['path_dicom','path_jpeg', 'diagnosis']\nfor drop in to_drop:\n    if drop in my_train.columns :\n        my_train.drop([drop], axis=1, inplace=True)\n\n# --- Before concatenatenating both together, let's preprocess roman_train ---\n# Replace NAN with 0 for patient_id\nroman_train['patient_id'] = roman_train['patient_id'].fillna(0)\n\n# OHE\nto_encode = ['sex', 'anatom_site_general_challenge']\nencoded_all = []\n\nroman_train[to_encode[0]] = roman_train[to_encode[0]].astype(str)\nroman_train[to_encode[1]] = roman_train[to_encode[1]].astype(str)\n\nlabel_encoder = LabelEncoder()\n\n# --- Read in Test data (also cleaned, imputed, OHE) ---\ntest_df = pd.read_csv('test_clean.csv')\n\n# Create path column to image folder for both Train and Test\npath_train = '../input/melanoma-external-malignant-256/train/train/'\npath_test = '../input/melanoma-external-malignant-256/test/test/'\n\ntrain_df['path_jpg'] = path_train + train_df['image_name'] + '.jpg'\ntest_df['path_jpg'] = path_test + test_df['image_name'] + '.jpg'\n\n\n# --- Last final thing: NORMALIZE! ---\ntrain_df['age'] = train_df['age'].fillna(-1)\n\nnormalized_train = preprocessing.normalize(train_df[['sex', 'age', 'anatomy']])\nnormalized_test = preprocessing.normalize(test_df[['sex', 'age', 'anatomy']])\n\ntrain_df['sex'] = normalized_train[:, 0]\ntrain_df['age'] = normalized_train[:, 1]\ntrain_df['anatomy'] = normalized_train[:, 2]\n\ntest_df['sex'] = normalized_test[:, 0]\ntest_df['age'] = normalized_test[:, 1]\ntest_df['anatomy'] = normalized_test[:, 2]\n\n\nprint('Len Train: {:,}'.format(len(train_df)), '\\n' +\n      'Len Test: {:,}'.format(len(test_df)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"vertical_flip = 0.5\nhorizontal_flip = 0.5\n\ncsv_columns = ['sex', 'age', 'anatomy']\nno_columns = 3","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"np.array(train_df.iloc[0][csv_columns].values,dtype=np.float32)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class MelanomaDataset(Dataset):\n    \n    def __init__(self, dataframe, vertical_flip, horizontal_flip,\n                 is_train=True, is_valid=False, is_test=False):\n        self.dataframe, self.is_train, self.is_valid = dataframe, is_train, is_valid\n        self.vertical_flip, self.horizontal_flip = vertical_flip, horizontal_flip\n        \n        # Data Augmentation (custom for each dataset type)\n        if is_train or is_test:\n            self.transform = Compose([RandomResizedCrop(height=224, width=224, scale=(0.4, 1.0)),\n                                      ShiftScaleRotate(rotate_limit=90, scale_limit = [0.8, 1.2]),\n                                      HorizontalFlip(p = self.horizontal_flip),\n                                      VerticalFlip(p = self.vertical_flip),\n                                      HueSaturationValue(sat_shift_limit=[0.7, 1.3], \n                                                         hue_shift_limit=[-0.1, 0.1]),\n                                      RandomBrightnessContrast(brightness_limit=[0.7, 1.3],\n                                                               contrast_limit= [0.7, 1.3]),\n                                      Normalize(),\n                                      ToTensor()])\n        else:\n            self.transform = Compose([Normalize(),\n                                      ToTensor()])\n            \n    def __len__(self):\n        return len(self.dataframe)\n    \n    def __getitem__(self, index):\n        # Select path and read image\n        image_path = self.dataframe['path_jpg'][index]\n        image = cv2.imread(image_path)\n        # For this image also import .csv information (sex, age, anatomy)\n        csv_data = np.array(self.dataframe.iloc[index][['sex', 'age', 'anatomy']].values, \n                            dtype=np.float32)\n        \n        # Apply transforms\n        image = self.transform(image=image)\n        # Extract image from dictionary\n        image = image['image']\n        \n        # If train/valid: image + class | If test: only image\n        if self.is_train or self.is_valid:\n            return (image, csv_data), self.dataframe['target'][index]\n        else:\n            return (image, csv_data)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class ResNet50Network(nn.Module):\n    def __init__(self, output_size, no_columns):\n        super().__init__()\n        self.no_columns, self.output_size = no_columns, output_size\n        \n        # Define Feature part (IMAGE)\n        self.features = resnet50(pretrained=True) # 1000 neurons out\n        # (CSV data)\n        self.csv = nn.Sequential(nn.Linear(self.no_columns, 500),\n                                 nn.BatchNorm1d(500),\n                                 nn.ReLU(),\n                                 nn.Dropout(p=0.2))\n        \n        # Define Classification part\n        self.classification = nn.Linear(1000 + 500, output_size)\n        \n        \n    def forward(self, image, csv_data, prints=False):\n        \n        if prints: print('Input Image shape:', image.shape, '\\n'+\n                         'Input csv_data shape:', csv_data.shape)\n        \n        # Image CNN\n        image = self.features(image)\n        if prints: print('Features Image shape:', image.shape)\n        \n        # CSV FNN\n        csv_data = self.csv(csv_data)\n        if prints: print('CSV Data:', csv_data.shape)\n            \n        # Concatenate layers from image with layers from csv_data\n        image_csv_data = torch.cat((image, csv_data), dim=1)\n        \n        # CLASSIF\n        out = self.classification(image_csv_data)\n        if prints: print('Out shape:', out.shape)\n        \n        return out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_example = ResNet50Network(output_size=output_size, no_columns=no_columns)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"example_data = MelanomaDataset(train_df, vertical_flip=0.5, horizontal_flip=0.5, \n                               is_train=True, is_valid=False, is_test=False)\nexample_loader = torch.utils.data.DataLoader(example_data, batch_size = 3, shuffle=True)\n\n# Get a sample\nfor (image, csv_data), labels in example_loader:\n    image_example, csv_data_example = image, csv_data\n    labels_example = torch.tensor(labels, dtype=torch.float32)\n    break\nprint('Data shape:', image_example.shape, '| \\n' , csv_data_example)\nprint('Label:', labels_example, '\\n')\n\n# Outputs\nout = model_example(image_example, csv_data_example, prints=True)\n\n# Criterion example\ncriterion_example = nn.BCEWithLogitsLoss()\n# Unsqueeze(1) from shape=[3] to shape=[3, 1]\nloss = criterion_example(out, labels_example.unsqueeze(1))   \nprint('Loss:', loss.item())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class EfficientNetwork(nn.Module):\n    def __init__(self, output_size, no_columns, b4=False, b2=False):\n        super().__init__()\n        self.b4, self.b2, self.no_columns = b4, b2, no_columns\n        \n        # Define Feature part (IMAGE)\n        if b4:\n            self.features = EfficientNet.from_pretrained('efficientnet-b4')\n        elif b2:\n            self.features = EfficientNet.from_pretrained('efficientnet-b2')\n        else:\n            self.features = EfficientNet.from_pretrained('efficientnet-b7')\n        \n        # (CSV)\n        self.csv = nn.Sequential(nn.Linear(self.no_columns, 250),\n                                 nn.BatchNorm1d(250),\n                                 nn.ReLU(),\n                                 nn.Dropout(p=0.2),\n                                 \n                                 nn.Linear(250, 250),\n                                 nn.BatchNorm1d(250),\n                                 nn.ReLU(),\n                                 nn.Dropout(p=0.2))\n        \n        # Define Classification part\n        if b4:\n            self.classification = nn.Sequential(nn.Linear(1792 + 250, output_size))\n        elif b2:\n            self.classification = nn.Sequential(nn.Linear(1408 + 250, output_size))\n        else:\n            self.classification = nn.Sequential(nn.Linear(2560 + 250, output_size))\n        \n        \n    def forward(self, image, csv_data, prints=False):    \n        \n        if prints: print('Input Image shape:', image.shape, '\\n'+\n                         'Input csv_data shape:', csv_data.shape)\n        \n        # IMAGE CNN\n        image = self.features.extract_features(image)\n        if prints: print('Features Image shape:', image.shape)\n            \n        if self.b4:\n            image = F.avg_pool2d(image, image.size()[2:]).reshape(-1, 1792)\n        elif self.b2:\n            image = F.avg_pool2d(image, image.size()[2:]).reshape(-1, 1408)\n        else:\n            image = F.avg_pool2d(image, image.size()[2:]).reshape(-1, 2560)\n        if prints: print('Image Reshaped shape:', image.shape)\n            \n        # CSV FNN\n        csv_data = self.csv(csv_data)\n        if prints: print('CSV Data:', csv_data.shape)\n            \n        # Concatenate\n        image_csv_data = torch.cat((image, csv_data), dim=1)\n        \n        # CLASSIF\n        out = self.classification(image_csv_data)\n        if prints: print('Out shape:', out.shape)\n        \n        return out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_example = EfficientNetwork(output_size=output_size, no_columns=no_columns,\n                                 b4=False, b2=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"example_data = MelanomaDataset(train_df, vertical_flip=0.5, horizontal_flip=0.5, \n                               is_train=True, is_valid=False, is_test=False)\nexample_loader = torch.utils.data.DataLoader(example_data, batch_size = 3, shuffle=True)\n\n# Get a sample\nfor (image, csv_data), labels in example_loader:\n    image_example, csv_data_example = image, csv_data\n    labels_example = torch.tensor(labels, dtype=torch.float32)\n    break\nprint('Data shape:', image_example.shape, '| \\n' , csv_data_example)\nprint('Label:', labels_example, '\\n')\n\n# Outputs\nout = model_example(image_example, csv_data_example, prints=True)\n\n# Criterion example\ncriterion_example = nn.BCEWithLogitsLoss()\n# Unsqueeze(1) from shape=[3] to shape=[3, 1]\nloss = criterion_example(out, labels_example.unsqueeze(1))   \nprint('Loss:', loss.item())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_len = len(train_df)\ntest_len = len(test_df)\n# -------------------\n\n\n# Out of Fold Predictions\noof = np.zeros(shape = (train_len, 1))\n\n# Predictions\npreds_submission = torch.zeros(size = (test_len, 1), dtype=torch.float32)\n\nprint('oof shape:', oof.shape, '\\n' +\n      'predictions shape:', preds_submission.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"k = 6  ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"group_fold = GroupKFold(n_splits = k)\n\n# Generate indices to split data into training and test set.\nfolds = group_fold.split(X = np.zeros(train_len), \n                         y = train_df['target'], \n                         groups = train_df['ID'].tolist())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs = 15\npatience = 3\nTTA = 3\nnum_workers = 8\nlearning_rate = 0.0005\nweight_decay = 0.0\nlr_patience = 1            # 1 model not improving until lr is decreasing\nlr_factor = 0.4            # by how much the lr is decreasing\n\nbatch_size1 = 32\nbatch_size2 = 16\n\nversion = 'v6'     ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_folds(preds_submission, model, version = 'v1'):\n    # Creates a .txt file that will contain the logs\n    f = open(f\"logs_{version}.txt\", \"w+\")\n    \n    \n    for fold, (train_index, valid_index) in enumerate(folds):\n        # Append to .txt\n        with open(f\"logs_{version}.txt\", 'a+') as f:\n            print('-'*10, 'Fold:', fold+1, '-'*10, file=f)\n        print('-'*10, 'Fold:', fold+1, '-'*10)\n\n\n        # --- Create Instances ---\n        # Best ROC score in this fold\n        best_roc = None\n        # Reset patience before every fold\n        patience_f = patience\n        \n        # Initiate the model\n        model = model\n\n        optimizer = torch.optim.Adam(model.parameters(), lr = learning_rate, weight_decay=weight_decay)\n        scheduler = ReduceLROnPlateau(optimizer=optimizer, mode='max', \n                                      patience=lr_patience, verbose=True, factor=lr_factor)\n        criterion = nn.BCEWithLogitsLoss()\n\n\n        # --- Read in Data ---\n        train_data = train_df.iloc[train_index].reset_index(drop=True)\n        valid_data = train_df.iloc[valid_index].reset_index(drop=True)\n\n        # Create Data instances\n        train = MelanomaDataset(train_data, vertical_flip=vertical_flip, horizontal_flip=horizontal_flip, \n                                is_train=True, is_valid=False, is_test=False)\n        valid = MelanomaDataset(valid_data, vertical_flip=vertical_flip, horizontal_flip=horizontal_flip, \n                                is_train=False, is_valid=True, is_test=False)\n        # Read in test data | Remember! We're using data augmentation like we use for Train data.\n        test = MelanomaDataset(test_df, vertical_flip=vertical_flip, horizontal_flip=horizontal_flip,\n                               is_train=False, is_valid=False, is_test=True)\n\n        # Dataloaders\n        train_loader = DataLoader(train, batch_size=batch_size1, shuffle=True, num_workers=num_workers)\n        # shuffle=False! Otherwise function won't work!!!\n                # how do I know? ^^\n        valid_loader = DataLoader(valid, batch_size=batch_size2, shuffle=False, num_workers=num_workers)\n        test_loader = DataLoader(test, batch_size=batch_size2, shuffle=False, num_workers=num_workers)\n\n\n        # === EPOCHS ===\n        for epoch in range(epochs):\n            start_time = time.time()\n            correct = 0\n            train_losses = 0\n\n            # === TRAIN ===\n            # Sets the module in training mode.\n            model.train()\n\n            for (images, csv_data), labels in train_loader:\n                # Save them to device\n                images = torch.tensor(images, device=device, dtype=torch.float32)\n                csv_data = torch.tensor(csv_data, device=device, dtype=torch.float32)\n                labels = torch.tensor(labels, device=device, dtype=torch.float32)\n\n                # Clear gradients first; very important, usually done BEFORE prediction\n                optimizer.zero_grad()\n\n                # Log Probabilities & Backpropagation\n                out = model(images, csv_data)\n                loss = criterion(out, labels.unsqueeze(1))\n                loss.backward()\n                optimizer.step()\n\n                # --- Save information after this batch ---\n                # Save loss\n                train_losses += loss.item()\n                # From log probabilities to actual probabilities\n                train_preds = torch.round(torch.sigmoid(out)) # 0 and 1\n                # Number of correct predictions\n                correct += (train_preds.cpu() == labels.cpu().unsqueeze(1)).sum().item()\n\n            # Compute Train Accuracy\n            train_acc = correct / len(train_index)\n\n\n            # === EVAL ===\n            # Sets the model in evaluation mode\n            model.eval()\n\n            # Create matrix to store evaluation predictions (for accuracy)\n            valid_preds = torch.zeros(size = (len(valid_index), 1), device=device, dtype=torch.float32)\n\n\n            # Disables gradients (we need to be sure no optimization happens)\n            with torch.no_grad():\n                for k, ((images, csv_data), labels) in enumerate(valid_loader):\n                    images = torch.tensor(images, device=device, dtype=torch.float32)\n                    csv_data = torch.tensor(csv_data, device=device, dtype=torch.float32)\n                    labels = torch.tensor(labels, device=device, dtype=torch.float32)\n\n                    out = model(images, csv_data)\n                    pred = torch.sigmoid(out)\n                    valid_preds[k*images.shape[0] : k*images.shape[0] + images.shape[0]] = pred\n\n                # Compute accuracy\n                valid_acc = accuracy_score(valid_data['target'].values, \n                                           torch.round(valid_preds.cpu()))\n                # Compute ROC\n                valid_roc = roc_auc_score(valid_data['target'].values, \n                                          valid_preds.cpu())\n\n                # Compute time on Train + Eval\n                duration = str(datetime.timedelta(seconds=time.time() - start_time))[:7]\n\n\n                # PRINT INFO\n                # Append to .txt file\n                with open(f\"logs_{version}.txt\", 'a+') as f:\n                    print('{} | Epoch: {}/{} | Loss: {:.4} | Train Acc: {:.3} | Valid Acc: {:.3} | ROC: {:.3}'.\\\n                     format(duration, epoch+1, epochs, train_losses, train_acc, valid_acc, valid_roc), file=f)\n                # Print to console\n                print('{} | Epoch: {}/{} | Loss: {:.4} | Train Acc: {:.3} | Valid Acc: {:.3} | ROC: {:.3}'.\\\n                     format(duration, epoch+1, epochs, train_losses, train_acc, valid_acc, valid_roc))\n\n\n                # === SAVE MODEL ===\n\n                # Update scheduler (for learning_rate)\n                scheduler.step(valid_roc)\n\n                # Update best_roc\n                if not best_roc: # If best_roc = None\n                    best_roc = valid_roc\n                    torch.save(model.state_dict(),\n                               f\"Fold{fold+1}_Epoch{epoch+1}_ValidAcc_{valid_acc:.3f}_ROC_{valid_roc:.3f}.pth\")\n                    continue\n\n                if valid_roc > best_roc:\n                    best_roc = valid_roc\n                    # Reset patience (because we have improvement)\n                    patience_f = patience\n                    torch.save(model.state_dict(),\n                               f\"Fold{fold+1}_Epoch{epoch+1}_ValidAcc_{valid_acc:.3f}_ROC_{valid_roc:.3f}.pth\")\n                else:\n                    # Decrease patience (no improvement in ROC)\n                    patience_f = patience_f - 1\n                    if patience_f == 0:\n                        with open(f\"logs_{version}.txt\", 'a+') as f:\n                            print('Early stopping (no improvement since 3 models) | Best ROC: {}'.\\\n                                  format(best_roc), file=f)\n                        print('Early stopping (no improvement since 3 models) | Best ROC: {}'.\\\n                              format(best_roc))\n                        break\n\n\n        # === INFERENCE ===\n        # Choose model with best_roc in this fold\n        best_model_path = '../working/' + [file for file in os.listdir('../working') if str(round(best_roc, 3)) in file and 'Fold'+str(fold+1) in file][0]\n        # Using best model from Epoch Train\n        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n        model = EfficientNetwork(output_size = output_size, no_columns=no_columns,\n                         b4=False, b2=True).to(device)\n        model.load_state_dict(torch.load(best_model_path))\n        # Set the model in evaluation mode\n        model.eval()\n\n\n        with torch.no_grad():\n            # --- EVAL ---\n            # Predicting again on Validation data to get preds for OOF\n            valid_preds = torch.zeros(size = (len(valid_index), 1), device=device, dtype=torch.float32)\n\n            for k, ((images, csv_data), _) in enumerate(valid_loader):\n                images = torch.tensor(images, device=device, dtype=torch.float32)\n                csv_data = torch.tensor(csv_data, device=device, dtype=torch.float32)\n\n                out = model(images, csv_data)\n                pred = torch.sigmoid(out)\n                valid_preds[k*images.shape[0] : k*images.shape[0] + images.shape[0]] = pred\n\n            # Save info to OOF\n            oof[valid_index] = valid_preds.cpu().numpy()\n\n\n            # --- TEST ---\n            # Now (Finally) prediction for our TEST data\n            for i in range(TTA):\n                for k, (images, csv_data) in enumerate(test_loader):\n                    images = torch.tensor(images, device=device, dtype=torch.float32)\n                    csv_data = torch.tensor(csv_data, device=device, dtype=torch.float32)\n\n                    out = model(images, csv_data)\n                    # Covert to probablities\n                    out = torch.sigmoid(out)\n\n                    # ADDS! the prediction to the matrix we already created\n                    preds_submission[k*images.shape[0] : k*images.shape[0] + images.shape[0]] += out\n\n\n            # Divide Predictions by TTA (to average the results during TTA)\n            preds_submission /= TTA\n\n\n        # === CLEANING ===\n        # Clear memory\n        del train, valid, train_loader, valid_loader, images, labels\n        # Garbage collector\n        gc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = EfficientNetwork(output_size = output_size, no_columns=no_columns,\n                         b4=False, b2=True)\n\n# # ===== Uncomment and Train =====\ntrain_folds(preds_submission = preds_submission, model = model, version = version)\n\n# # Save OOF values\nsave_oof = pd.DataFrame(data = oof, columns=['oof'])\nsave_oof.to_csv(f'oof_{version}.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"f = open('../input/siim-melanoma-prep-data/logs_v7.txt', \"r\")\ncontents = f.read()\nprint(contents)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# # --- EffNet B4 ---\nmodel = EfficientNetwork(output_size = output_size, no_columns=no_columns,b4=True, b2=False)\n\n# # Uncomment and Train\ntrain_folds(preds_submission = preds_submission, model = model, version = version)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# # --- ResNet50 ---\nmodel = ResNet50Network(output_size=output_size, no_columns=no_columns).to(device)\n\n# # Uncomment and Train\ntrain_folds(preds_submission = preds_submission, model = model, version = version)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Import OOF (pretrained)\noof = pd.read_csv('../input/siim-melanoma-prep-data/oof_v7.csv')\n\n# ROC on full Training data\nprint('OOF ROC: {:.3f}'.format(roc_auc_score(train_df['target'], oof)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Make OOF Binary\noof.loc[oof.oof >= 0.5, 'oof'] = 1\noof.loc[oof.oof < 0.5, 'oof'] = 0\n\n# Create Confusion Matrix\ncf_matrix = confusion_matrix(train_df['target'], oof)\n\n# Pretty CM:\ngroup_names = ['True Neg','False Pos','False Neg','True Pos']\n# Format of the absolute numbers\ngroup_counts = ['{:,}'.format(value) for value in cf_matrix.flatten()]\n# Format for relative numbers\ngroup_percentages = ['{0:.1%}'.format(value) for value in cf_matrix.flatten()/np.sum(cf_matrix)]\n\nlabels = [f'{v1}\\n{v2}\\n{v3}' for v1, v2, v3 in zip(group_names,group_counts,group_percentages)]\nlabels = np.asarray(labels).reshape(2,2)\n\n# --- The figure ---\nplt.figure(figsize=(16, 5))\nsns.heatmap(cf_matrix, annot=labels, fmt='', cmap='Oranges',xticklabels=['benign', 'malignant'], \n            yticklabels=['benign', 'malignant'], cbar=False)\n\nmatplotlib.rcParams.update({'font.size': 15})\nplt.tick_params(axis='both', labelsize=15)\nplt.title('Confusion Matrix: OOF Data', fontsize=20);","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Divide predictions by the number of folds\npreds_submission /= k\npreds_submission = preds_submission.cpu().numpy().reshape(-1,)\n\n# Import submission file\nss = pd.read_csv('/kaggle/input/siim-isic-melanoma-classification/sample_submission.csv')\n\nss['target'] = preds_submission\nss.to_csv(f'submission_{version}.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}