热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[论文理解]Whydodeepconvolutionalnetworksgeneralizesopoorlytosmallimagetransformations?

Whydodeepconvolutionalnetworksgeneralizesopoorlytosmallimagetransformations?IntroCNN的设计初衷是

Why do deep convolutional networks generalize so poorly to small image transformations?

Intro

CNN的设计初衷是为了使得模型具有微小平移、旋转不变性,而实际上本文通过实验验证了现在比较流行的神经网络都已经丧失了这样的能力,甚至图像只水平移动一个像素,预测的结果都将会发生很大的变化。之所以如此,作者认为CNN的下采样背离了隆奎斯特采样定理,就连augmentation也并不能缓解微小变化不变性的丧失。


Ignoring the Sampling Theorem



  1. 随机crop一张图然后resize,平移一个像素

  2. 原图rescale黑色填充背景,平移一个像素

  3. 原图rescale下方插值,平移一个像素

  4. 原图rescale,rescale相差一个像素值

结果如图,对人而言是看不出来什么区别的,但是网络的预测结果却明显不同。

仅仅这么一个微小变化,使得网络的输出发生这么大的变化,这显然是很不合理的,因此作者认为有下面的解释。

作者认为之所以CNN丧失了平移不变性是因为现在CNN的设计忽略了采样定理,也就是奈奎斯特采样定理。作者认为,CNN中的下采样操作,如stride 2 conv和pooling,由于采样频率没满足大于等于两倍的最高频,所以会导致微小形变不变性的丧失。

如何理解?

上图我做了三个实验,分别是原图、pooling后的图、conv2d(stride=4)后的图,下面是对应的频谱图。可以看出来,pooling、conv下采样层都是保留高频部分,丢弃低频部分。

可见,pooling层和conv层所做的下采样都是保留高频,丢弃低频成分。因此信号的频率都是高频,而采样频率是和stride相关的,可以理解为每隔多少像素采样一次,因此如果stride太大,采样频率就会过小,这样就不满足采样定理了。

import cv2
import numpy as np
import matplotlib.pyplot as plt
import skimage.measure
import torch
import torch.nn as nn
import torch.nn.functional as F
class FFT(object):
def __init__(self):
pass
def __call__(self,x):
f = np.fft.fft2(x)
fshift = np.fft.fftshift(f)
s1 = np.log(np.abs(fshift))
return s1
@staticmethod
def pooling(feature_map,kernel_size= 2):
inpt = torch.tensor(feature_map[np.newaxis,np.newaxis,:,:],dtype = torch.float32)

out = F.max_pool2d(inpt,kernel_size = kernel_size)

return out.numpy()[0,0,:,:]
#return skimage.measure.block_reduce(feature_map, (kernel_size,kernel_size), np.max)
@staticmethod
def conv2d(feature_map,kernel_size= 2,stride = 1):
inpt = torch.tensor(feature_map[np.newaxis,np.newaxis,:,:],dtype = torch.float32)
kernel = torch.ones((1,1,kernel_size,kernel_size)) / kernel_size
out = F.conv2d(inpt,weight = kernel,stride = stride)
return out.numpy()[0,0,:,:]

if __name__ == "__main__":
fft = FFT()
img = cv2.imread('/home/xueaoru/图片/test002.jpg', 0)
img2 = fft.pooling(img,4)
img3 = fft.conv2d(img,kernel_size = 5,stride = 4)
s1 = fft(img)
s2 = fft(img2)
s3 = fft(img3)
plt.subplot(231)
plt.imshow(img, 'gray')
plt.title('original')
plt.subplot(232)
plt.imshow(img2, 'gray')
plt.title('original2')
plt.subplot(233)
plt.imshow(img3, 'gray')
plt.title('original3')
plt.subplot(234)
plt.imshow(s1,'gray')
plt.title('center1')
plt.subplot(235)
plt.imshow(s2,'gray')
plt.title('center2')
plt.subplot(236)
plt.imshow(s3,'gray')
plt.title('center3')
plt.show()

此外,作者还说明了一件事:

网络越深,微小形变不变性丧失的越严重。上图可以看出vgg16比较浅,还看不出什么变化,但是resnet50已经丧失很多了,densenet201也是一样。


Why don't modern CNNs learn to be invariant from data?

我们训练之前一般会做很多image augmentation的,但是呢,为什么image augmentation也没能缓解平移不变性的丧失呢?

一个简单的回答就是网络学习到一种简单的判别函数,使得网络对训练集的图片的变换具有微小形变不变性,而对于测试集或者说没见过的数据的微小形变不具有不变性。这称为dataset bias。

上图是imagenet上训练集里狗的眼睛距离的统计结果,也就是说,一般情况下狗的眼睛肯定在这个range内,网络可以work,然是测试数据的眼睛距离如果不在这个range内的话,网络也许就不work了,因此要求网络学习到这个range之外的数据是很难的,虽然image augmentation有所帮助,但其实很难泛化到所有情况,特别是测试集和训练集不是同一分布的时候。


Possible Solutions



  1. 将下采样替换为:stride 1 maxpooling + stride 2 conv.也就是采样之前先blur,但是对于大数据效果甚微。

  2. data augmentation:多增加额外的augmentation。

  3. 减少二次采样操作:二次采样会导致可能不满足采样定律,所以减少二次采样可以保持不变性。



推荐阅读
  • 本文讨论了如何使用GStreamer来删除H264格式视频文件中的中间部分,而不需要进行重编码。作者提出了使用gst_element_seek(...)函数来实现这个目标的思路,并提到遇到了一个解决不了的BUG。文章还列举了8个解决方案,希望能够得到更好的思路。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • 本文介绍了机器学习手册中关于日期和时区操作的重要性以及其在实际应用中的作用。文章以一个故事为背景,描述了学童们面对老先生的教导时的反应,以及上官如在这个过程中的表现。同时,文章也提到了顾慎为对上官如的恨意以及他们之间的矛盾源于早年的结局。最后,文章强调了日期和时区操作在机器学习中的重要性,并指出了其在实际应用中的作用和意义。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 本文介绍了在iOS开发中使用UITextField实现字符限制的方法,包括利用代理方法和使用BNTextField-Limit库的实现策略。通过这些方法,开发者可以方便地限制UITextField的字符个数和输入规则。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
author-avatar
mobiledu2502869603
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有