def postprocess(self, results): """Postprocess results returned from model.""" try: import coco_metric # pylint: disable=g-import-not-at-top except ImportError: raise ImportError('To use the COCO dataset, you must clone the ' 'repo https://github.com/tensorflow/models and add ' 'tensorflow/models and tensorflow/models/research to ' 'the PYTHONPATH, and compile the protobufs by ' 'following https://github.com/tensorflow/models/blob/' 'master/research/object_detection/g3doc/installation.md' '#protobuf-compilation ; To evaluate using COCO' 'metric, download and install Python COCO API from' 'https://github.com/cocodataset/cocoapi') pred_boxes = results[ssd_constants.PRED_BOXES] pred_scores = results[ssd_constants.PRED_SCORES] # TODO(haoyuzhang): maybe use these values for visualization. # gt_boxes = results['gt_boxes'] # gt_classes = results['gt_classes'] source_id = results[ssd_constants.SOURCE_ID] raw_shape = results[ssd_constants.RAW_SHAPE] # COCO evaluation requires processing COCO_NUM_VAL_IMAGES exactly once. Due # to rounding errors (i.e., COCO_NUM_VAL_IMAGES % batch_size != 0), setting # `num_eval_epochs` to 1 is not enough and will often miss some images. We # expect user to set `num_eval_epochs` to >1, which will leave some unused # images from previous steps in `predictions`. Here we check if we are doing # eval at a new global step. if results['global_step'] > self.eval_global_step: self.eval_global_step = results['global_step'] self.predictions.clear() for i, sid in enumerate(source_id): self.predictions[int(sid)] = { ssd_constants.PRED_BOXES: pred_boxes[i], ssd_constants.PRED_SCORES: pred_scores[i], ssd_constants.SOURCE_ID: source_id[i], ssd_constants.RAW_SHAPE: raw_shape[i] } # COCO metric calculates mAP only after a full epoch of evaluation. Return # dummy results for top_N_accuracy to be compatible with benchmar_cnn.py. if len(self.predictions) >= ssd_constants.COCO_NUM_VAL_IMAGES: log_fn('Got results for all {:d} eval examples. Calculate mAP...'.format( ssd_constants.COCO_NUM_VAL_IMAGES)) annotation_file = os.path.join(self.params.data_dir, ssd_constants.ANNOTATION_FILE) # Size of predictions before decoding about 15--30GB, while size after # decoding is 100--200MB. When using async eval mode, decoding takes # 20--30 seconds of main thread time but is necessary to avoid OOM during # inter-process communication. decoded_preds = coco_metric.decode_predictions(self.predictions.values()) self.predictions.clear() if self.params.collect_eval_results_async: def _eval_results_getter(): """Iteratively get eval results from async eval process.""" while True: step, eval_results = self.async_eval_results_queue.get() self.eval_coco_ap = eval_results['COCO/AP'] mlperf.logger.log_eval_accuracy( self.eval_coco_ap, step, self.batch_size * self.params.num_gpus, ssd_constants.COCO_NUM_TRAIN_IMAGES) if self.reached_target(): # Reached target, clear all pending messages in predictions queue # and insert poison pill to stop the async eval process. while not self.async_eval_predictions_queue.empty(): self.async_eval_predictions_queue.get() self.async_eval_predictions_queue.put('STOP') break if not self.async_eval_process: # Limiting the number of messages in predictions queue to prevent OOM. # Each message (predictions data) can potentially consume a lot of # memory, and normally there should only be few messages in the queue. # If often blocked on this, consider reducing eval frequency. self.async_eval_predictions_queue = multiprocessing.Queue(2) self.async_eval_results_queue = multiprocessing.Queue() # Reason to use a Process as opposed to Thread is mainly the # computationally intensive eval runner. Python multithreading is not # truly running in parallel, a runner thread would get significantly # delayed (or alternatively delay the main thread). self.async_eval_process = multiprocessing.Process( target=coco_metric.async_eval_runner, args=(self.async_eval_predictions_queue, self.async_eval_results_queue, annotation_file)) self.async_eval_process.daemon = True self.async_eval_process.start() self.async_eval_results_getter_thread = threading.Thread( target=_eval_results_getter, args=()) self.async_eval_results_getter_thread.daemon = True self.async_eval_results_getter_thread.start() self.async_eval_predictions_queue.put( (self.eval_global_step, decoded_preds)) return {'top_1_accuracy': 0, 'top_5_accuracy': 0.} eval_results = coco_metric.compute_map(decoded_preds, annotation_file) self.eval_coco_ap = eval_results['COCO/AP'] ret = {'top_1_accuracy': self.eval_coco_ap, 'top_5_accuracy': 0.} for metric_key, metric_value in eval_results.items(): ret[constants.SIMPLE_VALUE_RESULT_PREFIX + metric_key] = metric_value mlperf.logger.log_eval_accuracy(self.eval_coco_ap, self.eval_global_step, self.batch_size * self.params.num_gpus, ssd_constants.COCO_NUM_TRAIN_IMAGES) return ret log_fn('Got {:d} out of {:d} eval examples.' ' Waiting for the remaining to calculate mAP...'.format( len(self.predictions), ssd_constants.COCO_NUM_VAL_IMAGES)) return {'top_1_accuracy': self.eval_coco_ap, 'top_5_accuracy': 0.}
def postprocess(self, results): """Postprocess results returned from model.""" try: import coco_metric # pylint: disable=g-import-not-at-top except ImportError: raise ImportError('To use the COCO dataset, you must clone the ' 'repo https://github.com/tensorflow/models and add ' 'tensorflow/models and tensorflow/models/research to ' 'the PYTHONPATH, and compile the protobufs by ' 'following https://github.com/tensorflow/models/blob/' 'master/research/object_detection/g3doc/installation.md' '#protobuf-compilation ; To evaluate using COCO' 'metric, download and install Python COCO API from' 'https://github.com/cocodataset/cocoapi') pred_boxes = results[ssd_constants.PRED_BOXES] pred_scores = results[ssd_constants.PRED_SCORES] # TODO(haoyuzhang): maybe use these values for visualization. # gt_boxes = results['gt_boxes'] # gt_classes = results['gt_classes'] source_id = results[ssd_constants.SOURCE_ID] raw_shape = results[ssd_constants.RAW_SHAPE] # COCO evaluation requires processing COCO_NUM_VAL_IMAGES exactly once. Due # to rounding errors (i.e., COCO_NUM_VAL_IMAGES % batch_size != 0), setting # `num_eval_epochs` to 1 is not enough and will often miss some images. We # expect user to set `num_eval_epochs` to >1, which will leave some unused # images from previous steps in `predictions`. Here we check if we are doing # eval at a new global step. if results['global_step'] > self.eval_global_step: self.eval_global_step = results['global_step'] self.predictions.clear() for i, sid in enumerate(source_id): self.predictions[int(sid)] = { ssd_constants.PRED_BOXES: pred_boxes[i], ssd_constants.PRED_SCORES: pred_scores[i], ssd_constants.SOURCE_ID: source_id[i], ssd_constants.RAW_SHAPE: raw_shape[i] } # COCO metric calculates mAP only after a full epoch of evaluation. Return # dummy results for top_N_accuracy to be compatible with benchmar_cnn.py. if len(self.predictions) >= ssd_constants.COCO_NUM_VAL_IMAGES: print('Got results for all {:d} eval examples. Calculate mAP...'.format( ssd_constants.COCO_NUM_VAL_IMAGES)) annotation_file = os.path.join(self.data_dir, ssd_constants.ANNOTATION_FILE) # Size of predictions before decoding about 15--30GB, while size after # decoding is 100--200MB. When using async eval mode, decoding takes # 20--30 seconds of main thread time but is necessary to avoid OOM during # inter-process communication. decoded_preds = coco_metric.decode_predictions(self.predictions.values()) self.predictions.clear() eval_results = coco_metric.compute_map(decoded_preds, annotation_file) self.eval_coco_ap = eval_results['COCO/AP'] ret = {'top_1_accuracy': self.eval_coco_ap, 'top_5_accuracy': 0.} return ret print('Got {:d} out of {:d} eval examples.' ' Waiting for the remaining to calculate mAP...'.format( len(self.predictions), ssd_constants.COCO_NUM_VAL_IMAGES)) return {'top_1_accuracy': self.eval_coco_ap, 'top_5_accuracy': 0.}