尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Unity ML-Agents 游戏集成指南:为三消(Match-3)游戏接入强化学习训练

Unity ML-Agents 游戏集成指南:为三消(Match-3)游戏接入强化学习训练 Unity ML-Agents 游戏集成指南为三消Match-3游戏接入强化学习训练【免费下载链接】ml-agentsThe Unity Machine Learning Agents Toolkit (ML-Agents) is an open-source project that enables games and simulations to serve as environments for training intelligent agents using deep reinforcement learning and imitation learning.项目地址: https://gitcode.com/gh_mirrors/ml/ml-agentsML-AgentsUnity Machine Learning Agents Toolkit不仅支持为通用 Agent 编写观测Observation、动作Action与奖励Reward还专门为若干常见游戏品类提供了开箱即用的集成工具。本指南聚焦其中最具代表性的Match-3三消集成它通过AbstractBoard抽象棋盘、Match3Sensor生成棋盘观测、Match3Actuator将模型动作翻译为棋盘移动并自动完成合法动作掩码Action Mask。读完本文你将掌握如何在自有三消游戏中实现AbstractBoard接口、挂载传感器与执行器组件、设计动作空间索引规则并借助示例场景与训练配置快速跑通完整训练流程。Game Integrations面向特定游戏品类的集成层在 ML-Agents 的文档体系中Game Integrations 是一组面向常见游戏类型的工具集合目标是降低把通用强化学习框架适配到具体游戏规则的重复劳动。其核心思想是把游戏规则与学习框架之间的边界抽象成少量接口由框架负责观测编码、动作映射与训练游戏侧只负责回答问题与执行指令。目前该集成层的主推实现是Match-3 集成它在AbstractBoard棋盘抽象、Move移动结构体、BoardSize棋盘尺寸结构体之上配套了一个观测传感器Match3Sensor和一个动作执行器Match3Actuator形成完整的观测 — 动作 — 掩码闭环。完整的 Match-3 技术文档见 Integrations-Match3.md其 C# 实现位于 Unity 包内的com.unity.ml-agents/Runtime/Integrations/Match3/目录下训练端还提供了专门的match3视觉编码器见 config/ppo/Match3.yaml 中的vis_encode_type: match3。需要特别说明的是示例中的 Match-3 游戏本身不可由人类玩家游玩只能通过训练驱动。它的意义在于验证 ML-Agents 集成层的完整工作流而不是提供一个可玩的小游戏。集成架构总览四个核心类各司其职Match-3 集成由四个核心类组成全部位于命名空间Unity.MLAgents.Integrations.Match3下类职责源码位置AbstractBoard游戏与 ML-Agents 之间的桥接抽象类回答棋盘尺寸、格子类型、移动合法性并执行移动AbstractBoard.csMove/BoardSize/Direction描述一次相邻格交换、棋盘尺寸与移动方向的数据结构Move.csMatch3Sensor/Match3SensorComponent将棋盘状态编码为向量或视觉观测Match3Sensor.cs、Match3SensorComponent.csMatch3Actuator/Match3ActuatorComponent将动作索引转换为Move并写入棋盘同时根据合法移动生成动作掩码Match3Actuator.cs、Match3ActuatorComponent.cs从源码结构看AbstractBoard是唯一的游戏侧必须实现的抽象类其余组件均可直接挂载复用。这正是该集成层把桥接工作收敛到单一抽象类的设计取向。AbstractBoard游戏与 ML-Agents 之间的桥梁AbstractBoard继承自MonoBehaviour因此必须挂在 GameObject 上是 ML-Agents 与你的游戏之间的桥接层。它允许 ML-Agents 做四件事询问棋盘当前与最大尺寸行数、列数、潜在棋子类型数询问某个格子的颜色即基础类型以及是否为特殊类型询问某个移动是否合法请求游戏执行一次移动。这些能力全部通过实现AbstractBoard的抽象方法获得。下面逐一说明每个方法的契约均以 AbstractBoard.cs 为准。GetMaxBoardSize()定义观测与动作的边界public abstract BoardSize GetMaxBoardSize();返回游戏可使用的最大BoardSize。它决定了观测与传感器的大小因此不要设得比实际需要更大——更大的尺寸意味着更长的观测向量与更多的动作分支训练成本随之上升。同时源码注释明确要求该方法返回值在运行期间不得改变因为观测规格和动作空间在初始化时就已确定。GetCurrentBoardSize()支持动态棋盘尺寸public virtual BoardSize GetCurrentBoardSize() { return GetMaxBoardSize(); }返回棋盘当前尺寸。默认实现直接返回GetMaxBoardSize()因此如果棋盘尺寸恒定不变就无需重写该方法。若当前尺寸小于最大尺寸框架会保证超出当前棋盘范围之外的格子不会调用GetCellType()与GetSpecialType()会移出当前棋盘范围的移动不会调用IsMoveValid()在传入IsMoveValid之前已由Move.InRangeForBoard()过滤。BoardSize结构体内部还定义了与运算符用于逐字段比较四个维度Rows、Columns、NumCellTypes、NumSpecialTypesDEBUG 构建下CheckBoardSizes()会校验当前尺寸没有超过初始化时的最大值否则发出警告。GetCellType()与GetSpecialType()读取格子状态public abstract int GetCellType(int row, int col); public abstract int GetSpecialType(int row, int col);GetCellType(row, col)返回该格子的颜色类型取值范围为0到BoardSize.NumCellTypes - 1含端点。值的具体顺序无关紧要只要稳定即可。GetSpecialType(row, col)返回该格子的特殊类型取值范围为0到BoardSize.NumSpecialTypes含端点。当NumSpecialTypes为 0 时表示棋盘不存在特殊类型此时框架会跳过特殊类型传感器。IsMoveValid()判定移动合法性public abstract bool IsMoveValid(Move m);由游戏规则决定某个Move是否合法。针对无特殊类型、无不可移动棋子的基础三消规则框架提供了现成的SimpleIsMoveValid(Move)方法public方法可直接调用它内部通过CheckHalfMove()将一次交换拆成两个半移动分别检查如果两个被交换格子的类型相同直接判定非法检查把移动方的格子换到对方位置后能否在水平或垂直方向形成 3 连及以上matchedUp matchedDown 2 || matchedLeft matchedRight 2对另一个方向另一颗棋子反向移动做同样检查任一方向成立即合法。需要注意的是CheckHalfMove会沿四个方向扫描同类型连续格子但会跳过移动来源方向避免把刚换走的格子重复计入。MakeMove()让游戏执行移动public abstract bool MakeMove(Move m);指示游戏执行给定移动返回true表示移动成功执行。训练期间被标记为非法invalid的移动偶尔仍会被请求——例如所有动作被掩码时的兜底分支——此时安全做法是什么都不做等待下一次移动请求而不是抛异常。辅助能力遍历移动与无合法移动回调AbstractBoard还内置了几个实用成员NumMoves()返回棋盘可能移动的总数等价于Move.NumPotentialMoves(GetMaxBoardSize())AllMoves()迭代当前棋盘范围内的所有潜在移动用InRangeForBoard过滤越界移动ValidMoves()迭代所有同时满足范围内且IsMoveValid()的移动是启发式策略枚举候选动作的主力入口OnNoValidMovesActionAction回调。当所有移动均非法时触发见下文Match3Actuator的兜底逻辑游戏可以借此重排棋盘或重置局面。Move 与 BoardSize动作空间的底层数据结构Move一次相邻格交换Move是一个结构体封装了一次交换两个相邻格子的操作字段包括MoveIndex移动索引、Row/Column被移动格子的坐标和Direction移动方向。Direction枚举定义了四个方向Up、Down、Left、Right。Move提供两个静态工厂方法与若干辅助方法见 Move.csMove.FromMoveIndex(int moveIndex, BoardSize maxBoardSize)从 0 到Move.NumPotentialMoves(maxBoardSize) - 1的索引构造Move用于遍历全部潜在移动也用于把 Agent 的决策离散动作索引还原成具体的移动Move.FromPositionAndDirection(int row, int col, Direction dir, BoardSize maxBoardSize)从行、列、方向构造Move。它内部会做两类校验越界抛出IndexOutOfRangeException例如col 0时不能向左移动并把Left/Down归一化为等价的Right/Up向左移动格(row, col)等价于向右移动格(row, col-1)从而保证每个移动只有唯一索引Move.NumPotentialMoves(BoardSize maxBoardSize)返回给定尺寸棋盘上的潜在移动总数源码公式为Rows * (Columns - 1) (Rows - 1) * Columns即棋盘内部边的数量OtherCell()返回本次交换涉及的另一颗格子的坐标OtherDirection()返回当前方向的相反方向InRangeForBoard(BoardSize boardSize)判断该移动在给定棋盘尺寸下是否越界两颗被交换格子的最大行列均须小于棋盘行列。动作空间索引规则先水平、后垂直动作索引的编号规则与论文Human Like Playtesting with Deep LearningFigure 2b一致水平移动Left/Right 对归一化为 Right先枚举垂直移动Up/Down 对归一化为 Up后枚举。具体实现见Move.FromMoveIndex()与Move.Next()前(maxCols - 1) * maxRows个索引对应所有水平移动方向为Right按列先变、行后变的顺序遍历剩余(maxRows - 1) * maxCols个索引对应所有垂直移动方向为Up。举例来说一个 8×8 棋盘共有8 × 7 7 × 8 112个潜在移动前 56 个为水平移动后 56 个为垂直移动这正是Match3Actuator使用的离散动作分支大小。BoardSize棋盘尺寸与类型数BoardSize是描述棋盘尺寸的结构体包含四个字段字段含义Rows行数Columns列数NumCellTypes棋盘可拥有的最大基础类型颜色/棋子数NumSpecialTypes特殊类型数可为 0为 0 时同类型格子视为等价它由GetMaxBoardSize()与GetCurrentBoardSize()返回并作为Move相关方法的maxBoardSize参数贯穿整个动作编解码过程。观测Match3Sensor 与 Match3SensorComponentMatch3Sensor通过AbstractBoard接口生成棋盘状态观测源码见 Match3Sensor.cs。其内部使用GridValueProvider一个int (int x, int y)委托读取格子值并提供两个工厂方法CellTypeSensor(board, obsType, name)编码每个格子的基础类型one-hot 大小为NumCellTypesSpecialTypeSensor(board, obsType, name)编码特殊类型one-hot 大小为NumSpecialTypes 1若NumSpecialTypes 0则返回null表示不需要该传感器。三种观测模式Match3ObservationTypeMatch3SensorComponent的ObservationType属性决定观测形式枚举值定义如下枚举值说明Vector对棋盘每个格子做 one-hot 编码后展平为向量。观测长度为Rows × Columns × oneHotSizeoneHotSize为基础类型数与特殊类型数之和按传感器分别计算UncompressedVisual与 Vector 相同的 one-hot 内容但按Rows × Columns排列成视觉观测通道数为 one-hot 大小不压缩CompressedVisual与 UncompressedVisual 相同的布局但训练时以多张 PNG 图片形式传输每张图 3 个通道RGB文档中的经验性观点是理论上视觉观测表现更好因为棋盘本身就是二维的、与视觉观测的空间结构天然匹配但该论断仍需更多实验验证——因此你可以通过ObservationType自由切换用实验数据说话。观测写入的实现细节Write()方法按当前棋盘尺寸内写 one-hot 值、超出部分写零的规则填充观测并且对超界区域做了无分支branchless优化以提升性能。视觉模式的压缩路径使用OneHotToTextureUtil每 3 个 one-hot 通道编码为一张 PNG 的 RGB 像素红/绿/蓝分别代表通道偏移 0/1/2因此一张图可表达 3 个类型位源码注释也坦承这种编码存在潜在浪费——例如 4 种基础类型 1 种特殊类型本可塞进 2 张图实际会用 3 张。Match3Sensor还实现了IDisposable在Dispose()中销毁内部复用的Texture2D。Match3SensorComponent运行时装配Match3SensorComponent继承SensorComponent通过[AddComponentMenu(ML Agents/Match 3 Sensor, ...)]暴露到编辑器菜单源码见 Match3SensorComponent.cs。它暴露两个可配置属性SensorName默认Match3 Sensor生成传感器对象的名称注意运行期修改不会影响 Agent 对传感器的排序ObservationType默认Vector观测模式。CreateSensors()在运行时从同一 GameObject 上获取AbstractBoard实现生成基础类型传感器 可选特殊类型传感器组合并返回。你不需要编写任何额外代码来使用它只需把它与你的 Agent 实现挂在同一个 GameObject 上。动作Match3Actuator 与 Match3ActuatorComponentMatch3Actuator负责把训练或推理产生的动作翻译成Move并发送给AbstractBoard.MakeMove()同时为每个潜在移动检查IsMoveValid()并据此设置 Agent 的动作掩码源码见 Match3Actuator.cs。动作空间与动作接收构造时Match3Actuator用Move.NumPotentialMoves(m_MaxBoardSize)计算潜在移动数并通过ActionSpec.MakeDiscrete(numMoves)声明单个离散分支的动作空间。OnActionReceived()中读取actions.DiscreteActions[0]作为moveIndex经Move.FromMoveIndex()还原为Move后调用m_Board.MakeMove(move)。此外还有一个m_ForceHeuristic开关若为真则忽略推理动作、强制调用启发式Heuristic文档与源码均注明这仅用于测试/生成对照统计。动作掩码让模型只探索合法移动WriteDiscreteActionMask()是Match3Actuator的核心逻辑遍历所有潜在移动索引 0 到NumMoves()-1对每个移动若InRangeForBoard(当前棋盘)且IsMoveValid()均成立则保留否则调用actionMask.SetActionEnabled(branch, i, false)将其禁用兜底逻辑如果所有移动都非法全部掩码会导致底层IDiscreteActionMask触发断言。此时若用户注册了m_Board.OnNoValidMovesAction回调则调用之否则记录警告日志随后强制保留最后一个动作未掩码SetActionEnabled(branch, numMoves - 1, true)让一个非法移动传入MakeMove()——文档明确表示处理一个非法移动比处理一个异常更可取因为MakeMove()本就被设计为可安全拒绝非法移动。启发式策略GreedyMove 与 EvalMovePointsMatch3Actuator内置了一个基于贪心评分的启发式Heuristic()调用GreedyMove()后者遍历m_Board.ValidMoves()并对每个移动调用EvalMovePoints(move)求分。默认EvalMovePoints()恒返回 1所有合法移动等概率并列最高分的移动通过**蓄水池采样reservoir sampling**均匀选取随机种子由构造参数seed提供。想要更聪明的启发式可以继承Match3Actuator并重写protected virtual int EvalMovePoints(Move move)用你游戏的真实得分函数作为评估标准——示例场景正是这么做的见下文。Match3ActuatorComponent运行时装配Match3ActuatorComponent继承ActuatorComponent源码见 Match3ActuatorComponent.cs暴露三个属性ActuatorName默认Match3 Actuator执行器名称RandomSeed默认-1启发式所用的随机种子-1表示自动生成使用 GameObject 的 InstanceID/EntityId 哈希ForceHeuristic默认false是否强制使用Agent.Heuristic()决定动作仅用于测试。CreateActuators()从同一 GameObject 获取AbstractBoard构造并返回一个Match3ActuatorActionSpec属性则根据棋盘最大尺寸动态计算MakeDiscrete(numMoves)。与传感器组件一样把它与你的 Agent 实现挂在同一个 GameObject 上即可无需编写额外代码。搭建 Match-3 训练模拟四步接入流程综合 Integrations-Match3.md 的指引接入自有三消游戏的完整流程如下实现AbstractBoard的抽象方法把你的棋盘规则尺寸、格子类型、特殊类型、合法移动判定、移动执行接入框架为Agent设计奖励当它做出你期望的行为如一行消除多个棋子、清除特定类型棋子时给予奖励把四个组件挂到同一个 GameObject 上Agent、你的AbstractBoard实现、Match3SensorComponent、Match3ActuatorComponent适时调用Agent.RequestDecision()当你准备好让 Agent 在下一个Academy步做出决策时调用在下一个Academy步棋盘上的MakeMove()会被调用。推荐的入门路径是先阅读并运行示例场景 Project/Assets/ML-Agents/Examples/Match3/Scenes/Match3.unity 及其脚本理解完整闭环再在自己的游戏中实现AbstractBoard。示例实现剖析Match3Board 与 Match3Agent示例场景的棋盘实现 Match3Board.cs 直接继承AbstractBoard展示了上述所有方法的落地方式用MinRows/MaxRows、MinColumns/MaxColumns、NumCellTypes、NumSpecialTypes等 Inspector 字段配置棋盘GetMaxBoardSize()返回最大配置GetCurrentBoardSize()返回每个 episode 开始时随机化的当前尺寸UpdateCurrentBoardSize()在Min~Max之间随机取值仅作示例你可按需修改内部用(int CellType, int SpecialType)[,] m_Cells保存棋盘MakeMove()先校验IsMoveValid()再交换两颗棋子得分模型定义了三种格子普通方块BasicCellPoints默认 1 分、特殊球SpecialCell1Points默认 2 分、特殊十字SpecialCell2Points默认 3 分IsMoveValid()直接复用基类的SimpleIsMoveValid()无特殊规则时的基础三消判定。Agent 实现 Match3Agent.cs 则演示了训练驱动下的游戏循环训练时Academy.Instance.IsCommunicatorOn为真走FastUpdate()快速路径——循环执行标记匹配 → 清除匹配并加奖励 → 重力下落 → 补新棋子直到无匹配随后检查Board.ValidMoves()是否存在合法移动若无则重排棋盘最后RequestDecision()。奖励为k_RewardMultiplier * pointsEarnedk_RewardMultiplier 0.01f。由于连锁消除会导致不同 Agent 的决策频率不同示例没有使用标准的 MaxSteps 机制而是通过MaxMoves默认 500统计每个 Agent 的移动次数并手动调用EpisodeInterrupted()结束 episode。值得注意的是示例还自定义了执行器 Match3ExampleActuator.cs它继承Match3Actuator并重写EvalMovePoints()用棋盘真实的得分规则按特殊类型加权评估每个潜在移动的预期得分从而让启发式策略学会挑分最高的走法。这正对应Match3Actuator文档中重写EvalMovePoints()以使用游戏计分作为更好的启发式估计的用法配套的组件 Match3ExampleActuatorComponent.cs 则重写CreateActuators()返回自定义执行器。训练配置使用 match3 视觉编码器仓库为 Match-3 场景提供了开箱即用的训练配置 config/ppo/Match3.yaml其中两个关键点network_settings.vis_encode_type: match3训练端使用专门为 Match-3 棋盘观测设计的视觉编码器若使用视觉观测network_settings.normalize: true、hidden_units: 256、num_layers: 4、batch_size: 16、buffer_size: 120、learning_rate: 0.0003、max_steps: 5000000等 PPO 超参数以及time_horizon: 128、reward_signals.extrinsic.gamma: 0.99。配置底部还定义了Match3SimpleHeuristic与Match3SmartHeuristic两个 behavior它们使用极小的网络hidden_units: 4、num_layers: 1因为目的不是真正训练模型而是仅运行启发式策略以生成对照数据——这与ForceHeuristic开关的测试用途相互印证。训练命令与仓库其他环境一致如mlagents-learn config/ppo/Match3.yaml --run-id...执行环境要求以仓库 Installation 与 Training-ML-Agents 文档为准。测试与验证观测与执行器的单元测试Match-3 集成在仓库中配有完整的单元测试可作为理解实现行为、验证自有集成的参考Match3ActuatorTests.cs覆盖动作掩码、非法移动兜底、MakeMove调用等执行器行为Match3SensorTests.cs覆盖向量/视觉观测的 one-hot 编码与 PNG 压缩输出测试资源目录 Tests/Editor/Integrations/Match3 中存放了预期观测快照match3obs_*.png等用于校验压缩视觉观测的编码正确性。延伸阅读集成总览Integrations.mdMatch-3 技术规范Integrations-Match3.md示例场景与脚本Project/Assets/ML-Agents/Examples/Match3集成层源码com.unity.ml-agents/Runtime/Integrations/Match3训练配置config/ppo/Match3.yaml【免费下载链接】ml-agentsThe Unity Machine Learning Agents Toolkit (ML-Agents) is an open-source project that enables games and simulations to serve as environments for training intelligent agents using deep reinforcement learning and imitation learning.项目地址: https://gitcode.com/gh_mirrors/ml/ml-agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表