跳到主要内容

节级大纲 — 《JavaScript深度学习》(deep-learning-with-javascript)

这一版是审稿意见落实后的第三版。 相对上一版改了三类东西:切章从 20 改成 22 (19 拆成「测试与瘦身 / 七种落点」、16 拆成「VAE / GAN」,依据在「切章账」); 两处跨章断裂与两组首次交付撞车按审稿意见重排;全书主线从二十行表格改写成十步散文(海拔问题)。

  • 原书:13 章正文 + 2 附录,清洗文本 52.9 万字(文件大小 118 万字节)。
  • 拆解:22 章。单章目标 17~24k 字节,和样板(每章约 23k)、母本(每章约 23k)同档。
  • 参照:母本 deep-learning-with-python-2e 原书 68.7 万字 → 14 章 / 32.7 万字节;样板 what-is-chatgpt-doing 原书 5.5 万字 → 8 篇 / 18.2 万字节。
  • 第 01 章已写完,口径可用,不重写,按下面「01 要补的四处」加料(其中主走查按审稿意见整条换掉)。

一、全书一条主线(总纲第 3 节的骨架)

判据是「只读这一节就能把这本书讲给别人听」。 所以这一节写成约十步散文, 一步可以覆盖两三章、一章也可以不单独占一步 —— 形状上就不能是章节摘要的拼接。 每一步只留效果句;机制名只留读者出门会撞见的那几个(过拟合、卷积、嵌入、注意力、温度), 其余(交叉熵、可微、本征空间、常数折叠)一律退回章节。数字只留三四个,每个当句给参照物。 「落在哪章」不写在这里,整栏挪进总纲第 4 节的章节地图。

① 起点:规则写不出来。 让程序认出照片里有没有人 —— 你写得再细,脸的大小、角度、 光线永远还有新花样。于是掉个头:人不写规则,人给答案(几千张标好「有人 / 没人」的照片), 让机器自己去找规则。

② 找规则,找的其实是「换一种说法」。 一堆黑点白点撒在纸上,横着切切不开、竖着切也切不开; 换成「离中心多远、在什么角度上」,一刀就分明了。数据没变,说法变了,难题就没了。 深度学习做的就是把这个换说法的动作自动化,而且一层接一层做几十次

③ 最小的那台机器,和它唯一的动作。 一条直线,两个可调的数。做法朴素得出奇: 看它答得离正确答案差多远 → 把每个数朝「差得少一点」的方向挪一丁点 → 换下一道题。 整本书后面所有模型,训练时干的都还是这一件事,只是可调的数从两个变成几十万个。

④ 你凭什么说它算得好。 一个误差数字自己不会说话。必须先找一个不动脑子的笨办法 (永远猜平均值)算出它的误差,把它摆在旁边当参照 —— 超不过它,再复杂的模型也白搭。 这条纪律后面每一章都要用。

⑤ 加层不等于加能力。 直线叠直线还是直线。真正给出能力的,是每层中间那一下弯折。 加上它,同一份房价数据的误差从五千美元降到三千八百美元;代价是从此没人读得懂中间那些数在算什么 —— 这是全书第一笔明码标价的交易:拿看得懂换算得准。

⑥ 换个输入,老办法就崩了。 图像要是拉成一长串数喂进去,「谁挨着谁」就永远丢了。 正解是拿一小块窗在整张图上滑,同一组数反复用在每一个位置(这叫卷积)。 同样是把一张手写数字变成一层特征,这么做只要一百多个可调的数,换成老办法要八百多万个。 更妙的是把一秒声音画成图之后,同一套东西照样成立。

⑦ 别人训好的模型,可以借。 从头训一个图像模型要几十万张图,你手里只有五十张。 办法是把别人在百万张图上训好的模型从中间截断,拿中间层吐出来的那一串数当这张图的浓缩说法 (这串数叫嵌入),只训最后几层。摄像头拍四个方向各五十张,几秒钟训完,就能拿脑袋玩吃豆人。

⑧ 到这儿数据一直是洗干净的 —— 现实不是。 数据大到读不进内存,得一条条流进来; 而且它本身是歪的:那份加州房价 CSV 是按经度排好的,直接切前八成当训练集, 你训出来的是一个只认海边房子的模型。这两章母本一个字都没有,是这本书不可替代的部分。

⑨ 看不见就只能猜。 画出来:数据画成五种图;模型也能画 —— 同一张猫照片, 浅层输出还看得出边和色块,深层只剩几块亮斑;还能让模型自己指出「我判这是猫,看的是这一块」。 看得见之后,最常撞见的那个现象叫过拟合:训练误差一路降,验证误差却掉头往上走。 一排治法之后,前九步的零碎技巧收口成一条通用流程。

⑩ 顺序,一直被忽略了。 到这儿所有模型对先后完全无感:把十天气象数据的两百四十个时刻打乱, 算出来一模一样。让上一步的输出流回下一步,顺序就进来了 —— 这和第 ⑥ 步是同一个想法, 一个把权重共享在空间上,一个共享在时间上。文字更麻烦,词得先变成数: 让每个词自己学一串数,意思相近的词这串数也相近。输出也可以是一串, 而当一份内部状态压不下整个输入时,就让输出端每写一个字都回头看一遍输入 —— 这叫注意力这本书写于 2017 年那篇论文之后、大模型时代之前,它只把注意力当成一个补丁。

⑪ 前面全是「判断」,现在让它「造」。 造文本的机制朴素到反常:只训一件事 —— 看前四十个字符猜第四十一个,猜完接回去再猜。外加一个旋钮控制它有多敢冒险, 这个旋钮的名字叫 temperature,原封不动活到了今天每一家大模型的接口里。 造图有两条别的路:把一张图压成两个数再还原,或者让两个网络一个造假一个鉴定、互相逼。

⑫ 连标签这根拐杖也扔掉。 上一步那两条路确实不用人贴标签 —— 但答案就在数据自己身上: 把这张图还原出来,对不对当场就知道。下棋不行,下棋连答案都没有, 只有一局打完之后的一个分,而且常常来得很晚。于是只能自己造训练信号: 这局撑得久,就把这局做过的动作整体往正的方向推。奖励太稀疏时这招失效, 改问「这一步连同以后所有的分加起来值多少」—— 强化学习就变回了一个普通的回归问题

⑬ 能力线到顶,剩下的全是工程。 怎么测一个每次跑都不一样的东西、 怎么把一个 14MB 的模型压到 3.5MB 而不崩(它压不住:准确率从 0.618 掉到 0.280,只好退回 7MB)、 怎么让它在浏览器 / 服务端 / 插件 / 桌面 / 手机 / 小程序 / 单片机这七种地方跑起来。

⑭ 最后作者亲手把它拆掉。 前面十三步造出来的那台机器,本质上只是一长串几何转换, 把一个空间里的点搬到另一个空间里去。证据很硬:一张大熊猫照片加上一层人眼看不出的扰动, 它就笃定地说是长臂猿;给八个样例,人会画一个圈,它画的是一堆紧贴着样例的碎边界。 费曼那句话被引在这里:它并不复杂,只是量大罢了。

⑮ 所以呢。 你造的不是一个会理解的东西,而是一台把表示换来换去的机器 —— 第 ② 步那句「学的是换一种说法」在这里收口。承认这一点,前面十三步教的每一件事一点没变得不值钱: 它解决的是「看见」和「听见」,而这已经足够革命。

判断(我们的,不是书里的): 全书真正的落点是原书第 13 章(我们的 22),不是第 12 章。 最后一章必须写足,否则读者拿到的是一本 TensorFlow.js 手册。 如果错,会错在: 如果主人的用途是「查 TF.js 的 API 怎么写」,那 20、21 两章反而更重要。


二、逐章节级大纲(一节一行:进来时以为 → 出去时知道)

每章末尾标两样:主走查(红线二加强:一条具体输入贯穿全章,每步带数)和承重词 (「读岔了整章就塌」的那一两个,单开一节从现象讲起;其余就地一段话)。

