選自Medium
作者:Franklin He
機器之心編譯
參與:Nurhachu Null、路
本文介紹了如何在 Google Colab(Google 提供免費 GPU 的機器學習環境)上運行 StarCraft II 機器學習項目,包括過程中遇到的問題和作者提出的解決方案。
如果你想開始使用 FREE StarCraft II 機器學習環境,請先完善 GPU 硬體,您可以看一下我的 Google Colab notebook:https://colab.research.google.com/drive/1AzCKV98UaQQz2aJIeGWlExcxBrpgKsIV
最近,我和幾位朋友開始了 StarCraft II 的機器學習項目。我覺得快速訓練神經網絡的能力對於研究者的成功是很重要的。為了向全球的 StarCraft II 研究者提供一個可復現、高效,且容易分享代碼的環境,我想看看我們能否讓 StrCraft II 在 Google Colab(Google 提供免費 GPU 的機器學習環境)上運行起來。
然而,在下載了 StarCraft II,並安裝完必需的庫之後,你會面臨以下問題:
I0331 08:30:17.832181 139972195997568 sc_process.py:148] Connection attempt 0 (running: None)
****** omitted reconnection attempts ******
I0331 08:32:17.048350 139972195997568 sc_process.py:148] Connection attempt 119 (running: -11)
I0331 08:32:18.050124 139972195997568 sc_process.py:180] Shutdown gracefully.
I0331 08:32:18.050344 139972195997568 sc_process.py:166] Shutdown with return code: -11
Failed to create the socket.
I0331 08:32:18.056085 139972195997568 sc2_env.py:327] Environment Close
構建額外的 Pylons 也無法修復這個問題。
理解返回代碼
我所做的第一件事就是弄清楚返回代碼的含義。
讀了 PySC2 的源碼(https://github.com/deepmind/pysc2/blob/39f84b01d662eb58b3d95791f59208c210afd4e7/pysc2/lib/sc_process.py)之後,我找到了設置返回代碼的代碼段:
@property
def running(self):
return self._proc.poll() if self._proc else False
poll() 來自 Python 的 subprocess 模塊,深入挖掘後發現 11 就是導致 StarCraft 中斷的信號。
信號 11 就是臭名昭著的段錯誤,這個信號給 C 語言編程者帶來了無窮無盡的噩夢。
為了確認,我發現 SC2 是可執行的,而且是自行執行的。
> !~/StarCraftII/Versions/Base59877/SC2_x64
Segmentation Fault (Core Dumped)
在 hard 模式下調試
正常情況下,我會啟動最喜歡的調試工具,那本文就變成了如何使用 GDB 的過程。
不過,我們是使用 Google Colab 來處理的,我們唯一擁有的就是一個 Jupyter Notebook 網頁。這意味著:
1. 沒有調試器
2. 沒有 root 特權
3. 工具有限,比如沒有 strace
RIP 調試
當你只有一個網頁的時候……
第一步就是在伺服器上嘗試不同版本的 StarCraft II,暴雪公司提供了 StarCraft II 的 4.0.2、3.17 和 3.16.1 三個版本。不幸的是,沒有一個能夠成功。
然後我決定在本地 Linux 機器上運行 StarCraft II,這個環境我可以控制並在其中進行調試。它還允許我測試我的假設。
第一個猜想:沒有找到需要的庫
我最初的猜測是,StarCraft II 作為一個遊戲,可能需要某些 OpenGL 函數和庫,而這些並不包含在我所用的 Google Colab 環境中。
為了驗證這個猜想,我在本地機器上運行 StarCraft II,這次是有 strace 工具的,這使得我可以跟蹤系統讓 StarCraft II 做了什麼。由於所有的庫都通過作業系統加載了,這樣一來,我就能夠跟蹤任何一個缺失的依賴項,或者查看是否有什麼奇怪的事情發生。
完整的 trace 日誌參見:https://gist.github.com/FrozenXZeus/53a85f58856cb346b90313110ce89bcc,下面展示了一小段:
execve("./SC2_x64", ["./SC2_x64"], 0x7fffc19e08b0 /* 49 vars */) = 0
brk(NULL) = 0x95bd000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
.
openat(AT_FDCWD, "/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
.
openat(AT_FDCWD, "/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
.
openat(AT_FDCWD, "/lib64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
.
openat(AT_FDCWD, "/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
...
openat(AT_FDCWD, "/lib64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
.
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
..
看一下這個結果,除了動態連結 C/C++ 庫之外,StarCraft II 沒有做任何事情,這否定了我的假設。
那為什麼會出現段錯誤呢?
因為同樣的程序在我的本地機器上運行的時候沒有崩潰,這也否定了暴雪的代碼有問題的假設。
快速搜索如何調試段錯誤使我想起了 Valgrind(http://valgrind.org/),令我驚訝的是,該工具竟然可以在 Google Colab 上使用。
Valgrind 的一段輸出如下:
==354== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==354== Access not within mapped region at address 0x8
==354== at 0x6B3DF0: ??? (in /content/StarCraftII/Versions/Base56787/SC2_x64)
==354== by 0x65FF97: ??? (in /content/StarCraftII/Versions/Base56787/SC2_x64)
==354== by 0x89CD5C6: MallocExtension::Initialize() (in /usr/lib/x86_64-linux-gnu/libtcmalloc.so.4.3.0)
==354== by 0x89B7D29: ??? (in /usr/lib/x86_64-linux-gnu/libtcmalloc.so.4.3.0)
==354== by 0x7B79AD9: call_init.part.0 (dl-init.c:72)
==354== by 0x7B79BEA: call_init (dl-init.c:30)
==354== by 0x7B79BEA: _dl_init (dl-init.c:120)
==354== by 0x7B69ED9: ??? (in /lib/x86_64-linux-gnu/ld-2.26.so)
==354== If you believe this happened as a result of a stack
==354== overflow in your program's main thread (unlikely but
==354== possible), you can try to increase the size of the
==354== main thread stack using the --main-stacksize= flag.
==354== The main thread stack size used in this run was 8388608.
==354==
==354== HEAP SUMMARY:
==354== in use at exit: 0 bytes in 0 blocks
==354== total heap usage: 4 allocs, 4 frees, 72,710 bytes allocated
==354==
==354== All heap blocks were freed -- no leaks are possible
==354==
==354== For counts of detected and suppressed errors, rerun with: -v
==354== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
那麼,唯一一個可以識別的函數就是 libtcmalloc.so.4.3.0 中的 MallocExtension::Initialize()。
對於不了解 TCMalloc 的人而言,它是谷歌的定製化內存分配器,用在 Google Chrome 等產品中。
等等.
回到我追蹤 StarCraft II 的時候,我記得只看到 C/C++庫被加載了。這似乎不正確,TCMalloc 是從哪裡來的呢?
結果證明,有一種方式能夠讓 TCMalloc 在沒有使用 TCMalloc 編譯的程序上強制執行。通過在 Linux 上設置 LD_PRELOAD 環境變量,你可以加載 TCMalloc 共享庫到程序中,強制讓程序使用 TCMalloc。
它在 Google Colab 上會是什麼樣子呢.
解決方案
不幸的是,設置 LD_PRELOAD 環境變量並不能傳播到環境的其他部分中。
通過執行以下命令:
!apt-get uninstall libtcmalloc*
我成功地卸載了 TCMalloc,然後儘管還有錯誤信息,但是 StarCraft II 已經開始運行了,StarCraft II 機器學習項目的大門也隨之開啟了。
我已經在 Google Colab 上提出了這個 bug(https://github.com/googlecolab/colabtools/issues/106),因此我們以後不必為此大費周折了。
基於 STARCRARFT II 進行的機器學習項目。
原文連結:https://medium.com/@n0mad/how-i-trained-starcraft-2-ais-using-googles-free-gpus-44bc635b0418
本文為機器之心編譯,轉載請聯繫本公眾號獲得授權。
✄---
加入機器之心(全職記者/實習生):hr@jiqizhixin.com
投稿或尋求報導:editor@jiqizhixin.com
廣告&商務合作:bd@jiqizhixin.com