深度学习项目拆解:识别猫的项目(代码片段)

Debroon Debroon     2022-12-31     192

关键词:

神经网络训练步骤

数据准备

数据下载:https://download.csdn.net/download/qq_41739364/22020268(都是一些动物的图片,像猫、狗、鸟)

import h5py                                                      # 数据是 H5 文件,需要 h5 模块
import matplotlib.pyplot as plt                                  # 绘图库,之后会查看图片
import numpy as np

train_dataset = h5py.File('./我的数据集/train_catvnoncat.h5','r') # 读取训练集(创建了一个字典格式的对象)
test_dataset = h5py.File('./我的数据集/test_catvnoncat.h5','r')   # 读取测试集(创建了一个字典格式的对象)

# 因为对象是字典,所以用数据之前,还需要键名
for key1 in train_dataset.keys():
	print( train_dataset[key1].name )                           # 查看训练集键名(标签类别list_classes、图片特征train_set_x、图片标签train_set_y)
	
for key2 in test_dataset.keys():
	print( test_dataset[key2].name )                            # 查看测试集键名(标签类别list_classes、图片特征test_set_x、图片标签test_set_y)

train_set_x = np.array(train_dataset["train_set_x"][:])         # 通过键名,访问所有数据,并保存到数组里
train_set_y = np.array(train_dataset["train_set_y"][:])         # 通过键名,访问所有数据,并保存到数组里

test_set_x = np.array(test_dataset["test_set_x"][:])            # 通过键名,访问所有数据,并保存到数组里
test_set_y = np.array(test_dataset["test_set_y"][:])            # 通过键名,访问所有数据,并保存到数组里


print("train_set_x.shape = ",train_set_x.shape)                 # 查看训练集数组维度( (209, 64, 64, 3) 意思是,209张图片,尺寸是 64*64*3,64x64x3 = 12288个特征 )
print("test_set_x.shape = ",test_set_x.shape)                   # 查看测试集数组维度( (50, 64, 64, 3) 意思是,50张图片,尺寸是 64*64*3,64x64x3 = 12288个特征 )


一张图片是一个三维数组 64 * 64 * 3,64 是长和宽,3 是 RGB 三个通道,因为这是一张彩色图片,每个像素点必须用三个数来代表,一张图片就要用 1 万多个数来描述。

209 张图片,是一个四维数组 209 * 64 * 64 * 3,而神经元的输入是二维的列矩阵 209 * 1,所以我们要转换一下。

# 图片特征 xx_set_x:(209, 64, 64, 3) -> (12288,209)
train_set_x = train_set_x.reshape(train_set_x.shape[0], -1).T    # (209, 64, 64, 3) 变成 (12288,209)
test_set_x = test_set_x.reshape(test_set_x.shape[0], -1).T       # (209, 64, 64, 3) 变成 (12288,50)

# 图片标签 xx_set_y:(209,) -> (1,209)
train_set_y = train_set_y.reshape(1,train_set_y.shape[0])        # (209,) 变成 (1,209)
test_set_y = test_set_y.reshape(1,test_set_y.shape[0])           # (50,) 变成 (1,50)

# P.S. 标签类别list_classes 非0即1,0即非猫,1即是猫。

最后归一化,我们要把数据经过处理后使之限定在一定的范围内。比如通常限制在区间 [0, 1]

train_set_x = train_set_x/255.0       
test_set_x = test_set_x/255.0
# 除以255.0是为了使数据的取值范围在sigmoid激励函数的取值范围内
#【注:灰度图像素取值为0-255,相除后取值在0-1之间,符合激励函数的输出范围】

好,现在我们把数据准备这部分封装为一个函数。

import h5py                                                      # 数据是 H5 文件,需要 h5 模块
import matplotlib.pyplot as plt                                  # 绘图库,之后会查看图片
import numpy as np

def load_dataset():
    # 创建文件对象
    train_dataset = h5py.File('./我的数据集/train_catvnoncat.h5','r')
    test_dataset = h5py.File('./我的数据集/test_catvnoncat.h5','r')
    
    # 读取数据
    train_set_x = np.array(train_dataset["train_set_x"][:])
    train_set_y = np.array(train_dataset["train_set_y"][:])
    test_set_x = np.array(test_dataset["test_set_x"][:])
    test_set_y = np.array(test_dataset["test_set_y"][:])

	# 查看第 110 张图片
    plt.figure(figsize=(2,2))
    plt.imshow(train_set_x[110])
    plt.show()
    
    # 变化维度以适应神经网络输入
    train_set_x = train_set_x.reshape(train_set_x.shape[0],-1).T  
    test_set_x = test_set_x.reshape(test_set_x.shape[0],-1).T  
    train_set_y = train_set_y.reshape(1,train_set_y.shape[0]) 
    test_set_y = test_set_y.reshape(1,test_set_y.shape[0]) 

	# 数据归一化
    train_set_x = train_set_x/255.0       
    test_set_x = test_set_x/255.0
    
    return train_set_x,train_set_y,test_set_x,test_set_y

if __name__ == '__main__':
    train_set_x, train_set_y, test_set_x, test_set_y = load_dataset()
    # 加载数据

 


定义神经网络结构

加载数据后,定义神经网络结构。

if __name__ == '__main__':
    load_dataset()
    # 加载数据
   
	fc_net = [12288, 4, 3, 2, 1] 
	# 用数组定义神经网络结构,输入层(12288个神经元)->第1层->第2层->第3层->第4层->a,有多少层、一层多少神经元,都取决于工程师的直觉,差不多就行   
	# 输出值a,a>0.5 ? 1:0

 


解析神经网络、初始化参数(w、b)

定义神经网络结构之后,解析神经网络

if __name__ == '__main__':
    train_set_x, train_set_y, test_set_x, test_set_y = load_dataset()
    # 加载数据
    
    fc_net = [12288, 4, 3, 2, 1] 
	# 用数组定义神经网络结构,输入层(12288个神经元)->第1层->第2层->第3层->第4层->a  
	# 输出值a,a>0.5 ? 1:0
    
    parameters = init_parameters(fc_net)
    # 解析神经网络,初始化权值

现在我们来实现初始化权值 init_parameters 的实现。

# 初始化参数
def init_parameters(fc_net):  
    parameters =                
    # 定义一个字典,存放参数矩阵W1,b1,W2,b2,W3,b3,W4,b4
    Layer_num = len(fc_net)       
    # 神经网络的层数,通过获取数组长度可得
    
    for L in range(1, Layer_num):  # 遍历层数,从第一层开始,但忽略输入层(第 0 层)
        parameters["W"+str(L)] = np.random.randn(fc_net[L], fc_net[L-1])*0.01   
        # 从标准正态分布中(取值范围[-3,3])选取值,为方便激活函数(取值范围[-1,1]),乘以0.01后,再赋值给创建的键值对(W1、W2、W3···)
        parameters["b"+str(L)] = np.zeros((fc_net[L], 1))
        
    for L in range(1, Layer_num):
        print("W"+str(L)+" = ", parameters["W"+str(L)].shape)
        print("b"+str(L)+" = ",  parameters["b"+str(L)].shape)
        
    return parameters

 


输入数据,前向传播

if __name__ == '__main__':
    train_set_x, train_set_y, test_set_x, test_set_y = load_dataset()
    # 加载数据
    
    fc_net = [12288, 4, 3, 2, 1] 
	# 输入层->第1层->第2层->第3层->第4层->a    
	# 输出值a,a>0.5 ? 1:0
    
    parameters = init_parameters(fc_net)
    # 初始化权值
    
    AL, cache = forward_pass(train_set_x, parameters, active_func = "tanh")
    # 最后一层激活值AL = train_set_x 输入数据、parameters W、b 保存位置、激活函数是 tanh

现在我们来实现激活函数。

def sigmoid(Z):
    return 1 / (1 + np.exp(-Z)) 

def tanh(Z): 
    return np.tanh(Z)

def ReLU(Z):    
    return np.maximum(0,Z) 

再来实现前向传播 forward_pass

def forward_pass(A0, parameters, active_func = "ReLU"):
    Layer_num = len(parameters) // 2  # 因为 parameters 是由 W、b 组成,所以除 2
    A = A0
    cache =         				  # 缓存 A 的字典
    cache["A0"] = A0  				  # 先缓存A0
     
    for L in range(1,Layer_num):      
        A_prev = A
        Z = np.dot(parameters["W"+str(L)],A_prev) + parameters["b"+str(L)]  # Z = WX + b
        cache["Z"+str(L)] = Z         # 缓存Z1 Z2 Z3 Z4
        
        if active_func == "sigmoid":  
            A = sigmoid(Z)            # sigmoid函数,适合用于深度网络
        elif active_func == "tanh":
            A = tanh(Z)               # tanh函数激活
        else:
            A = ReLU(Z)               # 1~3层用 ReLU 函数激活     
        cache["A"+str(L)] = A         # 继续缓存 A1 A2 A3 A4
    
    # 最末层采用sigmoid函数激活
    ZL = np.dot(parameters["W" + str(Layer_num)], A) + parameters["b" + str(Layer_num)]    #  1,2   2,209
    cache["Z" + str(Layer_num)] = ZL  # 缓存最末层的Z4
    AL = sigmoid(ZL)                  # sigmoid函数激活
    cache["A"+str(Layer_num)]=AL      # 继续缓存最末层的A4   
    
    return AL, cache

对比《深度学习食用指南》识别猫的项目,这里多了一个要缓存 A,这是为啥?

其实是一种算法策略:空间换时间,因为前向传播过程如下所示:

一般的前向传播过程,我们是一个一个计算的,处理完一个样本再处理下一个样本,等所有样本都处理完了,才能反向传播,求参数的梯度。

能不能同时计算呢?

  • a 0 a_0 a0 是输入样本,是不需要计算就可以得到的,我们把上面的 a 0 a_0 a0 堆叠起来。
  • b i b_i bi 也堆叠起来,后面的输出值 a i a_i ai 也堆叠起来。
  • w i w_i wi 矩阵也移过来。

就把多个样本中用 for 循环实现的多步串行计算,改成了用矩阵实现的一步完成的并行计算。

 


得到本轮迭代的损失值

if __name__ == '__main__':
    train_set_x, train_set_y, test_set_x, test_set_y = load_dataset()
    # 加载数据
    
    fc_net = [12288, 4, 3, 2, 1] 
	# 输入层->第1层->第2层->第3层->第4层->a    
	# 输出值a,a>0.5 ? 1:0
    
    parameters = init_parameters(fc_net)
    # 初始化权值
    
    AL,cache= forward_pass(train_set_x, parameters)
    # 最后一层激活值AL = train_set_x 输入数据、parameters W、b 保存位置

	cost = compute_cost(AL, train_set_y)

使用损失函数计算,预测值与标签值(真实值)的差距。

def compute_cost(AL, Y):
    m = Y.shape[1]                           # Y =(1,209)
    cost = (1/m)*np.sum((1/2)*(AL-Y)*(AL-Y)) # 代价函数
    return cost

 


求最末层误差,反向传播计算各层梯度

if __name__ == '__main__':
    train_set_x, train_set_y, test_set_x, test_set_y = load_dataset()
    # 加载数据
    
    fc_net = [12288, 4, 3, 2, 1] 
	# 输入层->第1层->第2层->第3层->第4层->a    
	# 输出值a,a>0.5 ? 1:0
    
    parameters = init_parameters(fc_net)
    # 初始化权值
    
    AL,cache= forward_pass(train_set_x, parameters)
    # 最后一层激活值AL = train_set_x 输入数据、parameters W、b 保存位置
    
    cost = compute_cost(AL, train_set_y)
    
    gradient = backward_pass(AL, parameters, cache, train_set_y)
    # 反向传播计算梯度

我们来实现反向传播 backward_pass

def backward_pass(AL, parameters, cache, Y):
    m = Y.shape[1]                         # 样本总数
    gradient =    					   # 保存各层参数梯度的字典
    Layer_num = len(parameters) // 2
    dZL = (AL-Y)*(AL*(1-AL))               # 获取最末层误差信号 dZL.shape = (1,209)  
    gradient["dW"+str(Layer_num)] = (1/m)*np.dot(dZL,cache["A"+str(Layer_num-1)].T)
    gradient["db"+str(Layer_num)] = (1/m)*np.sum(dZL,axis=1,keepdims = True)
    
    for L in reversed(range(1,Layer_num)): # 遍历[3,2,1],其中reversed函数[1,2,3]颠倒为[3,2,1]
        dZL = np.dot(parameters["W"+str(L+1)].T,dZL)*(AL*(1-AL))
        gradient["dW"+str(L)] = (1/m)*np.dot(dZL,cache["A"+str(L-1)].T)
        gradient["db"+str(L)] = (1/m)*np.sum(dZL,axis=1,keepdims = True)
        
    return gradient  

 


