Reinforcement Learning
ml-agents
TensorBoard
ONNX
Pyramids
deep-reinforcement-learning
ML-Agents-Pyramids
Instructions to use AnnaMats/ppo-Pyramids-Training with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- ml-agents
How to use AnnaMats/ppo-Pyramids-Training with ml-agents:
mlagents-load-from-hf --repo-id="AnnaMats/ppo-Pyramids-Training" --local-dir="./downloads"
- Notebooks
- Google Colab
- Kaggle
Download com.unity.ml-agents/Runtime/Sensors/Reflection/ObservableAttribute.cs from AnnaMats/ppo-Pyramids-Training: direct link, hf CLI and curl.
- Browser
- Download file 11.6 kB
-
https://huggingface.co/AnnaMats/ppo-Pyramids-Training/resolve/main/com.unity.ml-agents/Runtime/Sensors/Reflection/ObservableAttribute.cs
- Command line
-
hf download hf://AnnaMats/ppo-Pyramids-Training/com.unity.ml-agents/Runtime/Sensors/Reflection/ObservableAttribute.cs
-
curl -L -o ObservableAttribute.cs https://huggingface.co/AnnaMats/ppo-Pyramids-Training/resolve/main/com.unity.ml-agents/Runtime/Sensors/Reflection/ObservableAttribute.cs
11.6 kB
| using System; | |
| using System.Collections.Generic; | |
| using System.Reflection; | |
| using UnityEngine; | |
| namespace Unity.MLAgents.Sensors.Reflection | |
| { | |
| /// <summary> | |
| /// Specify that a field or property should be used to generate observations for an Agent. | |
| /// For each field or property that uses ObservableAttribute, a corresponding | |
| /// <see cref="ISensor"/> will be created during Agent initialization, and this | |
| /// sensor will read the values during training and inference. | |
| /// </summary> | |
| /// <remarks> | |
| /// ObservableAttribute is intended to make initial setup of an Agent easier. Because it | |
| /// uses reflection to read the values of fields and properties at runtime, this may | |
| /// be much slower than reading the values directly. If the performance of | |
| /// ObservableAttribute is an issue, you can get the same functionality by overriding | |
| /// <see cref="Agent.CollectObservations(VectorSensor)"/> or creating a custom | |
| /// <see cref="ISensor"/> implementation to read the values without reflection. | |
| /// | |
| /// Note that you do not need to adjust the VectorObservationSize in | |
| /// <see cref="Unity.MLAgents.Policies.BrainParameters"/> when adding ObservableAttribute | |
| /// to fields or properties. | |
| /// </remarks> | |
| /// <example> | |
| /// This sample class will produce two observations, one for the m_Health field, and one | |
| /// for the HealthPercent property. | |
| /// <code> | |
| /// using Unity.MLAgents; | |
| /// using Unity.MLAgents.Sensors.Reflection; | |
| /// | |
| /// public class MyAgent : Agent | |
| /// { | |
| /// [Observable] | |
| /// int m_Health; | |
| /// | |
| /// [Observable] | |
| /// float HealthPercent | |
| /// { | |
| /// get => return 100.0f * m_Health / float(m_MaxHealth); | |
| /// } | |
| /// } | |
| /// </code> | |
| /// </example> | |
| [] | |
| public class ObservableAttribute : Attribute | |
| { | |
| string m_Name; | |
| int m_NumStackedObservations; | |
| /// <summary> | |
| /// Default binding flags used for reflection of members and properties. | |
| /// </summary> | |
| const BindingFlags k_BindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; | |
| /// <summary> | |
| /// Supported types and their observation sizes and corresponding sensor type. | |
| /// </summary> | |
| static Dictionary<Type, (int, Type)> s_TypeToSensorInfo = new Dictionary<Type, (int, Type)>() | |
| { | |
| {typeof(int), (1, typeof(IntReflectionSensor))}, | |
| {typeof(bool), (1, typeof(BoolReflectionSensor))}, | |
| {typeof(float), (1, typeof(FloatReflectionSensor))}, | |
| {typeof(Vector2), (2, typeof(Vector2ReflectionSensor))}, | |
| {typeof(Vector3), (3, typeof(Vector3ReflectionSensor))}, | |
| {typeof(Vector4), (4, typeof(Vector4ReflectionSensor))}, | |
| {typeof(Quaternion), (4, typeof(QuaternionReflectionSensor))}, | |
| }; | |
| /// <summary> | |
| /// ObservableAttribute constructor. | |
| /// </summary> | |
| /// <param name="name">Optional override for the sensor name. Note that all sensors for an Agent | |
| /// must have a unique name.</param> | |
| /// <param name="numStackedObservations">Number of frames to concatenate observations from.</param> | |
| public ObservableAttribute(string name = null, int numStackedObservations = 1) | |
| { | |
| m_Name = name; | |
| m_NumStackedObservations = numStackedObservations; | |
| } | |
| /// <summary> | |
| /// Returns a FieldInfo for all fields that have an ObservableAttribute | |
| /// </summary> | |
| /// <param name="o">Object being reflected</param> | |
| /// <param name="excludeInherited">Whether to exclude inherited properties or not.</param> | |
| /// <returns></returns> | |
| static IEnumerable<(FieldInfo, ObservableAttribute)> GetObservableFields(object o, bool excludeInherited) | |
| { | |
| // TODO cache these (and properties) by type, so that we only have to reflect once. | |
| var bindingFlags = k_BindingFlags | (excludeInherited ? BindingFlags.DeclaredOnly : 0); | |
| var fields = o.GetType().GetFields(bindingFlags); | |
| foreach (var field in fields) | |
| { | |
| var attr = (ObservableAttribute)GetCustomAttribute(field, typeof(ObservableAttribute)); | |
| if (attr != null) | |
| { | |
| yield return (field, attr); | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Returns a PropertyInfo for all fields that have an ObservableAttribute | |
| /// </summary> | |
| /// <param name="o">Object being reflected</param> | |
| /// <param name="excludeInherited">Whether to exclude inherited properties or not.</param> | |
| /// <returns></returns> | |
| static IEnumerable<(PropertyInfo, ObservableAttribute)> GetObservableProperties(object o, bool excludeInherited) | |
| { | |
| var bindingFlags = k_BindingFlags | (excludeInherited ? BindingFlags.DeclaredOnly : 0); | |
| var properties = o.GetType().GetProperties(bindingFlags); | |
| foreach (var prop in properties) | |
| { | |
| var attr = (ObservableAttribute)GetCustomAttribute(prop, typeof(ObservableAttribute)); | |
| if (attr != null) | |
| { | |
| yield return (prop, attr); | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Creates sensors for each field and property with ObservableAttribute. | |
| /// </summary> | |
| /// <param name="o">Object being reflected</param> | |
| /// <param name="excludeInherited">Whether to exclude inherited properties or not.</param> | |
| /// <returns></returns> | |
| internal static List<ISensor> CreateObservableSensors(object o, bool excludeInherited) | |
| { | |
| var sensorsOut = new List<ISensor>(); | |
| foreach (var (field, attr) in GetObservableFields(o, excludeInherited)) | |
| { | |
| var sensor = CreateReflectionSensor(o, field, null, attr); | |
| if (sensor != null) | |
| { | |
| sensorsOut.Add(sensor); | |
| } | |
| } | |
| foreach (var (prop, attr) in GetObservableProperties(o, excludeInherited)) | |
| { | |
| if (!prop.CanRead) | |
| { | |
| // Skip unreadable properties. | |
| continue; | |
| } | |
| var sensor = CreateReflectionSensor(o, null, prop, attr); | |
| if (sensor != null) | |
| { | |
| sensorsOut.Add(sensor); | |
| } | |
| } | |
| return sensorsOut; | |
| } | |
| /// <summary> | |
| /// Create the ISensor for either the field or property on the provided object. | |
| /// If the data type is unsupported, or the property is write-only, returns null. | |
| /// </summary> | |
| /// <param name="o"></param> | |
| /// <param name="fieldInfo"></param> | |
| /// <param name="propertyInfo"></param> | |
| /// <param name="observableAttribute"></param> | |
| /// <returns></returns> | |
| /// <exception cref="UnityAgentsException"></exception> | |
| static ISensor CreateReflectionSensor(object o, FieldInfo fieldInfo, PropertyInfo propertyInfo, ObservableAttribute observableAttribute) | |
| { | |
| string memberName; | |
| string declaringTypeName; | |
| Type memberType; | |
| if (fieldInfo != null) | |
| { | |
| declaringTypeName = fieldInfo.DeclaringType.Name; | |
| memberName = fieldInfo.Name; | |
| memberType = fieldInfo.FieldType; | |
| } | |
| else | |
| { | |
| declaringTypeName = propertyInfo.DeclaringType.Name; | |
| memberName = propertyInfo.Name; | |
| memberType = propertyInfo.PropertyType; | |
| } | |
| if (!s_TypeToSensorInfo.ContainsKey(memberType) && !memberType.IsEnum) | |
| { | |
| // For unsupported types, return null and we'll filter them out later. | |
| return null; | |
| } | |
| string sensorName; | |
| if (string.IsNullOrEmpty(observableAttribute.m_Name)) | |
| { | |
| sensorName = $"ObservableAttribute:{declaringTypeName}.{memberName}"; | |
| } | |
| else | |
| { | |
| sensorName = observableAttribute.m_Name; | |
| } | |
| var reflectionSensorInfo = new ReflectionSensorInfo | |
| { | |
| Object = o, | |
| FieldInfo = fieldInfo, | |
| PropertyInfo = propertyInfo, | |
| ObservableAttribute = observableAttribute, | |
| SensorName = sensorName | |
| }; | |
| ISensor sensor = null; | |
| if (memberType.IsEnum) | |
| { | |
| sensor = new EnumReflectionSensor(reflectionSensorInfo); | |
| } | |
| else | |
| { | |
| var (_, sensorType) = s_TypeToSensorInfo[memberType]; | |
| sensor = (ISensor)Activator.CreateInstance(sensorType, reflectionSensorInfo); | |
| } | |
| // Wrap the base sensor in a StackingSensor if we're using stacking. | |
| if (observableAttribute.m_NumStackedObservations > 1) | |
| { | |
| return new StackingSensor(sensor, observableAttribute.m_NumStackedObservations); | |
| } | |
| return sensor; | |
| } | |
| /// <summary> | |
| /// Gets the sum of the observation sizes of the Observable fields and properties on an object. | |
| /// Also appends errors to the errorsOut array. | |
| /// </summary> | |
| /// <param name="o"></param> | |
| /// <param name="excludeInherited"></param> | |
| /// <param name="errorsOut"></param> | |
| /// <returns></returns> | |
| internal static int GetTotalObservationSize(object o, bool excludeInherited, List<string> errorsOut) | |
| { | |
| int sizeOut = 0; | |
| foreach (var (field, attr) in GetObservableFields(o, excludeInherited)) | |
| { | |
| if (s_TypeToSensorInfo.ContainsKey(field.FieldType)) | |
| { | |
| var (obsSize, _) = s_TypeToSensorInfo[field.FieldType]; | |
| sizeOut += obsSize * attr.m_NumStackedObservations; | |
| } | |
| else if (field.FieldType.IsEnum) | |
| { | |
| sizeOut += EnumReflectionSensor.GetEnumObservationSize(field.FieldType); | |
| } | |
| else | |
| { | |
| errorsOut.Add($"Unsupported Observable type {field.FieldType.Name} on field {field.Name}"); | |
| } | |
| } | |
| foreach (var (prop, attr) in GetObservableProperties(o, excludeInherited)) | |
| { | |
| if (!prop.CanRead) | |
| { | |
| errorsOut.Add($"Observable property {prop.Name} is write-only."); | |
| } | |
| else if (s_TypeToSensorInfo.ContainsKey(prop.PropertyType)) | |
| { | |
| var (obsSize, _) = s_TypeToSensorInfo[prop.PropertyType]; | |
| sizeOut += obsSize * attr.m_NumStackedObservations; | |
| } | |
| else if (prop.PropertyType.IsEnum) | |
| { | |
| sizeOut += EnumReflectionSensor.GetEnumObservationSize(prop.PropertyType); | |
| } | |
| else | |
| { | |
| errorsOut.Add($"Unsupported Observable type {prop.PropertyType.Name} on property {prop.Name}"); | |
| } | |
| } | |
| return sizeOut; | |
| } | |
| } | |
| } | |