跳到主内容
@wquguru
精选88PyTorch 博客(RSS)技巧与观点

PyTorch发布TinyTorch:从零手写ML框架的开源课程

TinyTorch: Don’t Just Import PyTorch. Build It.

原文
发到 X
推荐理由

想彻底搞懂PyTorch底层原理的同学必看,这个项目让你亲手写一遍Autograd和Attention,比读源码直观得多,直接去tinytorch.ai开始动手。

A framework you write yourself, tensors through transformers

一个你自己写的框架,从张量到 Transformer

TL;DR

TL;DR(太长不看)

Every mature systems project eventually needs a teaching version. TinyTorch is a free, open-source curriculum where you build a working ML framework from scratch, tensors through transformers, in pure Python, using PyTorch’s own API. Twenty modules. Runs on a laptop with 4 GB of RAM and no GPU. It is at tinytorch.ai.

每个成熟的系统项目最终都需要一个教学版本。TinyTorch 是一个免费、开源的课程体系,你可以在纯 Python 中,使用 PyTorch 自己的 API,从零开始构建一个可用的机器学习框架,涵盖从张量到 Transformer 的内容。共二十个模块。只需一台配备 4 GB 内存且无 GPU 的笔记本电脑即可运行。网址为 tinytorch.ai。

The rest of this post is why we think it needed to exist, and what six years of running it taught us that might be useful to anyone else doing open curriculum work.

本文其余部分将阐述我们认为它为何有必要存在,以及我们运营该项目六年所获得的、可能对其他从事开源课程工作的人有用的经验。

Every Systems Field Eventually Builds Its Teaching Version

每个系统领域最终都会构建其教学版本

Unix got too big to hold in your head, so Andrew Tanenbaum wrote MINIX. Small enough that a student could actually finish it. It went on to shape a generation of systems engineers and famously inspired Linux.

Unix 变得太大,难以在脑海中完整把握,因此 Andrew Tanenbaum 编写了 MINIX。它足够小巧,学生实际上能够完成整个项目。MINIX 进而塑造了一代系统工程师,并著名地启发了 Linux 的开发。

Compilers went the same way. LLVM and GCC are decades of excellent engineering and close to unreadable as a first text, so courses teach the Tiger compiler instead. MIT rewrote xv6 from x86 to RISC-V for the same reason, stripping out historical complexity to expose clean abstractions. Before all of them, Nachos and Pintos and SICP.

编译器领域也经历了同样的过程。LLVM 和 GCC 是数十年优秀工程的结晶,作为入门教材几乎难以阅读,因此课程转而教授 Tiger 编译器。MIT 出于相同原因,将 xv6 从 x86 重写为 RISC-V,剥离历史复杂性以暴露清晰的抽象概念。在此之前,还有 Nachos、Pintos 和 SICP。

None of these were trying to replace the production system. They taught what production systems have to hide.

这些项目都无意取代生产级系统。它们教授的是生产系统必须隐藏的内容。

PyTorch is at that point now, which is a compliment. There is genuinely good writing on its internals, most of it by the people who wrote them, and nearly all of it assumes you already think like a framework engineer. What has been missing is the rung below that. Something you build yourself, with grading infrastructure a university can actually adopt for credit, that a self-learner can get through without a GPU budget.

PyTorch 现在正处于这个阶段,这本身就是一种赞誉。关于其内部机制确实有优秀的文献,大多由编写者本人撰写,但几乎所有内容都假设你已经具备框架工程师的思维。缺失的是更低一级的阶梯。你需要自己动手构建它,拥有大学真正可用于计入学分的评分基础设施,并且自学者无需 GPU 预算也能顺利完成。

Why This Matters to PyTorch, Not Only to Students

这对 PyTorch 很重要,而不仅仅对学生重要

There is a version of this argument that only educators care about. This is not that version.

有一种观点只有教育工作者才会关心。但这并非那种观点。

Every framework runs on a small population of people who can reason about it from the inside. The ones who spot a memory leak in tensor caching, who know when gradient checkpointing is worth the recompute, who can look at a slow training run and name the bottleneck before they open a profiler.

每个框架都依赖于少数能够从内部理解它的人群。这些人能发现张量缓存中的内存泄漏,知道何时值得进行梯度检查点重计算,能在打开性能分析器之前,仅凭一次缓慢的训练运行就能指出瓶颈所在。

That population does not grow by itself. Right now most people get to PyTorch’s internals by accident, because something broke badly enough to force the trip. They learn the codebase under deadline pressure, from the outside in, in whatever order the bug happened to demand. Anyone who has onboarded a systems engineer knows the result, which is competence with holes in it.

这个群体不会自然增长。目前,大多数人是因为某些问题严重到迫使他们深入排查,才偶然接触到 PyTorch 的内部机制。他们在截止日期压力下,从外向内学习代码库,按照 bug 恰好要求出现的顺序进行学习。任何有过招聘系统工程师经验的人都清楚结果如何:那就是能力存在缺陷的胜任力。

