強化學習算法DeepCube,機器自行解決複雜魔方問題

譯者:AI研習社(季一帆

雙語原文鏈接:https://www.yanxishe.com/TextTranslation/2719


前瞻

我花了近一年的時間寫《動手深度強化學習》一書,距離該書出版已經過去半年了,在這段休整時間,我發現自己對強化學習的熱情已經無法退卻。無論是研究不同的RL方法,或是復現論文代碼,對我而言是極大的樂趣。幸運的是,RL在各個領域均在迅速發展,很多有趣的主題值得探討。

引言

多數人對深度強化學習的認識主要集中在應用DRL進行遊戲,這並不意外,因爲Deep Mind在2015年首次應用DRL進行Atari系列遊戲,並大獲成功。

事實證明,Atari系列套件與RL的結合簡直是天作之合,即使是現在,許多研究論文仍使用該套件來驗證自己的方法。隨着RL的發展,經典的53種Atari遊戲的挑戰性越來越小(在撰寫本文時,RL在一半以上的遊戲表現超過人類),所以,現在的一些研究轉向更復雜的遊戲,例如StarCraft和Dota2。

由於上述原因,會給人一種錯覺,即“ RL是用來玩遊戲的”,事實顯然不是這樣。在我2018年6月出版的書中,我不僅介紹了RL在Atari遊戲的應用,也介紹了其他領域的不同示例,包括股票交易(第8章),聊天機器人和NLP(第12章),自動駕駛(第13章),持續控制(第14-16章) )和棋盤遊戲(第18章)。

實際上,基於MDP的RL可以用於各種不同的領域,計算機遊戲只是關於複雜決策的一個簡易且關注度高的領域。

在本文中,我將詳細介紹將RL應用於組合優化領域的最新研究工作。本文對UCI(加利福尼亞大學歐文分校)的研究人員發表的論文“Solving the Rubik’s Cube Without Human Knowledge”進行解讀。除了論文解讀之外,我還使用PyTorch復現了論文,通過訓練模型和流程解讀實驗,並對論文方法進行改進。

下文我將結合代碼對論文的方法進行介紹,以加深對相關概念的理解。如果你只對理論方法感興趣,可以跳過代碼部分。

OK,現在開始吧!

Rubik魔方和組合優化問題

我估計每個人都知道魔方是什麼,所以我就不做過多魔方介紹了,而是將這部分的重點放在它與數學和計算機科學的聯繫。如非特殊說明,本文中的“立方體”是指3x3經典魔方。除了3x3經典魔方,還有其他一些變體魔方,但3x3經典魔方至今仍是最受歡迎的。

雖然看起來Rubik的3x3模型似乎非常簡單,但考慮到各種可能的旋轉轉換,這其實非常棘手。據計算,3x3經典魔方旋轉狀態總共有4.33 × 10¹⁹種不同狀態。如果考慮一些魔方拼接出錯的情況,即模仿無法通過旋轉復原,只有拆解重新進行合理的拼接,那麼總狀態增加約12倍(≈5.19×10²⁰)。

所有狀態都可以通過各種旋轉組合得到。例如,在某種狀態下順時針旋轉魔方左側,就會達到一種新的狀態,從該狀態逆時針旋轉同一側就會回到原始狀態。另外,如果連續三次旋轉魔方左側,則回到原始狀態的最短路徑是再將魔方左側順時針旋轉一次,而不是逆時針旋轉三次(雖然這樣也可以,但卻不是最佳的) 。

由於3x3魔方有6個面,並每個面可以沿兩個方向旋轉,因此總共有12種旋轉方式。當然,直接旋轉半圈(在同一方向上連續兩次旋轉)也是可以的,但爲簡單起見,我們將其視爲兩次旋轉。

數學中,有一些領域專門研究這樣的對象,最典型的便是抽象代數。抽象代數是數學研究的一個重要方向,也是現代計算機理論基礎之一,主要研究抽象對象集及其代數操作。根據抽象代數,Rubik魔方是一個非常複雜的‘’,有許多有趣的屬性。

但是魔方不只是簡單的狀態和變換,它還是不確定的,其主要目標是找到一個可以復原魔方的旋轉序列。這樣的問題可以通過組合優化進行研究,組合優化也是應用數學和理論計算機科學的一個典型子領域。該領域包含許多有價值的典型問題,例如:

  • 旅行商問題:在圖中找到最短的路徑;

  • 蛋白質摺疊模擬:尋找蛋白質的3D結構;

  • 資源分配:通過在消費者之間分配固定的資源,以獲得最佳目標。

還有其他一些類似的問題。這些問題的共同之處在於狀態空間特別大,從而導致通過遍歷所有可能組合以找到最佳解決方案是不可行的。Rubik魔方也屬於這類問題,該問題狀態空間爲4.33×10¹⁹,想要通過蠻力求解幾乎不可能。

最優化與‘上帝之數’

使組合優化問題變得棘手的原因是,儘管我們非常清楚該怎樣達到問題的目標狀態,但實際上我們並沒有很好的解決方案。魔方問題尤其如此:在發明魔方之後,就確定了通過12種旋轉可以達到目標狀態,但Ernő Rubik花了大約一個月的時間才找到一種復原方法。如今,有了許多不同的魔方復原方法,包括入門方法、Jessica Fridrich方法和許多其他方法。

所有這些方法差異巨大。例如,入門方法需要記住5-7種旋轉序列旋轉大約100次才能還原魔方。與之形成對比的是,當前三階魔方還原的世界紀錄是4.22秒,這需要更少的步驟,但也要求挑戰者需要記憶和訓練大量的旋轉序列。Jessica Fridrich方法平均約需55個動作,但需要熟悉大約120個動作序列。

但是,最大的問題是:給定任意狀態的三階魔方,其還原最短動作序列是什麼?十分遺憾,儘管三階魔方已經有54年的歷史了,這個問題依然沒有答案。只有在2010年,Google的研究小組證明,解決任何魔方狀態所需的最小移動量爲20,該數字也稱爲‘上帝之數’。當然,這只是一個平均數字,最佳解決方案可能要短一些,也就是說,復原很多魔方平均需要20步移動,但某個狀態可能不需要任何移動(已復原狀態)。

但是,上述研究僅證明了最少平均移動量,卻沒有找到實際的解決方案。如何找到任何給定狀態的最優解仍然是一個懸而未決的問題。

魔方復原的方法

該論文之前,魔方復原問題主要有兩個研究方向:

  1. 使用羣論方法,顯着減小要搜索的狀態空間。這種方法種最典型的包括Kociemba算法

  2. 使用蠻力搜索以及人工定義的啓發式搜索,使搜索指向最有可能的方向。典型的如Korth算法,該算法使用A *搜索和大型模式數據庫避免選擇錯誤的方向。

本文介紹了第三種方法:通過在海量不同狀態的魔方數據集上訓練神經網絡,獲得求解狀態方向的策略。該訓練不需要提供任何先驗知識,僅需要魔方數據集(不是物理魔方,而是計算機模型)。這是其與上述兩種方法的最大不同:前兩種方法需要大量的領域知識,並以計算機編碼進行定義。

後續章節是新的論文方法的詳細介紹。

數據表示

我們從數據表示開始介紹。在三階魔方問題中,我們首先對動作和狀態以某種方式進行編碼。

動作

此處的動作是指魔方在任何狀態下可能的旋轉,前文已經說過,我們總共只有12個動作。對於3階魔方,共有左,右,上,下,前和後六個側面可以旋轉。而對每一面,有兩種不同的操作,即該側的順時針和逆時針旋轉(90°或–90°)。一個很小但非常重要的細節是,當需要旋轉的面朝向你時,你能方便的進行操作。例如,你可以哦容易的旋轉正面,但對於背面而言,總是有些不太習慣。

根據上述說明,動作名稱可以根部不同側面的首字母做出以下定義。如右側的順時針旋轉命名爲R;至於逆時針的動作,可能會使用不同的符號,包括R'/r/r̃。第一種和最後一種表示法對於計算機代碼而言不太友好,因此我使用了小寫字母來表示動作的逆時針旋轉。這樣,右側面的兩個動作是R和r,左側面的兩個動作爲L和l,依此類推。

在我的代碼中,動作空間是通過python枚舉實現的,其中每個動作映射爲唯一的整數。

狀態

狀態是指三階魔方當前的排列組合方式,正如前文介紹的,該狀態空間極其龐大(4.33×10¹⁹個不同狀態)。但除了要面對海量的狀態,我們在選擇特定的狀態表示形式時,還要考慮到以下這些要求:

  • 避免冗餘:在極端情況下,我們可以通過記錄每側每個貼紙的顏色來表示魔方的狀態。但是,如果你計算一下這些組合的數量,會發現它等於6⁶⁸=6⁴⁸≈2.25×10³⁷,遠遠大於三階魔方的狀態空間大小,這意味着這種表示形式是高度冗餘的,例如,魔方兩側中心對稱的情況。至於爲什麼得到6⁶⁸,很簡單:三階魔方有6個面,每個面除了中心塊外有8個小立方體,所以總共有48個貼面,每個貼面可用6種顏色之一上色。

  • 內存效率:在後續的訓練和模型應用過程中,我們需要將大量魔方集的不同狀態保存在內存中,這可能會影響流程效率。因此,我們希望表示形式儘可能緊湊。

  • 轉換性能:另一方面,我們需要對某一狀態進行所有可能的旋轉操作,並且要求這些操作快速完成。如果在內存中的狀態表示非常緊湊(例如使用位編碼),這會導致魔方側面的每一次旋轉需要進行冗長的解壓縮過程,嚴重影響訓練速度。

  • 適宜的神經網絡:就像其他機器學習、深度學習實例中那樣,並非每個數據表示都符合神經網絡的輸入格式。在NLP中通常使用字符或單詞嵌入,在CV中將圖像從jpeg解碼爲原始像素,Random Forests則需要對數據進行大量特徵設計等。

在本文中,使用獨熱編碼將三階魔方的每個狀態表示爲20×24張量。接下來以下圖爲例,對這種表示方式進行說明。

將魔方中需要關注的面標爲白色

上圖中,我們用白色標記了我們需要關注的魔方模塊,其餘部分(藍色)是冗餘的,不需過多關注。我們都知道,3x3魔方由三種類型的模塊組成:8個三色的角塊,12個兩色的側邊塊和6個單色的中心塊。

雖然不太明顯,但實際上根本不需要過多關注中心塊,因爲它們不能更改其相對位置,只能整體旋轉。因此,對於中心塊,我們只需就其位置達成一致就可以。例如,在我的實現中,白色面總是在頂部,前面是紅色,左邊是綠色,依此類推。這使得數據集狀態的部分固定,意味着將魔方上所有可能的旋轉被視爲同一狀態。

由於無需關注中心塊,所以在上圖中所有中心塊都是藍色。那其餘藍色是怎麼回事呢?這是因爲每種特殊的立方模塊(角塊或側變塊)的顏色組合都是固定的。例如,根據上述對魔方前後左右各方向的定義(頂部爲白色,紅色爲正面等等),左上角塊一定是綠色、白色和紅色,其他立體塊不會有這三種顏色的組合。 側邊塊也是如此。

因此,要找到某個特定模塊的位置,我們只需要知道其某個面的位置即可。一般來說,你可以在側邊塊或角塊選擇一個面進行跟蹤關注,但是一旦選定,就要堅持下去。如上圖所示,我們選擇在頂部跟蹤八個立方塊貼面,從底部跟蹤八個貼面,以及四個側邊塊貼面,兩個在正面,兩個在背面。這樣,我們需要跟蹤關注的總計有20個貼面。

那麼,張量維度中的“ 24”是從哪裏來的?我們總共要跟蹤20種不同的貼面,但是由於魔方旋轉,它們可能出現在不同的位置,至於具體位置,這取決於要跟蹤的立體塊的類型。以角塊開始說明,我們總共有8個角塊,旋轉魔方可以按任何順序對它們進行重新排列。因此,任何一個角塊都可能出現在8個角中的任何一個位置。此外,每個角塊也可以旋轉,例如,這會使“綠色、白色、紅色”對應的角塊有以下三種可能的方向:

  • 白色在頂部,綠色在左面,紅色在前面;

  • 綠色在頂部,紅色在左面,白色在前面;

  • 紅色在頂部,白色在左面,綠色在前面;

因此,爲精確表示角塊的位置和方向,我們得到8×3=24種不同的組合。

至於12個側面塊,由於它們只有兩個貼面,因此只能有兩個方向。也得到24種組合,只不過是通過12×2=24計算得到的。最後,我們要跟蹤20個立方塊,8個角塊和12個側邊塊,每個立方塊有24個可能的位置。

獨熱編碼是指當前對象的位置爲1且其他位置爲0,該編碼可以輸入神經網絡進行處理。因此,本文中狀態的最終表示形式爲20×24的張量。

考慮到冗餘情況,這種表示方式非常接近總狀態空間,其可能的組合數量爲24²⁰≈4.02×10²⁷。雖然它仍遠大於魔方的狀態空間,但是這種方式要比比對每個貼面的所有顏色進行編碼要好得多。冗餘得原因是魔方旋轉自身得屬性,如不可能只旋轉一個角塊或是一個側邊塊,每次旋轉總是會轉一個面。

