You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 23:12:23