learn2learn icon indicating copy to clipboard operation
learn2learn copied to clipboard

Asynchronous vectorized environment does not work for cavia_trpo and maml_trpo.

Open yurunsheng1 opened this issue 5 years ago • 9 comments

Hi, first of all thank you so much for providing us such an excellent project! But I meet a problem and really need your help:

When I am running the cavia_trpo.py and maml_trpo.py, I met an error that:

######## /Users/yurunsheng/anaconda3/envs/marl/lib/python3.8/site-packages/gym/logger.py:30: UserWarning: WARN: Box bound precision lowered by casting to float32 warnings.warn(colorize('%s: %s'%('WARN', msg % args), 'yellow')) Traceback (most recent call last): File "", line 1, in File "/Users/yurunsheng/anaconda3/envs/marl/lib/python3.8/multiprocessing/spawn.py", line 116, in spawn_main exitcode = _main(fd, parent_sentinel) File "/Users/yurunsheng/anaconda3/envs/marl/lib/python3.8/multiprocessing/spawn.py", line 126, in _main self = reduction.pickle.load(from_parent) File "/Users/yurunsheng/anaconda3/envs/marl/lib/python3.8/site-packages/cherry/envs/base.py", line 56, in getattr return getattr(self.env, attr) File "/Users/yurunsheng/anaconda3/envs/marl/lib/python3.8/site-packages/cherry/envs/base.py", line 56, in getattr return getattr(self.env, attr) File "/Users/yurunsheng/anaconda3/envs/marl/lib/python3.8/site-packages/cherry/envs/base.py", line 56, in getattr return getattr(self.env, attr) [Previous line repeated 990 more times] File "/Users/yurunsheng/anaconda3/envs/marl/lib/python3.8/site-packages/cherry/envs/base.py", line 52, in getattr def getattr(self, attr): File "/Applications/PyCharm.app/Contents/helpers/pydev/_pydevd_bundle/pydevd_trace_dispatch_regular.py", line 392, in call is_stepping = pydev_step_cmd != -1 RecursionError: maximum recursion depth exceeded in comparison Traceback (most recent call last): File "/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 2073, in main() File "/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 2067, in main globals = debugger.run(setup['file'], None, None, is_module) File "/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 1418, in run return self._exec(is_module, entry_point_fn, module_name, file, globals, locals) File "/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 1425, in _exec pydev_imports.execfile(file, globals, locals) # execute the script File "/Applications/PyCharm.app/Contents/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile exec(compile(contents+"\n", file, 'exec'), glob, loc) File "/Users/yurunsheng/Desktop/learn2learn-master/examples/rl/cavia_trpo.py", line 231, in main() File "/Users/yurunsheng/Desktop/learn2learn-master/examples/rl/cavia_trpo.py", line 145, in main env = l2l.gym.AsyncVectorEnv([make_env for _ in range(num_workers)]) File "/Users/yurunsheng/Desktop/learn2learn-master/learn2learn/gym/async_vec_env.py", line 25, in init super(AsyncVectorEnv, self).init(env_fns, queue=self.queue) File "/Users/yurunsheng/Desktop/learn2learn-master/learn2learn/gym/envs/subproc_vec_env.py", line 72, in init self.remotes[0].send(('get_spaces', None)) File "/Users/yurunsheng/anaconda3/envs/marl/lib/python3.8/multiprocessing/connection.py", line 206, in send self._send_bytes(_ForkingPickler.dumps(obj)) File "/Users/yurunsheng/anaconda3/envs/marl/lib/python3.8/multiprocessing/connection.py", line 411, in _send_bytes self._send(header + buf) File "/Users/yurunsheng/anaconda3/envs/marl/lib/python3.8/multiprocessing/connection.py", line 368, in _send n = write(self._handle, buf) BrokenPipeError: [Errno 32] Broken pipe ###########

But it run properly in maml_dice.py.

May I ask you is there any difference between cavia_trpo.py and maml_dice.py when implementing the asynchronous vectorized environment and how to solve this prbolem? I use the MacOS 10.13.6 with python 3.8.

Here is the place the bug appear:

class SubprocVecEnv(gym.Env):

def __init__(self, env_factory, queue):
    self.lock = mp.Lock()
    self.remotes, self.work_remotes = zip(*[mp.Pipe() for _ in env_factory])
    self.workers = [EnvWorker(remote, env_fn, queue, self.lock)
                    for (remote, env_fn) in zip(self.work_remotes, env_factory)]
    for worker in self.workers:
        worker.daemon = True
        worker.start()
    for remote in self.work_remotes:
        remote.close()
    self.waiting = False
    self.closed = False
    self.remotes[0].send(('get_spaces', None))  #bugs here
    observation_space, action_space = self.remotes[0].recv()
    self.observation_space = observation_space
    self.action_space = action_space

