17. 自主学习:自监督预测头(--pred-coef)
★★★
2.7k 字 ·
源文件 PROJECT.md 第 3296 行起 ·
ruler arch optim read memory
#17.1 为什么是这个东西(而不是"先停下认字去做个自主学习阶段")
用户提出:「是不是该先让它拥有『自主学习能力』,再让它学会表达?」
这个直觉方向对,但"自主学习能力"其实是两件事:
| 是什么 | 可测判据 | 现状 | |
|---|---|---|---|
| 自主学习的能力 | 没有老师也能从经验里变好 | β=0 的成绩 vs 纯模仿 | 已经有了(判据 5 = 51.7%) |
| 自主学习的意愿 | 有没有自己的理由去学 | 没有外部奖励时会不会去探索 | 完全没有 |
认字任务给的是前者(β:1→0 就是"撤掉老师")。
★★ 但"先停下来做自主学习"是错的,因为:
认字任务是这个项目唯一能告诉我"视觉有没有用、记忆有没有用、状态有没有托住东西" 的仪器 —— 它有可验证的外部标准(读音是真值)。 放下它去做一个"自主学习阶段",我就失去了唯一的量具, 会变成"我觉得它在学"。
所以做法是加在它上面,不是替代它。
#17.2 设计:预测下一帧的编码(stop-gradient 当标签)
loss += pred_coef * MSE( pred(h_t), z_enc(s_{t+1}).detach() )| 选择 | 为什么 |
|---|---|
| 预测编码,不预测原始像素 | 96×96 像素的 MSE 会被"大部分是背景"主导,学到的多半是常数;编码是同一套已预热特征 |
目标是 z_enc(s_{t+1}) 且 stop-gradient | 否则模型可以把目标变得好预测(表征坍缩),表现是"损失下降但什么都没学会" |
一次算全序列(forward_with_pred) | _run_recurrence 返回 (B,T,units),不必在 rollout 里逐刻存状态(那要多传几 MB) |
| 头零初始化 | 给了一个精确的校准锚点(见下) |
#17.3 ★★ pred_rel = 1.0 就是"什么都没学到"
读数是相对误差 MSE / mean(z²):
| pred_rel | 含义 |
|---|---|
| 1.0 | 随机预测(零初始化头的理论值,实测正好 1.0) |
| 0.5 | 解释掉一半方差 |
| 0.0 | 完美预测 |
★ 这个 1.0 是免费的锚点 —— 和 §12.17 那个"31.2% vs 30.2%"是同一类东西: 没有它,看到 pred_rel=0.8 不知道算好还是坏。
#17.4 为什么它同时回答"能力"和"意愿"
- 能力:预测误差 = 它在不在学这个世界,不需要任何标注
- 意愿:预测误差就是"意外",是内在动机(好奇心)的标准定义
所以一条曲线同时回答两个问题,而且不需要给它新的任务 —— 与判据 5、无回显、留出字体并排看,一次实验四个读数。
#17.5 三条自检(防止"加了但静默无效")
新增一个目标函数最容易出的错是它根本没接进 loss(不报错,只表现为"没效果")。 所以自检里加了三条:
- 开预测头 ->
pred_rel是有限正数 - 预测头拿到了梯度(
|g| > 0)—— 否则它只是装饰 - 关预测头 ->
pred按设计为nan,且计算图与旧实现逐位相同 (--pred-coef 0时走原来的forward,不会悄悄改变旧读数)
★ 顺带一个自检本身的坑:update 返回有限值 那条原来检查 st.values() 全部有限,
而 pred 在关掉时按设计就是 nan -> 自检误报成"预测头算出了 nan"。
"故意关掉的功能"不该被算进有限性检查(已改成按 key 过滤)。
#17.6 ⚠️ PowerShell 工具链的第 4 次静默失效:.ps1 必须纯 ASCII这一阶段在"写运行脚本"这件小事上连踩四次,规律已经清楚,记下来一次说清:
| # | 现象 | 根因 | 修法 | |
|---|---|---|---|---|
| 1 | Tee-Object 写的日志中文变成 U+FFFD(不可恢复) | PowerShell 把管道输出按控制台编码(GBK)转文本 | 让 Python 自己写日志(--log) | |
| 2 | `2>&1 \ | ` 同样毁掉中文 | 同上(2>&1 也走文本转换) | 同上;或 2> file.err(只丢 stderr) |
| 3 | .ps1 里含中文 -> 字符串缺少终止符 之类的假语法错 | PowerShell 5.1 按 ANSI/GBK 读 .ps1,UTF-8 的中文被读成乱码字节 | .ps1 保持纯 ASCII;中文放 .py 里 | |
| 4 | 多行哈希表 + foreach 报一堆莫名其妙的语法错 | 解析器在上一处出错后级联误报(真正的原因可能在第 3 条) | 先查非 ASCII 字节数,(Get-Content -Raw).Length 式的检查没用 |
可复用的三条(都是这一阶段换来的):
.ps1里一个非 ASCII 字节都不要有。 用(Get-Content -Raw).Length检查不了,要按字节数:([System.IO.File]::ReadAllBytes($p) | Where-Object { $_ -gt 127 }).Count—— 实测三个脚本现在都是 0。- 中文参数走"代号 + Python 侧映射"。例子:
--new-cmd 下会毁掉整个脚本, 改成--new-cmd AUTO(Python 里解析成"挑一条与--base-cmd不同的指令")。 - 日志一律
--log(Python 自己写 UTF-8),不要经过 PowerShell 的管道。