强化学习实战1:OpenAI Gym 实验环境介绍

环境配置

我的 torch 版本是 2.3.0,然后 gym 版本是 0.22.0,python 版本是 3.8 ,pygame 版本是 2.6.0 。

首先安装一下 gym:

pip install gym==0.22.0 -i https://pypi.tuna.tsinghua.edu.cn/simple

然后安装一下 pygame:

pip install pygame -i https://pypi.tuna.tsinghua.edu.cn/simple

都安装好之后,可以写上下面的测试代码看是否能正常弹出一个游戏画面:

import gym  
env = gym.make('CartPole-v1')  
for _ in range(1000):  
    env.reset()  
    for _ in range(100):  
        env.render()  
        env.step(env.action_space.sample())  
env.close()

如果一切顺利,你将看到一个倒立摆小车在屏幕上移动,并随着时间步的推移而逐渐失去平衡。

环境介绍:以 CartPole-v0 为例

import gym

# 1、介绍倒立摆基本的游戏环境

env = gym.make('CartPole-v0')

# 打印此时的游戏环境是什么 :<TimeLimit<OrderEnforcing<CartPoleEnv<CartPole-v0>>>>
print(env)

# 打印其 action space:Discrete(2)
print(env.action_space)

# 对该动作空间做随机采样,也就是随机取出其中一个动作,输出为 0 或 1,也就是往左或者往右
print(env.action_space.sample())

# 打印观测空间,也就算 state space 状态空间,是一个意思
# 对于这个游戏环境,其 state space 有四个:
# 下标0表示小车位置,1表示小车速度,2表示锤的偏转角度,3表示锤的偏转角速度
# 补充:状态空间通常包含环境的完整信息,而观测空间可能只是部分信息;
# 在某些情况下,观测空间和状态空间可能是相同的,即智能体可以完全观察到环境的状态,
# 这样的环境被称为完全可观测(Fully Observable)。
# 在这个例子中,二者等价。
# 输出:Box([-4.8000002e+00 -3.4028235e+38 -4.1887903e-01 -3.4028235e+38],
#      [4.8000002e+00 3.4028235e+38 4.1887903e-01 3.4028235e+38], (4,), float32)
print(env.observation_space)

# 然后可以打印看一下其边界情况
# 输出:[-4.8000002e+00 -3.4028235e+38 -4.1887903e-01 -3.4028235e+38]
print(env.observation_space.low)
# 输出:[4.8000002e+00 3.4028235e+38 4.1887903e-01 3.4028235e+38]
print(env.observation_space.high)

# 我们同样可以对状态空间进行随机采样
print(env.observation_space.sample())

"""
我们并不直接操作状态,我们操作或者说选择的是 action,我们在 action space 中基于一定策略会选择一个 action。
然后作用在这个环境上使得环境状态转移到一个新的环境状态。
状态空间和动作空间环境已经给定了,此外还需要什么?我们还需要做下面两件事情:

当我们在当前 t 时刻(意味着此时状态为 st)选择了一个 action at,那么
我们将会得到一个 reward,称为 rt,同时因为在 st 状态下采取了 at 行为,状态 st 也将转移到 s(t+1) 状态下。

而实际上环境已经给了一个 step 函数,在这个函数内完成了上述两个步骤。
"""

# 来查看一下 step 函数内容
help(env.step)
# 输出如下
"""
step(action) method of gym.wrappers.time_limit.TimeLimit instance
    Run one timestep of the environment's dynamics. When end of
    episode is reached, you are responsible for calling `reset()`
    to reset this environment's state.
    
    Accepts an action and returns a tuple (observation, reward, done, info).
    
    Args:
        action (object): an action provided by the agent
    
    Returns:
        observation (object): agent's observation of the current environment
        reward (float) : amount of reward returned after previous action
        done (bool): whether the episode has ended, in which case further step() calls will return undefined results
        info (dict): contains auxiliary diagnostic information (helpful for debugging, logging, and sometimes learning)
"""

上面的代码是 CartPole 环境的一些介绍和简单使用,而下面的代码则是采用上面介绍的内容让 action 和 environment 交互实战感受一下:

