diff --git a/Project/ProjectSettings/ProjectVersion.txt b/Project/ProjectSettings/ProjectVersion.txt index ef4a753e2f..b71c05700f 100644 --- a/Project/ProjectSettings/ProjectVersion.txt +++ b/Project/ProjectSettings/ProjectVersion.txt @@ -1 +1 @@ -m_EditorVersion: 2018.4.20f1 +m_EditorVersion: 2018.4.24f1 diff --git a/com.unity.ml-agents/Editor/BehaviorParametersEditor.cs b/com.unity.ml-agents/Editor/BehaviorParametersEditor.cs index c47df58ba5..c178bc668f 100644 --- a/com.unity.ml-agents/Editor/BehaviorParametersEditor.cs +++ b/com.unity.ml-agents/Editor/BehaviorParametersEditor.cs @@ -104,15 +104,10 @@ void DisplayFailedModelChecks() // Grab the sensor components, since we need them to determine the observation sizes. // TODO make these methods of BehaviorParameters - SensorComponent[] sensorComponents; - if (behaviorParameters.UseChildSensors) - { - sensorComponents = behaviorParameters.GetComponentsInChildren(); - } - else - { - sensorComponents = behaviorParameters.GetComponents(); - } + var agent = behaviorParameters.gameObject.GetComponent(); + agent.sensors = new List(); + agent.InitializeSensors(); + var sensors = agent.sensors.ToArray(); ActuatorComponent[] actuatorComponents; if (behaviorParameters.UseChildActuators) @@ -127,7 +122,6 @@ void DisplayFailedModelChecks() // Get the total size of the sensors generated by ObservableAttributes. // If there are any errors (e.g. unsupported type, write-only properties), display them too. int observableAttributeSensorTotalSize = 0; - var agent = behaviorParameters.GetComponent(); if (agent != null && behaviorParameters.ObservableAttributeHandling != ObservableAttributeOptions.Ignore) { List observableErrors = new List(); @@ -146,7 +140,7 @@ void DisplayFailedModelChecks() if (brainParameters != null) { var failedChecks = Inference.BarracudaModelParamLoader.CheckModel( - barracudaModel, brainParameters, sensorComponents, actuatorComponents, + barracudaModel, brainParameters, sensors, actuatorComponents, observableAttributeSensorTotalSize, behaviorParameters.BehaviorType ); foreach (var check in failedChecks) diff --git a/com.unity.ml-agents/Runtime/Agent.cs b/com.unity.ml-agents/Runtime/Agent.cs index e1a4191b84..4f37506259 100644 --- a/com.unity.ml-agents/Runtime/Agent.cs +++ b/com.unity.ml-agents/Runtime/Agent.cs @@ -922,6 +922,10 @@ public virtual void Heuristic(in ActionBuffers actionsOut) /// internal void InitializeSensors() { + if (m_PolicyFactory == null) + { + m_PolicyFactory = GetComponent(); + } if (m_PolicyFactory.ObservableAttributeHandling != ObservableAttributeOptions.Ignore) { var excludeInherited = diff --git a/com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs b/com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs index 3c93efcf98..926c830c8d 100644 --- a/com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs +++ b/com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs @@ -26,13 +26,13 @@ internal class BarracudaModelParamLoader /// /// The BrainParameters that are used verify the compatibility with the InferenceEngine /// - /// Attached sensor components + /// Attached sensor components /// Attached actuator components /// Sum of the sizes of all ObservableAttributes. /// BehaviorType or the Agent to check. /// The list the error messages of the checks that failed public static IEnumerable CheckModel(Model model, BrainParameters brainParameters, - SensorComponent[] sensorComponents, ActuatorComponent[] actuatorComponents, + ISensor[] sensors, ActuatorComponent[] actuatorComponents, int observableAttributeTotalSize = 0, BehaviorType behaviorType = BehaviorType.Default) { @@ -82,13 +82,13 @@ public static IEnumerable CheckModel(Model model, BrainParameters brainP } failedModelChecks.AddRange( - CheckInputTensorPresence(model, brainParameters, memorySize, sensorComponents) + CheckInputTensorPresence(model, brainParameters, memorySize, sensors) ); failedModelChecks.AddRange( CheckOutputTensorPresence(model, memorySize) ); failedModelChecks.AddRange( - CheckInputTensorShape(model, brainParameters, sensorComponents, observableAttributeTotalSize) + CheckInputTensorShape(model, brainParameters, sensors, observableAttributeTotalSize) ); failedModelChecks.AddRange( CheckOutputTensorShape(model, brainParameters, actuatorComponents) @@ -109,7 +109,7 @@ public static IEnumerable CheckModel(Model model, BrainParameters brainP /// /// The memory size that the model is expecting. /// - /// Array of attached sensor components + /// Array of attached sensor components /// /// A IEnumerable of string corresponding to the failed input presence checks. /// @@ -117,7 +117,7 @@ static IEnumerable CheckInputTensorPresence( Model model, BrainParameters brainParameters, int memory, - SensorComponent[] sensorComponents + ISensor[] sensors ) { var failedModelChecks = new List(); @@ -135,10 +135,9 @@ SensorComponent[] sensorComponents // If there are not enough Visual Observation Input compared to what the // sensors expect. var visObsIndex = 0; - var varLenIndex = 0; - for (var sensorIndex = 0; sensorIndex < sensorComponents.Length; sensorIndex++) + for (var sensorIndex = 0; sensorIndex < sensors.Length; sensorIndex++) { - var sensor = sensorComponents[sensorIndex]; + var sensor = sensors[sensorIndex]; if (sensor.GetObservationShape().Length == 3) { if (!tensorsNames.Contains( @@ -153,12 +152,11 @@ SensorComponent[] sensorComponents if (sensor.GetObservationShape().Length == 2) { if (!tensorsNames.Contains( - TensorNames.ObservationPlaceholderPrefix + varLenIndex)) + TensorNames.ObservationPlaceholderPrefix + sensorIndex)) { failedModelChecks.Add( "The model does not contain an Observation Placeholder Input " + - $"for sensor component {varLenIndex} ({sensor.GetType().Name})."); - varLenIndex++; + $"for sensor component {sensorIndex} ({sensor.GetType().Name})."); } } @@ -231,15 +229,15 @@ static IEnumerable CheckOutputTensorPresence(Model model, int memory) /// Checks that the shape of the visual observation input placeholder is the same as the corresponding sensor. /// /// The tensor that is expected by the model - /// The sensor that produces the visual observation. + /// The sensor that produces the visual observation. /// /// If the Check failed, returns a string containing information about why the /// check failed. If the check passed, returns null. /// static string CheckVisualObsShape( - TensorProxy tensorProxy, SensorComponent sensorComponent) + TensorProxy tensorProxy, ISensor sensor) { - var shape = sensorComponent.GetObservationShape(); + var shape = sensor.GetObservationShape(); var heightBp = shape[0]; var widthBp = shape[1]; var pixelBp = shape[2]; @@ -259,15 +257,15 @@ static string CheckVisualObsShape( /// Checks that the shape of the rank 2 observation input placeholder is the same as the corresponding sensor. /// /// The tensor that is expected by the model - /// The sensor that produces the visual observation. + /// The sensor that produces the visual observation. /// /// If the Check failed, returns a string containing information about why the /// check failed. If the check passed, returns null. /// static string CheckRankTwoObsShape( - TensorProxy tensorProxy, SensorComponent sensorComponent) + TensorProxy tensorProxy, ISensor sensor) { - var shape = sensorComponent.GetObservationShape(); + var shape = sensor.GetObservationShape(); var dim1Bp = shape[0]; var dim2Bp = shape[1]; var dim1T = tensorProxy.Channels; @@ -291,16 +289,16 @@ static string CheckRankTwoObsShape( /// /// The BrainParameters that are used verify the compatibility with the InferenceEngine /// - /// Attached sensors + /// Attached sensors /// Sum of the sizes of all ObservableAttributes. /// The list the error messages of the checks that failed static IEnumerable CheckInputTensorShape( - Model model, BrainParameters brainParameters, SensorComponent[] sensorComponents, + Model model, BrainParameters brainParameters, ISensor[] sensors, int observableAttributeTotalSize) { var failedModelChecks = new List(); var tensorTester = - new Dictionary>() + new Dictionary>() { {TensorNames.VectorObservationPlaceholder, CheckVectorObsShape}, {TensorNames.PreviousActionPlaceholder, CheckPreviousActionShape}, @@ -316,22 +314,20 @@ static IEnumerable CheckInputTensorShape( } var visObsIndex = 0; - var varLenIndex = 0; - for (var sensorIndex = 0; sensorIndex < sensorComponents.Length; sensorIndex++) + for (var sensorIndex = 0; sensorIndex < sensors.Length; sensorIndex++) { - var sensorComponent = sensorComponents[sensorIndex]; - if (sensorComponent.GetObservationShape().Length == 3) + var sens = sensors[sensorIndex]; + if (sens.GetObservationShape().Length == 3) { tensorTester[TensorNames.VisualObservationPlaceholderPrefix + visObsIndex] = - (bp, tensor, scs, i) => CheckVisualObsShape(tensor, sensorComponent); + (bp, tensor, scs, i) => CheckVisualObsShape(tensor, sens); visObsIndex++; } - if (sensorComponent.GetObservationShape().Length == 2) + if (sens.GetObservationShape().Length == 2) { - tensorTester[TensorNames.ObservationPlaceholderPrefix + varLenIndex] = - (bp, tensor, scs, i) => CheckRankTwoObsShape(tensor, sensorComponent); - varLenIndex++; + tensorTester[TensorNames.ObservationPlaceholderPrefix + sensorIndex] = + (bp, tensor, scs, i) => CheckRankTwoObsShape(tensor, sens); } } @@ -349,7 +345,7 @@ static IEnumerable CheckInputTensorShape( else { var tester = tensorTester[tensor.name]; - var error = tester.Invoke(brainParameters, tensor, sensorComponents, observableAttributeTotalSize); + var error = tester.Invoke(brainParameters, tensor, sensors, observableAttributeTotalSize); if (error != null) { failedModelChecks.Add(error); @@ -367,14 +363,14 @@ static IEnumerable CheckInputTensorShape( /// The BrainParameters that are used verify the compatibility with the InferenceEngine /// /// The tensor that is expected by the model - /// Array of attached sensor components + /// Array of attached sensor components /// Sum of the sizes of all ObservableAttributes. /// /// If the Check failed, returns a string containing information about why the /// check failed. If the check passed, returns null. /// static string CheckVectorObsShape( - BrainParameters brainParameters, TensorProxy tensorProxy, SensorComponent[] sensorComponents, + BrainParameters brainParameters, TensorProxy tensorProxy, ISensor[] sensors, int observableAttributeTotalSize) { var vecObsSizeBp = brainParameters.VectorObservationSize; @@ -382,20 +378,18 @@ static string CheckVectorObsShape( var totalVecObsSizeT = tensorProxy.shape[tensorProxy.shape.Length - 1]; var totalVectorSensorSize = 0; - foreach (var sensorComp in sensorComponents) + foreach (var sens in sensors) { - if (sensorComp.GetObservationShape().Length == 1) + if ((sens.GetObservationShape().Length == 1)) { - totalVectorSensorSize += sensorComp.GetObservationShape()[0]; + totalVectorSensorSize += sens.GetObservationShape()[0]; } } - totalVectorSensorSize += observableAttributeTotalSize; - - if (vecObsSizeBp * numStackedVector + totalVectorSensorSize != totalVecObsSizeT) + if (totalVectorSensorSize != totalVecObsSizeT) { var sensorSizes = ""; - foreach (var sensorComp in sensorComponents) + foreach (var sensorComp in sensors) { if (sensorComp.GetObservationShape().Length == 1) { @@ -416,7 +410,7 @@ static string CheckVectorObsShape( $"but received: \n" + $"Vector observations: {vecObsSizeBp} x {numStackedVector}\n" + $"Total [Observable] attributes: {observableAttributeTotalSize}\n" + - $"SensorComponent sizes: {sensorSizes}."; + $"Sensor sizes: {sensorSizes}."; } return null; } @@ -429,13 +423,13 @@ static string CheckVectorObsShape( /// The BrainParameters that are used verify the compatibility with the InferenceEngine /// /// The tensor that is expected by the model - /// Array of attached sensor components (unused). + /// Array of attached sensor components (unused). /// Sum of the sizes of all ObservableAttributes (unused). /// If the Check failed, returns a string containing information about why the /// check failed. If the check passed, returns null. static string CheckPreviousActionShape( BrainParameters brainParameters, TensorProxy tensorProxy, - SensorComponent[] sensorComponents, int observableAttributeTotalSize) + ISensor[] sensors, int observableAttributeTotalSize) { var numberActionsBp = brainParameters.ActionSpec.NumDiscreteActions; var numberActionsT = tensorProxy.shape[tensorProxy.shape.Length - 1]; diff --git a/com.unity.ml-agents/Runtime/Inference/ModelRunner.cs b/com.unity.ml-agents/Runtime/Inference/ModelRunner.cs index 7143b273cc..f9faa08c42 100644 --- a/com.unity.ml-agents/Runtime/Inference/ModelRunner.cs +++ b/com.unity.ml-agents/Runtime/Inference/ModelRunner.cs @@ -36,7 +36,7 @@ internal class ModelRunner SensorShapeValidator m_SensorShapeValidator = new SensorShapeValidator(); - bool m_VisualObservationsInitialized; + bool m_ObservationsInitialized; /// /// Initializes the Brain with the Model that it will use when selecting actions for @@ -161,13 +161,13 @@ public void DecideBatch() { return; } - if (!m_VisualObservationsInitialized) + if (!m_ObservationsInitialized) { // Just grab the first agent in the collection (any will suffice, really). // We check for an empty Collection above, so this will always return successfully. var firstInfo = m_Infos[0]; m_TensorGenerator.InitializeObservations(firstInfo.sensors, m_TensorAllocator); - m_VisualObservationsInitialized = true; + m_ObservationsInitialized = true; } Profiler.BeginSample("ModelRunner.DecideAction"); diff --git a/com.unity.ml-agents/Runtime/Sensors/BufferSensor.cs b/com.unity.ml-agents/Runtime/Sensors/BufferSensor.cs index 8cd4832a70..4751d621bc 100644 --- a/com.unity.ml-agents/Runtime/Sensors/BufferSensor.cs +++ b/com.unity.ml-agents/Runtime/Sensors/BufferSensor.cs @@ -2,12 +2,19 @@ namespace Unity.MLAgents.Sensors { + /// + /// A Sensor that allows to observe a variable number of entities. + /// public class BufferSensor : ISensor, IDimensionPropertiesSensor, IBuiltInSensor { private int m_MaxNumObs; private int m_ObsSize; float[] m_ObservationBuffer; int m_CurrentNumObservables; + static DimensionProperty[] m_DimensionProperties = new DimensionProperty[]{ + DimensionProperty.VariableSize, + DimensionProperty.None + }; public BufferSensor(int maxNumberObs, int obsSize) { m_MaxNumObs = maxNumberObs; @@ -25,10 +32,7 @@ public int[] GetObservationShape() /// public DimensionProperty[] GetDimensionProperties() { - return new DimensionProperty[]{ - DimensionProperty.VariableSize, - DimensionProperty.None - }; + return m_DimensionProperties; } /// @@ -40,6 +44,13 @@ public DimensionProperty[] GetDimensionProperties() /// The float array observation public void AppendObservation(float[] obs) { + if (obs.Length != m_ObsSize) + { + throw new UnityAgentsException( + "The BufferSensor was expecting an observation of size " + + $"{m_ObsSize} but received {obs.Length} observations instead." + ); + } if (m_CurrentNumObservables >= m_MaxNumObs) { return; diff --git a/com.unity.ml-agents/Runtime/Sensors/BufferSensorComponent.cs b/com.unity.ml-agents/Runtime/Sensors/BufferSensorComponent.cs index a8f18233d0..f294e572ff 100644 --- a/com.unity.ml-agents/Runtime/Sensors/BufferSensorComponent.cs +++ b/com.unity.ml-agents/Runtime/Sensors/BufferSensorComponent.cs @@ -4,13 +4,23 @@ namespace Unity.MLAgents.Sensors { /// - /// A component for BufferSensor. + /// A SensorComponent that creates a . /// [AddComponentMenu("ML Agents/Buffer Sensor", (int)MenuGroup.Sensors)] public class BufferSensorComponent : SensorComponent { + /// + /// This is how many floats each entities will be represented with. This number + /// is fixed and all entities must have the same representation. + /// public int ObservableSize; + + /// + /// This is the maximum number of entities the `BufferSensor` will be able to + /// collect. + /// public int MaxNumObservables; + private BufferSensor m_Sensor; /// diff --git a/com.unity.ml-agents/Runtime/Sensors/CameraSensor.cs b/com.unity.ml-agents/Runtime/Sensors/CameraSensor.cs index 4458c32b06..2a289faef5 100644 --- a/com.unity.ml-agents/Runtime/Sensors/CameraSensor.cs +++ b/com.unity.ml-agents/Runtime/Sensors/CameraSensor.cs @@ -15,6 +15,10 @@ public class CameraSensor : ISensor, IBuiltInSensor, IDimensionPropertiesSensor string m_Name; int[] m_Shape; SensorCompressionType m_CompressionType; + static DimensionProperty[] m_DimensionProperties = new DimensionProperty[] { + DimensionProperty.TranslationalEquivariance, + DimensionProperty.TranslationalEquivariance, + DimensionProperty.None }; /// /// The Camera used for rendering the sensor observations. @@ -83,7 +87,7 @@ public int[] GetObservationShape() /// public DimensionProperty[] GetDimensionProperties() { - return new DimensionProperty[] { DimensionProperty.TranslationalEquivariance, DimensionProperty.TranslationalEquivariance, DimensionProperty.None }; + return m_DimensionProperties; } /// diff --git a/com.unity.ml-agents/Tests/Editor/ParameterLoaderTest.cs b/com.unity.ml-agents/Tests/Editor/ParameterLoaderTest.cs index 1be7fad172..7c1a3cca20 100644 --- a/com.unity.ml-agents/Tests/Editor/ParameterLoaderTest.cs +++ b/com.unity.ml-agents/Tests/Editor/ParameterLoaderTest.cs @@ -238,7 +238,7 @@ public void TestCheckModelValidContinuous(bool useDeprecatedNNModel) var errors = BarracudaModelParamLoader.CheckModel( model, validBrainParameters, - new SensorComponent[] { sensor_21_20_3, sensor_20_22_3 }, new ActuatorComponent[0] + new ISensor[] { new VectorSensor(8), sensor_21_20_3.CreateSensor(), sensor_20_22_3.CreateSensor() }, new ActuatorComponent[0] ); Assert.AreEqual(0, errors.Count()); // There should not be any errors } @@ -252,7 +252,7 @@ public void TestCheckModelValidDiscrete(bool useDeprecatedNNModel) var errors = BarracudaModelParamLoader.CheckModel( model, validBrainParameters, - new SensorComponent[] { sensor_21_20_3 }, new ActuatorComponent[0] + new ISensor[] { sensor_21_20_3.CreateSensor() }, new ActuatorComponent[0] ); Assert.AreEqual(0, errors.Count()); // There should not be any errors } @@ -265,7 +265,7 @@ public void TestCheckModelValidHybrid() var errors = BarracudaModelParamLoader.CheckModel( model, validBrainParameters, - new SensorComponent[] { }, new ActuatorComponent[0] + new ISensor[] { new VectorSensor(validBrainParameters.VectorObservationSize) }, new ActuatorComponent[0] ); Assert.AreEqual(0, errors.Count()); // There should not be any errors } @@ -280,7 +280,7 @@ public void TestCheckModelThrowsVectorObservationContinuous(bool useDeprecatedNN brainParameters.VectorObservationSize = 9; // Invalid observation var errors = BarracudaModelParamLoader.CheckModel( model, brainParameters, - new SensorComponent[] { sensor_21_20_3, sensor_20_22_3 }, new ActuatorComponent[0] + new ISensor[] { sensor_21_20_3.CreateSensor(), sensor_20_22_3.CreateSensor() }, new ActuatorComponent[0] ); Assert.Greater(errors.Count(), 0); @@ -288,7 +288,7 @@ public void TestCheckModelThrowsVectorObservationContinuous(bool useDeprecatedNN brainParameters.NumStackedVectorObservations = 2;// Invalid stacking errors = BarracudaModelParamLoader.CheckModel( model, brainParameters, - new SensorComponent[] { sensor_21_20_3, sensor_20_22_3 }, new ActuatorComponent[0] + new ISensor[] { sensor_21_20_3.CreateSensor(), sensor_20_22_3.CreateSensor() }, new ActuatorComponent[0] ); Assert.Greater(errors.Count(), 0); } @@ -301,7 +301,7 @@ public void TestCheckModelThrowsVectorObservationDiscrete(bool useDeprecatedNNMo var brainParameters = GetDiscrete1vis0vec_2_3action_recurrModelBrainParameters(); brainParameters.VectorObservationSize = 1; // Invalid observation - var errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new SensorComponent[] { sensor_21_20_3 }, new ActuatorComponent[0]); + var errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new ISensor[] { sensor_21_20_3.CreateSensor() }, new ActuatorComponent[0]); Assert.Greater(errors.Count(), 0); } @@ -314,7 +314,7 @@ public void TestCheckModelThrowsVectorObservationHybrid() brainParameters.VectorObservationSize = 9; // Invalid observation var errors = BarracudaModelParamLoader.CheckModel( model, brainParameters, - new SensorComponent[] { }, new ActuatorComponent[0] + new ISensor[] { }, new ActuatorComponent[0] ); Assert.Greater(errors.Count(), 0); @@ -322,7 +322,7 @@ public void TestCheckModelThrowsVectorObservationHybrid() brainParameters.NumStackedVectorObservations = 2;// Invalid stacking errors = BarracudaModelParamLoader.CheckModel( model, brainParameters, - new SensorComponent[] { }, new ActuatorComponent[0] + new ISensor[] { }, new ActuatorComponent[0] ); Assert.Greater(errors.Count(), 0); } @@ -335,12 +335,12 @@ public void TestCheckModelThrowsActionContinuous(bool useDeprecatedNNModel) var brainParameters = GetContinuous2vis8vec2actionBrainParameters(); brainParameters.ActionSpec = ActionSpec.MakeContinuous(3); // Invalid action - var errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new SensorComponent[] { sensor_21_20_3, sensor_20_22_3 }, new ActuatorComponent[0]); + var errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new ISensor[] { sensor_21_20_3.CreateSensor(), sensor_20_22_3.CreateSensor() }, new ActuatorComponent[0]); Assert.Greater(errors.Count(), 0); brainParameters = GetContinuous2vis8vec2actionBrainParameters(); brainParameters.ActionSpec = ActionSpec.MakeDiscrete(3); // Invalid SpaceType - errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new SensorComponent[] { sensor_21_20_3, sensor_20_22_3 }, new ActuatorComponent[0]); + errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new ISensor[] { sensor_21_20_3.CreateSensor(), sensor_20_22_3.CreateSensor() }, new ActuatorComponent[0]); Assert.Greater(errors.Count(), 0); } @@ -352,12 +352,12 @@ public void TestCheckModelThrowsActionDiscrete(bool useDeprecatedNNModel) var brainParameters = GetDiscrete1vis0vec_2_3action_recurrModelBrainParameters(); brainParameters.ActionSpec = ActionSpec.MakeDiscrete(3, 3); // Invalid action - var errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new SensorComponent[] { sensor_21_20_3 }, new ActuatorComponent[0]); + var errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new ISensor[] { sensor_21_20_3.CreateSensor() }, new ActuatorComponent[0]); Assert.Greater(errors.Count(), 0); brainParameters = GetContinuous2vis8vec2actionBrainParameters(); brainParameters.ActionSpec = ActionSpec.MakeContinuous(2); // Invalid SpaceType - errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new SensorComponent[] { sensor_21_20_3 }, new ActuatorComponent[0]); + errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new ISensor[] { sensor_21_20_3.CreateSensor() }, new ActuatorComponent[0]); Assert.Greater(errors.Count(), 0); } @@ -368,12 +368,12 @@ public void TestCheckModelThrowsActionHybrid() var brainParameters = GetHybridBrainParameters(); brainParameters.ActionSpec = new ActionSpec(3, new[] { 3 }); // Invalid discrete action size - var errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new SensorComponent[] { sensor_21_20_3, sensor_20_22_3 }, new ActuatorComponent[0]); + var errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new ISensor[] { sensor_21_20_3.CreateSensor(), sensor_20_22_3.CreateSensor() }, new ActuatorComponent[0]); Assert.Greater(errors.Count(), 0); brainParameters = GetContinuous2vis8vec2actionBrainParameters(); brainParameters.ActionSpec = ActionSpec.MakeDiscrete(2); // Missing continuous action - errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new SensorComponent[] { sensor_21_20_3, sensor_20_22_3 }, new ActuatorComponent[0]); + errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new ISensor[] { sensor_21_20_3.CreateSensor(), sensor_20_22_3.CreateSensor() }, new ActuatorComponent[0]); Assert.Greater(errors.Count(), 0); } @@ -381,7 +381,7 @@ public void TestCheckModelThrowsActionHybrid() public void TestCheckModelThrowsNoModel() { var brainParameters = GetContinuous2vis8vec2actionBrainParameters(); - var errors = BarracudaModelParamLoader.CheckModel(null, brainParameters, new SensorComponent[] { sensor_21_20_3, sensor_20_22_3 }, new ActuatorComponent[0]); + var errors = BarracudaModelParamLoader.CheckModel(null, brainParameters, new ISensor[] { sensor_21_20_3.CreateSensor(), sensor_20_22_3.CreateSensor() }, new ActuatorComponent[0]); Assert.Greater(errors.Count(), 0); } } diff --git a/config/ppo/Sorter_curriculum.yaml b/config/ppo/Sorter_curriculum.yaml index 102b475bd6..538dd1a1e0 100644 --- a/config/ppo/Sorter_curriculum.yaml +++ b/config/ppo/Sorter_curriculum.yaml @@ -35,7 +35,7 @@ environment_parameters: min_lesson_length: 100 threshold: 0.05 value: 2.0 - - name: Lesson1 # The '-' is important as this is a list + - name: Lesson1 completion_criteria: measure: progress behavior: Sorter @@ -43,7 +43,7 @@ environment_parameters: min_lesson_length: 100 threshold: 0.1 value: 4.0 - - name: Lesson2 # This is the start of the second lesson + - name: Lesson2 completion_criteria: measure: progress behavior: Sorter @@ -59,7 +59,7 @@ environment_parameters: min_lesson_length: 100 threshold: 0.2 value: 8.0 - - name: Lesson4 # The '-' is important as this is a list + - name: Lesson4 completion_criteria: measure: progress behavior: Sorter @@ -67,7 +67,7 @@ environment_parameters: min_lesson_length: 100 threshold: 0.25 value: 10.0 - - name: Lesson5 # This is the start of the second lesson + - name: Lesson5 completion_criteria: measure: progress behavior: Sorter @@ -83,7 +83,7 @@ environment_parameters: min_lesson_length: 100 threshold: 0.35 value: 14.0 - - name: Lesson7 # This is the start of the second lesson + - name: Lesson7 completion_criteria: measure: progress behavior: Sorter diff --git a/docs/Learning-Environment-Design-Agents.md b/docs/Learning-Environment-Design-Agents.md index c4e59b2e35..14ed068c86 100644 --- a/docs/Learning-Environment-Design-Agents.md +++ b/docs/Learning-Environment-Design-Agents.md @@ -511,22 +511,28 @@ setting the State Size. ### Variable Length Observations -It is possible for agents to collect observations from a varying number of GameObjects by using a `BufferSensor`. +It is possible for agents to collect observations from a varying number of +GameObjects by using a `BufferSensor`. You can add a `BufferSensor` to your Agent by adding a `BufferSensorComponent` to its GameObject. The `BufferSensor` can be useful in situations in which the Agent must pay -attention to a varying number of entities. On the trainer side, the `BufferSensor` +attention to a varying number of entities (for example, a varying number of +tiles in the [Sorter environment](Learning-Environment-Examples.md#sorter)). +On the trainer side, the `BufferSensor` is processed using an attention module. More information about attention mechanisms can be found [here](https://arxiv.org/abs/1706.03762). Training or doing inference with variable length observations can be slower than using -a flat vector observation. However, attention mechanisms enable solving problems that require comparative reasoning between entities in a scene -such as our [Sorter environmentt](Learning-Environment-Examples.md#sorter). +a flat vector observation. However, attention mechanisms enable solving +problems that require comparative reasoning between entities in a scene +such as our [Sorter environment](Learning-Environment-Examples.md#sorter). Note that even though the `BufferSensor` can process a variable number of entities, you still need to define a maximum number of entities. This is because our network architecture requires to know what the shape of the observations will be. If fewer entities are observed than the maximum, the observation will be padded with zeros and the trainer will ignore -the padded observations. +the padded observations. Note that attention layers are invariant to +the order of the entities, so there is no need to properly "order" the +entities before feeding them into the `BufferSensor`. The `BufferSensor` constructor and Editor inspector have two arguments: - `Observation Size` : This is how many floats each entities will be