首先声明这种方式的最大问题:
1、如果你的强化学习环境既包含连续动作,也包含离散动作,本文不敢确保是否可以正常使用,遇到过报错情况,目前我用的全部是连续,如果有人用了功能正常,欢迎评论区告知;
2、如果你的强化学习问题是多智能体方向的研究,放弃本文,gym_unity暂不支持多智能体训练,要么找办法实现mlagents外接算法(目前没找到能用的办法),要么用unity的mlagents自带PPO、SAC等。
开始这种方式之前,请先确认你已安装gym_unity:
pip3 install gym_unity
或者进入到ml-agents本地文件夹,进入gym_unity文件夹下,执行本地安装:
pip3 install -e .
既然都已经搜索这个问题了,那就是对强化学习的基本概念、gym库以及unity提供的强化学习工具MLAgents有了一定的了解,并且是已经去过github上的mlagents官方了,在那里可以看到大量官方说明文档,关于如何在unity开启一个训练场景,可以查看官方链接,官方说的很清楚(github上不去的可能要科学上网)
或者参照B站up主三次元魔法师的视频教程(在此感谢up,我的场景制作就是照着这个视频来的,也是因为看到有人用unity的mlagents还做视频,才继续用它来做强化学习的环境仿真)
创建好之后的小球追立方体场景如下图:
下面开始讲解Python代码如何使用这个建立好的场景,直接贴代码吧
from gym_unity.envs import UnityToGymWrapper
from mlagents_envs.environment import UnityEnvironment
max_step = 1000 # 整个训练的最大总步数
max_step_per_episode = 200 # 每个episode最大探索步数
if __name__ == '__main__':
total_step = 0
env_path = None
# env_path = "你的unity场景编译后的exe文件路径"
unity_env = UnityEnvironment(env_path)
"""
参数allow_multiple_obs=False代表不启用多种类型的观察值,因为我的状态空间没有包括视觉,
所以设为False,如果你的用到了视觉,根据官方文档,必须设为True才可正常接收到unity的视觉
状态信息
"""
env = UnityToGymWrapper(unity_env, allow_multiple_obs=False)
state_dim = env.observation_space.shape[0] # 获取状态空间的维度
action_dim = env.action_space.shape[0] # 获取动作空间的维度
while total_step < max_step: # 这里是按照最大总步数结束训练的,当然你也可以改成指定最大episode次数
state = env.reset()
current_ep_reward = 0
for t in range(1, max_step_per_episode + 1):
# action = agent.get_action(state) # 对于外接算法,这里的action应该是你的强化学习算法给出
action = [0.1, 0.05] # 时间原因,只测试Python与unity Editor对接功能,这里就固定了action
state_, reward, done, _ = env.step(action)
if done:
break
这里面有个env_path的定义,如果为None(与直接执行方法unity_env = UnityEnvironment()没有区别),这时候代码执行后,在终端可以看到以下信息,代表此时程序开始监听unity端口(了解通信的可能就猜到了,端口被占用了,就不可能启动第二个,所以训练就只能开一个)
这个时候去Unity Editor,回到前文中建立好的小球追立方体场景,首先在开始之前一定要确认下面几个关键点,否则可能导致Unity报错或者警告信息,甚至无法正常启动小球:
1.直接点击播放按钮,测试小球是否可以手动控制移动;
2.查看Unity Editor的Inspector面板,检查其中Behavior Parameters的动作空间、观察空间是否与你智能体挂载的C#脚本定义一致;
(Space Size 表示观察空间维度,下面的Continuous Action代表连续型动作维度,Discrete Branch表示离散动作维度。注意:如果连续动作和离散动作同时存在,我在执行后面Python程序时报错)
附:C#脚本中如何查看状态空间和动作空间维度:
1)去CollectObservations查看状态空间维度,因此这个小球的观察空间定义为8维
2)去Heuristic查看动作空间维度,因此这里定义的是2维。
3.Max Step确认一下,别写成0,否则会导致无法移动。
检查过后,点击Unity Editor上面的播放按钮即可看到Python代码控制了小球的运动(没法上传录制的视频,到这应该能看到小球运动了),因为我们在Python代码中的action只是为了测试而设置定值,可以看到小球朝着固定方向移动,到这里说明你已经成功了,只不过这时候的Python代码必须与Unity Editor同时开启运行,显然Editor的动画演示效果占用了大量内存、CPU和GPU性能,所以Unity还提供了无可视化界面的Python-Unity交互训练方式,见下文。
这里还是想再次强调一遍,将自定义的强化学习场景编译为exe文件之前,首先确认一下上面的Inspector面板参数,状态空间、动作空间维度是否与场景中智能体挂载的C#脚本定义一致。
确认无误后,开始编译exe过程:
1.在Unity Editor,点击File->Build Settings…,选中要编译的场景,勾选Server Build,然后点开左下角的Player Settings…
2.在打开的Player Settings…窗口内,一定要选中Run In BackGround* !!!
3.修改和确认以上设置之后,点击Build开始编译,此时弹出选择文件夹,这里新建了Demo文件夹
4.选择,然后开始编译,慢慢等,根据电脑配置和你的场景大小复杂程度,等待时间会不同:
5.编译完成,自动打开所在路径,也就是刚刚选择的Demo文件夹所在位置:
这里带有Unity图标的exe文件,就是我们的场景对应的exe了,但是当你双击运行的时候,会发现只是个命令行,没有显示你的场景画面,这就对了,因为编译之前设置的那一通,是让他以server方式后台运行,无可视化界面(走这一步不就是为了不要可视化节省电脑资源嘛),然后复制这个exe文件的路径,比如这里是F:\Projects\UnityProjects\ExecutableExamples\Demo\Off-Road.exe,提醒一下不要看到是exe就复制,我就搞错了一次,复制成了下面那个UnityCrashHandler64.exe,半天愣是没跑起来,还不知道哪的错=.=|||
然后把这个路径粘贴进Python代码,也就是之前的env_path路径:
env_path = None
现在变成了(注意这里的路径换成了双斜线):
env_path = "F:\\Projects\\UnityProjects\\ExecutableExamples\\Demo\\Off-Road.exe"
如果没有可视化界面,我们不知道智能体(小球)是否正常工作,所以在原来的Python代码里面加个观察空间(observation)的输出,同时也是为了检查环境返回的观察信息是否符合期望,新的完整代码就成了:
from gym_unity.envs import UnityToGymWrapper
from mlagents_envs.environment import UnityEnvironment
max_step = 1000 # 整个训练的最大总步数
max_step_per_episode = 200 # 每个episode最大探索步数
if __name__ == '__main__':
total_step = 0
env_path = "F:\\Projects\\UnityProjects\\ExecutableExamples\\Demo\\Off-Road.exe" # 改成你自己的exe文件路径
"""
勾选Run In Background*的exe无法显示图形界面
不勾选Run In Background*的exe可以用no_graphics参数决定是否显示
"""
unity_env = UnityEnvironment(env_path,
base_port=5000, # 端口自定义
seed=0, # 随机种子
no_graphics=True, # 显示图形界面,True不显示,False显示
timeout_wait=60,) # 超时时间设置
env = UnityToGymWrapper(unity_env, allow_multiple_obs=False)
state_dim = env.observation_space.shape[0] # 获取状态空间的维度
action_dim = env.action_space.shape[0] # 获取动作空间的维度
while total_step < max_step: # 这里是按照最大总步数结束训练的,当然你也可以改成指定最大episode次数
state = env.reset()
current_ep_reward = 0
for t in range(1, max_step_per_episode + 1):
# action = agent.get_action(state) # 对于外接算法,这里的action应该是你的强化学习算法给出
action = [0.1, 0.05] # 时间原因,只测试Python与unity Editor对接功能,这里就固定了action
state_, reward, done, _ = env.step(action)
print(state_)
if done:
break
然后运行程序,可以看到随着执行,不断输出小球每一次执行action之后获取的观察值信息(按照定义的收到的就是8维),同时你还可以看到一行WARNING信息,他告诉了你那个allow_multiple_obs参数的作用:
到这里说明你的exe正常,Python可以使用该环境的exe文件训练了,因为转成了gym的形式,所以只要你会用gym写自己的算法,无论是PPO、DDPG、SAC等等,理论上来说都不是问题了。但实际上,gym_unity目前还不完善,有一些限制(已知的明确的一点就是,这种方式下,unity编写的环境无法支持多智能体,无论是单一场景包含多人对抗的,还是你在Unity Editor复制了多个场景想用来加速训练,都不行了),但是相信这个AI盛行的时代,Unity也懂得顺应潮流,也许不久的将来也会提供更全面的gym环境支持。
PS:其实github上MLAgents官方都有,可我自己现在回去找都没找到原文,,他文档实在是太多了啊我的天,写的仓促,有错请指正。