強化學習(Reinforcement Learning) — 運作流程
這幾個月來,醬糊小弟開始學習強化學習(Reinforcement Learning),主要目的是想做出玩遊戲的 AI 機器人,例如: AI 玩超級瑪俐。
到目前爲止,小弟看過 3 個不同強化學習的案例,也看了不少網路上的影片跟文章。大體上,強化學習有三個角色:主程式、環境(Environment)、與遊戲機器人(Agent);流程上則是:建立 env 與 agent、探索、觀察、行動、記錄、回顧(學習)…。
我們將在這篇文章中討論強化學習的流程,以及這 3 個案例中,醬糊小弟學習到的觀點。
角色
Reinforcement learning 的程式都是由這三個角色所組成:Main flow、Agent、跟 Env。他們三者的職責分別如下:
Main flow — 主流程
它負責管控 env 跟 agent 和程式訓練的流程。我們可以透過 episodes
參數來控制要訓練的遊戲次數。
Agent — 遊戲機器人
它依照 env 的狀態(state)選擇每個階段(step)的動作(action)。當然,它有 AI 大腦來進行學習。常見的參數有:
State size
:Env 提供的 state shape,也可以說是整個模型的輸入。但是,他不一定會是 AI 模型的輸入,因爲我們可能會對資料做過堆疊或調整後在傳入 AI 模型。Action
:Env 提供的 action shape,也可以說是整個模型的輸出。但是,他不一定會是 AI 模型的輸出,因爲我們可能會對資料做過調整後在輸出。Memory size
:學習的過程中,我們會暫存state
和action
的組合來做整批訓練。如果,我們是讓 agent 一邊玩一邊學習的話,這個暫存空間就不需要;如果我們是玩完後在學習,就會需要暫存的空間。Memory size
就是這個暫存空間的大小。 當遊戲玩的越多時,暫存空間可能會不夠,這時後,我們會把舊的記憶刪掉,再加入新的。Training batch
:在玩完後學習的案例中,我們不一定會把全部的記憶都拿來訓練。所以,爲了降低訓練所花的時間,我們會在記憶庫中隨機的選出training batch
數量的記憶來訓練。Learning rate
:learning rate
是用在 AI 模型中的一個參數,我們通常是使用 Adam optimizer 來訓練我們的 AI 模型,所以這個參數也是 Adam 的 learning rate。Gamma
:Reinforcement learning 中的 discount factor。它是下一個 state 的最大收益(maxQ reward)對當下這個action
的價值比率。Exploration rate
:由於 reinforcement learning 本身是非監督式學習,所以,我們要有一些機會讓我們的 AI 模型進行探索。這個部分就是它的探索比率。
Env — 遊戲的環境
他會是遊戲的本身,或是代替主程式跟遊戲溝通的橋樑。由於小弟還沒看過夠多的範例,所以還沒有看到一些比較特殊的 Env 的實作。
運作流程
看完角色及參數後,我們就可以拿這些角色跟參數來排列出完整的運作流程:
一個基本的 Reinforcement Learning 的運作流程就上面的圖片一樣,主要分成 12 個步驟,其中每個步驟都可能有不同的實作:
1. Init env & agent
Reinforcement learning 的一開始,我們要做四件事:
a. 先初始化 env
b. 從 env 讀出遊戲的 state size
跟 action size
c. 初始化 agent 並把這個 state size
跟 action size
送進 agent
d. 載入現有的 AI 模型
實作上的變形
一些 agent 的實作中,我們可以看到不同 AI 模型的設計。到目前為止,小弟看過直接把
state size
跟action size
當成是 AI 模型的輸入跟輸出;也有看過把 state 堆疊起來在加上其他的參數當成輸入… 等。這部份是一個值得研究的主題,目前我們找到這篇文章有相關變形的比較。目前,小弟在這邊的了解並不多,如果大家有怎麼想法想要分享的,也請在下面留言分享。
2. Check if end of training
一般的實作上,我們都會使用固定的 episodes
判斷是否該終止訓練。當然, 我們也可以改成依照 rewards
的品質來判斷是否訓練完成。這部份在小弟看過的這 3 個範例中,並沒有什麼太大的差別,都是採用固定的 episodes
數量來當成終止條件 。
3. Reset env
從字面上來看,它就是按下遊戲的 reset 按鈕,每次遊戲一開始,我們都要 reset env,來確保遊戲的狀態是從新的開始。這部分是 env 的實作,通常,我們可以呼叫要訓練的 env 的 API 或是直接從新初始化一個新的 env 就可以了。
4. Check if end of game
Env 每次執行一個 action
後,我們會得到 next state
、reward
、以及遊戲是否結束(done
)。當遊戲結束後,就會進到下一個訓練的階段。這個部份,在小弟看過的這 3 個範例中,並沒有什麼太大的差別,都是看 env 回傳的 done
參數來判斷。
5. Check if exploring phase
我們在前一個章節中知道 agent 會有一個參數 exploration rate
,agent 在這個步驟的時候,會利用 exploration rate
來判斷是不是還在 exploring phase。常見的方式是:
a. 產生一個隨機亂數
b. 當這個亂數大於 exploration rate
,就直接使用 AI 模型來做預測
c. 如果小於等於 exploration rate
,就隨機選擇一個 action
送出去
實作上的變形
一般的實作上,我們會讓
exploration rate
永遠不會是 0,除非我們要使用訓練好的模型來進行應用時。最主要的是,在訓練時,我們可能會遇到無法收斂的情況,這時 agent 可能會陷入一個無窮迴圈的狀況,如果還有一些機率會隨機選擇action
,那就會有機會打破這個無窮迴圈。這裡,我們也看過有人的實作上會在訓練的時候讓exploration rate
降到 0 ,但是,這些實作會依照執行的時間長短在把exploration rate
加回來。
6. Random choose action
這一步相對簡單,就隨機選擇一個 action
送出去就可以了。目前,小弟還沒有看過什麼特別的實作。
7. Predict action with state
這裡是依照 env 提供的 state
,交給 AI 模型進行預測,找出分數最高的 action
回傳。小弟第一個學習到的範例中,AI 模型的輸出層採用 softmax activation function,它代表每一個 action 的機率。看完後面的幾個文章跟範例後,小弟發現,大部分的實作是採用 linear 或是 relu 的 activation function。訓練的過程中,大家也會給大於 1 的數值。這就表示,其實它並不是 action
的機率,而是在這個 state
下,每個 action
可能拿到的分數。如果大家知道其他使用 softmax 的原因,還麻煩在下面留言告訴小弟一聲。
這裡的實作上的變形會跟 1. init env & action 的一樣,是依照我們對 AI 模型有什麼變化而定。
8. Execution action
確定 action
後,我們只需要叫 env 中執行這個 action
。一般來說,env 執行完會回傳 next state
、rewards
、跟遊戲是否結束(done
)。這部分在小弟看過的範例中,都是一樣的。
9. Step training
Step training 不一定是每個 reinforcement learning 的實作都會有的步驟。如同前面說的,reinforcement learning 會有兩個地方可以進行訓練:每一個 execute action 之後、跟每一次遊戲結束後,我們可以稱這兩個為邊玩邊學跟玩完再學。
在小弟看過的實作及文章中,一共有:邊玩邊學、玩完再學、跟兩種一起學習。到目前為止,小弟還不知道應該選擇那一種。
10. Pack training data
如同前面說所,如果我們是使用玩完再學的策略時,我們要將 state
、next state
、reward
、跟 done
存起來,以在之後學習。這邊,如果我們發現所儲存的記憶比 memory size
大的時候,我們會把最舊的拿掉,在加入這次的。
這裡的實作上的變形會跟 1. init env & action 的一樣,是依照我們對 AI 模型有什麼變化而定。如果,我們有對 AI 模型的輸入做前置處理,這裡也要先做過前置處理。
11. Batch training
玩完再學的策略會在遊戲結束後進行學習。由於 AI 模型的訓練會花比較多的時間,所以,常見的實作都是會隨機從記憶庫中選取 training batch size
筆資料進行訓練。訓練的時候,我們常常會用 Q learning 的公式來計算:reward(fit) = reward(env) + gamma * maxQ(next_state, action)。我們常會用同一個訓練模型來對 next_state 進行預測,找出最大的 reward
(這個就是maxQ(next_state
, action
)),接着乘上 gamma
在加上 env 給我們的 reward
當成訓練用的真正 reward
。
實作上的變形
在之前看過的實作和文章中,小弟看過在選取的策略上,它會對 env
reward
高的項目做加成,用來達到有高分的操作比較容易被選到,但是,這個範例小弟還不是很了解,所以,也不敢說它是正確的。另一個變形是,我們常用單一個 AI 模型進行訓練和預測。但是,Q Learning 演算法中有一個對未來報酬的期待是用
next_state
來做reward
的預測,小弟也看過用兩個模型來做訓練和預測。在 Batch training 階段,會用一個落後 x 次訓練的模型來當成對未來報酬的預測模型,當訓練模型完成 x 次訓練後,就會將訓練模型的權重複製一份到預測模型中。這種做法有一個非常大的好處,就是我們可以一次訓練跟多的資料,也就是把訓練的資料以及預期的結果一次算出來,並且一次傳到 GPU 上做運算,效率會高上許多。
12. Update exploration rate
遊戲結束後,如果 exploration rate
有需要衰退時,這裏就會進行衰退的計算,並更新 exploration rate
。在常見的範例中,我們會在模型一開始訓練的時候,給他較高的 exploration rate
,例如一開始的 exploration rate
都會是 1
,然後每玩一次的遊戲衰退 0.01
,這樣在玩了越一百多的時候,會小於 0.5
,在玩了三百多次後,會接近於 0
。
實作上的變形
在之前看過的實作和文章中,小弟看過保底的
exploration rate
更新策略,也看過會下降及回升的策略。
共通性
在小弟自己開始實作一些題目之後,小弟有了一下的體悟:
Agent 可以共用
其實很多 agent 的實作都會把 AI 模型包在裡面,而且也會用 state_size
跟 action_size
當成參數傳進去。所以,一些問題,我們可以用同一個 agent 的實作來對不同的 env 進行訓練。所以,我們可以把 agent 抽象化成下面這個 interface:
class Agent:
def __init__(self, state_size, action_size):
# 初始化 agent
pass def remember(self, state, action, reward, next_action):
# 記憶目前的結果
pass def choose_action(self, state):
# 依照 state 選擇 action
pass def replay(self, batch_size):
# 玩完再學習
pass def train_step(self, state, action, reward, next_action):
# 邊玩邊學
pass # 載入及儲存 AI 模型
def load_weights(self, path):
pass def save_weights(self, path):
pass
AI 模型與 Agent 分離
從前面的討論中,我們可以發現,其實 AI 模型並不一定要跟 agent 的實作綁在一起。當我們選擇把它們兩個分開的時候,agent 還是可以有一些共同的 interface,只是在訓練相關的地方會是使用 model 的 interface。這部份因爲小弟還沒實作過,所以,就先不把 interface 給寫出來了。
未解之謎
Reinforcement learning 的學習過程中是需要許多的實作跟實驗,一下小弟列出一些目前小弟還不能回答的問題,如果大家知道其中的奧祕,還請在下方留言分享:
- 如何分析一個問題來知道我們要用多大的 AI 模型才能解決這個問題?
- Exploration rate 及其衰退該如何設定才能快一點收斂?
- 邊玩邊學跟玩完在學到底該如何調配?尤其是在一個不知道模型是不是有效的情況下,這個問題會更嚴重。
- 是不是每個問題都適合使用單一模型或是多個模型?