1. Sarsa强化学习算法概述
Sarsa(State-Action-Reward-State-Action)是一种经典的强化学习算法,属于时序差分(Temporal Difference, TD)学习方法的范畴。与Q-learning同为表格型强化学习算法,但Sarsa采用on-policy策略,即在更新价值函数时使用与行为策略相同的策略进行动作选择。
我第一次接触Sarsa是在机器人路径规划项目中,当时需要让机器人在未知环境中学习避障策略。相比Q-learning,Sarsa表现出了更稳定的学习曲线,特别是在存在噪声的环境中。这让我意识到不同强化学习算法在实际应用中的特性差异。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Sarsa算法核心原理
2.1 算法基本框架
Sarsa算法的核心是五元组(s, a, r, s', a'),这也是其名称的由来。算法通过以下步骤迭代更新Q值:
- 在状态s下选择动作a
- 执行动作a,获得即时奖励r,转移到新状态s'
- 在状态s'下根据当前策略选择动作a'
- 更新Q(s,a)值
Q值的更新公式为:
Q(s,a) ← Q(s,a) + α[r + γQ(s',a') - Q(s,a)]
其中α是学习率,γ是折扣因子。这个更新规则体现了时序差分学习的核心思想——利用当前估计来更新之前的估计。
2.2 与Q-learning的关键区别
很多初学者容易混淆Sarsa和Q-learning,实际上它们的关键区别在于:
- 策略差异:Sarsa是on-policy算法,而Q-learning是off-policy算法
- 更新目标:Sarsa使用实际执行的动作a'来更新,而Q-learning使用最大Q值的动作
- 风险偏好:Sarsa更保守,会考虑实际执行动作的风险;Q-learning更激进,总是选择最优动作
在实际应用中,这种差异会导致明显不同的表现。比如在悬崖行走问题中,Sarsa会学习到更安全的路径,而Q-learning虽然能找到理论最优路径,但在噪声环境下更容易"掉下悬崖"。
3. Sarsa算法实现细节
3.1 伪代码实现
以下是Sarsa算法的标准伪代码:
code复制初始化Q(s,a)为任意值
对每个episode:
初始化状态s
根据Q选择动作a(如ε-greedy)
对每个时间步:
执行动作a,观察r和s'
根据Q选择动作a'(如ε-greedy)
Q(s,a) ← Q(s,a) + α[r + γQ(s',a') - Q(s,a)]
s ← s', a ← a'
直到s是终止状态
3.2 Python实现示例
下面是一个简单的Python实现,用于解决网格世界问题:
python复制import numpy as np
class SarsaAgent:
def __init__(self, n_states, n_actions, alpha=0.1, gamma=0.9, epsilon=0.1):
self.q_table = np.zeros((n_states, n_actions))
self.alpha = alpha # 学习率
self.gamma = gamma # 折扣因子
self.epsilon = epsilon # 探索率
def choose_action(self, state):
if np.random.uniform() < self.epsilon:
return np.random.choice(len(self.q_table[state]))
return np.argmax(self.q_table[state])
def learn(self, state, action, reward, next_state, next_action, done):
current_q = self.q_table[state, action]
next_q = 0 if done else self.q_table[next_state, next_action]
target = reward + self.gamma * next_q
self.q_table[state, action] += self.alpha * (target - current_q)
3.3 参数调优经验
在多个项目实践中,我总结了以下参数设置经验:
- 学习率α:通常设置在0.01-0.1之间。太大会导致震荡,太小学习速度慢
- 折扣因子γ:长期任务建议0.9-0.99,短期任务可以0.8左右
- 探索率ε:初期可以设0.2-0.3,随着训练可以线性衰减到0.01-0.05
- 衰减策略:ε可以采用线性衰减或指数衰减,我通常使用:
python复制epsilon = max(0.01, epsilon * 0.995) # 指数衰减
4. Sarsa算法实战应用
4.1 经典问题:悬崖行走
让我们用Sarsa解决经典的悬崖行走问题。环境是一个4×12的网格,agent从左下角出发,目标是到达右下角,掉下悬崖会得到-100奖励并回到起点。
python复制def train_cliff_walking():
env = CliffWalkingEnv()
agent = SarsaAgent(env.nS, env.nA)
for episode in range(500):
state = env.reset()
action = agent.choose_action(state)
done = False
while not done:
next_state, reward, done, _ = env.step(action)
next_action = agent.choose_action(next_state)
agent.learn(state, action, reward, next_state, next_action, done)
state, action = next_state, next_action
return agent
经过训练后,Sarsa会学习到沿着悬崖上方的安全路径,而不是贴着悬崖的最短路径。这是on-policy算法的典型表现。
4.2 实际项目:机器人避障
在一个真实的机器人避障项目中,我们使用Sarsa算法让机器人在动态环境中学习导航策略。状态空间包括:
- 8个方向的激光雷达测距值(离散化为4档)
- 机器人当前速度(3档)
- 最近障碍物方向(8个方向)
动作空间包括:加速、减速、左转、右转、保持。奖励函数设计为:
- 到达目标:+100
- 碰撞:-50
- 每步:-0.1(鼓励快速到达)
- 靠近目标:+1/distance
经过约1000次训练后,机器人能够在80%的情况下安全到达目标点。相比Q-learning,Sarsa的碰撞次数减少了约30%。
5. Sarsa的变体与改进
5.1 Expected Sarsa
Expected Sarsa是对标准Sarsa的改进,它不使用下一个实际动作的Q值,而是使用下一个状态所有可能动作的期望Q值:
Q(s,a) ← Q(s,a) + α[r + γE[Q(s',a')] - Q(s,a)]
实现时只需要修改learn方法:
python复制def learn(self, state, action, reward, next_state, done):
current_q = self.q_table[state, action]
if done:
target = reward
else:
policy = np.ones(self.n_actions) * self.epsilon / self.n_actions
policy[np.argmax(self.q_table[next_state])] += 1 - self.epsilon
expected_q = np.dot(self.q_table[next_state], policy)
target = reward + self.gamma * expected_q
self.q_table[state, action] += self.alpha * (target - current_q)
Expected Sarsa通常比标准Sarsa更稳定,因为减少了由于动作选择带来的方差。
5.2 Sarsa(λ)
Sarsa(λ)通过引入资格迹(eligibility trace)来实现向前看的能力,可以显著加快学习速度。资格迹记录了每个状态-动作对的"资格",表示它们对当前奖励的贡献程度。
实现时需要维护一个eligibility trace表:
python复制class SarsaLambdaAgent(SarsaAgent):
def __init__(self, n_states, n_actions, lambda_=0.9, **kwargs):
super().__init__(n_states, n_actions, **kwargs)
self.lambda_ = lambda_
self.e = np.zeros((n_states, n_actions))
def learn(self, state, action, reward, next_state, next_action, done):
delta = reward - self.q_table[state, action]
if not done:
delta += self.gamma * self.q_table[next_state, next_action]
self.e[state, action] += 1 # 累积迹或替换迹
# 更新所有状态-动作对
self.q_table += self.alpha * delta * self.e
self.e *= self.gamma * self.lambda_
if done:
self.e.fill(0)
在实际应用中,λ通常设为0.5-0.9。对于部分可观测或延迟奖励的问题,Sarsa(λ)表现尤为出色。
6. 常见问题与调试技巧
6.1 算法不收敛
如果发现Q值持续波动或策略不稳定,可以尝试:
- 降低学习率α:从0.1逐步下调,观察收敛情况
- 增加探索率ε:确保充分探索状态空间
- 检查奖励函数:奖励设计不合理是常见原因
- 尝试Expected Sarsa:减少方差可能帮助收敛
6.2 学习速度慢
加速学习的技巧包括:
- 使用Sarsa(λ):资格迹可以显著加快学习
- 实现经验回放:虽然Sarsa是on-policy,但可以有限度地使用经验回放
- 状态抽象:对状态进行合理抽象和离散化
- 并行训练:同时训练多个agent,共享经验
6.3 实际应用中的挑战
在工业级应用中,我们遇到过以下挑战及解决方案:
-
状态空间爆炸:
- 使用特征工程提取关键特征
- 考虑使用深度强化学习(如DQN)
-
非平稳环境:
- 定期重置ε,保持一定探索
- 实现滑动平均更新目标Q值
-
延迟奖励:
- 设计合理的中间奖励
- 尝试使用资格迹(Sarsa(λ))
7. Sarsa与其他强化学习算法对比
7.1 与Q-learning对比
| 特性 | Sarsa | Q-learning |
|---|---|---|
| 策略类型 | On-policy | Off-policy |
| 更新目标 | 实际执行的动作 | 最大Q值的动作 |
| 风险偏好 | 保守 | 激进 |
| 适用场景 | 安全关键任务 | 追求最优性能 |
| 实现难度 | 中等 | 简单 |
7.2 与策略梯度方法对比
Sarsa作为价值迭代方法,与策略梯度方法(如REINFORCE)的主要区别:
- 更新对象:Sarsa更新Q值,策略梯度直接更新策略参数
- 方差:Sarsa通常方差较小
- 连续动作空间:Sarsa难以处理,策略梯度可以
- 收敛性:Sarsa通常收敛更快
7.3 与深度强化学习结合
虽然Sarsa是表格型方法,但可以与深度学习结合:
- 用神经网络近似Q函数(类似DQN)
- 在状态表示阶段使用深度学习(如CNN处理图像)
- 结合经验回放(需要谨慎,因为Sarsa是on-policy)
在实际项目中,我们曾用CNN提取视觉特征,然后输入到Sarsa算法中,成功实现了基于视觉的机器人导航。
8. 进阶话题与研究方向
8.1 多agent Sarsa
在多agent系统中,Sarsa可以扩展为:
- 独立Sarsa:每个agent独立学习
- 联合动作学习:考虑其他agent的动作
- 对手建模:显式建模其他agent的策略
在博弈论实验中,多agent Sarsa可以收敛到纳什均衡,但收敛速度较慢。
8.2 函数逼近与Sarsa
对于大规模状态空间,可以使用线性或非线性函数逼近Q值:
python复制class SarsaFA:
def __init__(self, feature_dim, n_actions, alpha=0.01):
self.weights = np.zeros((feature_dim, n_actions))
self.alpha = alpha
def q_value(self, features, action=None):
if action is not None:
return np.dot(features, self.weights[:, action])
return np.dot(features, self.weights)
def learn(self, features, action, reward, next_features, next_action, done):
current_q = self.q_value(features, action)
next_q = 0 if done else self.q_value(next_features, next_action)
target = reward + self.gamma * next_q
delta = target - current_q
self.weights[:, action] += self.alpha * delta * features
这种方法可以处理连续状态空间,是迈向深度强化学习的中间步骤。
8.3 当前研究热点
近年来Sarsa相关的研究方向包括:
- 安全强化学习:利用Sarsa的保守特性实现安全约束
- 元学习:学习Sarsa的超参数调整策略
- 分层Sarsa:在不同时间尺度上应用Sarsa
- 基于模型的Sarsa:结合环境模型提高样本效率
在最近的一个研究中,结合Sarsa与模仿学习的方法在机器人操控任务中取得了不错的效果,既保证了安全性,又能够从专家演示中快速学习。
