news 2026/9/5 20:17:20

ML-For-Beginners Q-Learning 进阶作业实战:用能量与疲劳建模“更真实的世界“并学习战胜狼

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ML-For-Beginners Q-Learning 进阶作业实战:用能量与疲劳建模“更真实的世界“并学习战胜狼

ML-For-Beginners Q-Learning 进阶作业实战:用能量与疲劳建模"更真实的世界"并学习战胜狼

【免费下载链接】ML-For-Beginners12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners

本篇指南基于 Microsoft ML-For-Beginners 强化学习课程中 Q-Learning 一课的进阶作业文档 assignment.it.md(原文为 assignment.md 的意大利语译文)展开,结合仓库中的环境实现 rlboard.py、原始课件 notebook.ipynb 以及官方参考解答 assignment-solution.ipynb,完整讲解如何把原版"找苹果"世界改造成带能量、疲劳与狼战斗的系统,重定义状态空间、修改奖励函数、跑通 Q-Learning 训练流程,并用随机游走基线做量化对比。读完后你将掌握:如何为马尔可夫决策过程扩展状态表示、如何按游戏规则设计奖励函数、如何调 epochs / 学习率衰减等超参数以应对"成功事件罕见"的训练难题。

1. 任务背景:从"找苹果"到"打狼"

本作业隶属于课程第 8 章 Reinforcement Learning 的第 1 课 1-QLearning。前序课件(README 与 notebook)中,Peter 在一个 8x8 棋盘上几乎可以无限移动:只要吃到苹果(+10)就赢,碰到狼或水(-10)就输,奖励函数只与格子类型有关。

作业文档开篇直接指出了这个世界的"不真实"之处,并给出改造目标——在更真实的世界里,Peter 必须偶尔停下来休息,也要进食。作业要求实现以下5 条新规则

  1. 移动消耗:Peter 每从一处移动到另一处,会损失能量(energy)并累积疲劳(fatigue)
  2. 进食回能:Peter 可以吃苹果(apple)来补充能量;
  3. 休息解乏:Peter 可以在树(tree)或草地(绿色格子)上休息以消除疲劳,即走到棋盘上带树或草的位置即可;
  4. 新目标:Peter 需要找到狼并将其杀死(而非原版中"躲开狼");
  5. 战斗条件:要杀死狼,Peter 必须满足一定的能量与疲劳水平,否则他会输掉战斗

注意规则 4 与原版 notebook 的关键差异:原版中狼是纯粹的负奖励终止格(end_reward = -10),而新世界中狼变成了博弈对象——到达狼的格子不再是"必死",而是触发一次取决于当前能量/疲劳的战斗判定。这正是本次作业奖励函数与状态空间都要重写的原因。

2. 作业指令:起点、必做项与两条关键提示

作业 assignment.md 的"Instructions"部分给出三步操作要求(译文版与英文版内容一致):

  1. 以原始 notebook 为起点:使用 notebook.ipynb 作为解决方案的起点(它包含 Board 环境、随机游走基线与 Q-Learning 训练循环);
  2. 改写奖励函数并训练:按游戏规则修改奖励函数,运行强化学习算法学习获胜的最佳策略;
  3. 保留随机游走并对比:在自己的方案中保留负责随机游走策略的代码,最后对比自己的算法与随机游走在"胜/负局数"上的结果。

文档还给出两条重要的Note(提示),它们直接决定了解法的设计方向:

  • 状态表示更复杂:新世界中,状态除了 Peter 的棋盘位置,还必须包含疲劳与能量水平。作业允许三种等价实现路线:
    • 把状态表示为元组(Board, energy, fatigue)
    • 为状态定义一个独立类(可以让它继承自Board);
    • 或者直接修改 rlboard.py 里的原始Board类。
  • 超参数需要调整,尤其是 epochs 数量:因为新游戏中"成功事件"(与狼战斗并获胜)是罕见事件(rare event),可以预期训练时间会远长于原版课件(原版 5000 epochs)。

这两条提示与仓库中的证据相互印证:参考解答 assignment-solution.ipynb 正是采用了"独立state类"路线,并把训练轮数提升到了10000 epochs(原版为 5000),学习率衰减常数也从原版的np.exp(-n / 10e5)调整为np.exp(-n / 3000),衰减得更快。

3. 状态建模:state类承载棋盘 + 能量 + 疲劳

原版世界中,状态 = 棋盘 + Peter 位置,Q 表形状为width x height x len(actions)。新世界中若仍只用位置作状态,Peter 走到狼时是否获胜就无法由状态决定——这违反马尔可夫性(结果还取决于历史累积的能量/疲劳)。因此参考解答新增了state类,把三要素封装在一起:

class state: def __init__(self, board, energy=10, fatigue=0, init=True): self.board = board self.energy = energy # 初始能量 10 self.fatigue = fatigue # 初始疲劳 0 self.dead = False if init: self.board.random_start() self.update() def at(self): return self.board.at() def update(self): if self.at() == Board.Cell.water: self.dead = True return if self.at() == Board.Cell.tree: self.fatigue = 0 # 规则3:树下休息,疲劳清零 if self.at() == Board.Cell.apple: self.energy = 10 # 规则2:吃苹果,能量回满到 10 def move(self, a): self.board.move(a) self.energy -= 1 # 规则1:移动扣 1 能量 self.fatigue += 1 # 规则1:移动加 1 疲劳 self.update() def is_winning(self): return self.energy > self.fatigue # 规则5:战斗判定条件

以上代码取自 assignment-solution.ipynb。从参考实现的取值看,具体游戏规则被落实为:

机制数值/条件对应作业规则
初始能量 / 疲劳energy=10, fatigue=0初始状态设定
每次移动energy -= 1, fatigue += 1规则 1
踩到苹果energy 重置为 10规则 2
踩到树/草地fatigue 重置为 0规则 3
战斗判定energy > fatigue 则胜规则 5
到达狼格按战斗判定返回胜/负规则 4

其中"energy > fatigue"是参考解答对规则 5 中"一定水平(certain levels)"的具体化选择——作业文档本身只要求"满足一定水平",把阈值、权重改成你自己喜欢的形式(如energy >= fatigue + 2)是允许的,这正是评分标准里"定义新世界规则"的考察点。

Board.Cell的格子类型常量定义在 rlboard.py:empty=0, water=1, wolf=2, tree=3, apple=4。参考解答用m.randomize(seed=13)固定随机种子(默认参数num_water=3, num_wolves=1, num_trees=5, num_apples=3,见 rlboard.py 的randomize方法),保证所有实验在同一张棋盘上进行,对比结果才可复现。

4. 游戏循环:新终止条件与随机游走基线

原 notebook 的walk函数只有"到苹果(成功)/ 到狼或水(死亡)"两种结局。新世界里结局分成三种,参考解答重写了walk

def random_policy(state): return random.choice(list(actions)) def walk(board, policy): n = 0 # 步数 s = state(board) while True: if s.at() == Board.Cell.wolf: if s.is_winning(): return n # 成功:杀死狼,返回正步数 else: return -n # 失败:战斗不敌,返回负步数 if s.at() == Board.Cell.water: return 0 # 溺水(第三种结局) a = actions[policy(m)] s.move(a) n += 1

返回值约定:正数 = 胜狼(值为步数)、负数 = 败于狼、0 = 溺水。对应地,统计函数改为按"胜/负/溺"三类计数:

def print_statistics(policy): s, w, n = 0, 0, 0 for _ in range(100): z = walk(m, policy) if z < 0: w += 1 # 被狼击败 elif z == 0: n += 1 # 溺水 else: s += 1 # 获胜 print(f"Killed by wolf = {w}, won: {s} times, drown: {n} times")

先跑随机游走基线。参考解答 notebook 中记录的输出为:

Killed by wolf = 5, won: 1 times, drown: 94 times

也就是说 100 局里随机游走只有约 1% 的胜率(1 次杀死狼)、94% 直接溺水。这组基线数字很重要:它量化了"新世界里随机策略有多弱",也是作业要求的对比基准。由于"获胜"需要同时满足"存活到狼"与"能量 > 疲劳"两个条件,而每次移动都会拉开能量与疲劳的差距,随机游走几乎注定在战斗前就溺死或战败——这也解释了作业 Note 中"战斗成功是罕见事件、训练会更慢"的论断。

5. 奖励函数:把"状态好坏"写成可学习的信号

作业的核心要求是"Modify the reward function above according to the rules of the game"。参考解答给出的奖励函数把即时状态量终止奖励结合:

def reward(s): r = s.energy - s.fatigue # 基础分:能量减疲劳 if s.at() == Board.Cell.wolf: return 100 if s.is_winning() else -100 if s.at() == Board.Cell.water: return -100 return r

设计要点:

  • 非终止步的奖励r = energy - fatigue始终为正(初始为 +10,随移动逐步衰减)。这意味着"多走路"本身是持续亏损的,agent 被激励尽快找到有利路径;同时也把"能量/疲劳比"这一隐变量直接写进了奖励梯度里,agent 不需要显式理解体力规则也能从奖励差值中学到"别走太久""尽快去树下休息"。
  • 终止奖励 ±100 量级远大于步进奖励,保证最终结果(战斗胜负、溺水)主导价值估计,符合 Q-Learning 处理"延迟奖励"的假设:真正的大奖励只在回合末尾出现,算法必须靠 Bellman 更新把信用回溯到前面的步。
  • 训练终止条件:参考解答的学习循环用abs(r) == 100判断回合结束——即只有"到达狼格(无论胜负)"或"溺水"才终止回合;吃苹果和树下休息都只是状态重置,不构成终止。

6. Q-Learning 训练循环:状态索引与超参数细节

Q 表仍按位置索引(形状width x height x len(actions)),因为参考解答选择把 energy/fatigue 放进奖励与状态类,而不是展开 Q 表的维度:

Q = np.ones((width, height, len(actions)), dtype=np.float) * 1.0 / len(actions) # 初值 0.25 def probs(v, eps=1e-4): v = v - v.min() + eps v = v / v.sum() return v

训练循环(10000 epochs)如下,每一行都对应 Q-Learning 的标准步骤:

lpath = [] for epoch in range(10000): # 随机起点,新建一局(energy=10, fatigue=0) s = state(m) n = 0 while True: x, y = s.board.human v = probs(Q[x, y]) # 由 Q 值导出动作概率(探索/利用平衡) while True: a = random.choices(list(actions), weights=v)[0] dpos = actions[a] if s.board.is_valid(s.board.move_pos(s.board.human, dpos)): break # 只允许落在棋盘内的合法移动 s.move(dpos) # 移动并更新 energy/fatigue r = reward(s) if abs(r) == 100: # 终止:胜/负狼 或 溺水 lpath.append(n) break alpha = np.exp(-n / 3000) # 学习率随步数指数衰减 gamma = 0.5 # 折扣因子 ai = action_idx[a] Q[x, y, ai] = (1 - alpha) * Q[x, y, ai] + alpha * (r + gamma * Q[x + dpos[0], y + dpos[1]].max()) n += 1

与原版课件(notebook.ipynb,README 中的 code block 8)逐条对比,关键差异及原因:

超参数/逻辑原版课件本作业参考解答原因
epochs500010000获胜事件罕见,需要更多探索(作业 Note 明确提示)
学习率衰减np.exp(-n / 10e5)np.exp(-n / 3000)更快衰减,后期稳定 Q 表
折扣因子 gamma0.50.5不变
越界处理check_correctness=False允许走出棋盘并终止回合内层 while 循环拒绝非法移动,重抽动作新世界回合只在"打狼/溺水"时终止,避免越界提前截断
回合终止r == end_reward or cum_reward < -1000abs(r) == 100新奖励函数只有 ±100 是终止信号

这里体现了一个工程取舍:参考解答通过"动作重采样"把 agent 约束在棋盘内,使每回合必然走到终止格,lpath(每回合步数列表)曲线因此更有统计意义。probs()中加eps=1e-4是为了避免初始 Q 值全相等时出现 0/0,这一点在 README 的 "Python implementation" 一节有同样说明。

7. 结果对比:Q-Learning 显著优于随机游走

训练完成后用 Q 表派生的策略(按 Q 值加权采样,兼顾利用与残余探索)走 100 局:

def qpolicy(m): x, y = m.human v = probs(Q[x, y]) a = random.choices(list(actions), weights=v)[0] return a print_statistics(qpolicy)

参考解答 notebook 中记录的输出为:

Killed by wolf = 1, won: 9 times, drown: 90 times

与基线(won: 1, killed: 5, drown: 94)相比:胜率从约 1% 提升到约 9%,战败数从 5 降到 1,溺水占比基本持平。参考解答对此的结论是:溺水案例"明显减少",但 Peter 仍不能总是杀死狼,并建议读者继续做超参数实验(epochs、alpha 衰减常数、gamma)来进一步改善——这恰好呼应了作业 Note 中"你可能需要调整超参数"的要求,也说明本作业的设计目标是让学习者亲身体验超参数优化(hyperparameter optimization)这一独立主题,README 末尾"Investigating the learning process"一节同样强调:学习率、学习率衰减与折扣因子这类超参数直接决定学习质量。

