【深度学习实战】向量化技术 实现 CPU/GPU并行计算
本文主要介绍的是,当我们 实践应用深度学习算法,去具体实现,大网络(网络的参数个数 很大)多样本(样本数量 很大) 情形下的计算处理时,如何通过向量化的方式,使得代码更加简化,计算更加高效。
举个栗子
拿逻辑回归中 的计算举例,、都是列向量,维度为 。如果你有很多的特征,那么就会有一个非常大的向量。
非向量化(for循环)做法
如果按照正常的非向量化的编程逻辑,实现思路如下(Python)。
z = 0
for i in range(n_x):
z += w[i] * x[i]
z += b
向量化做法
作为对比,向量化的实现能够非常直接地实现 的计算。
z = np.dot(w, x) + b
除了代码简洁化之外,向量化还能够通过,我们看下面的例子。
import time # 导入时间库
import numpy as np # 导入numpy库
a = np.array([1, 2, 3, 4]) # 创建一个数据a
print(a)
# [1 2 3 4]
a = np.random.rand(1000000)
b = np.random.rand(1000000) # 通过round随机得到两个一百万维度的数组
tic = time.time() # 现在测量一下当前时间
# 向量化的版本
c = np.dot(a, b)
toc = time.time()
print("Vectorized version:" + str(1000 * (toc - tic)) + "ms") # 打印一下向量化的版本的时间
# 继续增加非向量化的版本
c = 0
tic = time.time()
for i in range(1000000):
c += a[i] * b[i]
toc = time.time()
print(c)
print("For loop:" + str(1000 * (toc - tic)) + "ms") # 打印for循环的版本的时间
运行结果如下图:
在上面的代码中,使用两个方法——向量化和非向量化,进行了相同的计算,向量化版本花费了0.968毫秒,而非向量化版本的 for 循环花费了327.997毫秒,非向量化版本花费的时间多了300多倍。这意味着如果向量化方法需要花费一分钟去运行的数据,使用 for 循环将会花费5个小时去运行。
所以我们可以很直观地看出,向量化有多快。
向量化快速计算背后的原因
你可能听过很多类似如下的话,“大规模的深度学习使用了GPU或者图像处理单元实现”。但其实上面的示例我只用了CPU去实现。
事实上,CPU和GPU都有并行化的指令,他们有时候会叫做SIMD指令,这个代表了一个单独指令处理多维数据(GPU更加擅长SIMD计算,CPU虽不及GPU,不过事实上也不是太差)。这个基础的意义在于,如果你使用一些built-in函数,比如np.function
或者其它不要求你实现循环的函数,它可以让python的充分利用CPU或者GPU的并行化计算能力。
向量化的实现方式
我们主要可以通过 numpy内置函数 和 避开显式的循环(loop) 的方式进行向量化。
根据经验,在写神经网络程序时,应该避免写 循环(loop) 语句。不过有的 循环(loop) 还是不可避免的,比如需要多次迭代进行梯度下降。
向量化的具体例子
对向量中每个元素进行数学运算
比如做指数操作。
非向量化方法:初始化向量 ,然后通过循环依次计算每个元素
向量化方法:通过 python 的 numpy 内置函数,执行 u=np.exp(v)
命令
事实上,numpy库有很多向量函数。比如 u=np.log
是按元素计算对数函数、 np.abs()
是按元素取绝对值、np.maximum()
计算元素中的最大值,np.maximum(v, 0)
是计算每个元素和0相比的最大值,v**2
是计算每个元素的平方、 1/v
是计算每个元素的倒数等等。
神经网络的前向传播(以逻辑回归举例)
假设我们需要对 m 个训练样本进行前向传播运算。
如果是非向量化的正常做法,我们挨个样本地进行计算,首先要对第一个样本进行预测,,计算**函数 ,再计算第一个样本的预测值 。然后对第二个样本进行预测,第三个样本,依次类推。。。 个训练样本,就需要这样重复做 次。
使用向量化的做法,我们可以将训练输入定义成一个 行 列的矩阵 的形式,即一个形状的numpy数组。同样,我们构建一个 的行向量 用来存储 ,然后 就可以通过下面的方式求得。
以上操作就可以通过 一句 numpy 命令来实现。
同样的,从 到 我们也可以使用向量方式来实现统一的 sigmoid函数 运算。
神经网络的梯度下降(以逻辑回归举例)
那么,要如何同时计算 个数据的梯度?
根据 和 的梯度计算公式:
其中, , …
那么,我们可以将所有的 按列堆叠(横向排列),定义一个 形状的新的变量 。再定义 ,则 。
那么很容易就能得到 的向量化代码,
对于,为了更直观,我们先将其展开,得到
则 的向量化代码
最终我们得到高度向量化的,高效的,完整的逻辑回归的实现
前五个公式完成了前向和后向传播,后两个公式进行梯度下降更新参数。
个人小结
- 在进行神经网络的具体实现时,要学会通过向量化,进行简化表示,简化代码和运算加速
- 简单来说,向量化其实就是用 转化为向量,矩阵运算的形式 来对多参数多样本的运算进行统一的概括的表示,同时还能够利用到CPU/GPU的并行计算能力
- 在进行向量化之前,首先把 深度的学习符号表示,以及 基本的单个样本的前向后向的计算流程 掌握清楚
吴恩达 DeepLearning.ai