ML-Agents 自定义网格传感器(Custom Grid Sensors)完全指南:从 GridSensorBase 派生到自定义观测
ML-Agents 自定义网格传感器Custom Grid Sensors完全指南从 GridSensorBase 派生到自定义观测【免费下载链接】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网格传感器Grid Sensor为 ML-Agents 强化学习环境提供了一种基于俯视 2D 网格的观测方式可无死角地感知智能体周围区域内的物体。本文基于 Unity ML-Agents 官方文档《Custom Grid Sensors》展开结合仓库中的 GridSensorBase.cs、GridSensorComponent.cs、OneHotGridSensor.cs 与 CountingGridSensor.cs 源码系统讲解如何通过派生GridSensorBase与GridSensorComponent收集自定义属性作为观测以及包内置的两种网格传感器实现原理。读完本文你将掌握自定义网格传感器的完整开发流程、四个核心可重写方法的语义以及数据归一化与压缩之间的约束关系。Grid Sensor 与 RayCast 观测的取舍在自定义网格传感器之前先理解它解决什么问题。官方文档指出Grid Sensor 提供一种自顶向下视角的 2D 观测用于检测智能体周围的物体。与射线投射RayCasts相比它有两个关键差异无盲区射线只能探测有限数量的方向网格传感器则在整片网格区域内获得完整观测不存在间隙不被遮挡物体检测不会被智能体周边的其他物体阻断每个格子独立查询检测结果互不干扰。代价是更高的计算资源开销——网格越大、每格观测维度越高物理查询与数据编码的开销越大。因此 Grid Sensor 适合需要细粒度空间感知的场景例如需要区分某方向存在多个目标目标在网格中的精确位置等射线难以表达的信息。需要注意的适用前提根据 Learning-Environment-Design-Agents.md 的说明Grid Sensor 仅适用于 3D 环境在 2D 环境中不会正常工作。网格传感器的额外能力在于你可以从GridSensorBase基类派生在识别物体 Tag 之外收集自定义属性作为观测从而极大扩展 GridSensor 的用途。给 Agent 挂载 GridSensorComponent 后网格以俯视视角覆盖智能体周围区域图片来源Learning-Environment-Design-Agents.md创建自定义网格传感器的整体结构创建自定义网格传感器需要从两个类派生GridSensorBase传感器的实现本体定义传感器如何处理检测到的 Collider、数据长什么样、如何从检测对象构造观测GridSensorComponentUnity 组件层负责将传感器挂到 GameObject 上、管理参数并接入Agent的传感器系统。这种实现 组件的双层结构意味着GridSensorBase负责纯数据处理逻辑可在单元测试中独立验证GridSensorComponent负责与 Unity 场景、Inspector 交互二者通过CreateSensors()桥接见下文源码分析。派生自 GridSensorBase四个核心可重写方法GridSensorBase是网格传感器全部数据处理逻辑所在它在构造时完成网格布局初始化并在每帧感知时把检测结果写入观测缓冲区。根据用途你可能需要重写以下方法GetCellObservationSize()定义每格观测维度protected virtual int GetCellObservationSize() { return 1; }该方法返回每个格子的观测大小即写入dataBuffer的 float 数量默认值为1。从源码看它决定了整个传感器的观测规格在 GridSensorBase 构造函数 中m_NumCells m_GridSize.x * m_GridSize.z随后以ObservationSpec.Visual(m_CellObservationSize, m_GridSize.x, m_GridSize.z)构造观测规格因此总观测维度为每格维度 × 网格宽度 × 网格深度。重写GetObjectData时务必同步重写此方法否则写入缓冲区的数据量与实际分配的缓冲区不一致。GetObjectData()从检测对象构造观测protected virtual void GetObjectData(GameObject detectedObject, int tagIndex, float[] dataBuffer) { dataBuffer[0] tagIndex 1; }这是自定义网格传感器的核心入口。输入参数为detectedObject当前格子内检测到的 GameObjecttagIndex该对象 Tag 在DetectableTags列表中的索引从 0 开始dataBuffer待写入观测值的缓冲区其大小由GetCellObservationSize()决定。写入后的数据会从每个格子汇总作为观测发送给训练器。基类默认实现写入tagIndex 1注意基类默认编码不是 one-hot而是索引偏移而包内置的 OneHot 与 Counting 传感器则各自覆盖了此方法见下文。GridSensorBase.cs 的 XML 文档给出了一个覆盖示例——读取检测对象的 Rigidbody 速度作为观测protected override void GetObjectData(GameObject detectedObject, int tagIndex, float[] dataBuffer) { if (tagIndex Array.IndexOf(DetectableTags, RigidBodyObject)) { Rigidbody rigidbody detectedObject.GetComponentRigidbody(); dataBuffer[0] rigidbody.velocity.x; dataBuffer[1] rigidbody.velocity.y; dataBuffer[2] rigidbody.velocity.z; } }IsDataNormalized()声明数据是否归一化protected virtual bool IsDataNormalized() { return false; }返回观测数据是否归一化到 0~1 区间默认false。这个返回值直接决定了是否可以使用压缩观测PNG 压缩——压缩只支持归一化数据因为压缩本质上把观测值映射为图像像素通道。从 GridSensorBase.cs 的CompressionType属性 setter 可见底层约束set { if (!IsDataNormalized() value SensorCompressionType.PNG) { Debug.LogWarning($Compression type {value} is only supported with normalized data. The sensor will not compress the data.); return; } m_CompressionType value; }即当IsDataNormalized()返回false而请求 PNG 压缩时压缩设置会被静默忽略并给出警告。此外ValidateValues 方法 在启用 PNG 压缩时会对每次写入的数据逐值校验若出现0或1的数值会直接抛出UnityAgentsException提示数据必须归一化到 0-1 之间。当数据不在 0~1 区间但希望用压缩加速训练时应先在GetObjectData中自行归一化。官方文档给出的实践建议数据天然有界时归一化到可能范围即可。例如旋转角有界于0 ~ 360记录角度x时存x/360而非x数据无界时如位置、速度设置合理的 min/max 范围并据此归一化。GetProcessCollidersMethod()单元格内多对象的处理策略protected internal virtual ProcessCollidersMethod GetProcessCollidersMethod() { return ProcessCollidersMethod.ProcessClosestColliders; }当某个格子内检测到多个带有可检测 Tag 的对象时该方法决定传感器行为。ProcessCollidersMethod枚举定义于 GridSensorBase.cs目前提供两种枚举值语义适用场景ProcessClosestColliders默认只处理离智能体最近的 Collider每个格子的数据只由一个对象表示需要每格一个物体的空间表达ProcessAllColliders处理格子内所有检测到的 Collider每格数据具有可加性例如统计格子内的物体数量使用ProcessAllColliders时传入GetObjectData()的dataBuffer会包含同一格子内其他 Collider 已处理的数据因此你更可能对缓冲区做加减而不是整体覆盖。这一行为在 ProcessDetectedObject 方法 中有明确实现if (GetProcessCollidersMethod() ProcessCollidersMethod.ProcessAllColliders) { // 先把该格当前累计数据拷入 cellDataBuffer再做增量修改 Array.Copy(m_PerceptionBuffer, cellIndex * m_CellObservationSize, m_CellDataBuffer, 0, m_CellObservationSize); } else { // 只取最近 Collider先清空缓冲区再写入 Array.Clear(m_CellDataBuffer, 0, m_CellDataBuffer.Length); } GetObjectData(detectedObject, i, m_CellDataBuffer);这段源码清楚地展示了两种模式的本质区别ProcessAllColliders是累积式写入ProcessClosestColliders是覆盖式写入。派生自 GridSensorComponent把传感器接入 UnityGridSensorComponent继承自SensorComponent在 GridSensorComponent.cs 中定义。要创建你的传感器需要重写GetGridSensors()并返回想要使用的网格传感器数组public class CustomGridSensorComponent : GridSensorComponent { protected override GridSensorBase[] GetGridSensors() { return new GridSensorBase[] { new CustomGridSensor(...)}; } }它既可以返回多个不同的自定义网格传感器也可以混入包内自带的传感器。基类默认实现返回一个OneHotGridSensor见 GetGridSensors 默认实现。CreateSensors() 的内部装配流程理解组件如何工作有助于正确使用它。从 CreateSensors 方法 可以看到完整的装配链路创建BoxOverlapChecker实现自IGridPerception传入m_CellScale、m_GridSize、m_RotateWithAgent、m_ColliderMask、AgentGameObject、m_DetectableTags以及两个 Collider 缓冲区大小参数——这是物理查询的执行者创建调试用GridSensorBase(DebugGridSensor, ...)其压缩类型固定为SensorCompressionType.None因为 gizmo 数据是正整数压缩会触发校验异常调用GetGridSensors()获得自定义传感器数组若为空数组或null会抛出UnityAgentsException提示至少返回一个传感器只把m_GridPerception赋给第一个传感器确保物理查询每帧只更新一次其余传感器通过RegisterSensor注册若ObservationStacks ! 1每个传感器会用StackingSensor包裹以实现多帧观测堆叠。组件的 Inspector 参数基于 GridSensorComponentEditor.cs 的 Inspector 布局和组件的序列化字段各参数说明如下Sensor Name生成的网格传感器名称影响传感器排序运行时修改不生效Grid SettingsCell Scale / Grid Size每格大小与网格尺寸。GridSize只支持 2D 网格构造函数与属性 setter 都会强制y为 1源码中若m_GridSize.y ! 1会抛出UnityAgentsExceptionGridSensor only supports 2D grids.Editor 中也将 y 锁定为 1二者创建传感器后不可运行时修改Agent GameObject智能体根对象引用用于消歧与智能体同 Tag 的对象默认为当前 GameObjectRotate With Agent网格是否随智能体朝向旋转Detectable Tags可检测的 Tag 列表其长度直接决定 OneHot 每格观测维度Collider Mask物理层遮罩控制哪些层级的 Collider 参与检测Sensor SettingsObservation Stacks观测堆叠帧数范围 1~501 表示不堆叠Compression Type压缩类型默认 PNG仅在数据归一化时生效Collider and BufferInitial / Max Collider Buffer Size预分配缓冲区大小默认 4与绝对上限默认 500。源码注释说明使用OverlapBoxNonAlloc物理 API 预分配数组若发现 Collider 数达到InitialColliderBufferSize则数组翻倍扩容硬上限为 500Debug GizmoShow Gizmos / Gizmo Y Offset / Debug Colors是否显示网格 gizmo、gizmo 高度偏移、每个 Tag 对应的调试颜色。包内置的两种网格传感器仓库提供了两个开箱即用的网格传感器它们的实现也是编写自定义传感器的最佳参考。OneHotGridSensor默认的 one-hot 传感器这是GridSensorComponent使用的默认传感器检测带可检测 Tag 的对象观测为检测到的 Tag 索引的one-hot 表示。完整实现见 OneHotGridSensor.cs其四个方法的行为为GetCellObservationSize()detectableTags.LengthIsDataNormalized()trueGetProcessCollidersMethod()ProcessCollidersMethod.ProcessClosestCollidersGetObjectData()protected override void GetObjectData(GameObject detectedObject, int tagIndex, float[] dataBuffer) { dataBuffer[tagIndex] 1; }即每个格子用一个长度等于可检测 Tag 数的向量表示命中的 Tag 位置为 1其余为 0。由于数据天然归一化OneHot 传感器可直接使用 PNG 压缩。CountingGridSensor格子内物体计数CountingGridSensor是使用格子内所有 Collider的示例统计每种可检测 Tag 在格子中检测到的对象数量。完整实现见 CountingGridSensor.cs注意该文件带有MovedFrom(Unity.MLAgents.Extensions.Sensors)特性表明其命名空间历史上从 Extensions 迁移而来。其行为为GetCellObservationSize()detectableTags.LengthIsDataNormalized()falseGetProcessCollidersMethod()ProcessCollidersMethod.ProcessAllCollidersGetObjectData()protected override void GetObjectData(GameObject detectedObject, int tagIndex, float[] dataBuffer) { dataBuffer[tagIndex] 1; }注意这里用的是累加而非覆盖——与ProcessAllColliders累积语义严格对应。因为计数无上界、不满足 0~1 归一化约束该传感器不能使用数据压缩其构造函数中强制CompressionType SensorCompressionType.None见 CountingGridSensor.cs即便在组件上设置了 PNG 压缩也会被覆盖为 None。测试与验证仓库在 com.unity.ml-agents.tests 下提供了网格传感器的运行时测试其中 GridSensorTests.cs 覆盖了GridSensorBase、OneHotGridSensor、CountingGridSensor的观测规格、数据写入与压缩行为。编写自定义传感器时可以参考这些测试的断言方式验证GetCellObservationSize()与GetObjectData()写入的数据量是否匹配、归一化声明与压缩设置是否冲突。完整自定义示例流程综合以上内容一个自定义网格传感器的标准流程为派生GridSensorBase重写GetCellObservationSize()定义每格维度重写GetObjectData()从detectedObject提取自定义属性如速度、朝向、生命值写入dataBuffer重写IsDataNormalized()如实声明数据是否归一化若希望压缩训练则先归一化再返回true需要统计型观测时重写GetProcessCollidersMethod()返回ProcessAllColliders并在GetObjectData中做累加式写入派生GridSensorComponent重写GetGridSensors()返回上述传感器实例可多个在 Unity 中为 Agent 挂载自定义组件配置Detectable Tags、Collider Mask、网格尺寸与压缩类型运行时可开启Show Gizmos借助调试颜色检查各格子的检测结果是否符合预期。通过这一套扩展机制你可以把网格传感器从Tag 的 one-hot 地图升级为携带任意物理属性、游戏状态的自定义观测源在保持网格观测无盲区、抗遮挡优势的同时让强化学习智能体获得更丰富的空间特征输入。【免费下载链接】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),仅供参考

相关新闻

Spring Boot集成RocketMQ的5大生产级陷阱与解决方案

Spring Boot集成RocketMQ的5大生产级陷阱与解决方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 18:52:59 阅读更多 →
Pydantic AI 流式处理实战:run_stream 实时响应与结果获取快速上手

Pydantic AI 流式处理实战:run_stream 实时响应与结果获取快速上手

Pydantic AI 流式处理实战:run_stream 实时响应与结果获取快速上手 【免费下载链接】pydantic-ai How Python does AI. Agents, realtime voice, image generation, embeddings. Every model, every interface, typed end to end. 项目地址: https://gitcode.com/…

2026/9/20 18:52:59 阅读更多 →
Rust学习指南:从所有权、生命周期到项目实战

Rust学习指南:从所有权、生命周期到项目实战

简介:面向Rust初学者与系统编程爱好者的综合学习包,内含学习笔记和个人经典项目案例,旨在帮助读者跨越Rust较陡的学习曲线,深入理解所有权、借用检查器、模式匹配等核心概念,并通过实际项目经历从设计、编码到测试、部…

2026/9/20 18:52:59 阅读更多 →

最新新闻

OpenClaw 读 Moltbook 的 Skill.md,Base URL 填 TaoToken 的 /api

OpenClaw 读 Moltbook 的 Skill.md,Base URL 填 TaoToken 的 /api

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 20:54:17 阅读更多 →
通信原理实验:基于SystemView的2ASK系统仿真与误码率分析

通信原理实验:基于SystemView的2ASK系统仿真与误码率分析

简介:北京邮电大学通信原理软件实验报告基于SystemView平台,覆盖AM、SSB、FM调制解调、数字基带传输、OOK、2FSK、2PSK、16QAM及抽样定理等九个核心实验。每个实验均包含实验目的、原理推导、SystemView连接图、参数设置、波形截图与讨论分析&#xff0c…

2026/9/20 20:54:17 阅读更多 →
NemoClaw PR Comparator 的 Tier 0 资格门禁:六道合入门禁的判定机制、脚本实现与故障分类

NemoClaw PR Comparator 的 Tier 0 资格门禁:六道合入门禁的判定机制、脚本实现与故障分类

【免费下载链接】NemoClaw Run agents like Hermes, LangChain Deep Agents, and OpenClaw more securely inside NVIDIA OpenShell with managed inference 项目地址: https://gitcode.com/gh_mirrors/ne/NemoClaw 点击查看 免费下载 NemoClaw 维护者技能 nemocla…

2026/9/20 20:54:17 阅读更多 →
复合窗幕系统能耗模拟:DesignBuilder参数化建模与验证

复合窗幕系统能耗模拟:DesignBuilder参数化建模与验证

简介:复合窗幕系统建筑能耗模拟是建筑节能设计的重要研究课题,这份docx文档系统梳理了DesignBuilder软件下的参数化建模与验证全流程,适合建筑能耗模拟研究人员、绿色建筑设计师及相关专业学生参考。内容涵盖研究背景与意义、国内外研究现状、…

2026/9/20 20:54:17 阅读更多 →
Claude Code 跨会话保留精读,模型通道改走 TaoToken 行不行?

Claude Code 跨会话保留精读,模型通道改走 TaoToken 行不行?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 20:54:17 阅读更多 →
Celery 安全加固实战:broker 防护、auth 消息签名与入侵检测指南

Celery 安全加固实战:broker 防护、auth 消息签名与入侵检测指南

Celery 安全加固实战:broker 防护、auth 消息签名与入侵检测指南 【免费下载链接】celery Distributed Task Queue (development branch) 项目地址: https://gitcode.com/gh_mirrors/ce/celery 本文是 Celery 分布式任务队列安全配置的实操指南,核…

2026/9/20 20:53:16 阅读更多 →

日新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →