Skip to content

[MLA-1743] Backport inference GC Optimizations #4916

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 4 commits into from
Feb 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 2 additions & 1 deletion com.unity.ml-agents/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ Please refer to "Information that is passively collected by Unity" in the
#### com.unity.ml-agents (C#)
- Removed unnecessary memory allocations in `SensorShapeValidator.ValidateSensors()` (#4915)
- Removed unnecessary memory allocations in `SideChannelManager.GetSideChannelMessage()` (#4915)

- Removed several memory allocations that happened during inference. On a test scene, this
reduced the amount of memory allocated by approximately 25%. (#4916)

## [1.0.6] - 2020-11-13
### Minor Changes
Expand Down
21 changes: 13 additions & 8 deletions com.unity.ml-agents/Runtime/Inference/ApplierImpl.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.MLAgents.Inference.Utils;
Expand All @@ -13,12 +14,13 @@ namespace Unity.MLAgents.Inference
/// </summary>
internal class ContinuousActionOutputApplier : TensorApplier.IApplier
{
public void Apply(TensorProxy tensorProxy, IEnumerable<int> actionIds, Dictionary<int, float[]> lastActions)
public void Apply(TensorProxy tensorProxy, IList<int> actionIds, Dictionary<int, float[]> lastActions)
{
var actionSize = tensorProxy.shape[tensorProxy.shape.Length - 1];
var agentIndex = 0;
foreach (int agentId in actionIds)
for (var i = 0; i < actionIds.Count; i++)
{
var agentId = actionIds[i];
if (lastActions.ContainsKey(agentId))
{
var actionValue = lastActions[agentId];
Expand Down Expand Up @@ -54,7 +56,7 @@ public DiscreteActionOutputApplier(int[] actionSize, int seed, ITensorAllocator
m_Allocator = allocator;
}

public void Apply(TensorProxy tensorProxy, IEnumerable<int> actionIds, Dictionary<int, float[]> lastActions)
public void Apply(TensorProxy tensorProxy, IList<int> actionIds, Dictionary<int, float[]> lastActions)
{
//var tensorDataProbabilities = tensorProxy.Data as float[,];
var idActionPairList = actionIds as List<int> ?? actionIds.ToList();
Expand Down Expand Up @@ -99,8 +101,9 @@ public void Apply(TensorProxy tensorProxy, IEnumerable<int> actionIds, Dictionar
outputTensor.data.Dispose();
}
var agentIndex = 0;
foreach (int agentId in actionIds)
for (var i = 0; i < actionIds.Count; i++)
{
var agentId = actionIds[i];
if (lastActions.ContainsKey(agentId))
{
var actionVal = lastActions[agentId];
Expand Down Expand Up @@ -197,12 +200,13 @@ public MemoryOutputApplier(
m_Memories = memories;
}

public void Apply(TensorProxy tensorProxy, IEnumerable<int> actionIds, Dictionary<int, float[]> lastActions)
public void Apply(TensorProxy tensorProxy, IList<int> actionIds, Dictionary<int, float[]> lastActions)
{
var agentIndex = 0;
var memorySize = (int)tensorProxy.shape[tensorProxy.shape.Length - 1];
foreach (int agentId in actionIds)
for (var i = 0; i < actionIds.Count; i++)
{
var agentId = actionIds[i];
List<float> memory;
if (!m_Memories.TryGetValue(agentId, out memory)
|| memory.Count < memorySize)
Expand Down Expand Up @@ -234,13 +238,14 @@ public BarracudaMemoryOutputApplier(
m_Memories = memories;
}

public void Apply(TensorProxy tensorProxy, IEnumerable<int> actionIds, Dictionary<int, float[]> lastActions)
public void Apply(TensorProxy tensorProxy, IList<int> actionIds, Dictionary<int, float[]> lastActions)
{
var agentIndex = 0;
var memorySize = (int)tensorProxy.shape[tensorProxy.shape.Length - 1];

foreach (int agentId in actionIds)
for (var i = 0; i < actionIds.Count; i++)
{
var agentId = actionIds[i];
List<float> memory;
if (!m_Memories.TryGetValue(agentId, out memory)
|| memory.Count < memorySize * m_MemoriesCount)
Expand Down
46 changes: 29 additions & 17 deletions com.unity.ml-agents/Runtime/Inference/GeneratorImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public BiDimensionalOutputGenerator(ITensorAllocator allocator)
m_Allocator = allocator;
}

public void Generate(TensorProxy tensorProxy, int batchSize, IEnumerable<AgentInfoSensorsPair> infos)
public void Generate(TensorProxy tensorProxy, int batchSize, IList<AgentInfoSensorsPair> infos)
{
TensorUtils.ResizeTensor(tensorProxy, batchSize, m_Allocator);
}
Expand All @@ -40,7 +40,7 @@ public BatchSizeGenerator(ITensorAllocator allocator)
m_Allocator = allocator;
}

public void Generate(TensorProxy tensorProxy, int batchSize, IEnumerable<AgentInfoSensorsPair> infos)
public void Generate(TensorProxy tensorProxy, int batchSize, IList<AgentInfoSensorsPair> infos)
{
tensorProxy.data?.Dispose();
tensorProxy.data = m_Allocator.Alloc(new TensorShape(1, 1));
Expand All @@ -63,7 +63,7 @@ public SequenceLengthGenerator(ITensorAllocator allocator)
m_Allocator = allocator;
}

public void Generate(TensorProxy tensorProxy, int batchSize, IEnumerable<AgentInfoSensorsPair> infos)
public void Generate(TensorProxy tensorProxy, int batchSize, IList<AgentInfoSensorsPair> infos)
{
tensorProxy.shape = new long[0];
tensorProxy.data?.Dispose();
Expand Down Expand Up @@ -94,13 +94,14 @@ public void AddSensorIndex(int sensorIndex)
m_SensorIndices.Add(sensorIndex);
}

public void Generate(TensorProxy tensorProxy, int batchSize, IEnumerable<AgentInfoSensorsPair> infos)
public void Generate(TensorProxy tensorProxy, int batchSize, IList<AgentInfoSensorsPair> infos)
{
TensorUtils.ResizeTensor(tensorProxy, batchSize, m_Allocator);
var vecObsSizeT = tensorProxy.shape[tensorProxy.shape.Length - 1];
var agentIndex = 0;
foreach (var info in infos)
for (var infoIndex = 0; infoIndex < infos.Count; infoIndex++)
{
var info = infos[infoIndex];
if (info.agentInfo.done)
{
// If the agent is done, we might have a stale reference to the sensors
Expand All @@ -112,8 +113,10 @@ public void Generate(TensorProxy tensorProxy, int batchSize, IEnumerable<AgentIn
{
var tensorOffset = 0;
// Write each sensor consecutively to the tensor
foreach (var sensorIndex in m_SensorIndices)
// TOOD
for (var sensorIndexIndex = 0; sensorIndexIndex < m_SensorIndices.Count; sensorIndexIndex++)
{
var sensorIndex = m_SensorIndices[sensorIndexIndex];
var sensor = info.sensors[sensorIndex];
m_ObservationWriter.SetTarget(tensorProxy, agentIndex, tensorOffset);
var numWritten = sensor.Write(m_ObservationWriter);
Expand Down Expand Up @@ -151,14 +154,15 @@ public RecurrentInputGenerator(
}

public void Generate(
TensorProxy tensorProxy, int batchSize, IEnumerable<AgentInfoSensorsPair> infos)
TensorProxy tensorProxy, int batchSize, IList<AgentInfoSensorsPair> infos)
{
TensorUtils.ResizeTensor(tensorProxy, batchSize, m_Allocator);

var memorySize = tensorProxy.shape[tensorProxy.shape.Length - 1];
var agentIndex = 0;
foreach (var infoSensorPair in infos)
for (var infoIndex = 0; infoIndex < infos.Count; infoIndex++)
{
var infoSensorPair = infos[infoIndex];
var info = infoSensorPair.agentInfo;
List<float> memory;

Expand Down Expand Up @@ -206,14 +210,16 @@ public BarracudaRecurrentInputGenerator(
m_Memories = memories;
}

public void Generate(TensorProxy tensorProxy, int batchSize, IEnumerable<AgentInfoSensorsPair> infos)
public void Generate(TensorProxy tensorProxy, int batchSize, IList<AgentInfoSensorsPair> infos)
{
TensorUtils.ResizeTensor(tensorProxy, batchSize, m_Allocator);

var memorySize = (int)tensorProxy.shape[tensorProxy.shape.Length - 1];
var agentIndex = 0;
foreach (var infoSensorPair in infos)
for (var infoIndex = 0; infoIndex < infos.Count; infoIndex++)
{
var infoSensorPair = infos[infoIndex];

var info = infoSensorPair.agentInfo;
var offset = memorySize * m_MemoryIndex;
List<float> memory;
Expand Down Expand Up @@ -259,14 +265,16 @@ public PreviousActionInputGenerator(ITensorAllocator allocator)
m_Allocator = allocator;
}

public void Generate(TensorProxy tensorProxy, int batchSize, IEnumerable<AgentInfoSensorsPair> infos)
public void Generate(TensorProxy tensorProxy, int batchSize, IList<AgentInfoSensorsPair> infos)
{
TensorUtils.ResizeTensor(tensorProxy, batchSize, m_Allocator);

var actionSize = tensorProxy.shape[tensorProxy.shape.Length - 1];
var agentIndex = 0;
foreach (var infoSensorPair in infos)
for (var infoIndex = 0; infoIndex < infos.Count; infoIndex++)
{
var infoSensorPair = infos[infoIndex];

var info = infoSensorPair.agentInfo;
var pastAction = info.storedVectorActions;
if (pastAction != null)
Expand Down Expand Up @@ -297,14 +305,16 @@ public ActionMaskInputGenerator(ITensorAllocator allocator)
m_Allocator = allocator;
}

public void Generate(TensorProxy tensorProxy, int batchSize, IEnumerable<AgentInfoSensorsPair> infos)
public void Generate(TensorProxy tensorProxy, int batchSize, IList<AgentInfoSensorsPair> infos)
{
TensorUtils.ResizeTensor(tensorProxy, batchSize, m_Allocator);

var maskSize = tensorProxy.shape[tensorProxy.shape.Length - 1];
var agentIndex = 0;
foreach (var infoSensorPair in infos)
for (var infoIndex = 0; infoIndex < infos.Count; infoIndex++)
{
var infoSensorPair = infos[infoIndex];

var agentInfo = infoSensorPair.agentInfo;
var maskList = agentInfo.discreteActionMasks;
for (var j = 0; j < maskSize; j++)
Expand Down Expand Up @@ -333,7 +343,7 @@ public RandomNormalInputGenerator(int seed, ITensorAllocator allocator)
m_Allocator = allocator;
}

public void Generate(TensorProxy tensorProxy, int batchSize, IEnumerable<AgentInfoSensorsPair> infos)
public void Generate(TensorProxy tensorProxy, int batchSize, IList<AgentInfoSensorsPair> infos)
{
TensorUtils.ResizeTensor(tensorProxy, batchSize, m_Allocator);
TensorUtils.FillTensorWithRandomNormal(tensorProxy, m_RandomNormal);
Expand All @@ -359,12 +369,14 @@ public VisualObservationInputGenerator(
m_Allocator = allocator;
}

public void Generate(TensorProxy tensorProxy, int batchSize, IEnumerable<AgentInfoSensorsPair> infos)
public void Generate(TensorProxy tensorProxy, int batchSize, IList<AgentInfoSensorsPair> infos)
{
TensorUtils.ResizeTensor(tensorProxy, batchSize, m_Allocator);
var agentIndex = 0;
foreach (var infoSensorPair in infos)
for (var infoIndex = 0; infoIndex < infos.Count; infoIndex++)
{
var infoSensorPair = infos[infoIndex];

var sensor = infoSensorPair.sensors[m_SensorIndex];
if (infoSensorPair.agentInfo.done)
{
Expand Down
30 changes: 15 additions & 15 deletions com.unity.ml-agents/Runtime/Inference/ModelRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ internal class ModelRunner
bool m_Verbose = false;
string[] m_OutputNames;
IReadOnlyList<TensorProxy> m_InferenceInputs;
IReadOnlyList<TensorProxy> m_InferenceOutputs;
List<TensorProxy> m_InferenceOutputs;
Dictionary<string, Tensor> m_InputsByName;
Dictionary<int, List<float>> m_Memories = new Dictionary<int, List<float>>();

SensorShapeValidator m_SensorShapeValidator = new SensorShapeValidator();
Expand Down Expand Up @@ -84,6 +85,8 @@ public ModelRunner(
seed, m_TensorAllocator, m_Memories, barracudaModel);
m_TensorApplier = new TensorApplier(
brainParameters, seed, m_TensorAllocator, m_Memories, barracudaModel);
m_InputsByName = new Dictionary<string, Tensor>();
m_InferenceOutputs = new List<TensorProxy>();
}

public InferenceDevice InferenceDevice
Expand All @@ -96,15 +99,14 @@ public NNModel Model
get { return m_Model; }
}

static Dictionary<string, Tensor> PrepareBarracudaInputs(IEnumerable<TensorProxy> infInputs)
void PrepareBarracudaInputs(IReadOnlyList<TensorProxy> infInputs)
{
var inputs = new Dictionary<string, Tensor>();
foreach (var inp in infInputs)
m_InputsByName.Clear();
for (var i = 0; i < infInputs.Count; i++)
{
inputs[inp.name] = inp.data;
var inp = infInputs[i];
m_InputsByName[inp.name] = inp.data;
}

return inputs;
}

public void Dispose()
Expand All @@ -114,16 +116,14 @@ public void Dispose()
m_TensorAllocator?.Reset(false);
}

List<TensorProxy> FetchBarracudaOutputs(string[] names)
void FetchBarracudaOutputs(string[] names)
{
var outputs = new List<TensorProxy>();
m_InferenceOutputs.Clear();
foreach (var n in names)
{
var output = m_Engine.PeekOutput(n);
outputs.Add(TensorUtils.TensorProxyFromBarracuda(output, n));
m_InferenceOutputs.Add(TensorUtils.TensorProxyFromBarracuda(output, n));
}

return outputs;
}

public void PutObservations(AgentInfo info, List<ISensor> sensors)
Expand Down Expand Up @@ -176,16 +176,16 @@ public void DecideBatch()
Profiler.EndSample();

Profiler.BeginSample($"MLAgents.{m_Model.name}.PrepareBarracudaInputs");
var inputs = PrepareBarracudaInputs(m_InferenceInputs);
PrepareBarracudaInputs(m_InferenceInputs);
Profiler.EndSample();

// Execute the Model
Profiler.BeginSample($"MLAgents.{m_Model.name}.ExecuteGraph");
m_Engine.Execute(inputs);
m_Engine.Execute(m_InputsByName);
Profiler.EndSample();

Profiler.BeginSample($"MLAgents.{m_Model.name}.FetchBarracudaOutputs");
m_InferenceOutputs = FetchBarracudaOutputs(m_OutputNames);
FetchBarracudaOutputs(m_OutputNames);
Profiler.EndSample();

Profiler.BeginSample($"MLAgents.{m_Model.name}.ApplyTensors");
Expand Down
7 changes: 4 additions & 3 deletions com.unity.ml-agents/Runtime/Inference/TensorApplier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public interface IApplier
/// </param>
/// <param name="actionIds"> List of Agents Ids that will be updated using the tensor's data</param>
/// <param name="lastActions"> Dictionary of AgentId to Actions to be updated</param>
void Apply(TensorProxy tensorProxy, IEnumerable<int> actionIds, Dictionary<int, float[]> lastActions);
void Apply(TensorProxy tensorProxy, IList<int> actionIds, Dictionary<int, float[]> lastActions);
}

readonly Dictionary<string, IApplier> m_Dict = new Dictionary<string, IApplier>();
Expand Down Expand Up @@ -83,10 +83,11 @@ public TensorApplier(
/// <exception cref="UnityAgentsException"> One of the tensor does not have an
/// associated applier.</exception>
public void ApplyTensors(
IEnumerable<TensorProxy> tensors, IEnumerable<int> actionIds, Dictionary<int, float[]> lastActions)
IReadOnlyList<TensorProxy> tensors, IList<int> actionIds, Dictionary<int, float[]> lastActions)
{
foreach (var tensor in tensors)
for (var tensorIndex = 0; tensorIndex < tensors.Count; tensorIndex++)
{
var tensor = tensors[tensorIndex];
if (!m_Dict.ContainsKey(tensor.name))
{
throw new UnityAgentsException(
Expand Down
7 changes: 4 additions & 3 deletions com.unity.ml-agents/Runtime/Inference/TensorGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public interface IGenerator
/// the tensor's data.
/// </param>
void Generate(
TensorProxy tensorProxy, int batchSize, IEnumerable<AgentInfoSensorsPair> infos);
TensorProxy tensorProxy, int batchSize, IList<AgentInfoSensorsPair> infos);
}

readonly Dictionary<string, IGenerator> m_Dict = new Dictionary<string, IGenerator>();
Expand Down Expand Up @@ -129,10 +129,11 @@ public void InitializeObservations(List<ISensor> sensors, ITensorAllocator alloc
/// <exception cref="UnityAgentsException"> One of the tensor does not have an
/// associated generator.</exception>
public void GenerateTensors(
IEnumerable<TensorProxy> tensors, int currentBatchSize, IEnumerable<AgentInfoSensorsPair> infos)
IReadOnlyList<TensorProxy> tensors, int currentBatchSize, IList<AgentInfoSensorsPair> infos)
{
foreach (var tensor in tensors)
for (var tensorIndex = 0; tensorIndex < tensors.Count; tensorIndex++)
{
var tensor = tensors[tensorIndex];
if (!m_Dict.ContainsKey(tensor.name))
{
throw new UnityAgentsException(
Expand Down
Loading