憨批的语义分割重制版5——Keras 搭建自己的Unet语义分割平台

憨批的语义分割重制版5——Keras 搭建自己的Unet语义分割平台憨批的语义分割12——Keras搭建自己的Unet语义分割平台注意事项学习前言什么是Unet模型代码下载Unet实现思路一、预测部分1、主干网络介绍2、加强特征提取结构3、利用特征获得预测结果二、训练部分1、训练文件详解2、LOSS解析训练自己的Unet模型注意事项这是重新构建了的Unet语义分割网络,主要是文件框架上的构建,还有代码的实现,和之前的语义分割网络相比,更加完整也更清晰一些。建议还是学习这个版本的Unet。学习前言重置一下我最喜欢的Unet。什么是Unet模型Unet是一个优秀

大家好,又见面了,我是你们的朋友全栈君。

注意事项

这是重新构建了的Unet语义分割网络,主要是文件框架上的构建,还有代码的实现,和之前的语义分割网络相比,更加完整也更清晰一些。建议还是学习这个版本的Unet。

学习前言

重置一下我最喜欢的Unet。
在这里插入图片描述

什么是Unet模型

Unet是一个优秀的语义分割模型,其主要执行过程与其它语义分割模型类似。

Unet可以分为三个部分,如下图所示:

第一部分是主干特征提取部分,我们可以利用主干部分获得一个又一个的特征层,Unet的主干特征提取部分与VGG相似,为卷积和最大池化的堆叠。利用主干特征提取部分我们可以获得五个初步有效特征层,在第二步中,我们会利用这五个有效特征层可以进行特征融合。

第二部分是加强特征提取部分,我们可以利用主干部分获取到的五个初步有效特征层进行上采样,并且进行特征融合,获得一个最终的,融合了所有特征的有效特征层

第三部分是预测部分,我们会利用最终获得的最后一个有效特征层对每一个特征点进行分类,相当于对每一个像素点进行分类。
在这里插入图片描述

代码下载

Github源码下载地址为:
https://github.com/bubbliiiing/unet-keras

Unet实现思路

一、预测部分

1、主干网络介绍

在这里插入图片描述
Unet的主干特征提取部分由卷积+最大池化组成,整体结构与VGG类似。

本文所采用的主干特征提取网络为VGG16,这样也方便使用imagnet上的预训练权重。

VGG是由Simonyan 和Zisserman在文献《Very Deep Convolutional Networks for Large Scale Image Recognition》中提出卷积神经网络模型,其名称来源于作者所在的牛津大学视觉几何组(Visual Geometry Group)的缩写。

该模型参加2014年的 ImageNet图像分类与定位挑战赛,取得了优异成绩:在分类任务上排名第二,在定位任务上排名第一。
它的结构如下图所示:
在这里插入图片描述
这是一个VGG16被用到烂的图,但确实很好的反应了VGG16的结构。

当我们使用VGG16作为主干特征提取网络的时候,我们只会用到两种类型的层,分别是卷积层最大池化层

当输入的图像大小为512x512x3的时候,具体执行方式如下:
1、conv1:进行两次[3,3]的64通道的卷积,获得一个[512,512,64]的初步有效特征层,再进行2X2最大池化,获得一个[256,256,64]的特征层。
2、conv2:进行两次[3,3]的128通道的卷积,获得一个[256,256,128]的初步有效特征层,再进行2X2最大池化,获得一个[128,128,128]的特征层。
3、conv3:进行三次[3,3]的256通道的卷积,获得一个[128,128,256]的初步有效特征层,再进行2X2最大池化,获得一个[64,64,256]的特征层。
4、conv4:进行三次[3,3]的512通道的卷积,获得一个[64,64,512]的初步有效特征层,再进行2X2最大池化,获得一个[32,32,512]的特征层。
5、conv5:进行三次[3,3]的512通道的卷积,获得一个[32,32,512]的初步有效特征层。

在这里插入图片描述

from keras import layers
def VGG16(img_input):
# Block 1
x = layers.Conv2D(64, (3, 3),
activation='relu',
padding='same',
name='block1_conv1')(img_input)
x = layers.Conv2D(64, (3, 3),
activation='relu',
padding='same',
name='block1_conv2')(x)
feat1 = x
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)
# Block 2
x = layers.Conv2D(128, (3, 3),
activation='relu',
padding='same',
name='block2_conv1')(x)
x = layers.Conv2D(128, (3, 3),
activation='relu',
padding='same',
name='block2_conv2')(x)
feat2 = x
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)
# Block 3
x = layers.Conv2D(256, (3, 3),
activation='relu',
padding='same',
name='block3_conv1')(x)
x = layers.Conv2D(256, (3, 3),
activation='relu',
padding='same',
name='block3_conv2')(x)
x = layers.Conv2D(256, (3, 3),
activation='relu',
padding='same',
name='block3_conv3')(x)
feat3 = x
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
# Block 4
x = layers.Conv2D(512, (3, 3),
activation='relu',
padding='same',
name='block4_conv1')(x)
x = layers.Conv2D(512, (3, 3),
activation='relu',
padding='same',
name='block4_conv2')(x)
x = layers.Conv2D(512, (3, 3),
activation='relu',
padding='same',
name='block4_conv3')(x)
feat4 = x
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
# Block 5
x = layers.Conv2D(512, (3, 3),
activation='relu',
padding='same',
name='block5_conv1')(x)
x = layers.Conv2D(512, (3, 3),
activation='relu',
padding='same',
name='block5_conv2')(x)
x = layers.Conv2D(512, (3, 3),
activation='relu',
padding='same',
name='block5_conv3')(x)
feat5 = x
return feat1, feat2, feat3, feat4, feat5

2、加强特征提取结构

在这里插入图片描述
Unet所使用的加强特征提取网络是一个U的形状。

利用第一步我们可以获得五个初步的有效特征层,在加强特征提取网络这里,我们会利用这五个初步的有效特征层进行特征融合特征融合的方式就是对特征层进行上采样并且进行堆叠

为了方便网络的构建与更好的通用性,我们的Unet和上图的Unet结构有些许不同,在上采样时直接进行两倍上采样再进行特征融合,最终获得的特征层和输入图片的高宽相同。

具体示意图如下:
在这里插入图片描述

import numpy as np
from keras.models import *
from keras.layers import *
from nets.vgg16 import VGG16
def Unet(input_shape=(256,256,3), num_classes=21):
inputs = Input(input_shape)
feat1, feat2, feat3, feat4, feat5 = VGG16(inputs) 
channels = [64, 128, 256, 512]
P5_up = UpSampling2D(size=(2, 2))(feat5)
P4 = Concatenate(axis=3)([feat4, P5_up])
P4 = Conv2D(channels[3], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P4)
P4 = Conv2D(channels[3], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P4)
P4_up = UpSampling2D(size=(2, 2))(P4)
P3 = Concatenate(axis=3)([feat3, P4_up])
P3 = Conv2D(channels[2], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P3)
P3 = Conv2D(channels[2], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P3)
P3_up = UpSampling2D(size=(2, 2))(P3)
P2 = Concatenate(axis=3)([feat2, P3_up])
P2 = Conv2D(channels[1], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P2)
P2 = Conv2D(channels[1], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P2)
P2_up = UpSampling2D(size=(2, 2))(P2)
P1 = Concatenate(axis=3)([feat1, P2_up])
P1 = Conv2D(channels[0], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P1)
P1 = Conv2D(channels[0], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P1)
P1 = Conv2D(num_classes, 1, activation="softmax")(P1)
model = Model(inputs=inputs, outputs=P1)
return model

3、利用特征获得预测结果

利用1、2步,我们可以获取输入进来的图片的特征,此时,我们需要利用特征获得预测结果。

利用特征获得预测结果的过程为:
利用一个1×1卷积进行通道调整,将最终特征层的通道数调整成num_classes。
在这里插入图片描述