Building the thing yourself changes the arrival path, and it changes it permanently. Once you have implemented autograd you cannot unsee the computational graph. Once you have profiled your own memory allocation you cannot unknow the cost.

自己动手构建这些内容会改变你的认知路径,并且这种改变是永久性的。一旦你实现了自动微分(autograd),你就再也无法忽视计算图的存在。一旦你剖析过自己的内存分配机制,你就再也无法无视其中的成本。

Figure 1: The same linear layer, two ways. On the left, the framework call that works right up until it does not. On the right, the version you wrote and can open when something breaks. The difference is not syntax, it is whether the abstraction is a wall or a door.

图 1:同一个线性层,两种实现方式。左侧是框架提供的调用接口,它在正常运行时毫无问题,直到出现故障为止;右侧是你自己编写的版本,当出现问题时可以随时打开查看。两者的区别不在于语法,而在于抽象是一堵墙还是一扇门。

A student who has written backward() themselves, who allocated the momentum and variance buffers and watched Adam’s memory footprint triple, shows up to PyTorch’s real autograd with the mental model already loaded. They read the production code as a more sophisticated version of something they understand. That is a cheaper engineer to onboard.

一个亲手编写过 backward()、分配过动量和方差缓冲区并目睹 Adam 内存占用翻了三倍的学生,带着已经内化的心智模型来到 PyTorch 真正的自动微分机制面前。他们将生产代码视为自己所理解事物的更复杂版本。这意味着他们更容易上手,企业培养他们的成本更低。

The part we did not anticipate is that companies want this too. Teams have used TinyTorch for new-hire onboarding as a two to three week intensive, as internal training spread across a quarter, and as targeted debugging workshops where somebody works through Module 06 on autograd or Module 12 on attention because that is the subsystem they keep losing to. You do not have to be enrolled anywhere.

我们没有预料到的是,公司也渴望获得这种体验。团队将 TinyTorch 用作新员工入职培训,形式包括为期两到三周的强化训练、贯穿一个季度的内部培训,以及针对特定问题的调试工作坊——例如让某人深入钻研关于自动微分的第 06 模块或关于注意力机制的第 12 模块,因为这些子系统正是他们经常出错的领域。你不需要在任何地方注册报名。

What We Built

我们构建了什么

Twenty modules in four tiers, driven by a CLI called tito, delivered as Jupyter notebooks with the hard parts cut out for you to fill in. You need Python and to be comfortable with NumPy. You do not need a GPU, a cloud account, or any prior ML systems background.

共二十个模块,分为四个层级,通过名为 tito 的命令行工具交付,以 Jupyter Notebook 的形式呈现,其中最难的部分已被移除,留给你自行填充。你需要具备 Python 基础,并熟悉 NumPy。你不需要 GPU、云账户或任何先前的机器学习系统背景知识。

Figure 2: The four tiers. Each one depends on the tier below it, so you cannot skip ahead to optimization without having built the training loop you are optimizing. Foundation fits a half-semester module, all twenty fit a four-credit course, and self-paced learners take anywhere from a few intense weeks to several unhurried months.

图 2:四个层级。每个层级都依赖于其下方的层级,因此你不能跳过正在优化的训练循环而直接跳到优化部分。基础层级相当于半学期的课程模块,全部二十个模块构成一门四学分的课程,自定进度的学习者可能需要几周的高强度时间,也可能需要几个月的从容时间。

Three design decisions do most of the pedagogical work.

有三项设计决策承担了主要的教学功能。

Systems from day one. Module 01 ships a memory_footprint() method before it ships matrix multiplication. You learn that one batch of 32 ImageNet images costs 19 MB by computing it, not by reading it somewhere. Later you find out Adam needs roughly 3× the optimizer memory of SGD, because you allocated those buffers yourself and then measured them.

从第一天起就关注系统层面。在第 01 模块中,我们在实现矩阵乘法之前就先提供了一个 memory_footprint() 方法。你是通过实际计算得知一批 32 张 ImageNet 图像消耗 19 MB 内存,而不是通过阅读某处文档得知。后来你发现 Adam 所需的优化器内存大约是 SGD 的 3 倍,因为你自己分配了这些缓冲区并进行了测量。

Progressive disclosure. The Tensor class stays clean through Module 05, with no gradient machinery cluttering up data layout and arithmetic. Then in Module 06 you implement enable_autograd(), which bolts requires_grad, .grad, and .backward() onto the class you already understand. Your old code keeps working.

渐进式披露。Tensor 类在 Module 05 之前保持简洁,数据布局和算术运算中没有任何梯度机制的干扰。然后在 Module 06 中,你实现 enable_autograd(),将 requires_grad、.grad 和 .backward() 附加到你已经理解的类上。你之前的代码仍能正常工作。

We went back and forth on this one. The tasteful way to do it is inheritance. What we shipped is runtime monkey-patching, which is going to offend somebody reading this. It won because it keeps one Tensor class across all twenty modules instead of two, and because the moment your tensors visibly grow new powers turns out to be the thing students remember. It also happens to mirror PyTorch 0.4, which merged Variable into Tensor for roughly the same reason.

