-
Notifications
You must be signed in to change notification settings - Fork 130
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
Nested spaces in gRPC #526
Comments
Hi @sogartar,
Interesting suggestion! Possibly 🙂 I can see the value of nested action and observation spaces, but I don't know of any immediate use cases so I haven't prioritized it. The closest we have in the current version would be something like the JSON data structure returned by some of the LLVM environment's observations, but in that case I just send it over as raw bytes data and deserialize on the frontend. Cheers, |
Currently the structure for the action spaces is message ActionSpace {
string name = 1;
repeated ChoiceSpace choice = 2;
bool named_choices = 3;
}
message ChoiceSpace {
string name = 1;
oneof space {
...
}
} I could extend the protocol by adding to the package compiler_gym.spaces;
message ScalarLimit {
double value = 1;
}
message ScalarRange {
ScalarLimit min = 1;
ScalarLimit max = 2;
}
message Tuple {
string name = 1;
repeated Space value = 2;
}
message Scalar {
string name = 1;
oneof range {
ScalarRange int64_range = 2;
ScalarRange double_range = 3;
}
}
message Discrete {
string name = 1;
int64 n = 2;
}
message ScalarSequence {
string name = 1;
ScalarRange length_range = 2;
ScalarRange scalar_range = 3;
}
message NamedDiscrete {
string name = 1;
repeated string items = 2;
}
message Space {
string name = 1;
oneof value {
Space action_space = 2;
Tuple tuple = 3;
Scalar scalar = 4;
Discrete discrete = 5;
ScalarSequence scalar_sequence = 6;
NamedDiscrete named_discrete = 7;
}
} I don't know how open you are to breaking changes at this stage. |
I am open to breaking changes. The proto interface is described as somewhat stable 😉 . For reference, the last breaking change was in September (#369). It's not too hard to update the in-tree environment implementations and won't affect any user-facing APIs. Some initial thoughts on your proposed schema:
message Space {
...
}
message ActionSpace {
string name = 1;
Space space = 2;
}
message ObservationSpace {
string name = 1;
Space space = 2;
bool deterministic = 3;
bool platform_dependent = 4;
Observation default_value = 5;
} Overall I think your idea of making the proto schema more closely resemble the Python classes is great. The current schema has evolved over time and has become a bit bloated, there's definitely room for improvement. Happy holidays! Apologies I will be slow to respond to messages until mid January. Cheers, |
I will make a PR that introduces the new message structure and refactor the existing compiler environments. First I will propose the change to the protobuf message descriptions. Once the details are settled, I will refactor the environments.
I thought of putting them in a separate package like it is with the spaces interface in CompilerGym and OpenAI Gym. For example
Nested Spaces should also support names according to Compiler Gym's extension of OpenAI Gym's interface. It can be removed in all other places, but should be kept in
// A discrete space in which every point in the space is named. This can be used
// for representing enumerations.
message NamedDiscreteSpace {
// A list of names for every value in the space. The order in which these
// values are returned is used.
repeated string value = 1;
// If true, the set of space can be interpreted as a list of command line
// flags.
bool is_commandline = 2;
} The interface should allow to represent such information without modification of the gRPC interface. The Core Python API is considered stable, but it depends on OpenAI Gym, which is in alpha and I think a few months back they introduced breaking changes. |
When doing the refactoring of the protobuf messages I thought more about it and it seems that there could always be the need to extend the messages. Normal protobuf messages are statically typed, so extensions would always require a modification in CompilerGym. I saw this article that deals with this problem. Basically, you can use |
I agree, but just a small clarification: the aim of the proto schema is to provide a flexible enough set of messages that you can embed new data types into, not extend the schema to add new types. You shouldn't have to modify the proto schema to add support for a new data type.
There is already a mechanism to do this in CompilerGym, albeit only for observations, not actions. The ObservationSpace message has a CompilerGym/compiler_gym/service/proto/compiler_gym_service.proto Lines 250 to 256 in 9734103
The CompilerGym/compiler_gym/views/observation_space_spec.py Lines 143 to 162 in 9734103
For an example of how this is used, the LLVM environment declares the networkx graph space here and serializes and embeds the graphs here. There are two downsides to this:
So with all that said, I would propose you make the changes in this order:
Hopefully this rambly comment has helped give some context as to the design decisions of the current implementation 🙂. I will be out-of-office now until Jan 12th, but happy to discuss further when I'm back, perhaps on a call. Cheers, |
I don't know if that is still the case as this article is from a few years back.
message MyOpaqueType {
bytes data = 1;
} In the protobuf documentation for
C++ and Python have support for
I will think about it and present a more concrete approach. It will probably be a mechanism to register deserializers and dispatch based on the type URL from the In place of message Opaque {
string type_id = 1;
bytes data = 2;
} |
@ChrisCummins, the Python API is considered stable, but compiler_gym.spaces.Sequence has the problem of |
Hi @sogartar, yes the inconsistency is that In [3]: type(b'abc').__name__
Out[3]: 'bytes'
In [4]: type(b'abc'[0]).__name__
Out[4]: 'int' Now that I'm looking into it, the string sequence dtype is fine, since Python doesn't distinguish between string / character types, so they can just be strings: In [1]: type('abc').__name__
Out[1]: 'str'
In [2]: type('abc'[0]).__name__
Out[2]: 'str' If you're planning on making breaking changes to the proto API then it could also be a good time to clear up that inconsistency between bytes/int dtype for byte arrays. Cheers, |
Why not both? :-) message Event {
string type_id = 1;
oneof {
int32 int32_value = 2;
...
bytes bytes_value = 10;
Any any_value = 11;
}
} Then dispatch to any user-registered deserializer off the That means that implementations can use the Cheers, |
BTW thanks for your patience, I'm back from vacation now so will be more responsive. Cheers, |
@ChrisCummins, using |
OK, I will add the |
My idea was that if someone wants to have some type like an adjacency matrix they would have in protobuf message AdjacencyMatrix {
...
} Then use the |
Hi @sogartar, I was browsing through the gym sources today and noticed an interesting use of singledispatch to write a function for working with various different types. Might this be useful for the proto -> python deserializers? Maybe users could register their custom types using a mechanism like this. What do you think? Cheers, |
We can use this. It would be more straight forward for someone coming from outside and exploring the code base. |
Oh that's a good point. Can different environment class instances bind to a unique dispatcher? |
For observations I think it is already possible to do that by overriding _observation_view_type. It is a bit convoluted though. In the PR we are preparing for the MLIR environment I added customization of the action and action space conversion to The problem boils down to being able to pass/customize 4 functions.
I think the best approach is to either do that through inheritance and overriding or passing them to |
The default would be to instantiate the default converters from |
❓ Questions and Help
It looks like that the proto definitions of action space, action, observation space and observation do not support nesting in.
On the other hand OpenAI Gym's interface has Dict and by extension CompilerGym has also Dict. That makes deep hierarchies possible there.
Does It make sense to extend the gRPC interface to support this type of structure?
Additional Context
This is not a very pressing issue as currently the structure I want to represent is simple enough, that I can use flat names like
a.b
and
a.c
.In the future there may be the need for more complex structures.
The text was updated successfully, but these errors were encountered: