吴恩达深度学习_1_Week3浅层神经网络

1、本模型所用包
2、数据集
3、简单的逻辑回归分类算法
4、神经网络模型
5、所构建的神经网络模型在其它数据集上表现


第一门课:神经网络和深度学习
第三周:浅层神经网络

一、包

import numpy as np
import matplotlib.pyplot as plt    # 在python中绘制图像
from testCases import *            # testCases提供一些测试示例来验证函数的正确性
import sklearn                     # 为数据挖掘和数据分析提供简单高效的工具
import sklearn.datasets
import sklearn.linear_model
from planar_utils import plot_decision_boundary,sigmoid,load_planar_dataset,load_extra_datasets  
# 提供此项目中各种有效函数

np.random.seed(1)                  # 设置随机种子使得结果一致

二、数据集

在这里插入图片描述

# 数据以花朵的样例呈现,y=0为红色,y=1为蓝色;目标在于建立一个模型来适应数据
X, Y = load_planar_dataset()
# 可视化数据
plt.scatter(X[0, :],X[1, :],c=Y[0, :],s=40,cmap=plt.cm.Spectral)
# 数据由X矩阵包含x1和x2两类特征,Y向量包含red=0,blue=1两类标签组成;
# 以下代码得出X和Y的具体规模,以及得出训练集的数量
shape_X = X.shape      # 将变量 X 的形状信息赋值给变量 shape_X
shape_Y = Y.shape
m = X.shape[1]         # X包含两个特征代表有两层,看规模m即读取列数
print('X的规模是:'+str(shape_X))
print('Y的规模是:'+str(shape_Y))
print('拥有的训练集数据数量为 m=%d ' % m)

代码解释:

使用 Matplotlib 库中的 scatter 函数绘制散点图,并根据给定的颜色标签 Y 对散点进行着色
1. X[0, :] 和 X[1, :]:访问变量 X 中的数据。假设 X 是一个二维数组,其中包含了两个特征维度
2. X[0, :]: 表示取出第一个特征维度的所有值, X[1, :] 表示取出第二个特征维度的所有值。这样,获取了两个一维数组,用于表示散点图的 x 和 y 坐标
3. Y[0, :]:访问变量 Y 中的数据。假设 Y 是一个包含了颜色标签的数组,与 X 的数据对应
4. Y[0, :] 表示取出第一个颜色标签维度的所有值。这样,获取了一个一维数组,用于指定每个散点的颜色标签。
5. cmap=plt.cm.Spectral:指定了用于颜色映射的 colormap。使用 plt.cm.Spectral,它是 Matplotlib 中的一种预定义的颜色映射方案
6. plt.scatter(X[0, :], X[1, :], c=Y[0, :], s=40, cmap=plt.cm.Spectral):这一行代码调用 scatter 函数来绘制散点图
7. X[0, :] X[1, :] 表示散点的 x 和 y 坐标,c=Y[0, :] 表示散点的颜色标签,s=40 指定了散点的大小为 40,cmap=plt.cm.Spectral 指定了颜色映射方案
8. 这段代码的目的是根据给定的特征数据 X 和颜色标签 Y,绘制出一个散点图。散点图中的每个散点表示一个数据样本,其位置由特征数据决定,颜色由颜色标签决定
shape函数的用法:
1. 对于矩阵:shape[0]---读取数组的行数;shape[1]---读取数组的列数;shape[-1]---代表最后一个维度,如在二维张量中表示列数
2. 对于图像:shape[0]---图片高;shape[1]---图片长;shape[2]---图片通道数

三、运用逻辑回归进行分类预测

# 训练逻辑回归分类器
clf = sklearn.linear_model.LogisticRegressionCV()
clf.fit(X.T, Y[0, :].T)
# 对于逻辑回归绘制决策边界
plot_decision_boundary(lambda x: clf.predict(x), X, Y[0, :])
plt.title("Logistic Regression")
# 绘制准确率
LR_predictions = clf.predict(X.T)
print('逻辑回归预测的准确率为: %d ' % float((np.dot(Y,LR_predictions) + np.dot(1-Y,1-LR_predictions))/float(Y.size)*100) + '% ' + "(正确标记数据点的百分比)")

在这里插入图片描述
解释:数据集不是线性可分的,因此逻辑回归效果不佳。希望神经网络能做得更好。
代码解释:

使用scikit-learn(sklearn)库中的 LogisticRegressionCV 类来创建一个逻辑回归分类器,并使用训练数据进行模型的训练
1. sklearn.linear_model.LogisticRegressionCV():创建了一个 LogisticRegressionCV 类的实例,用于实现逻辑回归分类器
2. clf.fit(X.T, Y[0, :].T):这一行代码调用逻辑回归分类器的fit方法,用于训练模型
3. fit 方法需要传入训练数据和对应的标签
4. X.T 表示将特征数据 X 进行转置,以匹配逻辑回归模型所期望的输入格式
5. Y[0, :] 表示取出标签数据的第一个维度的所有值
6. .T 表示将其转置,以匹配逻辑回归模型所期望的标签格式。
7. clf:这部分代码将训练好的逻辑回归分类器保存在变量 clf 中,以便后续对新数据进行预测或其他操作。
这段代码的目的是使用逻辑回归分类器对训练数据进行训练,以学习特征数据和标签之间的关系
使用训练好的逻辑回归分类器对训练数据进行预测,并计算预测准确率
1. LR_predictions = clf.predict(X.T):调用逻辑回归分类器的 predict 方法,对训练数据 X.T 进行预测
2. np.dot(Y, LR_predictions):计算了两个数组 Y 和 LR_predictions 的点积,实际上是对应元素相乘后的求和运算,用于计算预测结果与真实标签的匹配情况。
3. np.dot(1-Y, 1-LR_predictions):计算了真实标签与预测结果不匹配的情况,即真实标签为 0,而预测结果也为 0 的数量。
4. float((np.dot(Y, LR_predictions) + np.dot(1-Y, 1-LR_predictions))/float(Y.size)*100):计算了预测准确率。
首先,通过求和计算了预测结果与真实标签匹配的数量。然后,将匹配数量除以总样本数量 Y.size,并将结果乘以 100,得到了百分比形式的准确率。
这段代码的目的是使用训练好的逻辑回归分类器对训练数据进行预测,并计算预测准确率

四、神经网络模型

由于逻辑回归的预测准确率不高,训练一个含义一个隐藏层的神经网络—对于a>0.5输出y=1其余输出y=0
一般建立单个神经网络:

  1. 定义神经网络结构(输入单元、隐藏层以及其它)
  2. 初始化模型参数
  3. 循环-运用前向传播-计算损失值;运用后向传播-得到梯度
  4. 更新参数

1、确定神经网络的结构

在这里插入图片描述

# 根据X和Y的规模确定输入层、输出层的规模,隐藏层设置为4层
# Arguments:
#     X -- 输入数据的规模(输入尺寸,实例数)    Y -- 标记规模(输出尺寸,实例数)
# Returns:
#     n_x -- 输入层规模;    n_h -- 隐藏层规模;     n_y -- 输出层规模
def layer_sizes(X,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("输入层的规模为: n_x = " + str(n_x))
print("隐藏层的规模为: n_h = " + str(n_h))
print("输出层的规模为: n_y = " + str(n_y))

代码解释:

计算神经网络的层大小(神经元数量)
1. def layer_sizes(X, Y)::定义函数 layer_sizes,它接受两个参数 X 和 Y,分别表示输入特征数据和标签数据
2. n_x = X.shape[0]:获取输入特征数据 X 的形状信息,并将其第一个维度的大小赋值给变量 n_x。
这里假设 X 是一个二维数组,其中第一个维度表示样本数量,第二个维度表示特征数量。因此,X.shape[0] 就表示样本数量。
3. n_h = 4:将隐藏层的神经元数量设定为 4
4. n_y = Y.shape[0]:获取标签数据 Y 的形状信息,Y.shape[0] 就表示样本数量
5. X_assess, Y_assess = layer_sizes_test_case():调用名为 layer_sizes_test_case 的测试函数,用于生成示例数据集 X_assess 和 Y_assess,用于后续的函数调用。

2、初始化模型的参数—W1,b1,W2,b2

# 权重W,使用np.random.randn(a,b) * 0.01,采用随机初始化shape (a,b)
# 偏差b,使用np.zeros((a,b)),可初始化为零
def initialize_parameters(n_x,n_h,n_y):
    np.random.seed(2)
    W1 = np.random.randn(n_h, n_x) * 0.01
    b1 = np.zeros((n_h,1))                  # b的行数为隐藏层数,列数为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中
    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"]))

3、循环

(1)前向传播

使用parameters从字典中检索出每个参数—实现前向传播,计算出Z和A

# Argument:
#   X -- 输入数据规模 (n_x, m)
#   parameters -- 包含模型参数的python字典 (初始化函数的输出)
# Returns:
#   A2 -- The sigmoid output of the second activation
#   cache -- a dictionary containing "Z1", "A1", "Z2" and "A2"
def forward_propagation(X,parameters):
# 从字典参数中检索每个参数
   W1 = parameters["W1"]
   W2 = parameters["W2"]
   b1 = parameters["b1"]
   b2 = parameters["b2"]
# 运用前向传播计算A2
   Z1 = np.dot(W1,X)+b1
   A1 = np.tanh(Z1)            # 输出层运用tanh激励函数
   Z2 = np.dot(W2,A1)+b2
   A2 = np.tanh(Z2)
# 断言语句确定维度
   assert (A2.shape == (1,X.shape[1]))
# 用cache存储Z1,A1,Z2,A2
   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)