根据各层的w、b梯度,使用梯度下降更新一次参数

if __name__ == '__main__':
    train_set_x, train_set_y, test_set_x, test_set_y = load_dataset()
    # 加载数据
    
    fc_net = [12288, 4, 3, 2, 1] 
	# 输入层->第1层->第2层->第3层->第4层->a    
	# 输出值a,a>0.5 ? 1:0
    
    parameters = init_parameters(fc_net)
    # 初始化权值
    
    AL,cache= forward_pass(train_set_x, parameters)
    # 最后一层激活值AL = train_set_x 输入数据、parameters W、b 保存位置
    
    cost = compute_cost(AL, train_set_y)
    
    gradient = backward_pass(AL, parameters, cache, train_set_y)
    # 反向传播计算梯度
    
    iterations = 500
    LearnRate = 0.01
    costs = []                               
    # 保存我们每次迭代计算得到的代价值
    parameters = update_parameters(gradient, parameters, LearnRate)
    # 根据梯度更新一次参数

得到梯度后,实现梯度下降。

def update_parameters(gradient,parameters,LearnRate):
    # w : =w-r*dw、b := b-r*db
    Layer_num = len(parameters) // 2
    for L in range(1,Layer_num+1): 
        parameters["W"+str(L)] = parameters["W"+str(L)] - LearnRate*gradient["dW"+str(L)]
        parameters["b"+str(L)] = parameters["b"+str(L)] - LearnRate*gradient["db"+str(L)]
    
    return parameters

 


重复以上步骤,直到损失值低于设定阈值,模型收敛

if __name__ 

深度学习项目演练:如何使用python和opencv进行人脸识别(代码片段)

...脸识别-在实时实时视频中检测和识别出一个人。在这个深度学习项目中,我们将学习如何使用Python识别实时视频中的人脸。我们将使用pythondlib的面部识别网络构建这个项目。Dlib是一个通用的软件库。使用dlib工具包,我... 查看详情

项目实战解析:基于深度学习搭建卷积神经网络模型算法,实现图像识别分类(代码片段)

...、图像识别分类总结前言随着人工智能的不断发展,深度学习这门技术也越来越重要,很多人都开启了学习机器学习,本文将通过项目开发实例,带领大家从零开始设计实现一款基于深度学习的图像识别算法。学... 查看详情

深度学习基于卷积神经网络(tensorflow)的人脸识别项目(代码片段)

