2017年9月5日 星期二

Unity說明文件範例正確性檢測 - 玩轉Unity編輯器測試工具

作者:Karl Jones 原文
發表於:2017/8/18

潤稿:Kelvin Lo

每當我遇到不熟悉的API,當下第一反應一定是去查查Unity文件,看看文件裡的範例來瞭解API的使用方式。但如果按照文件依樣畫葫蘆卻編譯失敗的話,是否可能是文件出錯了呢?

這是Unity Hackweek(註一)的一個專案,利用Unity 5.3以上的編輯器測試工具,來自動檢驗所有Unity腳本的範例程式是否編譯成功。

Unity腳本文件共有15000頁左右,其中並非所有文件都包含範例(這需要另外解決),但也已經不少了。手動檢查每個範例加上測試,在為期一周的Hackweek中很難辦到,也無法解決未來的API更新衍伸的文件更新問題。

然而去年發佈的Unity 5.3中包含一個新功能:Editor Test Runner,它是能在Unity中執行的單元測試框架(unit test framework)。這個功能發佈後就一直用於Unity內部測試,幫助我們追蹤問題。Unity所有腳本文件都保存為XML檔,可以在Unity內部專案中編輯。



專案已經包含解析XML檔的程式,所以只需在專案中加上編輯器測試即可使用這些功能。在編輯器測試框架中會用到TestCaseSource屬性,讓測試多次在不同的來源資料上執行。在本例中,來源資料就是程式範例文件:



這個方法會顯示所有執行在Test Runner上的測試。每個測試都能獨立執行,或通過Run ALL選項來同時執行。


本範例使用CodeDomProvider 編譯,這樣可以傳遞多個表示腳本的字串,並編譯和返回相關的錯誤及警告資訊。
首次測試反覆運算的縮減版(已刪除XML解析):




運作很正常! 編譯腳本的方式還需做些調整,因為有些腳本是組合在一起的方式形成一個範例。分別編譯所有範例以檢測是否有這種情況,如果出現錯誤再將其合併編譯,看看是否成功。

還有一些簡單範例就是一行程式,沒有封裝在函數內。可以在測試中進行封裝來處理這種問題,要遵循的規則就是這些例子必須能獨立執行(即開發者將它複製貼上到一個新的檔案中也可以被編譯和執行),否則就將這些範例視為測試失敗。

這個測試方法現在離正式作為文檔驗證工具還有一段距離。我還需要解決一個小問題:這個測試流程執行需花費30分鐘。由於我們每天需要執行約7000個版本,僅僅作為一個版本驗證測試來說這個執行時間太長了。

目前這個測試方法是依序執行的,一次一個腳本。由於測試彼此獨立,且無需呼叫Unity API,因為只測試編譯是否成功,所以完全可以並行執行這些測試。下面引入用於並存執行任務的.NET API-執行緒池。將測試作為單個任務放入執行緒池中,當執行緒可用時立即執行。這需要從單個函數執行,即不能用單獨的NUnit測試用範例來測試文件的單一範例。儘管不能單獨測試,但我們大大提高了整體執行的速度。



這將測試時間從30分鐘縮短至2分鐘,作為版本驗證來說已滿足需求。由於無法測試單個範例,所以在腳本文件編輯器中加入按鈕,以便文件編寫人員日後更新。執行測試時出錯腳本會顯示為紅色,並在下方顯示錯誤資訊。

首次執行測試時有326個錯誤,將這些加入白名單以便日後更新。畫面現在只剩32個,大多錯誤都是由於無法存取特定的程式集導致。整合該測試並未引入新的問題,所以可以確定如果棄用部分API導致測試失敗,則需要更新文件來使用新的API。

結語

本文只是Editor Test Runner工具一個非常有趣的使用案例,當然還有待改進,例如只能抓取C#範例,無法處理.js的編譯。但在不久的將來,這也將不再是問題。(註二)

感謝各位,完整程式碼可以從原文最後面取得。

<註一> Unity Hackweek是一個Unity內部活動,每年研發人員會集合並討論Unity有哪些需要改進的地方,並在為期一周的時間,動手做個初始原型,有點像是企業內部的黑客松。
<註二> Unity已經對外發佈未來即將不支援 Unity Java Script。會專心維護C#。

2017年9月4日 星期一

Unity遊戲開發中的AI - 基於Q-Learning的強化學習

作者:Arthur Juliani 原文
潤稿:Kelvin Lo


歡迎來到Unity AI系列文章第二篇,我們上次已經為大家介紹了遊戲開發中的AI - 入門,今天這篇文章將延續上次的內容繼續探討如何將它擴展到一個
完整能強化學習問題的吃角子老虎機。在這個過程裡,我們會展示如何利用一個Agent透過Q函數學習,來預估長期在特定條件下採取特定行為的值。本例僅使用一個簡單的網格空間(gridworld)以及一個Q-Representation列表。這原理可以應用於任何遊戲上。

Q-Learning演算法

情境老虎機回顧
強化學習(Reinforcement Learning)的目的是在特定環境下訓練一個Agent代理,通過學習來實現特定環境的最大化預期利益。在"遊戲開發中的AI -入門"一文中,環境是相對靜態的,環境狀態也很單純,就是代理躲在3個箱子其中之一,而行為就是選擇打開哪個寶箱。我們的演算法為每一對狀態行為學習Q函數,Q函數則對應在該狀態下隨著時間前進採取某種行為而獲得的預期利益。這樣的問題通常被稱為“情境老虎機”(Contextual Bandit)。

強化學習問題

要將前面的情境老虎機問題轉換為強化學習問題,還缺少兩個關鍵因素:稀有獎勵與狀態轉換。稀有獎勵是指代理並非每次採取行為都可以獲得獎勵。有時獎勵會“延遲”,因為有些行為可能不是必須的,也可能要在一系列非必須行為之後才能獲得獎勵。更具體的展示是,代理可能跟隨正確路徑,但只有到達終點才能獲得獎勵,而非走過的每一步都有獎。儘管中途沒有獎勵,但走過的每一步對到達終點來說都至關重要。我們需要一種方式來執行“信用分配”,即讓代理知道早期的行為是有價值的,儘管只是間接價值。

第二個缺失的因素是強化學習中狀態之間的轉換。有了狀態轉換之後,我們的行為不再是只根據獎勵函數R(s, a) ⇨ r來獲得獎勵,還會根據狀態轉換函數P(s, a) ⇨ s’來產生新的狀態。具體範例是,沿著路徑走過的每一步都會使代理到達路徑的新位置,也就是新的狀態。因此我們希望代理不僅要學習採取行動優化目前可能的獎勵,還要採取行動向可能提供更多獎勵的狀態移動。

貝爾曼更新

雖然新增的兩個複雜元素初看起來並不相關,但確是直接相關聯的。兩個元素都隱含了影響代理的未來最終狀態及其可能獲得的獎勵。通過這種質樸的理解,我們可以利用這種關係來學習在這些情形下應採取的最優行為。即在一個“真正”最優的Q-函數(只存在於理論)中,目當狀態的估值和行為可以被分解為直接獎勵r加上在下一狀態中代理採取行動的最大預期獎勵乘以一個折扣係數:

 

 這就是貝爾曼方程(Bellman Equation)也被稱作動態規劃方程式(Dynamic Programming Equation),由理查·貝爾曼(Richard Bellman)發現,可以按如下形式表述:




此處的𝛄 (gamma)是一個折扣因數,決定了代理對未來可能獲得獎勵的關注程度。如果值為1.0,則代理對未來所有的獎勵一視同仁,在永無止境的訓練中,估值可能會增加到無窮大。為此,𝛄應在0到1之間取值,典型取值範圍是0.7-0.99。

貝爾曼方程有效的原因在於:它提供了一種自動更新Q-函數的方法。Q*(s, a)是一個優化Q-函數。但即使當前的下一狀態的次優Q-value估值也有助於讓當前狀態的估值更加精確。由於每一步都主要依賴於真正的獎勵,所以可以相信Q-value估值自身會緩慢改進,並不斷趨近真實值。我們可以使用貝爾曼方程進行新的Q-Learning更新:



這個方程和之前情境老虎機中使用的更新演算法類似,不同點是Q-target現在包含下一步中未來期望獎勵的折扣值。


探索

為了讓代理更充分地探索狀態空間,我們使用了一種名為epsilon-greedy的探索更新形式。使用時將epsilon-greedy中ϵ初值設置為1.0,每次代理採取行動將該值減少一部分,而當代理選擇行動時,可選最貪婪的行動argmax(Q(s, a)),或者採用概率為ϵ的隨機行動(在搜索初期增加隨機性,提高搜索範圍空間,隨著代理積累經驗,逐步降低隨機影響)。直覺就是訓練開始時,代理的Q-value 估值與真實值相差較大,但通過對整個世界的學習後,ϵ值減少,Q-函數就慢慢與真實環境的Q-函數更一致,而使用Q函數採取行動的精確性也不斷提高。

Unity GridWorld


藍色的方塊是代理,紅色是障礙物,綠色是目標位置,綠色和紅色的球體代表GridWorld中每種狀態的估值。


為了演示Q-Learning代理,我們使用Unity建立了一個簡單的GridWorld環境。其中包含:
  1. 一個在世界中隨機位置出現的代理;
  2. 一個隨機的目標位置,我們希望代理通過學習向目標移動;
  3. 隨機放置的障礙物,我們希望代理學會躲避;

環境狀態(s)是一個整數,代表網格位置,四個行為(a)包括上、下、左、右,獎勵(r)規則為:移動到帶有目標的狀態時+1,移動到帶有障礙物的狀態時-1,為了鼓勵代理快速移動到目標,每次移動時-0.05。每個階段會在移動100次後,或者在代理到達既非目標又非障礙物的狀態時(碰到障礙時)結束。代理的Q-value存儲在表中,行代表狀態,列代表可採取的行為。

你可以點擊這裡直接從網頁看結果,也可以點擊這裡下載這個Unity專案,然後自己修改並應用於自己的遊戲。隨著代理不斷探索環境,不同顏色的球將會出現在網格世界的每個狀態中,這對應當前狀態下代理的平均Q-value估值,一旦代理完成優化策略的學習,這些球就會形成從開始到目標位置的直接值漸變。

後續計畫

此處的代理和環境代表了Q-Learning問題的經典表格,如果不符合你的需求也不用太擔心,Q-Learning演算法從90年代被提出至今,它已經歷了一系列重大的改進,Q學習可被應用於更加多變的動態場景中。Deepmind的Deep Q網路的一個主要示例,就是用於學習直接從圖元中進行幾十種不同的ATARI遊戲,像這裡僅用一個查閱資料表根本不可能實現的壯舉。為了實現這個目標,他們用到了一個由Deep Neural Network(DNN)網路控制的代理。通過神經網路,它可以學習將廣義Q-函數應用于完全不可見的狀態,例如顯示器上少見的圖元組合。

在後面的幾周中,我們會公佈一系列演算法的介面和展示專案,可以在Unity遊戲和模擬應用中訓練類似的深度強化學習代理。您可以查看影片,先簡要瞭解這些工具的功能。初次發佈版本將有些限制,主要用於研究、工業以及遊戲的QA測試。我們非常樂於看到在Unity中利用現代深度學習方法來學習遊戲行為,希望當此項技術成熟時,可以引爆機器學習技術在遊戲開發中的潛力,例如控制遊戲中複雜的NPC行為與遊戲動態等等。我們尚處於探索深度學習技術應用于遊戲開發的初期階段,也希望大家陪伴我們一起踏入後續的旅程。


2017年9月1日 星期五

遊戲開發中的AI - 入門

作者:Arthur Juliani 原文
潤稿:Kelvin Lo


Unity正朝著AI的方向潛心探索著。本文是Unity發佈的首篇AI相關文章,為大家介紹AI的一些概念及術語,詳細介紹機器學習相關理論與方法,並講解在使用Unity開發遊戲的過程中如何應用AI。未來我們還將為大家分享更多AI的內容。在過去幾年,Machine Learning(機器學習,ML)的進步,在檢查物件、翻譯、辨識語言,甚至玩遊戲等等都有突破性發展。值得一提的是,ML和玩遊戲之間的關係在Unity上很像是我們人類的心態。我們相信繼續鑽研能在製作遊戲這塊有突破性的發展,從改變貼圖和3D建模、動畫、人物動作或場景照明的製作方式,到自動產生NPC(非玩家角色)的程式碼。


