↓↓↓點(diǎn)擊關(guān)注,回復(fù)資料,10個(gè)G的驚喜
本文約5200字,建議閱讀10分鐘?本文為你舉例介紹MDP的基本概念。
馬爾可夫決策過(guò)程(Markov decision process, MDP)是人工智能中的一個(gè)重要概念,也是強(qiáng)化學(xué)習(xí)的理論基礎(chǔ)之一。在今天的文章中,我們使用來(lái)自Stuart Russell和Peter Norvig的《Artificial Intelligence: A Modern Approach》一書(shū)中的網(wǎng)格例子來(lái)介紹MDP的基本概念。
我們的吃豆人游戲
這里我們有一個(gè) 4×3 的網(wǎng)格世界,有一個(gè)機(jī)器人從左下角開(kāi)始并在這個(gè) 2D 世界中移動(dòng)來(lái)玩游戲。
世界示例
我們的機(jī)器人可以向四個(gè)方向移動(dòng):上、下、左、右,與吃豆人的相似之處是我們的世界被不可通行的墻包圍。黑色方塊代表的邊界內(nèi)也有不可通過(guò)的墻。右上角正方形中的綠色菱形代表終點(diǎn)線。如果我們到達(dá)這個(gè)方格,我們就會(huì)贏得這場(chǎng)比賽并獲得很多積分(在本例中為 +1)。在吃豆人中,總有鬼魂試圖傷害你。在我們的游戲中,我們有一個(gè)帶有紅色毒藥的方塊。如果我們進(jìn)入這個(gè)方格,我們就會(huì)輸?shù)舯荣惒⑹艿胶芏鄳土P(在這個(gè)例子中是 -1)。所有其他白色方塊都是正常的方塊。每次我們進(jìn)入其中一個(gè)時(shí),我們都會(huì)失去少量點(diǎn)數(shù)(在本例中為 -0.04)。如果我們隨機(jī)移動(dòng),希望最終幸運(yùn)地到達(dá)綠色菱形,那么我們每走一步就會(huì)損失 0.04 分,從而損失很多分。這就相當(dāng)于機(jī)器人的電力系統(tǒng),每走一步需要消耗一定的電量,所以機(jī)器人每走一步就要減去點(diǎn)積分,以保證最低的消耗。為簡(jiǎn)單起見(jiàn),我們假設(shè)我們的機(jī)器人總是從左下角開(kāi)始,如上圖所示。綜上所述,在玩這個(gè)游戲的時(shí)候,我們希望盡可能快地獲得+1點(diǎn),而一路上付出最少的-0.04,并且我們絕對(duì)要避免在紅毒中以-1結(jié)束游戲。MDP的定義
在《Artificial Intelligence: A Modern Approach》中,MDP 被定義為具有馬爾可夫轉(zhuǎn)移模型和附加獎(jiǎng)勵(lì)的完全可觀察的隨機(jī)環(huán)境的順序決策問(wèn)題稱(chēng)為馬爾可夫決策過(guò)程或 MDP,由一組狀態(tài)(具有初始狀態(tài) s?)組成;每個(gè)狀態(tài)下的一組動(dòng)作;一個(gè)轉(zhuǎn)換模型 P(s'| s, a);和獎(jiǎng)勵(lì)函數(shù) R(s)。
讓我們用我們的例子來(lái)分解這個(gè)定義中的一些關(guān)鍵字。代理(又叫智能體)是指機(jī)器人或吃豆人或我們放置在這個(gè)世界中的任何東西,它會(huì)環(huán)顧四周尋找可能的移動(dòng),考慮可能移動(dòng)的利弊,做出下一步移動(dòng)的決定,并執(zhí)行移動(dòng)。環(huán)境是指世界的樣子和世界的規(guī)則。在我們的例子中,環(huán)境包括我們的世界有多大,墻在哪里,如果我們撞到墻會(huì)發(fā)生什么,鉆石在哪里,如果我們到達(dá)那里,我們得到多少分,毒藥在哪里,如果我們到達(dá)還有我們輸了多少分,等等。MDP 中的狀態(tài)是指我們代理的狀態(tài),而不是我們環(huán)境的狀態(tài)。在 MDP 中,環(huán)境是給定的并且不會(huì)改變。相比之下,我們的代理可以將狀態(tài)從先前的移動(dòng)更改為當(dāng)前的移動(dòng)。在這個(gè)示例中代理有 12 個(gè)狀態(tài),代表我們的代理可能處于的 12 個(gè)方格。從技術(shù)上講,我們的代理不能處于黑色方格中,但為簡(jiǎn)單起見(jiàn),我們?nèi)詫⒑谏礁褚暈橐粋€(gè)狀態(tài)。在 MDP 中,我們使用 s 來(lái)表示狀態(tài),在我們的示例中,我們稱(chēng)它們?yōu)?s = 0, 1, 2, ..., 11。
動(dòng)作是指我們的代理在每個(gè)狀態(tài)下可以采取的動(dòng)作。每個(gè)狀態(tài)的一組可能的操作不一定相同。在我們的示例中,對(duì)于每個(gè)狀態(tài) s,我們有四個(gè)可能的動(dòng)作 A(s) = {up, down, left, and right}。我們使用 a 來(lái)表示動(dòng)作。獎(jiǎng)勵(lì)是指我們進(jìn)入一個(gè)狀態(tài)時(shí)獲得的積分。在我們的示例中,對(duì)于不同的狀態(tài),它是 +1、-1 或 -0.04。獎(jiǎng)勵(lì)僅依賴(lài)于狀態(tài),這個(gè)從狀態(tài)到獎(jiǎng)勵(lì)的函數(shù)表示為 R(s)。無(wú)論我們之前的狀態(tài)如何,我們?cè)谶M(jìn)入某個(gè)狀態(tài)時(shí)都會(huì)獲得相同的獎(jiǎng)勵(lì)。例如,當(dāng) s = 3 時(shí),r = R(s) = R(3)= +1。無(wú)論我們從左邊的方格向右移動(dòng)到它,還是從它下面的方格向上移動(dòng)到它,我們都會(huì)得到相同的 +1 獎(jiǎng)勵(lì)。
累加獎(jiǎng)勵(lì)意味著來(lái)自不同動(dòng)作的獎(jiǎng)勵(lì)是累積的。在我們的示例中,我們的最終積分(總獎(jiǎng)勵(lì))是從鉆石或毒藥獲得的積分與沿途可通過(guò)的方塊獲得的積分相加。不僅是最后一格獲得的獎(jiǎng)勵(lì),一路上獲得的所有小獎(jiǎng)勵(lì)也很重要。在 MDP 中,我們假設(shè)我們可以將這些獎(jiǎng)勵(lì)加在一起。轉(zhuǎn)換模型告訴我們,如果我們?cè)谀硞€(gè)狀態(tài)下選擇某個(gè)動(dòng)作,我們將進(jìn)入下一個(gè)狀態(tài)。這通常表示為表 P。如果我們處于狀態(tài) s 并且我們選擇一個(gè)動(dòng)作 a,那么 s' 成為下一個(gè)狀態(tài)的概率是 P(s'| s, a)。如果我們假設(shè)我們的世界是確定性的,那么我們預(yù)期的移動(dòng)方向總是會(huì)實(shí)現(xiàn)。例如,如果我們?cè)?s = 10 并且我們選擇 a = UP,我們肯定會(huì)進(jìn)入一個(gè)新的狀態(tài) s' = 6。作為概率分布,所有 12 個(gè) s' 的 P(s'| s = 10, a = UP) 之和總是等于 1。
隨機(jī)意味著我們的世界不是我們上面假設(shè)的確定性的。從某個(gè)狀態(tài)開(kāi)始,如果我們選擇相同的動(dòng)作,我們不能保證進(jìn)入相同的下一個(gè)狀態(tài)。在我們的這個(gè)游戲中,可以將其視為我們的機(jī)器人以某種方式出現(xiàn)故障的可能性。例如,如果它決定向左走,那么實(shí)際上向左走的可能性很大。然而,它有一個(gè)很小的可能性,無(wú)論它有多小,它都會(huì)瘋狂地向左以外的方向移動(dòng)。按照書(shū)中的例子,實(shí)際朝預(yù)期方向移動(dòng)的概率是 0.8。向預(yù)定方向左移 90 度的概率為 0.1,向預(yù)定方向向右移動(dòng) 90 度的概率為 0.1。例如,如果我們?cè)?s = 10 并且我們選擇 a = UP,我們有 0.8 的概率進(jìn)入預(yù)期的新?tīng)顟B(tài) s' = 6。我們也有 0.1 的概率到達(dá) s' = 9 并且到達(dá) s' = 11 的概率為 0.1。這是當(dāng) s = 10 且 a = UP 時(shí)的轉(zhuǎn)換模型。現(xiàn)在對(duì)于每對(duì)狀態(tài) s 和動(dòng)作 a,我們可以像這樣寫(xiě)出到達(dá)每個(gè)新?tīng)顟B(tài)的概率。將所有這些組合在一起,我們得到了轉(zhuǎn)換模型 P。我們有 12 種可能的狀態(tài)和 4 種可能的動(dòng)作。因此,我們的過(guò)渡模型 P 的維度為 12×4×12,共有 576 個(gè)概率值。
完全可觀察意味著我們的代理是知道世界的全部樣子以及它自己目前在那個(gè)世界中的位置。從某種意義上說(shuō),我們可以說(shuō)我們的代理有上帝視角。它可以訪問(wèn)在每次移動(dòng)中找到最佳決策所需的所有知識(shí)。這里的知識(shí)指的是我們的獎(jiǎng)勵(lì)函數(shù) R(s) 和過(guò)渡模型 P(s'| s, a)。順序意味著我們當(dāng)前的情況受先前決定的影響。出于同樣的原因,所有未來(lái)的情況都會(huì)受到我們當(dāng)前決定的影響。例如,如果我們從 s = 8 開(kāi)始并決定向上移動(dòng)作為我們的第一步,那么我們到達(dá) s = 4。我們無(wú)法在下一步移動(dòng)中到達(dá) s = 10。如果我們選擇向右移動(dòng)作為我們從 s = 8 開(kāi)始的第一步,那么我們到達(dá) s = 9?,F(xiàn)在我們可以通過(guò)向右移動(dòng)到達(dá) s = 10。換句話說(shuō),我們能否在第二步中達(dá)到 s = 10 取決于我們?cè)诘谝徊街械倪x擇。馬爾可夫意味著我們的世界是沒(méi)有記憶的。這似乎與我們對(duì)順序的定義相反,但實(shí)際上它們具有完全不同的含義。順序意味著我們能否在第二步中達(dá)到 s = 10 取決于我們?cè)诘谝徊街兴龅倪x擇。這意味著無(wú)論我們?nèi)绾蔚竭_(dá)狀態(tài) s = 10,無(wú)論我們是從 s = 9 或 s = 11 或 s = 6 到達(dá)它,一旦我們處于該狀態(tài),我們總是面臨相同的情況,具有相同可能的行動(dòng)的集合 。如果我們做出決定,將會(huì)發(fā)生什么并不取決于過(guò)去發(fā)生了什么。換句話說(shuō),這只是意味著無(wú)論你在游戲中做了什么,P(s'| s, a) 在整個(gè)游戲過(guò)程中都不會(huì)改變。當(dāng)我們第 100 次達(dá)到 s = 10 時(shí),我們將面臨與第一次達(dá)到相同的動(dòng)作選擇。如果我們?cè)谶@個(gè)狀態(tài)下選擇某個(gè)動(dòng)作,結(jié)果總是遵循相同的概率分布。如果某個(gè)動(dòng)作是我們第一次到達(dá)該狀態(tài)時(shí)狀態(tài) s = 10 的最優(yōu)動(dòng)作,那么該動(dòng)作始終是該狀態(tài)的最優(yōu)動(dòng)作。網(wǎng)格世界的代碼實(shí)現(xiàn)
我們使用 csv 文件來(lái)表示我們的世界地圖,其中 0 為可通過(guò)的白色方塊,1 為綠色方塊,2 為紅色方塊,3 為黑色方塊。對(duì)于我們的示例,csv 文件如下所示:我們使用以下代碼來(lái)實(shí)現(xiàn)網(wǎng)格世界示例。每種類(lèi)型方塊的獎(jiǎng)勵(lì)由字典獎(jiǎng)勵(lì)表示。import numpy as npimport matplotlib.pyplot as pltimport matplotlib.patches as patches
class GridWorld: def __init__(self, filename, reward=None): if reward is None: reward = {0: -0.04, 1: 1.0, 2: -1.0, 3: np.NaN} file = open(filename) self.map = np.array( [list(map(float, s.strip().split(","))) for s in file.readlines()] ) self.num_rows = self.map.shape[0] self.num_cols = self.map.shape[1] self.num_states = self.num_rows * self.num_cols self.num_actions = 4 self.reward = reward self.reward_function = self.get_reward_table() self.transition_model = self.get_transition_model()
def get_state_from_pos(self, pos): return pos[0] * self.num_cols + pos[1]
def get_pos_from_state(self, state): return state // self.num_cols, state % self.num_cols
獎(jiǎng)勵(lì)函數(shù)
正如我們上面解釋的,獎(jiǎng)勵(lì)函數(shù)R(s) 僅依賴(lài)于狀態(tài) s。我們使用以下代碼為每個(gè) s 生成獎(jiǎng)勵(lì)函數(shù) R(s) 的結(jié)果。class GridWorld: def get_reward_function(self): reward_table = np.zeros(self.num_states) for r in range(self.num_rows): for c in range(self.num_cols): s = self.get_state_from_pos((r, c)) reward_table[s] = self.reward[self.map[r, c]] return reward_table
轉(zhuǎn)換模型
讓我們回顧一下我們的游戲規(guī)則。如果我們撞到一堵墻,我們會(huì)被彈回并留在原處。如果我們想向上或向下移動(dòng),實(shí)際上向上或向下移動(dòng)的概率為 0.8,向左移動(dòng)的概率為 0.1,向右移動(dòng)的概率為 0.1。同樣,如果我們想向左或向右移動(dòng),實(shí)際上向左或向右移動(dòng)的概率為 0.8,向上的概率為 0.1,向下的概率為 0.1。class GridWorld: def get_transition_model(self, random_rate=0.2): transition_model = np.zeros((self.num_states, self.num_actions, self.num_states)) for r in range(self.num_rows): for c in range(self.num_cols): s = self.get_state_from_pos((r, c)) neighbor_s = np.zeros(self.num_actions) for a in range(self.num_actions): new_r, new_c = r, c if a == 0: new_r = max(r - 1, 0) elif a == 1: new_c = min(c + 1, self.num_cols - 1) elif a == 2: new_r = min(r + 1, self.num_rows - 1) elif a == 3: new_c = max(c - 1, 0) if self.map[new_r, new_c] == 3: new_r, new_c = r, c s_prime = self.get_state_from_pos((new_r, new_c)) neighbor_s[a] = s_prime for a in range(self.num_actions): transition_model[s, a, int(neighbor_s[a])] += 1 - random_rate transition_model[s, a, int(neighbor_s[(a + 1) % self.num_actions])] += random_rate / 2.0 transition_model[s, a, int(neighbor_s[(a - 1) % self.num_actions])] += random_rate / 2.0 return transition_model
因?yàn)楸容^小,所以可以直接可視化出來(lái):讓我們檢查一下我們的模型是否有意義。例如,如果我們看 s = 8,當(dāng)動(dòng)作向下時(shí),我們有 0.8 的概率向下然后撞墻并彈回 s' = 8,0.1 的概率向左走然后撞墻并返回 s' = 8,向右走并到達(dá) s' = 9 的概率為 0.1。因此,s' = 8 對(duì)應(yīng)于 p = 0.8 + 0.1 = 0.9,而 s' = 9 對(duì)應(yīng)于 p = 0.1。
策略
策略是指在每個(gè)狀態(tài)下要采取什么行動(dòng)的指令。它通常表示為 π,它是 s 的函數(shù)。例如,如果 s = 2 且 π(s) = π(2) = RIGHT,那么每當(dāng)代理處于狀態(tài) s = 2 時(shí)都會(huì)執(zhí)行 RIGHT 的動(dòng)作。它是否真的可以走到右邊的方塊是另一個(gè)故事,這取決于轉(zhuǎn)換模型中的概率。關(guān)鍵是,不管結(jié)果如何,只要策略返回應(yīng)該走到哪里,代理總是認(rèn)為策略是正確的并且執(zhí)行。我們查看策略的出發(fā)點(diǎn)是簡(jiǎn)單地生成一個(gè)隨機(jī)策略并將其可視化。class GridWorld:def generate_random_policy(self): return np.random.randint(self.num_actions, size=self.num_states)
假設(shè)這個(gè)隨機(jī)過(guò)程生成了以下策略。我們可以明確地寫(xiě)出這個(gè)策略:π(0) = RIGHT, π(1) = RIGHT, π(2) = LEFT, … π(11) = UP。
乍一看,這種隨機(jī)生成的策略似乎不起作用。例如,我們從s = 8開(kāi)始,政策要求向右進(jìn)入了s = 9,然后政策說(shuō)向下。然而,s = 9的底部是一堵墻。我們只是撞到那堵墻,然后反彈回s = 9。似乎我們?cè)趕 = 9處卡住了。我們不會(huì)永遠(yuǎn)被困在 s = 9 的原因是我們處于一個(gè)隨機(jī)的世界。即使策略告訴我們向下并且我們遵循該策略,我們最終在 s = 8 中的概率仍然為 0.1,而在 s = 10 中的概率為 0.1。策略的執(zhí)行
現(xiàn)在我們至少有一個(gè)策略,盡管它可能看起來(lái)不是很好。讓我們看看如果我們執(zhí)行它會(huì)發(fā)生什么。class GridWorld:def execute_policy(self, policy, start_pos=(2, 0)): s = self.get_state_from_pos(start_pos) total_reward = 0 state_history = [s] while True: temp = self.transition_model[s, policy[s]] s_prime = np.random.choice(self.num_states, p=temp) state_history.append(s_prime) r = self.reward_function[s_prime] total_reward += r s = s_prime if r == 1 or r == -1: break return total_reward
如果我們當(dāng)前處于狀態(tài) s,則我們的策略 a = π(s)。由于我們的世界是隨機(jī)的,我們使用 numpy.random.choice 根據(jù) P(s'| s, π(s)) 給出的概率分布來(lái)選擇 s'。因?yàn)檫@個(gè)過(guò)程是隨機(jī)的,不同的運(yùn)行可能會(huì)有不同的結(jié)果。讓我們嘗試一下。這個(gè)特定運(yùn)行的狀態(tài)歷史是 [8, 9, 9, 9, 9, 10, 10, 6, 10, 11, 7]。我們從 8 開(kāi)始,以 0.8 的概率進(jìn)入 9;然后我們嘗試下降 3 次,然后彈回 9;然后以 0.1 的概率,我們移動(dòng)到 10,然后是 11,最后不幸的是 7。沿著這條路徑我們使用 10 移動(dòng)。我們收到的總獎(jiǎng)勵(lì)是 -0.04 *10 加 -1 等于 -1.4 。
這只是一次運(yùn)行,我們可能在這一次運(yùn)行中不走運(yùn)。讓我們使用蒙特卡羅方法來(lái)評(píng)估該策略的好壞。對(duì)于這個(gè)例子,讓我們重復(fù)執(zhí)行 10,000 次并記錄我們?cè)诿看芜\(yùn)行中獲得的總獎(jiǎng)勵(lì)。在這 10,000 次重復(fù)運(yùn)行中,我們得到的最高總獎(jiǎng)勵(lì)為 -1.16,最低為 -8.5 左右。平均 -1.7。顯然這不是很好。讓我們看看一些其他策略。
更多策略
這是我們的隨機(jī)策略 #2 的結(jié)果。最高的是 0.8,這實(shí)際上是我們所能得到的。平均值為 -1.2,優(yōu)于之前的隨機(jī)策略 #1。但是最低的是 -55,這比隨機(jī)策略 #1 的 -8.5 差得多。
這個(gè)好像還不錯(cuò)。最高為0.8,最低為-1.64,平均為0.7??偟膩?lái)說(shuō),似乎比前兩個(gè)好很多。
如何找到最優(yōu)策略?
回顧我們的三個(gè)隨機(jī)策略,我們可以說(shuō)#3 似乎是最好的一個(gè)。還有另一個(gè)更好的嗎?如果是這樣,我們?nèi)绾握业剿?/span>顯然,我們有有限數(shù)量的可能策略。在我們的示例中,有 9 個(gè)狀態(tài)需要指定的操作并且每個(gè)狀態(tài)有 4 個(gè)可能的操作。,總共有 4? 項(xiàng)政策。如果我們重復(fù)執(zhí)行多次,這些策略中的每一個(gè)都有一定的預(yù)期總回報(bào)。因此,其中一個(gè)(或多個(gè),如果有聯(lián)系)將比其他人具有更高的預(yù)期總回報(bào)。因此,這種策略是最佳策略 π*。要找到最佳策略,一種天真的方法是嘗試所有 4? 策略并找到最佳策略。顯然,這根本不實(shí)用。在實(shí)踐中,我們有兩種方法:策略迭代和值迭代。我們將在以后的文張中討論這兩種方法。敬請(qǐng)關(guān)注!https://github.com/clumsyhandyman/mad-from-scratch