增強學習和OpeAI Gym的介紹:基礎增強學習問題的演示

OReillyData發表於2017-10-13

編者注:想要深入學習增強學習,請檢視Marcos Campos在2017年9月17 - 20日於舊金山舉行的O’Reilly人工智慧會議上所做的“增強學習介紹”輔導課。你可以在Justin Francis的GitHub上找到這個博文裡展示的程式碼。

那些對機器學習世界感興趣的人已經意識到了基於增強學習的人工智慧的能力。在過去的幾年裡,使用增強學習(RL,Reinforcement Learning)在很多方面取得了突破。DeepMind公司將深度學習與增強學習結合在一起,在眾多的Atari遊戲中來取得超越人類的表現。並在2016年3月的圍棋比賽中,以4:1擊敗了圍棋冠軍李世石。雖然RL目前在許多遊戲環境中都表現很出色,但它對解決需要最優決策和效率的問題而言是種全新方法,而且肯定會在機器智慧中發揮作用。

OpenAI成立於2015年底,是一個非營利組織。它的目的是“建立安全的人工通用智慧(AGI),並確保AGI的福利被儘可能廣泛和均勻地分佈”。除了探索關於AGI的諸多問題之外,OpenAI對機器學習世界的一個主要貢獻是開發了Gym和Universe軟體平臺。

Gym是為測試和開發RL演算法而設計的環境/任務的集合。它讓使用者不必再建立複雜的環境。Gym用Python編寫,它有很多的環境,比如機器人模擬或Atari 遊戲。它還提供了一個線上排行榜,供人們比較結果和程式碼。

簡單來說,RL是一種計算方法。在這種方法中,代理通過採取行動來與環境進行互動,從而最大化累積的獎勵。這裡有一個簡單的圖,我後面會經常提到。

640?wx_fmt=png&wxfrom=5&wx_lazy=1

圖1 增強學習:入門,第二版。來自Richard S. Sutton和Andrew G. Barto,獲准使用

處於當前狀態(St)的代理對環境的反應和響應採取行動(At) ,然後返回一個新的狀態(St+1)和對代理的行動進行的獎勵(Rt+1)。考慮到更新的狀態和獎勵,代理再選擇下一個動作,迴圈重複,直到環境任務被解決或終止。

OpenAI的Gym是基於這些基本原理。所以先讓我們來安裝Gym,看看它是如何與這個迴圈相關的。我們使用Python和Ubuntu終端安裝Gym(你也可以根據Gym在GitHub上的介紹使用Mac電腦)。

sudo apt-get install -y python3-numpy python3-dev python3-pip cmake zlib1g-dev libjpeg-dev xvfb libav-tools xorg-dev python-opengl libboost-all-dev libsdl2-dev swig

cd ~

git clone https://github.com/openai/gym.git

cd gym

sudo pip3 install -e ‘.[all]’

接下來,我們可以在我們的終端執行Python3並且匯入Gym。

python3

import gym

第一步,我們需要一個環境。作為我們的第一個例子,我們會匯入非常基礎的計程車環境。

env = gym.make(“Taxi-v2”)

為了初始化環境,我們必須重置它。

env.reset()

您會注意到重置環境將會返回一個整數。這個數字就是我們的初始狀態。在這個計程車環境中,所有可能的狀態都用一個從0到499的整數表示。我們可以使用以下命令來確定可能狀態的總數:

env.observation_space.n

如果您想要視覺化當前狀態,鍵入以下內容:

env.render()

在這個環境中,黃色方塊代表計程車,(“|”)表示一堵牆,藍色字母代表接乘客的位置,紫色字母是乘客下車的位置,計程車上有乘客時就會變綠。當我們看到代表環境的顏色和形狀時,演算法不會像我們那樣思考,它只會理解一個扁平的狀態,在這個例子裡就是一個整數。

現在我們已經載入了環境,並且知道了當前狀態,讓我們來探索代理可用的行動。

env.action_space.n

這個命令顯示了總共有6種可用的行動。Gym不會總是告訴你這些動作的含義,但在這個場景下,這6種可能的行動是:下(0)、上(1)、左(2)、右(3)、接乘客(4)和放下乘客(5)。

為了學習的方便,讓我們將當前狀態改寫為114。

env.env.s = 114

env.render()

現在我們讓計程車向上移動。

env.step(1)

env.render()

你會注意到這個env.step(1)動作會返回4個變數。

(14, -1, False, {‘prob’: 1.0})

在後面我們會定義這些變數如下:

state, reward, done, info = env.step(1)

這4個變數是:新狀態(St+1 = 14)、獎勵(Rt+1 = -1)、一個布林值(說明環境是否被終止或完成)以及額外的除錯資訊。每個Gym環境在行動後都會返回相同的4個變數,因為它們是增強學習問題的核心變數。

再看看渲染出來的環境。如果你向左走,你希望環境會回報什麼?當然,你會得到和以前一樣的回報。對於每個步驟,環境總是給出一個- 1的獎勵,讓代理嘗試找出最快的解決方案。如果衡量你的累計獎勵總數,持續地撞到牆會嚴重地懲罰你的最終獎勵。當每次搭載或放下乘客不正確的時候,環境也會給你一個- 10的回報。

因此,我們如何才能解決這個環境的任務?

一種令人驚訝的可以解決這個環境任務的方法就是隨機地在6種可能的行動中選擇一個。當你能成功接上一個乘客並把它放到它們想去的位置,這個環境的任務被認為得到解決。一旦實現,你會得到20分的獎勵,並且done變數會變成True。在進行了足夠多次隨機的行動後,你可能會最終幸運地完成任務。儘管這種機率很小但並非不可能。評估每個代理的表現的一個核心部分就是比較它們和隨機動作的代理。在Gym的一個環境裡,你可以用env.action_space.sample()來選擇隨機動作代理。你可以建一個迴圈,讓代理隨機動作直到任務解決。我們可以在迴圈里加上一個計數器來觀察需要多少步才能解決環境任務。

state = env.reset()

counter = 0

reward = None

while reward != 20:

state, reward, done, info = env.step(env.action_space.sample())

counter += 1

print(counter)

可能有人會非常幸運,在很短的時間裡就解決了任務。但平均下來,完全隨機的策略會花2000多步才能解決任務。因此想在未來最大化我們的獎勵,我們就必須讓演算法記住自己的動作和帶來的獎勵。這種情況下,演算法的記憶就會成為一個Q動作價值表。

未來管理這個Q表,我們會使用一個NumPy的array列表。列表的大小是狀態數(500)乘以可能的行動數(6),即500×6。

import numpy as np

Q = np.zeros([env.observation_space.n, env.action_space.n])

在經過多次解決任務的嘗試回合(episode)後,我們會更新Q值,逐步提升我們演算法的效率和表現。我們也希望能跟蹤我們每個回合的累積獎勵值,我們定義它為G。

G = 0

與大多數的機器學習問題類似,我們還是需要一個學習速率。我會使用我個人的最愛0.618,它也是數學黃金分割常量π。

alpha = 0.618

下面,我們可以實現最基本的Q值學習演算法。

for episode in range(1,1001):

done = False

G, reward = 0,0

state = env.reset()

while done != True:

action = np.argmax(Q[state]) #1

state2, reward, done, info = env.step(action) #2

Q[state,action] += alpha * (reward + np.max(Q[state2]) – Q[state,action]) #3

G += reward

state = state2

if episode % 50 == 0:

print(‘Episode {} Total Reward: {}’.format(episode,G))

這些程式碼單獨就可以解決這個計程車環境任務。裡面程式碼比較多,我會分解開來解釋。

註釋(#1):這個代理使用argmax函式來為當前的狀態選擇一個最高的Q值的行動。argmax函式會返回某狀態的最高值的索引/行動。最初時,我們的Q表裡的值都是0。但是在每一步之後,每個狀態—行動組的Q值都會被更新。

註釋(#2):代理採用此行動,然後我們儲存一下未來的狀態為state2 (St+1)。這將會允許代理來比較之前的狀態和新的狀態。

註釋(#3):使用獎勵來更新狀態—行動組(St , At)的Q值和state2 (St+1)的最大的Q值。這個更新是使用行動值公式(基於Bellman方程),並允許狀態—行動組被用一種遞迴的方法來更新(基於未來的值)。圖2裡介紹了迴圈更新的公式。

0?wx_fmt=png

圖2 Q值的遞迴更新。來源:Gregz448,CC0,基於Wikimedia Commons授權

在更新完成後,我們再更新總體的獎勵值G,並更新state (St)到之前state 2(St+1)。這樣,迴圈可以再次開始,而下一個行動也能被決定了。

在經過非常多輪的回合後,這個演算法會最終收斂,從而通過Q表來決定每個狀態的最優行動,確保達到最大的獎勵值。到這時,我們認為環境任務已經被解決。

現在,我們解決了一個非常簡單的環境任務。那讓我們試一試一個更復雜的Atari遊戲環境——Pacman(吃豆子的小黃人)

env = gym.make(“MsPacman-v0”)

state = env.reset()

你會注意到env.reset()返回了一個非常大的數字列表。更具體點,你可以鍵入state.shape來顯示這個狀態是一個210x160x3的張量。它代表了Atari遊戲裡面的長、寬和3個RGB的顏色通道組合成的畫素。如前,你可以視覺化這個環境。

env.render()

而且和之前一樣,我們可以看看所有可能的行動:

env.action_space.n

我們有9種可能的行動:整數0-8。需要注意的是代理並不知道每個行動是什麼意思。它的工作只是學會哪個行動將會優化獎勵。但是為了我們好理解,我們可以:

env.env.get_action_meanings()

結果展示出代理可以選擇的9個行動:什麼都不做,以及遊戲手柄上能做的8種動作。

用我們之前的策略,首先看看一個隨機的代理的表現如何。

state = env.reset()

reward, info, done = None, None, None

while done != True:

state, reward, done, info = env.step(env.action_space.sample())

env.render()

完全隨機的策略最多能得幾百分,而且從來沒能通過第一關。

繼續,我們現在是不能用基本的Q表演算法了。因為這裡有33,600個畫素點,每個點上有3個隨機的0-255之間的整數RGB值。很容易看出事情變得極度複雜了。這裡可以用到深度學習來解決。使用諸如卷積神經網路或是DQN,一個機器學習庫就能夠把複雜的高維畫素矩陣變成抽象的表達,並把這個表達轉化成一個優化的行動。

總結一下,你現在已經有了一些基礎知識,也知道如何使用Gym並基於別人的(甚至是你自創的)演算法來做一些實驗了。如果你希望你獲得本博文裡用的程式碼,並照著來做或是編輯,你可以在我的GitHub上找到這些程式碼。

RL領域正伴隨著新的更好的解決環境任務的方法的出現而快速擴張。目前為止,A3C方法是其中最流行的方法之一。增強學習將很可能在未來的人工智慧裡發揮更重要的作用,並會持續產出非常有趣的結果。

This article originally appeared in English: "Introduction to reinforcement learning and OpenAI Gym".

0?wx_fmt=jpeg

Justin Francis

Justin居住在加拿大西海岸的一個小農場。這個農場專注於樸門道德和設計的農藝。在此之前,他是一個非營利性社群合作社自行車商店的創始人和教育者。在過去的兩年中,他住在一艘帆船上,全職探索和體驗加拿大的喬治亞海峽。但現在他的主要精力都放在了學習機器學習。


繼在紐約和舊金山成功售罄門票後,由O'Reilly主辦的人工智慧大會將於2018年4月10-13日來到北京。目前講師徵集中:https://ai.oreilly.com.cn/ai-cn。

議題徵集截止日期:11月7日

0?wx_fmt=png


相關文章