003_wz_wed_DL_课程一第二周编程题(Logistic回归;神经网络思维;)

具有神经网络思维的Logistic回归

一、目的

搭建一个能够识别猫的简单的神经网络

二、训练集与测试集

百度网盘,提取码:1234

三、编程

注:本编程未使用提供的py文件——lr_utils.py
本次编程所需的所有模块

import h5py
import numpy as np
import matplotlib.pyplot as plt
from skimage import transform

numpy :是用Python进行科学计算的基本软件包;
h5py:是与H5文件中存储的数据集进行交互的常用软件包;
matplotlib:是一个著名的库,用于在Python中绘制图表;
skimage:在本次编程用来修改图片的维度

1.导入原始数据集进行剖析

将训练集保存到train_dataset,测试集保存到test_dataset

# 导入原始数据集
train_dataset = h5py.File("./datasets/train_catvnoncat.h5", "r")
test_dataset = h5py.File("./datasets/test_catvnoncat.h5", "r")

使用for循环查看训练集中的键:

for key in train_dataset.keys():
    print(key)

训练集中我们可以得到三个键:
train_set_x :保存的是训练集里面的图像数据;
train_set_y :保存的是训练集的图像对应的分类值(0 | 1,0表示不是猫,1表示是猫);
list_classes : 保存的是以bytes类型保存的两个字符串数据,数据为:b’non-cat’ b’cat’]
测试集中是test_set_xtest_set_ylist_classes
这些数据都可以用print函数打印出来查看
在这里插入图片描述
我们单独将训练集和测试集的原始数据和标签导出,使用x代表数据,y代表标签

# 单独导出训练集和测试集的原始数据和标签
train_set_x_orig = np.array(train_dataset["train_set_x"][:])
train_set_y_orig = np.array(train_dataset["train_set_y"][:])
test_set_x_orig = np.array(test_dataset["test_set_x"][:])
test_set_y_orig = np.array(test_dataset["test_set_y"][:])

我们可以选择任意一个样本查看一下是什么样的,以及标签

# 查看第三张图片和标签
plt.imshow(train_set_x_orig[2])
print(train_set_y_orig[2])
plt.show()

在这里插入图片描述
在这里插入图片描述
我们再查看一下数据的维度

print(train_set_x_orig.shape, train_set_y_orig.shape,
      test_set_x_orig.shape, test_set_y_orig.shape)

在这里插入图片描述
(209, 64, 64, 3)表示训练集有209张rgb图片,每个通道图片的大小是64*64的;(209,)表示标签的形状;也能看到测试集有50张图片

2.处理数据的维度

这一步非常重要,要将数据的维度处理成为神经网络输入的维度,很多问题都是由于维度没有处理好导致的。
现在我们数据的维度是:

数据集原始维度
train_set_x_orig(209, 64, 64, 3)
train_set_y_orig(209,)
test_set_x_orig(50, 64, 64, 3)
test_set_y_orig(50,)

现在让我们来回顾一下神经网络的前向传播是怎样的:
在这里插入图片描述
对于某一个训练样本i输入它的n个特征值,每个特征值乘上权重再加上b,我们将其结果记为 z ( i ) z^{(i)} z(i),即 z ( i ) = x i 1 w 1 + x i 2 w 2 + . . . + x i n w n + b z^{(i)}=x_{i1}w_1+x_{i2}w_2+...+x_{in}w_n+b z(i)=xi1w1+xi2w2+...+xinwn+b,经过激活函数a,就可以得到预测值,现在我们若有m个样本,每个样本具有n个特征,我们就能得到m个z,则我们需要对其进行向量化,去掉for循环,加快程序运行速度
在这里插入图片描述
由公式 Z = w T X + b Z=w^TX+b Z=wTX+b得:

在这里插入图片描述
那么对于本次数据集我们就可以得到我们需要的维度:
在这里插入图片描述

数据集原始维度需要的维度
train_set_x_orig=X(209, 64, 64, 3)(12288,209)
train_set_y_orig= y ^ \hat{y} y^(209,)(1, 209)
test_set_x_orig(50, 64, 64, 3)(12288,50)
test_set_y_orig(50,)(1, 50)

原始文档在此
现在我们开始处理数据维度,在此期间可以多次使用shape查看维度是否正确

# 处理数据的维度
m = train_set_x_orig.shape[0]
train_set_x_tran = train_set_x_orig.reshape((m, -1)).T
train_set_y_tran = train_set_y_orig.reshape((m, -1)).T
m = test_set_x_orig.shape[0]
test_set_x_tran = test_set_x_orig.reshape((m, -1)).T
test_set_y_tran = test_set_y_orig.reshape((m, -1)).T

查看数据的维度是否处理的正确

print(train_set_x_tran.shape, train_set_y_tran.shape, test_set_x_tran.shape, test_set_y_tran.shape)

在这里插入图片描述

3.标准化数据

对数据进行标准化,因为在图片中,一个数据的大小在0-255之间,我们可以选第一个样本的部分数据来看一下

print(train_set_x_tran[:9, :9])

在这里插入图片描述
这会导致不同的特征的权重差别比较大,通常会将数据处理在一个比较小的范围内,如0-1之间,防止不同特征之间权重比例失衡;我们对样本每个特征都除(max-min)=255即可

# 标准化数据
train_set_x_stan = train_set_x_tran / 255
test_set_x_stan = test_set_x_tran / 255

再看一下处理过后的数据
在这里插入图片描述

4.定义激活函数,初始化w和b

这里激活函数我们选用sigmoid函数,函数定义为:
A = s i g ( Z ) = g ( Z ) = 1 1 + e − Z A=sig(Z)=g(Z)=\frac{1}{1+e^{-Z}} A=sig(Z)=g(Z)=1+eZ1

# 定义sigmoid函数
def sigmoid(Z):
    s = 1 / (1 + np.exp(-Z))
    return s

初始化w和b

# 初始化w和b,w为n*1的数组,b为常数
n_dim = train_set_x_stan.shape[0]
w = np.zeros((n_dim, 1))
b = 0

5.定义前向传播函数、代价函数以及反向传播函数

我们再来看一下神经网络的反向传播,就是利用我们得到的代价损失函数L返回去去推导w和b
在这里插入图片描述
损失函数L和代价函数J
在这里插入图片描述
想看如何推导的,链接在此:001_wz_sf_逻辑回归(Logistic Regression)
使用梯度下降法推导dw和db
在这里插入图片描述
在这里插入图片描述
再对其向量化,最后就可以得到w和b以及损失函数J的迭代公式
在这里插入图片描述

原始文档在此

5.1 前向传播函数

Z = w T X + b Z = w^TX+b Z=wTX+b A = s i g m o i d ( Z ) A = sigmoid(Z) A=sigmoid(Z)

5.2 代价函数

J = − 1 m ∑ i = 1 m ( y ∗ l o g A + ( 1 − y ) ∗ l o g ( 1 − A ) ) J=-\frac{1}{m}\sum{^{m}_{i=1}}(y*logA+(1-y)*log(1-A)) J=m1i=1m(ylogA+(1y)log(1A))

5.3 反向传播函数

d w = 1 m X ( A − y ) dw=\frac{1}{m}X(A-y) dw=m1X(Ay) d b = 1 m ∑ i = 1 m ( A − y ) db=\frac{1}{m}\sum{^m_{i=1}}(A-y) db=m1i=1m(Ay)

# 定义前向传播函数、代价函数以及反向传播函数
def propagate(w, b, X, y, alpha):
    # 1.前向传播函数
    Z = np.dot(w.T, X) + b
    A = sigmoid(Z)

    # 2.代价函数
    m = train_set_x_stan.shape[1]
    J = -1 / m * np.sum((y * np.log(A)) + (1 - y) * np.log(1 - A))

    # 反向传播函数
    dw = 1 / m * np.dot(X, (A - y).T)
    db = 1 / m * np.sum(A - y)

    grands = {"dw": dw,
              "db": db}
    return grands, J

最后将dw,db,J返回

6.进行优化

迭代公式
w : = w − α d w w := w-\alpha dw w:=wαdw b : = b − α d b b:=b-\alpha db b=bαdb
设计一个成本列表,用于储存损失函数的数值,后面用于绘图,然后返回各个需要用到的参数
注:形参print_cost是一个控制间隔100次打印成本的布尔类型参数

# 优化部分
def optimize(w, b, X, y, alpha, n_iters, print_cost):
    costs = []
    for i in range(n_iters):
        grands, J = propagate(w, b, y, X)
        dw = grands["dw"]
        db = grands["db"]

        w = w - alpha * dw
        b = b - alpha * db

        if i % 100 == 0:
            costs.append(J)
            if print_cost:
                print("n_iters is", i, "cost is", J)

        grands = {"dw": dw, "db": db}
        params = {"w": w, "b": b}

    return grands, params, costs

