Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MLA-1634] Add ObservationSpec and update ISensor interfaces #5127

Merged
merged 23 commits into from
Mar 18, 2021

Conversation

chriselion
Copy link
Contributor

@chriselion chriselion commented Mar 16, 2021

Proposed change(s)

  • Add an InplaceArray implementation for "blittable" arrays with a max size of 4. This is used for ObservationSpec shapes and dimension properties.
  • Add an ObservationSpec struct and helper methods.
  • Change ISensor interface to return ObservationSpec instead of just a shape array.
  • Remove IDimensionPropertiesSensor and ITypedSensor interfaces, use information from ObservationSpec instead.

Note that this does not introduce CompressionSpec or remove ISparseChannelSensor yet; this was getting big, so I'm saving that for a subsequent PR.

I haven't updated the docs or migration guide yet, will do that soon. Test coverage is done though.

Follow-Ups in subsequent PRs

  • Convert SensorComponent too
  • Introduce CompressionSpce and remove ISparseChannelSensor

Useful links (Github issues, JIRA tickets, ML-Agents forum threads etc.)

https://jira.unity3d.com/browse/MLA-1634
Alternative to #5076
(Unity internal) design proposal

Types of change(s)

  • New feature
  • Code refactor
  • Breaking change

Checklist

  • Added tests that prove my fix is effective or that my feature works
  • Updated the changelog (if applicable)
  • Updated the documentation (if applicable)
  • Updated the migration guide (if applicable)

Other comments

@@ -2,6 +2,22 @@
"m_Name": "Settings",
"m_Path": "ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json",
"m_Dictionary": {
"m_DictionaryValues": []
"m_DictionaryValues": [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what to do with this. It got added in 7718dfe#diff-41dd07c8a0392e1f6c2a7ba1277f3426cdc92aa8258e563912c39db66800ade0 but wasn't computing coverage on the assemblies we care about.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I think it's just for local runs of code coverage

@@ -475,14 +475,6 @@ public void ClearPerceptionBuffer()
}
}

/// <summary>Gets the shape of the grid observation</summary>
/// <returns>integer array shape of the grid observation</returns>
public int[] GetFloatObservationShape()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was unused.

public override int[] GetObservationShape()
{
m_Shape = new[] { GridNumSideX, GridNumSideZ, ObservationPerCell };
return m_Shape;
var shape = m_ObservationSpec.Shape;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the SensorComponent override, not sure if we should change that to return a spec too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would lean toward yes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I'm going to punt that to a separate PR.

@@ -10,6 +10,7 @@ public interface IDiscreteActionMask
/// <summary>
/// Set whether or not the action index for the given branch is allowed.
/// </summary>
/// <remarks>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not from here, but was broken in staging.

/// This is a value type that does not allocate any additional memory.
/// </summary>
/// <remarks>
/// This does not implement any interfaces such as IList, in order to avoid any accidental boxing allocations.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small tradeoff between ergonomics and efficiency. It's small either way, so I'm willing to change this.

/// <param name="lhs"></param>
/// <param name="rhs"></param>
/// <returns>Whether the arrays are equivalent.</returns>
public static bool operator==(InplaceArray<T> lhs, InplaceArray<T> rhs)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the recommended way to do operator== and Equals() for a value type? Should the implementation be in Equals() instead?

/// <returns></returns>
public override int GetHashCode()
{
return Tuple.Create(m_Elem0, m_Elem1, m_Elem2, m_Elem3, Length).GetHashCode();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not currently used anywhere, but I had to add this if I overrode Equals().

/// <summary>
/// The ObservationType enum of the Sensor.
/// </summary>
public enum ObservationType
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were made public, but didn't make any other changes to them. We'll remove Reward and Message, and rename Goal later.

/// For example, a sensor that observes the velocity of a rigid body (in 3D) would use [3].
/// A sensor that returns an RGB image would use [Height, Width, 3].
/// </summary>
public InplaceArray<int> Shape;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open to discussion on the visibility for these fields, and also the constructor. I think the static helpers (Vector, VariableLength, Visual) are good for all the purposes that we currently support in the trainer, and a user could potentially implement their own trainer that supported different combos of properties (e.g. convolutional 1D or 3D).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want to expose the ObservationSpec() constructor, and with that it's flexible enough for users to customize their own and not necessary to expose the fields

We check in the constructor that the length of shape and dimensionProperties match. Users can potentially set shape and dimensionProperties with different length if we expose the fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, you convinced me. I'll make the fields internal and add public get properties.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

{
Debug.Assert(cachedShape[j] == sensorShape[j], "Sensor sizes must match.");
}
var cachedSpec = m_SensorShapes[i];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This got a little simpler (and probably faster)

@chriselion chriselion mentioned this pull request Mar 16, 2021
10 tasks
@@ -1,9 +1,10 @@
fileFormatVersion: 2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you, i saw this before and it was annoying me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it was accidental (but also annoying me).

Copy link
Contributor

@vincentpierre vincentpierre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like what I see

/// </summary>
/// <param name="length"></param>
/// <returns></returns>
public static ObservationSpec Vector(int length)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Vector and Visual, add ObservationType to the static constructors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but make them default to Default? Sure, that sounds reasonable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vincentpierre Any reason to not add that to VariableLength also?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The goal conditioning trainer will not work with VariableLength obs. We can add it though, but the trainer will raise an error or a warning when this happens.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, removed the variable length.

/// This does not implement any interfaces such as IList, in order to avoid any accidental boxing allocations.
/// </remarks>
/// <typeparam name="T"></typeparam>
public struct InplaceArray<T> where T : struct
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a

public struct ObservationShape : InplaceArray<int> { }

And same for DimensionProperties. Thoughts? Maybe overkill

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the constructors wouldn't work without adding them to ObservationShape too (plus DimensionProperties), which I'd rather not do.

And using ObservationShape = InplaceArray<int>; is only scoped for the file it's declared in, so wouldn't help any calling code.

var dimInfos = new EventObservationDimensionInfo[shape.Length];
for (var i = 0; i < shape.Length; i++)
{
dimInfos[i].Size = shape[i];
dimInfos[i].Flags = dimProps != null ? (int)dimProps[i] : 0;
dimInfos[i].Flags = (int)dimProps[i];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dats nice

/// This does not implement any interfaces such as IList, in order to avoid any accidental boxing allocations.
/// </remarks>
/// <typeparam name="T"></typeparam>
public struct InplaceArray<T> where T : struct
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any plans of adding methods for converting between this and barracuda tensorshape?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could do it as an extension method somewhere. Where would it be used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's save this for another PR - don't think it'll affect the public API

@chriselion chriselion merged commit a0b1578 into v2-staging Mar 18, 2021
@delete-merged-branch delete-merged-branch bot deleted the MLA-1634-ObservationSpec branch March 18, 2021 18:13
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants