已合并
refactor: decouple the check accuracy feature from triton, mlir, dvm. #35311
yvjc创建于 5月11日
refactor: decouple the check accuracy feature from triton, mlir, dvm. #35311
已合并
yvjc创建于 5月11日
已删除 :decouple_accuracy_v271合入到Ascend/pytorchv2.7.1
8 个文件变更+246-290
@@ -2,9 +2,9 @@
2 2 
3## 功能描述3## 功能描述
4 4 
5-INDUCTOR_ASCEND_CHECK_ACCURACY是Ascend Extension for PyTorch提供的精度校验工具,在torch.compile图编译后端为"Inductor"且模式为"Triton"时自动检测融合算子的数值精度。5+INDUCTOR_ASCEND_CHECK_ACCURACY是Ascend Extension for PyTorch提供的精度校验工具,在torch.compile图编译后端为"Inductor"时自动检测融合算子的数值精度。
6 6 
7-该工具可捕获融合算子对应的FX子图,生成独立可执行的单算子测试用例,并在相同输入条件下比对eager与Triton的输出差异。当差异超出预设阈值时,自动输出精度校验失败日志及诊断信息,辅助开发者快速定位精度问题。7+该工具可捕获融合算子对应的FX子图,生成独立可执行的单算子测试用例,并在相同输入条件下比对eager与融合算子的输出差异。当差异超出预设阈值时,自动输出精度校验失败日志及诊断信息,辅助开发者快速定位精度问题。
8 8 
9## 配置示例9## 配置示例
10 10 
@@ -36,9 +36,9 @@ export INDUCTOR_ASCEND_CHECK_ACCURACY_RTOL_ATOL="rtol=1e-6,atol=1e-7"
36 36 
37## 使用约束37## 使用约束
38 38 
39-- 此环境变量仅可在PyTorch2.7.1PyTorch2.9.0版本使用。39+- 此环境变量仅可在PyTorch2.7.1PyTorch2.9.0和PyTorch2.10版本使用。
40 40 
41-- 在torch.compile图编译后端为"Inductor"且模式为"Triton"(环境变量TORCHINDUCTOR_NPU_BACKEND为空或者"default")时可使用此环境变量。41+- 在torch.compile图编译后端为"Inductor"时可使用此环境变量。
42 42 
43## 支持的型号43## 支持的型号
44 44 
@@ -1,6 +1,7 @@
1import os1import os
2from unittest.mock import patch2from unittest.mock import patch
3-from unittest import skip3+ 
4+os.environ["INDUCTOR_ASCEND_CHECK_ACCURACY"] = "1"
4 5 
5import torch6import torch
6import torch.nn.functional as F7import torch.nn.functional as F
@@ -9,7 +10,6 @@ from testutils import TestUtils
9import torch_npu10import torch_npu
10 11 
11torch._inductor.config.fx_graph_cache = False12torch._inductor.config.fx_graph_cache = False
12-os.environ["INDUCTOR_ASCEND_CHECK_ACCURACY"] = "1"
13 13 
14 14 
15class TestCheckAccuracy(TestUtils):15class TestCheckAccuracy(TestUtils):
@@ -29,11 +29,11 @@ class TestCheckAccuracy(TestUtils):
29 nonlocal count_data_dump29 nonlocal count_data_dump
30 count_data_dump += 130 count_data_dump += 1
31 return status31 return status
32-
33- src_check_accuracy = NPUCachingAutotuner.check_accuracy
34 32 
35- def wrap_check_accuracy(self, *args, **kwargs):33+ src_check_accuracy = torch_npu._inductor.npu_compare.check_accuracy_triton
36- status = src_check_accuracy(self, *args, **kwargs)34+ 
35+ def wrap_check_accuracy(*args, **kwargs):
36+ status = src_check_accuracy(*args, **kwargs)
37 if status:37 if status:
38 nonlocal count_check_accuracy38 nonlocal count_check_accuracy
39 count_check_accuracy += 139 count_check_accuracy += 1
@@ -48,7 +48,7 @@ class TestCheckAccuracy(TestUtils):
48 _ = run(x, y)48 _ = run(x, y)
49 49 
50 with patch.object(NPUCachingAutotuner, "data_dump", wrap_data_dump), \50 with patch.object(NPUCachingAutotuner, "data_dump", wrap_data_dump), \
51- patch.object(NPUCachingAutotuner, "check_accuracy", wrap_check_accuracy):51+ patch.object(torch_npu._inductor.runtime.triton_heuristics, "check_accuracy_triton", wrap_check_accuracy):
52 self.assertTrue(torch_npu._inductor.config.dump_fx_graph)52 self.assertTrue(torch_npu._inductor.config.dump_fx_graph)
53 self.assertTrue(torch_npu._inductor.config.check_accuracy)53 self.assertTrue(torch_npu._inductor.config.check_accuracy)
54 54
@@ -69,4 +69,4 @@ class TestCheckAccuracy(TestUtils):
69 69
70 70 
71if __name__ == "__main__":71if __name__ == "__main__":
72- run_tests()72+ run_tests()
@@ -576,6 +576,7 @@ class TestPublicBindings(TestCase):
576 "torch_npu._inductor.dependencies",576 "torch_npu._inductor.dependencies",
577 "torch_npu._inductor.npu_device",577 "torch_npu._inductor.npu_device",
578 "torch_npu._inductor.npu_static_kernel",578 "torch_npu._inductor.npu_static_kernel",
579+ "torch_npu._inductor.npu_compare",
579 "torch_npu._inductor.utils",580 "torch_npu._inductor.utils",
580 "torch_npu._inductor.codegen._sizevars",581 "torch_npu._inductor.codegen._sizevars",
581 "torch_npu._inductor.codegen.common",582 "torch_npu._inductor.codegen.common",
@@ -7,6 +7,7 @@ from typing import Any, Callable, Dict, List, Optional, Tuple, Iterator
7 7 
8import torch8import torch
9from torch._inductor.compile_fx import clone_preserve_strides9from torch._inductor.compile_fx import clone_preserve_strides
10+from torch_npu._inductor.npu_compare import check_accuracy_mlir
10 11 
11from .. import config as anir_config12from .. import config as anir_config
12from .utils import replace_placeholders13from .utils import replace_placeholders
@@ -101,74 +102,23 @@ class MetaCompiler:
101 return failed_subgraph_dump_path102 return failed_subgraph_dump_path
102 103
103 def acc_compare_and_dump(self, *args, **kwargs):104 def acc_compare_and_dump(self, *args, **kwargs):
104- from torch.testing._comparison import _make_mismatch_msg
105 self.register_fx_fallback(self.kernel_meta)105 self.register_fx_fallback(self.kernel_meta)
106- launcher_fx = self.launchers[1]
107- launcher = self.launchers[0]
108- 
109- fx_outputs = [clone_preserve_strides(arg).to(torch.float32) if arg.dtype == torch.bfloat16 \
110- else clone_preserve_strides(arg) for arg in args[-self.num_outputs:]]
111- fx_inputs = [clone_preserve_strides(arg) if isinstance(arg, torch.Tensor) else arg for arg in args[:-self.num_outputs]]
112- fx_inputs = [inp.float() if isinstance(inp, torch.Tensor) and inp.dtype == torch.bfloat16 else inp for inp in fx_inputs]
113 106
114- fx_args = fx_inputs + fx_outputs107+ output, has_acc_error = check_accuracy_mlir(
115- launcher_fx(*fx_args, **kwargs)108+ *args,
116- 109+ kernel_name=self.kernel_name,
117- if self.dynamic:110+ launchers=self.launchers,
118- args_new = self.prepare_runtime_args(111+ num_outputs=self.num_outputs,
119- list(args),112+ dynamic=self.dynamic,
120- )113+ **kwargs
121- else:114+ )
122- args_new = args
123-
124- output = launcher(*args_new, **kwargs)
125- 
126- has_acc_error = False
127- num_inputs = len(args) - self.num_outputs
128- for idx, (actual, expected) in enumerate(zip(args[num_inputs:], fx_outputs)):
129- if actual.dtype != expected.dtype:
130- expected = expected.to(actual.dtype)
131- acc_comp_tol = anir_config.acc_comp_tol.get(actual.dtype, anir_config.acc_comp_tol['default'])
132- rtol = acc_comp_tol['rtol']
133- atol = acc_comp_tol['atol']
134- matches = torch.isclose(
135- actual, expected, rtol=rtol, atol=atol, equal_nan=True
136- )
137- if not matches.all():
138- abs_diff = abs(actual - expected)
139- rel_diff = abs_diff / abs(expected)
140- rel_diff.masked_fill_(matches, 0)
141- number_of_elements = matches.numel()
142- total_mismatches = number_of_elements - int(torch.sum(matches))
143- extra = (
144- f"Mismatched elements: {total_mismatches} / {number_of_elements} "
145- f"({total_mismatches / number_of_elements:.1%})"
146- )
147- msg = _make_mismatch_msg(
148- default_identifier="Tensor-likes",
149- identifier=None,
150- extra=extra,
151- abs_diff=abs_diff.max().item(),
152- abs_diff_idx=None,
153- atol=atol,
154- rel_diff=rel_diff.max().item(),
155- rel_diff_idx=None,
156- rtol=rtol,
157- )
158- print(f"Kernel Name: {self.kernel_name}\n{msg}", flush=True)
159- has_acc_error = True
160- 
161- del abs_diff
162- del rel_diff
163- del matches
164- del expected
165 115
166 if anir_config.fx_subgraph_dump_path:116 if anir_config.fx_subgraph_dump_path:
167 data = args117 data = args
168 if has_acc_error:118 if has_acc_error:
169 data_dump_path = self.fx_subgraph_dump('acc_failed')119 data_dump_path = self.fx_subgraph_dump('acc_failed')
170 self.data_dump_fake(*data, dump_path=data_dump_path)120 self.data_dump_fake(*data, dump_path=data_dump_path)
171- del fx_inputs121+ 
172 torch.npu.synchronize()122 torch.npu.synchronize()
173 self.launchers = [self.launchers[0]]123 self.launchers = [self.launchers[0]]
174 self.is_fallback_kernels = [self.is_fallback_kernels[0]]124 self.is_fallback_kernels = [self.is_fallback_kernels[0]]
@@ -12,7 +12,7 @@ from torch_npu._C.dvm import (
12 TorchKernel as Kernel,12 TorchKernel as Kernel,
13)13)
14 14 
15-from .fx_test import _accuracy_check_run15+from torch_npu._inductor.npu_compare import check_accuracy_dvm
16 16 
17 17 
18debug_mode = False18debug_mode = False
@@ -114,7 +114,7 @@ def kernel(
114 114 
115 def run(*args, **kwargs):115 def run(*args, **kwargs):
116 if fn._acc_meta is not None:116 if fn._acc_meta is not None:
117- _accuracy_check_run(kobj, fn._acc_meta, kernel_name, args)117+ check_accuracy_dvm(kobj, fn._acc_meta, kernel_name, args)
118 else:118 else:
119 kobj.run(*args)119 kobj.run(*args)
120 if debug_mode:120 if debug_mode:
@@ -1,6 +1,4 @@
1import os1import os
2-import sys
3-import importlib
4import hashlib2import hashlib
5import torch3import torch
6 4 
@@ -141,86 +139,3 @@ if __name__ == "__main__":
141 139 
142 print(f"[ok] generated: {file_path}")140 print(f"[ok] generated: {file_path}")
143 return file_path141 return file_path
144- 
145- 
146-def _load_fx_model(acc_meta):
147- """Load the traced FX GraphModule from disk for accuracy comparison."""
148- if acc_meta.get('_fx_model') is not None:
149- return acc_meta['_fx_model']
150- dump_path = os.path.join(
151- os.getenv("TORCHINDUCTOR_CACHE_DIR"),
152- acc_meta['traced_graph_cache'],
153- str(acc_meta['device_index']),
154- acc_meta['traced_graph_hash'],
155- )
156- sys.path.insert(0, dump_path)
157- try:
158- module = importlib.import_module(acc_meta['traced_graph_hash'])
159- finally:
160- sys.path.remove(dump_path)
161- Model = getattr(module, acc_meta['traced_graph_hash'])
162- model = Model()
163- acc_meta['_fx_model'] = model
164- return model
165-
166-
167-def _accuracy_check_run(kobj, acc_meta, kernel_name, args):
168- """Run DVM kernel then compare outputs against FX graph reference."""
169- from torch._inductor.compile_fx import clone_preserve_strides
170- from torch_npu._inductor.ascend_npu_ir.ascend_npu_ir import (
171- config as anir_config,
172- )
173- 
174- fx_model = _load_fx_model(acc_meta)
175- 
176- num_outputs = acc_meta['num_outputs']
177- num_inputs = len(args) - num_outputs
178- 
179- fx_inputs = []
180- for arg in args[:num_inputs]:
181- if isinstance(arg, torch.Tensor):
182- inp = clone_preserve_strides(arg)
183- if arg.dtype == torch.bfloat16:
184- inp = inp.float()
185- fx_inputs.append(inp)
186- else:
187- fx_inputs.append(arg)
188- 
189- fx_outputs = fx_model.forward(*fx_inputs)
190- if not isinstance(fx_outputs, (tuple, list)):
191- fx_outputs = (fx_outputs,)
192- 
193- kobj.run(*args)
194- 
195- for idx, (actual, expected) in enumerate(
196- zip(args[num_inputs:], fx_outputs)
197- ):
198- if not isinstance(actual, torch.Tensor):
199- continue
200- if actual.dtype != expected.dtype:
201- expected = expected.to(actual.dtype)
202- tol = anir_config.acc_comp_tol.get(
203- actual.dtype, anir_config.acc_comp_tol["default"]
204- )
205- rtol, atol = tol["rtol"], tol["atol"]
206- matches = torch.isclose(
207- actual, expected, rtol=rtol, atol=atol, equal_nan=True
208- )
209- if not matches.all():
210- abs_diff = torch.abs(actual - expected)
211- rel_diff = abs_diff / torch.clamp(torch.abs(expected), min=1e-20)
212- rel_diff.masked_fill_(matches, 0)
213- num_el = matches.numel()
214- num_mis = num_el - int(torch.sum(matches))
215- print(
216- f"CHECK ACCURACY FAILED! "
217- f"Kernel: {kernel_name}, "
218- f"Output idx: {idx}, "
219- f"Mismatched: {num_mis}/{num_el} ({num_mis / num_el:.1%}), "
220- f"Greatest Rel Diff: {rel_diff.max().item()}, "
221- f"Greatest Abs Diff: {abs_diff.max().item()}",
222- flush=True,
223- )
224- 
225- del abs_diff, rel_diff
226- del matches
@@ -0,0 +1,212 @@
1+import importlib
2+import os
3+import sys
4+from typing import Any, Iterable, Mapping
5+ 
6+import torch
7+from torch._inductor.compile_fx import clone_preserve_strides
8+ 
9+ 
10+def clone_for_accuracy(arg):
11+ if not isinstance(arg, torch.Tensor):
12+ return arg
13+ cloned = clone_preserve_strides(arg)
14+ return cloned.float() if cloned.dtype == torch.bfloat16 else cloned
15+ 
16+ 
17+def compare_outputs(
18+ actual_outputs: Iterable[Any],
19+ expected_outputs: Iterable[Any],
20+ kernel_name: str,
21+ tolerances: Mapping[Any, Mapping[str, float]],
22+):
23+ failed_indices = []
24+ for idx, (actual, expected) in enumerate(zip(actual_outputs, expected_outputs)):
25+ if not isinstance(actual, torch.Tensor) or not isinstance(expected, torch.Tensor):
26+ continue
27+ if actual.dtype != expected.dtype:
28+ expected = expected.to(actual.dtype)
29+
30+ tol = tolerances.get(actual.dtype, tolerances["default"])
31+ rtol, atol = tol["rtol"], tol["atol"]
32+ matches = torch.isclose(actual, expected, rtol=rtol, atol=atol, equal_nan=True)
33+ if not matches.all():
34+ _report_mismatch(idx, actual, expected, matches, rtol, atol, kernel_name)
35+ failed_indices.append(idx)
36+ del matches
37+
38+ return not failed_indices
39+ 
40+ 
41+def _report_mismatch(idx, actual, expected, matches, rtol, atol, kernel_name):
42+ try:
43+ abs_diff = torch.abs(actual - expected)
44+ except RuntimeError:
45+ abs_diff = torch.abs(actual.to(torch.float32) - expected.to(torch.float32))
46+ expected_abs = torch.abs(expected)
47+ if not expected_abs.is_floating_point() and not expected_abs.is_complex():
48+ expected_abs = expected_abs.to(torch.float32)
49+ rel_diff = abs_diff / torch.clamp(expected_abs, min=1e-20)
50+ rel_diff.masked_fill_(matches, 0)
51+ number_of_elements = matches.numel()
52+ total_mismatches = number_of_elements - int(torch.sum(matches))
53+ msg = (
54+ "CHECK ACCURACY FAILED! "
55+ f"Kernel: {kernel_name}, Output idx: {idx}, "
56+ f"Mismatched: {total_mismatches}/{number_of_elements} "
57+ f"({total_mismatches / number_of_elements:.1%}), "
58+ f"Greatest Rel Diff: {rel_diff.max().item()}, "
59+ f"Greatest Abs Diff: {abs_diff.max().item()}, "
60+ f"rtol: {rtol}, atol: {atol}"
61+ )
62+ print(msg, flush=True)
63+ del abs_diff, rel_diff
64+ 
65+ 
66+def get_triton_fx_graph_call(inductor_meta, auto_fallback=False):
67+ kernel_name = inductor_meta.get("kernel_name", "triton_")
68+ traced_graph_hash = inductor_meta.get("traced_graph_hash")
69+ dump_dir = inductor_meta.get("traced_graph_dir", "")
70+ dump_path = os.path.join(dump_dir, traced_graph_hash)
71+ if dump_dir == "" or not os.path.exists(dump_path):
72+ return None, None, None, None
73+ sys.path.append(dump_path)
74+ fx_module = importlib.import_module(traced_graph_hash)
75+ sys.path.remove(dump_path)
76+ 
77+ model = fx_module.model
78+ num_inputs = fx_module.num_inputs
79+ num_outputs = fx_module.num_outputs
80+ non_contiguous_indices = fx_module.non_contiguous_indices
81+ mismatch_indices_shapes = fx_module.mismatch_indices_shapes
82+ 
83+ def fx_graph_call(*fx_args):
84+ fx_inputs = [fx_args[idx].contiguous() if idx in non_contiguous_indices['inputs'] else \
85+ fx_args[idx] for idx in range(num_inputs)]
86+ if len(mismatch_indices_shapes):
87+ for ind, shape in mismatch_indices_shapes.items():
88+ if ind >= num_inputs:
89+ break
90+ fx_inputs[ind] = fx_inputs[ind].reshape(shape)
91+ model_outputs = model.forward(*fx_inputs)
92+ for idx, (out1, out2) in enumerate(zip(model_outputs, fx_args[num_inputs:(num_inputs + num_outputs)])):
93+ out1 = out1.reshape(out2.shape)
94+ if idx in non_contiguous_indices['outputs']:
95+ out2.copy_(out1)
96+ else:
97+ out2.data = out1.data
98+ 
99+ def fallback_call(*args):
100+ fx_args = [args[idx] for idx in fx_module.call_args_mapping]
101+ return fx_graph_call(*fx_args)
102+ 
103+ if auto_fallback:
104+ return fallback_call, kernel_name, None, None
105+ return fx_graph_call, kernel_name, dump_path, fx_module
106+ 
107+ 
108+def check_accuracy_triton(*args, launcher, grid, stream, inductor_meta, **kwargs):
109+ import torch_npu._inductor.config as npu_config
110+ fx_graph_call, kernel_name, dump_path, fx_module = get_triton_fx_graph_call(inductor_meta)
111+ if not fx_graph_call:
112+ return None
113+ call_outputs_indices = fx_module.call_args_mapping[fx_module.num_inputs:]
114+ 
115+ fx_args = []
116+ for idx in fx_module.call_args_mapping:
117+ arg = args[idx]
118+ if isinstance(arg, torch.Tensor):
119+ fx_args.append(clone_for_accuracy(arg))
120+
121+ fx_graph_call(*fx_args)
122+ 
123+ launcher(*args, **kwargs, stream=stream)
124+ 
125+ compare_outputs(
126+ [args[i] for i in call_outputs_indices],
127+ fx_args[fx_module.num_inputs:],
128+ kernel_name=kernel_name,
129+ tolerances=npu_config.acc_comp_tol,
130+ )
131+ 
132+ for arg in fx_args:
133+ del arg
134+ return True
135+ 
136+ 
137+def check_accuracy_mlir(*args, kernel_name, launchers, num_outputs, dynamic, **kwargs):
138+ from torch_npu._inductor.ascend_npu_ir.ascend_npu_ir import config as anir_config
139+ launcher_fx = launchers[1]
140+ launcher = launchers[0]
141+ 
142+ num_inputs = len(args) - num_outputs
143+ fx_outputs = [clone_for_accuracy(arg) for arg in args[num_inputs:]]
144+ fx_inputs = [clone_for_accuracy(arg) for arg in args[:num_inputs]]
145+ fx_args = fx_inputs + fx_outputs
146+ 
147+ launcher_fx(*fx_args, **kwargs)
148+ 
149+ if dynamic:
150+ args_new = ()
151+ for arg in args:
152+ if not torch.is_tensor(arg):
153+ args_new = args_new + (arg,)
154+ continue
155+ args_new = args_new + (arg, arg, 0) + arg.size() + arg.stride()
156+ else:
157+ args_new = args
158+
159+ output = launcher(*args_new, **kwargs)
160+ result = compare_outputs(
161+ args[num_inputs:],
162+ fx_outputs,
163+ kernel_name=kernel_name,
164+ tolerances=anir_config.acc_comp_tol,
165+ )
166+ del fx_inputs
167+ return (output, result)
168+ 
169+ 
170+def _load_fx_model(acc_meta):
171+ """Load the traced FX GraphModule from disk for accuracy comparison."""
172+ if acc_meta.get('_fx_model') is not None:
173+ return acc_meta['_fx_model']
174+ dump_path = os.path.join(
175+ os.getenv("TORCHINDUCTOR_CACHE_DIR"),
176+ acc_meta['traced_graph_cache'],
177+ str(acc_meta['device_index']),
178+ acc_meta['traced_graph_hash'],
179+ )
180+ sys.path.insert(0, dump_path)
181+ try:
182+ module = importlib.import_module(acc_meta['traced_graph_hash'])
183+ finally:
184+ sys.path.remove(dump_path)
185+ Model = getattr(module, acc_meta['traced_graph_hash'])
186+ model = Model()
187+ acc_meta['_fx_model'] = model
188+ return model
189+
190+
191+def check_accuracy_dvm(kobj, acc_meta, kernel_name, args):
192+ """Run DVM kernel then compare outputs against FX graph reference."""
193+ from torch_npu._inductor.ascend_npu_ir.ascend_npu_ir import config as anir_config
194+ 
195+ fx_model = _load_fx_model(acc_meta)
196+ 
197+ num_outputs = acc_meta['num_outputs']
198+ num_inputs = len(args) - num_outputs
199+ 
200+ fx_inputs = [clone_for_accuracy(arg) for arg in args[:num_inputs]]
201+ fx_outputs = fx_model.forward(*fx_inputs)
202+ if not isinstance(fx_outputs, (tuple, list)):
203+ fx_outputs = (fx_outputs,)
204+ 
205+ kobj.run(*args)
206+ 
207+ compare_outputs(
208+ args[num_inputs:],
209+ fx_outputs,
210+ kernel_name=kernel_name,
211+ tolerances=anir_config.acc_comp_tol,
212+ )
@@ -81,6 +81,7 @@ except ImportError:
81 81 
82import torch_npu82import torch_npu
83from torch_npu.utils._error_code import ErrCode, pta_error83from torch_npu.utils._error_code import ErrCode, pta_error
84+from torch_npu._inductor.npu_compare import check_accuracy_triton
84 85 
85from ..codegen.tile_generator import TileGenerator86from ..codegen.tile_generator import TileGenerator
86from ..codegen.triton_utils import NPUKernelType87from ..codegen.triton_utils import NPUKernelType
@@ -451,40 +452,6 @@ class NPUCachingAutotuner(CachingAutotuner):
451 self.exceptions = []452 self.exceptions = []
452 self.fn_name = None453 self.fn_name = None
453 454 
454- @staticmethod
455- def api_accuracy_checker(expected, actual, kernel_name, dump_path):
456- from msprobe.core.common.const import CompareConst
457- from msprobe.pytorch.api_accuracy_checker.compare.compare_utils import BENCHMARK_COMPARE_SUPPORT_LIST
458- from msprobe.pytorch.api_accuracy_checker.triton_adapter.get_compare_result import get_compare_result
459- from msprobe.pytorch.api_accuracy_checker.triton_adapter.precision_compare import precision_compare
460- from msprobe.pytorch.api_accuracy_checker.triton_adapter.common.compare_utils import \
461- convert_compare_column_to_row, print_check_details
462- from msprobe.pytorch.api_accuracy_checker.triton_adapter.precision_standard.triton_standard_register import \
463- exist_in_precision_standard
464- 
465- dtype = actual.dtype
466- 
467- # only float use precision standard
468- if exist_in_precision_standard(kernel_name):
469- if str(dtype) in BENCHMARK_COMPARE_SUPPORT_LIST:
470- compare_column = precision_compare(kernel_name, expected, actual, dtype) # calc metrics
471- compare_row = convert_compare_column_to_row(compare_column, kernel_name)
472- status = get_compare_result(compare_row, kernel_name) # get compare results
473- if status == CompareConst.ERROR:
474- log.warning(f'CHECK ACCURACY FAILED! kernel: {kernel_name}, Dump Path: {dump_path}')
475- print_check_details(compare_column, kernel_name)
476- actual.copy_(expected)
477- checked_by_msprobe = True
478- else:
479- log.warning(f'The data type {dtype} is not supported for new precision standard. '
480- f'Check accuracy by tolerance method.')
481- checked_by_msprobe = False
482- else:
483- log.warning(f'kernel_name {kernel_name} does not in new precision standard. '
484- f'Check accuracy by tolerance method.')
485- checked_by_msprobe = False
486- return checked_by_msprobe
487- 
488 def precompile(455 def precompile(
489 self,456 self,
490 warm_cache_only=False,457 warm_cache_only=False,
@@ -976,47 +943,6 @@ class NPUCachingAutotuner(CachingAutotuner):
976 return None943 return None
977 return dump_path944 return dump_path
978 945 
979- def get_fx_graph_call(self, auto_fallback=False):
980- kernel_name = self.inductor_meta.get("kernel_name", "triton_")
981- traced_graph_hash = self.inductor_meta.get("traced_graph_hash")
982- dump_dir = self.inductor_meta.get("traced_graph_dir", "")
983- dump_path = os.path.join(dump_dir, traced_graph_hash)
984- if dump_dir == "" or not os.path.exists(dump_path):
985- return None, None, None, None
986- sys.path.append(dump_path)
987- fx_module = importlib.import_module(traced_graph_hash)
988- sys.path.remove(dump_path)
989- 
990- model = fx_module.model
991- num_inputs = fx_module.num_inputs
992- num_outputs = fx_module.num_outputs
993- non_contiguous_indices = fx_module.non_contiguous_indices
994- mismatch_indices_shapes = fx_module.mismatch_indices_shapes
995- 
996- def fx_graph_call(*fx_args):
997- fx_inputs = [fx_args[idx].contiguous() if idx in non_contiguous_indices['inputs'] else \
998- fx_args[idx] for idx in range(num_inputs)]
999- if len(mismatch_indices_shapes):
1000- for ind, shape in mismatch_indices_shapes.items():
1001- if ind >= num_inputs:
1002- break
1003- fx_inputs[ind] = fx_inputs[ind].reshape(shape)
1004- model_outputs = model.forward(*fx_inputs)
1005- for idx, (out1, out2) in enumerate(zip(model_outputs, fx_args[num_inputs:(num_inputs + num_outputs)])):
1006- out1 = out1.reshape(out2.shape)
1007- if idx in non_contiguous_indices['outputs']:
1008- out2.copy_(out1)
1009- else:
1010- out2.data = out1.data
1011- 
1012- def fallback_call(*args):
1013- fx_args = [args[idx] for idx in fx_module.call_args_mapping]
1014- return fx_graph_call(*fx_args)
1015- 
1016- if auto_fallback:
1017- return fallback_call, kernel_name, None, None
1018- return fx_graph_call, kernel_name, dump_path, fx_module
1019- 
1020 def data_dump(self, *args, dump_path=None):946 def data_dump(self, *args, dump_path=None):
1021 dump_path = self.get_fx_graph_dump_path() if dump_path is None else dump_path947 dump_path = self.get_fx_graph_dump_path() if dump_path is None else dump_path
1022 if dump_path is None:948 if dump_path is None:
@@ -1037,61 +963,6 @@ class NPUCachingAutotuner(CachingAutotuner):
1037 self.fn_name = self.kernel_name963 self.fn_name = self.kernel_name
1038 return self.fn_name964 return self.fn_name
1039 965 
1040- def check_accuracy(self, *args, launcher, grid, stream, **kwargs):
1041- fx_graph_call, kernel_name, dump_path, fx_module = self.get_fx_graph_call()
1042- if not fx_graph_call:
1043- return None
1044- call_outputs_indices = fx_module.call_args_mapping[fx_module.num_inputs:]
1045- 
1046- fx_args = []
1047- for idx in fx_module.call_args_mapping:
1048- arg = args[idx]
1049- if isinstance(arg, torch.Tensor):
1050- fx_arg = clone_preserve_strides(arg).float() if arg.dtype == torch.bfloat16 else clone_preserve_strides(
1051- arg)
1052- fx_args.append(fx_arg)
1053- 
1054- fx_graph_call(*fx_args)
1055- 
1056- launcher(
1057- *args,
1058- **kwargs,
1059- stream=stream,
1060- )
1061- 
1062- try:
1063- import msprobe
1064- has_msprobe = True
1065- except ImportError:
1066- has_msprobe = False
1067- warning_once(log, "msprobe import failed, please check. "
1068- "It may be due to missing dependencies or other factors. "
1069- "Check accuracy by tolerance method.")
1070- for actual, expected in zip([args[i] for i in call_outputs_indices], fx_args[fx_module.num_inputs:]):
1071- if actual.dtype != expected.dtype:
1072- expected = expected.to(actual.dtype)
1073- checked_by_msprobe = False
1074- if has_msprobe:
1075- checked_by_msprobe = self.api_accuracy_checker(expected, actual, kernel_name, dump_path)
1076- if not has_msprobe or not checked_by_msprobe:
1077- acc_comp_tol = npu_config.acc_comp_tol.get(actual.dtype, npu_config.acc_comp_tol['default'])
1078- rtol = acc_comp_tol['rtol']
1079- atol = acc_comp_tol['atol']
1080- 
1081- matches = torch.isclose(
1082- actual, expected, rtol=rtol, atol=atol, equal_nan=True
1083- )
1084- if not matches.all():
1085- abs_diff = torch.abs(actual - expected)
1086- rel_diff = abs_diff / torch.abs(expected)
1087- rel_diff.masked_fill_(matches, 0)
1088- log.warning(f"CHECK ACCURACY FAILED! Greatest Relative Difference: {rel_diff.max().item()}, "
1089- f"Kernel Name: {kernel_name}, Dump Path: {dump_path}")
1090- del matches
1091- for arg in fx_args:
1092- del arg
1093- return True
1094- 
1095 @functools.lru_cache(None)966 @functools.lru_cache(None)
1096 def is_run_debug(self):967 def is_run_debug(self):
1097 return npu_config.dump_fx_graph or npu_config.check_accuracy968 return npu_config.dump_fx_graph or npu_config.check_accuracy
@@ -1108,7 +979,14 @@ class NPUCachingAutotuner(CachingAutotuner):
1108 _ = self.data_dump(*args)979 _ = self.data_dump(*args)
1109 980 
1110 if npu_config.check_accuracy:981 if npu_config.check_accuracy:
1111- if self.check_accuracy(*args, launcher=launcher, grid=grid_, stream=stream, **kwargs):982+ if check_accuracy_triton(
983+ *args,
984+ launcher=launcher,
985+ grid=grid_,
986+ stream=stream,
987+ inductor_meta=self.inductor_meta,
988+ **kwargs
989+ ):
1112 return "check_accuracy"990 return "check_accuracy"
1113 991 
1114 log.info(f"No debug mode is activated for kernel {kernel_name}.")992 log.info(f"No debug mode is activated for kernel {kernel_name}.")