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)和深度学习中均有应用。
要使用特定库中的函数,请使用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是一个向量。
如果是一个行向量,那么np.exp(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
。
# 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函数的梯度。公式为:
编写这个函数需要两个步骤:
- 使用 exercise 2 中的sigmoid()函数,s = sigmoid(x)
- 计算
#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变为(每行向量均除以其模长)。
例如,如果:
所以
可以注意到,无论矩阵的维数如何,这个函数都能很好地工作:这被称为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.pide(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:
- 对于,
- 对于矩阵 , 为矩阵第i行第j列的元素,有:
Notes:m
表示训练样本的数量,每个样本在矩阵中占一列,每个特征在矩阵中占一行。
Notes:从上面的公式可以看出,在转置
前,训练样本为按行排列的,其特征值按列排列。
softmax
应当作用于每个训练样本的所有特征值上,所以softmax将会是逐列作用于矩阵的(转置后)。
不过在这个练习中,主要是为了熟悉python的使用,因而使用简单的矩阵,即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.pide(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机制很有用。
文章出处登录后可见!