Farama-Foundation / PettingZoo

An API standard for multi-agent reinforcement learning environments, with popular reference environments and related utilities
https://pettingzoo.farama.org
Other
2.55k stars 405 forks source link

[suggestion] Add aec_wrapper_fn() to utils.conversions #529

Closed WillDudley closed 2 years ago

WillDudley commented 2 years ago

Motivation

I wish to refactor my custom MARL environment to a more standardised, clean format, so I am attempting to convert it to PettingZoo's format. My custom environment is intuitively a parallel environment, so I have refactored it as such. Thus, I want to utilise the tests to sanity-check my environment.

Issue

seed_test() fails with parallel env_fn, unlike aec_env_fn - the following is raised: AttributeError: 'raw_env' object has no attribute 'agent_iter'. Additionally, whilst there is a provided way to convert aec_env_fn -> parallel_env_fn here, there is no vice-versa. Hence it is not possible to easily seed test native parallel envs.

Proposed solutions

  1. Raise an error when passing a parallel_env_fn into seed_test().
  2. Add the following to utils.conversions:
def aec_wrapper_fn(env_fn):
    def aec_fn(**kwargs):
        env = env_fn(**kwargs)
        env = from_parallel_wrapper(env)
        return env
    return aec_fn

Notes

I'd submit a PR myself, but I am not too familiar in writing tests.

I am fairly new to PettingZoo so please forgive if this is an inappropriate suggestion (eg. custom environments should always be written as AEC)

benblack769 commented 2 years ago

Hi, I am glad you were able to implement a new pettingzoo environment.

We have implemented a number of parallel environments ourselves. What we have done to run the seed test on them is simply:

from pettingzoo.utils import from_parallel

def seed_test_paralllel(parallel_env):
   env = from_parallel(parallel_env)
   seed_test(env)

We would be happy to improve the error message that occurs when you try to run seed_test on a parallel environment to suggest this solution. We could also consider creating an alias for from_parallel that is easier to understand.

What sort of resolution works best for you?

WillDudley commented 2 years ago

Hello, thank you for the rapid and helpful reply. I'm afraid I don't think your solution works for me.

Failure with env_fn

The following code:

from pettingzoo.utils import from_parallel
from pettingzoo.test import parallel_api_test, seed_test, max_cycles_test, render_test
from pettingzoo.butterfly import pistonball_v4

def seed_test_parallel(parallel_env):
   env = from_parallel(parallel_env)
   seed_test(env)

seed_test_parallel(pistonball_v4.parallel_env)

produces the traceback

Traceback (most recent call last):
  File "/home/will/.config/JetBrains/PyCharm2021.2/scratches/scratch.py", line 9, in <module>
    seed_test_parallel(pistonball_v4.parallel_env)
  File "/home/will/.config/JetBrains/PyCharm2021.2/scratches/scratch.py", line 6, in seed_test_parallel
    env = from_parallel(parallel_env)
  File "/home/will/Repositories/myproject/venv/lib/python3.9/site-packages/pettingzoo/utils/conversions.py", line 30, in from_parallel
    aec_env = from_parallel_wrapper(par_env)
  File "/home/will/Repositories/myproject/venv/lib/python3.9/site-packages/pettingzoo/utils/conversions.py", line 131, in __init__
    self.metadata = parallel_env.metadata
AttributeError: 'function' object has no attribute 'metadata'

Failure with env

The following code:

from pettingzoo.utils import from_parallel
from pettingzoo.test import parallel_api_test, seed_test, max_cycles_test, render_test
from pettingzoo.butterfly import pistonball_v4

def seed_test_parallel(parallel_env):
   env = from_parallel(parallel_env)
   seed_test(env)

seed_test_parallel(pistonball_v4.parallel_env())

produces the traceback

Traceback (most recent call last):
  File "/home/will/.config/JetBrains/PyCharm2021.2/scratches/scratch.py", line 9, in <module>
    seed_test_parallel(pistonball_v4.parallel_env())
  File "/home/will/.config/JetBrains/PyCharm2021.2/scratches/scratch.py", line 7, in seed_test_parallel
    seed_test(env)
  File "/home/will/Repositories/myproject/venv/lib/python3.9/site-packages/pettingzoo/test/seed_test.py", line 95, in seed_test
    env1 = env_constructor()
TypeError: 'OrderEnforcingWrapper' object is not callable

Info

PettingZoo v1.13.1 from PyPi Python v3.9.7 Ubuntu 20.04

If it's not much trouble, could you either try to reproduce this, or point out the mistake in my code? I got the same errors for my custom env, which is what led to the initial confusion.

I assume these errors aren't intentional, otherwise I'd suggest catching them and providing a suggested remedy (eg. "parallel envs are not compatible with seed_test() - please convert the env to AEC via from_parallel first")

Many thanks

benblack769 commented 2 years ago

Ah, sorry, my example solution was quite off. I forgot how the seed_test works for a minute. Here is a successful solution.

from pettingzoo.utils import from_parallel
from pettingzoo.test import parallel_api_test, seed_test, max_cycles_test, render_test
from pettingzoo.butterfly import pistonball_v4

def seed_test_parallel(parallel_env_fn):
   def aec_env_fn():
      parallel_env = parallel_env_fn()
      env = from_parallel(parallel_env)
      return env
   seed_test(aec_env_fn)

seed_test_parallel(pistonball_v4.parallel_env)

I think I could add this function to the pettingzoo.test.seed_test.py if that would be helpful for you.

WillDudley commented 2 years ago

The addition of this proposed function would make intuitive sense to me. As a new user I assumed that:

Though I perhaps should've done more digging to find the natively written parallel environments you were talking about and inferred it from there.

Thanks a lot for your help. I'll leave it up to you whether to close this issue or submit a PR.

benblack769 commented 2 years ago

We hope that not all of our users have to dig deep into pettingzoo internals.

I think we can plan to go ahead and add a parallel_seed_test function.

benblack769 commented 2 years ago

Made a PR to resolve this #532