Q 表装不下了
上一卷的算法都很漂亮,但它们有个共同的前提:你能维护一张表,每个状态一行。这一章我们算一下那张表到底要多大——然后你会发现,体积其实是这个问题里最不严重的部分。
先算体积
那个数字
Atari 那一行值得念出来。
DQN 用的输入是 84×84 的灰度图——已经是缩小、降采样之后的了。一共 7056 个像素,每个像素 256 个灰度级。可能的画面数量:
256^7056 ≈ 10^16993
存它的 Q 表(每个状态 18 个动作,每个 4 字节)需要约 10^16982 TB。
作为对照:可观测宇宙里的原子总数大约是 10^80 个。
也就是说,那张表的字节数,是宇宙全部原子数的 10^16914 倍。
当数字大到这个程度,它已经不是量的问题了,是方法论必须整个换掉的信号。
而且请注意:连围棋都远远不是最坏的情况。围棋 10^170,在 Atari 一帧面前微不足道。让人类觉得「复杂到不可能」的围棋,在「一张任意的图片」面前不值一提。
但体积其实是最不要紧的那个
就算你有那么大的硬盘,表格法照样跑不动。原因有三个,一个比一个致命。
① 你得把每个格子都亲自走过
第 12 章那个收敛定理写得很明白:「每个状态-动作对被访问无穷多次」。
Atari 里,你要把 10^16993 个状态每个访问至少一次。按每秒一百万帧算,需要 10^16980 年。宇宙年龄是 10^10 年。
而绝大多数状态你一辈子只会遇到一次——那一次访问对学习毫无帮助,因为下次遇到的是另一个从没见过的状态。
② 表格法学不会「相似」
这一条才是真正的要害,而且它和体积完全无关。
假设你在打砖块,屏幕上球在 (100, 50)。你学会了「这时候该往左移」。
现在球在 (101, 50)。
对人来说这是同一个局面。对一张表来说,这是两个毫无关系的行。行号不同,内容独立,第一个学到的东西对第二个一点帮助都没有。
我们要的不是「一张更大的表」,是一个能把学到的东西传递给相似状态的东西。
这个能力有个名字:泛化(generalization)。
而「输入相似 → 输出相似」正好是函数的天然性质。所以:
Q : 表 → Q : 函数 Q[s][a] → Q(s, a; θ) 一张查找表 一个带参数 θ 的函数
参数 θ 的数量是固定的(比如一百万个权重),和状态数量完全无关。
10^16993 个状态,用 10^6 个参数去描述。这当然装不下所有信息——但它不需要装下所有信息,它只需要把「相似的状态该做相似的事」这个结构抓住。
③ 表格没法处理连续量
顺带说一句,就算状态数量不多,只要它是连续的,表格法就直接出局。
CartPole 的状态是四个实数(位置、速度、角度、角速度)。它不是「很多个状态」,是不可数无穷多个。你连行都编不出来。
传统做法是离散化:把每个维度切成若干格。但这一招在维度上升时会崩——四个维度每维切 20 格是 16 万个格子,还行;十个维度每维切 20 格就是 10^13 个,没法看了。这就是「维度灾难」这个词的原意。
换成函数之后,代价是什么
这本书反复说的那句话又来了:你拆掉的每一条限制,都会同时拆掉一条保证。
| 表格 | 函数逼近 | |
|---|---|---|
| 能处理的状态数 | 几千 | 无穷 |
| 泛化 | 完全没有 | 天生就有 |
| 改一个值会影响别的吗 | 不会,各存各的 | 会,参数是共享的 |
| 收敛保证 | 有(第 12 章那个定理) | 没有 |
第三行是好处,也是祸根。
「改一个值会影响别的」正是泛化的定义——学会了 (100,50) 就顺带学会了 (101,50),靠的就是它。
但它同时意味着:你没法只更新一个状态。每次更新都会把整个函数扯动一点,包括那些你根本没打算动的地方。
而强化学习恰好是用自己的估计更新自己的估计(第 11 章那个自举)。「牵一发而动全身」+「用自己更新自己」,凑在一起就会出事。
第 16 章有一个判例:奖励全程为 0,所有状态的真实价值都该是 0,而一个正确实现的算法把权重推到了 5.68×10⁶。
「深度强化学习」火起来之前,这个领域用了几十年别的东西,有些今天依然好用:
- 线性函数逼近:
Q(s,a) = wᵀφ(s,a)。你手工设计特征 φ,然后学一组权重。有相对干净的理论保证,而且训练极快。 - 瓦片编码(tile coding):拿几层互相错开的网格去覆盖连续空间。既有离散化的简单,又因为错开而获得了泛化。在低维连续控制上出奇地好用,Sutton 本人很偏爱它。
- 决策树 / 随机森林:可解释性好,在一些工业场景里仍在用。
神经网络的优势只有一个,但那一个很致命:不用你手工设计特征。Atari 那个 84×84 的画面,没人知道该提取什么特征——而卷积网络自己学出来了。
这也是 DQN 那篇论文真正的分量所在:它用同一套超参、同一个网络结构,打通了 49 个完全不同的游戏。以前每个游戏都要人来设计一套特征。
不要一上来就上神经网络。表格法在下面这些情况下依然是更好的选择:
- 状态数少于几万:表格更快、更稳、而且一定收敛。
- 你在调试:先在表格版本上把奖励函数和环境验证对(本书卷 V 讲的那些坑,在表格上暴露得更快)。
- 你需要可解释:Q 表可以直接打印出来看,神经网络不能。
一条实用的经验:先把你的问题缩小到一个能用表格解的版本,跑通了再放大。如果表格版都跑不通,那是环境或者奖励的问题,换神经网络只会让你更难定位。
SB3 里没有表格版的 Q-learning,正是因为它假定你已经过了那个阶段。真要用,二十行自己写(第 12 章有)。
那个学走路的小人的状态:十几个连续实数。不可数无穷多个状态。
但它的策略网络可能只有两层、几万个参数。这几万个参数要覆盖无穷多个状态,靠的就是泛化:「躯干前倾 12.3° 和前倾 12.4°,该做的事差不多。」
这个假设成立的时候,一切都好。而它不成立的地方,恰恰是最危险的地方——那些「差一点点就完全不同」的临界状态:重心刚好过了支撑面边缘、脚刚好要离地的那一瞬间。
你在视频里看到的那些「突然莫名其妙就摔了」的时刻,很多就发生在这种地方:函数在那儿光滑地插值了,而真实世界在那儿有一个断崖。
这一章的一句话
表格装不下不是因为硬盘不够,是因为它学不会「相似」。换成函数拿到了泛化,同时失去了「各存各的」——而那正是所有麻烦的入口。
下一章:2013 年,DeepMind 把这个函数换成了一个卷积网络,用同一套超参打通了 49 个 Atari 游戏。但那篇论文真正的贡献不是「用了 CNN」——是找齐了让它不炸的那一套配方。