首页 > 编程知识 正文

深度卷积神经网络算法,卷积神经网络的应用

时间:2023-05-04 01:33:07 阅读:13593 作者:3626

全体积神经网络(FCN )的keras实现前言不久前写了图像分割综述,学习了图像预处理、阈值图像分割、神经网络图像语义分割等知识,并用matlab和python实现,但没有时间共享现在手头忙的事情已经差不多完成了,所以汇总在一起共享。 FCN可以说是语义分割方向的开山之作,也是我进入基坑进行语义学习的第一个网络。 刚开始用tenserflow写得很辛苦,后来换乘keras很快就写了,所以希望先分享一下,以后学习的同学不要绕远点。

全卷积神经网络理论知识全卷积神经网络由Jonathan Long、Evan Shelhamer、Trevor Darrell等撰写文章' fullyconvolutionalnetworksforsemanticsegmentall

文章链接:

3359 open access.the CVF.com/content _ cvpr _ 2015/papers/long _ fully _ convolutional _ networks _ 2015 _ cvpr

FCN是以VGG16为基础改进的,首先让我们简单回顾一下VGG16的结构。

VGG-16是用于图像分类的卷积神经网络,上图显示了VGG的结构。 图中显示了几个不同的版本,包括11楼的(a,A-LRN )、13楼的(b )、qxdc的(c,d )和19楼的(e )。 其中最流行的是qxdc版本,其结构主要由5个卷积池模块、3个全连接层和1个组成,FCN文章在以下图片:中描绘了VGG-16的结构

上图所示的VGG-16直观,前五个卷积模块提取并压缩图像中的信息,后三个所有连接层还将信息输入softmax分类器中,最后在softmax中确定图像属于哪个类。

然而,对于图像分割任务来说,图像信息已经被上述五个模块高度编码,位置信息丢失很大,不能精确对准,因此FCN提出了一种对编码信息进行重新解码的方法。 用这种方法恢复位置信息,进行准确的图像分割。

另外,FCN用11大小的卷积层替换了VGG-16的最后三个所有连接层,大大减少了需要训练的参数。 FCN的结构请参照下图。

除了上述变化,FCN提出了一种跳过层连接结构,在对压缩的图像上采样(放大)之后,通过融合相应大小的浅层图像信息,更好地恢复图像的原始信息,提高图像的分割精度。

上图显示了FCN-8s的跃层连接结构。 FCN-8s基于之前说明的框架进行了8s这一跃层连接结构。 以下总是详细说明。 在上图中,图像经过5次压缩(绿色部分)后,图像尺寸变为原来的1/32尺寸(第5个绿色块),经过后面2层的11卷积后)尺寸保持不变),先将图像放大2倍(上采样) 16尺寸的图像信息),再进行一次2倍的上采样,此时图像变为1/8的大小,再次提取前面的池化层的1/8大小的图像信息(第三个绿色的块) )进行相加,得到的信息还是1/8 最后将该信息) zjdxy )直接进行8倍上采样,得到与原始图像大小相同的图像信息,按该信息的像素点分类得到的8s,应该是最后进行了8倍上采样。

根据以上三点的变更,用于图像分类的VGG-16网络被改编为用于图像分割工作的网络。

FCN的keras实现FCN的keras库代码如下:

from keras.applicationsimportvgg 16 from keras.modelsimportmodel,sequential fromkeras.layersimportconv 2d,Conv2DTranspose add activationfromkerasimportoptimizers # n classes是分类数,input_height和input_width是输入图像的高度和宽度的像素数,nChannels是输入图像的通道数deff cn input_width,nChannels ) :inputs=input () input_height Nhannels(###编码器单元conV1=conv2D(filters=32,inpput ) kernel _ si ight name=' block1_ con v1 ' (inputs ) conV1=conv2d(filters=32,kernel _ size=(3,3 ),padding=' )

ivation='relu', name='block1_conv2')(conv1) pool1 = MaxPooling2D(pool_size=(2, 2), name='block1_pool')(conv1) conv2 = Conv2D(filters=64, kernel_size=(3, 3), padding='same', activation='relu', name='block2_conv1')(pool1) conv2 = Conv2D(filters=64, kernel_size=(3, 3), padding='same', activation='relu', name='block2_conv2')(conv2) pool2 = MaxPooling2D(pool_size=(2, 2), name='block2_pool')(conv2) conv3 = Conv2D(filters=128, kernel_size=(3, 3), padding='same', activation='relu', name='block3_conv1')(pool2) conv3 = Conv2D(filters=128, kernel_size=(3, 3), padding='same', activation='relu', name='block3_conv2')(conv3) conv3 = Conv2D(filters=128, kernel_size=(3, 3), padding='same', activation='relu', name='block3_conv3')(conv3) pool3 = MaxPooling2D(pool_size=(2, 2), name='block3_pool')(conv3) score_pool3 = Conv2D(filters=nClasses, kernel_size=(3, 3), padding='same', activation='relu', name='score_pool3')(pool3)#此行代码为后面的跳层连接做准备 conv4 = Conv2D(filters=256, kernel_size=(3, 3), padding='same', activation='relu', name='block4_conv1')(pool3) conv4 = Conv2D(filters=256, kernel_size=(3, 3), padding='same', activation='relu', name='block4_conv2')(conv4) conv4 = Conv2D(filters=256, kernel_size=(3, 3), padding='same', activation='relu', name='block4_conv3')(conv4) pool4 = MaxPooling2D(pool_size=(2, 2), name='block4_pool')(conv4) score_pool4 = Conv2D(filters=nClasses, kernel_size=(3, 3), padding='same', activation='relu', name='score_pool4')(pool4)#此行代码为后面的跳层连接做准备 conv5 = Conv2D(filters=256, kernel_size=(3, 3), padding='same', activation='relu', name='block5_conv1')(pool4) conv5 = Conv2D(filters=256, kernel_size=(3, 3), padding='same', activation='relu', name='block5_conv2')(conv5) conv5 = Conv2D(filters=256, kernel_size=(3, 3), padding='same', activation='relu', name='block5_conv3')(conv5) pool5 = MaxPooling2D(pool_size=(2, 2), name='block5_pool')(conv5)###1×1卷积部分,加入了Dropout层以免过拟合 fc6 = Conv2D(filters=1024, kernel_size=(1, 1), padding='same', activation='relu', name='fc6')(pool5) fc6 = Dropout(0.3, name='dropout_1')(fc6) fc7 = Conv2D(filters=1024, kernel_size=(1, 1), padding='same', activation='relu', name='fc7')(fc6) fc7 = Dropout(0.3, name='dropour_2')(fc7)###下面的代码为跳层连接结构 score_fr = Conv2D(filters=nClasses, kernel_size=(1, 1), padding='same', activation='relu', name='score_fr')(fc7) score2 = Conv2DTranspose(filters=nClasses, kernel_size=(2, 2), strides=(2, 2), padding="valid", activation=None, name="score2")(score_fr) add1 = add(inputs=[score2, score_pool4], name="add_1") score4 = Conv2DTranspose(filters=nClasses, kernel_size=(2, 2), strides=(2, 2), padding="valid", activation=None, name="score4")(add1) add2 = add(inputs=[score4, score_pool3], name="add_2") UpSample = Conv2DTranspose(filters=nClasses, kernel_size=(8, 8), strides=(8, 8), padding="valid", activation=None, name="UpSample")(add2) outputs = Conv2D(1, 1, activation='sigmoid')(UpSample)#因softmax的特性,跳层连接部分的卷积层都有nClasses个卷积核,以保证softmax的运行 model = Model(inputs=inputs, outputs=outputs) model.summary() return model

训练代码如下:

import osos.environ["CUDA_VISIBLE_DEVICES"] = "0,1"from model import FCN_8Sfrom keras.callbacks import ModelCheckpoint, TensorBoardfrom data import trainGeneratorimport tensorflow as tffrom keras.optimizers import Adamconfig = tf.compat.v1.ConfigProto()config.gpu_options.allow_growth = Truetf.compat.v1.keras.backend.set_session(tf.compat.v1.Session(config=config))#以上三行代码为TF2.0解决GPU缓存问题的代码,TF1.0与此代码不同nClasses = 2input_height = 512input_width = 512nChannels = 1train_batch_size = 2epochs = 500mymodel = FCN_8S(nClasses, input_height, input_width, nChannels)#导入模型mymodel.compile(optimizer=Adam(lr=1e-4), loss='binary_crossentropy', metrics=['accuracy'])#设定数据增强参数data_gen_args = dict(rotation_range=0.2, #整数。随机旋转的度数范围。 width_shift_range=0.05, #浮点数、一维数组或整数 height_shift_range=0.05, #浮点数。剪切强度(以弧度逆时针方向剪切角度)。shear_range=0.05, fndhy_range=0.05, #浮点数 或 [lower, upper]。随机缩放范围horizontal_flip=True, fill_mode='nearest')# 建立测试集,样本和标签分别放在同一个目录下的两个文件夹中,文件夹名字为:'image','label'myGene = trainGenerator(train_batch_size,'./data/train','image','label',data_gen_args,save_to_dir = None)#得到一个生成器,以batch=1的速率无限生成增强后的数据model_checkpoint = ModelCheckpoint('fcn-500.hdf5', monitor='loss',verbose=1, save_best_only=True)#设定储存Check point的参数mymodel.fit_generator(generator=myGene,steps_per_epoch=90,epochs=epochs, callbacks=[model_checkpoint])#对模型进行训练

测试代码如下:

from model import FCN_8Sfrom data import *import tensorflow as tfphysical_devices = tf.config.experimental.list_physical_devices('GPU')assert len(physical_devices) > 0, "Not enough GPU hardware devices available"tf.config.experimental.set_memory_growth(physical_devices[0], True)# 输入测试数据集,testGene = testGenerator("data/moni", num_image=10, target_size=(512, 512))# 导入模型mymodel = FCN_8S(2,512, 512, 1) # model# 导入训练好的模型mymodel.load_weights("fcn-T4-500.hdf5")# 预测数据results = mymodel.predict_generator(testGene, 10, verbose=1) # kerassaveResult("data/pre", results) #保存预测图片print("over")

我用512×512像素的灰度图像对模型进行了训练,效果还不错,就是图像边缘的锯齿感比较严重。

最左边是待分割的图像,中间是人工手动分割的图像,右边是FCN-8s的分割结果,可以看到相对于人工的分割,FCN分割结果的锯齿很严重,所以我对代码进行了改进,多进行了两次的跳层连接,按照FCN文章中的命名规则应该叫FCN-2s,经过这次变动后,模型的分割效果就很好了

虽然还是有小的目标分割不出来,不过精度已经很高了,MIoU能达到98%。

以上内容希望能帮助到各位初学者。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。