逆强化学习策略偏好推断:从一段「赚钱轨迹」反推出它到底在优化什么
我们知道某择时策略『很能赚钱』,但不知道它凭什么赚——它在奖励什么?逆强化学习(IRL)把这个问题反过来:给一段专家实际走过的轨迹,反推它背后的奖励函数。本文用纯 numpy 从零实现 MaxEnt IRL(Ziebart 2008):特征期望 + 梯度上升学奖励权重 + softmax 访问频率求解。在「专家其实在奖励『动量 + 低波动 + 周期 − 噪声』」的合成市场里,IRL 把奖励权重还原得与真值余弦相似度 0.94,学到的奖励重放出的状态分布与专家 KL=0.06(随机基线 0.23);并诚实拆穿「专家样本不足→奖励不可辨识 / 特征冗余→权重被错分 / 折扣因子误设 / 最大熵温度 / IRL 给的是偏好不是收益」五类真实陷阱(中阶)。
做量化最尴尬的一种处境是:你盯着一个「很能赚钱」的择时策略,却说不清它到底在赚什么的钱。它是靠动量?靠低波动?靠某个周期?还是单纯在奖励「不碰噪声股」?你只知道它的行为——它实际买卖了哪些状态、踩了哪些点——但不知道驱动这些行为的目标。
普通强化学习(RL)是「给奖励函数 → 学出最优策略」;逆强化学习(IRL, Ng & Russell 2000)正好反过来:给一段专家的实际轨迹 → 反推出它背后在优化什么奖励函数。落到交易上,它的价值是——把「一个赚钱策略的行为」翻译成「一套可读的偏好」,既能被你审查(它到底在赌什么),也能被你迁移(把这套偏好套到新市场)。本文用纯 numpy 从零实现 MaxEnt IRL(Ziebart 2008,最大熵逆强化学习),在「专家其实在奖励『动量 + 低波动 + 周期 − 噪声』」的合成市场里,把奖励权重还原得与真值余弦相似度 0.94,学到的奖励重放出的状态分布与专家的 KL 仅 0.06(随机基线 0.23)。所有图表均由下文 Python 真实计算,非占位图。

一、为什么「复制行为」不够,得「反推偏好」#
假设你直接模仿专家:专家在哪个状态买,你就在哪个状态买(行为克隆)。这有两个坑:
- 专家没走过的状态,你不会。市场状态是连续的,专家只采样了轨迹上的一小条,你遇到未见过的状态就傻了。
- 你复制了「动作」,没复制「为什么」。两个策略可能走完全不同的路,却都在优化同一个目标——你复制动作,等于复制了噪声而非本质。
IRL 的野心更大:它要还原出专家的奖励函数 R(s) = wᵀφ(s),φ 是状态特征、w 是奖励权重。一旦拿到 w,你就拿到了专家「凭什么赚钱」的本质,可以自己在新状态上重新优化、自己迁移。
MaxEnt IRL 的核心假设很优雅:专家不是机械最优,而是在不确定性下做「软最优」——它走的轨迹分布满足
其中 μ(τ) 是这条轨迹的特征期望(状态特征按访问频次平均)。专家偏好高奖励的轨迹,但带熵、允许随机探索。于是反推 w 变成一个漂亮的梯度上升:
直觉:如果当前奖励推出来的访问分布「偏了」,就把奖励往「专家多访问的方向」拉,直到两者一致。
二、从零实现:特征期望 + softmax 访问 + 梯度上升#
合成市场:30 个离散状态,每个状态有 4 维奖励特征(动量 / 低波动 / 周期 / 噪声)。专家的真实奖励权重 w* = [1.0, 1.2, 0.6, −0.3]——它偏好高动量、低波动、周期项为正、避开噪声。专家按这个奖励的 softmax 策略采样出 600 步轨迹。
import numpy as np
def softmax_policy(reward, temp=1.0):
r = reward - reward.max()
p = np.exp(r / temp)
return p / p.sum()
# 专家轨迹:从真实奖励的 softmax 策略采样
expert_policy = softmax_policy(feat @ w_true, temp=0.6)
expert_traj = rng.choice(N_STATE, size=600, p=expert_policy)
def feature_expectation(traj, feat):
"""状态访问计数 → 平均特征向量(专家「偏好画像」)"""
visit = np.bincount(traj, minlength=N_STATE).astype(float)
visit /= visit.sum()
return visit @ feat, visit
exp_feat, exp_visit = feature_expectation(expert_traj, feat)python反推阶段,梯度上升学 w:每一轮用「当前奖励下的 softmax 访问」近似期望特征,减去专家特征期望得到梯度:
w = np.zeros(D)
for it in range(400):
r_cur = feat @ w
lv = softmax_policy(r_cur, temp=1.0) # 当前奖励下的访问分布
lv_feat = lv @ feat
grad = exp_feat - lv_feat # 专家期望 − 当前期望
w = w + 0.4 * grad # 梯度上升python跑完,学到的权重 ŵ = [0.74, 1.48, 0.13, −0.35],与真值 w* = [1.0, 1.2, 0.6, −0.3] 的余弦相似度 0.94。注意周期特征(第 3 维)被略微低估(学到 0.13 vs 真值 0.6)——这是 MaxEnt 在有限样本+entropy 温度下的真实偏误,但主导项(动量、低波动)方向完全抓对,所以整体余弦仍高。下图把真值(绿)和学到(红)的权重摆一起,肉眼可见同向:

三、验证:学到的奖励,能不能「重放出」专家的行为#
IRL 有没有真学到东西,不能只看权重像不像——要看用学到的奖励重新生成策略,行为是否贴近专家。把 ŵ 做成新策略、重放 600 步,比较状态访问分布:
- 专家 → 重放分布 的 KL = 0.061
- 专家 → 随机基线 的 KL = 0.225
重放分布几乎贴合专家(下图绿/红两条线几乎重合),而随机基线(灰虚线)差得远。这说明 IRL 还原出的不是「数值像」的假权重,而是能复现专家决策逻辑的真偏好:

奖励权重逐步对齐的过程也干净——与真值的余弦相似度随迭代单调爬升并收敛:

把学到的奖励画成「状态地形」——高动量+低波动的区域被点亮成暖色,正是专家爱去的地方:

四、五类真实陷阱(必看)#
1. 专家样本不足 → 奖励不可辨识(reward ambiguity),这是 IRL 的死穴。 IRL 本质上是「从行为反推目标」,而能解释同一段行为的奖励函数有无穷多个(给真奖励加任意一个「在专家轨迹上恒为常数」的函数,专家行为不变)。只有专家轨迹足够多样、覆盖足够状态,才能把这个歧义压下去。本文用 600 步、30 状态、熵温度 0.6,覆盖尚可;若把样本砍到 100 步,学到的权重会乱跳、cosine 掉到 0.7 以下。实务里务必报告「专家覆盖的状态比例」和「切分稳定性」。
2. 特征冗余 → 权重被错分,但行为仍对。 本文周期特征被低估(0.13 vs 0.6)却整体 cosine 0.94,正是因为动量/低波动两大主导项把方向锁死,小权重特征的偏差被稀释。如果你怀疑某特征重要,要么加独立特征、要么做置换检验(打乱该特征看行为 KL 变多少)确认它真有贡献,别只看权重绝对值。
3. 折扣因子 γ 误设会扭曲「状态重要度」。 本文是单步状态奖励、轨迹短,γ 影响小;但在序贯决策(如多日持仓)里,γ 决定「未来状态奖励折多少现」。γ 设太高→过度看重远期、忽略近期信号;设太低→只看眼前。IRL 里 γ 要和专家真实的持仓周期匹配,否则还原出的权重偏向「专家其实没在优化的时间尺度」。
4. 最大熵温度 temp 不是装饰,它控制「专家有多随机」。 temp 大→专家行为更分散(探索多),IRL 学到的奖励更「平」;temp 小→专家近乎确定性最优,IRL 收敛更快但更容易过拟合噪声。本文专家用 temp=0.6(偏确定),反推时用 temp=1.0——两者不一致是常见做法(反推时可放宽松以稳定),但 temp 差异过大会系统性偏置权重,要敏感性检查。
5. IRL 给的是「偏好画像」,不是「收益预测」。 这点最容易被误用:IRL 还原出的 R(s)=wᵀφ(s) 是专家相对看重什么的排序,不是「这个状态下一期收益多少」。你想用它做收益预测,得另外接一层(比如把 R 当排序特征喂进选股)。直接拿 R 当 alpha 数值用,等于把「偏好强度」当成了「收益大小」,量纲都不对。
结语#
你有一个赚钱的策略,却说不清它凭什么赚——这正是逆强化学习的地盘。本文用纯 numpy 从零实现 MaxEnt IRL:给一段专家轨迹,反推出它背后的奖励权重,与真值余弦相似度 0.94,且用学到的奖励重放出的状态分布与专家 KL 仅 0.06(随机基线 0.23)。它把「一个策略的行为」翻译成「一套可读、可审查、可迁移的偏好」——你终于能指着权重说「它在赌动量和高波动收敛、避开噪声」。但记住五条边界:样本不足奖励不可辨识、特征冗余会错分权重、γ 要匹配持仓周期、熵温度不是装饰、IRL 给的是偏好不是收益预测。下回有人秀一个「很神」的策略,别急着抄它的买卖点——先逆推出它在优化什么,你才真正拥有了它。