欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

CNN的基本原理与实战

程序员文章站 2022-04-18 12:46:57
...

CNN基本原理

主要包括卷积层,池化层,全连接层。

卷积层

1、二维卷积

(1)卷积(Conv2D)

主要负责提取图像钟的局部特征,卷积核进行卷积运算的过程如下:

CNN的基本原理与实战

注:蓝色图是输入,而青色图是输出,下同。

具体计算细节如下图:

CNN的基本原理与实战

每一个卷积核都可以从不同的角度提取图片中的信息。

假定输入图片大小 W×W,Filter大小 F×F ,步长 S,padding的像素数 P。

于是我们可以得出 输出图片大小为NxN,其中 N = (W − F + 2P )/S+1

(2)反卷积(Conv2DTranspose)

在进行反卷积之前先对图像进行填充,下图中的虚线表示填充,然后进行卷积:

CNN的基本原理与实战

卷积与反卷积的输入输出关系正好相反。

2、一维卷积(Conv1D)

在Conv1D中,内核沿一维滑动,如下图所示:

CNN的基本原理与实战

该数据是从一个人戴在手臂上的加速度计中收集的。数据表示所有三个轴上的加速度。Conv1D可以根据加速度计数据执行活动识别任务,例如人站着,走路,跳跃等。此数据有2个维度。第一维是时间步长,其他维是3轴上的加速度值。

下图说明了内核如何在加速度计数据上移动。每行代表某个轴的时间序列加速度。内核只能沿时间轴一维移动。

CNN的基本原理与实战

在tensorflow2.0中实现代码如下

Conv1D(1,kernel_size = 5,input_shape =1203))

参数input_shape120,3)表示120个时间步,每个时间步中有3个数据点。这3个数据点是x,y和z轴的加速度。

参数kernel_size为5,表示内核的宽度,卷积核高度与每个时间步中的数据点数相同。

Conv1D可以用于音频和文本数据等时间序列数据。如下图所示:

CNN的基本原理与实战

3、三维卷积(Conv3D)

Conv3D中卷积核按3个维度滑动,如下所示:

CNN的基本原理与实战

Conv3D主要用于3D图像数据。例如磁共振成像(MRI)数据。MRI数据被广泛用于检查大脑,脊髓,内部器官等。

三者的总结如下:

  • 1D CNN中,内核沿1个方向移动。1D CNN的输入和输出数据是2维的。主要用于时间序列数据。
  • 2D CNN中,内核沿2个方向移动。2D CNN的输入和输出数据是3维的。主要用于图像数据。
  • 3D CNN中,内核在3个方向上移动。3D CNN的输入和输出数据是4维的。通常用于3D 图像数据(MRI,CT扫描,视频)

池化层

池化层(Pooling)用来大幅降低参数量级(降维,防止过拟合),本质上是一种下采样,其过程如下:
CNN的基本原理与实战

原始图片是20×20的,我们对其进行下采样,采样窗口为10×10,最终将其下采样成为一个2×2大小的特征图。

下面介绍两种池化的逆过程

(1)UnSampling

下图描述了上采样下采样的过程,二者是一个相反的过程:

CNN的基本原理与实战

(2)UnPooling

下图描述了上池化的过程:

CNN的基本原理与实战

可以看出,两者的区别在于UnSampling阶段没有使用MaxPooling时的位置信息,而是直接将内容复制来扩充Feature Map。UnPooling的过程,特点是在Maxpooling的时候保留最大值的位置信息,之后在unPooling阶段使用该信息扩充Feature Map,除最大值位置以外,其余补0。

全连接层

全连接层类似传统神经网络的部分,用来输出想要的结果。

将卷积和池化的结果进行Flatten或者GlobalMaxPooling2D,生成一维结果向量。继续与全连接网络进行连接,输出想要的结果(回归或者分类)。

CNN的基本原理与实战

CNN的实现

手写数字识别

引入必要的库

from tensorflow.keras.layers import *
from tensorflow.keras.models import *

from tensorflow.keras import layers 
from tensorflow.keras import models
import tensorflow as tf
from tensorflow import keras
from sklearn import datasets
from sklearn.preprocessing import OneHotEncoder
import os
os.environ['CUDA_VISIABLE_DEVICE'] = '0'

加载数据集

(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
# 归一化
x_train = x_train.astype("float32") / 255
x_test = x_test.astype("float32") / 255

构建一个简单的CNN

# 定义输入
_input = Input(shape=(28,28,1),name='img')

# 开始二维卷积,池化
x = Conv2D(32,3,(1,1),padding='valid',activation='relu')(_input)
x = MaxPooling2D(2)(x)
x = Conv2D(64,3,(1,1),padding='same',activation='relu')(x)
x = MaxPooling2D(2)(x)

x = Conv2D(64,3,(1,1),padding='same',activation='relu')(x)
x = Flatten()(x)  #(none,256)
#接入全连接层
x = Dense(32,activation='relu')(x)
output = Dense(10,activation='relu')(x)

# 定义模型
model_1 = Model(_input,output)

# 编译
model_1.compile(loss =keras.losses.SparseCategoricalCrossentropy(from_logits=True),
               optimizer=keras.optimizers.RMSprop(),
               metrics = ['accuracy'])

注:SparseCategoricalCrossentropy适用于y=[2,5,6,9],CategoricalCrossentropy适用于y进行onehot后作为输入。

模型的训练

# 注意保持输入与模型的输入一致
history = model_1.fit(tf.expand_dims(x_train,-1), y_train,
            epochs=5,batch_size=512,
            validation_data=(tf.expand_dims(x_test,-1),y_test))v

CNN的基本原理与实战

训练结果可视化

import matplotlib.pyplot as plt
# 绘制训练 & 验证的准确率值
plt.plot(history.history['val_accuracy'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

# 绘制训练 & 验证的损失值
plt.plot(history.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

图片的编码解码

下面定义一个模型,能够将图像输入转换为 16 维向量的 encoder 模型,以及用于训练的端到端 autoencoder 模型。同时体现在tensorflow2.0中所有的模型均可像层一样被调用。

定义一个编码器

 定义图片一个编码器
encoder_input = Input(shape=(28,28,1),name='original_img')
x = layers.Conv2D(16,3,activation='relu')(encoder_input)  # (26,26,16)
x = layers.Conv2D(32,3,activation='relu')(x)         # (24,24,32)
x = layers.MaxPooling2D(3)(x) # 局部池化             # (8,8,32)
x = layers.Conv2D(16,3,activation='relu')(x)         # (6,6,16)
x = layers.Conv2D(16,3,activation='relu')(x)         # (4,4,16)
encoder_output = layers.GlobalMaxPooling2D()(x)  #全局池化, (None,16)

# 声明Model,可以将结果当作一个网络层一样调用
encoder = keras.Model(encoder_input,encoder_output,name='encoder')

定义一个解码器

# 定义解码器
decoder_input = keras.Input(shape=(16,),name='encoder_img')
x = layers.Reshape((4,4,1))(decoder_input)
x = layers.Conv2DTranspose(16,3,activation='relu')(x)    # (6, 6, 32)
x = layers.Conv2DTranspose(32,3,activation='relu')(x)   # (8, 8, 32)
x = layers.UpSampling2D(3)(x)                 # (24, 24, 32)
x = layers.Conv2DTranspose(16,3,activation='relu')(x)  #(26, 26, 16)
decoder_output = layers.Conv2DTranspose(1,3,activation='relu')(x) # 输出维度多少?28,28,1.
# 声明Model,可以将结果当作一个网络层一样调用
decoder = keras.Model(decoder_input,decoder_output,name='decoder')

定义完整的模型

autoencoder_input = keras.Input(shape=(28,28,1),name='img')

# 将模型像层一样调用
encoder_img = encoder(autoencoder_input)
decoder_img = decoder(encoder_img)

# 定义模型
autoencoder = keras.Model(autoencoder_input,decoder_img, name='autoencoder')

# 模型的编译
autoencoder.compile(loss = 'mse',
                    optimizer='RMSprop',
                    metrics=[tf.keras.metrics.Accuracy()])

模型的训练

autoencoder.fit(tf.expand_dims(x_train,-1), tf.expand_dims(x_train,-1),epochs=2,batch_size=512)

要注意模型的输入与输出分别是啥!!!

一个经典的图片编码解码器:

CNN的基本原理与实战

来自论文:Learning Deconvolution Network for Semantic Segmentation

参考:

一文看懂卷积神经网络-CNN(基本原理+独特价值+实际应用)

A technical report on convolution arithmetic in the context of deep learning

函数式API