模块代码:

import multiprocessing as mp

import numpy as np
from .vec_env import VecEnv, CloudpickleWrapper, clear_mpi_env_vars def worker(remote, parent_remote, env_fn_wrappers):
def step_env(env, action):
ob, reward, done, info = env.step(action)
if done:
ob = env.reset()
return ob, reward, done, info parent_remote.close()
envs = [env_fn_wrapper() for env_fn_wrapper in env_fn_wrappers.x]
try:
while True:
cmd, data = remote.recv()
if cmd == 'step':
remote.send([step_env(env, action) for env, action in zip(envs, data)])
elif cmd == 'reset':
remote.send([env.reset() for env in envs])
elif cmd == 'render':
remote.send([env.render(mode='rgb_array') for env in envs])
elif cmd == 'close':
remote.close()
break
elif cmd == 'get_spaces_spec':
remote.send(CloudpickleWrapper((envs[0].observation_space, envs[0].action_space, envs[0].spec)))
else:
raise NotImplementedError
except KeyboardInterrupt:
print('SubprocVecEnv worker: got KeyboardInterrupt')
finally:
for env in envs:
env.close() class SubprocVecEnv(VecEnv):
"""
VecEnv that runs multiple environments in parallel in subproceses and communicates with them via pipes.
Recommended to use when num_envs > 1 and step() can be a bottleneck.
"""
def __init__(self, env_fns, spaces=None, context='spawn', in_series=1):
"""
Arguments: env_fns: iterable of callables - functions that create environments to run in subprocesses. Need to be cloud-pickleable
in_series: number of environments to run in series in a single process
(e.g. when len(env_fns) == 12 and in_series == 3, it will run 4 processes, each running 3 envs in series)
"""
self.waiting = False
self.closed = False
self.in_series = in_series
nenvs = len(env_fns)
assert nenvs % in_series == 0, "Number of envs must be divisible by number of envs to run in series"
self.nremotes = nenvs // in_series
env_fns = np.array_split(env_fns, self.nremotes)
ctx = mp.get_context(context)
self.remotes, self.work_remotes = zip(*[ctx.Pipe() for _ in range(self.nremotes)])
self.ps = [ctx.Process(target=worker, args=(work_remote, remote, CloudpickleWrapper(env_fn)))
for (work_remote, remote, env_fn) in zip(self.work_remotes, self.remotes, env_fns)]
for p in self.ps:
p.daemon = True # if the main process crashes, we should not cause things to hang
with clear_mpi_env_vars():
p.start()
for remote in self.work_remotes:
remote.close() self.remotes[0].send(('get_spaces_spec', None))
observation_space, action_space, self.spec = self.remotes[0].recv().x
self.viewer = None
VecEnv.__init__(self, nenvs, observation_space, action_space) def step_async(self, actions):
self._assert_not_closed()
actions = np.array_split(actions, self.nremotes)
for remote, action in zip(self.remotes, actions):
remote.send(('step', action))
self.waiting = True def step_wait(self):
self._assert_not_closed()
results = [remote.recv() for remote in self.remotes]
results = _flatten_list(results)
self.waiting = False
obs, rews, dones, infos = zip(*results)
return _flatten_obs(obs), np.stack(rews), np.stack(dones), infos def reset(self):
self._assert_not_closed()
for remote in self.remotes:
remote.send(('reset', None))
obs = [remote.recv() for remote in self.remotes]
obs = _flatten_list(obs)
return _flatten_obs(obs) def close_extras(self):
self.closed = True
if self.waiting:
for remote in self.remotes:
remote.recv()
for remote in self.remotes:
remote.send(('close', None))
for p in self.ps:
p.join() def get_images(self):
self._assert_not_closed()
for pipe in self.remotes:
pipe.send(('render', None))
imgs = [pipe.recv() for pipe in self.remotes]
imgs = _flatten_list(imgs)
return imgs def _assert_not_closed(self):
assert not self.closed, "Trying to operate on a SubprocVecEnv after calling close()" def __del__(self):
if not self.closed:
self.close() def _flatten_obs(obs):
assert isinstance(obs, (list, tuple))
assert len(obs) > 0 if isinstance(obs[0], dict):
keys = obs[0].keys()
return {k: np.stack([o[k] for o in obs]) for k in keys}
else:
return np.stack(obs) def _flatten_list(l):
assert isinstance(l, (list, tuple))
assert len(l) > 0
assert all([len(l_) > 0 for l_ in l]) return [l__ for l_ in l for l__ in l_]

该模块实现多进程下的多环境交互,这里假设每个进程可以与多个环境进行串行的交互,每个进程可以交互的环境个数为in_series,默认该值为1。

每个子进程的交互的环境个数为nremotes。

self.nremotes = nenvs // in_series

将生成环境env的函数进行nremotes个数的划分:

