卷积神经网络理论(CNN)·基于tensorflow实现

传统神经网络的输入是一维的数据(比如28*28的图片,需要转化为一维向量)。

而卷积神经网络的输入是一个三维的(比如RGB)。

结构

卷积神经网络有以下结构:

  • 输入层
  • 卷积层
  • 池化层
  • 全连接层

输入层

顾名思义,输入层就是输入数据(可以是图片等数据)。

卷积层

卷积是什么?

在数学和信号处理中,卷积是一种将两个函数(或信号)结合以生成新函数的操作。卷积的操作可以用于信号的平滑、特征提取等多种用途。对于离散信号,卷积操作可以描述为:

给定两个离散信号 f[n]f[n] 和 g[n]g[n],它们的卷积 (f∗g)[n](f∗g)[n] 定义为:

(f * g)[n] = \sum_{k=-\infty}^{\infty} f[k] \cdot g[n - k]

  • f[n]:第一个信号或函数(通常是输入信号)。
  • g[n]:第二个信号或函数(通常是卷积核或滤波器)。
  • n:卷积结果的位置索引。
  • k:求和的索引变量,遍历所有可能的重叠位置。

在计算卷积时,我们将卷积核 gg 在信号 ff 上滑动,并对每个位置计算重叠部分的加权和。

对于有限长信号 f=[f0,f1,…,fM−1]f=[f0​,f1​,…,fM−1​] 和卷积核 g=[g0,g1,…,gN−1]g=[g0​,g1​,…,gN−1​],卷积的具体计算公式可以写成:

(f * g)[n] = \sum_{k=0}^{N-1} f[k] \cdot g[n - k]

案例引入一

如果有一只猫咪的图片,我需要进行训练分类。

我们知道猫咪的特征是耳朵、眼睛、鼻子。我在第二张图片上画的红色圈圈就是重要的特征。相反,绿色圈圈的就是不重要的特征。

我们要做的就是将这些重要的特征提取出来,将不重要的特征删除。

首先先看一下卷积的过程:

我们来仔细讲解以下这个过程:

假如我有一张5*5*3的图片作为输入。

我们首将5*5*1的这一层拿出来,作为案例。

我们接下来会设置一个权重矩阵,为3*3的矩阵,然后将所选区域与权重矩阵对应相乘得到一个特征点。然后得到一个特征图。

第一次:1*3+2*2+1*1+2*2=12。

第二次:1*2+2*1+2*1+1*2+2*2=12.0

第三次:

第四次:2*1+2*3+2*1=10

第五次、六次、七次、八次、九次。

一般一张RGB的图片有3个通道,我们需要在这三个通道上分别做卷积,然后相加。

案例引入二

注意因为我们的图片此时是3维的,分别有RGB三个通道,每个通道都是7*7的,,所以我们能的卷积核(也就是权重w),也要是3维的,这里我们选择的卷积核是3*3*3的我们也可以选择4*4*3的,总之最后的一个维度一定要是3,因为要对应前面的3个通道。从上面图片可以看出来,我们可以选择多个参数,上面我们选择了w0和w1。每个参数(这里的参数是二维的,如w0、w1),输出得到的output是3个通道的相加值。

比如w0[:,:,0]提取到的是0;w0[:,:,1]提取到的是2;w0[:,:,2]提取到的是0,三个数和常数相加0+0+2+1=3,就是输出的第一行第一列。

我们要求每一层的卷积卷积核的规格必须一样,比如w0核w1的规格必须一样(都是3*3),在不同的卷积层规格可以不一样。

我们再想一下,为什么要用多个w(w0、w1)?我们在神经网络中是如何提取特征的?使用多个神经元来提取每个特征并且给予一定的权重,就是这样不断训练确定参数以预测。CNN中的思路也是如此,用多个w(卷积核)来提取不同的特征。

举个例子,如果我们项通过一个神经网络预测房子的价格,我们会有以下结构:

这里我们没有建立正常的大家认知的一个网络,而是自己根据自己的想法来建立的。可以看出第四个神经元有两个输入分别是离学校距离、噪音程度,根据常识,我们可以判断出这是一个与“教育”有关的特征,这里的特征会自己训练出一个权重。

因为神经网络可以自己训练出权重,所以我们可以像下面这样,每个输入都指向每一个神经元,即使有的输入与这个神经元没有太大的关系,我们设置参数的时候还是可以将其权重设置的非常小,不会影响我们最终的结果。

卷积层涉及的参数

滑动窗口步长

每次提取特征的区域移动的单位,可以为1、2.....。

步长为1的窗口:
其中红色的是初始位置,蓝色的是向着右边移动一个单位的位置,绿色的是向下移动1个单位的位置。

步长为2的窗口:

注意:得到的特征图的大小与步长、卷积核大小有关

边缘填充

我们在进行特征提取的时候,有的点提取了很多次,有的点只提取了一次,有的提取了两次,比如下面3*3的一个卷积核来提取一个5*5的图片,有绿色点的被提取了两次。

再次提取,有绿色点的被提取了3次。

我们可以发现规律,越靠近中间位置的点,被提取的次数越多,在边缘的点被提取的次数非常少,但是我们在识别图片的时候,我们并不知道边缘地区的特征是否重要。因此我们要尽可能的将图片上面的特征全部提取。

有一个方法就是在图片周围加上一圈0或者两圈0,这样原来在边缘的点也变得在中间了。这就叫做边缘填充。为什么不添加1、2或者其他呢?因为如果添加其他的会影响得到的特征图。

卷积核个数

卷积核个数就是指选取的参数的量w0、w1、w2等有多少个卷积核就得到多少个特征图。

计算公式

我们通常不会只进行一次卷积,就像神经网络通常不会只设置一层隐藏层。

注意:卷积核的个数,会影响下一层的深度。本层的深度会影响下一层的卷积核的深度。

H_{2} = \frac{H_{1}-F_{H}+2P}{S}+1

W_{2}=\frac{W_{1}-F_{W}+2P}{S}+1

其中:W1、H1表示输入的宽度和高度。W2、H2表示输出的卷积核的宽度和长度。F表示卷积核长和宽的大小,P表示加几圈0,S表示步长。

举例:输入32*32*3,用10个5*5*3的卷积核来提取特征,步长为1,边界填充为2。

解:(32-5+2*2)/1+1=32。长和宽都不变,深度变为10(因为有10个卷积核)。

卷积参数共享

为了减少参数的个数,我们让每一个卷积核(wi)共享的提取每一个特征,即每一个卷积核不变(这是因为直观的想,图片每个地方的特征都不一样,应该在不同地方用不同的参数提取,但是这样参数就太大了,所以用一套参数来提取所有特征)。

池化层

池化层是用来压缩图像的长度和高度的,特征图的个数不会变。

下图中选择2*2正方形中最大的作为特征。

整体过程

每进行一次卷积操作,就要用激活函数激活,如果特征多了就用池化层压缩。最后得到的也是一个多维的数据,将其展为1为再进行回归或者预测。

基于tensorflow构建神经网络

本实验采用CIFAR10 数据集完成,包含 10 类,共 60000 张彩色图片,每类图片有 6000 张。此数据集中 50000 个样例被作为训练集,剩余 10000 个样例作为测试集。类之间相互独立,不存在重叠的部分。

导包:

import tensorflow as tf

from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt

下载数据:
 

(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()

train_images, test_images = train_images / 255.0, test_images / 255.0

搭建模型:
 

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))

layers.Conv2D

作用
Conv2D 是卷积神经网络中的一个卷积层,它主要用于从输入数据(通常是图像)中提取特征。卷积层通过滑动一个卷积核(或过滤器)在输入图像上执行卷积操作,生成特征图(或激活图)。这种操作可以帮助神经网络捕捉图像中的局部特征(如边缘、角点等)。

参数

  • filters: 卷积核的数量,即输出特征图的深度。更多的卷积核能提取更多的特征。
    • 示例filters=32 表示使用 32 个卷积核,每个卷积核会产生一个特征图。
  • kernel_size: 卷积核的大小,通常是一个整数或元组,表示卷积核的高度和宽度。
    • 示例kernel_size=(3, 3) 表示卷积核的大小为 3x3 像素。
  • activation: 激活函数,用于引入非线性特性,帮助模型学习复杂的模式。
    • 示例activation='relu' 使用 ReLU 激活函数。
  • input_shape: 输入数据的形状,仅在模型的第一层需要指定。它是一个元组,表示输入数据的高度、宽度和通道数。
    • 示例input_shape=(32, 32, 3) 表示输入图像的高度和宽度均为 32 像素,且有 3 个颜色通道(RGB)。

具体情景
假设我们在处理 32x32 像素的彩色图像(RGB),并希望提取 32 个特征图。我们使用的卷积层定义如下:

layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3))

  • filters=32:产生 32 个特征图。
  • kernel_size=(3, 3):每个卷积核的大小为 3x3 像素。
  • activation=‘relu’:对卷积结果应用 ReLU 激活函数。
  • input_shape=(32, 32, 3):输入是 32x32 像素的彩色图像。

layers.MaxPooling2D

作用
MaxPooling2D 是一个池化层,用于下采样(缩小)特征图的尺寸。池化操作可以减少特征图的空间维度,从而减少计算量,帮助防止过拟合,并使特征更具不变性。常用的池化方式是最大池化,它选择池化窗口内的最大值。

参数

  • pool_size: 池化窗口的大小,通常是一个整数或元组,表示池化窗口的高度和宽度。
    • 示例pool_size=(2, 2) 表示池化窗口的大小为 2x2 像素。
  • strides: 池化操作的步幅,表示每次池化窗口移动的步长。默认为池化窗口大小。
    • 示例strides=(2, 2) 表示池化窗口每次移动 2 像素。
  • padding: 池化操作的填充方式。通常设置为 'valid'(无填充)或 'same'(填充以保持输出尺寸与输入尺寸相同)。通常池化层不需要填充。
    • 示例:默认 'valid'

具体情景
在处理卷积层提取的特征图时,为了缩小特征图尺寸并减少计算量,可以使用最大池化层:

layers.MaxPooling2D((2, 2))

  • pool_size=(2, 2):池化窗口大小为 2x2 像素。
  • strides=(2, 2):池化窗口每次移动 2 像素。

为了完成模型,需要将卷积基(形状为 (4, 4, 64))的最后一个输出张量馈送到一个或多个 Dense 层以执行分类。Dense 层将向量作为输入(即 1 维),而当前输出为 3 维张量。首先,将 3 维输出展平(或展开)为 1 维,然后在顶部添加一个或多个 Dense 层。CIFAR 有 10 个输出类,因此使用具有 10 个输出的最终 Dense 层。

model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10))

layers.Dense

作用
Dense 是全连接层,用于将前一层的所有神经元与当前层的所有神经元连接。全连接层用于将特征映射到分类或回归任务的输出空间。它通常位于网络的末尾,用于整合和总结提取到的特征。

参数

  • units: 神经元的数量,决定了全连接层的输出维度。
    • 示例units=64 表示该层有 64 个神经元。
  • activation: 激活函数,用于对神经元的线性组合结果进行非线性变换。
    • 示例activation='relu' 使用 ReLU 激活函数。
  • use_bias: 是否使用偏置项,默认值为 True。可以选择是否添加偏置项。

具体情景
在特征提取后,我们使用全连接层将特征映射到最终的类别或回归值:

layers.Dense(64, activation='relu')

  • units=64:该层有 64 个神经元。
  • activation=‘relu’:对神经元的线性组合结果应用 ReLU 激活函数。

在分类任务的输出层,我们会有一个没有激活函数的全连接层,以便在之后应用 softmax 或其他激活函数来获取类别概率:

layers.Dense(10)

  • units=10:输出层有 10 个神经元,通常表示 10 个类别。

编译和训练

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

history = model.fit(train_images, train_labels, epochs=10, 
                    validation_data=(test_images, test_labels))

  • 24
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

背水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值