7.进行预测

传入测试集X_test,进行预测输出预测结果y_pred

# 预测部分
def predict(w, b, X_test):
    Z = np.dot(w.T, X_test)
    A = sigmoid(Z)
    
    m = X_test.shape[1]
    y_pred = np.zeros((1, m))
    
    for i in range(m):
        if A[:, i] > 0.5:
            y_pred[:, i] = 1
        else:
            y_pred[:, i] = 0
            
    return y_pred

8.模型整合

模型的整合,方面后面模型的调整

# 模型的整合
def model(w, b, X_train, y_train, X_test, y_test, alpha, n_iters, print_cost):
    grands, params, costs = optimize(w, b, X_train, y_train, alpha, n_iters, print_cost)
    w = params["w"]
    b = params["b"]

    y_train_pred = predict(w, b, X_train)
    y_test_pred = predict(w, b, X_test)

    print("alpha is", alpha)
    print("the train acc is", np.mean(y_train_pred == y_train) * 100, "%")
    print("the test acc is", np.mean(y_test_pred == y_test) * 100, "%")
    print("==============================")

    b = {
        "w": w,
        "b": b,
        "y_train_pred": y_train_pred,
        "y_test_pred": y_test_pred,
        "costs": costs,
        "alpha":alpha
    }

    return b

9.运行与结果分析

取学习速率(步长) α \alpha α=0.005,迭代次数n_iters=2000次,运行结果为在训练集上正确率99%,测试集上70%

d = model(w, b, train_set_x_stan, train_set_y_tran, test_set_x_stan, test_set_y_tran, alpha=0.005, n_iters=2000, print_cost=False)

在这里插入图片描述
学习成本的变化如下图
在这里插入图片描述
对于学习速率 α \alpha α的取值, α \alpha α决定了我们更新参数w和b的速度,如果 α \alpha α取值过大,我们得到的值可能会“超过”最优值;若 α \alpha α取值过小,我们需要迭代太多次才能熟练到最优值,所以 α \alpha α的取值至关重要,下面我们来看一下不同 α \alpha α值的成本曲线:

# alpha的不同取值
alphas = [0.01, 0.001, 0.0001]
for alpha in alphas:
    d = model(w, b, train_set_x_stan, train_set_y_tran, test_set_x_stan, test_set_y_tran,
              alpha=alpha, n_iters=2000, print_cost=False)
    plt.plot(d["costs"], label=str(alpha))
    plt.xlabel("per hundred iters")
    plt.ylabel("cost")
    plt.legend()
plt.show()

在这里插入图片描述
在这里插入图片描述
在相同的迭代次数下,可以明显看到在学习速率比较小时,整个成本下降的速度是越来越慢的,收敛到最优值是比较慢的;而对于比较大的学习速率,可见其收敛的速度很快,但是其在前面错过了一些局部最优值,所有前期曲线会有一部分上升,但是总体是在下降的。
可以参见文章:机器学习算法:梯度下降法——原理篇
在这里插入图片描述

10.测试

我们可以自己选择一张图片测试
在这里插入图片描述
读入要预测的图片,查看维度,将其改为我们所需要的维度,使用预测函数预测

# 读入图片
fname = "E:\py\DL\datasets\img1.jpg"
img_org = plt.imread(fname)
# print(img_org.shape)
# 修改维度
img_tran = transform.resize(img_org, (64, 64, 3)).reshape(64*64*3, 1)
#print(img_tran.shape)
# 进行预测
pred = predict(d["w"], d["b"], img_tran)
print(int(pred))
plt.imshow(img_org)
plt.show()

在这里插入图片描述
可以看到预测结果是1,预测成功了

11.源码

源码在此

四、总结

整个神经网络的架构如下
在这里插入图片描述
在整个过程中,要搞清楚这里面每一步做的都是为了什么,以及参数w和b在循环:计算当前损失(正向传播)–>计算当前梯度(反向传播)–>更新参数(梯度下降)中是如何求得的,这是比较关键的,还有一个是一定要计算好数据的维度,到哪一步得到的数据应该是什么维度。

五、参考文章

【中文】【吴恩达课后编程作业】Course 1 - 神经网络和深度学习 - 第二周作业
机器学习算法:梯度下降法——原理篇
特别感谢:B站UP主ladykaka007的视频

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值