Auto Byte

专注未来出行及智能汽车科技

微信扫一扫获取更多资讯

Science AI

关注人工智能与其他前沿技术、基础学科的交叉研究与融合发展

微信扫一扫获取更多资讯

Nurhachu Null编译

如何利用Google Colab免费训练StarCraft II

本文介绍了如何在 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

工程教程谷歌Colab
2
暂无评论
暂无评论~