{"metadata":{"colab":{"provenance":[],"gpuType":"T4"},"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"accelerator":"GPU","kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":59997,"databundleVersionId":6474669,"sourceType":"competition"}],"dockerImageVersionId":30528,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!wget https://raw.githubusercontent.com/mrdbourke/tensorflow-deep-learning/main/extras/helper_functions.py\nfrom helper_functions import create_tensorboard_callback, plot_loss_curves, unzip_data, compare_historys, walk_through_dir\n\n","metadata":{"id":"50rjnRWy4SNS","outputId":"9914d550-dc26-46a9-8e0d-9e2c8464bb78"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"unzip_data(\"/content/drive/MyDrive/HAKATHON-20230831T095410Z-001.zip\")","metadata":{"id":"HtsFrnDo4Zm1"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"unzip_data(\"/content/drive/MyDrive/bioverse-hackathon.zip\")","metadata":{"id":"GbD__QvnjD4d"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nprint(tf.__version__)","metadata":{"id":"pbbUdFIVCpCY","outputId":"1e9d6d16-f144-406b-f2cc-2c8c37e95e8f"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMG_SIZE = (224, 224)\ntrain_dir = '/content/HAKATHON'\n\ntrain_data, test_data = tf.keras.preprocessing.image_dataset_from_directory(train_dir,\n                                                                                label_mode=\"categorical\",\n                                                                                image_size=IMG_SIZE,\n                                                                                validation_split=0.2,\n                                                                                seed = 42,\n                                                                                batch_size=8,\n                                                                                subset=\"both\")","metadata":{"id":"G0LVQkiw6Yuf","outputId":"79b66125-7421-45cc-cb7a-d42832ff5578"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def data_augmenter():\n    '''\n    Create a Sequential model composed of 2 layers\n    Returns:\n        tf.keras.Sequential\n    '''\n    ### START CODE HERE\n    data_augmentation = tf.keras.Sequential()\n    data_augmentation.add(RandomFlip('horizontal'))\n    data_augmentation.add(RandomRotation(0.2))\n    ### END CODE HERE\n\n    return data_augmentation","metadata":{"id":"_eKj_GUULVAl"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Import the required modules for model creation\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.models import Sequential\nfrom sklearn import preprocessing\n\n## NEW: Newer versions of TensorFlow (2.10+) can use the tensorflow.keras.layers API directly for data augmentation\ndata_augmentation = Sequential([\n  layers.RandomFlip(\"horizontal\"),\n  layers.RandomRotation(0.2),\n  layers.RandomZoom(0.2),\n  layers.RandomHeight(0.2),\n  layers.RandomWidth(0.2),\n  #tf.keras.layers.experimental.preprocessing.Rescaling(1./255) # keep for ResNet50V2, remove for EfficientNetB0\n], name =\"data_augmentation\")","metadata":{"id":"N0Phgh2vPkZa"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.backend import conv2d\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.optimizers.legacy import Adam\n\n\n\n# Create base model\ninput_shape = (224, 224, 3)\nbase_model = tf.keras.applications.ResNet50(include_top=False)\nbase_model.trainable = False # freeze base model layers\n\n# Create Functional model\ninputs = layers.Input(shape=input_shape, name=\"input_layer\")\nx = data_augmentation(inputs)\n# Note: EfficientNetBX models have rescaling built-in but if your model didn't you could have a layer like below\n# x = layers.Rescaling(1./255)(x)\nx = base_model(x, training=False) # set base_model to inference mode only\nx = layers.GlobalAveragePooling2D(name=\"pooling_layer\")(x)\nx = layers.Dense(len(train_data.class_names))(x) # want one output neuron per class\n# Separate activation of output layer so we can output float32 activations\noutputs = layers.Activation(\"softmax\", dtype=tf.float32, name=\"softmax_float32\")(x)\nmodel = tf.keras.Model(inputs, outputs)\n\n# Compile the model\nmodel.compile(loss=\"categorical_crossentropy\", # Use sparse_categorical_crossentropy when labels are *not* one-hot\n              optimizer=tf.keras.optimizers.Adam(),\n              metrics=[\"accuracy\"])","metadata":{"id":"Jb6NvPSd6Jk4"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"id":"x4gfNCPrEUT1","outputId":"324c2d07-e893-4b01-a110-726d87048d2c"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Turn off all warnings except for errors\ntf.get_logger().setLevel('ERROR')\n\n# Fit the model with callbacks\nmodel_v1 = model.fit(train_data,\n                      epochs=15,\n                      steps_per_epoch=len(train_data),\n                      validation_data=test_data)                   #validation_steps=int(0.15 * len(test_data)))","metadata":{"id":"hTDX6iG4E0-C","outputId":"b0e452a6-73b9-4957-99a5-1a0e90294c4b"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"result_model = model.evaluate(test_data)\nresult_model\n","metadata":{"id":"9jLCaXBaFDeT","outputId":"289c61de-8b4b-4ad8-ad93-bb8917d9ce9d"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport pandas as pd\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\nimport numpy as np\n\nclass_labels = train_data.class_names\n\n# Path to the folder containing images for prediction\nprediction_folder = '/content/test'\n# Load the trained model\n# List of image filenames in the prediction folder\nimage_filenames = os.listdir(prediction_folder)\n# List to store predictions\npredictions = []\n# Class labels for mapping predicted class indices to class names\n# class_labels = ['normal', 'beneign', 'malignant']\n# Loop through each image and make predictions\nfor filename in image_filenames:\n    image_path = os.path.join(prediction_folder, filename)\n    img = load_img(image_path, target_size=(224, 224))\n    img_array = img_to_array(img)\n    #img_array = img_array / 255.0  # Normalize pixel values\n    img_array = np.expand_dims(img_array, axis=0)\n    # Add batch dimension\n    prediction = model.predict(img_array)\n    print(prediction)\n    predicted_class_index = np.argmax(prediction)\n    predicted_class = class_labels[predicted_class_index]\n    predictions.append((filename, predicted_class))\n# Create a DataFrame and save it as a CSV file\npredictions_df = pd.DataFrame(predictions, columns=['filename', 'class'])\npredictions_csv_path = 'predictions.csv'\npredictions_df.to_csv(predictions_csv_path, index=False)\nprint(f'Predictions saved to {predictions_csv_path}')","metadata":{"id":"7BEFgo-GhO4j","outputId":"460478d7-bf6f-407a-afaf-d32d97eb174e"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\n\n# Get predictions as numpy array\npredictions = model.predict(x_test)\n\n# Convert to pandas DataFrame\ndf = pd.DataFrame(predictions)\n\n# Write to excel\ndf.to_excel('predictions.xlsx', index=False)","metadata":{"id":"qiJFiOMDoFcH"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\n\n# Write headers\nws.append(['beneign', 'malignant', 'normal'])\n\n# Write predictions\nfor pred in predictions:\n    ws.append(pred)\n\nwb.save('predictions.xlsx')","metadata":{"id":"OeFgfj7wn3SG"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_loss_curves(model_v1)","metadata":{"id":"07iQNVqQGgAe","outputId":"c85936d7-4936-42ef-edeb-641682801b2b"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Note: The following confusion matrix code is a remix of Scikit-Learn's\n# plot_confusion_matrix function - https://scikit-learn.org/stable/modules/generated/sklearn.metrics.plot_confusion_matrix.html\nimport itertools\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom sklearn.metrics import confusion_matrix\n\n# Our function needs a different name to sklearn's plot_confusion_matrix\ndef make_confusion_matrix(y_true, y_pred, classes=None, figsize=(10, 10), text_size=15, norm=False, savefig=False):\n  \"\"\"Makes a labelled confusion matrix comparing predictions and ground truth labels.\n\n  If classes is passed, confusion matrix will be labelled, if not, integer class values\n  will be used.\n\n  Args:\n    y_true: Array of truth labels (must be same shape as y_pred).\n    y_pred: Array of predicted labels (must be same shape as y_true).\n    classes: Array of class labels (e.g. string form). If `None`, integer labels are used.\n    figsize: Size of output figure (default=(10, 10)).\n    text_size: Size of output figure text (default=15).\n    norm: normalize values or not (default=False).\n    savefig: save confusion matrix to file (default=False).\n\n  Returns:\n    A labelled confusion matrix plot comparing y_true and y_pred.\n\n  Example usage:\n    make_confusion_matrix(y_true=test_labels, # ground truth test labels\n                          y_pred=y_preds, # predicted labels\n                          classes=class_names, # array of class label names\n                          figsize=(15, 15),\n                          text_size=10)\n  \"\"\"\n  # Create the confustion matrix\n  cm = confusion_matrix(y_true, y_pred)\n  cm_norm = cm.astype(\"float\") / cm.sum(axis=1)[:, np.newaxis] # normalize it\n  n_classes = cm.shape[0] # find the number of classes we're dealing with\n\n  # Plot the figure and make it pretty\n  fig, ax = plt.subplots(figsize=figsize)\n  cax = ax.matshow(cm, cmap=plt.cm.Blues) # colors will represent how 'correct' a class is, darker == better\n  fig.colorbar(cax)\n\n  # Are there a list of classes?\n  if classes:\n    labels = classes\n  else:\n    labels = np.arange(cm.shape[0])\n\n  # Label the axes\n  ax.set(title=\"Confusion Matrix\",\n         xlabel=\"Predicted label\",\n         ylabel=\"True label\",\n         xticks=np.arange(n_classes), # create enough axis slots for each class\n         yticks=np.arange(n_classes),\n         xticklabels=labels, # axes will labeled with class names (if they exist) or ints\n         yticklabels=labels)\n\n  # Make x-axis labels appear on bottom\n  ax.xaxis.set_label_position(\"bottom\")\n  ax.xaxis.tick_bottom()\n\n  ### Added: Rotate xticks for readability & increase font size (required due to such a large confusion matrix)\n  plt.xticks(rotation=70, fontsize=text_size)\n  plt.yticks(fontsize=text_size)\n\n  # Set the threshold for different colors\n  threshold = (cm.max() + cm.min()) / 2.\n\n  # Plot the text on each cell\n  for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n    if norm:\n      plt.text(j, i, f\"{cm[i, j]} ({cm_norm[i, j]*100:.1f}%)\",\n              horizontalalignment=\"center\",\n              color=\"white\" if cm[i, j] > threshold else \"black\",\n              size=text_size)\n    else:\n      plt.text(j, i, f\"{cm[i, j]}\",\n              horizontalalignment=\"center\",\n              color=\"white\" if cm[i, j] > threshold else \"black\",\n              size=text_size)\n\n  # Save the figure to the current working directory\n  if savefig:\n    fig.savefig(\"confusion_matrix.png\")","metadata":{"id":"tFgzOGN-GsOU"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Note: This might take a minute or so due to unravelling 790 batches\ny_labels = []\nfor images, labels in test_data.unbatch(): # unbatch the test data and get images and labels\n  y_labels.append(labels.numpy().argmax()) # append the index which has the largest value (labels are one-hot)\ny_labels[:10] # check what they look like (unshuffled)","metadata":{"id":"zVpgtpBOWN5n","outputId":"cc3ca0d5-c204-4588-b77d-acfbe28f17ba"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_names = test_data.class_names\nclass_names","metadata":{"id":"hI8Qgcm_WQsK","outputId":"4ad0b3fc-6155-4798-c61e-d7a505a439ca"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred_probs = model.predict(test_data, verbose=1) # set verbosity to see how long it will take","metadata":{"id":"zNweUJqzWS0p","outputId":"d5c95353-fe1e-4cb6-e5fc-b2d0fc56eaab"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Get the class predicitons of each label\npred_classes = pred_probs.argmax(axis=1)\n\n# How do they look\npred_classes[:10]","metadata":{"id":"WHe5FH04WXXi","outputId":"eb499a23-f101-44b6-f73d-1ed027ab1971"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plot a confusion matrix with all 25250 predictions, ground truth labels and 101 classes\nmake_confusion_matrix(y_true=y_labels,\n                      y_pred=pred_classes,\n                      classes=class_names,\n                      figsize=(50, 50),\n                      text_size=20,\n                      norm=False,\n                      savefig=True)","metadata":{"id":"m4xBE5MpWbyN"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import classification_report\nprint(classification_report(y_labels, pred_classes))","metadata":{"id":"zDc0mh0kWeZW"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Unfreeze all of the layers in the base model\nbase_model.trainable = True\n\n# Refreeze every layer except for the last 5\nfor layer in base_model.layers[25:43]:\n  layer.trainable = False","metadata":{"id":"TwZ0xop4WkHL"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Recompile model with lower learning rate\nmodel.compile(loss='categorical_crossentropy',\n              optimizer=tf.keras.optimizers.Adam(), # 10x lower learning rate than default\n              metrics=['accuracy'])","metadata":{"id":"AWtNqOTcXm7G"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Fine-tune for 5 more epochs\nfine_tune_epochs = 15 # model has already done 5 epochs, this is the total number of epochs we're after (5+5=10)\n\nmodelV2 = model.fit(train_data,\n                                                     epochs=20,\n                                                     validation_data=test_data,\n                                                     validation_steps=int(0.15 * len(test_data)), # validate on 15% of the test data\n                                                     initial_epoch=15) # start from previous last epoch","metadata":{"id":"USz7bxtvXrzN","outputId":"ddc2f66d-6a93-425a-f522-cf494c7534a2"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"modelV2 = model.evaluate(test_data)\nmodelV2","metadata":{"id":"neUQBK1nYEa1","outputId":"e4ea8c70-9776-45e6-ef97-ccc15cfc8809"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"id":"AZCSReesYMQM"},"execution_count":null,"outputs":[]}]}