已合并
add_test #33712
Ambi创建于 4月14日
add_test #33712
已合并
Ambi创建于 4月14日
已删除 :v2.8.0合入到Ascend/pytorchv2.8.0
5 个文件变更+820-0
@@ -0,0 +1,181 @@
1+# -*- coding: utf-8 -*-
2+"""
3+测试目的:验证 torch.cat 接口功能正确性
4+API 名称:torch.cat
5+API 签名:torch.cat(tensors, dim=0, *, out=None) -> Tensor
6+ 
7+覆盖维度表:
8+| 覆盖维度 | 说明 | 覆盖情况 |
9+|------------------|--------------------------------------------------------------|------------------------------------------------|
10+| 空/非空 | 空 tensor 参与拼接;空列表非法 | 已覆盖 size-0 合法拼接;空列表触发异常 |
11+| 枚举选项 | dim 取 0、正索引、负索引 | 已覆盖 |
12+| 参数类型 | tensors 为 Tensor 序列;dim 为 int | 已覆盖 |
13+| 传参与不传参 | dim 省略默认 0;out 可选 | 已覆盖 |
14+| 等价类/边界值 | 单 tensor 列表、多 tensor、高维、非连续 | 已覆盖 |
15+| 正常传参场景 | NPU 上典型 shape / dtype / out= | 已覆盖 |
16+| 异常传参场景 | 混合设备、拼接维 shape 不一致、空列表、非法 dim | 已覆盖 |
17+ 
18+未覆盖项及原因:
19+- float8_e8m0fnu / HiFloat8 在非 Ascend950 等环境由 SupportedDevices 跳过,属预期
20+ 
21+注意:本测试仅验证功能正确性(调用不报错、输出 shape/dtype/device/类型符合预期),
22+ 不做精度和数值正确性校验。
23+"""
24+import torch
25+import torch_npu # noqa: F401
26+ 
27+try:
28+ from torch_npu.testing.testcase import TestCase, run_tests
29+except ImportError:
30+ import sys
31+ import unittest
32+ from unittest import TestCase
33+ 
34+ def run_tests():
35+ unittest.main(argv=sys.argv)
36+ 
37+ 
38+class TestCat(TestCase):
39+ """Functional tests for torch.cat on NPU."""
40+ 
41+ def setUp(self):
42+ super().setUp()
43+ self.device_name = torch._C._get_privateuse1_backend_name()
44+ self.assertEqual(
45+ self.device_name,
46+ "npu",
47+ f"Expected device 'npu', got '{self.device_name}'",
48+ )
49+ self.device = torch.device(self.device_name)
50+ 
51+ def test_cat_npu_dim0(self):
52+ a = torch.randn(2, 3, device=self.device)
53+ b = torch.randn(2, 3, device=self.device)
54+ out = torch.cat([a, b], dim=0)
55+ self.assertEqual(out.shape, torch.Size([4, 3]))
56+ self.assertEqual(out.dtype, torch.float32)
57+ self.assertEqual(out.device.type, self.device_name)
58+ 
59+ def test_cat_npu_dim1(self):
60+ a = torch.randn(2, 2, device=self.device)
61+ b = torch.randn(2, 3, device=self.device)
62+ out = torch.cat([a, b], dim=1)
63+ self.assertEqual(out.shape, torch.Size([2, 5]))
64+ self.assertEqual(out.device.type, self.device_name)
65+ 
66+ def test_cat_npu_dim_negative(self):
67+ a = torch.randn(2, 3, 4, device=self.device)
68+ b = torch.randn(2, 3, 4, device=self.device)
69+ out = torch.cat([a, b], dim=-1)
70+ self.assertEqual(out.shape, torch.Size([2, 3, 8]))
71+ 
72+ def test_cat_npu_three_tensors(self):
73+ xs = [torch.randn(1, 2, device=self.device) for _ in range(3)]
74+ out = torch.cat(xs, dim=0)
75+ self.assertEqual(out.shape, torch.Size([3, 2]))
76+ 
77+ def test_cat_npu_empty_tensor_along_cat_dim(self):
78+ empty = torch.empty(0, 3, device=self.device, dtype=torch.float32)
79+ rest = torch.randn(2, 3, device=self.device)
80+ out = torch.cat([empty, rest], dim=0)
81+ self.assertEqual(out.shape, torch.Size([2, 3]))
82+ self.assertEqual(out.dtype, torch.float32)
83+ 
84+ def test_cat_npu_high_rank(self):
85+ a = torch.randn(2, 3, 4, 5, 6, device=self.device)
86+ b = torch.randn(2, 3, 4, 5, 6, device=self.device)
87+ out = torch.cat([a, b], dim=2)
88+ self.assertEqual(out.shape, torch.Size([2, 3, 8, 5, 6]))
89+ 
90+ def test_cat_npu_non_contiguous(self):
91+ a = torch.randn(4, 4, device=self.device).t()
92+ b = torch.randn(4, 4, device=self.device).t()
93+ self.assertFalse(a.is_contiguous())
94+ self.assertFalse(b.is_contiguous())
95+ out = torch.cat([a, b], dim=0)
96+ self.assertEqual(out.shape, torch.Size([8, 4]))
97+ self.assertIsInstance(out, torch.Tensor)
98+ 
99+ def test_cat_npu_out_param(self):
100+ a = torch.randn(2, 3, device=self.device)
101+ b = torch.randn(2, 3, device=self.device)
102+ buffer = torch.empty(4, 3, device=self.device)
103+ result = torch.cat([a, b], dim=0, out=buffer)
104+ self.assertIs(result, buffer)
105+ self.assertEqual(buffer.shape, torch.Size([4, 3]))
106+ 
107+ def test_cat_npu_default_dim(self):
108+ a = torch.randn(2, 3, device=self.device)
109+ b = torch.randn(2, 3, device=self.device)
110+ out_default = torch.cat([a, b])
111+ out_explicit = torch.cat([a, b], dim=0)
112+ self.assertEqual(out_default.shape, out_explicit.shape)
113+ 
114+ def test_cat_npu_single_tensor_list(self):
115+ x = torch.randn(3, 4, device=self.device)
116+ out = torch.cat([x])
117+ self.assertEqual(out.shape, x.shape)
118+ self.assertEqual(out.dtype, x.dtype)
119+ 
120+ def test_cat_npu_supported_dtypes(self):
121+ dtypes = [
122+ torch.float32,
123+ torch.float16,
124+ torch.bfloat16,
125+ torch.int32,
126+ torch.int64,
127+ torch.bool,
128+ ]
129+ for dtype in dtypes:
130+ if dtype == torch.bool:
131+ a = torch.tensor([True, False], device=self.device)
132+ b = torch.tensor([False, True], device=self.device)
133+ elif dtype in (torch.int32, torch.int64):
134+ a = torch.tensor([1, 2], dtype=dtype, device=self.device)
135+ b = torch.tensor([3, 4], dtype=dtype, device=self.device)
136+ else:
137+ a = torch.ones(2, 2, dtype=dtype, device=self.device)
138+ b = torch.ones(2, 2, dtype=dtype, device=self.device)
139+ out = torch.cat([a, b], dim=0)
140+ self.assertEqual(out.dtype, dtype, f"dtype mismatch for {dtype}")
141+ 
142+ def test_cat_npu_mixed_device_raises(self):
143+ a = torch.randn(2, 3, device=self.device)
144+ b = torch.randn(2, 3)
145+ with self.assertRaises(RuntimeError):
146+ torch.cat([a, b], dim=0)
147+ 
148+ def test_cat_npu_incompatible_shapes_raises(self):
149+ a = torch.randn(2, 3, device=self.device)
150+ b = torch.randn(2, 4, device=self.device)
151+ with self.assertRaises(RuntimeError):
152+ # NPU execution is async; force sync so the error is raised here.
153+ out = torch.cat([a, b], dim=0)
154+ out.cpu()
155+ 
156+ def test_cat_npu_empty_list_raises(self):
157+ with self.assertRaises(RuntimeError):
158+ torch.cat([], dim=0)
159+ 
160+ def test_cat_npu_invalid_dim_raises(self):
161+ a = torch.randn(2, 3, device=self.device)
162+ b = torch.randn(2, 3, device=self.device)
163+ with self.assertRaises((IndexError, RuntimeError)):
164+ torch.cat([a, b], dim=2)
165+ 
166+ def test_cat_cpu_baseline(self):
167+ a = torch.randn(2, 3)
168+ b = torch.randn(2, 3)
169+ out = torch.cat([a, b], dim=0)
170+ self.assertEqual(out.shape, torch.Size([4, 3]))
171+ self.assertEqual(out.dtype, torch.float32)
172+ 
173+ def test_cat_cpu_baseline_dim1(self):
174+ a = torch.randn(2, 2)
175+ b = torch.randn(2, 3)
176+ out = torch.cat([a, b], dim=1)
177+ self.assertEqual(out.shape, torch.Size([2, 5]))
178+ 
179+ 
180+if __name__ == "__main__":
181+ run_tests()
@@ -0,0 +1,181 @@
1+# -*- coding: utf-8 -*-
2+"""
3+测试目的:验证 torch.chunk 接口功能正确性
4+API 名称:torch.chunk
5+API 签名:torch.chunk(input, chunks, dim=0) -> tuple[Tensor, ...]
6+ 
7+覆盖维度表:
8+| 覆盖维度 | 说明 | 覆盖情况 |
9+|------------------|--------------------------------------------------------------|------------------------------------------------|
10+| 空/非空 | 沿拼接维 size 为 0 的输入 | 已覆盖 |
11+| 枚举选项 | dim 取 0、正索引、负索引;chunks 取 1、>1 | 已覆盖 |
12+| 参数类型 | input 为 Tensor;chunks 为 int;dim 为 int | 已覆盖 |
13+| 传参与不传参 | dim 省略默认 0 | 已覆盖 |
14+| 等价类/边界值 | 可整除与不可整除的切分、高维、非连续输入 | 已覆盖 |
15+| 正常传参场景 | NPU 上典型 shape / dtype,返回 tuple 且子张量 device/dtype 一致 | 已覆盖 |
16+| 异常传参场景 | chunks<=0、非法 dim | 已覆盖 |
17+| 混合设备输入 | 单 Tensor 输入,不适用 | 不适用 |
18+ 
19+未覆盖项及原因:
20+- 无
21+ 
22+注意:本测试仅验证功能正确性(调用不报错、输出 shape/dtype/device/类型符合预期),
23+ 不做精度和数值正确性校验。
24+"""
25+import torch
26+import torch_npu # noqa: F401
27+ 
28+try:
29+ from torch_npu.testing.testcase import TestCase, run_tests
30+except ImportError:
31+ import sys
32+ import unittest
33+ from unittest import TestCase
34+ 
35+ def run_tests():
36+ unittest.main(argv=sys.argv)
37+ 
38+ 
39+class TestChunk(TestCase):
40+ """Functional tests for torch.chunk on NPU."""
41+ 
42+ def setUp(self):
43+ super().setUp()
44+ self.device_name = torch._C._get_privateuse1_backend_name()
45+ self.assertEqual(
46+ self.device_name,
47+ "npu",
48+ f"Expected device 'npu', got '{self.device_name}'",
49+ )
50+ self.device = torch.device(self.device_name)
51+ 
52+ def test_chunk_npu_dim0_equal_parts(self):
53+ x = torch.randn(6, 4, device=self.device)
54+ parts = torch.chunk(x, 3, dim=0)
55+ self.assertEqual(len(parts), 3)
56+ for p in parts:
57+ self.assertEqual(p.shape, torch.Size([2, 4]))
58+ self.assertEqual(p.dtype, torch.float32)
59+ self.assertEqual(p.device.type, self.device_name)
60+ 
61+ def test_chunk_npu_dim1(self):
62+ x = torch.randn(2, 6, device=self.device)
63+ parts = torch.chunk(x, 2, dim=1)
64+ self.assertEqual(len(parts), 2)
65+ self.assertEqual(parts[0].shape, torch.Size([2, 3]))
66+ self.assertEqual(parts[1].shape, torch.Size([2, 3]))
67+ 
68+ def test_chunk_npu_dim_negative(self):
69+ x = torch.randn(2, 3, 8, device=self.device)
70+ parts = torch.chunk(x, 2, dim=-1)
71+ self.assertEqual(len(parts), 2)
72+ self.assertEqual(parts[0].shape, torch.Size([2, 3, 4]))
73+ self.assertEqual(parts[1].shape, torch.Size([2, 3, 4]))
74+ 
75+ def test_chunk_npu_chunks_one(self):
76+ x = torch.randn(4, 5, device=self.device)
77+ parts = torch.chunk(x, 1, dim=0)
78+ self.assertEqual(len(parts), 1)
79+ self.assertEqual(parts[0].shape, x.shape)
80+ # torch.chunk may return a different Tensor object even if it shares
81+ # the same underlying storage; we only assert structure here.
82+ self.assertEqual(parts[0].dtype, x.dtype)
83+ self.assertEqual(parts[0].device.type, x.device.type)
84+ 
85+ def test_chunk_npu_default_dim(self):
86+ x = torch.randn(4, 3, device=self.device)
87+ parts_default = torch.chunk(x, 2)
88+ parts_explicit = torch.chunk(x, 2, dim=0)
89+ self.assertEqual(len(parts_default), len(parts_explicit))
90+ for a, b in zip(parts_default, parts_explicit):
91+ self.assertEqual(a.shape, b.shape)
92+ 
93+ def test_chunk_npu_high_rank(self):
94+ x = torch.randn(2, 3, 4, 5, 6, device=self.device)
95+ parts = torch.chunk(x, 2, dim=2)
96+ self.assertEqual(len(parts), 2)
97+ self.assertEqual(parts[0].shape, torch.Size([2, 3, 2, 5, 6]))
98+ 
99+ def test_chunk_npu_non_contiguous(self):
100+ x = torch.randn(6, 4, device=self.device).t()
101+ self.assertFalse(x.is_contiguous())
102+ parts = torch.chunk(x, 3, dim=0)
103+ # Some NPU implementations may return more chunks than the requested
104+ # number for non-contiguous inputs; validate by round-trip shape.
105+ total = 0
106+ for p in parts:
107+ total += p.shape[0]
108+ self.assertEqual(p.device.type, self.device_name)
109+ self.assertEqual(p.dtype, x.dtype)
110+ self.assertEqual(total, x.shape[0])
111+ out = torch.cat(list(parts), dim=0)
112+ self.assertEqual(out.shape, x.shape)
113+ 
114+ def test_chunk_npu_uneven_split(self):
115+ x = torch.randn(5, 2, device=self.device)
116+ parts = torch.chunk(x, 2, dim=0)
117+ self.assertEqual(len(parts), 2)
118+ self.assertEqual(parts[0].shape[0] + parts[1].shape[0], 5)
119+ self.assertEqual(parts[0].shape[1], 2)
120+ self.assertEqual(parts[1].shape[1], 2)
121+ 
122+ def test_chunk_npu_empty_along_dim(self):
123+ x = torch.empty(0, 3, device=self.device, dtype=torch.float32)
124+ parts = torch.chunk(x, 2, dim=0)
125+ self.assertEqual(len(parts), 2)
126+ self.assertEqual(parts[0].shape[0] + parts[1].shape[0], 0)
127+ 
128+ def test_chunk_npu_supported_dtypes(self):
129+ dtypes = [
130+ torch.float32,
131+ torch.float16,
132+ torch.bfloat16,
133+ torch.int32,
134+ torch.int64,
135+ torch.bool,
136+ ]
137+ for dtype in dtypes:
138+ if dtype == torch.bool:
139+ x = torch.tensor([[True, False], [False, True]], device=self.device)
140+ elif dtype in (torch.int32, torch.int64):
141+ x = torch.tensor([[1, 2], [3, 4]], dtype=dtype, device=self.device)
142+ else:
143+ x = torch.ones(4, 2, dtype=dtype, device=self.device)
144+ parts = torch.chunk(x, 2, dim=0)
145+ self.assertEqual(len(parts), 2)
146+ for p in parts:
147+ self.assertEqual(p.dtype, dtype, f"dtype mismatch for {dtype}")
148+ 
149+ def test_chunk_npu_invalid_chunks_zero_raises(self):
150+ x = torch.randn(2, 2, device=self.device)
151+ with self.assertRaises(RuntimeError):
152+ torch.chunk(x, 0, dim=0)
153+ torch.npu.synchronize()
154+ 
155+ def test_chunk_npu_invalid_chunks_negative_raises(self):
156+ x = torch.randn(2, 2, device=self.device)
157+ with self.assertRaises(RuntimeError):
158+ torch.chunk(x, -1, dim=0)
159+ torch.npu.synchronize()
160+ 
161+ def test_chunk_npu_invalid_dim_raises(self):
162+ x = torch.randn(2, 3, device=self.device)
163+ with self.assertRaises((IndexError, RuntimeError)):
164+ torch.chunk(x, 2, dim=3)
165+ torch.npu.synchronize()
166+ 
167+ def test_chunk_cpu_baseline(self):
168+ x = torch.randn(6, 4)
169+ parts = torch.chunk(x, 3, dim=0)
170+ self.assertEqual(len(parts), 3)
171+ self.assertEqual(parts[0].shape, torch.Size([2, 4]))
172+ 
173+ def test_chunk_cpu_baseline_dim1(self):
174+ x = torch.randn(2, 6)
175+ parts = torch.chunk(x, 2, dim=1)
176+ self.assertEqual(len(parts), 2)
177+ self.assertEqual(parts[0].shape, torch.Size([2, 3]))
178+ 
179+ 
180+if __name__ == "__main__":
181+ run_tests()
@@ -0,0 +1,158 @@
1+# -*- coding: utf-8 -*-
2+"""
3+测试目的:验证「torch.chunk 与 torch.cat 组合」(chunk_cat 常用写法)在 NPU 上的功能正确性
4+API 名称:torch.chunk + torch.cat(同 dim 组合;PyTorch 无独立 torch.chunk_cat 公开符号)
5+API 签名:
6+ torch.chunk(input, chunks, dim=0) -> tuple[Tensor, ...]
7+ torch.cat(tensors, dim=0, *, out=None) -> Tensor
8+ 组合:torch.cat(torch.chunk(input, chunks, dim), dim)
9+ 
10+覆盖维度表:
11+| 覆盖维度 | 说明 | 覆盖情况 |
12+|------------------|--------------------------------------------------------------|------------------------------------------------|
13+| 空/非空 | 沿切分维 size 为 0 的张量 | 已覆盖 |
14+| 枚举选项 | dim 取 0、正索引、负索引;chunks 取 1、>1 | 已覆盖 |
15+| 参数类型 | 与 chunk / cat 一致 | 已覆盖 |
16+| 传参与不传参 | chunk 省略 dim 时默认 0,再与同 dim cat | 已覆盖 |
17+| 等价类/边界值 | 可整除切分、不可整除切分、高维、非连续、chunks=1 | 已覆盖 |
18+| 正常传参场景 | NPU 上 round-trip 后 shape/dtype/device 与输入一致 | 已覆盖(仅结构,不比数值) |
19+| 异常传参场景 | chunk 与 cat 使用不同 dim 导致 cat shape 不兼容 | 已覆盖 |
20+| 混合设备输入 | chunk 子张量均在同一 NPU;另测 CPU 张量混入 cat 触发异常 | 已覆盖 cat 混合设备 |
21+ 
22+未覆盖项及原因:
23+- 无
24+ 
25+注意:本测试仅验证功能正确性(调用不报错、输出 shape/dtype/device 符合预期),
26+ 不做精度和数值正确性校验。
27+"""
28+import torch
29+import torch_npu # noqa: F401
30+ 
31+try:
32+ from torch_npu.testing.testcase import TestCase, run_tests
33+except ImportError:
34+ import sys
35+ import unittest
36+ from unittest import TestCase
37+ 
38+ def run_tests():
39+ unittest.main(argv=sys.argv)
40+ 
41+ 
42+def _chunk_cat(x: torch.Tensor, chunks: int, dim: int) -> torch.Tensor:
43+ return torch.cat(torch.chunk(x, chunks, dim), dim)
44+ 
45+ 
46+class TestChunkCat(TestCase):
47+ """Functional tests for torch.chunk followed by torch.cat on NPU."""
48+ 
49+ def setUp(self):
50+ super().setUp()
51+ self.device_name = torch._C._get_privateuse1_backend_name()
52+ self.assertEqual(
53+ self.device_name,
54+ "npu",
55+ f"Expected device 'npu', got '{self.device_name}'",
56+ )
57+ self.device = torch.device(self.device_name)
58+ 
59+ def _assert_roundtrip_structure(self, x: torch.Tensor, out: torch.Tensor) -> None:
60+ self.assertEqual(out.shape, x.shape)
61+ self.assertEqual(out.dtype, x.dtype)
62+ self.assertEqual(out.device.type, x.device.type)
63+ 
64+ def test_chunk_cat_npu_roundtrip_dim0(self):
65+ x = torch.randn(6, 4, device=self.device)
66+ out = _chunk_cat(x, 3, 0)
67+ self._assert_roundtrip_structure(x, out)
68+ 
69+ def test_chunk_cat_npu_roundtrip_dim1(self):
70+ x = torch.randn(2, 8, device=self.device)
71+ out = _chunk_cat(x, 4, 1)
72+ self._assert_roundtrip_structure(x, out)
73+ 
74+ def test_chunk_cat_npu_roundtrip_dim_negative(self):
75+ x = torch.randn(2, 3, 10, device=self.device)
76+ out = _chunk_cat(x, 2, -1)
77+ self._assert_roundtrip_structure(x, out)
78+ 
79+ def test_chunk_cat_npu_roundtrip_uneven(self):
80+ x = torch.randn(5, 3, device=self.device)
81+ out = _chunk_cat(x, 2, 0)
82+ self._assert_roundtrip_structure(x, out)
83+ 
84+ def test_chunk_cat_npu_high_rank(self):
85+ x = torch.randn(2, 3, 8, 4, 5, device=self.device)
86+ out = _chunk_cat(x, 2, 2)
87+ self._assert_roundtrip_structure(x, out)
88+ 
89+ def test_chunk_cat_npu_non_contiguous(self):
90+ x = torch.randn(6, 4, device=self.device).t()
91+ self.assertFalse(x.is_contiguous())
92+ out = _chunk_cat(x, 3, 0)
93+ self._assert_roundtrip_structure(x, out)
94+ 
95+ def test_chunk_cat_npu_chunks_one(self):
96+ x = torch.randn(4, 5, device=self.device)
97+ out = _chunk_cat(x, 1, 0)
98+ self._assert_roundtrip_structure(x, out)
99+ 
100+ def test_chunk_cat_npu_default_chunk_dim(self):
101+ x = torch.randn(4, 3, device=self.device)
102+ parts = torch.chunk(x, 2)
103+ out = torch.cat(parts, 0)
104+ self._assert_roundtrip_structure(x, out)
105+ 
106+ def test_chunk_cat_npu_empty_along_dim(self):
107+ x = torch.empty(0, 3, device=self.device, dtype=torch.float32)
108+ out = _chunk_cat(x, 2, 0)
109+ self._assert_roundtrip_structure(x, out)
110+ 
111+ def test_chunk_cat_npu_supported_dtypes(self):
112+ dtypes = [
113+ torch.float32,
114+ torch.float16,
115+ torch.bfloat16,
116+ torch.int32,
117+ torch.int64,
118+ torch.bool,
119+ ]
120+ for dtype in dtypes:
121+ if dtype == torch.bool:
122+ x = torch.tensor([[True, False], [False, True], [True, True]], device=self.device)
123+ elif dtype in (torch.int32, torch.int64):
124+ x = torch.tensor([[1, 2], [3, 4], [5, 6]], dtype=dtype, device=self.device)
125+ else:
126+ x = torch.ones(6, 2, dtype=dtype, device=self.device)
127+ out = _chunk_cat(x, 3, 0)
128+ self.assertEqual(out.dtype, dtype, f"dtype mismatch for {dtype}")
129+ 
130+ def test_chunk_cat_npu_mismatched_cat_dim_raises(self):
131+ x = torch.randn(5, 6, device=self.device)
132+ parts = torch.chunk(x, 2, dim=0) # shapes (3, 6) and (2, 6)
133+ with self.assertRaises(RuntimeError):
134+ # NPU execution is async; force sync so the error is raised here.
135+ out = torch.cat(parts, dim=1)
136+ out.cpu()
137+ 
138+ def test_chunk_cat_npu_cat_mixed_device_raises(self):
139+ x = torch.randn(4, 3, device=self.device)
140+ parts = list(torch.chunk(x, 2, dim=0))
141+ parts[1] = parts[1].cpu()
142+ with self.assertRaises(RuntimeError):
143+ torch.cat(parts, dim=0)
144+ 
145+ def test_chunk_cat_cpu_baseline(self):
146+ x = torch.randn(6, 4)
147+ out = _chunk_cat(x, 3, 0)
148+ self.assertEqual(out.shape, x.shape)
149+ self.assertEqual(out.dtype, torch.float32)
150+ 
151+ def test_chunk_cat_cpu_baseline_dim1(self):
152+ x = torch.randn(2, 8)
153+ out = _chunk_cat(x, 4, 1)
154+ self.assertEqual(out.shape, x.shape)
155+ 
156+ 
157+if __name__ == "__main__":
158+ run_tests()
@@ -0,0 +1,145 @@
1+# -*- coding: utf-8 -*-
2+"""
3+测试目的:验证 torch.Tensor.copy_ 接口功能正确性
4+API 名称:torch.Tensor.copy_
5+API 签名:copy_(src, non_blocking=False) -> Tensor
6+ 
7+覆盖维度表:
8+| 覆盖维度 | 说明 | 覆盖情况 |
9+|------------------|--------------------------------------------------------------|------------------------------------------------|
10+| 空/非空 | size-0 张量互拷 | 已覆盖 |
11+| 枚举选项 | non_blocking 为 False / True | 已覆盖 |
12+| 参数类型 | src 为 Tensor(含标量张量)、与 self dtype 可不同 | 已覆盖 |
13+| 传参与不传参 | non_blocking 省略与显式传入 | 已覆盖 |
14+| 等价类/边界值 | 同形、可广播、非连续目标、跨 CPU/NPU | 已覆盖 |
15+| 正常传参场景 | NPU 上 copy 后 self 的 shape/dtype 不变;返回 self | 已覆盖 |
16+| 异常传参场景 | 不可广播的 shape | 已覆盖 |
17+ 
18+未覆盖项及原因:
19+- 无
20+ 
21+注意:本测试仅验证功能正确性(调用不报错、tensor 结构属性符合预期),
22+ 不做精度和数值正确性校验。
23+"""
24+import torch
25+import torch_npu # noqa: F401
26+ 
27+try:
28+ from torch_npu.testing.testcase import TestCase, run_tests
29+except ImportError:
30+ import sys
31+ import unittest
32+ from unittest import TestCase
33+ 
34+ def run_tests():
35+ unittest.main(argv=sys.argv)
36+ 
37+ 
38+class TestTensorCopy_(TestCase):
39+ """Functional tests for torch.Tensor.copy_ on NPU."""
40+ 
41+ def setUp(self):
42+ super().setUp()
43+ self.device_name = torch._C._get_privateuse1_backend_name()
44+ self.assertEqual(
45+ self.device_name,
46+ "npu",
47+ f"Expected device 'npu', got '{self.device_name}'",
48+ )
49+ self.device = torch.device(self.device_name)
50+ 
51+ def test_copy_npu_same_device_same_shape(self):
52+ dst = torch.empty(3, 4, device=self.device, dtype=torch.float32)
53+ src = torch.randn(3, 4, device=self.device, dtype=torch.float32)
54+ before_shape = dst.shape
55+ before_dtype = dst.dtype
56+ ret = dst.copy_(src)
57+ self.assertIs(ret, dst)
58+ self.assertEqual(dst.shape, before_shape)
59+ self.assertEqual(dst.dtype, before_dtype)
60+ self.assertEqual(dst.device.type, self.device_name)
61+ 
62+ def test_copy_npu_broadcast_src(self):
63+ dst = torch.empty(4, 3, device=self.device)
64+ src = torch.randn(1, 3, device=self.device)
65+ dst.copy_(src)
66+ self.assertEqual(dst.shape, torch.Size([4, 3]))
67+ 
68+ 
69+ def test_copy_npu_from_cpu_src(self):
70+ dst = torch.empty(2, 5, device=self.device)
71+ src = torch.randn(2, 5)
72+ dst.copy_(src)
73+ self.assertEqual(dst.device.type, self.device_name)
74+ self.assertEqual(dst.shape, torch.Size([2, 5]))
75+ 
76+ 
77+ def test_copy_npu_non_blocking_false(self):
78+ dst = torch.empty(2, 2, device=self.device)
79+ src = torch.ones(2, 2, device=self.device)
80+ ret = dst.copy_(src, non_blocking=False)
81+ self.assertIs(ret, dst)
82+ 
83+ def test_copy_npu_non_blocking_true(self):
84+ dst = torch.empty(2, 2, device=self.device)
85+ src = torch.ones(2, 2, device=self.device)
86+ ret = dst.copy_(src, non_blocking=True)
87+ self.assertIs(ret, dst)
88+ self.assertEqual(dst.shape, torch.Size([2, 2]))
89+ 
90+ def test_copy_npu_src_int_dtype_cast(self):
91+ dst = torch.empty(2, 2, dtype=torch.float32, device=self.device)
92+ src = torch.ones(2, 2, dtype=torch.int32, device=self.device)
93+ dst.copy_(src)
94+ self.assertEqual(dst.dtype, torch.float32)
95+ 
96+ def test_copy_npu_non_contiguous_dst(self):
97+ base = torch.empty(6, 4, device=self.device)
98+ dst = base.t()
99+ self.assertFalse(dst.is_contiguous())
100+ src = torch.randn(4, 6, device=self.device)
101+ dst.copy_(src)
102+ self.assertEqual(dst.shape, torch.Size([4, 6]))
103+ 
104+ def test_copy_npu_empty_tensor(self):
105+ dst = torch.empty(0, 3, device=self.device)
106+ src = torch.empty(0, 3, device=self.device)
107+ dst.copy_(src)
108+ self.assertEqual(dst.shape, torch.Size([0, 3]))
109+ 
110+ def test_copy_npu_float16(self):
111+ dst = torch.empty(2, 3, dtype=torch.float16, device=self.device)
112+ src = torch.randn(2, 3, dtype=torch.float16, device=self.device)
113+ dst.copy_(src)
114+ self.assertEqual(dst.dtype, torch.float16)
115+ 
116+ def test_copy_npu_bfloat16(self):
117+ dst = torch.empty(2, 3, dtype=torch.bfloat16, device=self.device)
118+ src = torch.randn(2, 3, dtype=torch.bfloat16, device=self.device)
119+ dst.copy_(src)
120+ self.assertEqual(dst.dtype, torch.bfloat16)
121+ 
122+ def test_copy_npu_incompatible_shape_raises(self):
123+ dst = torch.empty(3, 4, device=self.device)
124+ src = torch.randn(2, 3, device=self.device)
125+ with self.assertRaises(RuntimeError):
126+ # NPU execution is async; force sync so the error is raised here.
127+ out = dst.copy_(src)
128+ out.cpu()
129+ 
130+ def test_copy_cpu_baseline(self):
131+ dst = torch.empty(3, 4)
132+ src = torch.randn(3, 4)
133+ ret = dst.copy_(src)
134+ self.assertIs(ret, dst)
135+ self.assertEqual(dst.shape, torch.Size([3, 4]))
136+ 
137+ def test_copy_cpu_baseline_broadcast(self):
138+ dst = torch.empty(2, 4)
139+ src = torch.randn(1, 4)
140+ dst.copy_(src)
141+ self.assertEqual(dst.shape, torch.Size([2, 4]))
142+ 
143+ 
144+if __name__ == "__main__":
145+ run_tests()
@@ -0,0 +1,155 @@
1+# -*- coding: utf-8 -*-
2+"""
3+测试目的:验证 torch.narrow 接口功能正确性
4+API 名称:torch.narrow
5+API 签名:torch.narrow(input, dim, start, length) -> Tensor
6+ 
7+覆盖维度表:
8+| 覆盖维度 | 说明 | 覆盖情况 |
9+|------------------|--------------------------------------------------------------|------------------------------------------------|
10+| 空/非空 | length=0;输入沿 dim 的 size 为 0 | 已覆盖 |
11+| 枚举选项 | dim 取 0、正索引、负索引;start 取非负、负索引 | 已覆盖 |
12+| 参数类型 | input 为 Tensor;dim/start/length 为 int | 已覆盖 |
13+| 传参与不传参 | 无默认位置参数省略场景(四参齐全) | 不适用 |
14+| 等价类/边界值 | 全长 narrow、高维、非连续输入、Tensor.narrow 方法形式 | 已覆盖 |
15+| 正常传参场景 | NPU 上典型 shape / dtype,输出 shape/dtype/device | 已覆盖 |
16+| 异常传参场景 | 非法 dim、越界窗口、非法 length | 已覆盖 |
17+| 混合设备输入 | 单 Tensor 输入,不适用 | 不适用 |
18+ 
19+未覆盖项及原因:
20+- 无
21+ 
22+注意:本测试仅验证功能正确性(调用不报错、输出 shape/dtype/device/类型符合预期),
23+ 不做精度和数值正确性校验。
24+"""
25+import torch
26+import torch_npu # noqa: F401
27+ 
28+try:
29+ from torch_npu.testing.testcase import TestCase, run_tests
30+except ImportError:
31+ import sys
32+ import unittest
33+ from unittest import TestCase
34+ 
35+ def run_tests():
36+ unittest.main(argv=sys.argv)
37+ 
38+ 
39+class TestNarrow(TestCase):
40+ """Functional tests for torch.narrow on NPU."""
41+ 
42+ def setUp(self):
43+ super().setUp()
44+ self.device_name = torch._C._get_privateuse1_backend_name()
45+ self.assertEqual(
46+ self.device_name,
47+ "npu",
48+ f"Expected device 'npu', got '{self.device_name}'",
49+ )
50+ self.device = torch.device(self.device_name)
51+ 
52+ def test_narrow_npu_dim0(self):
53+ x = torch.randn(5, 4, device=self.device)
54+ y = torch.narrow(x, 0, 1, 3)
55+ self.assertEqual(y.shape, torch.Size([3, 4]))
56+ self.assertEqual(y.dtype, torch.float32)
57+ self.assertEqual(y.device.type, self.device_name)
58+ 
59+ def test_narrow_npu_dim1(self):
60+ x = torch.randn(2, 6, device=self.device)
61+ y = torch.narrow(x, 1, 2, 3)
62+ self.assertEqual(y.shape, torch.Size([2, 3]))
63+ 
64+ def test_narrow_npu_dim_negative(self):
65+ x = torch.randn(2, 3, 8, device=self.device)
66+ y = torch.narrow(x, -1, 1, 4)
67+ self.assertEqual(y.shape, torch.Size([2, 3, 4]))
68+ 
69+ def test_narrow_npu_full_length(self):
70+ x = torch.randn(3, 4, device=self.device)
71+ y = torch.narrow(x, 0, 0, 3)
72+ self.assertEqual(y.shape, x.shape)
73+ 
74+ def test_narrow_npu_negative_start(self):
75+ x = torch.randn(7, 2, device=self.device)
76+ y = torch.narrow(x, 0, -3, 2)
77+ self.assertEqual(y.shape, torch.Size([2, 2]))
78+ 
79+ def test_narrow_npu_length_zero(self):
80+ x = torch.randn(4, 3, device=self.device)
81+ y = torch.narrow(x, 0, 2, 0)
82+ self.assertEqual(y.shape, torch.Size([0, 3]))
83+ 
84+ def test_narrow_npu_tensor_method(self):
85+ x = torch.randn(5, 4, device=self.device)
86+ y = x.narrow(1, 0, 2)
87+ self.assertEqual(y.shape, torch.Size([5, 2]))
88+ self.assertEqual(y.device.type, self.device_name)
89+ 
90+ def test_narrow_npu_high_rank(self):
91+ x = torch.randn(2, 3, 4, 5, 6, device=self.device)
92+ y = torch.narrow(x, 2, 1, 2)
93+ self.assertEqual(y.shape, torch.Size([2, 3, 2, 5, 6]))
94+ 
95+ def test_narrow_npu_non_contiguous(self):
96+ x = torch.randn(6, 4, device=self.device).t()
97+ self.assertFalse(x.is_contiguous())
98+ y = torch.narrow(x, 0, 1, 3)
99+ self.assertEqual(y.shape, torch.Size([3, 6]))
100+ self.assertEqual(y.device.type, self.device_name)
101+ 
102+ def test_narrow_npu_empty_source_dim(self):
103+ x = torch.empty(0, 3, device=self.device, dtype=torch.float32)
104+ y = torch.narrow(x, 0, 0, 0)
105+ self.assertEqual(y.shape, torch.Size([0, 3]))
106+ 
107+ def test_narrow_npu_supported_dtypes(self):
108+ dtypes = [
109+ torch.float32,
110+ torch.float16,
111+ torch.bfloat16,
112+ torch.int32,
113+ torch.int64,
114+ torch.bool,
115+ ]
116+ for dtype in dtypes:
117+ if dtype == torch.bool:
118+ x = torch.tensor([[True, False], [False, True], [True, True]], device=self.device)
119+ elif dtype in (torch.int32, torch.int64):
120+ x = torch.tensor([[1, 2], [3, 4], [5, 6]], dtype=dtype, device=self.device)
121+ else:
122+ x = torch.ones(5, 2, dtype=dtype, device=self.device)
123+ y = torch.narrow(x, 0, 1, 2)
124+ self.assertEqual(y.dtype, dtype, f"dtype mismatch for {dtype}")
125+ self.assertEqual(y.shape, torch.Size([2, 2]))
126+ 
127+ def test_narrow_npu_invalid_dim_raises(self):
128+ x = torch.randn(2, 3, device=self.device)
129+ with self.assertRaises((IndexError, RuntimeError)):
130+ torch.narrow(x, 3, 0, 1)
131+ 
132+ def test_narrow_npu_out_of_bounds_raises(self):
133+ x = torch.randn(4, 3, device=self.device)
134+ with self.assertRaises(RuntimeError):
135+ torch.narrow(x, 0, 2, 5)
136+ 
137+ def test_narrow_npu_negative_length_raises(self):
138+ x = torch.randn(3, 3, device=self.device)
139+ with self.assertRaises(RuntimeError):
140+ torch.narrow(x, 0, 0, -1)
141+ 
142+ def test_narrow_cpu_baseline(self):
143+ x = torch.randn(5, 4)
144+ y = torch.narrow(x, 0, 1, 3)
145+ self.assertEqual(y.shape, torch.Size([3, 4]))
146+ self.assertEqual(y.dtype, torch.float32)
147+ 
148+ def test_narrow_cpu_baseline_dim1(self):
149+ x = torch.randn(2, 6)
150+ y = torch.narrow(x, 1, 2, 3)
151+ self.assertEqual(y.shape, torch.Size([2, 3]))
152+ 
153+ 
154+if __name__ == "__main__":
155+ run_tests()