浏览代码

Reducing complexity on a number of classes. (#2480)

Only cosmetic and readability improvements. No functional changes were intended.

Utilities.cs
- Fixed comments across file
- Made class static
- Removed unnecessary imports
- Removed unused method arguments
- Renamed variables as appropriate to make usage clearer
- In AddRangeNoAlloc, disabled (by comment) Rider’s suggestion to revert to use of built-in Range field (Fixed)
- In TextureToTensorProxy, swapped order of first two arguments to be more in-line with convention of input, output

UtilitiesTests.cs
- Removed unnecessary imports
- Simplified array creation commands

GeneratorImp.cs
- Rider automatically deleted spaces on empty lines
- Changed call to TextureToTensorProxy to mirror new argument ordering

* Clean-up to UnityAgentsException.cs

- Removed unnecessary imports
- Fixed comment warning
- Fixed method header

* Improvements to Startup.cs

- Created const for SCENE_NAME field
- Fixed strin...
/develop-gpu-test
GitHub 5 年前
当前提交
69613a01
共有 22 个文件被更改,包括 1066 次插入925 次删除
  1. 63
      UnitySDK/Assets/ML-Agents/Editor/Tests/EditModeTestInternalBrainTensorApplier.cs
  2. 111
      UnitySDK/Assets/ML-Agents/Editor/Tests/EditModeTestInternalBrainTensorGenerator.cs
  3. 184
      UnitySDK/Assets/ML-Agents/Editor/Tests/MultinomialTest.cs
  4. 130
      UnitySDK/Assets/ML-Agents/Editor/Tests/RandomNormalTest.cs
  5. 19
      UnitySDK/Assets/ML-Agents/Editor/Tests/UtilitiesTests.cs
  6. 143
      UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/ApplierImpl.cs
  7. 255
      UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/BarracudaModelParamLoader.cs
  8. 144
      UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/GeneratorImpl.cs
  9. 34
      UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/TensorApplier.cs
  10. 66
      UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/TensorGenerator.cs
  11. 228
      UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/TensorProxy.cs
  12. 98
      UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/Utils/Multinomial.cs
  13. 62
      UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/Utils/RandomNormal.cs
  14. 2
      UnitySDK/Assets/ML-Agents/Scripts/LearningBrain.cs
  15. 19
      UnitySDK/Assets/ML-Agents/Scripts/Startup.cs
  16. 19
      UnitySDK/Assets/ML-Agents/Scripts/UnityAgentsException.cs
  17. 109
      UnitySDK/Assets/ML-Agents/Scripts/Utilities.cs
  18. 194
      UnitySDK/Assets/ML-Agents/Editor/Tests/DiscreteActionOutputApplierTest.cs
  19. 11
      UnitySDK/Assets/ML-Agents/Editor/Tests/DiscreteActionOutputApplierTest.cs.meta
  20. 83
      UnitySDK/Assets/ML-Agents/Editor/Tests/TensorUtilsTest.cs
  21. 11
      UnitySDK/Assets/ML-Agents/Editor/Tests/TensorUtilsTest.cs.meta
  22. 6
      UnitySDK/UnitySDK.sln.DotSettings

63
UnitySDK/Assets/ML-Agents/Editor/Tests/EditModeTestInternalBrainTensorApplier.cs


{
public AgentAction GetAction()
{
FieldInfo f = typeof(Agent).GetField(
var f = typeof(Agent).GetField(
private Dictionary<Agent, AgentInfo> GetFakeAgentInfos()
{
var goA = new GameObject("goA");

}
[Test]
public void Contruction()
public void Construction()
{
var bp = new BrainParameters();
var alloc = new TensorCachingAllocator();

{
var inputTensor = new TensorProxy()
{
Shape = new long[] {2, 3},
Data = new Tensor (2, 3, new float[] {1, 2, 3,
4, 5, 6})
shape = new long[] {2, 3},
data = new Tensor (2, 3, new float[] {1, 2, 3, 4, 5, 6})
Assert.NotNull(agent);
Assert.NotNull(agent);
Assert.AreEqual(action.vectorActions[2], 6);
Assert.AreEqual(action.vectorActions[2], 6);
Shape = new long[] {2, 5},
Data = new Tensor (2, 5, new[] {0.5f, 22.5f, 0.1f, 5f, 1f,
4f, 5f, 6f, 7f, 8f})
shape = new long[] {2, 5},
data = new Tensor (
2,
5,
new[] {0.5f, 22.5f, 0.1f, 5f, 1f, 4f, 5f, 6f, 7f, 8f})
var applier = new DiscreteActionOutputApplier(new int[]{2, 3}, 0, alloc);
var applier = new DiscreteActionOutputApplier(new []{2, 3}, 0, alloc);
Assert.NotNull(agent);
Assert.NotNull(agent);
Shape = new long[] {2, 5},
Data = new Tensor (2, 5, new[] {0.5f, 22.5f, 0.1f, 5f, 1f,
4f, 5f, 6f, 7f, 8f})
shape = new long[] {2, 5},
data = new Tensor (
2,
5,
new[] {0.5f, 22.5f, 0.1f, 5f, 1f, 4f, 5f, 6f, 7f, 8f})
Assert.NotNull(agent);
Assert.NotNull(agent);
Shape = new long[] {2, 1},
Data = new Tensor (2, 1, new[]{0.5f, 8f})
shape = new long[] {2, 1},
data = new Tensor (2, 1, new[]{0.5f, 8f})
Assert.NotNull(agent);
Assert.NotNull(agent);
action = agent.GetAction();
Assert.AreEqual(action.value, 8);
}

111
UnitySDK/Assets/ML-Agents/Editor/Tests/EditModeTestInternalBrainTensorGenerator.cs


using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using Barracuda;
using NUnit.Framework;

namespace MLAgents.Tests
{
public class EditModeTestInternalBrainTensorGenerator
public class EditModeTestInternalBrainTensorGenerator
private Dictionary<Agent, AgentInfo> GetFakeAgentInfos()
{
var goA = new GameObject("goA");

stackedVectorObservation = (new float[] {1f, 2f, 3f}).ToList(),
stackedVectorObservation = (new [] {1f, 2f, 3f}).ToList(),
storedVectorActions = new float[] {1, 2},
storedVectorActions = new [] {1f, 2f},
stackedVectorObservation = (new float[] {4f, 5f, 6f}).ToList(),
memories = (new float[] {1f, 1f, 1f}).ToList(),
storedVectorActions = new float[] {3, 4},
actionMasks = new bool[] {true, false, false, false, false},
stackedVectorObservation = (new [] {4f, 5f, 6f}).ToList(),
memories = (new [] {1f, 1f, 1f}).ToList(),
storedVectorActions = new [] {3f, 4f},
actionMasks = new [] {true, false, false, false, false},
};
return new Dictionary<Agent, AgentInfo>(){{agentA, infoA},{agentB, infoB}};

public void Contruction()
public void Construction()
{
var bp = new BrainParameters();
var alloc = new TensorCachingAllocator();

{
var inputTensor = new TensorProxy();
var alloc = new TensorCachingAllocator();
var batchSize = 4;
const int batchSize = 4;
Assert.IsNotNull(inputTensor.Data);
Assert.AreEqual(inputTensor.Data[0], batchSize);
Assert.IsNotNull(inputTensor.data);
Assert.AreEqual(inputTensor.data[0], batchSize);
var batchSize = 4;
const int batchSize = 4;
Assert.IsNotNull(inputTensor.Data);
Assert.AreEqual(inputTensor.Data[0], 1);
Assert.IsNotNull(inputTensor.data);
Assert.AreEqual(inputTensor.data[0], 1);
Shape = new long[] {2, 3}
shape = new long[] {2, 3}
var batchSize = 4;
const int batchSize = 4;
Assert.IsNotNull(inputTensor.Data);
Assert.AreEqual(inputTensor.Data[0, 0], 1);
Assert.AreEqual(inputTensor.Data[0, 2], 3);
Assert.AreEqual(inputTensor.Data[1, 0], 4);
Assert.AreEqual(inputTensor.Data[1, 2], 6);
Assert.IsNotNull(inputTensor.data);
Assert.AreEqual(inputTensor.data[0, 0], 1);
Assert.AreEqual(inputTensor.data[0, 2], 3);
Assert.AreEqual(inputTensor.data[1, 0], 4);
Assert.AreEqual(inputTensor.data[1, 2], 6);
Shape = new long[] {2, 5}
shape = new long[] {2, 5}
var batchSize = 4;
const int batchSize = 4;
Assert.IsNotNull(inputTensor.Data);
Assert.AreEqual(inputTensor.Data[0, 0], 0);
Assert.AreEqual(inputTensor.Data[0, 4], 0);
Assert.AreEqual(inputTensor.Data[1, 0], 1);
Assert.AreEqual(inputTensor.Data[1, 4], 0);
Assert.IsNotNull(inputTensor.data);
Assert.AreEqual(inputTensor.data[0, 0], 0);
Assert.AreEqual(inputTensor.data[0, 4], 0);
Assert.AreEqual(inputTensor.data[1, 0], 1);
Assert.AreEqual(inputTensor.data[1, 4], 0);
Shape = new long[] {2, 2},
ValueType = TensorProxy.TensorType.Integer
shape = new long[] {2, 2},
valueType = TensorProxy.TensorType.Integer
var batchSize = 4;
const int batchSize = 4;
Assert.IsNotNull(inputTensor.Data);
Assert.AreEqual(inputTensor.Data[0, 0], 1);
Assert.AreEqual(inputTensor.Data[0, 1], 2);
Assert.AreEqual(inputTensor.Data[1, 0], 3);
Assert.AreEqual(inputTensor.Data[1, 1], 4);
Assert.IsNotNull(inputTensor.data);
Assert.AreEqual(inputTensor.data[0, 0], 1);
Assert.AreEqual(inputTensor.data[0, 1], 2);
Assert.AreEqual(inputTensor.data[1, 0], 3);
Assert.AreEqual(inputTensor.data[1, 1], 4);
Shape = new long[] {2, 5},
ValueType = TensorProxy.TensorType.FloatingPoint
shape = new long[] {2, 5},
valueType = TensorProxy.TensorType.FloatingPoint
var batchSize = 4;
const int batchSize = 4;
Assert.IsNotNull(inputTensor.Data);
Assert.AreEqual(inputTensor.Data[0, 0], 1);
Assert.AreEqual(inputTensor.Data[0, 4], 1);
Assert.AreEqual(inputTensor.Data[1, 0], 0);
Assert.AreEqual(inputTensor.Data[1, 4], 1);
Assert.IsNotNull(inputTensor.data);
Assert.AreEqual(inputTensor.data[0, 0], 1);
Assert.AreEqual(inputTensor.data[0, 4], 1);
Assert.AreEqual(inputTensor.data[1, 0], 0);
Assert.AreEqual(inputTensor.data[1, 4], 1);
alloc.Dispose();
}
}

184
UnitySDK/Assets/ML-Agents/Editor/Tests/MultinomialTest.cs


using System;
using Barracuda;
using NUnit.Framework;
using UnityEngine;
using MLAgents.InferenceBrain;
using NUnit.Framework;
using MLAgents.InferenceBrain.Utils;
namespace MLAgents.Tests

[Test]
public void TestEvalP()
{
Multinomial m = new Multinomial(2018);
TensorProxy src = new TensorProxy
{
Data = new Tensor(1, 3, new[] {0.1f, 0.2f, 0.7f}),
ValueType = TensorProxy.TensorType.FloatingPoint
};
TensorProxy dst = new TensorProxy
{
Data = new Tensor(1, 3),
ValueType = TensorProxy.TensorType.FloatingPoint
};
m.Eval(src, dst);
float[] reference = {2, 2, 1};
for (var i = 0; i < dst.Data.length; i++)
{
Assert.AreEqual(reference[i], dst.Data[i]);
++i;
}
}
[Test]
public void TestEvalLogits()
public void TestDim1()
Multinomial m = new Multinomial(2018);
TensorProxy src = new TensorProxy
{
Data = new Tensor(1, 3, new[] {Mathf.Log(0.1f) - 50, Mathf.Log(0.2f) - 50, Mathf.Log(0.7f) - 50}),
ValueType = TensorProxy.TensorType.FloatingPoint
};
TensorProxy dst = new TensorProxy
{
Data = new Tensor(1, 3),
ValueType = TensorProxy.TensorType.FloatingPoint
};
m.Eval(src, dst);
var m = new Multinomial(2018);
var cdf = new[] {1f};
float[] reference = {2, 2, 2};
for (var i = 0; i < dst.Data.length; i++)
{
Assert.AreEqual(reference[i], dst.Data[i]);
++i;
}
Assert.AreEqual(0, m.Sample(cdf));
Assert.AreEqual(0, m.Sample(cdf));
Assert.AreEqual(0, m.Sample(cdf));
public void TestEvalBatching()
{
Multinomial m = new Multinomial(2018);
TensorProxy src = new TensorProxy
{
Data = new Tensor(2, 3, new []
{
Mathf.Log(0.1f) - 50, Mathf.Log(0.2f) - 50, Mathf.Log(0.7f) - 50,
Mathf.Log(0.3f) - 25, Mathf.Log(0.4f) - 25, Mathf.Log(0.3f) - 25
}),
ValueType = TensorProxy.TensorType.FloatingPoint
};
TensorProxy dst = new TensorProxy
{
Data = new Tensor(2, 3),
ValueType = TensorProxy.TensorType.FloatingPoint
};
m.Eval(src, dst);
float[] reference = {2, 2, 2, 0, 1, 0};
for (var i = 0; i < dst.Data.length; i++)
{
Assert.AreEqual(reference[i], dst.Data[i]);
++i;
}
}
[Test]
public void TestSrcInt()
public void TestDim1Unscaled()
Multinomial m = new Multinomial(2018);
var m = new Multinomial(2018);
var cdf = new[] {0.1f};
TensorProxy src = new TensorProxy
{
ValueType = TensorProxy.TensorType.Integer
};
Assert.Throws<NotImplementedException>(() => m.Eval(src, null));
Assert.AreEqual(0, m.Sample(cdf));
Assert.AreEqual(0, m.Sample(cdf));
Assert.AreEqual(0, m.Sample(cdf));
[Test]
public void TestDstInt()
{
Multinomial m = new Multinomial(2018);
TensorProxy src = new TensorProxy
{
ValueType = TensorProxy.TensorType.FloatingPoint
};
TensorProxy dst = new TensorProxy
{
ValueType = TensorProxy.TensorType.Integer
};
Assert.Throws<ArgumentException>(() => m.Eval(src, dst));
}
public void TestSrcDataNull()
public void TestDim3()
Multinomial m = new Multinomial(2018);
TensorProxy src = new TensorProxy
{
ValueType = TensorProxy.TensorType.FloatingPoint
};
TensorProxy dst = new TensorProxy
{
ValueType = TensorProxy.TensorType.FloatingPoint
};
var m = new Multinomial(2018);
var cdf = new[] {0.1f, 0.3f, 1.0f};
Assert.Throws<ArgumentNullException>(() => m.Eval(src, dst));
Assert.AreEqual(2, m.Sample(cdf));
Assert.AreEqual(2, m.Sample(cdf));
Assert.AreEqual(2, m.Sample(cdf));
Assert.AreEqual(1, m.Sample(cdf));
public void TestDstDataNull()
{
Multinomial m = new Multinomial(2018);
TensorProxy src = new TensorProxy
{
ValueType = TensorProxy.TensorType.FloatingPoint,
Data = new Tensor(0,1)
};
TensorProxy dst = new TensorProxy
{
ValueType = TensorProxy.TensorType.FloatingPoint
};
Assert.Throws<ArgumentNullException>(() => m.Eval(src, dst));
}
[Test]
public void TestUnequalBatchSize()
public void TestDim3Unscaled()
Multinomial m = new Multinomial(2018);
TensorProxy src = new TensorProxy
{
ValueType = TensorProxy.TensorType.FloatingPoint,
Data = new Tensor(1, 1)
};
TensorProxy dst = new TensorProxy
{
ValueType = TensorProxy.TensorType.FloatingPoint,
Data = new Tensor(2, 1)
};
var m = new Multinomial(2018);
var cdf = new[] {0.05f, 0.15f, 0.5f};
Assert.Throws<ArgumentException>(() => m.Eval(src, dst));
Assert.AreEqual(2, m.Sample(cdf));
Assert.AreEqual(2, m.Sample(cdf));
Assert.AreEqual(2, m.Sample(cdf));
Assert.AreEqual(1, m.Sample(cdf));
}
}

130
UnitySDK/Assets/ML-Agents/Editor/Tests/RandomNormalTest.cs


using System;
using Barracuda;
using MLAgents.InferenceBrain;
private const float firstValue = -1.19580f;
private const float secondValue = -0.97345f;
private const double epsilon = 0.0001;
private const float FirstValue = -1.19580f;
private const float SecondValue = -0.97345f;
private const double Epsilon = 0.0001;
RandomNormal rn = new RandomNormal(2018);
var rn = new RandomNormal(2018);
Assert.AreEqual(firstValue, rn.NextDouble(), epsilon);
Assert.AreEqual(secondValue, rn.NextDouble(), epsilon);
Assert.AreEqual(FirstValue, rn.NextDouble(), Epsilon);
Assert.AreEqual(SecondValue, rn.NextDouble(), Epsilon);
RandomNormal rn = new RandomNormal(2018, 5.0f);
var rn = new RandomNormal(2018, 5.0f);
Assert.AreEqual(firstValue + 5.0, rn.NextDouble(), epsilon);
Assert.AreEqual(secondValue + 5.0, rn.NextDouble(), epsilon);
Assert.AreEqual(FirstValue + 5.0, rn.NextDouble(), Epsilon);
Assert.AreEqual(SecondValue + 5.0, rn.NextDouble(), Epsilon);
RandomNormal rn = new RandomNormal(2018, 0.0f, 4.2f);
var rn = new RandomNormal(2018, 0.0f, 4.2f);
Assert.AreEqual(firstValue * 4.2, rn.NextDouble(), epsilon);
Assert.AreEqual(secondValue * 4.2, rn.NextDouble(), epsilon);
Assert.AreEqual(FirstValue * 4.2, rn.NextDouble(), Epsilon);
Assert.AreEqual(SecondValue * 4.2, rn.NextDouble(), Epsilon);
float mean = -3.2f;
float stddev = 2.2f;
RandomNormal rn = new RandomNormal(2018, mean, stddev);
const float mean = -3.2f;
const float stddev = 2.2f;
var rn = new RandomNormal(2018, mean, stddev);
Assert.AreEqual(firstValue * stddev + mean, rn.NextDouble(), epsilon);
Assert.AreEqual(secondValue * stddev + mean, rn.NextDouble(), epsilon);
}
[Test]
public void RandomNormalTestTensorInt()
{
RandomNormal rn = new RandomNormal(1982);
TensorProxy t = new TensorProxy
{
ValueType = TensorProxy.TensorType.Integer
};
Assert.Throws<NotImplementedException>(() => rn.FillTensor(t));
}
[Test]
public void RandomNormalTestDataNull()
{
RandomNormal rn = new RandomNormal(1982);
TensorProxy t = new TensorProxy
{
ValueType = TensorProxy.TensorType.FloatingPoint
};
Assert.Throws<ArgumentNullException>(() => rn.FillTensor(t));
Assert.AreEqual(FirstValue * stddev + mean, rn.NextDouble(), Epsilon);
Assert.AreEqual(SecondValue * stddev + mean, rn.NextDouble(), Epsilon);
float mean = -3.2f;
float stddev = 2.2f;
RandomNormal rn = new RandomNormal(2018, mean, stddev);
const float mean = -3.2f;
const float stddev = 2.2f;
var rn = new RandomNormal(2018, mean, stddev);
int numSamples = 100000;
const int numSamples = 100000;
for (int i = 0; i < numSamples; i++)
for (var i = 0; i < numSamples; i++)
double x = rn.NextDouble();
var x = rn.NextDouble();
if (i == 0)
{
oldM = newM = x;

}
}
double sampleMean = newM;
double sampleVariance = newS / (numSamples - 1);
double sampleStddev = Math.Sqrt(sampleVariance);
var sampleMean = newM;
var sampleVariance = newS / (numSamples - 1);
var sampleStddev = Math.Sqrt(sampleVariance);
}
[Test]
public void RandomNormalTestTensor()
{
RandomNormal rn = new RandomNormal(1982);
TensorProxy t = new TensorProxy
{
ValueType = TensorProxy.TensorType.FloatingPoint,
Data = new Tensor(1, 3, 4, 2)
};
rn.FillTensor(t);
float[] reference = new float[]
{
-0.4315872f,
-1.11074f,
0.3414804f,
-1.130287f,
0.1413168f,
-0.5105762f,
-0.3027347f,
-0.2645015f,
1.225356f,
-0.02921959f,
0.3716498f,
-1.092338f,
0.9561074f,
-0.5018106f,
1.167787f,
-0.7763879f,
-0.07491868f,
0.5396146f,
-0.1377991f,
0.3331701f,
0.06144788f,
0.9520947f,
1.088157f,
-1.177194f,
};
for (var i = 0; i < t.Data.length; i++)
{
Assert.AreEqual(t.Data[i], reference[i], 0.0001);
}
}
}
}

19
UnitySDK/Assets/ML-Agents/Editor/Tests/UtilitiesTests.cs


using NUnit.Framework;
using UnityEngine;
namespace MLAgents.Tests
{

public void TestCumSum()
{
var output = Utilities.CumSum(new int[]{1, 2, 3, 10});
CollectionAssert.AreEqual(output, new int[] {0, 1, 3, 6, 16});
var output = Utilities.CumSum(new []{1, 2, 3, 10});
CollectionAssert.AreEqual(output, new [] {0, 1, 3, 6, 16});
CollectionAssert.AreEqual(output, new int[]{0});
output = Utilities.CumSum(new int[]{100});
CollectionAssert.AreEqual(output, new int[]{0, 100});
output = Utilities.CumSum(new int[]{-1, 10});
CollectionAssert.AreEqual(output, new int[]{0, -1, 9});
CollectionAssert.AreEqual(output, new []{0});
output = Utilities.CumSum(new []{100});
CollectionAssert.AreEqual(output, new []{0, 100});
output = Utilities.CumSum(new []{-1, 10});
CollectionAssert.AreEqual(output, new []{0, -1, 9});
}
}
}

143
UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/ApplierImpl.cs


using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Barracuda;
using MLAgents.InferenceBrain.Utils;

{
public void Apply(TensorProxy tensorProxy, Dictionary<Agent, AgentInfo> agentInfo)
{
var actionSize = tensorProxy.Shape[tensorProxy.Shape.Length - 1];
var actionSize = tensorProxy.shape[tensorProxy.shape.Length - 1];
var agentIndex = 0;
foreach (var agent in agentInfo.Keys)
{

action[j] = tensorProxy.Data[agentIndex, j];
action[j] = tensorProxy.data[agentIndex, j];
}
agent.UpdateVectorAction(action);
agentIndex++;

/// </summary>
public class DiscreteActionOutputApplier : TensorApplier.Applier
{
private int[] _actionSize;
private Multinomial _multinomial;
private ITensorAllocator _allocator;
private readonly int[] _actionSize;
private readonly Multinomial _multinomial;
private readonly ITensorAllocator _allocator;
public DiscreteActionOutputApplier(int[] actionSize, int seed, ITensorAllocator allocator)
{
_actionSize = actionSize;

public void Apply(TensorProxy tensorProxy, Dictionary<Agent, AgentInfo> agentInfo)
{
//var tensorDataProbabilities = tensorProxy.Data as float[,];

var nBranchAction = _actionSize[actionIndex];
var actionProbs = new TensorProxy()
{
ValueType = TensorProxy.TensorType.FloatingPoint,
Shape = new long[]{batchSize, nBranchAction},
Data = _allocator.Alloc(new TensorShape(batchSize, nBranchAction))
valueType = TensorProxy.TensorType.FloatingPoint,
shape = new long[]{batchSize, nBranchAction},
data = _allocator.Alloc(new TensorShape(batchSize, nBranchAction))
for (var branchActionIndex = 0;
branchActionIndex < nBranchAction;
for (var branchActionIndex = 0;
branchActionIndex < nBranchAction;
actionProbs.Data[batchIndex, branchActionIndex] =
tensorProxy.Data[batchIndex, startActionIndices[actionIndex] + branchActionIndex];
actionProbs.data[batchIndex, branchActionIndex] =
tensorProxy.data[batchIndex, startActionIndices[actionIndex] + branchActionIndex];
ValueType = TensorProxy.TensorType.FloatingPoint,
Shape = new long[]{batchSize, 1},
Data = _allocator.Alloc(new TensorShape(batchSize, 1))
valueType = TensorProxy.TensorType.FloatingPoint,
shape = new long[]{batchSize, 1},
data = _allocator.Alloc(new TensorShape(batchSize, 1))
_multinomial.Eval(actionProbs, outputTensor);
Eval(actionProbs, outputTensor, _multinomial);
actions[ii, actionIndex] = outputTensor.Data[ii, 0];
actions[ii, actionIndex] = outputTensor.data[ii, 0];
}
}
var agentIndex = 0;

agentIndex++;
}
}
/// <summary>
/// Draw samples from a multinomial distribution based on log-probabilities specified
/// in tensor src. The samples will be saved in the dst tensor.
/// </summary>
/// <param name="src">2-D tensor with shape batch_size x num_classes</param>
/// <param name="dst">Allocated tensor with size batch_size x num_samples</param>
/// <param name="multinomial">Multinomial object used to sample values</param>
/// <exception cref="NotImplementedException">
/// Multinomial doesn't support integer tensors
/// </exception>
/// <exception cref="ArgumentException">Issue with tensor shape or type</exception>
/// <exception cref="ArgumentNullException">
/// At least one of the tensors is not allocated
/// </exception>
public static void Eval(TensorProxy src, TensorProxy dst, Multinomial multinomial)
{
if (src.DataType != typeof(float))
{
throw new NotImplementedException("Only float tensors are currently supported");
}
if (src.valueType != dst.valueType)
{
throw new ArgumentException(
"Source and destination tensors have different types!");
}
if (src.data == null || dst.data == null)
{
throw new ArgumentNullException();
}
if (src.data.batch != dst.data.batch)
{
throw new ArgumentException("Batch size for input and output data is different!");
}
var cdf = new float[src.data.channels];
for (var batch = 0; batch < src.data.batch; ++batch)
{
// Find the class maximum
var maxProb = float.NegativeInfinity;
for (var cls = 0; cls < src.data.channels; ++cls)
{
maxProb = Mathf.Max(src.data[batch, cls], maxProb);
}
// Sum the log probabilities and compute CDF
var sumProb = 0.0f;
for (var cls = 0; cls < src.data.channels; ++cls)
{
sumProb += Mathf.Exp(src.data[batch, cls] - maxProb);
cdf[cls] = sumProb;
}
// Generate the samples
for (var sample = 0; sample < dst.data.channels; ++sample)
{
dst.data[batch, sample] = multinomial.Sample(cdf);
}
}
}
private int memoriesCount;
private int memoryIndex;
private readonly int _memoriesCount;
private readonly int _memoryIndex;
this.memoriesCount = memoriesCount;
this.memoryIndex = memoryIndex;
_memoriesCount = memoriesCount;
_memoryIndex = memoryIndex;
var memorySize = (int)tensorProxy.Shape[tensorProxy.Shape.Length - 1];
var memorySize = (int)tensorProxy.shape[tensorProxy.shape.Length - 1];
if (memory == null || memory.Count < memorySize * memoriesCount)
if (memory == null || memory.Count < memorySize * _memoriesCount)
memory.AddRange(Enumerable.Repeat(0f, memorySize * memoriesCount));
memory.AddRange(Enumerable.Repeat(0f, memorySize * _memoriesCount));
memory[memorySize * memoryIndex + j] = tensorProxy.Data[agentIndex, j];
memory[memorySize * _memoryIndex + j] = tensorProxy.data[agentIndex, j];
agent.UpdateMemoriesAction(memory);
agentIndex++;

public void Apply(TensorProxy tensorProxy, Dictionary<Agent, AgentInfo> agentInfo)
{
var agentIndex = 0;
var memorySize = tensorProxy.Shape[tensorProxy.Shape.Length - 1];
var memorySize = tensorProxy.shape[tensorProxy.shape.Length - 1];
memory.Add(tensorProxy.Data[agentIndex, j]);
memory.Add(tensorProxy.data[agentIndex, j]);
}
agent.UpdateMemoriesAction(memory);

var agentIndex = 0;
foreach (var agent in agentInfo.Keys)
{
agent.UpdateValueAction(tensorProxy.Data[agentIndex, 0]);
agent.UpdateValueAction(tensorProxy.data[agentIndex, 0]);
agentIndex++;
}
}

255
UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/BarracudaModelParamLoader.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using MLAgents.InferenceBrain;
namespace MLAgents.InferenceBrain
{

Continuous
}
private const long ApiVersion = 2;
private IWorker _engine;
private Model _model;
private BrainParameters _brainParameters;
private List<string> _failedModelChecks = new List<string>();
private readonly IWorker _engine;
private readonly Model _model;
private readonly BrainParameters _brainParameters;
private readonly List<string> _failedModelChecks = new List<string>();
/// <param name="engine"> The Barracuda engine worker we get the parameters and the checks from
/// <param name="engine">
/// The Barracuda engine worker we get the parameters and the checks from
/// <param name="model"> The Barracuda engine model for loading static parameters
/// <param name="model">
/// The Barracuda engine model for loading static parameters
/// <param name="brainParameters"> The BrainParamters that are used verify the
/// compatibility with the InferenceEngine</param>
/// <param name="brainParameters">
/// The BrainParameters that are used verify the compatibility with the InferenceEngine
/// </param>
public static BarracudaModelParamLoader GetLoaderAndCheck(IWorker engine, Model model,
BrainParameters brainParameters)
public static BarracudaModelParamLoader GetLoaderAndCheck(
IWorker engine, Model model, BrainParameters brainParameters)
BarracudaModelParamLoader modelParamLoader = new BarracudaModelParamLoader(engine, model, brainParameters);
var modelParamLoader = new BarracudaModelParamLoader(engine, model, brainParameters);
private BarracudaModelParamLoader(IWorker engine, Model model, BrainParameters brainParameters)
private BarracudaModelParamLoader(
IWorker engine, Model model, BrainParameters brainParameters)
{
_engine = engine;
_model = model;

/// <summary>
/// Generates the Tensor inputs that are expected to be present in the Model.
/// Generates the Tensor inputs that are expected to be present in the Model.
List<TensorProxy> tensors = new List<TensorProxy>();
var tensors = new List<TensorProxy>();
Name = input.name,
ValueType = TensorProxy.TensorType.FloatingPoint,
Data = null,
Shape = input.shape.Select(i => (long)i).ToArray()
name = input.name,
valueType = TensorProxy.TensorType.FloatingPoint,
data = null,
shape = input.shape.Select(i => (long)i).ToArray()
Name = mem.input,
ValueType = TensorProxy.TensorType.FloatingPoint,
Data = null,
Shape = TensorUtils.TensorShapeFromBarracuda(mem.shape)
name = mem.input,
valueType = TensorProxy.TensorType.FloatingPoint,
data = null,
shape = TensorUtils.TensorShapeFromBarracuda(mem.shape)
tensors.Sort((el1, el2) => el1.Name.CompareTo(el2.Name));
tensors.Sort((el1, el2) => el1.name.CompareTo(el2.name));
/// Generates the Tensor outputs that are expected to be present in the Model.
/// Generates the Tensor outputs that are expected to be present in the Model.
/// </summary>
/// <returns>TensorProxy IEnumerable with the expected Tensor outputs</returns>
public string[] GetOutputNames()

if (_model == null)
{
names.Add(TensorNames.ActionOutput);
}
names.Add(TensorNames.ActionOutput);
var memory = GetIntScalar(TensorNames.MemorySize);
if (memory > 0)
{

}
names.Sort();
return names.ToArray();
}

/// If the node was not found or could not be retrieved, the value -1 will be returned.
/// If the node was not found or could not be retrieved, the value -1 will be returned.
/// </summary>
/// <param name="name">The name of the Tensor variable</param>
/// <returns>The value of the scalar variable in the model. (-1 if not found)</returns>

/// <summary>
/// Retrieves an IEnumerable of string corresponding to the failed compatibility checks
/// between the InferenceEngine and the BrainParameters.
/// between the InferenceEngine and the BrainParameters.
/// </summary>
public IEnumerable<string> GetChecks()
{

if (modelApiVersion == -1)
{
_failedModelChecks.Add(
"Model was not trained using the right version of ML-Agents. Cannot use this " +
"model.");
"Model was not trained using the right version of ML-Agents. " +
"Cannot use this model.");
return;
}
if (modelApiVersion != ApiVersion)

/// Converts the integer value in the model corresponding to the type of control to a
/// ModelActionType.
/// </summary>
/// <param name="isContinuousInt"> The integer value in the model indicating the
/// type of control</param>
/// <param name="isContinuousInt">
/// The integer value in the model indicating the type of control
/// </param>
/// <returns>The equivalent ModelActionType</returns>
private static ModelActionType GetActionType(int isContinuousInt)
{

case 0:
isContinuous = ModelActionType.Discrete;
break;
case 1:
case 1:
isContinuous = ModelActionType.Continuous;
break;
default:

/// <param name="requiredScalarFields"> Mapping from node names to int values</param>
private void CheckIntScalarPresenceHelper(Dictionary<string, int> requiredScalarFields)
{
foreach(var field in requiredScalarFields)
if (field.Value == -1)
foreach (var field in requiredScalarFields)
_failedModelChecks.Add(
$"Missing node in the model provided : {field.Key}");
if (field.Value == -1)
{
_failedModelChecks.Add($"Missing node in the model provided : {field.Key}");
}
}
}

/// </summary>
/// <param name="memory"> The memory size that the model is expecting/</param>
/// <param name="isContinuous"> Whether the model is expecting continuous or
/// discrete control.</param>
/// <returns>A IEnumerable of string corresponding to the failed input presence
/// checks.</returns>
/// <param name="memory">
/// The memory size that the model is expecting.
/// </param>
/// <param name="isContinuous">
/// Whether the model is expecting continuous or discrete control.
/// </param>
/// <returns>
/// A IEnumerable of string corresponding to the failed input presence checks.
/// </returns>
var tensorsNames = GetInputTensors().Select(x => x.Name).ToList();
var tensorsNames = GetInputTensors().Select(x => x.name).ToList();
// If there is no Vector Observation Input but the Brain Parameters expect one.
if ((_brainParameters.vectorObservationSize != 0) &&
(!tensorsNames.Contains(TensorNames.VectorObservationPlacholder)))

"for visual observation "+visObsIndex+".");
}
}
// If the model has a non-negative memory size but requires a recurrent input
if (memory > 0)
{

"The model does not contain a Recurrent Input Node but has memory_size.");
}
}
// If the model uses discrete control but does not have an input for action masks
if (isContinuous == ModelActionType.Discrete)
{

}
}
}
/// <param name="memory"> The memory size that the model is expecting/</param>
/// <returns>A IEnumerable of string corresponding to the failed output presence
/// checks.</returns>
/// <param name="memory">The memory size that the model is expecting/</param>
/// <returns>
/// A IEnumerable of string corresponding to the failed output presence checks.
/// </returns>
private void CheckOutputTensorPresence(int memory)
{
// If there is no Action Output.

}
if (!memOutputs.Any(x => x.EndsWith("_h")) ||
if (!memOutputs.Any(x => x.EndsWith("_h")) ||
!memOutputs.Any(x => x.EndsWith("_c")))
{
_failedModelChecks.Add(

}
/// <summary>
/// Generates failed checks that correspond to inputs shapes incompatibilities between
/// the model and the BrainParameters.

};
foreach (var mem in _model.memories)
{
}
for (var obsIndex = 0; obsIndex < _brainParameters.cameraResolutions.Length; obsIndex++)
{
var index = obsIndex;

// If the model expects an input but it is not in this list
foreach (var tensor in GetInputTensors())
{
if (!tensorTester.ContainsKey(tensor.Name))
if (!tensorTester.ContainsKey(tensor.name))
"Model requires an unknown input named : " + tensor.Name);
"Model requires an unknown input named : " + tensor.name);
var tester = tensorTester[tensor.Name];
var tester = tensorTester[tensor.name];
var error = tester.Invoke(tensor);
if (error != null)
{

}
}
/// <param name="tensorProxy"> The tensor that is expected by the model</param>
/// <returns>If the Check failed, returns a string containing information about why the
/// check failed. If the check passed, returns null.</returns>
/// <param name="tensorProxy">The tensor that is expected by the model</param>
/// <returns>
/// If the Check failed, returns a string containing information about why the
/// check failed. If the check passed, returns null.
/// </returns>
var totalVecObsSizeT = tensorProxy.Shape[tensorProxy.Shape.Length - 1];
var totalVecObsSizeT = tensorProxy.shape[tensorProxy.shape.Length - 1];
return string.Format(
"Vector Observation Size of the model does not match. " +
"Received {0} x {1} but was expecting {2}.",
vecObsSizeBp, numStackedVector, totalVecObsSizeT);
return "Vector Observation Size of the model does not match. Received " +
$"{vecObsSizeBp} x {numStackedVector} but was expecting {totalVecObsSizeT}.";
/// <summary>
/// Checks that the shape of the Previous Vector Action input placeholder is the same in the
/// model and in the Brain Parameters.

