OpenAI Gym使用巍沙、rendering畫圖

gym開源庫:包含一個(gè)測試問題集,每個(gè)問題成為環(huán)境(environment)荷鼠,可以用于自己的RL算法開發(fā)句携。這些環(huán)境有共享的接口,允許用戶設(shè)計(jì)通用的算法允乐。其包含了deep mind 使用的Atari游戲測試床矮嫉。

在強(qiáng)化學(xué)習(xí)中有2個(gè)基本概念,一個(gè)是環(huán)境(environment)牍疏,稱為外部世界蠢笋,另一個(gè)為智能體agent(寫的算法)。agent發(fā)送action至environment鳞陨,environment返回觀察和回報(bào)昨寞。

Gym官方文檔

Hello gym

import gym
# 創(chuàng)建一個(gè)小車倒立擺模型
env = gym.make(‘CartPole-v0’)
# 初始化環(huán)境
env.reset()
# 刷新當(dāng)前環(huán)境,并顯示
for _ in range(1000):
    env.render()
    env.step(env.action_space.sample()) # take a random action

[圖片上傳失敗...(image-f6cf84-1570442880862)]

設(shè)計(jì)理念圖,一個(gè)環(huán)境的step函數(shù)返回需要的信息厦滤,有4種返回值

  • observation
  • reward
  • done :判斷是否到了重新設(shè)定(reset)環(huán)境
  • info :用于調(diào)試的診斷信息援岩,有時(shí)也用于學(xué)習(xí),但智能體(agent )在正式的評價(jià)中不允許使用該信息進(jìn)行學(xué)習(xí)掏导。

該進(jìn)程通過調(diào)用reset()來啟動享怀,它返回一個(gè)初始observation。 所以之前代碼的更恰當(dāng)?shù)姆椒ㄊ亲袷?strong>done的標(biāo)志:

空間(Spaces)

在上面的例子中趟咆,已經(jīng)從環(huán)境的動作空間中抽取隨機(jī)動作凹蜈。但這些行動究竟是什么呢? 每個(gè)環(huán)境都帶有action_spaceobservation_space對象忍啸。這些屬性是Space類型仰坦,它們描述格式化的有效的行動和觀察。

import gym
env = gym.make('CartPole-v0')
# 離散空間允許固定范圍的非負(fù)數(shù)计雌,因此在這種情況下悄晃,有效的動作是0或1. 
print(env.action_space)
#> Discrete(2)
print(env.observation_space)
#> Box(4,)

Box空間表示一個(gè)n維box,所以有效的觀察將是4個(gè)數(shù)字的數(shù)組凿滤。 也可以檢查Box的范圍:

print(env.observation_space.high)
#> array([ 2.4       ,         inf,  0.20943951,         inf])
print(env.observation_space.low)
#> array([-2.4       ,        -inf, -0.20943951,        -inf])

這種內(nèi)省可以幫助編寫適用于許多不同環(huán)境的通用代碼妈橄。box和discrete是最常見的空間。你可以從一個(gè)空間中取樣翁脆,或者檢查某物是否屬于它:

from gym import spaces
space = spaces.Discrete(8) # Set with 8 elements {0, 1, 2, ..., 7}
x = space.sample()
assert space.contains(x)
assert space.n == 8

Env.render畫圖

參考Gym 簡單畫圖

# 首先眷蚓,導(dǎo)入庫文件(包括gym模塊和gym中的渲染模塊)
import gym
from gym.envs.classic_control import rendering

# 我們生成一個(gè)類,該類繼承 gym.Env. 同時(shí)反番,可以添加元數(shù)據(jù)沙热,改變渲染環(huán)境時(shí)的參數(shù)
class Test(gym.Env):
    # 如果你不想改參數(shù)叉钥,下面可以不用寫
    metadata = {
        'render.modes': ['human', 'rgb_array'],
        'video.frames_per_second': 2
    }
# 我們在初始函數(shù)中定義一個(gè) viewer ,即畫板
    def __init__(self):
        self.viewer = rendering.Viewer(600, 400)   # 600x400 是畫板的長和框
    # 繼承Env render函數(shù)
    def render(self, mode='human', close=False):
        # 下面就可以定義你要繪畫的元素了
        line1 = rendering.Line((100, 300), (500, 300))
        line2 = rendering.Line((100, 200), (500, 200))
        # 給元素添加顏色
        line1.set_color(0, 0, 0)
        line2.set_color(0, 0, 0)
        # 把圖形元素添加到畫板中
        self.viewer.add_geom(line1)
        self.viewer.add_geom(line2)

        return self.viewer.render(return_rgb_array=mode == 'rgb_array')
    
# 最后運(yùn)行
if __name__ == '__main__':
    t = Test()
    while True:
        t.render()

△.值得注意的是篙贸,畫板的水平方向是 x 軸投队, 垂直方向是 y 軸, 且原點(diǎn)在左下角

畫個(gè)圓

    def render(self, mode='human', close=False):
        # 畫一個(gè)直徑為 30 的園
        circle = rendering.make_circle(30)
        
        # 添加一個(gè)平移操作
        circle_transform = rendering.Transform(translation=(100, 200))
        # 讓圓添加平移這個(gè)屬性,
        circle.add_attr(circle_transform)
        
        self.viewer.add_geom(circle)
        return self.viewer.render(return_rgb_array=mode == 'rgb_array')

△注意.是圓心在平移

RingViewr

研究rings時(shí)寫的render

import gym
from gym.envs.classic_control import rendering
import time
import numpy as np
import random


class ringViewer(rendering.Viewer):
    '''
    畫板,直接繼承自rendering.Viewer
    '''
    def __init__(self,width, height, display=None):
        super(ringViewer, self).__init__(width, height, display=None)

    @staticmethod
    def pos2loc(pos=0):
        '''
        根據(jù)位置索引確定畫圖坐標(biāo)
        :param pos: 位置索引0-9
        :return: loc
        '''
        pass

    @staticmethod
    def getSize(size):
        '''
        設(shè)置畫圓的半徑
        :param size:[0-2]
        :return: radius
        '''
        pass

    @staticmethod
    def getColor(c=0):
        '''
        根據(jù)顏色索引選擇圓圈顏色
        :param c:
        :return: list
        '''
        pass
    
    def drawNewring(self, newring:list=None):
        '''
        畫新生成的圓
        :param newring:
        :return:
        '''
        for i in range(len(newring)):
            if newring[i] != 0:
                ring = rendering.make_circle(radius=self.getSize(i),
                                             res=50,
                                             filled=False)
                r, g, b = self.getColor(newring[i])
                ring.set_color(r, g, b)
                ring_transform = rendering.Transform(translation=(150,30))
                ring.add_attr(ring_transform)
                self.add_geom(ring)

    def _drawQG(self, qgs: list=None):
        '''
        畫棋盤上各個(gè)棋格的圓圈
        :param qgs:
        :return: None
        '''
        for num,qg in enumerate(qgs):
            for i in range(len(qg)):
                if qg[i] != 0:
                    ring = rendering.make_circle(radius=self.getSize(i),
                                                 res = 50,
                                                 filled=False)
                    r, g, b = self.getColor(qg[i])
                    ring.set_color(r, g, b)
                    ring_transform = rendering.Transform(translation=self.pos2loc(num))
                    ring.add_attr(ring_transform)
                    self.add_geom(ring)

    def getQG(self, qg: list=None):
        '''
        將len=27的list轉(zhuǎn)換為[[],[],...]
        :param qg: (27,1)的list
        :return: (9,1)的list
        '''
        qgs = []
        for x in range(3):
            for y in range(3):
                tmp = []
                for z in range(3):
                    tmp.append(qg[9*x+3*y+z])
                qgs.append(tmp)
        self._drawQG(qgs)


class Testenv(gym.Env):
    # 如果你不想改參數(shù)爵川,下面可以不用寫
    metadata = {
        'render.modes': ['human', 'rgb_array'],
        'video.frames_per_second': 2
    }

    def __init__(self):
        self.viewer = ringViewer(300, 400)   # 600x400 是畫板的長和框
        self.state:list = []
        self.state:list = []

    def setState(self, state):
        self.state = state

    def setNewring(self, newring=None):
        self.newring = newring

    def render(self, mode='human', close=False):
        # 由于沒有找到viewer源碼中刪除組件的代碼,于是每次在渲染前 清空上一次geoms和onetime_geoms列表 來達(dá)到消除的目的
        if self.state.any():
            self.viewer.geoms.clear()
            self.viewer.onetime_geoms.clear()
            self.viewer.getQG(self.state)
        if self.newring:
            self.viewer.drawNewring(self.newring)

        return self.viewer.render(return_rgb_array=mode == 'rgb_array')


if __name__ == '__main__':
    v = Testenv()
    while True:
        v.setState(np.random.randint(0,6,(27)))
        v.setNewring([random.randint(0,5) for x in range(3)])
        print(v.state)
        print(v.newring)
        v.render()
        time.sleep(2)

△.由于沒有找到viewer源碼中刪除組件的代碼,于是每次在渲染前 清空上一次geoms和onetime_geoms列表 來達(dá)到消除的目的

效果圖如下

ring.jpg

深入剖析gym環(huán)境構(gòu)建[轉(zhuǎn)]

由于該博客的代碼展示實(shí)在太亂,于是重新幫他排版了一下

我們繼續(xù)講敷鸦,從第1小節(jié)的尾巴開始。有三個(gè)重要的函數(shù):

  • env = gym.make(‘CartPole-v0’)
  • env.reset()
  • env.render()

第一個(gè)函數(shù)是創(chuàng)建環(huán)境寝贡,我們會在第3小節(jié)具體講如何創(chuàng)建自己的環(huán)境扒披,所以這個(gè)函數(shù)暫時(shí)不講。第二個(gè)函數(shù)env.reset()和第三個(gè)函數(shù)env.render()是每個(gè)環(huán)境文件都包含的函數(shù)圃泡。我們以cartpole為例碟案,對這兩個(gè)函數(shù)進(jìn)行講解。

Cartpole的環(huán)境文件在~你的gym目錄/gym/envs/classic_control/cartpole.py.

該文件定義了一個(gè)CartPoleEnv的環(huán)境類洞焙,該類的成員函數(shù)有:seed(), step(),reset()和render(). 第1小節(jié)調(diào)用的就是CartPoleEnv的兩個(gè)成員函數(shù)reset()和render()。下面拯啦,我們先講講這兩個(gè)函數(shù)澡匪,再介紹step()函數(shù)

2.1 reset()函數(shù)詳解

reset()為重新初始化函數(shù)。那么這個(gè)函數(shù)有什么用呢褒链?

在強(qiáng)化學(xué)習(xí)算法中唁情,智能體需要一次次地嘗試,累積經(jīng)驗(yàn)甫匹,然后從經(jīng)驗(yàn)中學(xué)到好的動作甸鸟。一次嘗試我們稱之為一條軌跡或一個(gè)episode. 每次嘗試都要到達(dá)終止?fàn)顟B(tài). 一次嘗試結(jié)束后,智能體需要從頭開始兵迅,這就需要智能體具有重新初始化的功能抢韭。函數(shù)reset()就是這個(gè)作用。

reset()的源代碼為:

def _reset()
    # 利用均勻隨機(jī)分布初試化環(huán)境的狀態(tài)
    self.state = self.np_random.uniform(low=-0.05, high=0.05, size=(4,))
    # 設(shè)置當(dāng)前步數(shù)為None
    self.steps_beyond_done = None
    # 返回環(huán)境的初始化狀態(tài)
    return np.array(self.state)

2.2 render()函數(shù)詳解

render()函數(shù)在這里扮演圖像引擎的角色恍箭。一個(gè)仿真環(huán)境必不可少的兩部分是物理引擎圖像引擎刻恭。物理引擎模擬環(huán)境中物體的運(yùn)動規(guī)律;圖像引擎用來顯示環(huán)境中的物體圖像扯夭。其實(shí)鳍贾,對于強(qiáng)化學(xué)習(xí)算法,該函數(shù)可以沒有交洗。但是骑科,為了便于直觀顯示當(dāng)前環(huán)境中物體的狀態(tài),圖像引擎還是有必要的构拳。另外咆爽,加入圖像引擎可以方便我們調(diào)試代碼梁棠。下面具體介紹gym如何利用圖像引擎來創(chuàng)建圖像。

我們直接看源代碼:

from gym.envs.classic_control import rendering
# 這一句導(dǎo)入rendering模塊伍掀,利用rendering模塊中的畫圖函數(shù)進(jìn)行圖形的繪制
class myenv(gym.Env)
    def _render(self, mode=’human’, close=False):
        if close:
            pass #省略掰茶,直接看關(guān)鍵代碼部分
        if self.viewer is None:
            # 如繪制600*400的窗口函數(shù)為:
            self.viewer = rendering.Viewer(screen_width, screen_height)
        # 其中screen_width=600, screen_height=400
        # 創(chuàng)建小車的代碼為:
            l,r,t,b = -cartwidth/2, cartwidth/2, cartheight/2, -cartheight/2
            axleoffset =cartheight/4.0
            cart = rendering.FilledPolygon([(l,b), (l,t), (r,t), (r,b)])
        # 其中rendering.FilledPolygon為填充一個(gè)矩形蜜笤。

創(chuàng)建完cart的形狀濒蒋,接下來給cart添加平移屬性和旋轉(zhuǎn)屬性。將車的位移設(shè)置到cart的平移屬性中把兔,cart就會根據(jù)系統(tǒng)的狀態(tài)變化左右運(yùn)動沪伙。具體代碼解釋,我已上傳到github上面了县好,gxnk/reinforcement-learning-code 围橡。想深入了解的同學(xué)可去下載學(xué)習(xí)。

2.3 step()函數(shù)詳解

該函數(shù)在仿真器中扮演物理引擎的角色缕贡。其輸入是動作a翁授,輸出是:下一步狀態(tài),立即回報(bào)晾咪,是否終止收擦,調(diào)試項(xiàng)。

該函數(shù)描述了智能體與環(huán)境交互的所有信息谍倦,是環(huán)境文件中最重要的函數(shù)塞赂。在該函數(shù)中,一般利用智能體的運(yùn)動學(xué)模型和動力學(xué)模型計(jì)算下一步的狀態(tài)和立即回報(bào)昼蛀,并判斷是否達(dá)到終止?fàn)顟B(tài)宴猾。

我們直接看源代碼:

def _step(self, action):
    assert self.action_space.contains(action), "%r (%s) invalid"%(action, type(action))
    state = self.state
    x, x_dot, theta, theta_dot = state #系統(tǒng)的當(dāng)前狀態(tài)
    force = self.force_mag if action==1 else -self.force_mag #輸入動作,即作用到車上的力
    costheta = math.cos(theta) #余弦函數(shù)
    sintheta = math.sin(theta) #正弦函數(shù)
    #底下是車擺的動力學(xué)方程式叼旋,即加速度與動作之間的關(guān)系仇哆。
    temp = (force + self.polemass_length * theta_dot * theta_dot * sintheta) / self.total_mass
    thetaacc = (self.gravity * sintheta - costheta* temp) / (self.length * (4.0/3.0 - self.masspole * costheta * costheta / self.total_mass)) #擺的角加速度
    xacc = temp - self.polemass_length * thetaacc * costheta / self.total_mass #小車的平移加速
    x = x + self.tau * x_dot
    x_dot = x_dot + self.tau * xacc
    theta = theta + self.tau * theta_dot
    theta_dot = theta_dot + self.tau * thetaacc #積分求下一步的狀態(tài)
    self.state = (x,x_dot,theta,theta_dot)

2.4 一個(gè)簡單的demo

下面,我給出一個(gè)最簡單的demo夫植,讓大家體會一下上面三個(gè)函數(shù)如何使用税产。