I also found @yaoxunji met the similar problem in https://github.com/learnables/learn2learn/issues/184. May our problems be similar?

Thank you so much for your attention!

Best, Runsheng

yurunsheng1 avatar Nov 29 '20 16:11 yurunsheng1

BTW, today i checked the code and found the difference is

########

def make_env():
    return gym.make(env_name)

Comparing with

def make_env():
    env = gym.make(env_name)
    env = ch.envs.ActionSpaceScaler(env)
    return env
##########

So i change the make_env() in maml_trpo.py and it seems can run normally. I found that ch.envs.ActionSpaceScaler() is just a wrapping to scale the action space. May I ask you why for the same environment particle-2D, maml_trpo.py uses ActionSpaceScaler(), while maml_dice.py doesnt?

Thank you again! Runsheng

yurunsheng1 avatar Nov 30 '20 11:11 yurunsheng1

Hello @yurunsheng1 ,

Thanks for the bug report. As you saw in the cherry issue, it seems to only affect some specific users and I don't know what the cause might be. I'd be happy to merge a fix if you find one.

seba-1511 avatar Dec 02 '20 20:12 seba-1511

Hi @seba-1511 ,

I found that just commenting out (delete) the getattr_() function in https://github.com/learnables/cherry/blob/master/cherry/envs/base.py will solve my problems.

But I am not sure whether this brute action will cause any potential risk.

May I ask you is there any usage for the getattr() function?

Thank in advance! Runsheng

yurunsheng1 avatar Dec 08 '20 05:12 yurunsheng1

Thanks for reporting @yurunsheng1 ,

It allows you to access env.property instead of env.env.property when you wrap your environment with ActionSpaceScaler. I guess the issue is with pickling. Which OS and Python version are you using?

seba-1511 avatar Dec 09 '20 00:12 seba-1511

Thank you so much for your reply! @seba-1511

I use the OS 10.13.6 and the Python 3.8.5.

BTW, If I set the breakpoint at the beginning of getattr(), I will find that the attr has been assigned _getstate _. Unfortunately, there is no _getstate _ in _dict _ (line 53), so it will go to (line 56, the first Fig).

Then the _attr _ = env, since there is no env in _dict _(line 53), it still go to line 56, conduct the same behaviors, and loop forever (the second figure).

image

image

Is it connected to pickling? Could you give more details?

Thanks again!

yurunsheng1 avatar Dec 09 '20 02:12 yurunsheng1

This observation makes sense: the infinite recursion is also what threw your original error.

I think you're right and the issue might be due to pickling. Here's a thread that proposes a fix, but maybe that instead of attr not in vars(self.env) we might have to check for hasattr(self.env, attr).

seba-1511 avatar Dec 09 '20 04:12 seba-1511

Thank you so much for useful suggestions!

It almost solve my problems!

I rewrite the _ getattr_(self, attr) as:

def _ getattr_(self, attr):
        if attr not in vars(self):
            raise AttributeError
        if attr in self.__dict__.keys():
            return getattr(self, attr)
        else:
            return getattr(self.env, attr)

However, it will still raise AttributeError .

But when I put _ getattr_(self, attr) into ActionSpaceScaler class, it can run successfully.

May I ask you whether this function is well-written?

Will it be an alternative solver to this problem if I put the function to the ActionSpaceScaler class?

Plus, if I use the hasattr(self.env, attr) as you recommended, it still cast the maximum recursion error.

def _ getattr_(self, attr):
        if hasattr(self.env, attr):
            raise AttributeError
        if attr in self.__dict__.keys():
            return getattr(self, attr)
        else:
            return getattr(self.env, attr)

yurunsheng1 avatar Dec 09 '20 10:12 yurunsheng1

I think we should try to fix this issue in Wrapper, so that other wrappers derived from it can also be used with multiprocessing. If you have time, could you try the following? (I'd do it myself but can't reproduce the error.)

def __getattr__(self, attr):
    if attr in self.__dict__.keys():
        return getattr(self, attr)
    elif attr in vars(self.env):  # also try: elif hasattr(self.env, attr):
        return getattr(self.env, attr)
    else:
        raise AttributeError

seba-1511 avatar Dec 10 '20 16:12 seba-1511

Very sorry for late reply but I was so busy these days 😭.

I ran both of the codes you suggested but it is sad that it still meets the maximum recursion bug as shown in the Figs.

But I still think the scheme you proposed are almost correct. Maybe there just still sth we ignore.

Just feel free to ask me to run the new code if you have any new idea. I am very willing to address the problems completely.

And also thank you again for giving me so many useful suggestions and helps!

image

image

yurunsheng1 avatar Dec 13 '20 17:12 yurunsheng1

Closing: inactive (and was resolved elsewhere?).

seba-1511 avatar May 29 '23 01:05 seba-1511