好了,數學知識就介紹這麼多,如果你想了解更多,推薦Alexander Frey和David Singmaster撰寫的著作“Handbook of Cubic Math”。

<ahelp_6" name="help_6"><divpara-item divitem-area="" item-en=""><divitem-area item-en=""></divitem-area></divpara-item></ahelp_6">

細心的讀者可能會注意到,這樣的魔方狀態的張量表示有一個重大缺點:內存效率低下。實際上,如果將狀態表示爲20×24的浮點張量,我們浪費了4×20×24=1920字節的內存,考慮到在訓練過程中需要表示數千種狀態,這會導致數百萬字節內存的損耗。爲了克服這個問題,在本文的實現中,我使用兩種表示形式:一種是張量,用做神經網絡輸入;另一種是更緊湊的表示形式,以便更長久地存儲不同的狀態。我們將這種緊湊狀態保存爲一系列列表,根據角塊和側邊面的排列及其方向進行編碼。這種表示方式不僅具有更高的內存效率(160字節),而且使魔方的轉換也更加方便。

更多細節參見該模塊,緊湊狀態見函數namedtuple,神經網絡張量表示見函數encode_inplace。

訓練過程

現在我們已經知道了三階魔方的狀態是如何以20×24張量編碼的,下面我會介紹本文使用的神經網絡結構及其訓練方法。

神經網絡結構

下圖是神經網絡結構(取自原論文):

該神經網絡將魔方狀態的20×24張量表示作爲輸入,併產生兩個輸出:

  • 策略。由12個數字組成,表示行動的概率分佈;

  • 值。使用一個標量表示對狀態的評估,具體含義見下文。

在輸入和輸出之間,神經網絡由若干ELU激活函數的全連接層。在我的代碼實現中,網絡結構與此處並無差異,詳見此處

訓練

可以看到,網絡非常簡單:策略告訴我們對當前狀態進行何種轉換,值用於評價狀態的好壞程度。那麼,最大的問題就是:如何訓練網絡?

論文提出的訓練方法是“ Auto-Didactic Iterations”(簡稱“ ADI”),該方法也簡潔明瞭。從目標狀態(復原的魔方)開始,執行一些預定義的長度爲N的隨機變換序列(文中給出了N個狀態的序列)。對序列中的每個狀態,一次執行以下過程:

  • 將所有可能的變換(總共12個)應用於狀態s;

  • 將這12個狀態傳遞給當前的神經網絡,以輸出值。這樣就得到s的12個子狀態的值;

  • 根據vᵢ = maxₐ(v(sᵢ,a)+R(A(sᵢ,a)))計算狀態的目標值,其中A(s, a)是對s執行動作a之後的新狀態;如果s是目標狀態,則R(s)爲1,否則爲0;

  • 狀態s的目標策略使用相同的公式進行計算,不同的是我們選擇最大值,即pᵢ = argmaxₐ (v(sᵢ,a)+R(A(sᵢ,a)))。這僅意味着目標策略只有在最大值的子狀態時取值爲1,否則爲0。

具體過程見下圖。生成序列爲x₀,x₁…,以魔方xᵢ爲例進行詳細說明,對狀態xᵢ,通過上述公式確定策略和值目標。

通過該過程,我們可以生成任意數量的訓練數據。

模型應用

假設我們已經通過上述過程訓練得到模型,那麼如何使用模型來複原魔方呢?根據網絡結構,我們很容易想到這樣的方法(但不幸的是該方法並不可行):

  • 向模型提供要解決的三階魔方的當前狀態;

  • 根據策略選擇最大可能的動作(或從結果分佈中採樣);

  • 對模型執行該動作;

  • 重複上述過程,知道魔方復原。

看上去這樣是可以奏效的,但是在實踐中,這樣的方法卻行不通。主要原因是模型質量不過關。由於狀態空間巨大,加上神經網絡特性,對於所有輸入狀態,不可能經過訓練使得NN返回準確的最佳動作。也就是說,模型並沒有告訴我們明確的求解思路,只是向我們提出值得探索的方向,但這些方向可能使我們更接近解決方案,也有可能會引起誤導。因爲在訓練過程中,不可能處理所有可能狀態。要知道,即使使用GPU以每秒處理數十萬狀態的速度進行訓練,對於4.33×10¹⁹的狀態空間,也需要經過一個月的訓練時間。因此,在訓練中我們只取狀態空間的一小部分,大約爲0.0000005%,這就要求我們使用更復雜的方法。

有一種非常適用的方法,即“蒙特卡洛樹搜索”,簡稱MCTS。該方法有很多變體,但總體思路很簡單,可以與衆所周知的蠻力搜索方法(如“廣度優先搜索BFS”或“深度優先搜索DFS”)對比來進行說明。在BFS和DFS中,我們嘗試所有可能的動作,並探索通過這些動作獲得的所有狀態對狀態空間進行詳盡搜索。可以發現,這種方式是上述過程的另一個極端。

MCTS在這兩種極端之間進行折衷:我們想要執行搜索,並且存在一些值得關注的信息,但是,某些情況下信息可能是不可靠的噪聲或錯誤,有時信息也可能提供正確的方向,從而加快搜索過程。

正如上文提到的,MCTS是一類方法,不同方法在具體細節和特徵方面有所不同,本文使用的是UCT方法(Upper Confidence bound1 applied to Trees)。該方法在樹上操作,其中節點是狀態,邊是動作,將所有狀態聯繫起來。在多數情況下,整個樹是非常巨大的,因此我們不會試圖構建整個樹,只是構建其中的一小部分。首先,讓我們從一棵由單個節點組成的樹開始,也就是我們的當前狀態。

每執行一步MCTS,都要沿着樹探索某些路徑,一般可以面對以下兩種選擇:

  • 當前節點是葉節點;

  • 當前節點在樹的中間,並具有子節點。

對於葉節點,通過對狀態執行所有可能的動作對其進行“擴展”,並檢查所有結果狀態是否爲目標狀態(如果找到了魔方復原的目標狀態,則搜索完成)。然後,將葉節點狀態傳遞給模型,輸出值和策略,將其存儲備用。

如果當前節點不是葉節點,那麼我們能夠知道該節點的子節點(可到達狀態),並從網絡獲得值和策略輸出。因此,我們需要決定選擇哪條路徑(換句話說,探索哪種行動最優)。這一決定極其重要,甚至稱得上是強化學習方法的基石,即“探索-利用問題”。一方面,神經網絡的策略告訴我們該怎麼做,另一方面,對於策略出錯的情況,可以通過探索周圍的狀態來解決。但由於狀態空間巨大,不能一直探索,這就要求我們在這兩者之間保持平衡,這直接影響着搜索性能和結果。

爲解決這個問題,對於每個狀態,我們爲每個可能的動作(共12個)設置計數器,每次在搜索過程中選擇某一動作,相應計數器就會增加。在決定採取特定動作時,可以通過計數器進行判定,即某一動作的執行次數越多,將來選擇的可能性就越小。

此外,模型返回的值也用於輔助決策,即從當前狀態的值及其子節點狀態的值中選擇最大值進行跟蹤。根據這樣的模型,可以從父節點的狀態找到最可能的路徑。

總而言之,對於非葉節點狀態,通過以下公式選擇要執行的動作:

其中,N(s,a)是狀態s選擇動作a的次數,P(s,a)是模型爲狀態s返回的策略,W(s,a)是模型根據狀態s的分支a下所有子節點狀態返回的最大值。

重複此過程,直到找到解決方案或時間耗盡。爲加快此過程,MCTS通常以並行方式進行,利用多個線程同時執行多個搜索。在這種情況下,可以從A(t)中減去一些額外損失,以防止多個線程探索相同路徑。

爲使用MCTS樹得到復原方案,論文作者提出兩種方法:

  • naïve:得到目標狀態後,使用從根狀態開始的路徑作爲復原方案;

  • BFS方法:得到目標狀態後,對MCTS樹執行BFS,以找到從根到此狀態的最短路徑。

論文提到,第二種方法找到的復原方案比第一種方案更短,這並不奇怪,因爲MCTS過程的隨機性,在第一種復原方案路徑中可能引入了無用的循環。

論文結果

論文的結果令人印象深刻。在使用三個GPU並行訓練了44小時之後,網絡學會了類似甚至超過人工復原魔方的方案。最終,將本文模型DeepCube已與先前介紹的兩種求解方法進行了比較,分別是Kociemba two-staged solver 和Korf IDA*。