最后,参考解答把每回合步数lpath画成曲线(plt.plot(lpath))来观察学习过程。结合 README 对原版学习曲线的三点解读(先升后降、中途可能因 Q 表被覆写而突跳),你可以用同一方法诊断自己的训练:曲线持续下降说明策略在收敛,突跳说明需要放缓学习率衰减。

8. 评分标准(Rubric)

作业文档附带的评分表用于自评你的解法达到哪个等级(以下依据 assignment.md 的 Rubric 翻译整理):

等级标准
优秀(Exemplary)提交的 notebook 包含新世界规则的完整定义、Q-Learning 算法实现与必要的文字说明;Q-Learning显著优于随机游走。
合格(Adequate)notebook 已提交,Q-Learning 已实现且优于随机游走,但改进不显著;或者 notebook 文档质量差、代码组织混乱。
需改进(Needs Improvement)对重定义世界规则做了一些尝试,但 Q-Learning 算法无法正常工作,或奖励函数未完整定义。

对照参考解答可以看出"优秀"档的构成要件:完整的规则形式化(state类 + 三条数值化机制)、可运行的训练循环、保留随机游走基线并输出对比统计、以及m.plot(Q)/lpath曲线等文字化解释。

9. 小结与延伸

这篇作业的本质是一次MDP 重设计练习:状态空间从"位置"扩展为"位置 + 能量 + 疲劳",终止集合从"苹果/狼/水"改为"战斗胜负 + 溺水",奖励从离散档位改为"状态量函数 + 终止大奖"。仓库中的完整证据链为:规则定义见 assignment.md,环境底层见 rlboard.py,教学推导(Bellman 方程、探索/利用、超参数讨论)见 README.md 与 notebook.ipynb,可运行参考解答见 assignment-solution.ipynb(同目录还有 R 与 Julia 版本)。

在参考解答之上可以继续做的实验:把is_winning的阈值改为energy >= fatigue + k观察胜率对战斗条件的敏感度;将 Q 表维度扩展到(width, height, energy_bins, fatigue_bins)以严格满足马尔可夫性;或调整alpha衰减常数与 epochs,验证作业 Note 中"罕见事件导致长训练"的判断。下一课 2-Gym 会把这些手工搭建的环境迁移到通用强化学习框架中。

【免费下载链接】ML-For-Beginners12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 20:16:27

OpenMAIC:开源AI课堂,文档一键变讲师,部署调优全攻略

上周为了给团队做一次产品方案内训&#xff0c;我把一份33页的方案文档拆了三个晚上&#xff1a;先提炼大纲、再写逐字稿、然后录音剪辑。第一天改稿就改了七遍&#xff0c;最崩溃的是我辛辛苦苦录完的讲解视频&#xff0c;业务部门听完只回了句“能不能把第三节再讲细一点”。…

作者头像 李华
网站建设 2026/9/5 20:16:13

从零跑通 Apktool:APK 反编译与重编译实操指南

从零跑通 Apktool&#xff1a;APK 反编译与重编译实操指南 【免费下载链接】Apktool A tool for reverse engineering Android apk files 项目地址: https://gitcode.com/GitHub_Trending/ap/Apktool Apktool 反编译一个 APK&#xff0c;再把改好的内容重新打包成能装回…

作者头像 李华
网站建设 2026/9/5 20:10:29

DataEase 内网离线部署指南:单机完整搭建 BI 可视化平台

DataEase 内网离线部署指南&#xff1a;单机完整搭建 BI 可视化平台 【免费下载链接】dataease &#x1f525; 人人可用的开源 BI 工具&#xff0c;数据可视化神器。An open-source BI tool alternative to Tableau. 项目地址: https://gitcode.com/GitHub_Trending/da/datae…

作者头像 李华
网站建设 2026/9/5 20:10:04

微信小程序高并发架构解析:前端、后端与C/C++协同实战

简介&#xff1a;本资源是一套面向微信小程序开发初学者与进阶者的12306火车票查询功能模仿项目源码&#xff0c;聚焦出行类应用实战&#xff0c;帮助开发者掌握真实业务场景下的UI构建、API对接与交互逻辑实现。压缩包共78个文件&#xff0c;含11个JS逻辑文件&#xff08;处理…

作者头像 李华
网站建设 2026/9/5 20:09:10

Mem0 插件 context-loader 技能详解:在任务开始前预加载相关记忆

Mem0 插件 context-loader 技能详解&#xff1a;在任务开始前预加载相关记忆 【免费下载链接】embedchain The Memory Layer for AI Agents - Drop-in memory infrastructure for AI agents and apps. Context that persists. Built for production. 项目地址: https://gitco…

作者头像 李华