从牛顿到爱因斯坦——2016 GTC大会手记(1)

2016年是AI元年。AlphaGo战胜李世石的那一刻,这个事实就已经是板上钉钉了。人类在自己发明的最优美最复杂的游戏中输给了机器。那是一个巅峰时刻,它并不是一个时代的终结,而是一个崭新时代的开始。我们为AlphaGo欢呼时,也许只是远远看到AI向我们走来,而今天在美国加州圣何塞举行的GTC大会上,我们清晰得听到了AI的敲门声。

NVIDIA公司CEO黄仁勋在GTC大会上宣布了多项产品,而所有这一切却仅仅指向一件事,那就是深度学习!

谈论深度学习之前,我们需要澄清几个概念——“AI 人工智能”、“Neural Network 神经网络”和“Deep Learning 深度学习”。

AI

AI是人类的一个梦想:我们想让机器变得跟我们同样聪明或者超过我们。而这个梦想,目前只完成了一半。美国心理学家、诺贝尔经济学奖得主丹尼尔·卡尼曼有一个“系统一”和“系统二”的理论。人类的“系统一”便是宽泛模糊的心理能力,或者说自主意识;比如,对面的人是不是生气了,姑娘真好看,回锅肉很好吃,某部电影是否是烂片等等;当然,这也包括围棋的“棋感”。而“系统二”是有客观结果的事务,比如数学运算,信息处理。人脑需要一段时间才能完成或者甚至无法完成属于“系统二”的任务。对于计算机则相反,“系统二”易如反掌,而“系统一”则是登天的难题。

直觉和理性

神经网络

神经网络就是我们为了解决机器的“系统一”难题而发展出来的计算机系统。这个系统采用规模很小但是数量庞大的计算单元来模拟人类的神经元;同时,这些数量庞大的神经元通过网络或者某种硬件连接起来模拟神经元之间可以通过神经突触传递信息的能力。每个计算单元可以接受一些输入,恰似神经元可以接受某种刺激;这些计算单元也可以给出一些输出并将这个输出传递给其他神经元作为输入,这正是对神经元之间的通信进行模拟。而且,这些神经元构成的网络是分层的,底层的输出恰是上层的输入。

神经元构成的层级结构

从宏观上看,整个神经网络会接受某些输入并且分析计算给出一些结果。设想一下人类观赏一朵花的过程:眼睛看到花的颜色和形状,鼻子闻到气味,这些信息经过大脑过滤并进一步处理,接着,根据已经存储在脑内的某些特征进行比较,人们可以知道这朵花是月季还是玫瑰。神经网络对信息的处理过程与此类似,它具有抽取输入、存储结果、分析和给出反馈的所有能力。使用”神经网络“,”系统一“的难题不再不可捉摸,而变成了一种机器可以学习的东西。

深度学习

深度学习是一种用神经网络解决计算问题的方法。之所以称其为”深度“,正是因为这个网络的层数众多。它与众不同的原因在于,这种算法的自诞生以来,其目标就是给所有其他算法画上句号。深度学习成功了。在很多领域,从此以后,只有一个算法,而这个算法能解决所有问题。它天然的具有暴力美学倾向。计算从此不再依赖于精巧的设计,而依赖于超大量的数据和强大的计算能力。GPU正是让机器长出大脑并且变得筋肉暴突的妖怪。

神经网络

GPU

每个GPU都有数量庞大的小型计算单元,而这些计算单元可以模拟神经元。

gpu-architecture

上图是NVIDIA的PASCAL核心GPU的结构示意图。图中密密麻麻的绿色小方格代表的就是可以模拟神经元的小型计算单元。GPU技术经历了Fixed pipeline技术之后,几乎所有的GPU厂商都走向了更加通用的Generic Shader技术。Generic Shader技术使用众多结构相同的微小的ALU(逻辑和计算单元)来对图形数据进行处理。通常,图形图像数据可以被分割成数据块,而且这些数据块之间不会有相互依赖的关系。借助这个特性,GPU可以在所有ALU中装载相同的处理程序对大量图形图像数据进行并行处理。这种并行处理最直观的体现就是下面这个视频。视频中GPU用10毫秒绘制了非常漂亮的蒙娜丽莎。

NVIDIA率先发现了这种通用的处理器结构可以用于除了图形计算以外的其他领域。于是,CUDA作为一门专门支持并行计算的计算机语言而诞生。

nvidia_adrian

更进一步,CUDA针对众多ALU处理器核心进行编程的能力被迅速用于模拟神经网络。为了完成多层神经网络结构,计算机程序会让GPU在按照顺序在装载不同的CUDA kernel(内核)。而每一次装载后运行的结果会被缓存在GPU的共享存储器中,这些结果通常会作为下一层神经元的输入来使用。采用这种方法不断的重新加载CUDA内核,计算机就可以使用GPU对生物的神经网络进行模拟。

机器的神经元

本届GTC发布的重量级硬件产品包含了TESLA P100NVIDIA DGX-1NVLINK,它们的目标也只有一个,就是为运行深度学习程序的计算机提供更多更快的神经元和神经突触。

NVIDIA DGX-1

DGX-1是专门用来运行深度学习的计算机;与传统计算机体系结构相比,使用它训练AlexNet的时间从原来的250小时缩短到2小时。

战胜李世石的分布式AlphaGo实际上由1,202块CPU和176块GPU组成。这些机器的神经元在运行期间对电能的消耗巨大,自身发热更是惊人。而NVIDIA此次在GTC发布的DGX-1自身就集成了所有这些计算能力。

DGX1Parts_575px

并且以低廉的价格推出市场。

DGX1Price

而在移动设备上,NVIDIA此前推出的Tegra TX1处理器和本次针对汽车市场推出的DRIVE PX2同样也具备运行神经网络程序的能力。

drivepx2

机器视觉

深度学习正在蚕食一切传统算法,包括机器视觉算法。机器视觉的目标就是要让机器具有人类的视觉感知能力。当人们看到第一朵玫瑰花开始,就有人想弄清楚人类视觉的原理。为了探索这个问题,伟大的牛顿甚至用自己的身体实验。他曾经用缝衣针刺穿面部深入眼球下方刺激以观察变化!

牛顿的手稿

从牛顿到爱因斯坦

与人类探索自身视觉之初的冲动一样,机器视觉到目前为止发展出的理论是一套没有主题的自助餐。没有统一的理论,仅仅有针对某些问题有某些方法的教条。深度学习则抛弃传统完全开辟了另一条道路,特别是针对模式识别的问题单独来看的话,这条全新的方法效果尤为显著。

深度学习在ImageNet测试上取得的成绩

上图中的绿色标记为深度学习算法取得的成绩,而蓝色标记是传统算法取得的成绩。可以看出,深度学习算法在该领域取得了极大成功,秒杀一切传统算法。

未来的趋势就是如此,伴随着GPU这样的技术变的更小更快更省电,机器视觉的教条也许会一个一个的土崩瓦解。

无人机用机载深度学习设备处理地面图像

上图显示的是本届GTC的一个讨论主题:无人机利用机载深度学习设备对地面图像进行处理。

从以程序为中心转变为以数据为中心,这是计算模型的根本改变。这是从牛顿到爱因斯坦的变革,一切都变了!

huanggtc2016

Jetson TK1的交叉编译工具链

Jetson TK1是NV推出的非常强大的开发板。除了硬件以外,NV还提供L4T这个以Ubuntu 14.04为基础的Linux系统作为示例软件。但是,不知道何种原因,NV并没有在文档中明确指出如何对Jetons TK1的L4T发行版做交叉编译。于是,我花了一些时间研究一下这个问题并且将结果简单的记在这里。

简而言之,对于在ARM CPU上运行的代码,全部都可以采用Ubuntu Precise提供的工具链进行交叉编译。因为Debian系发行版——包括Ubuntu——很早就开始支持Multiarch,开发者需要做的仅仅是安装支持multiarch的gcc等编译工具而已。具体步骤如下:

## Create backup files
$ sudo mkdir /etc/apt/bak/
$ sudo cp /etc/apt/sources.list /etc/apt/bak/sources.list
$ sudo cp -R /etc/apt/sources.list.d/ /etc/apt/bak/

## Prevent host architecture from pollution
$ sudo sed -i "s/deb /deb [arch=amd64,i386] /g" /etc/apt/sources.list
$ sudo sed -i "s/deb /deb [arch=amd64,i386] /g" /etc/apt/sources.list.d/*

## Add debian percise repository
$ sudo sh -c 'echo "deb http://jp.archive.ubuntu.com/ubuntu/ precise main universe" >> /etc/apt/sources.list'
$ sudo sh -c 'echo "deb-src http://jp.archive.ubuntu.com/ubuntu/ precise main universe" >> /etc/apt/sources.list'

## Update apt
$ sudo apt-get update

## Install armhf toolchain
$ sudo apt-get install g++-4.6-arm-linux-gnueabihf g++-arm-linux-gnueabihf

安装结束后可有用yavta项目来做工具链的验证。

$ git clone git://git.ideasonboard.org/yavta.git
$ cd yavta
$ CROSS_COMPILE=arm-linux-gnueabihf- make

检查交叉编译的的结果。

$ file ./yavta 
./yavta: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.31, BuildID[sha1]=9d2e056f30c0e01bdab26b64c97a5647b304d131, not stripped

然后就可以将编译好的二进制文件拷贝到target系统上运行了。

因为这样的工具链仅仅可以编译在CPU上运行的代码,对于在GPU上运行的代码来说仍然是无效的。所以,要彻底得做到对CUDA代码进行编译的话,还需要做更多努力。持续探索中。

OpenGL ES模拟器

OpenGL ES 3.0 programming guide这本书提供了很多例子。为了在PC上运行这些例子,我决定使用OpenGL ES 3.0的模拟器来做这件事。而且,这次我决定使用Windows :)。由于长期以来,我都在使用类Unix系统工作,对于如何在Windows系统中编程这件事情非常不在行。在屡次尝试才得到结果之后,我决定把这个过程记录下来。

安装OpenGL ES模拟器之后,EGL和GSES两个基本库都被安装进入ARM\Mali Developer Tools\Mali OpenGL ES Emulator 2.2.1。用git克隆这些代码

https://github.com/danginsburg/opengles3-book/

下载并安装CMake的Windows版本并且使用CMake对这份代码进行配置

cmake -G "Visual Studio 14 2015 Win64" \
-DEGL_LIBRARY="C:\Program Files\ARM\Mali Developer Tools\Mali OpenGL ES Emulator 2.2.1\libEGL.lib" \
-DOPENGLES3_LIBRARY="C:\Program Files\ARM\MaliDeveloper Tools\Mali OpenGL ES Emulator 2.2.1\libGLESv2.lib"

其中,-G "Visual Studio 14 2015 Win64"是帮助CMake产生在64bit的Windows上运行Visual Studio的Project文件。用Visual Studio打开CMake产生的solution文件,编译并链接。打开

opengles3-book\Chapter_2\Hello_Triangle\Debug\Hello_Triangle.exe

就可以看到这个三角形了。

hello-triangle