Q-Learning 是一种经典的强化学习算法,于 1989 年由 Watkins 提出。它通过迭代逼近最优 Q 函数,不依赖环境模型,理论保证收敛。核心概念包括 TD(时间差分)目标和贝尔曼方程。TD 目标利用当前奖励和未来估计的差值来更新 Q 值。读者学习后,能够在状态空间较小、动作离散且环境可采样的任务中应用 Q-Learning,例如在 OpenAI Gym 的 FrozenLake 环境中达到 80% 以上的胜率。Q-Learning 的关键参数包括学习率(lr)、折扣因子(gamma)和探索策略(ε-贪心)。ε-贪心策略通过平衡探索和利用来优化学习过程。此外,Q-Learning 适用于状态空间较小且动作离散的任务,对于状态空间较大或连续的任务,建议使用基于神经网络的 DQN 算法。
Q-Learning 算法
Q-Learning 是最经典的强化学习算法,1989 年被提出。它不依赖环境模型,直接学最优 Q 函数,理论保证收敛。
核心思想
回忆最优贝尔曼方程:
Q*(s, a) = R(s, a) + γ * sum_{s'} P(s'|s, a) * max_{a'} Q*(s', a')
Q-Learning 的想法:既然 Q* 满足这个方程,我就用迭代逼近它。每走一步,更新 Q:
Q(s, a) ← Q(s, a) + α * [ R(s, a) + γ * max_{a'} Q(s', a') - Q(s, a) ]
↑ ↑ ↑
当前估计 TD 目标(立即奖励 + 折扣的未来) 当前估计
α 是学习率,γ 是折扣因子。这个更新在 1989 年被 Watkins 证明,只要所有 (s, a) 对被访问无穷次, Q 一定收敛到 Q*。
关键概念:TD 目标
TD_target = R + γ * max_{a'} Q(s', a')
TD_error = TD_target - Q(s, a) (这是要"惊讶"多少)
直觉:看到奖励 R,加上对未来的最好估计,如果比现在的估计大,说明 Q(s, a) 偏低,往上更新。
TD = Temporal Difference = 时间差分。因为是用"现在的估计"和"下一步的估计"之差来更新,所以叫时间差分学习。
完整 Q-Learning 算法
import numpy as np
from collections import defaultdict
class QLearning:
def __init__(self, n_states, n_actions, lr=0.1, gamma=0.99, epsilon=0.1):
self.Q = np.zeros((n_states, n_actions)) # Q 表
self.lr = lr
self.gamma = gamma
self.epsilon = epsilon
def select_action(self, state):
"""ε-贪心: 小概率随机, 大概率选当前最优"""
if np.random.random() < self.epsilon:
return np.random.randint(self.Q.shape[1])
return np.argmax(self.Q[state])
def update(self, state, action, reward, next_state, done):
"""核心: Q-Learning 更新"""
if done:
target = reward
else:
target = reward + self.gamma * np.max(self.Q[next_state])
# 增量更新
self.Q[state, action] += self.lr * (target - self.Q[state, action])
实战:FrozenLake 环境
OpenAI Gym 的 FrozenLake(冰面滑行,经典入门):
SFFF S = 起点, 安全
FHFH F = 冰面, 可走
FFFH H = 洞, 掉进去就输
HFFG G = 目标, 奖励 +1
import gym
env = gym.make("FrozenLake-v1", is_slippery=False) # 不滑的话简单
agent = QLearning(env.observation_space.n, env.action_space.n,
lr=0.1, gamma=0.99, epsilon=0.1)
# 训练
episodes = 5000
for ep in range(episodes):
state, _ = env.reset()
done = False
while not done:
action = agent.select_action(state)
next_state, reward, terminated, truncated, _ = env.step(action)
done = terminated or truncated
agent.update(state, action, reward, next_state, done)
state = next_state
# 测试
wins = 0
for _ in range(100):
state, _ = env.reset()
done = False
while not done:
action = np.argmax(agent.Q[state])
state, reward, terminated, truncated, _ = env.step(action)
done = terminated or truncated
if reward == 1:
wins += 1
print(f"胜率: {wins}%")
跑 5000 轮应该能达到 80%+ 胜率。
探索 vs 利用:ε-贪心家族
ε-贪心是入门级探索策略,实践中通常用更聪明的:
1. ε-贪心(本节)
P(随机) = ε
P(最优) = 1 - ε
简单但有效。问题:探索均匀,没区分"哪些动作已知很烂"和"哪些未知"。
2. ε 衰减(常用)
# 训练初期多探索, 后期多用最优
epsilon = max(0.01, 0.5 * 0.99 ** episode)
3. UCB(Upper Confidence Bound)
同时考虑"估计值"和"不确定性":
a = argmax [ Q(s, a) + c * sqrt(ln(t) / N(s, a)) ]
↑
访问越少 → bonus 越大
4. 玻尔兹曼探索
按 Q 值的 softmax 概率采样:
P(a|s) ∝ exp(Q(s, a) / T)
T 是温度,T 大 → 更均匀(多探索),T 小 → 更贪心(多利用)。
Q-Learning 的局限
Q-Learning 假设 Q 表存在,但实际问题里状态空间可能无限(游戏画面、机器人传感器)。Q 表爆炸。
解决:用神经网络逼近 Q 函数——这就是下一章的 DQN。
Q-Learning 调参经验
| 参数 | 推荐范围 | 影响 |
|---|---|---|
lr (学习率) | 0.05 ~ 0.5 | 太小学得慢,太大不稳定 |
gamma (折扣) | 0.9 ~ 0.99 | 越大越"有远见",越小越"短视" |
epsilon | 0.05 ~ 0.2(衰减) | 太大学不到最优,太小陷入局部 |
episodes | 看任务 | 简单的 1k, 复杂的 1M+ |
实战:出租车问题
比 FrozenLake 复杂一点:
env = gym.make("Taxi-v3")
agent = QLearning(env.observation_space.n, env.action_space.n,
lr=0.1, gamma=0.99, epsilon=0.1)
# 训练
for ep in range(10000):
state, _ = env.reset()
done = False
while not done:
action = agent.select_action(state)
ns, r, term, trunc, _ = env.step(action)
done = term or trunc
agent.update(state, action, r, ns, done)
state = ns
# Q 表可视化
import numpy as np
print(f"训练后 Q 表: {agent.Q.shape}")
print(f"非零 Q 值: {(agent.Q != 0).sum()}")
总结:从 Q-Learning 到 DQN
Q-Learning 适合:
- 状态空间小(< 几万个)
- 离散动作
- 环境模型已知或能采样
不适合:
- 状态空间大/连续
- 状态是图像(几百万像素)
- 实时决策
下一章:用神经网络代替 Q 表 → DQN。
小结
- Q-Learning 直接学最优 Q 函数,不依赖环境模型
- 更新公式:
Q(s,a) ← Q(s,a) + α * [R + γ*max Q(s', a') - Q(s,a)] - ε-贪心及变种解决探索问题
- 表格型 Q-Learning 只适合小状态空间
- DQN 用神经网络逼近 Q(下章)
练习思考
- 在 FrozenLake 把 is_slippery 改成 True(冰面真滑),Q-Learning 还能学出来吗?为什么?
- ε=0(完全贪心)会发生什么?为什么?
- 尝试用玻尔兹曼探索替代 ε-贪心,对比在 FrozenLake 上的训练效果。
章末小测验
检验你对《Q-Learning 算法》的掌握程度。
Q-Learning 算法的主要特点是什么?
关于 TD 目标,以下哪些说法是正确的?
ε-贪心策略的缺点是什么?
Q-Learning 在哪些情况下表现良好?
以下哪些方法可以改进 Q-Learning 的探索策略?