没有 TPU,也能检查 TorchTPU 上手门槛
作者检查 TorchTPU 源码,并在没有 TPU 的机器上安装约 969MB 的安装包、运行文档示例。文章结合原生 PyTorch 后端定位与合作方测试通过率,审视迁移便利性及当前成熟度。
完整中文译文
10 月 20 日,在 PyTorch Conference 2026 上,Google 开源了 TorchTPU:一个面向自家 TPU 芯片的原生 PyTorch 后端,由 Google 与 Meta 的 PyTorch 团队共同开发,定位是取代 PyTorch/XLA。它主打的是可移植性。TPU 与 GPU、CPU 一样,成为 PyTorch 的原生设备;现有代码只需“极少的代码改动”就能迁移过来——把 "cuda" 换成 "tpu",或者在 Transformers v5 中传入 device_map="tpu"。Google 公布的一项训练数据是:使用 TorchTitan,在扩展到 8,192 颗 Ironwood 芯片的配置下,Qwen 3 8B 的模型 FLOPs 利用率最高可达 52%。作为首发合作伙伴,Hugging Face 的坦诚值得肯定:他们表示“还没有全部亮绿灯”,在 TPU 上运行的测试通过率为 96.5%。
我没有 TPU。看到这份公告的人,几乎也都没有 TPU。所以,我做了自己唯一能做的实验:克隆仓库,统计里面有什么,然后在一台完全没有 TPU 的机器上安装 wheel,运行文档自带的示例。这两部分实验都有收获。
repo github.com/google-pytorch/torch_tpu (Apache-2.0)
HEAD 5ee22ae, 2026-10-21 06:50 -0700 — a commit landing the
morning after launch day; this repo is being worked in public
files 2,092 total
547 .py / 502 .cc / 422 .h
lines 244,017 Python · 217,023 C/C++/headers
tests 244 files under tests/, 197 of them test files
wheel torch-tpu 0.2.0 on PyPI (also a 0.0.0 placeholder release),
~96 MB per wheel, Python 3.11+ per README,
wheel metadata Requires-Python >=3.12, torch >=2.11, <=2.15
不管 TorchTPU 还有什么特点,它绝不是一篇附带 GitHub 链接的新闻稿。约 50 万行代码、Bazel 构建系统、三种 eager 执行模式(Strict、Debug、DeferAndFuse)、三级编译缓存,以及 csrc/ops/ 下的 194 个目录——这是一个实打实的后端。
宣传中最醒目的覆盖范围说法是:“450 个核心 ATen 算子(同时支持前向和反向传播)”,并且据文档介绍,会持续在 5,000 个 Hugging Face 模型上进行验证。我试着从源码中核实 450 这个数字。找到的是 csrc/ops/op_names.h,其中的 OpName 枚举列出了 851 个算子变体。去掉 Out/Backward 后缀后,仍有约 690 个名称,因为重载形式(.dim、tensor 与 scalar 版本)是分别计数的。因此,“450”完全取决于 Google 如何把这些变体归并成“核心算子”——这个数字说得通,但仅凭仓库无法独立核实。严谨的说法应该是:已实现的接口范围包含数百个、接近上千个算子变体,而你引用的任何单一数字,都取决于采用的计数口径。
如果去看测试数据,还会发现这个仓库对自身的缺口也很坦诚。tests/native_functions_data.py 中有一份列表,维护者将其标记为临时列表,并表示它“应该被清空”:
UNREGISTERED_OPS in tests/native_functions_data.py : 365 entries
# "Ops that are missing a required C++ registration... this is a
# temporary list that should be emptied, either by adding a C++
# registration for the op, or by adjusting the logic in
# native_functions_test.py"
公平地说,按照这项测试的判断逻辑,这 365 个算子缺少 C++ 注册——其中不少是内部算子、处理 sparse/coalesced 的辅助算子,或者由算子分解和 fallback 路径处理的算子。这是一份 TODO 清单,不是失败计数。但它能有效纠正一种理解:不能把“450 个核心算子”读成“一切都能正常工作”。首发时的 TorchTPU 已经覆盖了很大的范围,但也明确尚未完成,而维护者把未完成的部分留在代码树里,让你可以自己统计。更多项目应该把这些限制以数据的形式一起交付。
没有 TPU 的实验
pip install torch_tpu==0.2.0 --extra-index-url https://download.pytorch.org/whl/cpu
第一次尝试以 No space left on device 告终——pip 会在 /tmp 中解包,而这台 VM 的 /tmp 是一个 512MB 的 tmpfs,这套软件栈所需的临时空间超过了 512MB。把 TMPDIR 指向一个有足够磁盘空间的位置后,安装在 1 分 53 秒内完成:
installed torch 2.14.1+cpu · torch_tpu 0.2.0 · numpy 2.5.4
footprint torch_tpu/ 330 MB
libtpu/ 639 MB (the PJRT runtime, a dependency)
total new native payload ≈ 969 MB before torch itself
machine 2 vCPU Linux VM, Python 3.12, no TPU (obviously)
接着执行导入,以及文档中的四行示例:
import torch
import torch_tpu
device = torch.device("tpu")
x = torch.randn((4, 4), device=device)
实际发生的事情,按顺序如下:
import torch_tpu OK, but slow: 11.10s, after a PJRT log line
("GetPjrtApi was found for TPU at .../libtpu.so")
and a UserWarning that tcmalloc is not loaded
and host performance "may be degraded"
torch.tpu.is_available() RuntimeError: "is_available is internal to
TorchTPU and can only be called by the PyTorch
framework... Use torch.accelerator.is_available
instead."
torch.tpu.device_count() RuntimeError, same lecture
torch.accelerator.is_available() False
torch.accelerator.device_count() 0
torch.accelerator.current_accelerator() None
torch.randn((4,4), device="tpu")
RuntimeError: "Expected one of cpu, cuda, ipu,
xpu, mkldnn, opengl, opencl, ideep, hip, ve,
fpga, maia, xla, lazy, vulkan, mps, meta, hpu,
mtia, privateuseone device type at start of
device string: tpu"
其中两项结果确实体现了不错的设计。通过现代的 torch.accelerator API,缺少硬件时的降级处理很干净——返回 False、0、None,没有崩溃,也没有因为寻找不存在的硬件而卡住。而 torch.tpu.* 抛出 RuntimeError,是 TorchTPU 有意阻止用户代码调用框架内部钩子,并告诉你正确的 API 写法。这比悄悄返回错误结果要好。
第三项结果,则给整场发布加上了一条脚注。README 示例在检测硬件之前就失败了——卡在设备字符串解析这一步。在这个构建版本上(torch 2.14.1+cpu,符合 wheel 自己声明的 torch>=2.11, <=2.15 范围),PyTorch 的解析器根本不认识 "tpu" 这种设备类型。底层的 TorchTPU 是一个 PrivateUse1 后端——这就是它的集成机制,错误信息中列出的 privateuseone 就是线索。在真正的 TPU VM 上,使用 Google 测试过的那套确切软件栈,想必这个名称能够正确解析,示例也能运行;但我无法在这里验证,也不会假装验证过。我能说的是,“只改一个词”的说法,成立的关键在于软件栈必须完全匹配——从习惯性地写下 device="cuda",到真正用上 device="tpu",中间隔着 969MB 的原生二进制文件、11 秒的导入时间、一个换了名称的可用性查询 API,以及一个会被常规 CPU 构建中默认解析器直接拒绝的设备名称。
这些都不意味着 TorchTPU 是空头产品——恰恰相反。这个仓库内容扎实,提交活跃(发布后的第二天早上,HEAD 就有了更新),对尚未完成的算子清单也很坦诚,而且在没有硬件时,多数失败方式都处理得相当友好。如果 52% MFU 这个数字能经得住独立复现,CUDA 护城河的故事很快就会变得有意思,因为切换成本确实可能降到接近修改一个设备字符串的程度。
但“极少的代码改动”描述的是:在 TPU VM 上运行 Google 测试过的配置,而公告的大多数读者并没有这样的环境。四行 README 示例,与我在普通硬件上运行它时出现的四种不同情况之间的差距,正是采用过程中阻力所在——而且这些阻力可以测量,所以我测了。等到有 Ironwood 使用权限的人公布 tokens/sec 和 MFU,我才会相信性能这半边故事。在那之前,可移植性这半边故事是:代码是真的,限制也是真的,而且都公开交付了——包括那些限制,这恰恰是我欣赏的部分。
来源:Google Cloud 博客公告,以及 google-pytorch/torch_tpu 仓库(README、docs/intro_to_torchtpu.md、csrc/ops/op_names.h、tests/native_functions_data.py——所有统计均由我基于 HEAD 5ee22ae 完成);torch-tpu 和 libtpu 的 PyPI 项目页面;MarkTechPost 在 10 月 20 日发布的首发综述,其中提供了 52% MFU,以及 11.49s 对比 2.78s 的微调数据(均由 Google 报告);madrobot.blog 在 10 月 20 日引用的 Hugging Face 表述:“还没有全部亮绿灯”,以及 96.5% 的数据。安装、导入和设备探测的输出均来自我自己的运行结果,按原样引用;我没有可用的 TPU,本文也没有测量任何 TPU 性能。
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。