专栏首页相约机器人使用Keras上的分段模型和实施库进行道路检测

使用Keras上的分段模型和实施库进行道路检测

作者 | Insaf Ashrapov

来源 | googleblog

编辑 | 代码医生团队

在本文中,将展示如何编写自己的数据生成器以及如何使用albumentations作为扩充库。与segmentation_models库一起,它为Unet和其他类似unet的架构提供了数十个预训练。有关完整代码,请访问Github。

https://github.com/Diyago/ML-DL-scripts/tree/master/DEEP%20LEARNING/segmentation/Segmentation%20pipeline

理论

语义图像分割的任务是用相应的所表示的类标记图像的每个像素。对于这样的任务,具有不同改进的Unet架构已经显示出最佳结果。它背后的核心思想只是几个卷积块,它们提取深度和不同类型的图像特征,接着是所谓的反卷积或上采样块,它们恢复了输入图像的初始形状。除了在每个卷积层之后,还有一些跳过连接,这有助于网络记住初始图像并帮助防止渐变渐变。有关更多详细信息,请阅读arxiv文章。

https://arxiv.org/abs/1505.04597

数据集 - 卫星图像

对于分段,不需要太多数据就能获得不错的结果,即使是100张带注释的照片也足够了。目前,将使用来自Massachusetts Roads Dataset ,大约有1100多个带注释的列车图像,它们甚至提供验证和测试数据集。不幸的是,没有下载按钮,所以必须使用脚本。此脚本将完成工作(可能需要一些时间才能完成)。

https://www.cs.toronto.edu/~vmnih/data/

https://gist.github.com/Diyago/83919fcaa9ca46e4fcaa632009ec2dbd

来看看图片示例:

马萨诸塞州道路数据集图像和地面真相掩模ex。

注释和图像质量似乎相当不错,网络应该能够检测道路。

库安装

首先,需要安装带有TensorFlow的Keras。对于Unet构造,将使用Pavel Yakubovskiy的库名为segmentation_models,用于数据扩充albumentation库。稍后会详细介绍它们。两个库都经常更新,所以更喜欢直接从git更新它们。

conda install -c conda-forge keras
pip install git + https://github.com/qubvel/efficientnet
pip install git + https://github.com/qubvel/classification_models.git
pip install git + https://github.com/qubvel/segmentation_models
pip install git + https://github.com/albu/albumentations
pip install tta-wrapper

定义数据生成器

作为数据生成器,将使用自定义生成器。它应该继承keras.utils.Sequence并且应该定义这样的方法:

  • __init__(类初始化)
  • __len __(返回数据集的长度)
  • on_epoch_end(时代末期的行为)
  • __getitem__(生成的批处理用于送入网络)

使用自定义生成器的一个主要优点是,可以使用拥有的每种格式数据,并且可以执行任何操作 - 只是不要忘记为keras生成所需的输出(批处理)。

这里定义__init__方法。它的主要部分是为图像设置路径(self.image_filenames)和掩码名称(self.mask_names)。不要忘记对它们进行排序,因为对于self.image_filenames [i]相应的掩码应该是self.mask_names [i]。

def __init__(self, root_dir=r'../data/val_test', image_folder='img/', mask_folder='masks/',
             batch_size=1, image_size=768, nb_y_features=1,
             augmentation=None,
             suffle=True):
    self.image_filenames = listdir_fullpath(os.path.join(root_dir, image_folder))
    self.mask_names = listdir_fullpath(os.path.join(root_dir, mask_folder))
    self.batch_size = batch_size
    self.augmentation = augmentation
    self.image_size = image_size
    self.nb_y_features = nb_y_features
    self.suffle = suffle
        
def listdir_fullpath(d):
return np.sort([os.path.join(d, f) for f in os.listdir(d)])

下一件重要的事__getitem__。通常,不能将所有图像存储在RAM中,因此每次生成新的一批数据时,都应该读取相应的图像。下面定义训练方法。为此创建一个空的numpy数组(np.empty),它将存储图像和掩码。然后通过read_image_mask方法读取图像,将增强应用到每对图像和蒙版中。最后返回批处理(X,y),它已准备好安装到网络中。

def __getitem__(self, index):
      data_index_min = int(index*self.batch_size)
      data_index_max = int(min((index+1)*self.batch_size, len(self.image_filenames)))
 
      indexes = self.image_filenames[data_index_min:data_index_max]
      this_batch_size = len(indexes) # The last batch can be smaller than the others
 
      X = np.empty((this_batch_size, self.image_size, self.image_size, 3), dtype=np.float32)
      y = np.empty((this_batch_size, self.image_size, self.image_size, self.nb_y_features), dtype=np.uint8)
 
      for i, sample_index in enumerate(indexes):
 
          X_sample, y_sample = self.read_image_mask(self.image_filenames[index * self.batch_size + i],
                                                  self.mask_names[index * self.batch_size + i])
 
          # if augmentation is defined, we assume its a train set
          if self.augmentation is not None:
 
              # Augmentation code
              augmented = self.augmentation(self.image_size)(image=X_sample, mask=y_sample)
              image_augm = augmented['image']
              mask_augm = augmented['mask'].reshape(self.image_size, self.image_size, self.nb_y_features)
              # divide by 255 to normalize images from 0 to 1
              X[i, ...] = image_augm/255
              y[i, ...] = mask_augm
          else:
              ...
  return X, y

接下来,定义生成器,它们将被送入网络:

test_generator = DataGeneratorFolder(root_dir = './data/road_segmentation_ideal/training',
                           image_folder = 'input/',
                           mask_folder = 'output/',
                           nb_y_features = 1)
 
train_generator = DataGeneratorFolder(root_dir = './data/road_segmentation_ideal/training',
                                      image_folder = 'input/',
                                      mask_folder = 'output/',
                                      batch_size=4,
                                      image_size=512,
                                      nb_y_features = 1, augmentation = aug_with_crop)

数据增强- albumentations

数据增强是一种策略,可以显着增加可用于训练模型的数据的多样性,而无需实际收集新数据。它有助于防止过度拟合并使模型更加健壮。

有很多用于此类任务的库:imaging,augmentor,solt,keras / pytorch的内置方法,或者可以使用OpenCV库编写自定义扩充。但我强烈推荐albumentations库。它使用起来非常快速和方便。有关用法示例,请访问官方存储库或查看示例笔记本。

https://github.com/albu/albumentations

https://github.com/albu/albumentations/tree/master/notebooks

在任务中,将使用基本的扩充,例如翻转和对比与非平凡的ElasticTransform。可以在上图中的示例。

def aug_with_crop(image_size = 256, crop_prob = 1):
    return Compose([
        RandomCrop(width = image_size, height = image_size, p=crop_prob),
        HorizontalFlip(p=0.5),
        VerticalFlip(p=0.5),
        RandomRotate90(p=0.5),
        Transpose(p=0.5),
        ShiftScaleRotate(shift_limit=0.01, scale_limit=0.04, rotate_limit=0, p=0.25),
        RandomBrightnessContrast(p=0.5),
        RandomGamma(p=0.25),
        IAAEmboss(p=0.25),
        Blur(p=0.01, blur_limit = 3),
        OneOf([
            ElasticTransform(p=0.5, alpha=120, sigma=120 * 0.05, alpha_affine=120 * 0.03),
            GridDistortion(p=0.5),
            OpticalDistortion(p=1, distort_limit=2, shift_limit=0.5)                  
        ], p=0.8)
], p = 1)

定义所需的扩充后,可以轻松获得输出:

augmented = aug_with_crop(image_size = 1024)(image=img, mask=mask)
image_aug = augmented['image']
mask_aug = augmented['mask']

回调

将使用常见的回调:

  • ModelCheckpoint - 允许在训练时保存模型的权重
  • ReduceLROnPlateau - 如果验证指标停止增加,则减少训练
  • EarlyStopping - 一旦验证指标停止增加几个时期,就停止训练
  • TensorBoard - 监控训练进度的好方法。链接到官方文档

https://www.tensorflow.org/tensorboard/r2/scalars_and_keras

from keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping, TensorBoard
 
# reduces learning rate on plateau
lr_reducer = ReduceLROnPlateau(factor=0.1,
                               cooldown= 10,
                               patience=10,verbose =1,
                               min_lr=0.1e-5)
# model autosave callbacks
mode_autosave = ModelCheckpoint("./weights/road_crop.efficientnetb0imgsize.h5",
                                monitor='val_iou_score',
                                mode='max', save_best_only=True, verbose=1, period=10)
 
# stop learining as metric on validatopn stop increasing
early_stopping = EarlyStopping(patience=10, verbose=1, mode = 'auto')
 
# tensorboard for monitoring logs
tensorboard = TensorBoard(log_dir='./logs/tenboard', histogram_freq=0,
                          write_graph=True, write_images=False)
 
callbacks = [mode_autosave, lr_reducer, tensorboard, early_stopping]

训练

作为模型,将使用Unet。最简单的使用方法是从segmentation_models库中获取。

