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

Observation does not distinguish between empty cells and unobserved cells #35

Closed
abaisero opened this issue Nov 15, 2018 · 6 comments
Closed

Comments

@abaisero
Copy link
Contributor

abaisero commented Nov 15, 2018

I think it would be beneficial (at least to me) to include the option of distinguishing between a cell which is observed to be empty, and a cell which is not seen at all (e.g. behind a wall). This is currently not the case, as both scenarios correspond to 0 values in the observation image.

I would probably try to do this in my own fork, but if there is any interest in pulling this to the main repo I would like to discuss it here because there's multiple ways to approach this:

  1. Adding an item to the observation dictionary.
    pros: does not change observation image, i.e. less likely to break existing code. Completely separates "what is seen" from "whether it is seen", so that the user can choose whether to use just one of both.
    cons: The original ImgObsWrapper would ignore the addition and just return the original image.

  2. Adding a cell type value to the observation image; perhaps this can be done by adding a new cell type altogether "Unseen" which will only be used in observation grids?
    pros: minor change to observation image, less likely to break code
    cons: Arguably awkward to add a type which is not associated with the state of the true environments and its objects.

  3. Adding a binary channel to the observation image.
    pros: dedicated channel, "unseen" is not a physical property inherent to the environment so it makes sense to separate it from things like the actual items.
    cons: major change to observation image, more likely to break existing code.

Personally, I think option 1 would work best: Existing code will continue working as before, and methods which want to exploit the new mask are able to do so. New observation wrappers can be added to handle the case where the user wants just the image, or the image and the "mask".

Thoughts?

@maximecb
Copy link
Contributor

maximecb commented Nov 15, 2018

You're not the first to bring this up, which suggests it's probably a good idea to add this information to observations.

Your analysis of the options is pretty spot on, and it's good that you take code breakage into account, most people pay no attention to this.

I think I might lean towards option 2. The unseen cell type could take integer value 0, and everything else would be shifted up by 1. It probably won't break code. Actually, the upside is that a neural network (or other algorithm) trained with this new observation format should be able to take advantage of the extra information without any changes to the code.

@abaisero
Copy link
Contributor Author

Good point, I agree option 2 is both the least invasive and requires less changes to models to exploit the new info: "unseen" (or "n/a") can just be a separate value in the observation image. I assume this new value would be used in all three channels, i.e. the other channels would also be shifted by one?

Related: The third channel is currently only used to indicate whether a door is open or closed, but I tend to think of it as a more general "cell/object state". Do you share this view? If new objects with a modifiable state were to be introduced, would their state also inhabit the third channel?

@abaisero
Copy link
Contributor Author

This might require a new Object to be defined; Grid.encode() only has access to the objects in the grid (with None taking a special meaning), and not the agent itself.

The least invasive way seems to add an Unseen / Unknown cell type, but this seems backwards to me: If anything, an Empty cell is more of an actual physical property of the grid, compared to an Unseen. This may require more work to carefully make sure nothing breaks, but what do you think about either:

  1. Letting None mean "not applicable" and adding a new Empty cell type; or
  2. Adding both an Unknown cell type and an Empty cell type; this way the grid contents are homogeneous and always WorldObj.

I prefer number 1, but I obviously lack a lot of understanding in how this may influence and break everything else, so it's your choice.

@maximecb
Copy link
Contributor

In terms of the least code breakage, it would be best not to add new cell types.

I would encode Unseen as (0, 0, 0) on all 3 channels and increment the existing cell type integer values by 1.

For Grid.encode(), we might want to pass the visibility mask as an optional argument.

@abaisero
Copy link
Contributor Author

Just to be clear, you're suggesting that the encodings for the second and third channels should not change, right? i.e. In the color channel, 0 should remain red, which at the same time means that both empty cells and unseen cells will be encoded as having the same code as red?

@maximecb
Copy link
Contributor

Yes

abaisero added a commit to abaisero/gym-minigrid that referenced this issue Nov 16, 2018
…ls (Farama-Foundation#35)

 * add ('unseen', 0) to `OBJECT_TO_IDX` dictionary;  all other values are
 shifted up by 1 to make space for the new value.

 * update `Grid.encode` to take an optional `vis_mask` argument, and
 return an image which now distinguishes between unseen and empty cells
 (values respectively 0 and 1).

 * update `Grid.decode` to handle the above changes;  values 0 and 1 in
 input array are both mapped to None in output grid.

 * make Grid.decode() a static method;  it was already used as a static
 method but was missing the appropriate decorator.

 * update "observation encode/decode roundtrip" test in run_tests.py;
 the visualization mask necessary to perform the test is found by
 manually checking the first channel of the image for value 0.
maximecb pushed a commit that referenced this issue Nov 16, 2018
…ls (#35) (#36)

* add ('unseen', 0) to `OBJECT_TO_IDX` dictionary;  all other values are
 shifted up by 1 to make space for the new value.

 * update `Grid.encode` to take an optional `vis_mask` argument, and
 return an image which now distinguishes between unseen and empty cells
 (values respectively 0 and 1).

 * update `Grid.decode` to handle the above changes;  values 0 and 1 in
 input array are both mapped to None in output grid.

 * make Grid.decode() a static method;  it was already used as a static
 method but was missing the appropriate decorator.

 * update "observation encode/decode roundtrip" test in run_tests.py;
 the visualization mask necessary to perform the test is found by
 manually checking the first channel of the image for value 0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants