FrozenLake-v1环境中Q-learning的Q-table无法更新问题求助
问题定位与修复方案
核心问题分析
你的Q-table始终为零的原因主要有两个:
- Epsilon衰减逻辑错误:当前代码在**每一步(step)**都执行epsilon衰减,而非每个episode结束后衰减。初始epsilon=0.9,每次减0.005,仅180步就会降到0以下,之后
random.random() < epsilon永远为False,算法一直选择np.argmax(Q[state])——但Q初始全零,每次选的都是索引0的动作,结合默认环境的随机性(slippery=True),大概率无法到达终点,奖励始终为0,导致Q-table更新项为0,无法产生有效更新。 - FrozenLake默认奖励机制限制:默认环境下只有到达终点时才会获得1的奖励,其余所有状态(包括掉冰洞)的奖励都是0。如果前期探索不足,无法触发正向奖励,Q-table就没有更新的动力。
修复后的代码
import gymnasium as gym import numpy as np import random def run(): env = gym.make("FrozenLake-v1") Q = np.zeros((env.observation_space.n, env.action_space.n)) alpha = 0.7 gamma = 0.95 epsilon = 0.9 epsilon_decay = 0.005 epsilon_min = 0.01 episode = 0 episodes = 10000 print("Before training") print(Q) while episode < episodes: state, info = env.reset() # 每个episode开始时重置状态 terminated = False truncated = False while not terminated and not truncated: # 探索-利用选择动作 if random.random() < epsilon: action = env.action_space.sample() else: action = np.argmax(Q[state]) new_state, reward, terminated, truncated, info = env.step(action) # Q-learning更新公式 Q[state, action] = Q[state, action] + alpha * (reward + gamma * np.max(Q[new_state]) - Q[state, action]) state = new_state # 每个episode结束后再衰减epsilon if epsilon > epsilon_min: epsilon -= epsilon_decay episode += 1 print("After training") print(Q) env.close() run()
关键修复点说明
- 调整Epsilon衰减时机:将epsilon的衰减逻辑移到每个episode结束后,避免衰减过快导致过早失去探索能力,确保算法有足够机会探索到终点获得正向奖励。
- 重构循环结构:改为外层控制episode数量,内层处理每个episode的所有step,逻辑更清晰,符合强化学习训练的常规流程。
- 移除冗余类型转换:gym返回的reward本身就是数值类型,无需强制转换为float。
额外优化建议
- 可以将环境设置为
slippery=False(确定性环境)测试算法,更容易看到Q-table的更新效果,命令为:env = gym.make("FrozenLake-v1", slippery=False) - 增加每轮episode的总奖励打印,方便观察训练进度:比如在每个episode结束后输出当前轮次的累计奖励。
内容的提问来源于stack exchange,提问作者Jelles
相关产品推荐
相关产品推荐

