OpenAI Gym 經典控制環境介紹——CartPole(倒立擺)

来源:https://www.cnblogs.com/sixuwuxian/archive/2022/10/06/16758343.html
-Advertisement-
Play Games

OpenAI Gym是一款用於研發和比較強化學習演算法的工具包,本文主要介紹Gym模擬環境的功能和工具包的使用方法,並詳細介紹其中的經典控制問題中的倒立擺(CartPole-v0/1)問題。最後針對倒立擺問題如何建立控制模型並採用爬山演算法優化進行了介紹,並給出了相應的完整python代碼示例和解釋。要... ...


功能演示動圖

摘要:OpenAI Gym是一款用於研發和比較強化學習演算法的工具包,本文主要介紹Gym模擬環境的功能和工具包的使用方法,並詳細介紹其中的經典控制問題中的倒立擺(CartPole-v0/1)問題。最後針對倒立擺問題如何建立控制模型並採用爬山演算法優化進行了介紹,並給出了相應的完整python代碼示例和解釋。要點如下:


1. 前言

    自從AlphaGo的橫空出世之後,整個工業界都為之振奮,也確定了強化學習在人工智慧領域的重要地位,越來越多的人加入到強化學習的研究和學習中。強化學習(Reinforcement learning, RL)是機器學習的一個子領域,在智能控制機器人及分析預測等領域有許多應用。強化學習通過與環境進行交互獲得的獎賞指導行為,目標是使智能體獲得最大的獎賞,最終開發出智能體(Agent)做出決策和控制。

    OpenAI Gym是一個研究和比較強化學習相關演算法的開源工具包,包含了許多經典的模擬環境和各種數據。目前強化學習的研究面臨著使用的環境缺乏標準化的問題,這個問題使得很難複製已發表的研究結果以及比較不同論文的結果,個人認為Gym正好為這一問題提供了很好的解決方案。因此非常有必要學習一下Gym這一快捷工具包,經過一段時間對深度強化學習的研究和學習,我這裡將前期所學做一個整理和總結。


2. OpenAI Gym模擬環境介紹

    Gym是一個研究和開發強化學習相關演算法的模擬平臺,無需智能體先驗知識,並相容常見的數值運算庫如 TensorFlow、Theano等。OpenAI Gym由以下兩部分組成:

  • Gym開源庫:測試問題的集合。當你測試強化學習的時候,測試問題就是環境,比如機器人玩游戲,環境的集合就是游戲的畫面。這些環境有一個公共的介面,允許用戶設計通用的演算法。
  • OpenAI Gym服務:提供一個站點和API(比如經典控制問題:CartPole-v0),允許用戶對他們的測試結果進行比較。

    簡單來說OpenAI Gym提供了許多問題和環境(或游戲)的介面,而用戶無需過多瞭解游戲的內部實現,通過簡單地調用就可以用來測試和模擬。接下來以經典控制問題CartPole-v0為例,簡單瞭解一下Gym的特點,以下代碼來自OpenAI Gym官方文檔

import gym
env = gym.make('CartPole-v0')
env.reset()
for _ in range(1000):
    env.render()
    env.step(env.action_space.sample()) # take a random action
env.close()

運行效果如下:

功能演示動圖

    以上代碼中可以看出,gym的核心介面是Env。作為統一的環境介面,Env包含下麵幾個核心方法:

  • reset(self):重置環境的狀態,返回觀察。
  • step(self, action):推進一個時間步長,返回observation, reward, done, info
  • render(self, mode='human', close=False):重繪環境的一幀。預設模式一般比較友好,如彈出一個視窗。
  • close(self):關閉環境,並清除記憶體。

    以上代碼首先導入gym庫,第2行創建CartPole-v0環境,併在第3行重置環境狀態。在for迴圈中進行1000個時間步長(timestep)的控制,第5行刷新每個時間步長環境畫面,第6行對當前環境狀態採取一個隨機動作(0或1),最後第7行迴圈結束後關閉模擬環境。

2.1 觀測(Observations)

    在上面代碼中使用了env.step()函數來對每一步進行模擬,在Gym中,env.step()會返回 4 個參數:

  • 觀測 Observation (Object):當前step執行後,環境的觀測(類型為對象)。例如,從相機獲取的像素點,機器人各個關節的角度或棋盤游戲當前的狀態等;
  • 獎勵 Reward (Float): 執行上一步動作(action)後,智能體( agent)獲得的獎勵(浮點類型),不同的環境中獎勵值變化範圍也不相同,但是強化學習的目標就是使得總獎勵值最大;
  • 完成 Done (Boolen): 表示是否需要將環境重置 env.reset。大多數情況下,當 DoneTrue 時,就表明當前回合(episode)或者試驗(tial)結束。例如當機器人摔倒或者掉出臺面,就應當終止當前回合進行重置(reset);
  • 信息 Info (Dict): 針對調試過程的診斷信息。在標準的智體模擬評估當中不會使用到這個info,具體用到的時候再說。

    總結來說,這就是一個強化學習的基本流程,即"agent-environment loop",在每個時間點上,智能體(可以認為是你寫的演算法)選擇一個動作(action),環境返回上一次action的觀測(Observation)和獎勵(Reward),用圖表示為

功能演示動圖

    在 Gym 模擬中,每一次回合開始,需要先執行 reset() 函數,返回初始觀測信息,然後根據標誌位 done 的狀態,來決定是否進行下一次回合。所以更恰當的方法是遵守done的標誌,同樣我們可以參考OpenAI Gym官方文檔中的代碼如下

import gym
env = gym.make('CartPole-v0')
for i_episode in range(20):
    observation = env.reset()
    for t in range(100):
        env.render()
        print(observation)
        action = env.action_space.sample()
        observation, reward, done, info = env.step(action)
        if done:
            print("Episode finished after {} timesteps".format(t+1))
            break
env.close()

    當done 為真時,控制失敗,此階段episode 結束。可以計算每 episode 的回報就是其堅持的t+1時間,堅持的越久回報越大,在上面演算法中,agent 的行為選擇是隨機的,平均回報為20左右。

2.2 空間(Spaces

    在前面的兩個小例子中,每次執行的動作(action)都是從環境動作空間中隨機進行選取的,但是這些動作 (action) 是什麼?在 Gym 的模擬環境中,有運動空間 action_space 和觀測空間observation_space 兩個指標,程式中被定義為 Space類型,用於描述有效的運動和觀測的格式和範圍。下麵是一個代碼示例:

import gym
env = gym.make('CartPole-v0')
print(env.action_space)
#> Discrete(2)
print(env.observation_space)
#> Box(4,)

從程式運行結果可以看出:

  • action_space 是一個離散Discrete類型,從discrete.py源碼可知,範圍是一個{0,1,...,n-1} 長度為 n 的非負整數集合,在CartPole-v0例子中,動作空間表示為{0,1}
  • observation_space 是一個Box類型,從box.py源碼可知,表示一個 n 維的盒子,所以在上一節列印出來的observation是一個長度為 4 的數組。數組中的每個元素都具有上下界。
print(env.observation_space.high)
print(env.observation_space.low)
[4.8000002e+00 3.4028235e+38 4.1887903e-01 3.4028235e+38]
[-4.8000002e+00 -3.4028235e+38 -4.1887903e-01 -3.4028235e+38]

    利用運動空間和觀測空間的定義和範圍,可以將代碼寫得更加通用。在許多模擬環境中,BoxDiscrete是最常見的空間描述,在智體每次執行動作時,都屬於這些空間範圍內,代碼示例為:

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

CartPole-v0慄子中,運動只能選擇左和右,分別用{0,1}表示。

2.3 OpenAI Gym中可用的環境

Gym中從簡單到複雜,包含了許多經典的模擬環境和各種數據,其中包括:

  • 經典控制和文字游戲:經典的強化學習示例,方便入門;

  • 演算法:從例子中學習強化學習的相關演算法,在Gym的模擬演算法中,由易到難方便新手入坑;

  • 雅達利游戲:利用強化學習來玩雅達利的游戲。Gym中集成了對強化學習有著重要影響的Arcade Learning Environment,並且方便用戶安裝;

  • 2D3D的機器人:這個是我一直很感興趣的一部分,在Gym中控制機器人進行模擬。需要利用第三方的物理引擎如 MuJoCo

2.4 註冊表

    Gym是一個包含各種各樣強化學習模擬環境的大集合,並且封裝成通用的介面暴露給用戶,查看所有環境的代碼如下

from gym import envs
print(envs.registry.all())
#> [EnvSpec(DoubleDunk-v0), EnvSpec(InvertedDoublePendulum-v0), EnvSpec(BeamRider-v0), EnvSpec(Phoenix-ram-v0), EnvSpec(Asterix-v0), EnvSpec(TimePilot-v0), EnvSpec(Alien-v0), EnvSpec(Robotank-ram-v0), EnvSpec(CartPole-v0), EnvSpec(Berzerk-v0), EnvSpec(Berzerk-ram-v0), EnvSpec(Gopher-ram-v0), ...

    Gym支持將用戶製作的環境寫入到註冊表中,需要執行 gym.make()和在啟動時註冊register,具體可參考這篇博客:gym介紹。同時我們可以通過寫入新的註冊表實現對環境中的某些參數設置進行修改,例如

form gym.envs.registration import register
register(
    id='CartPole-v2',
    entry_point='gym.envs.classic_control:CartPoleEnv',
    max_episode_steps=200*4,
    reward_threshold=195.0*4,
)
env = gym.make('CartPole-v2')

2.5 OpenAI Gym評估平臺

    用戶可以記錄和上傳演算法在環境中的表現或者上傳自己模型的Gist,生成評估報告,還能錄製模型玩游戲的小視頻。在每個環境下都有一個排行榜,用來比較大家的模型表現。詳細介紹可以參考這篇博文:OpenAI Gym評估平臺OpenAI教程,當然更加準確的表述還是應該參考OpenAI Gym官方文檔


3. CartPole-v0/1原理與功能

    在CartPole-v0的環境中,實際參考了論文:AG Barto, RS Sutton and CW Anderson, "Neuronlike Adaptive Elements That Can Solve Difficult Learning Control Problem", IEEE Transactions on Systems, Man, and Cybernetics, 1983.中的倒立擺控制問題。

    Cart Pole即車桿游戲,游戲模型如下圖所示。游戲裡面有一個小車,上有豎著一根桿子,每次重置後的初始狀態會有所不同。小車需要左右移動來保持桿子豎直,為了保證游戲繼續進行需要滿足以下兩個條件:

  • 桿子傾斜的角度\(\theta\)不能大於15°
  • 小車移動的位置\(x\)需保持在一定範圍(中間到兩邊各2.4個單位長度)
功能演示動圖

動作(action

  • 左移(0)
  • 右移(1)

狀態變數(state variables

  • \(x\):小車在軌道上的位置(position of the cart on the track
  • \(\theta\):桿子與豎直方向的夾角(angle of the pole with the vertical
  • \(\dot{x}\):小車速度(cart velocity
  • \(\dot{\theta }\):角度變化率(rate of change of the angle
import gym
env = gym.make('CartPole-v0')
observation = env.reset()
print(observation)
#> [-0.00478028 -0.02917182  0.00313288  0.03160127]

    以上代碼顯示了初始狀態下的取值,每次調用env.reset( )將重新產生一個初始狀態。列印出的observation的四個元素分別表示了小車位置、小車速度、桿子夾角及角變化率。

游戲獎勵(reward

    在gymCart Pole環境(env)裡面,左移或者右移小車的action之後,env會返回一個+1的reward。其中CartPole-v0中到達200個reward之後,游戲也會結束,而CartPole-v1中則為500。最大獎勵(reward)閾值可通過前面介紹的註冊表進行修改。


4. 爬山演算法解決倒立擺問題

    為了能夠有效控制倒立擺首先應建立一個控制模型。明顯的,這個控制模型的輸入應該是當前倒立擺的狀態(observation)而輸出為對當前狀態做出的決策動作(action)。從前面的知識我們瞭解到決定倒立擺狀態的observation是一個四維向量,包含小車位置(\(x\))、桿子夾角(\(\theta\))、小車速度(\(\dot{x}\))及角變化率(\(\dot{\theta }\)),如果對這個向量求它的加權和,那麼就可以根據加權和值的符號來決定採取的動作(action),用sigmoid函數將這個問題轉化為二分類問題,從而可以建立一個簡單的控制模型。其模型如下圖所示:

功能演示動圖

    上圖的實際功能與神經網路有幾分相似,但比神經網路要簡單得多。通過加入四個權值,我們可以通過改變權重值來改變決策(policy),即有加權和\(H_{sum}=\omega _{1}x+\omega _{2}\theta +\omega _{3}\dot{x}+\omega _{4}\dot{\theta}+b\),若\(H_{sum}\)的符號為正判定輸出為1,否則為0。為了得到一組較好的權值從而有效控制倒立擺,我們可以採用爬山演算法(hill climbing algorithm)進行學習優化。爬山演算法是一種啟髮式方法,是對深度優先搜索的一種改進,它利用反饋信息幫助生成解的決策。

    爬山演算法的基本思路是每次迭代時給當前取得的最優權重加上一組隨機值,如果加上這組值使得有效控制倒立擺的持續時間變長了那麼就更新它為最優權重,如果沒有得到改善就保持原來的值不變,直到迭代結束。在迭代過程中,模型的參數不斷得到優化,最終得到一組最優的權值作為控制模型的解。其代碼如下:

# coding: utf8

import numpy as np
import gym
import time

def get_action(weights, observation):# 根據權值對當前狀態做出決策
    wxb = np.dot(weights[:4], observation) + weights[4] # 計算加權和
    if wxb >= 0:# 加權和大於0時選取動作1,否則選取0
        return 1
    else:
        return 0

def get_sum_reward_by_weights(env, weights):
# 測試不同權值的控制模型有效控制的持續時間(或獎勵)
    observation = env.reset() # 重置初始狀態
    sum_reward = 0 # 記錄總的獎勵
    for t in range(1000):
        # time.sleep(0.01)
        # env.render()
        action = get_action(weights, observation) # 獲取當前權值下的決策動作
        observation, reward, done, info = env.step(action)# 執行動作並獲取這一動作下的下一時間步長狀態
        sum_reward += reward
        # print(sum_reward, action, observation, reward, done, info)
        if done:# 如若游戲結束,返回
            break
    return sum_reward


def get_weights_by_random_guess():
# 選取隨機猜測的5個隨機權值
    return np.random.rand(5)

def get_weights_by_hill_climbing(best_weights):
# 通過爬山演算法選取權值(在當前最好權值上加入隨機值)
    return best_weights + np.random.normal(0, 0.1, 5)

def get_best_result(algo="random_guess"):
    env = gym.make("CartPole-v0")
    np.random.seed(10)
    best_reward = 0 # 初始最佳獎勵
    best_weights = np.random.rand(5) # 初始權值為隨機取值

    for iter in range(10000):# 迭代10000次
        cur_weights = None

        if algo == "hill_climbing": # 選取動作決策的演算法 
            # print(best_weights)
            cur_weights = get_weights_by_hill_climbing(best_weights)
        else: # 若為隨機猜測演算法,則選取隨機權值
            cur_weights = get_weights_by_random_guess()
		# 獲取當前權值的模型控制的獎勵和
        cur_sum_reward = get_sum_reward_by_weights(env, cur_weights)

        # print(cur_sum_reward, cur_weights)
		# 更新當前最優權值
        if cur_sum_reward > best_reward:
            best_reward = cur_sum_reward
            best_weights = cur_weights
		# 達到最佳獎勵閾值後結束
        if best_reward >= 200:
            break

    print(iter, best_reward, best_weights)
    return best_reward, best_weights

# 程式從這裡開始執行
print(get_best_result("hill_climbing")) # 調用爬山演算法尋優並輸出結果 

# env = gym.make("CartPole-v0")
# get_sum_reward_by_weights(env, [0.22479665, 0.19806286, 0.76053071, 0.16911084, 0.08833981])

    爬山演算法本質是一種局部擇優的方法,效率高但因為不是全局搜索,所以結果可能不是最優。在這裡採用的模型較為簡單,如若想要獲得更好的學習效果可以考慮更加複雜的模型,如深度神經網路。


5. 結束語

    可以看到網上有很多通過深度Q學習演算法解決倒立擺問題的文章,DQN確實不失為一種較好的解決方法,不過作為強化學習的基礎部分這裡就總結這麼多了,關於DQN後面也會具體總結介紹。

    由於博主能力有限,博文中提及的方法與代碼即使經過測試,也難免會有疏漏之處。希望您能熱心指出其中的錯誤,以便下次修改時能以一個更完美更嚴謹的樣子,呈現在大家面前。同時如果有更好的實現方法也請您不吝賜教。

人工智慧博士,機器學習及機器視覺愛好者,公眾號主及B站UP主,專註專業知識整理與項目總結約稿、軟體項目開發、原理指導請聯繫微信:sixuwuxian(備註來意),郵箱:[email protected],微信公眾號:“AI技術研究與分享”。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 什麼是API API (Application Programming Interface) :應用程式編程介面 java中的API 指的就是 JDK 中提供的各種功能的 Java類,這些類將底層的實現封裝了起來,我們不需要關心這些類是如何實現的,只需要學習這些類如何使用即可,我們可以通過幫助文檔來 ...
  • admin後臺管理 django給您提供了一個可視化圖形界面,來方便您來對資料庫里的表進行增刪改查的管理 但是!使用admin後臺管理你自己註冊的模型表時,需要自行進行先註冊該表! 在應用下的admin.py里進行註冊: from django.contrib import admin from a ...
  • Google翻譯大概是目前機器翻譯中翻譯最為準確的了,本文分別使用了兩種可行的方式編寫了簡易的谷歌翻譯軟體。將詳細介紹調用谷歌翻譯API和自行定義谷歌翻譯介面的方式,最後講解如何通過pyqt5實現軟體UI界面並附上全部程式文件。要點如下:調用Google翻譯API方式、自行定義谷歌翻譯介面方式、谷歌... ...
  • 這篇博文在早前本人寫的介紹拼圖游戲的基礎上推出帶有GUI用戶界面的增強版,這裡將通過上、中、下三篇博文詳細介紹利用MATLAB GUI設計的拼圖游戲完整實現過程,每篇都會附上相應代碼及解釋。中篇主要講解拼圖游戲中游戲難度選擇(拼圖階數設置)與拼圖塊數字提示功能的詳細實現過程。中篇的要點如下:拼圖游戲... ...
  • 什麼是敏感性分析 敏感性分析(sensitivity analysis)是指從定量分析的角度研究有關因素髮生某種變化對某一個或一組關鍵指標影響程度的一種不確定分析技術。每個輸入的靈敏度用某個數值表示即敏感性指數(sensitivity index) 敏感性指數包括以下幾種: 一階指數:度量單個模型輸 ...
  • 1、概念 遞歸就是方法自己調用自己,每次調用時傳入不同的變數.遞歸有助於編程者解決複雜的問題,同時可以讓代碼變得簡潔。並且遞歸用到了虛擬機棧 2、能解決的問題 數學問題 八皇後問題 漢諾塔 求階乘 迷宮問題 球和籃子 各種排序演算法 3、規則 方法的變數是獨立的,不會相互影響的 如果方法中使用的是引用 ...
  • 前端代碼搭建 主要利用的是bootstrap3中js插件里的模態框版塊 <li><a href="" data-toggle="modal" data-target=".bs-example-modal-lg">修改密碼</a></li> <div class="modal fade bs-exam ...
  • python爬蟲瀏覽器偽裝 #導入urllib.request模塊 import urllib.request #設置請求頭 headers=("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, l ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...