遗传算法与深度学习实战(25)——使用Keras构建卷积神经网络

news/2024/12/26 5:22:15/

遗传算法与深度学习实战(25)——使用Keras构建卷积神经网络

    • 0. 前言
    • 1. 卷积神经网络基本概念
      • 1.1 卷积
      • 1.2 步幅
      • 1.3 填充
      • 1.4 激活函数
      • 1.5 池化
    • 2. 使用 Keras 构建卷积神经网络
    • 3. CNN 层的问题
    • 4. 模型泛化
    • 小结
    • 系列链接

0. 前言

卷积神经网络 (Convolutional Neural Network, CNN) 的提出是为了解决传统神经网络的缺陷。即使对象位于图片中的不同位置或其在图像中具有不同占比,CNN 依旧能够正确的处理这些图像,因此在对象分类/检测任务中更加有效。在本节中,我们将使用 Keras 构建卷积神经网络模型进行图像分类,介绍 CNN 的基础知识,并构建 CNN 模型。

1. 卷积神经网络基本概念

在本节中,首先介绍卷积神经网络 (Convolutional Neural Network, CNN) 的相关概念与组成,了解 CNN 的工作原理。

1.1 卷积

卷积是两个矩阵间的乘法——通常一个矩阵具有较大尺寸,另一个矩阵则较小。要了解卷积,首先讲解以下示例。给定矩阵 A 和矩阵 B 如下:

矩阵

在进行卷积时,我们将较小的矩阵在较大的矩阵上滑动,在上述两个矩阵中,当较小的矩阵 B 需要在较大矩阵 A 的整个区域上滑动时,会得到 9 次乘法运算,过程如下。
在矩阵 A 中从第 1 个元素开始选取与矩阵 B 相同尺寸的子矩阵 [ 1 2 0 1 1 1 3 3 2 ] \left[ \begin{array}{ccc} 1 & 2 & 0\\ 1 & 1 & 1\\ 3 & 3 & 2\\\end{array}\right] 113213012 和矩阵 B 相乘并求和:

卷积-1

1 × 3 + 2 × 1 + 0 × 1 + 1 × 2 + 1 × 3 + 1 × 1 + 3 × 2 + 3 × 2 + 2 × 3 = 29 1\times 3+2\times 1+0\times 1+1\times 2+1\times 3+1\times 1+3\times 2+3\times 2 + 2\times 3=29 1×3+2×1+0×1+1×2+1×3+1×1+3×2+3×2+2×3=29

然后,向右滑动一个窗口,选择第 2 个与矩阵 B 相同尺寸的子矩阵 [ 2 0 2 1 1 2 3 2 1 ] \left[ \begin{array}{ccc} 2 & 0 & 2\\ 1 & 1 & 2\\ 3 & 2 & 1\\\end{array}\right] 213012221 和矩阵 B 相乘并求和:

卷积-2

2 × 3 + 0 × 1 + 2 × 1 + 1 × 2 + 1 × 3 + 2 × 1 + 3 × 2 + 2 × 2 + 1 × 3 = 28 2\times 3+0\times 1+2\times 1+1\times 2+1\times 3+2\times 1+3\times 2+2\times 2 + 1\times 3=28 2×3+0×1+2×1+1×2+1×3+2×1+3×2+2×2+1×3=28

然后,再向右滑动一个窗口,选择第 3 个与矩阵 B 相同尺寸的子矩阵 [ 0 2 3 1 2 0 2 1 2 ] \left[ \begin{array}{ccc} 0 & 2 & 3\\ 1 & 2 & 0\\ 2 & 1 & 2\\\end{array}\right] 012221302 和矩阵 B 相乘并求和:

卷积-3

0 × 3 + 2 × 1 + 3 × 1 + 1 × 2 + 2 × 3 + 0 × 1 + 2 × 2 + 1 × 2 + 2 × 3 = 25 0\times 3+2\times 1+3\times 1+1\times 2+2\times 3+0\times 1+2\times 2+1\times 2 + 2\times 3=25 0×3+2×1+3×1+1×2+2×3+0×1+2×2+1×2+2×3=25

