{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":8089,"databundleVersionId":44321,"sourceType":"competition"},{"sourceId":24242,"sourceType":"datasetVersion","datasetId":18570}],"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Intro\n\nThis piece of work is inspired by a [youtube video lecture](https://www.youtube.com/watch?v=vaL1I2BD_xY) by Martin Gorner, a Google developer \nwho put forth this idea of combining YOLO grid with SqueezeNet (instead of DarkNet - original stack for [YOLO](https://arxiv.org/pdf/1506.02640.pdf)).","metadata":{"_cell_guid":"e1f0f9ef-b2c2-4fe0-8098-24bd8b6cbbf9","_uuid":"6d83a1815b19019b63290af1a21834be59701070"}},{"cell_type":"code","source":"import os\nimport sys\nimport numpy as np\nimport tensorflow as tf\nimport random\nimport math\nimport warnings\nimport pandas as pd\nimport cv2\nimport matplotlib.pyplot as plt\nimport matplotlib.cm as cm\nimport matplotlib.ticker as ticker\n\nfrom tqdm import tqdm\nfrom itertools import chain\nfrom skimage.io import imread, imshow, imread_collection, concatenate_images\nfrom skimage.transform import resize\nfrom skimage.morphology import label\n\nwarnings.filterwarnings('ignore')\n# warnings.filterwarnings('ignore', category=UserWarning)\n# warnings.filterwarnings('ignore', category=FutureWarning)\n\nseed = 42\nrandom.seed = seed\ntf.random.set_seed = seed\nnp.random.seed = seed","metadata":{"_cell_guid":"04e6a10f-9963-48e1-9f87-def2cf0c7616","_uuid":"ace99be745c98fc8919e877a991adf5bde701ac3","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('TensorFlow version', tf.__version__)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# os.listdir('/kaggle/input/yolo-from-scratch-tensorflow-2')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def set_seeds(seed=24):\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    random.seed = seed\n    tf.random.set_seed = seed\n    np.random.seed = seed    \n    \n# def set_global_determinism(seed=24):\n#     set_seeds(seed=seed)\n\n#     os.environ['TF_DETERMINISTIC_OPS'] = '1'\n#     os.environ['TF_CUDNN_DETERMINISTIC'] = '1'\n    \n#     tf.config.threading.set_inter_op_parallelism_threads(1)\n#     tf.config.threading.set_intra_op_parallelism_threads(1)\n\n# Call the above function with seed value\nset_seeds(seed=24)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMG_WIDTH = 384\nIMG_HEIGHT = 384\nIMG_CHANNELS = 3\n\n\nROOT_DIR = \"/kaggle/input/data-science-bowl-2018\"\nWORKING_DIR = \"/kaggle/working\"\nTRAIN_PATH = f'{WORKING_DIR}/train'\nTEST_PATH = f'{WORKING_DIR}/test'","metadata":{"_cell_guid":"53fa742a-7b4c-4490-837c-016b3c34c3d5","_uuid":"a9e074a502adde1fffb5be9139934ffeb700dfdf","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# importing required modules\nfrom zipfile import ZipFile \n\n# specifying the zip file name \ntrain_zip_file = f\"{ROOT_DIR}/stage1_train.zip\"\ntest_zip_file = f\"{ROOT_DIR}/stage1_test.zip\"\n\n# opening the zip file in READ mode \nwith ZipFile(train_zip_file, 'r') as zip: \n    # printing all the contents of the zip file \n#     zip.printdir() \n  \n    # extracting all the files \n    print('Extracting all the files for training...') \n    zip.extractall(path=TRAIN_PATH) \n    print('Done!') \n    \n# opening the zip file in READ mode \nwith ZipFile(test_zip_file, 'r') as zip: \n    # printing all the contents of the zip file \n#     zip.printdir() \n  \n    # extracting all the files \n    print('Extracting all the files for testing...') \n    zip.extractall(path=TEST_PATH) \n    print('Done!') ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_ids = next(os.walk(TRAIN_PATH))[1]\ntest_ids = next(os.walk(TEST_PATH))[1]\n\ntrain_images = np.zeros((len(train_ids), IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS), dtype=np.uint8)\ntest_images = np.zeros((len(test_ids), IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS), dtype=np.uint8)","metadata":{"_cell_guid":"c7cadfa9-4b8c-4a72-8042-38b82b57e6c8","_uuid":"a7f29a280bd557e3d42de110d60ec60bf254a21d","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Resize train images.\nprint('resize train images... ')\nsys.stdout.flush()\n\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    \n    train_images[n] = img\n\nprint('Done!')","metadata":{"scrolled":true,"_cell_guid":"61bd8439-48fa-4ff8-b308-2c06e736e55e","_uuid":"cb2c127840f51e9f63d22b7d4bc691433ed3812c","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def store_bounding_boxes(img, train_id, mask_id, rotby_90):\n    ret, thresh = cv2.threshold(img, 127, 255, 0)\n    contours, _ = cv2.findContours(thresh.astype(np.uint8), 1, 2)\n    cnt = contours[0]\n        \n    x, y, w, h = cv2.boundingRect(cnt)    \n    \n    x = x * (IMG_WIDTH/img.shape[1])\n    w = w * (IMG_WIDTH/img.shape[1])\n    y = y * (IMG_WIDTH/img.shape[0])\n    h = h * (IMG_WIDTH/img.shape[0])\n    \n    if(x > IMG_WIDTH-1):\n        x = IMG_WIDTH-1\n    if(y > IMG_HEIGHT-1):\n        y = IMG_HEIGHT-1\n    if(x+w > IMG_WIDTH-1):\n        w = IMG_WIDTH-1 - x\n    if(y+h > IMG_HEIGHT-1):\n        h = IMG_HEIGHT-1 - y\n        \n    bbdict = { \"train_id\": train_id, \"mask_id\": mask_id, \"rotby_90\": rotby_90, \"x\": x, \"y\": y, \"w\": w, \"h\": h}\n    return bbdict","metadata":{"_cell_guid":"f323fcc1-f5ad-49da-ae66-9114f02d318b","_uuid":"05c2163cc42f5cfbc0064f4bcf2ee542ee3d10b6","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# path_bboxes_csv = \"/kaggle/working/bboxes.csv\"\npath_bboxes_csv = '/kaggle/input/d/vijaybj/data-science-bowl-2018/bboxes.csv'\nif not os.path.isfile(path_bboxes_csv):\n    bboxes = pd.DataFrame(columns=[\"train_id\", \"mask_id\", \"rotby_90\", \"x\", \"y\", \"w\", \"h\"])\n    row_count = 1\n    for n, id_ in tqdm(enumerate(train_ids), total=len(train_ids)):\n        path = TRAIN_PATH + \"/\" + id_\n        for mask_id, mask_file in enumerate(next(os.walk(path + '/masks/'))[2]):\n            mask_ = imread(path + '/masks/' + mask_file)\n            for r in range(4):\n                bboxes.loc[row_count] = store_bounding_boxes(np.rot90(mask_, r), id_, mask_id, r)\n                row_count += 1\n    bboxes.to_csv('bboxes.csv', index=False)\nelse:\n    bboxes = pd.read_csv(path_bboxes_csv)","metadata":{"scrolled":true,"_cell_guid":"8bf9d677-d161-4965-98f1-1898235bfb3e","_uuid":"e7e51d42966cbfb60988aaae2c97d27ed036e16e","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"GRID_DIM = 12\nGRID_PIX = IMG_WIDTH//GRID_DIM\nBATCH_SIZE = 16","metadata":{"_cell_guid":"3fe09645-5de6-42cf-ac58-a27cd8f07842","_uuid":"b9fe4667636d82dfb581816be128ed701e050721","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_ids_df = pd.DataFrame(columns=[\"idx\", \"id_\"])\ncnt = 0\nfor n, id_ in tqdm(enumerate(train_ids), total=len(train_ids)):\n    train_ids_df.loc[cnt] = { \"idx\": n, \"id_\": id_}\n    cnt += 1\n\ntrain_ids_df = train_ids_df.set_index(['idx'])","metadata":{"_cell_guid":"4539f816-97c4-4076-a736-89b8f83f0f10","_uuid":"34821e885175fe4fc94c03f5eebd57d056dbb7a8","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"bboxes['grid_row'] = bboxes['y']//GRID_PIX\nbboxes['grid_column'] = bboxes['x']//GRID_PIX\n\nbboxes['grid_center_x'] = bboxes['grid_column'] * GRID_PIX + GRID_PIX/2\nbboxes['grid_center_y'] = bboxes['grid_row'] * GRID_PIX + GRID_PIX/2\n\nbboxes['box_center_x'] = bboxes.x + bboxes['w']/2\nbboxes['box_center_y'] = bboxes.y + bboxes['h']/2\n\nbboxes['new_x'] = (bboxes.box_center_x - bboxes.grid_center_x)/(IMG_WIDTH)\nbboxes['new_y'] = (bboxes.box_center_y - bboxes.grid_center_y)/(IMG_HEIGHT)\n\nbboxes['new_w'] = np.sqrt(bboxes.w/(IMG_WIDTH))\nbboxes['new_h'] = np.sqrt(bboxes.h/(IMG_WIDTH))\n\nbboxes['confidence'] = 1\n\nbboxes['box_area'] = bboxes.new_w*bboxes.new_h","metadata":{"scrolled":true,"_cell_guid":"57f6e469-ff8f-4640-9c49-066230d172b4","_uuid":"34f67397be5647147d935e46c1d4c2676a2b329f","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mask_count = 1\n#Set maximum bounding boxes allowed per grid cell\nMAX_BB_CNT = 2","metadata":{"scrolled":true,"_cell_guid":"393aa0a8-1460-435b-b138-126358f7c71f","_uuid":"fc694c7985f0fdf7f9afcc957a12599d2a700310","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_grid_info(tr_id, rotby_90):\n    df = bboxes.loc[(bboxes.train_id == tr_id) & (bboxes.rotby_90 == rotby_90), 'grid_row':'box_area']\n    df.drop(['grid_center_x', 'grid_center_y','box_center_x', 'box_center_y',], axis = 1, inplace=True)\n    df = df.sort_values(['grid_column', 'grid_row', 'box_area'], ascending=False)\n    #print(len(df))\n    global mask_count\n    mask_count += len(df)\n    label_info = np.zeros(shape=(GRID_DIM, GRID_DIM, MAX_BB_CNT, 5),  dtype=np.float32) + 0.000001\n    \n    for ind, row in df.iterrows():\n        i = int(row[0])\n        j = int(row[1])\n        for b in range(MAX_BB_CNT):\n            if(label_info[i, j, b][4] != 1.0):\n                label_info[i, j, b] = np.array(row[2:7])\n                break\n    return label_info","metadata":{"_cell_guid":"bebafd3e-3c9e-4553-8951-12bc50c9275a","_uuid":"d98d67b7a65591259de624a4e684d8c66146e2d1","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomDataGenerator(tf.keras.utils.Sequence):\n    def __init__(self, train_images, batch_size=32, n_channels=3, shuffle=True):\n        self.train_ids = train_ids\n        self.train_images = train_images\n        self.batch_size = batch_size\n        self.n_channels = n_channels\n        self.shuffle = shuffle\n        self.indexes = np.arange(len(self.train_images))\n        \n        self.on_epoch_end()\n\n    def __len__(self):\n        # Denotes the number of batches per epoch\n        return len(self.train_images) // self.batch_size\n\n    def __getitem__(self, index):\n        # Generate one batch of data\n        indexes = self.indexes[index * self.batch_size:(index + 1) * self.batch_size]\n\n        batch_images, batch_labels = self.__get_data(indexes)\n#         print('indices:', indexes)\n#         print('image paths:', batch_image_paths)\n\n        return batch_images, batch_labels\n\n    def on_epoch_end(self):\n        # Shuffle data at the end of each epoch\n        if self.shuffle == True:\n            np.random.shuffle(self.indexes)\n\n    def __get_data(self, indexes):\n        #'Generates data containing batch_size samples'\n        batch_images = np.empty(shape=(self.batch_size, IMG_HEIGHT, IMG_WIDTH, self.n_channels))\n        batch_labels = np.empty(shape=(self.batch_size, GRID_DIM, GRID_DIM, MAX_BB_CNT, 5))\n        for i, idx in enumerate(indexes):\n            rotation = random.randint(0, 3)\n            img = self.__get_image(idx, rotation)\n            label = self.__get_label(idx, rotation)\n\n            batch_images[i] = img\n            batch_labels[i] = label\n    \n        return batch_images, batch_labels\n    \n    def __get_image(self, index, rotation):\n        image = np.rot90(train_images[index], rotation)\n        return image\n\n    def __get_label(self, index, rotation):\n        grid_info = get_grid_info(train_ids[index], rotation)\n        return grid_info             \n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def draw_bboxes(img, bbs1):\n#     print(img.shape)\n    f, axs = plt.subplots(1,2)\n    axs[0].imshow(img)\n    for i, b in enumerate(bbs1):\n        cv2.rectangle(img,(b[0], b[1]),(b[2], b[3]),(0,255,0),2)\n\n    axs[1].imshow(img)","metadata":{"_cell_guid":"4d109332-ee00-4ce5-b928-2981ebccbe1a","_uuid":"012a319735ee860225612b3db531dcc7de34dce7","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"grid_dim = GRID_DIM\nmax_bbox_count = MAX_BB_CNT\ngrid_pix = GRID_PIX\nimg_width = IMG_WIDTH\nimg_height = IMG_HEIGHT\n\ndef draw_data(img, boxes1, thresh):\n    print(boxes1.shape)\n#     boxes1 = boxes1.cpu()\n    boxes1 = np.reshape(boxes1, newshape=[grid_dim, grid_dim, max_bbox_count, 5])\n    bbs1 = []\n\n    for i in range(grid_dim):\n        for j in range(grid_dim):\n            for b in range(max_bbox_count):\n                if(boxes1[i][j][b][4] > thresh):\n    #                 print('boxes1[i][j][b][4] == boxes2[i][j][b][4]:', boxes1[i][j][b][4])\n\n                    grid_center_x = ((j+0)*grid_pix + grid_pix/2)\n                    grid_center_y = ((i+0)*grid_pix + grid_pix/2)\n    #                 print(boxes1[i][j][b] == boxes2[i][j][b])\n\n                    new_box_center_x = boxes1[i][j][b][0] * img_width + grid_center_x\n                    new_box_center_y = boxes1[i][j][b][1] * img_height + grid_center_y\n\n                    new_w = np.square(boxes1[i][j][b][2]) * img_width\n                    new_h = np.square(boxes1[i][j][b][3]) * img_height\n\n                    x1 = new_box_center_x - new_w/2\n                    y1 = new_box_center_y - new_h/2\n\n                    x2 = new_box_center_x + new_w/2\n                    y2 = new_box_center_y + new_h/2\n\n                    bbs1.append((math.floor(x1), math.floor(y1), math.ceil(x2), math.ceil(y2)))\n                    \n    draw_bboxes(img, bbs1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# To process the dataset in batches create the batches of batch_size\ntrain_generator = CustomDataGenerator(\n    train_images=train_images,\n    batch_size=16,\n    # other parameters as needed\n)\nlen(train_generator)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# images, labels = next(iter(train_generator))\n# # print(images.shape, labels.shape)\n# image = images[2].copy() / 255.\n# label = labels[2].copy()\n# # print(label.shape)\n# draw_data(image, label, thresh=0.1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class YoloLogitsLayer(tf.keras.layers.Layer):\n\n    def __init__(self, **kwargs):\n        super(YoloLogitsLayer, self).__init__(**kwargs)\n        \n    def call(self, logits):\n        net = tf.reshape(logits, [-1, GRID_DIM*1, GRID_DIM*1, MAX_BB_CNT*5*16, 1])\n        net = tf.keras.layers.AveragePooling3D([1, 1, 16], [1, 1, 16], padding=\"valid\")(net)\n\n        net = tf.reshape(net, [-1, GRID_DIM*GRID_DIM*MAX_BB_CNT, 5]) #GRID_DIM = 12\n        net = tf.transpose(net, [1, 2, 0])        \n\n        logits_tensor = tf.map_fn(lambda x:\n                                tf.stack([\n                                    tf.tanh(x[0]),\n                                    tf.tanh(x[1]),\n                                    tf.sqrt(tf.sigmoid(x[2])),\n                                    tf.sqrt(tf.sigmoid(x[3])),\n                                    tf.sigmoid(x[4])\n                                ]), net)\n\n        logits_tensor = tf.transpose(logits_tensor, [2, 0, 1])\n        logits_tensor = tf.reshape(logits_tensor, [-1, GRID_DIM, GRID_DIM, MAX_BB_CNT, 5])\n\n        return logits_tensor","metadata":{"_cell_guid":"31e600d9-4b19-4f17-84df-7e22559b6ff1","_uuid":"18e2016bfe77e41ee5b80937ce854761341283e2","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def normalize_yolo_loss(y_pred, labels):\n    lambda_coords = 5.0\n    lambda_noobj = 0.5\n    \n    yolo_loss = tf.math.reduce_sum(tf.math.squared_difference(labels, y_pred), axis=0)\n    yolo_loss = tf.math.reduce_sum(yolo_loss, axis=0)\n    yolo_loss = tf.math.reduce_sum(yolo_loss, axis=0)\n    yolo_loss = tf.math.reduce_sum(yolo_loss, axis=0)\n\n    yolo_loss = tf.stack([tf.math.multiply(lambda_coords, yolo_loss[0]), \n                          tf.math.multiply(lambda_coords, yolo_loss[1]),\n                          yolo_loss[2],\n                          yolo_loss[3],\n                          tf.math.multiply(lambda_noobj, yolo_loss[4])])\n    yolo_loss = tf.math.reduce_sum(yolo_loss)\n\n    return  yolo_loss","metadata":{"_cell_guid":"92ac7464-bb2f-41ea-93f7-88308379d664","_uuid":"39ae1bf5322d8a9590d6c1cde641a8feb35d6132","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def l_relu(features):\n    return tf.nn.leaky_relu(features, 0.1)","metadata":{"_cell_guid":"011d9e8d-f2f5-4e8f-b70f-5eaeaeac009c","_uuid":"d3a09342ef22164571512d2ea5a8fc0a5ecc83be","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class FireModule(tf.keras.layers.Layer):\n    def __init__(self, squeeze_channels, expand_channels, **kwargs):\n        super(FireModule, self).__init__(**kwargs)\n        self.squeeze = tf.keras.layers.Conv2D(filters=squeeze_channels, kernel_size=1, strides=1, padding='same', activation=l_relu)\n        self.expand1 = tf.keras.layers.Conv2D(filters=expand_channels, kernel_size=1, strides=1, padding='same', activation=l_relu)\n        self.expand3 = tf.keras.layers.Conv2D(filters=expand_channels, kernel_size=3, strides=1, padding='same', activation=l_relu)\n#         self.leaky_relu = tf.keras.layers.LeakyReLU(negative_slope=0.1)  # activation layer\n\n    def call(self, inputs):\n        #TensorFlow uses 'call' instead of 'forward' in pytorch\n        squeeze = self.squeeze(inputs)\n        expand1 = self.expand1(squeeze)\n        expand3 = self.expand3(squeeze)\n\n        return tf.concat([expand1, expand3], axis=3)  # Concatenate along channel dimension","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Below code need optimization may be by using Variable Scope.\ninputs = tf.keras.Input(shape=(IMG_HEIGHT, IMG_WIDTH, 3))\n\nnet = tf.keras.layers.Conv2D(32, kernel_size=1, strides=1, padding=\"same\", \n                       activation=l_relu, name='conv0')(inputs) #384 \n\nnet = tf.keras.layers.MaxPool2D(pool_size=2, strides=2, padding=\"same\")(net) #192\n\nnet = FireModule(32, 64)(net)\nnet = FireModule(32, 64)(net)\nnet = FireModule(32, 64)(net)\n\nnet = tf.keras.layers.MaxPool2D(pool_size=2, strides=2, padding=\"same\")(net) #96\n\n\nnet = FireModule(64, 96)(net)\nnet = FireModule(64, 96)(net)\nnet = FireModule(64, 96)(net)\n\n\nnet = tf.keras.layers.MaxPool2D(pool_size=2, strides=2, padding=\"same\")(net) #48\n\nnet = FireModule(128, 160)(net)\nnet = FireModule(128, 160)(net)\nnet = FireModule(128, 128)(net)\n\nnet = tf.keras.layers.MaxPool2D(pool_size=2, strides=2, padding=\"same\")(net) #24\n\nnet = FireModule(256, 512)(net)\nnet = FireModule(256, 512)(net)\nnet = FireModule(256, 512)(net)\n\nnet = tf.keras.layers.MaxPool2D(pool_size=2, strides=2, padding=\"same\")(net) #12\n\nnet = FireModule(512, 1024)(net)\nnet = FireModule(512, 1024)(net)\nnet = FireModule(512, 1024)(net)\n\n\nlogits = tf.keras.layers.Conv2D(filters=MAX_BB_CNT*5*16, kernel_size=1, strides=1, padding=\"same\",\n                       activation=None, name='conv40')(net) #12\n\nyolo_logits_layer = YoloLogitsLayer()\nyolo_logits = yolo_logits_layer(logits)\n\nmodel = tf.keras.Model(inputs=inputs, outputs=yolo_logits, name=\"yolo_model\")","metadata":{"_cell_guid":"0d5e7f2a-d015-4733-b6a4-0070778c5a07","_uuid":"1f8dbd627374389c081c93622e2526b6d30d5ace","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(\n                initial_learning_rate=0.001,\n                decay_steps=100000,\n                decay_rate=0.96,\n                staircase=True)\noptimizer = tf.keras.optimizers.Adam(learning_rate=lr_schedule)\n\nmodel.compile(optimizer=optimizer, loss=normalize_yolo_loss)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"early_stopping = tf.keras.callbacks.EarlyStopping(monitor='loss',mode='min', patience=5, \n                                                  restore_best_weights=True)\n\nhistory = model.fit(\n    train_generator,\n    batch_size=32,\n    epochs=300,\n    callbacks=[early_stopping]\n    # other arguments for model.fit\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.save('yolo_model.keras')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.history['loss'])\n# plt.plot(history.history['val_loss'])\nplt.title('model loss')\nplt.ylabel('loss')\nplt.xlabel('epoch')\nplt.legend(['train', 'val'], loc='upper left')\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Get and resize test images\nsizes_test = []\nprint('resize test images ... ')\nsys.stdout.flush()\n\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","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_img = test_images[0].copy()\n\ntest_img = np.expand_dims(test_img, axis=0)\nresult = model.predict(test_img)\npred_boxes = result[0]\ndraw_data(test_img.squeeze(), pred_boxes, thresh=0.1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}