跳到主要内容

章节切分大纲:Deep Learning with PyTorch 2e → 16 章

切法:对着原书 17 章走,两处合并(ch1+ch2 都是低密度入门;ch16+ch17 都是「从训练到生产」的工程收尾)、 两处拆开(ch5 是全书机制核心,一节一条链太长,拆成「手工梯度下降」与「autograd/优化器/过拟合」; ch8 拆成「卷积本身」与「设计空间:宽度/深度/正则化/初始化」)。

01 一次范式转移:从手工特征到预训练模型(原 ch1+ch2)

  • 进来时以为「AI 就是会思考」→ 出去时知道:它只是一类「用例子逼近复杂非线性过程」的算法,智能问题被 Dijkstra 一句话挂起
  • 进来时以为「做机器学习就是调算法」→ 出去时知道:老办法的瓶颈在手工特征工程,深度学习的转移是把「造特征」也交给训练
  • 进来时以为「模型是写出来的程序」→ 出去时知道:预训练模型 = 架构 + 训练时见过的数据,网上下载就能跑
  • 进来时以为「跑模型很复杂」→ 出去时知道:bobby.jpg 走一遍 预处理→前向→1000 分→softmax→86% 金毛;训练集外的输入会高置信胡说
  • 进来时以为「生成图像是另一个世界」→ 出去时知道:扩散修复也是同一个生态;模型是脚手架,权重才是内容
  • 进来时以为「PyTorch 是唯一的」→ 出去时知道:竞争格局(Theano/TF/JAX/HF)与 PyTorch 两张王牌(GPU 加速 + autograd)

02 一切从张量开始(原 ch3)

  • 进来时以为「数据在程序里是列表」→ 出去时知道:张量是一块连续内存上的视图,跟 Python 列表的 boxed 对象完全不同
  • 进来时以为「索引、转置都要复制数据」→ 出去时知道:size/offset/stride 三元组,转置只是换 stride,不复制
  • 进来时以为「形状不一样就不能算」→ 出去时知道:broadcasting 从右往左对齐,1 的维会被「虚拟复制」
  • 进来时以为「数字就是数字」→ 出去时知道:dtype 决定字节数与范围,float32 默认、bfloat16 的由来
  • 进来时以为「GPU 是另一套 API」→ 出去时知道:device 属性 + .to(),同一份代码两边跑;NumPy 零拷贝互操作

03 把真实世界装进张量(原 ch4)

  • 进来时以为「数据就是数据」→ 出去时知道:图像 N×C×H×W、CT 加 D 维成 5D,布局约定比内容更要命
  • 进来时以为「表格里的数都能直接算」→ 出去时知道:连续/序数/类别三种值,类别值硬编码成数会注入假的大小关系
  • 进来时以为「类别只能变编号」→ 出去时知道:one-hot 与 scatter_;硫阈值手工分类 74%/61% 说明单特征阈值的上限
  • 进来时以为「时间序列只是多一列」→ 出去时知道:view+transpose 把 17520×17 重排成 730×17×24,一分钱数据没动
  • 进来时以为「词只能 one-hot」→ 出去时知道:7261 词表装不下世界,嵌入把 one-hot 换成 100 维浮点向量,「意思变距离」

04 学习的机制:开普勒到梯度下降(原 ch5 上半)

  • 进来时以为「机器学习很新」→ 出去时知道:开普勒 1609 年的七步就是数据科学手册,包括留一部分数据做验证
  • 进来时以为「学习是玄学」→ 出去时知道:模型 t_c=w*t_u+b + 损失(均方差)就把「学」变成了「调 w、b 让损失最小」
  • 进来时以为「梯度很高深」→ 出去时知道:先数值扰动(delta=0.1)再解析求导,梯度=损失对每个参数的变化率
  • 进来时以为「训练总会收敛」→ 出去时知道:lr=1e-2 直接发散到 inf;学习率是超参数;w 与 b 梯度差 50 倍逼出输入归一化
  • 主走查:11 对温度计读数,5000 轮后 w=5.37、b=-17.30,揭开谜底——那支温度计显示的是华氏度

05 autograd、优化器与过拟合(原 ch5 下半)

  • 进来时以为「求导要自己推」→ 出去时知道:requires_grad 让张量记家谱,backward 沿计算图回传,grad 是累加不是覆盖
  • 进来时以为「更新参数要自己写循环」→ 出去时知道:optim.SGD/Adam 把更新策略抽象出去;SGD 的 S 来自小批量
  • 进来时以为「训练损失降就是学会」→ 出去时知道:训练/验证分叉才是过拟合信号;图 5.14 四种曲线
  • 进来时以为「数据越多越好用到尽」→ 出去时知道:test set 只用一次,数据泄漏让评估虚高
  • 主走查延续:同一温度计数据,autograd 版训练循环 zero_grad→backward→step

06 神经网络登场:激活、层与 nn 模块(原 ch6)

  • 进来时以为「神经元很神秘」→ 出去时知道:o=f(w·x+b),一个线性变换套一个固定的非线性函数
  • 进来时以为「多叠几层线性也行」→ 出去时知道:线性叠线性还是线性,激活函数才是让网络能逼近任意曲线的关键
  • 进来时以为「训练神经网络有标准答案」→ 出去时知道:非凸误差面,参数没有个体含义,两次训练参数不同但都对
  • 进来时以为「tanh 是个名字」→ 出去时知道:敏感区/饱和区,垃圾车 -0.97、熊 0.10、好狗 0.99;ReLU 为何成默认
  • 进来时以为「PyTorch 模型要写很多」→ 出去时知道:nn.Module 递归收集参数、nn.Linear、nn.Sequential 三层拼出第一个真网络

07 鸟与飞机:图像分类与分类损失(原 ch7)

  • 进来时以为「图像很特殊」→ 出去时知道:CIFAR-10 拉直成 3072 个数就能进全连接;Dataset/DataLoader 两个方法撑起数据侧
  • 进来时以为「分类就是回归换皮」→ 出去时知道:类别输出要满足概率约束,softmax=指数再归一
  • 进来时以为「MSE 哪都能用」→ 出去时知道:分类要最大化正确类的概率,NLL/交叉熵在快对时仍有坡度,MSE 早就躺平
  • 进来时以为「准确率 81% 不错」→ 出去时知道:训练集 100% 验证 81% 是过拟合;157 万参数的第一层是罪魁祸首
  • 进来时以为「多训练就行」→ 出去时知道:全连接没有平移不变性,飞机挪一格全部重学——逼出下一章的卷积

08 卷积:局部性与平移不变(原 ch8 上半)

  • 进来时以为「卷积是个数学装饰」→ 出去时知道:同一个 3×3 小权重块滑过全图,一次满足局部性+平移不变+参数少
  • 进来时以为「卷积核是专家手工设计的」→ 出去时知道:手工核只能演示(模糊核、边缘核),真网络里核是反向传播学出来的
  • 进来时以为「3×3 只能看 3 个像素」→ 出去时知道:池化减半分辨率,两层叠出 8×8 感受野
  • 进来时以为「网络随便拼」→ 出去时知道:Conv→Tanh→MaxPool→…→view→Linear 的形状账,Sequential 缺 reshape 当场报错
  • 主走查:同一只鸟图,18090 参数的卷积网 train 95%/val 90%,错误率比 374 万参数的全连接减半

