计算机视觉的自动编码器:无限可能的世界

介绍

大家好,在过去的几个月中,我致力于计算机视觉自动编码器 的开发,坦白地说,我对使用它们可以构建的大量应用程序印象深刻。

本文的目的是解释自动编码器,可以使用自动编码器构建的一些应用程序,未连接的编码器-解码器层的缺点以及诸如U-Net之类的体系结构如何帮助提高自动编码器的质量。

1. 什么是自动编码器?

简单来说,自动编码器是一种顺序神经网络,由两个组件组成,一个是编码器,另一个是**解码器。**供我们参考,假设我们正在处理图像,**编码器的工作是从图像中提取特征,从而减小图像的高度和宽度,但同时增加其深度,**即编码器对图像进行了潜在表示。现在,解码器的工作是解码潜在表示并形成满足我们给定标准的图像。从下面的图像中可以很容易理解。

图1:自动编码器架构

自动编码器的输入和输出都是图像,在下面给出的示例中,自动编码器将输入转换为Monet样式的绘画。

图2:自动编码器的输入和输出

2. 自动编码器,用于语义分割和未连接的编码器-解码器层的缺点

语义分割是指为图像的每个像素分配标签,从而将属于同一对象的像素分组在一起,以下图像将帮助你更好地理解这一点。

图3:图像及其语义分割输出

以下代码定义了用于此应用程序的自动编码器体系结构:

myTransformer = tf.keras.models.Sequential([
## defining encoder 
    tf.keras.layers.Input(shape= (256, 256, 3)),
    tf.keras.layers.Conv2D(filters = 16, kernel_size = (3,3), activation = 'relu', padding = 'same'),
    tf.keras.layers.MaxPool2D(pool_size = (2, 2)),
    tf.keras.layers.Conv2D(filters = 32, kernel_size = (3,3), strides = (2,2), activation = 'relu',
    padding = 'valid'),
    tf.keras.layers.Conv2D(filters = 64, kernel_size = (3,3), strides = (2,2), activation = 'relu',
    padding = 'same'),
    tf.keras.layers.MaxPool2D(pool_size = (2, 2)),
    tf.keras.layers.Conv2D(filters = 64, kernel_size = (3,3), activation = 'relu', padding = 'same'),
    tf.keras.layers.Conv2D(filters = 128, kernel_size = (3,3), activation = 'relu', padding = 'same'),
    tf.keras.layers.Conv2D(filters = 128, kernel_size = (3,3), activation = 'relu', padding = 'same'),
    tf.keras.layers.Conv2D(filters = 256, kernel_size = (3,3), activation = 'relu', padding = 'same'),
    tf.keras.layers.Conv2D(filters = 512, kernel_size = (3,3), activation = 'relu', padding = 'same'),
    ## defining decoder path
    tf.keras.layers.UpSampling2D(size = (2,2)),
    tf.keras.layers.Conv2D(filters = 256, kernel_size = (3,3), activation = 'relu', padding = 'same'),
    tf.keras.layers.Conv2D(filters = 128, kernel_size = (3,3), activation = 'relu', padding = 'same'),
    tf.keras.layers.Conv2D(filters = 128, kernel_size = (3,3), activation = 'relu', padding = 'same'),
    tf.keras.layers.Conv2D(filters = 128, kernel_size = (3,3), activation = 'relu', padding = 'same'),
    tf.keras.layers.UpSampling2D(size = (2,2)),
    tf.keras.layers.Conv2D(filters = 64, kernel_size = (3,3), activation = 'relu', padding = 'same'),
    tf.keras.layers.UpSampling2D(size = (2,2)),
    tf.keras.layers.Conv2D(filters = 32, kernel_size = (3,3), activation = 'relu', padding = 'same'),
    tf.keras.layers.UpSampling2D(size = (2,2)),
    tf.keras.layers.Conv2D(filters = 16, kernel_size = (3,3), activation = 'relu', padding = 'same'),
    tf.keras.layers.Conv2D(filters = 3, kernel_size = (3,3), activation = 'relu', padding = 'same'),
])

请参考本文的参考部分以获取完整的训练渠道。以下是你使用此网络可获得的结果

图4:用于语义分割的自动编码器结果

很好,看来我们的自动编码器可以很好地解决此问题,但是,你是否觉得所获得的结果有点模糊,可能出了什么问题?

2.1 自动编码器中未连接的编码器-解码器层的缺点

