摘要: GPU在机器学习中相当重要,但不多有人能解释清楚,本文对此进行了一番研究。
若是你从事机器学习,或者碰巧是NVidia的投资者,你必定据说过GPU对这个领域相当重要。但对我来讲,GPU一直是个谜。我对“GPU=快速”有很好的理解,但仅此而已。服务器
老实说,这能让你走得更远。我开始着手使用Keras进行ML工做,Keras是谷歌的TensorFlow库之上的API。Keras是一个设计精美的API,它作出了一个很是实际的决定:大多数事情应该是简单的,困难的事情应该是可能的。并发
正由于如此,我真的不须要学习任何关于GPU的知识。我只是运行了一些神奇的操做系统命令和一些神奇的代码行-嘣!-大规模模型训练加速。我对这种状况很是满意。机器学习
然而,在feedly最新的项目中,咱们决定试用PyTorch,由于它愈来愈流行。但也有一些有利的数据。新的(强烈推荐的)fast.ai课程顺序从Keras切换到PyTorch。 PyTorch模型也赢得了不少最近的Kaggle比赛。性能
因此咱们深刻研究并发现PyTorch经过清晰一致的API使全部事情成为可能。它比Keras更灵活,因此权衡的是简单的事情变得更难,但困难的事情变得更容易。若是你正在尝试新的或不寻常的模型(或者你碰巧是一个控制狂),PyTorch绝对是一个更好的选择。学习
当GPU加速个人PyTorch模型的时候,我谷歌了一下神奇的“GPU -> on”代码行,我发现它不存在!一如既往,Pytorch使这比Keras更难实现,可是提供了一些关于如何着手作事的API。全部这一切的结果是,我不得不咬紧牙关,创建了一个关于GPU如何被用来加速模型训练的心智模型。优化
为何GPU很快编码
模型一般具备许多不少参数。例如,流行的VGG图像分类模型有大约1.4亿个参数,分为16层!在运行推理(预测)时,你须要将输入数据(图像)传递到每一个图层,一般将该数据乘以图层参数。在训练期间,你还必须稍微调整每一个参数以更好地拟合数据。那是很大的计算量!spa
CPU很擅长快速完成一些事情。 这一般很好,有足够的分支(若是用户这样作,那样作),以及大规模并行性实际上不可能的其余顺序约束。GPU很好,能够作不少“慢”的事情。因为它们最初用于执行图形要求,所以它们但愿一次性完成大量工做(考虑将图像的全部像素转换为灰度)。因此这里有一个权衡,对于ML来讲GPU因为能够并行完成这些巨大的算术运算而赢得大量时间。操作系统
具体来讲,个人macbook有一个运行速度为3.1Ghz且有4个内核的CPU。NVidia K80 GPU拥有近5000个内核,尽管运行速度要慢得多——562Mhz。虽然这样作并不公平,但你能够看到K80的时钟速度大约慢了6倍,可是并行速度提升了1250倍。设计
如何考虑GPU
PyTorch不是代码行“GPU -> on”,而是“CUDA”张量。CUDA是一个用于在GPU上执行操做的库。基本上,PyTorch要求你声明要在GPU上放置的内容,而后你能够像往常同样执行操做。因此我想,让咱们试着在GPU上添加一个图层:
我运行代码,当即获得了一个错误在隐藏层计算中:
为何?我当即知道它与我添加的.cuda()代码有关,但我不知道为何。在思考了GPU应该如何加速以后,我意识到,“固然它不工做,一个张量在GPU上,另外一个仍然在主内存中!”一切都搞定了。Pytorch容许在GPU内存中分配张量,而后使用GPU对这些张量进行操做。可是这些操做的结果会怎样呢?让咱们试试另外一个例子:
这是GPU内存中的另外一个张量!通过更多的反复试验,我发现我不得不改变本身的思惟方式。原来我觉得内存、CPU和GPU都混在一块儿了:
我意识到我须要这样想:
从本质上说,CPU/主内存和GPU/GPU内存都位于各自的小宇宙中。来自软件工程背景的我开始将GPU操做看做是一个REST API。当你使用REST API时,真正的成本是来回发送数据。在本地执行任务的速度与在远程服务器上执行任务的速度同样快。可是你要避免的是大量的数据来回传输,由于这是纯粹的开销。
把这个类比往前推,咱们能够看到,固然,PyTorch matmul结果是一个GPU张量是有道理的。这样就很容易在GPU上进行进一步的操做,而不须要将数据传送到主内存,而后再返回到GPU。因此若是咱们想要使用GPU,咱们真的想要GPU上的全部参数,由于这些参数将会被反复使用在前向传递中产生预测而后在后向传递中更新。每一批特性都必须被传送到GPU内存中。可是中间的和最终的结果(好比隐藏层的输出)只能存在于GPU内存中。咱们须要作的就是不断向GPU发送命令,告诉它如何操做参数和权重。
所以,在API类比中,咱们只作两个“重”请求(在上图中加星标的),一个用于初始化权重,另外一个用于在训练后得到最终权重。但咱们可能会在这两个请求之间发出数百万个轻量级请求来训练模型。
GPU性能的提升是真实的,并且是惊人的
那么什么样的加速是可能的呢?PyTorch有一个不错的MNIST小例子咱们可使用。使用CPU运行10个epoch须要153秒,使用GPU须要83秒。咱们能够从理论上说,更大的模型能够得到更大的收益。 不错,真不错。
一些实验
这一切都很棒。通过一番思考和一些糟糕的绘图以后,我对GPU的了解要好得多,而且所需的额外编码也不错。但个人想法是否正确?回答这个问题的最好方法是创建一个实验。我想向本身证实运输数据是工做流程的“缓慢部分”。因此我尝试了如下三件事:
1.作一个200x200矩阵乘以numpy,一个高度优化的CPU线性代数库。
2.使用PyTorch cuda张量在GPU上进行200x200矩阵乘法运算。
3.使用PyTorch cuda张量在GPU上进行200x200矩阵乘法运算,每次都来回复制数据。
正如预期的那样,GPU只运行得更快,这一次大约是6倍。有趣的是,1和3几乎花费了相同的时间。GPU操做的效率几乎彻底被数据传输的低效所平衡!
本文做者:【方向】
本文为云栖社区原创内容,未经容许不得转载。