09 设计空间:宽度、深度、正则化与初始化(原 ch8 下半)

  • 进来时以为「写网络就是堆 Sequential」→ 出去时知道:subclass nn.Module + forward,functional API 管无状态操作
  • 进来时以为「越大越好」→ 出去时知道:宽度=每层的通道数,加宽加容量也加过拟合
  • 进来时以为「正则化是玄学调料」→ 出去时知道:weight decay 按值缩权、dropout 随机置零、batch norm 按小批量归一,三者机制各异
  • 进来时以为「100 层是天方夜谭」→ 出去时知道:梯度消失被 ResNet 的跳连解决——给梯度一条不乘长链的近路
  • 进来时以为「初始化随便给」→ 出去时知道:PyTorch 默认初始化不理想,Kaiming/Xavier 是论文级的讲究;猫 Fred 会 0.99 自信被误判(overgeneralization)

10 Transformer 与文本生成(原 ch9)

  • 进来时以为「生成文本要理解语言」→ 出去时知道:ELIZA 1960s 就会装;统计生成只管「下一个该是什么」
  • 进来时以为「数对子就够了」→ 出去时知道:bigram 27²=729 尚可,词级词表指数爆炸,自监督=标签从数据自己长出来
  • 进来时以为「注意力是黑话」→ 出去时知道:Q/K/V 就是检索三件事,softmax(q·k) 打分再加权取 V
  • 进来时以为「Transformer 很复杂」→ 出去时知道:decoder 块=掩码多头注意力+残差+层归一化+前馈,六个堆起来生成像样人名
  • 进来时以为「Transformer 只管文本」→ 出去时知道:位置嵌入补顺序;ViT 把图像切块当 token,[CLS] 聚合全局

11 扩散模型:从噪声里把图变回来(原 ch10)

  • 进来时以为「生成图像没法像文本那样逐个吐」→ 出去时知道:目标相同——学训练集分布再采样;VAE/GAN 两条先路
  • 进来时以为「加噪声就是破坏」→ 出去时知道:前向过程按噪声日程缓慢毁结构,闭式解一步算出任意 t 的 x_t
  • 进来时以为「生成就是解码」→ 出去时知道:训练目标是「给脏数据和 t,预测加进去的噪声」,MSE 就够
  • 进来时以为「采样和训练一样快」→ 出去时知道:反向没有闭式解,1000 步迭代是扩散慢的根源
  • 主走查:PyTorch logo 3177 个点,加噪到纯随机,再从 1000 个随机点一步步把 logo 变回来

12 肺癌项目:问题设计与数据管线(原 ch11+ch12)

  • 进来时以为「端到端一把梭」→ 出去时知道:99.9999% 体素无关,三步流水线(加载→分割→分类)是拿数据量换可行性
  • 进来时以为「CT 就是图片」→ 出去时知道:体素非立方、HU 单位、患者坐标系毫米 vs 数组坐标,voxel 账要先算清
  • 进来时以为「标注是干净的」→ 出去时知道:551066 候选只有 1351 真结节;两文件坐标对不齐要靠直径模糊匹配
  • 进来时以为「Dataset 是别人写的」→ 出去时知道:len+getitem 自建桥;缓存让 I/O 快 50 倍
  • 进来时以为「切分随便切」→ 出去时知道:按大小排序后每隔 10 个取验证,保证两层都代表真实分布

13 训练循环与 99.7% 的假象(原 ch13)

  • 进来时以为「训练脚本几行就行」→ 出去时知道:CLI 应用结构、DataLoader 多进程、SGD lr=0.001 momentum=0.99 默认
  • 进来时以为「模型设计靠灵感」→ 出去时知道:tail/backbone/head 分工,两层 3×3×3 叠出 5×5×5 感受野比单层省参数
  • 进来时以为「loss 一个数就够」→ 出去时知道:reduction='none' 留每样本损失,metrics 三行(label/pred/loss)是调试的命根
  • 进来时以为「99.7% 正确是 A+」→ 出去时知道:验证集阳性 0/136,模型全答「不是」;全 False 也能 99 分的考试
  • 进来时以为「看数字就够」→ 出去时知道:TensorBoard 趋势线,global_step 用样本数不用 epoch

