如何使用OpenAI Gym构建强化学习环境

622 阅读8分钟

使用OpenAI Gym构建强化学习环境

如果你曾经从事过深度学习(DL)或机器学习(ML),你就会知道监督学习和无监督学习是使用的两种关键技术。

强化学习(RL)之所以脱颖而出,是因为它被用来在现场环境中训练模型。

许多标准的OpenAI RL环境可以使你建立一个项目。它们包括CartPole-v0SpaceInvaders-v0

然而,它们可能是有局限性的,因为其中一些环境是为解决特定任务而建立的。

本教程将向你展示如何使用OpenAI Gym构建一个自定义的RL环境。具体来说,我们将建立一个RL模型来自动调节温度,使其达到一个最佳范围。

我们将使用OpenAI Gym完成这项任务,这是一个强化学习工具包,使你能够开发和比较RL算法。

前提条件

要跟上本教程,你需要熟悉。

目标

在我们开始之前,有几件事我们需要注意。

  • 首先,我们希望我们的最佳温度在37到39摄氏度之间。

  • 淋浴的长度将是60秒。如果你与其他标准RL环境合作过,你知道它们有一个情节长度。在这种情况下,我们的情节长度将是60秒。这意味着模型将试图在60秒内进入该最佳温度范围。

  • 我们的模型将执行三个动作;调高、离开和调低。我们可以把我们的温度调高,调低,或者让它保持原状。

让我们从安装我们的依赖性开始。

安装和导入所需的依赖项

我们将安装四个关键的依赖项。

  • TensorFlow 允许我们对深度学习模型进行训练和推理。
  • OpenAI Gym 允许我们建立我们的环境。
  • Keras 是一个高水平的API,使我们能够建立深度学习模型。
  • Keras-rl2 为我们提供几个预定义的代理来建立RL模型。
!pip install tensorflow==2.3.0
!pip install gym
!pip install keras
!pip install keras-rl2

下一步是将依赖关系导入我们的笔记本。

import numpy as np
from gym import Env
from gym.spaces import Box, Discrete
import random

在上面的代码中,我们已经导入了。

  • 来自OpenAI Gym的Env 类。这个占位符类允许我们在它上面建立我们的自定义环境。
  • DiscreteBox 空间来自gym.spaces 。它们允许我们定义我们可以在环境中采取的行动和当前状态。
  • numpy 来帮助我们进行数学运算。
  • random 允许我们测试我们的随机环境。

用OpenAI Gym构建自定义RL环境

我们首先创建一个CustomEnv 类。当我们把Env 传递给CustomEnv 类时,我们继承了OpenAI Gym环境类中的方法和属性。

class CustomEnv(Env):

我们已经在CustomEnv 类中实现了四个不同的函数。我们创建了__init__ 函数来初始化行动、观察和情节长度。

Discrete 空间接收一个固定的非负值范围。对于我们的情况,它需要三个行动; , , 。down (0) stay(1) up (2)

observation_space 将持有我们当前温度的数组。接下来,我们将我们的起始温度设置为38 度加上一个随机整数。最后,我们将淋浴长度设置为60 秒。

Discrete 空间不同,Box 空间更加灵活,允许我们在0100 之间传递多个值。此外,你可以用它来保存图像、音频和数据帧。

    def __init__(self):
        self.action_space = Discrete(3)
        self.observation_space = Box(low=np.array([0]), high=np.array([100]))
        self.state = 38 + random.randint(-3,3)
        self.shower_length = 60

step 函数定义了我们在采取行动后所做的事情。我们已经将我们的动作值设置为-1 。理想情况下,这意味着。

  • 如果我们将行动(0)与-1 一起应用,我们会得到一个-1 的值。这个动作将使温度降低1
  • 如果我们将动作(1)与-1 一起应用,我们会得到一个0 的值。这个动作将保持当前的温度。
  • 如果我们将动作(2)与-1 一起应用,我们会得到一个1 的值。这个动作将增加温度,1

我们也在减少淋浴的长度,1

在计算奖励时,如果温度在其最佳范围内,即37 ,和39 ,我们给出的奖励是1

如果温度不在最佳范围内,我们给出的奖励是-1 。我们的模型会一直尝试用这个函数收敛,使温度在最佳范围内。

    def step(self, action):
        self.state += action -1 
        self.shower_length -= 1 
        
        # Calculating the reward
        if self.state >=37 and self.state <=39: 
            reward =1 
        else: 
            reward = -1 
        
        # Checking if shower is done
        if self.shower_length <= 0: 
            done = True
        else:
            done = False
        
        # Setting the placeholder for info
        info = {}
        
        # Returning the step information
        return self.state, reward, done, info

我们使用render 函数来显示我们的结果。然而,我们不会在本教程中使用它。但是,这是你编写可视化代码的地方。

    def render(self):
        # This is where you would write the visualization code

