时序差分学习(Temporal-Difference Learning, TD Learning)是强化学习中一种关键的值函数估计方法,结合了蒙特卡洛方法(Monte Carlo)和动态规划(Dynamic Programming)的优点。它在智能体与环境交互的过程中,通过对当前经验进行更新,逐步逼近真实的值函数。
强化学习环境一般建模为一个马尔可夫决策过程(MDP),用一个五元组表示:
( S , A , P , R , γ ) (\mathcal{S}, \mathcal{A}, P, R, \gamma) (S,A,P,R,γ)
目标是学习一个策略 π \pi π 下的状态值函数或状态-动作值函数:
状态值函数:
V π ( s ) = E π [ ∑ t = 0 ∞ γ t R t + 1 ∣ S 0 = s ] V^\pi(s) = \mathbb{E}_\pi \left[ \sum_{t=0}^{\infty} \gamma^t R_{t+1} \mid S_0 = s \right] Vπ(s)=Eπ[t=0∑∞γtRt+1∣S0=s]
状态-动作值函数:
Q π ( s , a ) = E π [ ∑ t = 0 ∞ γ t R t + 1 ∣ S 0 = s , A 0 = a ] Q^\pi(s,a) = \mathbb{E}_\pi \left[ \sum_{t=0}^{\infty} \gamma^t R_{t+1} \mid S_0 = s, A_0 = a \right] Qπ(s,a)=Eπ[t=0∑∞γtRt+1∣S0=s,A0=a]
TD方法的核心思想是利用从环境中获得的一个步长的估计来更新当前状态的值,而不必等到整个回合结束。
最简单的TD方法是 TD(0),更新公式如下:
V ( S t ) ← V ( S t ) + α [ R t + 1 + γ V ( S t + 1 ) − V ( S t ) ] V(S_t) \leftarrow V(S_t) + \alpha \left[ R_{t+1} + \gamma V(S_{t+1}) - V(S_t) \right] V(St)←V(St)+α[Rt+1+γV(St+1)−V(St)]
其中:
因此更新可简写为:
V ( S t ) ← V ( S t ) + α δ t V(S_t) \leftarrow V(S_t) + \alpha \delta_t V(St)←V(St)+αδt
方法 | 是否需要模型 | 更新时机 | 收敛性 |
---|---|---|---|
蒙特卡洛 | 否 | 回合结束后 | 有限状态下收敛 |
动态规划 | 是 | 批量同步更新 | 依赖完整模型 |
时序差分 | 否 | 每步实时更新 | 收敛更快,更稳定 |
SARSA 是一个on-policy 的方法,表示用当前策略采样,并使用当前策略的行为值函数进行更新。
Q ( S t , A t ) ← Q ( S t , A t ) + α [ R t + 1 + γ Q ( S t + 1 , A t + 1 ) − Q ( S t , A t ) ] Q(S_t, A_t) \leftarrow Q(S_t, A_t) + \alpha \left[ R_{t+1} + \gamma Q(S_{t+1}, A_{t+1}) - Q(S_t, A_t) \right] Q(St,At)←Q(St,At)+α[Rt+1+γQ(St+1,At+1)−Q(St,At)]
Q-learning 是一个off-policy方法,使用当前策略采样,但用最优动作进行更新:
Q ( S t , A t ) ← Q ( S t , A t ) + α [ R t + 1 + γ max a Q ( S t + 1 , a ) − Q ( S t , A t ) ] Q(S_t, A_t) \leftarrow Q(S_t, A_t) + \alpha \left[ R_{t+1} + \gamma \max_{a} Q(S_{t+1}, a) - Q(S_t, A_t) \right] Q(St,At)←Q(St,At)+α[Rt+1+γamaxQ(St+1,a)−Q(St,At)]
TD(λ) 是 TD 的一个广义形式,结合了 TD(0) 和蒙特卡洛方法,通过引入一个迹衰减因子 λ。
定义 n n n-步回报为:
G t ( n ) = R t + 1 + γ R t + 2 + ⋯ + γ n − 1 R t + n + γ n V ( S t + n ) G_t^{(n)} = R_{t+1} + \gamma R_{t+2} + \cdots + \gamma^{n-1} R_{t+n} + \gamma^n V(S_{t+n}) Gt(n)=Rt+1+γRt+2+⋯+γn−1Rt+n+γnV(St+n)
TD(λ)使用不同步长的回报加权平均:
G t λ = ( 1 − λ ) ∑ n = 1 ∞ λ n − 1 G t ( n ) G_t^\lambda = (1 - \lambda) \sum_{n=1}^\infty \lambda^{n-1} G_t^{(n)} Gtλ=(1−λ)n=1∑∞λn−1Gt(n)
然后用 G t λ G_t^\lambda Gtλ 来更新值函数:
V ( S t ) ← V ( S t ) + α ( G t λ − V ( S t ) ) V(S_t) \leftarrow V(S_t) + \alpha (G_t^\lambda - V(S_t)) V(St)←V(St)+α(Gtλ−V(St))
资格迹是一种跟踪哪些状态最近被访问的机制:
E t ( s ) = γ λ E t − 1 ( s ) + 1 ( S t = s ) E_t(s) = \gamma \lambda E_{t-1}(s) + \mathbf{1}(S_t = s) Et(s)=γλEt−1(s)+1(St=s)
更新规则为:
V ( s ) ← V ( s ) + α δ t E t ( s ) V(s) \leftarrow V(s) + \alpha \delta_t E_t(s) V(s)←V(s)+αδtEt(s)
这是一种“前向-后向等价”实现方式。
强化学习系列——深度Q网络(DQN算法)
在实际问题中(如图像输入),状态空间往往极其庞大,无法保存所有状态值。此时引入神经网络函数逼近器进行值函数估计,结合TD更新目标:
Loss = ( y t − Q ( s t , a t ; θ ) ) 2 \text{Loss} = \left( y_t - Q(s_t, a_t; \theta) \right)^2 Loss=(yt−Q(st,at;θ))2
y t = R t + 1 + γ max a Q ( s t + 1 , a ; θ − ) y_t = R_{t+1} + \gamma \max_a Q(s_{t+1}, a; \theta^-) yt=Rt+1+γamaxQ(st+1,a;θ−)
其中 θ \theta θ 是当前网络参数, θ − \theta^- θ− 是目标网络参数。
时序差分学习提供了一种高效、可扩展的值函数估计方法,其基本形式 TD(0)、进阶形式 SARSA 和 Q-learning、以及广义形式 TD(λ),构成了强化学习算法的核心基础。
import numpy as np
# 定义环境
num_states = 5
num_actions = 3
Q = np.zeros((num_states, num_actions)) # 动作值函数
rewards = np.array([[-1, 0, -1], # 状态0的奖励表
[-1, -1, 0], # 状态1的奖励表
[0, -1, -1], # 状态2的奖励表
[-1, 0, -1], # 状态3的奖励表
[-1, -1, 0]]) # 状态4的奖励表
gamma = 0.8 # 折扣因子
alpha = 0.1 # 学习率
epsilon = 0.1 # ε-greedy策略的ε值
# 定义SARSA算法
def sarsa(num_episodes):
for episode in range(num_episodes):
state = 0 # 初始状态
action = epsilon_greedy(state) # 初始动作
while state != num_states - 1: # 直到达到终止状态
next_state = action # 下一个状态为当前动作
next_action = epsilon_greedy(next_state) # 下一个动作
# 使用SARSA更新动作值函数
Q[state, action] += alpha * (rewards[state, action] + gamma * Q[next_state, next_action] - Q[state, action])
state = next_state
action = next_action
# ε-greedy策略
def epsilon_greedy(state):
if np.random.uniform(0, 1) < epsilon:
action = np.random.randint(num_actions) # 随机选择一个动作
else:
action = np.argmax(Q[state]) # 选择具有最大动作值的动作
return action
# 运行SARSA算法
sarsa(num_episodes=100)
# 输出结果
print("最优动作值函数:")
print(Q)
下面是一个Q-learning的简单实现示例,使用 OpenAI Gym
中的经典环境 FrozenLake(冰湖):
import gym
import numpy as np
import random
# 创建环境
env = gym.make("FrozenLake-v1", is_slippery=False) # 禁用滑动以简化学习
# Q表初始化:状态数 × 动作数
state_size = env.observation_space.n
action_size = env.action_space.n
Q = np.zeros((state_size, action_size))
# 超参数
alpha = 0.1 # 学习率
gamma = 0.99 # 折扣因子
epsilon = 1.0 # 探索率(ε-greedy)
epsilon_min = 0.01
epsilon_decay = 0.995
episodes = 1000
max_steps = 100
# 训练过程
for episode in range(episodes):
state = env.reset()[0]
done = False
for _ in range(max_steps):
# ε-greedy 策略选择动作
if random.uniform(0, 1) < epsilon:
action = env.action_space.sample()
else:
action = np.argmax(Q[state, :])
# 执行动作
next_state, reward, done, _, _ = env.step(action)
# Q值更新
best_next_action = np.argmax(Q[next_state, :])
td_target = reward + gamma * Q[next_state, best_next_action]
td_error = td_target - Q[state, action]
Q[state, action] += alpha * td_error
state = next_state
if done:
break
# 衰减 ε
epsilon = max(epsilon_min, epsilon * epsilon_decay)
# 显示学习到的Q表
print("Learned Q-table:")
print(np.round(Q, 2))
Q-table 是一个 16 × 4 16 \times 4 16×4 的矩阵,每一行表示一个状态,每一列表示一个动作。
训练完成后,可以用 Q-table 导出策略:
π ( s ) = arg max a Q ( s , a ) \pi(s) = \arg\max_a Q(s,a) π(s)=argamaxQ(s,a)
安装 Gym(如果尚未安装):
pip install gym
# 测试策略
state = env.reset()[0]
env.render()
for _ in range(20):
action = np.argmax(Q[state])
state, reward, done, _, _ = env.step(action)
env.render()
if done:
print("Reached goal!" if reward == 1 else "Fell into hole!")
break