-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Barracuda inference for hybrid actions #4611
Barracuda inference for hybrid actions #4611
Conversation
{ | ||
actionValue = new float[actionSize]; | ||
lastActions[agentId] = actionValue; | ||
actionBuffer = new ActionBuffers(new float[m_ActionSpec.NumContinuousActions], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I don't like about this is ContinuousActionOutputApplier has to initialize new ActionBuffers based on discrete actions branchSizes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe make another ActionBuffers constructor (or static method) that takes an ActionSpec?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I can do that.
But even with that I'm still not able to initialize continuous/discrete field separately and still need both sizes to initialize the new ActionBuffers here, due to ActionBuffers's read-only properties. I wonder if it's reasonable to change that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think initializing them separately is a requirement; you have all the information you need in the ActionSpec. Encapsulating it in an ActionBuffers static method seems fine to me.
You could also move the logic to a ModelRunner method, and call it in ModelRunner.DecideBatch(), just before the call to m_TensorApplier.ApplyTensors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is also the case that the DiscreteActionOutputApplier initializes ActionBuffers. Maybe we could have a InitializeBuffers method that gets called by both ContinuousActionOutputApplier and DiscreteActionOutputApplier if the ActionBuffers does not yet exist,.
com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs
Outdated
Show resolved
Hide resolved
com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs
Outdated
Show resolved
Hide resolved
com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs
Outdated
Show resolved
Hide resolved
com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs
Outdated
Show resolved
Hide resolved
{ | ||
actionValue = new float[actionSize]; | ||
lastActions[agentId] = actionValue; | ||
actionBuffer = new ActionBuffers(new float[m_ActionSpec.NumContinuousActions], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is also the case that the DiscreteActionOutputApplier initializes ActionBuffers. Maybe we could have a InitializeBuffers method that gets called by both ContinuousActionOutputApplier and DiscreteActionOutputApplier if the ActionBuffers does not yet exist,.
@@ -16,7 +16,7 @@ internal class BarracudaModelParamLoader | |||
{ | |||
enum ModelActionType | |||
{ | |||
Unknown, | |||
Hybrid, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should still leave Unknown to be 0, and make Hybrid the third option
names.Add(TensorNames.ActionOutput); | ||
if (!model.outputs.Contains(TensorNames.ContinuousActionOutput) && !model.outputs.Contains(TensorNames.DiscreteActionOutput)) | ||
{ | ||
names.Add(TensorNames.ActionOutputDeprecated); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the change, I think this is a very complex part of the codebase that we do not modify often, so do not hesitate to add some code comments.
@@ -164,9 +178,6 @@ public static string[] GetOutputNames(Model model) | |||
|
|||
var modelApiVersion = (int)model.GetTensorByName(TensorNames.VersionNumber)[0]; | |||
var memorySize = (int)model.GetTensorByName(TensorNames.MemorySize)[0]; | |||
var isContinuousInt = (int)model.GetTensorByName(TensorNames.IsContinuousControl)[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are modifying the expectation on the constants and outputs of the model. I think you should summarize in the PR description the overall changes made and how older models will work with the new code (and vice versa)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated in the description
} | ||
else | ||
{ | ||
var isContinuous = model.GetTensorByName(TensorNames.IsContinuousControl)[0] > 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is IsContinuousControl
deprecated? If it is the case, rename to IsContinuousControlDeprecated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, changed it as suggested
modelActionType = GetActionType(modelContinuousActionSize > 0, modelDiscreteActionSize > 0); | ||
} | ||
else | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{ | |
{ | |
// For backwards compatibility |
com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs
Outdated
Show resolved
Hide resolved
@@ -23,12 +23,16 @@ internal static class TensorNames | |||
public const string MemorySize = "memory_size"; | |||
public const string VersionNumber = "version_number"; | |||
public const string IsContinuousControl = "is_continuous_control"; | |||
public const string ActionOutputShape = "action_output_shape"; | |||
public const string ActionOutput = "action"; | |||
public const string ActionOutputShapeDeprecated = "action_output_shape"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separate the Deprecated section from the rest with a blank line for clarity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move ActionOutputShapeDeprecated at the bottom with ActionOutputDeprecated
@@ -157,7 +157,7 @@ public void TestGetOutputTensors1() | |||
{ | |||
var model = ModelLoader.Load(continuous2vis8vec2actionModel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you made a lot of improvements to the model loading logic. I think you should add more tests to check your logic (loading an old model and a new model and see if they behave properly)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More tests with new models added
if (actionSpec.NumContinuousActions > 0) | ||
{ | ||
m_Dict[TensorNames.ActionOutput] = new ContinuousActionOutputApplier(); | ||
var tensorName = useDeprecated ? TensorNames.ActionOutputDeprecated : TensorNames.ContinuousActionOutput; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
model.ContinuousOutputName()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it's possible that the model is null
here
actionSpec.CheckNotHybrid(); | ||
|
||
bool useDeprecated = false; | ||
if (barracudaModel != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we just early out if the model is null? Might make some of the code cleaner. (same for TensorGenerator below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -72,12 +65,9 @@ public static int GetNumVisualInputs(Model model) | |||
|
|||
foreach (var input in model.inputs) | |||
{ | |||
if (input.shape.Length == 4) | |||
if (input.name.StartsWith(TensorNames.VisualObservationPlaceholderPrefix)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't have to be in this PR, but you might want to consider moving GetNumVisualInputs(), GetOutputNames(), etc to the extension methods too.
@@ -152,21 +149,13 @@ public static string[] GetOutputNames(Model model) | |||
return failedModelChecks; | |||
} | |||
|
|||
foreach (var constantName in TensorNames.RequiredConstants) | |||
var modelApiVersionTensor = model.GetTensorByName(TensorNames.VersionNumber); | |||
if (modelApiVersionTensor == null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, doesn't need to be in this PR, but I feel like we lost some of the checks that the tensors we need are in the Model. It's never an issue for model files that we create, but a frequent source of forum/github posts would be people trying to train their own models, then add them for inference and get null reference errors because the assumed the tensors were there without checking.
I need to look a little more closely, but I think things like HasContinuousOutputs() would throw if not of the expected tensors are there.
We could add something like
bool CheckExpectedTensors(List<string> errorMessagesOut) {}
to the extension methods, call it once here, and then assume everything is present after that.
We should also have a test that CheckModel() with a basically empty model doesn't throw and returns some error strings.
Feel free to just log a jira as a reminder to come back to this, since I think it's a small regression in usability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I took care of that by the order of the checks, but I agree we should check it explicitly for safety.
Made a JIRA ticket.
…echnologies/ml-agents into develop-hybrid-inference
Some tests are failing because since this PR is not self-contained, and it needs some changes on python. Leave those to python PR will check when merge. |
* Add hybrid action capability flag (#4576) * Change BrainParametersProto to support ActionSpec (#4579) * Assign new BrainParametersProto fields based on capabilities (#4581) * ActionBuffer with hybrid actions for RemotePolicy (#4592) * Barracuda inference for hybrid actions (#4611) * Refactor BarracudaModel loader checks (#4629) * Export separate nodes for continuous/discrete actions (#4655) * Separate continuous/discrete actions in AgentActionProto (#4698) * Force different nodes for new and deprecated action output (#4705)
Proposed change(s)
Barracuda inference for hybrid actions.
Major changes:
1. The input argument
lastActions
to TensorApplier.IApplier is now anActionBuffers
instead of float[].2. Changes to model output nodes
To support hybrid actions, deprecated old action output nodes which only work for single-type actions and added new output nodes:
action
in favor ofcontinuous_actions
anddiscrete_actions
action_output_shape
in favor ofcontinuous_action_output_shape
anddiscrete_action_output_shape
is_continuous_control
is also deprecatedNow the expectation of the model outputs is either set of:
action
,action_output_shape
,is_continuous_control
continuous_actions
,discrete_actions
,continuous_action_output_shape
,discrete_action_output_shape
Running inference will use the new nodes by default, and fall back to old ones if they doesn't exist.
Deprecated nodes are still supported and the code is able to run old models.
Version compatibility:
old model, old C# - current behavior, use old output nodes
new model, old C# - use old output nodes just like current behavior, new nodes are ignored
old model, new C# - detect that new output nodes do not exist in the model and fall back to old ones
new model, new C# - use new output nodes
Useful links (Github issues, JIRA tickets, ML-Agents forum threads etc.)
Types of change(s)
Checklist
Other comments