Neural Networks and Deep Learning(week 2_python 编程练习)

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)和深度学习中均有应用。

sigmoid

sigmoid%28x%29%3D%5Cfrac%7B1%7D%7B1%2Be%5E%7B-x%7D%7D
要使用特定库中的函数,请使用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%3D%28x_1%2C%20x_2%2C%20...%20%2Cx_n%29是一个行向量,那么np.exp(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 +3s = 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

%5Ctext%7BFor%20%7D%20x%20%5Cin%20%5Cmathbb%7BR%7D%5En%20%5Ctext%7B%2C%20%7D%20sigmoid%28x%29%20%3D%20sigmoid%5Cbegin%7Bpmatrix%7D%20x_1%20%5C%5C%20x_2%20%5C%5C%20...%20%5C%5C%20x_n%20%5C%5C%20%5Cend%7Bpmatrix%7D%20%3D%20%5Cbegin%7Bpmatrix%7D%20%5Cfrac%7B1%7D%7B1%2Be%5E%7B-x_1%7D%7D%20%5C%5C%20%5Cfrac%7B1%7D%7B1%2Be%5E%7B-x_2%7D%7D%20%5C%5C%20...%20%5C%5C%20%5Cfrac%7B1%7D%7B1%2Be%5E%7B-x_n%7D%7D%20%5C%5C%20%5Cend%7Bpmatrix%7D

# 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函数的梯度。公式为:
sigmoid%5C_derivative%28x%29%20%3D%20%5Csigma%27%28x%29%20%3D%20%5Csigma%28x%29%20%281%20-%20%5Csigma%28x%29%29
编写这个函数需要两个步骤:

  1. 使用 exercise 2 中的sigmoid()函数,s = sigmoid(x)
  2. 计算%5Csigma%27%28x%29%3Ds%281-s%29
#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的向量。

RGB

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变为%5Cfrac%7Bx%7D%7B%5C%7C%20x%20%5C%7C%7D(每行向量均除以其模长)。

例如,如果:

x%20%3D%20%5Cbegin%7Bbmatrix%7D%200%20%26%203%20%26%204%20%5C%5C%202%20%26%206%20%26%204%20%5C%5C%20%5Cend%7Bbmatrix%7D

所以
%5C%7C%20x%5C%7C%20%3D%20%5Ctext%7Bnp.linalg.norm%28x%2C%20axis%3D1%2C%20keepdims%3DTrue%29%7D%20%3D%20%5Cbegin%7Bbmatrix%7D%205%20%5C%5C%20%5Csqrt%7B56%7D%20%5C%5C%20%5Cend%7Bbmatrix%7D%5Ctag%7B4%7D

x%5C_normalized%20%3D%20%5Cfrac%7Bx%7D%7B%5C%7C%20x%5C%7C%7D%20%3D%20%5Cbegin%7Bbmatrix%7D%200%20%26%20%5Cfrac%7B3%7D%7B5%7D%20%26%20%5Cfrac%7B4%7D%7B5%7D%20%5C%5C%20%5Cfrac%7B2%7D%7B%5Csqrt%7B56%7D%7D%20%26%20%5Cfrac%7B6%7D%7B%5Csqrt%7B56%7D%7D%20%26%20%5Cfrac%7B4%7D%7B%5Csqrt%7B56%7D%7D%20%5C%5C%20%5Cend%7Bbmatrix%7D%5Ctag%7B5%7D

可以注意到,无论矩阵的维数如何,这个函数都能很好地工作:这被称为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:

  • 对于x%20%5Cin%20%5Cmathbb%7BR%7D%5E%7B1%5Ctimes%20n%7D
    %5Cbegin%7Bpmatrix%7D%20softmax%28x%29%20%26%3D%20softmax%5Cleft%28%5Cbegin%7Bbmatrix%7D%20x_1%20%26%26%20x_2%20%26%26%20...%20%26%26%20x_n%20%5Cend%7Bbmatrix%7D%5Cright%29%20%5C%5C%26%3D%20%5Cbegin%7Bbmatrix%7D%20%5Cfrac%7Be%5E%7Bx_1%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_j%7D%7D%20%26%26%20%5Cfrac%7Be%5E%7Bx_2%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_j%7D%7D%20%26%26%20...%20%26%26%20%5Cfrac%7Be%5E%7Bx_n%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_j%7D%7D%20%5Cend%7Bbmatrix%7D%20%5Cend%7Bpmatrix%7D
  • 对于矩阵x%20%5Cin%20%5Cmathbb%7BR%7D%5E%7Bm%5Ctimes%20n%7D , x_%7Bij%7D为矩阵第i行第j列的元素,有:

%5Cbegin%7Bpmatrix%7D%20softmax%28x%29%20%26%3D%20softmax%5Cbegin%7Bbmatrix%7D%20x_%7B11%7D%20%26%20x_%7B12%7D%20%26%20x_%7B13%7D%20%26%20%5Cdots%20%26%20x_%7B1n%7D%20%5C%5C%20x_%7B21%7D%20%26%20x_%7B22%7D%20%26%20x_%7B23%7D%20%26%20%5Cdots%20%26%20x_%7B2n%7D%20%5C%5C%20%5Cvdots%20%26%20%5Cvdots%20%26%20%5Cvdots%20%26%20%5Cddots%20%26%20%5Cvdots%20%5C%5C%20x_%7Bm1%7D%20%26%20x_%7Bm2%7D%20%26%20x_%7Bm3%7D%20%26%20%5Cdots%20%26%20x_%7Bmn%7D%20%5Cend%7Bbmatrix%7D%20%5C%5C%20%5C%5C%26%3D%20%5Cbegin%7Bbmatrix%7D%20%5Cfrac%7Be%5E%7Bx_%7B11%7D%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_%7B1j%7D%7D%7D%20%26%20%5Cfrac%7Be%5E%7Bx_%7B12%7D%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_%7B1j%7D%7D%7D%20%26%20%5Cfrac%7Be%5E%7Bx_%7B13%7D%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_%7B1j%7D%7D%7D%20%26%20%5Cdots%20%26%20%5Cfrac%7Be%5E%7Bx_%7B1n%7D%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_%7B1j%7D%7D%7D%20%5C%5C%20%5Cfrac%7Be%5E%7Bx_%7B21%7D%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_%7B2j%7D%7D%7D%20%26%20%5Cfrac%7Be%5E%7Bx_%7B22%7D%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_%7B2j%7D%7D%7D%20%26%20%5Cfrac%7Be%5E%7Bx_%7B23%7D%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_%7B2j%7D%7D%7D%20%26%20%5Cdots%20%26%20%5Cfrac%7Be%5E%7Bx_%7B2n%7D%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_%7B2j%7D%7D%7D%20%5C%5C%20%5Cvdots%20%26%20%5Cvdots%20%26%20%5Cvdots%20%26%20%5Cddots%20%26%20%5Cvdots%20%5C%5C%20%5Cfrac%7Be%5E%7Bx_%7Bm1%7D%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_%7Bmj%7D%7D%7D%20%26%20%5Cfrac%7Be%5E%7Bx_%7Bm2%7D%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_%7Bmj%7D%7D%7D%20%26%20%5Cfrac%7Be%5E%7Bx_%7Bm3%7D%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_%7Bmj%7D%7D%7D%20%26%20%5Cdots%20%26%20%5Cfrac%7Be%5E%7Bx_%7Bmn%7D%7D%7D%7B%5Csum_%7Bj%7De%5E%7Bx_%7Bmj%7D%7D%7D%20%5Cend%7Bbmatrix%7D%20%5C%5C%20%5C%5C%20%26%3D%20%5Cbegin%7Bpmatrix%7D%20softmax%5Ctext%7B%28first%20row%20of%20x%29%7D%20%5C%5C%20softmax%5Ctext%7B%28second%20row%20of%20x%29%7D%20%5C%5C%20%5Cvdots%20%5C%5C%20softmax%5Ctext%7B%28last%20row%20of%20x%29%7D%20%5C%5C%20%5Cend%7Bpmatrix%7D%20%5Cend%7Bpmatrix%7D

Notes:m表示训练样本的数量,每个样本在矩阵中占一列,每个特征在矩阵中占一行。

Notes:从上面的公式可以看出,在转置前,训练样本为按行排列的,其特征值按列排列。

softmax应当作用于每个训练样本的所有特征值上,所以softmax将会是逐列作用于矩阵的(转置后)。

不过在这个练习中,主要是为了熟悉python的使用,因而使用简单的矩阵m%5Ctimes%20n,即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机制很有用。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2022年3月16日 下午5:06
下一篇 2022年3月16日 下午5:30

相关推荐