01-revolution-and-javascript.md(原第 1 章)—— 已写完,不重写,补四处(主走查整条换掉)

  1. 进来时以为「认出照片里有没有人」就是把规则写细一点 → 出去时知道规则追不上变化,只能掉头:人给答案(标签),机器找规则
  2. 进来时以为 AI / 机器学习 / 神经网络 / 深度学习可以混着说 → 出去时知道是四层嵌套,而且机器学习里一大半根本不用神经网络(五个名字各给一句它干什么,不是列名字)
  3. 进来时以为模型在背答案 → 出去时知道它在找更好的表示:同一堆点换成极坐标就分得开了
  4. 进来时以为 2012 年的爆发是某个天才算法 → 出去时知道是硬件、数据、算法三股力量同时到位(那一串算法名同样拆成表格各给一句)
  5. 进来时以为浏览器只是展示界面 → 出去时知道五笔算得清的账:服务器钱、上传延迟、隐私、白拿用户显卡、免安装
  6. 进来时以为 TensorFlow.js 是个玩具库 → 出去时知道张量是这套东西的通用容器,以及它和 Keras 双向兼容的家谱(顺带补一句:这本书是《Python深度学习》的 JS 重写,肖莱是第四作者)
  7. 可带走的
  • 主走查(审稿意见:整条换掉,不用自拍那条): 用原书图 1-4 那条 —— 平面上一个点, 三步走完。① 笛卡儿坐标 (3, 1)(−3, 1):纵坐标同为 1,横坐标一正一负却都可能是白点, 两个坐标各自都切不开;② 换成「半径 + 角度」:(3,1) 是 3.16 / 18.4°,(−3,1) 是 3.16 / 161.6°, 半径一模一样,角度完全不重叠;③ 再算 |角度| − 135:−116.6 判白,+26.6 判黑 —— 一个阈值就完事。 再加一个 (−1.5, 0.5):半径只有 1.58、角度同样是 161.6°,说明第 ③ 步把半径这条无关信息整个扔了。 变换与判据是书里的(text/11-ch01-1-javascript.txt:159:167),三个具体坐标是我们按书里的规则自己挑的, 正文里要当场写明。这条走查正好压住本章承重词「表示」,而且不和 06 章 MNIST 那条逐层形状走查重题。
  • 承重词: 表示(§3 单开一节,从黑白点讲起);次:标签 / 样例 / 模型(§1 就地)。
  • 另外三处要补: ① §2 末尾一段塞了五个算法名一个没解释(段级配额上限 1),拆成表格,素材在原书信息栏 1-1; ② §2 与 §4 两处推给「后面会讲」——梯度下降在本章给一句能顶用的话(看答案差多远,再把每个数朝差得少一点的方向挪一丁点),正式机制仍归 02; ③ §6 家谱里补一句「这本书是《Python深度学习》的 JS 重写,肖莱是第四作者」(素材 08-fm.txt:504-fm.txt:11)。

02-first-model.md(原 2.1–2.2 + 附录 B 张量基础)

  1. 进来时以为训练一个模型要很多准备 → 出去时知道整条流水线只有六步(拿数据 → 装成张量 → 搭模型 → compile → fit → evaluate/predict),5 行 JS 跑得完
  2. 进来时以为张量是高深数学 → 出去时知道它是「带类型和形状的数值容器」,[40,1] 读得出是 40 个样例每个 1 个特征;批次那一维写成 null
  3. 进来时以为模型天生会预测 → 出去时知道单层密集层就是 y = kernel·x + bias,这两个数一开始是随机的,训练就是把它们挪对
  4. 进来时以为「误差」只有一种 → 出去时知道损失是你的一个函数(这里选平均绝对误差:[1.1,2.2,3.3,3.6][1,2,3,4] 算出 0.25),优化器是另一个选择
  5. 进来时以为损失下降是黑箱 → 出去时知道损失是一张碗,梯度指向碗壁最陡的上坡方向,训练就是反着它走一小步;步子(学习率)开到 0.5 会直接跳出碗外
  6. 进来时以为反向传播深不可测 → 出去时知道它就是链式法则从损失端一路乘回权重端,一个权重就能手算完
  7. 进来时以为训得久就是训得好 → 出去时知道 10 轮得到 0.318,比「永远猜平均下载时间 0.295 秒」这个笨办法的 0.220 还差(这叫欠拟合);200 轮 0.0488,才真的比笨办法好 4 倍
  8. 进来时以为学会了这条规律就能一直用 → 出去时知道拿 10000MB 去问它会得到 718 秒,而训练集里根本没有这么大的文件(外推)
  • 主走查: 训练集第一个样例 sizeMB=0.080 / timeSec=0.135(书里的真数,规律是 0.1 + 0.07×大小)→ 随机初值 → 10 轮 MAE 0.318 → 200 轮 0.0488另起一处:单权重反向传播,x=2, y=5, v=0 → 损失 25 → 梯度 −20 → 学习率 0.01 → v 变成 0.2,理论最优 2.5。
  • 承重词: 梯度下降(单开一节,从「损失是一张碗」讲起)、反向传播(单开一节,手算)。这是全书唯一一章允许两个承重词都单开节的地方。

03-multifeature-workflow.md(原 2.3–2.4)

这一章管「一次评估怎么做才不骗自己」(和 11 章划死界线:那一章管「反复评估时怎么不骗自己」)。

审稿意见落实两处: ① 与 02 的「常识基准」撞车 —— 选了审稿人给的第二个方案: 0.220 和 0.295 是下载时间那份数据独有的、离开 02 章无处安放,所以常识基准的首次交付留在 02, 03 行 3 改写成「上一章你已经拿它比过一次,这一章把它变成一条纪律,并且看它在 12 个特征上怎么算」, 承重词从「常识基准」换成「均方误差」;② 节序倒置 —— 误差函数的选择必须排在基准之前, 否则读者在算基准时撞见一个没定义过的 MSE。

  1. 进来时以为多几个特征只是输入变长 → 出去时知道取值范围差出几个数量级(同一行里 tax:222 挨着 crim:0.3237),不先拉到同一把尺子上,训练会被大数那一路带跑
  2. 进来时以为拉尺子要写循环 → 出去时知道两个张量动作就够:按轴归约(一次算出 12 个列平均)+ 广播(一个 12 长的向量能直接减到 333×12 的表上)
  3. 进来时以为误差就是误差、02 章那把尺子接着用就行 → 出去时知道尺子是的:一个样例差 30,平均绝对误差记 3,均方误差记 90;怕大错就选后者,这一章选后者
  4. 进来时以为基准是上一章比过一次的事 → 出去时知道它是开工前必须先算出来的一个数,而且换一个任务、换一把尺子就得重算:永远猜平均房价 22.77 千美元,均方误差 85.58,折回去是差 9250 美元
  5. 进来时以为「测试损失 25.32」这个数字自己会说话 → 出去时知道它只在 85.58 旁边才叫「好」:折回去是差 5030 美元 对 9250 美元,少了将近一半
  6. 进来时以为训练集加测试集两份就够 → 出去时知道中间还得有验证集:测试集一旦被你拿来做过选择,它就不再是没见过的数据
  7. 进来时以为权重能读出因果 → 出去时知道线性模型的权重确实能读方向和大小,但两个特征强相关时权重会乱窜,而且相关不是因果(房顶湿度与房价)
  • 主走查: 波士顿房价一条真实记录 {crim:0.3237, zn:0, indus:2.18, …, tax:222, ptratio:18.7, lstat:2.94} → 标准化 → 线性模型 → 测试 MSE 25.32 对基准 85.58(折成平均差 5030 美元 对 9250 美元)。
  • 承重词: 均方误差(单开一节,从「同样差 30,一个记 3 一个记 90」讲起);次:标准化(z-score)、验证集。常识基准在这里是回指 + 升格成纪律,不重新交付。

04-nonlinearity.md(原 3.1)

  1. 进来时以为不够强就多叠几层 → 出去时知道纯线性层叠一百层还是一条直线;书里做了对照实验,把 sigmoid 拆掉,均方误差立刻从 14~15 退回 25
  2. 进来时以为激活函数是数学细节 → 出去时知道它是容量的唯一来源:把任意大小的数挤进 0~1,级联起来就折得出弯的形状
  3. 进来时以为加了非线性就学不了直的关系 → 出去时知道 sigmoid 中段本来就近似一条直线,原来的线性关系一点没丢
  4. 进来时以为「容量」是个模糊形容 → 出去时知道它指这个模型能表示多丰富的关系,而且有边际:再叠一层从 701 个参数涨到 3251 个,均方误差只从 1415 降到 10.813.4
  5. 进来时以为参数都能像上一章那样读出含义 → 出去时知道隐藏层那 900 个参数一个也读不出来,深度学习是拿可解释性换容量
  6. 进来时以为调模型靠灵感 → 出去时知道先要分清两种数:训练会改的叫权重,训练不改、由你定的叫超参数(层数、每层几个单元、学习率、训几轮);后者不可微,只能靠网格搜索这类笨办法试(5×4=20 组)
  • 主走查: 同一份波士顿房价、同一条记录 → 12 个特征 → 50 个 sigmoid 单元 → 1 个输出。参数逐个算清:12×50+50=650,加 50×1+1=51,共 701;测试 MSE 从 25 降到 1415(平均差 37003900 美元 对 5000 美元)。
  • 承重词: 非线性 / 激活函数(单开一节,从「叠层为什么会白叠」讲起);次:超参数。

05-classification.md(原 3.2–3.3)

  1. 进来时以为分类就是输出 0 或 1 → 出去时知道输出层吐的是 0~1 的概率,判成哪一类取决于你划在哪儿的阈值(默认 0.5,可以挪)
  2. 进来时以为准确率高就是模型好 → 出去时知道 100 个网站里只有 5 个是钓鱼网站时,一个「永远猜不是」的废模型也有 95%
  3. 进来时以为一个准确率数字够看 → 出去时知道要摊成四格表(真阳 4 / 假阳 1 / 假阴 2 / 真阴 93),从中读出精确率 80%(说是钓鱼的里有多少真是)和召回率 66.7%(真钓鱼的里抓到几个)
  4. 进来时以为阈值该有标准答案 → 出去时知道挪阈值就是在这两者之间换;把每个阈值画成一个点连成曲线,曲线下面积随机是 0.5、这个模型是 0.981
  5. 进来时以为既然看准确率就拿它当训练目标 → 出去时知道不行:准确率是台阶函数,导数处处为零,梯度一算全是零,训练一步也走不动
  6. 进来时以为交叉熵只是另一个误差公式 → 出去时知道它专盯「你给正确答案打了多少概率」:同样是 0.9,它给 0.100 的损失而均方误差只给 0.01,所以越接近正确它越不松手
  7. 进来时以为三个类别可以编成 0/1/2 → 出去时知道那等于告诉模型「类别 2 比类别 0 大两倍」;正解是每类一个格子(one-hot),输出层换成把几个数变成和为 1 的概率
  8. 进来时以为选哪种输出层是记忆题 → 出去时知道它是一张三行的配方表(回归 / 二分类 / 多分类各自的最后一层、损失、指标),这张表到最后一章(第 22 章)还会再用一次,那里给完整版
  • 主走查: 钓鱼网站检测,一个网站的 30 个特征 → 输出概率 0.8 → 阈值 0.5 判「是」;100 个测试样本摊成 4 / 1 / 2 / 93 → 精确率 80%、召回率 66.7% → 曲线下面积 0.981。另起一处: 鸢尾花三分类,[-3, 0, -8][0.047, 0.952, 0.0003]
  • 承重词: 交叉熵(单开一节,从「为什么不能拿准确率当目标」讲起);次:混淆矩阵那一家(精确率 / 召回率 / ROC / AUC)。

06-convnet.md(原第 4 章)—— 主张:卷积这个想法能吃图,也能吃声

  1. 进来时以为图像喂进去之前要拉成一长串 → 出去时知道拉直就把「谁挨着谁」永久丢了;图像要保持成 [高,宽,通道],一批就是四维
  2. 进来时以为卷积是个数学名词 → 出去时知道它就是拿一块 3×3 的小窗在图上一格一格滑,每停一处把窗里的数和窗上的数对位相乘再相加(和图像编辑软件里的锐化滤镜是同一件事)
  3. 进来时以为窗这么小看不到什么 → 出去时知道关键不在窗小,在同一块窗扫遍全图:同样把 28×28 的一张图换成一层特征,卷积用 160 个参数,密集层要 848 万个 —— 差五万三千倍
  4. 进来时以为池化只是省算力 → 出去时知道它换来两件事:数字挪一两个像素也照样认,以及下一层的窗能间接看到 11×11 而不只是 5×5
  5. 进来时以为「网络是分层认东西的」是可以直接信的 → 出去时知道此刻你只能信它:原书图 4-6 说浅层认边和角、中层认眼睛鼻子、深层才认出猫,但书在这一章没给任何证据;第 10 章会把每一层的输出真打印出来给你看(记进许诺兑现表)
  6. 进来时以为「卷积好」是句口号 → 出去时知道书里做了同参数量的对照:99.0% 对 97.0%,错误率差 3 倍(随机猜是 10%)
  7. 进来时以为模型越大越好 → 出去时知道 59 万参数的加强版会开始背训练集,得在中间插 dropout:训练时随机把一部分输出置零,逼它们别互相勾结(Hinton 的银行柜员故事)
  8. 进来时以为模型训完就只在内存里 → 出去时知道存出来是两个文件(一份 JSON 结构 + 一份二进制权重),下一章要用的 MobileNet 就是这么加载进来的
  9. 进来时以为卷积是图像专用 → 出去时知道把一秒声音切成 43 帧 × 232 个频率格,它就是一张 43×232 的图,同一套结构认 20 个口令能到 94%
  • 主走查: MNIST 里一张写着「7」的图 → [28,28,1] → 16 个 3×3 核 → [26,26,16] → 池化 [13,13,16] → 32 个核 → [11,11,32] → 池化 → 扁平 → 64 → 10 个概率,第 8 个最大。另起一处: 一秒「stop」录音 → 43×232 时频谱 → 同一套结构。
  • 承重词: 卷积(单开一节,滑窗点积配 ASCII 图);次:参数共享。
  • 移走的: tfjs-node 安装 / CUDA / GPU 快 5 倍 → 21 章。06 只留一句「这个加强版大到浏览器训不动,书里搬到 Node 上训,怎么装、怎么用显卡见第 21 章」,这句要记进许诺兑现表
  • ⚠ 原书自相矛盾,必须当场交代(审稿意见落实): 原书 4.2 一节里混着两版模型的数。 4.2.1 那段算「200 个参数 对 361 万个」用的是 5×5 的核、8 个过滤器、输出 24×24×8(:123); 可代码清单 4-1 写的是 3×3 的核、16 个过滤器、输出 [26,26,16](:61:143)。 4.2.4 更是同一节里先说扁平层输入是 [4,4,16]、后说是 [3,3,32](:158:163),按清单 4-1 推下去应该是 [5,5,32]→[800]决定:整章统一到代码清单 4-1 那一版(那是读者真能跑起来的代码), 参数量换成我们自己按清单 4-1 算的 160(3×3×1×16 + 16)对 848 万(784 × 10816), 正文里当场写明「这两个数是我们按代码清单 4-1 推的,原书 4.2.1 那段用的是另一版模型(5×5 核、8 个过滤器),给的是 200 对 361 万」, 并顺带点破 4.2.4 的形状矛盾。

07-transfer-learning.md(原第 5 章)

  1. 进来时以为教模型认一个新类别就得重训 → 出去时知道别人在百万张图上训好的模型,前面那些层学到的边、角、纹理对你的任务同样有用,你只要换掉最后几层
  2. 进来时以为「复用」就是拿来接着训 → 出去时知道先把借来的层冻住能买到三样东西,书里给了四个数(这组数来自 MNIST 前五个数字迁到后五个数字那个示例,不是摄像头那 50 张图):冻住训一轮损失 0.30、准确率 0.87→0.91、训完 0.97、耗时 30 秒;不冻是 0.37 / 0.87 / 0.95 / 60 秒。书自己的结论是「非固化策略并未导致结果的显著改进」,所以卖点要写准:起点更好、时间省一半(冻住的层不参与反向传播)、最终只差两个点 —— 不许写成「把人家的权重冲毁」,书里没这么说;要提大梯度就照书里写成「训练早期梯度很大、所有权重剧烈波动,固化把这段波动挡在外面」。而且冻了必须重新 compile 才生效
  3. 进来时以为输出形状对不上就没法用 → 出去时知道可以从中间截断:MobileNet 第 87 层出来的是 7×7×256 ≈ 1.25 万个数,这就是这张图的嵌入 —— 比原图 15 万个数小一个数量级,却更好用
  4. 进来时以为模型搭好就固定了 → 出去时知道层可以像管道一样接:符号张量是「还没有数、只有形状的占位符」,拿它当接头就能把新头部焊到旧模型上
  5. 进来时以为迁移只有一种做法 → 出去时知道三种(冻住直接接头 / 先把嵌入算出来存下再训一个小模型 / 端到端换头),快慢与灵活性各不同
  6. 进来时以为训完新头部就到头 → 出去时知道还能微调:解冻顶部几层、重新 compile、用很小的学习率再训一轮,口令识别从 84% 提到 90~92%
  7. 进来时以为迁移只能在同类任务之间做 → 出去时知道分类模型能改成「画框」的回归模型,但两路误差量级差太远,得自己写损失函数把形状那一路乘以 224 才配平
  • 主走查: 摄像头拍的 4 个方向各 50 张图 → 截断的 MobileNet → 每张变成 1.25 万个数的嵌入 → 新头部(扁平 + 两层密集,最后 4 类)→ 几秒训完 → 拿它玩吃豆人。
  • 承重词: 嵌入(单开一节,从「截断模型,看中间层吐出什么」讲起 —— 第 13 章的词嵌入是同一个想法,那里要回指);次:固化与微调。

08-data-pipeline.md(原 6.1–6.3 + 附录 B 内存管理)

  1. 进来时以为数据就是先读进内存的一个数组 → 出去时知道大数据集根本读不进来(Node 默认上限 1.4GB),要改成一条惰性的流:声明时一个字节都不读,取到哪条才去拿哪条
  2. 进来时以为流只能来自文件 → 出去时知道三种来源(现成数组 / CSV 网址 / 自己写的生成器函数),生成器那种能造出无限多的样例
  3. 进来时以为链式调用每一步都会遍历一遍数据 → 出去时知道它们只是在搭流水线;书里用一个计数器证明了「先跳过再转换」比反过来少算一大截
  4. 进来时以为流没法划分训练集和测试集 → 出去时知道用同一个随机种子打乱两次、一次取前面一次跳过前面就行;而标准化在流上要用闭包一边走一边累计 —— 无限流根本算不出真平均
  5. 进来时以为训练只有 fit 一个入口 → 出去时知道流要用 fitDataset,而且得你自己告诉它一轮算几批(卡牌游戏:50 轮 × 50 批 × 100 = 25 万个样例,准确率 75%)
  6. 进来时以为浏览器拿不到实时数据 → 出去时知道摄像头和麦克风也是流(每次抓一帧),但要先空跑几次预热,否则第一次推断慢得离谱
  7. 进来时以为 JavaScript 会自动回收内存 → 出去时知道张量住在显卡里、垃圾回收管不着:一个每帧推断的循环会一直漏,要么手动释放,要么整段包进 tf.tidy;张量计数能直接看出有没有在漏
  • 主走查: 同一份波士顿房价 CSV,这次做成流 —— tf.data.csv(url) 声明完毕、零请求 → .skip(300).take(1).toArray() 才真正发出请求,拿回 {crim:0.3237, zn:0, indus:2.18, …, tax:222, lstat:2.94} → 配置哪一列是标签 → 分批 → fitDataset。另起一处: 摄像头一帧的抓取与释放。
  • 承重词: 惰性流(单开一节,从「数据大到读不进来」讲起);次:张量要手动释放(这是浏览器端独有的账,母本没有)。

09-dirty-data.md(原 6.4–6.5)

  1. 进来时以为拿到数据就能训 → 出去时知道整套训练建立在一个前提上:每个样例都是从同一个分布里独立抽出来的。前提一破,前面所有评估数字都不作数
  2. 进来时以为数据集不会「有偏」→ 出去时知道最常见的两种偏斜长什么样:训练时只见过工作日的路况、麦克风坏掉那半天录的音
  3. 进来时以为文件里的行序无所谓 → 出去时知道加州房价那份 CSV 是按经度排好的,前一半全是海边、后一半全是内陆;打乱窗口开到 10、50、250 都没用,要开到 6000,画出来那条斜线才散开
  4. 进来时以为离群值只是几个怪数字 → 出去时知道一个 145000 公斤的体重会把整把尺子带歪,要么截断,要么另加一个「这是离群值」的特征
  5. 进来时以为缺失值填个平均就完了 → 出去时知道先得分清它为什么缺(完全随机缺 / 随别的特征缺 / 因为它自己的值才缺),第三种填什么都是错的;四种补法各有代价
  6. 进来时以为数据不够只能去收集 → 出去时知道可以造伪样例(把猫图旋转、错切),但它产生不了新信息,而且绝不能用在验证集和测试集上
  • 主走查: 加州房价那 17000 行 → 画「经度 对 行号」发现是一条斜线 → 直接切前 80% 会训出一个只认海边的模型 → 打乱窗口 10 → 50 → 250 → 6000,斜线才散开。另起一处: 一张猫图旋转/错切成伪样例。
  • 承重词: 独立同分布这个前提(单开一节,从经度那个事故讲起);次:偏斜。
  • 接线: 这一章的事故和 11 章「时序数据的验证集必须在训练集时段之后」是同一个坑的两面,两边都要点破。

10-visualization.md(原第 7 章)

  1. 进来时以为可视化就是给报告配图 → 出去时知道它是唯一能看见「数据长什么样、模型在看什么」的手段;五种图各管一件事(折线看趋势、散点看两列的关系、柱状看每一项、直方看分布、热图看矩阵)
  2. 进来时以为数据画得越全越好 → 出去时知道 42 万个点画出来是一团黑,要靠三招才看得见:只画一段时间、每 6 个点取 1 个、只挑几列;还得先标准化,否则气温(−1040)和气压(9801000)根本画不进同一张图
  3. 进来时以为「越深越抽象」只是第 06 章那句没证据的说法 → 出去时知道它是能一层层取出来看的东西:同一张猫照片,第 1 组卷积层的输出还像原图(边缘、色块),第 5 组只剩几块亮斑(兑现 06 行 5 的许诺)
  4. 进来时以为拿到图就算看见了 → 出去时知道还能读出第二件事:亮着的格子一层比一层少,深层甚至整片空白 —— 空白说明那个过滤器要找的东西这张图里没有;这条路是在提纯,不是在描摹
  5. 进来时以为「这个过滤器在找什么」没法回答 → 出去时知道可以反过来问:固定住权重,让一张随机噪声图自己去变,每一步朝「让这个过滤器输出更大」的方向挪,80 步之后浮现的花纹就是它想看到的东西
  6. 进来时以为模型说「埃及猫」你只能信 → 出去时知道能让它指出看的是哪一块:拿类别概率对最后一层卷积输出求梯度,加权求和成一张 14×14 的灰度图,放大回 224×224 盖在原图上,亮的正是猫脸
  7. (章末)进来时以为「对输入求梯度」是可视化专用 → 出去时知道第 22 章会用完全一样的动作把模型骗过去(原书 13 章自己点破了这条线,要接上)
  • 主走查: 一张 cat.jpg → VGG16 → 第 1 组卷积层的输出(边缘、色块)→ 第 5 组(几块亮斑)→ 「埃及猫」概率 0.89 → 类激活图落在猫头上。
  • 承重词: 对输入求梯度(单开一节,从「过滤器想看到什么」讲起);次:类激活图。

