图像语意分割训练Cityscapes数据集SegNet-ConvNet神经网络详解

本文主要是介绍图像语意分割训练Cityscapes数据集SegNet-ConvNet神经网络详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:经过几个月的学习研究,在神经网络中训练多分类语意分割模型识别城市街景信息,终于在最近得到了理想中的实验结果。在我陷入对细节参数调整不当及诸多问题时,苦于没有一篇能够“面向新手编程”的博客。因而我在能够在解决一系列问题到达终点后总结这一路踩过的坑,希望对后来者有所帮助。
接下来就是用我训练完成的神经网络模型结合我所学专业(风景园林)研究领域问题完成论文撰写,希望能够投稿核心期刊成功。^ _^

我所提供的代码及讲解均是基于Cityscapes这一数据集默认19分类的基础上完成,若有朋友想要训练其他数量分类及用于他处,可学习思路并自行修改代码。

放一组训练完成模型进行识别出来的图,激励各位朋友和我自己在深度学习的路上坚持下去。
我使用百度地图API获取了天津大学门口的一处坐标点街景图片进行识别测试。
在predict(预测)阶段我后续添加了绿化率识别算法模块,可将绿色像素遍历并计数求得占总像素比率。
在这里插入图片描述
在这里插入图片描述
1.图片数据获取
需要使用Cityscapes这一数据集训练神经网络模型:
该数据集主要用来做汽车自动驾驶识别,要么是像我用来做城市街景信息的识别分类。模型训练出来后,识别数据的获取就至关重要,在我的另一篇博客中:
Python通过百度全景图API爬取街景图像
我详细讲解了如何通过百度地图官方API,通过Python的爬虫代码批量获取坐标全景图片。

2.数据集预处理
我们知道,在深度学习图像语意分割的训练过程中,需要有数据集及分好类的标签,这样才可以让你的神经网络进行学习,进而训练出模型,用来识别你想要识别的图片场景等。Cityscapes便是包含大量街道图片、视频用来训练识别的数据集。
在我另一篇博客中对数据集的下载、处理都进行了详细的解释,这里就不做过多解释。
图像语意分割Cityscapes训练数据集使用方法分享

3.图像语意分割神经网络列举
这里还是要感谢博主:Bubbliiiing提供的神经网络合集及博文讲解。
博主提供的神经网络代码均是基于2分类的斑马线图像分割,而我需要多分类的图像语意分割,各位朋友在学习时可以仔细对照修改前后的网络代码差别,会对网络细节需要修改的参数更深层的理解。
我将博主共享的模型代码做了一份整理(下图),我将分两篇博文选取其中两个进行讲解。
分别是SenNet-ConvNet(简单)和DeepLabNet-XceptionNet(复杂)。
在这里插入图片描述
4.Make_Dataset
神经网络通过图片进行网络参数训练时,图片的获取需要从电脑异步读取,例如读取2张训练2张,如果读取所有上千张图片再抽取训练这样并不可行。
通过将图片和标签名称写入txt文件,在网络中读取txt文件合成完整的图片路径,进行读取。

import os#自行修改文件绝对路径
left = os.listdir(r"F:\202006Practice\cityscapesScripts-master\leftImg8bit\val")
gtfine = os.listdir(r"F:\202006Practice\cityscapesScripts-master\gtFine\val")#自行修改txt文件相对路径
with open("read_data/val_data0.txt","w") as f:for name in left:png = name.replace("leftImg8bit","gtFine_labelTrainIds")# 判断left是否存在对应的gtfineif png in gtfine:f.write(name+";"+png+"\n")

我将leftImg8bit和gtFine下的train和val数据集,将图片从各个城市的文件夹中剪切到了一个文件下。原因是我并没有想到什么非常好的办法,可以让程序按城市顺序读取图片并训练,不如将2974张train及500张val图片分别放到一起进行训练及验证。feed数据阶段若有朋友了解更好操作方法还请不吝赐教!
代码第4、5行路径可以更改为你电脑中图片绝对路径。我这里放一张文件夹截图作为示例。
因为有原图及标签两个文件夹,所以也需要生成两个txt文件,第4、5行路径及第7行生成文件名称需要相对应的修改。
在这里插入图片描述
5.SenNet-ConvNet神经网络图像语意分割多分类训练
为了篇幅美观及阅读舒适,所有代码均放到了文章末尾。
编码网络ConvNet及解码网络SegNet均放在nets这一文件夹下,主要是通过
model = Model (输入,输出)
这一代码进行网络的构建,神经网络结构Bubbliiiing已经进行了非常详细的讲解,我就不需要过多解释。

