{"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":"This notebook is inspired from [COTS detection w/ TensorFlow Object Detection API](https://www.kaggle.com/khanhlvg/cots-detection-w-tensorflow-object-detection-api) ","metadata":{}},{"cell_type":"markdown","source":"# **Download and extract TensorFlow Model Garden**","metadata":{}},{"cell_type":"code","source":"!pip install --user tensorflow==2.6.0 -q","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:08:33.961215Z","iopub.execute_input":"2021-12-15T15:08:33.961912Z","iopub.status.idle":"2021-12-15T15:09:39.125491Z","shell.execute_reply.started":"2021-12-15T15:08:33.961820Z","shell.execute_reply":"2021-12-15T15:09:39.124602Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!git clone https://github.com/tensorflow/models.git\n    \n# Check out a certain commit to ensure that future changes in the TF ODT API codebase won't affect this notebook.\n!cd models ","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:09:39.127687Z","iopub.execute_input":"2021-12-15T15:09:39.128180Z","iopub.status.idle":"2021-12-15T15:10:22.074524Z","shell.execute_reply.started":"2021-12-15T15:09:39.128127Z","shell.execute_reply":"2021-12-15T15:10:22.073476Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%bash\ncd models/research\n\n# Compile protos.\nprotoc object_detection/protos/*.proto --python_out=.\n\n# Install TensorFlow Object Detection API.\n# Note: I fixed the version of some dependencies to make it work on Kaggle notebook. In particular:\n# * scipy==1.6.3 to avoid the missing GLIBCXX_3.4.26 error\n# * tensorflow to 2.6.0 to make it compatible with the CUDA version preinstalled on Kaggle.\n# When Kaggle notebook upgrade to TF 2.7, you can use the default setup.py script:\n# cp object_detection/packages/tf2/setup.py .\n# Install TensorFlow Object Detection API.\nwget https://storage.googleapis.com/odml-dataset/others/setup.py\npip install -q --user .\n\n# Test if the Object Dectection API is working correctly\npython object_detection/builders/model_builder_tf2_test.py\n# cp object_detection/packages/tf2/setup.py .\n# python -m pip install --use-feature=2020-resolver .\n\n# # Test if the Object Dectection API is working correctly\n# python object_detection/builders/model_builder_tf2_test.py","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:10:22.078936Z","iopub.execute_input":"2021-12-15T15:10:22.079186Z","iopub.status.idle":"2021-12-15T15:11:43.145102Z","shell.execute_reply.started":"2021-12-15T15:10:22.079155Z","shell.execute_reply":"2021-12-15T15:11:43.144059Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Dependencies**","metadata":{}},{"cell_type":"code","source":"import contextlib2\nimport io\nimport IPython\nimport json\nimport numpy as np\nimport os\nimport pathlib\nimport pandas as pd\nimport sys\nimport tensorflow as tf\nimport time\n\nfrom PIL import Image, ImageDraw","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:11:43.147774Z","iopub.execute_input":"2021-12-15T15:11:43.149314Z","iopub.status.idle":"2021-12-15T15:11:43.995307Z","shell.execute_reply.started":"2021-12-15T15:11:43.149269Z","shell.execute_reply":"2021-12-15T15:11:43.993056Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Loading the dataset**","metadata":{}},{"cell_type":"code","source":"INPUT_DIR = \"../input/tensorflow-great-barrier-reef\"\nsys.path.append(INPUT_DIR)\nimport greatbarrierreef","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:11:43.999522Z","iopub.status.idle":"2021-12-15T15:11:44.000216Z","shell.execute_reply.started":"2021-12-15T15:11:43.999958Z","shell.execute_reply":"2021-12-15T15:11:43.999985Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(tf.__version__)\nprint(tf.test.is_gpu_available())\nprint(tf.config.list_physical_devices('GPU'))","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-12-15T15:11:44.001457Z","iopub.status.idle":"2021-12-15T15:11:44.002255Z","shell.execute_reply.started":"2021-12-15T15:11:44.001965Z","shell.execute_reply":"2021-12-15T15:11:44.001992Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_df = pd.read_csv(os.path.join(INPUT_DIR, 'train.csv'))\ndata_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:11:44.003499Z","iopub.status.idle":"2021-12-15T15:11:44.004231Z","shell.execute_reply.started":"2021-12-15T15:11:44.003978Z","shell.execute_reply":"2021-12-15T15:11:44.004003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TRAINING_RATIO = 0.8\nprint(len(data_df))\n\nsplit_index = int(TRAINING_RATIO * len(data_df))\nwhile data_df.iloc[split_index - 1].sequence == data_df.iloc[split_index].sequence:\n    split_index += 1\n\ntrain_data_df = data_df.iloc[:split_index].sample(frac=1).reset_index(drop=True)\nval_data_df = data_df.iloc[split_index:].sample(frac=1).reset_index(drop=True)\n\ntrain_positive_count = len(train_data_df[train_data_df.annotations != '[]'])\nval_positive_count = len(val_data_df[val_data_df.annotations != '[]'])\n\nprint('Training ratio (all samples):', \n      float(len(train_data_df)) / (len(train_data_df) + len(val_data_df)))\nprint('Training ratio (positive samples):', \n      float(train_positive_count) / (train_positive_count + val_positive_count))","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:11:44.005272Z","iopub.status.idle":"2021-12-15T15:11:44.005996Z","shell.execute_reply.started":"2021-12-15T15:11:44.005754Z","shell.execute_reply":"2021-12-15T15:11:44.005781Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data_df = train_data_df[train_data_df.annotations != '[]'].reset_index()\nprint('Number of positive images used for training:', len(train_data_df))\nval_data_df = val_data_df[val_data_df.annotations != '[]'].reset_index()\nprint('Number of positive images used for validation:', len(val_data_df))","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:11:44.007133Z","iopub.status.idle":"2021-12-15T15:11:44.007963Z","shell.execute_reply.started":"2021-12-15T15:11:44.007705Z","shell.execute_reply":"2021-12-15T15:11:44.007733Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Visualizing a randomly selected image","metadata":{}},{"cell_type":"code","source":"def image_with_annotation(video_id, video_frame, data_df, image_path):\n    \"\"\"Visualize annotations of a given image.\"\"\"\n    full_path = os.path.join(image_path, os.path.join(f'video_{video_id}', f'{video_frame}.jpg'))\n    image = Image.open(full_path)\n    draw = ImageDraw.Draw(image)\n\n    rows = data_df[(data_df.video_id == video_id) & (data_df.video_frame == video_frame)]\n    for _, row in rows.iterrows():\n        annotations = json.loads(row.annotations.replace(\"'\", '\"'))\n        for annotation in annotations:\n            draw.rectangle((\n                annotation['x'], \n                annotation['y'],\n                (annotation['x'] + annotation['width']), \n                (annotation['y'] + annotation['height']),\n                ), outline=(255, 0, 10), width = 3)\n        \n    buf = io.BytesIO()\n    image.save(buf, 'PNG')\n    data = buf.getvalue()\n\n    return data\n\n# Test visualization of a randomly selected image\nimage_path = os.path.join(INPUT_DIR, 'train_images')\ntest_index = 3\nvideo_id = train_data_df.iloc[test_index].video_id\nvideo_frame = train_data_df.iloc[test_index].video_frame\nIPython.display.Image(image_with_annotation(video_id, video_frame, data_df, image_path))","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:11:44.009102Z","iopub.status.idle":"2021-12-15T15:11:44.009889Z","shell.execute_reply.started":"2021-12-15T15:11:44.009638Z","shell.execute_reply":"2021-12-15T15:11:44.009666Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **tf_record**\nModels based on the TensorFlow object detection API need a special format for all input data, called TFRecord file format, Tensorflow’s own binary storage format.\n\nIf you are working with large datasets, using a binary file format for storage of your data can have a significant impact on the performance of your import pipeline and as a consequence on the training time of your model. Binary data takes up less space on disk, takes less time to copy and can be read much more efficiently from disk.\n\nIt is optimized for use with Tensorflow in multiple ways. To start with, it makes it easy to combine multiple datasets and integrates seamlessly with the data import and preprocessing functionality provided by the library.Especially for datasets that are too large to be stored fully in memory this is an advantage as only the data that is required at the time (e.g. a batch) is loaded from disk and then processed.\n\n#### A TFRecord file contains a sequence of records. The file can only be read sequentially.\n**[Official Tutorial](https://www.tensorflow.org/tutorials/load_data/tfrecord)**","metadata":{}},{"cell_type":"markdown","source":"### **tf.train.Example**\n\n[Creating a tf.train.Example message](https://www.tensorflow.org/tutorials/load_data/tfrecord#creating_a_tftrainexample_message)","metadata":{}},{"cell_type":"code","source":"BytesList = tf.train.BytesList\nFloatList = tf.train.FloatList\nIntList = tf.train.Int64List\n\nfrom object_detection.utils import dataset_util\n\ndef image_feature(value):\n    \"\"\"Returns a bytes_list from a string / byte.\"\"\"\n    return tf.train.Feature(\n        bytes_list=BytesList(value=[tf.io.encode_jpeg(value).numpy()])\n    )\n\ndef bytes_feature(value):\n    \"\"\"Returns a bytes_list from a string / byte.\"\"\"\n    return tf.train.Feature(bytes_list=BytesList(value=[value.encode()]))\n\ndef bytes_feature_list(value):\n    \"\"\"Returns a bytes_list from a string / byte.\"\"\"\n    return tf.train.Feature(bytes_list=BytesList(value=value))\n\ndef _float_feature(value):\n  \"\"\"Returns a float_list from a float / double.\"\"\"\n  return tf.train.Feature(float_list=FloatList(value=[value]))\n\n\ndef float_feature_list(value):\n    \"\"\"Returns a list of float_list from a float / double.\"\"\"\n    return tf.train.Feature(float_list=tf.train.FloatList(value=value))\n\ndef _int64_feature(value):\n  \"\"\"Returns an int64_list from a bool / enum / int / uint.\"\"\"\n  return tf.train.Feature(int64_list=IntList(value=[value]))\n\ndef _int64_feature_list(value):\n  \"\"\"Returns an int64_list from a bool / enum / int / uint.\"\"\"\n  return tf.train.Feature(int64_list=IntList(value=value))\n\n\n\ndef create_tf_example(video_id, video_frame, data_df, image_dir_path):\n    full_path = os.path.join(image_dir_path, os.path.join(f'video_{video_id}', f'{video_frame}.jpg'))\n    img = open(full_path,'rb').read()\n    filename = f'{video_id}:{video_frame}'.encode('utf8')\n    image = Image.open(full_path)\n    image_format = 'jpeg'.encode('utf8')\n    \n    height = image.size[1] # Image height\n    width = image.size[0] # Image width\n    \n    xmins = [] # List of normalized left x coordinates in bounding box (1 per box)\n    xmaxs = [] # List of normalized right x coordinates in bounding box\n             # (1 per box)\n    ymins = [] # List of normalized top y coordinates in bounding box (1 per box)\n    ymaxs = [] # List of normalized bottom y coordinates in bounding box\n             # (1 per box)\n    classes_text = [] # List of string class name of bounding box (1 per box)\n    classes = [] # List of integer class id of bounding box (1 per box)\n    \n    \n    rows = data_df[(data_df.video_id == video_id) & (data_df.video_frame == video_frame)]\n    for _, row in rows.iterrows():\n        annotations = json.loads(row.annotations.replace(\"'\", '\"'))\n        for annotation in annotations:\n            xmins.append(annotation['x'] / width) \n            xmaxs.append((annotation['x'] + annotation['width']) / width) \n            ymins.append(annotation['y'] / height) \n            ymaxs.append((annotation['y'] + annotation['height']) / height) \n\n            classes_text.append('COTS'.encode('utf8'))\n            classes.append(1)\n            \n    tf_example = tf.train.Example(features=tf.train.Features(feature={\n      'image/height': dataset_util.int64_feature(height),\n      'image/width': dataset_util.int64_feature(width),\n      'image/filename': dataset_util.bytes_feature(filename),\n      'image/source_id': dataset_util.bytes_feature(filename),\n      'image/encoded': dataset_util.bytes_feature(img),\n      'image/format': dataset_util.bytes_feature(image_format),\n      'image/object/bbox/xmin': dataset_util.float_list_feature(xmins),\n      'image/object/bbox/xmax': dataset_util.float_list_feature(xmaxs),\n      'image/object/bbox/ymin': dataset_util.float_list_feature(ymins),\n      'image/object/bbox/ymax': dataset_util.float_list_feature(ymaxs),\n      'image/object/class/text': dataset_util.bytes_list_feature(classes_text),\n      'image/object/class/label': dataset_util.int64_list_feature(classes),\n    }))\n    \n    return tf_example\n            \n# tf_example = create_tf_example(0, 13, data_df, os.path.join(INPUT_DIR, 'train_images'))\n\ndef convert_to_tfrecord(data_df, tf_record_file, image_dir_path):\n    with tf.io.TFRecordWriter(tf_record_file) as writer:\n        for index, row in data_df.iterrows():\n            if index % 500 == 0:\n                print('Processed {0} images.'.format(index))\n            tf_example = create_tf_example(row.video_id, row.video_frame, data_df, image_path)\n            writer.write(tf_example.SerializeToString())\n        print('Completed processing {0} images.'.format(len(data_df)))\n\n        \nimage_path = os.path.join(INPUT_DIR, 'train_images')\n!mkdir dataset\n\nprint('Converting TRAIN images...')\nconvert_to_tfrecord(train_data_df, 'dataset/cots_train.tfrecord',image_path)\n\nprint('Converting validation images...')\nconvert_to_tfrecord(val_data_df, 'dataset/cots_val.tfrecord',image_path)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-15T15:11:44.011238Z","iopub.status.idle":"2021-12-15T15:11:44.011960Z","shell.execute_reply.started":"2021-12-15T15:11:44.011719Z","shell.execute_reply":"2021-12-15T15:11:44.011745Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Label Map Creation**\nA Label Map is a simple .txt file (.pbtxt to be exact). It links labels to some integer values. The TensorFlow Object Detection API needs this file for training and detection purposes.","metadata":{}},{"cell_type":"code","source":"# Create a label map to map between label index and human-readable label name.\n\nlabel_map_str = \"\"\"item {\n  id: 1\n  name: 'COTS'\n}\"\"\"\n\nwith open('dataset/label_map.pbtxt', 'w') as f:\n  f.write(label_map_str)\n\n!more dataset/label_map.pbtxt","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:11:44.013074Z","iopub.status.idle":"2021-12-15T15:11:44.013859Z","shell.execute_reply.started":"2021-12-15T15:11:44.013613Z","shell.execute_reply":"2021-12-15T15:11:44.013640Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Model selection**\n\nOne of the coolest features of the TensorFlow Object Detection API is the opportunity to work with a set of state of the art models, pre-trained on the COCO dataset! We can fine-tune these models for our purposes and get great results.","metadata":{}},{"cell_type":"code","source":"!wget http://download.tensorflow.org/models/object_detection/tf2/20200711/efficientdet_d4_coco17_tpu-32.tar.gz\n!tar -xvzf efficientdet_d4_coco17_tpu-32.tar.gz","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"example1 = \"efficientdet_d0_coco17_tpu-32/pipeline.config\"\nfile1 = open(example1, \"r\") \nFileContent = file1.read()\nprint(FileContent)","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:11:44.017103Z","iopub.status.idle":"2021-12-15T15:11:44.017871Z","shell.execute_reply.started":"2021-12-15T15:11:44.017621Z","shell.execute_reply":"2021-12-15T15:11:44.017649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Model configuration**\nWe downloaded and extracted a pre-trained model of our choice. Now we want to configure it.\n\n**Model configuration** is a process that lets us tailor model-related artifacts (e.g. hyperparameters, loss function, etc) so that it can be trained (fine-tuned) to tackle detection for the objects that we’re interested in. That’s it.\n\nThe TensorFlow Object Detection API allows model configuration via the **pipeline.config** file that goes along with the pre-trained model. ","metadata":{}},{"cell_type":"code","source":"from string import Template\n\nconfig_file_template = \"\"\"\n# SSD with EfficientNet-b0 + BiFPN feature extractor,\n# shared box predictor and focal loss (a.k.a EfficientDet-d3).\n# See EfficientDet, Tan et al, https://arxiv.org/abs/1911.09070\n# See Lin et al, https://arxiv.org/abs/1708.02002\n# Initialized from an EfficientDet-D3 checkpoint.\n#\n# Train on GPU\n\nmodel {\n  ssd {\n    inplace_batchnorm_update: true\n    freeze_batchnorm: false\n    num_classes: 1\n    add_background_class: false\n    box_coder {\n      faster_rcnn_box_coder {\n        y_scale: 10.0\n        x_scale: 10.0\n        height_scale: 5.0\n        width_scale: 5.0\n      }\n    }\n    matcher {\n      argmax_matcher {\n        matched_threshold: 0.5\n        unmatched_threshold: 0.5\n        ignore_thresholds: false\n        negatives_lower_than_unmatched: true\n        force_match_for_each_row: true\n        use_matmul_gather: true\n      }\n    }\n    similarity_calculator {\n      iou_similarity {\n      }\n    }\n    encode_background_as_zeros: true\n    anchor_generator {\n      multiscale_anchor_generator {\n        min_level: 3\n        max_level: 7\n        anchor_scale: 4.0\n        aspect_ratios: [1.0, 2.0, 0.5]\n        scales_per_octave: 3\n      }\n    }\n    image_resizer {\n      keep_aspect_ratio_resizer {\n        min_dimension: 1280\n        max_dimension: 1280\n        pad_to_max_dimension: true\n        }\n    }\n    box_predictor {\n      weight_shared_convolutional_box_predictor {\n        depth: 64\n        class_prediction_bias_init: -4.6\n        conv_hyperparams {\n          force_use_bias: true\n          activation: SWISH\n          regularizer {\n            l2_regularizer {\n              weight: 0.00004\n            }\n          }\n          initializer {\n            random_normal_initializer {\n              stddev: 0.01\n              mean: 0.0\n            }\n          }\n          batch_norm {\n            scale: true\n            decay: 0.99\n            epsilon: 0.001\n          }\n        }\n        num_layers_before_predictor: 3\n        kernel_size: 3\n        use_depthwise: true\n      }\n    }\n    feature_extractor {\n      type: 'ssd_efficientnet-b0_bifpn_keras'\n      bifpn {\n        min_level: 3\n        max_level: 7\n        num_iterations: 3\n        num_filters: 64\n      }\n      conv_hyperparams {\n        force_use_bias: true\n        activation: SWISH\n        regularizer {\n          l2_regularizer {\n            weight: 0.00004\n          }\n        }\n        initializer {\n          truncated_normal_initializer {\n            stddev: 0.03\n            mean: 0.0\n          }\n        }\n        batch_norm {\n          scale: true,\n          decay: 0.99,\n          epsilon: 0.001,\n        }\n      }\n    }\n    loss {\n      classification_loss {\n        weighted_sigmoid_focal {\n          alpha: 0.25\n          gamma: 1.5\n        }\n      }\n      localization_loss {\n        weighted_smooth_l1 {\n        }\n      }\n      classification_weight: 1.0\n      localization_weight: 1.0\n    }\n    normalize_loss_by_num_matches: true\n    normalize_loc_loss_by_codesize: true\n    post_processing {\n      batch_non_max_suppression {\n        score_threshold: 1e-8\n        iou_threshold: 0.5\n        max_detections_per_class: 100\n        max_total_detections: 100\n      }\n      score_converter: SIGMOID\n    }\n  }\n}\n\ntrain_config: {\n  fine_tune_checkpoint: \"efficientdet_d0_coco17_tpu-32/checkpoint/ckpt-0\"\n  fine_tune_checkpoint_version: V2\n  fine_tune_checkpoint_type: \"detection\"\n  batch_size: 2\n  sync_replicas: false\n  startup_delay_steps: 0\n  replicas_to_aggregate: 1\n  use_bfloat16: false\n  num_steps: $training_steps\n  data_augmentation_options {\n    random_horizontal_flip {\n    }\n  }\n  data_augmentation_options {\n    random_scale_crop_and_pad_to_square {\n      output_size: 1280\n      scale_min: 0.5\n      scale_max: 2.0\n    }\n  }\n  optimizer {\n    momentum_optimizer: {\n      learning_rate: {\n        cosine_decay_learning_rate {\n          learning_rate_base: 5e-3\n          total_steps: $training_steps\n          warmup_learning_rate: 5e-4\n          warmup_steps: $warmup_steps\n        }\n      }\n      momentum_optimizer_value: 0.9\n    }\n    use_moving_average: false\n  }\n  max_number_of_boxes: 100\n  unpad_groundtruth_tensors: false\n}\n\ntrain_input_reader: {\n  label_map_path: \"dataset/label_map.pbtxt\"\n  tf_record_input_reader {\n    input_path: \"dataset/cots_train.tfrecord\"\n  }\n}\n\neval_config: {\n  metrics_set: \"coco_detection_metrics\"\n  use_moving_averages: false\n  batch_size: 2;\n}\n\neval_input_reader: {\n  label_map_path: \"dataset/label_map.pbtxt\"\n  shuffle: false\n  num_epochs: 1\n  tf_record_input_reader {\n    input_path: \"dataset/cots_val.tfrecord\"\n  }\n}\n\"\"\"","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:11:44.019198Z","iopub.status.idle":"2021-12-15T15:11:44.019786Z","shell.execute_reply.started":"2021-12-15T15:11:44.019550Z","shell.execute_reply":"2021-12-15T15:11:44.019575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the training pipeline\n\nTRAINING_STEPS = 20000\nWARMUP_STEPS = 2000\nPIPELINE_CONFIG_PATH='dataset/pipeline.config'\n\npipeline = Template(config_file_template).substitute(\n    training_steps=TRAINING_STEPS, warmup_steps=WARMUP_STEPS)\n\nwith open(PIPELINE_CONFIG_PATH, 'w') as f:\n    f.write(pipeline)","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:11:44.020897Z","iopub.status.idle":"2021-12-15T15:11:44.021669Z","shell.execute_reply.started":"2021-12-15T15:11:44.021414Z","shell.execute_reply":"2021-12-15T15:11:44.021442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"MODEL_DIR='cots_efficientdet_d0'\n!mkdir {MODEL_DIR}\n!python models/research/object_detection/model_main_tf2.py \\\n    --pipeline_config_path={PIPELINE_CONFIG_PATH} \\\n    --model_dir={MODEL_DIR} \\\n    --alsologtostderr","metadata":{"execution":{"iopub.status.busy":"2021-12-15T15:11:44.022828Z","iopub.status.idle":"2021-12-15T15:11:44.023590Z","shell.execute_reply.started":"2021-12-15T15:11:44.023355Z","shell.execute_reply":"2021-12-15T15:11:44.023382Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}