11-fitting-workflow.md(原第 8 章)—— 管「反复评估时怎么不骗自己」

  1. 进来时以为损失一直降就是好事 → 出去时知道要同时盯两条线:两条都高是欠拟合,训练降验证升是过拟合,这两条线的走势是你唯一的诊断依据
  2. 进来时以为欠拟合就是训得不够 → 出去时知道也可能是模型根本表示不了:线性回归预测耶拿气温,平均差 7.6 摄氏度,再训一百轮还是这个数
  3. 进来时以为过拟合只能减层 → 出去时知道第一件武器很反直觉:在损失里加上所有权重的平方和,逼模型别把哪个权重调得太大
  4. 进来时以为正则化是玄学 → 出去时知道它是奥卡姆剃刀的算法版,而且看得见:加了之后把权重画成直方图,分布明显变窄
  5. 进来时以为治过拟合就这一招 → 出去时知道还有第 06 章那个 dropout、把绝对值加进损失的那种、把每层输出重新拉回同一尺度的批标准化,以及最省事的早停(连续几轮不再变好就停)
  6. 进来时以为拿到问题就该建模 → 出去时知道通用流程第一步是问「这件事该不该用机器学习」(书里拿两数相加当反例),然后才是定指标、定评估方案(时序数据的验证集必须在训练集时段之后)、定基准
  7. 进来时以为调参就是把每个旋钮试一遍 → 出去时知道正确顺序是先刻意做到过拟合、找到容量的临界点,再往回加正则化;而且拿验证集调得太久,验证集也会被你「训」过一遍,所以测试集只能用一次
  • 主走查: 耶拿气象数据(前 10 天 × 14 个指标,共 240 步)→ 预测 24 小时后的气温。线性回归验证 MAE 0.9(折回 7.6 摄氏度)→ 加隐藏层的 MLP 训练 0.2(1.7 度)但验证 0.35(3 度)且往上翘 → 加正则化后两条线重新贴住,验证落在 0.29 上下
  • ⚠ 跨章台阶,审稿意见落实(不许省): 主走查末尾必须补上「贴住 ≠ 有用」这一级 —— 正则化版 MLP 的验证 MAE 书里只给了曲线、没给数字,但书在下一章明说这条曲线 「和第 8 章 MLP 模型得到的最佳结果大致相等,甚至还要稍微好一点」, 而它比的那个数是 0.2903(text/21-ch09.txt:63)。所以这一章收尾要当场写一句: 两条线是贴住了,可贴住的水平大约是 0.29 —— 而这个 0.29 到底算好算坏,下一章要用一行代码的笨办法来回答。 不给这一级,读者出门时会相信模型已经修好了,而 12 章开口就推翻它。这一句要记进许诺兑现表。
  • 承重词: 过拟合 / 欠拟合(单开一节,从「两条曲线分叉」这个现象讲起);次:正则化。
  • 与 03 的界线(写死): 03 讲一次评估(基准怎么升格成纪律、三件套、误差函数怎么选),11 讲反复评估(曲线怎么读、武器怎么选、调参纪律)。dropout 的机制只在 06 讲一次,11 只把它摆进武器表里回指,不重讲。

12-rnn.md(原 9.1)

  1. 进来时以为把 240 步 × 14 个指标拉成一长串喂进去就行 → 出去时知道密集层对顺序完全无感:把这 240 步打乱,算出来一模一样,因为乘法和加法本来就不分先后
  2. 进来时以为你上一章刚修好的那个模型至少是有用的 → 出去时知道它贴住的那个水平,一行代码就能达到:「24 小时后的气温 = 现在的气温」,MAE 0.2903;上一章那个正则化版 MLP 停在 0.29 上下,打了个平手,等于白训(这是 11 章那句许诺的兑现,不是反转)
  3. 进来时以为循环神经网络是另一套复杂结构 → 出去时知道它就是「包在 for 循环里的一个小单元」:每一步吃当前时刻的输入,再吃上一步自己吐出来的状态,算完又传给下一步
  4. 进来时以为「记住状态」要很多参数 → 出去时知道正相反:那个小单元的权重被 240 个时刻反复共用,1537 个参数打赢 10.7 万参数的 MLP(0.27 对 0.29)—— 这和第 06 章卷积核扫遍全图是同一个想法,一个共享在空间上,一个共享在时间上
  5. 进来时以为 RNN 处处都好 → 出去时知道两处硬伤:第 t 步必须等第 t−1 步算完,没法并行(一批 3000 毫秒 对 950 毫秒);而且序列一长,前面的信息在一路相乘中衰减到没有
  6. 进来时以为要用 GRU / LSTM 得先看懂公式 → 出去时知道要点只有一句:多了两个门,由数据自己学出「这一步该记多少、该忘多少」;换上去,验证 MAE 降到 0.266
  • 主走查: 和 11 章同一份耶拿数据、同一个任务、同一个输入 [240, 14] → 先证明打乱顺序结果不变 → simpleRNN(32 单元)→ 1537 个参数 → MAE 0.27 → GRU 0.266,并排放着基准 0.2903
  • 承重词: 状态回流(循环)(单开一节,从「打乱顺序结果不变」这个现象讲起);次:参数共享在时间上的版本(回指 06)。

13-text-representation.md(原 9.2)

  1. 进来时以为文字可以直接喂给模型 → 出去时知道模型只吃数;而且书里先说清一件事:这类模型不理解句子的意思,它只是在统计结构和标签之间搭一座桥
  2. 进来时以为给每个词编个号就行 → 出去时知道编号隐含大小顺序,得改成一万个格子只有一个是 1;一句 18 个词的话因此变成 18 万个数,词表外的词还只能统统算作一个「不认识」
  3. 进来时以为那就把这些格子加起来 → 出去时知道好处是不管多长都是定长的一万个数,代价是顺序全丢:情感分析能到 0.89,但「别误会,我不是说它不好」这种双重否定它读不出来
  4. 进来时以为词的向量得由人设计 → 出去时知道词嵌入是一张可训练的表:500 个词每个配 128 个数共 6.4 万个,而一万格子的做法要 500 万个;训完之后意思相近的词,这串数也相近
  5. 进来时以为抓顺序只能靠上一章的 RNN → 出去时知道一维卷积也行:一个宽 5 的窗沿句子滑,窗内五个词的先后它分得清;准确率 0.91,比 LSTM 还高一点、快 6 倍
  6. 进来时以为卷积能一路用下去 → 出去时知道它只看得见窗内那几个词,隔得远的呼应抓不到,得靠堆叠一层层把视野撑开
  7. 进来时以为把句子处理成模型能吃的样子只是琐事 → 出去时知道长度不齐要统一裁到 500 并在前面补零,而且浏览器端这套预处理必须和训练时一模一样,否则就是自己给自己制造第 09 章那种偏斜
  • 主走查: 一条 IMDb 影评(书里那句双重否定的例子)→ 小写去标点 → 查表变词号,不认识的记成「不认识」→ 裁到 500 并前补零 → 定长向量的做法 0.89、读不出双重否定 → 换成嵌入 + 一维卷积,0.91。
  • 承重词: 词嵌入(单开一节,从「6.4 万对 500 万」和「意思变成距离」讲起,回指 07 的嵌入);次:定长向量化(one-hot / multi-hot)。

14-seq2seq-attention.md(原 9.3)

  1. 进来时以为输出只能是一个数或一个类别 → 出去时知道输出也可以是一串:输入「JUL 18, 2034」,输出「2034-07-18」,一个字符一个字符地吐
  2. 进来时以为一串换一串就是逐位翻译 → 出去时知道要分成两半:一半把整个输入读成一份内部状态,另一半拿着这份状态从头生成;训练时喂给后一半的是右移一格的正确答案,推断时只能喂它自己上一步吐出来的字符
  3. 进来时以为这样就够了 → 出去时知道瓶颈在中间那份状态:不管输入多长,全部意思都被压进这一份固定大小的数里
  4. 进来时以为办法是把状态做大 → 出去时知道正解是让生成端每写一个字符就回头看一遍输入端每一步的输出,按「和我现在要写的这个字符有多相关」加权取用
  5. 进来时以为注意力是个说法 → 出去时知道它是一个能打印出来的矩阵:10 个输出位置 × 12 个输入位置,画成热图,能看见模型写年份那四位时亮的正好是输入里年份所在的位置
  6. 进来时以为生成时每步挑概率最大的字符就是最优 → 出去时知道那只是贪心,真要更好得同时留住几条候选路
  7. (时代坐标)进来时以为注意力是给这套结构打的补丁 → 出去时知道 2017 年之后它反过来吃掉了整个架构:去掉循环、只留注意力,这就是今天所有大模型的底座 —— 书成稿于 2019 年 9 月,没有这一步
  • 主走查: 「JUL 18, 2034」→ 逐字符嵌入 → 编码成一份状态 → 解码第一步吃 <ST> 吐出「2」,此刻注意力矩阵亮的是输入里的「2034」→ 逐字符吐完「2034-07-18」。
  • 承重词: 注意力(单开一节,从「那一份状态压不下」这个瓶颈讲起);次:编码器 - 解码器。
  • 外部缺口(全书最大的一处): Transformer。不上网,引母本 book=deep-learning-with-python-2e §11-text-transformer,备选 build-large-language-model §03-attention-core