https://github.com/qubvel/segmentation_models

  • backbone_name:用作编码器的分类模型的名称。EfficientNet目前在分类模型中是最先进的,所以尝试一下。虽然它应该提供更快的推理并且具有更少的训练参数,但它比着名的resnet模型消耗更多的GPU内存。还有很多其他选择可供尝试
  • encoder_weights - 使用imagenet权重加速训练
  • encoder_freeze:如果为True,则将编码器(骨干模型)的所有层设置为不可训练的。首先冻结和训练模型然后解冻可能是有用的
  • decoder_filters - 可以指定解码器块的数量。在某些情况下,具有简化解码器的较重编码器可能是有用的。

初始化Unet模型后,应该编译它。此外将IOU(交叉联合)设置为将监控的度量和bce_jaccard_loss(二进制交叉熵加jaccard损失)作为将优化的损失。

model = Unet(backbone_name = 'efficientnetb0', encoder_weights='imagenet', encoder_freeze = False)
model.compile(optimizer = Adam(), loss=bce_jaccard_loss, metrics=[iou_score])
 
history = model.fit_generator(train_generator, shuffle =True,
                  epochs=50, workers=4, use_multiprocessing=True,
                  validation_data = test_generator,
                  verbose = 1, callbacks=callbacks)

开始训练后,可以查看张量板日志。可以很好地看到模型训练,即使在50个时代之后也没有达到全球/地方的最佳状态。

Tensorboard日志

损失和IOU指标历史记录

推理

因此在验证时有0.558 IOU,但是每个像素预测都高于0,将其视为掩码。通过选择适当的阈值,可以进一步将结果提高0.039(7%)。

验证阈值调整

度量标准确实非常有趣,但更具洞察力的模型预测。从下面的图片中看到网络很好地完成了任务,这很棒。对于推理代码和计算指标,可以阅读完整代码。

https://github.com/Diyago/ML-DL-scripts/tree/master/DEEP%20LEARNING/segmentation/Segmentation%20pipeline

本文分享自微信公众号 - 相约机器人(xiangyuejiqiren),作者:代码医生

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 基于TensorFlow Eager Execution的简单神经网络模型

    Eager Execution是TensorFlow(TF)中一种从头开始构建深度学习模型的好方法。它允许您构建原型模型,而不会出现TF常规使用的图形方法所带来...

    代码医生工作室
  • Auto-Tinder-训练AI玩打火机刷卡游戏

    Auto Tinder是一个纯粹出于娱乐和教育目的而创建的概念项目。绝不能滥用它来伤害任何人或向平台发送垃圾邮件。自动绑定脚本不应与您的绑定文件一起使用,因为它...

    代码医生工作室
  • 使用CNN和PyTorch进行面部关键点检测

    面部关键点也称为面部地标,通常指定面部的鼻子,眼睛,嘴巴等区域,该面部按68个关键点分类,并带有该坐标的坐标(x,y)。使用面部关键点,可以实现面部识别,情绪识...

    代码医生工作室
  • qemu-guest-agent原理及实践

    QEMU Guest Agent是运行在虚拟机内部的一个守护程序(qemu-guest-agent.service),用它来辅助Hypervisor实现对Gue...

    虚拟化云计算
  • <技术贴>当图虫遇到爬虫...根据”分类名称”,获取json数据根据json数据,获取图集url与title爬虫架构:运行界面:最终效果

    首先,图虫网是一个很棒的图片网站,这里的爬虫只是为了研究技术,请读者朋友们,不要大量采集网站信息,爬取的图片,请取得版权后再使用... ? 图虫网 根据”分类...

    zhaoolee
  • 在 Google Colab 中快速实践深度学习

    Colaboratory 是一个免费的 Jupyter 笔记本环境,不需要进行任何设置就可以使用,并且完全在云端运行。借助 Colaboratory,我们可以在...

    王下邀月熊
  • 因为有你,所以成功---红帽云套件合作伙伴招募回顾

    前言:昨天下午(11月29日),红帽举办了云套件合作伙伴(BP)招募会。会上,红帽几位架构分享了云套件解决方案以及销售方法。合作伙伴们也踊跃提出了疑问和见解,大...

    魏新宇
  • 工具篇 | “手把手教你搭建一个全能的学习环境(包括但不限于Python)”

    最近有读者问我关于自学使用的开发环境搭建的问题。所以特意在这里发一篇我本人为了学习和个人开发使用的环境。其实之前也讨论过相关的内容,只不过涉及的很浅。

    LogicPanda
  • 链表(上):如何实现LRU缓存淘汰算法?

    这些策略你不用死记,我打个比方你很容易就明白了。假如说,你买了很多本技术书,但有一天你发现,这些书太多了,太占书房空间了,你要做个大扫除,扔掉一些书籍。那这个时...

    Jingbin
  • APICloud开发者进阶之路|[ APP开发技巧 ] Db模块操作封装JS类,超级好用。带错误提示

    APICloud

扫码关注云+社区

领取腾讯云代金券