Files
2026-07-13 12:40:42 +08:00

847 lines
29 KiB
Python

# Copyright (c) 2020 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 math
import os
import tempfile
import unittest
import numpy as np
from dygraph_to_static_utils import (
Dy2StTestBase,
enable_to_static_guard,
static_guard,
)
from predictor_utils import PredictorTools
import paddle
from paddle.base import ParamAttr
from paddle.base.framework import unique_name
from paddle.jit.pir_translated_layer import PIR_INFER_MODEL_SUFFIX
from paddle.jit.translated_layer import INFER_MODEL_SUFFIX, INFER_PARAMS_SUFFIX
SEED = 2000
DATATYPE = 'float32'
# Note: Set True to eliminate randomness.
# 1. For one operation, cuDNN has several algorithms,
# some algorithm results are non-deterministic, like convolution algorithms.
if paddle.is_compiled_with_cuda():
paddle.set_flags({'FLAGS_cudnn_deterministic': True})
def get_interp1d_mask(
tscale, dscale, prop_boundary_ratio, num_sample, num_sample_perbin
):
"""generate sample mask for each point in Boundary-Matching Map"""
mask_mat = []
for start_index in range(tscale):
mask_mat_vector = []
for duration_index in range(dscale):
if start_index + duration_index < tscale:
p_xmin = start_index
p_xmax = start_index + duration_index
center_len = float(p_xmax - p_xmin) + 1
sample_xmin = p_xmin - center_len * prop_boundary_ratio
sample_xmax = p_xmax + center_len * prop_boundary_ratio
p_mask = _get_interp1d_bin_mask(
sample_xmin,
sample_xmax,
tscale,
num_sample,
num_sample_perbin,
)
else:
p_mask = np.zeros([tscale, num_sample])
mask_mat_vector.append(p_mask)
mask_mat_vector = np.stack(mask_mat_vector, axis=2)
mask_mat.append(mask_mat_vector)
mask_mat = np.stack(mask_mat, axis=3)
mask_mat = mask_mat.astype(np.float32)
sample_mask = np.reshape(mask_mat, [tscale, -1])
return sample_mask
def _get_interp1d_bin_mask(
seg_xmin, seg_xmax, tscale, num_sample, num_sample_perbin
):
"""generate sample mask for a boundary-matching pair"""
plen = float(seg_xmax - seg_xmin)
plen_sample = plen / (num_sample * num_sample_perbin - 1.0)
total_samples = [
seg_xmin + plen_sample * ii
for ii in range(num_sample * num_sample_perbin)
]
p_mask = []
for idx in range(num_sample):
bin_samples = total_samples[
idx * num_sample_perbin : (idx + 1) * num_sample_perbin
]
bin_vector = np.zeros([tscale])
for sample in bin_samples:
sample_upper = math.ceil(sample)
sample_decimal, sample_down = math.modf(sample)
if int(sample_down) <= (tscale - 1) and int(sample_down) >= 0:
bin_vector[int(sample_down)] += 1 - sample_decimal
if int(sample_upper) <= (tscale - 1) and int(sample_upper) >= 0:
bin_vector[int(sample_upper)] += sample_decimal
bin_vector = 1.0 / num_sample_perbin * bin_vector
p_mask.append(bin_vector)
p_mask = np.stack(p_mask, axis=1)
return p_mask
class Conv1D(paddle.nn.Layer):
def __init__(
self,
prefix,
num_channels=256,
num_filters=256,
size_k=3,
padding=1,
groups=1,
act="relu",
):
super().__init__()
fan_in = num_channels * size_k * 1
k = 1.0 / math.sqrt(fan_in)
param_attr = ParamAttr(
name=prefix + "_w",
initializer=paddle.nn.initializer.Uniform(low=-k, high=k),
)
bias_attr = ParamAttr(
name=prefix + "_b",
initializer=paddle.nn.initializer.Uniform(low=-k, high=k),
)
self._conv2d = paddle.nn.Conv2D(
in_channels=num_channels,
out_channels=num_filters,
kernel_size=(1, size_k),
stride=1,
padding=(0, padding),
groups=groups,
weight_attr=param_attr,
bias_attr=bias_attr,
)
def forward(self, x):
x = paddle.unsqueeze(x, axis=[2])
x = self._conv2d(x)
x = paddle.squeeze(x, axis=[2])
return x
class BMN(paddle.nn.Layer):
def __init__(self, cfg):
super().__init__()
self.tscale = cfg.tscale
self.dscale = cfg.dscale
self.prop_boundary_ratio = cfg.prop_boundary_ratio
self.num_sample = cfg.num_sample
self.num_sample_perbin = cfg.num_sample_perbin
self.hidden_dim_1d = 256
self.hidden_dim_2d = 128
self.hidden_dim_3d = 512
# Base Module
self.b_conv1 = Conv1D(
prefix="Base_1",
num_channels=cfg.feat_dim,
num_filters=self.hidden_dim_1d,
size_k=3,
padding=1,
groups=4,
act="relu",
)
self.b_conv2 = Conv1D(
prefix="Base_2",
num_filters=self.hidden_dim_1d,
size_k=3,
padding=1,
groups=4,
act="relu",
)
# Temporal Evaluation Module
self.ts_conv1 = Conv1D(
prefix="TEM_s1",
num_filters=self.hidden_dim_1d,
size_k=3,
padding=1,
groups=4,
act="relu",
)
self.ts_conv2 = Conv1D(
prefix="TEM_s2", num_filters=1, size_k=1, padding=0, act="sigmoid"
)
self.te_conv1 = Conv1D(
prefix="TEM_e1",
num_filters=self.hidden_dim_1d,
size_k=3,
padding=1,
groups=4,
act="relu",
)
self.te_conv2 = Conv1D(
prefix="TEM_e2", num_filters=1, size_k=1, padding=0, act="sigmoid"
)
# Proposal Evaluation Module
self.p_conv1 = Conv1D(
prefix="PEM_1d",
num_filters=self.hidden_dim_2d,
size_k=3,
padding=1,
act="relu",
)
# init to speed up
sample_mask = get_interp1d_mask(
self.tscale,
self.dscale,
self.prop_boundary_ratio,
self.num_sample,
self.num_sample_perbin,
)
self.sample_mask = paddle.to_tensor(sample_mask)
self.sample_mask.stop_gradient = True
self.p_conv3d1 = paddle.nn.Conv3D(
in_channels=128,
out_channels=self.hidden_dim_3d,
kernel_size=(self.num_sample, 1, 1),
stride=(self.num_sample, 1, 1),
padding=0,
weight_attr=paddle.ParamAttr(name="PEM_3d1_w"),
bias_attr=paddle.ParamAttr(name="PEM_3d1_b"),
)
self.p_conv2d1 = paddle.nn.Conv2D(
in_channels=512,
out_channels=self.hidden_dim_2d,
kernel_size=1,
stride=1,
padding=0,
weight_attr=ParamAttr(name="PEM_2d1_w"),
bias_attr=ParamAttr(name="PEM_2d1_b"),
)
self.p_conv2d2 = paddle.nn.Conv2D(
in_channels=128,
out_channels=self.hidden_dim_2d,
kernel_size=3,
stride=1,
padding=1,
weight_attr=ParamAttr(name="PEM_2d2_w"),
bias_attr=ParamAttr(name="PEM_2d2_b"),
)
self.p_conv2d3 = paddle.nn.Conv2D(
in_channels=128,
out_channels=self.hidden_dim_2d,
kernel_size=3,
stride=1,
padding=1,
weight_attr=ParamAttr(name="PEM_2d3_w"),
bias_attr=ParamAttr(name="PEM_2d3_b"),
)
self.p_conv2d4 = paddle.nn.Conv2D(
in_channels=128,
out_channels=2,
kernel_size=1,
stride=1,
padding=0,
weight_attr=ParamAttr(name="PEM_2d4_w"),
bias_attr=ParamAttr(name="PEM_2d4_b"),
)
def forward(self, x):
# Base Module
x = paddle.nn.functional.relu(self.b_conv1(x))
x = paddle.nn.functional.relu(self.b_conv2(x))
# TEM
xs = paddle.nn.functional.relu(self.ts_conv1(x))
xs = paddle.nn.functional.relu(self.ts_conv2(xs))
xs = paddle.squeeze(xs, axis=[1])
xe = paddle.nn.functional.relu(self.te_conv1(x))
xe = paddle.nn.functional.relu(self.te_conv2(xe))
xe = paddle.squeeze(xe, axis=[1])
# PEM
xp = paddle.nn.functional.relu(self.p_conv1(x))
# BM layer
xp = paddle.matmul(xp, self.sample_mask)
xp = paddle.reshape(xp, shape=[0, 0, -1, self.dscale, self.tscale])
xp = self.p_conv3d1(xp)
xp = paddle.tanh(xp)
xp = paddle.squeeze(xp, axis=[2])
xp = paddle.nn.functional.relu(self.p_conv2d1(xp))
xp = paddle.nn.functional.relu(self.p_conv2d2(xp))
xp = paddle.nn.functional.relu(self.p_conv2d3(xp))
xp = paddle.nn.functional.sigmoid(self.p_conv2d4(xp))
return xp, xs, xe
def bmn_loss_func(
pred_bm, pred_start, pred_end, gt_iou_map, gt_start, gt_end, cfg
):
def _get_mask(cfg):
dscale = cfg.dscale
tscale = cfg.tscale
bm_mask = []
for idx in range(dscale):
mask_vector = [1 for i in range(tscale - idx)] + [
0 for i in range(idx)
]
bm_mask.append(mask_vector)
bm_mask = np.array(bm_mask, dtype=np.float32)
self_bm_mask = paddle.static.create_global_var(
shape=[dscale, tscale], value=0, dtype=DATATYPE, persistable=True
)
paddle.assign(bm_mask, self_bm_mask)
self_bm_mask.stop_gradient = True
return self_bm_mask
def tem_loss_func(pred_start, pred_end, gt_start, gt_end):
def bi_loss(pred_score, gt_label):
pred_score = paddle.reshape(x=pred_score, shape=[-1])
gt_label = paddle.reshape(x=gt_label, shape=[-1])
gt_label.stop_gradient = True
pmask = paddle.cast(x=(gt_label > 0.5), dtype=DATATYPE)
num_entries = paddle.cast(paddle.shape(pmask), dtype=DATATYPE)
num_positive = paddle.cast(paddle.sum(pmask), dtype=DATATYPE)
ratio = num_entries / num_positive
coef_0 = 0.5 * ratio / (ratio - 1)
coef_1 = 0.5 * ratio
epsilon = 0.000001
# temp = paddle.log(pred_score + epsilon)
loss_pos = paddle.multiply(paddle.log(pred_score + epsilon), pmask)
loss_pos = coef_1 * paddle.mean(loss_pos)
loss_neg = paddle.multiply(
paddle.log(1.0 - pred_score + epsilon), (1.0 - pmask)
)
loss_neg = coef_0 * paddle.mean(loss_neg)
loss = -1 * (loss_pos + loss_neg)
return loss
loss_start = bi_loss(pred_start, gt_start)
loss_end = bi_loss(pred_end, gt_end)
loss = loss_start + loss_end
return loss
def pem_reg_loss_func(pred_score, gt_iou_map, mask):
gt_iou_map = paddle.multiply(gt_iou_map, mask)
u_hmask = paddle.cast(x=gt_iou_map > 0.7, dtype=DATATYPE)
u_mmask = paddle.logical_and(gt_iou_map <= 0.7, gt_iou_map > 0.3)
u_mmask = paddle.cast(x=u_mmask, dtype=DATATYPE)
u_lmask = paddle.logical_and(gt_iou_map <= 0.3, gt_iou_map >= 0.0)
u_lmask = paddle.cast(x=u_lmask, dtype=DATATYPE)
u_lmask = paddle.multiply(u_lmask, mask)
num_h = paddle.cast(paddle.sum(u_hmask), dtype=DATATYPE)
num_m = paddle.cast(paddle.sum(u_mmask), dtype=DATATYPE)
num_l = paddle.cast(paddle.sum(u_lmask), dtype=DATATYPE)
r_m = num_h / num_m
u_smmask = paddle.assign(
local_random.uniform(
0.0, 1.0, [gt_iou_map.shape[1], gt_iou_map.shape[2]]
).astype(DATATYPE)
)
u_smmask = paddle.multiply(u_mmask, u_smmask)
u_smmask = paddle.cast(x=(u_smmask > (1.0 - r_m)), dtype=DATATYPE)
r_l = num_h / num_l
u_slmask = paddle.assign(
local_random.uniform(
0.0, 1.0, [gt_iou_map.shape[1], gt_iou_map.shape[2]]
).astype(DATATYPE)
)
u_slmask = paddle.multiply(u_lmask, u_slmask)
u_slmask = paddle.cast(x=(u_slmask > (1.0 - r_l)), dtype=DATATYPE)
weights = u_hmask + u_smmask + u_slmask
weights.stop_gradient = True
loss = paddle.nn.functional.square_error_cost(pred_score, gt_iou_map)
loss = paddle.multiply(loss, weights)
loss = 0.5 * paddle.sum(loss) / paddle.sum(weights)
return loss
def pem_cls_loss_func(pred_score, gt_iou_map, mask):
gt_iou_map = paddle.multiply(gt_iou_map, mask)
gt_iou_map.stop_gradient = True
pmask = paddle.cast(x=(gt_iou_map > 0.9), dtype=DATATYPE)
nmask = paddle.cast(x=(gt_iou_map <= 0.9), dtype=DATATYPE)
nmask = paddle.multiply(nmask, mask)
num_positive = paddle.sum(pmask)
num_entries = num_positive + paddle.sum(nmask)
ratio = num_entries / num_positive
coef_0 = 0.5 * ratio / (ratio - 1)
coef_1 = 0.5 * ratio
epsilon = 0.000001
loss_pos = paddle.multiply(paddle.log(pred_score + epsilon), pmask)
loss_pos = coef_1 * paddle.sum(loss_pos)
loss_neg = paddle.multiply(
paddle.log(1.0 - pred_score + epsilon), nmask
)
loss_neg = coef_0 * paddle.sum(loss_neg)
loss = -1 * (loss_pos + loss_neg) / num_entries
return loss
pred_bm_reg = paddle.squeeze(
paddle.slice(pred_bm, axes=[1], starts=[0], ends=[1]), axis=[1]
)
pred_bm_cls = paddle.squeeze(
paddle.slice(pred_bm, axes=[1], starts=[1], ends=[2]), axis=[1]
)
bm_mask = _get_mask(cfg)
pem_reg_loss = pem_reg_loss_func(pred_bm_reg, gt_iou_map, bm_mask)
pem_cls_loss = pem_cls_loss_func(pred_bm_cls, gt_iou_map, bm_mask)
tem_loss = tem_loss_func(pred_start, pred_end, gt_start, gt_end)
loss = tem_loss + 10 * pem_reg_loss + pem_cls_loss
return loss, tem_loss, pem_reg_loss, pem_cls_loss
class Args:
epoch = 1
batch_size = 4
learning_rate = 0.1
learning_rate_decay = 0.1
lr_decay_iter = 4200
l2_weight_decay = 1e-4
valid_interval = 20
log_interval = 5
train_batch_num = valid_interval
valid_batch_num = 5
tscale = 50
dscale = 50
feat_dim = 100
prop_boundary_ratio = 0.5
num_sample = 2
num_sample_perbin = 2
def optimizer(cfg, parameter_list):
bd = [cfg.lr_decay_iter]
base_lr = cfg.learning_rate
lr_decay = cfg.learning_rate_decay
l2_weight_decay = cfg.l2_weight_decay
lr = [base_lr, base_lr * lr_decay]
optimizer = paddle.optimizer.Adam(
paddle.optimizer.lr.PiecewiseDecay(boundaries=bd, values=lr),
parameters=parameter_list,
weight_decay=paddle.regularizer.L2Decay(coeff=l2_weight_decay),
)
return optimizer
def fake_data_reader(args, mode='train'):
def iou_with_anchors(anchors_min, anchors_max, box_min, box_max):
"""Compute jaccard score between a box and the anchors."""
len_anchors = anchors_max - anchors_min
int_xmin = np.maximum(anchors_min, box_min)
int_xmax = np.minimum(anchors_max, box_max)
inter_len = np.maximum(int_xmax - int_xmin, 0.0)
union_len = len_anchors - inter_len + box_max - box_min
jaccard = np.divide(inter_len, union_len)
return jaccard
def ioa_with_anchors(anchors_min, anchors_max, box_min, box_max):
"""Compute intersection between score a box and the anchors."""
len_anchors = anchors_max - anchors_min
int_xmin = np.maximum(anchors_min, box_min)
int_xmax = np.minimum(anchors_max, box_max)
inter_len = np.maximum(int_xmax - int_xmin, 0.0)
scores = np.divide(inter_len, len_anchors)
return scores
def get_match_map(tscale):
match_map = []
tgap = 1.0 / tscale
for idx in range(tscale):
tmp_match_window = []
xmin = tgap * idx
for jdx in range(1, tscale + 1):
xmax = xmin + tgap * jdx
tmp_match_window.append([xmin, xmax])
match_map.append(tmp_match_window)
match_map = np.array(match_map)
match_map = np.transpose(match_map, [1, 0, 2])
match_map = np.reshape(match_map, [-1, 2])
match_map = match_map
anchor_xmin = [tgap * i for i in range(tscale)]
anchor_xmax = [tgap * i for i in range(1, tscale + 1)]
return match_map, anchor_xmin, anchor_xmax
def get_video_label(match_map, anchor_xmin, anchor_xmax):
video_second = local_random.randint(75, 90)
label_num = local_random.randint(1, 3)
gt_bbox = []
gt_iou_map = []
for idx in range(label_num):
duration = local_random.uniform(
video_second * 0.4, video_second * 0.8
)
start_t = local_random.uniform(
0.1 * video_second, video_second - duration
)
tmp_start = max(min(1, start_t / video_second), 0)
tmp_end = max(min(1, (start_t + duration) / video_second), 0)
gt_bbox.append([tmp_start, tmp_end])
tmp_gt_iou_map = iou_with_anchors(
match_map[:, 0], match_map[:, 1], tmp_start, tmp_end
)
tmp_gt_iou_map = np.reshape(
tmp_gt_iou_map, [args.dscale, args.tscale]
)
gt_iou_map.append(tmp_gt_iou_map)
gt_iou_map = np.array(gt_iou_map)
gt_iou_map = np.max(gt_iou_map, axis=0)
gt_bbox = np.array(gt_bbox)
gt_xmins = gt_bbox[:, 0]
gt_xmaxs = gt_bbox[:, 1]
gt_len_small = 3.0 / args.tscale
gt_start_bboxs = np.stack(
(gt_xmins - gt_len_small / 2, gt_xmins + gt_len_small / 2), axis=1
)
gt_end_bboxs = np.stack(
(gt_xmaxs - gt_len_small / 2, gt_xmaxs + gt_len_small / 2), axis=1
)
match_score_start = []
for jdx in range(len(anchor_xmin)):
match_score_start.append(
np.max(
ioa_with_anchors(
anchor_xmin[jdx],
anchor_xmax[jdx],
gt_start_bboxs[:, 0],
gt_start_bboxs[:, 1],
)
)
)
match_score_end = []
for jdx in range(len(anchor_xmin)):
match_score_end.append(
np.max(
ioa_with_anchors(
anchor_xmin[jdx],
anchor_xmax[jdx],
gt_end_bboxs[:, 0],
gt_end_bboxs[:, 1],
)
)
)
gt_start = np.array(match_score_start)
gt_end = np.array(match_score_end)
return gt_iou_map, gt_start, gt_end
def reader():
batch_out = []
iter_num = args.batch_size * 100
match_map, anchor_xmin, anchor_xmax = get_match_map(args.tscale)
for video_idx in range(iter_num):
video_feat = local_random.random_sample(
[args.feat_dim, args.tscale]
).astype('float32')
gt_iou_map, gt_start, gt_end = get_video_label(
match_map, anchor_xmin, anchor_xmax
)
if mode == 'train' or mode == 'valid':
batch_out.append((video_feat, gt_iou_map, gt_start, gt_end))
elif mode == 'test':
batch_out.append(
(video_feat, gt_iou_map, gt_start, gt_end, video_idx)
)
else:
raise NotImplementedError(f'mode {mode} not implemented')
if len(batch_out) == args.batch_size:
yield batch_out
batch_out = []
return reader
# Validation
def val_bmn(model, args):
val_reader = fake_data_reader(args, 'valid')
loss_data = []
for batch_id, data in enumerate(val_reader()):
video_feat = np.array([item[0] for item in data]).astype(DATATYPE)
gt_iou_map = np.array([item[1] for item in data]).astype(DATATYPE)
gt_start = np.array([item[2] for item in data]).astype(DATATYPE)
gt_end = np.array([item[3] for item in data]).astype(DATATYPE)
x_data = paddle.to_tensor(video_feat)
gt_iou_map = paddle.to_tensor(gt_iou_map)
gt_start = paddle.to_tensor(gt_start)
gt_end = paddle.to_tensor(gt_end)
gt_iou_map.stop_gradient = True
gt_start.stop_gradient = True
gt_end.stop_gradient = True
pred_bm, pred_start, pred_end = model(x_data)
loss, tem_loss, pem_reg_loss, pem_cls_loss = bmn_loss_func(
pred_bm, pred_start, pred_end, gt_iou_map, gt_start, gt_end, args
)
avg_loss = paddle.mean(loss)
loss_data += [
float(avg_loss),
float(tem_loss),
float(pem_reg_loss),
float(pem_cls_loss),
]
if batch_id == args.valid_batch_num:
break
return loss_data
class TestTrain(Dy2StTestBase):
def setUp(self):
self.args = Args()
self.place = (
paddle.CPUPlace()
if not paddle.is_compiled_with_cuda()
else paddle.CUDAPlace(0)
)
self.temp_dir = tempfile.TemporaryDirectory()
self.model_save_dir = os.path.join(self.temp_dir.name, 'inference')
self.model_save_prefix = os.path.join(self.model_save_dir, 'bmn')
self.model_filename = "bmn" + INFER_MODEL_SUFFIX
self.pir_model_filename = "bmn" + PIR_INFER_MODEL_SUFFIX
self.params_filename = "bmn" + INFER_PARAMS_SUFFIX
self.dy_param_path = os.path.join(self.temp_dir.name, 'bmn_dy_param')
def tearDown(self):
self.temp_dir.cleanup()
def train_bmn(self, args, to_static):
with unique_name.guard():
loss_data = []
paddle.seed(SEED)
paddle.framework.random._manual_program_seed(SEED)
global local_random
local_random = np.random.RandomState(SEED)
bmn = paddle.jit.to_static(BMN(args))
adam = optimizer(args, parameter_list=bmn.parameters())
train_reader = fake_data_reader(args, 'train')
for epoch in range(args.epoch):
for batch_id, data in enumerate(train_reader()):
video_feat = np.array([item[0] for item in data]).astype(
DATATYPE
)
gt_iou_map = np.array([item[1] for item in data]).astype(
DATATYPE
)
gt_start = np.array([item[2] for item in data]).astype(
DATATYPE
)
gt_end = np.array([item[3] for item in data]).astype(
DATATYPE
)
x_data = paddle.to_tensor(video_feat)
gt_iou_map = paddle.to_tensor(gt_iou_map)
gt_start = paddle.to_tensor(gt_start)
gt_end = paddle.to_tensor(gt_end)
gt_iou_map.stop_gradient = True
gt_start.stop_gradient = True
gt_end.stop_gradient = True
pred_bm, pred_start, pred_end = bmn(x_data)
loss, tem_loss, pem_reg_loss, pem_cls_loss = bmn_loss_func(
pred_bm,
pred_start,
pred_end,
gt_iou_map,
gt_start,
gt_end,
args,
)
avg_loss = paddle.mean(loss)
avg_loss.backward()
adam.minimize(avg_loss)
bmn.clear_gradients()
# log loss data to verify correctness
loss_data += [
float(avg_loss),
float(tem_loss),
float(pem_reg_loss),
float(pem_cls_loss),
]
# validation
if batch_id % args.valid_interval == 0 and batch_id > 0:
bmn.eval()
val_loss_data = val_bmn(bmn, args)
bmn.train()
loss_data += val_loss_data
if batch_id == args.train_batch_num:
if to_static:
paddle.jit.save(bmn, self.model_save_prefix)
else:
paddle.save(
bmn.state_dict(),
self.dy_param_path + '.pdparams',
)
break
return np.array(loss_data)
def test_train(self):
with enable_to_static_guard(True):
static_res = self.train_bmn(self.args, to_static=True)
with enable_to_static_guard(False):
dygraph_res = self.train_bmn(self.args, to_static=False)
np.testing.assert_allclose(
dygraph_res,
static_res,
rtol=1e-05,
err_msg=f'dygraph_res: {dygraph_res[~np.isclose(dygraph_res, static_res)]},\n static_res: {static_res[~np.isclose(dygraph_res, static_res)]}',
atol=1e-8,
)
# Prediction needs trained models, so put `test_predict` at last of `test_train`
self.verify_predict()
def verify_predict(self):
args = Args()
args.batch_size = 1 # change batch_size
test_reader = fake_data_reader(args, 'test')
for batch_id, data in enumerate(test_reader()):
video_data = np.array([item[0] for item in data]).astype(DATATYPE)
static_pred_res = self.predict_static(video_data)
dygraph_pred_res = self.predict_dygraph(video_data)
dygraph_jit_pred_res = self.predict_dygraph_jit(video_data)
predictor_pred_res = self.predict_analysis_inference(video_data)
for dy_res, st_res, dy_jit_res, predictor_res in zip(
dygraph_pred_res,
static_pred_res,
dygraph_jit_pred_res,
predictor_pred_res,
):
np.testing.assert_allclose(
st_res,
dy_res,
rtol=1e-05,
err_msg=f'dygraph_res: {dy_res[~np.isclose(st_res, dy_res)]},\n static_res: {st_res[~np.isclose(st_res, dy_res)]}',
atol=1e-8,
)
np.testing.assert_allclose(
st_res,
dy_jit_res,
rtol=1e-05,
err_msg=f'dygraph_jit_res: {dy_jit_res[~np.isclose(st_res, dy_jit_res)]},\n static_res: {st_res[~np.isclose(st_res, dy_jit_res)]}',
atol=1e-8,
)
np.testing.assert_allclose(
st_res,
predictor_res,
rtol=1e-05,
err_msg=f'dygraph_jit_res: {predictor_res[~np.isclose(st_res, predictor_res)]},\n static_res: {st_res[~np.isclose(st_res, predictor_res)]}',
atol=1e-8,
)
break
def predict_dygraph(self, data):
with enable_to_static_guard(False):
bmn = paddle.jit.to_static(BMN(self.args))
# load dygraph trained parameters
model_dict = paddle.load(self.dy_param_path + ".pdparams")
bmn.set_dict(model_dict)
bmn.eval()
x = paddle.to_tensor(data)
pred_res = bmn(x)
pred_res = [var.numpy() for var in pred_res]
return pred_res
def predict_static(self, data):
with static_guard():
exe = paddle.static.Executor(self.place)
model_filename = self.pir_model_filename
# load inference model
[
inference_program,
feed_target_names,
fetch_targets,
] = paddle.static.io.load_inference_model(
self.model_save_dir,
executor=exe,
model_filename=model_filename,
params_filename=self.params_filename,
)
pred_res = exe.run(
inference_program,
feed={feed_target_names[0]: data},
fetch_list=fetch_targets,
)
return pred_res
def predict_dygraph_jit(self, data):
bmn = paddle.jit.load(self.model_save_prefix)
bmn.eval()
x = paddle.to_tensor(data)
pred_res = bmn(x)
pred_res = [var.numpy() for var in pred_res]
return pred_res
def predict_analysis_inference(self, data):
model_filename = self.pir_model_filename
output = PredictorTools(
self.model_save_dir,
model_filename,
self.params_filename,
[data],
)
out = output()
return out
if __name__ == "__main__":
unittest.main()