15-text-generation.md(原 10.1)

  1. 进来时以为 14 章那个逐字符吐出「2034-07-18」的模型就叫「造」 → 出去时知道那个任务的答案由输入唯一决定(输入写着 2034,输出就得是 2034),原书把它当成分类题在做;这一章要的是没有唯一答案的东西,所以连「对不对」都得重新定义 —— 原书 10.1 开篇自己写着「在上一章的日期格式转换示例中……然而,这明显不适用于本章的文本生成任务。这是因为此处既没有明确的输入序列,也无法准确地定义输出是什么」(text/22-ch10.txt:41) 判别式 / 生成式的分野放在这一步之后再落地,不许当前提 —— 因为 14 章的模型确实在「造」,拿它当反例会被读者当场证伪
  2. 进来时以为生成文本需要懂语法 → 出去时知道机制朴素到反常:只训一件事 —— 看前 40 个字符猜第 41 个;猜完接到末尾、丢掉最前一个,再猜下一个
  3. 进来时以为「猜得准不准」没有参照 → 出去时知道有:香农 1951 年测出英文每个字母约 1.3 位信息,而 71 个字符里瞎猜是 4.7 位;模型损失从 3.2 降到 1.4~1.5,离人类语言的下限已经不远
  4. 进来时以为每步挑概率最高的字符最好 → 出去时知道那会立刻掉进复读,同一句话反复吐
  5. 进来时以为随机挑就行了 → 出去时知道要有一个能拧的旋钮:把概率取对数、除以一个温度值、再归一化。低温把大的抬得更大([0.1,0.7,0.2] 在 0.25 下成 [0.0004,0.993,0.0066]),高温拉平(0.75 下是 [0.059,0.792,0.149]);排序始终不变,变的只是差距
  6. 进来时以为这个旋钮是这本书的土办法 → 出去时知道它原封不动活到了今天:你在任何一家大模型接口里看到的 temperature,就是这里这个数
  • 主走查: 莎士比亚文本,一个 40 字符的窗口 → 堆叠 LSTM → 71 个字符各自的概率 → 温度 0.25 和 0.75 各采样一次,给出两段风格不同的续写 → 接到末尾、窗口右移一格 → 再来一次。
  • 承重词: 温度(单开一节,从「总挑最大的就会复读」这个现象讲起);次:判别式与生成式的分野。

16-latent-space-and-vae.md(原 10.2)—— 审稿意见落实:GAN 已拆出去,不留到写作时再定

  1. 进来时以为压缩和生成是两件事 → 出去时知道自编码器长得像一个沙漏:把 784 个像素挤成 2 个数,再从这 2 个数还原回 784 个像素;能还原得回来,说明这 2 个数装下了这张图的要点
  2. 进来时以为中间那两个数只是压缩结果 → 出去时知道它们张开的那个平面可以漫游:在 20×20 的网格上取点、每点解码成一张图,能看见 T 恤连续变形成连帽衫再变成裤子
  3. 进来时以为经典自编码器就够用 → 出去时知道它的本征空间是散的、点与点之间有空洞;VAE 的做法是不输出一个点,而是输出一个均值和一个方差,再从中随机取一个点来解码 —— 逼着邻近的点也必须解码得像样
  4. 进来时以为「随机取一个点」没法训练(随机的东西求不了导) → 出去时知道把随机挪到旁路:结果 = 均值 + 标准差 × 一个从标准正态里抽的数,梯度照样能穿过均值和方差回去
  5. 进来时以为损失还是老一套 → 出去时知道有两笔账要一起算(还原得像不像 + 分布散不散),两笔量级差得远,配平的手法和第 07 章那个乘 224 是同一个;而且这种多输出损失 fit() 装不下,得自己写训练循环
  • 主走查: Fashion-MNIST 里一件 T 恤(28×28 = 784 个数)→ 编码成均值 2 个数、对数方差 2 个数 → 采样出中间那 2 个数 → 解码回 784 → 在 20×20 网格上漫游,看它连续变成连帽衫。
  • 承重词: 本征空间(单开一节,从「两个数就能还原一张图」讲起);次:重参数化、两笔损失的配平。
  • 拆章依据: 五行里要交付的生面孔是自编码器 / 编码器 / 解码器 / 本征向量与本征空间 / 均值与方差 / 采样 / 重参数化 / 两笔损失 / 自定义训练循环 —— 摊到四五个小节上才压得进节级配额。

17-gan.md(原 10.3)

  1. 进来时以为造图只有上一章那条路 → 出去时知道还有完全不同的一条:一个网络造假、一个网络鉴定,轮流训。鉴定方看真图假图各一批学着分辨;造假方把自己造的图贴上「真」的标签、并把鉴定方冻住,于是梯度只往造假方回流
  2. 进来时以为造图的网络也是卷积 → 出去时知道它反着走:从 100 个随机数出发,先密集成 3×3×384,再一层层放大到 7×7、14×14、28×28,用的是卷积的逆运算
  3. 进来时以为想生成哪个数字全凭运气 → 出去时知道给鉴定方加第二个输出(既判真假、也判类别),造假方就多了一个类别输入:让它生成一个「8」,它就生成 8
  4. 进来时以为 GAN 和别的模型一样训 → 出去时知道它的损失曲线根本不单调,你没法用损失判断训得好不好;能训起来靠的是一堆经验规矩(真实度标签用 0.95 不用 1、鉴定方里插 dropout、拿带步长的卷积代替池化)
  • 主走查: 100 个随机数 + 类别「8」→ 3×3×384 → 7×7 → 14×14 → 28×28 → 鉴定方给出「真实度 + 类别」两个输出 → 造假方拿着「真」这个标签、隔着冻住的鉴定方反传。
  • 承重词: 对抗训练(单开一节,从「没有标准答案,那就让另一个网络来当裁判」讲起);次:卷积的逆运算、ACGAN 的条件生成。

18-rl-policy-gradient.md(原 11.1–11.2)

  1. 进来时以为学习一定要有标准答案 → 出去时知道还有第三种:没人告诉你这一步对不对,只有一个事后的分,而且分常常要等很久才来
  2. 进来时以为强化学习是一堆新名词 → 出去时知道就五个:做事的那个、它面对的世界、它能做的动作、它看得到的东西、做完之后世界给的分;在倒立摆里这五个分别是什么,能一一指出来
  3. 进来时以为策略网络输出的就是要做的动作 → 出去时知道它输出的是「往左推」的概率,然后掷一次骰子决定;不掷骰子就永远试不到没试过的做法,全靠骰子又用不上已经学会的东西
  4. 进来时以为没有标签就没有训练信号 → 出去时知道信号是自己造的:先按当前策略玩完一整局,把每一步的梯度都存下来;这局玩得长,说明这局里的动作大体是对的,就把这些梯度按正的方向用上
  5. 进来时以为一局里每一步的功过相同 → 出去时知道要打折扣:离结束越近的动作对失败的责任越大;再把一批局的奖励减均值除标准差,短局里的动作整体变负,长局里早期的动作整体变正
  6. 进来时以为这么土的办法不会有用 → 出去时知道倒立摆 25 次迭代、几分钟就能撑满 500 步上限;但曲线一路剧烈波动是常态,而且它要试错 400 局 —— 换成真车真机械臂,这个代价付不起
  • 主走查: 倒立摆一局:观察是 4 个物理量(位置、速度、角度、角速度)→ 策略网络输出一个数 → 变成概率 0.62 → 掷骰子选「向右推」→ 撑了 37 步倒了 → 折扣化 + 标准化后这一局早期的动作拿到负权重 → 25 次迭代后撑满 500 步。(0.62 和 37 步是为演示编的,书里只给 500 步和 25 次迭代 —— 正文里要当场标明。)
  • 承重词: 奖励(以及折扣与标准化)(单开一节,从「分数来得晚、而且一局只有一个」这个现象讲起);次:策略梯度。

