“人類對周遭世界的認知,只是我們腦海中的一個模型。”
——系統動力學之父J.W.Forrester
LSTM之父Jürgen Schmidhuber再發新作!
這一次,他借鑑了人類認知世界的模式,為機器建造了一個世界觀模型。
諸多證據表明,人腦為了處理日常生活中的海量資訊,學會了對這些時空資訊作出抽象化的處理。藉此,我們能夠在面對周遭複雜的資訊時,進行迅速而準確的分析。而我們在當前所“看”到的這個世界,也受到了大腦對未來世界預測的影響。
比方說,棒球選手可以毫不費力地擊中打時速100英里的棒球,正是得益於大腦對棒球運動軌跡的精確判斷。
那麼,我們能不能讓機器也學會這樣的世界觀呢?機器有了世界觀後又將具備怎麼樣的能力呢?
今天,文摘菌就帶你一起來讀LSTM之父的一篇最新力作。同時,文摘菌也會手把手教你訓練出一個有簡單世界觀的AI賽車手。到底有多厲害,試了就知道!
提出問題
讓我們通過一個具體案例來探究這個問題:如何讓機器擁有世界觀?
假設我們要訓練出一個AI賽車手,讓它擅長在2D賽道上駕駛汽車。示例如下圖。
在每個時間節點,這個AI賽車手都會觀察它的周圍環境(64×64畫素彩色影象),然後決定並執行操作——設定方向(-1到1)、加速(0到1)或制動(0到1)。在它執行操作後,它所處的環境會返回下一個觀測結果。以此類推,這個過程講不斷重複。
它的目標是,在儘可能短的時間內走完賽道。
解決方案
我們給出一個由三部分組成的解決方案。
變分自編碼器(VAE)
當你在開車的時候做決定時,你並不會主動分析你檢視中的每一個“畫素”——相反,你的大腦會將視覺資訊凝聚成較少數量的“隱藏”實體,比如道路的筆直程度、即將到來的彎道以及你在道路中的相對位置,從而判斷出你需要操作的下一個動作。
這正是VAE的要義所在——將64x64x3(RGB)輸入影象壓縮成一個長度為32的特徵向量(z)。
藉此,我們的AI賽車手可以用更少的資訊去表示周圍的環境,從而提高學習效率。
遞迴神經網路(RNN)
沒有遞迴神經網路的AI賽車手可能會把車開成這樣。。。
回想一下。當你開車的時候,其實是會對下一秒可能出現的情況進行持續預估的。
而RNN就能夠模擬這種前瞻性思維。
與VAE類似,RNN試圖捕捉到汽車在其所處環境中當前狀態的隱藏特性,但這次的目的是要基於先前的“z”和先前的動作來預測下一個“z”的樣子。
控制器(Controller)
目前為止,我們還沒有提到任何有關選擇動作的事情。因為,這些選擇都是控制器要做的。
控制器是一個密集連線的神經網路,輸入是z(VAE的當前隱藏狀態——長度為32)和h(RNN的隱藏狀態——長度為256)的串聯,3個輸出神經元對應於三個動作,並被縮放到適當的範圍內。
為了理解這三個組成部分所擔任的不同角色,以及他們是如何一起工作的,我們可以想象他們之間的一段對話:
世界模型體系結構圖
VAE:(關注最新的64 * 64 * 3的觀測結果)這看起來像一條直路,前方稍微向左彎曲,汽車朝向道路方向(z)。
RNN:基於該描述(z)和控制器在上一個時間節點(動作)選擇加速的情況,我將更新我的隱藏狀態(h),以便預測下一個觀測結果仍然是筆直的道路,但要略微左轉一點。
Controller:基於VAE(z)的描述和RNN(h)反饋的當前隱藏狀態,我的神經網路下一個輸出的動作為[0.34,0.8,0]。
然後,這個操作會被傳遞給環境,該環境會返回更新後的觀測結果,並重新開始迴圈。
現在,讓我們來實際演練一下吧!
實現程式碼來了
如果你使用的是高規格膝上型電腦,則可以在本地執行此解決方案,但我建議你在谷歌雲端計算平臺(Google Cloud Compute)上用功能更強大的計算機來執行,從而在短時間內完成。
以下步驟已經在Linux(Ubuntu 16.04)上進行了測試——在Mac或Windows上只需要更改軟體包安裝的相關命令即可。
第一步:下載程式碼
在命令列中輸入以下內容:
git clone https://github.com/AppliedDataSciencePartners/WorldModels.git
第二步:建立虛擬環境
建立一個Python3虛擬環境(這裡使用的是virutalenv和virtualenvwrapper):
sudo apt-get install python-pip sudo pip install virtualenv sudo pip install virtualenvwrapper export WORKON_HOME=~/.virtualenvs source /usr/local/bin/virtualenvwrapper.sh mkvirtualenv --python=/usr/bin/python3 worldmodels
第三步:安裝程式包
sudo apt-get install cmake swig python3-dev zlib1g-dev python-opengl mpich xvfb xserver-xephyr vnc4server cd WorldModels pip install -r requirements.txt
第四步:生成隨機訓練資料
對於這個塞車問題,VAE和RNN都可以使用隨機生成的訓練資料——也就是在每個時間節點隨機採取動作所生成的觀測資料。實際上,我們可以使用偽隨機動作,使車在初始狀態就能加速離開起跑線。
由於VAE和RNN獨立於決策控制器,我們需要確保遇到各種各樣的觀測結果,並且選擇不同行動來應對,並將結果儲存為訓練資料。
要生成隨機策略,請從命令列執行以下命令:
python 01_generate_data.py car_racing --total_episodes 2000 – start_batch 0 --time_steps 300
如果你的伺服器沒有顯示結果,你可以執行以下命令:
xvfb-run -a -s "-screen 0 1400x900x24" python 01_generate_data.py car_racing --total_episodes 2000 --start_batch 0 --time_steps 300
以上命令將會產生2000個策略,儲存在200個批次中,每個批次10個)。
在./data資料夾中,你會看到以下檔案(*為批次號):
obs_data_*.npy (此檔案將64 * 64 * 3影象儲存為numpy陣列)
action_data_*.npy (此檔案儲存三維動作)
第五步:訓練VAE
這裡我們只需要用obs_data_*.npy就可以訓練VAE。確保你已經完成了第四步,否則這個檔案不在./data資料夾下。
在命令列中執行下列語句:
python 02_train_vae.py --start_batch 0 --max_batch 9 --new_model
在每一批從0到9的資料中都會訓練出一個新的變分自編碼器VAE。模型的權重儲存在./vae/weights.h5中。“--new_model”引數表明從頭開始訓練模型。
如果資料夾中已經存在weights.h5,也沒有宣告“--new_model”引數,指令碼將直接匯入這個檔案中的權重,繼續訓練現有的模型。這樣的話,你就可以實現模型的迭代訓練,而不需要對每批資料都重新執行。
VAE架構的相關引數都在 ./vae/arch.py檔案裡宣告。
第六步:生成迴圈神經網路RNN資料
現在我們就可以利用這個訓練好的VAE模型生成RNN模型的訓練集。
RNN模型要求把經由VAE編碼後的影象資料(z)和動作(a)作為輸入,把一個時間步長前的由VAE模型編碼後的影象資料作為輸出。
執行這行命令可以生成這些資料:
python 03_generate_rnn_data.py --start_batch 0 --max_batch 9
這一步需要把第0至9批的obs_data_*.npy 和 action_data_*.npy檔案轉成在RNN中訓練所需要的格式。
這兩組檔案儲存在./data(*是批量編號)
rnn_input_*.npy(儲存了[z a]串聯向量)
rnn_output_*.npy(儲存了前一個時間步長的z向量)
第七步:訓練RNN模型
訓練RNN只需要用到rnn_input_*.npy和rnn_output_*.npy檔案。確認你已經完成了第六步,否則這個檔案不在./data資料夾下。
在命令列執行:
python 04_train_rnn.py --start_batch 0 --max_batch 9 --new_model
在每一批從0到9的資料中都會訓練出一個新的VAE。模型的權重儲存在./rnn/weights.h5。“--new_model”表明從頭開始訓練模型。
和VAE訓練很相似的是,如果資料夾中已經存在weights.h5,也沒有宣告“--new_model”標誌,指令碼將直接匯入檔案中的權重,繼續訓練現有的模型。這樣的話,你就可以實現RNN模型的迭代訓練,而不需要對每批資料都重新執行。
RNN迴圈神經網路模型的具體引數都在./rnn/arch.py檔案裡宣告。
第八步:訓練控制器
到了最有趣的部分了!
到目前為止,我們已經使用深度學習搭建了VAE模型和RNN模型。VAE能把高維的圖片降至低維的隱藏資料,RNN用來預測隱藏空間中資料的時序變化。正因為我們可以對每個模型都採用隨機抽取的資料來建立訓練集,模型才有可能達到預期效果。
為了訓練控制器,我們將採用強化學習的方法,它使用了名叫CMA-ES(自適應協方差矩陣進化演算法)的進化演算法。
輸入是一個288(32+256)維向量,輸出是一個3維向量,因此我們要訓練的引數有288 * 3 + 1 (bias) = 867個。
CMA-ES演算法,首先隨機生成867個引數(即一個群體)的副本,然後對環境中每個群體成員變數做測試,並記錄其平均得分。正如自然選擇中的法則一樣,產生最高得分的權重變數允許其繼續“繁殖”,並生出下一代。
執行下列程式碼將在你的機器上啟動這個過程,併為變數選擇合適的值。
python 05_train_controller.py car_racing --num_worker 16 – num_worker_trial 4 --num_episode 16 --max_length 1000 --eval_steps 25
或者在伺服器上執行,但不顯示結果:
xvfb-run -s "-screen 0 1400x900x24" python 05_train_controller.py car_racing --num_worker 16 --num_worker_trial 2 --num_episode 4 – max_length 1000 --eval_steps 25
--num_worker 16:worker的個數不要超過可用核心的數量
--num_work_trial 2 :每個worker測試的群體成員的數量(num_worker * num_work_trial表示每一代群體的總規模)
--num_episode 4:為群體的每個成員進行打分的次數(分數將是該次打分的平均得分)
--max_length 1000:一次打分中最大時間步長
--eval_steps 25:每隔25步對權重進行評估
預設情況下,控制器每次執行都會從零開始,將程式的當前狀態儲存到controller目錄的pickle檔案中。這樣你就可以通過指定相關檔案,從上一次儲存的地方繼續訓練。
每生成一代後,演算法的當前狀態和最佳權重的集合將會輸出到./controller資料夾。
第九步:視覺化結果
經過200代的訓練,我已經訓練出一個平均得分約為833.13的角色。我在谷歌雲上使用配置為Ubuntu 16.04, 18 vCPU, 67.5GB RAM的機器,採用的是本文給出的步驟和引數。
在論文中,作者試圖在2000代訓練後達到約906的平均得分,這是迄今為止該環境下的最高分。他利用了稍高的規格設定(例如10,000集訓練資料,群體大小設為64,64臺核心機器,每次試驗16次)。
如果你想視覺化控制器的當前狀態,那你只需要執行下列程式碼:
python model.py car_racing –filename ./controller/car_racing.cma.4.32.best.json --render_mode – record_video
--filename:想要新增到控制器的權重json的路徑
--render_mode :在螢幕上顯示環境
--record_video:輸出mp4檔案到./video資料夾,展現出每個片段
--final_mode:執行100次控制器測試,輸出平均得分
就是這樣啦!
第十步:幻覺學習
到這一步已經很了不起了——但下一步則更令人興奮哦,同時對人工智慧未來的發展也很有啟發意義。
增加難度,我們可以讓賽車在行進過程中避免火球的襲擊。
作者展示了角色將怎樣實際地學會如何在自己的VAE / RNN模型啟發的幻覺夢境中玩遊戲,而不是在實際的遊戲環境中。
我們唯一需要做出的改變是,訓練RNN使其也可以預測出在下一個時間步長中賽車被火球擊中的概率。這樣,VAE / RNN組合模型可以作為一個獨立的環境被封裝起來,並用於訓練控制器。這就是“世界模式”的概念。
我們將幻覺學習的概念總結如下:
角色的初始訓練資料不過是與真實環境的隨機互動。通過這一互動,它對世界“如何運作”形成了一種潛在的理解——世界運作的物理規律,以及自己的行為會如何影響世界的狀態。
然後,它可以利用這種理解為一個給定的任務建立一個最佳策略,甚至無需在現實環境中進行測試,因為它可以使用自己的一套環境模型作為各種測試的“試驗場”。
就像嬰兒學走路一樣。小嬰兒通過自己的探索建立一個初步的世界觀,明白自己的動作會帶來的後果,然後一步步調整自己的策略。在這一過程中,嬰兒甚至能夠在腦海中進行自我模擬。
最後,獻上這篇論文的動態演示連結:
https://worldmodels.github.io/