当向右滑到尽头时,向下滑动一个窗口,并从矩阵 A 左边开始,选择第 4 个与矩阵 B 相同尺寸的子矩阵 [ 1 1 1 3 3 2 1 0 2 ] \left[ \begin{array}{ccc} 1 & 1 & 1\\ 3 & 3 & 2\\ 1 & 0 & 2\\\end{array}\right] 131130122 和矩阵 B 相乘并求和:

卷积-4

1 × 3 + 1 × 1 + 1 × 1 + 3 × 2 + 3 × 3 + 2 × 1 + 1 × 2 + 0 × 2 + 2 × 3 = 30 1\times 3+1\times 1+1\times 1+3\times 2+3\times 3+2\times 1+1\times 2+0\times 2 + 2\times 3=30 1×3+1×1+1×1+3×2+3×3+2×1+1×2+0×2+2×3=30

然后,继续向右滑动,并重复以上过程滑动矩阵窗口,直到滑动到最后一个子矩阵为止,得到最终的结果 [ 29 28 25 30 30 27 20 24 34 ] \left[ \begin{array}{ccc} 29 & 28 & 25\\ 30 & 30 & 27\\ 20 & 24 & 34\\\end{array}\right] 293020283024252734

特征图

完整的卷积计算过程如以下动图所示:

卷积

通常,我们把较小的矩阵 B 称为滤波器 (filter) 或卷积核 (kernel),使用 ⊗ \otimes 表示卷积运算,较小矩阵中的值通过梯度下降被优化学习,卷积核中的值则为网络权重。卷积后得到的矩阵,也称为特征图 (feature map)。
卷积核的通道数与其所乘矩阵的通道数相等。例如,当图像输入形状为 5 x 5 x 3 时(其中 3 为图像通道数),形状为 3 x 3 的卷积核也将具有 3 个通道,以便进行矩阵卷积运算:

三通道卷积

可以看到无论卷积核有多少通道,一个卷积核计算后都只能得到一个通道。多为了捕获图像中的更多特征,通常我们会使用多个卷积核,得到多个通道的特征图,当使用多个卷积核时,计算过程如下:

多卷积核

需要注意的是,卷积并不等同于滤波,最直观的区别在于滤波后的图像大小不变,而卷积会改变图像大小,关于它们之间更详细的计算差异,并非本节重点,因此不再展开介绍。

1.2 步幅

在前面的示例中,卷积核每次计算时在水平和垂直方向只移动一个单位,因此可以说卷积核的步幅 (Strides) 为 (1, 1),步幅越大,卷积操作跳过的值越多,例如以下为步幅为 (2, 2) 时的卷积过程:

步幅为2的卷积计算

1.3 填充

在前面的示例中,卷积操作对于输入矩阵的不同位置计算的次数并不相同,具体来说对于边缘的数值在卷积时,仅仅使用一次,而位于中心的值则会被多次使用,因此可能导致卷积错过图像边缘的一些重要信息。如果要增加对于图像边缘的考虑,我们将在输入矩阵的边缘周围的填充 (Padding) 零,下图展示了用 0 填充边缘后的矩阵进行的卷积运算,这种填充形式进行的卷积,称为 same 填充,卷积后得到的矩阵大小为 ⌊ d + 2 p − k s ⌋ + 1 \lfloor\frac {d+2p-k} s\rfloor+1 sd+2pk+1,其中 s s s 表示步幅, p p p 表示填充大小, k k k 表示滤波器尺寸。而未进行填充时执行卷积运算,也称为 valid 填充。

填充

1.4 激活函数

在传统神经网络中,隐藏层不仅将输入值乘以权重,而且还会对数据应用非线性激活函数,将值通过激活函数传递。CNN 中同样包含激活函数,包括 SigmoidReLUtanhLeakyReLU 等。

1.5 池化

研究了卷积的工作原理之后,我们将了解用于卷积操作之后的另一个常用操作:池化 (Pooling)。假设卷积操作的输出如下,为 2 x 2

[ 29 28 20 24 ] \left[ \begin{array}{cc} 29 & 28\\ 20 & 24\\\end{array}\right] [29202824]

假设使用池化块(或者类比卷积核,我们也可以称之为池化核)为 2 x 2 的最大池化,那么将会输出 29 作为池化结果。假设卷积步骤的输出是一个更大的矩阵,如下所示:
[ 29 28 25 29 20 24 30 26 27 23 26 27 24 25 23 31 ] \left[ \begin{array}{cccc} 29 & 28 & 25 & 29\\ 20 & 24 & 30 & 26\\ 27 & 23 & 26 & 27\\ 24 & 25 & 23 & 31\\\end{array}\right] 29202724282423252530262329262731
当池化核为 2 x 2,且步幅为 2 时,最大池化会将此矩阵划分为 2 x 2 的非重叠块,并且仅保留每个块中最大的元素值,如下所示:

[ 29 28 ∣ 25 29 20 24 ∣ 30 26 — — — — — 27 23 ∣ 26 27 24 25 ∣ 23 31 ] = [ 29 30 27 31 ] \left[ \begin{array}{ccccc} 29 & 28 & | & 25 & 29\\ 20 & 24 & | & 30 & 26\\ —&—&—&—&—\\ 27 & 23 & | & 26 & 27\\ 24 & 25 & | & 23 & 31\\\end{array}\right]=\left[ \begin{array}{cc} 29 & 30\\ 27 & 31\\\end{array}\right] 29202724282423252530262329262731 =[29273031]

从每个池化块中,最大池化仅选择具有最高值的元素。除了最大池化外,也可以使用平均池化,其将输出每个池化块中的平均值作为结果,在实践中,与其他类型的池化相比,最常使用的池化为最大池化。

2. 使用 Keras 构建卷积神经网络

在本节中,我们在 Fashion-MNIST 数据集上执行图像分类,Fashion-MNIST 是一个基本测试数据集,可以对其进行裁剪,减少用于训练或推理的数据量,以减少进化所需的运行时间。

(1) 加载 Fashion 数据集,对数据进行归一化并将其整形为形状为 (28,28,1) 的张量,其中 1 表示通道,这是因为数据集中的 2D 数组未定义通道,我们从原始数据集中提取前 1,000 个样本进行训练和 100 个用于测试:

import tensorflow as tf
from tensorflow.keras import datasets, layers, models
import numpy as np
import math
import timeimport matplotlib.pyplot as plt
from livelossplot import PlotLossesKerasdataset = datasets.fashion_mnist
(x_train, y_train), (x_test, y_test) = dataset.load_data()# normalize and reshape data
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1).astype("float32") / 255.0
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1).astype("float32") / 255.0x_train = x_train[:1000]
y_train= y_train[:1000]
x_test = x_test[:100]
y_test= y_test[:100]class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat','Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']def plot_data(num_images, images, labels):grid = math.ceil(math.sqrt(num_images))plt.figure(figsize=(grid*2,grid*2))for i in range(num_images):plt.subplot(grid,grid,i+1)plt.xticks([])plt.yticks([])plt.grid(False)     plt.imshow(images[i].reshape(28,28))plt.xlabel(class_names[labels[i]])      plt.show()plot_data(25, x_train, y_train)

减小数据集规模并非理想方案,但当我们尝试优化数千甚至数万个个体时,这样做可以节省大量时间。

数据集

(2) 构建模型, 每个 Conv2D 层定义了应用于输入的卷积操作。在连续应用卷积层的过程中,滤波器或通道的数量从上一层扩展。例如,第一个 Conv2D 层将输入通道从 1 扩展到 64。然后,后续层将其缩小到 32,然后到 16,其中每个卷积层都添加一个 MaxPooling 层,用于总结特征:

model = models.Sequential()
model.add(layers.Conv2D(64, (3, 3), activation='relu', padding="same", input_shape=(28, 28, 1)))
model.add(layers.MaxPooling2D((2, 2), padding="same"))
model.add(layers.Conv2D(32, (3, 3), activation='relu', padding="same"))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(16, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))model.summary()

通过在图像上滑动滤波器块来生成相应的输出,其中每次卷积核滑动操作得到一个输出值,滤波器中的卷积核值或权重/参数是可以学习的。通常卷积操作的输出非常大,每个滤波器都会产生类似图像的输出块。减少数据量可以通过使用池化层,除了最大池化,还可以使用其他变体来获取收集特征的最小值或平均值。设置模型的卷积和最大池化层之后,使用 model.summary() 打印模型摘要。

模型摘要

(3) 展平 CNN 层的输出,并输入到全连接层中,该层包含 10 个神经元(输出为 10 个类别):

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

网络模型

(4) 训练模型,训练后输出结果如下所示。通常,在此数据集的优化后的性能达到 98% 左右,由于使用完整数据集进行训练非常耗时,我们仅抽取了少量数据样本:

model.compile(optimizer='adam',loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics=['accuracy'])history = model.fit(x_train, y_train, epochs=10, validation_data=(x_test, y_test),callbacks=[PlotLossesKeras()],verbose=0)test_loss, test_acc = model.evaluate(x_test,  y_test, verbose=2)

模型性能监控

可以看到,在验证数据上的准确率稳定在 81% 左右。由于同一类别中的样本变化很小,在 Fashion-MNIST 数据集上使用简单 CNN 就可以得到较高准确率,但对于像 CIFAR-10CIFAR-100 同一类别中样本变化较大的数据集,情况将有所不同。
观察训练和测试的损失和准确率之间的差异。可以看到,模型在第 3epoch 时在测试数据上的推理能力开始下降。这可能与数据规模缩小或模型构建有关。在之后的学习中,我们将介绍一些经典的 CNN 架构。

3. CNN 层的问题

接下来,我们将进一步探索 CNN 架构,并了解了 CNN 的局限性。当正确使用时,CNN 是一个很好的工具,但如果使用不当,也会引发一系列问题,了解问题有助于更好的理解进化优化。

(1) 构建模型,只使用一个 CNN 层。定义一个具有 64 个滤波器和 3×3 卷积核的层,模型摘要输入如下所示,模型总参数量超过 600 万:

model = models.Sequential()
model.add(layers.Conv2D(64, (3, 3), activation='relu', padding="same", input_shape=(28, 28, 1)))
model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu'))
model.add(layers.Dense(10))model.summary()

模型摘要

(2) 训练模型,训练结果输出如下。可以看到,模型在训练数据上的表现非常好,但在验证/测试数据上的表现很差。这是因为具有超过 600 万参数的模型会记住训练数据集,无法很好的泛化到模型未见到的数据集上,即过拟合现象。可以看到训练集的准确率接近 100%,然而在测试/验证集的准确率大幅下降:

model.compile(optimizer='adam',loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics=['accuracy'])history = model.fit(x_train, y_train, epochs=10, validation_data=(x_test, y_test),callbacks=[PlotLossesKeras()],verbose=0)

CNN 问题

4. 模型泛化

我们通常希望构建能够泛化的模型,因此,将数据分成训练集和测试集来验证模型的泛化能力。为了提高模型的泛化能力,可以应用例如批归一化和 dropout 等技术。然而,在某些情况下,泛化可能并非最终目标,我们可能希望识别特定的数据集,在这种情况下,就需要模型能够记住数据。

(1) 接下来,我们研究池化对卷积输出的影响,构建包含池化层的卷积神经网络,为了提高模型的泛化能力,还在池化层之间添加了批归一化层:

model = models.Sequential()
model.add(layers.Conv2D(64, (3, 3), activation='relu', padding="same", input_shape=(28, 28, 1)))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2), padding="same"))
model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu'))
model.add(layers.Dense(10))model.summary()

模型摘要如下所示。可以看到,由于添加了池化,此模型的参数量约为上一模型的四分之一。

模型摘要

(2) 对模型进行 10epoch 的训练,输出结果如下所示。虽然该模型仍存在过拟合的现象,但模型已经具有很好的泛化能力,可以看到模型验证准确率得到提升且损失得到降低:

model.compile(optimizer='adam',loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics=['accuracy'])history = model.fit(x_train, y_train, epochs=10, validation_data=(x_test, y_test),callbacks=[PlotLossesKeras()],verbose=0)

模型训练过程

我们可以通过调整多个超参数改进模型,例如添加更多的 CNN 层、批归一化层、dropout、池化层,或修改卷积层的核大小或滤波器数量等。

小结

卷积神经网络 (Convolutional Neural Network, CNN) 是一种深度学习模型,特别适用于图像和视频等数据。它的设计灵感来源于生物学中对动物视觉皮层的理解,通过多层次的卷积和池化操作来实现对图像特征的学习和提取。在本节中,我们介绍了 CNN 的基本组件,并使用 Keras 实现了 CNN 模型。

系列链接

遗传算法与深度学习实战(1)——进化深度学习
遗传算法与深度学习实战(2)——生命模拟及其应用
遗传算法与深度学习实战(3)——生命模拟与进化论
遗传算法与深度学习实战(4)——遗传算法(Genetic Algorithm)详解与实现
遗传算法与深度学习实战(5)——遗传算法中常用遗传算子
遗传算法与深度学习实战(6)——遗传算法框架DEAP
遗传算法与深度学习实战(7)——DEAP框架初体验
遗传算法与深度学习实战(8)——使用遗传算法解决N皇后问题
遗传算法与深度学习实战(9)——使用遗传算法解决旅行商问题
遗传算法与深度学习实战(10)——使用遗传算法重建图像
遗传算法与深度学习实战(11)——遗传编程详解与实现
遗传算法与深度学习实战(12)——粒子群优化详解与实现
遗传算法与深度学习实战(13)——协同进化详解与实现
遗传算法与深度学习实战(14)——进化策略详解与实现
遗传算法与深度学习实战(15)——差分进化详解与实现
遗传算法与深度学习实战(16)——神经网络超参数优化
遗传算法与深度学习实战(17)——使用随机搜索自动超参数优化
遗传算法与深度学习实战(18)——使用网格搜索自动超参数优化
遗传算法与深度学习实战(19)——使用粒子群优化自动超参数优化
遗传算法与深度学习实战(20)——使用进化策略自动超参数优化
遗传算法与深度学习实战(21)——使用差分搜索自动超参数优化
遗传算法与深度学习实战(22)——使用Numpy构建神经网络
遗传算法与深度学习实战(23)——利用遗传算法优化深度学习模型
遗传算法与深度学习实战(24)——在Keras中应用神经进化优化


http://www.ppmy.cn/news/1551319.html

相关文章

springboot343大学生选修选课系统的设计与实现(论文+源码)_kaic

毕 业 设 计(论 文) 大学生选修选课系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此&#xff0c…

如何给GitHub的开源项目贡献PR

🎯导读:本文详细介绍了如何向开源项目“代码随想录”贡献自己的题解。首先,需要Fork原项目的仓库至个人GitHub账户,然后解决克隆仓库时可能遇到的SSH密钥问题。接着,按照标准流程对本地仓库进行代码或文档的修改&#…

NAT拓展

NAT ALG(NAT应用级网) 为某些应用层协议,因为其报文内容可能携带IP相关信息,而普通NAT转化无法将这些IP转化,从而导致协议无法正常运行 例如FTP,DHCP,RSTP,ICMP,IPSEC…

AJAX 实时搜索

AJAX 实时搜索 AJAX(Asynchronous JavaScript and XML)实时搜索是一种无需刷新整个网页就能从服务器获取数据并在网页上展示的技术。这种技术极大地提升了用户体验,尤其是在搜索引擎、在线购物网站、社交媒体平台等应用中。本文将详细介绍AJ…

小程序 - 个人简历

为了让招聘人员快速地认识自己,可以做一个“个人简历”微信小程序, 展示自己的个人信息。 下面将对“个人简历”微信小程序进行详细讲解。 目录 个人简历 创建图片目录 页面开发 index.wxml index.wxss 功能实现截图 总结 个人简历 创建图片目录…

如何使用 Codegen 加速 React Native 开发?

写在前面 在 React Native 开发中,经常需要编写大量的样板代码,例如组件、屏幕、API 等。这些重复性的工作不仅浪费时间,还容易出错。为了解决这个问题,Facebook 推出了一个名为 Codegen 的工具,它可以根据模板和配置…

上海迪士尼奇幻冬日巡游:IP营销如何出圈?

迪士尼,作为全球娱乐产业的巨头,一直以其卓越的IP营销能力闻名于世。而其推出的“迪士尼奇幻冬日巡游”,无疑再次展示了其深厚的营销功底和独特的IP魅力。上海迪士尼在品牌营销上如何出圈,吸引忠实消费者,成为了一个值…

【一文读懂】大语言模型

学习参考 项目教程:中文教程 代码仓库:代码地址 仓库代码目录说明: requirements.txt:官方环境下的安装依赖 notebook:Notebook 源代码文件 docs:Markdown 文档文件 figures:图片 data_base&…