​活动地址:CSDN21天学习挑战赛目录前言基本思路关于环境OpenCVOpenCV具有的特征OpenCV具有的功能安装OpenCV关键APIimreadnamedWindow示例cv2.VideoCapture(0)CascadeClassifiercap.isOpened()ok,frame=cap.read()cv2.cvtColor(frame,cv2.COLOR_B 查看详情

深度学习--tensorflow(项目)验证码生成与识别(多任务学习)(代码片段)

目录基础理论一、生成验证码数据集1、生成验证码训练集1-0、判断文件夹是否为空1-1、创建字符集(数字、大小写英文字母)1-2、随机生成验证码(1000个,长度为4)2、生成验证码测试集代码二、获取数据... 查看详情

深度学习基于卷积神经网络(tensorflow)的人脸识别项目(代码片段)

目录前言基本思路测试人脸识别效果设计思路详细代码加载模型人脸预测主要逻辑测试效果总结所有代码face_predict_use_keras.pykeras_train.pyload_data.pyface_predict_use_keras.py以上就是全部代码啦。有啥疑问就评论区讨论奥。前言经过前段... 查看详情

python项目演练:使用深度学习自动识别车牌号附源代码(代码片段)

本文分享的项目旨在识别车牌。为了检测车牌,我们将使用OpenCV来识别车牌,并使用pythonpytesseract从车牌中提取字符和数字。 OpenCV是一个开源机器学习库,为计算机视觉提供通用基础设施。而Pytesseract是一个Tesseract-OC... 查看详情

深度学习基于卷积神经网络(tensorflow)的人脸识别项目(代码片段)

​活动地址:CSDN21天学习挑战赛目录前言基本思路激活函数Sigmoid函数Tanh/双曲正切激活函数ReLU激活函数损失函数作用建立神经网络模型参数说明CNN模型网络结构训练模型训练结果评估模型加载模型评估测试测试结果总结前言... 查看详情

「深度学习一遍过」必修20:基于alexnet的mnist手写数字识别(代码片段)

本专栏用于记录关于深度学习的笔记,不光方便自己复习与查阅,同时也希望能给您解决一些关于深度学习的相关问题,并提供一些微不足道的人工神经网络模型设计思路。专栏地址:「深度学习一遍过」必修篇... 查看详情

「深度学习一遍过」必修22:基于googlenet的mnist手写数字识别(代码片段)

本专栏用于记录关于深度学习的笔记,不光方便自己复习与查阅,同时也希望能给您解决一些关于深度学习的相关问题,并提供一些微不足道的人工神经网络模型设计思路。专栏地址:「深度学习一遍过」必修篇... 查看详情

「深度学习一遍过」必修22:基于googlenet的mnist手写数字识别(代码片段)

本专栏用于记录关于深度学习的笔记,不光方便自己复习与查阅,同时也希望能给您解决一些关于深度学习的相关问题,并提供一些微不足道的人工神经网络模型设计思路。专栏地址:「深度学习一遍过」必修篇... 查看详情

「深度学习一遍过」必修20:基于alexnet的mnist手写数字识别(代码片段)

本专栏用于记录关于深度学习的笔记,不光方便自己复习与查阅,同时也希望能给您解决一些关于深度学习的相关问题,并提供一些微不足道的人工神经网络模型设计思路。专栏地址:「深度学习一遍过」必修篇... 查看详情

基于cnn卷积神经网络的tensorflow+keras深度学习的人脸识别(代码片段)

基于CNN卷积神经网络的TensorFlow+Keras深度学习的人脸识别前言项目实现效果补充模型数据嵌入模型CNN神经网络模型项目概述项目运行流程核心环境配置项目核心代码详解目录核心代码设置数据集目录收集人脸识别数据——UUID格... 查看详情

「深度学习一遍过」必修19:基于lenet-5的mnist手写数字识别(代码片段)

本专栏用于记录关于深度学习的笔记,不光方便自己复习与查阅,同时也希望能给您解决一些关于深度学习的相关问题,并提供一些微不足道的人工神经网络模型设计思路。专栏地址:「深度学习一遍过」必修篇... 查看详情

「深度学习一遍过」必修23:基于resnet18的mnist手写数字识别(代码片段)

本专栏用于记录关于深度学习的笔记,不光方便自己复习与查阅,同时也希望能给您解决一些关于深度学习的相关问题,并提供一些微不足道的人工神经网络模型设计思路。专栏地址:「深度学习一遍过」必修篇... 查看详情

「深度学习一遍过」必修19:基于lenet-5的mnist手写数字识别(代码片段)

本专栏用于记录关于深度学习的笔记,不光方便自己复习与查阅,同时也希望能给您解决一些关于深度学习的相关问题,并提供一些微不足道的人工神经网络模型设计思路。专栏地址:「深度学习一遍过」必修篇... 查看详情

「深度学习一遍过」必修23:基于resnet18的mnist手写数字识别(代码片段)

本专栏用于记录关于深度学习的笔记,不光方便自己复习与查阅,同时也希望能给您解决一些关于深度学习的相关问题,并提供一些微不足道的人工神经网络模型设计思路。专栏地址:「深度学习一遍过」必修篇... 查看详情

「深度学习一遍过」必修21:基于vgg16net的mnist手写数字识别(代码片段)

本专栏用于记录关于深度学习的笔记,不光方便自己复习与查阅,同时也希望能给您解决一些关于深度学习的相关问题,并提供一些微不足道的人工神经网络模型设计思路。专栏地址:「深度学习一遍过」必修篇... 查看详情

「深度学习一遍过」必修21:基于vgg16net的mnist手写数字识别(代码片段)

本专栏用于记录关于深度学习的笔记,不光方便自己复习与查阅,同时也希望能给您解决一些关于深度学习的相关问题,并提供一些微不足道的人工神经网络模型设计思路。专栏地址:「深度学习一遍过」必修篇... 查看详情