19-rl-q-learning.md(原 11.3)

  1. 进来时以为上一章那套能通吃 → 出去时知道贪吃蛇就不行:走一步空地扣 0.2 分,吃到水果才加 10 分,绝大多数动作拿到的是同一个数,「这一步好不好」的信号被淹没了
  2. 进来时以为奖励稀疏就没办法 → 出去时知道换个问法:不问「这一步该做什么」,改问「在这个局面下做这个动作,把以后所有的分都算进来,值多少」
  3. 进来时以为「以后所有的分」算不出来 → 出去时知道它可以递归成两项:当前的即时奖励 + 折扣 × 下一个局面里最好那个动作的值。七状态的小例子里,一条路是 −3 + 0.9×10 = 6,另一条是 3 + 0.9×(−4) = −0.6,看着吃亏的那条其实更值
  4. 进来时以为这些值可以列成一张表 → 出去时知道 9×9 的贪吃蛇局面数是天文数字,表存不下;改成让一个卷积网络吃下 [9,9,2] 的局面、吐出三个动作各自的值
  5. 进来时以为强化学习到这儿更玄了 → 出去时知道恰恰相反:它此刻变成了一个普通的回归问题 —— 预测值去拟合「即时奖励 + 折扣 × 下一步最好的值」,损失就是均方误差
  6. 进来时以为一个网络就够 → 出去时知道目标是网络自己算的,自己追自己会震荡:要另开一个冻住的网络专门算目标,每 1000 步才同步一次
  7. 进来时以为一边玩一边训就行 → 出去时知道连续几步的局面高度相似,直接拿来训会相关到失效:走过的五元组要先存进一个滚动的池子,再从里面随机抽;而且乱走的比例要从 0.5 慢慢降到 0.01,但永远不降到 0
  8. 进来时以为训完就有一条完美的蛇 → 出去时知道数小时之后它平均吃到 18 个水果、学会了贴边走,但身体超过 20 节就会把自己困死
  • 主走查: 贪吃蛇 9×9 的一个局面 → [9,9,2] 张量(蛇头 2、蛇身 1、水果 1)→ 在线网络吐出三个值 → 乱走的比例决定听它的还是瞎走 → 走一步拿到 −0.2 → 五元组进池子 → 抽一批 → 冻住的网络算出目标 → 均方误差 → 反传。
  • 承重词: 值(Q)与它的递归写法(单开一节,从「这一步好不好没法直接知道」讲起);次:两个网络与回放池。
  • 深究引外书: book=reinforcement-learning-sutton-bartobook=an-introduction-to-deep-reinforcement-learning。这本只给入门。

20-test-and-shrink.md(原 12.1–12.2)—— 审稿意见落实:原 19 章一分为二

  1. 进来时以为模型训完就算交付 → 出去时知道模型是个二进制大文件,和代码一起进版本库会炸;而且流水线上每一段(数据、训练、模型、服务)都得单独测
  2. 进来时以为测模型就是断言准确率大于某个数 → 出去时知道训练有随机性,这种断言必然间歇性失败:先固定随机种子,然后只断言确定的东西 —— 形状对不对、训两轮损失有没有降、输出在不在 0~1 之间
  3. 进来时以为拿一组固定的输入输出对比最保险 → 出去时知道那是最容易腐烂的测试;线上出的错该回到训练集里去修,而不是变成一条单元测试
  4. 进来时以为模型文件大点无所谓 → 出去时知道 14MB 已经是一个普通网页(1828KB)的 8 倍;把每个权重从 32 位压到 8 位能省 75%,而且压完再 gzip 更小
  5. 进来时以为量化就是均匀地损失一点精度 → 出去时知道必须逐个模型试:房价模型和 MNIST 模型几乎纹丝不动,MobileNetV2 到 8 位直接崩(0.618 掉到 0.280),16 位却完全无恙
  6. 进来时以为推断速度只能靠换硬件 → 出去时知道换一种模型格式就能快 2030%(浏览器)到 7090%(Node):它把训练才用得上的灵活性丢掉,换来把批标准化那 6 个运算合成 2 个、把连着的几个运算并成一个
  7. 进来时以为计时就是前后各取一次时间 → 出去时知道推断函数不等显卡算完就返回了,必须等结果真取回来才算数;而且第一次调用永远特别慢,要先空跑几次
  • 主走查: 一个训好的 MobileNetV2 → 14MB → 8 位量化成 3.5MB,但准确率从 0.618 掉到 0.280 → 退回 16 位,7MB、准确率无恙 → 转成推断专用格式,浏览器里快 20~30% → 等结果真取回来再计时。
  • 承重词: 权重量化(单开一节,从「14MB 是普通网页的 8 倍」这笔账讲起);次:黄金值测试、推断专用格式与常数折叠。

21-seven-deployments.md(原 12.3 + 附录 A + 从 06 移来的 Node/GPU)

  1. 进来时以为「部署」就是把文件放到网站上 → 出去时知道光是发到网页上就有三笔账:跨域怎么配、浏览器缓存怎么碎、以及隐私换来的代价是模型会被人整个下走
  2. 进来时以为客户端和服务端二选一 → 出去时知道还有五种落点(浏览器插件 / 桌面应用 / 手机原生 / 微信小程序 / 单片机),每种在体积、隐私、算力上换的账都不一样,书里给了一张表逐条摆开
  3. 进来时以为训练也在这些地方跑 → 出去时知道训练那条路要回到 Node:CPU 版直接用和 Python 版一样的 C++ 库,要用显卡还得先装 CUDA 和 CuDNN(GPU 版比 CPU 版快 5 倍)
  4. 进来时以为持续训练是自动的 → 出去时知道要在流水线上插三道闸:样例校验器(身高不能超过 280 厘米这类)、模型校验器、以及分人群看指标的模型评估器
  • 主走查: 上一章那个 7MB 的 MobileNetV2 → 放到静态服务器 → 浏览器加载(跨域头、缓存)→ 同一份文件换到 Node、换到小程序、换到树莓派,逐处写出体积/隐私/算力这三笔账各变成什么。
  • 承重词: 落点决定你付什么代价(单开一节,从「同一个文件放到不同地方,变的不是代码是账」讲起);次:CUDA/cuDNN、持续训练。
  • 要还的债: 06 章那句「怎么装、怎么用显卡见第 21 章」在这里兑现。

22-limits-and-horizon.md(原第 13 章)—— 全书落点,必须写足

  1. 进来时以为读完前二十一章造出来的是个会看会听的东西 → 出去时知道作者亲手把它拆开:整个深度学习就是一长串可微的几何转换,把一个向量空间里的点搬到另一个向量空间里去 —— 第 01 章那句「学的是表示」在这里收口
  2. 进来时以为它至少认得它分对的那些图 → 出去时知道它看的根本不是内容:一张大熊猫照片加上一层人眼看不出的扰动,它就笃定地说是长臂猿;而算这层扰动的动作,和第 10 章画过滤器用的是同一个(原书自己点破了这条线)
  3. 进来时以为认错只是训练数据不够 → 出去时知道差别在泛化的方式:给 8 个样例,人会画一个圈,神经网络画出的是一堆贴着样例的不规则边界;它没有任何先验知识,所以只能靠海量标注去糊
  4. 进来时以为「不理解」是一句贬低 → 出去时知道费曼那句话说得更准:它并不复杂,只是量大罢了。承认这一点之后前二十一章一点没变得不值钱 —— 它解决的是感知问题,而这已经足够革命
  5. (新增,审稿意见落实:补原书 13.2.2/13.2.3 的覆盖漏洞) 进来时以为合上书就只剩感慨 → 出去时知道手上有两张现成的表: ① 三大网络类型怎么按输入数据挑(向量型数据 → MLP、图像与时频谱 → convnet、序列 → RNN), 配上 05 章那张输出层配方表的完整版(回归 / 二分类 / 多分类 / 多标签各自的最后一层、损失、指标)—— 这里兑现 05 行 8 那句「这张表到最后一章还会再用一次」; ② 一份 npm 装上就能用的现成模型清单,按「能干什么」组织而不是按包名: 认物体、框出位置、认人脸、认手、认人体姿势、认口令、判毒性发言、把句子变成向量、生成音乐 —— 这一节恰恰是母本一个字都没有的 JS 独有资产,不许漏
  6. 进来时以为作者的展望是套话 → 出去时知道 2019 年他押了六个方向(无监督 / 半监督、专用硬件、自动化建模、模型复用、新领域、边缘设备),2026 年回头逐条看,押中了哪几个、错在哪里
  7. 进来时以为学完这本书就到头了 → 出去时知道往下走有三条明确的路,以及这本书和母本、和书架上其他几本的分工(哪些问题回来问它,哪些它答不了)
  • 主走查: 一张大熊猫照片 → 模型说是熊猫 → 加一层由「长臂猿类别梯度」算出来的扰动 → 肉眼看不出差别 → 模型改口说是长臂猿。**⚠ 书里只有定性描述,没给百分比。**要用那两个经典数字就必须标「补充(不在书里,来自通用知识)」,或者干脆只用书里的说法。
  • 承重词: 局部泛化 vs 极限泛化(单开一节,从「8 个样例画边界」这个实验讲起);次:对抗样例。
  • 舍弃并写明理由: 原书 13.2.4 那张「可能性空间」清单(向量→向量、图像→文本……)整节舍弃 —— 它是把前面各章的任务重新排列一遍,对读者不产生新判断,而 13.2.2 / 13.2.3 那两张表是能带走的工具。
  • 要联网核的两处(全书仅剩两处): ① 六个预测的 2026 现状(后两条要外部);② WebGPU 在 TensorFlow.js 里的现状(影响 01 和 21 的「今天还成立吗」)。一次抓一个,同一地址失败两次立刻换源。

