概述
Neural Networks and Deep Learning(week 2_python 编程练习)
吴恩达深度学习课程第二周编程练习——python的numpy基础
Python Basics with Numpy
这个练习会对python作一个简要的介绍,熟悉python部分函数的使用。 (原练习中有一小部分介绍了iPython Botebooks(jupyter notebook)的使用,此文省略)
Instructions:
- 学习使用python3
- 在题目没有明确要求时,避免使用for、while循环
学习目标:
- 学会使用numpy函数以及numpy的矩阵操作
- 理解python中
broadcasting广播
的概念 - 学会向量化代码的编写
1. 运行最基本的numpy函数
在这个练习中可以学到几个关键的numpy函数比如np.exp
,np.log
,np.reshape
。
1.1 sigmoid函数,np.exp()
在使用np.exp()
之前,先使用math.exp()
来运行sigmoid函数。通过比较,能够看出为什么np.exp()
比math.exp()
更好。
Exercise 1 - Basic_sigmoid
写一个函数返回sigmoid的计算值。使用math.exp()
作为指数运算函数。
Reminder: sigmoid函数通常也被叫做回归函数logistic function
。sigmoid是个非线性函数,在机器学习(Logistic regression)和深度学习中均有应用。
s
i
g
m
o
i
d
(
x
)
=
1
1
+
e
−
x
sigmoid(x)=frac{1}{1+e^{-x}}
sigmoid(x)=1+e−x1
要使用一个特定库中的函数,使用package_name.function
。运行以下代码,观察使用了math.exp()
的例子。
import math
def basic_sigmoid(x):
"""
计算sigmoid(x)
参数:
x -- A,标量
s -- sigmoid(X)
"""
s = 1/(1+math.exp(-x))
return s
print("basic_sigmoid(1) = " + str(basic_sigmoid(1)))
正确的输出应为basic_sigmoid(1) = 0.7310585786300049
。
事实上,在深度学习中很少使用math库,math库的输入均为实数,而在深度学习中使用的几乎都是矩阵和向量。这就是numpy更有用的原因。
### 在深度学习中使用numpy而不是math的原因 ###
x = [1, 2, 3] # x是python中的列表对象
basic_sigmoid(x) # 运行时会出错,因为x是一个向量。
如果
x
=
(
x
1
,
x
2
,
.
.
.
,
x
n
)
x=(x_1, x_2, ... ,x_n)
x=(x1,x2,...,xn)是一个行向量,那么np.exp(x)
能将指数运算作用在行向量的每个元素
x
x
x上。np.exp(x)=(e^{x_1},e^{x_2},...,e^{x_n})
。
import numpy as np
#np.exp的例子
t_x = np.array([1, 2, 3])
print(np.exp(t_x)) #结果是(exp(1), exp(2), exp(3))
print(1/t_x)
正确的输出应为:
[ 2.71828183 7.3890561 20.08553692] [1. 0.5 0.33333333]
另外,如果x是向量,那么s = x +3
或s = 1/x
这样的python运算,输出的结果s也会是一个向量,并且维度与x相同。
# example of vector operation
t_x = np.array([1, 2, 3])
print (t_x + 3)
正确的输出为:[4 5 6]
。
更多有关numpy函数的信息,可以登陆numpy官网查看。
Exercise 2 - sigmoid
使用numpy.exp()
计算sigmoid。
Instructions: x既可以是一个实数,也可以是一个向量或矩阵。在numpy中表示向量、矩阵等的数据结构叫做numpy arrays
。
For x ∈ R n , s i g m o i d ( x ) = s i g m o i d ( x 1 x 2 . . . x n ) = ( 1 1 + e − x 1 1 1 + e − x 2 . . . 1 1 + e − x n ) text{For } x in mathbb{R}^n text{, } sigmoid(x) = sigmoidbegin{pmatrix} x_1 \ x_2 \ ... \ x_n \ end{pmatrix} = begin{pmatrix} frac{1}{1+e^{-x_1}} \ frac{1}{1+e^{-x_2}} \ ... \ frac{1}{1+e^{-x_n}} \ end{pmatrix} For x∈Rn, sigmoid(x)=sigmoid⎝⎜⎜⎛x1x2...xn⎠⎟⎟⎞=⎝⎜⎜⎛1+e−x111+e−x21...1+e−xn1⎠⎟⎟⎞
# FUNCTION:sigmoid
def sigmoid(x):
"""
计算sigmoid(x)
参数:
x -- 标量A或者任意大小的数组(numpy array)
返回:
s -- sigmoid(X)
"""
s = 1/(1+np.exp(-x))
return s
t_x = np.array([1, 2, 3])
print("sigmoid(t_x) = " + str(sigmoid(t_x)))
正确输出应为:sigmoid(t_x) = [0.73105858 0.88079708 0.95257413]
1.2 Sigmoid Gradient(sigmoid函数梯度)
在反向传播中需要计算梯度来优化损失函数,接下来编写梯度函数。
Exercise 3 - sigmoid_derivative
对于输入x,使用函数sigmoid_grad()
计算sigmoid函数的梯度。公式为:
s
i
g
m
o
i
d
_
d
e
r
i
v
a
t
i
v
e
(
x
)
=
σ
′
(
x
)
=
σ
(
x
)
(
1
−
σ
(
x
)
)
sigmoid_derivative(x) = sigma'(x) = sigma(x) (1 - sigma(x))
sigmoid_derivative(x)=σ′(x)=σ(x)(1−σ(x))
编写这个函数需要两步:
- 使用
exercise 2
中的sigmoid()函数,s = sigmoid(x) - 计算 σ ′ ( x ) = s ( 1 − s ) sigma'(x)=s(1-s) σ′(x)=s(1−s)
#FUNVTION:sigmoid_derivative
def sigmoid_derivative(x):
"""
对于输入x,计算sigmoid(x)的梯度(导数,坡度)
可以将sigmoid函数的输出存为变量,再使用这个变量来计算梯度。
参数:
x -- 标量A或者任意大小的数组(numpy array)
返回:
ds -- 计算出的梯度
"""
def sigmoid(x):
s = 1/(1+np.exp(-x))
return s
s = sigmoid(x)
ds = s*(1-s)#写相乘的代码时,记得写上"*"
return ds
t_x = np.array([1, 2, 3])
print ("sigmoid_derivative(t_x) = " + str(sigmoid_derivative(t_x)))
正确的输出为:sigmoid_derivative(t_x) = [0.19661193 0.10499359 0.04517666]
1.3 Reshaping arrays(改变数组的维度)
深度学习中常用的两个numpy函数:np.shape()
和np.reshape()
。
X.shape
:获得矩阵/向量X的维度。X.reshape()
:改变X的维度。
例如,在计算机科学中,一个图像可以被3D的数组(length,height,depth=3)表示。当你要将图片作为算法的输入时,需要将其转化为(length* height * depth,1)的向量。换言之,需要将3D的数组展开称为1D的向量。
Exercise 4 - image2vector
编写函数image2vector()
,输入为(length,height,3)的数组,输出为(length*height *3,1)的向量。
例如:如果要将一个(a,b,c)的数组v展开成一个(a*b,c)的向量,可以:
v = v.reshape((v.shape[0] * v.shape[1], v.shape[2]))
# v.shape[0] = a ; v.shape[1] = b ; v.shape[2] = c
- 不要在编写代码时将图片的维度直接写为常数,使用
image.shape[]
获取需要的维度参数。 - 可以使用
v = v.reshape(-1,1)
。-1表示未指定值,即行未指定,列为1。
#FUNCTION:像素数组到向量的转化
def image2vector(image):
"""
参数:
image -- 维度(length, height, depth)的numpy array
返回:
v -- 维度为(length*height*depth, 1)的向量
"""
v = image.reshape(image.shape[0]*image.shape[1]*image.shape[2],1)
return v
# 这是一个3*3*2的数组,对应图像的维度则为:(num_px_x, num_px_y,3),3表示RGB值。
#此处可以查阅numpy.array()的使用。
#numpy.array(a,b,c)表示创建了a页,b行,c列的数组。
#对应于此处,3*3*2的数组即表示3页,3行2列的数据。
#相应地,图像维度为(num_px_x=3,num_px_y=2,3)
#RGB即红绿蓝,在像素表示时各占一页,所以有3页。
t_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]]])
print ("image2vector(image) = " + str(image2vector(t_image)))
正确的输出为:
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]]
1.4 Normalizing rows(逐行归一化)
归一化是机器学习和深度学习中常用的技巧,归一化后的数据能在梯度下降中更快地收敛。归一化指将x变为 x ∥ x ∥ frac{x}{| x |} ∥x∥x(每行向量均除以其模长)。
例如,若:
x = [ 0 3 4 2 6 4 ] x = begin{bmatrix} 0 & 3 & 4 \ 2 & 6 & 4 \ end{bmatrix} x=[023644]
那么
∥
x
∥
=
np.linalg.norm(x, axis=1, keepdims=True)
=
[
5
56
]
(4)
| x| = text{np.linalg.norm(x, axis=1, keepdims=True)} = begin{bmatrix} 5 \ sqrt{56} \ end{bmatrix}tag{4}
∥x∥=np.linalg.norm(x, axis=1, keepdims=True)=[556](4)
x _ n o r m a l i z e d = x ∥ x ∥ = [ 0 3 5 4 5 2 56 6 56 4 56 ] (5) x_normalized = frac{x}{| x|} = begin{bmatrix} 0 & frac{3}{5} & frac{4}{5} \ frac{2}{sqrt{56}} & frac{6}{sqrt{56}} & frac{4}{sqrt{56}} \ end{bmatrix}tag{5} x_normalized=∥x∥x=[05625356654564](5)
可以注意到,不管维度多少的矩阵,这个函数都能很好地运行:这叫broadcasting(广播)
。在第五部分会介绍。
当keepdims=True
时,原矩阵x会自动广播
并保持原来的维数不变来进行计算。keepdims
默认为false
。
keepdims
是如何保持维度不变的:被减少的轴仍以维度1保留在结果中。
axis=1
指按行计算模长进行归一化。axis=0
表示按列来计算。
numpy.linalg.norm
还有一个参数ord
,这个参数用来制定归一化的类型。默认ord=2
即二范数。熟悉更多归一化运算,访问numpy.linalg.norm。
Exercise 5 - normalize_rows
编写函数normalizeRowa()
来按行归一化矩阵。输入x是个矩阵,在将这个函数作用到x上后,x的每一行都应是长度为1的向量。
Note: 不要使用x /= x_norm
,操作符/=
不适用于矩阵之间的除法。
# FUNCTION:逐行归一化。
def normalize_rows(x):
"""
编写一个函数能够将矩阵x逐行归一化,归一化后的x每行只有1个元素。
参数:
x -- (n,m)维的numpy矩阵A
返回:
x -- 逐行正则化后的矩阵x。
"""
# 计算x的二范数即模长||x||,存入x_norm中。
# 使用 np.linalg.norm(...,ord=2,axis = ...,keepdims =True)
# x除以其模长。
x_norm = np.linalg.norm(x,axis=1,keepdims=True)#here is keepdims not Keepdims
x = np.divide(x,x_norm)
return x
x = np.array([[0, 3, 4],
[1, 6, 4]])
print("normalizeRows(x) = " + str(normalize_rows(x)))
正确的输出应为:
normalizeRows(x) = [[0. 0.6 0.8 ]
[0.13736056 0.82416338 0.54944226]]
Note: 在函数normalize_rows()
中,你也可以试着打印出x_norm和x的维度,可以发现x_norm和x的维度不同。那不同维度的矩阵是如何相除的?这就叫做广播
。
Exercise 6 - softmax
使用numpy来实现softmax()
。归一化之后,当你还需要进行分类时(两类/多类),就需要使用softmax。
Instructions:
-
对于 x ∈ R 1 × n x in mathbb{R}^{1times n} x∈R1×n,
( 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 ] ) begin{pmatrix} softmax(x) &= softmaxleft(begin{bmatrix} x_1 && x_2 && ... && x_n end{bmatrix}right) \&= begin{bmatrix} frac{e^{x_1}}{sum_{j}e^{x_j}} && frac{e^{x_2}}{sum_{j}e^{x_j}} && ... && frac{e^{x_n}}{sum_{j}e^{x_j}} end{bmatrix} end{pmatrix} (softmax(x)=softmax([x1x2...xn])=[∑jexjex1∑jexjex2...∑jexjexn]) -
对于矩阵 x ∈ R m × n x in mathbb{R}^{mtimes n} x∈Rm×n, x i j x_{ij} xij为矩阵第i行第j列的元素,有:
( 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 ] = ( s o f t m a x (first row of x) s o f t m a x (second row of x) ⋮ s o f t m a x (last row of x) ) ) begin{pmatrix} softmax(x) &= softmaxbegin{bmatrix} x_{11} & x_{12} & x_{13} & dots & x_{1n} \ x_{21} & x_{22} & x_{23} & dots & x_{2n} \ vdots & vdots & vdots & ddots & vdots \ x_{m1} & x_{m2} & x_{m3} & dots & x_{mn} end{bmatrix} \ \&= begin{bmatrix} frac{e^{x_{11}}}{sum_{j}e^{x_{1j}}} & frac{e^{x_{12}}}{sum_{j}e^{x_{1j}}} & frac{e^{x_{13}}}{sum_{j}e^{x_{1j}}} & dots & frac{e^{x_{1n}}}{sum_{j}e^{x_{1j}}} \ frac{e^{x_{21}}}{sum_{j}e^{x_{2j}}} & frac{e^{x_{22}}}{sum_{j}e^{x_{2j}}} & frac{e^{x_{23}}}{sum_{j}e^{x_{2j}}} & dots & frac{e^{x_{2n}}}{sum_{j}e^{x_{2j}}} \ vdots & vdots & vdots & ddots & vdots \ frac{e^{x_{m1}}}{sum_{j}e^{x_{mj}}} & frac{e^{x_{m2}}}{sum_{j}e^{x_{mj}}} & frac{e^{x_{m3}}}{sum_{j}e^{x_{mj}}} & dots & frac{e^{x_{mn}}}{sum_{j}e^{x_{mj}}} end{bmatrix} \ \ &= begin{pmatrix} softmaxtext{(first row of x)} \ softmaxtext{(second row of x)} \ vdots \ softmaxtext{(last row of x)} \ end{pmatrix} end{pmatrix} ⎝⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎛softmax(x)=softmax⎣⎢⎢⎢⎡x11x21⋮xm1x12x22⋮xm2x13x23⋮xm3……⋱…x1nx2n⋮xmn⎦⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎢⎡∑jex1jex11∑jex2jex21⋮∑jexmjexm1∑jex1jex12∑jex2jex22⋮∑jexmjexm2∑jex1jex13∑jex2jex23⋮∑jexmjexm3……⋱…∑jex1jex1n∑jex2jex2n⋮∑jexmjexmn⎦⎥⎥⎥⎥⎥⎤=⎝⎜⎜⎜⎛softmax(first row of x)softmax(second row of x)⋮softmax(last row of x)⎠⎟⎟⎟⎞⎠⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎞
Notes: m
表示训练样本的数量,每个样本在矩阵中占一列,每个特征在矩阵中占一行。
Notes: 从上面的公式可以看出,在转置
前,训练样本为按行排列的,其特征值按列排列。
softmax
应当作用于每个训练样本的所有特征值上,所以softmax将会是逐列作用于矩阵的(转置后)。
不过在这个练习中,主要是为了熟悉python的使用,因而使用简单的矩阵 m × n mtimes n m×n,即m行n列的矩阵。
# FUNCTION:softmax
def softmax(x):
"""
逐行计算输入x的softmax()
完成后的代码应当既能作用于行向量,又能作用于(m,n)维的矩阵。
参数:
x -- (m,n)维的numpy矩阵A
返回:
s -- 与softmax(x)等价的numpy矩阵A,维度为(m,n)
"""
#(≈ 3 lines of code)
# 使用np.exp(...)将exp()作用于x的每个元素上。
# x_exp = ...
# 创建向量x_sum将x_exp逐行想加。使用np.sum(..., axis = 1, keepdims = True).
# x_sum = ...
# 通过将x_exp与x_sum相除计算softmax(x)。这会自动使用numpy的广播机制。
# s = ...
# YOUR CODE STARTS HERE
x_exp = np.exp(x)
x_sum = np.sum(x_exp,axis = 1,keepdims=True)
s = np.divide(x_exp,x_sum)
# YOUR CODE ENDS HERE
return s
t_x = np.array([[9, 2, 5, 0, 0],
[7, 5, 0, 0 ,0]])
print("softmax(x) = " + str(softmax(t_x)))
正确的输出应为:
softmax(x) = [[9.80897665e-01 8.94462891e-04 1.79657674e-02 1.21052389e-04
1.21052389e-04]
[8.78679856e-01 1.18916387e-01 8.01252314e-04 8.01252314e-04
8.01252314e-04]]
Notes:
- 试着打印出x_exp,x_sum,x的维度,可以看到x_sum的维度是(2,1)而其余的维度都是(2,5)。x_exp/x_sum能够相除,是由于python的
广播
机制。
总结:
- Np.exp(x)对任意np.array类型的变量x均有效,并且可以对x中的每个元素作指数运算。
- sigmoid()和sigmoid()的梯度。
- Image2vector 在深度学习中经常用到。
- np.reshape使用很多。如果能使用np.reshape()保证矩阵的维度是你想要的维度,能够避免很多bug的出现。
- numpy有许多效率很高的函数。
broadcasting
机制很有用。
最后
以上就是欣喜白昼为你收集整理的Neural Networks and Deep Learning(week 2_python 编程练习)Neural Networks and Deep Learning(week 2_python 编程练习)的全部内容,希望文章能够帮你解决Neural Networks and Deep Learning(week 2_python 编程练习)Neural Networks and Deep Learning(week 2_python 编程练习)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复