爲驗證本文方法的效率,論文使用640個隨機打亂的魔方對不同方法分別進行測試,並設置最大求解步驟爲1000步,最大求解時間爲1小時,實現發現DeepCube和Kociemba方法均能在限制步驟和時間內復原魔方。 具體而言,Kociemba求解速度非常快,其中值僅爲一秒鐘,但是由於依賴人工定義規則,其求解並不總是最短的。DeepCube方法花費了更多的時間,中值約爲10分鐘,但在55%的情況,該方法會比Kociemba得到更好的復原方案,即更少的步驟。從我個人的角度來看,55%雖然不足以說NN明顯更好,但至少證明該方法還不錯。下圖(摘自論文)顯示了所有求解方法的復原步數分佈。可以看到,由於復原時間較長,在1000步魔方復原測試中沒有比較Korf求解方法,但爲了將DeepCube與Korf求解方法的性能進行比較,論文進一步設計了更容易的15步魔方復原測試集。

實現細節

好的,現在我們開始介紹代碼實現。在本部分中,我將簡要介紹代碼方案及一些關鍵設計,但在此之前,我還是要先強調一些事情:

  • 我不是該項目的研究人員,因此這段代碼只是想要復現論文的方法。但不幸的是,由於論文沒有提供確切的超參數信息,因此我進行了大量猜測和試驗,但實現結果與論文的結果依然存在較大差異。

  • 同時,我試圖以通用方式實施所有操作來簡化實驗。例如,有關魔方狀態和轉換的詳細信息不做詳細展示,僅僅通過添加一個新模塊來抽象化3x3魔方問題。在我的代碼中,分別對2x2魔方和3x3魔方進行實驗,但類似這樣有固定可預測動作集的、環境完全可見的問題都可以通過這樣的方式進行解決。下一節會做詳細說明。

  • 相比代碼性能,我更關注代碼的可讀性與簡潔性,當然,對於不引入過多複雜性與成本消耗就能提高模型性能的操作,我在代碼中還是保留了它們。例如,僅通過分割魔方數據集和正向網絡傳遞,就可以將訓練過程加快5倍。但是,如果需要將大多數內容重構爲多GPU和多線程模式,我爲簡單起見就沒有這樣做。典型的就是MCTS進程,通常採用多線程代碼實現,加快模型速度,但這就需要處理進程之間的同步問題。我沒考慮那麼多,只是以串行方式進行MCTS,僅對批量搜索進行了簡單優化。

綜上,我的代碼由以下幾部分組成:

  1. 魔方環境,用於定義觀察/狀態空間、可能的動作以及網絡狀態的表示,見libcube / cubes模塊

  2. 神經網絡,包括要訓練的模型、訓練樣本的生成和循環訓練過程。見the training toollibcube / model.py模塊

  3. 魔方復原方法, 見the solver toollibcube/mcts.py

  4. 其他一些不同組件,例如超參數的配置文件和魔方數據生成文件等。

魔方環境

正如前文介紹的,組合優化可不是個小問題,而且種類繁多,即使單就魔方而言,也包含數十種變體,包括2x2x2、3x3x3和4x4x4Rubick魔方,以及Square-1,Pyraminx等。本文介紹的方法不依賴於預定義的領域知識、動作集和狀態空間大小,具有較強的適用性。具體而言,求解魔方問題基於以下假設:

  • 環境狀態必須是完全可觀察的,根據觀察結果可以區分不同狀態。在魔方問題中,我們可以觀察到魔方所有面的狀態,因此該問題符合我們的假設。但對於類似撲克牌這樣的問題,我們是看不到對手的牌的,本文方法就不再適用了。

  • 動作的數量是離散且有限的。在魔方復原問題中,我們只需執行12中動作,這符合假設。但是對操作空間是“旋轉角度α∈[-120°…+ 120°]”這樣的非離散動作的問題,就需要不同的處理方法了。

  • 環境的準確建模。換句話說,我們要能夠回答以下問題:“對狀態s採取行動a會產生什麼結果?”。如果無法解決這樣的問題,ADI和MCTS方法都會失效。這個要求對於實現模型是及其必要的。然而,對於大多數問題,並不存在這樣的模型,或者模型的輸出非常嘈雜,但在象棋或圍棋之類的遊戲中,遊戲規則即是這樣的符合要求的模型。

  • 領域確定性。即對相同狀態的相同動作會得到相同的最終狀態。不過我覺得,即使採取隨機行動也應該會起作用,但也不一定。

爲了使我們的方法可以很方便的遷移到非3x3魔方的問題,我將所有具體的環境信息都移到了一個單獨模塊,並通過抽象接口CubeEnv與其餘代碼進行聯繫(見此處)。通過這樣的方式,每個環境都有一個名稱,指定環境名稱即可使用相應的的環境類型。目前,我們定義了兩種不同的環境:經典三階魔方cube3x3和二階魔方cube2x2。

