Skip to content

Commit 4224225

Browse files
committed
format docment
1 parent 4663a9a commit 4224225

2 files changed

Lines changed: 84 additions & 66 deletions

File tree

src/flag_gems/logging_utils.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
"""
1212

1313
import logging
14-
import functools
1514
import traceback
1615
from pathlib import Path
1716

1817
import torch
1918

19+
2020
class LogOncePerLocationFilter(logging.Filter):
2121
def __init__(self):
2222
super().__init__()
@@ -127,7 +127,11 @@ def get_call_location():
127127
def compare_outputs(fg_out, pt_out, rtol, atol):
128128
if isinstance(fg_out, torch.Tensor) and isinstance(pt_out, torch.Tensor):
129129
if fg_out.shape != pt_out.shape:
130-
return False, {"error": "shape_mismatch", "fg": tuple(fg_out.shape), "pt": tuple(pt_out.shape)}
130+
return False, {
131+
"error": "shape_mismatch",
132+
"fg": tuple(fg_out.shape),
133+
"pt": tuple(pt_out.shape),
134+
}
131135
try:
132136
fg = fg_out.detach().float()
133137
pt = pt_out.detach().float()
@@ -146,18 +150,23 @@ def compare_outputs(fg_out, pt_out, rtol, atol):
146150
return False, info
147151
return True, {}
148152

149-
def enable_precision_check(rtol=1e-4, atol=1e-5, log_once=True, max_checks=10, path=None):
153+
154+
def enable_precision_check(
155+
rtol=1e-4, atol=1e-5, log_once=True, max_checks=10, path=None
156+
):
150157
setup_precision_logging(path)
151-
precision_config.update({
152-
"enabled": True,
153-
"rtol": rtol,
154-
"atol": atol,
155-
"log_once": log_once,
156-
"max_checks": max_checks,
157-
"logged_ops": set(),
158-
})
158+
precision_config.update(
159+
{
160+
"enabled": True,
161+
"rtol": rtol,
162+
"atol": atol,
163+
"log_once": log_once,
164+
"max_checks": max_checks,
165+
"logged_ops": set(),
166+
}
167+
)
159168

160169

161170
def disable_precision_check():
162171
"""close precision log file and disable precision check."""
163-
precision_config["enabled"] = False
172+
precision_config["enabled"] = False

src/flag_gems/runtime/register.py

Lines changed: 63 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import warnings
21
import functools
2+
import warnings
3+
34
import torch
45

5-
from . import backend, common, error
6-
from .backend.device import DeviceDetector
76
from ..logging_utils import (
8-
precision_config,
7+
compare_outputs,
98
get_precision_logger,
109
get_tensor_info,
11-
get_call_location,
12-
compare_outputs,
10+
precision_config,
1311
)
12+
from . import backend, common, error
13+
from .backend.device import DeviceDetector
1414

1515

1616
class Register:
@@ -34,7 +34,6 @@ def __init__(
3434
self.all_ops = []
3535
self.all_keys = []
3636

37-
3837
# optional mapping func_name -> list of config entries
3938
self.full_config_by_func = full_config_by_func
4039
self.cpp_patched_ops = set(cpp_patched_ops or [])
@@ -144,27 +143,13 @@ def get_vendor_name(self):
144143
def get_current_device(self):
145144
return self.device.name
146145

147-
# def _wrap_op_with_precision_check(op_key, fn):
148-
# @functools.wraps(fn)
149-
# def wrapper(*args, **kwargs):
150-
# fg_result = fn(*args, **kwargs)
151-
152-
# cfg = precision_config
153-
# if cfg["enabled"] and op_key not in cfg["logged_ops"]:
154-
# cfg["logged_ops"].add(op_key)
155-
# logger = get_precision_logger()
156-
# input_info = [get_tensor_info(a) for a in args if get_tensor_info(a)]
157-
# logger.info(f"Op: {op_key} | in: {input_info}")
158-
159-
# return fg_result
160-
# return wrapper
161-
162-
# 精度检查时允许的最大 tensor 元素数(超过则跳过,避免大 tensor 拷贝开销)
163-
_MAX_NUMEL_FOR_CHECK = 1 * 1024 * 1024 # 1M 元素
146+
147+
# Maximum tensor element count allowed for precision check (skip if exceeded to avoid large tensor copy overhead)
148+
_MAX_NUMEL_FOR_CHECK = 1 * 1024 * 1024 # 1M elements
164149

165150

166151
def _get_dtype_tolerance(args, default_rtol, default_atol):
167-
"""根据输入 tensor 的 dtype 自动调整容差"""
152+
"""Automatically adjust tolerance based on the dtype of input tensors"""
168153
for a in args:
169154
if isinstance(a, torch.Tensor) and a.is_floating_point():
170155
if a.dtype in (torch.bfloat16, torch.float16):
@@ -174,7 +159,7 @@ def _get_dtype_tolerance(args, default_rtol, default_atol):
174159

175160

176161
def _to_cpu(x):
177-
"""递归地将 tensor 移到 CPU"""
162+
"""Recursively move tensors to CPU"""
178163
if isinstance(x, torch.Tensor):
179164
return x.detach().cpu()
180165
elif isinstance(x, (list, tuple)):
@@ -185,7 +170,7 @@ def _to_cpu(x):
185170

186171

187172
def _max_tensor_numel(args):
188-
"""返回参数中最大 tensor 的元素数"""
173+
"""Return the element count of the largest tensor in the arguments"""
189174
max_n = 0
190175
for a in args:
191176
if isinstance(a, torch.Tensor):
@@ -194,65 +179,88 @@ def _max_tensor_numel(args):
194179

195180

196181
def _wrap_op_with_precision_check(op_key, fn):
197-
"""包装 FlagGems 算子,在执行后与 PyTorch 原生 CPU 实现做精度对比。
182+
"""Wrap a FlagGems operator to compare its output against the native PyTorch CPU implementation after execution.
198183
199-
由于 FlagGems 替换了 CUDA dispatch,无法在 GPU 上调用原生实现,
200-
因此将输入拷贝到 CPU 计算参考结果。通过以下方式控制性能开销:
201-
- max_checks: 每个算子只检查前 N 次调用(默认 10)
202-
- 跳过大 tensor(超过 1M 元素)
203-
- 一旦记录过失败就不再检查该算子
184+
Since FlagGems replaces the CUDA dispatch, the native implementation cannot be called on GPU,
185+
so inputs are copied to CPU to compute the reference result. Performance overhead is controlled by:
186+
- max_checks: only check the first N calls per operator (default 10)
187+
- skip large tensors (over 1M elements)
188+
- once a failure is logged, that operator is no longer checked
204189
"""
205190
_call_count = 0
206191

207192
@functools.wraps(fn)
208193
def wrapper(*args, **kwargs):
209194
nonlocal _call_count
210195

211-
# 先执行 FlagGems 实现
196+
# Execute the FlagGems implementation first
212197
fg_result = fn(*args, **kwargs)
213198

214199
cfg = precision_config
215200
if not cfg["enabled"]:
216201
return fg_result
217202

218-
# 已经记录过失败的算子不再检查
203+
# Skip operators that have already logged a failure
219204
if op_key in cfg["logged_ops"]:
220205
return fg_result
221206

222-
# 采样:每个算子只检查前 N 次调用
207+
# Sampling: only check the first N calls per operator
223208
_call_count += 1
224209
if _call_count > cfg.get("max_checks", 10):
225210
return fg_result
226211

227-
op_name = op_key.split("::")[-1].split(".")[0] if "::" in op_key else op_key.split(".")[0]
212+
op_name = (
213+
op_key.split("::")[-1].split(".")[0]
214+
if "::" in op_key
215+
else op_key.split(".")[0]
216+
)
228217

229-
# 跳过 out variant(参数签名不同,CPU 调用容易出错)
218+
# Skip out variants (different argument signatures, prone to errors when calling on CPU)
230219
overload_part = op_key.split(".")[-1] if "." in op_key else ""
231220
if overload_part == "out" or op_name.endswith("_out"):
232221
return fg_result
233222

