2.11 向量化
这篇文章我们来讲向量化,这需要你有一定的python知识,不然听了缺少实践也不好。当然你一定是能够听懂的。
向量化是非常基础的去除代码中 for 循环的艺术,在深度学习安全领域、深度学习实践
中,你会经常发现自己训练大数据集,因为深度学习算法处理大数据集效果很棒,所以你的
代码运行速度非常重要,否则如果在大数据集上,你的代码可能花费很长时间去运行,你将
要等待非常长的时间去得到结果。
那么为什么用向量化的效率会高呢?
向量化是利用NumPy等库提供的高效数组操作来替代显式的循环。NumPy等库的底层实现是用C语言编写的,因此在处理数组操作时非常高效。
import numpy as np #导入 numpy 库
a = np.array([1,2,3,4]) #创建一个数据
print(a)
# [1 2 3 4]
import time #导入时间库
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 循环的版本的时
间
这里我们来具体感受一下,向量化到底有什么魅力。
在两个方法中,向量化和非向量化计算了相同的值,如你所见,向量化版本花费了 1.5 毫秒,非向量化版本的 for 循环花费了大约几乎 500 毫秒,非向量化版本多花费了 300 倍时 间。所以在这个例子中,仅仅是向量化你的代码,就会运行 300 倍快。这意味着如果向量化方法需要花费一分钟去运行的数据,for 循环将会花费 5 个小时去运行。
一句话总结,以上都是再说和 for 循环相比,向量化可以快速得到结果。
你可能听过很多类似如下的话,“大规模的深度学习使用了 GPU 或者图像处理单元实
现”,但是我做的所有的案例都是在 jupyter notebook 上面实现,这里只有 CPU,CPU 和 GPU
都有并行化的指令,他们有时候会叫做 SIMD 指令,这个代表了一个单独指令多维数据。这
个的基础意义是,如果你使用了 built-in 函数,像 np.function 或者并不要求你实现循环的。
它可以让 python 的充分利用并行化计算,这是事实在 GPU 和 CPU 上面计算,GPU 更加擅长 SIMD 计算,但是 CPU 事实上也不是太差,可能没有 GPU 那么擅长吧。
2.13 向量化逻辑回归
我们已经讨论过向量化是如何显著加速你的代码,在这里我们将讨论如何实现逻辑回归的向量化计算。
这样就能处理整个数据集,甚至不会用一个明确的 for 循环就能实现对于整个数据集梯度下降算法的优化,并且当我们后面谈到神经网络时同样也不会用到一个明确的 for 循环。
可以想象,这项技术是多么伟大。
从这幅图中也不难见得我们的意图,本质上,我们就是将一连串的数据变成了一些行向量和列向量,再通过矩阵化的乘法,从而对一组数据进行计算训练,比显性的for循环快速很多。但是在这边,我们先了解一下广播和前向传播。
广播
在深度学习中,广播(Broadcasting)是一种强大的技术,它允许不同形状的数组进行算术运算。广播机制使得在处理张量(多维数组)时更加灵活和高效。这种机制在许多深度学习框架中都有实现,如NumPy、TensorFlow和PyTorch。
广播的核心思想是自动扩展较小的数组,使其与较大的数组具有相同的形状,从而可以进行逐元素操作。具体规则如下:
维度对齐:如果两个数组的维度不同,较短的数组会在其形状前面添加1,直到两个数组的维度相同。
尺寸匹配:对于每个维度,如果两个数组的尺寸相同或其中一个为1,则可以进行广播。如果某个维度的尺寸不匹配且都不为1,则无法进行广播。
看起来很难理解,但其实你就理解为向量的加减,只不过拥有限制,同类人才能加减。也就是说,要么0向量那一定可以进行广播,要么长度相同来叠加,才能广播。
import numpy as np
# 一维数组与标量
a = np.array([1, 2, 3])
b = 2
result = a + b # 结果是 [3, 4, 5]
# 二维数组与一维数组
A = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([1, 0, -1])
result = A + b # 结果是 [[2, 2, 2], [5, 5, 5]]
# 三维数组与二维数组
A = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
B = np.array([[1, 2], [3, 4]])
result = A + B # 结果是 [[[2, 4], [6, 8]], [[6, 8], [10, 12]]]
这里放一下具体实现,可能代码会更容易理解。
前向传播
前向传播(Forward Propagation)是深度学习中神经网络的核心过程之一。它是指从输入层开始,通过每一层的计算,最终得到输出层的结果。前向传播是训练和推理过程中必不可少的步骤。
也就是说,我们从第一节课的房价预测开始,就已经一直在使用这个前向传播了。他里面包括输入层、隐层和输出层。
下面是一个使用Python和NumPy实现的简单全连接神经网络的前向传播过程:看不懂就跳过,但是要大致理解思路
import numpy as np
# 定义激活函数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# 定义输入数据
x = np.array([0.1, 0.2, 0.3])
# 初始化权重和偏置
W1 = np.random.randn(4, 3) # 4个隐藏单元,3个输入特征
b1 = np.random.randn(4, 1)
W2 = np.random.randn(2, 4) # 2个隐藏单元,4个输入特征
b2 = np.random.randn(2, 1)
W3 = np.random.randn(1, 2) # 1个输出单元,2个输入特征
b3 = np.random.randn(1, 1)
# 前向传播
z1 = np.dot(W1, x) + b1
h1 = sigmoid(z1)
z2 = np.dot(W2, h1) + b2
h2 = sigmoid(z2)
z3 = np.dot(W3, h2) + b3
y = sigmoid(z3)
print("Output:", y)
好了,感谢阅读,我们下篇文章见!