已合并
[Task-32/33][v2.7.1] API Consistency: torch.autograd.gradcheck & torch.autograd.profiler.emit_itt #42011
Yhw050920创建于 7月18日
[Task-32/33][v2.7.1] API Consistency: torch.autograd.gradcheck & torch.autograd.profiler.emit_itt #42011
已合并
共 3 个文件变更+403-0
| @@ -0,0 +1,125 @@ | |||
| 1 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd | ||
| 2 | +# All rights reserved. | ||
| 3 | +# | ||
| 4 | +# Licensed under the BSD 3-Clause License (the "License") | ||
| 5 | +# you may not use this file except in compliance with the License. | ||
| 6 | +# You may obtain a copy of the License at | ||
| 7 | +# https://opensource.org/licenses/BSD-3-Clause | ||
| 8 | +# Unless required by applicable law or agreed to in writing, software | ||
| 9 | +# distributed under the License is distributed on an "AS IS" BASIS, | ||
| 10 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 11 | +# See the License for the specific language governing permissions and | ||
| 12 | +# limitations under the License. | ||
| 13 | + | ||
| 14 | +""" | ||
| 15 | +Add validation cases for torch.autograd.profiler.emit_itt on Ascend NPU. | ||
| 16 | + | ||
| 17 | +Intel ITT is not available on some NPU build configurations. | ||
| 18 | +This file validates emit_itt parameter coverage (enabled, record_shapes). | ||
| 19 | +Tests with enabled=True are guarded by ITT availability check, | ||
| 20 | +matching the upstream test_profiler_emit_itt pattern. | ||
| 21 | +""" | ||
| 22 | +import torch | ||
| 23 | +from torch.autograd.profiler import emit_itt | ||
| 24 | + | ||
| 25 | +from torch_npu.testing.testcase import TestCase, run_tests | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +ITT_AVAILABLE = torch.profiler.itt.is_available() | ||
| 29 | + | ||
| 30 | + | ||
| 31 | +class TestEmitItt(TestCase): | ||
| 32 | + """Test cases for torch.autograd.profiler.emit_itt on Ascend NPU.""" | ||
| 33 | + | ||
| 34 | + def test_emit_itt_import(self): | ||
| 35 | + """emit_itt is callable or context manager.""" | ||
| 36 | + self.assertTrue(callable(emit_itt) or hasattr(emit_itt, "__enter__")) | ||
| 37 | + | ||
| 38 | + def test_emit_itt_enabled_false_noop(self): | ||
| 39 | + """enabled=False is a no-op and computation works normally.""" | ||
| 40 | + torch.manual_seed(42) | ||
| 41 | + x = torch.tensor([1.0, 2.0, 3.0], dtype=torch.float32, device="npu") | ||
| 42 | + with emit_itt(enabled=False): | ||
| 43 | + result = x + 1.0 | ||
| 44 | + expected = torch.tensor([2.0, 3.0, 4.0], device="npu") | ||
| 45 | + self.assertTrue(torch.equal(result, expected)) | ||
| 46 | + | ||
| 47 | + def test_emit_itt_enabled_false_record_shapes_true(self): | ||
| 48 | + """enabled=False + record_shapes=True: no-op with correct result.""" | ||
| 49 | + torch.manual_seed(42) | ||
| 50 | + x = torch.tensor([1.0, 2.0, 3.0], dtype=torch.float32, device="npu") | ||
| 51 | + with emit_itt(enabled=False, record_shapes=True): | ||
| 52 | + result = x - 1.0 | ||
| 53 | + expected = torch.tensor([0.0, 1.0, 2.0], device="npu") | ||
| 54 | + self.assertTrue(torch.equal(result, expected)) | ||
| 55 | + | ||
| 56 | + def test_emit_itt_enabled_true_record_shapes_true(self): | ||
| 57 | + """enabled=True + record_shapes=True (guarded by ITT availability).""" | ||
| 58 | + if not ITT_AVAILABLE: | ||
| 59 | + self.skipTest("ITT is required") | ||
| 60 | + torch.manual_seed(42) | ||
| 61 | + x = torch.tensor([1.0, 2.0, 3.0], dtype=torch.float32, device="npu") | ||
| 62 | + with emit_itt(enabled=True, record_shapes=True): | ||
| 63 | + result = x - 1.0 | ||
| 64 | + expected = torch.tensor([0.0, 1.0, 2.0], device="npu") | ||
| 65 | + self.assertTrue(torch.equal(result, expected)) | ||
| 66 | + | ||
| 67 | + def test_emit_itt_enabled_true_record_shapes_false(self): | ||
| 68 | + """enabled=True + record_shapes=False (guarded by ITT availability).""" | ||
| 69 | + if not ITT_AVAILABLE: | ||
| 70 | + self.skipTest("ITT is required") | ||
| 71 | + torch.manual_seed(42) | ||
| 72 | + x = torch.tensor([1.0, 2.0, 3.0], dtype=torch.float32, device="npu") | ||
| 73 | + with emit_itt(enabled=True, record_shapes=False): | ||
| 74 | + result = x * 2.0 | ||
| 75 | + expected = torch.tensor([2.0, 4.0, 6.0], device="npu") | ||
| 76 | + self.assertTrue(torch.equal(result, expected)) | ||
| 77 | + | ||
| 78 | + def test_emit_itt_enabled_true_default(self): | ||
| 79 | + """enabled=True (default) does not disrupt computation (guarded).""" | ||
| 80 | + if not ITT_AVAILABLE: | ||
| 81 | + self.skipTest("ITT is required") | ||
| 82 | + torch.manual_seed(42) | ||
| 83 | + x = torch.tensor([1.0, 2.0, 3.0], dtype=torch.float32, device="npu") | ||
| 84 | + with emit_itt(): | ||
| 85 | + result = x + 1.0 | ||
| 86 | + expected = torch.tensor([2.0, 3.0, 4.0], device="npu") | ||
| 87 | + self.assertTrue(torch.equal(result, expected)) | ||
| 88 | + | ||
| 89 | + def test_emit_itt_with_model_npu(self): | ||
| 90 | + """emit_itt works with NN model on NPU (guarded by ITT availability).""" | ||
| 91 | + if not ITT_AVAILABLE: | ||
| 92 | + self.skipTest("ITT is required") | ||
| 93 | + torch.manual_seed(42) | ||
| 94 | + model = torch.nn.Linear(10, 5).npu() | ||
| 95 | + x = torch.randn(3, 10, device="npu") | ||
| 96 | + with emit_itt(): | ||
| 97 | + output = model(x) | ||
| 98 | + self.assertEqual(output.shape, (3, 5)) | ||
| 99 | + | ||
| 100 | + def test_emit_itt_execution_order(self): | ||
| 101 | + """Operations inside emit_itt execute in correct order (guarded).""" | ||
| 102 | + if not ITT_AVAILABLE: | ||
| 103 | + self.skipTest("ITT is required") | ||
| 104 | + torch.manual_seed(42) | ||
| 105 | + x = torch.tensor([1.0, 2.0, 3.0], dtype=torch.float32, device="npu") | ||
| 106 | + with emit_itt(): | ||
| 107 | + x = x + 1.0 | ||
| 108 | + x = x * 2.0 | ||
| 109 | + expected = torch.tensor([4.0, 6.0, 8.0], device="npu") | ||
| 110 | + self.assertTrue(torch.equal(x, expected)) | ||
| 111 | + | ||
| 112 | + def test_emit_itt_record_shapes_true(self): | ||
| 113 | + """record_shapes=True does not disrupt computation (guarded).""" | ||
| 114 | + if not ITT_AVAILABLE: | ||
| 115 | + self.skipTest("ITT is required") | ||
| 116 | + torch.manual_seed(42) | ||
| 117 | + x = torch.tensor([1.0, 2.0, 3.0], dtype=torch.float32, device="npu") | ||
| 118 | + with emit_itt(record_shapes=True): | ||
| 119 | + result = x * 2.0 | ||
| 120 | + expected = torch.tensor([2.0, 4.0, 6.0], device="npu") | ||
| 121 | + self.assertTrue(torch.equal(result, expected)) | ||
| 122 | + | ||
| 123 | + | ||
| 124 | +if __name__ == "__main__": | ||
| 125 | + run_tests() | ||
| @@ -0,0 +1,265 @@ | |||
| 1 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd | ||
| 2 | +# All rights reserved. | ||
| 3 | +# | ||
| 4 | +# Licensed under the BSD 3-Clause License (the "License") | ||
| 5 | +# you may not use this file except in compliance with the License. | ||
| 6 | +# You may obtain a copy of the License at | ||
| 7 | +# https://opensource.org/licenses/BSD-3-Clause | ||
| 8 | +# Unless required by applicable law or agreed to in writing, software | ||
| 9 | +# distributed under the License is distributed on an "AS IS" BASIS, | ||
| 10 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 11 | +# See the License for the specific language governing permissions and | ||
| 12 | +# limitations under the License. | ||
| 13 | + | ||
| 14 | +""" | ||
| 15 | +Add validation cases for torch.autograd.gradcheck on Ascend NPU. | ||
| 16 | + | ||
| 17 | +PyTorch community has independent test cases for gradcheck in | ||
| 18 | +test/test_autograd.py, but these cases cannot run on NPU because Ascend NPU | ||
| 19 | +does not support float64 for some operations. This file validates that | ||
| 20 | +gradcheck works correctly in slow_mode with float64 on NPU for the | ||
| 21 | +operations that Ascend NPU supports, and covers parameter combinations | ||
| 22 | +including raise_exception, check_undefined_grad, check_batched_grad, | ||
| 23 | +fast_mode, and edge cases. | ||
| 24 | +""" | ||
| 25 | +import torch | ||
| 26 | +from torch.autograd import gradcheck, gradgradcheck | ||
| 27 | + | ||
| 28 | +from torch_npu.testing.testcase import TestCase, run_tests | ||
| 29 | + | ||
| 30 | + | ||
| 31 | +class TestGradcheck(TestCase): | ||
| 32 | + """Test cases for torch.autograd.gradcheck on Ascend NPU.""" | ||
| 33 | + | ||
| 34 | + def test_gradcheck_slow_mode_mul(self): | ||
| 35 | + """slow_mode mul with gradient value verification.""" | ||
| 36 | + torch.manual_seed(42) | ||
| 37 | + | ||
| 38 | + def f(inp): | ||
| 39 | + return inp.mul(5) | ||
| 40 | + | ||
| 41 | + x = torch.rand(10, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 42 | + self.assertTrue(gradcheck(f, x, fast_mode=False)) | ||
| 43 | + xc = x.detach().clone().requires_grad_(True) | ||
| 44 | + y = f(xc) | ||
| 45 | + y.sum().backward() | ||
| 46 | + self.assertTrue(torch.allclose(xc.grad, torch.full_like(xc, 5.0))) | ||
| 47 | + | ||
| 48 | + def test_gradcheck_slow_mode_linear(self): | ||
| 49 | + """slow_mode linear function.""" | ||
| 50 | + torch.manual_seed(42) | ||
| 51 | + | ||
| 52 | + def f(x): | ||
| 53 | + return 3 * x + 2 | ||
| 54 | + | ||
| 55 | + x = torch.rand(4, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 56 | + self.assertTrue(gradcheck(f, x, fast_mode=False)) | ||
| 57 | + xc = x.detach().clone().requires_grad_(True) | ||
| 58 | + y = f(xc) | ||
| 59 | + y.sum().backward() | ||
| 60 | + self.assertTrue(torch.allclose(xc.grad, torch.full_like(xc, 3.0))) | ||
| 61 | + | ||
| 62 | + def test_gradcheck_slow_mode_sin_cos(self): | ||
| 63 | + """slow_mode sin and cos.""" | ||
| 64 | + torch.manual_seed(42) | ||
| 65 | + | ||
| 66 | + def f(x): | ||
| 67 | + return x.sin().cos() | ||
| 68 | + | ||
| 69 | + x = torch.rand(8, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 70 | + self.assertTrue(gradcheck(f, x, fast_mode=False)) | ||
| 71 | + xc = x.detach().clone().requires_grad_(True) | ||
| 72 | + y = f(xc) | ||
| 73 | + y.sum().backward() | ||
| 74 | + self.assertFalse(torch.allclose(xc.grad, torch.zeros_like(xc.grad))) | ||
| 75 | + | ||
| 76 | + def test_gradcheck_slow_mode_exp(self): | ||
| 77 | + """slow_mode exp.""" | ||
| 78 | + torch.manual_seed(42) | ||
| 79 | + | ||
| 80 | + def f(x): | ||
| 81 | + return x.exp() | ||
| 82 | + | ||
| 83 | + x = torch.rand(3, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 84 | + self.assertTrue(gradcheck(f, x, fast_mode=False)) | ||
| 85 | + xc = x.detach().clone().requires_grad_(True) | ||
| 86 | + y = f(xc) | ||
| 87 | + y.sum().backward() | ||
| 88 | + self.assertTrue(torch.allclose(xc.grad, xc.exp(), rtol=1e-5)) | ||
| 89 | + | ||
| 90 | + def test_gradcheck_slow_mode_sum(self): | ||
| 91 | + """slow_mode sum reduction.""" | ||
| 92 | + torch.manual_seed(42) | ||
| 93 | + | ||
| 94 | + def f(x): | ||
| 95 | + return x.sum() | ||
| 96 | + | ||
| 97 | + x = torch.rand(4, 5, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 98 | + self.assertTrue(gradcheck(f, x, fast_mode=False)) | ||
| 99 | + xc = x.detach().clone().requires_grad_(True) | ||
| 100 | + y = f(xc) | ||
| 101 | + y.backward() | ||
| 102 | + self.assertTrue(torch.allclose(xc.grad, torch.ones_like(xc))) | ||
| 103 | + | ||
| 104 | + def test_gradcheck_slow_mode_multiple_inputs(self): | ||
| 105 | + """slow_mode multiple inputs.""" | ||
| 106 | + torch.manual_seed(42) | ||
| 107 | + | ||
| 108 | + def f(x, y): | ||
| 109 | + return x * y + x | ||
| 110 | + | ||
| 111 | + x = torch.rand(5, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 112 | + y = torch.rand(5, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 113 | + self.assertTrue(gradcheck(f, (x, y), fast_mode=False)) | ||
| 114 | + xc = x.detach().clone().requires_grad_(True) | ||
| 115 | + yc = y.detach().clone().requires_grad_(True) | ||
| 116 | + z = f(xc, yc) | ||
| 117 | + z.sum().backward() | ||
| 118 | + self.assertTrue(torch.allclose(xc.grad, yc + 1.0)) | ||
| 119 | + self.assertTrue(torch.allclose(yc.grad, xc)) | ||
| 120 | + | ||
| 121 | + def test_gradcheck_slow_mode_return_tuple(self): | ||
| 122 | + """slow_mode function returning tuple.""" | ||
| 123 | + torch.manual_seed(42) | ||
| 124 | + | ||
| 125 | + def f(x): | ||
| 126 | + return x.sin(), x.cos() | ||
| 127 | + | ||
| 128 | + x = torch.rand(5, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 129 | + self.assertTrue(gradcheck(f, x, fast_mode=False)) | ||
| 130 | + xc = x.detach().clone().requires_grad_(True) | ||
| 131 | + s, c = f(xc) | ||
| 132 | + (s.sum() + c.sum()).backward() | ||
| 133 | + self.assertFalse(torch.allclose(xc.grad, torch.zeros_like(xc.grad))) | ||
| 134 | + | ||
| 135 | + def test_gradgradcheck_slow_mode_mul(self): | ||
| 136 | + """gradgradcheck slow_mode with mul.""" | ||
| 137 | + torch.manual_seed(42) | ||
| 138 | + | ||
| 139 | + def f(inp): | ||
| 140 | + return inp.mul(5) | ||
| 141 | + | ||
| 142 | + x = torch.rand(5, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 143 | + self.assertTrue(gradgradcheck(f, x, fast_mode=False)) | ||
| 144 | + | ||
| 145 | + def test_gradgradcheck_slow_mode_multiple_inputs(self): | ||
| 146 | + """gradgradcheck slow_mode with multiple inputs.""" | ||
| 147 | + torch.manual_seed(42) | ||
| 148 | + | ||
| 149 | + def f(x, y): | ||
| 150 | + return x * y | ||
| 151 | + | ||
| 152 | + x = torch.rand(3, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 153 | + y = torch.rand(3, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 154 | + self.assertTrue(gradgradcheck(f, (x, y), fast_mode=False)) | ||
| 155 | + | ||
| 156 | + # Parameter coverage tests | ||
| 157 | + | ||
| 158 | + def test_gradcheck_raise_exception_false(self): | ||
| 159 | + """raise_exception=False returns False on mismatch.""" | ||
| 160 | + torch.manual_seed(42) | ||
| 161 | + | ||
| 162 | + def f(x): | ||
| 163 | + return x * torch.tensor([1.0, 2.0, 3.0], device=x.device) | ||
| 164 | + | ||
| 165 | + x = torch.rand(3, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 166 | + result = gradcheck(f, x, raise_exception=False, atol=1e-10, rtol=1e-10) | ||
| 167 | + self.assertIsInstance(result, bool) | ||
| 168 | + | ||
| 169 | + def test_gradcheck_nondet_tol(self): | ||
| 170 | + """nondet_tol parameter works.""" | ||
| 171 | + torch.manual_seed(42) | ||
| 172 | + | ||
| 173 | + def f(x): | ||
| 174 | + return x.sin() | ||
| 175 | + | ||
| 176 | + x = torch.rand(5, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 177 | + result = gradcheck(f, x, nondet_tol=1.0) | ||
| 178 | + self.assertTrue(result) | ||
| 179 | + | ||
| 180 | + def test_gradcheck_check_backward_ad_false(self): | ||
| 181 | + """check_backward_ad=False skips backward AD check.""" | ||
| 182 | + torch.manual_seed(42) | ||
| 183 | + | ||
| 184 | + def f(x): | ||
| 185 | + return x.neg() | ||
| 186 | + | ||
| 187 | + x = torch.rand(3, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 188 | + # check_backward_ad=False with check_forward_ad=True | ||
| 189 | + result = gradcheck(f, x, fast_mode=False, check_backward_ad=False, | ||
| 190 | + check_forward_ad=True) | ||
| 191 | + self.assertIsInstance(result, bool) | ||
| 192 | + | ||
| 193 | + def test_gradcheck_check_batched_grad(self): | ||
| 194 | + """check_batched_grad=True with slow_mode.""" | ||
| 195 | + torch.manual_seed(42) | ||
| 196 | + | ||
| 197 | + def f(x): | ||
| 198 | + return x.pow(2) | ||
| 199 | + | ||
| 200 | + x = torch.rand(4, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 201 | + self.assertTrue(gradcheck(f, x, fast_mode=False, check_batched_grad=True)) | ||
| 202 | + | ||
| 203 | + def test_gradcheck_check_undefined_grad_false(self): | ||
| 204 | + """check_undefined_grad=False skips undefined grad check.""" | ||
| 205 | + torch.manual_seed(42) | ||
| 206 | + | ||
| 207 | + def f(x): | ||
| 208 | + return x.mul(5) | ||
| 209 | + | ||
| 210 | + x = torch.rand(4, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 211 | + result = gradcheck(f, x, check_undefined_grad=False) | ||
| 212 | + self.assertIsInstance(result, bool) | ||
| 213 | + | ||
| 214 | + def test_gradcheck_custom_eps_atol_rtol(self): | ||
| 215 | + """Custom eps, atol, rtol values.""" | ||
| 216 | + torch.manual_seed(42) | ||
| 217 | + | ||
| 218 | + def f(x): | ||
| 219 | + return x.sin() | ||
| 220 | + | ||
| 221 | + x = torch.rand(5, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 222 | + self.assertTrue(gradcheck(f, x, fast_mode=False, | ||
| 223 | + eps=1e-4, atol=1e-3, rtol=1e-2)) | ||
| 224 | + | ||
| 225 | + # Edge cases | ||
| 226 | + | ||
| 227 | + def test_gradcheck_single_element_tensor(self): | ||
| 228 | + """1-element tensor (boundary value).""" | ||
| 229 | + torch.manual_seed(42) | ||
| 230 | + | ||
| 231 | + def f(x): | ||
| 232 | + return x * 2 | ||
| 233 | + | ||
| 234 | + x = torch.rand(1, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 235 | + self.assertTrue(gradcheck(f, x, fast_mode=False)) | ||
| 236 | + | ||
| 237 | + def test_gradcheck_no_requires_grad_input_raises(self): | ||
| 238 | + """Input without requires_grad raises ValueError.""" | ||
| 239 | + torch.manual_seed(42) | ||
| 240 | + | ||
| 241 | + def f(x): | ||
| 242 | + return x * 2 | ||
| 243 | + | ||
| 244 | + x = torch.rand(3, dtype=torch.float64, device="npu", requires_grad=False) | ||
| 245 | + with self.assertRaises((ValueError, RuntimeError)): | ||
| 246 | + gradcheck(f, x, fast_mode=False) | ||
| 247 | + | ||
| 248 | + def test_gradcheck_masked_parameter(self): | ||
| 249 | + """masked=True with masked=False comparison.""" | ||
| 250 | + torch.manual_seed(42) | ||
| 251 | + | ||
| 252 | + def f(x): | ||
| 253 | + return x.mul(5) | ||
| 254 | + | ||
| 255 | + x = torch.rand(4, dtype=torch.float64, device="npu", requires_grad=True) | ||
| 256 | + r1 = gradcheck(f, x, fast_mode=False, masked=True, | ||
| 257 | + raise_exception=False) | ||
| 258 | + r2 = gradcheck(f, x, fast_mode=False, masked=False, | ||
| 259 | + raise_exception=False) | ||
| 260 | + self.assertIsInstance(r1, bool) | ||
| 261 | + self.assertIsInstance(r2, bool) | ||
| 262 | + | ||
| 263 | + | ||
| 264 | +if __name__ == "__main__": | ||
| 265 | + run_tests() | ||
| @@ -181,3 +181,16 @@ index 4aeeb87..f50850a 100644 | |||
| 181 | context_fn = functools.partial(create_selective_checkpoint_contexts, policy_fn) | 181 | context_fn = functools.partial(create_selective_checkpoint_contexts, policy_fn) |
| 182 | out = checkpoint(fn, x, use_reentrant=False, context_fn=context_fn) | 182 | out = checkpoint(fn, x, use_reentrant=False, context_fn=context_fn) |
| 183 | out.sum().backward(retain_graph=True) | 183 | out.sum().backward(retain_graph=True) |
| 184 | + | ||
| 185 | + | ||
| 186 | + out.sum().backward() | ||
| 187 | + self.assertFalse(s.grad is None or s.grad.abs().sum().item() == 0) | ||
| 188 | + | ||
| 189 | +- @unittest.skipIf(not torch.profiler.itt.is_available(), "ITT is required") | ||
| 190 | + def test_profiler_emit_itt(self, device): | ||
| 191 | + a = torch.tensor([1, 2, 3], dtype=torch.float32, device=device) | ||
| 192 | +- with emit_itt(): | ||
| 193 | +- a.add(1.0) | ||
| 194 | ++ if torch.profiler.itt.is_available(): | ||
| 195 | ++ with emit_itt(): | ||
| 196 | ++ a.add(1.0) | ||
【openlibing.ci】检测到当前PR中存在代码检查告警抑制 2 处,详情见下表,请Committer检视合理性。 / Detected 2 code check alert suppression(s) in this PR, see table below. Committers please review.
import torch_npu # noqa: F401import torch_npu # noqa: F401