{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Proof of concept for SIIM-ISIC Melanoma Challenge using RADTorch","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"### Please updavote if you find this notebook useful ! Thanks","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## 1. The Challege\n\n### 1.A. Your Skin, Get to Know it\n\n![](https://i.ibb.co/Wpnr9gJ/peau.png)\n\n\nThe skin is the body’s largest organ. It protects against heat, sunlight, injury, and infection. Skin also helps control body temperature and stores water, fat, and vitamin D. The skin has several layers, but the two main layers are the epidermis (upper or outer layer) and the dermis (lower or inner layer). Skin cancer begins in the epidermis, which is made up of three kinds of cells:\n\n* *Squamous cells*: Thin, flat cells that form the top layer of the epidermis.\n* *Basal cells*: Round cells under the squamous cells.\n* *Melanocytes*: Cells that make melanin and are found in the lower part of the epidermis. Melanin is the pigment that gives skin its natural color. When skin is exposed to the sun, melanocytes make more pigment and cause the skin to darken.\n\n\n(Source : https://www.dana-farber.org/skin-cancer/)\n\n\n\n### 1.B. Skin Cancer\n\n![](https://i.ibb.co/68n6TvG/GB-couleurs.png)\n\n\nSkin cancer is the most prevalent type of cancer. Melanoma, specifically, is responsible for 75% of skin cancer deaths, despite being the least common skin cancer. The American Cancer Society estimates over 100,000 new melanoma cases will be diagnosed in 2020. It's also expected that almost 7,000 people will die from the disease. As with other cancers, early and accurate detection—potentially aided by data science—can make treatment more effective.\n\n<br>\n\n---\n\n\n## 2. RADTorch\n\nRADTorch (https://www.radtorch.com) is an ongoing project that provides a framework of higher level classes and functions that aim at significantly reducing the time needed for implementatto createent machine and deep learning algorithms on DICOM medical images.\n\n\nRADTorch is built upon widely used machine learning and deep learning frameworks. These include:\n* PyTorch for Deep Learning and Neural Networks.\n* Scikit-learn for Data Management and Machine Learning Algorithms.\n* PyDICOM for handling of DICOM data.\n* Bokeh, Matplotlib and Seaborn for Data Visualization.\n","execution_count":null},{"metadata":{"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"!git clone -b nightly https://github.com/radtorch/radtorch/ -q\n!pip install radtorch/. -q\n!rm -r radtorch\n\nfrom radtorch.settings import *\nfrom radtorch import core, utils\nfrom sklearn import preprocessing\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"utils.set_random_seed(100)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"\n\n## 3. Approach\n\nMy approach to solve this challenge will include the following steps:\n\n#### A. Model Training\n\n1. Extract Imaging Features from provided train dataset using one of the famous CNN architectures with ImageNet pre-trained weights (e.g. vgg16, resnet50 , ..)\n2. Pre-process the Patient Clinical features including creating dummy features and interaction terms between categorical features.\n3. Combine both feature sets into a single feature input vector.\n4. Since the data is **extremely unbalanced**, data has to balanced using upsample, downsample or SMOTE.\n5. Train a regular machine learning classifier (e.g. logistic regression, ...)\n\n#### B. Inference\n1. Perform steps 1-3 from model training pipeline but on test images.\n2. Use the trained classifier to classify instances of test feature vector.\n3. Combine results in submission csv","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"### A.  Model Training","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"### Step 1 : Imaging Features Extraction\n\nI am going to be demonstrating here train images features extracted using Alexnet architecture that I extracted earlier.","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"train_img_features = pd.read_csv('/kaggle/input/radtorch-challenges-data/train_imaging_features_alexnet.csv')","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"train_img_features.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Step 2: Clinical Data Pre-processing","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def create_patient_data(csv, normalize_age=True, test=False, drop_missing=True, root='/kaggle/input/siim-isic-melanoma-classification/jpeg/train/', ext='.jpg'):\n    patient_features = pd.read_csv(csv)\n    if drop_missing==True:\n        patient_features.dropna(inplace=True)  \n    x = []\n    for i, r in patient_features.iterrows(): x.append(root+r['image_name']+ext)\n    patient_features['IMAGE_PATH']=x\n    cat_columns=['sex','anatom_site_general_challenge']\n    dummy_data = pd.get_dummies(patient_features[['sex','anatom_site_general_challenge']])\n    patient_features=pd.concat([patient_features, dummy_data], axis=1)\n    dummy_col = ['sex_female',\t'sex_male',\t'anatom_site_general_challenge_head/neck',\t'anatom_site_general_challenge_lower extremity',\t'anatom_site_general_challenge_oral/genital',\t'anatom_site_general_challenge_palms/soles',\t'anatom_site_general_challenge_torso',\t'anatom_site_general_challenge_upper extremity']\n    if normalize_age:\n        min_max_scaler = preprocessing.MinMaxScaler()\n        patient_features[['age_approx']]=min_max_scaler.fit_transform(patient_features[['age_approx']])\n    return patient_features[['IMAGE_PATH','age_approx', ]+dummy_col]","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"train_clinical_features=create_patient_data('/kaggle/input/siim-isic-melanoma-classification/train.csv', drop_missing=False, normalize_age=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_clinical_features.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Step 3 and 4: Combine Imaging and Clinical Features + Solve Class Imbalance","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def balance_data(df, label_col='IMAGE_LABEL', method='upsample'):\n    counts=df.groupby(label_col).count()\n    classes=df[label_col].unique().tolist()\n    max_class_num=counts.max()[0]\n    max_class_id=counts.idxmax()[0]\n    min_class_num=counts.min()[0]\n    min_class_id=counts.idxmin()[0]\n    if method=='upsample':\n        resampled_subsets = [df[df[label_col]==max_class_id]]\n        for i in [x for x in classes if x != max_class_id]:\n            class_subset=df[df[label_col]==i]\n            upsampled_subset=resample(class_subset, n_samples=max_class_num, random_state=100)\n            resampled_subsets.append(upsampled_subset)\n    elif method=='downsample':\n        resampled_subsets = [df[df[label_col]==min_class_id]]\n        for i in [x for x in classes if x != min_class_id]:\n            class_subset=df[df[label_col]==i]\n            upsampled_subset=resample(class_subset, n_samples=min_class_num, random_state=100)\n            resampled_subsets.append(upsampled_subset)\n    resampled_df = pd.concat(resampled_subsets) \n    return resampled_df \n\ndef create_data(img_features, pt_features, test_split, balance='upsample'):\n    min_max_scaler = preprocessing.MinMaxScaler()\n    img_features[img_features.columns.tolist()[2:]] = min_max_scaler.fit_transform(img_features[img_features.columns.tolist()[2:]])\n\n    combined = pd.merge(left=pt_features, right=img_features, left_on='IMAGE_PATH', right_on='IMAGE_PATH')\n\n    feature_names=[x for x in combined.columns.tolist() if x not in ['IMAGE_PATH', 'IMAGE_LABEL']]\n\n    if test_split:\n        train,  test  = train_test_split(combined, test_size=test_split, random_state=100)\n  \n    else:\n        train = combined\n\n    if balance:\n        train=balance_data(train, method=balance) \n\n    if test_split:\n        feature_dict =  { \n    'train': {'features':train[feature_names], 'features_names':feature_names, 'labels': train.IMAGE_LABEL.tolist()}, \n    'test': {'features':test[feature_names], 'features_names':feature_names, 'labels': test.IMAGE_LABEL.tolist()}\n        }     \n        return feature_dict\n    else:\n        return train\n","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"train_data = create_data(train_img_features, train_clinical_features, 0.25, balance='downsample')\ntrain_data['train']['features'].head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Step 5: Train Classifier","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"classifier_hyper={'tree_method':'gpu_hist', \n                    'learning_rate':0.25, \n                    'eval_score':'auc',\n                    'booster':'dart',\n                    'random_state':100,\n                    'n_estimators':800\n                    }","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"clf = core.Classifier(extracted_feature_dictionary=train_data, \n                      type='xgboost',\n                      parameters=classifier_hyper,\n                      cv=True,\n                      num_splits=5)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train = clf.run()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"clf.confusion_matrix()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"clf.roc()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Inference","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"test_clinical_features = create_patient_data('/kaggle/input/siim-isic-melanoma-classification/test.csv', root='/kaggle/input/siim-isic-melanoma-classification/jpeg/test/', normalize_age=False, test=True, drop_missing=False)\ntest_imaging_features = pd.read_csv('/kaggle/input/radtorch-challenges-data/test_imaging_features_alexnet.csv')\ntest_features = create_data(test_imaging_features, test_clinical_features, test_split=False, balance=False)\nfeature_names=[x for x in test_features.columns.tolist() if x not in ['IMAGE_PATH', 'IMAGE_LABEL']]\ntest_features = test_features[feature_names]\npredictions = clf.classifier.predict_proba(test_features)\nprediction_of_malignancy = [i[1] for i in predictions]\nsubmission = pd.read_csv('/kaggle/input/siim-isic-melanoma-classification/sample_submission.csv')\nsubmission['target']=prediction_of_malignancy\nsubmission.head()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"clf.export('trained_classifier.pkl')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}