public static void CompareObservation(ISensor sensor, float[] expected) { var numExpected = expected.Length; const float fill = -1337f; var output = new float[numExpected]; for (var i = 0; i < numExpected; i++) { output[i] = fill; } Assert.AreEqual(fill, output[0]); ObservationWriter writer = new ObservationWriter(); writer.SetTarget(output, sensor.GetObservationShape(), 0); // Make sure ObservationWriter didn't touch anything Assert.AreEqual(fill, output[0]); sensor.Write(writer); for (var i = 0; i < numExpected; i++) { Assert.AreEqual(expected[i], output[i]); } }
internal override void WriteReflectedField(ObservationWriter writer) { var vecVal = (UnityEngine.Vector2)GetReflectedValue(); writer[0] = vecVal.x; writer[1] = vecVal.y; }
/// <summary> /// Utility method for writing a PoseExtractor to an ObservationWriter. /// </summary> /// <param name="writer"></param> /// <param name="settings"></param> /// <param name="poseExtractor"></param> /// <param name="baseOffset">The offset into the ObservationWriter to start writing at.</param> /// <returns>The number of observations written.</returns> public static int WritePoses(this ObservationWriter writer, PhysicsSensorSettings settings, PoseExtractor poseExtractor, int baseOffset = 0) { var offset = baseOffset; if (settings.UseModelSpace) { foreach (var pose in poseExtractor.GetEnabledModelSpacePoses()) { if (settings.UseModelSpaceTranslations) { writer.Add(pose.position, offset); offset += 3; } if (settings.UseModelSpaceRotations) { writer.Add(pose.rotation, offset); offset += 4; } } foreach (var vel in poseExtractor.GetEnabledModelSpaceVelocities()) { if (settings.UseModelSpaceLinearVelocity) { writer.Add(vel, offset); offset += 3; } } } if (settings.UseLocalSpace) { foreach (var pose in poseExtractor.GetEnabledLocalSpacePoses()) { if (settings.UseLocalSpaceTranslations) { writer.Add(pose.position, offset); offset += 3; } if (settings.UseLocalSpaceRotations) { writer.Add(pose.rotation, offset); offset += 4; } } foreach (var vel in poseExtractor.GetEnabledLocalSpaceVelocities()) { if (settings.UseLocalSpaceLinearVelocity) { writer.Add(vel, offset); offset += 3; } } } return(offset - baseOffset); }
public void TestBufferSensor() { var bufferSensor = new BufferSensor(20, 4); var shape = bufferSensor.GetObservationShape(); var dimProp = bufferSensor.GetDimensionProperties(); Assert.AreEqual(shape[0], 20); Assert.AreEqual(shape[1], 4); Assert.AreEqual(shape.Length, 2); Assert.AreEqual(dimProp[0], DimensionProperty.VariableSize); Assert.AreEqual(dimProp[1], DimensionProperty.None); Assert.AreEqual(dimProp.Length, 2); bufferSensor.AppendObservation(new float[] { 1, 2, 3, 4 }); bufferSensor.AppendObservation(new float[] { 5, 6, 7, 8 }); var obsWriter = new ObservationWriter(); var obs = bufferSensor.GetObservationProto(obsWriter); Assert.AreEqual(shape, obs.Shape); Assert.AreEqual(obs.DimensionProperties.Count, 2); Assert.AreEqual((int)dimProp[0], obs.DimensionProperties[0]); Assert.AreEqual((int)dimProp[1], obs.DimensionProperties[1]); for (int i = 0; i < 8; i++) { Assert.AreEqual(obs.FloatData.Data[i], i + 1); } for (int i = 8; i < 80; i++) { Assert.AreEqual(obs.FloatData.Data[i], 0); } }
public void TestRaycastMiss() { var obj = new GameObject("agent"); var perception = obj.AddComponent <RayPerceptionSensorComponent3D>(); perception.RaysPerDirection = 0; perception.MaxRayDegrees = 45; perception.RayLength = 20; perception.DetectableTags = new List <string>(); perception.DetectableTags.Add(k_CubeTag); perception.DetectableTags.Add(k_SphereTag); var sensor = perception.CreateSensor(); var expectedObs = (2 * perception.RaysPerDirection + 1) * (perception.DetectableTags.Count + 2); Assert.AreEqual(sensor.GetObservationSpec().Shape[0], expectedObs); var outputBuffer = new float[expectedObs]; ObservationWriter writer = new ObservationWriter(); writer.SetTarget(outputBuffer, sensor.GetObservationSpec(), 0); var numWritten = sensor.Write(writer); Assert.AreEqual(numWritten, expectedObs); // Everything missed Assert.AreEqual(new float[] { 0, 0, 1, 1 }, outputBuffer); }
public void TestWritesToIList() { ObservationWriter writer = new ObservationWriter(); var buffer = new[] { 0f, 0f, 0f }; var shape = new[] { 3 }; writer.SetTarget(buffer, shape, 0); // Elementwise writes writer[0] = 1f; writer[2] = 2f; Assert.AreEqual(new[] { 1f, 0f, 2f }, buffer); // Elementwise writes with offset writer.SetTarget(buffer, shape, 1); writer[0] = 3f; Assert.AreEqual(new[] { 1f, 3f, 2f }, buffer); // AddRange writer.SetTarget(buffer, shape, 0); writer.AddRange(new[] { 4f, 5f }); Assert.AreEqual(new[] { 4f, 5f, 2f }, buffer); // AddRange with offset writer.SetTarget(buffer, shape, 1); writer.AddRange(new[] { 6f, 7f }); Assert.AreEqual(new[] { 4f, 6f, 7f }, buffer); }
public void TestBufferSensorComponent() { var agentGameObj = new GameObject("agent"); var bufferComponent = agentGameObj.AddComponent <BufferSensorComponent>(); bufferComponent.MaxNumObservables = 20; bufferComponent.ObservableSize = 4; var sensor = bufferComponent.CreateSensor(); var shape = bufferComponent.GetObservationShape(); Assert.AreEqual(shape[0], 20); Assert.AreEqual(shape[1], 4); Assert.AreEqual(shape.Length, 2); bufferComponent.AppendObservation(new float[] { 1, 2, 3, 4 }); bufferComponent.AppendObservation(new float[] { 5, 6, 7, 8 }); var obsWriter = new ObservationWriter(); var obs = sensor.GetObservationProto(obsWriter); Assert.AreEqual(shape, obs.Shape); Assert.AreEqual(obs.DimensionProperties.Count, 2); for (int i = 0; i < 8; i++) { Assert.AreEqual(obs.FloatData.Data[i], i + 1); } for (int i = 8; i < 80; i++) { Assert.AreEqual(obs.FloatData.Data[i], 0); } }
public void TestCameraSensor() { foreach (var grayscale in new[] { true, false }) { foreach (SensorCompressionType compression in Enum.GetValues(typeof(SensorCompressionType))) { var width = 24; var height = 16; var camera = Camera.main; var c = new GameObject(); if (ReferenceEquals(null, camera)) { camera = c.AddComponent <Camera>(); } var sensor = new CameraSensor(camera, width, height, grayscale, "TestCameraSensor", compression); var obsWriter = new ObservationWriter(); var obs = sensor.GetObservationProto(obsWriter); Assert.AreEqual((int)compression, (int)obs.CompressionType); var expectedShape = new[] { height, width, grayscale ? 1 : 3 }; Assert.AreEqual(expectedShape, obs.Shape); UnityEngine.Object.DestroyImmediate(c); } } }
public int Write(ObservationWriter writer) { BoardState state = board.GetCurrentBoardState(); int offset = 0; foreach (Index index in Index.GetAllIndices()) { if (state.TryGetPiece(index, out (Team team, Piece piece)teamedPiece)) { Piece realPiece = board.currentGame.GetRealPiece(teamedPiece); writer.Add(new Vector3( (float)teamedPiece.team, ((float)realPiece) + 1f, index.GetSingleVal() ), offset); } else { writer.Add(new Vector3(0, 0, index.GetSingleVal()), offset); } offset += 3; } return(offset); }
/// <summary> /// Puts a Texture2D into a ObservationWriter. /// </summary> /// <param name="texture"> /// The texture to be put into the tensor. /// </param> /// <param name="obsWriter"> /// Writer to fill with Texture data. /// </param> /// <param name="grayScale"> /// If set to <c>true</c> the textures will be converted to grayscale before /// being stored in the tensor. /// </param> /// <returns>The number of floats written</returns> internal static int TextureToTensorProxy( Texture2D texture, ObservationWriter obsWriter, bool grayScale) { var width = texture.width; var height = texture.height; var texturePixels = texture.GetPixels32(); // During training, we convert from Texture to PNG before sending to the trainer, which has the // effect of flipping the image. We need another flip here at inference time to match this. for (var h = height - 1; h >= 0; h--) { for (var w = 0; w < width; w++) { var currentPixel = texturePixels[(height - h - 1) * width + w]; if (grayScale) { obsWriter[h, w, 0] = (currentPixel.r + currentPixel.g + currentPixel.b) / 3f / 255.0f; } else { // For Color32, the r, g and b values are between 0 and 255. obsWriter[h, w, 0] = currentPixel.r / 255.0f; obsWriter[h, w, 1] = currentPixel.g / 255.0f; obsWriter[h, w, 2] = currentPixel.b / 255.0f; } } } return(height * width * (grayScale ? 1 : 3)); }
public int Write(ObservationWriter writer) { for (int i = 0; i < m_Width * m_Height * m_Channels; i++) { writer[i] = 0.0f; } return(m_Width * m_Height * m_Channels); }
/// <summary> /// Utility method for writing a PoseExtractor to an ObservationWriter. /// </summary> /// <param name="writer"></param> /// <param name="settings"></param> /// <param name="poseExtractor"></param> /// <param name="baseOffset">The offset into the ObservationWriter to start writing at.</param> /// <returns>The number of observations written.</returns> public static int WritePoses(this ObservationWriter writer, PhysicsSensorSettings settings, PoseExtractor poseExtractor, int baseOffset = 0) { var offset = baseOffset; if (settings.UseModelSpace) { var poses = poseExtractor.ModelSpacePoses; var vels = poseExtractor.ModelSpaceVelocities; for (var i = 0; i < poseExtractor.NumPoses; i++) { var pose = poses[i]; if (settings.UseModelSpaceTranslations) { writer.Add(pose.position, offset); offset += 3; } if (settings.UseModelSpaceRotations) { writer.Add(pose.rotation, offset); offset += 4; } if (settings.UseModelSpaceLinearVelocity) { writer.Add(vels[i], offset); offset += 3; } } } if (settings.UseLocalSpace) { var poses = poseExtractor.LocalSpacePoses; var vels = poseExtractor.LocalSpaceVelocities; for (var i = 0; i < poseExtractor.NumPoses; i++) { var pose = poses[i]; if (settings.UseLocalSpaceTranslations) { writer.Add(pose.position, offset); offset += 3; } if (settings.UseLocalSpaceRotations) { writer.Add(pose.rotation, offset); offset += 4; } if (settings.UseLocalSpaceLinearVelocity) { writer.Add(vels[i], offset); offset += 3; } } } return(offset - baseOffset); }
internal override void WriteReflectedField(ObservationWriter writer) { var quatVal = (UnityEngine.Quaternion)GetReflectedValue(); writer[0] = quatVal.x; writer[1] = quatVal.y; writer[2] = quatVal.z; writer[3] = quatVal.w; }
public byte[] GetCompressedObservation() { var writer = new ObservationWriter(); var flattenedObservation = new float[ObservationSpec.Shape[0] * ObservationSpec.Shape[1] * ObservationSpec.Shape[2]]; writer.SetTarget(flattenedObservation, ObservationSpec.Shape, 0); Write(writer); byte[] bytes = Array.ConvertAll(flattenedObservation, (z) => (byte)z); return(bytes); }
public int Write(ObservationWriter writer) { BoardState state = board.GetCurrentBoardState(); writer[0] = (float)state.currentMove; // progression towards 50 move rule writer[1] = board.currentGame.turnsSincePawnMovedOrPieceTaken; return(2); }
/// <inheritdoc/> public int Write(ObservationWriter writer) { var numWritten = writer.WritePoses(m_Settings, m_PoseExtractor); foreach (var jointExtractor in m_JointExtractors) { numWritten += jointExtractor.Write(m_Settings, writer, numWritten); } return(numWritten); }
/// <summary> /// Default implementation of Write interface. This creates a temporary array, /// calls WriteObservation, and then writes the results to the ObservationWriter. /// </summary> /// <param name="writer"></param> /// <returns>The number of elements written.</returns> public virtual int Write(ObservationWriter writer) { // TODO reuse buffer for similar agents, don't call GetObservationShape() var numFloats = this.ObservationSize(); float[] buffer = new float[numFloats]; WriteObservation(buffer); writer.AddRange(buffer); return(numFloats); }
/// <summary> /// Default implementation of Write interface. This creates a temporary array, /// calls WriteObservation, and then writes the results to the ObservationWriter. /// </summary> /// <param name="writer"></param> /// <returns>The number of elements written.</returns> public virtual int Write(ObservationWriter writer) { // TODO reuse buffer for similar agents var numFloats = this.ObservationSize(); float[] buffer = new float[numFloats]; WriteObservation(buffer); writer.AddList(buffer); return(numFloats); }
public int Write(ObservationWriter writer) { for (var h = 0; h < ObservationSpec.Shape[0]; h++) { for (var w = 0; w < ObservationSpec.Shape[1]; w++) { for (var c = 0; c < ObservationSpec.Shape[2]; c++) { writer[h, w, c] = CurrentObservation[h, w, c]; } } } return(ObservationSpec.Shape[0] * ObservationSpec.Shape[1] * ObservationSpec.Shape[2]); }
/// <inheritdoc/> public int Write(ObservationWriter writer) { // if (m_Board.Rows != m_Rows || m_Board.Columns != m_Columns || m_Board.NumCellTypes != m_NumCellTypes) // { // Debug.LogWarning( // $"Board shape changes since sensor initialization. This may cause unexpected results. " + // $"Old shape: Rows={m_Rows} Columns={m_Columns}, NumCellTypes={m_NumCellTypes} " + // $"Current shape: Rows={m_Board.Rows} Columns={m_Board.Columns}, NumCellTypes={m_Board.NumCellTypes}" // ); // } if (m_ObservationType == Match3ObservationType.Vector) { int offset = 0; for (var r = 0; r < m_Rows; r++) { for (var c = 0; c < m_Columns; c++) { var val = m_GridValues(r, c); for (var i = 0; i < m_OneHotSize; i++) { writer[offset] = (i == val) ? 1.0f : 0.0f; offset++; } } } return(offset); } else { // TODO combine loops? Only difference is inner-most statement. int offset = 0; for (var r = 0; r < m_Rows; r++) { for (var c = 0; c < m_Columns; c++) { var val = m_GridValues(r, c); for (var i = 0; i < m_OneHotSize; i++) { writer[r, c, i] = (i == val) ? 1.0f : 0.0f; offset++; } } } return(offset); } }
public int Write(ObservationWriter writer) { using (TimerStack.Instance.Scoped("Float2DSensor.Write")) { for (var h = 0; h < Height; h++) { for (var w = 0; w < Width; w++) { writer[h, w, 0] = floatData[h, w]; } } var numWritten = Height * Width; return(numWritten); } }
/// <inheritdoc/> public int Write(ObservationWriter writer) { for (int c = 0; c < m_PixelGrid.Channels; c++) { for (int x = 0; x < m_PixelGrid.Width; x++) { for (int y = 0; y < m_PixelGrid.Height; y++) { writer[y, x, c] = m_PixelGrid.Read(c, x, y); } } } return(m_Shape.Size); }
public void TestRaycastsScaled() { SetupScene(); var obj = new GameObject("agent"); var perception = obj.AddComponent <RayPerceptionSensorComponent3D>(); obj.transform.localScale = new Vector3(2, 2, 2); perception.RaysPerDirection = 0; perception.MaxRayDegrees = 45; perception.RayLength = 20; perception.DetectableTags = new List <string>(); perception.DetectableTags.Add(k_CubeTag); var radii = new[] { 0f, .5f }; foreach (var castRadius in radii) { perception.SphereCastRadius = castRadius; var sensor = perception.CreateSensors()[0]; sensor.Update(); var expectedObs = (2 * perception.RaysPerDirection + 1) * (perception.DetectableTags.Count + 2); Assert.AreEqual(sensor.GetObservationSpec().Shape[0], expectedObs); var outputBuffer = new float[expectedObs]; ObservationWriter writer = new ObservationWriter(); writer.SetTarget(outputBuffer, sensor.GetObservationSpec(), 0); var numWritten = sensor.Write(writer); Assert.AreEqual(numWritten, expectedObs); // Expected hits: // ray 0 should hit the cube at roughly 1/4 way // Assert.AreEqual(1.0f, outputBuffer[0]); // hit cube Assert.AreEqual(0.0f, outputBuffer[1]); // missed unknown tag // Hit is at z=9.0 in world space, ray length was 20 // But scale increases the cast size and the ray length var scaledRayLength = 2 * perception.RayLength; var scaledCastRadius = 2 * castRadius; Assert.That( outputBuffer[2], Is.EqualTo((9.5f - scaledCastRadius) / scaledRayLength).Within(.0005f) ); } }
public int Write(PhysicsSensorSettings settings, ObservationWriter writer, int offset) { if (m_Body == null || m_Body.isRoot) { return(0); } var currentOffset = offset; // Write joint positions if (settings.UseJointPositionsAndAngles) { switch (m_Body.jointType) { case ArticulationJointType.RevoluteJoint: case ArticulationJointType.SphericalJoint: // All joint positions are angular for (var dofIndex = 0; dofIndex < m_Body.dofCount; dofIndex++) { var jointRotationRads = m_Body.jointPosition[dofIndex]; writer[currentOffset++] = Mathf.Sin(jointRotationRads); writer[currentOffset++] = Mathf.Cos(jointRotationRads); } break; case ArticulationJointType.FixedJoint: // No observations break; case ArticulationJointType.PrismaticJoint: writer[currentOffset++] = GetPrismaticValue(); break; } } if (settings.UseJointForces) { for (var dofIndex = 0; dofIndex < m_Body.dofCount; dofIndex++) { // take tanh to keep in [-1, 1] writer[currentOffset++] = (float)System.Math.Tanh(m_Body.jointForce[dofIndex]); } } return(currentOffset - offset); }
public void TestWritesToTensor3D() { ObservationWriter writer = new ObservationWriter(); var t = new TensorProxy { valueType = TensorProxy.TensorType.FloatingPoint, data = new Tensor(2, 2, 2, 3) }; writer.SetTarget(t, 0, 0); writer[1, 0, 1] = 1f; Assert.AreEqual(1f, t.data[0, 1, 0, 1]); writer.SetTarget(t, 0, 1); writer[1, 0, 0] = 2f; Assert.AreEqual(2f, t.data[0, 1, 0, 1]); }
/// <summary> /// Generate an ObservationProto for the sensor using the provided ObservationWriter. /// This is equivalent to producing an Observation and calling Observation.ToProto(), /// but avoid some intermediate memory allocations. /// </summary> /// <param name="sensor"></param> /// <param name="observationWriter"></param> /// <returns></returns> public static ObservationProto GetObservationProto(this ISensor sensor, ObservationWriter observationWriter) { var shape = sensor.GetObservationShape(); ObservationProto observationProto = null; if (sensor.GetCompressionType() == SensorCompressionType.None) { var numFloats = sensor.ObservationSize(); var floatDataProto = new ObservationProto.Types.FloatData(); // Resize the float array // TODO upgrade protobuf versions so that we can set the Capacity directly - see https://github.com/protocolbuffers/protobuf/pull/6530 for (var i = 0; i < numFloats; i++) { floatDataProto.Data.Add(0.0f); } observationWriter.SetTarget(floatDataProto.Data, sensor.GetObservationShape(), 0); sensor.Write(observationWriter); observationProto = new ObservationProto { FloatData = floatDataProto, CompressionType = (CompressionTypeProto)SensorCompressionType.None, }; } else { var compressedObs = sensor.GetCompressedObservation(); if (compressedObs == null) { throw new UnityAgentsException( $"GetCompressedObservation() returned null data for sensor named {sensor.GetName()}. " + "You must return a byte[]. If you don't want to use compressed observations, " + "return SensorCompressionType.None from GetCompressionType()." ); } observationProto = new ObservationProto { CompressedData = ByteString.CopyFrom(compressedObs), CompressionType = (CompressionTypeProto)sensor.GetCompressionType(), }; } observationProto.Shape.AddRange(shape); return(observationProto); }
/// <inheritdoc/> public int Write(ObservationWriter writer) { m_Board.CheckBoardSizes(m_MaxBoardSize); var currentBoardSize = m_Board.GetCurrentBoardSize(); int offset = 0; var isVisual = m_ObservationType != Match3ObservationType.Vector; // This is equivalent to // for (var r = 0; r < m_MaxBoardSize.Rows; r++) // for (var c = 0; c < m_MaxBoardSize.Columns; c++) // if (r < currentBoardSize.Rows && c < currentBoardSize.Columns) // WriteOneHot // else // WriteZero // but rearranged to avoid the branching. for (var r = 0; r < currentBoardSize.Rows; r++) { for (var c = 0; c < currentBoardSize.Columns; c++) { var val = m_GridValues(r, c); writer.WriteOneHot(offset, r, c, val, m_OneHotSize, isVisual); offset += m_OneHotSize; } for (var c = currentBoardSize.Columns; c < m_MaxBoardSize.Columns; c++) { writer.WriteZero(offset, r, c, m_OneHotSize, isVisual); offset += m_OneHotSize; } } for (var r = currentBoardSize.Rows; r < m_MaxBoardSize.Columns; r++) { for (var c = 0; c < m_MaxBoardSize.Columns; c++) { writer.WriteZero(offset, r, c, m_OneHotSize, isVisual); offset += m_OneHotSize; } } return(offset); }
public static void WriteZero(this ObservationWriter writer, int offset, int row, int col, int oneHotSize, bool isVisual) { if (isVisual) { for (var i = 0; i < oneHotSize; i++) { writer[row, col, i] = 0.0f; } } else { for (var i = 0; i < oneHotSize; i++) { writer[offset] = 0.0f; offset++; } } }
/// <inheritdoc/> public int Write(ObservationWriter writer) { using (TimerStack.Instance.Scoped("GridSensor.Write")) { int index = 0; for (var h = m_GridSize.z - 1; h >= 0; h--) { for (var w = 0; w < m_GridSize.x; w++) { for (var d = 0; d < m_CellObservationSize; d++) { writer[h, w, d] = m_PerceptionBuffer[index]; index++; } } } return(index); } }
/// <inheritdoc/> public int Write(ObservationWriter writer) { using (TimerStack.Instance.Scoped("GridSensor.WriteToTensor")) { int index = 0; for (var h = GridNumSideZ - 1; h >= 0; h--) // height { for (var w = 0; w < GridNumSideX; w++) // width { for (var d = 0; d < ObservationPerCell; d++) // depth { writer[h, w, d] = m_PerceptionBuffer[index]; index++; } } } return(index); } }