[DeeplearningAI 笔记]第一章2.11-2.16 向量化与 python/numpy 向量说明

2020-08-14 10:46:55 浏览数 (1)

2.11 向量化

  • 向量化是消除代码中显示 for 循环语句的艺术,在训练大数据集时,深度学习算法才变得高效,所以代码运行的非常快十分重要.所以在深度学习领域中将大数据集进行向量化操作变得十分重要.
  • 对于非向量化数据的计算,我们会使用循环去遍历整个数据集计算对应项的乘积.例如我们要计算一个数据样本,其中 w 和 b 都是一个 n 维向量,计算式子:
Z=W^{T} b

那么我们的式子会写为:

代码语言:javascript复制
z=0
for i in range(n-x)
z =w[i]*x[i]
z =b
  • 但是这种计算方法就十分慢.如果我们使用向量化的方法,我们的语句会写为
代码语言:javascript复制
z=np.dot(w,x) b
  • tips:jupyter notebook 中 cell 的运行与输出结果可以直接使用 Shift Enter 运行代码并且将结果输出.
  • 这时我们使用 jupyter notebook 去计算一下两个百万级的数据相乘后花了多少时间
代码语言:javascript复制
import numpy as np
import time
a = np.random.rand(1000000)
b = np.random.rand(1000000)
# 向量化版本
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("For loop:"  str(1000*(toc-tic))   "ms")

  • 经过试验我们看出非向量化版本比向量化版本多计算了大约 300 倍的时间. 对于大多数深度学习来说,可扩展的深度学习实现是在 GPU(图像处理单元)上做的,GPU 和 CPU 都有并行化的指令.也叫做 SIMD 指令(单指令流多数据流).GPU 比 CPU 更加擅长 SIMD 指令,但是 CPU 也不差.总体而言向量化能够加速你的代码.经验法则是只要有其他可能,就不要使用显示 for 循环.

2.16 python/numpy 向量说明

  • python 语言有很高的灵活性,这是一种优势也是一种劣势,总体来说这是 python 语言的优势,这让 python 语言的表现力更强.但是这也是一个劣势,有时会出现一些非常细微的错误和非常奇怪的错误,特别是当你不熟悉 python 语言和 numpy 广播运作的方式时.例如如果你想用一个列向量把它加到一个行向量上,你可能会认为维度不匹配或者是类型错误等等错误,但实际上这是可以执行的,实际上会得到一个行向量和一个列向量求和之后的矩阵.
代码语言:javascript复制
import numpy as np
a = np.random.randn(5)
# 生成五个随机高斯变量,存储在数组a中
代码语言:javascript复制
print(a)
代码语言:javascript复制
[-1.17703191 -0.67152812  0.07475093  0.36539824 -0.07583196]
代码语言:javascript复制
print(a.shape)
代码语言:javascript复制
(5,)
代码语言:javascript复制
# (5, )的shape即是python中秩为1的数组
# 它既不是行向量也不是列向量,这导致他有一些不直观的效果
# 例如,如果我们将a.T也写出来,即a矩阵的转置形式,这时候看起来还是和a一样的.
# 这是一种很奇特的结构,在编写程序一定要避免
print(a.T)
代码语言:javascript复制
[-1.17703191 -0.67152812  0.07475093  0.36539824 -0.07583196]
代码语言:javascript复制
# 所以这时候发现a和a的转置看起来是一样的,这时候我们print a和a的转置的内积
# 我们会认为a和a的转置相乘,按理说应该被称为矩阵的外积,也就说应该会得到一个矩阵
# 但是实际上我们得到的是一个数字
print(np.dot(a, a.T))
代码语言:javascript复制
1.98120819241
代码语言:javascript复制
# 所以我们建议在编写神经网络时不要使用形状是(5,)或者(n,)这种秩为1的数组
# 我们应该显示的使用shape为(n,1)的向量
a = np.random.rand(5, 1)
# 这时候我们得到是5行1列的向量
print(a)
代码语言:javascript复制
[[ 0.74009072]
 [ 0.03667174]
 [ 0.91847869]
 [ 0.15726344]
 [ 0.41720873]]
代码语言:javascript复制
# 并且这时a.T已经变成一个行向量了
print(a.T)
# 注意在这个数据结构中有两个方括号
print(a.T.shape)
代码语言:javascript复制
[[ 0.74009072  0.03667174  0.91847869  0.15726344  0.41720873]]
(1, 5)
代码语言:javascript复制
# 并且这时候我们计算 a 和 a的转置的内积
print(np.dot(a, a.T))
# 会得到一个向量的外积
代码语言:javascript复制
[[ 0.54773428  0.02714041  0.67975756  0.11638921  0.30877231]
 [ 0.02714041  0.00134482  0.03368221  0.00576712  0.01529977]
 [ 0.67975756  0.03368221  0.84360311  0.14444312  0.38319733]
 [ 0.11638921  0.00576712  0.14444312  0.02473179  0.06561168]
 [ 0.30877231  0.01529977  0.38319733  0.06561168  0.17406313]]
  • 如果在实际操作中还是得到了一个秩为 1 的向量,不要犹豫,你可以使用 reshape 操作,将其转化成一个 15 或者是 51 的数组
  • 并且在程序编写的过程中可以适当使用 assert 语句,确保向量的形状是自己所需要的.

参考资料

[1]

吴恩达老师课程原地址: https://mooc.study.163.com/smartSpec/detail/1001319001.htm

0 人点赞