这种模糊性的原因在于**,**即使我们可以实现目标,但输出质量还不够好。因此,当信息从编码器传递到解码器时,功能映射就会丢失。因此,最合乎逻辑的方法是将解码器层与编码器层中的对应层连接起来,从而补偿重建图像时丢失的特征,这就是像U-Net这样的体系结构。从下图可以更好地理解这一点:

图5:Unet体系结构

看一下解码器和编码器层之间的互连,它们使像U-Net这样的体系结构优于原始自动编码器。

如此说来,让我们讨论一些可以使用UNet构建的实际应用程序。

3. 自动编码器的一些实际应用

3.1 通过预测相关掩码进行图像分割

这是你遇到的另一个分割问题,与上述示例不同。给定一幅图像,将要求你为图像中的目标物体预测一个二进制掩码,当你将此预测掩码与给定图像相乘时,你将获得目标图像。

此类预测模型可用于查找肾脏中癌细胞或结石的位置。因为一张图片的价值胜过千言万语,这里有一张图片可以说明我所说的:

图6:实际的分割

这是定义所用模型架构的代码。

# defining Conv2d block for our u-net
# this block essentially performs 2 convolution
def Conv2dBlock(inputTensor, numFilters, kernelSize = 3, doBatchNorm = True):
    #first Conv
    x = tf.keras.layers.Conv2D(filters = numFilters, kernel_size = (kernelSize, kernelSize),
                              kernel_initializer = 'he_normal', padding = 'same') (inputTensor)
    if doBatchNorm:
        x = tf.keras.layers.BatchNormalization()(x)
    x =tf.keras.layers.Activation('relu')(x)
    #Second Conv
    x = tf.keras.layers.Conv2D(filters = numFilters, kernel_size = (kernelSize, kernelSize),
                              kernel_initializer = 'he_normal', padding = 'same') (x)
    if doBatchNorm:
        x = tf.keras.layers.BatchNormalization()(x)
    x = tf.keras.layers.Activation('relu')(x)
    return x

# Now defining Unet 
def GiveMeUnet(inputImage, numFilters = 16, droupouts = 0.1, doBatchNorm = True):
    # defining encoder Path
    c1 = Conv2dBlock(inputImage, numFilters * 1, kernelSize = 3, doBatchNorm = doBatchNorm)
    p1 = tf.keras.layers.MaxPooling2D((2,2))(c1)
    p1 = tf.keras.layers.Dropout(droupouts)(p1)
    c2 = Conv2dBlock(p1, numFilters * 2, kernelSize = 3, doBatchNorm = doBatchNorm)
    p2 = tf.keras.layers.MaxPooling2D((2,2))(c2)
    p2 = tf.keras.layers.Dropout(droupouts)(p2)
    c3 = Conv2dBlock(p2, numFilters * 4, kernelSize = 3, doBatchNorm = doBatchNorm)
    p3 = tf.keras.layers.MaxPooling2D((2,2))(c3)
    p3 = tf.keras.layers.Dropout(droupouts)(p3)
    c4 = Conv2dBlock(p3, numFilters * 8, kernelSize = 3, doBatchNorm = doBatchNorm)
    p4 = tf.keras.layers.MaxPooling2D((2,2))(c4)
    p4 = tf.keras.layers.Dropout(droupouts)(p4)
    c5 = Conv2dBlock(p4, numFilters * 16, kernelSize = 3, doBatchNorm = doBatchNorm)
    # defining decoder path
    u6 = tf.keras.layers.Conv2DTranspose(numFilters*8, (3, 3), strides = (2, 2), padding = 'same')(c5)
    u6 = tf.keras.layers.concatenate([u6, c4])
    u6 = tf.keras.layers.Dropout(droupouts)(u6)
    c6 = Conv2dBlock(u6, numFilters * 8, kernelSize = 3, doBatchNorm = doBatchNorm)
    u7 = tf.keras.layers.Conv2DTranspose(numFilters*4, (3, 3), strides = (2, 2), padding = 'same')(c6)
    u7 = tf.keras.layers.concatenate([u7, c3])
    u7 = tf.keras.layers.Dropout(droupouts)(u7)
    c7 = Conv2dBlock(u7, numFilters * 4, kernelSize = 3, doBatchNorm = doBatchNorm)
    u8 = tf.keras.layers.Conv2DTranspose(numFilters*2, (3, 3), strides = (2, 2), padding = 'same')(c7)
    u8 = tf.keras.layers.concatenate([u8, c2])
    u8 = tf.keras.layers.Dropout(droupouts)(u8)
    c8 = Conv2dBlock(u8, numFilters * 2, kernelSize = 3, doBatchNorm = doBatchNorm)
    u9 = tf.keras.layers.Conv2DTranspose(numFilters*1, (3, 3), strides = (2, 2), padding = 'same')(c8)
    u9 = tf.keras.layers.concatenate([u9, c1])
    u9 = tf.keras.layers.Dropout(droupouts)(u9)
    c9 = Conv2dBlock(u9, numFilters * 1, kernelSize = 3, doBatchNorm = doBatchNorm)
    output = tf.keras.layers.Conv2D(1, (1, 1), activation = 'sigmoid')(c9)
    model = tf.keras.Model(inputs = [inputImage], outputs = [output])
    return model