在train这一训练主函数模块中,为了多分类训练需要对一些代码细节进行修改:

  • 11行:NCLASSES需要从2改为19。这里便是控制最终多分类的数量。
  • 18行:我将城市的名字写成一个列表。因为我尝试用for循环遍历城市名字,并随机从城市列表中取图片进行训练,上文解释过最终我还是将所有城市图片复制到了同一文件夹下,故这两行代码可以注释掉或忽略。
  • 20行:共18个城市,我尝试生成一个1~18的随机数,用于随机取数据。最终放弃,同上。
  • 22行:非随机取城市。最终放弃,同上。
  • 38行:路径改为你电脑中存放的原图位置。37行为原代码,注释掉方便回溯,可忽略。
  • 48行:路径改为你电脑中存放的标签位置。47行为原代码,注释掉方便回溯,可忽略。
  • 51行:原代码是基于斑马线的二分类训练,原图及标签格式分别为PNG和JPG,然而在cityscapes中原图和标签格式均为PNG,此时就会出现一个问题,RGB三个值相等的灰度PNG图读取进来的维度会变为1维,而非JPG图片的3维。当时经过我多次测试,通过PIL.Image中convert方法可以将读取的“L”灰度图模式(1维)转为“RGB”模式(3维)。
  • 57行:问题同上。我尝试直接将1维升为3维,失败。此行代码可忽略。
  • 62行:问题同上。这是最优的解决办法,但和57行的方法仅能取其一,另一种注释掉。
    通过和Bubbliiiing交流后顿悟,仅需将:0删掉即可,使用57行图像格式转换的方法有可能在训练时数据会出问题。但我测试没出问题。
  • 84行:预训练网络路径。若你没有下载预训练网络,可以在第一次训练时使用79-82行代码,控制台会显示一个网址,并自动进行预训练网络的下载,此时停止训练,使用浏览器输入这一网址下载预训练网络,完成后放到新建一个model的文件夹内。第二次训练即可使用第84行代码(注释掉79-82),直接指向你电脑内的预训练网络路径位置。
  • 85行:最终训练完成后,会自动保存一个名为“last1.h5”的权重文件,假如你认为并没有达到你的预期效果,只需将预训练网络替换为上次训练保存结果即可继承之前的权重继续训练。
  • 91行:替换txt文件路径。

至此代码便没有进行其他内容的修改。

6.下期预告
有细心的朋友可能会发现,只用到了一个txt文件进行训练集的数据读取,而另外一个验证集txt根本没有用到,也没有用到验证集的图片。
在代码101行可以找到问题的答案。
原博主将训练集数量的90%用于训练,而剩下10%用于验证,这确实是一种取巧的方法,优点是快速简单。

在这里插入图片描述
然而对最终训练模型的过拟合临界点、训练早停轮次(epoch)的选择会有影响,原因如下:
虽然在一个轮次中分为了90%训练和10%验证,但神经网络的参数权重终究在之前的轮次训练中接触过100%的图片,所以对神经网络曾“见过”的图片在另外轮次中作为验证集终究是有失公允。
思考题😕😕😕:针对这样一个问题,在没有给出解决代码的前提下,你能否根据原博主的原网络代码尝试仿写出获取训练集的方法呢?
在下一篇博文代码中,增加了数据增强函数模块,迁移学习函数模块,以及思考题-验证集获取函数模块。

个人水平有限,若有理解不到之处,还请多指正~

from nets.segnet import convnet_segnet
from keras.optimizers import Adam
from keras.callbacks import TensorBoard, ModelCheckpoint, ReduceLROnPlateau, EarlyStopping
from PIL import Image
import keras
from keras import backend as K
import numpy as np
import cv2
import random
from keras.utils.data_utils import get_file
NCLASSES = 19
HEIGHT = 416
WIDTH = 416#[aachen,1][bochum,2][bremen,3][cologne,4][darmstadt,5][dusseldorf,6][erfurt,7][hamburg,8][hanover,9]
#[jena,10][krefeld,11][monchengladbach,12][strasbourg,13][stuttgart,14][tubingen,15][ulm,16][weimar,17][zurich,18]city_list = ["aachen","bochum","bremen","cologne","darmstadt","dusseldorf","erfurt","hamburg","hanover","jena","krefeld","monchengladbach","strasbourg","stuttgart","tubingen","ulm","weimar","zurich"]
# txt_number = random.randint(1,18)
txt_number = 0
# name_path = city_list[txt_number-1]def generate_arrays_from_file(lines,batch_size):# 获取总长度n = len(lines)i = 0while 1:X_train = []Y_train = []# 获取一个batch_size大小的数据for _ in range(batch_size):if i==0:np.random.shuffle(lines)name = lines[i].split(';')[0]# 从文件中读取图像# img = Image.open(r".\dataset2\jpg" + '/' + name)img = Image.open(r"F:\202006Practice\cityscapesScripts-master\leftImg8bit\train" + '/' + name)img = img.resize((WIDTH,HEIGHT))img = np.array(img)img = img/255X_train.append(img)name = (lines[i].split(';')[1]).replace("\n", "")# 从文件中读取图像# img = Image.open(r".\dataset2\png" + '/' + name)img = Image.open(r"F:\202006Practice\cityscapesScripts-master\gtFine\train" + '/' + name)#一种方法:尝试从“L”转为“RGB”# img = img.convert("RGB")img = img.resize((int(WIDTH/2),int(HEIGHT/2)))img = np.array(img)#二种方法:尝试升维   失败# img = img[:, :, None]seg_labels = np.zeros((int(HEIGHT/2),int(WIDTH/2),NCLASSES))for c in range(NCLASSES):# seg_labels[: , : , c ] = (img[:,:,0] == c ).astype(int)seg_labels[: , : , c ] = (img[:] == c ).astype(int)seg_labels = np.reshape(seg_labels, (-1, NCLASSES))Y_train.append(seg_labels)# 读完一个周期后重新开始i = (i+1) % nyield (np.array(X_train),np.array(Y_train))def loss(y_true, y_pred):loss = K.categorical_crossentropy(y_true,y_pred)return lossif __name__ == "__main__":log_dir = "logs/"# 获取modelmodel = convnet_segnet(n_classes=NCLASSES,input_height=HEIGHT, input_width=WIDTH)# model.summary()# WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5'# weights_path = get_file('vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5',#                                 WEIGHTS_PATH_NO_TOP,#                                 cache_subdir='models')weights_path = (r"model/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5")# weights_path = (log_dir+r"last1.h5")model.load_weights(weights_path,by_name=True)# 打开数据集的txtwith open(r"F:\202006Practice\1.make_dataset\read_data\train_data{}.txt".format(txt_number),"r") as f:lines = f.readlines()# 打乱行,这个txt主要用于帮助读取数据来训练# 打乱的数据更有利于训练np.random.seed(10101)np.random.shuffle(lines)np.random.seed(None)# 90%用于训练,10%用于估计。num_val = int(len(lines)*0.1)num_train = len(lines) - num_val# 保存的方式,3世代保存一次checkpoint_period = ModelCheckpoint(log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',monitor='val_loss',save_weights_only=True,save_best_only=True,period=3)# 学习率下降的方式,val_loss3次不下降就下降学习率继续训练reduce_lr = ReduceLROnPlateau(monitor='val_loss',factor=0.5,patience=3,verbose=1)# 是否需要早停,当val_loss一直不下降的时候意味着模型基本训练完毕,可以停止early_stopping = EarlyStopping(monitor='val_loss',min_delta=0,patience=10,verbose=1)# 交叉熵model.compile(loss = loss,optimizer = Adam(lr=1e-3),metrics = ['accuracy'])batch_size = 4print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))# 开始训练model.fit_generator(generate_arrays_from_file(lines[:num_train], batch_size),steps_per_epoch=max(1, num_train//batch_size),validation_data=generate_arrays_from_file(lines[num_train:], batch_size),validation_steps=max(1, num_val//batch_size),epochs=50,# epochs=1,initial_epoch=0,callbacks=[checkpoint_period, reduce_lr,early_stopping])model.save_weights(log_dir+'last1.h5')

广告:
我以街景数据为基础在SCI一区顶刊发表文章两篇(影响因子共计18分)
(DOI:10.1016/j.isprsjprs.2022.06.011)(DOI:10.3389/fpubh.2022.891736)
有需要大量采集城市街景(百度街景/谷歌街景)、技术支持、论文指导服务同学,请私聊联系我。
私信回复不及时请联系邮箱:wanglei2021@tju.edu.cn
免费领取街景请关注公众号:城石科技
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

这篇关于图像语意分割训练Cityscapes数据集SegNet-ConvNet神经网络详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/541831

相关文章

详谈redis跟数据库的数据同步问题

《详谈redis跟数据库的数据同步问题》文章讨论了在Redis和数据库数据一致性问题上的解决方案,主要比较了先更新Redis缓存再更新数据库和先更新数据库再更新Redis缓存两种方案,文章指出,删除R... 目录一、Redis 数据库数据一致性的解决方案1.1、更新Redis缓存、删除Redis缓存的区别二

Redis事务与数据持久化方式

《Redis事务与数据持久化方式》该文档主要介绍了Redis事务和持久化机制,事务通过将多个命令打包执行,而持久化则通过快照(RDB)和追加式文件(AOF)两种方式将内存数据保存到磁盘,以防止数据丢失... 目录一、Redis 事务1.1 事务本质1.2 数据库事务与redis事务1.2.1 数据库事务1.

Mysql 中的多表连接和连接类型详解

《Mysql中的多表连接和连接类型详解》这篇文章详细介绍了MySQL中的多表连接及其各种类型,包括内连接、左连接、右连接、全外连接、自连接和交叉连接,通过这些连接方式,可以将分散在不同表中的相关数据... 目录什么是多表连接?1. 内连接(INNER JOIN)2. 左连接(LEFT JOIN 或 LEFT

Java中switch-case结构的使用方法举例详解

《Java中switch-case结构的使用方法举例详解》:本文主要介绍Java中switch-case结构使用的相关资料,switch-case结构是Java中处理多个分支条件的一种有效方式,它... 目录前言一、switch-case结构的基本语法二、使用示例三、注意事项四、总结前言对于Java初学者

Linux内核之内核裁剪详解

《Linux内核之内核裁剪详解》Linux内核裁剪是通过移除不必要的功能和模块,调整配置参数来优化内核,以满足特定需求,裁剪的方法包括使用配置选项、模块化设计和优化配置参数,图形裁剪工具如makeme... 目录简介一、 裁剪的原因二、裁剪的方法三、图形裁剪工具四、操作说明五、make menuconfig

Oracle Expdp按条件导出指定表数据的方法实例

《OracleExpdp按条件导出指定表数据的方法实例》:本文主要介绍Oracle的expdp数据泵方式导出特定机构和时间范围的数据,并通过parfile文件进行条件限制和配置,文中通过代码介绍... 目录1.场景描述 2.方案分析3.实验验证 3.1 parfile文件3.2 expdp命令导出4.总结

更改docker默认数据目录的方法步骤

《更改docker默认数据目录的方法步骤》本文主要介绍了更改docker默认数据目录的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1.查看docker是否存在并停止该服务2.挂载镜像并安装rsync便于备份3.取消挂载备份和迁

详解Java中的敏感信息处理

《详解Java中的敏感信息处理》平时开发中常常会遇到像用户的手机号、姓名、身份证等敏感信息需要处理,这篇文章主要为大家整理了一些常用的方法,希望对大家有所帮助... 目录前后端传输AES 对称加密RSA 非对称加密混合加密数据库加密MD5 + Salt/SHA + SaltAES 加密平时开发中遇到像用户的

不删数据还能合并磁盘? 让电脑C盘D盘合并并保留数据的技巧

《不删数据还能合并磁盘?让电脑C盘D盘合并并保留数据的技巧》在Windows操作系统中,合并C盘和D盘是一个相对复杂的任务,尤其是当你不希望删除其中的数据时,幸运的是,有几种方法可以实现这一目标且在... 在电脑生产时,制造商常为C盘分配较小的磁盘空间,以确保软件在运行过程中不会出现磁盘空间不足的问题。但在

Springboot使用RabbitMQ实现关闭超时订单(示例详解)

《Springboot使用RabbitMQ实现关闭超时订单(示例详解)》介绍了如何在SpringBoot项目中使用RabbitMQ实现订单的延时处理和超时关闭,通过配置RabbitMQ的交换机、队列和... 目录1.maven中引入rabbitmq的依赖:2.application.yml中进行rabbit