Dynamically Editing Pipeline Config for Tensorflow Object Detection
Question:
I’m using tensorflow object detection API, and I want to be able to edit config file dynamically in python, which looks like this. I thought of using protocol buffers library in python, but I’m not sure how to go about.
model {
ssd {
num_classes: 1
image_resizer {
fixed_shape_resizer {
height: 300
width: 300
}
}
feature_extractor {
type: "ssd_inception_v2"
depth_multiplier: 1.0
min_depth: 16
conv_hyperparams {
regularizer {
l2_regularizer {
weight: 3.99999989895e-05
}
}
initializer {
truncated_normal_initializer {
mean: 0.0
stddev: 0.0299999993294
}
}
activation: RELU_6
batch_norm {
decay: 0.999700009823
center: true
scale: true
epsilon: 0.0010000000475
train: true
}
}
...
...
}
Is there a simple/easy way to change specific values for fields like height in image_resizer -> fixed_shape_resizer from say 300 to 500? And write back the file with modified values without changing anything else?
EDIT:
Though answer provided by @DmytroPrylipko worked for most of the parameters in the config, I face some issues with “composite field”..
That is, if we have configuration like:
train_input_reader: {
label_map_path: "/tensorflow/data/label_map.pbtxt"
tf_record_input_reader {
input_path: "/tensorflow/models/data/train.record"
}
}
And I add this line to edit input_path:
pipeline_config.train_input_reader.tf_record_input_reader.input_path = "/tensorflow/models/data/train100.record"
It throws error:
TypeError: Can't set composite field
Answers:
Yes, using Protobuf Python API is quite easy:
edit_pipeline.py:
import argparse
import tensorflow as tf
from google.protobuf import text_format
from object_detection.protos import pipeline_pb2
def parse_arguments():
parser = argparse.ArgumentParser(description='')
parser.add_argument('pipeline')
parser.add_argument('output')
return parser.parse_args()
def main():
args = parse_arguments()
pipeline_config = pipeline_pb2.TrainEvalPipelineConfig()
with tf.gfile.GFile(args.pipeline, "r") as f:
proto_str = f.read()
text_format.Merge(proto_str, pipeline_config)
pipeline_config.model.ssd.image_resizer.fixed_shape_resizer.height = 300
pipeline_config.model.ssd.image_resizer.fixed_shape_resizer.width = 300
config_text = text_format.MessageToString(pipeline_config)
with tf.gfile.Open(args.output, "wb") as f:
f.write(config_text)
if __name__ == '__main__':
main()
The way I call the script:
TOOL_DIR=tool/tf-models/research
(
cd $TOOL_DIR
protoc object_detection/protos/*.proto --python_out=.
)
export PYTHONPATH=$PYTHONPATH:$TOOL_DIR:$TOOL_DIR/slim
python3 edit_pipeline.py pipeline.config pipeline_new.config
Composite fields
In case of repeated fields, you must treat them as arrays (e.g. use extend()
, append()
methods):
pipeline_config.train_input_reader.tf_record_input_reader.input_path[0] = '/tensorflow/models/data/train100.record'
Eval Input reader error
This is a common error trying to edit the composite field. ( “no attribute tf_record_input_reader found” in case of eval_input_reader )
It’s mentioned below in @latida’s answer.
Fix that by setting it as an array field.
pipeline_config.eval_input_reader[0].label_map_path = label_map_full_path
pipeline_config.eval_input_reader[0].tf_record_input_reader.input_path[0] = val_record_path
pipeline_config.eval_input_reader[0].label_map_path = label_map_full_path
pipeline_config.eval_input_reader[0].tf_record_input_reader.input_path[0] = val_record_path
This is the same above code with small changes that suit the tensorflow V2.
import argparse
import tensorflow as tf
from google.protobuf import text_format
from object_detection.protos import pipeline_pb2
def parse_arguments():
parser = argparse.ArgumentParser(description='')
parser.add_argument('pipeline')
parser.add_argument('output')
return parser.parse_args()
def main():
args = parse_arguments()
pipeline_config = pipeline_pb2.TrainEvalPipelineConfig()
with tf.io.gfile.GFile(args.pipeline, "r") as f:
proto_str = f.read()
text_format.Merge(proto_str, pipeline_config)
pipeline_config.model.ssd.image_resizer.fixed_shape_resizer.height = 300
pipeline_config.model.ssd.image_resizer.fixed_shape_resizer.width = 300
config_text = text_format.MessageToString(pipeline_config)
with tf.io.gfile.GFile(args.output, "wb") as f:
f.write(config_text)
if __name__ == '__main__':
main()
I’ve found this to be a useful approach for overriding the object detection pipeline.config
:
from object_detection.utils import config_util
from object_detection import model_lib_v2
PIPELINE_CONFIG_PATH = 'path_to_your_pipeline.config'
# Load the pipeline config as a dictionary
pipeline_config_dict = config_util.get_configs_from_pipeline_file(PIPELINE_CONFIG_PATH)
# OVERRIDE EXAMPLES
# Example 1: Override the train tfrecord path
pipeline_config_dict['train_input_config'].tf_record_input_reader.input_path[0] = 'your/override/path/to/train.record'
# Example 2: Override the eval tfrecord path
pipeline_config_dict['eval_input_config'].tf_record_input_reader.input_path[0] = 'your/override/path/to/test.record'
# Convert the pipeline dict back to a protobuf object
pipeline_config = config_util.create_pipeline_proto_from_configs(pipeline_config_dict)
# EXAMPLE USAGE:
# Example 1: Run the object detection train loop with your overrides (has to be string representation)
model_lib_v2.train_loop(config_override=str(pipeline_config))
# Example 2: Save the pipeline config to disk
config_util.save_pipeline_config(config, 'path/to/save/new/pipeline.config)
I’m very new to programming but I wanted to share something that I was trying to do because the original question also gives me trouble.
Let’s say I already have a config file on my computer and I’ve compiled all of my TF2 Object Detection protos but now I want to change the preprocessing. I use python.
First, I’ll get my config file as a python dictionary
from object_detection.utils import config_util
# PATH_TO_MY_CONFIG_FILE can be whatever the path is to your config file
configs = config_util.get_configs_from_pipeline_file(PATH_TO_MY_CONFIG_FILE)
Next, I’d like to check what data augmentations / preprocessing I currently have.
print(configs['train_config'].data_augmentation_options)
print(type(configs['train_config'].data_augmentation_options[0]))
[random_horizontal_flip {
}
, random_scale_crop_and_pad_to_square {
output_size: 512
scale_min: 0.10000000149011612
scale_max: 2.0
}
]
<class ‘object_detection.protos.preprocessor_pb2.PreprocessingStep’>
It looks to me like configs[‘train_config’].data_augmentation_options is a python list containing instances of the class PreprocessingStep that is from the file preprocessor_pb2.py
When I previously tried running code from the TF2 Object Detection github repo there was some code that compiled protos for me. The protocompiler took my preprocessor.proto file and created a new file from it called preprocessor_pb2.py that is now on my computer. In this python file there is a class called PreprocessingStep.
I will use this script to make a new preprocessing step for my configuration.
from object_detection.protos import preprocessor_pb2
# Construct a new PreprocessingStep object
my_new_data_augmentation = preprocessor_pb2.PreprocessingStep()
# I would like to randomly change some color images to gray with %20 probability
my_new_data_augmentation.random_rgb_to_gray.probability = 0.2
print(my_new_data_augmentation)
random_rgb_to_gray {
probability: 0.20000000298023224
}
A PreprocessingStep step object has a lot of different fields. You can look inside the file preprocessor_pb2.py for a list of fields you can modify or you can look at the preprocessor.proto on the TF2 OD Github at the list of messages (These are the text in red). The messages are the names of the fields you can change.
Once you’ve selected a field to modify you can further set the optional parameters. In my example ‘probability’ is the only parameter you can modify for the ‘random_rgb_to_gray’ preprocessing step (I think).
Also, I don’t think you can set your PreprocessingStep object to have multiple preprocessing fields. For example, if I did
my_new_data_augmentation.random_rgb_to_gray.probability = 0.2
my_new_data_augmentation.random_adjust_hue.max_delta = 0.1
print(my_new_data_augmentation)
random_adjust_hue {
max_delta: 0.10000000149011612
}
things will just get overwritten.
I guess, now my preprocessing step is random_adjust_hue. I will go ahead and add this to my data augmentations now using list.append()
configs['train_config'].data_augmentation_options.append(my_new_data_augmentation)
print(configs['train_config'].data_augmentation_options)
[random_horizontal_flip {
}
, random_scale_crop_and_pad_to_square {
output_size: 512
scale_min: 0.10000000149011612
scale_max: 2.0
}
, random_adjust_hue {
max_delta: 0.10000000149011612
}
]
Now I can save my configs using the usual config_util.create_pipeline_proto_from_configs() method.
Like I said I’m very new to programming and I don’t know if this idea causes some bugs that I’m not aware of but I wanted to share this in case somebody else finds this helpful as a starting place to build on I guess.
Thanks to others post in this thread, this is what I’m doing
My model variables
:
##change chosen model to deploy different models available in the TF2 object detection zoo
MODELS_MATRIX = {
'SSD-MobileNet-v2-320x320': {
'name': 'ssd_mobilenet_v2_320x320_coco17_tpu-8',
'file': 'ssd_mobilenet_v2_320x320_coco17_tpu-8.tar.gz',
'checkpoint': 'checkpoint/ckpt-0',
'url': 'http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_mobilenet_v2_320x320_coco17_tpu-8.tar.gz'
},
'SSD-MobileNet-V2-FPNLite-640x640': {
'name': 'ssd_mobilenet_v2_fpnlite_640x640_coco17_tpu-8',
'file': 'ssd_mobilenet_v2_fpnlite_640x640_coco17_tpu-8.tar.gz',
'checkpoint': 'checkpoint/ckpt-0',
'url': 'http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_mobilenet_v2_fpnlite_640x640_coco17_tpu-8.tar.gz'
},
'SSD-ResNet101-V1-FPN-640x640': {
'name': 'ssd_resnet101_v1_fpn_640x640_coco17_tpu-8',
'file': 'ssd_resnet101_v1_fpn_640x640_coco17_tpu-8.tar.gz',
'checkpoint': 'checkpoint/ckpt-0',
'url': 'http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_resnet101_v1_fpn_640x640_coco17_tpu-8.tar.gz'
}
}
# local paths
local_pre_trainied_models_path = '/content/workspace/training/pre-trained-models'
local_models_path = '/content/workspace/training/models'
# model variables
chosen_model = 'SSD-ResNet101-V1-FPN-640x640'
model_url = MODELS_MATRIX[chosen_model]['url']
model_file = MODELS_MATRIX[chosen_model]['file']
model_name = MODELS_MATRIX[chosen_model]['name']
model_fine_tune_checkpoint = local_pre_trainied_models_path +'/'+ MODELS_MATRIX[chosen_model]['name'] + '/' + MODELS_MATRIX[chosen_model]['checkpoint']
model_fine_tune_checkpoint_type = "detection"
# Set this to false if you are not training on a TPU
model_use_bfloat16 = False
# For faster training time, images should be resized to 300x300 and then annotated
# Images should contain the objects of interest at various scales, angles, lighting conditions, locations
# For acceptable results - [email protected] of 0.9 the model was trained with batch size of 24
# and 5000 steps. this takes about 1h using 2 augmentations.
# using 5 augmentations it takes about 2h
# A step means using a single batch of data. larger batch, less steps required
model_num_steps = 13000
#Number of evaluation steps.
model_num_eval_steps = 50
model_batch_size = 16
model_iou_threshold = 0.50
model_num_classes = 1
# tf records and labels
model_train_record_file = '/content/workspace/training/annotations/train/license-plates.tfrecord'
model_train_label_map_pbtxt_file = '/content/workspace/training/annotations/train/license-plates_label_map.pbtxt'
model_test_record_file = '/content/workspace/training/annotations/test/license-plates.tfrecord'
model_test_label_map_pbtxt_file = '/content/workspace/training/annotations/test/license-plates_label_map.pbtxt'
Configuring my pipeline`:
import tensorflow as tf
from google.protobuf import text_format
from object_detection.protos import pipeline_pb2
custom_pipeline_file = f"{local_models_path}/anrp_{model_name}/pipeline.config"
pipeline_conf = pipeline_pb2.TrainEvalPipelineConfig()
# merge conf
with tf.io.gfile.GFile(custom_pipeline_file, "r") as f:
proto_str = f.read()
text_format.Merge(proto_str, pipeline_conf)
# model
pipeline_conf.model.ssd.num_classes = model_num_classes
pipeline_conf.model.ssd.post_processing.batch_non_max_suppression.iou_threshold = model_iou_threshold
# train_config
pipeline_conf.train_config.batch_size = model_batch_size
pipeline_conf.train_config.num_steps = model_num_steps
pipeline_conf.train_config.fine_tune_checkpoint = model_fine_tune_checkpoint
pipeline_conf.train_config.fine_tune_checkpoint_type = model_fine_tune_checkpoint_type
pipeline_conf.train_config.use_bfloat16 = model_use_bfloat16
# train_input_reader
pipeline_conf.train_input_reader.label_map_path = model_train_label_map_pbtxt_file
pipeline_conf.train_input_reader.tf_record_input_reader.input_path[0] = model_train_record_file
# eval_config
pipeline_conf.eval_config.metrics_set[0] = "coco_detection_metrics"
pipeline_conf.eval_config.use_moving_averages = False
# eval_input_reader
pipeline_conf.eval_input_reader[0].label_map_path = model_test_label_map_pbtxt_file
pipeline_conf.eval_input_reader[0].tf_record_input_reader.input_path[0] = model_test_record_file
config_text = text_format.MessageToString(pipeline_conf)
# debug
print(pipeline_conf)
print(config_text)
# override my conf
# with tf.io.gfile.GFile(custom_pipeline_file, "wb") as f:
# f.write(config_text)
I’m using tensorflow object detection API, and I want to be able to edit config file dynamically in python, which looks like this. I thought of using protocol buffers library in python, but I’m not sure how to go about.
model {
ssd {
num_classes: 1
image_resizer {
fixed_shape_resizer {
height: 300
width: 300
}
}
feature_extractor {
type: "ssd_inception_v2"
depth_multiplier: 1.0
min_depth: 16
conv_hyperparams {
regularizer {
l2_regularizer {
weight: 3.99999989895e-05
}
}
initializer {
truncated_normal_initializer {
mean: 0.0
stddev: 0.0299999993294
}
}
activation: RELU_6
batch_norm {
decay: 0.999700009823
center: true
scale: true
epsilon: 0.0010000000475
train: true
}
}
...
...
}
Is there a simple/easy way to change specific values for fields like height in image_resizer -> fixed_shape_resizer from say 300 to 500? And write back the file with modified values without changing anything else?
EDIT:
Though answer provided by @DmytroPrylipko worked for most of the parameters in the config, I face some issues with “composite field”..
That is, if we have configuration like:
train_input_reader: {
label_map_path: "/tensorflow/data/label_map.pbtxt"
tf_record_input_reader {
input_path: "/tensorflow/models/data/train.record"
}
}
And I add this line to edit input_path:
pipeline_config.train_input_reader.tf_record_input_reader.input_path = "/tensorflow/models/data/train100.record"
It throws error:
TypeError: Can't set composite field
Yes, using Protobuf Python API is quite easy:
edit_pipeline.py:
import argparse
import tensorflow as tf
from google.protobuf import text_format
from object_detection.protos import pipeline_pb2
def parse_arguments():
parser = argparse.ArgumentParser(description='')
parser.add_argument('pipeline')
parser.add_argument('output')
return parser.parse_args()
def main():
args = parse_arguments()
pipeline_config = pipeline_pb2.TrainEvalPipelineConfig()
with tf.gfile.GFile(args.pipeline, "r") as f:
proto_str = f.read()
text_format.Merge(proto_str, pipeline_config)
pipeline_config.model.ssd.image_resizer.fixed_shape_resizer.height = 300
pipeline_config.model.ssd.image_resizer.fixed_shape_resizer.width = 300
config_text = text_format.MessageToString(pipeline_config)
with tf.gfile.Open(args.output, "wb") as f:
f.write(config_text)
if __name__ == '__main__':
main()
The way I call the script:
TOOL_DIR=tool/tf-models/research
(
cd $TOOL_DIR
protoc object_detection/protos/*.proto --python_out=.
)
export PYTHONPATH=$PYTHONPATH:$TOOL_DIR:$TOOL_DIR/slim
python3 edit_pipeline.py pipeline.config pipeline_new.config
Composite fields
In case of repeated fields, you must treat them as arrays (e.g. use extend()
, append()
methods):
pipeline_config.train_input_reader.tf_record_input_reader.input_path[0] = '/tensorflow/models/data/train100.record'
Eval Input reader error
This is a common error trying to edit the composite field. ( “no attribute tf_record_input_reader found” in case of eval_input_reader )
It’s mentioned below in @latida’s answer.
Fix that by setting it as an array field.
pipeline_config.eval_input_reader[0].label_map_path = label_map_full_path
pipeline_config.eval_input_reader[0].tf_record_input_reader.input_path[0] = val_record_path
pipeline_config.eval_input_reader[0].label_map_path = label_map_full_path
pipeline_config.eval_input_reader[0].tf_record_input_reader.input_path[0] = val_record_path
This is the same above code with small changes that suit the tensorflow V2.
import argparse
import tensorflow as tf
from google.protobuf import text_format
from object_detection.protos import pipeline_pb2
def parse_arguments():
parser = argparse.ArgumentParser(description='')
parser.add_argument('pipeline')
parser.add_argument('output')
return parser.parse_args()
def main():
args = parse_arguments()
pipeline_config = pipeline_pb2.TrainEvalPipelineConfig()
with tf.io.gfile.GFile(args.pipeline, "r") as f:
proto_str = f.read()
text_format.Merge(proto_str, pipeline_config)
pipeline_config.model.ssd.image_resizer.fixed_shape_resizer.height = 300
pipeline_config.model.ssd.image_resizer.fixed_shape_resizer.width = 300
config_text = text_format.MessageToString(pipeline_config)
with tf.io.gfile.GFile(args.output, "wb") as f:
f.write(config_text)
if __name__ == '__main__':
main()
I’ve found this to be a useful approach for overriding the object detection pipeline.config
:
from object_detection.utils import config_util
from object_detection import model_lib_v2
PIPELINE_CONFIG_PATH = 'path_to_your_pipeline.config'
# Load the pipeline config as a dictionary
pipeline_config_dict = config_util.get_configs_from_pipeline_file(PIPELINE_CONFIG_PATH)
# OVERRIDE EXAMPLES
# Example 1: Override the train tfrecord path
pipeline_config_dict['train_input_config'].tf_record_input_reader.input_path[0] = 'your/override/path/to/train.record'
# Example 2: Override the eval tfrecord path
pipeline_config_dict['eval_input_config'].tf_record_input_reader.input_path[0] = 'your/override/path/to/test.record'
# Convert the pipeline dict back to a protobuf object
pipeline_config = config_util.create_pipeline_proto_from_configs(pipeline_config_dict)
# EXAMPLE USAGE:
# Example 1: Run the object detection train loop with your overrides (has to be string representation)
model_lib_v2.train_loop(config_override=str(pipeline_config))
# Example 2: Save the pipeline config to disk
config_util.save_pipeline_config(config, 'path/to/save/new/pipeline.config)
I’m very new to programming but I wanted to share something that I was trying to do because the original question also gives me trouble.
Let’s say I already have a config file on my computer and I’ve compiled all of my TF2 Object Detection protos but now I want to change the preprocessing. I use python.
First, I’ll get my config file as a python dictionary
from object_detection.utils import config_util
# PATH_TO_MY_CONFIG_FILE can be whatever the path is to your config file
configs = config_util.get_configs_from_pipeline_file(PATH_TO_MY_CONFIG_FILE)
Next, I’d like to check what data augmentations / preprocessing I currently have.
print(configs['train_config'].data_augmentation_options)
print(type(configs['train_config'].data_augmentation_options[0]))
[random_horizontal_flip {
}
, random_scale_crop_and_pad_to_square {
output_size: 512
scale_min: 0.10000000149011612
scale_max: 2.0
}
]
<class ‘object_detection.protos.preprocessor_pb2.PreprocessingStep’>
It looks to me like configs[‘train_config’].data_augmentation_options is a python list containing instances of the class PreprocessingStep that is from the file preprocessor_pb2.py
When I previously tried running code from the TF2 Object Detection github repo there was some code that compiled protos for me. The protocompiler took my preprocessor.proto file and created a new file from it called preprocessor_pb2.py that is now on my computer. In this python file there is a class called PreprocessingStep.
I will use this script to make a new preprocessing step for my configuration.
from object_detection.protos import preprocessor_pb2
# Construct a new PreprocessingStep object
my_new_data_augmentation = preprocessor_pb2.PreprocessingStep()
# I would like to randomly change some color images to gray with %20 probability
my_new_data_augmentation.random_rgb_to_gray.probability = 0.2
print(my_new_data_augmentation)
random_rgb_to_gray {
probability: 0.20000000298023224
}
A PreprocessingStep step object has a lot of different fields. You can look inside the file preprocessor_pb2.py for a list of fields you can modify or you can look at the preprocessor.proto on the TF2 OD Github at the list of messages (These are the text in red). The messages are the names of the fields you can change.
Once you’ve selected a field to modify you can further set the optional parameters. In my example ‘probability’ is the only parameter you can modify for the ‘random_rgb_to_gray’ preprocessing step (I think).
Also, I don’t think you can set your PreprocessingStep object to have multiple preprocessing fields. For example, if I did
my_new_data_augmentation.random_rgb_to_gray.probability = 0.2
my_new_data_augmentation.random_adjust_hue.max_delta = 0.1
print(my_new_data_augmentation)
random_adjust_hue {
max_delta: 0.10000000149011612
}
things will just get overwritten.
I guess, now my preprocessing step is random_adjust_hue. I will go ahead and add this to my data augmentations now using list.append()
configs['train_config'].data_augmentation_options.append(my_new_data_augmentation)
print(configs['train_config'].data_augmentation_options)
[random_horizontal_flip {
}
, random_scale_crop_and_pad_to_square {
output_size: 512
scale_min: 0.10000000149011612
scale_max: 2.0
}
, random_adjust_hue {
max_delta: 0.10000000149011612
}
]
Now I can save my configs using the usual config_util.create_pipeline_proto_from_configs() method.
Like I said I’m very new to programming and I don’t know if this idea causes some bugs that I’m not aware of but I wanted to share this in case somebody else finds this helpful as a starting place to build on I guess.
Thanks to others post in this thread, this is what I’m doing
My model variables
:
##change chosen model to deploy different models available in the TF2 object detection zoo
MODELS_MATRIX = {
'SSD-MobileNet-v2-320x320': {
'name': 'ssd_mobilenet_v2_320x320_coco17_tpu-8',
'file': 'ssd_mobilenet_v2_320x320_coco17_tpu-8.tar.gz',
'checkpoint': 'checkpoint/ckpt-0',
'url': 'http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_mobilenet_v2_320x320_coco17_tpu-8.tar.gz'
},
'SSD-MobileNet-V2-FPNLite-640x640': {
'name': 'ssd_mobilenet_v2_fpnlite_640x640_coco17_tpu-8',
'file': 'ssd_mobilenet_v2_fpnlite_640x640_coco17_tpu-8.tar.gz',
'checkpoint': 'checkpoint/ckpt-0',
'url': 'http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_mobilenet_v2_fpnlite_640x640_coco17_tpu-8.tar.gz'
},
'SSD-ResNet101-V1-FPN-640x640': {
'name': 'ssd_resnet101_v1_fpn_640x640_coco17_tpu-8',
'file': 'ssd_resnet101_v1_fpn_640x640_coco17_tpu-8.tar.gz',
'checkpoint': 'checkpoint/ckpt-0',
'url': 'http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_resnet101_v1_fpn_640x640_coco17_tpu-8.tar.gz'
}
}
# local paths
local_pre_trainied_models_path = '/content/workspace/training/pre-trained-models'
local_models_path = '/content/workspace/training/models'
# model variables
chosen_model = 'SSD-ResNet101-V1-FPN-640x640'
model_url = MODELS_MATRIX[chosen_model]['url']
model_file = MODELS_MATRIX[chosen_model]['file']
model_name = MODELS_MATRIX[chosen_model]['name']
model_fine_tune_checkpoint = local_pre_trainied_models_path +'/'+ MODELS_MATRIX[chosen_model]['name'] + '/' + MODELS_MATRIX[chosen_model]['checkpoint']
model_fine_tune_checkpoint_type = "detection"
# Set this to false if you are not training on a TPU
model_use_bfloat16 = False
# For faster training time, images should be resized to 300x300 and then annotated
# Images should contain the objects of interest at various scales, angles, lighting conditions, locations
# For acceptable results - [email protected] of 0.9 the model was trained with batch size of 24
# and 5000 steps. this takes about 1h using 2 augmentations.
# using 5 augmentations it takes about 2h
# A step means using a single batch of data. larger batch, less steps required
model_num_steps = 13000
#Number of evaluation steps.
model_num_eval_steps = 50
model_batch_size = 16
model_iou_threshold = 0.50
model_num_classes = 1
# tf records and labels
model_train_record_file = '/content/workspace/training/annotations/train/license-plates.tfrecord'
model_train_label_map_pbtxt_file = '/content/workspace/training/annotations/train/license-plates_label_map.pbtxt'
model_test_record_file = '/content/workspace/training/annotations/test/license-plates.tfrecord'
model_test_label_map_pbtxt_file = '/content/workspace/training/annotations/test/license-plates_label_map.pbtxt'
Configuring my pipeline`:
import tensorflow as tf
from google.protobuf import text_format
from object_detection.protos import pipeline_pb2
custom_pipeline_file = f"{local_models_path}/anrp_{model_name}/pipeline.config"
pipeline_conf = pipeline_pb2.TrainEvalPipelineConfig()
# merge conf
with tf.io.gfile.GFile(custom_pipeline_file, "r") as f:
proto_str = f.read()
text_format.Merge(proto_str, pipeline_conf)
# model
pipeline_conf.model.ssd.num_classes = model_num_classes
pipeline_conf.model.ssd.post_processing.batch_non_max_suppression.iou_threshold = model_iou_threshold
# train_config
pipeline_conf.train_config.batch_size = model_batch_size
pipeline_conf.train_config.num_steps = model_num_steps
pipeline_conf.train_config.fine_tune_checkpoint = model_fine_tune_checkpoint
pipeline_conf.train_config.fine_tune_checkpoint_type = model_fine_tune_checkpoint_type
pipeline_conf.train_config.use_bfloat16 = model_use_bfloat16
# train_input_reader
pipeline_conf.train_input_reader.label_map_path = model_train_label_map_pbtxt_file
pipeline_conf.train_input_reader.tf_record_input_reader.input_path[0] = model_train_record_file
# eval_config
pipeline_conf.eval_config.metrics_set[0] = "coco_detection_metrics"
pipeline_conf.eval_config.use_moving_averages = False
# eval_input_reader
pipeline_conf.eval_input_reader[0].label_map_path = model_test_label_map_pbtxt_file
pipeline_conf.eval_input_reader[0].tf_record_input_reader.input_path[0] = model_test_record_file
config_text = text_format.MessageToString(pipeline_conf)
# debug
print(pipeline_conf)
print(config_text)
# override my conf
# with tf.io.gfile.GFile(custom_pipeline_file, "wb") as f:
# f.write(config_text)