1616# =============================================================================
1717
1818import os
19- import sys
20-
21- import logging
22- import time
2319import shutil
20+ import sys
2421
25- from functools import partial
22+ import numpy as np
2623import ujson as json
2724
28- import numpy as np
2925import tensorflow as tf
3026
3127from pycocotools .coco import COCO
4642
4743class CommandLineAPI (BaseCommandLineAPI ):
4844
49- SAMPLES_IN_VALIDATION_SET = 5000
45+ SAMPLES_IN_VALIDATION_SET = 50000
5046
5147 def __init__ (self ):
5248 super (CommandLineAPI , self ).__init__ ()
@@ -66,40 +62,110 @@ def __init__(self):
6662 )
6763
6864
65+ # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #
66+ # %%%%%%%%%%%%%%%%% IMPLEMENT MODEL-SPECIFIC FUNCTIONS HERE %%%%%%%%%%%%%%%%%% #
67+ # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #
68+
69+
6970class BenchmarkRunner (BaseBenchmarkRunner ):
7071
71- ACCURACY_METRIC_NAME = "mAP"
72-
73- def before_benchmark (self , ** kwargs ):
74- self ._output_name_map = (
75- # <tf.Tensor 'detection_boxes:0' shape=(8, None, None) dtype=float32>
76- (0 , 'boxes' ),
77- # <tf.Tensor 'detection_classes:0' shape=(8, None) dtype=float32>
78- (1 , 'classes' ),
79- # <tf.Tensor 'num_detections:0' shape=(8,) dtype=float32>
80- (2 , 'num_detections' ),
81- # <tf.Tensor 'detection_scores:0' shape=(8, None) dtype=float32>
82- (3 , 'scores' ),
72+ def get_dataset_batches (self ):
73+ """Returns a list of batches of input samples.
74+
75+ Each batch should be in the form [x, y], where
76+ x is a numpy array of the input samples for the batch, and
77+ y is a numpy array of the expected model outputs for the batch
78+
79+ Returns:
80+ - dataset: a TF Dataset object
81+ - bypass_data_to_eval: any object type that will be passed unmodified to
82+ `evaluate_result()`. If not necessary: `None`
83+
84+ Note: script arguments can be accessed using `self._args.attr`
85+ """
86+
87+ coco_api = COCO (annotation_file = self ._args .annotation_path )
88+ image_ids = coco_api .getImgIds ()
89+
90+ image_paths = []
91+ for image_id in image_ids :
92+ coco_img = coco_api .imgs [image_id ]
93+ image_paths .append (
94+ os .path .join (self ._args .data_dir , coco_img ['file_name' ])
95+ )
96+
97+ dataset = tf .data .Dataset .from_tensor_slices (image_paths )
98+
99+ def load_image_op (path ):
100+ image = tf .io .read_file (path )
101+ image = tf .image .decode_jpeg (image , channels = 3 )
102+
103+ return tf .data .Dataset .from_tensor_slices ([image ])
104+
105+ dataset = dataset .interleave (
106+ load_image_op ,
107+ cycle_length = tf .data .experimental .AUTOTUNE ,
108+ block_length = 8 ,
109+ num_parallel_calls = tf .data .experimental .AUTOTUNE
83110 )
84111
85- def compute_accuracy_metric (self , predictions , expected , ** kwargs ):
86- return self ._eval_model (
87- predictions = predictions ,
88- image_ids = kwargs ["image_ids" ],
89- annotation_path = kwargs ["annotation_path" ]
112+ def preprocess_fn (image ):
113+ if self ._args .input_size is not None :
114+ image = tf .image .resize (
115+ image ,
116+ size = (self ._args .input_size , self ._args .input_size )
117+ )
118+ image = tf .cast (image , tf .uint8 )
119+ return image
120+
121+ dataset = dataset .map (
122+ map_func = preprocess_fn ,
123+ num_parallel_calls = tf .data .experimental .AUTOTUNE ,
90124 )
91125
92- def _eval_model (self , predictions , image_ids , annotation_path ):
126+ dataset = dataset .batch (self ._args .batch_size , drop_remainder = False )
127+
128+ dataset = dataset .prefetch (buffer_size = tf .data .experimental .AUTOTUNE )
129+
130+ return dataset , None
131+
132+ def preprocess_model_inputs (self , data_batch ):
133+ """This function prepare the `data_batch` generated from the dataset.
134+ Returns:
135+ x: input of the model
136+ y: data to be used for model evaluation
137+
138+ Note: script arguments can be accessed using `self._args.attr`
139+ """
140+
141+ return data_batch , np .array ([])
142+
143+ def postprocess_model_outputs (self , predictions , expected ):
144+ """Post process if needed the predictions and expected tensors. At the
145+ minimum, this function transforms all TF Tensors into a numpy arrays.
146+ Most models will not need to modify this function.
147+
148+ Note: script arguments can be accessed using `self._args.attr`
149+ """
93150
94- # for key in predictions:
95- # predictions[key] = np.vstack(predictions[key])
96- # if key == 'num_detections':
97- # predictions[key] = predictions[key].ravel()
151+ predictions = {k : t .numpy () for k , t in predictions .items ()}
152+
153+ return predictions , expected
154+
155+ def evaluate_model (self , predictions , expected , bypass_data_to_eval ):
156+ """Evaluate result predictions for entire dataset.
157+
158+ This computes overall accuracy, mAP, etc. Returns the
159+ metric value and a metric_units string naming the metric.
160+
161+ Note: script arguments can be accessed using `args.attr`
162+ """
163+ coco_api = COCO (annotation_file = self ._args .annotation_path )
164+ image_ids = coco_api .getImgIds ()
98165
99- coco = COCO (annotation_file = annotation_path )
100166 coco_detections = []
101167 for i , image_id in enumerate (image_ids ):
102- coco_img = coco .imgs [image_id ]
168+ coco_img = coco_api .imgs [image_id ]
103169 image_width = coco_img ['width' ]
104170 image_height = coco_img ['height' ]
105171
@@ -127,163 +193,27 @@ def _eval_model(self, predictions, image_ids, annotation_path):
127193 coco_detections_path = os .path .join (tmp_dir , 'coco_detections.json' )
128194 with open (coco_detections_path , 'w' ) as f :
129195 json .dump (coco_detections , f )
130- cocoDt = coco .loadRes (coco_detections_path )
196+
197+ cocoDt = coco_api .loadRes (coco_detections_path )
131198
132199 shutil .rmtree (tmp_dir )
133200
134201 # compute coco metrics
135- eval = COCOeval (coco , cocoDt , 'bbox' )
202+ eval = COCOeval (coco_api , cocoDt , 'bbox' )
136203 eval .params .imgIds = image_ids
137204
138205 eval .evaluate ()
139206 eval .accumulate ()
140207 eval .summarize ()
141208
142- return eval .stats [0 ]
143-
144- def process_model_output (self , outputs , ** kwargs ):
145- # outputs = graph_func(batch_images)
146- if isinstance (outputs , dict ):
147- outputs = {k : t .numpy () for k , t in outputs .items ()}
148- else :
149- outputs = {
150- name : outputs [idx ].numpy ()
151- for idx , name in self ._output_name_map
152- }
153-
154- return outputs
155-
156-
157- def get_dataset (
158- batch_size , images_dir , image_ids , input_size , use_synthetic_data
159- ):
160-
161- image_paths = []
162-
163- for image_id in image_ids :
164- coco_img = coco .imgs [image_id ]
165- image_paths .append (os .path .join (images_dir , coco_img ['file_name' ]))
166-
167- dataset = tf .data .Dataset .from_tensor_slices (image_paths )
168-
169- def load_image_op (path ):
170- image = tf .io .read_file (path )
171- image = tf .image .decode_jpeg (image , channels = 3 )
172-
173- return tf .data .Dataset .from_tensor_slices ([image ])
174-
175- dataset = dataset .interleave (
176- lambda path : load_image_op (path ),
177- cycle_length = tf .data .experimental .AUTOTUNE ,
178- block_length = 8 ,
179- num_parallel_calls = tf .data .experimental .AUTOTUNE
180- )
181-
182- def preprocess_fn (image ):
183- if input_size is not None :
184- image = tf .image .resize (image , size = (input_size , input_size ))
185- image = tf .cast (image , tf .uint8 )
186- return image
187-
188- dataset = dataset .apply (
189- tf .data .experimental .map_and_batch (
190- map_func = preprocess_fn ,
191- batch_size = batch_size ,
192- num_parallel_calls = tf .data .experimental .AUTOTUNE ,
193- drop_remainder = True
194- )
195- )
196-
197- if use_synthetic_data :
198- dataset = dataset .take (count = 1 ) # loop over 1 batch
199- dataset = dataset .cache ()
200- dataset = dataset .repeat ()
201-
202- dataset = dataset .prefetch (buffer_size = tf .data .experimental .AUTOTUNE )
203-
204- return dataset
209+ return eval .stats [0 ] * 100 , "mAP %"
205210
206211
207212if __name__ == '__main__' :
208213
209214 cmdline_api = CommandLineAPI ()
210215 args = cmdline_api .parse_args ()
211216
212- coco = COCO (annotation_file = args .annotation_path )
213- image_ids = coco .getImgIds ()
214-
215- def _input_fn (input_data_dir , build_steps , model_phase ):
216-
217- dataset = get_dataset (
218- batch_size = args .batch_size ,
219- images_dir = input_data_dir ,
220- image_ids = image_ids ,
221- input_size = args .input_size ,
222- # even when using synthetic data, we need to
223- # build and/or calibrate using real training data
224- # to be in a realistic scenario
225- use_synthetic_data = False ,
226- )
217+ runner = BenchmarkRunner (args )
227218
228- for i , batch_images in enumerate (dataset ):
229- if i >= build_steps :
230- break
231-
232- print ("* [%s] - step %04d/%04d" % (model_phase , i + 1 , build_steps ))
233- yield batch_images ,
234-
235- calibration_input_fn = partial (
236- _input_fn ,
237- input_data_dir = args .calib_data_dir ,
238- build_steps = args .num_calib_batches // args .batch_size ,
239- model_phase = "Calibration"
240- )
241-
242- optimize_offline_input_fn = partial (
243- _input_fn ,
244- input_data_dir = args .data_dir ,
245- build_steps = 1 ,
246- model_phase = "Building"
247- )
248-
249- runner = BenchmarkRunner (
250- input_saved_model_dir = args .input_saved_model_dir ,
251- output_saved_model_dir = args .output_saved_model_dir ,
252- allow_build_at_runtime = args .allow_build_at_runtime ,
253- calibration_input_fn = calibration_input_fn ,
254- debug = args .debug ,
255- gpu_mem_cap = args .gpu_mem_cap ,
256- input_signature_key = args .input_signature_key ,
257- max_workspace_size_bytes = args .max_workspace_size ,
258- minimum_segment_size = args .minimum_segment_size ,
259- num_calib_batches = args .num_calib_batches ,
260- optimize_offline = args .optimize_offline ,
261- optimize_offline_input_fn = optimize_offline_input_fn ,
262- output_tensor_names = args .output_tensor_names ,
263- precision_mode = args .precision ,
264- use_dynamic_shape = args .use_dynamic_shape ,
265- use_tftrt = args .use_tftrt
266- )
267-
268- get_benchmark_input_fn = partial (
269- get_dataset ,
270- images_dir = args .data_dir ,
271- image_ids = image_ids ,
272- input_size = args .input_size
273- )
274-
275- runner .execute_benchmark (
276- batch_size = args .batch_size ,
277- display_every = args .display_every ,
278- get_benchmark_input_fn = get_benchmark_input_fn ,
279- num_iterations = args .num_iterations ,
280- num_warmup_iterations = args .num_warmup_iterations ,
281- skip_accuracy_testing = (
282- args .use_synthetic_data or args .skip_accuracy_testing
283- ),
284- use_synthetic_data = args .use_synthetic_data ,
285- use_xla = args .use_xla ,
286- ########### Additional Settings ############
287- image_ids = image_ids ,
288- annotation_path = args .annotation_path
289- )
219+ runner .execute_benchmark ()
0 commit comments