学习SARSA建议与Q-Learning相结合起来学习
一、 SARSA算法
SARSA 是一种无模型 (Model-Free)、基于值函数 (Value-Based) 的在线策略 (On-Policy) 强化学习算法。与 Q-Learning 不同,SARSA 在更新时不会去幻想“未来的完美最优动作”(这里可以理解为Q-Learning中的 max Q ),而是老老实实地用当前策略实际生成的动作来更新价值。
它的名字概括了算法执行一次更新所必须经历的五个步骤(时间线):状态(State)、动作(Action)、奖励(Reward)、下一状态(State') 和下一动作(Action')。
二、 核心要素
在马尔可夫决策过程 (MDP) 中,SARSA 的运行同样依赖于以下核心要素,但在处理流程上有着严格的“接力”要求:
-
状态(S):智能体当前所处的环境情况。
-
动作(A):智能体在状态S下可以选择的动作(例如:网格游戏中的上下左右)。
-
奖励(R):执行动作后,环境反馈的即时评分(掉坑扣分,到终点得分)。
-
折扣因子(
):介于 0 到 1 之间。决定了智能体是“短视”的(接近 0),还是近 1,重视长期累积奖励。
-
动作价值函数(Q(S, A)):代表在状态S下执行动作A,预期能拿到的总奖励的折现和。
-
下一状态与下一动作(
):这是 SARSA 的灵魂要素。智能体不仅要知道自己到了哪,还必须在更新前就确切决定好下一步要干什么。(通俗的对比Q-Learning就是不是取该状态下采取可以获得最大Q值的动作,而是按当前策略选一个动作)
三、 贝尔曼期望方程与 TD 更新
此部分对于初学者可以多看几遍,理解与Q-Learning的区别,并从中理解on-policy与off-policy,绝大部分公式推导是一致的。
3.1 回报(Return)
智能体的终极目标是未来累积奖励最大化。我们定义从时间 t 开始的总回报 Gt 为:
可以将其写成递归的形式,这是后续所有公式的基石:
3.2 价值函数(Value Function)
为了评估某个状态或动作的好坏,我们依然使用那两个核心函数:
3.2.1 状态价值函数 (State-Value Function)
在策略的指导下,从状态 s 出发,未来能获得的期望回报:
3.2.2 动作价值函数 (Action-Value Function)
它表示在状态 s 下,先执行动作 a,然后后续所有步骤都遵循策略,所能获得的期望回报:
【核心差异点】:Q-Learning 的目标是寻找绝对的“最优策略”,因此它推导出了贝尔曼最优方程(含有最大化操作)。但 SARSA 算法由于是同轨策略 (On-Policy),它评估的就是智能体当前正在使用的策略 。因此,期望被保留了下来,我们得到的是贝尔曼期望方程 (Bellman Expectation Equation):
直观理解:当前状态-动作的评估价值,等于真实的即时奖励,加上按照当前策略实际走出的下一步动作的未来折现价值。
3.3 时序差分 (TD Learning)
观察贝尔曼期望方程,它包含一个期望。在模型未知 (Model-Free) 的环境中,我们无法计算真实的转移概率,所以依然使用单次经验去“采样”逼近!
智能体在环境中实际走一步,观察到真实的下一状态 和真实奖励
。此时,智能体必须立刻根据当前的
-贪心策略,抽出下一个动作
。我们用这组实际发生的数据来代替期望:
-
旧的认知:
-
TD Target:
(注意:这里没有 max!)
-
TD Error:
我们使用学习率 将这个偏差更新到旧记忆中,这就得到了 SARSA 的最终更新公式:
四、 On-Policy 与 Off-Policy 的深刻直觉
很多初学者容易搞混这两种策略的区别,其实它们反映了智能体对“犯错”的不同态度。
-
Q-Learning(Off-Policy/离线策略):行为策略和目标策略是分离的。它在现实中虽然会因为
探索而随机瞎走,但在大脑里更新 Q 表时,永远用 max 假设自己下一步绝对不会走错。这种极度乐观导致它在面对悬崖时,敢于贴着悬崖边走最短路径。
-
SARSA(On-Policy/同轨策略):行为策略和目标策略是统一的。它深知自己的策略存在
的随机瞎走概率,在算 TD Target 时的
真的可能会抽中掉下悬崖的烂招。因此,SARSA 会把这种犯错的风险实打实地计算进 Q 值里,从而学到一条极其安全的绕远路线。
五、示例代码
本次代码与上一章【强化学习笔记】1.Q_Learning算法及示例代码基本一致,仅做了小部分修改
import numpy as np
import gymnasium as gym
class QLearningAgent:
def __init__(self, state_size, action_size=4):
"""初始化:设置状态空间大小和动作空间大小"""
self.state_size = state_size
self.action_size = action_size
self.Q_table = np.zeros((self.state_size, self.action_size))
def choose_action(self, state, epsilon):
"""选取动作"""
if np.random.rand() < epsilon:
return np.random.randint(self.action_size)
else:
get_max_Q = np.max(self.Q_table[state])
actions = np.where(self.Q_table[state] == get_max_Q)[0]
return np.random.choice(actions)
def update(self, state, action, reward, next_state, next_action, done, alpha, gamma):
"""更新Q表"""
if done == True:
self.Q_table[state, action] += alpha * (reward - self.Q_table[state, action])
else:
self.Q_table[state, action] += alpha * (reward + gamma * self.Q_table[next_state, next_action] - self.Q_table[state, action])
return self.Q_table[state, action]
# 1. 初始化环境
# is_slippery=False 冰面不滑
env = gym.make("FrozenLake-v1", is_slippery=False, render_mode="human")
state_size = env.observation_space.n
action_size = env.action_space.n
# 2. 创建智能体
agent = QLearningAgent(state_size, action_size)
# 3. 设置训练超参数
total_episodes = 2000
alpha = 0.8 # 学习率
gamma = 0.95 # 折扣因子
epsilon = 1.0 # 初始探索率
epsilon_min = 0.01 # 最小探索率
epsilon_decay = 0.995 # 指数衰减率
# 记录奖励
rewards_per_episode = []
print("开始训练...")
# 4. 开始大循环
for episode in range(total_episodes):
# 重置环境
state, info = env.reset()
done = False
total_reward = 0
# 选取初始动作
action = agent.choose_action(state, epsilon)
while not done:
# 执行动作,获取新版 Gym 的 5 个返回值
next_state, reward, terminated, truncated, info = env.step(action)
# 合并结束信号
done = terminated or truncated
# 触发记忆更新
next_action = agent.choose_action(next_state, epsilon)
agent.update(state, action, reward, next_state, next_action, done, alpha, gamma)
# 极其关键的:状态推进
state = next_state
action = next_action
total_reward += reward
# 单回合结束,记录奖励
rewards_per_episode.append(total_reward)
# 核心进阶:Epsilon 指数衰减
epsilon = max(epsilon_min, epsilon * epsilon_decay)
# 每 500 回合打印一次进度报告
if (episode + 1) % 500 == 0:
recent_win_rate = np.mean(rewards_per_episode[-100:])
print(f"--- 回合: {episode + 1}/{total_episodes} ---")
print(f"当前 Epsilon: {epsilon:.3f}")
print(f"最近 100 局胜率: {recent_win_rate * 100:.1f}%")
print("\n训练彻底完成")
print("\n智能体脑海中的 Q-Table (4个动作方向的价值评估):")
print(np.round(agent.Q_table, 3))
env.close()
可视化结果



3066

被折叠的 条评论
为什么被折叠?