# 2、尝试用 action 和 env 交互
done = False
score = 0
# env.reset()函数的主要作用是将环境重置到其初始状态,并返回这个初始状态给调用者
state = env.reset()

while not done:
    # 可视化窗口展现
    env.render()
    # 从 action space 中随机采取一个 action
    action = env.action_space.sample()
    # 将该 action 传入 env 的 step 中完成 reward 的计算和状态转移
    observation, reward, done, info = env.step(action)
    # 统计一下这一轮下来总共获得了多少分数
    score += reward
print(f'total reward:{score}')

运行结果如下(两部分代码的运行结果一起打印了):

在这里插入图片描述

另外如果够专注的话,是能够看到有个画面在屏幕上一闪而过的,对于这个闪退的问题我们后面会解决。

解决闪退问题:将env保存为一个 mp4 / gif

之前的代码闪退太快,来看一下一个比较缓慢的效果:

import gym
import time
env_name = "CartPole-v0"
env = gym.make(env_name)

state = env.reset()
done = False
total_reward = 0

while not done:
    env.render()
    action = env.action_space.sample()
    # 打印随机采样的action
    print(action)
    observation, reward, done, info = env.step(action)
    total_reward += reward
    # 加一点延迟
    time.sleep(0.2)
print(total_reward)

运行效果如下:

在这里插入图片描述

因为渲染出来的摆锤效果是动态的,因此这里就不再展示,但是你应该和我的效果一样,是能够看到它摆的过程的。

接下来我们要做的事情就是将这么一个动态变化的过程给保存下来,怎么保存?其实重点在 env 中的 render 方法,默认情况下,我们调用 render 方法其有一个参数 mode,默认值为 “human”,其返回值为一个个 bool 值,即是否打开。

此时我们可以将这个默认值改成 “rgb_array”,此时 render 的返回将是当前时刻图像的 rgb 数值数组,这样的话我们就实现了将其放入内存里面的操作。

import gym
import time
env_name = "CartPole-v0"
env = gym.make(env_name)

state = env.reset()
done = False
total_reward = 0
# 定义一个帧数组,用来存下每一帧的 rgb 数据
frames = []
while not done:
    frames.append(env.render(mode="rgb_array"))
    action = env.action_space.sample()
    # 打印随机采样的action
    print(action)
    observation, reward, done, info = env.step(action)
    total_reward += reward
    # 加一点延迟
    time.sleep(0.2)
print(total_reward)
# 再打印一下 frames 数组的一些信息,以更形象化的理解它
print(len(frames))
print(frames[0].shape)

运行结果如下:

在这里插入图片描述

可以看到这一次只进行了十四轮小锤就倒了,因此 frames 数组的大小为 14,然后每一帧图片的形状为 (400, 600, 3),一个彩色图像。

接下来我们就可以通过一些第三方的工具包,来实现保存为 mp4 的功能了:

# 引入将 env 保存为 mp4 所需要的包,主要是一个图表包 pyplot 和一个动画包 animation
import matplotlib.pyplot as plt
from matplotlib import animation

def display_frames_to_video(frames):
    plt.figure(figsize=(frames[0].shape[0]/72, frames[0].shape[1]/72), dpi=72)
    plt.axis("off")
    patch = plt.imshow(frames[0])

    def animate(i):
        patch.set_data(frames[i])

    anim = animation.FuncAnimation(plt.gcf(), animate, frames=range(len(frames)),interval=50)
    anim.save("cartpole.mp4")
	# 保存为 gif 也很简单:
	# anim.save("cartpole.gif", writer="imagemagick")
display_frames_to_video(frames)

提一嘴:plot 是英文图表的意思,animation 是英文定格动画的意思

运行结果如下:

在这里插入图片描述

可以看见已经生成了我们想要的 mp4 文件。

对于上面的这一段代码,使用 GPT 给出了一个比较详尽的解释,知道怎么用就行:

在这里插入图片描述
在这里插入图片描述

对于动画处理这种标准工具代码的流程是比较固定的,大概知道怎么回事就行,用的时候直接 CV。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在地球迷路的怪兽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值