private string CheckPreviousActionShape(TensorProxy tensorProxy)
{
var numberActionsBp = _brainParameters.vectorActionSize.Length;
var numberActionsT = tensorProxy.Shape[tensorProxy.Shape.Length - 1];
var numberActionsT = tensorProxy.shape[tensorProxy.shape.Length - 1];
return string.Format(
"Previous Action Size of the model does not match. " +
"Received {0} but was expecting {1}.",
numberActionsBp, numberActionsT);
return "Previous Action Size of the model does not match. " +
$"Received {numberActionsBp} but was expecting {numberActionsT}.";
/// <param name="tensorProxy"> The tensor that is expected by the model</param>
/// <param name="visObsIndex"> The index of the visual observation.</param>
/// <returns>If the Check failed, returns a string containing information about why the
/// check failed. If the check passed, returns null.</returns>
/// <param name="tensorProxy">The tensor that is expected by the model</param>
/// <param name="visObsIndex">The index of the visual observation.</param>
/// <returns>
/// If the Check failed, returns a string containing information about why the
/// check failed. If the check passed, returns null.
/// </returns>
var pixelBp = resolutionBp.blackAndWhite ? 1 : 3;
var heightT = tensorProxy.Shape[1];
var widthT = tensorProxy.Shape[2];
var pixelT = tensorProxy.Shape[3];
var pixelBp = resolutionBp.blackAndWhite ? 1 : 3;
var heightT = tensorProxy.shape[1];
var widthT = tensorProxy.shape[2];
var pixelT = tensorProxy.shape[3];
return string.Format(
"The visual Observation {0} of the model does not match. " +
"Received TensorProxy of shape [?x{1}x{2}x{3}] but was expecting [?x{4}x{5}x{6}].",
visObsIndex, widthBp, heightBp, pixelBp, widthT, heightT, pixelT);
return $"The visual Observation {visObsIndex} of the model does not match. " +
$"Received TensorProxy of shape [?x{widthBp}x{heightBp}x{pixelBp}] but " +
$"was expecting [?x{widthT}x{heightT}x{pixelT}].";
/// <param name="isContinuous"> Whether the model is expecting continuous or
/// discrete control.</param>
/// <param name="modelActionSize"> The size of the action output that is expected
/// by the model.</param>
/// <returns>A IEnumerable of string corresponding to the incompatible shapes between
/// model and BrainParameters.</returns>
/// <param name="isContinuous">
/// Whether the model is expecting continuous or discrete control.
/// </param>
/// <param name="modelActionSize">
/// The size of the action output that is expected by the model.
/// </param>
/// <returns>
/// A IEnumerable of string corresponding to the incompatible shapes between model
/// and BrainParameters.
/// </returns>
_failedModelChecks.Add(
"Cannot infer type of Control from the provided model.");
_failedModelChecks.Add("Cannot infer type of Control from the provided model.");
return;
}
if (isContinuous == ModelActionType.Continuous &&

/// model and in the Brain Parameters.
/// </summary>
/// <param name="shape"> The tensor shape that is expected by the model</param>
/// <param name="modelActionSize"> The size of the action output that is expected
/// by the model.</param>
/// <returns>If the Check failed, returns a string containing information about why the
/// check failed. If the check passed, returns null.</returns>
/// <param name="modelActionSize">
/// The size of the action output that is expected by the model.
/// </param>
/// <returns>
/// If the Check failed, returns a string containing information about why the
/// check failed. If the check passed, returns null.
/// </returns>
return string.Format(
"Action Size of the model does not match. " +
"The BrainParameters expect {0} but the model contains {1}.",
bpActionSize, modelActionSize);
return "Action Size of the model does not match. The BrainParameters expect " +
$"{bpActionSize} but the model contains {modelActionSize}.";
/// <param name="modelActionSize"> The size of the action output that is expected
/// by the model.</param>
/// <param name="modelActionSize">
/// The size of the action output that is expected by the model.
/// </param>
/// <returns>If the Check failed, returns a string containing information about why the
/// check failed. If the check passed, returns null.</returns>
private string CheckContinuousActionOutputShape(TensorShape shape, int modelActionSize)

{
return string.Format(
"Action Size of the model does not match. " +
"The BrainParameters expect {0} but the model contains {1}.",
bpActionSize, modelActionSize);
return "Action Size of the model does not match. The BrainParameters expect " +
$"{bpActionSize} but the model contains {modelActionSize}.";
}
}

