提交 d5483606 编写于 作者: H huangjun12 提交者: SunGaofeng

fix bug of bmn/bsn from QA, modify reader to match windows and refine code for...

fix bug of bmn/bsn from QA, modify reader to match windows and refine code for predict and eval (#3740)
上级 e24cc920
......@@ -7,7 +7,7 @@ MODEL:
num_sample: 32
num_sample_perbin: 3
anno_file: "data/dataset/bmn/activitynet_1.3_annotations.json"
feat_path: '/paddle/PaddleProject/data/fix_feat_100'
feat_path: 'data/dataset/bmn/fix_feat_100'
TRAIN:
subset: "train"
......
......@@ -8,7 +8,7 @@ MODEL:
num_sample: 32
num_sample_perbin: 3
anno_file: "data/dataset/bmn/activitynet_1.3_annotations.json"
feat_path: '/paddle/PaddleProject/data/fix_feat_100'
feat_path: 'data/dataset/bmn/fix_feat_100'
pgm_top_K_train: 500
pgm_top_K: 1000
pgm_threshold: 0.5
......
......@@ -12,11 +12,11 @@
## 生成文件列表
打开generate\_list.sh,将其中的TRAIN\_DIR和VALID\_DIR修改成用户所保存的mp4文件路径,运行脚本
运行下面的代码即可生成trainlist.txt、vallist.txt和testlist.txt,
bash generate_list.sh
python generate_filelist.py ${TRAIN_DIR} ${VALID_DIR}
即可生成trainlist.txt、vallist.txt和testlist.txt
其中TRAIN\_DIR和VALID\_DIR分别是存放训练和验证数据集文件的路径。注意请确认[kinetics-400\_train.csv](https://github.com/activitynet/ActivityNet/tree/master/Crawler/Kinetics/data/kinetics-400_train.csv)已经下载到本地,不然运行generate\_filelist.py时会报错
另外,如果要观察模型推断的效果,可以复制testlist.txt生成inferlist.txt,
......
......@@ -17,13 +17,14 @@ import sys
num_classes = 400
replace_space_by_underliner = True # whether to replace space by '_' in labels
fn = sys.argv[1] #'trainlist_download400.txt'
train_dir = sys.argv[
2] #'/docker_mount/data/k400/Kinetics_trimmed_processed_train'
val_dir = sys.argv[3] #'/docker_mount/data/k400/Kinetics_trimmed_processed_val'
trainlist = sys.argv[4] #'trainlist.txt'
vallist = sys.argv[5] #'vallist.txt'
1] #e.g., '/docker_mount/data/k400/Kinetics_trimmed_processed_train'
val_dir = sys.argv[
2] #e.g., '/docker_mount/data/k400/Kinetics_trimmed_processed_val'
fn = 'kinetics-400_train.csv' # this should be download first from ActivityNet
trainlist = 'trainlist.txt'
vallist = 'vallist.txt'
testlist = 'testlist.txt'
fl = open(fn).readlines()
fl = [line.strip() for line in fl if line.strip() != '']
......@@ -74,5 +75,26 @@ def generate_file(Faction_label_dict, Ftrain_dir, Ftrainlist, Fnum_classes):
trainlist_outfile.close()
###### generate file list for training
generate_file(action_label_dict, train_dir, trainlist, num_classes)
###### generate file list for validation
generate_file(action_label_dict, val_dir, vallist, num_classes)
###### generate file list for evaluation
sampling_times = 10
cropping_times = 3
fl = open(vallist).readlines()
fl = [line.strip() for line in fl if line.strip() != '']
f_test = open(testlist, 'w')
for i in range(len(fl)):
line = fl[i].split(' ')
fn = line[0]
label = line[1]
for j in range(sampling_times):
for k in range(cropping_times):
test_item = fn + ' ' + str(i) + ' ' + str(j) + ' ' + str(k) + '\n'
f_test.write(test_item)
f_test.close()
# Download txt name
TRAINLIST_DOWNLOAD="kinetics-400_train.csv"
# path of the train and valid data
TRAIN_DIR=YOUR_TRAIN_DATA_DIR # replace this with your train data dir
VALID_DIR=YOUR_VALID_DATA_DIR # replace this with your valid data dir
python generate_filelist.py $TRAINLIST_DOWNLOAD $TRAIN_DIR $VALID_DIR trainlist.txt vallist.txt
# generate test list
python generate_testlist_multicrop.py
# Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
#
# 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 os
vallist = 'vallist.txt'
testlist = 'testlist.txt'
sampling_times = 10
cropping_times = 3
fl = open(vallist).readlines()
fl = [line.strip() for line in fl if line.strip() != '']
f_test = open(testlist, 'w')
for i in range(len(fl)):
line = fl[i].split(' ')
fn = line[0]
label = line[1]
for j in range(sampling_times):
for k in range(cropping_times):
test_item = fn + ' ' + str(i) + ' ' + str(j) + ' ' + str(k) + '\n'
f_test.write(test_item)
f_test.close()
......@@ -119,7 +119,7 @@ def test(args):
test_outs = exe.run(fetch_list=test_fetch_list,
feed=test_feeder.feed(feat_data),
return_numpy=False)
test_outs += vinfo
test_outs += [vinfo]
else:
test_outs = exe.run(fetch_list=test_fetch_list,
feed=test_feeder.feed(data))
......
......@@ -3,7 +3,9 @@
- ActivityNet数据集的具体使用说明可以参考其[官方网站](http://activity-net.org)
- 下载指标评估代码,请从[ActivityNet Gitub repository](https://github.com/activitynet/ActivityNet.git)下载,将Evaluation文件夹拷贝至PaddleVideo目录下。
- 下载指标评估代码,请从[ActivityNet Gitub repository](https://github.com/activitynet/ActivityNet.git)下载,将Evaluation文件夹拷贝至PaddleVideo目录下。(注:若使用python3,print函数需要添加括号,请对Evaluation目录下的.py文件做相应修改。)
- 请下载[activity\_net\_1\_3\_new.json](https://paddlemodels.bj.bcebos.com/video_detection/activity_net_1_3_new.json)文件,并将其放置在PaddleVideo/Evaluation/data目录下,相较于原始的activity\_net.v1-3.min.json文件,我们过滤了其中一些失效的视频条目。
- 计算精度指标
......
......@@ -97,7 +97,7 @@ class MetricsCalculator():
os.path.join(self.output_path, "%s.csv" % video_name), index=False)
def accumulate(self, fetch_list):
cur_batch_size = 1 # iteration counter
cur_batch_size = 1 # iteration counter,for test and inference, batch_size=1
total_loss = fetch_list[0]
tem_loss = fetch_list[1]
pem_reg_loss = fetch_list[2]
......
......@@ -61,13 +61,15 @@ class MetricsCalculator():
os.makedirs(self.output_path_pem)
def save_results(self, pred_iou, props_info, fid):
video_name = self.video_list[fid]
if self.mode == 'infer':
video_name = self.video_list[fid[0]]
else:
video_name = self.video_list[fid[0][0]]
df = pd.DataFrame()
df["xmin"] = props_info[0, 0, :]
df["xmax"] = props_info[0, 1, :]
df["xmin_score"] = props_info[0, 2, :]
df["xmax_score"] = props_info[0, 3, :]
df["xmin"] = props_info[0, :, 0]
df["xmax"] = props_info[0, :, 1]
df["xmin_score"] = props_info[0, :, 2]
df["xmax_score"] = props_info[0, :, 3]
df["iou_score"] = pred_iou.squeeze()
df.to_csv(
os.path.join(self.output_path_pem, video_name + ".csv"),
......@@ -83,13 +85,13 @@ class MetricsCalculator():
if self.mode == 'test':
pred_iou = np.array(fetch_list[1])
props_info = np.array(fetch_list[2])
fid = fetch_list[3][0][0]
fid = np.array(fetch_list[3])
self.save_results(pred_iou, props_info, fid)
def accumulate_infer_results(self, fetch_list):
pred_iou = np.array(fetch_list[0])
props_info = np.array(fetch_list[1])
fid = fetch_list[2][0]
props_info = np.array([item[0] for item in fetch_list[1]])
fid = [item[1] for item in fetch_list[1]]
self.save_results(pred_iou, props_info, fid)
def finalize_metrics(self):
......
......@@ -39,7 +39,6 @@ class MetricsCalculator():
1.0 / self.tscale * i for i in range(1, self.tscale + 1)
]
if self.mode == "test" or self.mode == "infer":
print('1212')
self.output_path_tem = cfg[self.mode.upper()]["output_path_tem"]
self.output_path_pgm_feature = cfg[self.mode.upper()][
"output_path_pgm_feature"]
......@@ -101,15 +100,21 @@ class MetricsCalculator():
os.makedirs(self.output_path_pgm_proposal)
def save_results(self, pred_tem, fid):
video_name = self.video_list[fid]
pred_start = pred_tem[0, 0, :]
pred_end = pred_tem[0, 1, :]
pred_action = pred_tem[0, 2, :]
output_tem = np.stack([pred_start, pred_end, pred_action], axis=1)
video_df = pd.DataFrame(output_tem, columns=["start", "end", "action"])
video_df.to_csv(
os.path.join(self.output_path_tem, video_name + ".csv"),
index=False)
batch_size = pred_tem.shape[0]
for i in range(batch_size):
if self.mode == 'test':
video_name = self.video_list[fid[i][0]]
elif self.mode == 'infer':
video_name = self.video_list[fid[i]]
pred_start = pred_tem[i, 0, :]
pred_end = pred_tem[i, 1, :]
pred_action = pred_tem[i, 2, :]
output_tem = np.stack([pred_start, pred_end, pred_action], axis=1)
video_df = pd.DataFrame(
output_tem, columns=["start", "end", "action"])
video_df.to_csv(
os.path.join(self.output_path_tem, video_name + ".csv"),
index=False)
def accumulate(self, fetch_list):
cur_batch_size = 1 # iteration counter
......@@ -126,12 +131,12 @@ class MetricsCalculator():
if self.mode == 'test':
pred_tem = np.array(fetch_list[4])
fid = fetch_list[5][0][0]
fid = fetch_list[5]
self.save_results(pred_tem, fid)
def accumulate_infer_results(self, fetch_list):
pred_tem = np.array(fetch_list[0])
fid = fetch_list[1][0]
fid = fetch_list[1]
self.save_results(pred_tem, fid)
def finalize_metrics(self):
......
......@@ -128,7 +128,6 @@ class MetricsCalculator():
def accumulate_infer_results(self, fetch_list):
fname = fetch_list[2][0]
print('fname', fetch_list[2])
loc_pred = np.array(fetch_list[0])
cls_pred = np.array(fetch_list[1])
assert len(loc_pred) == 1, "please set batchsize to be 1 when infer"
......
......@@ -23,11 +23,7 @@ logger = logging.getLogger(__name__)
class MetricsCalculator():
def __init__(self,
name='ETS',
mode='train',
dict_file =''
):
def __init__(self, name='ETS', mode='train', dict_file=''):
self.name = name
self.mode = mode # 'train', 'valid', 'test', 'infer'
self.dict_file = dict_file
......@@ -49,9 +45,14 @@ class MetricsCalculator():
elif (self.mode == 'test') or (self.mode == 'infer'):
seq_ids = fetch_list[0]
seq_scores = fetch_list[1]
vid = fetch_list[2][0]
stime = fetch_list[2][1]
etime = fetch_list[2][2]
b_vid = [item[0] for item in fetch_list[2]]
b_stime = [item[1] for item in fetch_list[2]]
b_etime = [item[2] for item in fetch_list[2]]
# for test and inference, batch size=1
vid = b_vid[0]
stime = b_stime[0]
etime = b_etime[0]
#get idx_to_word
self.idx_to_word = dict()
......@@ -65,12 +66,20 @@ class MetricsCalculator():
for j in range(end - start)[:1]:
sub_start = seq_ids.lod()[1][start + j]
sub_end = seq_ids.lod()[1][start + j + 1]
sent = " ".join([self.idx_to_word[idx]
for idx in np.array(seq_ids)[sub_start:sub_end][1:-1]])
sent = " ".join([
self.idx_to_word[idx]
for idx in np.array(seq_ids)[sub_start:sub_end][1:-1]
])
if vid not in self.result_dict:
self.result_dict[vid] = [{'timestamp': [stime, etime], 'sentence': sent}]
self.result_dict[vid] = [{
'timestamp': [stime, etime],
'sentence': sent
}]
else:
self.result_dict[vid].append({'timestamp': [stime, etime], 'sentence': sent})
self.result_dict[vid].append({
'timestamp': [stime, etime],
'sentence': sent
})
def accumulate_infer_results(self, fetch_list):
# the same as test
......@@ -79,9 +88,16 @@ class MetricsCalculator():
def finalize_metrics(self, savedir):
self.filepath = os.path.join(savedir, self.out_file)
with open(self.filepath, 'w') as f:
f.write(json.dumps({'version': 'VERSION 1.0', 'results': self.result_dict, 'external_data': {}}, indent=2))
logger.info('results has been saved into file: {}'.format(self.filepath))
f.write(
json.dumps(
{
'version': 'VERSION 1.0',
'results': self.result_dict,
'external_data': {}
},
indent=2))
logger.info('results has been saved into file: {}'.format(
self.filepath))
def finalize_infer_metrics(self, savedir):
# the same as test
......
......@@ -75,6 +75,7 @@ BMN的训练数据采用ActivityNet1.3提供的数据集,数据下载及准备
- 使用CPU进行评估时,请将上面的命令行或者run.sh脚本中的`use_gpu`设置为False。
- 注:评估时可能会出现loss为nan的情况。这是由于评估时用的是单个样本,可能存在没有iou>0.6的样本,所以为nan,对最终的评估结果没有影响。
在ActivityNet1.3数据集下评估精度如下:
......
......@@ -27,7 +27,6 @@ def iou_with_anchors(anchors_min, anchors_max, box_min, box_max):
int_xmax = np.minimum(anchors_max, box_max)
inter_len = np.maximum(int_xmax - int_xmin, 0.)
union_len = len_anchors - inter_len + box_max - box_min
#print inter_len,union_len
jaccard = np.divide(inter_len, union_len)
return jaccard
......
......@@ -100,7 +100,7 @@ class BsnTem(ModelBase):
assert self.mode != 'infer', \
'dataloader is not recommendated when infer, please set use_dataloader to be false.'
self.dataloader = fluid.io.DataLoader.from_generator(
feed_list=feed_list, capacity=8, iterable=True)
feed_list=feed_list, capacity=8, iterable=True)
self.feat_input = [feat]
self.gt_start = gt_start
......@@ -213,7 +213,7 @@ class BsnPem(ModelBase):
def build_input(self, use_dataloader=True):
feat_shape = [None, self.top_K, self.feat_dim]
gt_iou_shape = [None. self.top_K, 1]
gt_iou_shape = [None, self.top_K, 1]
props_info_shape = [None, self.top_K, 4]
fileid_shape = [None, 1]
self.use_dataloader = use_dataloader
......@@ -243,9 +243,7 @@ class BsnPem(ModelBase):
name='fileid', shape=fileid_shape, dtype='int64')
feed_list.append(fileid)
elif self.mode == 'infer':
props_info = fluid.data(
name='props_info', shape=props_info_shape, dtype='float32')
feed_list.append(props_info)
pass
else:
raise NotImplementedError('mode {} not implemented'.format(
self.mode))
......@@ -254,7 +252,7 @@ class BsnPem(ModelBase):
assert self.mode != 'infer', \
'dataloader is not recommendated when infer, please set use_dataloader to be false.'
self.dataloader = fluid.io.DataLoader.from_generator(
feed_list=feed_list, capacity=4, iterable=True)
feed_list=feed_list, capacity=4, iterable=True)
self.feat_input = [feat]
self.gt_iou = gt_iou
......@@ -304,7 +302,7 @@ class BsnPem(ModelBase):
elif self.mode == 'test':
return self.feat_input + [self.gt_iou, self.props_info, self.fileid]
elif self.mode == 'infer':
return self.feat_input + [self.props_info]
return self.feat_input
else:
raise NotImplementedError('mode {} not implemented'.format(
self.mode))
......@@ -321,8 +319,7 @@ class BsnPem(ModelBase):
[self.props_info, self.fileid]
elif self.mode == 'infer':
preds = self.outputs()
fetch_list = [item for item in preds] + \
[self.props_info]
fetch_list = [item for item in preds]
else:
raise NotImplementedError('mode {} not implemented'.format(
self.mode))
......
......@@ -31,7 +31,6 @@ def iou_with_anchors(anchors_min, anchors_max, box_min, box_max):
int_xmax = np.minimum(anchors_max, box_max)
inter_len = np.maximum(int_xmax - int_xmin, 0.)
union_len = len_anchors - inter_len + box_max - box_min
#print inter_len,union_len
jaccard = np.divide(inter_len, union_len)
return jaccard
......
......@@ -146,7 +146,16 @@ def infer(args):
infer_outs = exe.run(fetch_list=fetch_list,
feed=infer_feeder.feed(data_feed_in),
return_numpy=False)
infer_result_list = infer_outs + vinfo
infer_result_list = infer_outs + [vinfo]
elif args.model_name == 'BsnPem':
data_feed_in = [items[:1] for items in data]
vinfo = [items[1:] for items in data]
video_id = [items[2] for items in data]
infer_outs = exe.run(fetch_list=fetch_list,
feed=infer_feeder.feed(data_feed_in),
return_numpy=False)
infer_result_list = infer_outs + [vinfo]
else:
data_feed_in = [items[:-1] for items in data]
video_id = [items[-1] for items in data]
......
......@@ -13,11 +13,15 @@
#limitations under the License.
import os
import platform
import random
import numpy as np
import multiprocessing
import json
import logging
import functools
import paddle
logger = logging.getLogger(__name__)
from .reader_utils import DataReader
......@@ -150,7 +154,11 @@ class BMNReader(DataReader):
if self.num_threads == 1:
return self.make_reader()
else:
return self.make_multiprocess_reader()
sysstr = platform.system()
if sysstr == 'Windows':
return self.make_multithread_reader()
else:
return self.make_multiprocess_reader()
def make_infer_reader(self):
"""reader for inference"""
......@@ -196,6 +204,41 @@ class BMNReader(DataReader):
return reader
def make_multithread_reader(self):
def reader():
if self.mode == 'train':
random.shuffle(self.video_list)
for video_name in self.video_list:
video_idx = self.video_list.index(video_name)
yield [video_name, video_idx]
def process_data(sample, mode):
video_name = sample[0]
video_idx = sample[1]
video_feat = self.load_file(video_name)
gt_iou_map, gt_start, gt_end = self.get_video_label(video_name)
if mode == 'train' or mode == 'valid':
return (video_feat, gt_iou_map, gt_start, gt_end)
elif mode == 'test':
return (video_feat, gt_iou_map, gt_start, gt_end, video_idx)
else:
raise NotImplementedError('mode {} not implemented'.format(
mode))
mapper = functools.partial(process_data, mode=self.mode)
def batch_reader():
xreader = paddle.reader.xmap_readers(mapper, reader,
self.num_threads, 1024)
batch = []
for item in xreader():
batch.append(item)
if len(batch) == self.batch_size:
yield batch
batch = []
return batch_reader
def make_multiprocess_reader(self):
"""multiprocess reader"""
......
......@@ -13,12 +13,15 @@
#limitations under the License.
import os
import platform
import random
import numpy as np
import pandas as pd
import multiprocessing
import json
import logging
import functools
import paddle
logger = logging.getLogger(__name__)
from .reader_utils import DataReader
......@@ -136,7 +139,11 @@ class BSNVideoReader(DataReader):
if self.num_threads == 1:
return self.make_reader()
else:
return self.make_multiprocess_reader()
sysstr = platform.system()
if sysstr == 'Windows':
return self.make_multithread_reader()
else:
return self.make_multiprocess_reader()
def make_infer_reader(self):
"""reader for inference"""
......@@ -182,6 +189,42 @@ class BSNVideoReader(DataReader):
return reader
def make_multithread_reader(self):
def reader():
if self.mode == 'train':
random.shuffle(self.video_list)
for video_name in self.video_list:
video_idx = self.video_list.index(video_name)
yield [video_name, video_idx]
def process_data(sample, mode):
video_name = sample[0]
video_idx = sample[1]
video_feat = self.load_file(video_name)
gt_start, gt_end, gt_action = self.get_video_label(video_name)
if mode == 'train' or mode == 'valid':
return (video_feat, gt_start, gt_end, gt_action)
elif mode == 'test':
return (video_feat, gt_start, gt_end, gt_action, video_idx)
else:
raise NotImplementedError('mode {} not implemented'.format(
self.mode))
mapper = functools.partial(process_data, mode=self.mode)
def batch_reader():
xreader = paddle.reader.xmap_readers(mapper, reader,
self.num_threads, 1024)
batch = []
for item in xreader():
batch.append(item)
if len(batch) == self.batch_size:
yield batch
batch = []
return batch_reader
def make_multiprocess_reader(self):
"""multiprocess reader"""
......@@ -304,8 +347,10 @@ class BSNProposalReader(DataReader):
props_end = pdf.xmax.values[:]
props_start_score = pdf.xmin_score.values[:]
props_end_score = pdf.xmax_score.values[:]
props_info = np.stack(
[props_start, props_end, props_start_score, props_end_score])
props_info = np.hstack([
props_start[:, np.newaxis], props_end[:, np.newaxis],
props_start_score[:, np.newaxis], props_end_score[:, np.newaxis]
])
if self.mode == "infer":
return props_info
else:
......@@ -325,7 +370,11 @@ class BSNProposalReader(DataReader):
if self.num_threads == 1:
return self.make_reader()
else:
return self.make_multiprocess_reader()
sysstr = platform.system()
if sysstr == 'Windows':
return self.make_multithread_reader()
else:
return self.make_multiprocess_reader()
def make_infer_reader(self):
"""reader for inference"""
......@@ -371,6 +420,41 @@ class BSNProposalReader(DataReader):
return reader
def make_multithread_reader(self):
def reader():
if self.mode == 'train':
random.shuffle(self.video_list)
for video_name in self.video_list:
video_idx = self.video_list.index(video_name)
yield [video_name, video_idx]
def process_data(sample, mode):
video_name = sample[0]
video_idx = sample[1]
props_feat = self.load_file(video_name)
props_iou, props_info = self.get_props(video_name)
if mode == 'train' or mode == 'valid':
return (props_feat, props_iou)
elif mode == 'test':
return (props_feat, props_iou, props_info, video_idx)
else:
raise NotImplementedError('mode {} not implemented'.format(
mode))
mapper = functools.partial(process_data, mode=self.mode)
def batch_reader():
xreader = paddle.reader.xmap_readers(mapper, reader,
self.num_threads, 1024)
batch = []
for item in xreader():
batch.append(item)
if len(batch) == self.batch_size:
yield batch
batch = []
return batch_reader
def make_multiprocess_reader(self):
"""multiprocess reader"""
......
......@@ -99,6 +99,8 @@ class KineticsReader(DataReader):
img_mean=self.img_mean,
img_std=self.img_std)
else:
assert os.path.exists(self.filelist), \
'{} not exist, please check the data list'.format(self.filelist)
_reader = self._reader_creator(self.filelist, self.mode, seg_num=self.seg_num, seglen = self.seglen, \
short_size = self.short_size, target_size = self.target_size, \
img_mean = self.img_mean, img_std = self.img_std, \
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册