天天看点

Python基础与Numpy

对比普通实现方法与使用Numpy科学计算模块实现的差别,体现使用Numpy的优势在哪里。
    • 1、Sigmoid函数,np.exp()
    • 2、Sigmoid 梯度
    • 3、重塑矩阵(Reshaping arrays)
    • 4、规范化
    • 5、广播(broadcasting)和Softmax函数
    • 6、矢量化(向量化)
    • 7、L1 和 L2 损失函数

1、Sigmoid函数,np.exp()

np.exp():e的多少次幂,即 ex e x

我们分别使用 math.exp()、np.exp() 来实现 sigmoid中的指数函数的构建。

![](http://p9huev7ij.bkt.clouddn.com/18-7-22/92320173.jpg) Sigmoid函数公式为: Sigmoid=11+e−x S i g m o i d = 1 1 + e − x

首先使用普通的数学方式来实现:

import math

def basic_sigmoid(x):
    '''
    计算输入为 x 的sigmoid函数
    Arguments: x: 实数
    Return:s--sigmoid(x)
    '''
    s =  / ( + math.exp(-x))
    return s
           

但是事实上,深度学习中很少用 ’math‘ 模块,因为它的输入必须是一个实数,而在深度学习中,输入经常为矩阵或是向量。

import numpy as np

x = np.array([,,])
print(np.exp(x))

>> [     ]
           

结果是将输入矩阵的每个元素都对应的做了 ex e x 运算。

x = np.array([,,])
print(x+)
           

输出结果为矩阵的每一个元素都做相同的运算。

注:

这里输入的作为运算的矩阵必须是 np.array([ , , ]) 生成的, nimpy array,否则无法执行这些运算。

我们可以构建一个输入为矩阵的 Sigmoid S i g m o i d 函数:

sigmoid(x)=sigmoid⎛⎝⎜x1x2x3⎞⎠⎟=⎛⎝⎜⎜⎜11+e−x111+e−x211+e−x3⎞⎠⎟⎟⎟,For x∈Rn s i g m o i d ( x ) = s i g m o i d ( x 1 x 2 x 3 ) = ( 1 1 + e − x 1 1 1 + e − x 2 1 1 + e − x 3 ) , F o r   x ∈ R n

import numpy as np

def sigmoid(x):
    s =  / ( + np.exp(-x))
    return s

x = np.array([,,])
sigmoid(x)


>>  [  ]
           

对每一个输入矩阵的元素做了 11+e−x 1 1 + e − x 运算,然后返回了同样形状的矩阵。

2、Sigmoid 梯度

我们需要使用反向传播来计算优化损失函数的梯度,梯度也就是导数。

首先我们对 Sigmiod S i g m i o d 函数求导:

Sigmoid′=11+e−x−1(1+e−x)2 S i g m o i d ′ = 1 1 + e − x − 1 ( 1 + e − x ) 2

令 Sigmoid S i g m o i d 函数表示为 σ(x) σ ( x ) 即梯度函数可以写为:

sigmoid_derivative(x)=σ′(x)=σ(x)(1−σ(x)) s i g m o i d _ d e r i v a t i v e ( x ) = σ ′ ( x ) = σ ( x ) ( 1 − σ ( x ) )

简化即计算:

σ′(x)=s(1−s) σ ′ ( x ) = s ( 1 − s )

def sigmoid_derivative(x):
    s = sigmoid(x)
    ds = s * ( - s)
    return ds


x = np.array([,,])
print('Sigmoid_derivative')


>> [  ]
           

同样是对每个元素应用了 Sigmoid 求导公式。

3、重塑矩阵(Reshaping arrays)

X.shape():可以得到矩阵 / 向量 X 的形状

X.reshape():用于将 X 改变成其他的形状

例如,在科学计算的时候,输入一张图片是一个3D形状的矩阵 (length,height,depth=3) ( l e n g t h , h e i g h t , d e p t h = 3 ) ,然而,当把这张图片作为一个算法的输入的时候,要将它转换为一个向量的形状 (length∗height∗3,1) ( l e n g t h ∗ h e i g h t ∗ 3 , 1 ) ,即将3D矩阵转换为了1D的向量。

def image2vector(image):
    v = image.reshape(image.shape[] * image.shape[] * image.shape[], )
    return v


# 这是3*3*2的矩阵,典型的图片其实应该是(x * y * 3)的,因为对应RGB三层
image = np.array([[[ ,  ],
        [ ,  ],
        [  ,  ]],

       [[ ,  ],
        [ ,  ],
        [ ,  ]],

       [[ ,  ],
        [ ,  ],
        [ ,  ]]])

>> image2vector(image) = [[ ]
 [ ]
 [ ]
 [ ]
 [  ]
 [ ]
 [ ]
 [ ]
 [ ]
 [ ]
 [ ]
 [ ]
 [ ]
 [ ]
 [ ]
 [ ]
 [ ]
 [ ]]
           
reshape 3*3*2 转化为了 (3*3*2)*1 即 18*1 维的矩阵。

shape:

image 尺寸为 3×3×2 3 × 3 × 2

则:

image.shape[0]=3image.shape[1]=3image.shape[2]=2 i m a g e . s h a p e [ 0 ] = 3 i m a g e . s h a p e [ 1 ] = 3 i m a g e . s h a p e [ 2 ] = 2

4、规范化

深度学习中另一个常用的技术是规范化数据,规范化后由于梯度下降收敛的更加迅速,所以往往能得到更好的性能。规范化即将输入 x 的每一行的元素改变为 x||x|| x | | x | |

例如:

x=[023644] x = [ 0 3 4 2 6 4 ]

接下来:

||x||=np.linalg.norm(x,axis=1,keepdims=True)=[556−−√] | | x | | = n p . l i n a l g . n o r m ( x , a x i s = 1 , k e e p d i m s = T r u e ) = [ 5 56 ]

所以:

x_normalized=x||x||=[0256√35656√45456√] x _ n o r m a l i z e d = x | | x | | = [ 0 3 5 4 5 2 56 6 56 4 56 ]

即:

将 x 的每一行元素都除以 ||x|| | | x | | 对应行的元素。

规范化后,输入矩阵 x 的每一行会变为一个单位长度的向量(即长度为1)

def normalizeRows(x):
    x_norm = np.linalg.norm(x, axis = , keepdims = True)
    x = x / norm
    return x


Input: 
    x = np.array([
    [, , ],
    [, , ]])
Output:
    [[                           ]
    [     ]]
           

注意:

在这个过程中,如果输出 x_norm 的形状以及 x 的形状,你会发现他们的形状并不相同。

x_norm 有同样的行数,但只有一列

所以,当使用 x_norm 分割 x 的时候是如何进行的呢?这就是 Numpy 中的广播(broadcasting)。

5、广播(broadcasting)和Softmax函数

广播是 Numpy 中一个概念,它在执行不同形状之间矩阵的数学运算时非常的有用。

例如:

使用 Numpy 实现一个 Softmax 函数,当你的算法需要二分类或者分更多的类的时候,你可以将 softmax 函数作为一个规范化函数使用。

- 对于 x∈R1×n 对 于   x ∈ R 1 × n

softmax(x)=softmax([x1 x2 ⋅⋅⋅ xn])=[ex1∑jexj ex2∑jexj ⋅⋅⋅ exn∑jexj] s o f t m a x ( x ) = s o f t m a x ( [ x 1   x 2   · · ·   x n ] ) = [ e x 1 ∑ j e x j   e x 2 ∑ j e x j   · · ·   e x n ∑ j e x j ]

  • 对于矩阵 x∈Rm×n, xij 映射到输入x的第 i 行和第 j 列,即: 对 于 矩 阵   x ∈ R m × n ,   x i j   映 射 到 输 入 x 的 第   i   行 和 第   j   列 , 即 :

    softmax(x)=softmax⎡⎣⎢⎢⎢⎢⎢x11x21⋮xm1x12x22⋮xm2x13x23⋮xm3⋯⋯⋱⋯x1nx2n⋮xmn⎤⎦⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢ex11∑jex1jex21∑jex2j⋮exm1∑jexmjex12∑jex1jex22∑jex2j⋮exm2∑jexmjex13∑jex1jex23∑jex2j⋮exm3∑jexmj⋯⋯⋱⋯ex1n∑jex1jex2n∑jex2j⋮exmn∑jexmj⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥ s o f t m a x ( x ) = s o f t m a x [ x 11 x 12 x 13 ⋯ x 1 n x 21 x 22 x 23 ⋯ x 2 n ⋮ ⋮ ⋮ ⋱ ⋮ x m 1 x m 2 x m 3 ⋯ x m n ] = [ e x 11 ∑ j e x 1 j e x 12 ∑ j e x 1 j e x 13 ∑ j e x 1 j ⋯ e x 1 n ∑ j e x 1 j e x 21 ∑ j e x 2 j e x 22 ∑ j e x 2 j e x 23 ∑ j e x 2 j ⋯ e x 2 n ∑ j e x 2 j ⋮ ⋮ ⋮ ⋱ ⋮ e x m 1 ∑ j e x m j e x m 2 ∑ j e x m j e x m 3 ∑ j e x m j ⋯ e x m n ∑ j e x m j ]

即输入 x 矩阵的每个元素除以该行元素所有的和( 新的 x11=x11x11+x12+⋯+x1n 新 的   x 11 = x 11 x 11 + x 12 + ⋯ + x 1 n )

def sotfmax(x):
    x_exp = np.exp(x)
    x_sum = np.sum(x_exp, axis = , keepdims = True)
    s = x_exp / x_sum
    return s
           

np.sum⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪axiskeepdims=None=1=True否则对所有元素求和对每一行求和保留原格式,同等维数降维 n p . s u m { a x i s = N o n e 对所有元素求和 = 1 对每一行求和 k e e p d i m s = T r u e 保留原格式,同等维数 否 则 降维

np.exp() 对任意 np.array 数组 x 的每个位置的元素应用了指数函数。

6、矢量化(向量化)

在深度学习处理大量数据的时候,非计算上最优的函数会成为你的算法中的一个巨大的瓶颈,并导致模型的运行花费巨大的时间。为了确保你的代码计算的效率,我们需要使用矢量化;

下面,将对 向量点积(dot)、外积(outer)、元素逐个相乘(elementwise)以及矩阵点积(gdot)分别用经典方法和 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] x 1 = [ 9 , 2 , 5 , 0 , 0 , 7 , 5 , 0 , 0 , 0 , 9 , 2 , 5 , 0 , 0 ] x 2 = [ 9 , 2 , 2 , 9 , 0 , 9 , 2 , 5 , 0 , 0 , 9 , 2 , 5 , 0 , 0 ]

time.process_time()用来计时,tic 记下程序运行前时刻计数值,toc 记下程序运行结束后时刻的计数值,相减 ×1000 × 1000 即为 ms。

  • 向量点积:
# 经典方法实现     
tic = time.process_time()
dot = 
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(,len(x1))
gdot = np.zeros(W.shape[])    # 即3个[···],[···],[···]一维矩阵,每个矩阵内有15个元素
for i in range(W.shape[]):
    for j in range(len(x1)):
        gdot[i] += W[i,j] * x1[j]


# Numpy方法实现
gdot = np.dot(W, x1)
           

先随机生成一个 3×len(x1) 3 × l e n ( x 1 ) 即 (3×15) ( 3 × 15 ) 的 Numpy 矩阵 W

然后遍历这三个矩阵

再遍历每个矩阵内的元素

每个矩阵内的每个元素和x1相应位置的元素做乘法,再加和。

最后得到 [x x x] 这样 3×1 的矩阵

注意:

np.dot() 是矩阵-矩阵或矩阵-向量 相乘(带求和)

np.multiply() 是元素间的相乘

7、L1 和 L2 损失函数

定义损失来评估模型的性能。预测值 y^ y ^ 和真实值 y y 之间的差值即为损失值。

在深度学习中,使用类似梯度下降优化算法来最小化损失值。

L1损失函数:

L1(y^,y)=∑i=0m|y(i)−y^(i)|L1(y^,y)=∑i=0m|y(i)−y^(i)|

定义 L1 损失函数:

def L1(yhat, y):
    loss = np.sum(np.abs(y - yhat))
    return loss



yhat = np.array([, , , , ])
y = np.array([, , , , ])
L1 = L1(yhat, y)

>> L1 = 
           

定义 L2 损失函数:

L2(y^,y)=∑i=0m(y(i)−y^(i))2 L 2 ( y ^ , y ) = ∑ i = 0 m ( y ( i ) − y ^ ( i ) ) 2

def L2(yhat, y):
    loss = np.dot((y - yhat), (y - yhat))
    return loss
           

L1:差值的绝对值之和;

L2:差值的平方之和;

注:

1. (y - yhat).T :即转置,如果矩阵维数为1,则返回自身;

2. 如果 x=[x1,x2,…,xn] x = [ x 1 , x 2 , … , x n ] ,那么

np.dot(x,x)=∑j=0nx2j n p . d o t ( x , x ) = ∑ j = 0 n x j 2