234-
# 跳过不需要检查的算子
223+
# Skip operators that do not need checking
235224
skip_ops = {
236-
# 纯 layout / 内存操作
237-
'copy_', '_to_copy', 'view', 'reshape', 'expand', 'permute',
238-
'transpose', 'contiguous', 'clone', 'to', 'empty', 'zeros',
239-
'ones', 'full', 'masked_fill_',
240-
# 随机采样算子(GPU/CPU 随机数生成器不同,结果必然不一致)
241-
'exponential_', 'normal_', 'uniform_', 'bernoulli_', 'random_',
242-
'multinomial', 'randperm',
243-
# 排序/选择算子(相同值的排序顺序可能不同,不适合逐元素比较)
244-
'sort', 'topk', 'argsort',
225+
# Pure layout / memory operations
226+
"copy_",
227+
"_to_copy",
228+
"view",
229+
"reshape",
230+
"expand",
231+
"permute",
232+
"transpose",
233+
"contiguous",
234+
"clone",
235+
"to",
236+
"empty",
237+
"zeros",
238+
"ones",
239+
"full",
240+
"masked_fill_",
241+
# Random sampling operators (GPU/CPU RNGs differ, results will inevitably mismatch)
242+
"exponential_",
243+
"normal_",
244+
"uniform_",
245+
"bernoulli_",
246+
"random_",
247+
"multinomial",
248+
"randperm",
249+
# Sorting/selection operators (order of equal values may differ, not suitable for element-wise comparison)
250+
"sort",
251+
"topk",
252+
"argsort",
245253
}
246254
if op_name in skip_ops:
247255
return fg_result
248256

249-
# 跳过大 tensor,避免拷贝开销
257+
# Skip large tensors to avoid copy overhead
250258
if _max_tensor_numel(args) > _MAX_NUMEL_FOR_CHECK:
251259
return fg_result
252260

253261
try:
254-
# 解析 op_key 获取正确的 overload
255-
# op_key 形如 "add.Tensor", "mm.default", "softmax.int"
262+
# Parse op_key to get the correct overload
263+
# op_key is in the form "add.Tensor", "mm.default", "softmax.int", etc.
256264
parts = op_key.split(".")
257265
base_name = parts[0]
258266
overload_name = parts[1] if len(parts) > 1 else "default"
@@ -264,17 +272,17 @@ def wrapper(*args, **kwargs):
264272
if aten_overload is None:
265273
return fg_result
266274

267-
# 将输入拷贝到 CPU,调用原生 aten 实现(CPU 上不受 FlagGems 影响)
275+
# Copy inputs to CPU and call the native aten implementation (unaffected by FlagGems on CPU)
268276
cpu_args = [_to_cpu(a) for a in args]
269277
cpu_kwargs = {k: _to_cpu(v) for k, v in kwargs.items()}
270278

271279
with torch.no_grad():
272280
pt_result_cpu = aten_overload(*cpu_args, **cpu_kwargs)
273281

274-
# FlagGems 结果也拷贝到 CPU 做比较(避免把 CPU 结果搬回 GPU
282+
# Also copy FlagGems result to CPU for comparison (avoid moving CPU result back to GPU)
275283
fg_result_cpu = _to_cpu(fg_result)
276284

277-
# 根据 dtype 自动调整容差
285+
# Automatically adjust tolerance based on dtype
278286
rtol, atol = _get_dtype_tolerance(args, cfg["rtol"], cfg["atol"])
279287

280288
is_close, info = compare_outputs(fg_result_cpu, pt_result_cpu, rtol, atol)
@@ -300,6 +308,7 @@ def wrapper(*args, **kwargs):
300308

301309
return wrapper
302310

311+
303312
class PrecisionCheckRegister(Register):
304313
def register_impl(self, key, fn):
305314
if self.lib is None:

0 commit comments

Comments
 (0)