吴恩达深度学习 | (5) 神经网络与深度学习专项课程第三周编程作业

吴恩达深度学习专项课程的所有实验均采用Jupyter Notebooks实现,不熟悉的朋友可以提前使用一下Notebooks。本周的实验主要是训练一个单隐层神经网络,进行2分类任务。采用的数据集都是平面数据集(2维数据集,输入特征数=2)。

目录

1.实验综述

2.导入必要的包

3.数据集

4.简单逻辑回归

5.神经网络模型

6.在其他数据集上进行尝试

 

1.实验综述

2.导入必要的包

import numpy as np
import matplotlib.pyplot as plt
from testCases import * #提供一些测试用例  定义在testCases.py文件中
import sklearn #提供简单高效的数据挖掘和分析工具
import sklearn.datasets
import sklearn.linear_model
#提供本实验中可以用到的各种有用的函数
#这些函数定义在 planar_utils.py文件中
from planar_utils import plot_decision_boundary,sigmoid,load_planar_dataset,load_extra_datasets

3.数据集

首先看一下待分类数据集,下面的代码将会加载一个2分类数据集。

  • 可视化数据集
X,Y=load_planar_dataset()  #加载2维数据集 X:特征矩阵(n_x,m)(每一列是样本的特征向量(包含两个特征)) Y:(1,m)样本标签
#可视化该数据集 形状是一朵“花” 红色代表y=0,蓝色y=1.实验任务是构建模型分类这些数据
#Y是一个用二维数组表示的行向量(1,m)  使用np.squeeze(Y) 把Y变为包含m个元素的一维数组
plt.scatter(X[0,:],X[1,:],c=np.squeeze(Y),s=40,cmap=plt.cm.Spectral)

def load_planar_dataset():
    np.random.seed(1)
    m = 400 # number of examples
    N = int(m/2) # number of points per class
    D = 2 # dimensionality
    X = np.zeros((m,D)) # data matrix where each row is a single example
    Y = np.zeros((m,1), dtype='uint8') # labels vector (0 for red, 1 for blue)
    a = 4 # maximum ray of the flower
    
    #生成数据集
    for j in range(2):
        ix = range(N*j,N*(j+1))
        t = np.linspace(j*3.12,(j+1)*3.12,N) + np.random.randn(N)*0.2 # theta
        r = a*np.sin(4*t) + np.random.randn(N)*0.2 # radius
        X[ix] = np.c_[r*np.sin(t), r*np.cos(t)]
        Y[ix] = j
        
    X = X.T #每列表示一个样本 (D,m)
    Y = Y.T #(1,m)

    return X, Y

 

  • 查看数据集大小 
#查看样本数  X,Y的形状
shape_X=X.shape
shape_Y=Y.shape

m=X.shape[1]  #样本数为矩阵X的列数   X:nx*m (nx=2)
print ('The shape of X is: ' + str(shape_X))
print ('The shape of Y is: ' + str(shape_Y))
print ('I have m = %d training examples!' % (m))

4.简单逻辑回归

再使用神经网络进行分类之前,先使用逻辑回归分类器分类上述数据集。

直接调用sklearn封装好的逻辑回归模型

  • 训练逻辑回归分类器
#训练逻辑回归分类器
clf = sklearn.linear_model.LogisticRegressionCV(); #使用默认的超参数
clf.fit(X.T,Y.T)  #X.T (m,nx) Y.T(m,1)  每一行代表一个样本
  • 绘制决策边界,计算在训练集上的准确率
#绘制逻辑回归的决策边界
plot_decision_boundary(lambda x: clf.predict(x),X,np.squeeze(Y))
plt.title('Logistic Regression')

#打印准确率
LR_predictions=clf.predict(X.T) #预测的label
print ('Accuracy of logistic regression: %d ' % float((np.dot(Y,LR_predictions) + np.dot(1-Y,1-LR_predictions))/float(Y.size)*100) +
       '% ' + "(percentage of correctly labelled datapoints)")
def plot_decision_boundary(model, X, y):
    # Set min and max values and give it some padding
    #确定网格的边界
    x_min, x_max = X[0, :].min() - 1, X[0, :].max() + 1
    y_min, y_max = X[1, :].min() - 1, X[1, :].max() + 1
    h = 0.01
    # Generate a grid of points with distance h between them
    #生成网格点
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    # Predict the function value for the whole grid
    #预测每个网格点的label
    Z = model(np.c_[xx.ravel(), yy.ravel()])
    #转为网格的形状
    Z = Z.reshape(xx.shape)
    # Plot the contour and training examples
    #绘制等高线图 渲染决策区域和决策边界
    plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
    plt.ylabel('x2')
    plt.xlabel('x1')
    #画出数据集的样本点
    plt.scatter(X[0, :], X[1, :], c=y, cmap=plt.cm.Spectral)

 

  • 总结

上图中的数据集是线性不可分的,所以逻辑回归分类器(线性分类器)的效果不是很好。接下来试一下神经网络分类器。

5.神经网络模型

训练单隐层神经网络模型。

  • 网络结构

  • 数学表达式

  • 构建神经网络的一般方法

  • 定义神经网络结构

def layer_sizes(X,Y):
    '''
    参数:
    X:数据集样本特征矩阵  (n_x,m)
    Y: 数据集样本对于标签   (1,m)
    
    返回:
    n_x:输入层单元数
    n_h:隐层单元数
    n_y:输出层单元数
    '''
    n_x=X.shape[0] #样本特征向量维数(特征数量)
    n_h=4
    n_y=Y.shape[0]  
    
    return (n_x,n_h,n_y)

X_assess, Y_assess = layer_sizes_test_case()
(n_x, n_h, n_y) = layer_sizes(X_assess, Y_assess)
print("The size of the input layer is: n_x = " + str(n_x))
print("The size of the hidden layer is: n_h = " + str(n_h))
print("The size of the output layer is: n_y = " + str(n_y))

  • 随机初始化模型参数

确保参数的维度是正确的。

随机初始化权重参数,偏置参数初始化为0.

def initialize_parameters(n_x,n_h,n_y):
    '''
    参数:
    n_x:输入层单元数
    n_h:隐层单元数
    n_y:输出层单元数
    
    返回:
    初始化的参数,字典形式(若每一列是一个样本的特征向量话,W的维度是后一层单元数*前一层单元数)
    W1:n_h*n_x 
    b1:n_h*1
    W2:n_y*n_h
    b2:n_y*1
    '''
    np.random.seed(2) #设置随机种子 确保生成的随机数不变
    
    W1=np.random.randn(n_h,n_x)*0.01
    b1=np.zeros((n_h,1))
    W2=np.random.randn(n_y,n_h)*0.01
    b2=np.zeros((n_y,1))
    
    assert (W1.shape == (n_h, n_x))
    assert (b1.shape == (n_h, 1))
    assert (W2.shape == (n_y, n_h))
    assert (b2.shape == (n_y, 1))
    
    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2}
    return parameters

n_x, n_h, n_y = initialize_parameters_test_case()

parameters = initialize_parameters(n_x, n_h, n_y)
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))

  • 迭代

1)前向传播:

def forward_propagation(X,parameters):
    '''
    X:数据集的输入特征矩阵 每一列是一个样本的输入特征向量 (n_x,m)
    parameters:模型参数 字典形式
    
    返回:
    A2:神经网络的输出
    cache:存储中间结果Z1,A1,Z2,A2  字典形式
    '''
    
    W1=parameters['W1'] #(n_h,n_x)
    b1=parameters['b1']  #(n_h,1)
    W2=parameters['W2'] #(n_y=1,n_h)
    b2=parameters['b2'] #(n_y=1,1)
    
    Z1=np.dot(W1,X)+b1 #(n_h,m)
    A1=np.tanh(Z1)  #(n_h,m) 隐层使用tanh激活函数
    Z2=np.dot(W2,A1)+b2 #(n_y=1,m)
    A2=sigmoid(Z2) #2分类 输出层用sigmoid激活函数(planar_utils.py中定义) (n_y=1,m)
    
    assert(A2.shape == (1, X.shape[1])) #(1,m)
    
    #缓存中间结果 便于反向传播计算梯度
    cache = {"Z1": Z1,
             "A1": A1,
             "Z2": Z2,
             "A2": A2}
    return A2,cache

X_assess, parameters = forward_propagation_test_case()
A2, cache = forward_propagation(X_assess, parameters)
# Note: we use the mean here just to make sure that your output matches ours. 
print(np.mean(cache['Z1']) ,np.mean(cache['A1']),np.mean(cache['Z2']),np.mean(cache['A2']))  
    

2)计算代价函数

def compute_cost(A2,Y,parameters):
    '''
    计算交叉熵损失 上式(13)
    
    参数:
    A2: 神经网络输出 (1,m) 预测概率
    Y: 样本真实标签 (1,m)
    parameters:模型参数
    
    返回:
    cost:交叉熵损失 上式(13)
    '''

    cost=-np.mean(Y*np.log(A2)+(1-Y)*np.log(1-A2)) #*等价于np.multiply 对应位置元素相乘
    
    assert(isinstance(cost,float))
    
    return cost

A2, Y_assess, parameters = compute_cost_test_case()
print("cost = " + str(compute_cost(A2, Y_assess, parameters)))

3)反向传播(向量化)

def backward_propagation(parameters,cache,X,Y):
    '''
    实现神经网络的反向传播
    
    参数:
    parameters:模型参数
    cache:存储前向传播的中间结果 Z1,A1,Z2,A2
    X:数据集特征矩阵 (n_x,m)
    Y:数据集样本对应标签 (1,m)
    
    返回:
    grads:模型参数的梯度 字典形式
    '''
    m=X.shape[1]
    
    A1=cache['A1'] #(n_h,m)
    A2=cache['A2'] #(1,m)
    
    W1=parameters['W1']
    W2=parameters['W2']
    
    dZ2=A2-Y  #(1,m)
    dW2=np.dot(dZ2,A1.T)/m #(1,n_h)
    db2=np.mean(dZ2,axis=1,keepdims=True) #标量
    dZ1=np.dot(W2.T,dZ2)*(1-np.power(A1,2)) #(n_h,m) a=g(z)=tanz求导 1-a^2
    dW1=np.dot(dZ1,X.T)/m #(n_h,n_x)
    db1=np.mean(dZ1,axis=1,keepdims=True) #(n_h,1)
    #keepdims=True 保持维度,用2维数组表示向量
    
    grads = {"dW1": dW1,
             "db1": db1,
             "dW2": dW2,
             "db2": db2}
    
    return grads

parameters, cache, X_assess, Y_assess = backward_propagation_test_case()

grads = backward_propagation(parameters, cache, X_assess, Y_assess)
print ("dW1 = "+ str(grads["dW1"]))
print ("db1 = "+ str(grads["db1"]))
print ("dW2 = "+ str(grads["dW2"]))
print ("db2 = "+ str(grads["db2"]))

 

4)使用梯度下降法更新参数

def update_parameters(parameters,grads,learning_rate=1.2):
    '''
    使用梯度下降法更新参数
    
    参数:
    parameters:模型参数
    grads:模型参数的梯度
    learning_rate:学习率
    
    返回:
    parameters:更新后的参数
    '''
    
    W1=parameters['W1']
    b1=parameters['b1']
    W2=parameters['W2']
    b2=parameters['b2']
    
    dW1=grads['dW1']
    db1=grads['db1']
    dW2=grads['dW2']
    db2=grads['db2']
    
    W1=W1-learning_rate*dW1
    b1=b1-learning_rate*db1
    W2=W2-learning_rate*dW2
    b2=b2-learning_rate*db2
    
    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2}
    
    return parameters

parameters, grads = update_parameters_test_case()
parameters = update_parameters(parameters, grads)

print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))

  • 把以上三部分汇总到nn_model()中
def nn_model(X,Y,n_h,num_iterations=10000,print_cost=False):
    '''
    参数:
    X:数据集特征矩阵 (n_x,m)
    Y:数据集样本标签 (1,m)
    n_h:隐层单元数量
    num_iterations:梯度下降迭代次数
    print_cost:若为True,没1000次迭代 打印一次cost
    
    返回:
    parameters:学习好的参数
    costs:每1000次迭代后的cost
    '''
    np.random.seed(3)
    n_x=layer_sizes(X,Y)[0]
    n_y=layer_sizes(X,Y)[2]
    
    parameters=initialize_parameters(n_x,n_h,n_y) #随机初始化模型参数
    W1=parameters['W1']
    b1=parameters['b1']
    W2=parameters['W2']
    b2=parameters['b2']
    
    costs=[]
    #梯度下降法迭代过程
    
    for i in range(num_iterations): #使用batch GD,每次使用全部的样本计算梯度,做一次梯度下降
        
        A2,cache=forward_propagation(X,parameters) #前向传播
        cost=compute_cost(A2,Y,parameters) #计算cost
        grads=backward_propagation(parameters,cache,X,Y) #反向传播
        parameters=update_parameters(parameters,grads)#更新参数
        
        if print_cost and i%1000==0:
            costs.append(cost)
            print ("Cost after iteration %i: %f" %(i, cost))
    return parameters,costs

X_assess, Y_assess = nn_model_test_case()

parameters,_= nn_model(X_assess, Y_assess, 4, num_iterations=10000, print_cost=True)
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))

 

  • 预测

def predict(parameters,X):
    '''
    参数:
    parameters:训练好的参数 字典形式
    X:数据集样本特征矩阵 (n_x,m)
    
    返回:
    predictions:模型在数据集X上的预测结果 red:0/blue:1
    '''
    A2,cache=forward_propagation(X,parameters)
    predictions=np.around(A2)
    '''
    predictions[A2>0.5]=1
    predictions[A2<=0.5]=0
    '''
    
    return predictions
    
parameters, X_assess = predict_test_case()

predictions = predict(parameters, X_assess)
print("predictions mean = " + str(np.mean(predictions)))    

1)查看神经网络模型在planar数据集上的分类效果

#训练一个有n_h个隐藏单元的单隐层神经网络
parameters,_=nn_model(X,Y,n_h=4,num_iterations=10000,print_cost=True)

#绘制决策边界
plot_decision_boundary(lambda x:predict(parameters,x.T),X,np.squeeze(Y))
plt.title("Decision Boundary for hidden layer size " + str(4))

 

 

2)打印模型在训练集上的准确率

#打印模型在训练上的准确率
predictions = predict(parameters, X)
print ('Accuracy: %d' % float((np.dot(Y,predictions.T) + np.dot(1-Y,1-predictions.T))/float(Y.size)*100) + '%')

 效果比逻辑回归分类器好很多,神经网络可以学习得到高度非线性的决策边界。

  • 尝试不同的隐层单元数
plt.figure(figsize=(16, 32))
hidden_layer_sizes = [1, 2, 3, 4, 5, 20, 50] #不同的隐层单元数
for i, n_h in enumerate(hidden_layer_sizes):
    plt.subplot(5, 2, i+1)
    plt.title('Hidden Layer of size %d' % n_h)
    parameters,_= nn_model(X, Y, n_h, num_iterations = 5000)
    plot_decision_boundary(lambda x: predict(parameters, x.T), X, np.squeeze(Y))
    predictions = predict(parameters, X)
    accuracy = float((np.dot(Y,predictions.T) + np.dot(1-Y,1-predictions.T))/float(Y.size)*100)
    print ("Accuracy for {} hidden units: {} %".format(n_h, accuracy))
    

 

 

  • 其他尝试

  • 实验总结

6.在其他数据集上进行尝试

# 加载数据集(4个)
noisy_circles, noisy_moons, blobs, gaussian_quantiles, no_structure = load_extra_datasets()

datasets = {"noisy_circles": noisy_circles,
            "noisy_moons": noisy_moons,
            "blobs": blobs,
            "gaussian_quantiles": gaussian_quantiles}


dataset = "noisy_circles" #可以更改为不同的数据集 
#选择noisy_moons数据集
X, Y = datasets[dataset]
X, Y = X.T, Y.reshape(1, Y.shape[0]) #X转型为特征矩阵(n_x,m) 每一列为一个样本的特征向量
#Y转型为行向量 (1,m)

# 对标签Y进行处理 进行2分类 0/1
if dataset == "noisy_circles":
    Y = Y%2

#可视化数据集
plt.scatter(X[0, :], X[1, :], c=np.squeeze(Y), s=40, cmap=plt.cm.Spectral);
  • 可视化数据集

  • 训练单隐层神经网络  尝试不同隐层单元数 
#训练单隐层神经网络  尝试不同隐层单元数 
plt.figure(figsize=(16, 32))
hidden_layer_sizes = [1, 2, 3, 4, 5, 20, 50]
for i, n_h in enumerate(hidden_layer_sizes):
    plt.subplot(5, 2, i+1)
    plt.title('Hidden Layer of size %d' % n_h)
    parameters,_ = nn_model(X, Y, n_h, num_iterations = 5000)
    plot_decision_boundary(lambda x: predict(parameters, x.T), X,np.squeeze(Y))
    predictions = predict(parameters, X)
    accuracy = float((np.dot(Y,predictions.T) + np.dot(1-Y,1-predictions.T))/float(Y.size)*100)
    print ("Accuracy for {} hidden units: {} %".format(n_h, accuracy))
  • 训练集准确率
  • 决策边界

 

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值