我们使用reset 函数来重置我们的环境或更新每个情节。它重设了淋浴温度和时间。

    def reset(self):
        self.state = 38 + random.randint(-3,3)
        self.shower_length = 60 
        return self.state

让我们把我们的类存储在一个名为env 的自定义变量内。

env = CustomEnv()

让我们来玩玩我们的环境。

episodes = 20 #20 shower episodes
for episode in range(1, episodes+1):
    state = env.reset()
    done = False
    score = 0 
    
    while not done:
        action = env.action_space.sample()
        n_state, reward, done, info = env.step(action)
        score+=reward
    print('Episode:{} Score:{}'.format(episode, score))

输出。

Episode:1 Score:-44
Episode:2 Score:-58
Episode:3 Score:-26
Episode:4 Score:-56
Episode:5 Score:-28
Episode:6 Score:-60
Episode:7 Score:-38
Episode:8 Score:2
Episode:9 Score:-22
Episode:10 Score:-34
Episode:11 Score:-60
Episode:12 Score:-10
Episode:13 Score:-24
Episode:14 Score:-18
Episode:15 Score:22
Episode:16 Score:-12
Episode:17 Score:-28
Episode:18 Score:-40
Episode:19 Score:22
Episode:20 Score:-30

在运行了20 不同的淋浴后,我们得到不同的奖励值。记住,如果淋浴不在3739 度之间的最佳范围内,我们得到的奖励是-1

大多数奖励表明,我们远远超出了最佳温度范围。最好的奖励是22 ,这表明我们采取的一些步骤可能是在这个最佳范围内。

让我们继续使用Keras来建立一个深度学习模型。

使用Keras创建一个深度学习模型

我们首先从TensorFlow中导入所有必要的依赖关系。

import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten
from tensorflow.keras.optimizers import Adam

下一步涉及到定义我们的statesactions

states = env.observation_space.shape
actions = env.action_space.n

当你运行上面的代码时,它会给你我们的状态的形状和行动的数量。现在我们来建立我们的模型。

def build_model(states, actions):
    model = Sequential()    
    model.add(Dense(24, activation='relu', input_shape=states))
    model.add(Dense(24, activation='relu'))
    model.add(Dense(actions, activation='linear'))
    return model

在模型中,我们将温度(input_shape=states)传递给我们的深度学习模型的输入,然后返回三个不同的动作。

model = build_model(states, actions)

当你运行下面的代码时,它将给我们的模型一个总结。

model.summary()

然后,我们可以将这个模型传递给Keras-RL 模型。

用Keras-RL构建代理

我们首先从Keras-RL中导入必要的依赖项。

from rl.agents import DQNAgent
from rl.policy import BoltzmannQPolicy
from rl.memory import SequentialMemory

然后,我们使用上面一节中创建的模型建立一个DQNagent 。我们使用Boltzmann Q策略。

它在q 值上建立了一个概率规律,并返回一个根据这个规律随机选择的行动。

DQN代理使用Sequential memory 来存储各种状态、行动和奖励。

def build_agent(model, actions):
    policy = BoltzmannQPolicy()
    memory = SequentialMemory(limit=50000, window_length=1)
    dqn = DQNAgent(model=model, memory=memory, policy=policy, 
                  nb_actions=actions, nb_steps_warmup=10, target_model_update=1e-2)
    return dqn
dqn = build_agent(model, actions)
dqn.compile(Adam(lr=1e-3), metrics=['mae'])
dqn.fit(env, nb_steps=60000, visualize=False, verbose=1)

在上面的代码中,我们的自定义RL环境现在可以训练我们的dqn 模型来设置正确的最佳温度。

我们训练代理60000步,但你可以训练更长时间以产生更好的结果。你可以使用nb_steps 参数来改变它。

如果你碰巧遇到这个属性错误,Sequential 对象没有属性_compile_time_distribution_strategy ,请确保在build_model 函数之后包括del model ,然后你可以重新运行单元。

60000 步之后,我们得到的奖励是-0.3908 。在最初的10000 步中,我们开始的奖励是-0.6412 。最后减少到-0.3908

该模型并不完美,但当我们增加训练步骤的数量时,你会得到更好的结果(正的奖励)。

正值意味着温度在其最佳温度之内。你可以尝试在创建模型时加入一些随机数字,看看你的代理在训练后会有什么表现。

测试我们的自定义RL环境

训练完我们的模型后,我们就可以去测试它了。让我们写下以下代码。

results = dqn.test(env, nb_episodes=150, visualize=False)
print(np.mean(results.history['episode_reward']))

经测试,我们的平均奖励值为59 。这是一个高奖励。我们的模型表现良好。然而,当你在你的模型中加入一些噪音时,情况可能就不是这样了。

这是一个理想的例子,可能不代表真实情况,即你的朋友随机调整淋浴温度。试着做实验,看看你能得到什么。

总结

在本教程中,我们使用OpenAI Gym和Keras构建了一个自定义的RL环境。