三、切章账:为什么是 22 章

依据全部是新词密度和走查数,不是字数。

改动原来现在依据
原书第 6 章(数据)拆两章一章08 + 09原文 73k + 30k 字符,合起来 11 个新词、3 条走查(超「一章最多另起两处」);而且两半是两件事:数据怎么流 / 数据本身是歪的
原书第 9 章拆三章两章12 + 13 + 14原文 32k / 38k / 28k,三条完全不同的走查(耶拿气温 / IMDb 影评 / 日期字符串);而且 14 要给最大的时代缺口(Transformer)留出地方
原书第 10 章(生成式)拆三章一章15 + 16 + 17全书新词密度最高的一章(12 个)。文本生成、VAE、GAN 是三种媒介、三条走查;16 单算就有 9 个承重面孔,不拆一定破节级配额
原书第 11 章(强化学习)拆两章一章18 + 19原文 42k + 54k,15 个新词,两个游戏、两套机制;而且「奖励稀疏 → 策略梯度失效 → 换价值法」正好是一次干净的「上一步逼出下一步」
原书第 12 章拆两章一章20 + 21审稿意见落实。 原来一章要吃第 12 章(86k 字节)+ 附录 A(10k)+ 从 06 挪来的 4.3(约 25k),约 120k 源文压进 17~24k,压缩比 1:5,而 04 章吃 3.1 的 21k 是 1:1 —— 两头差五倍且无交代。按原书自己的节界拆:20 = 12.1 测试 + 12.2 瘦身,21 = 12.3 七种落点 + 附录 A + Node/GPU
原书第 4 章瘦身十一个承重块挪走 tfjs-node / CUDA / GPU → 21「装 CUDA」和「卷积核怎么滑」是两个心智模式,读者在这里会断线。但 model.save/load 留在 06,因为 07 要靠它加载 MobileNet
03 与 11 划死界线界线模糊03 = 一次评估;11 = 反复评估两章都在讲「怎么算模型好不好」,不写死会讲重

压缩比核对(审稿意见要求写明): 22 章之后,单章吃的源文落在 21k60k 字节之间, 最厚的是 06(原书第 4 章 82k,已挪走 4.3 的 25k,余 57k)和 10(原书第 7 章 60k),压缩比约 1:2.5; 最薄的是 04(原书 3.1 约 21k)和 11(原书第 8 章 43k),约 1:11:2。没有一章还留着 1:5。

如果主人要更少的章: 唯一的合并候选是 08 + 09(合回原书第 6 章的一章);其余五处拆分都由走查数或节级配额硬顶着,合了就得砍解释。


四、自查:有没有两行的「出去时知道」是同一件事

逐对核过。下面前两组是审稿意见新查出来的,原来漏了;其余八组沿用上一版的判定。

疑似撞车判定
02「常识基准」与 03「常识基准」原来两处都写成第一次交付,是真撞车。 现在:首次交付留在 02(0.318 打不过 0.220 那一步,0.220 属于下载时间那份数据、离开 02 无处安放);03 改成回指 + 升格成纪律(换任务换尺子要重算,85.58 是怎么来的),03 的承重词换成均方误差
06「网络是分层的」与 10「层越深越抽象」原来两处的「出去时知道」是同一句、连例子都同是一只猫,是真撞车。 现在:06 改成一句带许诺的判断(书这么说,可此刻你只能信它,第 10 章打印给你看),10 赚到的是证据不是结论(第 5 组亮斑、深层空白),并且 10 行 4 换成「亮着的格子一层比一层少」这一条新东西
02「训久了才好」与 11「两条曲线分叉」02 只给欠拟合一个(0.318 打不过 0.220),11 给的是读法(两条线的走势才是诊断依据)。不同
03「基准这条纪律」与 11「通用流程里的定基准」03 把它变成开工前的一步并算出 85.58,11 是把它编进流程的第 6 步并回指。11 不重讲,只用一行回指
04「超参数是什么」与 11「调参纪律」04 给定义 + 网格搜索,11 给顺序(先过拟合再正则化)和「验证集会被训脏」。不同
06「dropout 怎么工作」与 11「正则化武器表」dropout 的机制全书只在 06 讲一次,11 只把它摆进表里、说什么时候用哪个。写作时必须守住
06「卷积的参数共享」与 12「RNN 的参数共享」12 明确写成「同一个想法的第二次出现:一个共享在空间,一个共享在时间」,是呼应不是重复
07「图像嵌入」与 13「词嵌入」07 是截断模型取中间层,13 是一张可训练的查找表;都落到「低维表示」,但走查和来源完全不同,13 要显式回指 07
01「学的是表示」与 22「向量空间的几何转换」22 是收口,正文里要写明「第 01 章埋的这条线在这里收」,不是重讲
05「softmax + 交叉熵」与 15「温度采样」05 讲训练时怎么算损失,15 讲生成时怎么挑字符,同一个概率向量、两件事
10「对输入求梯度」与 22「对抗样例」10 用它解释模型,22 用它欺骗模型 —— 同一个动作、两种用途,22 要显式回指

五、外部来源与检查器的账(照抄上一位的结论,不重复劳动)

  • 绝大部分缺口不必上网: Transformer / 注意力 → 母本 deep-learning-with-python-2e §11-text-transformer;强化学习深究 → 两本 RL 书;卷积与注意力的通用机制 → nndl-2e。互引写法用 book=<id> §<章> + 事实=
  • 只剩两处真要联网: 六个预测的 2026 现状、WebGPU 在 TF.js 里的现状(都归 22 章 / 回填 01、21)。AlexNet 年表降级成通用知识。
  • 和母本的分工(书卡已写死): 纯机制(反向传播、泛化、Transformer)引母本;浏览器与 Node 的账、数据管线、tfjs-vis、量化与部署是这本不可替代的部分,不许推给母本。
  • 检查器现状(误报原样留着,没动脚本、没动豁免账): book-jargon 39 处里约 15 处硬误报全部落在 index.md —— 那是 book-build 生成的壳,命中的是原书章节标题,改成手写总纲后自动消失;约 9 处是中文无词边界的子串误切(「对数据」切出「对数」、「标准化」切出「批」)。book-dodged 67 个词现阶段整份是误报 —— 它拿整本书当分母,而现在只写了一小部分,22 章写完再跑才有意义--quota 段级超额 10 处是真的,和 01 要补的第 ① 条是同一批地方。

六、动笔顺序与分工

前半(01–11)与后半(12–22)分两位写。

  • 前半: 01 已写完(补四处,其中主走查整条换掉)→ 02…11 连续写完 → 手写 index.md(六节,handwritten: true)。
  • 后半: 12…22。接手前先读本文件 §一(主线,总纲第 3 节的骨架)、§二 里 12 起的每一章、§三 切章账、§四 撞车表, 以及 index.md 末尾的许诺兑现表 —— 前半留下的债全在那张表里。

每章写完就地跑 book-jargonbook-verify,逐条看;门禁是提醒不是标准,误报原样报上来,不许改脚本、不许改豁免账。