{"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":"# TP Data parallelism for Computer Vision : Breast Cancer Detection","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-04-03T07:19:41.961321Z","iopub.execute_input":"2023-04-03T07:19:41.962053Z","iopub.status.idle":"2023-04-03T07:19:42.012017Z","shell.execute_reply.started":"2023-04-03T07:19:41.96202Z","shell.execute_reply":"2023-04-03T07:19:42.010219Z"}}},{"cell_type":"markdown","source":"## Imports","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nimport matplotlib.pyplot as plt\nimport time\nimport numpy as np\nimport pandas as pd","metadata":{"execution":{"iopub.status.busy":"2023-04-07T14:03:32.836292Z","iopub.execute_input":"2023-04-07T14:03:32.83666Z","iopub.status.idle":"2023-04-07T14:03:48.846946Z","shell.execute_reply.started":"2023-04-07T14:03:32.836612Z","shell.execute_reply":"2023-04-07T14:03:48.845707Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Load the data","metadata":{}},{"cell_type":"code","source":"IMG_DIRECTORY : str = '/kaggle/input/breast-images-png/'\ndef generate_df(file_path : str) -> pd.DataFrame:\n    df = pd.read_csv(file_path)\n    df[\"path\"] = IMG_DIRECTORY  + df[\"patient_id\"].astype(str) + \"_\" + df[\"image_id\"].astype(str) + \".png\"\n    return df\nbreast_cancer_detection_df = generate_df(\"/kaggle/input/rsna-breast-cancer-detection/train.csv\")","metadata":{"execution":{"iopub.status.busy":"2023-04-07T14:03:48.849561Z","iopub.execute_input":"2023-04-07T14:03:48.850471Z","iopub.status.idle":"2023-04-07T14:03:49.081887Z","shell.execute_reply.started":"2023-04-07T14:03:48.850426Z","shell.execute_reply":"2023-04-07T14:03:49.080758Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"strategy = tf.distribute.MirroredStrategy()\nIMG_SIZE = 256\n\nBATCH_SIZE = 32*strategy.num_replicas_in_sync\nAUTO = tf.data.AUTOTUNE\n\ndef load_dataset(df: pd.DataFrame)-> tf.data.Dataset :\n    paths = df.path.values\n    labels = df.cancer.values\n    def decode_img(paths, labels):\n        raw = tf.io.read_file(paths)\n        img = tf.io.decode_png(raw, channels=3)\n        img = tf.image.resize(img, (IMG_SIZE, IMG_SIZE))\n        img = tf.reshape(img, (IMG_SIZE, IMG_SIZE, 3))\n        return img, tf.cast(labels, tf.float32)\n    ds = tf.data.Dataset.from_tensor_slices((paths, labels))\n    ds = ds.map(decode_img, num_parallel_calls=AUTO)\n    return ds\n\n\ndef get_dataset(df: pd.DataFrame) -> tf.data.Dataset :\n    ds = load_dataset(df)\n    options = tf.data.Options()\n    options.experimental_distribute.auto_shard_policy = tf.data.experimental.AutoShardPolicy.DATA\n    ds = ds.with_options(options)\n    ds = ds.batch(BATCH_SIZE)\n    ds = ds.prefetch(AUTO)\n    return ds","metadata":{"execution":{"iopub.status.busy":"2023-04-07T14:03:49.083243Z","iopub.execute_input":"2023-04-07T14:03:49.083639Z","iopub.status.idle":"2023-04-07T14:03:54.620779Z","shell.execute_reply.started":"2023-04-07T14:03:49.083599Z","shell.execute_reply":"2023-04-07T14:03:54.619244Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Retrive DataSets","metadata":{}},{"cell_type":"code","source":"ds = get_dataset(breast_cancer_detection_df)","metadata":{"execution":{"iopub.status.busy":"2023-04-07T14:03:54.624061Z","iopub.execute_input":"2023-04-07T14:03:54.624712Z","iopub.status.idle":"2023-04-07T14:03:54.741007Z","shell.execute_reply.started":"2023-04-07T14:03:54.624666Z","shell.execute_reply":"2023-04-07T14:03:54.739738Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Display some images","metadata":{}},{"cell_type":"code","source":"elements = ds.skip(0).take(1)\nnb_images = 3\nfor e in elements:\n    images = e[0].numpy().astype('uint8')\n    for img in images[0:nb_images]:\n        plt.imshow(img)\n        plt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-04-07T14:03:54.742501Z","iopub.execute_input":"2023-04-07T14:03:54.742888Z","iopub.status.idle":"2023-04-07T14:03:55.939343Z","shell.execute_reply.started":"2023-04-07T14:03:54.742836Z","shell.execute_reply":"2023-04-07T14:03:55.938221Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Build a simple CNN model (such as mnist example)","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras import Sequential, Model\nfrom tensorflow.keras.layers import Conv2D,MaxPooling2D, MaxPooling2D, Dropout,Flatten, Dense\n\n\ndef build_model() -> Model:\n    model = tf.keras.Sequential([\n        Conv2D(filters=32, kernel_size=(3, 3), activation='relu', input_shape=(256, 256, 3)),\n        MaxPooling2D(pool_size=(2, 2)),\n        Conv2D(filters=64, kernel_size=(3, 3),activation='relu'),\n        MaxPooling2D(pool_size=(2, 2)),\n        Flatten(),\n        Dense(16, activation='sigmoid')\n    ])\n\n    model.compile(loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n                optimizer=tf.keras.optimizers.Adam(),\n                metrics=['accuracy'])\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2023-04-07T14:39:52.537596Z","iopub.execute_input":"2023-04-07T14:39:52.538816Z","iopub.status.idle":"2023-04-07T14:39:52.550591Z","shell.execute_reply.started":"2023-04-07T14:39:52.538755Z","shell.execute_reply":"2023-04-07T14:39:52.548622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Building models","metadata":{}},{"cell_type":"code","source":"\ndef multi_gpu_model():\n    with strategy.scope():\n        multi_model = build_model()\n        return multi_model\n\n\n# Initialize one GPU model\nsimple_model = build_model()\nsimple_model.summary()\n","metadata":{"execution":{"iopub.status.busy":"2023-04-07T14:40:11.551621Z","iopub.execute_input":"2023-04-07T14:40:11.552618Z","iopub.status.idle":"2023-04-07T14:40:11.636682Z","shell.execute_reply.started":"2023-04-07T14:40:11.552562Z","shell.execute_reply":"2023-04-07T14:40:11.635895Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training models","metadata":{}},{"cell_type":"code","source":"import time \n\nEPOCHS = 5\ndef run_model(model: Model,ds: tf.data.Dataset) -> [ tf.keras.callbacks.History, float ]:\n    start_time = time.time()\n    history = model.fit(ds, epochs=EPOCHS,use_multiprocessing=True)\n    end_time = time.time()\n    total_time = end_time - start_time\n    return history, total_time","metadata":{"execution":{"iopub.status.busy":"2023-04-07T15:10:37.61192Z","iopub.execute_input":"2023-04-07T15:10:37.612864Z","iopub.status.idle":"2023-04-07T15:10:37.619812Z","shell.execute_reply.started":"2023-04-07T15:10:37.612811Z","shell.execute_reply":"2023-04-07T15:10:37.618071Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"simple_history, total_simple_model_time = run_model(simple_model,ds)\ngpu_history,total_gpu_time = run_model(multi_gpu_model(),ds)","metadata":{"execution":{"iopub.status.busy":"2023-04-07T14:40:22.252241Z","iopub.execute_input":"2023-04-07T14:40:22.252881Z","iopub.status.idle":"2023-04-07T15:02:06.328542Z","shell.execute_reply.started":"2023-04-07T14:40:22.252838Z","shell.execute_reply":"2023-04-07T15:02:06.327457Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Accuracy comparison","metadata":{}},{"cell_type":"code","source":"print(f\"One GPU time = {total_simple_model_time}\")\nprint(f\"Two GPU time = {total_gpu_time}\")\n\nfig, axs = plt.subplots(1, 2,figsize=(18,8))\naxs[0].plot(gpu_history.history['accuracy'],label = '2 GPUs')\naxs[0].plot(simple_history.history['accuracy'],label = '1 GPU')\naxs[0].set_title('model accuracy')\naxs[0].set_ylabel('accuracy')\naxs[0].set_xlabel('epoch')\naxs[1].plot(simple_history.history['loss'],label = '1 GPU')\naxs[1].plot(gpu_history.history['loss'],label = '2 GPUs')\naxs[1].set_title('model loss')\naxs[1].set_ylabel('accuracy')\naxs[1].set_xlabel('epoch')\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-04-07T15:02:17.828114Z","iopub.execute_input":"2023-04-07T15:02:17.828503Z","iopub.status.idle":"2023-04-07T15:02:18.291712Z","shell.execute_reply.started":"2023-04-07T15:02:17.828469Z","shell.execute_reply":"2023-04-07T15:02:18.290685Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Analysis\n### Accuracy\nWe can see that the 2GPUs model is constantly increasing in accuracy whereas the single GPU model is slowly decreasing after first epoch.\n### Loss\nWe can see that the single GPU execution has a better loss result than the 2GPUs.\n### Execution time\nWe can see that 2GPUs execution is faster much faster than the single GPU.","metadata":{}}]}