Unity ML-Agents外部脚本调用Reward函数未生效问题
Unity ML-Agents 手动设置奖励、终止回合不生效问题解决
问题描述
使用Unity ML-Agents开展强化学习测试时,通过外部脚本调用Agent自定义奖励方法,运行时仅打印Hello, Agent日志,奖励设置未生效,训练回合也未正常终止,初步怀疑与override重写方法存在冲突。
问题相关代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using Unity.MLAgents; using Unity.MLAgents.Actuators; using Unity.MLAgents.Sensors; public class MirrorAgent : Agent { Rigidbody rBody; float degree; public void reward() { Debug.Log("Hello, Agent"); SetReward(1.0f); EndEpisode(); } void Start() { rBody = GetComponent<Rigidbody>(); degree = Random.Range(35.0f, 150.0f); } public Transform Target; public override void OnEpisodeBegin() { if(this.transform.localPosition.y < -0.5 || this.transform.localPosition.y > 0.3 || this.transform.localPosition.x > 0.4 || this.transform.localPosition.x < -0.4 ) { this.transform.localRotation = Quaternion.Euler(new Vector3(0.0f, 0.0f, 0.0f)); } } public override void CollectObservations(VectorSensor sensor) { sensor.AddObservation(Target.localPosition); sensor.AddObservation(this.transform.localPosition); sensor.AddObservation(this.transform.rotation.z); sensor.AddObservation(rBody.velocity.x); sensor.AddObservation(rBody.velocity.y); sensor.AddObservation(rBody.transform.rotation.z); } public float forceMultiplier = 5; public override void OnActionReceived(ActionBuffers actionBuffers) { Vector3 controlSignal = Vector3.zero; controlSignal.x = actionBuffers.ContinuousActions[0]; controlSignal.y = actionBuffers.ContinuousActions[1]; rBody.AddForce(controlSignal * forceMultiplier); if (this.transform.localPosition.y < 1 || this.transform.localPosition.y > 4 || this.transform.localPosition.x > 1 || this.transform.localPosition.x < 0 ) { EndEpisode(); } } public override void Heuristic(in ActionBuffers actionsOut) { var continuousActionsOut = actionsOut.ContinuousActions; continuousActionsOut[0] = Input.GetAxis("Horizontal"); continuousActionsOut[1] = Input.GetAxis("Vertical"); } }
排查结果&修复方案
这个问题和override重写方法没有关系,是代码逻辑和API使用的问题,按以下顺序修复即可:
- 修复OnActionReceived中错误的出界判断逻辑
现有判断条件存在逻辑错误:只要Agent的y坐标小于1就会触发EndEpisode,Agent在初始位置、正常移动的绝大多数状态下都会满足该条件,等于几乎每帧都在强制终止回合。手动调用reward()设置的奖励会被紧接着的帧级终止逻辑覆盖,同时因为重置逻辑缺失,视觉上看不出回合变化。
根据实际活动范围修改判断条件,比如活动范围是x∈[-1,1]、y∈[0,4]的话,修改为:if (this.transform.localPosition.y < 0 || this.transform.localPosition.y > 4 || this.transform.localPosition.x < -1 || this.transform.localPosition.x > 1 ) { SetReward(-1f); // 出界给负奖励,避免无奖励终止 EndEpisode(); } - 补全OnEpisodeBegin的重置逻辑
现有OnEpisodeBegin仅在极小范围内重置旋转,没有重置刚体速度、Agent位置、目标位置,EndEpisode触发后场景状态没有明显变化,会误以为回合没有终止。补全逻辑:public override void OnEpisodeBegin() { // 重置刚体运动状态 rBody.velocity = Vector3.zero; rBody.angularVelocity = Vector3.zero; // 出界时重置Agent位置和旋转 if(this.transform.localPosition.y < -0.5 || this.transform.localPosition.y > 4 || this.transform.localPosition.x > 1 || this.transform.localPosition.x < -1 ) { this.transform.localPosition = Vector3.zero; this.transform.localRotation = Quaternion.identity; } // 随机重置目标位置 Target.localPosition = new Vector3(Random.Range(-0.9f, 0.9f), Random.Range(0.5f, 3.5f), 0); } - 确认奖励API使用和引用正确性
SetReward()会直接覆盖当前步骤的奖励值,如果需要累加奖励请改用AddReward()- 外部脚本调用reward()方法时,要确认引用的是场景中处于激活状态、正在参与训练的Agent实例,不要引用项目中的预制体资源,预制体上的组件虽然可以执行Debug.Log,但不会接入实际训练流程
- 确认训练连接状态
检查Agent挂载的Behavior Parameters组件配置是否正确,确认ml-agents训练进程已经正常连接,Agent处于默认训练模式,Heuristic模式下奖励不会被上传到训练进程。 - (可选规范)自定义方法名建议使用C#通用的帕斯卡命名法,将
reward()改名为ApplyGoalReward()这类语义明确的名称,避免和内置API重名产生隐性冲突。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

