{"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":"# [Implementing Fully Convolutional Networks (FCNs) from scratch in Keras and TensorFlow (Build image segmentation model from scratch) article](https://www.machinelearningnuggets.com/implementing-fully-convolutional-networks-fcns-from-scratch-in-keras-and-tensorflow/)","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nimport os\nimport random\nimport numpy as np\n \nfrom tqdm import tqdm \n\nfrom skimage.io import imread, imshow\nfrom skimage.transform import resize\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import train_test_split\n","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:23:27.783847Z","iopub.execute_input":"2022-12-10T07:23:27.784341Z","iopub.status.idle":"2022-12-10T07:23:27.790168Z","shell.execute_reply.started":"2022-12-10T07:23:27.784297Z","shell.execute_reply":"2022-12-10T07:23:27.789227Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from zipfile import ZipFile\nwith ZipFile(\"../input/data-science-bowl-2018/stage1_train.zip\",\"r\") as zip_ref:\n    zip_ref.extractall(\"./stage1_train\")\n    \nwith ZipFile(\"../input/data-science-bowl-2018/stage1_test.zip\",\"r\") as zip_ref:\n    zip_ref.extractall(\"./stage1_test\")    ","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:23:27.792855Z","iopub.execute_input":"2022-12-10T07:23:27.793543Z","iopub.status.idle":"2022-12-10T07:23:33.576087Z","shell.execute_reply.started":"2022-12-10T07:23:27.793504Z","shell.execute_reply":"2022-12-10T07:23:33.575019Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# __author__ = \"Sreenivas Bhattiprolu\"\n# https://www.youtube.com/watch?v=0kiroPnV1tM\nseed = 42\nnp.random.seed = seed\n\nIMG_WIDTH = 128\nIMG_HEIGHT = 128\nIMG_CHANNELS = 3\n\nTRAIN_PATH = 'stage1_train/'\nTEST_PATH = 'stage1_test/'\n\ntrain_ids = next(os.walk(TRAIN_PATH))[1]\ntest_ids = next(os.walk(TEST_PATH))[1]\n\nX = np.zeros((len(train_ids), IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS), dtype=np.uint8)\ny = np.zeros((len(train_ids), IMG_HEIGHT, IMG_WIDTH, 1), dtype=bool)","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:23:33.577773Z","iopub.execute_input":"2022-12-10T07:23:33.578172Z","iopub.status.idle":"2022-12-10T07:23:33.587588Z","shell.execute_reply.started":"2022-12-10T07:23:33.578135Z","shell.execute_reply":"2022-12-10T07:23:33.586350Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('Resizing training images and masks')\nfor n, id_ in tqdm(enumerate(train_ids), total=len(train_ids)):   \n    path = TRAIN_PATH + id_\n    img = imread(path + '/images/' + id_ + '.png')[:,:,:IMG_CHANNELS]  \n    img = resize(img, (IMG_HEIGHT, IMG_WIDTH), mode='constant', preserve_range=True)\n    X[n] = img  #Fill empty X_train with values from img\n    mask = np.zeros((IMG_HEIGHT, IMG_WIDTH, 1), dtype=bool)\n    for mask_file in next(os.walk(path + '/masks/'))[2]:\n        mask_ = imread(path + '/masks/' + mask_file)\n        mask_ = np.expand_dims(resize(mask_, (IMG_HEIGHT, IMG_WIDTH), mode='constant',  \n                                      preserve_range=True), axis=-1)\n        mask = np.maximum(mask, mask_)  \n            \n    y[n] = mask ","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:23:33.589327Z","iopub.execute_input":"2022-12-10T07:23:33.589767Z","iopub.status.idle":"2022-12-10T07:27:36.648863Z","shell.execute_reply.started":"2022-12-10T07:23:33.589733Z","shell.execute_reply":"2022-12-10T07:27:36.647699Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# test images\ntest_images = np.zeros((len(test_ids), IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS), dtype=np.uint8)\nsizes_test = []\nprint('Resizing test images') \nfor n, id_ in tqdm(enumerate(test_ids), total=len(test_ids)):\n    path = TEST_PATH + id_\n    img = imread(path + '/images/' + id_ + '.png')[:,:,:IMG_CHANNELS]\n    sizes_test.append([img.shape[0], img.shape[1]])\n    img = resize(img, (IMG_HEIGHT, IMG_WIDTH), mode='constant', preserve_range=True)\n    test_images[n] = img\n\nprint('Done!')","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:36.652278Z","iopub.execute_input":"2022-12-10T07:27:36.652688Z","iopub.status.idle":"2022-12-10T07:27:38.003444Z","shell.execute_reply.started":"2022-12-10T07:27:36.652647Z","shell.execute_reply":"2022-12-10T07:27:38.002195Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:38.005457Z","iopub.execute_input":"2022-12-10T07:27:38.005906Z","iopub.status.idle":"2022-12-10T07:27:38.027748Z","shell.execute_reply.started":"2022-12-10T07:27:38.005850Z","shell.execute_reply":"2022-12-10T07:27:38.026868Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(X_test)","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:38.029352Z","iopub.execute_input":"2022-12-10T07:27:38.029730Z","iopub.status.idle":"2022-12-10T07:27:38.037781Z","shell.execute_reply.started":"2022-12-10T07:27:38.029696Z","shell.execute_reply":"2022-12-10T07:27:38.036742Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_x = random.randint(0, len(X_train))\nplt.axis(\"off\")\nimshow(X_train[image_x])\nplt.show()\nplt.axis(\"off\")\nimshow(np.squeeze(y_train[image_x]))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:38.039355Z","iopub.execute_input":"2022-12-10T07:27:38.039973Z","iopub.status.idle":"2022-12-10T07:27:38.270337Z","shell.execute_reply.started":"2022-12-10T07:27:38.039929Z","shell.execute_reply":"2022-12-10T07:27:38.269191Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_classes = 1","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:38.271789Z","iopub.execute_input":"2022-12-10T07:27:38.272367Z","iopub.status.idle":"2022-12-10T07:27:38.276593Z","shell.execute_reply.started":"2022-12-10T07:27:38.272331Z","shell.execute_reply":"2022-12-10T07:27:38.275533Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"inputs = tf.keras.layers.Input(shape=(None, None, 3))","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:38.278087Z","iopub.execute_input":"2022-12-10T07:27:38.278754Z","iopub.status.idle":"2022-12-10T07:27:39.562032Z","shell.execute_reply.started":"2022-12-10T07:27:38.278676Z","shell.execute_reply":"2022-12-10T07:27:39.561050Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def encoder(inputs):\n    c1 = tf.keras.layers.Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(inputs)\n    c1 = tf.keras.layers.Dropout(0.1)(c1)\n    c1 = tf.keras.layers.Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c1)\n    p1 = tf.keras.layers.MaxPooling2D((2, 2))(c1)\n\n    c2 = tf.keras.layers.Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p1)\n    c2 = tf.keras.layers.Dropout(0.1)(c2)\n    c2 = tf.keras.layers.Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c2)\n    p2 = tf.keras.layers.MaxPooling2D((2, 2))(c2)\n\n    c3 = tf.keras.layers.Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p2)\n    c3 = tf.keras.layers.Dropout(0.2)(c3)\n    c3 = tf.keras.layers.Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c3)\n    p3 = tf.keras.layers.MaxPooling2D((2, 2))(c3)\n\n    c4 = tf.keras.layers.Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p3)\n    c4 = tf.keras.layers.Dropout(0.2)(c4)\n    c4 = tf.keras.layers.Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c4)\n    p4 = tf.keras.layers.MaxPooling2D(pool_size=(2, 2))(c4)\n\n    c5 = tf.keras.layers.Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p4)\n    c5 = tf.keras.layers.Dropout(0.2)(c5)\n    c5 = tf.keras.layers.Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c5)\n    p5 = tf.keras.layers.MaxPooling2D(pool_size=(2, 2))(c5)\n\n    c6 = tf.keras.layers.Conv2D(256, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p5)\n    c6 = tf.keras.layers.Dropout(0.3)(c6)\n    c6 = tf.keras.layers.Conv2D(256, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c6)\n\n    u6 = tf.keras.layers.Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same')(c6)\n    c6 = tf.keras.layers.Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u6)\n    c6 = tf.keras.layers.Dropout(0.2)(c6)\n    c6 = tf.keras.layers.Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c6)\n    return c6","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:39.563411Z","iopub.execute_input":"2022-12-10T07:27:39.563774Z","iopub.status.idle":"2022-12-10T07:27:39.579808Z","shell.execute_reply.started":"2022-12-10T07:27:39.563739Z","shell.execute_reply":"2022-12-10T07:27:39.578696Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def decoder(c6):\n    u7 = tf.keras.layers.Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(c6)\n    c7 = tf.keras.layers.Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u7)\n    c7 = tf.keras.layers.Add()([u7, c7])\n\n    u8 = tf.keras.layers.Conv2DTranspose(32, (2, 2), strides=(2, 2), padding='same')(c7)\n    c8 = tf.keras.layers.Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u8)\n    c8 = tf.keras.layers.Add()([u8, c8])\n\n    u9 = tf.keras.layers.Conv2DTranspose(16, (2, 2), strides=(2, 2), padding='same')(c8)\n    c9 = tf.keras.layers.Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u9)\n    c9 = tf.keras.layers.Add()([u9, c9])\n\n    u10 = tf.keras.layers.Conv2DTranspose(16, (2, 2), strides=(2, 2), padding='same')(c9)\n    c10 = tf.keras.layers.Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u10)\n    c10 = tf.keras.layers.Add()([u10, c10])\n\n    outputs = tf.keras.layers.Conv2D(num_classes, (1, 1), activation='sigmoid')(c10)\n    return outputs\n","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:39.581569Z","iopub.execute_input":"2022-12-10T07:27:39.582255Z","iopub.status.idle":"2022-12-10T07:27:39.613450Z","shell.execute_reply.started":"2022-12-10T07:27:39.582215Z","shell.execute_reply":"2022-12-10T07:27:39.612310Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"encoder = encoder(inputs)\noutputs = decoder(encoder)","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:39.615227Z","iopub.execute_input":"2022-12-10T07:27:39.616046Z","iopub.status.idle":"2022-12-10T07:27:45.714826Z","shell.execute_reply.started":"2022-12-10T07:27:39.616003Z","shell.execute_reply":"2022-12-10T07:27:45.713890Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = tf.keras.Model(inputs=[inputs], outputs=[outputs])","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:45.719606Z","iopub.execute_input":"2022-12-10T07:27:45.720306Z","iopub.status.idle":"2022-12-10T07:27:45.730238Z","shell.execute_reply.started":"2022-12-10T07:27:45.720269Z","shell.execute_reply":"2022-12-10T07:27:45.729349Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:45.731541Z","iopub.execute_input":"2022-12-10T07:27:45.731889Z","iopub.status.idle":"2022-12-10T07:27:45.745093Z","shell.execute_reply.started":"2022-12-10T07:27:45.731859Z","shell.execute_reply":"2022-12-10T07:27:45.743956Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.keras.utils.plot_model(model, \"model.png\",show_shapes=True)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:45.747004Z","iopub.execute_input":"2022-12-10T07:27:45.747344Z","iopub.status.idle":"2022-12-10T07:27:47.871115Z","shell.execute_reply.started":"2022-12-10T07:27:45.747307Z","shell.execute_reply":"2022-12-10T07:27:47.869158Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:47.872596Z","iopub.execute_input":"2022-12-10T07:27:47.873092Z","iopub.status.idle":"2022-12-10T07:27:47.896068Z","shell.execute_reply.started":"2022-12-10T07:27:47.873049Z","shell.execute_reply":"2022-12-10T07:27:47.895083Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"callbacks = [\n        tf.keras.callbacks.EarlyStopping(patience=15, monitor='val_loss'),\n        tf.keras.callbacks.TensorBoard(log_dir='logs')]\n\nmodel.fit(X_train, y_train, validation_data=(X_test,y_test), batch_size=16, epochs=100, callbacks=callbacks)","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:27:47.897363Z","iopub.execute_input":"2022-12-10T07:27:47.897925Z","iopub.status.idle":"2022-12-10T07:29:06.397493Z","shell.execute_reply.started":"2022-12-10T07:27:47.897888Z","shell.execute_reply":"2022-12-10T07:29:06.396498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loss = model.history.history['loss']\nval_loss = model.history.history['val_loss']\n\nplt.figure()\nplt.plot( loss, 'r', label='Training loss')\nplt.plot( val_loss, 'bo', label='Validation loss')\nplt.title('Training and Validation Loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss Value')\nplt.ylim([0, 1])\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:29:06.399659Z","iopub.execute_input":"2022-12-10T07:29:06.400517Z","iopub.status.idle":"2022-12-10T07:29:12.425488Z","shell.execute_reply.started":"2022-12-10T07:29:06.400478Z","shell.execute_reply":"2022-12-10T07:29:12.424530Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"accuracy = model.history.history['accuracy']\nval_accuracy = model.history.history['val_accuracy']\n\nplt.figure()\nplt.plot( accuracy, 'r', label='Training accuracy')\nplt.plot( val_accuracy, 'bo', label='Validation accuracy')\nplt.title('Training and Validation accuracy')\nplt.xlabel('Epoch')\nplt.ylabel('Loss Value')\nplt.ylim([0, 1])\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:29:12.427055Z","iopub.execute_input":"2022-12-10T07:29:12.427423Z","iopub.status.idle":"2022-12-10T07:29:12.638267Z","shell.execute_reply.started":"2022-12-10T07:29:12.427387Z","shell.execute_reply":"2022-12-10T07:29:12.637385Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def display(display_list):\n  plt.figure(figsize=(15, 15))\n\n  title = ['Input image', 'True mask', 'Predicted mask']\n\n  for i in range(len(display_list)):\n    plt.subplot(1, len(display_list), i+1)\n    plt.title(title[i])\n    plt.imshow(tf.keras.utils.array_to_img(display_list[i]))\n    plt.axis('off')\n  plt.show()","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:29:12.639614Z","iopub.execute_input":"2022-12-10T07:29:12.639918Z","iopub.status.idle":"2022-12-10T07:29:12.645711Z","shell.execute_reply.started":"2022-12-10T07:29:12.639893Z","shell.execute_reply":"2022-12-10T07:29:12.644698Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"i = random.randint(0, len(X_test))\nsample_image = X_test[i]\nsample_mask = y_test[i]","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:29:46.035373Z","iopub.execute_input":"2022-12-10T07:29:46.035989Z","iopub.status.idle":"2022-12-10T07:29:46.041563Z","shell.execute_reply.started":"2022-12-10T07:29:46.035944Z","shell.execute_reply":"2022-12-10T07:29:46.040144Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions = model.predict(X_test)","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:29:46.351439Z","iopub.execute_input":"2022-12-10T07:29:46.351786Z","iopub.status.idle":"2022-12-10T07:29:46.542791Z","shell.execute_reply.started":"2022-12-10T07:29:46.351757Z","shell.execute_reply":"2022-12-10T07:29:46.541865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(predictions[0])","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:29:46.657462Z","iopub.execute_input":"2022-12-10T07:29:46.658117Z","iopub.status.idle":"2022-12-10T07:29:46.666543Z","shell.execute_reply.started":"2022-12-10T07:29:46.658076Z","shell.execute_reply":"2022-12-10T07:29:46.665648Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(predictions)","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:29:46.930548Z","iopub.execute_input":"2022-12-10T07:29:46.931451Z","iopub.status.idle":"2022-12-10T07:29:46.938803Z","shell.execute_reply.started":"2022-12-10T07:29:46.931402Z","shell.execute_reply":"2022-12-10T07:29:46.937785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"prediction = model.predict(sample_image[tf.newaxis, ...])[0]","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:29:47.231937Z","iopub.execute_input":"2022-12-10T07:29:47.232522Z","iopub.status.idle":"2022-12-10T07:29:47.278215Z","shell.execute_reply.started":"2022-12-10T07:29:47.232482Z","shell.execute_reply":"2022-12-10T07:29:47.277123Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predicted_mask = (prediction > 0.5).astype(np.uint8)","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:29:47.591240Z","iopub.execute_input":"2022-12-10T07:29:47.591954Z","iopub.status.idle":"2022-12-10T07:29:47.598249Z","shell.execute_reply.started":"2022-12-10T07:29:47.591912Z","shell.execute_reply":"2022-12-10T07:29:47.597117Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display([sample_image, sample_mask,predicted_mask])","metadata":{"execution":{"iopub.status.busy":"2022-12-10T07:29:48.026722Z","iopub.execute_input":"2022-12-10T07:29:48.027593Z","iopub.status.idle":"2022-12-10T07:29:48.290550Z","shell.execute_reply.started":"2022-12-10T07:29:48.027551Z","shell.execute_reply":"2022-12-10T07:29:48.289597Z"},"trusted":true},"execution_count":null,"outputs":[]}]}