import numpy as np
from keras.models import *
from keras.layers import *
from nets.vgg16 import VGG16
def Unet(input_shape=(256,256,3), num_classes=21):
inputs = Input(input_shape)
feat1, feat2, feat3, feat4, feat5 = VGG16(inputs) 
channels = [64, 128, 256, 512]
P5_up = UpSampling2D(size=(2, 2))(feat5)
P4 = Concatenate(axis=3)([feat4, P5_up])
P4 = Conv2D(channels[3], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P4)
P4 = Conv2D(channels[3], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P4)
P4_up = UpSampling2D(size=(2, 2))(P4)
P3 = Concatenate(axis=3)([feat3, P4_up])
P3 = Conv2D(channels[2], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P3)
P3 = Conv2D(channels[2], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P3)
P3_up = UpSampling2D(size=(2, 2))(P3)
P2 = Concatenate(axis=3)([feat2, P3_up])
P2 = Conv2D(channels[1], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P2)
P2 = Conv2D(channels[1], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P2)
P2_up = UpSampling2D(size=(2, 2))(P2)
P1 = Concatenate(axis=3)([feat1, P2_up])
P1 = Conv2D(channels[0], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P1)
P1 = Conv2D(channels[0], 3, activation='relu', padding='same', kernel_initializer='he_normal')(P1)
P1 = Conv2D(num_classes, 1, activation="softmax")(P1)
model = Model(inputs=inputs, outputs=P1)
return model

二、训练部分

1、训练文件详解

我们使用的训练文件采用VOC的格式。
语义分割模型训练的文件分为两部分。
第一部分是原图,像这样:
在这里插入图片描述
第二部分标签,像这样:
在这里插入图片描述
原图就是普通的RGB图像,标签就是灰度图或者8位彩色图。

原图的shape为[height, width, 3],标签的shape就是[height, width],对于标签而言,每个像素点的内容是一个数字,比如0、1、2、3、4、5……,代表这个像素点所属的类别。

语义分割的工作就是对原始的图片的每一个像素点进行分类,所以通过预测结果中每个像素点属于每个类别的概率与标签对比,可以对网络进行训练。

2、LOSS解析

本文所使用的LOSS由两部分组成:
1、Cross Entropy Loss。
2、Dice Loss。

Cross Entropy Loss就是普通的交叉熵损失,当语义分割平台利用Softmax对像素点进行分类的时候,进行使用。

Dice loss将语义分割的评价指标作为Loss,Dice系数是一种集合相似度度量函数,通常用于计算两个样本的相似度,取值范围在[0,1]。

计算公式如下:
在这里插入图片描述
就是预测结果和真实结果的交乘上2,除上预测结果加上真实结果。其值在0-1之间。越大表示预测结果和真实结果重合度越大。所以Dice系数是越大越好。

如果作为LOSS的话是越小越好,所以使得Dice loss = 1 – Dice,就可以将Loss作为语义分割的损失了。
实现代码如下:

def dice_loss_with_CE(beta=1, smooth = 1e-5, alpha = 0.25, gamma=2.0, threhold=0.5):
def _dice_loss_with_CE(y_true, y_pred):
y_pred = K.clip(y_pred, K.epsilon(), 1.0 - K.epsilon())
CE_loss = - y_true[...,:-1] * K.log(y_pred)
CE_loss = K.mean(K.sum(CE_loss, axis = -1))
tp = K.sum(y_true[...,:-1] * y_pred, axis=[0,1,2])
fp = K.sum(y_pred         , axis=[0,1,2]) - tp
fn = K.sum(y_true[...,:-1], axis=[0,1,2]) - tp
score = ((1 + beta ** 2) * tp + smooth) / ((1 + beta ** 2) * tp + beta ** 2 * fn + fp + smooth)
score = tf.reduce_mean(score)
dice_loss = 1 - score
# dice_loss = tf.Print(dice_loss, [dice_loss, focal_loss])
return CE_loss + dice_loss
return _dice_loss_with_CE

训练自己的Unet模型

首先前往Github下载对应的仓库,下载完后利用解压软件解压,之后用编程软件打开文件夹。
注意打开的根目录必须正确,否则相对目录不正确的情况下,代码将无法运行。

一定要注意打开后的根目录是文件存放的目录。
在这里插入图片描述

一、数据集的准备

本文使用VOC格式进行训练,训练前需要自己制作好数据集,如果没有自己的数据集,可以通过Github连接下载VOC12+07的数据集尝试下。
训练前将图片文件放在VOCdevkit文件夹下的VOC2007文件夹下的JPEGImages中。
训练前将标签文件放在VOCdevkit文件夹下的VOC2007文件夹下的SegmentationClass中。

在这里插入图片描述

二、数据集的处理

在完成数据集的摆放之后,我们需要对数据集进行下一步的处理,目的是获得训练用的train.txt以及val.txt,需要用到根目录下的voc_annotation.py。

如果下载的是我上传的voc数据集,那么就不需要运行根目录下的voc_annotation.py。
如果是自己制作的数据集,那么需要运行根目录下的voc_annotation.py,从而生成train.txt和val.txt。
在这里插入图片描述

三、开始网络训练

通过voc_annotation.py我们已经生成了train.txt以及val.txt,此时我们可以开始训练了。训练的参数较多,大家可以在下载库后仔细看注释,其中最重要的部分依然是train.py里的num_classes。

num_classes用于指向检测类别的个数+1!训练自己的数据集必须要修改!

在这里插入图片描述
之后就可以开始训练了。

四、训练结果预测

训练结果预测需要用到两个文件,分别是unet.py和predict.py。
我们首先需要去unet.py里面修改model_path以及num_classes,这两个参数必须要修改。

model_path指向训练好的权值文件,在logs文件夹里。
num_classes指向检测类别的个数+1。

在这里插入图片描述
完成修改后就可以运行predict.py进行检测了。运行后输入图片路径即可检测。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/148888.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 安全狗:云时代的服务器安全守护者

    安全狗:云时代的服务器安全守护者

  • 51单片机之红外通信原理图_单片机红外通信原理

    51单片机之红外通信原理图_单片机红外通信原理红外通信基础

    2022年10月23日
  • php 数学函数集锦

    php 数学函数集锦php 数学函数集锦

  • GSLB原理介绍

    GSLB原理介绍1.GSLB     GSLB,是GlobalServerLoadBalance的缩写,意思是全局负载均衡。目的是实现在广域网(包括互联网)上不同地域的服务器间的流量调配,保证使用户的请求能被离用户最近或者服务质量最好的服务器来处理,从而确保访问质量。       能通过判断服务器的负载,包括CPU占用、带宽占用等数据,决定服务器的可用性,同时能判断用户(访问者)与服

  • 星愿浏览器有什么优点_星愿浏览器插件

    星愿浏览器有什么优点_星愿浏览器插件目的:想基于浏览器进程抓包,但是想获得噪声相对小的数据,则找相对ChromeGoogle等主流browser更简单的浏览器;想使用Google的某个扩展程序,所以找基于Chrome内核的浏览器所以,我要找基于Chrome内核的简单浏览器最后找到了这几个符合条件的浏览器:星愿、百分cent、Vival、Brave星愿优点:星愿的主页面具有相当的自主性,可以自由拖动添加图标和更换背景、搜索框等。其主页有个搜索漫画的功能,好像在看漫画这一块做了一些页面优化。缺点:只能在它提供的星愿商店里下扩.

  • html设置背景图片的代码_html背景代码

    html设置背景图片的代码_html背景代码今天河北魅力网络客户让改一下代码,让背景图片实现不随滚动条来滚动,实现这种效果其实很简单,加个代码就行。<bodybackground=”bj.jpg”style=”background-attachment:fixed”;>style=”background-attachment:fixed”;>这样就实现了背景图片固定效果,虽然简单但很实用…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号