# 这里使用平均值确保输出与正确输出匹配
print(np.mean(cache['Z1']),np.mean(cache['A1']),np.mean(cache['Z2']),np.mean(cache['A2']))
print(A2.shape)
print(X_assess.shape)

(2)计算损失函数J

在这里插入图片描述

# TIP:logprobs = np.multiply(np.log(A2),Y)    cost = - np.sum(logprobs)
def compute_cost(A2,Y,parameters):
    m = Y.shape[1]
    logprobs = np.multiply(np.log(A2), Y) + np.multiply(np.log(1 - A2), (1 - Y))
    cost = - (1.0 / m) * np.sum(logprobs)
    cost = np.squeeze(cost)       # 确保cost是我们期待的维度
    assert (isinstance(cost, float))
    return cost
A2, Y_assess, parameters = compute_cost_test_case()
print("cost = " + str(compute_cost(A2, Y_assess, parameters)))

代码解释:

计算逻辑回归模型的损失函数(cost function)
1. m = Y.shape[1]:获取标签数据 Y 的形状信息,Y.shape[1] 表示样本数量。
2. logprobs = np.multiply(np.log(A2), Y) + np.multiply(np.log(1 - A2), (1 - Y)):计算损失函数中的每个样本的损失值
A2 表示模型的预测结果,Y 表示真实标签数据。通过 np.log 函数和 np.multiply 函数,分别计算了预测结果与真实标签匹配的部分和不匹配的部分的损失值
3. cost = - (1.0 / m) * np.sum(logprobs):计算整个样本集的平均损失值,通过对 logprobs 求和,并乘以一个负数和一个缩放因子,得到平均损失值
4. cost = np.squeeze(cost):使用 np.squeeze 函数将损失值 cost 的维度压缩,确保其为我们期望的维度。这是为了消除不必要的维度,以便后续计算和比较。
5. assert (isinstance(cost, float)):使用断言语句检查 cost 是否为浮点数类型。如果不是浮点数类型,将会触发断言错误。
这段代码的目的是计算逻辑回归模型的损失函数,用于衡量模型预测结果与真实标签之间的差异

在这里插入图片描述

(3)反向传播—计算梯度

# TIP:1−𝑎2可以用(1 - np.power(A1, 2))
def backward_propagation(parameters, cache, X, Y):
    m = X.shape[1]
# 从字典中检索出参数
    W1 = parameters["W1"]
    W2 = parameters["W2"]
# 从cache中检索出A1,A2
    A1 = cache["A1"]
    A2 = cache["A2"]
# 反向传播,计算dW1, db1, dW2, db2
    dZ2 = A2 - Y
    dW2 = 1.0 / m * np.dot(dZ2, A1.T)
    db2 = 1.0 / m * np.sum(dZ2, axis=1, keepdims=True)
    dZ1 = np.dot(W2.T, dZ2) * (1 - np.power(A1, 2))
    dW1 = 1.0 / m * np.dot(dZ1, X.T)
    db1 = 1.0 / m * np.sum(dZ1, axis=1, keepdims=True)
    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"]))
# 运用梯度下降,用dW1,db1,dW2,db2更新W1,b1,W2,b2
def update_parameters(parameters,grads,learning_rate = 1.2):
# 检索参数
    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"]))

代码解释:

用于获取神经网络输入层的大小(输入特征数量)
1. layer_sizes(X, Y):调用了一个名为 layer_sizes 的函数,并传入输入特征数据 X 和标签数据 Y 作为参数。该函数返回一个包含层大小信息的元组 (n_x, n_h, n_y)2. layer_sizes(X, Y)[0]:使用索引 [0] 从返回的元组中获取第一个元素,即输入层的大小 n_x。
在元组中,各个元素的顺序与其在返回语句中的位置相对应,因此通过索引 [0] 可以获取到 n_x。
这段代码的目的是通过调用 layer_sizes 函数,获取神经网络输入层的大小(输入特征数量)。它利用元组的索引操作,从函数返回的结果中提取所需的层大小信息。

在这里插入图片描述

在这里插入图片描述

(4)将前三部分融合进nn_model()中—创建神经网络

# Arguments:
#     X -- dataset of shape (2, number of examples)
#     Y -- labels of shape (1, number of examples)
#     n_h -- size of the hidden layer
#     num_iterations -- Number of iterations in gradient descent loop
#     print_cost -- if True, print the cost every 1000 iterations
# Returns:
#     parameters -- parameters learnt by the model. They can then be used to predict.

def nn_model(X, Y, n_h, num_iterations = 10000, print_cost=False):
    np.random.seed(3)
    n_x = layer_sizes(X,Y)[0]
    n_y = layer_sizes(X,Y)[2]
# 初始化参数然后存储W1,W2,b1,b2
    parameters = initialize_parameters(n_x, n_h, n_y)
    W1 = parameters["W1"]
    b1 = parameters["b1"]
    W2 = parameters["W2"]
    b2 = parameters["b2"]
# 循环---梯度下降
    for i in range(0,num_iterations):
# 前向传播
        A2,cache = forward_propagation(X,parameters)
# 损失函数
        cost = compute_cost(A2,Y,parameters)
# 反向传播
        grads = backward_propagation(parameters,cache,X,Y)
# 梯度下降参数更新
        parameters = update_parameters(parameters,grads,learning_rate=1.2)
# 每1000次迭代打印一次成本
        if print_cost and i % 10000 == 0:
           print("迭代后的成本为 %i: %f" %(i, cost))
    return parameters
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"]))

在这里插入图片描述

(5)预测—使用前向传播来预测结果—red:0/blue:1

# TIP:假如要根据阈值将矩阵X的条目设置为0和1,可以执行:X_new = (X>threshold)
def predict(parameters,X):
# 使用前向传播计算可能性,使用0.5作为门槛区分出0/1
    A2, cache = forward_propagation(X, parameters)
    predictions = (A2 > 0.5)
    return predictions
parameters, X_assess = predict_test_case()
predictions = predict(parameters, X_assess)
print("平均预测率为 = " + str(np.mean(predictions)))
# 运行模型并查看其在平面数据集上的表现,使用单个隐藏层nh测试模型
# 使用单个隐藏层建立模型
parameters = nn_model(X, Y, n_h=4, num_iterations=10000, print_cost=True)
# 绘制出决策边界
plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y[0, :])
plt.title("对于隐藏层尺寸的决策边界为 " + str(4))
# 输出准确率
predictions = predict(parameters, X)
print('准确率: %d' % float((np.dot(Y,predictions.T) + np.dot(1-Y,1-predictions.T))/float(Y.size)*100) + '%')

(6)调整隐藏图层大小

# 以下代码可观察到模型在各种隐藏层大小下的不同行为
plt.figure(figsize=(16, 32))
hidden_layer_sizes = [1, 2, 3, 4, 5, 10, 20]
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, Y[0, :])
    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))
# 解释:较大的模型(具有更多隐藏层单元)能够更好拟合训练集,直到最终最大的模型过度拟合数据。
# 最佳隐藏层大小似乎约为 n_h = 5。事实上,这里的一个值似乎很好地拟合了数据,而不会引起明显的过拟合。
# 对于正则化,它允许使用非常大的模型(例如 n_h = 50),而无需过多的过度拟合。

五、其它数据集的表现

# Datasets
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_moons"

X, Y = datasets[dataset]
X, Y = X.T, Y.reshape(1, Y.shape[0])

# make blobs binary
if dataset == "blobs":
    Y = Y%2

# Visualize the data
plt.scatter(X[0, :], X[1, :], c=Y[0, :], s=40, cmap=plt.cm.Spectral)

Reference:
http://scs.ryerson.ca/~aharley/neural-networks/
http://cs231n.github.io/neural-networks-case-study/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值