如果你要使用自己的魔方數據或其他不同的環境,只需要修改該模塊,通過接口即可在其它代碼中使用你自定義的環境。

訓練

模型訓練過程見train.pylibcube/model.py。爲簡化實驗,同時增強實驗的可重複性,在單獨的ini文件中設置訓練的所有參數,包括:

  • 要使用的環境的名稱,我們提供了cube2x2和cube3x3兩個環境;

  • 運行名稱,在TensorBoard的名稱和目錄中顯示,並用於保存模型;

  • ADI的目標值計算方法。本代碼提供兩種計算方式:一種是原論文的方法,另一種是我改進的方法。實驗表明,我的改進方法收斂更加穩定;

  • 訓練參數,包括batch、是否使用CUDA、學習率、LR衰減等。

可以在ini文件夾查看我的實驗設置。訓練過程中,TensorBoard參數被寫入runs文件夾,並將最優模型保存到saves文件。

搜索過程

訓練的結果是一個帶有網絡權重的模型文件。根據模型可以使用MCTS方法復原魔方,具體實現見solver.pylibcube/mcts.py模塊。

其中,求解器可用於不同模式:

  1. 復原一個雜亂魔方。該魔方由一系列由逗號分隔的動作索引打亂,該序列由-p選項傳遞。例如,-p 1,6,1是依次執行第二個動作、第七個動作、第二個動作來打亂魔方。動作執行是面向特定環境的,通過-e選項傳遞,在魔方環境模塊可以找到帶有索引的動作。例如,2x2魔方的動作1,6,1分別表示L,R',L變換。

  2. 從文本文件(每行代表一個魔方數據)讀取排列並進行復原。文件名通過-i選項傳遞。我在cubes_tests文件夾提供了幾個示例,此外,你還可以使用gen_cubes.py生成自己的數據集。

  3. 生成更多步驟的打亂魔方並進行復原。

  4. 執行復雜的系列打亂測試,並對其復原,然後將結果寫入csv文件。通過-o選項可以啓用此模式,這可用於評估模型的質量,但同時也需要花費更多的時間。一旦選擇該選項,就會生成測試結果圖。

在所有情況下,都需要使用-e選項來傳遞環境名稱,並使用-m選項傳遞模型文件。此外,還有其他參數可以調整MCTS、時間或搜索步長等,在此不做過多贅述。

實驗結果

一開始我已經說過,我不是論文的研究人員,因此本工作僅僅是復現論文並進行簡單實驗。但是,原論文沒有提供相關方法的詳細信息,例如超參數,在訓練過程中對魔方打亂的步數,收斂性等等。爲獲取這些信息,我已向論文作者發送了一封電子郵件,但至今未收到他們的回覆。

因此,我進行大量的實驗,但實驗結果與論文結果仍存在較大差異。首先,原始方法的收斂非常不穩定,即使降低學習率和增大batch,訓練依然不穩定,值損失呈指數增長,如下圖所示。

經過多次實驗,我認爲導致這種現象的原因是原始方法中值目標是錯誤的。

確實如此,在公式vᵢ = maxₐ(v(s, a) + R(A(s, a)))中,網絡返回的值v(s,a)總是與實際獎勵R(s)相加,即使對目標狀態也是這樣。這樣,網絡返回的實際值可以是-100、10⁶或3.1415。這樣大的差異對神經網絡極不友好,尤其是MSE值目標。

<ahelp_16" name="help_16"><divpara-item divitem-area="" item-en=""><divitem-area item-en=""></divitem-area></divpara-item></ahelp_16">

爲此,我做了以下修改,將目標狀態值設爲0:

具體而言,指定參數value_targets_method = zero_goal_value而不是默認的value_targets_method = paper,你可以在ini文件中選擇該新的目標函數。

通過這種簡單修改,訓練過程模型可以更快地收斂穩定狀態,見下圖。

二階魔方

原論文中,使用三個Titan XP GPU並行訓練了44小時,在這個過程中,模型總計看過約80億魔方狀態。根據這樣的敘述,可以得到訓練速度約等於每秒查看50000魔方狀態。我的實現在單個GTX 1080Ti上進行,其訓練速度爲15000/秒,與論文差別不大。因此,使用論文的數據,在單個GPU上訓練一次大概需要6天時間,這使得實驗和超參數調整及其困難。

