{"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":"# ***SIIM-ISIC Melanoma Classification***","metadata":{}},{"cell_type":"markdown","source":"**Arbeitsauftrag:**\nErstellen Sie eine kurze explorative Datenanalyse zur train.csv um erste Einsichten zu gewinnen. Auffälligkeiten bitte in kurzer Form im Markdown notieren.\nErstellen Sie ein Pytorch-Dataset, in dem Sie die Bilder und tabularen Daten zusammenfassen. Das Dataset wird drei(!) Dinge zurückgeben (das Bild, die passende Zeile aus dem Dataframe sowie das Target)\nErstellen Sie ein Pytorch-Modell, welches ausschließlich aufgrund der Bilder klassifiziert.\nTesten Sie das Modell mit einem Sample\nTrainieren Sie das Modell und geben Sie die Accuracy sowie den F1-Score aus\nKombinieren Sie nun tabulare Daten und Bilder: Erstellen Sie ein weiteres Pytorch-Modell welches das Bild UND die tabularen Daten verarbeiten kann. (Tipp: die Forward-Methode bekommt hier das Bild sowie die passende Zeile aus dem Dataframe übergeben, es handelt sich hier um ein Multimodales-Modell)\nHalten Sie ihr Vorgehen in Form eines (kurzen, gerne auch stichwortartigen) Protokolls im Markdown fest. Gehen Sie auch auf Probleme und Sackgassen ein!\nBeide Modelle sollen eine submission erstellen!","metadata":{}},{"cell_type":"code","source":"#imports\n!pip install efficientnet\nimport numpy as np\nimport pandas as pd\nimport os\nimport re\nimport random, math, time\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.utils import resample\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.metrics import roc_curve, auc\nfrom keras.callbacks import History\nimport tensorflow as tf\nimport tensorflow.keras as keras\nimport tensorflow.keras.backend as K\nimport efficientnet.tfkeras as effnet\nimport matplotlib.pyplot as plt\nimport cv2\nimport seaborn as sns\nimport torch, os, torchvision\nimport torch.nn as nn\nfrom torch.nn import functional as F\nfrom torch.utils.data import Dataset, DataLoader, random_split\nimport torchvision.transforms as transforms\nfrom tqdm import tqdm, tqdm_notebook\nimport gc\nfrom keras.applications.densenet import preprocess_input, DenseNet169\nfrom keras.models import Model\nfrom keras.layers import GlobalAveragePooling2D, Input, Lambda, AveragePooling1D\nimport keras.backend as K","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-07-03T11:37:19.916309Z","iopub.execute_input":"2023-07-03T11:37:19.917154Z","iopub.status.idle":"2023-07-03T11:37:45.306988Z","shell.execute_reply.started":"2023-07-03T11:37:19.917118Z","shell.execute_reply":"2023-07-03T11:37:45.305935Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device(\"cuda\") if torch.cuda.is_available() else torch.device(\"cpu\")\nprint(f'Using {device}')","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:45.308862Z","iopub.execute_input":"2023-07-03T11:37:45.309561Z","iopub.status.idle":"2023-07-03T11:37:45.340304Z","shell.execute_reply.started":"2023-07-03T11:37:45.309527Z","shell.execute_reply":"2023-07-03T11:37:45.33847Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = pd.read_csv(\"../input/siim-isic-melanoma-classification/train.csv\")\ntest_df = pd.read_csv(\"../input/siim-isic-melanoma-classification/test.csv\")\npath_train = '/kaggle/input/siim-isic-melanoma-classification/jpeg/train'\npath_test = '/kaggle/input/siim-isic-melanoma-classification/jpeg/test'\n","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:45.346458Z","iopub.execute_input":"2023-07-03T11:37:45.347204Z","iopub.status.idle":"2023-07-03T11:37:45.476328Z","shell.execute_reply.started":"2023-07-03T11:37:45.347116Z","shell.execute_reply":"2023-07-03T11:37:45.475307Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Explorative Datenanalyse für Train.csv**","metadata":{}},{"cell_type":"code","source":"train_df.info()","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:45.477708Z","iopub.execute_input":"2023-07-03T11:37:45.478052Z","iopub.status.idle":"2023-07-03T11:37:45.55503Z","shell.execute_reply.started":"2023-07-03T11:37:45.478019Z","shell.execute_reply":"2023-07-03T11:37:45.554013Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#nach missing values schauen\ntrain_df.isnull().sum()","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:45.556616Z","iopub.execute_input":"2023-07-03T11:37:45.557022Z","iopub.status.idle":"2023-07-03T11:37:45.618984Z","shell.execute_reply.started":"2023-07-03T11:37:45.556989Z","shell.execute_reply":"2023-07-03T11:37:45.617962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Es fehlen einige Werte, vorallem bei \"anatom_site_general_challenge\".     ","metadata":{}},{"cell_type":"code","source":"train_df['sex'].hist(figsize=(6, 4))","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:45.62084Z","iopub.execute_input":"2023-07-03T11:37:45.62126Z","iopub.status.idle":"2023-07-03T11:37:45.886643Z","shell.execute_reply.started":"2023-07-03T11:37:45.62122Z","shell.execute_reply":"2023-07-03T11:37:45.88575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Es gibt etwas mehr Männer im Datenset","metadata":{}},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"sns.boxplot(x = 'age_approx', data = train_df)\n","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:45.888299Z","iopub.execute_input":"2023-07-03T11:37:45.888971Z","iopub.status.idle":"2023-07-03T11:37:46.073876Z","shell.execute_reply.started":"2023-07-03T11:37:45.888935Z","shell.execute_reply":"2023-07-03T11:37:46.072899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Das Durschnittsalter liegt zwischen 40 und 60 Jahren. Außerdem ist zu erkennen, dass es einen Patient mit Alter 0 gibt. Diesen werde ich noch anpassen","metadata":{}},{"cell_type":"code","source":"train_df[train_df['age_approx'] < 1].head()\n","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:46.075864Z","iopub.execute_input":"2023-07-03T11:37:46.076825Z","iopub.status.idle":"2023-07-03T11:37:46.097496Z","shell.execute_reply.started":"2023-07-03T11:37:46.076787Z","shell.execute_reply":"2023-07-03T11:37:46.096623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots(figsize = (9, 7))\nsns.countplot(y = 'anatom_site_general_challenge', data = train_df)\nplt.ylabel(\"Location\")","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:46.102393Z","iopub.execute_input":"2023-07-03T11:37:46.102663Z","iopub.status.idle":"2023-07-03T11:37:46.406009Z","shell.execute_reply.started":"2023-07-03T11:37:46.10264Z","shell.execute_reply":"2023-07-03T11:37:46.405065Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Die meisten Personen haben die Hautprobleme am Oberkörper. An Hand- und Fußflächen sowie im Oral- und Genitalbereich kommen sie am seltensten vor.","metadata":{}},{"cell_type":"code","source":"train_df['diagnosis'].value_counts(normalize = True)\n","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:46.407301Z","iopub.execute_input":"2023-07-03T11:37:46.40835Z","iopub.status.idle":"2023-07-03T11:37:46.422Z","shell.execute_reply.started":"2023-07-03T11:37:46.408313Z","shell.execute_reply":"2023-07-03T11:37:46.42114Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\"unknown\" ist die häufigste Diagnose, aber klammere ich erstmal aus um die wirklichen diagnostizierten Krankheiten zu betrachten.\n","metadata":{}},{"cell_type":"code","source":"Diag_known = train_df[train_df['diagnosis'] != 'unknown']['diagnosis']","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:46.423776Z","iopub.execute_input":"2023-07-03T11:37:46.424166Z","iopub.status.idle":"2023-07-03T11:37:46.439551Z","shell.execute_reply.started":"2023-07-03T11:37:46.424131Z","shell.execute_reply":"2023-07-03T11:37:46.438638Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots(figsize = (10, 8))\nsns.countplot(y = Diag_known)\nplt.ylabel(\"Diagnosen\")","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:46.44125Z","iopub.execute_input":"2023-07-03T11:37:46.441586Z","iopub.status.idle":"2023-07-03T11:37:46.744502Z","shell.execute_reply.started":"2023-07-03T11:37:46.441555Z","shell.execute_reply":"2023-07-03T11:37:46.743578Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\"Nevus\" tritt eindeutig am häufigsten auf, ist allerdings auch eine harmlose/gutartige Diagnose. Danach kommt der hochgradig bösartige Tumor \"Melanoma\", gefolgt von den wiederrum gutartigen \"seborrheic Keratosis\".  ","metadata":{}},{"cell_type":"code","source":"train_df['benign_malignant'].value_counts()\n","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:46.74599Z","iopub.execute_input":"2023-07-03T11:37:46.747117Z","iopub.status.idle":"2023-07-03T11:37:46.760421Z","shell.execute_reply.started":"2023-07-03T11:37:46.747061Z","shell.execute_reply":"2023-07-03T11:37:46.759358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Somit ist festzustellen, dass deutlich mehr gutartige Diagnosen im Datenset auftauchen. Es ist also ein unbalanced Dataset!","metadata":{}},{"cell_type":"markdown","source":"# Datenaufbereitung","metadata":{}},{"cell_type":"markdown","source":"Der Patient mit 0 Jahren","metadata":{}},{"cell_type":"code","source":"Patient_Null =train_df[train_df['age_approx']<1]['patient_id']\nPatient_Null","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:46.761821Z","iopub.execute_input":"2023-07-03T11:37:46.762271Z","iopub.status.idle":"2023-07-03T11:37:46.771004Z","shell.execute_reply.started":"2023-07-03T11:37:46.76223Z","shell.execute_reply":"2023-07-03T11:37:46.770134Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#set age_approx to mean for patients with age_approx < 1\nfor i in Patient_Null:\n    train_df.loc[train_df['patient_id'] == i, 'age_approx'] = train_df['age_approx'].mean()\n\n#look up IP_1300691\ntrain_df[train_df['patient_id'] == 'IP_1300691']","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:46.772573Z","iopub.execute_input":"2023-07-03T11:37:46.773321Z","iopub.status.idle":"2023-07-03T11:37:46.806588Z","shell.execute_reply.started":"2023-07-03T11:37:46.773289Z","shell.execute_reply":"2023-07-03T11:37:46.805637Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Eine weitere Baustelle ist das unbalanced Dataset. Dies werde ich versuchen mit Unter-Sampling zu lösen.","metadata":{}},{"cell_type":"code","source":"train_df['target'].hist()","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:46.808269Z","iopub.execute_input":"2023-07-03T11:37:46.808593Z","iopub.status.idle":"2023-07-03T11:37:47.060924Z","shell.execute_reply.started":"2023-07-03T11:37:46.808563Z","shell.execute_reply":"2023-07-03T11:37:47.060006Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Trennen der Daten nach Klassen\ndf_majority = train_df[train_df.target == 0]  # Mehrheitsklasse\ndf_minority = train_df[train_df.target == 1]  # Minderheitsklasse\n\n# Unterproben der Mehrheitsklasse, um die gleiche Anzahl von Datenpunkten wie in der Minderheitsklasse zu erhalten\ndf_majority_downsampled = resample(df_majority, \n                                   replace=True,\n                                   n_samples=len(df_minority),  \n                                   random_state=42)  # für die Reproduzierbarkeit\n\n# Kombinieren der Unterproben der Mehrheitsklasse mit der Minderheitsklasse\ndf_balanced = pd.concat([df_majority_downsampled, df_minority])\n\n# Überprüfen des ausgewogenen Verhältnisses der Klassen\ndf_balanced['target'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:47.06244Z","iopub.execute_input":"2023-07-03T11:37:47.062808Z","iopub.status.idle":"2023-07-03T11:37:47.084928Z","shell.execute_reply.started":"2023-07-03T11:37:47.062775Z","shell.execute_reply":"2023-07-03T11:37:47.084061Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_balanced.info()","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:47.086164Z","iopub.execute_input":"2023-07-03T11:37:47.086586Z","iopub.status.idle":"2023-07-03T11:37:47.103143Z","shell.execute_reply.started":"2023-07-03T11:37:47.086553Z","shell.execute_reply":"2023-07-03T11:37:47.101688Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Missing Values\nDer ausgeklammerte Code war mein eigentlicher Ansatz. Aber nachdem ich mich nochmal mit den Mitschülern ausgetauscht hatte, habe ich den\"OneHotEncoder\" benutzt. Damit ist es möglich, einmal die kategorischen zu numerischen umzuwandeln und im gleichen Zug einige Features zu entfernen oder anzupassen.","metadata":{}},{"cell_type":"code","source":"#nochmal nach missing values schauen\n#test_df.isnull().sum()\n#train_df.isnull().sum()\n#replace missing values anatom_site_general_challenge with unknown \n#train_df['anatom_site_general_challenge'].fillna('unknown', inplace = True)\n#test_df['anatom_site_general_challenge'].fillna('unknown', inplace = True)\n#replace missing values age_approx with mean\n#train_df['age_approx'].fillna(train_df['age_approx'].mean(), inplace = True)\n#train_df['sex'].fillna('unknown', inplace = True)\n#train_df.isnull().sum()\n#mapping = {'male' : 1, 'female' : 0}\n#train_df['sex'] = train_df['sex'].map(mapping)\n#test_df['sex'] = test_df['sex'].map(mapping)\n#train_df.head()\n#turn anatom_site_general_challenge into numerical values\n#mapping = {'torso' : 0, 'lower extremity' : 1, 'upper extremity' : 2, 'head/neck' : 3, 'palms/soles' : 4, 'oral/genital' : 5, 'unknown' : 6}\n#train_df['anatom_site_general_challenge'] = train_df['anatom_site_general_challenge'].map(mapping)\n#test_df['anatom_site_general_challenge'] = test_df['anatom_site_general_challenge'].map(mapping)\n#train_df.head()\n#turn diagnosis into numerical values\n#mapping = {'unknown' : 0, 'nevus' : 1, 'melanoma' : 2, 'seborrheic keratosis' : 3, 'lentigo NOS' : 4, 'lichenoid keratosis' : 5, 'solar lentigo' : 6, 'cafe-au-lait macule' : 7, 'atypical melanocytic proliferation' : 8, 'lichen planus-like keratosis' : 9, 'actinic keratosis' : 10}\n#train_df['diagnosis'] = train_df['diagnosis'].map(mapping)\n\n#turn benign_malignant into numerical values\n#mapping = {'benign' : 0, 'malignant' : 1}\n#train_df['benign_malignant'] = train_df['benign_malignant'].map(mapping)\n#train_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:47.105379Z","iopub.execute_input":"2023-07-03T11:37:47.105812Z","iopub.status.idle":"2023-07-03T11:37:47.11348Z","shell.execute_reply.started":"2023-07-03T11:37:47.105771Z","shell.execute_reply":"2023-07-03T11:37:47.112145Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\n\nx = torch.rand(8, 4)\ny = torch.randint(2, (8,))\nweights = torch.rand(8, 1) \nx = torch.cat((x, weights), dim=1)\nmodel = torch.nn.Linear(4, 2)\n\nloss_fn = torch.nn.CrossEntropyLoss(reduction='none')\ndef weighted_loss(y, y_hat, w):\n  return (loss_fn(y, y_hat)*w).mean()\n\nloss = weighted_loss(model(x[:, :-1]), y, x[:, -1])\nprint (loss)","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:47.115395Z","iopub.execute_input":"2023-07-03T11:37:47.116251Z","iopub.status.idle":"2023-07-03T11:37:47.27208Z","shell.execute_reply.started":"2023-07-03T11:37:47.116198Z","shell.execute_reply":"2023-07-03T11:37:47.271051Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#notwendig um den Encoder zu nutzen\ntest_df['sex'][0] = np.nan","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-07-03T11:37:47.273743Z","iopub.execute_input":"2023-07-03T11:37:47.274082Z","iopub.status.idle":"2023-07-03T11:37:47.280321Z","shell.execute_reply.started":"2023-07-03T11:37:47.274038Z","shell.execute_reply":"2023-07-03T11:37:47.279352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.preprocessing import OneHotEncoder\ncategorical = ['sex', 'anatom_site_general_challenge']\ncat_to_be_deleted = ['diagnosis', 'benign_malignant']\ncategorical_cols_train = []\ncategorical_cols_test = []\n\nfor col in categorical:\n    categorical_cols_train += [f\"{col[0]}_{val}\" for val in train_df[col].unique()]\n    \nfor col in categorical:\n    categorical_cols_test += [f\"{col[0]}_{val}\" for val in test_df[col].unique()]\n\nprint(categorical_cols_train)\nprint(categorical_cols_test)\n\nencoder = OneHotEncoder(handle_unknown='ignore', sparse_output=False)\nfinal_train = pd.DataFrame(encoder.fit_transform(df_balanced[categorical]),\n                          index=df_balanced.index, columns=categorical_cols_train)\n\nfinal_train['target'] = df_balanced['target'] \nfinal_train.insert(0, 'image_name', df_balanced['image_name'])\nfinal_train.insert(1, 'patient_id', df_balanced['patient_id'])\nfinal_test = pd.DataFrame(encoder.transform(test_df[categorical]),\n                            index=test_df.index, columns=categorical_cols_train)\nfinal_test.insert(0, 'image_name', test_df['image_name'])\nfinal_test.insert(1, 'patient_id', test_df['patient_id'])","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:47.281871Z","iopub.execute_input":"2023-07-03T11:37:47.282699Z","iopub.status.idle":"2023-07-03T11:37:47.32182Z","shell.execute_reply.started":"2023-07-03T11:37:47.282666Z","shell.execute_reply":"2023-07-03T11:37:47.320793Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"final_test.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:47.323335Z","iopub.execute_input":"2023-07-03T11:37:47.323661Z","iopub.status.idle":"2023-07-03T11:37:47.345829Z","shell.execute_reply.started":"2023-07-03T11:37:47.323631Z","shell.execute_reply":"2023-07-03T11:37:47.344875Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"final_train.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:47.347168Z","iopub.execute_input":"2023-07-03T11:37:47.347857Z","iopub.status.idle":"2023-07-03T11:37:47.374953Z","shell.execute_reply.started":"2023-07-03T11:37:47.347819Z","shell.execute_reply":"2023-07-03T11:37:47.373993Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dataset #1","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nfrom PIL import Image\nimport torch\nfrom torch.utils.data import Dataset\n\ncsv_file = \"../input/siim-isic-melanoma-classification/train.csv\"\nimage_dir = '/kaggle/input/siim-isic-melanoma-classification/jpeg/train'\n\nclass MelanomaDataset(Dataset):\n    def __init__(self, image_dir, dataframe, transform=None):\n        self.image_dir = image_dir\n        self.dataframe = dataframe\n        self.transform = transform\n        \n    def __len__(self):\n        return len(self.dataframe)\n    \n    def __getitem__(self, idx):\n        img_name = self.dataframe.iloc[idx]['image_name'] + '.jpg'\n        img_path = os.path.join(self.image_dir, img_name)\n        image = Image.open(img_path).convert('RGB')\n        \n        tabular_data = self.dataframe.iloc[idx].drop(['image_name'])\n        \n        target = self.dataframe.iloc[idx]['target']\n        \n        if self.transform:\n            image = self.transform(image)\n        \n        return image, tabular_data, target\n\n# Lade das DataFrame\ndf1 = pd.read_csv(csv_file)\n\n# Erstelle eine Instanz des Melanoma-Datasets\ndata1 = MelanomaDataset(image_dir, df1)\n\n# Zugriff auf die Elemente des Datasets\nimage, tabular_data, target = data1[0]","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:47.376365Z","iopub.execute_input":"2023-07-03T11:37:47.377001Z","iopub.status.idle":"2023-07-03T11:37:47.675679Z","shell.execute_reply.started":"2023-07-03T11:37:47.376965Z","shell.execute_reply":"2023-07-03T11:37:47.674716Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Erstelle eine Instanz des Melanoma-Datasets\ndata1 = MelanomaDataset(image_dir, df1)\n\n# Zugriff auf die Elemente des Datasets\nimage, tabular_data, target = data1[0]\n\n# Beispielhafter Zugriff auf die Daten des ersten Elements\nprint(\"Bild:\", image)\nprint(\"Tabellarische Daten:\", tabular_data)\nprint(\"Target:\", target)","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:47.67718Z","iopub.execute_input":"2023-07-03T11:37:47.677519Z","iopub.status.idle":"2023-07-03T11:37:47.899375Z","shell.execute_reply.started":"2023-07-03T11:37:47.677487Z","shell.execute_reply":"2023-07-03T11:37:47.898378Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Erstelle eine Instanz des Melanoma-Datasets\ndata1 = MelanomaDataset(image_dir, df1)\n\n# Zugriff auf die Elemente des Datasets\nimage, tabular_data, target = data1[1000]\n\n# Zeige das Bild an\nplt.imshow(image)\nplt.axis('off')  # Deaktiviere die Achsenbeschriftungen\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:47.905118Z","iopub.execute_input":"2023-07-03T11:37:47.905901Z","iopub.status.idle":"2023-07-03T11:37:50.897185Z","shell.execute_reply.started":"2023-07-03T11:37:47.905874Z","shell.execute_reply":"2023-07-03T11:37:50.896329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model nur Bilder","metadata":{}},{"cell_type":"markdown","source":"Beim ersten Versuch hatte ich in 10 Epochen jeweils 98% also overfitting. Dann mit learnrate und weight decay rumprobiert und Besserungen erfahren. Jetzt in sieben Epochen dieses Ergebnis:\n* Epoch 1/7: Train Loss: 0.1617, Test Loss: 0.5029, Accuracy: 71.76%, F1-Score: 0.0267\n* Epoch 2/7: Train Loss: 0.0864, Test Loss: 0.4796, Accuracy: 76.21%, F1-Score: 0.0000\n* Epoch 3/7: Train Loss: 0.0687, Test Loss: 0.4649, Accuracy: 80.85%, F1-Score: 0.0571\n* Epoch 4/7: Train Loss: 0.0653, Test Loss: 0.5266, Accuracy: 75.44%, F1-Score: 0.0863\n* Epoch 5/7: Train Loss: 0.0653, Test Loss: 0.4672, Accuracy: 80.08%, F1-Score: 0.0885\n* Epoch 6/7: Train Loss: 0.0622, Test Loss: 0.3837, Accuracy: 86.46%, F1-Score: 0.1250\n* Epoch 7/7: Train Loss: 0.0602, Test Loss: 0.7383, Accuracy: 56.29%, F1-Score: 0.0504","metadata":{}},{"cell_type":"markdown","source":"(Dauer ca. 35 Min)","metadata":{}},{"cell_type":"code","source":"import os\n!pip install scikit-learn\n!pip install efficientnet_pytorch\nimport pandas as pd\nfrom sklearn.metrics import f1_score\nfrom PIL import Image\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\nfrom efficientnet_pytorch import EfficientNet\n\n# Set device\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# Define dataset class\nclass MelanomaDataset(Dataset):\n    def __init__(self, csv_file, img_path, transform=None):\n        self.data = pd.read_csv(csv_file)\n        self.img_path = img_path\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.data) // 4\n\n    def __getitem__(self, idx):\n        image_path = self.data.iloc[idx]['image_name']\n        full_path = os.path.join(self.img_path, image_path + '.jpg')\n        image = Image.open(full_path).convert('RGB')\n\n        if self.transform is not None:\n            image = self.transform(image)\n\n        label = self.data.iloc[idx]['target']\n        return image, label\n\n# Define the PyTorch model\nclass MelanomaClassifier(nn.Module):\n    def __init__(self, num_classes):\n        super(MelanomaClassifier, self).__init__()\n        self.backbone = EfficientNet.from_pretrained('efficientnet-b0')\n        self.dropout_backbone = nn.Dropout(p=0.2)  # Dropout regularization\n        self.fc = nn.Linear(1000, num_classes)\n\n    def forward(self, x):\n        x = self.backbone(x)\n        x = self.dropout_backbone(x)\n        x = self.fc(x)\n        return x\n\n# Define the model\nnum_classes = 2\nmodel = MelanomaClassifier(num_classes).to(device)\n\n# Define loss function and optimizer\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.0001, weight_decay=0.02)  # L2 regularization\n\n# Define transformations for data augmentation and resizing\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),  # Resize images to a consistent size\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomVerticalFlip(),\n    transforms.RandomRotation(20),\n    transforms.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0.1),  # Additional color jitter\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n])\n\n# Load and preprocess the dataset\ncsv_file = \"../input/siim-isic-melanoma-classification/train.csv\"\nimg_path = '/kaggle/input/siim-isic-melanoma-classification/jpeg/train'\n\ntrain_dataset = MelanomaDataset(csv_file, img_path, transform=transform)\ntest_dataset = MelanomaDataset(csv_file, img_path, transform=transform)\ntrain_dataset.data = train_dataset.data[:len(train_dataset) // 4]\ntest_dataset.data = test_dataset.data[:len(test_dataset) // 4]\n\n# Define data loaders\nbatch_size = 8\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\ntest_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)\n\n# Training loop\nnum_epochs = 7\n\nfor epoch in range(num_epochs):\n    model.train()\n    train_loss = 0.0\n\n    for images, labels in train_loader:\n        images = images.to(device)\n        labels = labels.to(device)\n\n        optimizer.zero_grad()\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        train_loss += loss.item() * images.size(0)\n\n    train_loss /= len(train_loader.dataset)\n\n    model.eval()\n    test_loss = 0.0\n    correct = 0\n    y_true = []\n    y_pred = []\n\n    with torch.no_grad():\n        for images, labels in test_loader:\n            images = images.to(device)\n            labels = labels.to(device)\n\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n            test_loss += loss.item() * images.size(0)\n\n            _, predicted = torch.max(outputs.data, 1)\n            correct += (predicted == labels).sum().item()\n\n            y_true.extend(labels.cpu().numpy())\n            y_pred.extend(predicted.cpu().numpy())\n\n    test_loss /= len(test_loader.dataset)\n    accuracy = 100.0 * correct / len(test_loader.dataset)\n    f1 = f1_score(y_true, y_pred)  # Calculate F1-Score\n\n    print(f'Epoch {epoch+1}/{num_epochs}: Train Loss: {train_loss:.4f}, Test Loss: {test_loss:.4f}, Accuracy: {accuracy:.2f}%, F1-Score: {f1:.4f}')\n","metadata":{"execution":{"iopub.status.busy":"2023-07-03T11:37:50.898199Z","iopub.execute_input":"2023-07-03T11:37:50.898531Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Modell Tabulare + Bilder","metadata":{}},{"cell_type":"markdown","source":"Ich habe das Multimodale Modell leider nicht zu laufen bringen können. Youtube, Infoseiten und ChatGpt konnten mir da irgendwie nicht richtig weiterhelfen und ich habe mich am Ende nur noch von Error zu Error gehangelt... Hätte ich mehr Zeit investieren können, wäre es bestimmt machbar gewesen. Aber die habe ich dann am Ende einfach zu schlecht gemanaged!","metadata":{}},{"cell_type":"code","source":"import os\nimport math\nimport pandas as pd\nfrom sklearn.metrics import f1_score\nfrom PIL import Image\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\nfrom efficientnet_pytorch import EfficientNet\n\n# Set device\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\ncsv_file = \"../input/siim-isic-melanoma-classification/train.csv\"\nimg_path = '/kaggle/input/siim-isic-melanoma-classification/jpeg/train'\n\n# Define dataset class for multimodal data\nclass MelanomaDataset(Dataset):\n    def __init__(self, csv_file, img_path, tabular_data, transform=None):\n        self.data = pd.read_csv(csv_file)\n        self.img_path = img_path\n        self.tabular_data = tabular_data\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.data) // 4\n\n    def __getitem__(self, idx):\n        if idx >= len(self.data):\n            idx = len(self.data) - 1\n        image_path = self.data.iloc[idx]['image_name']\n\n        if self.transform is not None:\n            image = Image.open(os.path.join(self.img_path, image_path + '.jpg'))\n            image = self.transform(image)\n\n        label = self.data.iloc[idx]['target']\n        tabular_features = self.tabular_data.iloc[idx]  # Get tabular features for the corresponding index\n        return image, tabular_features, label\n\n\n# Define the PyTorch model for multimodal data\nclass MelanomaClassifier(nn.Module):\n    def __init__(self, num_classes, num_tabular_features):\n        super(MelanomaClassifier, self).__init__()\n        self.backbone = EfficientNet.from_pretrained('efficientnet-b0')\n        self.dropout_backbone = nn.Dropout(p=0.2)  # Dropout regularization\n        self.fc_image = nn.Linear(1000, num_classes)\n        self.fc_tabular = nn.Linear(num_tabular_features, num_classes)\n\n    def forward(self, x_image, x_tabular):\n        x_image = self.backbone(x_image)\n        x_image = self.dropout_backbone(x_image)\n        x_image = self.fc_image(x_image)\n\n        x_tabular = self.fc_tabular(x_tabular)\n\n        # Combine image and tabular features\n        x = torch.cat((x_image, x_tabular), dim=1)\n\n        return x\n\n# Define the model\nnum_classes = 2\nnum_tabular_features = 10  # Update this with the actual number of tabular features\nmodel = MelanomaClassifier(num_classes, num_tabular_features).to(device)\n\n# Define loss function and optimizer\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001, weight_decay=0.01)  # L2 regularization\n\n# Define transformations for data augmentation and resizing\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),  # Resize images to a consistent size\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomVerticalFlip(),\n    transforms.RandomRotation(20),\n    transforms.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0.1),  # Additional color jitter\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n])\n\ntrain_dataset = MelanomaDataset(csv_file, img_path, tabular_data, transform=transform)\ntest_dataset = MelanomaDataset(csv_file, img_path, tabular_data, transform=transform)\ntrain_dataset.data = train_dataset.data[:math.floor(len(train_dataset) / 4)]\ntest_dataset.data = test_dataset.data[:math.floor(len(test_dataset) / 4)]\n\n# Define data loaders\nbatch_size = 8\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\ntest_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)\n\n# Training loop\nnum_epochs = 10\n\nfor epoch in range(num_epochs):\n    model.train()\n    train_loss = 0.0\n\n    for images, tabular_features, labels in train_loader:\n        images = images.to(device)\n        tabular_features = tabular_features.to(device)\n        labels = labels.to(device)\n\n        optimizer.zero_grad()\n        outputs = model(images, tabular_features)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        train_loss += loss.item() * images.size(0)\n\n    train_loss /= len(train_loader.dataset)\n\n    model.eval()\n    test_loss = 0.0\n    correct = 0\n    y_true = []\n    y_pred = []\n\n    with torch.no_grad():\n        for images, tabular_features, labels in test_loader:\n            images = images.to(device)\n            tabular_features = tabular_features.to(device)\n            labels = labels.to(device)\n\n            outputs = model(images, tabular_features)\n            loss = criterion(outputs, labels)\n            test_loss += loss.item() * images.size(0)\n\n            _, predicted = torch.max(outputs.data, 1)\n            correct += (predicted == labels).sum().item()\n\n            y_true.extend(labels.cpu().numpy())\n            y_pred.extend(predicted.cpu().numpy())\n\n    test_loss /= len(test_loader.dataset)\n    accuracy = 100.0 * correct / len(test_loader.dataset)\n    f1 = f1_score(y_true, y_pred)  # Calculate F1-Score\n\n    print(f'Epoch {epoch+1}/{num_epochs}: Train Loss: {train_loss:.4f}, Test Loss: {test_loss:.4f}, Accuracy: {accuracy:.2f}%, F1-Score: {f1:.4f}')\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}