env_fns = np.array_split(env_fns, self.nremotes)

在这个模块中多进程使用multiprocessing来实现的。

进程自己的信息传递使用Pipe管道来实现:

self.remotes, self.work_remotes = zip(*[ctx.Pipe() for _ in range(self.nremotes)])

从管道的生成可以看出一个有nremotes个子进程,也为其分别生成了nremotes个数个Pipe。

每个pipe都有两个端口,这里使用remotes和work_remotes来表示。

这里说明下pipe的两个端口都是可以进行读信息和存信息的操作的,不过如果有多个进程同时操作同一个端口会导致消息的操作出错,这样的话如果一个管道设计固定为两个进程进行消息传递可以自行指定两个端口分别给两个进程进行操作。

一个pipe的两个端口就像一个真实管道的两个端口一样。

生成nremotes个子进程,分别将nremotes个管道的两端和生成环境的函数可序列化包装后传递给子进程:

self.ps = [ctx.Process(target=worker, args=(work_remote, remote, CloudpickleWrapper(env_fn)))
for (work_remote, remote, env_fn) in zip(self.work_remotes, self.remotes, env_fns)]

在这个类的设计中为1个主进程分别和nremotes个子进程进行交互。

在父进程中只对self.remotes进行操作,对其进行消息的读取和存储。

在子进程中只对self.work_remotes进行操作,对其进行消息的读取和存储。

在父进程中关闭对self.work_remotes的操作:

for remote in self.work_remotes:
remote.close()

在子进程中关闭对self.remotes的操作:

parent_remote.close()

在父进程中生成多个子进程,并设置子进程的模式为daemon,同时在生成子进程时要清空mpi的环境变量否则mpi的引入会导致子进程的挂起:

for p in self.ps:
p.daemon = True # if the main process crashes, we should not cause things to hang
with clear_mpi_env_vars():
p.start()

函数:

def step_async(self, actions):
def step_async(self, actions):

对动作进行划分使用pipe传递给对应的子进程并从管道中取出子进程返回的消息。

在对收到的observation后需要做处理,如果observation为dict类型则需要将多个环境的observation的对应的key保持不变将value进行堆叠,reward,done信息也是使用np.array进行堆叠,info则用list做集合。

如果各个环境的observation为np.array类型则对他们进行np.stack堆叠。

在图像绘制上继承父类vec_env.py中的特性:

    def render(self, mode='human'):
imgs = self.get_images()
bigimg = tile_images(imgs)
if mode == 'human':
self.get_viewer().imshow(bigimg)
return self.get_viewer().isopen
elif mode == 'rgb_array':
return bigimg
else:
raise NotImplementedError def get_viewer(self):
if self.viewer is None:
from gym.envs.classic_control import rendering
self.viewer = rendering.SimpleImageViewer()
return self.viewer

subproc_vec_env.py中的:

    def get_images(self):
self._assert_not_closed()
for pipe in self.remotes:
pipe.send(('render', None))
imgs = [pipe.recv() for pipe in self.remotes]
imgs = _flatten_list(imgs)
return imgs

可以看到render函数也是将收集到的各个子进程的图片拼接后进行绘制。

在worker函数中:

    def step_env(env, action):
ob, reward, done, info = env.step(action)
if done:
ob = env.reset()
return ob, reward, done, info

如果在单个进程中单个环境的done=True,则直接进行env.rest(),返回的状态为reset后的observation。

close函数:

    def close(self):
if self.closed:
return
if self.viewer is not None:
self.viewer.close()
self.close_extras()
self.closed = True
    def close_extras(self):
self.closed = True
if self.waiting:
for remote in self.remotes:
remote.recv()
for remote in self.remotes:
remote.send(('close', None))
for p in self.ps:
p.join()

在close操作时要通知子进程进行close操作,在主进程中需要阻塞等待子进程。

========================================

