新手的第一個強化學習示例一般都從Open Gym開始。在這些示例中,我們不斷地向環境施加動作,並得到觀測和獎勵,這也是Gym Env的基本用法:
state, reward, done, info = env.step(action)
其中state是agent的觀測狀態,reward是採取了action之後環境返回的獎勵,done是判斷後繼狀態是否是終止狀態的flag,info是一些自定義的訊息。
當後繼狀態是終止狀態時,需要重置環境,使之回到初始狀態:
env.reset()
接下來,我們就以以上兩個基本用法為目標,自定義一個Gym下的簡單環境:
S0 | S1 | S2 |
-1 | -1 | 10 |
初始狀態S0,終止狀態S2,抵達狀態S0 S1 S2的獎勵分別為-1,-1和10,agent有向左和向右兩個動作。
步驟1:建立資料夾和檔案
本人為了做深度學習,使用conda的環境管理功能建立了名為 pytorch1.1的環境,於是來到目錄:D:\Anaconda\envs\pytorch1.1\Lib\site-packages\gym\envs
建立資料夾 user ,用於專門存放自定義的環境,然後進入該目錄:D:\Anaconda\envs\pytorch1.1\Lib\site-packages\gym\envs\user,建立檔案 __init__.py 和 basic_env.py。
當然,也可以直接在預設的root環境下操作。來到目錄:D:\Anaconda\Lib\site-packages\gym\envs,建立資料夾user,進入該目錄D:\Anaconda\Lib\site-packages\gym\envs\user,建立檔案 __init__.py 和 basic_env.py。
步驟2:編寫 basic_env.py 和 __init__.py
basic_env是我們要寫的簡單環境示例的檔名,內容如下:
import gym class BasicEnv(gym.Env): def __init__(self): self.action_space = ['left', 'right'] # 動作空間 self.state_space = ['s0', 's1', 's2'] # 狀態空間 self.state_transition = { # 狀態轉移表 's0': {'left':'s0', 'right':'s1'}, 's1': {'left':'s0', 'right':'s2'} } self.reward = {'s0':-1, 's1':-1, 's2':10} # 獎勵 self.state = 's0' def step(self, action): next_state = self.state_transition[self.state][action] # 通過兩個關鍵字查詢狀態轉移表中的後繼狀態 self.state = next_state reward = self.reward[next_state] if next_state == 's2': done = True else: done = False info = {} return next_state, reward, done, info def reset(self): self.state = 's0' return self.state def render(self, mode='human'): draw = ['-' for i in range(len(self.state_space))] draw[self.state_space.index(self.state)] = 'o' draw = ''.join(draw) print(draw)
__init__.py是引入環境類的入口函式,寫入:
from gym.envs.user.basic_env import BasicEnv
步驟3:註冊環境
來到目錄:D:\Anaconda\envs\pytorch1.1\Lib\site-packages\gym,所有的環境都在__init__.py檔案中註冊,開啟這個檔案,發現很多類似這樣的程式碼:
# Toy Text # ---------------------------------------- register( id="Blackjack-v1", entry_point="gym.envs.toy_text:BlackjackEnv", kwargs={"sab": True, "natural": False}, ) register( id="FrozenLake-v1", entry_point="gym.envs.toy_text:FrozenLakeEnv", kwargs={"map_name": "4x4"}, max_episode_steps=100, reward_threshold=0.70, # optimum = 0.74 ) register( id="FrozenLake8x8-v1", entry_point="gym.envs.toy_text:FrozenLakeEnv", kwargs={"map_name": "8x8"}, max_episode_steps=200, reward_threshold=0.85, # optimum = 0.91 )
模仿這個格式,我們新增自己的程式碼,註冊自己的環境:
# User # ---------------------------------------- register( id="BasicEnv-v0", # 環境名 entry_point="gym.envs.user:BasicEnv", #介面 reward_threshold=10, # 獎勵閾值 max_episode_steps=10, # 最大步長 )
註冊了的環境,可以通過向gym的通用介面寫入環境名建立。除了環境名和介面兩個基本資訊外,獎勵閾值和最大步長則是與訓練相關的引數,還可以自行新增其他引數。
步驟4:測試環境
在測試程式碼中,我們設定了一個主迴圈,讓agent隨機選擇向左或向右,直到抵達終止狀態,或達到了在註冊環境中設定的最大步長max_episode_steps(實現方式是使得done = True),程式碼如下:
import gym import random import time from gym import envs print(envs.registry.all()) # 檢視所有已註冊的環境 env = gym.make('BasicEnv-v0') env.reset() # 在第一次step前要先重置環境 不然會報錯 action_space = env.action_space while True: action = random.choice(action_space) # 隨機動作 state, reward, done, info = env.step(action) print('reward: %d' % reward) env.render() time.sleep(0.5) if done: break
效果如下: