部分DL笔记
P17 Vectorization
什么是Vectorization?
- 在Logistic Regression中,我们需要去计算
$$
z = w^Tx + b\
w =
\begin{bmatrix}
. \
. \
.
\end{bmatrix}_{n1}
x =
\begin{bmatrix}
. \
. \
.
\end{bmatrix}_{n*1},w\in R^{n_x}
$$
如果有很多特征,那么他们就是非常大的向量,所以w和x都是R内的nX维向量
- 在Logistic Regression中,我们需要去计算
在Python或Numpy中,使用
z = np.dot(w,x)+b
来计算上面的式子,并且比使用for loop来计算快得
P18 More vectorization examples
上一节课学习了如何向量化,如何使用内置函数,避免使用显式for loop,能不使用它就不要去使用。这样可以使得程序运行速度显著加快,让我们再看几个例子。
让v向量转化为u向量
$$
v = \begin{bmatrix}
v_1 \
.\
.\
.\
v_n
\end{bmatrix},
u = \begin{bmatrix}
e^{v_1} \
.\
.\
.\
e^{v_n}
\end{bmatrix}
$$
- 一种非向量化的实现
1 |
|
注释:np.zeros()
返回来一个给定形状和类型的用0填充的数组
zeros(shape, dtype=float, order=‘C’)
shape:形状
dtype:数据类型,可选参数,默认numpy.float64
order:可选参数,c代表与c语言类似,行优先;F代表列优先
1 |
|
- 利用numpy实现
1 |
|
numpy的其他方法
需要是np.array()
创建的vector
np.log()
:返回对所有元素取对数之后的向量np.abs()
:返回对所有元素取绝对值之后的向量np.maximum()
:返回向量中所有元素和0相比的最大值v**2
:返回对所有元素取平方之后的向量1/v
:返回对所有元素取倒数之后的向量np.dot()
:函数主要功能有两个——向量点积和矩阵乘法向量点积:如果处理的是一维数组,则得到的是两数组的內积。
例1:
1
2
3
4
5
6import numpy as np
x=np.array([0,1,2,3,4])#等价于:x=np.arange(0,5)
y=x[::-1]
print x
print y
print np.dot(x,y)输出:
1
2
3[0 1 2 3 4]
[4 3 2 1 0]
10例2:
1
2
3
4
5
6import numpy as np
x=np.arange(0,5)
y=np.random.randint(0,10,5)
print x
print y
print np.dot(x,y)输出:
1
2
3[0 1 2 3 4]
[5 1 0 9 2]
36如果是二维数组(矩阵)之间的运算,则得到的是矩阵积
1.np.dot(x, y), 当x为二维矩阵,y为一维向量,这时y会转换一维矩阵进行计算
首先,我们来看一下一维向量和一位矩阵的不同
例3:
1
2
3
4
5
6
7
8
9
10import numpy as np
x=np.arange(0,5)
# 0,10,是随机数的方位,size=(5,1),也就是5维矩阵,且每一维元素数为1个
y=np.random.randint(0,10,size=(5,1))
print x
print y
# 查看矩阵或者数组的维数
print "x.shape:"+str(x.shape)
print "y.shape"+str(y.shape)
print np.dot(x,y)输出:
1
2
3
4
5
6
7
8
9[0 1 2 3 4]
[[3]
[7]
[2]
[8]
[1]]
x.shape:(5,)
y.shape(5, 1)
[39]可以看出一维向量的shape是(5, ), 而一维矩阵的shape是(5, 1), 若两个参数x和y中有一个是矩阵时(包括一维矩阵),dot便进行矩阵乘法运算,同时若有个参数为向量,会自动转换为一维矩阵进行计算。
2.np.dot(x, y)中,x、y都是二维矩阵,进行矩阵积计算
np.dot(x, y)两个二维矩阵满足第一个矩阵的列数与第二个矩阵的行数相同,那么可以进行矩阵的乘法,即矩阵积
例4:1
2
3
4
5
6
7
8import numpy as np
x=np.arange(0,6).reshape(2,3)
y=np.random.randint(0,10,size=(3,2))
print x
print y
print "x.shape:"+str(x.shape)
print "y.shape"+str(y.shape)
print np.dot(x,y)输出:
1
2
3
4
5
6
7
8
9[[0 1 2]
[3 4 5]]
[[7 5]
[0 7]
[6 2]]
x.shape:(2, 3)
y.shape(3, 2)
[[12 11]
[51 53]]注意:矩阵积计算不遵循交换律,np.dot(x,y) 和 np.dot(y,x) 得到的结果是不一样的。
简化Logistic Regression代码
这里去掉了一个for loop,一个用来遍历特征的循环,以便加快计算,后面将学习如何去掉遍历样本的循环
P19 Vectorizing Logistic Regression
如何实现在Logistic Regression上面的向量化,以便可以同时处理整个训练集,来实现gradient descent的一步迭代,针对整个训练集的一步迭代,而不需要使用任何显式的for loop。
$$
z^{(i)} = w^Tx^{(i)} + b \
a^{(i)} = \sigma(z^{(i)})\
X = \begin{bmatrix}
.&.&&. \
.&.&&. \
x^{(1)}&x^{(2)}&…… &x^{(m)}\
.&.&&. \
.&.&&. \
\end{bmatrix}_{n_xm}\\
Z = [z{(1)}z{(2)},……z{(m)}] = w^TX+[b,……,b]_{1m} = [w^TX^{(1)}+b,w^TX^{(2)}+b,……,w^TX^{(m)}+b]\\
A = [a^{(1)},a^{(2)},……,a^{(m)}] = \sigma(Z)
$$
使用numpy:
1 |
|
p20 Vectorizing Logistic Regression’s Gradient Computation
我们将学习如何向量化同时计算m个训练数据的梯度。
回顾:
$$
dz^{(1)} = a^{(1)} - y^{(1)}……dz^{(m)} = a^{(m)} - y^{(m)}\
dz = [dz^{(1)},……,dz^{(m)}]{1*m}
$$
我们已经描述了如何计算:
$$
a^{(i)} = \sigma(z^{(i)})\
X = \begin{bmatrix}
.&.&&. \
.&.&&. \
x^{(1)}&x^{(2)}&…… &x^{(m)}\
.&.&&. \
.&.&&. \
\end{bmatrix}{n_xm}\\
Z = [z{(1)}z{(2)},……z{(m)}] = w^TX+[b,……,b]_{1m} = [w^TX^{(1)}+b,w^TX^{(2)}+b,……,w^TX^{(m)}+b]\
A = [a^{(1)},a^{(2)},……,a^{(m)}] = \sigma(Z)\
Y = [y^{(1)},y^{(2)},……,y^{(m)}]{1*m}
$$
那么有:
$$
dZ = [dz^{(1)},dz^{(2)},……,dz^{(m)}]=
\A - Y = [a^{(1)}-y^{(1)},a^{(2)}-y^{(2)},……,a^{(m)}-y^{(m)}]
$$
虽然我们已经去掉了一个for loop(用于遍历每个样本的特征的循环)但是我们仍然还有一个遍历训练集的for loop,以w计算为例:
$$
dw = 0\
dw += x^{(1)}dz\
dw += x^{(2)}dz\
dw += x^{(3)}dz\……\
dw += x^{(m)}dz\
dw /= m\\
db = 0\
db += dz^{(1)}\
db += dz^{(2)}\
db += dz^{(3)}\……\
db += dz^{(m)}\
db /= m
$$
向量化实现:
$$
db = \frac{1}{m}\sum{i=1}^mdz^{(i)}
$$
1 |
|
$$
dw = \frac{1}{m}X(dZ)^T \= \frac{1}{m}\begin{bmatrix}
.&.&&. \
.&.&&. \
x^{(1)}&x^{(2)}&…… &x^{(m)}\
.&.&&. \
.&.&&. \
\end{bmatrix}_{n_x*m}\begin{bmatrix}
dz^(1) \
.\
.\
dz^{(m)}
\end{bmatrix}_{m1}\=\frac{1}{m}[x^{(1)}dz^{(1)}+……+x^{(m)}dz^{(m)}]
$$
所以,综上,对于一次迭代应该有:
$$
Z = w^Tx+b=np.dot(w.T,X) + b\
A=\sigma(Z)\
dZ = A-Y\
dw = \frac{1}{m}XdZ^T\
db = \frac{1}{m}np*sum(dZ)\
w := w -\alpha dw \
b := b - \alpha db
$$
可以看到我们去掉了所有的for loop,但是,要由于要进行多次迭代,我们仍然需要使用for loop,即:for iteration in range(times)
p21 Python中的广播
广播是一种可以让python代码执行得更快的手段,本节介绍python中的广播是如何运作的。
计算每种食物中,来自carbon的calorie所占的比例,但是不使用for loop
- 用一行代码对各列求和,可得到四种不同食物的卡路里总量、
- 第二行代码让每一列都除以对应的和
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35import numpy as np
# 例子1:
A = np.array([[56.0, 0.0, 4.4, 68.0],
[1.2, 104.0, 52.0, 8.0],
[1.8, 135.0, 99.0, 0.9]])
print(A)
calorie = A.sum(axis=0)
# axis 代表每列竖直相加,如果希望水平方向相加,可以令axis = 1
print(calorie)
percentage = 100 * A / calorie.reshape(1, 4)
# 使用矩阵A,将它除以1x4的矩阵,就得到百分比矩阵
# 这里可以省略reshape,由于它的算法复杂度为O(1),成本很低,所以能写就写,以确保矩阵的正确性
# A为3x4矩阵,将他除以一个1x4的矩阵,这似乎是不可行的
print(percentage)
# 例子2:
B = np.array([1, 2, 3, 4])
B += 10
print(B) # [11 12 13 14]
# 例子3:
C = np.array([[2, 0, 35, 5], [54, 54, 4545, 5]])
print(B + C)
# [[ 13 12 48 19]
# [ 65 66 4558 19]]
# 将一个m*n的矩阵加上一个1*n的矩阵,python会将矩阵复制m次,将它变成一个m*n的矩阵之后再相加
D = np.array([100, 100]).reshape(2, -1)
print(C + D)
# [[ 102 100 135 105]
# [ 154 154 4645 105]]
# 这里水平复制了三次python广播中的一些通用规则:
numpy中reshape函数的三种常见相关用法
- numpy.arange(n).reshape(a, b) 依次生成n个自然数,并且以a行b列的数组形式显示
1 |
|
- mat (or array).reshape(c, -1) 必须是矩阵格式或者数组格式,才能使用 .reshape(c, -1) 函数, 表示将此矩阵或者数组重组,以 c行d列的形式表示
1 |
|
-1的作用就在此**: 自动计算d:d=数组或者矩阵里面所有的元素个数/c**, d必须是整数,不然报错)
(reshape(-1, m)即列数固定,行数需要计算)
1 |
|
- numpy.arange(a,b,c) 从 数字a起, 步长为c, 到b结束,生成array
- numpy.arange(a,b,c).reshape(m,n) :将array的维度变为m 行 n列。
1 |
|
P22 A note on python / numpy vectors
1 |
|