重要性采样(Importance Sampling)详解:从"为什么要有这个东西"讲起
🎯 一句话定位:
重要性采样就是「我没法从目标分布 p 里采样,只好从另一个容易的分布 q 里采样,然后给每个样本乘一个修正权重,让最终的期望(平均值)还能算对」的一套技巧。
它离你的 CartPole 代码只有一步之遥:你现在 rollout() 采轨迹用的是当前策略 πθ旧,算完梯度就立即更新成 θ新,这叫同策略 on-policy。
可是一旦你想「旧策略采到的轨迹能不能复用给更新了好几次的新策略再用?」或者「我想让一个专家/随机策略录的示范数据,也能训练我的当前策略?」——这时候同策略不行了,就得靠重要性采样来「修正分布差」。
〇、先讲一个大白话例子:想算中国人平均身高,却只抽到了北京人
这一节一个公式都不写,你把直觉建立起来,后面的数学其实就是把这句话翻译成符号。
故事背景
你是一个人口调查员,任务是算:
全中国人的平均身高(期望)是多少?
最理想的做法(叫「从目标分布 p 里采样」):
- 把 14 亿人编上号,完全随机抽 1 万人,每人测身高,相加 ÷ 10000 → 这就是无偏估计,平均下来一定是真的全国均值。
可是现实打了你一巴掌:公司预算只够你跑一趟北京,你只能在北京街头抽样 1 万人(这叫「从提议分布 q 里采样」,因为方便、便宜、能拿到)。
北京人身高其实比全国平均整体偏高一点(比如北京的 q 分布整体右移了几厘米)。
关键问题来了:
如果我就拿着「北京抽的 1 万人」的数据,硬算一个 sum(身高)/10000,会怎么样?
👉 结果肯定偏大,有系统性偏差(Bias)。
怎么救?—— 给每个人乘一个「校正系数」再求平均
答案:不是直接把身高求平均,而是给每个人的身高乘一个「他有多大代表性」的权重,再加起来。
直觉:
- 在北京抽到一个特别矮的人(150cm):这个人在北京分布 q 里是罕见的(北京矮的少,抽到概率低),但他在全国分布 p 里其实不罕见(全国矮个子比例比北京高很多);
→ 说明他的「代表性很高」,他的身高在全国平均值里应该被放大一点权重。
- 在北京抽到一个特别高的人(195cm):这个人在北京分布里挺常见,在全国分布里却挺罕见;
→ 说明他的「代表性很低」,他的身高在全国平均值里应该被缩小一点权重。
这个「校正系数」就是著名的:
w(x)=q(x)p(x) - p(x):目标分布里出现一个身高为 x 的人的真实概率密度(我们关心的全国分布)
- q(x):实际采样分布(提议分布)里出现身高 x 的概率密度(我们实际上抽样的北京分布)
- 读成:"这个人在目标里有多常见 ÷ 在采样里有多常见"
你再感受一下它的直觉:
- 如果某个人在 p 里很常见、在 q 里很少见 → 分子大、分母小 → w>1 → 放大他的贡献(代表性强)
- 如果某个人在 p 里很少见、在 q 里很常见 → 分子小、分母大 → w<1 → 缩小他的贡献(代表性弱)
- 如果两者一样常见 → w=1 → 这个人本来就有代表性,不用修正。
好了,重要性采样的全部直觉就这一句话:
"从 q 抽一个样本 xi,不要直接用 f(xi),要给它乘权重 w(xi)=q(xi)p(xi) 再加起来求平均,结果就等于从 p 里抽样的期望。"
下面就是把这句大白话写成严谨的数学公式,你会发现每一步都对应着上面故事里的一句话。
一、问题的正式提法:我想算 p 分布下 f(X) 的期望,但是抽不到 p
1.1 我们真正想算的东西("目标期望")
我们有一个目标随机变量 X,它服从分布 p(x)。我们想求一个函数 f(x) 在这个分布下的平均值(期望):
EX∼p[f(X)]=∫xp(x)f(x)dx(目标期望) 如果我们能直接从 p 里抽 N 个样本 x1,…,xN∼p,那就太爽了,直接样本平均就行:
EX∼p[f(X)]≈N1i=1∑Nf(xi)(样本平均(无偏差)) 1.2 现实:抽不到 p,只能抽到另一个分布 q
什么时候我们抽不到 p?在强化学习里这是家常便饭,举三个你以后一定遇到的场景:
| 场景 | 目标分布 p(想从它抽) | 提议分布 q(只能从它抽) |
|---|
| 🎮 离策略(off-policy)训练:想训练新策略 πθ新,但轨迹是旧策略 πθ旧 跑出来的 | 新策略的轨迹分布 πθ新(τ) | 旧策略的轨迹分布 πθ旧(τ) |
| 📖 模仿学习:专家录了一堆示范,想训练我的当前策略 | 我的当前策略 πθ(τ) | 专家策略 πexpert(τ) |
| 🗄️ 经验回放(DQN / Replay Buffer):我把之前很多步的 (s,a,r,s′) 都放缓冲区里存着,想拿出来训练当前策略 | 当前策略的 (s,a) 联合分布 | 过去一堆老策略混合的 (s,a) 联合分布 |
这就是"为什么会出现重要性采样"的根本原因:
"想算的分布 p 拿不到样本,只能拿到另一个分布 q 的样本,需要用数学把它还原回来。"
二、核心公式推导:一步到位,就靠"乘个 1"的 trick
重要性采样的数学推导短到离谱,你高中数学就能看懂。我们的目标是:
把「对 p(x) 积分」改写成「对 q(x) 积分」,这样就能用 q 的样本来算。
只需要一个小学代数的技巧:在积分里面乘以 q(x)q(x)(它等于 1,不改变值)。
EX∼p[f(X)]=∫xp(x)f(x)dx=∫x重要性权重 w(x)q(x)p(x)⋅f(x)q(x)dx 最后那个式子正好就是「随机变量 w(X)⋅f(X) 在 q 分布下的期望」:
EX∼p[f(X)]=EX∼q[q(X)p(X)f(X)](IS 核心恒等式) 这就是重要性采样全部的理论基础,一行就证完了。
2.1 怎么用它?—— Monte Carlo 抽样版
把右边的期望,用从 q 里抽出来的 N 个样本 x1,…,xN∼q 做样本平均:
EX∼p[f(X)] ≈ μIS=N1i=1∑N wiq(xi)p(xi)⋅f(xi)(IS 蒙特卡洛估计器) 2.2 一个最重要的性质:它是无偏的
这个估计器对不对?我们来证一下它的期望正好是目标值(也就是「平均下来一定对」):
Ex1,…,xN∼q[μIS]=N1i=1∑NEX∼q[q(X)p(X)f(X)]=N1⋅N⋅EX∼p[f(X)]=EX∼p[f(X)] 就这么简单:只要你抽 xi 时,xi 在 q 里有概率(即 q(xi)>0),并且 p(xi)>0 的任何 xi 也必须在 q 里有概率(这个条件叫「q 的支撑集包含 p 的支撑集」,大白话就是「p 可能出现的样本,q 也能抽到」),这个估计器就一定无偏。
🚨 必须满足的前提(缺一不可):
∀x,p(x)>0⟹q(x)>0(支撑集包含条件) 人话翻译:凡是目标分布 p 可能产生的任何样本 x,采样分布 q 也必须能抽到它(至少概率要大于 0,哪怕 10−8 也行,不能是绝对 0)。
要是不满足,会发生什么?—— 某个样本 xi 在 p 里出现了,但是在 q 里根本抽不到,那这一项的权重就会变成:
w(xi)=0p(xi)=∞ 整个估计直接被这一项拉到无穷大,直接炸掉。
💡 强化学习里这句话对应的一条工程铁律:
旧策略 πθ旧 绝对不能在任何状态下把某个动作的概率置成硬 0。
举个 CartPole 的例子:你旧策略在某个状态下「永远只会向右推」,向左推的概率是实打实的 0(比如你用 argmax 选动作或者对 Softmax 做了硬截断)。
之后新策略 πθ新 学到在这个状态下「应该向左推」,想复用这批旧数据训练时,重要性权重就会变成:
πθ旧(a左∣s)πθ新(a左∣s)=0某个正数=∞ 梯度直接爆炸,训练全毁。
这就是为什么所有策略梯度算法里,策略网络的最后一层一定要用 Softmax,而且输出概率再小也只会趋近于 0(至少是 10−8 量级),永远不会出现硬 0 —— 本质就是为了满足上面这个「支撑集包含条件」。
三、再讲一个极其简单的数值例子:你亲手算一遍就全记住了
这一节你自己跟着算 30 秒,比看 10 页推导还管用。
- 目标分布 p:两枚硬币公平正反面,p(正)=0.5, p(反)=0.5
- 提议分布 q:两枚硬币被做了手脚,出正的概率只有 0.2,出反的概率 0.8(很偏)
- 我们想算的函数 f(x):
- f(正)=100
- f(反)=0
手算真值(不抽样,直接数学算)
EX∼p[f(X)]=0.5×100+0.5×0=50 所以正确答案一定是 50。
我们假装不知道 p,只能从 q 里抽 10 次
假设我实际从 q 里抽了 10 次(按概率 0.2 / 0.8 抽的),抽到:
❌ 错的做法:直接算样本平均(不加权重)
错误估计=101(2 次正面100+100+8 次反面0+⋯+0)=10200=20 结果 20,比真值 50 小了一倍半!——这就是因为我们用了一个"正面严重偏少"的分布去抽样,却没校正。
✅ 对的做法:重要性采样,每个样本先乘权重 wi=p/q
先算两种结果的权重:
- w(正)=q(正)p(正)=0.20.5=2.5
- w(反)=q(反)p(反)=0.80.5=0.625
然后按 IS 公式加起来:
μIS=101(2 次正面2.5×100+2.5×100+8 次反面0.625×0+⋯+0.625×0)=10500=50 正好等于真值!
你看这 2 次正面,每个都被乘了 2.5 的权重——因为 q 分布里"正面"被抽得太少了(只抽到 2 次,真实 p 里应该抽到 5 次),所以每 1 次正面样本就要代表原来的 2.5 次,权重就是 2.5。反面被抽得太多,权重就小于 1。
这就是重要性采样名字里「重要性」这三个字的来源:
每个样本对目标期望的"真实贡献重要程度",和它在采样分布 q 里出现的频率不一定一样,所以要乘以 p/q 这个权重,把它的重要性纠正回来。
四、重要性采样的「致命弱点」:方差巨大 & 极端权重
重要性采样听起来太爽了,不管你是啥分布,我都能换一个分布抽,然后乘个权重就对了?
——听起来像天上掉馅饼,所以它一定有代价。代价就是:方差可能炸到你怀疑人生。
4.1 直觉:你全靠几个「罕见样本」撑起来,能不抖吗?
回到刚才那个硬币例子:
- 正面在 p 里概率 0.5,在 q 里只有 0.2
- 权重 w(正)=2.5,看起来还好;
- 但如果我把 q(正) 改成 0.0001(就是说 q 里几乎抽不到正面),那么:
w(正)=0.00010.5=5000 这意味着什么?——我可能抽 10000 个样本才遇到 1 次正面,这 1 次正面的 1 个样本就要代表 5000 个样本的贡献!
- 如果我这次运气好,抽到了 1 次正面 → 估计值会一下冲上天;
- 如果我这次运气差,10000 次里一次正面都没抽到 → 估计值直接等于 0,和真值 50 差十万八千里。
这就叫「方差爆炸」——虽然「平均下来」这个估计器是无偏的(E[μ^]=50),但你单次拿一批样本算出来的结果,波动能从 0 到几百万,根本没法用。
4.2 数学上怎么看方差爆炸(一句话)
IS 估计器的方差公式是(你不用记,看结论就行):
Varx∼q[w(X)f(X)]=Eq[w(X)2f(X)2]−(Ep[f(X)])2 注意到了吗?——权重 w(x) 是「平方」的。只要有的样本权重特别大,方差就会被它的平方成倍放大。
业界有一句非常有名的吐槽:
「重要性采样在论文里永远成立,在工程里永远因为方差太大用不了。」
所以不要以为学到 IS 就解决了 off-policy,真正的强化学习算法(PPO、SAC、Importance Sampling with ESS 等)90% 的精力都是在解决「IS 的方差太大怎么压」。
五、救星 1:归一化重要性采样(WIS / Weighted Importance Sampling)
5.1 一个非常讨厌的现实:很多时候我们连 p(x) 自己都只知道差个常数倍
举个贝叶斯的常见情况(你以后看 RL 的贝叶斯算法、能量模型一定会遇到):
- 我们想从「后验分布 p(θ∣D)=p(D)p(D∣θ)p(θ)」里抽样本,
- 分母那个「证据 p(D)」是一个极其难算的积分(有时根本算不出来),
- 所以我们只能写出 p~(θ)=p(D∣θ)p(θ),其中 p(θ∣D)=Zp~(θ),而归一化常数 Z=p(D) 未知。
这时候分子分母都有一个未知的 Z,但它们能约掉。于是有人发明了:
5.2 WIS 的公式(「权重归一化版」)
μWIS=∑i=1Nwi∑i=1Nwif(xi),其中 wi=q(xi)p(xi)(WIS 归一化估计器) 你对比一下普通 IS:
- 普通 IS:
sum(w_i * f_i) / N (权重平均用的是样本数 N) - WIS:
sum(w_i * f_i) / sum(w_i) (权重平均用的是权重和本身)
5.3 WIS 直觉:权重和本来就应该是 N
当你从 q 抽了 N 个样本,在「理想状况」下 ∑wi=N(因为每个权重平均是 1),但现实里抽样有随机误差,∑wi 经常不等于 N。WIS 的做法就是强制让权重和等于 1(归一化之后),把「归一化常数未知」的问题抵消掉。
5.4 代价:WIS 是有偏的,但是方差小很多
- WIS 不保证「期望等于真值」,是有偏估计;
- 但它在工程中比普通 IS 稳定太多,因为它自动把极端大的权重给压缩了(你一个 wi=10000,但分母里也有这个 10000,相当于你再大也得被别的权重平均一下)。
⚠️ RL 算法里一个小知识点:
其实我们平时在 REINFORCE 的 ∇θJ 估计器里,一般用的还是普通 IS(非归一化),因为策略梯度本身就是期望为 0 的无偏估计,换成 WIS 会引入偏差。但是对于离策略策略评估(比如要估计 Vπ新,却用旧策略的数据),WIS 几乎是标配。
六、救星 2:限制 p 和 q 不要差太远(策略比限制 / PPO 裁剪)
刚才我们说了,IS 方差炸的根本原因就是某些样本权重特别大。那怎么让权重不要太大?
一句话答案:别让 p 和 q 差太远。
6.1 为什么 RL 里我们会遇到「p 和 q 差太远」?
在策略梯度里:
- p=πθ新(a∣s)(现在刚更新完 θ 的策略,是我们想训练的目标)
- q=πθ旧(a∣s)(刚才采数据时用的旧策略)
- 重要性权重就是大名鼎鼎的:
ρt(at∣st)=πθ旧(at∣st)πθ新(at∣st)(RL 状态-动作级重要性比率) - 如果我一次梯度步太大,θ新 飞出去老远 → 这个比值 ρt 在某些 (s,a) 上变成 10、100、甚至 10000 → 方差直接炸。
- 那怎么办?立法限制「新策略和旧策略的重要性比率,不许超出 [1-ε, 1+ε] 这个范围」。
这就是 PPO(Proximal Policy Optimization,近邻策略优化)干的核心事,也正是你读完《基线原理》和《重要性采样》之后下一个要学的算法。
PPO 裁剪目标(Clipped Surrogate Objective)就是:
LCLIP(θ)=Et[ min( ρt(θ)A^t, clip(ρt(θ),1−ε,1+ε)A^t ) ](PPO 裁剪目标) 大白话翻译这行公式:
- 如果 A^t>0(这个动作是好动作,我想让它概率变大)→ 但也不许你把 ρt 拉到 1+ε 以上,再多就封顶了;
- 如果 A^t<0(这个动作是坏动作,我想让它概率变小)→ 但也不许你把 ρt 压到 1−ε 以下,再少就封底了;
- 用
min 取两者的更保守那一个(悲观估计),防止更新过猛。
🎯 所以:PPO 的裁剪机制本质上就是「强行压制重要性采样的极端权重,换来方差可控」——这是重要性采样在实际强化学习中最著名的一次落地。
七、在强化学习里,重要性采样到底被用到了哪些地方?
这里给你一张全景地图,把「轨迹级、步级、策略评估、策略梯度」四种常见形态一次讲完。
7.1 应用一:离策略的策略梯度(从「旧策略轨迹」训练「新策略」)
你现在的 CartPole Agent.update() 是同策略的:数据是刚 rollout 的,策略和更新用的是同一个,所以不用 IS。
但如果你想把 300 个 step 之前 rollout 的轨迹全部存起来,现在拿出来反复训练(这叫数据复用,可以大大降低采样成本),你就得用 IS 修正。
- 同策略(你现在的):
∇θJ(θ)=Eτ∼πθ[ t=0∑T∇θlogπθ(At∣St)Gt ] - 离策略(旧策略 β 采样,新策略 πθ 训练) + 轨迹级 IS:
∇θJ(θ)=Eτ∼β⎣⎡ 轨迹级重要性权重 w(τ)P(τ;β)P(τ;πθ)⋅t=0∑T∇θlogπθ(At∣St)Gt ⎦⎤(off-policy 轨迹级 IS) 这个 w(τ) 其实非常好算,因为轨迹就是一串 (s0,a0,…,sT),每一步都是乘起来的,转移概率都约掉之后只剩策略乘积的比值:
P(τ;β)P(τ;πθ)=t=0∏T−1β(at∣st)πθ(at∣st) 但是要注意:轨迹级权重是 ∏t,乘了 T 个小于 1 或大于 1 的数,会指数爆炸或指数消失。
所以工程里几乎不会用"全轨迹级 IS",而是用下面的「步级 IS + 因果性」。
7.2 应用二:步级 IS + 因果性(PPO 的实际做法)
每一步各自乘以「这一步之前的乘积」(只到 t,不到 T,避免乘 T 项指数爆炸),这是所有离策略策略梯度算法的标准做法:
∇θJ(θ)=Eτ∼β⎣⎡ t=0∑T 截止到 t 的累计比率 ρ0:t(k=0∏tβ(ak∣sk)πθ(ak∣sk))⋅∇θlogπθ(at∣st)A^t ⎦⎤(步级 IS + 因果策略梯度) 这就是 PPO、V-trace、IMPALA 这些工业级离策略算法在背后用的公式。
7.3 应用三:离策略策略评估 OPE(Offline RL 最核心的问题)
你有一批历史数据(比如已经下线的机器人/广告系统过去一年的决策日志),现在想在不上线测试的前提下,预测:「如果我换一个新策略 πe 去跑,回报会变成多少?」
这个问题叫 Off-Policy Evaluation(OPE),它的核心公式就是 IS:
J(πe)=Eτ∼β[ P(τ;β)P(τ;πe)G(τ) ] 然后用 WIS 压方差(否则历史数据和新策略稍微差一点就没法用了)。Offline RL 领域绝大多数论文,本质上都是在发明更稳的「IS 权重截断 / 权重正则化 / Doubly Robust 双重稳健」方法。
八、回到 CartPole:你的「批均值基线」和「重要性采样」是亲戚!
读到这你可能会想:你现在的 CartPole baseline 代码里,不是「减了一个基线 b」吗?它和重要性采样到底有啥关系?
——答案:它们都是在干「让梯度估计更稳定」这件事,但是手段不一样,并且以后你会把它们合起来用。
| 方法 | 解决的问题 | 手段 |
|---|
基线 b(你 CartPole baseline 里那个 avg_reward) | 梯度估计的「方差太大」(整局回报 G 波动大) | 在目标函数里做减法:把 G(τ) 换成 (G(τ)−b),期望不变,方差下降 |
| 重要性采样(本讲) | 「分布变了,样本来自另一个分布」导致估计有偏 | 在目标函数里做乘法:每个样本乘权重 p/q,把分布纠正回来,保证无偏 |
| 两者一起用(PPO 的实际形态) | 分布不一样 + 方差还大 → 要两个都用 | wi⋅(Gi−b)=π旧π新⋅(Gi−V(si)),最后再 PPO clip 一下 wi |
所以学习顺序就是你现在文档的顺序(完全顺的):
REINFORCE(同策略,没基线)
↓ 讲完后你写了 cartpole_reinforce_v1.py
加入基线(减 avg_reward 或减 V(s_t) Critic)
↓ 讲完后你写了 baseline 版本(减批均值)
加入重要性采样(旧数据给新策略用,乘权重 π_new/π_old)
↓
加入 PPO clip(限制权重别太大,方差可控)
你现在就差最后一步了(PPO),前面的地基都铺好了。
九、常见坑总结(直接避坑)
- 坑:忘了支撑集条件,q 抽不到某些 x → 除 0 或直接偏差巨大
- 避:Softmax 输出永远 > 0;策略绝对不要加 argmax 式「确定选动作」采样;旧策略别把任何动作概率锁死。
- 坑:p 和 q 差太远 → 方差爆炸,估计器每一次跑出来都不一样,完全不可信
- 避:PPO clip,或者「更新几步就重新采样(on-policy/near-on-policy)」,或者 WIS。
- 坑:把普通 IS 用在「权重和分布极差的情况」,结果被一两个样本牵着鼻子走
- 避:监控权重的 ESS(有效样本数)ESS=∑wi2(∑wi)2
如果 ESS 比 N 小很多(比如 ESS < N/10),就说明你的权重大部分被几个极端大的占据了,这一批样本扔了重采,或者 clip 一下权重再算。
- 坑:把 WIS 用在策略梯度(需要无偏)
- 避:策略梯度里的 IS 比率用「普通 IS」,策略评估 OPE 里用「WIS + Doubly Robust」。
十、一页纸总结
| 问题 | 答案 |
|---|
| 为什么出现? | 想从 p 抽抽不到,只能从另一个方便的 q 抽 |
| 核心公式? | Ep[f]=Eq[qpf] |
| 权重叫什么? | 重要性权重 w=p/q(目标概率 ÷ 采样概率) |
| 优点? | 只要 p 的支撑集包含在 q 里,就是「无偏」的,平均下来一定对 |
| 代价? | 权重会平方地放大方差,p 和 q 稍微一远就炸 |
| 两大解药? | ① WIS(权重归一化,换偏差换方差) ② 限制 p/q 不要太离谱(PPO clip / TRPO 约束) |
| 在 RL 里什么时候用? | 离策略训练 / 经验回放复用 / OPE 离线评估 / PPO 的新旧策略比率 ρt |
你现在理解了重要性采样,再去看 PPO 的 ρt(θ) 会有「啊,原来就是它!」的感觉——PPO 就是在重要性采样外面包了一层「安全护栏 clip」,让工程上能用。