- 本章是 Make Your First GAN With PyTorch 的第 4 章,本书的介绍详见这篇文章。
- 本章针对的 神经网络 是指在本书第 2 章建立的数字分类的网络,该网络详见 这篇文章。
- 而且,本文也是基于 Google Colab 开展的,详细情况说明见这篇文章的说明。
在 Make Your Own Neural Network 中明确了如何计算信号穿过一个神经网络,以及如何使用反向传播来更新网络权重。
我们发现这个过程涉及的计算,不用写出几百甚至上千个分立的计算式,而是可以直接写成一个简单的矩阵相乘。而类似于 numpy
的库,可以用于完成矩阵相乘,速度很快效率很高,使用 numpy
来对两个矩阵进行相乘, 比单纯使用 Python 代码完成所需计算的效率更高。
numpy
是 Python 中一种开源的数值计算扩展库,入门介绍可以参见这篇文章。
使用 numpy
对矩阵相乘,避免了在 Python 的软件层的一些复杂操作。同时,numpy
可以直接对矩阵制的存储内存进行操作,同时使用了 CPU 的一些特性,比如并行计算,来提升效率。
下面通过实例,探究一下使用 numpy
的矩阵乘法比直接使用 Python 高效多少。新建一个 notebook 文件并导入 torch
和 numpy
,在一个新的 cell 中输入下面的代码:
# 方形矩阵的尺寸为 size
size = 600
a = numpy.random.rand(size, size)
b = numpy.random.rand(size, size)
上述代码简单创建了两个 numpy
数组,元素值为 0 和 1 之间的随机值,数组的宽度和高度都是 size
,这里设置为 600。
在一个新 cell 中输入下面的代码:
%%timeit
x = numpy.dot(a, b)
其中 %%timeit
是对一个 cell 运行时间进行记录的特殊命令,其他代码则是简单使用 numpy
来对两个数据进行矩阵相乘。
运行该代码,并观察代码运行所需的时间:
- 上面图片中最后一行,说明
%%timeit
命令运行了代码多次,并从中选出最好的时间,以尽量减少其他影响。运行时间的最佳值是 12.7 毫秒,考虑到数组的尺寸很大,这个时间已经相当快了。
下面编写代码,故意不使用 numpy
来完成矩阵相乘,而是使用 Python 从两个矩阵中所有组合的值来构建答案矩阵。
由于代码比较复杂(也比较直接),这里不探讨具体的代码,重要的是这个代码避免了使用
numpy
来完成相乘。
可以看到这个代码使用了 3 分钟 11 秒(191秒),相比之前时间更长。
也就是说,numpy
版本的代码大约快了 1500 倍!
- 需要注意的是,这些计时测试非常简单,但是并不科学,只是一个粗略的比较。如果真的想要比较性能,应该在控制选项的情况下运行更多的测试。
- 但是无论如何,可以看到
numpy
矩阵相乘比纯 Python 的代码要快几个数量级。
相比这里的实验,许多实际的神经网络要大很多,而且处理更多的数据,训练时间可能非常长,即使使用如 numpy
等可以做快速矩阵相乘的库也可能需要几小时、几天甚至几周。
为了寻求更高的速度,机器学习研究人员开始利用一些计算机中的特殊硬件,这些硬件最初是为了提高图形性能而设计的,也就是 “显卡”。
所有的电脑都有 CPU(Central Processing Unit,中央处理器),可以将 CPU 视为我们的大脑,是电脑完成绝大多数工作的主要部件。但是,由于 CPU 是用来完成通用目标的,对各种不同的任务都很擅长。
除了 CPU 外,显卡中包括了 GPU (Graphics Processing Unit,图像处理器)。不同于通用的 CPU,GPU 用于 完成特定任务,其中一个任务是使用并行计算,快速完成包括矩阵相乘在内的算术计算。
下面的图像展示了 CPU 和 GPU 的核心区别:
如果需要做很多的计算,CPU 需要逐个完成计算。现代的 CPU 可能使用 2 个或 4 个核心,甚至 8 个或 16 个核心来完成这些计算,直到最近才有定制的包括了 64 个核心的 CPU 。
但是,GPU 有很多算术核心,现在可能包括数千个,这意味着巨大的工作负载可以分配到这些核心上,而且这些工作可以很快完成。
NVIDIA 在 GPU 市场处于引领地位,并且使用他们的软件工具进行硬件加速已经相当成熟,所以已经成为了机器学习研究中的标准,这个软件框架称之为 CUDA。
- CUDA 的缺点是只能使用 NVIDIA 的 GPU。
- Google Colab 服务允许使用免费的 GPU 来加速计算。Colab 的 GPU 几乎是现有的最强大的,但是 Google 不允许用户连续使用一个 GPU 超过 12 个小时。
为了在 Google Colab 的 Python notebook 中使用 GPU,需要改变一些设定。
在 notebook 文件顶部的选项目录中,选择 Runtime,并选择 Change runtype type:
保持 runtime type 为 Python 3,然后将 硬件加速器(Hardware accelerator) 从 None 改为 GPU。
上述设定将重启 Google 平台的虚拟机,并且增加 GPU 到其中。
我们能做的最简单的事是创建一个运行在 GPU 上的张量。
在本书的开头,我们创建了类似下面的张量:
x = torch.tensor(3.5)
print(x)
这个简单的代码并没有指定张量使用何种类型的数字,所以使用了默认的float32 类型。实际上 numpy
有很多数据类型的选项,如整型变量为 int32,浮点型数据为 float32,甚至可以使用 float64 获得更高的精度。
如果想要数据类型更具体,可以写成下面形式:
x = torch.FloatTensor([3.5])
简单使用 x.type()
来检查类型,可以看到类型为 torch.FloatTensor
:
为了在 GPU 上创建张量,可以将类型更改为 torch.cuda.FloatTensor
。
可以看到类型已经被更改了:
使用 GPU 上的张量很简单,很多情况下与正常使用 PyTorch 没有区别:
# 使用 GPU 上的张量进行计算
y = x * x
y
观察结果:
计算并不是由 CPU,而是由 GPU 完成的,获得的结果也是 GPU 上的张量。
- 这看起来只是一个很小的成就,但实际上很难得。特别是过去使用 GPU 加速非常困难,现在用很简单的语句就能实现。
- 其实,刚完成的简单计算并不能从 GPU 强大的功能中收益。为了从 GPU 中获益,需要很多的数据,并将数据分为不同部分提供给 GPU 核心。
下面来使用之前使用的 600*600 的矩阵来创建 CUDA 张量,并在 GPU 上完成矩阵相乘:
aa = torch.cuda.FloatTensor(a)
bb = torch.cuda.FloatTensor(b)
PyTorch 函数中用来完成等效矩阵相乘的函数是 matmul()
:
cc = torch.matmul(aa, bb)
在一个单独的 cell 中进行计时:
- 可以看到,使用 GPU 计算使用了 74.4 微秒。不是 毫秒,而是 微秒。这非常快!
尽管并不严格,但这个简单的测试确实显示出使用 CUDA 进行矩阵相
乘比使用 numpy
快了 150 倍。
使用不同的矩阵尺寸完成上述实验,可以对 CPU 和 GPU 的性能有更好的比较。
下面的图像展示了 numpy
和 CUDA 对矩阵尺寸为 100 到 2000 的矩阵相乘的时间。
- 可以看到随着矩阵增大,
numpy
速度降低(所需时间增加),使用 CUDA 的计算速度虽然也有所降低。但是在这种规模下,GPU 速度非常非常快!- 该图表确实显示了 GPU 处理大量数据的好处,这些数据可以分解成大块并开展并行计算。
对于少量数据,可能会惊讶地发现 GPU 可能会变慢。这是因为在单独的计算中, GPU 并不总是比 CPU 快,而且在 CPU 和 GPU 之间移动数据也要付出代价。仅当可以利用许多计算核心时(拥有足够的数据时),GPU 才有优势。
下面介绍一些代码,这些代码已经成为检查 CUDA 是否可用的标准方法:
if torch.cuda.is_available():
torch.set_default_tensor_type(torch.cuda.FloatTensor)
print("using cuda:", torch.cuda.get_device_name(0))
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
上述代码使用 torch.cuda.is_available()
进行简单检查。如果 CUDA 可用,就将默认的张量类型设置为 torch.cuda.FloatTensor
,并输出 CUDA 发现的设备类型。
代码同时设定了一个 PyTorch device
变量,使得在非默认情况下,方便
地将数据转移到 GPU 中。同时,如果 CUDA 不可用, device
将指向 CPU。
下面来试一下代码,观察 CUDA 可以发现的设备:
- 可以看到 CUDA 设备是一个 Tesla P100,这个硬件非常强大和昂贵。
- GPU包括了很多计算核心,使用高并行方法来完成特定的计算。最早 GPU 是用来加速计算机图像的,现在随着机器学习计算量的增加,对 GPU 的使用也在增加;
- CUDA 是 NVIDIA 用来GPU 加速计算的编程框架。PyTorch 使得不大幅度改变代码形式的情况下可以简单的使用 CUDA;
- 在综合基准上来看,比如矩阵相乘,GPU 比 CPU 的性能可以高出150 倍以上;
- 单次计算中,GPU 可能比 CPU 更慢。在 CPU 和 GPU 之间传递数据也有时间消耗,如果数据不能广泛分配到很多核心上,使用 GPU 可能没有多少甚至没有任何优势。