概述
本篇属于理论篇,你将了解什么是向量化、向量化对神经网络训练优化的重要性,以及如何向量化 Logistic 回归及其梯度输出。
转自猴开发博客:深度学习(二)向量化 Logistic 回归及其梯度输出
2.0 向量化概述
在前面,你已经认识了 Logistic 回归,并且对梯度下降以及梯度下降是如何工作的有了一个具体的认知。如果你有认真阅读第一篇的话,相信你还记得在第一篇中曾经提到过一个矩阵 X X X,它表示将所有的输入样本在水平方向上堆叠起来,也就是下面这个样子:
为了在后面方便说明,这里将每一个输入样本的下标也标示出来,这样你将看到公式(1)更加完整的形式:
为了确保你明白公式(2)中每一个角标的含义,在这里特别说明一下,使用小括号括起来的上标表示的是样本的编号,而没有用括号括起来的下标代表的是样本的某一个输入,例如对于符号 x n x ( 2 ) x^{(2)}_{n_x} xnx(2),它所代表的是训练集中第2个训练样本的第 n x n_x nx 个输入,因为 n x n_x nx 是指输入的总个数,所以 x n x ( 2 ) x^{(2)}_{n_x} xnx(2) 表示的就是第2个训练样本的最后一个输入。
将原本独立的一个个样本组合在一起,构成一个新的矩阵,其实这就是向量化。你可能要问,在上篇中已经实现了 Logistic 回归,使用 x x x 表示单个样本,在对所有样本逐个计算就足够了,为什么还要使用向量化引入一个样本矩阵 X X X?
2.1 非向量化与向量化实例
试想,如果给你一个给你 1000000 个数据 a 1 a_1 a1~ a 1000000 a_{1000000} a1000000,以及 1000000 个数据 b 1 b_1 b1~ b 1000000 b_{1000000} b1000000,要你求每一对 a i a_i ai 和 b i b_i bi 相乘的结果的总和 c c c,你会怎么做?
在接触向量化之前,你应该会想到使用 for 循环,将 a i a_i ai 与 b i b_i bi 的乘积依次相加,就可以得到结果 c c c 了,我们来试一下。
使用 for 循环
import numpy as np
import time as t
# 生成 1000000 随机数据
a = np.random.rand(1000000)
b = np.random.rand(1000000)
# for 循环版本
c = 0
# 开始计时
startTime = t.time()
# 循环计算
for i in range(1000000):
c += a[i]*b[i]
# 停止计时
deltaTime = t.time() - startTime
# 输出结果与耗时情况
print("计算结果:" + str(c) + ", for 循环计算耗时:" + str(1000 * deltaTime) + "ms")
以上是使用 for 循环完成要求计算的 python 代码,输出结果是:
计算结果:249879.05298545936, for 循环计算耗时:519.999980927ms
使用向量化
# 向量化版本
c = 0
# 开始计时
startTime = t.time()
#矩阵计算
c = np.dot(a,b)
# 停止计时
deltaTime = t.time() - startTime
# 输出结果与耗时情况
print("计算结果:" + str(c) + ", 矩阵计算耗时:" + str(1000 * deltaTime) + "ms")
以上是使用向量化完成要求计算的 python 代码,输出结果是:
计算结果:249879.05298545936, 矩阵计算耗时:0.999927520752ms
进行多次计算,可以绘制出 for 循环与向量化计算的耗时对比图:
实在是令人惊喜,正如你所看到的,向量化版本没有使用 for 循环就正确完成了所有计算,并且计算的代码量只有一行,而仅针对简单的乘法与加法运算而言,向量化计算的效率就要比 for 循环高出 500 倍上下,在其他更加复杂的运算下,这个差距还会拉得更大。可以看到,无论从简洁性还是从效率的角度讲,向量化计算几乎是完美的。
因此,不管是在什么算法当中,如果能够不使用 for 循环就尽量不要使用 for 循环,其效率实在是太糟糕了。在神经网络的训练过程中,效率显得尤为重要,面对数量巨大的训练样本,向量化你的模型是非常有必要的,它能够大量地节约你的时间去做更多的训练,或是做参数的调整。
2.2 向量化 Logistic 回归
在前面你已经见识到了向量化威力,通过向量化你能够实现数据的并发计算,进而为你节约大量的时间。下面,我将用伪代码给出 Logistic 回归非向量化版本,即使用 for 循环编码实现上一篇当中的理论模型,你可以直接阅读代码,并思考如何向量化这个过程。
for 循环版本
1 | f o r for for i i i = = = 1 1 1 t o to to m m m
2 | { \{ {
3 | z ( i ) z^{(i)} z(i) = = = w T x ( i ) w^Tx^{(i)} wTx(i) + + + b b b # 计算线性输出
4 | a ( i ) a^{(i)} a(i) = = = σ ( z ( i ) ) \sigma(z^{(i)}) σ(z(i)) # 映射到 [ 0 , 1 ] [0,1] [0,1]
5 | J J