Files
paddlepaddle--paddle/test/ai_edited_test/test_ai_extension_ops.py
T
2026-07-13 12:40:42 +08:00

353 lines
14 KiB
Python

# Copyright (c) 2024 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.
# [AUTO-GENERATED]
# Target file: python/paddle/nn/functional/extension.py
# Coverage target: sequence_mask, gather_tree, temporal_shift, diag_embed
# 未覆盖行: static graph paths for some functions
import unittest
import numpy as np
import paddle
from paddle.nn.functional.extension import (
diag_embed,
gather_tree,
sequence_mask,
temporal_shift,
)
class TestSequenceMask(unittest.TestCase):
"""Test sequence_mask function.
测试 sequence_mask 函数。"""
def setUp(self):
paddle.disable_static()
def test_sequence_mask_basic(self):
"""Test sequence_mask with basic 1D input.
测试基本一维输入的 sequence_mask。"""
x = paddle.to_tensor([3, 1, 1, 0])
mask = sequence_mask(x, maxlen=4)
expected = np.array(
[[1, 1, 1, 0], [1, 0, 0, 0], [1, 0, 0, 0], [0, 0, 0, 0]]
)
np.testing.assert_array_equal(mask.numpy(), expected)
def test_sequence_mask_2d_input(self):
"""Test sequence_mask with 2D input.
测试二维输入的 sequence_mask。"""
x = paddle.to_tensor([[3, 2], [1, 4]])
mask = sequence_mask(x, maxlen=5)
self.assertEqual(mask.shape, [2, 2, 5])
# First row, first column: length 3
np.testing.assert_array_equal(mask.numpy()[0, 0], [1, 1, 1, 0, 0])
# Second row, second column: length 4
np.testing.assert_array_equal(mask.numpy()[1, 1], [1, 1, 1, 1, 0])
def test_sequence_mask_no_maxlen(self):
"""Test sequence_mask with maxlen=None (auto-computed).
测试 maxlen=None(自动计算)的 sequence_mask。"""
x = paddle.to_tensor([3, 1, 5])
mask = sequence_mask(x)
# maxlen should be max(x) = 5
self.assertEqual(mask.shape, [3, 5])
np.testing.assert_array_equal(mask.numpy()[2], [1, 1, 1, 1, 1])
def test_sequence_mask_custom_dtype(self):
"""Test sequence_mask with custom dtype.
测试自定义数据类型的 sequence_mask。"""
x = paddle.to_tensor([2, 1, 3])
mask = sequence_mask(x, maxlen=4, dtype="float32")
self.assertEqual(mask.dtype, paddle.float32)
np.testing.assert_array_equal(mask.numpy()[0], [1.0, 1.0, 0.0, 0.0])
def test_sequence_mask_int32_dtype(self):
"""Test sequence_mask with int32 dtype.
测试 int32 数据类型的 sequence_mask。"""
x = paddle.to_tensor([1, 3, 2])
mask = sequence_mask(x, maxlen=3, dtype="int32")
self.assertEqual(mask.dtype, paddle.int32)
np.testing.assert_array_equal(mask.numpy()[1], [1, 1, 1])
def test_sequence_mask_float64_dtype(self):
"""Test sequence_mask with float64 dtype.
测试 float64 数据类型的 sequence_mask。"""
x = paddle.to_tensor([2, 0, 1])
mask = sequence_mask(x, maxlen=3, dtype="float64")
self.assertEqual(mask.dtype, paddle.float64)
def test_sequence_mask_all_zeros(self):
"""Test sequence_mask with all zeros input.
测试全零输入的 sequence_mask。"""
x = paddle.to_tensor([0, 0, 0])
mask = sequence_mask(x, maxlen=4)
expected = np.zeros((3, 4), dtype=np.int64)
np.testing.assert_array_equal(mask.numpy(), expected)
def test_sequence_mask_all_max(self):
"""Test sequence_mask where all lengths equal maxlen.
测试所有长度等于 maxlen 的 sequence_mask。"""
x = paddle.to_tensor([4, 4, 4])
mask = sequence_mask(x, maxlen=4)
expected = np.ones((3, 4), dtype=np.int64)
np.testing.assert_array_equal(mask.numpy(), expected)
def test_sequence_mask_maxlen_zero_raises(self):
"""Test sequence_mask with maxlen=0 raises error.
测试 maxlen=0 时 sequence_mask 抛出异常。"""
x = paddle.to_tensor([0, 0])
with self.assertRaises(RuntimeError):
sequence_mask(x, maxlen=0)
def test_sequence_mask_single_element(self):
"""Test sequence_mask with single element.
测试单元素的 sequence_mask。"""
x = paddle.to_tensor([2])
mask = sequence_mask(x, maxlen=3)
np.testing.assert_array_equal(mask.numpy(), [[1, 1, 0]])
def test_sequence_mask_3d_input(self):
"""Test sequence_mask with 3D input.
测试三维输入的 sequence_mask。"""
x = paddle.to_tensor([[[2], [1]], [[3], [0]]])
mask = sequence_mask(x, maxlen=4)
self.assertEqual(mask.shape, [2, 2, 1, 4])
class TestGatherTree(unittest.TestCase):
"""Test gather_tree function.
测试 gather_tree 函数。"""
def setUp(self):
paddle.disable_static()
def test_gather_tree_basic(self):
"""Test gather_tree with basic beam search data from docstring example.
测试文档字符串示例中基本束搜索数据的 gather_tree。"""
ids = paddle.to_tensor(
[[[2, 2], [6, 1]], [[3, 9], [6, 1]], [[0, 1], [9, 0]]]
)
parents = paddle.to_tensor(
[[[0, 0], [1, 1]], [[1, 0], [1, 0]], [[0, 0], [0, 1]]]
)
result = gather_tree(ids, parents)
expected = np.array(
[[[2, 2], [1, 6]], [[3, 3], [6, 1]], [[0, 1], [9, 0]]]
)
np.testing.assert_array_equal(result.numpy(), expected)
def test_gather_tree_output_shape(self):
"""Test gather_tree output shape matches input.
测试 gather_tree 输出形状与输入匹配。"""
ids = paddle.randint(0, 10, [5, 3, 4])
parents = paddle.randint(0, 4, [5, 3, 4])
result = gather_tree(ids, parents)
self.assertEqual(result.shape, [5, 3, 4])
def test_gather_tree_int32(self):
"""Test gather_tree with int32 dtype.
测试 int32 数据类型的 gather_tree。"""
ids = paddle.to_tensor(
[[[1, 0], [2, 1]], [[3, 2], [4, 3]]], dtype="int32"
)
parents = paddle.to_tensor(
[[[0, 0], [0, 1]], [[0, 0], [1, 1]]], dtype="int32"
)
result = gather_tree(ids, parents)
self.assertEqual(result.dtype, paddle.int32)
self.assertEqual(result.shape, [2, 2, 2])
def test_gather_tree_int64(self):
"""Test gather_tree with int64 dtype.
测试 int64 数据类型的 gather_tree。"""
ids = paddle.to_tensor(
[[[1, 0], [2, 1]], [[3, 2], [4, 3]]], dtype="int64"
)
parents = paddle.to_tensor(
[[[0, 0], [0, 1]], [[0, 0], [1, 1]]], dtype="int64"
)
result = gather_tree(ids, parents)
self.assertEqual(result.dtype, paddle.int64)
def test_gather_tree_identity_parents(self):
"""Test gather_tree where all parents point to themselves (identity).
测试所有 parent 指向自身的 gather_tree(恒等映射)。"""
ids = paddle.to_tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
parents = paddle.to_tensor([[[0, 1], [0, 1]], [[0, 1], [0, 1]]])
result = gather_tree(ids, parents)
# With identity parents, the last step stays the same
np.testing.assert_array_equal(
result.numpy()[-1].tolist(), ids.numpy()[-1].tolist()
)
def test_gather_tree_single_beam(self):
"""Test gather_tree with beam_size=1.
测试 beam_size=1 的 gather_tree。"""
ids = paddle.to_tensor([[[1], [2]], [[3], [4]], [[5], [6]]])
parents = paddle.to_tensor([[[0], [0]], [[0], [0]], [[0], [0]]])
result = gather_tree(ids, parents)
self.assertEqual(result.shape, [3, 2, 1])
def test_gather_tree_invalid_ndim(self):
"""Test gather_tree raises ValueError for non-3D input.
测试 gather_tree 对非三维输入引发 ValueError。"""
ids = paddle.to_tensor([[1, 2], [3, 4]])
parents = paddle.to_tensor([[0, 1], [1, 0]])
with self.assertRaises(ValueError):
gather_tree(ids, parents)
class TestTemporalShift(unittest.TestCase):
"""Test temporal_shift function.
测试 temporal_shift 函数。"""
def setUp(self):
paddle.disable_static()
def test_temporal_shift_nchw(self):
"""Test temporal_shift with NCHW format.
测试 NCHW 格式的 temporal_shift。"""
x = paddle.randn([6, 4, 2, 2], dtype="float32")
out = temporal_shift(x, seg_num=2, shift_ratio=0.25)
self.assertEqual(out.shape, x.shape)
self.assertEqual(out.dtype, x.dtype)
def test_temporal_shift_nhwc(self):
"""Test temporal_shift with NHWC format.
测试 NHWC 格式的 temporal_shift。"""
x = paddle.randn([6, 2, 2, 4], dtype="float32")
out = temporal_shift(x, seg_num=2, shift_ratio=0.25, data_format="NHWC")
self.assertEqual(out.shape, x.shape)
self.assertEqual(out.dtype, x.dtype)
def test_temporal_shift_custom_ratio(self):
"""Test temporal_shift with custom shift_ratio.
测试自定义 shift_ratio 的 temporal_shift。"""
x = paddle.randn([6, 8, 2, 2], dtype="float32")
out = temporal_shift(x, seg_num=2, shift_ratio=0.2)
self.assertEqual(out.shape, x.shape)
def test_temporal_shift_larger_segments(self):
"""Test temporal_shift with more segments.
测试更多分段的 temporal_shift。"""
x = paddle.randn([12, 4, 2, 2], dtype="float32")
out = temporal_shift(x, seg_num=4, shift_ratio=0.25)
self.assertEqual(out.shape, x.shape)
def test_temporal_shift_float16(self):
"""Test temporal_shift with float16 input.
测试 float16 输入的 temporal_shift。"""
x = paddle.randn([6, 4, 2, 2], dtype="float16")
out = temporal_shift(x, seg_num=2, shift_ratio=0.25)
self.assertEqual(out.shape, x.shape)
self.assertEqual(out.dtype, x.dtype)
def test_temporal_shift_float64(self):
"""Test temporal_shift with float64 input.
测试 float64 输入的 temporal_shift。"""
x = paddle.randn([6, 4, 2, 2], dtype="float64")
out = temporal_shift(x, seg_num=2, shift_ratio=0.25)
self.assertEqual(out.shape, x.shape)
self.assertEqual(out.dtype, x.dtype)
def test_temporal_shift_invalid_format(self):
"""Test temporal_shift raises ValueError for invalid data_format.
测试 temporal_shift 对无效 data_format 引发 ValueError。"""
x = paddle.randn([6, 4, 2, 2], dtype="float32")
with self.assertRaises(ValueError):
temporal_shift(
x, seg_num=2, shift_ratio=0.25, data_format="invalid"
)
def test_temporal_shift_nhwc_larger(self):
"""Test temporal_shift with NHWC and larger input.
测试 NHWC 格式和较大输入的 temporal_shift。"""
x = paddle.randn([12, 4, 4, 8], dtype="float32")
out = temporal_shift(x, seg_num=3, shift_ratio=0.25, data_format="NHWC")
self.assertEqual(out.shape, x.shape)
def test_temporal_shift_seg_num_1(self):
"""Test temporal_shift with seg_num=1.
测试 seg_num=1 的 temporal_shift。"""
x = paddle.randn([3, 4, 2, 2], dtype="float32")
out = temporal_shift(x, seg_num=1, shift_ratio=0.25)
self.assertEqual(out.shape, x.shape)
class TestDiagEmbed(unittest.TestCase):
"""Test diag_embed function.
测试 diag_embed 函数。"""
def setUp(self):
paddle.disable_static()
def test_diag_embed_1d(self):
"""Test diag_embed with 1D input (produces 2D diagonal matrix).
测试一维输入的 diag_embed(生成二维对角矩阵)。"""
import warnings
x = paddle.to_tensor([1, 2, 3])
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
out = diag_embed(x)
self.assertEqual(out.shape, [3, 3])
# Diagonal should be [1, 2, 3]
for i in range(3):
self.assertEqual(out.numpy()[i, i], i + 1)
def test_diag_embed_2d(self):
"""Test diag_embed with 2D input.
测试二维输入的 diag_embed。"""
import warnings
x = paddle.to_tensor([[1, 2], [3, 4]])
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
out = diag_embed(x)
# Should produce 3D output with diagonal 2D slices
self.assertEqual(out.shape, [2, 2, 2])
def test_diag_embed_with_offset(self):
"""Test diag_embed with offset parameter.
测试带有 offset 参数的 diag_embed。
offset shifts the diagonal, so output size expands."""
import warnings
x = paddle.to_tensor([1, 2, 3])
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
out = diag_embed(x, offset=1)
# offset=1 with 1D input of size 3 -> output is 4x4 (max_dim + abs(offset))
self.assertEqual(list(out.shape), [4, 4])
def test_diag_embed_negative_offset(self):
"""Test diag_embed with negative offset.
测试负 offset 的 diag_embed。
Negative offset shifts diagonal down, expanding output size."""
import warnings
x = paddle.to_tensor([1, 2])
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
out = diag_embed(x, offset=-1)
# offset=-1 with 1D input of size 2 -> output is 3x3
self.assertEqual(list(out.shape), [3, 3])
if __name__ == "__main__":
unittest.main()