Prhub

#25911 Purge usage of pytorch named tensors

原始 PR 作者 jbschlosser 合并时间 2026-05-27 05:58 文件变更 17 提交数 2 评论 9 代码增减 +247 / -159

执行摘要

移除 PyTorch named tensors 依赖,避免向上兼容风险

PyTorch将在未来版本中移除named tensors特性(参见PyTorch #173895)。为了避免SGLang仓库因此中断,PR清除了所有该特性的使用。作者强调使用仅局限于调试工具和关联测试,风险极低。

建议阅读核心文件 tensor_naming.py 的变更,理解如何用私有属性模拟命名语义。该模式可推广到其他需要绕过废弃 API 的场景。同时也值得查看 review 讨论中关于原地修改与非连续张量的设计权衡。

讨论亮点
  • Qiaolin-Yu 指出新实现 apply_dim_names 直接修改 tensor,而原 refine_names 返回新视图。作者回应改为创建别名以保持原语义。
  • Qiaolin-Yu 询问对非连续 tensor 是否有问题。作者回应使用 torch.ops.aten.alias 保留 contiguity 和 strides,并改进了代码。

实现拆解

  1. tensor_naming.py 中定义了三个辅助函数:get_dim_names(读取)、apply_dim_names(赋予)和 without_dim_names(移除),将维度名称存储为张量的 _dim_names 私有属性。
  2. 在涉及维度名称操作的多个 executor 文件(如 unsharder/executor.pytoken_aligner/smart/executor.pyreorderer/executor.pybundle_comparator.py 等)中,将 tensor.names 替换为 get_dim_names,将 tensor.refine_names() 替换为 apply_dim_names,将 tensor.rename(None) 替换为 without_dim_names
  3. 同步更新了关联的测试文件,确保断言中张量比较时调用 without_dim_names 来消除维度名称影响。
  4. 根据 review 意见,将 apply_dim_names 从直接修改输入张量改为通过 torch.ops.aten.alias 创建别名后修改,保持非原地语义;同时使用 alias 确保非连续张量的兼容性。
文件 模块 状态 重要度
python/sglang/srt/debug_utils/comparator/dims_spec/tensor_naming.py 张量命名 modified 7.0
python/sglang/srt/debug_utils/comparator/aligner/unsharder/executor.py 去分片 modified 6.5
python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/executor.py 令牌对齐 modified 6.04
python/sglang/srt/debug_utils/comparator/bundle_comparator.py 束比较 modified 5.94
test/registered/debug_utils/comparator/aligner/unsharder/test_executor.py 测试 modified 5.54

关键符号

get_dim_names apply_dim_names without_dim_names resolve_dim_by_name

关键源码片段

python/sglang/srt/debug_utils/comparator/dims_spec/tensor_naming.py core-logic

定义核心辅助函数 get_dim_names、apply_dim_names、without_dim_names,是整个 PR 的变更基础。

from __future__ import annotations
from typing import Optional
import torch_DIM_NAMES_ATTR = "_dim_names" # 私有属性名称,用于存储维度名称def get_dim_names(tensor: torch.Tensor) -> tuple[Optional[str], ...]:
    """获取张量的维度名称。如果未设置名称,则返回全 None 的元组。"""
    names = getattr(tensor, _DIM_NAMES_ATTR, None)
    if names is not None:
        return names
    return (None,) * tensor.ndimdef apply_dim_names(tensor: torch.Tensor, dim_names: list[str]) -> torch.Tensor:
    """为张量设置维度名称。返回一个带有名称的新视图,不修改原张量。"""
    if tensor.ndim != len(dim_names):
        raise ValueError(
            f"dims metadata mismatch: tensor has {tensor.ndim} dims (shape {list(tensor.shape)}) "
            f"but dims string specifies {len(dim_names)} names {dim_names}. "
            f"Please fix the dims string in the dumper.dump() call to match the actual tensor shape."
        )
    view = torch.ops.aten.alias(tensor) # 创建别名,保留 contiguity 和 strides
    view._dim_names = tuple(dim_names) # 在别名上设置私有属性
    return viewdef without_dim_names(tensor: torch.Tensor) -> torch.Tensor:
    """返回一个没有维度名称的新视图。"""
    return torch.ops.aten.alias(tensor) # 别名不会继承 _dim_names
python/sglang/srt/debug_utils/comparator/aligner/unsharder/executor.py core-logic

在核心 unshard 逻辑中全面替换 named tensor 操作为新辅助函数,体现 PR 的主要调用模式。

def _apply_unshard(
    params: UnsharderParams,
    ordered_tensors: list[torch.Tensor],
    *,
    axis: ParallelAxis,
    group_index: int,
) -> tuple[torch.Tensor, list[ReplicatedCheckResult]]:
    if isinstance(params, PickParams):
        checks = _verify_replicated_group(ordered_tensors, axis=axis, group_index=group_index)
        return ordered_tensors[0], checks
​
    if isinstance(params, ConcatParams):
        dim: int = resolve_dim_by_name(ordered_tensors[0], params.dim_name)
        names = get_dim_names(ordered_tensors[0]) # 获取原始维度名称
        result = torch.cat(ordered_tensors, dim=dim)
        if names[0] is not None:
            result = apply_dim_names(result, list(names)) # 保留名称
        return result, []
​
    if isinstance(params, ReduceSumParams):
        names = get_dim_names(ordered_tensors[0])
        stripped = [without_dim_names(t) for t in ordered_tensors] # 移除名称后再 stack/sum
        result = torch.stack(stripped).sum(dim=0)
        if names[0] is not None:
            result = apply_dim_names(result, list(names))
        return result, []
    # ...

评论区精华

apply_dim_names 原地修改 vs 新视图 设计

Qiaolin-Yu 指出新实现直接修改 tensor 的 _dim_names 属性,而原 refine_names() 返回新视图不修改原张量。

结论:作者通过创建别名 (torch.ops.aten.alias) 并在别名上设置属性,保持非原地语义。 · 已解决

非连续张量兼容性 正确性

Qiaolin-Yu 询问使用 alias 是否对非连续张量有副作用。

结论:作者使用 torch.ops.aten.alias 保留原张量的 contiguity 和 strides,确认无问题。 · 已解决

风险与影响

主要风险在于调试工具(debug_utils/comparator)的维度名称传递可能出现遗漏或错误,导致张量对齐或比较失败。但由于所有变更均基于简单的 API 替换,且测试覆盖充分,风险可控。此外,使用私有属性 _dim_names 需要确保在张量别名传播时不丢失,torch.ops.aten.alias 能正确共享数据但不会自动传播属性,因此 without_dim_names 通过不设置 _dim_names 来模拟无名称状态,语义正确。

直接影响是清理了废弃 API,保证未来 PyTorch 升级时不会因 named tensors 移除而出错。受影响范围限定在 debug_utils/comparator 模块及其测试,不影响核心推理或训练路径。对于使用调试工具的开发人员,行为保持透明。

依赖私有属性 调试工具范围 PyTorch 升级兼容

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论