# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve. # #Licensed under the Apache License, Version 2.0 (the "License"); #you may not use this file except in compliance with the License. #You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # #Unless required by applicable law or agreed to in writing, software #distributed under the License is distributed on an "AS IS" BASIS, #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #See the License for the specific language governing permissions and #limitations under the License. import numpy as np import pandas as pd import os import sys import json sys.path.append('../') from hapi.metrics import Metric from bmn_utils import boundary_choose, bmn_post_processing class BmnMetric(Metric): """ only support update with batch_size=1 """ def __init__(self, cfg, mode): super(BmnMetric, self).__init__() self.cfg = cfg self.mode = mode #get video_dict and video_list if self.mode == 'test': self.get_test_dataset_dict() if not os.path.isdir(self.cfg.TEST.output_path): os.makedirs(self.cfg.TEST.output_path) if not os.path.isdir(self.cfg.TEST.result_path): os.makedirs(self.cfg.TEST.result_path) elif self.mode == 'infer': self.get_infer_dataset_dict() if not os.path.isdir(self.cfg.INFER.output_path): os.makedirs(self.cfg.INFER.output_path) if not os.path.isdir(self.cfg.INFER.result_path): os.makedirs(self.cfg.INFER.result_path) def add_metric_op(self, *args): if self.mode == 'test': # only extract pred_bm, pred_start, pred_en from outputs # and video_index from label here pred_bm, pred_start, pred_en, _, _, _, video_index = args else: # in infer mode, labels only contains video_index pred_bm, pred_start, pred_en, video_index = args return pred_bm, pred_start, pred_en, video_index def update(self, pred_bm, pred_start, pred_end, fid): # generate proposals pred_start = pred_start[0] pred_end = pred_end[0] fid = fid[0] if self.mode == 'infer': output_path = self.cfg.INFER.output_path else: output_path = self.cfg.TEST.output_path tscale = self.cfg.MODEL.tscale dscale = self.cfg.MODEL.dscale snippet_xmins = [1.0 / tscale * i for i in range(tscale)] snippet_xmaxs = [1.0 / tscale * i for i in range(1, tscale + 1)] cols = ["xmin", "xmax", "score"] video_name = self.video_list[fid] pred_bm = pred_bm[0, 0, :, :] * pred_bm[0, 1, :, :] start_mask = boundary_choose(pred_start) start_mask[0] = 1. end_mask = boundary_choose(pred_end) end_mask[-1] = 1. score_vector_list = [] for idx in range(dscale): for jdx in range(tscale): start_index = jdx end_index = start_index + idx if end_index < tscale and start_mask[ start_index] == 1 and end_mask[end_index] == 1: xmin = snippet_xmins[start_index] xmax = snippet_xmaxs[end_index] xmin_score = pred_start[start_index] xmax_score = pred_end[end_index] bm_score = pred_bm[idx, jdx] conf_score = xmin_score * xmax_score * bm_score score_vector_list.append([xmin, xmax, conf_score]) score_vector_list = np.stack(score_vector_list) video_df = pd.DataFrame(score_vector_list, columns=cols) video_df.to_csv( os.path.join(output_path, "%s.csv" % video_name), index=False) return 0 # result has saved in output path def accumulate(self): return 'post_processing is required...' # required method def reset(self): print("Post_processing....This may take a while") if self.mode == 'test': bmn_post_processing(self.video_dict, self.cfg.TEST.subset, self.cfg.TEST.output_path, self.cfg.TEST.result_path) elif self.mode == 'infer': bmn_post_processing(self.video_dict, self.cfg.INFER.subset, self.cfg.INFER.output_path, self.cfg.INFER.result_path) def name(self): return 'bmn_metric' def get_test_dataset_dict(self): anno_file = self.cfg.MODEL.anno_file annos = json.load(open(anno_file)) subset = self.cfg.TEST.subset self.video_dict = {} for video_name in annos.keys(): video_subset = annos[video_name]["subset"] if subset in video_subset: self.video_dict[video_name] = annos[video_name] self.video_list = list(self.video_dict.keys()) self.video_list.sort() def get_infer_dataset_dict(self): file_list = self.cfg.INFER.filelist annos = json.load(open(file_list)) self.video_dict = {} for video_name in annos.keys(): self.video_dict[video_name] = annos[video_name] self.video_list = list(self.video_dict.keys()) self.video_list.sort()