这个标题ai-engineering-from-scratch我盯了很久,最近在整理自己过去两年的工程笔记时,又把它翻出来重读了一遍。如果你也在找一条真正“从零开始”进入 AI 工程的路,而不是被各种现成框架和模型 API 包着走、遇到问题就抓瞎,那这个项目值得你花时间研究。它不是一个教你三分钟跑通 demo 的速成教程,而是一条把 AI 工程的底层逻辑、数学模型、系统设计、工程实践串起来的完整路线。这篇文章我会把这条路线拆开讲清楚,包括每一阶段学什么、为什么这么安排、踩过哪些坑、以及怎么用它指导自己动手做项目。
1. 这个项目到底在解决什么问题
1.1 AI 工程不是“调包”,是工程能力
我在带团队的时候见过太多这样的候选人:简历上写着熟悉 PyTorch、会调 Transformer 接口,但一问到“模型推理延迟为什么高”“显存占用怎么优化”“数据倾斜怎么处理”就支支吾吾。根源不在于他们不够聪明,而在于学习路径出了问题——大多数人是从“使用”出发,而非从“原理和工程”出发。
ai-engineering-from-scratch这个名字本身就点明了它的立场:既然叫 from scratch,就意味着不依赖任何黑盒。它不是教你 import 一个模型然后跑个训练脚本,而是帮你把 AI 工程这条链路从零搭建起来。
具体来说,它覆盖了以下几大块:
- 数学基础:线性代数、概率论、最优化方法,这些是理解模型结构的前提
- 编程基础:Python 进阶、数据结构、Linux 环境、Git 工作流
- 机器学习核心:损失函数、梯度下降、正则化、评估指标、偏差与方差
- 深度学习进阶:反向传播、常见网络结构、注意力机制、训练技巧
- 工程化能力:数据管道、模型训练与调优、推理优化、服务部署、监控运维
这不是随便堆砌的知识点清单,而是一条有前后依赖关系的路径。比如不先搞懂反向传播的数学原理,后面调学习率、改网络结构就是纯凭感觉;不先掌握数据管道的设计,后面做大规模训练时反复洗数据会把你折磨到怀疑人生。
1.2 为什么值得从零开始
你可能有疑问:现在框架这么成熟,HuggingFace 上模型随便下,直接上手不是更快吗?这里我用自己的经历给你一个最现实的回答。
我刚入行的时候就是图快,直接下载预训练模型,用现成代码微调了一个中文情感分析模型。当时效果还不错,准确率 92%。但等到了生产环境,问题一个接一个来:数据分布变了,线上效果掉到 85%;并发一上来,推理延迟从 100ms 飙升到 800ms;模型版本更新后行为不一致,线上出现诡异的结果。我当时完全不知道怎么排查,因为模型对我来说就是个黑盒。
后来我把基础补上了,重新按照 from scratch 的思路走了一遍,才真正建立起解决问题的能力。比如说,当你理解了注意力机制的矩阵运算过程,你就明白为什么序列长度增加会导致推理显存暴涨,进而知道 FlashAttention 到底优化了什么。这种"从根上理解"的能力,是任何速成教程都给不了的。
1.3 适合谁和怎么用
说实话,这个项目不适合完全没有编程基础的人。你可以不会机器学习,但至少得写过一段时间代码,了解基本的数据结构和算法。
我建议三拨人可以重点关注这条路线:
- 转行 AI 工程方向的开发者:如果你之前做后端、做前端,想转 AI,这条路线能帮你系统补齐理论盲区,不掉进"会调库但不懂原理"的坑
- 在校学生:特别是想做 AI 方向科研或者准备面试的学生,这条路线能帮你把零散的课程知识串成体系
- 已经在做 AI 但又觉得根基不牢的工程师:我属于这类人,补基础是值得的
怎么用也是有讲究的。不要试图一次性从头看到尾,我见过太多人收藏了这条路线然后吃灰。正确姿势是:按阶段来,每个阶段学完必须配一个动手项目。后面我会给出一个结合实际案例的学习路线规划,可以直接抄作业。
2. 核心知识体系的拆解与编排逻辑
2.1 数学基础:够用就行的底线思维
一说到数学,很多人就头大。我一开始也怀疑,做工程要那么深数学干嘛?但实际工作中你会发现,模型的公式推导你可能不需要亲自来,但读懂论文、复现模型、理解训练过程的每一行日志,都需要数学敏感度。
这里我有几个具体建议,按优先级来:
- 线性代数的核心是矩阵乘法、转置、秩、特征值。你要能做到看到 Transformer 结构图时,能脑补出 Q、K、V 三个矩阵是怎么算出来的,注意力的 shape 是怎么流动的
- 概率论重点掌握常见分布、条件概率、贝叶斯公式、最大似然估计。这些是理解交叉熵损失、KL 散度、各种采样策略的基石
- 最优化方法知道梯度下降的变体就够了,包括 SGD、Momentum、Adam 的原理,以及学习率调度为什么要做 warmup
我说一个真实例子。我最初调参的时候,加了 warmup 策略纯粹是看别人这么干。直到某天我认真看了 Adam 的更新公式,理解了它在训练前期因为二阶动量估计不准会导致步长过大,才明白 warmup 是在补偿这个偏差。从此以后,我遇到训练发散问题,第一反应不再是盲目调参,而是去看优化器的状态和公式。这就是数学基础带来的降维打击。
2.2 从零实现一个玩具神经网络
如果你问这条路线里最重要的动手项目是什么,我会说是"纯 Python + NumPy 实现一个两层神经网络,并在 MNIST 上训练到 90% 以上的准确率"。别笑,这个项目含金量远超你的想象。
在这个过程中你会亲手实现以下内容:
- 参数初始化:理解为什么不能全初始化为零,以及 Xavier 初始化的推导动机
- 前向传播:实现线性层、ReLU 激活、Softmax 输出层
- 损失计算:实现交叉熵损失,并推导其梯度
- 反向传播:手写链式法则,逐层计算梯度
- 参数更新:实现梯度下降,理解学习率对收敛的影响
- 评估与验证:划分训练集、验证集,画出学习曲线
我到现在都记得第一次手写反向传播时的感受。写前向传播很简单,但到了反向传播,你需要在纸上画出计算图,一个节点一个节点地推导。等把整个流程写通、训练成功的那一刻,神经网络在我眼里不再是魔法,而是一台可解释的"梯度计算器"。
从这以后,不管多复杂的模型,我都能快速定位问题所在。比如我做 BERT 系列模型时遇到 loss 不降,我能从梯度流动的角度去排查,而不是干等。
2.3 从学习到工程的桥梁:系统设计与工具链
学完算法和模型只是第一步,AI 工程和算法研究之间的鸿沟在于"工程化"。路线里把系统设计和工具链放在很靠后的位置,我一开始觉得不合理,后来才明白这个安排是有讲究的——你如果连模型怎么训练都不清楚,谈什么系统设计。
这条路线里推荐的工程能力栈是这样的:
- 版本管理:Git + DVC,用来管理代码和数据
- 环境管理:Docker,保证训练和推理环境一致性
- 训练管理:MLflow 或 W&B,记录实验指标、参数、模型 artifact
- 任务编排:Airflow 或者 Prefect,做数据管道的定时调度
- 服务部署:FastAPI + ONNX Runtime 或 Triton,提供推理服务
- 监控告警:Prometheus + Grafana,跟踪线上推理质量
不必一上来全都要会。我的建议是,在 from scratch 路线的前三个阶段,只用 Git 和简单的 Python 环境就够了。等到了第四阶段(工程化部分),再引入 Docker、MLflow 和 FastAPI,按需学习。
3. 我建议的实操路径:四阶段动手计划
3.1 阶段一:打地基(4-6 周)
这一阶段不需要干太复杂的事,核心目标是把"机器学习的编程基础"打牢固。
具体任务清单如下:
- 每天一小时,复习 Python 的类、装饰器、生成器、上下文管理器
- 掌握 NumPy 的高级索引和广播机制,这直接决定你写模型前向传播时代码是否优雅、高效
- 用 pandas 做一次真实数据集的基础清洗和分析,理解数据里常见的脏数据模式
- 把 Git 分支管理、rebase、merge 搞清楚。我见过太多人在项目协作时因为不会处理冲突浪费一整天
这个阶段最容易犯的错是贪快。总觉得自己会写 Python 就可以跳过 NumPy 和 pandas 的深入学习。实际上,后面手写模型时,一个形状不匹配的报错就能让你看到怀疑人生。如果你 NumPy 的广播机制理解得透彻,调试效率至少提升一倍。
我在带人时发现一个现象:很多人写 from-scratch 模型的时候,报错信息根本看不懂,因为不理解维度变化。所以在阶段一,我要求必须把每一步的 tensor shape 写在注释里。养成了这个习惯,后面的调试会顺畅很多。
3.2 阶段二:手写基础模型(6-8 周)
这阶段是核心中的核心,分三步走。
第一步:用 NumPy 手写线性回归和逻辑回归。你需要实现梯度下降、闭式解(对线性回归)、正则化项,然后在波士顿房价(或者现在的 California housing)和鸢尾花数据集上做实验。看看加入 L2 正则化后权重和泛化能力怎么变化。
第二步:手写一个多层感知机(MLP),用反向传播在 MNIST 上实现分类。先不要用 PyTorch 的自动求导,全程手写梯度。虽然代码会多一些,但这个过程的收获是任何框架给不了的。
第三步:把 MLP 用 PyTorch 重写一遍。对照你的 NumPy 实现,理解框架帮我们做了哪些事情,比如自动求导、GPU 计算、批量训练等。这时候框架对你来说就不是黑盒了。
这一阶段的验收标准是:
- 能够从零写出 forward 和 backward,不需要查资料
- 能解释梯度消失为什么会出现,以及 ReLU 如何缓解
- 能画出损失曲线和准确率曲线,判断模型是否收敛、是否过拟合
3.3 阶段三:深度学习应用与训练技巧(8-10 周)
有了基础模型的底子,就可以进入深度学习的主流领域了。我建议按照图像和文本两条线并行:
- 图像线:实现一个 CNN 网络(从 LeNet 到 ResNet 的简化版),在 CIFAR-10 上做分类。重点体验卷积操作的参数共享特性和平移等变性
- 文本线:实现一个简化版的 Transformer,在机器翻译或文本分类任务上做训练。这一步比较复杂,可以先从单层自注意力开始,理解 QKV 的交互,再逐层叠加
这个阶段有很多细节会让人抓狂。比如训练 Transformer 时的学习率设置、warmup 步数、梯度裁剪、dropout 位置,这些都是工程经验。我自己的做法是建立一份实验笔记,每改一个参数就记录实验结果,形成自己的"调参感觉"。
这个阶段的常见误区是只跑通不出错,不去深究为什么这样设计。比如很多人会用 LayerNorm,但不知道它和 BatchNorm 在训练行为上的差异。等到了 NLP 任务,错误的归一化选择会导致训练极度不稳定。所以每用到一个技巧,我都建议追问一句:它解决了什么问题?代价是什么?
3.4 阶段四:工程化与真实落地(4-6 周)
当你在模型层面有掌控感之后,就可以迈向工程化阶段了。这里我建议做一个端到端的项目,作为整个 from-scratch 路线的收官之作。
我推荐的项目是:构建一个文本分类服务,支持在线训练、评估、部署和监控。
具体步骤如下:
- 用 DVC 管理数据集版本,模拟数据更新的场景
- 用 MLflow 记录所有实验的指标和配置
- 训练一个文本分类模型(可以基于阶段三的 Transformer)
- 把模型导出为 ONNX 格式,写一个 FastAPI 服务调用
- 用 Docker 镜像化整个服务,在本机部署
- 用 Locust 压测服务,观察吞吐量和延迟
- 给服务配置一个简单的无偏评估逻辑,定期用真实线上数据评估模型漂移
这个项目做完,你简历上能写的东西就完全是另一个量级了。我从"能跑通教程"的 level 进阶到"能交付生产级系统"的 level,就是靠着类似这样的项目经历。
4. 实操过程中的问题排查实录
4.1 训练不收敛,loss 变成 NaN
这是新手最常撞上的问题,也是 from-scratch 路线里绕不开的坎。我自己的排查顺序是:
- 检查数值稳定性:把输入归一化到合理范围,比如图像除以 255,文本 embedding 加上 LayerNorm
- 降低学习率:如果你用的是默认 lr=0.001,试试 0.0001,有时候纯粹是步子迈太大了
- 检查梯度:在第一次迭代时打印梯度,看是否出现异常大值或 NaN。如果梯度爆炸,加梯度裁剪
- 检查损失函数实现:交叉熵损失是否包含了 log_softmax?是否出现 log(0) 的情况
- 数据问题:标签是否从 0 开始连续编号?数据里是否有 NaN?我用 pandas 一查,经常发现源数据里藏着缺失值
很多人在这一步就直接放弃了,回头去调包用 PyTorch 现成模型,反而掩盖了问题的本质。实际上,几乎 90% 的训练不稳定问题,要么是数值实现细节出错,要么是学习率不当,要么是数据有问题。
4.2 显存溢出(OOM)
当你尝试把 batch size 调大时,显存溢出几乎是必然的。我的处理经验是:
- 不要盲目减小 batch size,先检查模型的输入输出有没有保持,有没有意外缓存了中间张量
- 把 PyTorch 的梯度检查打开:
torch.autograd.detect_anomaly(),定位是哪一层爆掉 - 用
torch.cuda.max_memory_allocated()查看峰值显存,判断瓶颈在哪 - 一个非常实用的减显存小技巧:混合精度训练(amp),在 A100 这类卡上显存占用几乎减半
这里我要特别说说 from-scratch 项目特有的痛点:手写反向传播时的中间缓存。我曾经实现一个深层网络时没做好内存管理,导致同样 batch size 下显存占用比 PyTorch 实现高出 3 倍。后来才意识到问题出在中间激活值没有主动释放。所以写代码时,尽量让中间变量用完即弃,或者改用with torch.no_grad()块来避免不必要的梯度记录。
4.3 过拟合与欠拟合的定位
很多人在做 from-scratch 项目时会把"验证集效果不好"简单归结为模型能力不行。实际上需要系统排查:
- 先看训练集效果。如果训练集都学不好,多半是模型容量不够或者学习率设置不对,属于欠拟合
- 如果训练集很好但验证集差,那就是过拟合。优先加数据增强、正则化、dropout、降低模型容量
- 画出训练和验证的损失曲线。两条线差距越来越大,过拟合特征;两条线都不降,学习率、模型结构大概率有问题
- 检查数据泄漏。我在做分类任务时遇到过验证集准确率奇高但线上效果差,最终发现是数据预处理时把目标变量不小心混进了特征
这条排查思路看起来基础,但在我带过的团队成员里,至少有一半人不会系统地按这个顺序排查,而是凭感觉乱试。
4.4 推理性能优化经验
from-scratch 路线走到工程化阶段,你一定会遇到推理性能问题。我的优化策略优先级是:
- 模型裁剪和量化:把 FP32 转 INT8,很多场景下精度损失可接受。我用 ONNX Runtime 做 INT8 量化,推理速度通常提升 2 到 4 倍
- 批处理:把请求合并成 batch。但要小心 batch 内序列长度差距过大导致的计算浪费,建议用动态 padding
- 服务框架:FastAPI 的异步处理能力一般,真到高并发建议上 Triton
- 缓存:把高频请求的重复计算缓存起来。我用过 Redis 做语义相似度计算的缓存,命中率高的场景收益非常明显
推理优化这块的知识,单靠刷课程是学不来的。我建议你在 from-scratch 收官项目里专门花一周时间做压测和优化,把每个过程的延迟数据记录下来,形成自己的优化案例库。面试的时候拿出来讲,比背八股文强一百倍。
5. 学习资源与工具选型建议
5.1 路线里隐含的资源清单
很多人在公众号和知乎收藏各种 AI 学习路线,我这里帮ai-engineering-from-scratch把配套资源梳理成可直接照做的清单:
- 数学三件套:《线性代数及其应用》(David C. Lay)、《概率论与数理统计》(陈希孺)、《最优化导论》(Boyd)
- 机器学习经典:周志华《机器学习》(西瓜书)+ Andrew Ng 的 CS229 笔记
- 深度学习核心:《深度学习》(花书)+ CS231n + CS224n 的课程笔记
- 动手实践:fast.ai 的 Practical Deep Learning for Coders
- 工程化范式:Designing Machine Learning Systems(Chip Huyen)
注意,这套路线不是让你全部看完,而是"哪块卡住了就去啃哪块"。我自己就从没完整看过花书,但每到关键概念(比如 BatchNorm、注意力机制),我都会回头翻对应的章节。
5.2 环境与工具选择的个人建议
一台带 NVIDIA GPU 的电脑(哪怕是二手 1080Ti)比任何云 GPU 都值得先入手。从零学习阶段你大部分时间在调试,本机交互式环境远比云端方便。等真需要大算力了,再考虑按需租赁。
开发环境方面我的选择是:
- VS Code + Remote SSH,远程连服务器开发
- Jupyter Notebook 用于数据探索,但正式代码要用 .py 脚本组织
- Conda 管理 Python 环境,别用系统 Python
- 全部代码用 Git 管理,哪怕是一个人写
这里要特别提一个坑:很多人喜欢在 Notebook 里写完所有代码,然后直接交付。这在大型项目里是大忌,因为 Notebook 的隐藏状态极难排查。我在从零训练模型的时候吃过这个亏——某个变量在之前的 cell 里被覆盖了,导致后面所有 cell 的结果都不可信。排查了整整一天。从那以后,我坚持"Notebook 只做探索,正式训练脚本一律用 .py 文件"。
5.3 如何避免学习过程中的信息过载
AI 领域更新极快,如果你每个关注点都想追,一定会陷入焦虑。我从这个 from-scratch 项目里学到的最大心得是:分清"长期不变的知识"和"短期变化的信息"。
长期不变的是数学基础、模型原理、系统设计原则。这些值得花大块时间深度学习。
短期变化的是新框架、新模型架构、新工具。这些只在需要的时候查文档、看 release note、读一两个优秀的技术博客就足够了。
我的学习习惯是:在 from-scratch 路线的每个阶段,我给自己定一个目标产出物。比如学完手写模型之后,目标是写一篇 tutorial 讲清楚自己踩过的坑。学完工程化之后,目标是把整套项目代码开源。有了产出物,学习就不再是"看了很多课还是不会写"。
6. 从零开始的过程中,我不太想说但又必须聊的体验
6.1 两次“从零开始”的对比
严格来说,我完整走这条路线走了两遍。第一遍是刚转行时,跟着各种资料东一榔头西一棒槌,当时觉得什么都学了,但什么都没学透。第二遍是工作中遇到瓶颈后,老老实实按照体系化的路线重建知识框架,才真正建立了掌控感。
我举一个具体例子。第一遍学 Transformer 的时候,我看完博客就觉得自己懂了,还照着网上代码跑了个翻译 demo。但第二遍学的时候,我要求自己从注意力计算的 shape 推导开始,手动实现一遍多头注意力的矩阵运算,再对照源码逐行分析。两个版本学到的东西完全不是一回事。
所以这个项目给我最大的改变,不只是知识储备的加深,而是学习方式的转变——从"看会了"转为"做出来 + 能解释"。
6.2 给正在这条路上挣扎的人几句掏心窝的话
在做 AI 工程这条路上,我见过太多人因为一开始进展缓慢就放弃,或者因为看懂了一两个教程就沾沾自喜。这两者都不可取。
我最终能走通这条路,靠的是把一个大目标拆成无数个"今天能完成的小动作"。今天不用想着一口气学会整个 Transformer,只要把 Q、K、V 的运算动手推导一遍就算赢了。明天把注意力头和维度匹配的代码跑通就算前进了一步。这样一点点积累,半年后回头一看,你已经走出了很远。
另外我想说,做 from-scratch 项目的过程中,遇到挫败是常态。我自己最崩溃的一次是花了整整五天调一个模型就是不收敛,最后发现是数据标准化写错了。但那五天的痛苦过程,反而让我对数据预处理的各种细节刻骨铭心,后来做任何项目都会先检查数据。这种深刻的记忆,比任何顺利跑通的 demo 都珍贵。
把这个从零开始的工程化路线走完,你掌握的不只是算法原理和代码能力,更是"遇到问题能从根上解决"的自信。