爲解決這個問題,我設置了簡單的2x2魔方環境,只需一個小時的訓練時間。如果你也想繼續復現,可參見repo中的兩個ini文件:

  • cube2x2-paper-d200.ini:使用原論文中的值目標方法;

  • cube2x2-zero-goal-d200.ini:改進的0值目標計算方法。

在這兩種配置中,狀態批次均爲10k,魔方打亂步驟爲200,其他訓練參數也相同。

分別進行訓練後,生成了兩個模型(模型文件):

  • 原論文方法的損失爲0.18184;

  • 改進0值方法的損失爲0.014547。

實驗表明,模型損失越小,成功率越高,可用於復原更多打亂步驟的魔方。兩種模型的實驗結果如圖所示。

接下來對魔方復原過程中的MCTS步驟進行對比。如下圖所示,改進的0目標模型通常以更少的步驟復原魔方,也就是說,該模型學到更優的復原策略。

最後,比較不同魔方復原方法的長度。下圖繪製了naïve和BFS方案的長度。從圖中可以看出,naïve方法的長度要比BFS長約10倍,這表明調整MCTS參數可以改善模型性能。同時還可以發現,“零目標”模型的解決方案比原論文模型更長,其原因可能是前一種方法不存在更長的復原路徑。

<ahelp_17" name="help_17"><divpara-item divitem-area="" item-en=""><divitem-area item-en="">

</divitem-area></divpara-item></ahelp_17">

<ahelp_17" name="help_17"><divpara-item divitem-area="" item-en=""><divitem-area item-en=""></divitem-area></divpara-item></ahelp_17">

三階魔方

3x3魔方的模型訓練過程要複雜的多,所以在這裏僅進行簡單介紹。但即使只是簡單的實驗,也表明0值目標函數可以極大地提高訓練穩定性和模型質量。另外,三階魔方訓練一次大約需要20個小時,想要進行大量實驗需要花費很多時間和耐心。

正是由於上述原因,我的實驗結果不如論文所示結果,我得到的最佳模型僅解決12-15步的亂序魔方復原問題,對於更復雜的問題則無能爲力。如果你想獲得更好的效果,可能使用更多CPU內核+並行MCTS來提升模型性能。爲了獲得數據,我將搜索過程限制在10分鐘內,並對每個亂序干擾生成五個隨機干擾。

下圖是論文方法與改進的零目標值方法的比較。

下圖所示爲找到的最佳解決方案的長度。圖示表明兩點:第一,在10-15干擾深度範圍內,“零目標”方法求解長度大於論文的,這意味着模型雖然沒有找到生成測試數據的干擾序列,但發現了更長其他解決方法;第二,對於12-18深度範圍,原論文方法找到比干擾序列更短的解決方案,可能的原因是生成了簡併測試序列。

進一步的改進和實驗

針對上述研究,有許多其他方法可提升模型性能,改進實驗結果。比如:

  • 更詳細的輸入和更復雜的神經網絡。由於魔方問題非常複雜,僅僅通過簡單的前饋神經網絡並不能獲得最佳模型,考慮卷積網絡可能會提升模型的學習能力;

  • 訓練期間的振盪和不穩定性在RL問題中十分常見,這可能是步間相關性導致的。通常的解決方法是,在使用策略網絡學習引導值時引入目標網絡;

  • 引入臨時緩衝區可提高訓練速度;

  • 實驗表明,樣本加權(與擾亂深度成反比)有助於獲得更好的策略,該策略知道如何解決擾亂魔方問題,但這也可能使對更深狀態的學習過程變慢。爲此,可以使用自適應權重,以減少其在後續訓練階段的影響;

  • 在訓練過程中使用熵損失來正則化學習策略;

  • 2x2魔方的訓練模型沒有考慮到魔方問題中存在的不動中間塊,因此整個二階魔方都可以旋轉。由於二階魔方的狀態空間很小,所以無需考慮冗餘的相同狀態,但對於4x4魔方來說,去冗餘至關重要;

  • 多次實驗尋找更好的訓練參數和MCTS參數。

感謝你的閱讀,期待你的評論!本文的PDF文件可從此處下載。


AI研習社是AI學術青年和AI開發者技術交流的在線社區。我們與高校、學術機構和產業界合作,通過提供學習、實戰和求職服務,爲AI學術青年和開發者的交流互助和職業發展打造一站式平臺,致力成爲中國最大的科技創新人才聚集地。

如果,你也是位熱愛分享的AI愛好者。歡迎與譯站一起,學習新知,分享成長。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章