import gym
import time
env = gym.make('CartPole-v0')   
#創(chuàng)造環(huán)境observation = env.reset()       
#初始化環(huán)境,observation為環(huán)境狀態(tài)
count = 0
for t in range(100):    
    action = env.action_space.sample()  
    #隨機(jī)采樣動作    
    observation, reward, done, info = env.step(action)  
    #與環(huán)境交互偷崩,獲得下一步的時(shí)刻    
    if done:                     
        break    
    env.render()         
    #繪制場景    
    count+=1    
    time.sleep(0.2)      
    #每次等待0.2s
    print(count)             
    #打印該次嘗試的步數(shù)

第3小節(jié):創(chuàng)建自己的gym環(huán)境并利示例qlearning的方法

在上一小節(jié)中以cartpole為例子深入剖析了gym環(huán)境文件的重要組成辟拷。我們知道,一個(gè)gym環(huán)境最少的組成需要包括reset()函數(shù)和step()函數(shù)阐斜。當(dāng)然衫冻,圖像顯示函數(shù)render()一般也是需要的。這一節(jié)谒出,我會以機(jī)器人找金幣為例給大家演示如何構(gòu)建一個(gè)全新的gym環(huán)境隅俘,并以此環(huán)境為例邻奠,示例最經(jīng)典的強(qiáng)化學(xué)習(xí)算法qlearning算法。在3.1節(jié)中为居,給出機(jī)器人找金幣的問題陳述碌宴;第3.2節(jié)中,給出構(gòu)建gym環(huán)境的過程蒙畴;第3.3節(jié)中贰镣,利用qlearning方法實(shí)現(xiàn)機(jī)器人找金幣的智能決策。全部代碼已傳到github上膳凝。

3.1 機(jī)器人找金幣的問題陳述

img

圖1.1 機(jī)器人找金幣

如圖1.1 為機(jī)器人在網(wǎng)格世界找金幣的示意圖碑隆。該網(wǎng)格世界一共有8個(gè)狀態(tài),其中狀態(tài)6和狀態(tài)8為死亡區(qū)域蹬音,狀態(tài)7為金幣區(qū)域上煤。機(jī)器人的初始位置為網(wǎng)格世界中任意一個(gè)狀態(tài)。機(jī)器人從初始狀態(tài)出發(fā)尋找金幣著淆。機(jī)器人進(jìn)行一次探索劫狠,進(jìn)入死亡區(qū)域或找到金幣,本次探測結(jié)束永部。機(jī)器人找到金幣的回報(bào)為1独泞,進(jìn)入死亡區(qū)域回報(bào)為-1,機(jī)器人在區(qū)域1-5之間轉(zhuǎn)換時(shí)扬舒,回報(bào)為0阐肤。我們的目標(biāo)是找到一個(gè)策略使得機(jī)器人不管處在什么狀態(tài)(1-5)都能找到金幣凫佛。對于這個(gè)機(jī)器人找金幣的游戲讲坎,我們可以利用強(qiáng)化學(xué)習(xí)的方法來實(shí)現(xiàn)。

構(gòu)建網(wǎng)格世界的gym環(huán)境

該例子的代碼,除了本篇博客有以外,OpenAI Gym構(gòu)建自定義強(qiáng)化學(xué)習(xí)環(huán)境有更仔細(xì)和規(guī)范的代碼貼出

一個(gè)gym的環(huán)境文件愧薛,其主體是個(gè)類晨炕,在這里我們定義類名為:GridEnv, 其初始化為環(huán)境的基本參數(shù),因?yàn)闄C(jī)器人找金幣的過程是一個(gè)馬爾科夫過程毫炉,我們在強(qiáng)化學(xué)習(xí)入門課程的第一講已經(jīng)介紹過了一個(gè)馬爾科夫過程應(yīng)該包括狀態(tài)空間瓮栗,動作空間,回報(bào)函數(shù)瞄勾,狀態(tài)轉(zhuǎn)移概率费奸。因此,我們在類GridEnv的初始化時(shí)便給出了相應(yīng)的定義进陡。網(wǎng)格世界的全部代碼在gxnk/reinforcement-learning-code,文件名為 grid_mdp.py. 我們看源代碼:

# 狀態(tài)空間為:
self.states = [1,2,3,4,5,6,7,8]
# 動作空間為:
  self.actions = ['n','e','s','w']
# 回報(bào)函數(shù)為:
  self.rewards = dict(); #回報(bào)的數(shù)據(jù)結(jié)構(gòu)為字典
  self.rewards['1_s'] = -1.0
  self.rewards['3_s'] = 1.0
    self.rewards['5_s'] = -1.0
# 狀態(tài)轉(zhuǎn)移概率為:
  self.t = dict(); #狀態(tài)轉(zhuǎn)移的數(shù)據(jù)格式為字典
  self.t['1_s'] = 6
  self.t['1_e'] = 2
  self.t['2_w'] = 1
  self.t['2_e'] = 3
  self.t['3_s'] = 7
  self.t['3_w'] = 2
  self.t['3_e'] = 4
  self.t['4_w'] = 3
  self.t['4_e'] = 5
  self.t['5_s'] = 8
  self.t['5_w'] = 4

有了狀態(tài)空間愿阐,動作空間和狀態(tài)轉(zhuǎn)移概率,我們便可以寫step(a)函數(shù)了趾疚。這里特別注意的是缨历,step()函數(shù)的輸入是動作以蕴,輸出為:下一個(gè)時(shí)刻的動作,回報(bào)辛孵,是否終止丛肮,調(diào)試信息。尤其需要注意的是輸出的順序不要弄錯(cuò)了魄缚。對于調(diào)試信息宝与,可以為空,但不能缺少鲜滩,否則會報(bào)錯(cuò)伴鳖,常用{}來代替。我們看源代碼:

step函數(shù)的建立:

def _step(self, action):
    #系統(tǒng)當(dāng)前狀態(tài)
    state = self.state
      #判斷系統(tǒng)當(dāng)前狀態(tài)是否為終止?fàn)顟B(tài)
    if state in self.terminate_states:
        return state, 0, True, {}
    key = "%d_%s"%(state, action) #將狀態(tài)和動作組成字典的鍵值
    #狀態(tài)轉(zhuǎn)移
    if key in self.t:
        next_state = self.t[key]
    else:
        next_state = state
        self.state = next_state
        is_terminal = False
    if next_state in self.terminate_states:
        is_terminal = True
    if key not in self.rewards:
        r = 0.0
    else:
        r = self.rewards[key]
    return next_state, r,is_terminal,{}

step()函數(shù)就是這么簡單徙硅。下面我們重點(diǎn)介紹下如何寫render()函數(shù)榜聂。從圖1.1機(jī)器人找金幣的示意圖我們可以看到,網(wǎng)格世界是由一些線和圓組成的嗓蘑。因此须肆,我們可以調(diào)用rendering中的畫圖函數(shù)來繪制這些圖像。

render函數(shù)的建立:

整個(gè)圖像是一個(gè)600*400的窗口桩皿,可用如下代碼實(shí)現(xiàn):

from gym.envs.classic_control import rendering

self.viewer = rendering.Viewer(screen_width, screen_height)
# 創(chuàng)建網(wǎng)格世界豌汇,一共包括11條直線,事先算好每條直線的起點(diǎn)和終點(diǎn)坐標(biāo)泄隔,然后繪制這些直線拒贱,代碼如下:
#創(chuàng)建網(wǎng)格世界
def render(self):
    self.line1 = rendering.Line((100,300),(500,300))
    self.line2 = rendering.Line((100, 200), (500, 200))
    self.line3 = rendering.Line((100, 300), (100, 100))
    self.line4 = rendering.Line((180, 300), (180, 100))
    self.line5 = rendering.Line((260, 300), (260, 100))
    self.line6 = rendering.Line((340, 300), (340, 100))
    self.line7 = rendering.Line((420, 300), (420, 100))
    self.line8 = rendering.Line((500, 300), (500, 100))
    self.line9 = rendering.Line((100, 100), (180, 100))
    self.line10 = rendering.Line((260, 100), (340, 100))
    self.line11 = rendering.Line((420, 100), (500, 100))
    # 接下來,創(chuàng)建死亡區(qū)域佛嬉,我們用黑色的圓圈代表死亡區(qū)域逻澳,源代碼如下:

    # 創(chuàng)建第一個(gè)骷髏
    self.kulo1 = rendering.make_circle(40)
    self.circletrans = rendering.Transform(translation=(140,150))
    self.kulo1.add_attr(self.circletrans)
    self.kulo1.set_color(0,0,0)
    # 創(chuàng)建第二個(gè)骷髏
    self.kulo2 = rendering.make_circle(40)
    self.circletrans = rendering.Transform(translation=(460, 150))
    self.kulo2.add_attr(self.circletrans)
    self.kulo2.set_color(0, 0, 0)
    # 創(chuàng)建金幣區(qū)域,用金色的圓來表示:
    # 創(chuàng)建金條
    self.gold = rendering.make_circle(40)
    self.circletrans = rendering.Transform(translation=(300, 150))
    self.gold.add_attr(self.circletrans)
    self.gold.set_color(1, 0.9, 0)

    # 創(chuàng)建機(jī)器人暖呕,我們依然用圓來表示機(jī)器人斜做,為了跟死亡區(qū)域和金幣區(qū)域不同,我們可以設(shè)置不同的顏色:
    # 創(chuàng)建機(jī)器人
    self.robot= rendering.make_circle(30)
    self.robotrans = rendering.Transform()
    self.robot.add_attr(self.robotrans)
    self.robot.set_color(0.8, 0.6, 0.4)
    # 創(chuàng)建完之后湾揽,給11條直線設(shè)置顏色瓤逼,并將這些創(chuàng)建的對象添加到幾何中代碼如下:
    self.line1.set_color(0, 0, 0)
    self.line2.set_color(0, 0, 0)
    self.line3.set_color(0, 0, 0)
    self.line4.set_color(0, 0, 0)
    self.line5.set_color(0, 0, 0)
    self.line6.set_color(0, 0, 0)
    self.line7.set_color(0, 0, 0)
    self.line8.set_color(0, 0, 0)
    self.line9.set_color(0, 0, 0)
    self.line10.set_color(0, 0, 0)
    self.line11.set_color(0, 0, 0)
    # 添加組件到Viewer中
    self.viewer.add_geom(self.line1)
    self.viewer.add_geom(self.line2)
    self.viewer.add_geom(self.line3)
    self.viewer.add_geom(self.line4)
    self.viewer.add_geom(self.line5)
    self.viewer.add_geom(self.line6)
    self.viewer.add_geom(self.line7)
    self.viewer.add_geom(self.line8)
    self.viewer.add_geom(self.line9)
    self.viewer.add_geom(self.line10)
    self.viewer.add_geom(self.line11)
    self.viewer.add_geom(self.kulo1)
    self.viewer.add_geom(self.kulo2)
    self.viewer.add_geom(self.gold)
    self.viewer.add_geom(self.robot)
    # 接下來,開始設(shè)置機(jī)器人的位置库物。機(jī)器人的位置根據(jù)其當(dāng)前所處的狀態(tài)不同霸旗,所在的位置不同。我們事先計(jì)算出每個(gè)狀態(tài)處機(jī)器人位置的中心坐標(biāo)戚揭,并存儲到兩個(gè)向量中诱告,并在類初始化中給出:
        self.x=[140,220,300,380,460,140,300,460]
        self.y=[250,250,250,250,250,150,150,150]
    # 根據(jù)這兩個(gè)向量和機(jī)器人當(dāng)前的狀態(tài),我們就可以設(shè)置機(jī)器人當(dāng)前的圓心坐標(biāo)了即:

        if self.state is None: return None

        self.robotrans.set_translation(self.x[self.state-1], self.y[self.state- 1])

    # 最后還需要一個(gè)返回語句:
        return self.viewer.render(return_rgb_array=mode == 'rgb_array')

以上便完成了render()函數(shù)的建立

reset()函數(shù)的建立:

reset()函數(shù)常常用隨機(jī)的方法初始化機(jī)器人的狀態(tài)毫目,即:

def _reset(self):
    self.state = self.states[int(random.random() * len(self.states))]
    return self.state

環(huán)境的注冊

全部的代碼請去github上下載學(xué)習(xí)蔬啡。下面重點(diǎn)講一講如何將建好的環(huán)境進(jìn)行注冊诲侮,以便通過gym的標(biāo)準(zhǔn)形式進(jìn)行調(diào)用。其實(shí)環(huán)境的注冊很簡單箱蟆,只需要3步:

第一步:將我們自己的環(huán)境文件(我創(chuàng)建的文件名為grid_mdp.py)拷貝到你的gym安裝目錄/gym/gym/envs/classic_control文件夾中沟绪。(拷貝在這個(gè)文件夾中因?yàn)橐褂胷endering模塊。當(dāng)然空猜,也有其他辦法绽慈。該方法不唯一)

第二步:打開該文件夾(第一步中的文件夾)下的init.py文件,在文件末尾加入語句:from gym.envs.classic_control.grid_mdp import GridEnv

第三步:進(jìn)入文件夾你的gym安裝目錄/gym/gym/envs辈毯,打開該文件夾下的init.py文件坝疼,添加代碼:

register(
    # gym.make(‘id’)時(shí)的id
    id='GridWorld-v0',
    # 函數(shù)路口
    entry_point='gym.envs.classic_control:GridEnv',
    max_episode_steps=200,
    reward_threshold=100.0,
)

第一個(gè)參數(shù)id就是你調(diào)用gym.make(‘id’)時(shí)的id, 這個(gè)id你可以隨便選取,我取的谆沃,名字是GridWorld-v0

第二個(gè)參數(shù)就是函數(shù)路口了钝凶。

后面的參數(shù)原則上來說可以不必要寫。

經(jīng)過以上三步唁影,就完成了注冊耕陷。

下面,我們給個(gè)簡單的demo來測試下我們的環(huán)境的效果吧:

我們依然寫個(gè)終端程序:

import gym

env = gym.make('GridWorld-v0')
env.reset()
env.render()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末据沈,一起剝皮案震驚了整個(gè)濱河市哟沫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锌介,老刑警劉巖嗜诀,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異孔祸,居然都是意外死亡隆敢,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門融击,熙熙樓的掌柜王于貴愁眉苦臉地迎上來筑公,“玉大人雳窟,你說我怎么就攤上這事尊浪。” “怎么了封救?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵拇涤,是天一觀的道長。 經(jīng)常有香客問我誉结,道長鹅士,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任惩坑,我火速辦了婚禮掉盅,結(jié)果婚禮上也拜,老公的妹妹穿的比我還像新娘。我一直安慰自己趾痘,他們只是感情好慢哈,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著永票,像睡著了一般卵贱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上侣集,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天键俱,我揣著相機(jī)與錄音,去河邊找鬼世分。 笑死编振,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的臭埋。 我是一名探鬼主播党觅,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼斋泄!你這毒婦竟也來了杯瞻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤炫掐,失蹤者是張志新(化名)和其女友劉穎魁莉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體募胃,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旗唁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了痹束。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片检疫。...
    茶點(diǎn)故事閱讀 37,989評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖祷嘶,靈堂內(nèi)的尸體忽然破棺而出屎媳,到底是詐尸還是另有隱情,我是刑警寧澤论巍,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布烛谊,位于F島的核電站,受9級特大地震影響嘉汰,放射性物質(zhì)發(fā)生泄漏丹禀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望双泪。 院中可真熱鬧持搜,春花似錦、人聲如沸焙矛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽薄扁。三九已至剪返,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間邓梅,已是汗流浹背脱盲。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留日缨,地道東北人钱反。 一個(gè)月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像匣距,于是被迫代替她去往敵國和親面哥。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容