卷积神经网络(Convolutional Neural Networks)是一种深度学习模型或类似于人工神经网络的多层感知器,常用来分析视觉图像。卷积神经网络(Convolutional Neural Network,CNN)是一种在计算机视觉领域取得了巨大成功的深度学习模型,该算法的灵感来自于人脑的一部分,即视觉皮层。视觉皮层是人脑的一部分,负责处理来自外界的视觉信息。它有不同的层,每一层都有自己的功能,即每一层从图像或任何视觉中提取一些信息,最后将从每一层接收到的所有信息组合起来,对图像/视觉进行解释或分类。同样,CNN有各种滤波器,每个滤波器从图像中提取一些信息,例如边缘、不同种类的形状(垂直、水平、圆形),然后将所有这些组合起来识别图像。在过去的几年中,CNN已经在图像识别、目标检测、图像生成和许多其他领域取得了显著的进展,成为了计算机视觉和深度学习研究的重要组成部分。
卷积 | 卷积运算示例 |
---|---|
一、计算机成像原理
在了解卷积神经网络前,我们先来看看图像在计算机中的表示。RGB图像是一种在计算机视觉和图像处理领域广泛使用的彩色图像表示方法。RGB代表红色(Red)、绿色(Green)和蓝色(Blue),这是三种基本的颜色,通过不同的组合可以生成各种颜色。每个像素在RGB图像中通过这三种颜色的不同强度值来表示,通常这些值的范围是从0到255(8位表示)。在计算机中,RGB图像通常存储为一个三维数组或矩阵:第一个维度和第二个维度对应于图像的像素位置(行和列)。第三个维度有三个元素,分别对应红色、绿色和蓝色通道的值。例如,一个800x600的RGB图像可以表示为一个800x600x3的数组。
RGB图像 | R | G | B |
---|---|---|---|
上面RGB这幅图的本质是一个4003003的一个矩阵PI 400, 300, 3,说明这个图像有400列,300行,以及在色彩上有三个分量。每个分量单独拿出来都是一个400300(1)的矩阵。如你所见,它们并不是彩色的,而是一幅灰度图像,对于一副8bit的图像来说,矩阵元素的取值范围是从0-255(0 - 2^8-1),矩阵中的元素对应我们所说的像素(pixel),其值即该像素的灰度值,数值越大,像素的颜色越‘白/浅’;数值越小,像素的颜色越’黑/深‘
对于图像每个分量来说,它只是灰度,谈论色彩没有意义,它是“黑白”的!(用黑白来描述灰度图像并不准确,用深浅可能更准确一些,但也不严谨。所以我加上了引号。你要愿意把通道设成红色绿色紫色黄色都行。在图像显示时,我们把图像的R分量放进红色通道里,B分量放进蓝色通道里,G分量放进绿色通道里。经过一系列处理,显示在屏幕上的就是我们所看到的彩色图像了。
所以说,通道和一幅图像根本就没关系!数字图像是矩阵,矩阵只描述其空间位置和在色彩上的分量,哪有通道了?通道是什么?CHANNEL!图片中有channel这个概念吗?有个回答说通道类似颜料,这个意思就有点接近了。想要什么颜色,对应的通道里的灰度值就大一点就行了。
计算机图像 | RGB颜色模型 | 三维数组 |
---|---|---|
二、卷积神经网络的原理
用CNN卷积神经网络识别图片,一般需要的步骤有:
(1) 卷积层(Convolutional Layer)初步提取特征
(2) 池化层(Pooling Layer)提取主要特征
(3) 全连接层(Fully Connected Layer)将各部分特征汇总
(4) 产生分类器(classifier),进行预测识别
2.1 卷积层工作原理
卷积层的作用:就是提取图片每个小部分里具有的特征
假定我们有一个尺寸为 6∗6 的图像,每一个像素点里都存储着图像的信息。我们再定义一个卷积核(相当于权重),用来从图像中提取一定的特征。卷积核与数字矩阵对应位相乘再相加,得到卷积层输出结果。
(429 = 18x1+54x0+51x1+55x0+121x1+75x0+35x1+24x0+204x1)
卷积核的取值在没有以往学习的经验下,可由函数随机生成,再逐步训练调整。当所有的像素点都至少被覆盖一次后,就可以产生一个卷积层的输出(下图的步长为1)
机器一开始并不知道要识别的部分具有哪些特征,是通过与不同的卷积核相作用得到的输出值,相互比较来判断哪一个卷积核最能表现该图片的特征——比如我们要识别图像中的某种特征(比如曲线),也就是说,这个卷积核要对这种曲线有很高的输出值,对其他形状(比如三角形)则输出较低。卷积层输出值越高,就说明匹配程度越高,越能表现该图片的特征。
卷积层具体工作过程:
比如我们设计的一个卷积核如下左,想要识别出来的曲线如下右:
卷积核 | 漫画老鼠 |
---|---|
现在我们用上面的卷积核,来识别这个简化版的图片——一只漫画老鼠。当机器识别到老鼠的屁股的时候,真实区域数字矩阵与卷积核相乘作用后,输出较大:6600;而用同一个卷积核,来识别老鼠的耳朵的时候,输出则很小:0 。
老鼠屁股 | 老鼠耳朵 |
---|---|
我们就可以认为:现有的这个卷积核保存着曲线的特征,匹配识别出来了老鼠的屁股是曲线的。我们则还需要其他特征的卷积核,来匹配识别出来老鼠的其他部分。卷积层的作用其实就是通过不断的改变卷积核,来确定能初步表征图片特征的有用的卷积核是哪些,再得到与相应的卷积核相乘后的输出矩阵。
2.2 池化层工作原理
池化层的输入就是卷积层输出的原数据与相应的卷积核相乘后的输出矩阵
池化层的目的:
- 为了减少训练参数的数量,降低卷积层输出的特征向量的维度
- 减小过拟合现象,只保留最有用的图片信息,减少噪声的传递
最常见的两种池化层的形式: - 最大池化:max-pooling——选取指定区域内最大的一个数来代表整片区域
- 均值池化:mean-pooling——选取指定区域内数值的平均值来代表整片区域(Average Pooling)
举例说明两种池化方式:(池化步长为2,选取过的区域,下一次就不再选取)
在 4∗4 的数字矩阵里,以步长 2∗2 选取区域,比如上左将区域[1,2,3,4]中最大的值4池化输出;上右将区域[1,2,3,4]中平均值5/2池化输出。
2.3 全连接层工作原理
卷积层和池化层的工作就是提取特征,并减少原始图像带来的参数。然而,为了生成最终的输出,我们需要应用全连接层来生成一个等于我们需要的类的数量的分类器。全连接层的工作原理和之前的神经网络学习很类似,我们需要把池化层输出的张量重新切割成一些向量,乘上权重矩阵,加上偏置值,然后对其使用ReLU激活函数,用梯度下降法优化参数既可。
2.4 CNN的结构组成
上面我们已经知道了卷积(convolution)、池化(pooling)以及填白(padding)是怎么进行的,接下来我们就来看看CNN的整体结构,它包含了3种层(layer):
Convolutional layer(卷积层–CONV):由滤波器filters和激活函数构成。 一般要设置的超参数包括filters的数量、大小、步长,以及padding是“valid”还是“same”。当然,还包括选择什么激活函数。
Pooling layer (池化层–POOL):这里里面没有参数需要我们学习,因为这里里面的参数都是我们设置好了,要么是Maxpooling,要么是Averagepooling。 需要指定的超参数,包括是Max还是average,窗口大小以及步长。 通常,我们使用的比较多的是Maxpooling,而且一般取卷积核大小为(2,2)、步长为2的filter,这样,经过pooling之后,输入的长宽都会缩小2倍,channels不变。
Fully Connected layer(全连接层–FC):这个前面没有讲,是因为这个就是我们最熟悉的家伙,就是我们之前学的神经网络中的那种最普通的层,就是一排神经元。因为这一层是每一个单元都和前一层的每一个单元相连接,所以称之为“全连接”。 这里要指定的超参数,无非就是神经元的数量,以及激活函数。
CNN三维图 | CNN结构图 |
---|---|
三、卷积神经网路的Python实现
使用Keras库构建和训练一个简单神经网络模型来处理鸢尾花(Iris)数据集的示例代码的详细解释:
3.1 导入Keras库和相关模块
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.utils import to_categorical
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
3.2 模型的设定
- Sequential:用于创建一个按顺序添加层的神经网络模型。
- Dense:用于创建一个全连接层。
- Activation:用于指定层的激活函数。
有两种方式来设定模型:
方式一:将网络层实例列表直接传递给Sequential
构造函数。
方式二:先创建一个Sequential
模型,然后使用add()
方法依次添加各层。
3.3 Iris数据集的导入和切分及标准化
iris = load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
#load\_iris**:导入鸢尾花数据集,train\_test\_split**:将数据集划分为训练集和测试集,测试集占30%
#StandardScaler:对训练集和测试集进行标准化处理
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
#to\_categorical:将分类标签转换为独热编码(One-Hot Encoding)
y_train = to_categorical(y_train, 3)
y_test = to_categorical(y_test, 3)
3.4 建立神经网络模型三部曲
#建立模型
model = Sequential([
Dense(10, input_shape=(4,)),
Activation('sigmoid'),
Dense(10),
Activation('relu'),
Dense(10),
Activation('tanh'),
Dense(3),
Activation('softmax')
])
# 编译模型
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
#compile:指定损失函数为categorical_crossentropy,优化器为rmsprop,评估标准为accuracy
# 训练模型
history = model.fit(X_train, y_train, epochs=100, batch_size=5, verbose=1)
#fit:使用训练集数据和标签训练模型,指定训练的轮数(epochs)
3.5 模型评价与预测
#evaluate:在测试集上评估模型的性能,打印测试集上的损失函数和预测准确率。
loss, accuracy = model.evaluate(X_test, y_test, verbose=0)
print(f'Test loss: {loss:.4f}')
print(f'Test accuracy: {accuracy:.4f}')
#predict:对测试集进行预测,打印预测结果及其形状
predictions = model.predict(X_test)
print(predictions)
print(predictions.shape)
3.6 可视化展示
#使用matplotlib.pyplot绘制训练过程中的准确率和损失函数变化图
plt.plot(history.history['accuracy'])
plt.plot(history.history['loss'])
plt.title('Model accuracy and loss')
plt.xlabel('Epoch')
plt.legend(['Accuracy', 'Loss'], loc='upper left')
plt.show()
3.7 程序展示
#全部代码
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.utils import to_categorical
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
# 导入Iris数据集
iris = load_iris()
X = iris.data
y = iris.target
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 数据标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# 因变量转换为哑变量
y_train = to_categorical(y_train, 3)
y_test = to_categorical(y_test, 3)
# 建立神经网络模型
model = Sequential([
Dense(10, input_shape=(4,)),
Activation('sigmoid'),
Dense(10),
Activation('relu'),
Dense(10),
Activation('tanh'),
Dense(3),
Activation('softmax')
])
# 编译模型
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
# 训练模型
history = model.fit(X_train, y_train, epochs=100, batch_size=5, verbose=1)
# 模型评价
loss, accuracy = model.evaluate(X_test, y_test, verbose=0)
print(f'Test loss: {loss:.4f}')
print(f'Test accuracy: {accuracy:.4f}')
# 模型预测
predictions = model.predict(X_test)
print(predictions)
print(predictions.shape)
# 可视化展示
plt.plot(history.history['accuracy'])
plt.plot(history.history['loss'])
plt.title('Model accuracy and loss')
plt.xlabel('Epoch')
plt.legend(['Accuracy', 'Loss'], loc='upper left')
plt.show()
这段代码展示了如何使用Keras构建一个简单的神经网络模型,从数据预处理到模型训练、评估和预测的完整流程。
总结
卷积网络在本质上是一种输入到输出的映射,它能够学习大量的输入与输出之间的映射关系,而不需要任何输入和输出之间的精确的数学表达式,只要用已知的模式对卷积网络加以训练,网络就具有输入输出对之间的映射能力。CNN一个非常重要的特点就是头重脚轻(越往输入权值越小,越往输出权值越多),呈现出一个倒三角的形态,这就很好地避免了BP神经网络中反向传播的时候梯度损失得太快。
卷积神经网络CNN主要用来识别位移、缩放及其他形式扭曲不变性的二维图形。由于CNN的特征检测层通过训练数据进行学习,所以在使用CNN时,避免了显式的特征抽取,而隐式地从训练数据中进行学习;再者由于同一特征映射面上的神经元权值相同,所以网络可以并行学习,这也是卷积网络相对于神经元彼此相连网络的一大优势。卷积神经网络以其局部权值共享的特殊结构在语音识别和图像处理方面有着独特的优越性,其布局更接近于实际的生物神经网络,权值共享降低了网络的复杂性,特别是多维输入向量的图像可以直接输入网络这一特点避免了特征提取和分类过程中数据重建的复杂度。