Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

[ET-VK] fp16 linear on an RDNA3.5 iGPU: default (texture) export runs at ~1.1 TFLOP/s, coopmat unreachable without buffer storage, and the stock buffer path is ~20x less accurate

未关闭
#24,196 0 条评论 0 个 reaction 已指派 1 人 在 GitHub 查看

维护者通常 1 天内回复

@SS-JIA 已经在做这个了。

开始于 2026年10月29日。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
42/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
cpp, python, pytorch

调研方向

Start with gemm/GemmCommon.h and is_coopmat_eligible(), then trace how VulkanPartitioner chooses texture or buffer storage for linear outputs. Reproduce the reported measurements with the provided export and check scripts on an RDNA3.5 Vulkan GPU. Done means the default export reaches an appropriate accurate kernel, with measurements confirming both performance and relative error.

由索引模型根据 Issue 内容生成。

描述

module: vulkan rfc
Summary

On an RDNA3.5 integrated GPU (Radeon 880M/890M, gfx1150, RADV), an fp16 nn.Linear lowered to the Vulkan backend shows three issues at main (4db778e):

  1. The default export uses texture storage and runs at about 1.1 TFLOP/s. A standalone fp16 cooperative-matrix GEMM with fp32 accumulation runs at 7.4 TFLOP/s on the same GPU at the same shape, so the default path reaches about 15% of that.
  2. The cooperative-matrix path is unreachable from a default export. is_coopmat_eligible() requires storage_type_of(out) == kBuffer, and the default export produces texture-backed outputs. Lifting the integrated-GPU gate (#22665, #22899) therefore changes nothing for a default-exported model: the timings with the gate removed are identical to stock.
  3. Forcing buffer storage is faster, but on stock builds it is about 20× less accurate. The error is 1.6e-2 relative, against 7.5e-4 for the texture path. With the integrated-GPU gate removed, the same buffer model runs on the coopmat kernel at 0.73 ms (2.9 TFLOP/s) with 3.8e-4 relative error, so the loss of accuracy comes from the non-coopmat buffer kernel. My guess is fp16 accumulation, but I have not checked the shader.

Taken together: a user who exports normally gets the slow path, and a user who forces buffers to get the fast path gets 20× more error unless the GPU also passes the coopmat gate.

Results

Model: fp16, input 256×2048, Linear(2048, 2048). "one" is a single bias-free layer; "two" is Linear, ReLU, Linear with bias. "Buffer" means VulkanPartitioner({"texture_limits": (1, 1, 1)}). "Gate removed" means main with only !adapter->is_integrated_gpu() && deleted from gemm/GemmCommon.h.

The time is per inference: (wall time of 401 executions − wall time of 1 execution) / 400, in one executor_runner process each, taken twice. The error is max|out − ref| / max|ref|, where ref is the same fp16 weights and input computed in fp32 by eager PyTorch.

model storage stock main: ms TFLOP/s rel. error gate removed: ms TFLOP/s rel. error
one default (texture) 1.95 / 1.97 1.10 7.48e-4 2.01 / 1.97 1.08 7.48e-4
one buffer 1.39 / 1.41 1.53 1.62e-2 0.78 / 0.73 2.86 3.79e-4
two default (texture) 3.77 / 3.86 1.13 1.22e-3 3.73 / 3.62 1.17 1.22e-3
two buffer 2.52 / 2.46 1.72 1.21e-2 1.26 / 1.22 3.47 4.14e-4

For reference, a standalone fp16 × fp16 → fp32 VK_KHR_cooperative_matrix GEMM at M=256, N=K=2048 on the same GPU takes 0.29 ms per dispatch, about 7.4 TFLOP/s.

The same eight measurements at the older commit b20f16a gave the same numbers within noise.

Questions
  • Should a linear or matmul whose shape is coopmat-eligible get buffer-backed output at export time, so that the coopmat kernel is reachable without the user knowing about texture_limits?
  • Is the error in the buffer tiled kernel expected, for example because it accumulates in fp16? If it is, fp32 accumulation would bring it in line with the texture path.
Repro
# export.py - writes one_default.pte, one_buffer.pte, two_default.pte, two_buffer.pte
import torch
from executorch.exir import to_edge
from executorch.backends.vulkan.partitioner.vulkan_partitioner import VulkanPartitioner

class Two(torch.nn.Module):
    def __init__(s):
        super().__init__()
        s.seq = torch.nn.Sequential(torch.nn.Linear(2048, 2048), torch.nn.ReLU(), torch.nn.Linear(2048, 2048))
    def forward(s, x): return s.seq(x)

class One(torch.nn.Module):
    def __init__(s):
        super().__init__(); s.l = torch.nn.Linear(2048, 2048, bias=False)
    def forward(s, x): return s.l(x)

torch.manual_seed(0)
x = torch.randn(256, 2048).half()
for name, m in (("two", Two()), ("one", One())):
    m = m.eval().half()
    for tag, opts in (("default", {}), ("buffer", {"texture_limits": (1, 1, 1)})):
        ep = torch.export.export(m, (x,), strict=False)
        prog = to_edge(ep).to_backend(VulkanPartitioner(opts)).to_executorch()
        open(f"{name}_{tag}.pte", "wb").write(prog.buffer)
# check.py <one|two> <default|buffer> - accuracy against eager fp32 on the same weights
import sys, torch
from executorch.runtime import Runtime
# (same Two / One classes as above)
torch.manual_seed(0)
x = torch.randn(256, 2048).half()
models = {"two": Two().eval().half(), "one": One().eval().half()}   # same construction order as export.py
name, tag = sys.argv[1], sys.argv[2]
prog = Runtime.get().load_program(open(f"{name}_{tag}.pte", "rb").read())
meth = prog.load_method("forward")
out = meth.execute([x])[0].float()
ref = models[name].float()(x.float())
print(f"{name}_{tag}: {((out - ref).abs().max() / ref.abs().max()):.2e}")

Timing: executor_runner --model_path <pte> --num_executions {1,401}, wall-clocked as described above.

Environment
  • ExecuTorch: main at 4db778ea79b4c34777a9da94dd4d3c9627aef9be (1.6.0+4db778e), built from source with EXECUTORCH_BUILD_VULKAN=ON.
  • torch / torchao: torch 2.14.0+cpu; torchao 0.19.0.dev20260907 (nightly, the version main requires).
  • GPU: AMD Ryzen AI 9 365, Radeon 880M (reported as "AMD Radeon 890M Graphics (RADV GFX1150)"), subgroup size 64, VK_KHR_cooperative_matrix supported.
  • Driver: Mesa 25.2.8-0ubuntu0.24.04.4 (RADV), Vulkan API 1.4.318.
  • OS: Linux 7.0.0-38-generic, Ubuntu.

Related: #22665 (the integrated-GPU coopmat gate) and #22899 (supports_fp16_cooperative_matrix). cc @SS-JIA @manuelcandales @digantdesai @cbilgin

主要语言
Python
星标
5.1k
派生
1.2k
平均合并
1 天 21 小时
30 天内合并 PR
695

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

pytorch/executorch 的其他 Issue

查看 pytorch/executorch 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。