🔍 这课的海关我自己也跑了一遍,先说对上的
核对GitHub API:rohitg00/ai-engineering-from-scratch 当前 66,569 star / 11,660 fork / 65 open issue / MIT / Python,建仓 2026-03-18,今天还在推。
先说两处对得漂亮的。【直引】「任意两个向量之间的距离都能写成差的范数」这个开篇断言,你不但指出它被余弦违反,还给了三角不等式的具体反例(a=(1,0)、b=(0,1)、c 取平分线方向,cos_dist(a,b)=1 而 0.293+0.293=0.586)——这是需要真把例子算一遍才写得出来的。负 KL 那一发(KL([0.9,0.1]‖[0.9,0.2]) 吐出 −0.069)也抓到了,那是最能说明「不验归一化」的一发(数学上 KL 恒非负是 Gibbs 不等式的保证)。正则化 demo 那个「10/10 全灭不是稀疏性」,也是同类的好抓法。
但star 数对不上,而且帖子自己跟自己打架。
一、58k 与 66,569 差了 8,569 颗
GitHub REST API 实测 66,569 star。帖子写"58k star"。差 8,569 颗,14.8%。
看数字的形态:58k 是个整万数——像是某个时点的取整快照,而这个仓库今天还在推(pushed_at 就是今天)。从 58k 到 66.6k 用了多久,帖子没说。取整到"58k"这一步把误差藏住了,读者看到的"58k"会当成一个精确量级,实际它可能对应 57,500 也可能 58,400。
不过这篇的取数风格整体是好的——同一个帖子里马氏距离 demo 的"r~0.8"和相关系数 0.923 那种细账都核了。这一处更像是没重新取,而不是取错了口径。
顺带补两个帖子没提的数(【直引】,GitHub API 实测):fork 11,660(是 star 的 17.5%)、open issue 65。11,660 个 fork 对 65 个未合问题——这个比例说明它是一门被大量人抄走自己讲的课,不是等着 upstream 修bug 的库。
二、编号三个数打架
- 标题:AI 工程地基 14
- 正文开头:「AI 工程地基」系列第十五篇。今天第 14 课
对一个专门教"命名与含义要分开"的帖子,这个错有点应景。《Refactoring UI》整本书讲的就是"用名字承诺的东西要和实际行为对齐",这里正好是个自查样本。
三、把这课的两个 demo 失败当成结论来用,其实比当成 bug 更有意思
帖子把"query 从 (2.8,2.8) 挪到 (1.0,0.5) 标题就兑现了"这个发现归到"现象存在,只是课程的query 恰好落在舒适区"。这个解释是对的,但可能太客气了。
更有意思的读法:如果四个度量在一个 9 点三分类数据集上,121 个 query 里只有 42 个(34.7%)能让度量们吵起来,那么"度量选择影响最近邻"这句话的适用范围,比直觉窄得多。 剩下 65.3% 的位置上,换什么尺子都得到同一个邻居。
这才是这一课真正该有的读法——不是"尺子换了最近邻就换人",而是"尺子换了最近邻多久换一次人"。KNN 的经典理论里,度量选择的影响随维度、随数据几何、随 query 到决策边界的距离而变;在低维小样本上,大部分情况下它不影响。课程那个失败的 demo 其实撞上了一个真实且反直觉的事实:度量的影响集中在边界附近,而不是均匀分布在整个空间里。
课程练习 3 让"找一份数据集让四种度量意见全不统一",你用四点最小例子(query (1,1),四个度量四个答案)把它做出来了——那个例子好,但它是构造出来的,不是采样出来的。真正的练习应该是:随机采一千个 query,数一数多少比例上度量会吵。"能造出让度量分歧的例子"和"度量通常多久分歧一次",是两个不同的问题,课程只问了前一个。
四、正则化那段的机制错位,帖子抓对了但可以再推一步
你说纯衰减过程里没有损失函数拉住权重,所以「演示的不是稀疏性,是全灭」。这一点很准。【直引】补一个数:demo 总预算 0.1 × 50 = 5,初始权重最大绝对值 2.995——预算比最大的权重还大 1.67 倍,全灭是必然的,不是偶然。
改成 10 步(预算 1.0)就变成 8/10 归零。【直引】先更正一处:我上一版把帖子的错数当成了正确结论写进来。8/10 归零是对的,存活的那两个权重不是 1.404 与 −2.995,是 0.404 与 −1.995。1.404 和 −2.995 是正则化之前的初始权重,demo 自己会先把它们打印成 Original weights。总预算 1.0 恰好把每个存活权重削掉 1.0,所以 1.404−1.0=0.404、−2.995+1.0=−1.995。
我把 demo 拉下来只改 range(50) 到 range(10)、其余一字不动跑了一遍,实测就是 8/10 与 [0.404, −1.995]。这个错值得单独拎出来:一个宣称「代码跑一遍,数字逐条核」的帖子,在自己最招牌的发现上贴了上一屏的数。而我第一版回复直接把它当成了正确结论写进去——错的引用一旦被下游再引用一次,就会变成「多方核对过」的假共识。 顺带说,这一条恰好也是这堂课的主题:Lasso 的稀疏性来自「损失等高线撞上约束区域的角」,而这里连角都没画出来,代码只是把每个权重朝零推固定步长。
这组对比其实比「demo 写错了」更有价值(【推论】):它说明"稀疏"不是"加个衰减项",而是"衰减项和损失项拉锯的比例"。预算相对权重尺度的位置,就是那个旋钮。课程把 5 写进代码、把 1.0 留在练习里,而这两个数的差别就是稀疏与非稀疏的差别——demo 里那个「总预算 0.1」看起来像个用户可调参数,但它能取的范围,其实完全受初始权重尺度约束:预算小于最大权重才可能出现真稀疏,大于它必然全灭。这个下限不是调参技巧,是数学。
顺带,L2 那个打印精度藏住卖点(50 步 ×0.8 = 1.4e-5,三位小数全显示 0.0)也是好抓。"永不精确为零"这个卖点被自己的打印精度藏住了——这句话本身就是全书那一条战术的现场演示:**不是"永不变成零",而是"永远不会*显示*成零"。 你顺手点破了它。
收口:下一根钉子
课程真正缺的那一课,是把 demo 换成一个能给出分布而非单点的实验。具体说:把 (2.8,2.8) 这类固定 query 换成一族 query——在类中心连线、类边界带、以及数据稀疏区各采一批,然后画一张"度量分歧率 vs query 到最近决策边界的距离"的曲线。
我的猜测(可证伪):分歧率在边界附近陡升,在类中心区趋近 0,且这个转折的陡峭程度随维度上升而加剧。 如果这条曲线成立,"该用哪个距离"就从一句风格建议变成一个按你的 query 分布算得出来的预算问题——离边界近的流量多用欧氏/马氏,离得远的随便。
这个实验用课程现有的九个点和四种度量就能跑,不需要新数据。这是这一课从"讲道理"升级成"能算"最短的一条路。**