ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

将 Q-Learning 从 CartPole 迁移到 Mountain Car:ML-For-Beginners 强化学习连续状态实战指南

将 Q-Learning 从 CartPole 迁移到 Mountain Car:ML-For-Beginners 强化学习连续状态实战指南 将 Q-Learning 从 CartPole 迁移到 Mountain CarML-For-Beginners 强化学习连续状态实战指南【免费下载链接】ML-For-Beginners12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-BeginnersMountain Car登山小车是强化学习课程中最能检验算法是否真正理解环境抽象的一课任务仍由 OpenAI Gym 提供但动作、状态、奖励都发生了本质变化要求你以最小改动把上一课学到的 Q-Learning 迁移过来。本篇基于 ML-For-Beginners 仓库的 2-Gym 课程与作业展开将带你完整梳理 Mountain Car 的动作空间、观测空间与奖励规则并结合 CartPole 原始代码给出状态离散化、Q-Table 结构和超参数调整的移植方案最终掌握同一套强化学习算法如何以最小代码改动适应不同环境的核心方法。OpenAI Gym 的统一抽象为什么换环境可以只改几行代码在开始移植之前需要先理解本作业背后的设计哲学。本课 README 指出OpenAI Gym 被刻意设计成所有环境提供同一套 API即每个环境都暴露相同的reset、step、render方法并统一抽象出动作空间action space与观测空间observation space。只要遵守这套约定同一份 Q-Learning 代码就能在不同环境间以最小改动复用。在上一课 CartPole Skating 中Peter 学习滑冰保持平衡使用的是经典CartPole-v1环境而本作业的目标环境是MountainCar-v0。两者的共同点是环境通过env.reset()初始化并获得初始观测每个仿真步调用env.step(action)返回四元组(obs, rew, done, info)观测是连续实数向量Q-Learning 需要一个离散化步骤才能建立 Q-Table动作空间是离散的可直接枚举。因此作业要求详见 assignment.md很明确沿用现有 notebook 代码替换新环境、改写状态离散化函数尽量少改算法主体再用超参数把结果调优。Mountain Car 环境深度解析Mountain Car 环境描述了一辆陷在山谷中的小车它无法凭借自身动力在一次冲刺中爬上山坡唯一的成功之道是在左右两个坡面之间来回往返、积累动量momentum最终借着惯性冲上右侧山顶夺取旗帜。动作空间每一步三选一值含义0向左加速Accelerate to the left1不加速Do not accelerate2向右加速Accelerate to the right与 CartPole 只有两个动作左右推滑块不同Mountain Car 引入了不加速的第三个动作。这一看似多余的中性动作在等待小车利用下坡积蓄速度时很有意义也让策略空间更大。从代码层面看动作数由env.action_space.n决定CartPole 为 2MountainCar 为 3——这是移植时第一处需要留意的地方。观测空间仅两个连续量作业文档给出了观测空间的取值边界编号观测MinMax0小车位置Car Position-1.20.61小车速度Car Velocity-0.070.07与 CartPole 的 4 维观测小车位置、小车速度、杆角度、杆角速度相比Mountain Car 的观测只有 2 维因此状态维度更小、更易处理但两个观测都是连续的这是它与上一课离散棋盘最大的区别也是连续状态空间这一课程主题的体现。值得注意的是CartPole 的 4 个观测值中速度和角速度没有上下界notebook 中打印出的 high 为3.4028235e38即无穷大而 Mountain Car 的位置与速度全部有界。这一差异会直接影响离散化策略的选择我们稍后详细讨论。奖励系统稀疏且严格惩罚Mountain Car 的奖励设计相当棘手原文用rather tricky若智能体抵达山顶旗帜位置 0.5获得奖励0若智能体位置小于 0.5每一步获得奖励-1。也就是说成功之前的每一步都在累计负奖励而成功的瞬间只给 0 分。由于单次仿真每步固定 -1累计奖励在数值上近似等于到达终点所需步数的相反数——到达得越快累计奖励越接近 0越大。这启发我们算法学习的目标本质上是在 200 步限制内尽量早地抵达旗帜。回合终止条件一个回合episode在以下任一条件满足时结束小车位置大于 0.5成功登上右侧山顶拿到旗帜回合长度超过 200 步超时失败。200 步上限把问题变成了一个效率竞赛单纯会爬上坡还不够还必须在 200 步内完成。作业的评分标准详见下文评价标准之所以强调在 200 步内夺取旗帜正是因为这是本环境的默认求解目标。为什么必须做状态离散化Q-Learning 需要一张 Q-Table 来记录在状态 s 下执行动作 a 的长期价值 Q(s,a)。Q-Table 的索引要求状态是有限数量的离散取值。Mountain Car 的观测是连续值位置、速度各自在区间内取无穷多个实数因此必须先把连续观测装箱映射到有限状态集合。本课 README 介绍了两种主流离散化思路划分箱子Divide into bins预先知道某值的取值范围时把区间切成若干bins再用 numpy 的digitize把观测值替换为它所属的箱子编号。其优点是能精确控制状态总数取决于你选择的箱子数量。缩放取整Scaling rounding用线性缩放把数值映射到某个有限区间再取整。缺点是状态规模控制较弱尤其当某些观测没有上下界时会得到无穷多状态。CartPole 原始代码里两套方案都有# CartPole 版按固定粒度缩放后转 int对应 README code block 6 def discretize(x): return tuple((x / np.array([0.25, 0.25, 0.01, 0.1])).astype(np.int))# 通用分箱方案对应 README code block 7 def create_bins(i, num): return np.arange(num 1) * (i[1] - i[0]) / num i[0] ints [(-5, 5), (-2, 2), (-0.5, 0.5), (-2, 2)] # 各参数取值区间 nbins [20, 20, 10, 10] # 各参数箱数 bins [create_bins(ints[i], nbins[i]) for i in range(4)] def discretize_bins(x): return tuple(np.digitize(x[i], bins[i]) for i in range(4))Mountain Car 的观测恰好全部有界位置 [-1.2, 0.6]速度 [-0.07, 0.07]所以两种离散化方案都适用这是它相对 CartPole 的一个便利之处——CartPole 的速度与角速度无界只能依赖极端值极少出现的假设来兜底。从 CartPole 移植到 Mountain Car最小改动清单对照作业给出的指令替换新环境、改写状态离散化、尽量不改算法主体一份可运行的移植需要覆盖以下四处1. 替换环境并确认空间import gym env gym.make(MountainCar-v0) print(env.action_space) # Discrete(3)0/1/2 三种动作 print(env.observation_space) # Box([-1.2 -0.07], [0.6 0.07], (2,)) print(env.action_space.sample())CartPole 中用gym.make(CartPole-v1)这里换成MountainCar-v0即可。初始化后建议用env.observation_space.low / high与env.action_space.n编程式读取边界与动作数而不是硬编码这样代码能进一步做到环境无关。2. 重写离散化函数二维有界观测由于观测降为二维缩放系数数组也要从 4 个元素改成 2 个。以分箱方式为例可把区间与箱数替换成def create_bins(i, num): return np.arange(num 1) * (i[1] - i[0]) / num i[0] # Mountain Car 的位置与速度区间 ints [(-1.2, 0.6), (-0.07, 0.07)] nbins [20, 20] bins [create_bins(ints[i], nbins[i]) for i in range(2)] def discretize(x): return tuple(np.digitize(x[i], bins[i]) for i in range(2))也可以用上一小节第一套缩放取整思路为位置与速度各选一个合适的粒度除数bin 宽例如位置区间跨度 1.8、速度区间跨度 0.14想分别得到约 36 与 28 个刻度时可写为np.array([0.05, 0.005])。两种写法在 CartPole 课程里都出现过选择哪种只影响状态精度与收敛速度不影响算法框架。小技巧分箱后可以在仿真循环里print(discretize(obs))观察状态编号是否落在预期的中段区间如位置 0 附近应得到约 10 号箱用于快速自检离散化是否合理——这一习惯在 notebook 的 code block 8 中被原样演示过。3. Q-Table 结构字典 vs 张量本课 README 指出当状态规模已知时Q-Table 可以用固定形状的张量表示例如 CartPole 分箱后是 20×20×10×10×2但当状态边界不确定时如缩放法可能产生负编号或越界值更稳妥的做法是用Python 字典以(state, action)二元组为键、以 Q 值为值未出现的条目默认返回 0Q {} actions (0, 1, 2) # Mountain Car 有三个动作 def qvalues(state): return [Q.get((state, a), 0) for a in actions]这段结构直接沿用 CartPole 课程的 code block 9唯一改动是把actions从(0, 1)扩为(0, 1, 2)。字典方案的健壮性对 Mountain Car 尤其有价值它天然容忍离散化偶尔产生的极端状态编号避免数组越界崩溃。4. 训练主循环与贝尔曼更新算法主体几乎可以原封不动复用。以课程中的 Q-Learning 循环为模板def probs(v, eps1e-4): v v - v.min() eps v v / v.sum() return v alpha 0.3 # 学习率 gamma 0.9 # 折扣因子 epsilon 0.90 # 探索/利用平衡 for epoch in range(...): obs env.reset() done False cum_reward 0 while not done: s discretize(obs) if random.random() epsilon: # 利用按 Q-Table 概率分布采样动作 v probs(np.array(qvalues(s))) a random.choices(actions, weightsv)[0] else: # 探索随机选动作 a np.random.randint(env.action_space.n) obs, rew, done, info env.step(a) cum_reward rew ns discretize(obs) # Q-Learning 值更新Q(s,a) ← (1-α)·Q(s,a) α·(r γ·max Q(s,·)) Q[(s, a)] (1 - alpha) * Q.get((s, a), 0) \ alpha * (rew gamma * max(qvalues(ns)))其中三个超参数的含义在 README 中有明确说明也是你调优的主战场alpha学习率决定每一步用新估计覆盖旧 Q 值的程度gamma折扣因子决定未来奖励相对当前奖励的权重epsilon探索/利用因子以epsilon概率按 Q-Table 采样利用其余概率随机动作探索用于触达从未见过的状态区域。在 Mountain Car 中探索尤其关键如果智能体从不乱冲去积累动量它永远学不会左右摆荡的窍门。收敛策略调超参 记录最优 Q-Table作业特别加了提示超参数调整很可能是让算法收敛的必要条件。原因在于 Mountain Car 的奖励既稀疏又全负每步 -1随机策略几乎总是超时 200 步被截断累计奖励恒在 -200 附近Q 值初始阶段很难产生有效梯度信息。建议的收敛策略有三条全部在课程 README 的Varying hyperparameters一节有据可查衰减学习率开始时让alpha接近 1 快速吸收经验随着 Q-Table 逐渐可信再调低避免新样本把已学到的价值整段覆盖。增大epsilon或反其道而行README 给出的方向是让epsilon缓慢上升、从探索更多过渡到利用更多也可以反直觉地从低 epsilon 起步观察结果再调重点是不要全程固定而是让探索-利用比例随训练动态变化。保存表现最优的 Q-Table训练中累计奖励会出现回落——新经验有时会破坏已经学好的 Q 值。README 为此引入了Qmax与Qbest机制每 5000 轮打印平均累计奖励一旦平均值刷新纪录就把当前 Q-Table 备份到Qbest训练结束后用它而不是最后一份 Q 表来评估。Qmax 0 cum_rewards [] # ... 训练循环内部 ... if epoch % 5000 0: avg np.average(cum_rewards) print(f{epoch}: {avg}, alpha{alpha}, epsilon{epsilon}) if avg Qmax: Qmax avg Qbest Q # 保留最优 Q 表 cum_rewards []此外由于本环境每步奖励为 -1你可以把累计奖励当作到达旗帜所需步数的相反数来读当单回合累计奖励大于 -199 时即代表该回合在 200 步内成功夺旗。训练收敛后用 CartPole 课程中按概率分布采样策略再跑一遍的方式渲染验证调用env.render()就能直观看到小车先向左侧山坡后退、借助下坡加速再冲向右侧山顶的经典动作轨迹。评价标准如何才算真正解决 Mountain Car作业最后给出了清晰的三档评分标尺这也是衡量你自己移植成果的检查清单标准优秀Exemplary合格Adequate需改进Needs Improvement要求Q-Learning 算法从 CartPole 示例成功移植仅做了最小代码改动并能在 200 步内解决夺旗问题从网上拿来了新的 Q-Learning 算法但文档完善或移植了现有算法却未达到期望结果未能成功移植任何算法但完成了实质性的阶段性工作实现了状态离散化、Q-Table 数据结构等从中可以提炼出三条评价维度改动是否足够小体现对环境抽象的理解、是否真的收敛体现对超参数与奖励结构的把握、中间成果是否完整离散化与 Q-Table 是比跑通更基础的能力证据。仓库资源导航本作业与课程的完整上下文都可以在当前仓库中继续阅读2-Gym 课程 READMECartPole 问题的完整讲解含离散化、Q-Table、训练主循环与绘图分析2-Gym 原始作业英文 与多语言译本如 中文译本CartPole 课程 Notebook直接照此改造的起点代码内含 13 个 code block 及其运行输出2-Gym 参考解答CartPole 已训练完成的完整 Notebook1-QLearning 课程 READMEQ-Learning 算法、epsilon-greedy 与棋盘环境的原理出处rlboard.py 是其环境实现。结语从 CartPole 到 Mountain Car 学到了什么Mountain Car 与 CartPole 看似是两套完全不同的物理任务但借助 OpenAI Gym 统一的环境接口我们几乎原封不动地复用了同一份 Q-Learning 主循环真正改动的只有环境 ID、动作数量、观测维数对应的离散化函数以及为了让负稀疏奖励环境收敛而必须调优的超参数。这个以最小改动跨环境迁移的过程正是课程想要传达的能力——理解算法所依赖的抽象远比背诵某个环境的特定解法更重要。当你后续遇到动作空间或观测空间更复杂例如连续动作、图像观测的任务时这套识别空间结构→离散化→组织价值表→调超参的分析框架仍然适用。【免费下载链接】ML-For-Beginners12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表