DeepLearing学习笔记-数据矢量化

背景:

通过矢量化提高矩阵运算速度

准备知识:

dot/outer/elementwise product 的区别:

dot product 点乘:

向量点积:
向量的点乘,也叫向量的内积、数量积,对两个向量执行点乘运算,就是对这两个向量对应位一一相乘之后求和的操作,点乘的结果是一个标量。
定义: ab=||a||||b||cos(θ) ,即是两个向量的模和两向量夹角余弦的乘积。
点乘的几何意义是可以用来表征或计算两个向量之间的夹角,以及在b向量在a向量方向上的投影。
矩阵内积:
内积是一种降维运算,变成一个数。矩阵的内积是每行每列的点积所组成的矩阵。所以,点积是一维向量之间的操作,内积是多维向量,即矩阵的操作。两者本质是一样的。其实,内积就是我们一般常用的矩阵乘积,行列进行相互乘积,作为结果矩阵指定位置的元素结果值。所以,要求a矩阵的列数量等于b矩阵的行数量。
示例代码:

x = numpy.array([1, 2])
y = numpy.array([10, 20])
print("Array inner:")
print(numpy.inner(x, y))
''' Output:
Array inner:
50
'''

x = numpy.mat([[1, 2], [3, 4]])
y = numpy.mat([10, 20])
print("Matrix inner:")
print(numpy.inner(x, y))
Output:
Matrix inner:
[[ 50]
 [110]]

outer product 外积:

两个向量的叉乘,又叫向量积、外积、叉积,叉乘的运算结果是一个向量而不是一个标量,是向量的升维运算。并且两个向量的外积与这两个向量组成的坐标平面垂直。m维向量和n维向量的外积是m*n维矩阵。
定义:
a×b
矩阵外积:
假设a的维度是(m,n),b的维度是(p,q)
a×b=a11...a1m.........a1m...amnb11...b1p.........b1q...bpq=a11b11...a1nb11a21b11...amnb11..................a11b1q...a1nb1qa21b1q...amnb1qa11b21...a1nb21a21b21...amnb21..................a11bpq...a1nbpqa21bpq...amnbpq(1)
向量外积:
a=(x1,y1,z1)
b=(x2,y2,z2)
a×b=ix1x2jy1y2kz1z2=(y1z2y2z1)i(x1z2x2z1)j+(x1y2x2y1)k(2)
其中:
i=(1,0,0)j=(0,1,0)k=(0,0,1)
叉乘几何意义:
在三维几何中,向量a和向量b的叉乘结果是一个向量,更为熟知的叫法是法向量,该向量垂直于a和b向量构成的平面。
在二维空间中,叉乘还有另外一个几何意义就是:aXb等于由向量a和向量b构成的平行四边形的面积。

示例代码:

x = numpy.array([1, 3])
y = numpy.array([10, 20])
print("Array outer:")
print(numpy.outer(x, y))
''' Output:
Array outer:
[[10 20]
 [30 60]]
'''

x = numpy.mat([[1, 2], [3, 4]])
y = numpy.mat([10, 20])
print("Matrix outer:")
print(numpy.outer(x, y))
Output:
Matrix outer:
[[10 20]
 [20 40]
 [30 60]
 [40 80]]

elementwise product 元素积:

定义:
ab
有三种情况:
ab=[a1am][b1...bm](3)

ab=[a1an]b1b2...bm =a1b1...a1bm.........anb1...anbm(4)
第三种情况,就是两个矩阵尺寸相同,则是对应位置的元素乘积。

示例代码:

x = numpy.array([1, 3])
y = numpy.array([10, 20])
print("Array element-wise product:")
print(x * y)

输出:
Array element-wise product:
[10 60]

矢量化操作:

循环实现矩阵运算:

import time

x1 = [9, 2, 5, 0, 0, 7, 5, 0, 0, 0, 9, 2, 5, 0, 0]
x2 = [9, 2, 2, 9, 0, 9, 2, 5, 0, 0, 9, 2, 5, 0, 0]
#用循环来实现dot product
### CLASSIC DOT PRODUCT OF VECTORS IMPLEMENTATION ###
tic = time.process_time()
dot = 0
for i in range(len(x1)):
    dot+= x1[i]*x2[i]
toc = time.process_time()
print ("dot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")

#用循环来实现outer product
### CLASSIC OUTER PRODUCT IMPLEMENTATION ###
tic = time.process_time()
outer = np.zeros((len(x1),len(x2))) # we create a len(x1)*len(x2) matrix with only zeros
for i in range(len(x1)):
    for j in range(len(x2)):
        outer[i,j] = x1[i]*x2[j]