请参考本文的参考部分以了解整个训练流程。

3.2 根据卫星图像预测路线图

你可以将上述架构应用于在卫星图像中查找道路,因为如果你想到这一点,那么这又是一个分割问题,使用适当的数据集就可以轻松实现此任务。与往常一样,这是一个显示此概念的图像。

图7:根据航拍图像预测路线

与往常一样,你可以在“参考”部分中找到代码。

3.3 使用自动编码器实现超分辨率

你是否曾在放大低分辨率图像时注意到发生的像素失真?超分辨率本质上是指提高低分辨率图像的分辨率。现在,也可以仅通过对图像进行上采样并使用双线性插值法来填充新的像素值来实现此目的,但是由于你无法增加图像中的信息量,因此生成的图像将变得模糊

为了解决这个问题,我们教了一个神经网络来预测高分辨率图像的像素值(**本质上是增加信息)。**你可以使用自动编码器来实现这一点(这就是本文标题为“无限可能的世界”的原因!)。

你只需在模型的输出层中将通道数更改为3(而不是1),就可以对上述体系结构进行一些小的更改。这里有几个结果:

结论

这些只是我设法使用自动编码器构建的一些应用程序,但可能性是无限的,因此,我建议读者充分发挥自己的创造力,并找到更好的自动编码器用途。谢谢。

参考

1.) Vanilla AutoEncoder

  • https://www.kaggle.com/vanvalkenberg/image-segmentation-using-encoder-decoder-networks

2.) UNet Code and  Binary Segmentation

  • https://www.kaggle.com/vanvalkenberg/coding-u-net-for-image-segmentation

3.) UNet for Road map generation from aerial Images.

  • https://www.kaggle.com/vanvalkenberg/road-maps-from-aerial-images

4.) Super Resolution

  • https://www.kaggle.com/vanvalkenberg/super-resolution-low-res-to-high-res-images

☆ END ☆

如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「uncle_pn」,欢迎添加小编微信「 mthler」,每日朋友圈更新一篇高质量博文。

扫描二维码添加小编↓

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【为什么需要学习计算机视觉?】 计算机视觉是当代人工智能中最活跃的领域,贡献了超过40%的应用及近半数的人工智能从业者。课程结合视觉基本原理及实战,介绍图像和视觉处理的基本知识和相关应用,包括视觉系统构成,图像处理基础,特征提取与描述,运动跟踪,位姿估计,三维重构等内容。课程理论与实战结合,注重教学内容的可视化和工程实践,为人工智能视觉研发及算法工程师等相关高薪职位就业打下坚实基础。 图像处理和计算机视觉的课程大家已经看过很多,但总有“听不透”,“用不了”的感觉。课程致力于创建人人都能听的懂的计算机视觉,通过生动、细腻的讲解配合实战演练,让学生真正学懂、用会。 【超实用课程内容】 课程内容分为三篇,包括图像处理基础,视觉环境搭建,特征提取与描述、生成对抗网络等内容。课程理论与实战结合,注重教学内容的可视化和工程实践,为人工智能视觉研发及算法工程师等相关高薪职位就业打下坚实基础。 【课程如何观看?】 移动端:CSDN 学院APP(注意不是CSDN APP哦) 本课程为录播课,课程永久有效观看时长,但是大家可以抓紧时间学习后一起讨论哦~ 【学员专享增值服务】 源码开放 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化 下载方式:电脑登录播放页面点击右方课件打包下载

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值