OpenAI gym的建模思想


一、強化學習問題需要描述那些內容

強化學習中最主要的兩類對象是“個體”和“環境”,其次還有一些像“即時獎勵”、“收獲”、“狀態”、“行為”、“價值”、“策略”、“學習”、“控制”等概念。這些概念把個體和環境聯系起來。通過理論學習,我們知道:

1. 環境響應個體的行為。當個體執行一個行為時,它需要根據環境本身的動力學來更新環境,也包括更新個體狀態,同時給以個體一個反饋信息:即時獎勵。

2. 對於個體來說,它並不掌握整個環境信息,它只能通過觀測來獲得其可以獲得的信息,它能觀測到哪些信息取決於問題的難度;同樣個體需要一定的行為與環境進行交互,哪些行為是被允許的,也要由個體和環境協商好。因此環境要確定個體的觀測空間和行為空間。

3. 個體還應該有一個決策功能,該功能根據當前觀測來判斷下一時刻該采取什么行為,也就是決策過程。

4. 個體具有執行一個確定行為的功能。

5. 智能的個體應能從與環境的交互中學習到知識,進而在與環境交互時盡可能多的獲取獎勵,最終達到最大化累積獎勵的目的。

6. 環境應該給個體設置一個(些)終止條件,即當個體處在這個狀態或這些狀態之一時,約定交互結束,即產生一個完整的Episode。隨后重新開始一個Episode或者退出交互。

把上面的過程提煉成偽代碼可以是下面這樣:

 

class Environment(): self.states # 所有可能的狀態集合 self.agent_cur_state # 記錄個體當前的狀態 self.observation_space # 個體的觀測空間 self.action_space # 個體的行為空間 def reward(self) -> reward # 根據狀態確定個體的即時獎勵 def dynamics(self, action) -> None # 根據當前狀態和個體的行為確定個體的新狀態 def is_episode_end(self) -> Bool # 判斷是否一個Episode結束 def obs_for_agent() -> obs # 環境把個體當前狀態做一定變換,作為個體的觀測 class Agent(env: Environment): self.env = env # 個體依附於一個環境存在 self.obs # 個體的觀測 self.reward # 個體獲得的即時獎勵 def performPolicy(self, obs) -> action # 個體執行一個策略產生一個行為 def performAction(self, action) -> None # 個體與環境交互,執行行為 action = self.performPolicy(self.obs) self.env.dynamics(action) def observe(self) -> next_obs, reward # 個體得到從環境反饋來的觀測和獎勵 self.obs = self.env.obs_for_agent() self.reward = self.env.reward()

按照上面的設計,可以寫出一個不錯的個體與環境的類。但是我們不打算按照這個寫下去,我們看看gym庫是如何描述環境,以及個體通過什么方式與環境進行交互。

二、gym庫介紹

gym的官方網址在:這里,其庫代碼托管地址在:這里

gym庫的在設計環境以及個體的交互時基本上也是解決上述問題,但是它有它的規范和接口。gym庫的核心在文件core.py里,這里定義了兩個最基本的類Env和Space。前者是所有環境類的基類,后者是所有空間類的基類。從Space基類衍生出幾個常用的空間類,其中最主要的是Discrete類和Box類。通過其__init__方法的參數以及其它方法的實現可以看出前者對應於一維離散空間,后者對應於多維連續空間。它們既可以應用在行為空間中,也可以用來描述狀態空間,具體怎么用看問題本身。例如如果我要描述上篇提到的一個4*4的格子世界,其一共有16個狀態,每一個狀態只需要用一個數字來描述,這樣我可以把這個問題的狀態空間用Discrete(16)對象來描述就可以了。對於另外一個經典的小車爬山的問題(如下圖),小車的狀態是用兩個變量來描述的,一個是小車對應目標旗桿的水平距離,另一個是小車的速度(是沿坡度切線方向的速率還是速度在水平方向的分量這個沒仔細研究),因此環境要描述小車的狀態需要2個連續的變量。由於描述小車的狀態數據對個體完全可見,因此小車的狀態空間即是小車的觀測空間,此時再用Discrete來描述就不行了,要用Box類,Box空間可以定義多維空間,每一個維度可以用一個最低值和最大值來約束。同時小車作為個體可以執行的行為只有3個:左側加速、不加速、右側加速。因此行為空間可以用Discrete來描述。最終,該環境類的觀測空間和行為空間描述如下:

self.min_position = -1.2 self.max_position = 0.6 self.max_speed = 0.07 self.goal_position = 0.5 self.low = np.array([self.min_position, -self.max_speed]) self.high = np.array([self.max_position, self.max_speed]) self.action_space = spaces.Discrete(3) self.observation_space = spaces.Box(self.low, self.high)

從這段代碼可以看出,要定義一個Discrete類的空間只需要一個參數n就可以了,而定義一個多維的Box空間需要知道每一個維度的最小最大值,當然也要知道維數。

有了描述空間的對象,再來看環境類如何聲明就簡單的多了。先來看看代碼中關於環境基類的一段解釋:

class Env(object): """The main OpenAI Gym class. It encapsulates an environment with arbitrary behind-the-scenes dynamics. An environment can be partially or fully observed. The main API methods that users of this class need to know are: step reset render close seed When implementing an environment, override the following methods in your subclass: _step _reset _render _close _seed And set the following attributes: action_space: The Space object corresponding to valid actions observation_space: The Space object corresponding to valid observations reward_range: A tuple corresponding to the min and max possible rewards Note: a default reward range set to [-inf,+inf] already exists. Set it if you want a narrower range. The methods are accessed publicly as "step", "reset", etc.. The non-underscored versions are wrapper methods to which we may add functionality over time. """ # Override in SOME subclasses def _close(self): pass # Set these in ALL subclasses action_space = None observation_space = None # Override in ALL subclasses def _step(self, action): raise NotImplementedError def _reset(self): raise NotImplementedError def _render(self, mode='human', close=False): return def _seed(self, seed=None): return []

看得出,個體主要通過環境的一下幾個方法進行交互:step,reset,render,close,seed,而這幾個都是公用方法,具體每一個方法實際調用的都是其內部方法:_step,_reset,_render,_close,_seed。此外這段描述還指出,如果你要編寫自己的環境類,也主要是重寫這些私有方法,同時指定該環境的觀測和行為空間。_close方法可以不用重寫。這幾個方法主要完成的個性化功能如下:

_step: 最核心的方法,定義環境的動力學,確定個體的下一個狀態、獎勵信息、是否Episode終止,以及一些額外的信息,按約定,額外的信息不被允許用來訓練個體。

_reset: 開啟個體與環境交互前調用該方法,確定個體的初始狀態以及其他可能的一些初始化設置。

_seed: 設置一些隨機數的種子。

_render: 如果需要將個體與環境的交互以動畫的形式展示出來的話,需要重寫該方法。簡單的UI設計可以用gym包裝好了的pyglet方法來實現,這些方法在rendering.py文件里定義。具體使用這些方法進行UI繪制需要了解基本的OpenGL編程思想和接口,這里暫時不做細說。

可以看出,使用gym編寫自己的Agent代碼,需要在你的Agent類中聲明一個env變量,指向對應的環境類,個體使用自己的代碼產生一個行為,將該行為送入env的step方法中,同時得到觀測狀態、獎勵值、Episode是否終止以及調試信息等四項信息組成的元組:

state, reward, is_done, info = env.step(a)

state 是一個元組或numpy數組,其提供的信息維度應與觀測空間的維度一樣、每一個維度的具體指在制定的low與high之間,保證state信息符合這些條件是env類的_step方法負責的事情。

reward 則是根據環境的動力學給出的即時獎勵,它就是一個數值。

is_done 是一個布爾變量,True或False,你可以根據具體的值來安排個體的后續動作。

info 提供的數據因環境的不同差異很大,通常它的結構是一個字典:

{"key1":data1,"key2":data2,...} 

獲取其中的信息應該不難。

最后一點,在自己的代碼中如何建立個環境類對象呢?有兩種情況,一種是在gym庫里注冊了的對象,你只要使用下面的語句:

import gym env = gym.make("registered_env_name")

其中不同的環境類有不同的注冊名,只要把make方法內的字符串改成對應的環境名就可以了。

另外一種使用自己編寫的未注冊的環境類,這種很簡單,同一般的建立對象的語句沒什么區別:

env = MyEnvClassName()

相信讀者已經基本清楚了如何使用gym提供的環境類了。下一步就是如何編寫自己的環境類了。


轉自:https://zhuanlan.zhihu.com/p/28086233


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM