深度神经网络

计算机视觉和图像处理

  1. Tensorflow入门
  2. 深度神经网络
  3. 图像分类
  4. 目标检测
  5. 图像分割
  6. OpenCV
  7. 图像特征提取与描述
  8. 视频操作
  9. 人脸案例

深度神经网络

  • 一、神经网络介绍
    • [1.1 什么是神经网络](#1.1 什么是神经网络)
    • [1.2 神经元是如何工作的?](#1.2 神经元是如何工作的?)
      • [1.2.1 激活函数(Activation Function)](#1.2.1 激活函数(Activation Function))
        • [1.2.1.1 Sigmoid函数](#1.2.1.1 Sigmoid函数)
        • [1.2.1.2 tanh函数](#1.2.1.2 tanh函数)
        • [1.2.1.3 RELU函数](#1.2.1.3 RELU函数)
        • [1.2.1.4 LeakReLu函数](#1.2.1.4 LeakReLu函数)
        • [1.2.1.5 SoftMax函数](#1.2.1.5 SoftMax函数)
        • [1.2.1.7 如何选择激活函数](#1.2.1.7 如何选择激活函数)
      • [1.2.2 参数初始化](#1.2.2 参数初始化)
    • [1.3 神经网络的搭建](#1.3 神经网络的搭建)
      • [1.3.1 通过Sequential构建](#1.3.1 通过Sequential构建)
      • [1.3.2 利用function API构建](#1.3.2 利用function API构建)
      • [1.3.3 通过Model的子类构建](#1.3.3 通过Model的子类构建)
    • [1.4 神经网络的优缺点](#1.4 神经网络的优缺点)
  • 二、常见损失函数
    • [2.1 分类任务](#2.1 分类任务)
      • [2.1.1 多分类任务](#2.1.1 多分类任务)
      • [2.1.2 二分类任务](#2.1.2 二分类任务)
    • [2.2 回归任务](#2.2 回归任务)
      • [2.2.1 MAE损失](#2.2.1 MAE损失)
      • [2.2.2 MSE损失](#2.2.2 MSE损失)
      • [2.2.3 smooth L1损失](#2.2.3 smooth L1损失)
  • 三、深度学习的优化方法
    • [3.1 梯度下降算法](#3.1 梯度下降算法)
    • [3.2 反向传播算法(BP算法)](#3.2 反向传播算法(BP算法))
    • [3.3 梯度下降优化方法](#3.3 梯度下降优化方法)
      • [3.3.1 动量梯度下降算法](#3.3.1 动量梯度下降算法)
      • [3.3.2 AdaGrad](#3.3.2 AdaGrad)
      • [3.3.3 RMSprop](#3.3.3 RMSprop)
      • [3.3.4 Adam](#3.3.4 Adam)
  • 四、深度学习正则化
    • [4.1 L1和L2正则化](#4.1 L1和L2正则化)
    • [4.2 Droupout正则化](#4.2 Droupout正则化)
    • [4.3 提前停止](#4.3 提前停止)
    • [4.4 批标准化](#4.4 批标准化)
  • 五、神经网络案例
  • 六、卷积神经网络CNN
    • [6.1 CNN网络的构成](#6.1 CNN网络的构成)
    • [6.2 卷积层](#6.2 卷积层)
    • [6.3 池化层](#6.3 池化层)
    • [6.4 全连接层](#6.4 全连接层)
    • [6.5 卷积神经网络的构建](#6.5 卷积神经网络的构建)

一、神经网络介绍

1.1 什么是神经网络

人工神经网络( Artificial Neural Network, 简写为ANN)简称为神

经网络(NN),是⼀种模仿生物神经网络结构和功能的计算模型。

人工神经网络中的神经元模型

人工神经元接收来⾃其他神经元或外部源的输入,每个输入都有⼀个相关的权值(w),它是根据该输入对当前神经元的重要性来确定的,对该输入加权并与其他输入求和后,经过⼀个激活函数f,计算得到该神经元的输出。


神经网络模型

神经网络中信息只向⼀个方向移动,即从输入节点向前移动,通过隐藏节

点,再向输出节点移动,网络中没有循环。其中的基本构件是:

  • 输⼊层:即输入x的那⼀层
  • 隐藏层:输入层和输出层之间都是隐藏层
  • 输出层:即输出y的那⼀层

1.2 神经元是如何工作的?

人工神经元接收到⼀个或多个输入,对他们进行加权并相加,总和通过⼀个非线性函数产生输出。

1.2.1 激活函数(Activation Function)

1.2.1.1 Sigmoid函数

数学表达式:
f ( x ) = 1 1 + e − x f(x)={1 \over 1+e^{-x}} f(x)=1+e−x1

曲线图形如下所示:

sigmoid在定义域内处处可导,且两侧倒数逐渐趋近于0。如何x的值很大或者很小的时候,呢么函数的梯度(函数的斜率)会非常小,在反向传播的过程中,导致了向低层传递的梯度也变得非常小。。这种现象被称为梯度消失。⼀般来说,sigmoid 网络在5层之内就会产生梯度消失现象。而且,该激活函数并不是以0为中心的,所以在实践中这种激活函数使用的很少。sigmoid函数一般只用于二分类的输出层。

实现方法:

python 复制代码
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

# 定义x, y
x = np.linspace(-10,10,100)
y = tf.nn.sigmoid(x)

# 绘图
plt.plot(x,y)
plt.grid()
plt.rcParams['axes.unicode_minus'] = False
plt.show()
1.2.1.2 tanh函数

数学表达式:
t a n h ( x ) = e x − e − x e x + e − x tanh(x)={e^x - e^{-x} \over e^x + e^{-x}} tanh(x)=ex+e−xex−e−x

曲线图形如下所示:

tanh也是一种非常常见的激活函数。与sigmoid相比,他是以0为中心的,使得其收敛速度要比sigmoid快,减少迭代次数。然而,从图中可以看出,tanh两侧的导数也为0,同样也造成梯度消失。

若使用时可在隐藏层使用tanh函数,在输出层使用sigmoid函数。

实现方法:

python 复制代码
x = np.linspace(-10,10,100)
y = tf.nn.tanh(x)

plt.plot(x,y)
plt.grid()
plt.show()
1.2.1.3 RELU函数

数学表达式:
f ( x ) = m a x ( 0 , x ) f(x)={max(0,x)} f(x)=max(0,x)

曲线图形如下所示:

ReLU是目前最常用的激活函数。从图中可以看到,当x<0时,relu导数为0,而当x>0时,则不存在饱和问题。所以,ReLU能够在x>0时保持梯度不衰减,从而缓解梯度消失问题。然而,随着训练的推进,部分输入会落入小于0区域,导致对应权重无法更新,这种现象被称为"神经元死亡"。

实现方法:

python 复制代码
x = np.linspace(-10,10,100)
y = tf.nn.relu(x)

plt.plot(x,y)
plt.grid()
plt.show()
1.2.1.4 LeakReLu函数

数学表达式:
f ( x ) = m a x ( 0.1 x , x ) f(x)={max(0.1x,x)} f(x)=max(0.1x,x)

曲线图形如下所示:

实现方法:

python 复制代码
x = np.linspace(-10,10,100)
y = tf.nn.leaky_relu(x)

plt.plot(x,y)
plt.grid()
plt.show()
1.2.1.5 SoftMax函数

数学表达式:
s o f t m a x ( z i ) = e z i ∑ j e z j softmax(z_i)={e^{z_i} \over \sum_je^{z_j}} softmax(zi)=∑jezjezi

使用方法:

softmax用于多分类过程,它是二分类函数sigmoid在多分类上的推广,目的是将多分类的结果以概率的形式展现出来。

softmax直白来说就是将网络输出的logits通过softmax函数,就映射成为(0,1)的值,而这些值得累和为1(满足概率得性质),呢么我们将它理解成概率,选取概率最大(也就是值对应最大的)结点,作为我们得预测目标类别。

实现方法:

python 复制代码
x = tf.constant([0.2,0.02,0.15,1.3,0.5,0.06,1.1,0.05,3.75])
y = tf.nn.softmax(x)

y
1.2.1.7 如何选择激活函数

隐藏层:

  • 优先选择ReLU激活函数
  • 如果ReLU效果不好,呢么尝试其他激活,如LeakyReLU等。
  • 一般不使用sigmoid、tanh函数。

输出层:

  • 二分类问题选择sigmoid激活函数
  • 多分类问题选择softmax激活函数
  • 回归问题选择identity激活函数

1.2.2 参数初始化

对于某一个神经元来说,需要初始化的参数有两类:1.权重W,2.偏置b。偏置b初试化为0即可。

  1. 随机初始化

    从均值为0,标准差为1的高斯分布中取样,使用一些很小的值对参数w进行初始化。

  2. 标准初始化

    从区间均匀随机取值。即在( − 1 d , 1 d {-1 \over \sqrt d},{1 \over \sqrt d} d −1,d 1)均匀分布中生成当前神经元的权重,其中d为每个神经元的输入数量

  3. Xavier初始化
    基本思想:

    各层的激活值和梯度的方差在传播过程中保持一致,也叫做Glorot初始化。

    实现的方法:

    • 正态化Xavier初始化:
      从以0为中心,标准差为 s t d e v = ( 2 / ( f a n _ i n + f a n _ o u t ) ) stdev = \sqrt (2 / (fan\_in + fan\_out)) stdev=( 2/(fan_in+fan_out))的正态分布中抽取样本,其中fan_in是输入神经元的个事,fan_out是输出神经元个数。

    实现方法:

    python 复制代码
    # 正态分布
    # 实例化
    initializern = tf.keras.initializers.glorot_normal()
    value = initializern((9,1))
    
    value
    • 标准化Xavier初始化:
      从[-limit,limit]中的均匀分布中抽取样本,其中limit是 6 f a n _ i n + f a n _ o u t \sqrt {6 \over fan\_in + fan\_out} fan_in+fan_out6 ,其中fan_in是输入神经元的个数,fan_out是输出神经元个数。

    实现方法:

    python 复制代码
    # 标准化:均匀分布
    initializern = tf.keras.initializers.glorot_uniform()
    value = initializern((9,1))
    
    value
  4. He初始化
    基本思想:

    正向传播时,激活值的方差保持不变;反向传播时,关于状态值的梯度的方差保持不变。

    实现的方法:

    • 正态化的he初始化
      He正态分布初始化是以0为中心,标准差为 s t d d e v = 2 f a n _ i n stddev = {\sqrt {2 \over fan\_in}} stddev=fan_in2 的截断正态分布中抽取样本,其中fan_in是输入神经元。
    python 复制代码
    #正态分布
    initializer = tf.keras.initializers.he_normal()
    values = initializer((9,1))
    
    values
    • 标准化的he初始化
      从[-limit,limit]中的均匀分布中抽取样本,其中limit是 6 f a n _ i n \sqrt {6 \over fan\_in } fan_in6 ,其中fan_in是输入神经元的个数。
    python 复制代码
    # 标准化
    initializer = tf.keras.initializers.he_uniform()
    values = initializer((9,1))
    
    values

1.3 神经网络的搭建


神经网络模型

tf.keras中构建模型有两种方式,一种是通过Sequential构建,一种是通过Model类构建。Sequential是按一定的顺序对层进行堆叠,而Model用来构建比较复杂的网络模型。

1.3.1 通过Sequential构建

python 复制代码
from tensorflow import keras
from tensorflow.keras import layers

# 定义Sequential模型
model = keras.Sequential([
    # 第一个隐藏层
    layers.Dense(3,activation="relu",kernel_initializer="he_normal",input_shape=(3,)),
    # 第二个隐藏层
    layers.Dense(2,activation="relu",kernel_initializer="he_normal"),
    # 输出层
    layers.Dense(2,activation="sigmoid",kernel_initializer="he_normal")
],
    name = "my_Sequential"
)
python 复制代码
# 展示模型结果
model.summary()
python 复制代码
# 展示模型结果
keras.utils.plot_model(model,show_shapes=True)

1.3.2 利用function API构建

python 复制代码
# 定义模型的输入
inputs = keras.Input(shape=(3,),name="input")
# 第一层
x = layers.Dense(3,activation="relu",name="layer1")(inputs)
# 第二层
x = layers.Dense(2,activation="relu",name="layer2")(x)
# 第三层(输出层)
outputs = layers.Dense(2,activation="sigmoid",name="layer3")(x)
# 使用Model来创建模型,指明输入和输出
model = keras.Model(inputs=inputs,outputs=outputs,name="my_model")
python 复制代码
model.summary()
python 复制代码
keras.utils.plot_model(model,show_shapes=True)

1.3.3 通过Model的子类构建

python 复制代码
# 定义一个MyModel类,该类继承keras.Model
class MyModel(keras.Model):
    # 定义网络的层结构
    def __init__(self):
        # 调用父类 keras.Model的构造函数,确保父类的构造函数被正确执行
        super(MyModel,self).__init__()
        # 第一个隐藏层
        self.layer1 = layers.Dense(3,activation="relu",name="layer1")
        # 第二个隐藏层
        self.layer2 = layers.Dense(2,activation="relu",name="layer2")
        # 输出层
        self.layer3 = layers.Dense(2,activation="sigmoid",name="layer3")
    # 定义网络的向前传播
    def call(self,inputs):
        x = self.layer1(inputs)
        x = self.layer2(x)
        outputs = self.layer3(x)
        return outputs
python 复制代码
# 实例化MyModel
model = MyModel()
# 设置输入
x = tf.ones((1,3))
y = model(x)
python 复制代码
y
python 复制代码
model.summary()

1.4 神经网络的优缺点

  1. 优点
  • 精度高,性能优于其他的机器学习方法
  • 可以近似任意的非线性函数
  • 有大量的框架和库可供调用
  1. 缺点
  • 黑箱,很难解释模型是怎么工作的
  • 训练时间长,需要大量的计算力
  • 网络模型复杂,需要调整参数
  • 小数据集上表现不佳,容易发生过拟合

二、常见损失函数

2.1 分类任务

在深度学习的分类任务中使用最多的是交叉熵损失函数。

2.1.1 多分类任务

多分类任务通常使用softmax将logits转换为概率的形式,所以多分类的交叉熵损失也叫softmax损失。

在tf.keras中使用Cat实现:

python 复制代码
# 设置真实值和预测值
y_true = [[0, 1, 0], [0, 0, 1]] 
y_pred = [[0.05, 0.95, 0], [0.1, 0.8, 0.1]] 
# 将列表转换为张量
y_true = tf.convert_to_tensor(y_true)
y_pred = tf.convert_to_tensor(y_pred)

# 或者直接创建张量
# y_true= tf.constant([[0, 1, 0], [0, 0, 1]])
# y_pred = tf.constant([[0.05, 0.95, 0], [0.1, 0.8, 0.1]] )

# 实例化交叉熵损失
cce = tf.keras.losses.CategoricalCrossentropy()
# 计算损失结果
cce(y_true,y_pred)

2.1.2 二分类任务

处理二分类任务时,使用sigmoid激活函数,所以损失函数使用二分类的交叉熵损失函数。

python 复制代码
# 设置真实值和预测值(张量类型)
y_true = tf.constant([[0],[1]])
y_pred = tf.constant([[0.4],[0.6]])
# 实例化
bca = tf.keras.losses.BinaryCrossentropy()
# 计算损失结果
bca(y_true,y_pred)

2.2 回归任务

2.2.1 MAE损失

Mean absolute loss(MAE)也称为L1 Loss

python 复制代码
# 设置真实值和预测值(张量类型)
y_true = tf.constant([[0],[1]])
y_pred = tf.constant([[0.4],[0.6]])
# 实例化
bca = tf.keras.losses.BinaryCrossentropy()
# 计算损失结果
bca(y_true,y_pred)

2.2.2 MSE损失

Mean Squated Loss也被称为L2 loss。

python 复制代码
# 设置真实值和预测值
y_true = tf.constant([[0.],[1.]])
y_pred = tf.constant([[1.],[1.]])
# 实例化
mae = tf.keras.losses.MeanAbsoluteError()
# 计算损失结果
mae(y_true,y_pred)

2.2.3 smooth L1损失

通常在目标检测中使用该损失函数。

python 复制代码
# 设置真实值和预测值
y_true = tf.constant([[0],[1]])
y_pred = tf.constant([[0.6],[0.4]])
# 实例化
h = tf.keras.losses.Huber()
# 计算损失结果
h(y_true,y_pred)

三、深度学习的优化方法

3.1 梯度下降算法

梯度下降法简单来说就是一种寻找使损失函数最小化的方法。

梯度下降算法 定义 缺点 优点
BGD(批量梯度下降) 每次迭代时需要计算每个样本损失函数的梯度并求和 计算量大、迭代速度满 全局最优化
SGD(随机梯度下降) 每次迭代时只采集一个样本,计算这个样本损失函数的梯度并更新参数 准确度下降、存在噪音、非全局最优化 训练速度快、支持在线学习
MAGD(小批量梯度下降) 每次迭代时,随机选取一小部分训练样本来计算梯度并更新参数 准确度不如BGD、非全局最优解 计算小批量数据得梯度更加高效、支持在线学习

实际中使用较多的是小批量的梯度下降算法。
实现过程:

python 复制代码
import tensorflow as tf
# 实例化优化方法:SGD
opt = tf.keras.optimizers.SGD(learning_rate=0.1)
# 定义要调整的参数
var = tf.Variable(1.0)
# 使用GradientTape记录损失函数的计算过程
with tf.GradientTape() as tape:
    # 定义损失函数
     loss = (var ** 2) / 2.0
# 计算梯度
grad = tape.gradient(loss,var)
# 应用梯度到对应的变量上
opt.apply_gradients([(loss,var)])
# 展示参数更新结果
var.numpy()

3.2 反向传播算法(BP算法)

反向传播的核心思想是在前向传播计算输出之后,从输出层开始,沿着网络层往输入方向逐层计算每个权重对损失函数的影响(即梯度)。然后使用这些梯度来更新网络中的权重。

3.3 梯度下降优化方法

3.3.1 动量梯度下降算法

动量梯度下降引入了一个"动量"项,使得梯度更新不仅依赖于当前的梯度,还考虑了之前梯度的方向。这种机制可以帮助加速收敛速度。

在tf.keras中使用Momentum算法仍使用SGD方法,但要设置momentum参数,实现过程:

python 复制代码
# 实例化
opt = tf.keras.optimizers.SGD(learning_rate=0.1,momentum=0.9)
# 定义要更新的参数
var = tf.Variable(1.0)
var0 = var.value()
# 进行循环训练
for step in range(2):
    with tf.GradientTape() as tape:
        # 定义损失函数
        loss = (var ** 2)/2.0
    # 计算梯度
    gradient = tape.gradient(loss,[var])
    # 应用梯度到对应的变量上
    opt.apply_gradients([(loss,var)])
    # 第一次更新更新
    if step == 0:
        var1 = var.value()
    # 第一次更新更新
    elif step == 1:
        var2 = var.value()
python 复制代码
var0, var1, var2
python 复制代码
# 第一次更新步长
var0 - var1
python 复制代码
# 第二次更新步长
var1 - var2

3.3.2 AdaGrad

AdaGrad 根据每个参数的历史梯度大小动态调整学习率,使得在梯度变化较大的维度上学习率减小,而在梯度变化较小的维度上学习率增大。这有助于解决某些问题中的稀疏性和非均匀性。

python 复制代码
# 实例化
# initial_accumulator_value累加器用于存储每个参数的历史梯度的平方和
# epsilon为了避免梯度平方和的倒数为无穷大(即分母为零的情况),会在分母加上一个很小的正值。这也有助于提高数值稳定性。
opt = tf.keras.optimizers.Adagrad(learning_rate=0.1,initial_accumulator_value=0.1,epsilon=1e-06)
# 定义要更新的参数
var = tf.Variable(1.0)
# 使用GradientTape记录损失函数计算过程
with tf.GradientTape() as tape:
    loss = (var ** 2) / 2.0
# 计算梯度
gradient = tape.gradient(loss,[var])
# 应用梯度到对应的变量上
opt.apply_gradients([(loss,var)])
# 展示更新结果
var

3.3.3 RMSprop

RMSProp 改进了 AdaGrad 的一些不足之处,通过使用指数加权平均来计算梯度的平方根,从而避免了学习率过快衰减的问题。

python 复制代码
# 实例化
opt = tf.keras.optimizers.RMSprop(learning_rate=0.1,rho=0.9)
# 定义要更新的参数
# rho控制了对过去梯度平方的指数衰减平均
var = tf.Variable(1.0)
# 使用GradientTape记录损失函数计算过程
with tf.GradientTape() as tape:
    loss = (var ** 2) / 2.0
# 计算梯度
gradient = tape.gradient(loss,[var])
# 应用梯度到对应的变量上
opt.apply_gradients([(loss,var)])
# 展示更新结果
var

3.3.4 Adam

Adam 结合了 Momentum 和 RMSProp 的优点,使用了一阶矩(动量)和二阶矩(RMS)的指数加权平均来适应性地调整学习率。Adam 在实践中非常流行,因为它通常表现出色,并且需要很少的手动调参。

python 复制代码
# 实例化
opt = tf.keras.optimizers.Adam(learning_rate=0.1)
# 定义要调整的参数
var = tf.Variable(1.0)
# 使用GradientTape记录损失函数计算过程
with tf.GradientTape() as tape:
    loss = (var ** 2) / 2.0
# 计算梯度
gradient = tape.gradient(loss,[var])
# 应用梯度到对应的变量上
opt.apply_gradients([(loss,var)])
# 展示更新结果
var

四、深度学习正则化

在设计机器学习算法时不仅要求在训练集上误小,而且希望在新样本上

的泛化能力强。许多机器学习算法都采用相关的策略来减小测试误差,这

些策略被统称为正则化(缓解网络过拟合的策略)。因为神经网络的强大的表示能力经常遇到过拟合,所以需要使用不同形式的正则化策略。

4.1 L1和L2正则化

L1和L2是最常见的正则化方法。它们在损失函数中增加一个正则项,由于添加了这个正则化项,权重矩阵的值减小,因为它假定具有更小权重矩阵的神经网络导致更简单的模型。因此,它也会在一定程度上减少过拟合。

  • L1正则化
python 复制代码
tf.keras.regularizers.L1(l1=0.01)
  • L2正则化
python 复制代码
tf.keras.regularizers.L2(l2=0.01)
  • L1L2正则化
python 复制代码
tf.keras.regularizers.L1L2(l1=0.0,l2=0.0)

我们直接在某一层的layers中指明正则化类型和超参数即可:

python 复制代码
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras import regularizers

# 定义Sequential模型
model = keras.Sequential([
    # 第一个隐藏层,L1正则化
    layers.Dense(3,activation="relu",kernel_initializer="he_normal",kernel_regularizer=regularizers.l1(0.001),input_shape=(3,)),
    # 第二个隐藏层,L2正则化
    layers.Dense(2,activation="relu",kernel_initializer="he_normal",kernel_regularizer=regularizers.l2(0.001)),
    # 输出层,L1L2正则化
    layers.Dense(2,activation="sigmoid",kernel_initializer="he_normal",kernel_regularizer=regularizers.L1L2(0.001,0.001))
],
    name = "my_Sequential"
)

4.2 Droupout正则化

dropout是在深度学习领域最常用的正则化技术。Dropout 技术通过随机"丢弃"一部分神经元(即设置其权重为零),从而暂时从网络中移除这些神经元及其连接。在每个训练阶段(epoch),随机选择不同比例的神经元进行丢弃。这样做的效果是,在每次迭代过程中,神经网络都会形成不同的"稀疏网络",这些稀疏网络实际上是相互独立训练的。

python 复制代码
import numpy as np

# 定义dropout层,每个神经元有0.2的概率被丢弃
layer = layers.Dropout(0.2,input_shape=(2,))
# 定义输入数据
data = np.arange(1,11).reshape(5,2).astype(np.float32)
# 对输入数据进行失活
outputs = layer(data,training=True)
outputs

4.3 提前停止

提前停止是将一部分训练集作为验证集。当验证集的性能越来越差时或者性能不再提升,则立即停止对该模型的训练。

python 复制代码
# 定义回调函数
# 损失值在连续的三个训练周期(patience=3)内没有改善,则训练将提前停止。
callback = keras.callbacks.EarlyStopping(monitor="loss",patience=3)
# 定义一层的网络
model = keras.Sequential([layers.Dense(10)])
# 模型编译
model.compile(keras.optimizers.SGD(),loss="mse")
# 模型训练
# epoch表示模型遍历整个数据集次数
# batch_size 指定每次更新模型参数时使用的样本数量
history = model.fit(np.arange(100).reshape(5,20),np.array([0,1,0,1,0]),epochs=10,callbacks=callback,batch_size=1,verbose=1)
# 打印运行的epochs
len(history.history["loss"])

4.4 批标准化

批标准化(BN层)是针对单个神经元进行,利用网络训练时一个mini-batch的数据来计算该神经元的均值和方差归一化后并重构。因而称为Batch Normalization。

python 复制代码
# 直接将其放⼊构建神经⽹络的结构中即可
# center 添加一个可学习的偏移量beta到归一化的激活上
# scale 乘以一个可学习的缩放因子gamma到归一化的激活上
# beta_initializer、gamma_initializer 初始化
tf.keras.layers.BatchNormalization(epsilon=0.001,center=True,scale=True,
									beta_initializer="zeros",gamma_initializer="ones")

五、神经网络案例

使用手写数字的MNIST数据集进行神经网络训练,该数据集包含60,000个用于训练的样本和10,000个用于测试的样本,其值为0到255。

python 复制代码
# 导入相应的包
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = (7,7)
import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Dropout,Activation,BatchNormalization
from tensorflow.keras import utils
from tensorflow.keras import regularizers
  1. 加载数据
python 复制代码
# 加载数据集
(x_train,y_train),(x_test,y_test) = mnist.load_data()
python 复制代码
x_train.shape,y_train.shape
python 复制代码
# 显示数据
for i in range(9):
    plt.subplot(3,3,i + 1)
    plt.imshow(x_train[i],cmap="gray")
    plt.title(y_train[i])
  1. 数据处理

神经网络中的每个训练样本是一个向量,因此需要对输入进行重塑,使每个28x28的图像成为一个的784维向量。另外,需将输入数据进行归一化处理,从0-255调整到0-1

python 复制代码
# 调整数据维度
x_train = x_train.reshape(60000,784)
x_test = x_test.reshape(10000,784)

# 格式转换
x_train = x_train.astype("float32")
x_test = x_test.astype("float32")

# 归一化(将数据范围调整到[0,1]之间)
x_train= x_train/255
x_test = x_test/255
python 复制代码
x_train.shape,x_test.shape
python 复制代码
# 将目标值转换成热编码
y_train = utils.to_categorical(y_train,10)
y_test = utils.to_categorical(y_test,10)
python 复制代码
y_train
  1. 模型构建
python 复制代码
# 使用序列模型进行构建
model = Sequential([
    # 全连接层:2个隐层,1个输出层
    # 第一个隐层:512个神经元,先激活后BN,随机失活
    Dense(512,activation="relu",input_shape=(784,)),
    BatchNormalization(),
    Dropout(0.2),
    # 第二个隐层:512个神经元,先BN后激活,随机失活
    Dense(512,kernel_regularizer=regularizers.l2(0.01)),
    BatchNormalization(),
    Activation("relu"),
    Dropout(0.2),
    # 输出层
    Dense(10,activation="softmax")
])
python 复制代码
model.summary()
  1. 模型编译
python 复制代码
# 模型编译,指明损失函数、优化器、评估指标
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
  1. 模型训练
python 复制代码
# batch_size每次送入模型中样本个数,epochs所有样本的迭代次数,并指明验证数据集
history = model.fit(x_train,y_train,batch_size=128,epochs=4,verbose=1,validation_data=(x_test,y_test))
python 复制代码
# 绘制损失函数变化曲线
plt.figure(figsize=(14,8))
# 训练集损失函数变化
plt.plot(history.history['loss'],label='train_loss')
# 验证集损失函数变化
plt.plot(history.history['val_loss'],label='val_loss')
plt.legend()
plt.grid()
python 复制代码
# 绘制准确率的变化曲线
plt.figure(figsize=(14,8)) 
# 训练集准确率 
plt.plot(history.history["accuracy"], label="train_accuracy") 
# 验证集准确率
plt.plot(history.history["val_accuracy"], label="val_accuracy")
plt.legend() 
plt.grid() 
  1. 模型测试
python 复制代码
# 模型测试
score = model.evaluate(x_test,y_test,verbose=1)
score
  1. 模型保存
python 复制代码
# 保存模型架构与权重在h5⽂件中 
model.save('my_model.h5')
# 加载模型
model = tf.keras.models.load_model("my_model.h5")

六、卷积神经网络CNN

6.1 CNN网络的构成

CNN网络主要构成:卷积层、池化层、全连接层构成,其中卷积层负责提取图像特征;池化层回来降维,防止过拟合;全连接层用来输出结果。

6.2 卷积层

卷积运算本质上就是在滤波器和输入数据的局部区域间做点积。

卷积有多通道卷积和多卷积核卷积。

卷积核的实现:

python 复制代码
tf.keras.layers.Conv2D(filters,kernel_size,strides=(1,1),padding='valid',activation=None)
# fileters 卷积过滤器的数量,对应输出特征图的通道数
# kernel_size 过滤器filter的大小
# stride 步长
# padding valid在输入周围不进行填充,same在输入周围进行填充

6.3 池化层

  1. 最大池化,取窗口内的最大值作为输出。
python 复制代码
tf.keras.layers.MaxPool2D(pool_size=(2,2),strides=2,padding='valid')
  1. 平均池化,取窗口内的所有值的均值作为输出
python 复制代码
tf.keras.layers.AveragePooling2D(pool_size=(2,2),strides=2,padding='valid')

6.4 全连接层

全连接层位于CNN网络的末端,经过卷积层的特征提取和池化层的降维,将特征图转化为一维向量送入到全连接层中进行分类和回归操作。

6.5 卷积神经网络的构建

python 复制代码
# 导包
import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Conv2D,MaxPooling2D
  1. 数据加载
python 复制代码
(train_image,train_label),(test_image,test_label) = mnist.load_data()
python 复制代码
train_image.shape,train_label.shape
  1. 数据处理
python 复制代码
# 维度调整
train_image = train_image.reshape(60000,28,28,1)
python 复制代码
train_image.shape
python 复制代码
test_image = test_image.reshape(10000,28,28,1)
  1. 模型搭建
python 复制代码
model = Sequential([
    # 卷积层,6个5*5的卷积
    layers.Conv2D(filters=6,kernel_size=5,activation="relu",input_shape=(28,28,1)),
    # 池化层
    layers.MaxPooling2D(pool_size=2,strides=2),
    # 卷积层,16个5*5的卷积
    layers.Conv2D(filters=16,kernel_size=5,activation="relu"),
    # 池化层
    layers.MaxPooling2D(pool_size=2,strides=2),
    # 将卷积层的输出展平为一维向量
    layers.Flatten(),
    # 全卷积层
    layers.Dense(120,activation="relu"),
    layers.Dense(84,activation="relu"),
    layers.Dense(10,activation="softmax")
])
python 复制代码
model.summary()
  1. 模型编译
python 复制代码
# 优化器
optimizer = tf.keras.optimizers.SGD(learning_rate=0.1)
# 模型编译
model.compile(optimizer=optimizer,loss='sparse_categorical_crossentropy',metrics=["accuracy"])
  1. 模型训练
python 复制代码
model.fit(train_image,train_label,epochs=5,batch_size=128,verbose=1)
  1. 模型评估
python 复制代码
model.evaluate(test_image,test_label,verbose=1)
相关推荐
deephub21 分钟前
优化注意力层提升 Transformer 模型效率:通过改进注意力机制降低机器学习成本
人工智能·深度学习·transformer·大语言模型·注意力机制
搏博33 分钟前
神经网络问题之二:梯度爆炸(Gradient Explosion)
人工智能·深度学习·神经网络
KGback39 分钟前
【论文解析】HAQ: Hardware-Aware Automated Quantization With Mixed Precision
人工智能
电子手信1 小时前
知识中台在多语言客户中的应用
大数据·人工智能·自然语言处理·数据挖掘·知识图谱
不高明的骗子1 小时前
【深度学习之一】2024最新pytorch+cuda+cudnn下载安装搭建开发环境
人工智能·pytorch·深度学习·cuda
Chef_Chen1 小时前
从0开始学习机器学习--Day33--机器学习阶段总结
人工智能·学习·机器学习
搏博1 小时前
神经网络问题之:梯度不稳定
人工智能·深度学习·神经网络
Sxiaocai1 小时前
使用 PyTorch 实现并训练 VGGNet 用于 MNIST 分类
pytorch·深度学习·分类
GL_Rain1 小时前
【OpenCV】Could NOT find TIFF (missing: TIFF_LIBRARY TIFF_INCLUDE_DIR)
人工智能·opencv·计算机视觉
shansjqun1 小时前
教学内容全覆盖:航拍杂草检测与分类
人工智能·分类·数据挖掘