共 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() | ||