Search Unity

How to set decision-period from the python side when training with env as executable?

Discussion in 'ML-Agents' started by julienroyd, Mar 11, 2021.

  1. julienroyd

    julienroyd

    Joined:
    Feb 7, 2021
    Posts:
    6
    Hi,

    I was wondering how to modify the decision-requester of UnityEnvironment.

    More specifically how to set the `Decision Period` when creating the UnityEnvironment from the python side (this parameter can be found in the Editor under the Decision Requester component of the Agent).

    I know that Engine Parameters can be set using a communication channel between the Python code and environment executable (see related thread). However, I can't find a similar parameter for decision-period, which is a parameter of the Agent and not the Engine.

    Any idea?
     
  2. awjuliani

    awjuliani

    Unity Technologies

    Joined:
    Mar 1, 2017
    Posts:
    69
    Hello,

    Since agents can call RequestDecision on their own, and all agents can do so at completely different code-defined times, there is no global variable corresponding to the decision frequency. If you would like to send custom information which can be used to change the rate at which agents make decisions from python, I would recommend using a custom side channel. https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Custom-SideChannels.md
     
  3. julienroyd

    julienroyd

    Joined:
    Feb 7, 2021
    Posts:
    6
    @awjuliani , thanks a lot for your response!

    So according to the example in the link that you gave me, I adapted a bit the Custom Side Channel to have it only receive messages from python to C# and not the other way around, since this is all I need, and so that it sends a float rather than a string.

    I have added this C# script that defines my FloatChannel to my Unity Project:
    Code (CSharp):
    1. using UnityEngine;
    2. using Unity.MLAgents.SideChannels;
    3. using System;
    4.  
    5. public class FloatChannel : SideChannel
    6. {
    7.     public FloatChannel()
    8.     {
    9.         ChannelId = new Guid("621f0a93-4f87-11ea-a6bf-722f4387d1f7");
    10.     }
    11.  
    12.     protected override void OnMessageReceived(IncomingMessage msg)
    13.     {
    14.         var receivedFloat = msg.ReadFloat32();
    15.         Debug.Log(String.Format("From Python : {0}", receivedFloat));
    16.     }
    17. }
    Then in my Agent's C# script in the same project, I have added these lines:
    Code (CSharp):
    1.     FloatChannel floatChannel;
    2.  
    3.     public void Awake()
    4.     {
    5.         floatChannel = new FloatChannel();
    6.         SideChannelManager.RegisterSideChannel(floatChannel);
    7.     }
    8.     public void OnDestroy()
    9.     {
    10.         if (Academy.IsInitialized){
    11.             SideChannelManager.UnregisterSideChannel(floatChannel);
    12.         }
    13.     }
    And finally on the Python side, I have defined the following class, passed it in the side_channels argument of the UnityEnvironment and I simply call floatChannel.send_float(data=10.) before initiating training.
    Code (python):
    1. from mlagents_envs.side_channel.side_channel import (
    2.     SideChannel,
    3.     OutgoingMessage,
    4. )
    5. import uuid
    6.  
    7.  
    8. class FloatChannel(SideChannel):
    9.  
    10.     def __init__(self) -> None:
    11.         super().__init__(uuid.UUID("621f0a93-4f87-11ea-a6bf-722f4387d1f7"))
    12.  
    13.     def send_float(self, data: float) -> None:
    14.         msg = OutgoingMessage()
    15.         msg.write_float32(data)
    16.         super().queue_message_to_send(msg)
    17.  
    So it seems like I am almost there, however I don't know how to store the received float in the C# side and overwrite the DecisionRequester's decision_period?

    Any help would be appreciated, thanks! :)
     
  4. awjuliani

    awjuliani

    Unity Technologies

    Joined:
    Mar 1, 2017
    Posts:
    69
    You should be able to store the received float information in a public variable in your SideChannel class, and then query it by your agent, if the agent has a reference to it.
     
    julienroyd likes this.
  5. julienroyd

    julienroyd

    Joined:
    Feb 7, 2021
    Posts:
    6
    Yeah, makes sense! And then, I am not sure how to have the DecisionRequester update its decision period. If I want to change the decision period, do I need to call `this.RequestDecision()` myself in the Update() method of my agent at every decision_period frames, or is there an attribute of DecisionRequester that I can overwritte once say in `OnEpisodeBegin()`, i.e. something like `DecisionRequester.decision_period = floatChannel.receivedFloat;`?
     
    Last edited: Mar 12, 2021
  6. awjuliani

    awjuliani

    Unity Technologies

    Joined:
    Mar 1, 2017
    Posts:
    69