Files
paddlepaddle--paddle/test/xpu/test_sequence_conv_op_xpu.py
2026-07-13 12:40:42 +08:00

451 lines
14 KiB
Python

# 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 random
import sys
import unittest
import numpy as np
import paddle
sys.path.append("../")
from get_test_cover_info import (
XPUOpTestWrapper,
create_test_class,
get_xpu_op_support_types,
)
from op_test_xpu import XPUOpTest
paddle.enable_static()
np.set_printoptions(threshold=np.inf)
def seqconv(
x,
lod,
filter,
context_length,
context_start,
padding_trainable=False,
padding_data=None,
):
[T, M] = x.shape
col = np.zeros((T, context_length * M)).astype('float32')
offset = [0]
for seq_len in lod[0]:
offset.append(offset[-1] + seq_len)
begin_pad = np.max([0, -context_start])
for i in range(len(offset) - 1):
for j in range(context_length):
in_begin = offset[i] + context_start + j
in_end = offset[i + 1] + context_start + j
out_begin = offset[i]
out_end = offset[i + 1]
if in_begin < offset[i]:
pad_size = np.min(
[offset[i] - in_begin, offset[i + 1] - offset[i]]
)
if padding_trainable:
sub_w = padding_data[j : j + pad_size, :]
col[
offset[i] : offset[i] + pad_size, j * M : (j + 1) * M
] = sub_w
out_begin = offset[i] + pad_size
in_begin = offset[i]
if in_end > offset[i + 1]:
pad_size = np.min(
[in_end - offset[i + 1], offset[i + 1] - offset[i]]
)
if padding_trainable:
sub_w = padding_data[
begin_pad + context_start + j - pad_size : begin_pad
+ context_start
+ j,
:,
]
col[
offset[i + 1] - pad_size : offset[i + 1],
j * M : (j + 1) * M,
] = sub_w
in_end = offset[i + 1]
out_end = offset[i + 1] - pad_size
if in_end <= in_begin:
continue
in_sub = x[in_begin:in_end, :]
col[out_begin:out_end, j * M : (j + 1) * M] += in_sub
return np.dot(col, filter)
class XPUTestSequenceConv(XPUOpTestWrapper):
def __init__(self):
self.op_name = 'sequence_conv'
class TestSeqProject(XPUOpTest):
def setUp(self):
self.init_test_case()
self.op_type = 'sequence_conv'
self.dtype = self.in_type
self.use_xpu = True
if (
self.context_length == 1
and self.context_start == 0
and self.padding_trainable
):
print(
"If context_start is 0 "
"and context_length is 1,"
" padding_trainable should be false."
)
return
# one level, batch size
x = np.random.uniform(
-6.10907e-05,
0.000104218,
[self.input_size[0], self.input_size[1]],
).astype(self.dtype)
w = np.random.uniform(
-3.17068e-05,
0.000159822,
[
self.context_length * self.input_size[1],
self.output_representation,
],
).astype(self.dtype)
begin_pad = np.max([0, -self.context_start])
end_pad = np.max([0, self.context_start + self.context_length - 1])
total_pad = begin_pad + end_pad
padding_data = np.random.uniform(
0, 0, [total_pad, self.input_size[1]]
).astype(self.dtype)
self.pad_data = padding_data
self.inputs = {
'X': (x, self.lod),
'Filter': w,
}
self.inputs_val = ['X', 'Filter']
self.inputs_val_no_x = ['Filter']
self.inputs_val_no_f = ['X']
if total_pad != 0:
self.inputs['PaddingData'] = padding_data
self.inputs_val = ['X', 'PaddingData', 'Filter']
self.inputs_val_no_x = ['PaddingData', 'Filter']
self.inputs_val_no_f = ['PaddingData', 'X']
self.attrs = {
'contextStart': self.context_start,
'contextLength': self.context_length,
'paddingTrainable': self.padding_trainable,
'contextStride': self.context_stride,
}
out = seqconv(
x,
self.lod,
w,
self.context_length,
self.context_start,
self.padding_trainable,
self.pad_data,
)
self.outputs = {'Out': out}
def test_check_output(self):
place = paddle.XPUPlace(0)
self.check_output_with_place(place)
def test_check_grad_input(self):
self.check_grad(['X'], 'Out', no_grad_set=set(self.inputs_val_no_x))
def test_check_grad_padding_data(self):
if self.padding_trainable:
self.check_grad(
['PaddingData'], 'Out', no_grad_set={'X', 'Filter'}
)
def test_check_grad_Filter(self):
self.check_grad(
['Filter'], 'Out', no_grad_set=set(self.inputs_val_no_f)
)
def test_check_grad_input_filter(self):
if self.padding_trainable:
self.check_grad(
['X', 'Filter'], 'Out', no_grad_set={'PaddingData'}
)
def test_check_grad_padding_input(self):
if self.padding_trainable:
self.check_grad(
self.inputs_val_no_f, 'Out', no_grad_set={'Filter'}
)
def test_check_grad_padding_filter(self):
if self.padding_trainable:
self.check_grad(self.inputs_val_no_x, 'Out', no_grad_set={'X'})
def init_test_case(self):
self.input_row = 7
self.input_col = 25
self.context_start = -2
self.context_length = 5
self.padding_trainable = False
self.context_stride = 1
self.input_size = [self.input_row, self.input_col]
offset_lod = [[0, 1, self.input_row]]
self.lod = [[]]
# convert from offset-based lod to length-based lod
for i in range(len(offset_lod[0]) - 1):
self.lod[0].append(offset_lod[0][i + 1] - offset_lod[0][i])
self.output_representation = 8 # output feature size
class TestSeqProjectCase1(TestSeqProject):
def init_test_case(self):
self.input_row = 11
self.context_start = -2
self.context_length = 5
self.padding_trainable = False
self.context_stride = 1
self.input_size = [self.input_row, 50]
offset_lod = [[0, 4, 5, 8, self.input_row]]
self.lod = [[]]
# convert from offset-based lod to length-based lod
for i in range(len(offset_lod[0]) - 1):
self.lod[0].append(offset_lod[0][i + 1] - offset_lod[0][i])
self.output_representation = 8 # output feature size
class TestSeqProjectCase2Len0(TestSeqProject):
def init_test_case(self):
self.input_row = 11
self.context_start = -2
self.context_length = 5
self.padding_trainable = False
self.context_stride = 1
self.input_size = [self.input_row, 50]
offset_lod = [[0, 0, 4, 5, 5, 8, self.input_row, self.input_row]]
self.lod = [[]]
# convert from offset-based lod to length-based lod
for i in range(len(offset_lod[0]) - 1):
self.lod[0].append(offset_lod[0][i + 1] - offset_lod[0][i])
self.output_representation = 8 # output feature size
class TestSeqProjectCase3(TestSeqProject):
def init_test_case(self):
self.input_row = 25
self.context_start = -2
self.context_length = 5
self.padding_trainable = False
self.context_stride = 1
self.input_size = [self.input_row, 25]
idx = list(range(self.input_size[0]))
del idx[0]
offset_lod = [
[
0,
*np.sort(random.sample(idx, 8)).tolist(),
self.input_size[0],
]
]
self.lod = [[]]
# convert from offset-based lod to length-based lod
for i in range(len(offset_lod[0]) - 1):
self.lod[0].append(offset_lod[0][i + 1] - offset_lod[0][i])
self.output_representation = 8 # output feature size
class TestSeqProjectCase4(TestSeqProject):
def init_test_case(self):
self.input_row = 7835
self.input_col = 128
self.context_start = -2
self.context_length = 5
self.padding_trainable = False
self.context_stride = 1
self.input_size = [self.input_row, self.input_col]
offset_lod = [
[
0,
1,
2,
3,
131,
241,
242,
263,
264,
265,
266,
267,
268,
387,
515,
516,
644,
645,
772,
794,
922,
923,
924,
944,
945,
1073,
1074,
1202,
1330,
1458,
1556,
1557,
1558,
1686,
1748,
1876,
1912,
1913,
1914,
2032,
2066,
2194,
2308,
2309,
2347,
2475,
2476,
2477,
2478,
2606,
2607,
2735,
2736,
2737,
2738,
2838,
2966,
2967,
2968,
2969,
3097,
3225,
3353,
3481,
3482,
3520,
3642,
3643,
3754,
3882,
3883,
4010,
4011,
4012,
4140,
4219,
4228,
4356,
4357,
4415,
4475,
4476,
4604,
4605,
4606,
4694,
4695,
4808,
4936,
4961,
4962,
5004,
5132,
5260,
5312,
5440,
5441,
5569,
5570,
5675,
5676,
5750,
5810,
5811,
5939,
6021,
6149,
6277,
6278,
6364,
6425,
6519,
6647,
6648,
6739,
6867,
6995,
6996,
7120,
7223,
7244,
7367,
7407,
7408,
7467,
7595,
7699,
7827,
7835,
]
]
self.lod = [[]]
# convert from offset-based lod to length-based lod
for i in range(len(offset_lod[0]) - 1):
self.lod[0].append(offset_lod[0][i + 1] - offset_lod[0][i])
self.output_representation = 8 # output feature size
support_types = get_xpu_op_support_types('sequence_conv')
for stype in support_types:
create_test_class(globals(), XPUTestSequenceConv, stype)
class TestSeqConvApi(unittest.TestCase):
def test_api(self):
with paddle.pir_utils.OldIrGuard():
from paddle import base
x = paddle.static.data('x', shape=[-1, 32], lod_level=1)
y = paddle.static.nn.sequence_lod.sequence_conv(
input=x, num_filters=2, filter_size=3, padding_start=None
)
place = base.CPUPlace()
x_tensor = base.create_lod_tensor(
np.random.rand(10, 32).astype("float32"), [[2, 3, 1, 4]], place
)
exe = base.Executor(place)
exe.run(base.default_startup_program())
ret = exe.run(
feed={'x': x_tensor}, fetch_list=[y], return_numpy=False
)
if __name__ == '__main__':
unittest.main()