Skip to content

Optimisation - Removed a lot of garbage allocation #1804

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

Merged
merged 2 commits into from
Mar 19, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Garbage collection optimisations:
- Changed a few IEnumerable instances to IReadOnlyList. This avoids some unnecessary GC allocs that cast the Lists to IEnumerables.
- Moved cdf allocation outside of the loop to avoid unnecessary GC allocation.
- Changed GeneratorImpl to use plain float and int arrays instead of Array during generation. This avoids SetValue performing boxing on the arrays, which eliminates an awful lot of GC allocs.
  • Loading branch information
tkggwatson committed Mar 8, 2019
commit 3c3751934081d14ca8cfccc1c590c611d18ce97c
20 changes: 12 additions & 8 deletions UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/GeneratorImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,15 @@ public void Generate(Tensor tensor, int batchSize, Dictionary<Agent, AgentInfo>
{
tensor.Shape[0] = batchSize;
var vecObsSizeT = tensor.Shape[tensor.Shape.Length - 1];
tensor.Data = new float[batchSize, vecObsSizeT];
var floatArray = new float[batchSize, vecObsSizeT];
tensor.Data = floatArray;
var agentIndex = 0;
foreach (var agent in agentInfo.Keys)
{
var vectorObs = agentInfo[agent].stackedVectorObservation;
for (var j = 0; j < vecObsSizeT; j++)
{
tensor.Data.SetValue(vectorObs[j], new int[2] {agentIndex, j});
floatArray[agentIndex, j] = vectorObs[j];
}
agentIndex++;
}
Expand All @@ -92,7 +93,8 @@ public void Generate(Tensor tensor, int batchSize, Dictionary<Agent, AgentInfo>
{
tensor.Shape[0] = batchSize;
var memorySize = tensor.Shape[tensor.Shape.Length - 1];
tensor.Data = new float[batchSize, memorySize];
var floatArray = new float[batchSize, memorySize];
tensor.Data = floatArray;
var agentIndex = 0;
foreach (var agent in agentInfo.Keys)
{
Expand All @@ -108,7 +110,7 @@ public void Generate(Tensor tensor, int batchSize, Dictionary<Agent, AgentInfo>
{
break;
}
tensor.Data.SetValue(memory[j], new int[2] {agentIndex, j});
floatArray[agentIndex, j] = memory[j];
}
agentIndex++;
}
Expand Down Expand Up @@ -170,14 +172,15 @@ public void Generate(Tensor tensor, int batchSize, Dictionary<Agent, AgentInfo>
{
tensor.Shape[0] = batchSize;
var actionSize = tensor.Shape[tensor.Shape.Length - 1];
tensor.Data = new int[batchSize, actionSize];
var intArray = new int[batchSize, actionSize];
tensor.Data = intArray;
var agentIndex = 0;
foreach (var agent in agentInfo.Keys)
{
var pastAction = agentInfo[agent].storedVectorActions;
for (var j = 0; j < actionSize; j++)
{
tensor.Data.SetValue((int) pastAction[j], new int[2] {agentIndex, j});
intArray[agentIndex, j] = (int) pastAction[j];
}

agentIndex++;
Expand All @@ -197,15 +200,16 @@ public void Generate(Tensor tensor, int batchSize, Dictionary<Agent, AgentInfo>
{
tensor.Shape[0] = batchSize;
var maskSize = tensor.Shape[tensor.Shape.Length - 1];
tensor.Data = new float[batchSize, maskSize];
var floatArray = new float[batchSize, maskSize];
tensor.Data = floatArray;
var agentIndex = 0;
foreach (var agent in agentInfo.Keys)
{
var maskList = agentInfo[agent].actionMasks;
for (var j = 0; j < maskSize; j++)
{
var isUnmasked = (maskList != null && maskList[j]) ? 0.0f : 1.0f;
tensor.Data.SetValue(isUnmasked, new int[2] {agentIndex, j});
floatArray[agentIndex, j] = isUnmasked;
}
agentIndex++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ private ModelParamLoader(TFSharpInferenceEngine engine, BrainParameters brainPar
/// Generates the Tensor inputs that are expected to be present in the Model.
/// </summary>
/// <returns>Tensor IEnumerable with the expected Tensor inputs</returns>
public IEnumerable<Tensor> GetInputTensors()
public IReadOnlyList<Tensor> GetInputTensors()
{
return _engine?.InputFeatures();
}
Expand All @@ -58,7 +58,7 @@ public IEnumerable<Tensor> GetInputTensors()
/// Generates the Tensor outputs that are expected to be present in the Model.
/// </summary>
/// <returns>Tensor IEnumerable with the expected Tensor outputs</returns>
public IEnumerable<Tensor> GetOutputTensors()
public IReadOnlyList<Tensor> GetOutputTensors()
{
var tensorList = new List<Tensor>();
if (_brainParameters.vectorActionSpaceType == SpaceType.continuous)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ private Tensor GetOpMetadata(TFOperation op)
return t;
}

public IEnumerable<Tensor> InputFeatures()
public IReadOnlyList<Tensor> InputFeatures()
{
List<Tensor> inputs = new List<Tensor>();
foreach (var op in m_graph.GetEnumerator())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public void Eval(Tensor src, Tensor dst)
throw new ArgumentException("Batch size for input and output data is different!");
}

float[] cdf = new float[input_data.GetLength(1)];

for (int batch = 0; batch < input_data.GetLength(0); ++batch)
{
// Find the class maximum
Expand All @@ -71,7 +73,6 @@ public void Eval(Tensor src, Tensor dst)

// Sum the log probabilities and compute CDF
float sumProb = 0.0f;
float[] cdf = new float[input_data.GetLength(1)];
for (int cls = 0; cls < input_data.GetLength(1); ++cls)
{
sumProb += Mathf.Exp(input_data[batch, cls] - maxProb);
Expand Down
4 changes: 2 additions & 2 deletions UnitySDK/Assets/ML-Agents/Scripts/LearningBrain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ public class LearningBrain : Brain
"(This field is not applicable for training).")]
public InferenceDevice inferenceDevice = InferenceDevice.CPU;

private IEnumerable<Tensor> _inferenceInputs;
private IEnumerable<Tensor> _inferenceOutputs;
private IReadOnlyList<Tensor> _inferenceInputs;
private IReadOnlyList<Tensor> _inferenceOutputs;

[NonSerialized]
private bool _isControlled;
Expand Down