這篇文章適合的讀者

我們想和Unity的開發者們一起探討關於AI和ML在遊戲開發過程中能發揮的力量,同時也想討論AI用在美術製程的可能性。藉由這次機會剛好可以對ML研究者展現以Unity作為AI研究/開發平台的潛力。像是機器人和自動駕駛等等的模擬平台,讓有興趣的人或研究學生透入研究Unity和ML。


何謂ML(機器學習)

首先來介紹下Machine Learning(機器學習,下文簡稱ML)和遊戲Artificial Intelligence(人工智慧,下文簡稱AI)間的關係。現在大部分遊戲裡的AI都是手動硬寫的,由大量判斷式組成,有時會包含多達數千條規則。而且必須由人工維護和測試。而ML所依賴的演算法可以自動從原始資料尋找規律,無需專業人員預先定義資料的解讀邏輯。

以圖片內容分類這個電腦視覺問題為例。直到幾年前,科學家們仍採用人工編寫篩檢程式,辨識圖像上的特徵,用來分辨某個圖像中包含的是貓還是狗。而ML,特別是最新的深度學習方法,只需圖像和類型標籤,就可以自動學習有用特徵。我們相信這種自動化學習不僅可以拓展Unity平台的應用範圍,例如用於ML場景模擬,還可以幫助所有開發者簡化和加速遊戲的開發過程。

這種自動化學習尤其可以應用在非玩家角色(NPC)的行為。我們可以使用Reinforcement Learning(增強學習,簡稱RL ) 來訓練NPC,預估某一環境中施行特定行為的價值。一旦訓練完成,NPC即可以最佳行為模式做出反應,不用程式對它們的行為進行篩選。後面的文章我們會介紹RL的應用,所有的範例專案也都會公開放在Github上面,你也可以透過WebGL看看整個專案展示。

用RL演算法學習的吃角子老虎

RL背後的一個核心概念是價值估計,並依照此進行對應動作。在繼續深入之前,最好先瞭解一些術語。

在RL裡執行動作的個體稱為agent(代理),它使用policy(策略)進行動作決策。一個代理通常嵌於一個environment(環境)中,並在任意給定的時刻都處於某個特定的state(狀態)。從那個狀態,它可以進行一系列actions(動作)。某個給定狀態的value(值)指的是處於該狀態的最終回報價值。在某個狀態執行一個動作可以讓代理進入另一個新的狀態,獲得一個reward(回報),或者同時擁有兩者。所有RL代理都在盡可能最大化累計回報。



這個RL 範例專案有個問題,技術上稱為multi-armed bandit(或稱為N-armed bandit problem)。這名字源自於為了平衡多台老虎機的回報產生最優化的結果而生,也稱作"Single-arm bandits",設計用來一點一滴的從玩家身上回收錢。在這樣的設定下,環境只包含一種狀態,代理能採取n個動作中的一個。每個動作都會立即為代理提供一個回報。而代理的目地是找出能提供最多回報的動作。

為了更好理解,可以想成一個迷宮遊戲。代理進入一個房間,發現牆邊放著一排寶箱。每個寶箱都有一定的機率開到一顆鑽石(回報+1)或一個敵人惡魂(回報-1)。

代理的目標就是學習思考哪個寶箱最有可能出鑽石。(比如判斷結果為從右屬過來第三個箱子)。要找出回報最高的寶箱最簡單的方法就是逐一嘗試。在代理獲得足夠的資訊並採取最佳行動之前,大部分RL的工作就是簡單的不斷嘗試錯誤。上面這個例子用RL的術語來描述就是,"嘗試"對應的是採取一系列動作(多次打開每個寶箱),學習對應的是更新每個動作的估計值。一旦有了足夠的樣本,就可以讓代理總是選擇那個具有最高估計值的寶箱。

三個寶箱,每個都有機率開出鑽石或敵人



這些估計值可以透過一個反覆運算過程獲得。這個過程從最初的一系列估計V(a)開始,並根據每次動作的結果進行調整。運算式如下:


α對應我們的學習率,V(a)是給定動作的價值估計,r是採取動作後馬上可以獲得的回報。


上面的算式很直覺,它表示出我們將當下的價值估計向獲得回報的方向做了一些微調。這樣就能確保變化的估計值能更好的反應環境中的真實動態。如此一來,還能確保估計不會變得過大,如果我們只計算正向結果就可能會發生這種情況。要完成相應程式,我們可以使用一組值估計向量,並透過代理動作對應的索引來引用它們。



三個寶箱上方顯示的是代理的估計值(綠色球體),以及真實的概率值(中間的半透明球體)。在這個例子中,三個寶箱的潛在正向回報概率分別是 10%(左),20%(中),80%(右)。隨著訓練進行,代理的估計值會變得越來越精確。



情境吃角子老虎(Contextual Bandits)

上述所描述的情況缺少了真實環境中有的一個要素,它只有一個狀態。在現實或遊戲世界裡,一個環境可能會處於幾十(房子裡的房間)到數十億(一個螢幕上的圖元)種可能狀態中的一種。每個狀態都有它們自己獨特的動態特性,即動作如何提供新的回報或者允許狀態間的轉移。

因此,我們需要對動作與估計值以及狀態設定條件。用符號表示,現在將用Q(s,a)取代V(a)。它的抽象意思是,現在期望獲得的回報,是我們所採取的動作以及採取該動作時所處狀態的一個函數。

在迷宮遊戲中,狀態的概念使我們可以在不同的房間中擁有不同的寶箱組。每個房間可以有不同的最理想寶箱,因此,代理需要學習在不同房間中採取不同的動作。用程式來實現的話就是使用一個價值估計的matrix來取代一個簡單的array。這個matrix可以用[state, action]來索引。



探索(Exploring)和利用(Exploiting)

讓RL能運作還需要一個重要的因素。在代理學得採用最佳回報動作的策略之前,需要有另一個策略使它可以充分瞭解世界,以確保它知道什麼是最佳策略。這會引出了一個經典問題,如何平衡探索(exploration)(通過不斷試錯學習環境的價值結構)和利用(exploitation )(基於環境習得的價值結構採取動作)。雖然有時這兩個目標會一致,但大多數狀況它們都會相左。有一系列策略可以平衡這兩個目標。下面列出了其中一部分:

  • 一個簡單卻強大的策略是遵循“optimism in the face of uncertainty”的原則。它的做法是,代理每個動作都從高值估計V(a)開始,這樣它就會貪婪地(利用最大值)採取動作,使它將每個動作都至少執行一次。
  • 如果動作沒有獲得好的回報,就降低對應的價值估計,反之則保持高價值估計,因為該操作可以作為後續好操作的候選。但是僅靠這種自身啟發式演算法通常仍然不夠,因為我們可能需要持續探索某個特定狀態以找到一個低頻率,卻有巨大的回報。
  • 另一個策略是為每個動作的價值估計添加隨機亂數,隨後根據新的亂數估計進行貪婪行為(act greedily)。使用這種方式,只要亂數值小於真實最優動作與其他動作間的差異值,就能收斂至最優的價值估計。
  • 也可以進一步利用估計值本身的特性,將它們進行歸一化(Normalize),依據概率採取動作。這種情況下,如果每個動作的價值估計大致相等,將會以相同概率採取動作。反之,如果一個動作的價值估計要大得多,我們將會更多的選擇這個動作。這樣就能通過遞減選擇無回報動作,慢慢將它們淘汰。這也是在範例專案中所採用的策略。



結語

有了這篇文章以及相關程式碼,你現在也可以嘗試在Unity中使用文章描述的演算法了。但這僅僅是入門而已,在後面的文章我們將通過Q-Learning來講解一個完整的RL問題,並以此為基礎,開始探討深度神經網路,解決視覺豐富遊戲環境中,愈趨複雜的代理行為的學習策略問題。使用這些進階的方法來訓練代理成為我們遊戲中的同伴或對手,適用的遊戲類型可以是格鬥遊戲、賽車、第一人稱射擊,或甚至即時策略遊戲等等。不需要編寫任何規則,只需專注於你希望代理達成的狀態,而非它如何達成的過程。

後續我們還會提供一些工具的早期版本,讓對使用Unity進行深度RL研究感興趣的開發者,可以將諸如Tensorflow或PyTorch等框架編寫的模型連接到Unity製作的環境中。一起探索未來可能是新的遊戲製作方式領域!

著作人