toc = time.process_time()
print ("outer = " + str(outer) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")

#用循环来实现 元素之间乘积
### CLASSIC ELEMENTWISE IMPLEMENTATION ###
tic = time.process_time()
mul = np.zeros(len(x1))
for i in range(len(x1)):
    mul[i] = x1[i]*x2[i]
toc = time.process_time()
print ("elementwise multiplication = " + str(mul) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")

#用循环来实现泛化的点积,即内积。
### CLASSIC GENERAL DOT PRODUCT IMPLEMENTATION ###
W = np.random.rand(3,len(x1)) # Random 3*len(x1) numpy array
tic = time.process_time()
gdot = np.zeros(W.shape[0])
for i in range(W.shape[0]):
    for j in range(len(x1)):
        gdot[i] += W[i,j]*x1[j]
toc = time.process_time()
print ("gdot = " + str(gdot) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")

执行结果:

dot = 278
 ----- Computation time = 0.0ms
outer = [[ 81.  18.  18.  81.   0.  81.  18.  45.   0.   0.  81.  18.  45.   0.
    0.]
 [ 18.   4.   4.  18.   0.  18.   4.  10.   0.   0.  18.   4.  10.   0.
    0.]
 [ 45.  10.  10.  45.   0.  45.  10.  25.   0.   0.  45.  10.  25.   0.
    0.]
 [  0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.
    0.]
 [  0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.
    0.]
 [ 63.  14.  14.  63.   0.  63.  14.  35.   0.   0.  63.  14.  35.   0.
    0.]
 [ 45.  10.  10.  45.   0.  45.  10.  25.   0.   0.  45.  10.  25.   0.
    0.]
 [  0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.
    0.]
 [  0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.
    0.]
 [  0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.
    0.]
 [ 81.  18.  18.  81.   0.  81.  18.  45.   0.   0.  81.  18.  45.   0.
    0.]
 [ 18.   4.   4.  18.   0.  18.   4.  10.   0.   0.  18.   4.  10.   0.
    0.]
 [ 45.  10.  10.  45.   0.  45.  10.  25.   0.   0.  45.  10.  25.   0.
    0.]
 [  0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.
    0.]
 [  0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.   0.
    0.]]
 ----- Computation time = 0.0ms
elementwise multiplication = [ 81.   4.  10.   0.   0.  63.  10.   0.   0.   0.  81.   4.  25.   0.   0.]
 ----- Computation time = 0.0ms
gdot = [ 17.02350757  18.34972831  15.85377834]
 ----- Computation time = 0.0ms

上述的运行结果,并没有很直观表现循环操作的耗时,这是因为测试时候选用的数据量少的缘故。

基于numpy的矢量化矩阵运算

x1 = [9, 2, 5, 0, 0, 7, 5, 0, 0, 0, 9, 2, 5, 0, 0]
x2 = [9, 2, 2, 9, 0, 9, 2, 5, 0, 0, 9, 2, 5, 0, 0]

### VECTORIZED DOT PRODUCT OF VECTORS ###
tic = time.process_time()
dot = np.dot(x1,x2)
toc = time.process_time()
print ("dot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")

### VECTORIZED OUTER PRODUCT ###
tic = time.process_time()
outer = np.outer(x1,x2)
toc = time.process_time()
print ("outer = " + str(outer) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")

### VECTORIZED ELEMENTWISE MULTIPLICATION ###
tic = time.process_time()
mul = np.multiply(x1,x2)
toc = time.process_time()
print ("elementwise multiplication = " + str(mul) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")

### VECTORIZED GENERAL DOT PRODUCT ###
tic = time.process_time()
dot = np.dot(W,x1)
toc = time.process_time()
print ("gdot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")

运行结果:

dot = 278
 ----- Computation time = 0.0ms
outer = [[81 18 18 81  0 81 18 45  0  0 81 18 45  0  0]
 [18  4  4 18  0 18  4 10  0  0 18  4 10  0  0]
 [45 10 10 45  0 45 10 25  0  0 45 10 25  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [63 14 14 63  0 63 14 35  0  0 63 14 35  0  0]
 [45 10 10 45  0 45 10 25  0  0 45 10 25  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [81 18 18 81  0 81 18 45  0  0 81 18 45  0  0]
 [18  4  4 18  0 18  4 10  0  0 18  4 10  0  0]
 [45 10 10 45  0 45 10 25  0  0 45 10 25  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]]
 ----- Computation time = 0.0ms
elementwise multiplication = [81  4 10  0  0 63 10  0  0  0 81  4 25  0  0]
 ----- Computation time = 0.0ms
gdot = [ 17.02350757  18.34972831  15.85377834]
 ----- Computation time = 0.0ms

采用矢量化的方式执行,结果更加简洁高效(数据量大时候,更加明显)。且对于np.dot是可以适用于矩阵或者矩阵向量的。对应元素的乘积,可以用np.multiply()或者*操作符。

循环方式和矢量化速度对比:

import time
import numpy as np
a = np.random.rand(1000000)
b = np.random.rand(1000000)
tic = time.time()
c = np.dot(a,b)
print(c)
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("loop version:" + str(1000*(toc-tic)) + "ms")

运行结果如下:

250375.165705
vectorized version:24.0023136138916ms
250375.165705
loop version:543.0543422698975ms

你可能感兴趣的:(Python)