144
UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/GeneratorImpl.cs


/// </summary>
public class BiDimensionalOutputGenerator : TensorGenerator.Generator
{
private ITensorAllocator _allocator;
private readonly ITensorAllocator _allocator;
public void Generate(TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
{
TensorUtils.ResizeTensor(tensorProxy, batchSize, _allocator);

/// </summary>
public class BatchSizeGenerator : TensorGenerator.Generator
{
private ITensorAllocator _allocator;
private readonly ITensorAllocator _allocator;
tensorProxy.Data = _allocator.Alloc(new TensorShape(1,1));
tensorProxy.Data[0] = batchSize;
tensorProxy.data = _allocator.Alloc(new TensorShape(1,1));
tensorProxy.data[0] = batchSize;
}
}

/// </summary>
public class SequenceLengthGenerator : TensorGenerator.Generator
{
private ITensorAllocator _allocator;
private readonly ITensorAllocator _allocator;
tensorProxy.Shape = new long[0];
tensorProxy.Data = _allocator.Alloc(new TensorShape(1,1));
tensorProxy.shape = new long[0];
tensorProxy.data = _allocator.Alloc(new TensorShape(1,1));
tensorProxy.Data[0] = 1;
tensorProxy.data[0] = 1;
}
}

/// </summary>
public class VectorObservationGenerator : TensorGenerator.Generator
{
private ITensorAllocator _allocator;
private readonly ITensorAllocator _allocator;
public void Generate(TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
public void Generate(
TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
var vecObsSizeT = tensorProxy.Shape[tensorProxy.Shape.Length - 1];
var vecObsSizeT = tensorProxy.shape[tensorProxy.shape.Length - 1];
var agentIndex = 0;
foreach (var agent in agentInfo.Keys)
{

tensorProxy.Data[agentIndex, j] = vectorObs[j];
tensorProxy.data[agentIndex, j] = vectorObs[j];
}
agentIndex++;
}

/// </summary>
public class RecurrentInputGenerator : TensorGenerator.Generator
{
private ITensorAllocator _allocator;
private readonly ITensorAllocator _allocator;
public void Generate(TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
public void Generate(
TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
var memorySize = tensorProxy.Shape[tensorProxy.Shape.Length - 1];
var memorySize = tensorProxy.shape[tensorProxy.shape.Length - 1];
var agentIndex = 0;
foreach (var agent in agentInfo.Keys)
{

{
break;
}
tensorProxy.Data[agentIndex, j] = memory[j];
tensorProxy.data[agentIndex, j] = memory[j];
private int memoriesCount;
private int memoryIndex;
private ITensorAllocator _allocator;
private int _memoriesCount;
private readonly int _memoryIndex;
private readonly ITensorAllocator _allocator;
this.memoryIndex = memoryIndex;
this._memoryIndex = memoryIndex;
public void Generate(TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
public void Generate(
TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
var memorySize = (int)tensorProxy.Shape[tensorProxy.Shape.Length - 1];
var memorySize = (int)tensorProxy.shape[tensorProxy.shape.Length - 1];
var memory = agentInfo[agent].memories;
var memory = agentInfo[agent].memories;
var offset = memorySize * _memoryIndex;
int offset = memorySize * memoryIndex;
if (memory == null)
{
agentIndex++;

{
break;
}
tensorProxy.Data[agentIndex, j] = memory[j + offset];
tensorProxy.data[agentIndex, j] = memory[j + offset];
}
agentIndex++;
}

/// </summary>
public class PreviousActionInputGenerator : TensorGenerator.Generator
{
private ITensorAllocator _allocator;
private readonly ITensorAllocator _allocator;
public void Generate(TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
public void Generate(
TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
var actionSize = tensorProxy.Shape[tensorProxy.Shape.Length - 1];
var actionSize = tensorProxy.shape[tensorProxy.shape.Length - 1];
var agentIndex = 0;
foreach (var agent in agentInfo.Keys)
{

tensorProxy.Data[agentIndex, j] = pastAction[j];
tensorProxy.data[agentIndex, j] = pastAction[j];
}
agentIndex++;

/// </summary>
public class ActionMaskInputGenerator : TensorGenerator.Generator
{
private ITensorAllocator _allocator;
private readonly ITensorAllocator _allocator;
public void Generate(TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
public void Generate(
TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
var maskSize = tensorProxy.Shape[tensorProxy.Shape.Length - 1];
var maskSize = tensorProxy.shape[tensorProxy.shape.Length - 1];
var agentIndex = 0;
foreach (var agent in agentInfo.Keys)
{

var isUnmasked = (maskList != null && maskList[j]) ? 0.0f : 1.0f;
tensorProxy.Data[agentIndex, j] = isUnmasked;
tensorProxy.data[agentIndex, j] = isUnmasked;
}
agentIndex++;
}

/// </summary>
public class RandomNormalInputGenerator : TensorGenerator.Generator
{
private RandomNormal _randomNormal;
private ITensorAllocator _allocator;
private readonly RandomNormal _randomNormal;
private readonly ITensorAllocator _allocator;
public void Generate(TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
public void Generate(
TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
_randomNormal.FillTensor(tensorProxy);
TensorUtils.FillTensorWithRandomNormal(tensorProxy, _randomNormal);
/// dimensional float array of dimension [batchSize x width x heigth x numChannels].
/// dimensional float array of dimension [batchSize x width x height x numChannels].
private int _index;
private bool _grayScale;
private ITensorAllocator _allocator;
public VisualObservationInputGenerator(int index, bool grayScale, ITensorAllocator allocator)
private readonly int _index;
private readonly bool _grayScale;
private readonly ITensorAllocator _allocator;
public VisualObservationInputGenerator(
int index, bool grayScale, ITensorAllocator allocator)
public void Generate(TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
public void Generate(
TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo)
Utilities.TextureToTensorProxy(tensorProxy, textures, _grayScale, _allocator);
}
}
Utilities.TextureToTensorProxy(textures, tensorProxy, _grayScale);
}
}
}

34
UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/TensorApplier.cs


using Barracuda;
namespace MLAgents.InferenceBrain
{
{
/// <summary>
/// Mapping between the output tensor names and the method that will use the
/// output tensors and the Agents present in the batch to update their action, memories and

/// <summary>
/// Applies the values in the Tensor to the Agents present in the agentInfos
/// </summary>
/// <param name="tensorProxy"> The Tensor containing the data to be applied to the Agents</param>
/// <param name="agentInfo"> Dictionary of Agents to AgentInfo that will reveive
/// the values of the Tensor.</param>
/// <param name="tensorProxy">
/// The Tensor containing the data to be applied to the Agents
/// </param>
/// <param name="agentInfo">
/// Dictionary of Agents to AgentInfo that will receive
/// the values of the Tensor.
/// </param>
Dictionary<string, Applier> _dict = new Dictionary<string, Applier>();
private readonly Dictionary<string, Applier> _dict = new Dictionary<string, Applier>();
/// <summary>
/// Returns a new TensorAppliers object.

/// <param name="seed"> The seed the Appliers will be initialized with.</param>
/// <param name="allocator"> Tensor allocator</param>
public TensorApplier(BrainParameters bp, int seed, ITensorAllocator allocator, object barracudaModel = null)
/// <param name="barracudaModel"></param>
public TensorApplier(
BrainParameters bp, int seed, ITensorAllocator allocator, object barracudaModel = null)
{
_dict[TensorNames.ValueEstimateOutput] = new ValueEstimateApplier();
if (bp.vectorActionSpaceType == SpaceType.continuous)

else
{
_dict[TensorNames.ActionOutput] = new DiscreteActionOutputApplier(bp.vectorActionSize, seed, allocator);
_dict[TensorNames.ActionOutput] =
new DiscreteActionOutputApplier(bp.vectorActionSize, seed, allocator);
Model model = (Model) barracudaModel;
var model = (Model) barracudaModel;
_dict[model.memories[i].output] = new BarracudaMemoryOutputApplier(model.memories.Length, i);
_dict[model.memories[i].output] =
new BarracudaMemoryOutputApplier(model.memories.Length, i);
}
}
}

{
foreach (var tensor in tensors)
{
if (!_dict.ContainsKey(tensor.Name))
if (!_dict.ContainsKey(tensor.name))
"Unknow tensorProxy expected as output : "+tensor.Name);
$"Unknown tensorProxy expected as output : {tensor.name}");
_dict[tensor.Name].Apply(tensor, agentInfos);
_dict[tensor.name].Apply(tensor, agentInfos);
}
}
}

66
UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/TensorGenerator.cs


using System.Collections.Generic;
using System.Runtime.InteropServices.ComTypes;
using Barracuda;
namespace MLAgents.InferenceBrain

/// When the TensorProxy is an Input to the model, the shape of the Tensor will be modified
/// depending on the current batch size and the data of the Tensor will be filled using the
/// Dictionary of Agent to AgentInfo.
/// When the TensorProxy is an Output of the model, only the shape of the Tensor will be modified
/// using the current batch size. The data will be prefilled with zeros.
/// When the TensorProxy is an Output of the model, only the shape of the Tensor will be
/// modified using the current batch size. The data will be pre-filled with zeros.
/// </summary>
public class TensorGenerator
{

/// <param name="batchSize"> The number of agents present in the current batch</param>
/// <param name="agentInfo"> Dictionary of Agent to AgentInfo containing the
/// information that will be used to populate the tensor's data</param>
void Generate(TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo);
void Generate(
TensorProxy tensorProxy, int batchSize, Dictionary<Agent, AgentInfo> agentInfo);
Dictionary<string, Generator> _dict = new Dictionary<string, Generator>();
ITensorAllocator _allocator;
private readonly Dictionary<string, Generator> _dict = new Dictionary<string, Generator>();
/// <summary>
/// Returns a new TensorGenerators object.

/// <param name="seed"> The seed the Generators will be initialized with.</param>
/// <param name="allocator"> Tensor allocator</param>
public TensorGenerator(BrainParameters bp, int seed, ITensorAllocator allocator, object barracudaModel = null)
/// <param name="barracudaModel"></param>
public TensorGenerator(
BrainParameters bp, int seed, ITensorAllocator allocator, object barracudaModel = null)
_allocator = allocator;
_dict[TensorNames.BatchSizePlaceholder] = new BatchSizeGenerator(_allocator);
_dict[TensorNames.SequenceLengthPlaceholder] = new SequenceLengthGenerator(_allocator);
_dict[TensorNames.VectorObservationPlacholder] = new VectorObservationGenerator(_allocator);
_dict[TensorNames.RecurrentInPlaceholder] = new RecurrentInputGenerator(_allocator);
_dict[TensorNames.BatchSizePlaceholder] =
new BatchSizeGenerator(allocator);
_dict[TensorNames.SequenceLengthPlaceholder] =
new SequenceLengthGenerator(allocator);
_dict[TensorNames.VectorObservationPlacholder] =
new VectorObservationGenerator(allocator);
_dict[TensorNames.RecurrentInPlaceholder] =
new RecurrentInputGenerator(allocator);
Model model = (Model) barracudaModel;
var model = (Model) barracudaModel;
_dict[model.memories[i].input] = new BarracudaRecurrentInputGenerator(i, _allocator);
_dict[model.memories[i].input] =
new BarracudaRecurrentInputGenerator(i, allocator);
_dict[TensorNames.PreviousActionPlaceholder] = new PreviousActionInputGenerator(_allocator);
_dict[TensorNames.ActionMaskPlaceholder] = new ActionMaskInputGenerator(_allocator);
_dict[TensorNames.RandomNormalEpsilonPlaceholder] = new RandomNormalInputGenerator(seed, _allocator);
_dict[TensorNames.PreviousActionPlaceholder] =
new PreviousActionInputGenerator(allocator);
_dict[TensorNames.ActionMaskPlaceholder] =
new ActionMaskInputGenerator(allocator);
_dict[TensorNames.RandomNormalEpsilonPlaceholder] =
new RandomNormalInputGenerator(seed, allocator);
if (bp.cameraResolutions != null)
{
for (var visIndex = 0;

var index = visIndex;
var bw = bp.cameraResolutions[visIndex].blackAndWhite;
_dict[TensorNames.VisualObservationPlaceholderPrefix + visIndex] = new
VisualObservationInputGenerator(index, bw, _allocator);
_dict[TensorNames.VisualObservationPlaceholderPrefix + visIndex] =
new VisualObservationInputGenerator(index, bw, allocator);
_dict[TensorNames.ActionOutput] = new BiDimensionalOutputGenerator(_allocator);
_dict[TensorNames.RecurrentOutput] = new BiDimensionalOutputGenerator(_allocator);
_dict[TensorNames.ValueEstimateOutput] = new BiDimensionalOutputGenerator(_allocator);
_dict[TensorNames.ActionOutput] = new BiDimensionalOutputGenerator(allocator);
_dict[TensorNames.RecurrentOutput] = new BiDimensionalOutputGenerator(allocator);
_dict[TensorNames.ValueEstimateOutput] = new BiDimensionalOutputGenerator(allocator);
}
/// <summary>

/// data that will be used to modify the tensors</param>
/// <exception cref="UnityAgentsException"> One of the tensor does not have an
/// associated generator.</exception>
public void GenerateTensors(IEnumerable<TensorProxy> tensors,
int currentBatchSize,
public void GenerateTensors(
IEnumerable<TensorProxy> tensors,
int currentBatchSize,
if (!_dict.ContainsKey(tensor.Name))
if (!_dict.ContainsKey(tensor.name))
"Unknow tensorProxy expected as input : " + tensor.Name);
$"Unknown tensorProxy expected as input : {tensor.name}");
_dict[tensor.Name].Generate(tensor, currentBatchSize, agentInfos);
_dict[tensor.name].Generate(tensor, currentBatchSize, agentInfos);
}
}
}

228
UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/TensorProxy.cs


using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using MLAgents.InferenceBrain.Utils;
/// <summary>
/// Tensor - A class to encapsulate a Tensor used for inference.
///
/// This class contains the Array that holds the data array, the shapes, type and the placeholder in the
/// execution graph. All the fields are editable in the inspector, allowing the user to specify everything
/// but the data in a graphical way.
/// </summary>
[System.Serializable]
public class TensorProxy
{
public enum TensorType
{
Integer,
FloatingPoint
};
private static Dictionary<TensorType, Type> m_typeMap = new Dictionary<TensorType, Type>()
{
{ TensorType.FloatingPoint, typeof(float)},
{TensorType.Integer, typeof(int)}
};
public string Name;
public TensorType ValueType;
// Since Type is not serializable, we use the DisplayType for the Inspector
public Type DataType
{
get { return m_typeMap[ValueType]; }
}
public long[] Shape;
public Tensor Data;
}
public class TensorUtils
{
public static void ResizeTensor(TensorProxy tensor, int batch, ITensorAllocator allocator)
{
if (tensor.Shape[0] == batch &&
tensor.Data != null && tensor.Data.batch == batch)
return;
tensor.Data?.Dispose();
tensor.Shape[0] = batch;
if (tensor.Shape.Length == 4)
tensor.Data = allocator.Alloc(new TensorShape(batch, (int)tensor.Shape[1], (int)tensor.Shape[2], (int)tensor.Shape[3]));
else
tensor.Data = allocator.Alloc(new TensorShape(batch, (int)tensor.Shape[tensor.Shape.Length - 1]));
}
/// <summary>
/// Tensor - A class to encapsulate a Tensor used for inference.
///
/// This class contains the Array that holds the data array, the shapes, type and the
/// placeholder in the execution graph. All the fields are editable in the inspector,
/// allowing the user to specify everything but the data in a graphical way.
/// </summary>
[Serializable]
public class TensorProxy
{
public enum TensorType
{
Integer,
FloatingPoint
};
public static Array BarracudaToFloatArray(Tensor tensor)
{
Array res;
if (tensor.height == 1 && tensor.width == 1)
res = new float[tensor.batch, tensor.channels];
else
res = new float[tensor.batch, tensor.height, tensor.width, tensor.channels];
Buffer.BlockCopy(tensor.readonlyArray, 0, res, 0, tensor.length * Marshal.SizeOf<float>());
private static readonly Dictionary<TensorType, Type> _typeMap =
new Dictionary<TensorType, Type>()
{
{TensorType.FloatingPoint, typeof(float)},
{TensorType.Integer, typeof(int)}
};
return res;
}
public static Array BarracudaToIntArray(Tensor tensor)
{
public string name;
public TensorType valueType;
if (tensor.height == 1 && tensor.width == 1)
{
var res = new int[tensor.batch, tensor.channels];
for (int b = 0; b < tensor.batch; b++)
for (int c = 0; c < tensor.channels; c++)
{
res[b, c] = (int)tensor[b, c];
}
// Since Type is not serializable, we use the DisplayType for the Inspector
public Type DataType => _typeMap[valueType];
public long[] shape;
public Tensor data;
}
return res;
}
else
{
var res = new int[tensor.batch, tensor.height, tensor.width, tensor.channels];
for (int b = 0; b < tensor.batch; b++)
for (int y = 0; y < tensor.height; y++)
for (int x = 0; x < tensor.width; x++)
for (int c = 0; c < tensor.channels; c++)
{
res[b, y, x, c] = (int)tensor[b, y, x, c];
}
public static class TensorUtils
{
public static void ResizeTensor(TensorProxy tensor, int batch, ITensorAllocator allocator)
{
if (tensor.shape[0] == batch &&
tensor.data != null && tensor.data.batch == batch)
{
return;
}
return res;
}
}
tensor.data?.Dispose();
tensor.shape[0] = batch;
public static Tensor ArrayToBarracuda(Array array)
{
Tensor res;
if (array.Rank == 2)
res = new Tensor(array.GetLength(0), array.GetLength(1));
else
res = new Tensor(array.GetLength(0), array.GetLength(1), array.GetLength(2), array.GetLength(3));
if (tensor.shape.Length == 4)
{
tensor.data = allocator.Alloc(
new TensorShape(
batch,
(int) tensor.shape[1],
(int) tensor.shape[2],
(int) tensor.shape[3]));
}
else
{
tensor.data = allocator.Alloc(
new TensorShape(
batch,
(int) tensor.shape[tensor.shape.Length - 1]));
}
}
int offset = 0;
var barracudaArray = res.data != null ? res.tensorOnDevice.SharedAccess(out offset) : null;
internal static long[] TensorShapeFromBarracuda(TensorShape src)
{
if (src.height == 1 && src.width == 1)
{
return new long[] {src.batch, src.channels};
}
Buffer.BlockCopy(array, 0, barracudaArray, offset, res.length * Marshal.SizeOf<float>());
return res;
}
return new long[] {src.batch, src.height, src.width, src.channels};
}
internal static long[] TensorShapeFromBarracuda(TensorShape src)
{
if (src.height == 1 && src.width == 1)
return new long[2] {src.batch, src.channels};
public static TensorProxy TensorProxyFromBarracuda(Tensor src, string nameOverride = null)
{
var shape = TensorShapeFromBarracuda(src.shape);
return new TensorProxy
{
name = nameOverride ?? src.name,
valueType = TensorProxy.TensorType.FloatingPoint,
shape = shape,
data = src
};
}
return new long[4] {src.batch, src.height, src.width, src.channels};
}
/// <summary>
/// Fill a pre-allocated Tensor with random numbers
/// </summary>
/// <param name="tensorProxy">The pre-allocated Tensor to fill</param>
/// <param name="randomNormal">RandomNormal object used to populate tensor</param>
/// <exception cref="NotImplementedException">
/// Throws when trying to fill a Tensor of type other than float
/// </exception>
/// <exception cref="ArgumentNullException">
/// Throws when the Tensor is not allocated
/// </exception>
public static void FillTensorWithRandomNormal(
TensorProxy tensorProxy, RandomNormal randomNormal)
{
if (tensorProxy.DataType != typeof(float))
{
throw new NotImplementedException("Only float data types are currently supported");
}
public static TensorProxy TensorProxyFromBarracuda(Tensor src, string nameOverride = null)
{
var shape = TensorShapeFromBarracuda(src.shape);
return new TensorProxy
{
Name = nameOverride ?? src.name,
ValueType = TensorProxy.TensorType.FloatingPoint,
Shape = shape,
Data = src
};
}
}
if (tensorProxy.data == null)
{
throw new ArgumentNullException();
}
for (var i = 0; i < tensorProxy.data.length; i++)
{
tensorProxy.data[i] = (float) randomNormal.NextDouble();
}
}
}
}

98
UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/Utils/Multinomial.cs


using System;
using Assert = UnityEngine.Assertions.Assert;
using UnityEngine;
namespace MLAgents.InferenceBrain.Utils
namespace MLAgents.InferenceBrain.Utils
/// Multinomial - Draws samples from a multinomial distribution in log space
/// Reference: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/kernels/multinomial_op.cc
/// Multinomial - Draws samples from a multinomial distribution given a (potentially unscaled)
/// cumulative mass function (CMF). This means that the CMF need not "end" with probability
/// mass of 1.0. For instance: [0.1, 0.2, 0.5] is a valid (unscaled). What is important is
/// that it is a cumulative function, not a probability function. In other words,
/// entry[i] = P(x \le i), NOT P(i - 1 \le x \lt i).
/// (\le stands for less than or equal to while \lt is strictly less than).
private readonly System.Random m_random;
private readonly System.Random _random;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="seed">
/// Seed for the random number generator used in the sampling process.
/// </param>
m_random = new System.Random(seed);
_random = new System.Random(seed);
/// Draw samples from a multinomial distribution based on log-probabilities specified in tensor src. The samples
/// will be saved in the dst tensor.
/// Samples from the Multinomial distribution defined by the provided cumulative
/// mass function.
/// <param name="src">2-D tensor with shape batch_size x num_classes</param>
/// <param name="dst">Allocated tensor with size batch_size x num_samples</param>
/// <exception cref="NotImplementedException">Multinomial doesn't support integer tensors</exception>
/// <exception cref="ArgumentException">Issue with tensor shape or type</exception>
/// <exception cref="ArgumentNullException">At least one of the tensors is not allocated</exception>
public void Eval(TensorProxy src, TensorProxy dst)
/// <param name="cmf">
/// Cumulative mass function, which may be unscaled. The entries in this array need
/// to be monotonic (always increasing). If the CMF is scaled, then the last entry in
/// the array will be 1.0.
/// </param>
/// <returns>A sampled index from the CMF ranging from 0 to cmf.Length-1.</returns>
public int Sample(float[] cmf)
if (src.DataType != typeof(float))
{
throw new NotImplementedException("Multinomial does not support integer tensors yet!");
}
if (src.ValueType != dst.ValueType)
{
throw new ArgumentException("Source and destination tensors have different types!");
}
if (src.Data == null || dst.Data == null)
var p = (float) _random.NextDouble() * cmf[cmf.Length - 1];
var cls = 0;
while (cmf[cls] < p)
throw new ArgumentNullException();
++cls;
if (src.Data.batch != dst.Data.batch)
{
throw new ArgumentException("Batch size for input and output data is different!");
}
float[] cdf = new float[src.Data.channels];
for (int batch = 0; batch < src.Data.batch; ++batch)
{
// Find the class maximum
float maxProb = float.NegativeInfinity;
for (int cls = 0; cls < src.Data.channels; ++cls)
{
maxProb = Mathf.Max(src.Data[batch, cls], maxProb);
}
// Sum the log probabilities and compute CDF
float sumProb = 0.0f;
for (int cls = 0; cls < src.Data.channels; ++cls)
{
sumProb += Mathf.Exp(src.Data[batch, cls] - maxProb);
cdf[cls] = sumProb;
}
// Generate the samples
for (int sample = 0; sample < dst.Data.channels; ++sample)
{
float p = (float)m_random.NextDouble() * sumProb;
int cls = 0;
while (cdf[cls] < p)
{
++cls;
}
dst.Data[batch, sample] = cls;
}
}
return cls;
}
}
}

62
UnitySDK/Assets/ML-Agents/Scripts/InferenceBrain/Utils/RandomNormal.cs


using System;
using UnityEngine;
/// RandomNormal - A random number generator that produces normally distributed random numbers using the Marsaglia
/// polar method (https://en.wikipedia.org/wiki/Marsaglia_polar_method)
/// RandomNormal - A random number generator that produces normally distributed random
/// numbers using the Marsaglia polar method:
/// https://en.wikipedia.org/wiki/Marsaglia_polar_method
private readonly double m_mean;
private readonly double m_stddev;
private readonly System.Random m_random;
private readonly double _mean;
private readonly double _stddev;
private readonly Random _random;
m_mean = mean;
m_stddev = stddev;
m_random = new System.Random(seed);
_mean = mean;
_stddev = stddev;
_random = new Random(seed);
private bool m_hasSpare = false;
private double m_spare = 0.0f;
private bool _hasSpare;
private double _spareUnscaled;
/// <summary>
/// Return the next random double number

{
if (m_hasSpare)
if (_hasSpare)
m_hasSpare = false;
return m_spare * m_stddev + m_mean;
_hasSpare = false;
return _spareUnscaled * _stddev + _mean;
u = m_random.NextDouble() * 2.0 - 1.0;
v = m_random.NextDouble() * 2.0 - 1.0;
u = _random.NextDouble() * 2.0 - 1.0;
v = _random.NextDouble() * 2.0 - 1.0;
} while (s >= 1.0 || s == 0.0);
} while (s >= 1.0 || Math.Abs(s) < double.Epsilon);
m_spare = u * s;
m_hasSpare = true;
return v * s * m_stddev + m_mean;
}
_spareUnscaled = u * s;
_hasSpare = true;
/// <summary>
/// Fill a pre-allocated Tensor with random numbers
/// </summary>
/// <param name="t">The pre-allocated Tensor to fill</param>
/// <exception cref="NotImplementedException">Throws when trying to fill a Tensor of type other than float</exception>
/// <exception cref="ArgumentNullException">Throws when the Tensor is not allocated</exception>
public void FillTensor(TensorProxy t)
{
if (t.DataType != typeof(float))
{
throw new NotImplementedException("Random Normal does not support integer tensors yet!");
}
if (t.Data == null)
{
throw new ArgumentNullException();
}
for (int i = 0; i < t.Data.length; i++)
t.Data[i] = (float)NextDouble();
return v * s * _stddev + _mean;
}
}
}

2
UnitySDK/Assets/ML-Agents/Scripts/LearningBrain.cs


var inputs = new Dictionary<string, Tensor>();
foreach (var inp in _inferenceInputs)
{
inputs[inp.Name] = inp.Data;
inputs[inp.name] = inp.data;
}
return inputs;

19
UnitySDK/Assets/ML-Agents/Scripts/Startup.cs


using System;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;

{
void Awake()
{
string sceneName = Environment.GetEnvironmentVariable("SCENE_NAME");
private const string SceneVariableName = "SCENE_NAME";
private void Awake()
{
var sceneName = Environment.GetEnvironmentVariable(SceneVariableName);
throw new ArgumentException("You didn't specified the SCENE_NAME environment variable");
throw new ArgumentException(
$"You didn't specified the {SceneVariableName} environment variable");
throw new ArgumentException("The scene " + sceneName + " doesn't exist within your build. ");
throw new ArgumentException(
$"The scene {sceneName} doesn't exist within your build. ");
}
}

19
UnitySDK/Assets/ML-Agents/Scripts/UnityAgentsException.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System;
/// Contains exceptions specific to ML-Agents.
/// Contains exceptions specific to ML-Agents.
public class UnityAgentsException : System.Exception
public class UnityAgentsException : Exception
{
/// When a UnityAgentsException is called, the timeScale is set to 0.
/// The simulation will end since no steps will be taken.

}
/// A constructor is needed for serialization when an exception propagates
/// from a remoting server to the client.
protected UnityAgentsException(System.Runtime.Serialization.SerializationInfo info,
/// A constructor is needed for serialization when an exception propagates
/// from a remoting server to the client.
protected UnityAgentsException(
System.Runtime.Serialization.SerializationInfo info,
}
}
}

109
UnitySDK/Assets/ML-Agents/Scripts/Utilities.cs


using UnityEngine;
using System.Collections;
using Barracuda;
public class Utilities
public static class Utilities
/// Converts a list of Texture2D into a Tensor.
/// Converts a list of Texture2D into a TensorProxy.
/// <param name="tensorProxy">
/// Tensor proxy to fill with Texture data.
/// </param>
/// <param name="blackAndWhite">
/// If set to <c>true</c> the textures
/// will be converted to grayscale before being stored in the tensor.
/// <param name="tensorProxy">
/// TensorProxy to fill with Texture data.
/// <param name="allocator">Tensor allocator</param>
public static void TextureToTensorProxy(TensorProxy tensorProxy, List<Texture2D> textures, bool blackAndWhite,
ITensorAllocator allocator)
/// <param name="grayScale">
/// If set to <c>true</c> the textures will be converted to grayscale before
/// being stored in the tensor.
/// </param>
public static void TextureToTensorProxy(
List<Texture2D> textures,
TensorProxy tensorProxy,
bool grayScale)
var batchSize = textures.Count;
var numTextures = textures.Count;
var data = tensorProxy.Data;
var data = tensorProxy.data;
for (var b = 0; b < batchSize; b++)
for (var t = 0; t < numTextures; t++)
var cc = textures[b].GetPixels32();
var texturePixels = textures[t].GetPixels32();
var currentPixel = cc[(height - h - 1) * width + w];
if (!blackAndWhite)
var currentPixel = texturePixels[(height - h - 1) * width + w];
if (grayScale)
// For Color32, the r, g and b values are between
// 0 and 255.
data[b, h, w, 0] = currentPixel.r / 255.0f;
data[b, h, w, 1] = currentPixel.g / 255.0f;
data[b, h, w,2] = currentPixel.b / 255.0f;
data[t, h, w, 0] =
(currentPixel.r + currentPixel.g + currentPixel.b) / 3f / 255.0f;
data[b, h, w, 0] = (currentPixel.r + currentPixel.g + currentPixel.b)
/ 3f / 255.0f;
// For Color32, the r, g and b values are between 0 and 255.
data[t, h, w, 0] = currentPixel.r / 255.0f;
data[t, h, w, 1] = currentPixel.g / 255.0f;
data[t, h, w, 2] = currentPixel.b / 255.0f;
/// larger than the input array since it has a padded 0 at the begining.
/// larger than the input array since it has a padded 0 at the beginning.
/// <param name="input">
/// Input array whose elements will be cumulatively added
/// </param>
public static int[] CumSum(int [] array)
public static int[] CumSum(int [] input)
var result = new int[array.Length + 1];
for (var actionIndex = 0; actionIndex < array.Length; actionIndex++)
var result = new int[input.Length + 1];
for (var actionIndex = 0; actionIndex < input.Length; actionIndex++)
runningSum += array[actionIndex];
runningSum += input[actionIndex];
result[actionIndex + 1] = runningSum;
}
return result;

/// Shifts list elements to the left by the specified amount.
/// Shifts list elements to the left by the specified amount (in-place).
/// Target list
/// List whose elements will be shifted
/// <param name="amount">
/// Shift amount
/// <param name="shiftAmount">
/// Amount to shift the elements to the left by
public static void ShiftLeft<T>(List<T> list, int amount)
public static void ShiftLeft<T>(List<T> list, int shiftAmount)
for (var i = amount; i < list.Count; i++)
for (var i = shiftAmount; i < list.Count; i++)
list[i - amount] = list[i];
list[i - shiftAmount] = list[i];
/// Replaces target list elements with source list elements starting at specified position in target list.
/// Replaces target list elements with source list elements starting at specified position
/// in target list.
/// Target list
/// Target list, where the elements are added to
/// Source list
/// Source array, where the elements are copied from
/// Offset in target list
/// Starting position in target list to copy elements to
/// </param>
/// </summary>
public static void ReplaceRange<T>(List<T> dst, List<T> src, int start)

}
}
/// Adds elements to list without extra temp allocations (assuming it fits pre-allocated capacity of the list).
/// Regular List<T>.AddRange() unfortunately allocates temp list to add items.
/// Adds elements to list without extra temp allocations (assuming it fits pre-allocated
/// capacity of the list). The built-in List/<T/>.AddRange() unfortunately allocates
/// a temporary list to add items (even if the original array has sufficient capacity):
/// Note: this implementation might be slow with large numbers of elements in the source array.
/// Note: this implementation might be slow with a large source array.
/// Target list
/// Target list, where the elements are added to
/// Source array
/// Source array, where the elements are copied from
// ReSharper disable once ParameterTypeCanBeEnumerable.Global
var offset = dst.Count;
for (var i = 0; i < src.Length; i++)
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var item in src)
dst.Add(src[i]);
dst.Add(item);
}
}
}

194
UnitySDK/Assets/ML-Agents/Editor/Tests/DiscreteActionOutputApplierTest.cs


using System;
using Barracuda;
using NUnit.Framework;
using UnityEngine;
using MLAgents.InferenceBrain;
using MLAgents.InferenceBrain.Utils;
namespace MLAgents.Tests
{
public class DiscreteActionOutputApplierTest
{
[Test]
public void TestEvalP()
{
var m = new Multinomial(2018);
var src = new TensorProxy
{
data = new Tensor(1, 3, new[] {0.1f, 0.2f, 0.7f}),
valueType = TensorProxy.TensorType.FloatingPoint
};
var dst = new TensorProxy
{
data = new Tensor(1, 3),
valueType = TensorProxy.TensorType.FloatingPoint
};
DiscreteActionOutputApplier.Eval(src, dst, m);
float[] reference = {2, 2, 1};
for (var i = 0; i < dst.data.length; i++)
{
Assert.AreEqual(reference[i], dst.data[i]);
++i;
}
}
[Test]
public void TestEvalLogits()
{
var m = new Multinomial(2018);
var src = new TensorProxy
{
data = new Tensor(
1,
3,
new[] { Mathf.Log(0.1f) - 50, Mathf.Log(0.2f) - 50, Mathf.Log(0.7f) - 50 }),
valueType = TensorProxy.TensorType.FloatingPoint
};
var dst = new TensorProxy
{
data = new Tensor(1, 3),
valueType = TensorProxy.TensorType.FloatingPoint
};
DiscreteActionOutputApplier.Eval(src, dst, m);
float[] reference = {2, 2, 2};
for (var i = 0; i < dst.data.length; i++)
{
Assert.AreEqual(reference[i], dst.data[i]);
++i;
}
}
[Test]
public void TestEvalBatching()
{
var m = new Multinomial(2018);
var src = new TensorProxy
{
data = new Tensor(2, 3, new []
{
Mathf.Log(0.1f) - 50, Mathf.Log(0.2f) - 50, Mathf.Log(0.7f) - 50,
Mathf.Log(0.3f) - 25, Mathf.Log(0.4f) - 25, Mathf.Log(0.3f) - 25
}),
valueType = TensorProxy.TensorType.FloatingPoint
};
var dst = new TensorProxy
{
data = new Tensor(2, 3),
valueType = TensorProxy.TensorType.FloatingPoint
};
DiscreteActionOutputApplier.Eval(src, dst, m);
float[] reference = {2, 2, 2, 0, 1, 0};
for (var i = 0; i < dst.data.length; i++)
{
Assert.AreEqual(reference[i], dst.data[i]);
++i;
}
}
[Test]
public void TestSrcInt()
{
var m = new Multinomial(2018);
var src = new TensorProxy
{
valueType = TensorProxy.TensorType.Integer
};
Assert.Throws<NotImplementedException>(
() => DiscreteActionOutputApplier.Eval(src, null, m));
}
[Test]
public void TestDstInt()
{
var m = new Multinomial(2018);
var src = new TensorProxy
{
valueType = TensorProxy.TensorType.FloatingPoint
};
var dst = new TensorProxy
{
valueType = TensorProxy.TensorType.Integer
};
Assert.Throws<ArgumentException>(
() => DiscreteActionOutputApplier.Eval(src, dst, m));
}
[Test]
public void TestSrcDataNull()
{
var m = new Multinomial(2018);
var src = new TensorProxy
{
valueType = TensorProxy.TensorType.FloatingPoint
};
var dst = new TensorProxy
{
valueType = TensorProxy.TensorType.FloatingPoint
};
Assert.Throws<ArgumentNullException>(
() => DiscreteActionOutputApplier.Eval(src, dst, m));
}
[Test]
public void TestDstDataNull()
{
var m = new Multinomial(2018);
var src = new TensorProxy
{
valueType = TensorProxy.TensorType.FloatingPoint,
data = new Tensor(0,1)
};
var dst = new TensorProxy
{
valueType = TensorProxy.TensorType.FloatingPoint
};
Assert.Throws<ArgumentNullException>(
() => DiscreteActionOutputApplier.Eval(src, dst, m));
}
[Test]
public void TestUnequalBatchSize()
{
var m = new Multinomial(2018);
var src = new TensorProxy
{
valueType = TensorProxy.TensorType.FloatingPoint,
data = new Tensor(1, 1)
};
var dst = new TensorProxy
{
valueType = TensorProxy.TensorType.FloatingPoint,
data = new Tensor(2, 1)
};
Assert.Throws<ArgumentException>(
() => DiscreteActionOutputApplier.Eval(src, dst, m));
}
}
}

