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

Add compatibility wrapper for DeepMind Melting Pot #39

Closed
wants to merge 50 commits into from

Conversation

elliottower
Copy link
Contributor

See: google-deepmind/meltingpot#117

Pytest and pre-commit hooks passing.

Also fixed misc.pyrght errors (e.g., step() argument action of type int incompatible with int64 -> action: ActionType (from pettingzoo.utils.env) and made comments a bit more consistent (using the same language to describe the wrappers ,etc).

@elliottower
Copy link
Contributor Author

@pseudo-rnd-thoughts
Copy link
Member

Could you fix pre-commit and tests

Copy link
Member

@jjshoots jjshoots left a comment

Choose a reason for hiding this comment

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

Overall LGTM, aside from some minor comments. @pseudo-rnd-thoughts may want to have a second look as he tends to be more detail oriented and may have preferences over certain aspects.


@pytest.mark.parametrize("substrate_name", SUBSTRATES)
def test_seeding(substrate_name):
"""Tests the seeding of the openspiel conversion wrapper."""
Copy link
Member

Choose a reason for hiding this comment

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

Typo in this docstring.

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 catch

@@ -0,0 +1,57 @@
"""Tests the functionality of the MeltingPotCompatibility wrapper on meltingpot substrates."""
Copy link
Member

Choose a reason for hiding this comment

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

The tests look good to me, but perhaps @pseudo-rnd-thoughts may want to have a second look.

@@ -0,0 +1,61 @@
"""Shared utils for meltingpot."""
Copy link
Member

Choose a reason for hiding this comment

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

This looks rather similar to the dm_env utils, do you think the two could be merged, especially the spec_to_space functionality? Or perhaps rename the timestep_to_observations into multiagent_timestep_to_observations to make it more verbose.

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 I’ll look into that

self.player_roles = substrate.get_config(self.substrate_name).default_player_roles
self.max_cycles = max_cycles
self.env_config = {"substrate": self.substrate_name, "roles": self.player_roles}
EzPickle.__init__(self, self.render_mode, self.env_config, self.max_cycles)
Copy link
Member

Choose a reason for hiding this comment

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

Could the ezpickle be moved up?

Copy link
Member

Choose a reason for hiding this comment

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

Move to be the first line of the function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The EzPickle init line takes a few arguments which need to be extracted from the environment (env config, which contains player_roles) so it can't be done on the first line.

self.player_roles = substrate.get_config(self.substrate_name).default_player_roles
self.max_cycles = max_cycles
self.env_config = {"substrate": self.substrate_name, "roles": self.player_roles}
EzPickle.__init__(self, self.render_mode, self.env_config, self.max_cycles)
Copy link
Member

Choose a reason for hiding this comment

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

Move to be the first line of the function

self._env.observation_spec()[0]['WORLD.RGB']) # type: ignore

# Set agents
self._num_players = len(self._env.observation_spec())
Copy link
Member

Choose a reason for hiding this comment

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

Does this include the "WORLD.RGB"? Should it not be len() - 1

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 was code from their previous pettingzoo code and the number of players stayed consistent with the observation and such, but I’ll check again to see if it might be an issue.

Copy link
Member

Choose a reason for hiding this comment

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

What it an issue ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

WORLD.RGB is just one entry in each observation, self._env.observation_spec() just has a dict for each agent so is of length(num_players)


state_space = utils.spec_to_space(
self._env.observation_spec()[0]['WORLD.RGB'])
return state_space
Copy link
Member

Choose a reason for hiding this comment

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

Why are we not using self.state_space?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you mean to make it in the init constructor rather than a separate method? I had it that way originally but saw the action space and observation space in most other examples were separate methods so thought it might be more readable that way. Although those are functions with agent id as input, whereas this is independent of agent. Wasn’t sure if it was necessary at all because a lot of examples don’t have state space included.

Copy link
Member

Choose a reason for hiding this comment

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

It is just confusing as the observation-spec doesn't change and you already define self.state_space which is equivalent to this function. So just use the variable that already exists or remove the variable

) -> Tuple[
ObsDict, Dict[str, float], Dict[str, bool], Dict[str, bool], Dict[str, dict]
]:
"""step.
Copy link
Member

Choose a reason for hiding this comment

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

Update docstring

"""
rgb_arr = self.state()[0]['WORLD.RGB']
if self.render_mode == 'human':
plt.cla()
Copy link
Member

Choose a reason for hiding this comment

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

@jjshoots Do we care that we are using matplotlib for rendering

Copy link
Member

Choose a reason for hiding this comment

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

True, I think we should avoid import matplotlib if possible. I'm not sure how it's done in meltingpot, but if it's not possible to not use matplotlib, I think that's still fine. We can simply make it a dependency for meltingpot only.

@elliottower is it possible to use PIL instead?

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’m not familiar with PIL but from some googling looks doable. https://stackoverflow.com/questions/57316491/how-to-convert-matplotlib-figure-to-pil-image-object-without-saving-image
Something like this? Or do you mean to avoid matplotlib entirely? Is it because plt is slow? And I’ve on seen pettingzoo games use pygame not PIL, is there a consensus on one or the other?

Copy link
Member

Choose a reason for hiding this comment

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

We generally try to avoid imports of large libraries, especially if we're not using their main functionality. Since we only want to display images, MPL is a bit overkill. That said, PIL is also a bit of a large library, and so is PyGame. I think the consensus for one over the other has thus far just been 'most of the other libraries tend not to use MPL, so let's not use that'. There may be other reasons that I don't know of.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense, will look into it today.

})


def spec_to_space(spec: tree.Structure[dm_env.specs.Array]) -> spaces.Space:
Copy link
Member

Choose a reason for hiding this comment

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

As jet mentioned, remove and replace with the existing dm spec to space

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So the existing spec to space is actually less general than this one, and is a bit less clear (imo) so I’ve actually replaced the existing one with this and adapted the functionality to work with both cases. Will commit the changes later today.

tests/test_meltingpot.py Outdated Show resolved Hide resolved
shimmy/meltingpot_compatibility.py Outdated Show resolved Hide resolved
tests/test_meltingpot.py Outdated Show resolved Hide resolved
tests/test_meltingpot.py Outdated Show resolved Hide resolved
@pseudo-rnd-thoughts
Copy link
Member

pseudo-rnd-thoughts commented Mar 7, 2023

@jjshoots As meltingpot requires DMLab2D is it possible for test this in the CI?
I forgot if we are able to test with lab or lab2d or neither

@elliottower
Copy link
Contributor Author

Addressed these comments (including the minor openspiel changes), cleaned up docstrings and swapped the rendering from plt to pygame. I also added a test for pygame rendering as it's different from how the underlying env does rendering by default, although it may not be necessary.

Problem is now that the seeding seems to be broken and I'm not sure how to go about fixing it. @jjshoots @pseudo-rnd-thoughts

@jjshoots
Copy link
Member

@elliottower, seeding for meltingpot? It may be the case that meltingpot just has very bad seeding techniques that doesn't actually make it deterministic. This would not be the first time. Our solution to this was to set nondeterministic=True in the gymnasium API check, or disable seeding tests for those that are failing seeding in PZ tests.

@elliottower
Copy link
Contributor Author

@elliottower, seeding for meltingpot? It may be the case that meltingpot just has very bad seeding techniques that doesn't actually make it deterministic. This would not be the first time. Our solution to this was to set nondeterministic=True in the gymnasium API check, or disable seeding tests for those that are failing seeding in PZ tests.

Oh okay that’s good to know. I asked how hard it would be to supply a seed and they said it wouldn’t be easy and recommended something similar to disable seeding.

@pseudo-rnd-thoughts
Copy link
Member

pseudo-rnd-thoughts commented Mar 14, 2023

I found this in the CI

----------------------------- Captured stderr call -----------------------------

