Search Unity

OnActionReceived() order of execution with respect to MonoBehaviour

Discussion in 'ML-Agents' started by ShirelJosef, Sep 30, 2020.

  1. ShirelJosef

    ShirelJosef

    Joined:
    Nov 11, 2019
    Posts:
    21
    Hi,
    My agent have a script that manipulate it's movement during FixedUpdate (CatDynamics.cs). I have another script (CatAgent.cs) that inherits from Agent and therefore, have OnActionRecieved(). I want the actions received in CatAgent.cs (by policy or heuristic) that are stored in variables to propagate to CatDynamics.cs by reading these variables in CatDynamics.cs during the FixedUpdate().

    Basically the order I want is:
    OnActionReceived() (update variable in CatAgent.cs ) -> FixedUpdate() in CayDynmics.cs (Read the variables from CatAgent.cs)

    During the same loop,
    Does OnActionReceived() happens before any other MonoBehaviour FixedUpdate calls?

    Thank you
     
  2. henrypeteet

    henrypeteet

    Unity Technologies

    Joined:
    Aug 19, 2020
    Posts:
    37
    Edit (realized my initial answer doesn't actually work): Thanks for the question. When using the DecisionRequester I don't think there is a way to adjust the arbitrary call order that Unity assigns all MonoBehaviors. Ideally you could adjust the script running order but I am not sure if we expose the script you would need to adjust. Let me get back to you. Script execution order is described here https://docs.unity3d.com/Manual/class-MonoManager.html. But I will need to find if you can adjust the timing for our Academy.
     
    Last edited: Oct 2, 2020
  3. mbaske

    mbaske

    Joined:
    Dec 31, 2017
    Posts:
    473
    Have you considered doing managed updates? I usually propagate all agent actions top-down from OnActionReceived. So in your case, CatAgent would have a reference to CatDynamics and you would replace CatDynamics' FixedUpdate method with a custom update method you'd call from OnActionReceived (which itself is invoked on FixedUpdate steps). I find this approach to be pretty solid, since it ensures a clear execution order. Also, you can pass down any action values directly this way and don't need to worry about storing them somewhere.
     
    ShirelJosef and henrypeteet like this.
  4. henrypeteet

    henrypeteet

    Unity Technologies

    Joined:
    Aug 19, 2020
    Posts:
    37
    Follow up: If you want to control the order in which OnActionReceived() is called with respect to a specific FixedUpdate() then the correct way to do that currently is to turn off the Academy's default steps, and manually call EnvironmentStep.

    Code (CSharp):
    1.  
    2. // On Startup
    3. Academy.Instance.AutomaticSteppingEnabled = false
    4. // Whenever you want OnActionReceived() to be called
    5. Academy.Instance.EnvironmentStep()
    However I would recommend against this if you can avoid it. If at all possible I would recommend something more along the lines of what @mbaske is talking about. Ideally your agent's OnActionReceived would just propagate data to other objects which will do whatever they need. Because OnActionReceived from the DecisionRequester is always within the FixedUpdate stage it should work nicely with the normal game loop.
     
  5. ShirelJosef

    ShirelJosef

    Joined:
    Nov 11, 2019
    Posts:
    21
    @henrypeteet thank you for taking the time to answer my question. As you recommended I am trying to avoid "breaking" the flow, as not knowing the internal of the system will sure make me break something there...
    @mbaske , it is a great idea and I will probably use it, although I wished for a solution which doesn't require to change how the basic "cat" works (not using CatDynamics fixedupdate or so...)
     
  6. hatzmeister

    hatzmeister

    Joined:
    Jun 5, 2018
    Posts:
    7
    Hi all

    @henrypeteet @mbaske

    I have an agent that runs actions in external software which return the result of these actions. This is done with callbacks.

    So the logic is as follows:
    Initialiaze()
    {
    // Send values to ext. software for the first time only just so I get a current state of values
    }
    OnEpisodeBegin()
    {
    // Randomize values to be sent to external software
    // Randomize target value
    }
    OnActionReceived()
    {
    //Get the values from the action array, send them over. When the external calculations are done, a callback is triggered and I receive the result and Set the rewards
    }


    Of course I have the CollectObservations() and Heuristic() as well.
    My logic is that I should 1) RequestDesicion() at the end of OnActionReceived or 2) Make AutomaticStepping=false in Intialize() and RequestDesicion(); EnvironmentStep(); at the end of OnActionReceived

    None of the two works. Any Advice?
     
  7. mbaske

    mbaske

    Joined:
    Dec 31, 2017
    Posts:
    473
    This usually works for me. If you put RequestDesicion() in your callback handler and the callback is triggered reliably, that should keep the agent loop running.
     
  8. hatzmeister

    hatzmeister

    Joined:
    Jun 5, 2018
    Posts:
    7
    @mbaske Thank you for replying.
    When I don't use the DesicionRequester and RequestDecisions manually my machine falls in something like an infinite loop and I have to shut down unity.
    Also what a bout the stepping? When I turn it to false in Initialize(), then OnEpisodeBegin() never gets triggered.
    Finally how do you combine the above with EndEpisode()?
    Is there a chance you could share some example, or even some pseudo?
     
  9. mbaske

    mbaske

    Joined:
    Dec 31, 2017
    Posts:
    473
    You can try it with the 3DBall example project. Remove the Decision Requester component. Then add RequestDecision(); to the agent's OnActionReceived and to the OnEpisodeBegin methods. RequestDecision(); should be the last line in both method bodies.
     
  10. hatzmeister

    hatzmeister

    Joined:
    Jun 5, 2018
    Posts:
    7
    @mbaske I was told by a member of Unity Technologies that:
    "RequestDecision should be called outside of Agent methods. For example, you cannot call it inside CollectObservations or OnActionReceive. In the latest release there should be some guardrails to prevent these recursions you mentioned."
     
  11. mbaske

    mbaske

    Joined:
    Dec 31, 2017
    Posts:
    473
    Ah, good to know. Looking at the Agent code (API 1.2.0), calling RequestDecision() sets the m_RequestDecision flag, but doesn't seem to invoke anything right away. At least I didn't encounter any recursions yet, when I requested new decisions from within OnActionReceived.