50行Python代碼教AI做到動作均衡

尋夢新聞LINE@每日推播熱門推薦文章,趣聞不漏接❤️

加入LINE好友

50行Python代碼教AI做到動作均衡 科技 第1張

作者 | Mike Shi

譯者 | linstancy

責編 | Jane

出品 | AI科技大本營(id:rgznai100)

50行Python代碼教AI做到動作均衡 科技 第2張

【導讀】本文將為大家展示如何通過 Numpy 庫和 50行 Python 代碼,使用標準的 OpenAI Gym平台創建智能體 (agent),就教會機器處理推車桿問題 (cart pole problem) ,保持平衡。

推車桿問題 (cart pole problem) ,大家可以類比好像在手指尖上垂直平衡鉛筆一樣,需要通過左右推動來平衡車頂部的桿,這是個非常具有挑戰性的問題!

今天,我們不過多的討論強化學習的基礎理論,希望大家在下面的編譯器里,不斷嘗試,體會這個項目。一開始,大家只需要點擊「Start」,開始配置需要的環境即可。

50行Python代碼教AI做到動作均衡 科技 第3張

快速入門強化學習 (RL)

如果你是機器學習或強化學習領域的新人,先了解一下下面的一些基礎知識和術語,為後面做鋪墊。如果你已經掌握了基礎知識,那可以跳過這部分內容。

  • 強化學習

強化學習旨在教會我們的智能體 (算法或機器) 執行特定的任務或動作,而無需顯式地告訴它該如何做。想像一個嬰兒在隨機抬動自己的腿,當站立起來時就給予他一個獎勵。同樣地,智能體的目標是在其生命周內最大化獎勵值,而獎勵取決於特定的任務。比如寶寶站立這個例子,站立時給予獎勵記為1,否則記為0。

AlphaGo 就是一個典型的強化學習智能體例子,教會智能體如何玩遊戲並最大化其獎勵 (即贏得遊戲)。而在本文中就將創建一個智能體,教它如何通過左右推動推車來解決推車上的桿平衡問題。

  • 狀態

50行Python代碼教AI做到動作均衡 科技 第4張

狀態即當前遊戲的樣子,通常用數字來表示。在乒乓球比賽中,它可能是每個球拍與x、y坐標軸的垂直位置或者是乒乓球的速度。在推車桿的情況下,這里的狀態由4個數字組成:即推車的位置,推車的速度,桿的位置 (作為角度) 和桿的角速度。這4個數字作為向量 (或數組) 提供給智能體,這非常重要:將狀態作為一組數字意味著智能體能夠對它進行一些數學運算,以便決定如何根據狀態來採取什麼行動。

  • 策略

策略是一種可以處理遊戲狀態的函數 (例如棋盤的位置或者推車和桿的位置), 並輸出智能體在該位置應該採取的動作 (例如移動可能將推車推到左邊)。在智能體採取相應的操作後,遊戲將以下一個狀態更新,此時將再次根據其輸入策略做出決策,這個過程一直持續到遊戲達到某個終止條件時結束。策略同樣是個非常關鍵的因素,因為它反映了是智能體背後的決策能力,這也是我們所需要認真考慮的。

  • 點積 (dot product)

兩個數組 (向量) 之間的點積可以簡單理解為,將第一個數組的每個元素乘以第二個數組的對應元素,並將它們全部加在一起。假設想要計算數組 A 和 B 的點積,形如 A[0]*B[0]+A[1]*B[1] ……隨後將使用此運算結果再乘以一個狀態 (同樣是一個向量) 和一個策略值 (同樣也是一個向量)。這部分內容將在下一節詳細介紹。

制定策略

為了解決推車遊戲,我們希望所設計的機器學習策略能夠贏得遊戲或最大化遊戲獎勵。對於智能體而言,這里將接收4維數組所表示策略,每一維代表每個組成的重要性 (推車的位置,桿位等四個組成)。隨後,再將點積的結果與策略、狀態向量進行處理並輸出最終的結果。根據結果的正負值決定是向左還是向右推動推車。這聽起來可能有點抽象,下面就通過一個具體的例子,來看看整個過程將發生什麼。

假設推車在遊戲中靜止地處在中間位置,當桿向右傾斜時車也將向右傾斜,如下圖這樣:

50行Python代碼教AI做到動作均衡 科技 第5張

所對應的的狀態如下圖所示:

50行Python代碼教AI做到動作均衡 科技 第4張

此時的狀態向量為 [0, 0, 0.2, 0.05]。直觀地說,現在我們想要將推車推向右側,並將桿拉直。這里通過訓練中得到了一個很好的策略,即 [-0.116, 0.332, 0.207, 0.352]。將上面的狀態向量與策略向量進行點積處理,如果得到的結果為正,則將推車向右推動;反之則向左推動。

50行Python代碼教AI做到動作均衡 科技 第4張

顯然,這里的輸出是個正數,這意味著在這種策略下智能體將推車向右推動,這也正是我們想要的結果。那麼,該如何得到這個策略向量呢,以便智能體能夠朝著我們希望的方向推動?或者說如果隨機選擇一個策略,那麼智能體又該如何行動呢?

開始編輯

在該項目主頁 repl.it 上彈出一個 Python 實例。repl.it允許用戶快速啟動大量不同編程環境的雲實例環境並在強大雲編譯器 (IDE) 中編輯代碼,這個強大的 IDE 能在任何地方訪問,如下圖所示。

50行Python代碼教AI做到動作均衡 科技 第8張

安裝所需的包

安裝這個項目所需的兩個軟件包:numpy 用於幫助數值計算,而 OpenAI Gym 則作為智能體的模擬器。如下圖所示,只需在編輯器左側的包搜尋工具中輸入 gym 和 numpy,然後單擊加號按鈕即可安裝這兩個包。

50行Python代碼教AI做到動作均衡 科技 第9張

創建基礎環境

這里首先將剛安裝的兩個依賴包導入到 main.py 腳本中並設置一個新的 gym環境。隨後定義一個名為 play 的函數,該函數將被賦予一個環境和一個策略向量,在環境中執行策略向量並返回分數以及每個時間步的遊戲觀測值。最後,將通過分數高低來反映策略的效果好壞,以及在單次遊戲中策略的表現。如此,就可以測試不同的策略,查看他們在遊戲中的表現!

import gym
import numpy as np

env = gym.make('CartPole-v1')

下面從函數定義開始,將遊戲重置為開始狀態,如下所示。

def play(env, policy):
observation = env.reset()

接著初始化一些變量,用來跟蹤遊戲是否達到終止條件,策略得分以及遊戲中每個步驟的觀測值,如下所示。

 done = False
score = 0
observations = []

現在,只需要一些時間步來開始遊戲,直到 gym 提示遊戲結束為止。

for _ in range(5000):
observations += [observation.tolist()] # Record the observations for normalization and replay

if done: # If the simulation was over last iteration, exit loop
break

# Pick an action according to the policy matrix
outcome = np.dot(policy, observation)
action = 1 if outcome > 0 else 0

# Make the action, record reward
observation, reward, done, info = env.step(action)
score += reward

return score, observations

如下,這部分的代碼主要是用於開始遊戲並記錄結果,而與策略相關的代碼就是這兩行:

 outcome = np.dot(policy, observation)
action = 1 if outcome > 0 else 0

在這里所做的只是對策略向量和狀態 (觀測) 數組之間進行點積運算,就像在之前具體例子中所展現的那樣。隨後根據結果的正負,選擇1或0 (向左或右) 的動作。到這里為止,main.py 腳本如下所示:

import gym
import numpy as np

env = gym.make('CartPole-v1')

def play(env, policy):
observation = env.reset()

done = False
score = 0
observations = []

for _ in range(5000):
observations += [observation.tolist()] # Record the observations for normalization and replay

if done: # If the simulation was over last iteration, exit loop
break

# Pick an action according to the policy matrix
outcome = np.dot(policy, observation)
action = 1 if outcome > 0 else 0

# Make the action, record reward
observation, reward, done, info = env.step(action)
score += reward

return score, observations

下面開始尋找該遊戲的最優策略!

第一次遊戲

現在已經有了一個函數,用來反映策略的好壞。因此,接下來要做的事開始制定一些策略,並查看他們的表現如何。如果一開始你想嘗試一些隨機的策略,那麼這些策略的結果將會怎樣呢?這里使用 numpy 來隨機生成一些的策略,這些策略都是4維數組或1×4矩陣,即選擇4個0到1之間的數字作為遊戲的策略,如下所示。

policy = np.random.rand(1,4)

有了這些策略以及上面所創建的環境,下面就可以開始遊戲並獲得策略分數:

score, observations = play(env, policy)
print('Policy Score', score)

只需點擊運行即可開始遊戲,它將輸出每個策略所對應的得分,如下所示。

50行Python代碼教AI做到動作均衡 科技 第10張

最後,所有的策略獲得的最高得分為500,在這里隨機生成的策略可能並不能得到太好的結果,而且通過隨機生成的方式,很難解釋智能體是如何進行遊戲的。下一步將介紹如何選擇並設置遊戲的策略,來查看智能體的遊戲表現。

觀察我們的智能體

這里使用 Flask 來設置輕量級服務器,以便可以在瀏覽器中查看智能體的表現。 Flask 是一個輕量級的 Python HTTP 服務器框架,可以為 HTML UI 和數據提供服務。由於渲染和 HTTP 服務器背後的細節對智能體的訓練並不重要,在這里只是簡單介紹下。首先需要將 Flask 安裝為 Python 包,就像上面安裝 gym 和 numpy 包一樣,如下所示。

50行Python代碼教AI做到動作均衡 科技 第11張

接下來,在腳本的底部創建一個 flask 服務器,它將在 /data 端點上公開遊戲的每個幀的記錄,並在 / 上托管 UI,如下所示。

from flask import Flask
import json
app = Flask(__name__, static_folder='.')
@app.route("/data")
def data():
return json.dumps(observations)
@app.route('/')
def root():
return app.send_static_file('./index.html')
app.run(host='0.0.0.0', port='3000')

此外,還需要添加兩個文件:一個是項目的空白 Python 文件,這是 repl.it 用於檢測 repl 是處於評估模式還是項目模式的關鍵。這里只需使用新文件按鈕添加空白的 Python 腳本即可。隨後,還需要創建一個將承載渲染 UI 的 index.html 文件。在此不需要深入了解這部分的內容,只需將此 index.html 上傳到 repl.it 項目即可。

好了,現在的項目目錄應該像這樣,如下所示:

50行Python代碼教AI做到動作均衡 科技 第12張

有了這兩個新文件,當運行 repl 時它將回放所選擇的遊戲策略,便於我們尋找一個最優的策略。

50行Python代碼教AI做到動作均衡 科技 第13張

策略搜尋

在第一次遊戲中只是通過 numpy 為智能體隨機生成一些策略並開始遊戲。那麼,如何選擇一些遊戲策略,並在遊戲結束時只保留那個結果最好的策略呢?在這里,制定遊戲時並不只是生成一個策略,而是通過編寫一個循環來生成一些策略,跟蹤每個策略的執行情況並在最後保存最佳的策略。

首先創建一個名為 max 的元組,它將存儲遊戲過程所出現的最佳策略得分、觀測和策略數組,如下所示。

max = (0, [], [])

接下來將生成並評估10個策略,並將得分最大值的策略保存。此外,這里還需要在 /data 端點返回最佳策略的重放,如下所示。

for _ in range(10):
policy = np.random.rand(1,4)
score, observations = play(env, policy)

if score > max[0]:
max = (score, observations, policy)

print('Max Score', max[0])

此外,這個端點:

@app.route("/data")
def data():
return json.dumps(observations)

應改為:

@app.route("/data")
def data():
return json.dumps(max[1])

最後 main.py 腳本應像這樣,如下圖所示:

import gym
import numpy as np
env = gym.make('CartPole-v1')
def play(env, policy):
observation = env.reset()
done = False
score = 0
observations = []
for _ in range(5000):
observations += [observation.tolist()] # Record the observations for normalization and replay
if done: # If the simulation was over last iteration, exit loop
break
# Pick an action according to the policy matrix
outcome = np.dot(policy, observation)
action = 1 if outcome > 0 else 0
# Make the action, record reward
observation, reward, done, info = env.step(action)
score += reward
return score, observations
max = (0, [], [])
for _ in range(10):
policy = np.random.rand(1,4)
score, observations = play(env, policy)
if score > max[0]:
max = (score, observations, policy)
print('Max Score', max[0])
from flask import Flask
import json
app = Flask(__name__, static_folder='.')
@app.route("/data")
def data():
return json.dumps(max[1])
@app.route('/')
def root():
return app.send_static_file('./index.html')
app.run(host='0.0.0.0', port='3000')

如果現在運行 repl,正常情況所得到的最大分數應為500。如果沒有的話,請再次嘗試運行 repl! 通過這種方式,能夠完美地觀察遊戲策略是如何讓桿達到平衡的!

如何加速?

(1)這里智能體達到平衡的速度並不夠塊。回想前面制定策略時,首先只是在0到1範圍內隨機創建了策略數組,這恰好是有效的。但如果這里智能體翻轉大於運算符所設定的那樣,那麼可能將看到災難性的失敗結果。可以嘗試將 action> 0 if outcome>0 else 0 改為 action=1 if outcome<0 else 0。

效果似乎並沒有很明顯,這可能是因為如果恰好選擇少於而不是大於,那麼可能永遠也找不到解決遊戲的策略。為了緩解這種情況,在實際操作時也應該生成一些帶負數的策略。雖然這將使得搜尋一個好策略的過程變得更加困難 (因為包含許多負的策略並不好),但所帶來的好處是不再需要通過特定算法來匹配特定遊戲。如果嘗試在 OpenAI gym 的其他環境中這樣做,那麼算法肯定會失敗。

要做到這一點,不能使用 policy = np.random.rand(1,4),需要將改為 policy = np.random.rand(1,4) -0.5。如此,所生成的策略中每個數字都在-0.5到0.5之間,而不是0到1。但是由於這樣做會使得最優策略的搜尋過程變得困難,因此在上面的 for 循環中,不要迭代10個策略,更改這部分的代碼嘗試搜尋100個策略 (for _ in range (100):)。當然,你也可以先嘗試迭代10次,看看用負的策略獲得最優策略的困難性。

好了,現在的 main.py 腳本可參考

https://gist.github.com/MikeShi42/e1c5551bbf2cb2064da962ad8b198c1b

如果現在運行 repl,無論使用的是否大於或小於,仍然可以找到一個好的遊戲策略。

(2)不僅如此,即使所生成的策略可能能夠在一次遊戲中得到最高分500的結果,那它能夠在每次遊戲中都有這樣的表現呢?當生成100個策略並選擇在單次運行中表現最佳的策略時,該策略可能只是單次最佳策略,或者它可能是一個非常糟糕的策略,只是恰好在一次遊戲中有非常好的性能。因為遊戲本身具有隨機性 (如起始位置每次都不同),因此策略可以只是在一個起始位置表現良好,而不是在其他位置。

因此,為了解決這個問題,需要評估一個策略在多次實驗中的表現。現在就採取之前實驗得到的最佳政策,查看它在100次遊戲實驗中的表現。在這里對最優策略進行100次遊戲 (最大索引值為2) 並記錄每次的遊戲得分。隨後使用 numpy 計算該策略的平均分數並將其列印到終端。你可能會注意到,最佳的遊戲策略實際上並不一定是最優秀的。

總結

好了,以上已經成功創建了一個能夠非常有效地解決推車桿問題的 AI 智能體。當然它還有很大的改進空間,這將是後續系列文章的一部分。此外,後續的工作還可以對一些問題展開研究:

  • 尋找「真正的」最優策略 (即在100次獨立遊戲中表現良好)
  • 優化最佳策略搜尋所需的次數 (即樣本效率問題)
  • 選擇正確搜尋策略,而不是嘗試隨機地選擇。
  • 在其他的環境中創建。

原文地址:https://towardsdatascience.com/from-scratch-ai-balancing-act-in-50-lines-of-python-7ea67ef717

  (*本文為 AI科技大本營約稿文章,轉載請微信聯繫 1092722531)

>50行Python代碼教AI做到動作平衡

About 尋夢園
尋夢園是台灣最大的聊天室及交友社群網站。 致力於發展能夠讓會員們彼此互動、盡情分享自我的平台。 擁有數百間不同的聊天室 ,讓您隨時隨地都能找到志同道合的好友!