{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":20270,"databundleVersionId":1222630,"sourceType":"competition"},{"sourceId":8481400,"sourceType":"datasetVersion","datasetId":5017274},{"sourceId":8564242,"sourceType":"datasetVersion","datasetId":5119916}],"dockerImageVersionId":30699,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import (\n    Input, Dense, Concatenate, Conv2D, BatchNormalization,\n    Dropout, GlobalAveragePooling2D, Flatten\n)\nfrom sklearn.preprocessing import LabelEncoder, MinMaxScaler\nfrom sklearn.model_selection import train_test_split\n\n# Load data\ntrain_df = pd.read_csv('/kaggle/input/skin-canser-b584m584/Melanoma-b584m584/b584m584.csv')\ntest_df = pd.read_csv('/kaggle/input/melanoma/test.csv')\n\n# Clean and preprocess data\nmetadata = train_df.drop(columns=['benign_malignant', 'image_name', 'patient_id', 'lesion_id', 'diagnosis'])\nmean_age = metadata['age_approx'].mean()\n\nmetadata['age_approx'] = metadata['age_approx'].fillna(mean_age)\nmetadata['anatom_site_general_challenge'] = metadata['anatom_site_general_challenge'].fillna('Unknown')\n\nscaler = MinMaxScaler()\n\nmetadata['age_approx'] = scaler.fit_transform(metadata[['age_approx']])\n\nmode_sex = metadata['sex'].mode()[0]\nmetadata['sex'] = metadata['sex'].fillna(mode_sex)\n\nanatom_site_encoder = LabelEncoder()\n\nmetadata['anatom_site_general_challenge'] = anatom_site_encoder.fit_transform(metadata['anatom_site_general_challenge'])\n\nsex_encoder = LabelEncoder()\nmetadata['sex'] = sex_encoder.fit_transform(metadata['sex'])\n\n# Define paths to image directories\nbenign_dir = '/kaggle/input/skin-canser-b584m584/Melanoma-b584m584/benign'\nmalignant_dir = '/kaggle/input/skin-canser-b584m584/Melanoma-b584m584/malignant'\n\n# Preprocess images\ndef preprocess_image(filepath):\n    img = tf.keras.preprocessing.image.load_img(filepath, target_size=(128, 128))\n    img = tf.keras.preprocessing.image.img_to_array(img)\n    img = tf.keras.applications.resnet50.preprocess_input(img)\n    return img\n\n# Create a dictionary to store images and their labels\nimage_dict = {}\nfor dir_path, label in [(benign_dir, 0), (malignant_dir, 1)]:\n    for fname in os.listdir(dir_path):\n        filepath = os.path.join(dir_path, fname)\n        if os.path.exists(filepath):\n            image_dict[fname] = (preprocess_image(filepath), label)\n\n# Filter the dataframe to include only entries with corresponding images\ntrain_df = train_df[train_df['image_name'].apply(lambda x: x + '.jpeg' in image_dict)]\ntrain_df = train_df.sort_values(by='image_name')\n\n# Extract images and labels\nimages = []\nlabels = []\nfor img_name in train_df['image_name']:\n    img, label = image_dict[img_name + '.jpeg']\n    images.append(img)\n    labels.append(label)\nimages = np.array(images)\nlabels = np.array(labels)\ntrain_df = train_df.drop(columns=['image_name'])\n\n# Split data into training and validation sets\nX_train_img, X_val_img, X_train_meta, X_val_meta, y_train, y_val = train_test_split(\n    images, metadata, labels, test_size=0.3, random_state=42)\n\n# Define MirroredStrategy for multi-GPU training\nmirrored_strategy = tf.distribute.MirroredStrategy()\n\n# Data augmentation\ndata_augmentation = tf.keras.Sequential([\n    tf.keras.layers.RandomFlip(\"horizontal_and_vertical\"),\n    tf.keras.layers.RandomRotation(0.2),\n    tf.keras.layers.RandomZoom(0.2),\n    tf.keras.layers.RandomContrast(0.2),\n    tf.keras.layers.RandomTranslation(0.1, 0.1),\n])\n\n# Define the model\nwith mirrored_strategy.scope():\n    image_input = Input(shape=(128, 128, 3))\n    augmented_images = data_augmentation(image_input)\n    base_model = tf.keras.applications.ResNet50(include_top=False, input_tensor=augmented_images, weights='imagenet')\n    for layer in base_model.layers:\n        layer.trainable = True\n    x = base_model.output\n    x = GlobalAveragePooling2D()(x)\n    x = Dense(1024, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.01))(x)\n\n    metadata_input = Input(shape=(X_train_meta.shape[1],))\n    y = Dense(128, activation='relu')(metadata_input)\n    y = Dense(64, activation='relu')(y)\n    y = Dense(32, activation='relu')(y)\n    y = Dense(16, activation='relu')(y)\n\n    concatenated = Concatenate()([x, y])\n    output = Dense(1, activation='sigmoid')(concatenated)\n\n    model = Model(inputs=[image_input, metadata_input], outputs=output)\n    optimizer = tf.keras.optimizers.Adam(learning_rate=0.0001)\n    model.compile(optimizer=optimizer, loss='binary_crossentropy', metrics=['accuracy'])\n\n# Callbacks\nearly_stopping = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True)\nlr_scheduler = tf.keras.callbacks.ReduceLROnPlateau(factor=0.5, patience=5, min_lr=1e-6)\ncheckpoint = tf.keras.callbacks.ModelCheckpoint('best_model.keras', monitor='val_loss', save_best_only=True, mode='min')\ntensorboard = tf.keras.callbacks.TensorBoard(log_dir='./logs')\n\n# Train the model\nhistory = model.fit(\n    [X_train_img, X_train_meta], y_train,\n    epochs=60, batch_size=32,\n    validation_data=([X_val_img, X_val_meta], y_val),\n    callbacks=[early_stopping, lr_scheduler, checkpoint, tensorboard]\n)","metadata":{"execution":{"iopub.status.busy":"2024-05-31T12:59:44.126842Z","iopub.execute_input":"2024-05-31T12:59:44.127236Z","iopub.status.idle":"2024-05-31T13:11:36.368009Z","shell.execute_reply.started":"2024-05-31T12:59:44.127203Z","shell.execute_reply":"2024-05-31T13:11:36.367120Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Create subplots\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))\n\n# Plot training & validation accuracy\nax1.plot(history.history['accuracy'], marker='o', color='blue', label='Training Accuracy')\nax1.plot(history.history['val_accuracy'], marker='o', color='orange', label='Validation Accuracy')\nax1.set_title('Model Accuracy')\nax1.set_ylabel('Accuracy')\nax1.set_xlabel('Epoch')\nax1.grid(True)\nax1.legend(loc='lower right')\n\n# Annotate best validation accuracy\nbest_val_acc = max(history.history['val_accuracy'])\nbest_val_epoch = history.history['val_accuracy'].index(best_val_acc) + 1\nax1.annotate(f'Best Val Acc: {best_val_acc:.4f}', xy=(best_val_epoch, best_val_acc),\n             xytext=(best_val_epoch, best_val_acc - 0.05),\n             arrowprops=dict(facecolor='black', shrink=0.05))\n\n# Plot training & validation loss\nax2.plot(history.history['loss'], marker='o', color='blue', label='Training Loss')\nax2.plot(history.history['val_loss'], marker='o', color='orange', label='Validation Loss')\nax2.set_title('Model Loss')\nax2.set_ylabel('Loss')\nax2.set_xlabel('Epoch')\nax2.grid(True)\nax2.legend(loc='upper right')\n\n# Annotate early stopping\nif 'early_stopping' in locals():\n    ax2.annotate('Early Stopping', xy=(len(history.history['loss']), history.history['val_loss'][-1]),\n                 xytext=(len(history.history['loss']) - 10, history.history['val_loss'][-1] + 0.1),\n                 arrowprops=dict(facecolor='black', shrink=0.05))\n\n# Adjust layout\nplt.tight_layout()\n\n# Show plots\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-05-31T13:11:36.371134Z","iopub.execute_input":"2024-05-31T13:11:36.371918Z","iopub.status.idle":"2024-05-31T13:11:37.140033Z","shell.execute_reply.started":"2024-05-31T13:11:36.371879Z","shell.execute_reply":"2024-05-31T13:11:37.138880Z"},"trusted":true},"execution_count":null,"outputs":[]}]}