Downloading CMU mocap data:   0%|          | 0.00/466M [00:00<?, ?it/s]
Downloading CMU mocap data:   1%|          | 4.00M/466M [00:00<00:21, 22.0Mit/s]
Downloading CMU mocap data:   3%|▎         | 16.0M/466M [00:00<00:08, 55.7Mit/s]
Downloading CMU mocap data:   5%|▌         | 24.0M/466M [00:00<00:08, 57.4Mit/s]
Downloading CMU mocap data:   9%|▊         | 40.0M/466M [00:00<00:05, 78.1Mit/s]
Downloading CMU mocap data:  12%|█▏        | 56.1M/466M [00:00<00:04, 95.9Mit/s]
Downloading CMU mocap data:  15%|█▌        | 72.1M/466M [00:00<00:03, 109Mit/s] 
Downloading CMU mocap data:  19%|█▉        | 88.1M/466M [00:01<00:03, 111Mit/s]
Downloading CMU mocap data:  23%|██▎       | 105M/466M [00:01<00:02, 128Mit/s] 
Downloading CMU mocap data:  26%|██▌       | 122M/466M [00:01<00:02, 141Mit/s]
Downloading CMU mocap data:  31%|███       | 143M/466M [00:01<00:02, 163Mit/s]
Downloading CMU mocap data:  34%|███▍      | 160M/466M [00:01<00:02, 156Mit/s]
Downloading CMU mocap data:  38%|███▊      | 175M/466M [00:01<00:02, 144Mit/s]
Downloading CMU mocap data:  41%|████▏     | [192](https://github.com/Farama-Foundation/Shimmy/actions/runs/4355883425/jobs/7613638215#step:4:193)M/466M [00:01<00:02, 129Mit/s]
Downloading CMU mocap data:  46%|████▋     | 216M/466M [00:01<00:01, 153Mit/s]
Downloading CMU mocap data:  50%|████▉     | 231M/466M [00:01<00:01, 155Mit/s]
Downloading CMU mocap data:  53%|█████▎    | 247M/466M [00:02<00:01, 124Mit/s]
Downloading CMU mocap data:  58%|█████▊    | 269M/466M [00:02<00:01, 150Mit/s]
Downloading CMU mocap data:  61%|██████▏   | 285M/466M [00:02<00:01, 127Mit/s]
Downloading CMU mocap data:  64%|██████▍   | 299M/466M [00:02<00:01, 116Mit/s]
Downloading CMU mocap data:  68%|██████▊   | 318M/466M [00:02<00:01, 133Mit/s]
Downloading CMU mocap data:  71%|███████▏  | 332M/466M [00:02<00:01, 107Mit/s]
Downloading CMU mocap data:  75%|███████▌  | 349M/466M [00:03<00:00, 122Mit/s]
Downloading CMU mocap data:  81%|████████  | 376M/466M [00:03<00:00, 158Mit/s]
Downloading CMU mocap data:  84%|████████▍ | 393M/466M [00:03<00:00, 134Mit/s]
Downloading CMU mocap data:  88%|████████▊ | 408M/466M [00:03<00:00, 96.7Mit/s]
Downloading CMU mocap data:  93%|█████████▎| 433M/466M [00:03<00:00, 126Mit/s] 
Downloading CMU mocap data:  96%|█████████▋| 449M/466M [00:03<00:00, 120Mit/s]
Downloading CMU mocap data: 100%|██████████| 466M/466M [00:03<00:00, 124Mit/s]

However, I don't seem to be able to replicate the issue locally.
I know that we don't register the cmu_2020_tracking.cmu_humanoid_tracking as this has mocap tracking

shimmy/utils/dm_env.py Outdated Show resolved Hide resolved
shimmy/registration.py Outdated Show resolved Hide resolved
shimmy/utils/meltingpot.py Show resolved Hide resolved
tests/test_meltingpot.py Outdated Show resolved Hide resolved
Copy link
Member

@jjshoots jjshoots left a comment

Choose a reason for hiding this comment

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

Overall LGTM, some minor questions which I think once solved get my greenlight for merging.

Comment on lines +1 to +4
#!/bin/sh
set -eu

if [[ "$(uname -s)" == 'Linux' ]]; then
Copy link
Member

Choose a reason for hiding this comment

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

Minor nitpick, could we name /bin to /scripts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds like a good idea, do you agree @pseudo-rnd-thoughts ?

setup.py Show resolved Hide resolved
tests/test_openspiel.py Show resolved Hide resolved
tests/test_melting_pot.py Show resolved Hide resolved
# "dm_control/compatibility-env-v0", env=wrapped_env, disable_env_checker=True
# )
# check_env(env.unwrapped, skip_render_check=True)
# env.close()
Copy link
Member

Choose a reason for hiding this comment

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

Apologies if I missed out the discussion on this, but is there a reason this entire file is commented out?

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 this is definitely a mistake from my part, I thought for some reason when I synced with master that this changed but now looking at master that file hasn’t changed for a month. Will clean it up.

shimmy/utils/meltingpot.py Show resolved Hide resolved

Print the current game state.
"""
print(self.game_state)
Copy link
Member

Choose a reason for hiding this comment

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

This is kinda weird since some openspiel environments actually have a render function, but I guess c'est la vie.

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 wasn’t actually aware of that, the current code just ignores rendering and says it’s not implemented but I could check if the env has a render function and if not just print the state.

Copy link
Member

@pseudo-rnd-thoughts pseudo-rnd-thoughts left a comment

Choose a reason for hiding this comment

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

IMHO, this PR has become several different PRs: adding meltingpot support, documentation updates and possibly more given the number of files edited.
Therefore, I would propose closing this PR and opening new PRs for each of the problems addressed. This should make reviewing and understanding the PRs later if necessary

@jjshoots
Copy link
Member

@pseudo-rnd-thoughts Actually I think that's a bit counter productive. I mean for us it makes sense, but for Elliot it will be a whole lot of work

@elliottower
Copy link
Contributor Author

@pseudo-rnd-thoughts Actually I think that's a bit counter productive. I mean for us it makes sense, but for Elliot it will be a whole lot of work

It’s all good, it’s best practice so I’m happy to practice it now and spend the extra day splitting things up and organizing. Looks messy to do a single PR commit with all these changes (although committing directly to master I feel like the sequential changes would be fine, it’s just that PRs get condensed into one commit afaik)

@pseudo-rnd-thoughts
Copy link
Member

@elliottower I would recommend not using main for prs as it can cause issues if you need to revert commits etc

@elliottower
Copy link
Contributor Author

@elliottower I would recommend not using main for prs as it can cause issues if you need to revert commits etc

I meant like if you had made some of these changes directly to main because you have access, without doing a PR, as separate commits, then it would probably be fine. Definitely agree about PRs though there’s a reason separate branches are used. Anyways I’m going to refactor and clean things up today and reopen some PRs here and on pettingzoo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants