這是本篇文章是《機器學(xué)習(xí)入門》系列文章的第五篇镐侯,該系列有如下文章:
《機器學(xué)習(xí)入門——基礎(chǔ)篇》
《機器學(xué)習(xí)入門——實戰(zhàn)篇之監(jiān)督學(xué)習(xí)》
《機器學(xué)習(xí)入門——實戰(zhàn)篇之非監(jiān)督學(xué)習(xí)》
《機器學(xué)習(xí)入門——實戰(zhàn)篇之深度學(xué)習(xí)》
《機器學(xué)習(xí)入門——實戰(zhàn)篇之強化學(xué)習(xí)》
在《機器學(xué)習(xí)入門——基礎(chǔ)篇》中已經(jīng)介紹過強化學(xué)習(xí)的概念执庐,也介紹了動態(tài)規(guī)劃和蒙特卡洛方法。因為這兩部分內(nèi)容都是可以寫成專著的大塊頭摸航,本文不做詳述,咱們直接進入實戰(zhàn)此再,用一個簡單的栗子來進入強化學(xué)習(xí)的世界饵较。
有這么一個經(jīng)典案例,就是“機器人走迷宮”镐捧,通過強化學(xué)習(xí)算法潜索,讓機器人自己學(xué)會尋找走出迷宮的辦法臭增,并不斷優(yōu)化這個路徑,最后得到較優(yōu)解竹习。
在該項目中誊抛,使用強化學(xué)習(xí)算法,實現(xiàn)一個自動走迷宮機器人整陌。
1拗窃、如上圖所示,智能機器人顯示在右上角泌辫。在我們的迷宮中随夸,有陷阱(紅色炸彈)及終點(藍色的目標(biāo)點)兩種情景。機器人要盡量避開陷阱震放、盡快到達目的地宾毒。
2、機器人可執(zhí)行的動作包括:向上走 u殿遂、向右走 r诈铛、向下走 d、向左走 l勉躺。
3、執(zhí)行不同的動作后觅丰,根據(jù)不同的情況會獲得不同的獎勵饵溅,具體而言,有以下幾種情況妇萄。
撞到墻壁:-10
走到終點:50
走到陷阱:-30
其余情況:-0.1
正式開始代碼之前蜕企,我們先來理一理思路,強化學(xué)習(xí)作為機器學(xué)習(xí)算法的一種冠句,其模式是讓智能體在“訓(xùn)練”中學(xué)到“經(jīng)驗”轻掩,以實現(xiàn)給定的任務(wù)。但不同于監(jiān)督學(xué)習(xí)與非監(jiān)督學(xué)習(xí)懦底,在強化學(xué)習(xí)的框架中唇牧,我們更側(cè)重通過讓被訓(xùn)練的對象與環(huán)境的交互來學(xué)習(xí)。通常在監(jiān)督學(xué)習(xí)和非監(jiān)督學(xué)習(xí)任務(wù)中聚唐,被訓(xùn)練對象往往需要通過給定的訓(xùn)練集丐重,輔之以既定的訓(xùn)練目標(biāo)(如最小化損失函數(shù)),通過給定的學(xué)習(xí)算法來實現(xiàn)這一目標(biāo)杆查。然而在強化學(xué)習(xí)中扮惦,被訓(xùn)練對象則是通過其與環(huán)境交互得到的獎勵進行學(xué)習(xí)。這個環(huán)境可以是虛擬的(如虛擬的迷宮)亲桦,也可以是真實的(自動駕駛汽車在真實道路上收集數(shù)據(jù))崖蜜。
在強化學(xué)習(xí)中有五個核心組成部分浊仆,它們分別是:
環(huán)境(Environment)
智能體(Agent)
狀態(tài)(State)
動作(Action)
獎勵(Reward)
在某一時間節(jié)點 t:
智能體在從環(huán)境中感知其所處的狀態(tài):
智能體根據(jù)某些準(zhǔn)則選擇動作:
環(huán)境根據(jù)智能體選擇的動作,向智能體反饋獎勵
通過合理的學(xué)習(xí)算法豫领,智能體將在這樣的問題設(shè)置下抡柿,成功學(xué)到一個在狀態(tài)選擇動作的策略
對應(yīng)“機器人走迷宮”這個題目,我們就能得到以下名詞的含義:
環(huán)境 : 迷宮的各條路徑氏堤,迷宮路徑上的陷阱沙绝,最終迷宮的出口也就是目標(biāo)位置
狀態(tài) : 為了便于將機器人走迷宮的問題抽象成一個數(shù)學(xué)上好操作的模型,我們在迷宮中加入了左邊鼠锈,例如(0闪檬,0)這樣的點,這樣機器人在任何一個時間點都會對應(yīng)一個位置坐標(biāo)购笆,同時粗悯,這個坐標(biāo)會結(jié)合環(huán)境具體情況帶給機器人一個激勵,有正向激勵同欠,也有負(fù)向激勵样傍,這些激勵會直接被帶入我們的算法公式,算出具體值铺遂,來刺激機器人做出下一步動作的決策衫哥;比如終點坐標(biāo)帶來的激勵就是很大的一個正向值50,比如陷阱坐標(biāo)所帶來的就是一個很大的負(fù)向值-30襟锐,而如果不是什么特別的位置的坐標(biāo)撤逢,也就是其余情況,就會給一個恰當(dāng)?shù)呢?fù)向激勵粮坞,刺激機器人繼續(xù)尋找目標(biāo)蚊荣;以上描述就是這個模型的狀態(tài)
動作 : 向上,向下莫杈,向左互例,向右各種方向上的移動
獎勵 : 撞到墻壁:-10; 走到終點:50筝闹;走到陷阱:-30媳叨;其余情況:-0.1
這個項目中,我們采用基于 Q-Learning 的強化學(xué)習(xí)算法关顷。Q-Learning 是一個值迭代(Value Iteration)算法肩杈。與策略迭代(Policy Iteration)算法不同,值迭代算法會計算每個”狀態(tài)“或是”狀態(tài)-動作“的值(Value)或是效用(Utility)解寝,然后在執(zhí)行動作的時候扩然,會設(shè)法最大化這個值。因此聋伦,對每個狀態(tài)值的準(zhǔn)確估計夫偶,是我們值迭代算法的核心界睁。通常我們會考慮最大化動作的長期獎勵,即不僅考慮當(dāng)前動作帶來的獎勵兵拢,還會考慮動作長遠的獎勵翻斟。
在 Q-Learning 算法中,我們把這個長期獎勵記為 Q 值说铃,我們會考慮每個 ”狀態(tài)-動作“ 的 Q 值访惜,具體而言,它的計算公式為:
也就是對于當(dāng)前的“狀態(tài)-動作” 腻扇,我們考慮執(zhí)行動作 ?? 后環(huán)境給我們的獎勵 债热,以及執(zhí)行動作 ?? 到達 后,執(zhí)行任意動作能夠獲得的最大的Q值 , 為折扣因子幼苛。
不過一般地窒篱,我們使用更為保守地更新 Q 表的方法,即引入松弛變量 ?????????舶沿,按如下的公式進行更新墙杯,使得 Q 表的迭代變化更為平緩。
在強化學(xué)習(xí)中括荡,「探索-利用」問題是非常重要的高镐。具體來說,根據(jù)上面的定義畸冲,我們會盡可能地讓機器人在每次選擇最優(yōu)的決策嫉髓,來最大化長期獎勵。但是這樣做有如下的弊端:
在初步的學(xué)習(xí)中召夹,我們的 Q 值會不準(zhǔn)確岩喷,如果在這個時候都按照 Q 值來選擇恕沫,那么會造成錯誤监憎。
學(xué)習(xí)一段時間后,機器人的路線會相對固定婶溯,則機器人無法對環(huán)境進行有效的探索鲸阔。
因此我們需要一種辦法,來解決如上的問題迄委,增加機器人的探索褐筛。由此我們考慮使用 epsilon-greedy 算法(是一種貪心算法,加入了隨機因子epsilon的貪心算法)叙身,即在小車選擇動作的時候渔扎,以一部分的概率隨機選擇動作,以一部分的概率按照最優(yōu)的 Q 值選擇動作信轿。同時晃痴,這個選擇隨機動作的概率應(yīng)當(dāng)隨著訓(xùn)練的過程逐步減小残吩。
簡單的實現(xiàn)以下這個貪心算法epsilon-greedy,有如下代碼:
import random
# 動作列表如下
actions = ['u','r','d','l']
qline = {'u':1.2, 'r':-2.1, 'd':-24.5, 'l':27}
# epsilon以0.3的概率進行隨機選擇
epsilon = 0.3
def choose_action(epsilon):
action = None
# 以前面定義好的一個epsilon進行選擇
if epsilon < random.random():
# 隨機選擇一個動作
action = random.choice(actions)
else:
# 否則選擇具有最大 Q 值的動作
action = max(qline, key=qline.get)
return action
接下來我們就可以生成迷宮啦倘核,本文開始的時候看到的迷宮太過簡單泣侮,我們給一個稍微有點難度的。
from Maze import Maze
myMaze = Maze(maze_size=(10,11), trap_number=5)
Python是不是很溫馨又簡單紧唱,居然有Maze這個東西活尊。
好了,我們生成好了這么一個迷宮漏益,準(zhǔn)備去訓(xùn)練小機器人蛹锰。接下來,就是最核心的部分遭庶,我們的小機器人啦宁仔,也就是要一個Robot類。
Robot類中峦睡,我們需要實現(xiàn)諸多功能翎苫,以使得我們成功實現(xiàn)一個強化學(xué)習(xí)智能體≌チ耍總體來說煎谍,之前我們是人為地在環(huán)境中移動了機器人,但是現(xiàn)在通過實現(xiàn) Robot 這個類龙屉,機器人將會自己移動呐粘。通過實現(xiàn)學(xué)習(xí)函數(shù),Robot 類將會學(xué)習(xí)到如何選擇最優(yōu)的動作转捕,并且更新強化學(xué)習(xí)中對應(yīng)的參數(shù)作岖。
首先 Robot 有多個輸入,其中 alpha=0.5, gamma=0.9, epsilon0=0.5 表征強化學(xué)習(xí)相關(guān)的各個參數(shù)的默認(rèn)值五芝,這些在之前我們已經(jīng)了解到痘儡,Maze 應(yīng)為機器人所在迷宮。
隨后需要一個 Robot.update 函數(shù)枢步,它指明了在每次執(zhí)行動作時沉删,Robot 需要執(zhí)行的指令。下面我們來看一看Robot這個類醉途。
需要一個初始化函數(shù)將參數(shù)引入:
def __init__(self, maze, alpha=0.5, gamma=0.9, epsilon0=0.5):
還需要一個更新函數(shù)矾瑰,每次把參數(shù)做一個更新:
def update_parameter(self):
self.t = self.t + 1
if self.testing:
# 測試
self.epsilon = self.epsilon0
else:
# 學(xué)習(xí)過程中更新參數(shù),讓epsilon逐漸變小
# 從而實現(xiàn)參數(shù)的收斂
if self.epsilon0 - self.t * 0.03 > 0:
self.epsilon = self.epsilon0 - self.t * 0.03
else:
self.epsilon = 0.01
return self.epsilon
然后有這么一個選擇動作的函數(shù):
def choose_action(self):
def is_random_exploration():
if random.random() < self.epsilon:
return True
else:
return False
if self.learning:
if is_random_exploration():
return self.valid_actions[random.randint(0, 3)]
else:
return max(self.Qtable[self.state], key = self.Qtable[self.state].get)
elif self.testing:
return max(self.Qtable[self.state], key = self.Qtable[self.state].get)
else:
return self.valid_actions[random.randint(0, 3)]
當(dāng)然了隘擎,必須要有一個更新知識表的函數(shù):
def update_Qtable(self, r, action, next_state):
if self.learning:
q_with_cur_state = self.Qtable[self.state][action]
q_with_next_state = r + self.gamma * max(self.Qtable[next_state].values())
self.Qtable[self.state][action] += self.alpha * (q_with_next_state - q_with_cur_state)
最后有一個整體的更新函數(shù):
def update(self):
self.state = self.sense_state() # 取得目前的狀態(tài)
self.create_Qtable_line(self.state) # 生成Qtable的記錄
action = self.choose_action() # 選擇一個動作
reward = self.maze.move_robot(action) # 移動機器人
next_state = self.sense_state() # 下一個狀態(tài)
self.create_Qtable_line(next_state) # 下一個記錄
if self.learning and not self.testing:
# 更新Qtable殴穴,注意,這個表是機器人的“經(jīng)驗”所在
# 初始化的時候這個表里面都設(shè)置成0
# 隨著訓(xùn)練的深入,可以逐步更新這個表采幌,從而指導(dǎo)機器人移動
self.update_Qtable(reward, action, next_state)
self.update_parameter() # 更新參數(shù)
return action, reward
上述部分并不是全部的代碼恍涂,我們略去了一些小的方法,只講了比較核心的幾個函數(shù)植榕,有心的讀者可以自己去補充并實現(xiàn)這個項目再沧。
在實現(xiàn)了上述內(nèi)容之后,我們就可以開始對我們 Robot 進行訓(xùn)練并調(diào)參了尊残。這里我們使用了另一個類Runner用來迭代這個模型炒瘸,從而實現(xiàn)整個訓(xùn)練過程及可視化。使用如下的代碼寝衫,可以成功對機器人進行訓(xùn)練顷扩。并且在當(dāng)前文件夾中生成一個視頻,記錄整個訓(xùn)練的過程慰毅。通過觀察該視頻隘截,我們能夠發(fā)現(xiàn)訓(xùn)練過程中的問題,并且優(yōu)化代碼及參數(shù)汹胃。
# 可選的參數(shù):
epoch = 40
epsilon0 = 0.5
alpha = 0.5
gamma = 0.9
maze_size = (10,11)
trap_number = 5
from Runner import Runner
g = Maze(maze_size=maze_size,trap_number=trap_number)
r = Robot(g,alpha=alpha, epsilon0=epsilon0, gamma=gamma)
r.set_status(learning=True, testing=False)
runner = Runner(r, g)
runner.run_training(epoch, display_direction=True)
# 我們姑且把整個訓(xùn)練的過程記錄成process.mp4文件吧
runner.generate_movie(filename = "process.mp4")
至此婶芭,我們這個項目的主要代碼就介紹完了,希望大家可以對強化學(xué)習(xí)有一個直觀的認(rèn)識:)
這是本篇文章是《機器學(xué)習(xí)入門》系列文章的第五篇着饥,該系列有如下文章:
《機器學(xué)習(xí)入門——基礎(chǔ)篇》
《機器學(xué)習(xí)入門——實戰(zhàn)篇之監(jiān)督學(xué)習(xí)》
《機器學(xué)習(xí)入門——實戰(zhàn)篇之非監(jiān)督學(xué)習(xí)》
《機器學(xué)習(xí)入門——實戰(zhàn)篇之深度學(xué)習(xí)》
《機器學(xué)習(xí)入門——實戰(zhàn)篇之強化學(xué)習(xí)》