大家好,我是锋哥。最近连载更新《TensorFlow2 Python深度学习》技术专题。
本课程主要讲解基于TensorFlow2的Python深度学习知识,包括深度学习概述,TensorFlow2框架入门知识,以及卷积神经网络(CNN),循环神经网络(RNN),生成对抗网络(GAN),模型保存与加载等。同时也配套视频教程 《2026版 TensorFlow2 Python深度学习 视频教程》
卷积神经网络(CNN)介绍
一、什么是卷积神经网络
卷积神经网络(Convolutional Neural Network,简称CNN)是一种深度学习模型,广泛应用于图像处理、视频分析、语音识别、自然语言处理等领域。CNN的设计灵感来源于人类视觉神经系统的工作原理,旨在模仿生物视觉皮层的感知过程。以手写数字识别为例,整个识别的过程如下所示:
CNN由多个不同层次的神经网络构成,每一层通过特定的操作提取图像或数据中的不同特征。主要的层包括:
- 输入层(Input Layer): 输入图像等信息
- 卷积层(Convolutional Layer) :这是CNN的核心部分,通过卷积操作提取输入数据(如图像)的局部特征。卷积操作是通过滤波器(或卷积核)对输入数据进行滑动,并计算每个位置的加权和,生成特征图。滤波器通常会学习到不同的图像特征,如边缘、纹理、颜色等。
- 激活层(Activation Layer) :通常在卷积层之后添加激活函数(如ReLU函数),引入非线性因素,使得网络可以学习到更复杂的模式。
- 池化层(Pooling Layer) :池化操作的目的是减少数据的维度,从而减小计算量,同时保留重要的特征。最常见的池化操作是最大池化(Max Pooling)和平均池化(Average Pooling)。池化层通常用于减少图像尺寸(如2x2池化),降低计算负担。
- 全连接层(Fully Connected Layer) :在卷积和池化层之后,通常会有一个或多个全连接层,用来将提取到的特征与最终的分类结果连接起来。全连接层通常用于最后的输出,例如图像分类的类别。
- 输出层(Output Layer) :最后一层用于输出最终的预测结果,例如图像分类中每个类别的概率分布。
二、输入层
输入层比较简单,这一层的主要工作就是输入图像等信息,因为卷积神经网络主要处理的是图像相关的内容,但是我们人眼看到的图像和计算机处理的图像是一样的么?很明显是不一样的,对于输入图像,首先要将其转换为对应的二维矩阵,这个二位矩阵就是由图像每一个像素的像素值大小组成的,我们可以看一个例子,如下图所示的手写数字“8”的图像,计算机读取后是以像素值大小组成的二维矩阵存储的图像。
上图又称为灰度图像,因为其每一个像素值的范围是0255(由纯黑色到纯白色),表示其颜色强弱程度。另外还有黑白图像,每个像素值要么是0(表示纯黑色),要么是255(表示纯白色)。我们日常生活中最常见的就是RGB图像,有三个通道,分别是红色、绿色、蓝色。每个通道的每个像素值的范围也是0255,表示其每个像素的颜色强弱。但是我们日常处理的基本都是灰度图像,因为比较好操作(值范围较小,颜色较单一),有些RGB图像在输入给神经网络之前也被转化为灰度图像,也是为了方便计算,否则三个通道的像素一起处理计算量非常大。当然,随着计算机性能的高速发展,现在有些神经网络也可以处理三通道的RGB图像。
现在我们已经知道了,输入层的作用就是将图像转换为其对应的由像素值构成的二维矩阵,并将此二维矩阵存储,等待后面几层的操作。
三、卷积层
那图片输入进来之后该怎么处理呢?假设我们已经得到图片的二维矩阵了,想要提取其中特征,那么卷积操作就会为存在特征的区域确定一个高值,否则确定一个低值。这个过程需要通过计算其与卷积核(Convolution Kernel)的乘积值来确定。假设我们现在的输入图片是一个人的脑袋,而人的眼睛是我们需要提取的特征,那么我们就将人的眼睛作为卷积核,通过在人的脑袋的图片上移动来确定哪里是眼睛,这个过程如下所示:
通过整个卷积过程又得到一个新的二维矩阵,此二维矩阵也被称为特征图(Feature Map),最后我们可以将得到的特征图进行上色处理(我只是打个比方,比如高值为白色,低值为黑色),最后可以提取到关于人的眼睛的特征,如下所示:
看着上面的描述可能有点懵,别急,首先卷积核也是一个二维矩阵,当然这个二维矩阵要比输入图像的二维矩阵要小或相等,卷积核通过在输入图像的二维矩阵上不停的移动,每一次移动都进行一次乘积的求和,作为此位置的值,这个过程如下图所示:
可以看到,整个过程就是一个降维的过程,通过卷积核的不停移动计算,可以提取图像中最有用的特征。我们通常将卷积核计算得到的新的二维矩阵称为特征图,比如上方动图中,下方移动的深蓝色正方形就是卷积核,上方不动的青色正方形就是特征图。
有的读者可能注意到,每次卷积核移动的时候中间位置都被计算了,而输入图像二维矩阵的边缘却只计算了一次,会不会导致计算的结果不准确呢?
让我们仔细思考,如果每次计算的时候,边缘只被计算一次,而中间被多次计算,那么得到的特征图也会丢失边缘特征,最终会导致特征提取不准确,那为了解决这个问题,我们可以在原始的输入图像的二维矩阵周围再拓展一圈或者几圈,这样每个位置都可以被公平的计算到了,也就不会丢失任何特征,此过程可见下面两种情况,这种通过拓展解决特征丢失的方法又被称为Padding。
- Padding取值为1,拓展一圈
- Padding取值为2,拓展两圈
四、池化层
刚才我们也提到了,有几个卷积核就有多少个特征图,现实中情况肯定更为复杂,也就会有更多的卷积核,那么就会有更多的特征图,当特征图非常多的时候,意味着我们得到的特征也非常多,但是这么多特征都是我们所需要的么?显然不是,其实有很多特征我们是不需要的,而这些多余的特征通常会给我们带来如下两个问题:
1,过拟合
2,维度过高
为了解决这个问题,我们可以利用池化层,那什么是池化层呢?池化层又称为下采样,也就是说,当我们进行卷积操作后,再将得到的特征图进行特征提取,将其中最具有代表性的特征提取出来,可以起到减小过拟合和降低维度的作用,这个过程如下所示:
那有的读者可能会问了,我应该以什么规则进行特征提取呢?其实这个过程类似于卷积的过程,就是一个正方形的小方块在图片上进行移动,每次我们取这个正方形方框中最具有代表性的特征,那么问题又来了,如何提取到最有代表性的特征呢,通常有两种方法:
1,最大池化
顾名思义,最大池化就是每次取正方形中所有值的最大值,这个最大值也就相当于当前位置最具有代表性的特征,这个过程如下所示:
这里有几个参数需要说明一下:
① kernel_size = 2:池化过程使用的正方形尺寸是2×2,如果是在卷积的过程中就说明卷积核的大小是2×2
② stride = 2:每次正方形移动两个位置(从左到右,从上到下),这个过程其实和卷积的操作过程一样
③ padding = 0:这个之前介绍过,如果此值为0,说明没有进行拓展
2,平均池化
平均池化就是取此正方形区域中所有值的平均值,考虑到每个位置的值对于此处特征的影响,平均池化计算也比较简单,整个过程如下图所示:
对于其中的参数含义与上面介绍的最大池化一致,另外,需要注意计算平均池化时采用向上取整。
以上就是关于池化层的所有操作,我们再回顾一下,经过池化后,我们可以提取到更有代表性的特征,同时还减少了不必要的计算,这对于我们现实中的神经网络计算大有脾益,因为现实情况中神经网络非常大,而经过池化层后,就可以明显的提高模型的效率。所以说,池化层的好处很多,将其优点总结如下:
1,在减少参数量的同时,还保留了原图像的原始特征
2,有效防止过拟合
3,为卷积神经网络带来平移不变性
以上两个优点我们之前已经介绍过了,那什么又是平移不变性呢?可以用我们之前的一个例子,如下图所示:
可以看到,两张原始图片的位置有所不同,一个是正常的,另一个是人的脑袋稍稍左移了一些,经过卷积操作后,得到各自对应的特征图,这两张特征图也和原始图片的位置相对应,一个眼睛特征的位置是正常的,另一个眼睛特征的位置稍稍左移了一些,虽然人可以分辨,但是经过神经网络计算后,就可能带来误差,因为应该出现眼睛的位置并没有出现眼睛,那应该怎么办呢?此时使用池化层进行池化操作,可以发现,虽然池化之前两幅图片的眼睛特征不在一个位置,但是经过池化之后,眼睛特征的位置都是相同的,这就为后续神经网络的计算带来了方便,此性质就是池化的平移不变性
五、全连接层
假设还是上面人的脑袋的示例,现在我们已经通过卷积和池化提取到了这个人的眼睛、鼻子和嘴的特征,如果我想利用这些特征来识别这个图片是否是人的脑袋该怎么办呢?此时我们只需要将提取到的所有特征图进行“展平”,将其维度变为1 × x 1×x1×x,这个过程就是全连接的过程,也就是说,此步我们将所有的特征都展开并进行运算,最后会得到一个概率值,这个概率值就是输入图片是否是人的概率,这个过程如下所示:
单看这个过程可能还是不太清晰,所以我们可以把之前的过程与全连接层结合起来,如下图所示:
可以看到,经过两次卷积和最大池化之后,得到最后的特征图,此时的特征都是经过计算后得到的,所以代表性比较强,最后经过全连接层,展开为一维的向量,再经过一次计算后,得到最终的识别概率,这就是卷积神经网络的整个过程。
六、输出层
卷积神经网络的输出层理解起来就比较简单了,我们只需要将全连接层得到的一维向量经过计算后得到识别值的一个概率,当然,这个计算可能是线性的,也可能是非线性的。在深度学习中,我们需要识别的结果一般都是多分类的,所以每个位置都会有一个概率值,代表识别为当前值的概率,取最大的概率值,就是最终的识别结果。在训练的过程中,可以通过不断地调整参数值来使识别结果更准确,从而达到最高的模型准确率。
转载自:blog.csdn.net/IronmanJay/…
通俗理解池化层,卷积层以及全连接层
核心比喻:AI如何判断一张图片是猫还是狗
想象一下,这个AI就是一个 “动物识别小分队” ,里面有三个岗位:
1. 卷积层 —— “局部特征侦察兵”
他的任务: 拿个放大镜,在图片上寻找各种小零件和局部特征。
-
他是怎么工作的?
-
他手里有很多种“特征过滤器”:
- 过滤器A: 专门探测 “竖线” (比如猫/狗的胡须、腿的边缘)。
- 过滤器B: 专门探测 “斜线” (比如猫耳朵的尖角)。
- 过滤器C: 专门探测 “小圆圈” (比如眼睛的轮廓)。
-
他拿着这些过滤器,扫过图片的每一个角落。
-
-
在猫狗识别中:
- 当他用 “竖线过滤器” 扫过猫的脸部时,会在胡须的位置产生强烈反应,报告:“发现密集竖线区域!可能为胡须! ”
- 当他用 “斜线过滤器” 扫过头顶时,会在猫耳朵的尖端产生强烈反应,报告:“发现尖角特征!可能为立耳! ”
- 当他用 “圆圈过滤器” 扫过面部时,会在眼睛周围产生反应,报告:“发现圆形特征!可能为眼睛! ”
通俗总结:卷积层只管找“小零件”,比如边缘、角落、纹理。它不关心这些零件最后能组装成什么,它只负责发现它们。
2. 池化层 —— “信息浓缩员”
他的任务: 把侦察兵送来的密密麻麻的“特征报告图”进行简化,抓住重点,忽略次要信息。
-
他是怎么工作的?
- 他用一个2x2的方格在特征图上滑动。
- 对于每个方格,他只保留最重要的那个数字(最大池化)。比如一个方格里有
[10, 5, 2, 8],他只看那个最显著的10,忽略其他。 - 这样,报告图的尺寸就缩小了,但最重要的特征位置被保留了下来。
-
在猫狗识别中:
- 侦察兵报告说,在脸部的某个小区域里,有4个点都探测到了“胡须特征”,信号强度分别是
[5, 8, 2, 6]。 - 池化层一看,说:“不用记那么细,反正这个区域有胡须。我就记住最强的信号
8就行了。” - 这样做的好处是: 即使图片里的猫头稍微歪了一点,胡须的位置在小范围内移动了,但浓缩后的报告依然会显示“这个区域有强烈的胡须特征”。这让AI对图片的微小变化(如平移、旋转)不敏感,更稳定。
- 侦察兵报告说,在脸部的某个小区域里,有4个点都探测到了“胡须特征”,信号强度分别是
通俗总结:池化层负责“降维”和“提炼”,让数据量变小,同时让特征更突出、更鲁棒。
3. 全连接层 —— “终极决策大脑”
他的任务: 坐在指挥部里,把前面送来的所有浓缩后的特征信息综合起来,进行全局分析,最终拍板。
-
他是怎么工作的?
-
他把池化层送来的所有关于“胡须”、“耳朵形状”、“眼睛”、“鼻子”、“毛皮纹理”等浓缩报告,全部铺开,连接在一起,形成一个长长的“特征清单”。
-
他开始调动他通过学习(训练)得来的“知识”进行推理:
- “规则1: 如果‘尖尖的小耳朵’特征很强,同时 ‘脸型较圆’特征也很强,并且 ‘胡须短而硬’特征明显...那么这很可能是猫。”
- “规则2: 如果‘耳朵下垂’特征很强,同时 ‘嘴巴较长’特征也很强,并且 ‘体型较大’特征明显...那么这很可能是狗。”
-
-
在猫狗识别中:
- 全连接层综合所有信息后,可能会输出:
[猫: 92%, 狗: 8%]。 - 最终,AI就得出结论:“这张图片有92%的可能是猫!”
- 全连接层综合所有信息后,可能会输出:
通俗总结:全连接层是“分类器”,它考虑所有特征之间的复杂组合关系,做出最终的判断。
整个工作流程回顾(看图说话)
假设我们输入一张猫的图片:
-
卷积层(侦察兵)先上:
- 报告1:在位置A发现尖耳朵特征!
- 报告2:在位置B发现圆眼睛特征!
- 报告3:在位置C发现长胡须特征!
-
池化层(浓缩员)接着处理:
- 把关于尖耳朵的详细报告简化,只标明“左上区域有强尖耳信号”。
- 把关于圆眼睛的详细报告简化,只标明“中部区域有强圆眼信号”。
- ...以此类推。数据量大大减少,但关键信息都在。
-
全连接层(决策大脑)最后拍板:
- 它看到浓缩报告里同时出现了 “尖耳朵” + “圆眼睛” + “长胡须” 等特征。
- 根据它学到的知识,这些特征组合在一起,极大概率对应的是 “猫” 这个类别。
- 输出结果: “这是猫!”
简单总结三者的核心区别:
- 卷积层:问“哪里有什么? ”(发现局部特征)
- 池化层:问“这些特征里哪个最重要? ”(浓缩信息)
- 全连接层:问“根据所有这些特征,它最可能是什么? ”(全局综合与分类)
简单来说:卷积用来提取特征,池化压缩特征,全连接层用来加权重
MNIST数据集介绍
MNIST(Modified National Institute of Standards and Technology)数据集是一个常用于机器学习和深度学习领域的经典数据集,特别是在图像识别任务中。它由美国国家标准与技术研究院(NIST)提供,广泛用于手写数字识别的研究和算法测试。
主要特点:
-
数据内容:
-
MNIST数据集包含了28x28像素的灰度图像,表示从0到9的手写数字。每个图像展示了一个单一的手写数字(0到9之一)。
-
数据集分为两个部分:
- 训练集:包含60,000个样本,用于训练模型。
- 测试集:包含10,000个样本,用于测试和评估模型的性能。
-
-
标签信息:
- 每个图像都有一个对应的标签,表示图像中手写数字的真实值(即0到9之间的某个数字)。
-
数据预处理:
- 图像的大小是28x28像素,灰度级别为0到255,其中0表示白色,255表示黑色。图像通常在输入神经网络之前会被标准化或者归一化。
-
应用领域:
- 手写数字识别:这是MINIST数据集的经典应用,用于测试各种机器学习算法的性能。
- 分类问题:可以用于对比不同模型(如支持向量机、神经网络、决策树等)的分类准确性。
卷积神经网络示例-使用MNIST识别数字示例
import tensorflow as tf
from keras import Input, layers
from matplotlib import pyplot as plt
# 1,加载MNIST数据集
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)
print(x_train[0], x_train[0].shape)
print(y_train, y_train.shape)
# 2,数据预处理
x_train = x_train / 255.0 # 归一化
x_test = x_test / 255.0 # 归一化
print(x_train[0], x_train[0].shape)
# 将数据重塑为 (样本数, 高, 宽, 通道数) 的形状
print(x_train, x_train.shape)
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1)
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1)
print(x_train, x_train.shape)
# 3,构建CNN模型
model = tf.keras.models.Sequential([
Input(shape=(28, 28, 1)),
layers.Conv2D(32, (3, 3), activation='relu'), # 第一卷积层,卷积核大小3x3,滤波器数为32,ReLU激活函数
layers.MaxPooling2D((2, 2)), # 第一池化层,2x2最大池化
layers.Conv2D(64, (3, 3), activation='relu'), # 第二卷积层,卷积核大小3x3,滤波器数为64,ReLU激活函数
layers.MaxPooling2D((2, 2)), # 第二池化层,2x2最大池化
layers.Flatten(), # 展平层 将二维特征图展平为一维
layers.Dense(64, activation='relu'), # 全连接层,64个神经元,ReLU激活函数
layers.Dense(10, activation='softmax') # 输出层,10个神经元(对应数字0-9),softmax激活函数
])
# 4,模型编译
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
# 5,模型训练
history = model.fit(x_train, y_train, epochs=5, validation_data=(x_test, y_test), verbose=1)
# 6,模型评估
test_loss, test_acc = model.evaluate(x_test, y_test)
print(f"Test accuracy: {test_acc}")
运行结果:
可视化训练过程:
# 设置matplotlib使用黑体显示中文
plt.rcParams['font.family'] = 'Microsoft YaHei'
plt.plot(history.history['accuracy'], label='训练准确率')
plt.plot(history.history['val_accuracy'], label='验证准确率')
plt.xlabel('轮次')
plt.ylabel('准确率')
plt.legend()
plt.show()
预测结果:
# 预测测试集中的一张图片
predictions = model.predict(x_test)
# 显示第一个预测结果
print(f"Predicted label: {predictions[0].argmax()}")
print(f"True label: {y_test[0]}")
# 显示第一张图片
plt.imshow(x_test[0].reshape(28, 28), cmap='gray')
plt.show()
Fashion MNIST数据集介绍
Fashion MNIST 是一个由 Zalando 公司发布的图像分类数据集,通常用于机器学习和计算机视觉任务,特别是图像分类的研究。它可以作为 MNIST 数据集(手写数字图像分类)的替代,因为它包含了更多的实际应用场景,并且数据类型更加复杂。Fashion MNIST 被广泛应用于算法验证和基准测试。
数据集特点
-
图像尺寸:每张图像是 28x28 像素的灰度图。
-
类别:该数据集包含 10 类不同的服饰产品。具体类别包括:
- T恤/上衣(T-shirt/top)
- 裙子(Trouser)
- 套头衫(Pullover)
- 连衣裙(Dress)
- 外套(Coat)
- 凉鞋(Sandal)
- 衬衫(Shirt)
- 运动鞋(Sneaker)
- 包(Bag)
- 踝靴(Ankle boot)
这些图像是灰度图像,意味着每个像素的值在 0 到 255 之间,表示不同的灰度强度。
数据集构成
- 训练集:包含 60,000 张图像,均匀分布在 10 个类别中。
- 测试集:包含 10,000 张图像,用于评估模型的性能。
使用场景
Fashion MNIST 被用作初学者和研究者训练和测试图像分类模型的标准数据集。它的难度适中,适合用于以下应用:
- 深度学习入门:用于神经网络(尤其是卷积神经网络)的训练。
- 算法对比:不同机器学习算法的性能比较。
- 特征提取与学习:用于测试特征工程和表示学习方法。
- 图像分类基础:了解和练习分类任务。
卷积神经网络示例2-使用Fashion MNIST识别时装示例
import tensorflow as tf
from keras import Input, layers
from matplotlib import pyplot as plt
# 1,加载Fashion MINIST数据集
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.fashion_mnist.load_data()
print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)
print(x_train[0], x_train[0].shape)
print(y_train, y_train.shape)
# 2,数据预处理
x_train = x_train / 255.0 # 归一化
x_test = x_test / 255.0 # 归一化
print(x_train[0], x_train[0].shape)
# 将数据重塑为 (样本数, 高, 宽, 通道数) 的形状
print(x_train, x_train.shape)
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1)
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1)
print(x_train, x_train.shape)
# 3,构建CNN模型
model = tf.keras.models.Sequential([
Input(shape=(28, 28, 1)),
layers.Conv2D(32, (3, 3), activation='relu'), # 第一卷积层,卷积核大小3x3,滤波器数为32,ReLU激活函数
layers.MaxPooling2D((2, 2)), # 第一池化层,2x2最大池化
layers.Conv2D(64, (3, 3), activation='relu'), # 第二卷积层,卷积核大小3x3,滤波器数为64,ReLU激活函数
layers.MaxPooling2D((2, 2)), # 第二池化层,2x2最大池化
layers.Conv2D(128, (3, 3), activation='relu'), # 第三卷积层,卷积核大小3x3,滤波器数为64,ReLU激活函数
layers.MaxPooling2D((2, 2)), # 第三池化层,2x2最大池化
layers.Flatten(), # 展平层 将二维特征图展平为一维
layers.Dense(512, activation='relu'), # 全连接层,512个神经元,ReLU激活函数
layers.Dense(10, activation='softmax') # 输出层,10个神经元(对应数字0-9),softmax激活函数
])
# 4,模型编译
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
# 5,模型训练
history = model.fit(x_train, y_train, epochs=5, validation_data=(x_test, y_test), verbose=1)
# 6,模型评估
test_loss, test_acc = model.evaluate(x_test, y_test)
print(f"Test accuracy: {test_acc}")
项目运行结果:
可视化训练过程:
# 7,可视化训练过程
# 设置matplotlib使用黑体显示中文
plt.rcParams['font.family'] = 'Microsoft YaHei'
plt.plot(history.history['accuracy'], label='训练准确率')
plt.plot(history.history['val_accuracy'], label='验证准确率')
plt.xlabel('轮次')
plt.ylabel('准确率')
plt.legend()
plt.show()
预测结果:
# 预测测试集中的一张图片
predictions = model.predict(x_test)
# 显示第一个预测结果
print(f"Predicted label: {predictions[0].argmax()}")
print(f"True label: {y_test[0]}")
# 显示第一张图片
plt.imshow(x_test[0].reshape(28, 28), cmap='gray')
plt.show()
使用Dropout层解决过拟合问题
之前的Fashion MINIST示例,我们会发现一个问题,训练数据准确率效果挺好,但是到了测试验证准确率就相对变差。这个其实就是过拟合了,原因就是训练过来的模型过于复杂。
我们在之前学习机器学习的时候,学过过拟合和欠拟合。
简单总结:
过拟合是模型过于复杂,导致训练数据表现好,但是测试数据表现就差。
欠拟合是模型过于简单,导致训练数据和测试数据表现都不好。
在神经网络里面,欠拟合问题很好解决,我们只需要增加层,增加每层的神经元,以及增加轮训训练次数即可。
解决过拟合的话,我们也有多种解决方案,适当的减少层,降低神经元数,以及我们今天要介绍的,使用Dropout丢弃层。
只需要在全连接之前,加一个Dropout丢弃层即可。
Dropout丢弃层是一种神经网络正则化技术,通过在训练阶段随机丢弃部分神经元,防止模型过拟合并提升泛化能力。
layers.Dropout(0.5), # 添加Dropout层来防止过拟合 随机丢弃50%的节点
我们重新运行测试,发现训练数据和验证数据效果都好很多了。