| using System.Linq; | |
| namespace Unity.MLAgents.Sensors | |
| { | |
| /// <summary> | |
| /// The compression setting for visual/camera observations. | |
| /// </summary> | |
| public enum SensorCompressionType | |
| { | |
| /// <summary> | |
| /// No compression. Data is preserved as float arrays. | |
| /// </summary> | |
| None, | |
| /// <summary> | |
| /// PNG format. Data will be stored in binary format. | |
| /// </summary> | |
| PNG | |
| } | |
| /// <summary> | |
| /// A description of the compression used for observations. | |
| /// </summary> | |
| /// <remarks> | |
| /// Most ISensor implementations can't take advantage of compression, | |
| /// and should return CompressionSpec.Default() from their ISensor.GetCompressionSpec() methods. | |
| /// Visual observations, or mulitdimensional categorical observations (for example, image segmentation | |
| /// or the piece types in a match-3 game board) can use PNG compression reduce the amount of | |
| /// data transferred between Unity and the trainer. | |
| /// </remarks> | |
| public struct CompressionSpec | |
| { | |
| internal SensorCompressionType m_SensorCompressionType; | |
| /// <summary> | |
| /// The compression type that the sensor will use for its observations. | |
| /// </summary> | |
| public SensorCompressionType SensorCompressionType | |
| { | |
| get => m_SensorCompressionType; | |
| } | |
| internal int[] m_CompressedChannelMapping; | |
| /// <summary> | |
| /// The mapping of the channels in compressed data to the actual channel after decompression. | |
| /// </summary> | |
| /// <remarks> | |
| /// The mapping is a list of integer index with the same length as | |
| /// the number of output observation layers (channels), including padding if there's any. | |
| /// Each index indicates the actual channel the layer will go into. | |
| /// Layers with the same index will be averaged, and layers with negative index will be dropped. | |
| /// For example, mapping for CameraSensor using grayscale and stacking of two: [0, 0, 0, 1, 1, 1] | |
| /// Mapping for GridSensor of 4 channels and stacking of two: [0, 1, 2, 3, -1, -1, 4, 5, 6, 7, -1, -1] | |
| /// </remarks> | |
| public int[] CompressedChannelMapping | |
| { | |
| get => m_CompressedChannelMapping; | |
| } | |
| /// <summary> | |
| /// Return a CompressionSpec indicating possible compression. | |
| /// </summary> | |
| /// <param name="sensorCompressionType">The compression type to use.</param> | |
| /// <param name="compressedChannelMapping">Optional mapping mapping of the channels in compressed data to the | |
| /// actual channel after decompression.</param> | |
| public CompressionSpec(SensorCompressionType sensorCompressionType, int[] compressedChannelMapping = null) | |
| { | |
| m_SensorCompressionType = sensorCompressionType; | |
| m_CompressedChannelMapping = compressedChannelMapping; | |
| } | |
| /// <summary> | |
| /// Return a CompressionSpec indicating no compression. This is recommended for most sensors. | |
| /// </summary> | |
| /// <returns></returns> | |
| public static CompressionSpec Default() | |
| { | |
| return new CompressionSpec | |
| { | |
| m_SensorCompressionType = SensorCompressionType.None, | |
| m_CompressedChannelMapping = null | |
| }; | |
| } | |
| /// <summary> | |
| /// Return whether the compressed channel mapping is "trivial"; if so it doesn't need to be sent to the | |
| /// trainer. | |
| /// </summary> | |
| /// <returns></returns> | |
| internal bool IsTrivialMapping() | |
| { | |
| var mapping = CompressedChannelMapping; | |
| if (mapping == null) | |
| { | |
| return true; | |
| } | |
| // check if mapping equals zero mapping | |
| if (mapping.Length == 3 && mapping.All(m => m == 0)) | |
| { | |
| return true; | |
| } | |
| // check if mapping equals identity mapping | |
| for (var i = 0; i < mapping.Length; i++) | |
| { | |
| if (mapping[i] != i) | |
| { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| } | |
| } | |