baselines算法库common/vec_env/subproc_vec_env.py模块分析的更多相关文章

  1. 图像滤镜艺术---ZPhotoEngine超级算法库

    原文:图像滤镜艺术---ZPhotoEngine超级算法库 一直以来,都有个想法,想要做一个属于自己的图像算法库,这个想法,在经过了几个月的努力之后,终于诞生了,这就是ZPhotoEngine算法库. ...

  2. scikit-learn 支持向量机算法库使用小结

    之前通过一个系列对支持向量机(以下简称SVM)算法的原理做了一个总结,本文从实践的角度对scikit-learn SVM算法库的使用做一个小结.scikit-learn SVM算法库封装了libsvm ...

  3. 【Python】【Web.py】详细解读Python的web.py框架下的application.py模块

    详细解读Python的web.py框架下的application.py模块   这篇文章主要介绍了Python的web.py框架下的application.py模块,作者深入分析了web.py的源码, ...

  4. 第三百零六节,Django框架,models.py模块,数据库操作——创建表、数据类型、索引、admin后台,补充Django目录说明以及全局配置文件配置

    Django框架,models.py模块,数据库操作——创建表.数据类型.索引.admin后台,补充Django目录说明以及全局配置文件配置 数据库配置 django默认支持sqlite,mysql, ...

  5. 使用织梦开源的分词算法库编写的YII获取分词扩展

    在编辑文章中,很多时候都需要自动根据文章内容获取关键字的功能,因此,本文主要是说明如何在yii中使用织梦开源的分词算法编写一个独立的扩展,可以在不同的模块中使用,步骤如下: 1 到这里下载其他朋友整理 ...

  6. 四 Django框架,models.py模块,数据库操作——创建表、数据类型、索引、admin后台,补充Django目录说明以及全局配置文件配置

    Django框架,models.py模块,数据库操作——创建表.数据类型.索引.admin后台,补充Django目录说明以及全局配置文件配置 数据库配置 django默认支持sqlite,mysql, ...

  7. mahout算法库(四)

    mahout算法库 分为三大块 1.聚类算法 2.协同过滤算法(一般用于推荐) 协同过滤算法也可以称为推荐算法!!! 3.分类算法 算法类 算法名 中文名 分类算法               Log ...

  8. 操作MySQL-数据库的安装及Pycharm模块的导入

    操作MySQL-数据库的安装及Pycharm模块的导入 1.基于pyCharm开发环境,在CMD控制台输入依次输入以下步骤: (1)pip3 install PyMySQL  < 安装 PyMy ...

  9. 痞子衡嵌入式:对比MbedTLS算法库纯软件实现与i.MXRT上DCP,CAAM硬件加速器实现性能差异

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是MbedTLS算法库纯软件实现与i.MXRT上DCP,CAAM硬件加速器实现性能差异. 近期有 i.MXRT 客户在集成 OTA SBL ...

  10. snowland-smx密码算法库

    snowland-smx密码算法库 一.snowland-smx密码算法库的介绍 snowland-smx是python实现的国密套件,对标python实现的gmssl,包含国密SM2,SM3,SM4 ...

随机推荐

  1. 使用嵌套的ScriptableObject及ReorderableList创建习题持久化数据

    使用嵌套的ScriptableObject及ReorderableList创建习题持久化数据 效果展示 题集持久化数据:存储题目,可以直接在inspector面板上创建对应的问题子项 问题持久化数据 ...

  2. python 使用pandas修改数据到excel,报“SettingwithCopyWarning A value is trying to be set on a copy of a slice from a DataFrame”的解决方法

    场景: 通过pandas模块,将测试数据回写到excel,测试数据有写到excel文件,但控制台输出警告信息如下 警告: SettingwithCopyWarning A value is tryin ...

  3. Masonry在视图相对关系处理中的各种“offset”

    如果我们需要设置一个view在另一个view的右边缘距离一定距离的地方,利用Masonry这么写: [a mas_makeConstraints:^(MASConstraintMaker *make) ...

  4. ISCSI配置与挂载

    ISCSI介绍 iSCSI使用 TCP/IP 协议,来提供网络存储. 客户端挂载后,可以对其进行分区,进行格式化,就好像是安装在本机上的硬盘一样. 为了保证传输速率,通常采用光纤. 配置环境 Cent ...

  5. EthernetIP IO从站设备数据 转opc ua项目案例

    1 案例说明 设置网关采集EthernetIP IO设备数据 把采集的数据转成opc ua协议转发给其他系统. 2 VFBOX网关工作原理 VFBOX网关是协议转换网关,是把一种协议转换成另外一种协议 ...

  6. Android 编译系统 defconfig文件的确定

    Android 编译系统 defconfig文件的确定 背景 经常在驱动改动的时候,同时改动2个文件,才知道他们分别对应不同的编译结果. 路径 对应版本 kernel/msm-4.4/arch/arm ...

  7. 化合物同位素理论同位素分布计算软件Isopro 3.0

    大家好,今天分享一款软件,即可以计算化合物理论同位素分布的软件Isopro 3.0.在做质谱的实验时,特别对合成的化合物进行质量表征时,往往要求ppm绝对值在5以内,对质谱的分辨率要求很高.对于小分子 ...

  8. 【论文阅读】IROS2017: Voxblox & RAL2019: Voxblox++

    IROS2017: Voxblox & RAL2019: Voxblox++ Status: Finished Type: RAL Year: 2019 组织/Sensor: ETH-ASL ...

  9. Centos7搭建Minio环境(配置开机自启)

    Minio 添加环境变量 # 设置控制台账号 最少3位 export MINIO_ACCESS_KEY=admin # 设置密码 最少8位 export MINIO_SECRET_KEY=123456 ...

  10. Spring5.X的注解配置项目

    pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...