11
UnitySDK/Assets/ML-Agents/Editor/Tests/DiscreteActionOutputApplierTest.cs.meta


fileFormatVersion: 2
guid: aa4c4ceac5f246a0b341958724ecd752
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

83
UnitySDK/Assets/ML-Agents/Editor/Tests/TensorUtilsTest.cs


using System;
using Barracuda;
using MLAgents.InferenceBrain;
using MLAgents.InferenceBrain.Utils;
using NUnit.Framework;
namespace MLAgents.Tests
{
public class TensorUtilsTest
{
[Test]
public void RandomNormalTestTensorInt()
{
var rn = new RandomNormal(1982);
var t = new TensorProxy
{
valueType = TensorProxy.TensorType.Integer
};
Assert.Throws<NotImplementedException>(
() => TensorUtils.FillTensorWithRandomNormal(t, rn));
}
[Test]
public void RandomNormalTestDataNull()
{
var rn = new RandomNormal(1982);
var t = new TensorProxy
{
valueType = TensorProxy.TensorType.FloatingPoint
};
Assert.Throws<ArgumentNullException>(
() => TensorUtils.FillTensorWithRandomNormal(t, rn));
}
[Test]
public void RandomNormalTestTensor()
{
var rn = new RandomNormal(1982);
var t = new TensorProxy
{
valueType = TensorProxy.TensorType.FloatingPoint,
data = new Tensor(1, 3, 4, 2)
};
TensorUtils.FillTensorWithRandomNormal(t, rn);
var reference = new []
{
-0.4315872f,
-1.11074f,
0.3414804f,
-1.130287f,
0.1413168f,
-0.5105762f,
-0.3027347f,
-0.2645015f,
1.225356f,
-0.02921959f,
0.3716498f,
-1.092338f,
0.9561074f,
-0.5018106f,
1.167787f,
-0.7763879f,
-0.07491868f,
0.5396146f,
-0.1377991f,
0.3331701f,
0.06144788f,
0.9520947f,
1.088157f,
-1.177194f,
};
for (var i = 0; i < t.data.length; i++)
{
Assert.AreEqual(t.data[i], reference[i], 0.0001);
}
}
}
}

11
UnitySDK/Assets/ML-Agents/Editor/Tests/TensorUtilsTest.cs.meta


fileFormatVersion: 2
guid: 0a700a7c6187a433ca44d60d243bb0cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

6
UnitySDK/UnitySDK.sln.DotSettings


<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Logits/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Marsaglia/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=multinomial/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Probs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=stddev/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
正在加载...
取消
保存