我们对此反复斟酌。优雅的做法是继承。但我们最终采用的是运行时猴子补丁(monkey-patching),这可能会让阅读此文的读者感到不适。之所以选择它,是因为它在所有二十个模块中只保留一个 Tensor 类,而不是两个;而且当你的张量明显获得新功能的那一刻,恰恰是学生最难忘的部分。这也恰好与 PyTorch 0.4 的做法相呼应,后者出于大致相同的原因将 Variable 合并到了 Tensor 中。

Figure 3: The gradient of matrix multiplication, as a learner meets it in Module 06. The docstring gives you the mathematical rule and the numbered approach breaks it into steps, but the implementation is yours. All twenty modules look like this.

图 3:矩阵乘法的梯度,作为学习者在 Module 06 中遇到的内容。文档字符串提供了数学规则,编号方法将其分解为步骤,但实现由你完成。所有二十个模块都是这样的结构。

Build to validate. Six historical milestones prove your implementation works. Rosenblatt’s Perceptron in 1958, the XOR crisis in 1969, the backpropagation revival in 1986, the CNN breakthrough in 1998 where your network has to clear 75% on CIFAR-10, the transformer in 2017, and finally MLPerf-style benchmarking. The history is there for motivation. The task performance is there because it is a much harder thing to fake than a unit test. Your autograd is correct because your network learns.

构建以验证。六个历史里程碑证明你的实现是正确的。1958 年的 Rosenblatt 感知机、1969 年的 XOR 危机、1986 年反向传播的复兴、1998 年 CNN 突破(此时你的网络必须在 CIFAR-10 上达到 75% 的正确率)、2017 年的 Transformer,以及最后的 MLPerf 风格基准测试。历史背景用于提供动机。任务性能的存在是因为它比单元测试更难伪造。你的 autograd 是正确的,因为你的网络能够学习。

Figure 4: The milestone ladder. A milestone unlocks only when the modules beneath it produce a working implementation, so the timeline doubles as a progress tracker and a correctness proof. Students recreate 67 years of ML history running nothing but code they wrote.

图 4:里程碑阶梯。只有当下方的模块产生可工作的实现时,里程碑才会解锁,因此时间线同时充当进度跟踪器和正确性证明。学生仅通过运行自己编写的代码,重现了 67 年的机器学习历史。

Throughout, TinyTorch mirrors PyTorch’s API deliberately. The API is the transfer mechanism and it carries both ways. Somebody who builds loss.backward() here can open PyTorch’s version afterward and recognize the shape of it. A PyTorch developer can read our attention module in an afternoon and see how the graph gets constructed.

在整个过程中,TinyTorch 刻意镜像 PyTorch 的 API。API 是传输机制,且双向通用。在这里构建 loss.backward() 的人,之后可以打开 PyTorch 的版本并识别出它的结构。PyTorch 开发者可以在一个下午内阅读我们的注意力模块,了解图是如何构建的。

Figure 5: A TinyTorch training loop next to the equivalent PyTorch loop. The imports differ and almost nothing else does, which is the entire point. Nothing you learn here has to be unlearned later.

图 5:TinyTorch 训练循环与等效 PyTorch 循环并列。导入语句不同,除此之外几乎没有任何区别,这正是其核心目的。你在这里学到的任何东西,以后都不需要重新学习。

Two things it is not. The resemblance stops at the API surface, so there is no dispatcher, no C++ or CUDA layer, no JIT, nothing distributed. And it is slow. Pure Python runs somewhere between 100 and 10,000 times slower than PyTorch, which we will come back to, because it turned out to matter.

它有两点不是。相似之处仅止于 API 表面,因此没有分发器(dispatcher),没有 C++ 或 CUDA 层,没有 JIT,也没有分布式功能。而且它很慢。纯 Python 的运行速度比 PyTorch 慢 100 到 10,000 倍左右,这一点我们稍后会再讨论,因为它后来被证明很重要。

Where It Came From

它的起源

TinyTorch did not start as a framework. It started as a course with a problem.

TinyTorch 并非作为一个框架起步的。它是从一个带有问题的课程开始的。

CS 249r launched at Harvard in 2020, a graduate seminar on TinyML, and there was no textbook to assign. So the course notes became one. We put the book up as an open repository, students and educators started fixing examples and proposing chapters, and by 2024 it had outgrown its TinyML origins because people kept asking about training at scale. It split into two volumes.

CS 249r 于 2020 年在哈佛开设,是一门关于 TinyML 的研究生研讨课,当时没有可指定的教科书。于是课程笔记就成了书。我们将这本书作为开放仓库发布,学生和教师开始修复示例并提出章节建议,到了 2024 年,由于人们不断询问大规模训练的问题,它已经超出了其 TinyML 的起源范围。它分成了两卷。

更进一步:量化金融体系

看懂新闻只是起点——沿量化金融路径,把它变成能交付的工程能力

进入量化体系 →

相似阅读

关联信息,但可能不是同一事件