14 指标、平衡与增广(原 ch14)

  • 进来时以为「准确率是唯一指标」→ 出去时知道:警犬 Chirpy/Dozer 两极,精确率与召回率各管一种错
  • 进来时以为「F1 是个公式」→ 出去时知道:它是精确率召回率的调和平均;算术平均/取小/相乘为什么都不行
  • 进来时以为「不平衡只是难看」→ 出去时知道:400:1 时 15 个 batch 才见一个正样本,权重被单向拉塌;交替采样 1:1 复活训练
  • 进来时以为「增广就是凑数」→ 出去时知道:五种增广保住代表性又难以背下;缓存必须在增广之前;噪声是破坏性的
  • 进来时以为「指标越高越好」→ 出去时知道:全增广牺牲总正确率换召回率;按场景选指标(筛查要召回)

15 分割与微调:让模型自己找候选(原 ch15)

  • 进来时以为「分类回答一切」→ 出去时知道:分类=放大镜(有没有),分割=热图(在哪);语义/实例/检测三分
  • 进来时以为「分割要手工标 mask」→ 出去时知道:SAM 点一下出 mask,零样本;11M 图 1.1B mask 训出来的基础模型
  • 进来时以为「SAM 直接能用」→ 出去时知道:它吃 2D 不吃 3D,要抽切片;自然图像到医学影像有 domain gap
  • 进来时以为「微调是重新训练」→ 出去时知道:用 SAM 生成的 mask 当 ground truth,只微调 SegFormer 的解码头,小模型单卡可训
  • 进来时以为「保存模型就是存整个对象」→ 出去时知道:state_dict 只存参数,load_state_dict 要求 1:1 对应

16 从单卡到集群再到生产(原 ch16+ch17)

  • 进来时以为「多 GPU 就是快一点」→ 出去时知道:梯度不合并模型会分叉;allreduce 同步是 data parallelism 的关键一步
  • 进来时以为「并行只有一种」→ 出去时知道:数据/模型/流水线/张量四种并行,按模型「深瘦还是浅胖」选;FSDP 把参数也切片
  • 进来时以为「部署=把模型放网上」→ 出去时知道:Gradio 原型→FastAPI 服务→请求批处理+流式;量化 6.5GB→1.8GB
  • 进来时以为「导出是格式转换」→ 出去时知道:torch.export 抓全图、torch.compile 允许断图回退;ONNX 跨生态,LibTorch/ExecuTorch 出 Python
  • 进来时以为「优化靠猜」→ 出去时知道:torch.profiler 看 aten::addmm 占 65%,编译前后 trace 对比

自查(任意两行「出去时知道」是同一件事 → 合并)

  • 04 与 05 都讲 ch5,但 04 的落点是「梯度下降+归一化让损失收敛」,05 的落点是「自动求导+评估结构」;前者回答「怎么调」,后者回答「怎么自动化、怎么知道调好没」——不是同一件事,保留拆分
  • 08 与 09 都讲 ch8,08 落点是「卷积为什么赢」,09 落点是「选好结构之后还有哪些旋钮」——不同
  • 13 与 14 都涉及「指标」,13 落点是「单看总正确率会被骗」(现象),14 落点是「精确率/召回率/F1/平衡/增广」(解法)——因果关系,不同
  • 02 的 dtype 与 03 的归一化:02 讲「张量自己是什么」,03 讲「数据怎么进张量」——不同
  • 10 的嵌入与 03 的嵌入:03 只到「one-hot 装不下→浮点向量」,10 讲「嵌入在生成任务里被训练、被注意力使用」——层进,不同
  • 12 与 13:12 是「数据怎么变成样本」,13 是「样本怎么进训练+第一仗打败」——不同
  • 16 合并 ch16+17 的风险:新词密度高(rank/allreduce/DDP/FSDP/量化/导出/compile…)。对策:章内分节严格控制,每节新词 ≤5;两章共享「训练完→生产」一条链,合并成立 EOF