Python基础与Numpy
对比普通实现方法与使用Numpy科学计算模块实现的差别,体现使用Numpy的优势在哪里。
1、Sigmoid函数,np.exp()
np.exp():e的多少次幂,即
我们分别使用 math.exp()、np.exp() 来实现 sigmoid中的指数函数的构建。
import math
def basic_sigmoid(x):
'''
计算输入为 x 的sigmoid函数
Arguments: x: 实数
Return:s--sigmoid(x)
'''
s = 1 / (1 + math.exp(-x))
return s
但是事实上,深度学习中很少用 ’math‘ 模块,因为它的输入必须是一个实数,而在深度学习中,输入经常为矩阵或是向量。
import numpy as np
x = np.array([1,2,3])
print(np.exp(x))
>> [ 2.71828183 7.3890561 20.08553692]
结果是将输入矩阵的每个元素都对应的做了 运算。
x = np.array([1,2,3])
print(x+3)
输出结果为矩阵的每一个元素都做相同的运算。
注:
这里输入的作为运算的矩阵必须是 np.array([ , , ]) 生成的, nimpy array,否则无法执行这些运算。
我们可以构建一个输入为矩阵的 函数:
import numpy as np
def sigmoid(x):
s = 1 / (1 + np.exp(-x))
return s
x = np.array([1,2,3])
sigmoid(x)
>> [0.73105858 0.88079708 0.95257413]
对每一个输入矩阵的元素做了 运算,然后返回了同样形状的矩阵。
2、Sigmoid 梯度
我们需要使用反向传播来计算优化损失函数的梯度,梯度也就是导数。
首先我们对 函数求导:
令 函数表示为 即梯度函数可以写为:
简化即计算:
def sigmoid_derivative(x):
s = sigmoid(x)
ds = s * (1 - s)
return ds
x = np.array([1,2,3])
print('Sigmoid_derivative')
>> [0.19661193 0.10499359 0.04517666]
同样是对每个元素应用了 Sigmoid 求导公式。
3、重塑矩阵(Reshaping arrays)
X.shape():可以得到矩阵 / 向量 X 的形状
X.reshape():用于将 X 改变成其他的形状
例如,在科学计算的时候,输入一张图片是一个3D形状的矩阵,然而,当把这张图片作为一个算法的输入的时候,要将它转换为一个向量的形状 ,即将3D矩阵转换为了1D的向量。
def image2vector(image):
v = image.reshape(image.shape[0] * image.shape[1] * image.shape[2], 1)
return v
# 这是3*3*2的矩阵,典型的图片其实应该是(x * y * 3)的,因为对应RGB三层
image = np.array([[[ 0.67826139, 0.29380381],
[ 0.90714982, 0.52835647],
[ 0.4215251 , 0.45017551]],
[[ 0.92814219, 0.96677647],
[ 0.85304703, 0.52351845],
[ 0.19981397, 0.27417313]],
[[ 0.60659855, 0.00533165],
[ 0.10820313, 0.49978937],
[ 0.34144279, 0.94630077]]])
>> image2vector(image) = [[ 0.67826139]
[ 0.29380381]
[ 0.90714982]
[ 0.52835647]
[ 0.4215251 ]
[ 0.45017551]
[ 0.92814219]
[ 0.96677647]
[ 0.85304703]
[ 0.52351845]
[ 0.19981397]
[ 0.27417313]
[ 0.60659855]
[ 0.00533165]
[ 0.10820313]
[ 0.49978937]
[ 0.34144279]
[ 0.94630077]]
reshape 3*3*2 转化为了 (3*3*2)*1 即 18*1 维的矩阵。
shape:
image 尺寸为
则:
4、规范化
深度学习中另一个常用的技术是规范化数据,规范化后由于梯度下降收敛的更加迅速,所以往往能得到更好的性能。规范化即将输入 x 的每一行的元素改变为
例如:
接下来:
所以:
即:
将 x 的每一行元素都除以 对应行的元素。
规范化后,输入矩阵 x 的每一行会变为一个单位长度的向量(即长度为1)
def normalizeRows(x):
x_norm = np.linalg.norm(x, axis = 1, keepdims = True)
x = x / norm
return x
Input:
x = np.array([
[0, 3, 4],
[1, 6, 4]])
Output:
[[ 0. 0.6 0.8 ]
[ 0.13736056 0.82416338 0.54944226]]
注意:
在这个过程中,如果输出 x_norm 的形状以及 x 的形状,你会发现他们的形状并不相同。
x_norm 有同样的行数,但只有一列
所以,当使用 x_norm 分割 x 的时候是如何进行的呢?这就是 Numpy 中的广播(broadcasting)。
5、广播(broadcasting)和Softmax函数
广播是 Numpy 中一个概念,它在执行不同形状之间矩阵的数学运算时非常的有用。
例如:
使用 Numpy 实现一个 Softmax 函数,当你的算法需要二分类或者分更多的类的时候,你可以将 softmax 函数作为一个规范化函数使用。
-
即输入 x 矩阵的每个元素除以该行元素所有的和()
def sotfmax(x):
x_exp = np.exp(x)
x_sum = np.sum(x_exp, axis = 1, keepdims = True)
s = x_exp / x_sum
return s
np.exp() 对任意 np.array 数组 x 的每个位置的元素应用了指数函数。
6、矢量化(向量化)
在深度学习处理大量数据的时候,非计算上最优的函数会成为你的算法中的一个巨大的瓶颈,并导致模型的运行花费巨大的时间。为了确保你的代码计算的效率,我们需要使用矢量化;
下面,将对 向量点积(dot)、外积(outer)、元素逐个相乘(elementwise)以及矩阵点积(gdot)分别用经典方法和 Numpy 来实现。
首先,令:
time.process_time()用来计时,tic 记下程序运行前时刻计数值,toc 记下程序运行结束后时刻的计数值,相减 即为 ms。
- 向量点积:
# 经典方法实现
tic = time.process_time()
dot = 0
for i in range(len(x1)):
dot += x1[i] * x2[i]
toc = time.process_time() # tic toc用来计时
print(dot)
# Numpy方法实现
dot = np.dot(x1, x2)
- 外积:
# 经典方法实现
outer = np.zeros(len(x1), len(x2)) #创建一个(15×15)的全0矩阵
for i in range(len(x1)):
for j in range(len(x2)):
outer[i, j] = x1[i] * x2[j]
# Numpy方法实现
outer = np.outer(x1, x2)
生成一个 len(x1)*len(x2) 的矩阵。
- 逐个元素相乘:
# 经典方法实现
mul = np.zeros(len(x1))
for i in range(len(x1)):
mul[i] = x1[i] * x2[j]
# Numpy方法实现
mul = np.multiply(x1, x2)
生成的仍为同型矩阵,每位的元素为x1, x2相应位元素的乘积。
- 矩阵点积:
# 经典方法实现
W = np.random.rand(3,len(x1))
gdot = np.zeros(W.shape[0]) # 即3个[···],[···],[···]一维矩阵,每个矩阵内有15个元素
for i in range(W.shape[0]):
for j in range(len(x1)):
gdot[i] += W[i,j] * x1[j]
# Numpy方法实现
gdot = np.dot(W, x1)
先随机生成一个 即 的 Numpy 矩阵 W
然后遍历这三个矩阵
再遍历每个矩阵内的元素
每个矩阵内的每个元素和x1相应位置的元素做乘法,再加和。
最后得到 [x x x] 这样 3×1 的矩阵
注意:
np.dot() 是矩阵-矩阵或矩阵-向量 相乘(带求和)
np.multiply() 是元素间的相乘
7、L1 和 L2 损失函数
定义损失来评估模型的性能。预测值 和真实值 之间的差值即为损失值。
在深度学习中,使用类似梯度下降优化算法来最小化损失值。
L1损失函数:
定义 L1 损失函数:
def L1(yhat, y):
loss = np.sum(np.abs(y - yhat))
return loss
yhat = np.array([.9, 0.2, 0.1, .4, .9])
y = np.array([1, 0, 0, 1, 1])
L1 = L1(yhat, y)
>> L1 = 1.1
定义 L2 损失函数:
def L2(yhat, y):
loss = np.dot((y - yhat), (y - yhat))
return loss
L1:差值的绝对值之和;
L2:差值的平方之和;
注:
1. (y - yhat).T :即转置,如果矩阵维数为1,则返回自身;
2. 如果 ,那么