给出代码地址:https://github.com/kastnerkyle/deform-conv,keras版本的。

可以直接看目录scripts下的scaled_mnist.py,网络模型由函数get_deform_cnn()加载:

# ---
# Deformable CNNinputs, outputs = get_deform_cnn(trainable=False)
model = Model(inputs=inputs, outputs=outputs)

get_deform_cnn()定义在目录deform_conv下的cnn.py中,整体就是一个普通的cnn网络,只不过卷积前加了ConvOfffset2D:

def get_deform_cnn(trainable):inputs = l = Input((28, 28, 1), name='input')# conv11l = Conv2D(32, (3, 3), padding='same', name='conv11', trainable=trainable)(l)l = Activation('relu', name='conv11_relu')(l)l = BatchNormalization(name='conv11_bn')(l)# conv12l_offset = ConvOffset2D(32, name='conv12_offset')(l)l = Conv2D(64, (3, 3), padding='same', strides=(2, 2), name='conv12', trainable=trainable)(l_offset)l = Activation('relu', name='conv12_relu')(l)l = BatchNormalization(name='conv12_bn')(l)...return inputs, outputs

上面代码中由ConvOffset2D得到的l_offset应该是偏移/形变后的feature maps,因为紧接着Conv2D的输入就是l_offset,接下来看一下ConvOffset2D类的定义(ConvOffset2D类在deform_conv目录下的layers.py中):

class ConvOffset2D(Conv2D):"""ConvOffset2D"""def __init__(self, filters, init_normal_stddev=0.01, **kwargs):"""Init"""self.filters = filterssuper(ConvOffset2D, self).__init__(self.filters * 2, (3, 3), padding='same', use_bias=False,# TODO gradients are near zero if init is zeroskernel_initializer='zeros',# kernel_initializer=RandomNormal(0, init_normal_stddev),**kwargs)def call(self, x):# TODO offsets probably have no nonlinearity?x_shape = x.get_shape()offsets = super(ConvOffset2D, self).call(x)offsets = self._to_bc_h_w_2(offsets, x_shape)x = self._to_bc_h_w(x, x_shape)x_offset = tf_batch_map_offsets(x, offsets)x_offset = self._to_b_h_w_c(x_offset, x_shape)return x_offset

首先该类是Conv2D的子类,然后调用了父类的构造函数:参数filters改为2*self.filters,卷积核大小为(3, 3),padding=‘same'。构造器所作的是利用keras.layers自带的Conv2D卷积得到每一个feature map的每一个pixel的横纵偏移量,因此改卷积的filters的数量变成了2倍,因为每一个输入的feature map会产生两个feature maps输出,分别表示输入的feature map中每一个pixel在横,纵坐标上的偏移量。并且,该卷积输出的feature maps必须和输入同尺寸,因为对应每一个pixel,所以卷积核固定为(3,3),同时padding=’same‘。

然后把该ConvOffset2D类的对象直接像函数一样调用时,就相当于执行了call()方法,在call()方法中,调用父类的call()方法输入feature maps得到偏移量,通过self._to_bc_h_w_2()改变offsets维度到(b*c, h, w, 2),然后改变feature maps维度到(b*c, h, w),然后利用tf_batch_map_offsets()得到偏移后的feature maps,最后再通过self._to_b_h_w_c()恢复用于卷积的维度(b, h, w, c)。tf_batch_map_offsets()的代码如下(定义于目录deform_conv下的deform_conv.py文件中):

def tf_batch_map_offsets(input, offsets, order=1):"""Batch map offsets into inputParameters---------input : tf.Tensor. shape = (b, s, s)offsets: tf.Tensor. shape = (b, s, s, 2)"""input_shape = tf.shape(input)batch_size = input_shape[0]input_size = input_shape[1]offsets = tf.reshape(offsets, (batch_size, -1, 2))grid = tf.meshgrid(tf.range(input_size), tf.range(input_size), indexing='ij')grid = tf.stack(grid, axis=-1)grid = tf.cast(grid, 'float32')grid = tf.reshape(grid, (-1, 2))grid = tf_repeat_2d(grid, batch_size)coords = offsets + gridmapped_vals = tf_batch_map_coordinates(input, coords)return mapped_vals

通过meshgrid得到网格坐标,加上偏移坐标就是偏移后的feature maps坐标对应值,只要把原feature maps的值映射过来就好(就是最后一步的tf_batch_map_coordinates)。

最后使用形变卷积的时候,ConvOffset2D的参数filter要注意,应该是上一个卷积的filters的数量,如下所示:

inputs = Input((48,48,1))
x = ConvOffset2D(1)(inputs)
x = Conv2D(16, (5,5), activation='relu')(x)
x = BatchNormalization()(x)
x = ConvOffset2D(16)(x)
x = Conv2D(16, (5,5), activation='relu')(x)
x = BatchNormalization()(x)
x = MaxPooling2D((2,2))(x)
x = ConvOffset2D(16)(x)
x = Conv2D(32, (5,5), activation='relu')(x)
x = BatchNormalization()(x)
x = ConvOffset2D(32)(x)
x = Conv2D(32, (5,5), activation='relu')(x)

卷积系列——形变卷积(Deformable convolution)代码理解和使用相关推荐

  1. Deformable Convolution Networks

    Deformable Convolution Networks 论文链接 1.双线性插值原理 由于可形变卷积在获取偏移位置像素点时候,需要用到双线性插值,所以我就把它先放到上面,并附上参考链接: 参考 ...

  2. Deep Learning论文笔记之(五)CNN卷积神经网络代码理解

    Deep Learning论文笔记之(五)CNN卷积神经网络代码理解 zouxy09@qq.com http://blog.csdn.net/zouxy09          自己平时看了一些论文,但 ...

  3. 深度学习之 DCN(Deformable Convolution)-可变形卷积

    Paper link: http://openaccess.thecvf.com/content_ICCV_2017/papers/Dai_Deformable_Convolutional_Netwo ...

  4. 输出分组_通过分组卷积的思想,巧妙的代码实现动态卷积(Dynamic Convolution)

    论文的题目为<Dynamic Convolution: Attention over Convolution Kernels> paper的地址https://arxiv.org/pdf/ ...

  5. 可变形卷积系列(三) Deformable Kernels,创意满满的可变形卷积核 | ICLR 2020

    论文提出可变形卷积核(DK)来自适应有效感受域,每次进行卷积操作时都从原卷积中采样出新卷积,是一种新颖的可变形卷积的形式,从实验来看,是之前方法的一种有力的补充.   来源:晓飞的算法工程笔记 公众号 ...

  6. 空洞卷积(扩张卷积,带孔卷积,atrous convolution)的一些总结与理解

    空洞卷积(扩张卷积,带孔卷积,atrous convolution)是一种区别于普通卷积的卷积方式,从字面理解,就是卷积层中有洞. 1.一维理解 以一维为例: 图中(a)Input feature表示 ...

  7. 可变形卷积(Deformable Convolution)

    可变形卷积 前言: 一.可变形卷积 1.原文摘要(Abstract) 2.可变形卷积 前言: 之前分了两次将深度学习中常用的各种卷积操作进行了汇总介绍,具体包括标准2D卷积.1×1卷积.转置卷积.膨胀 ...

  8. Deformable Convolution 可变形卷积

      可变形卷积概念出自2017年论文:Deformable Convolutional Networks   顾名思义,可变形卷积的是相对于标准卷积的概念而来. (a) 一个经典的 3×33 \tim ...

  9. [论文理解](未完成)形变卷积网络Warped Convolutions: Efficient Invariance to Spatial Transformations

    1.几个问题 1.1 基本信息 PMLR 2017 1.2 做了什么 将群卷积转换为了标准卷积,只要先对图像和卷积核进行某个特殊的预处理. 1.3 实现方法 将群卷积扩展到连续空间,然后将群G限制为指 ...

最新文章

  1. ios 常见性能优化
  2. 面向生信分析的高性 RStudio 服务器
  3. SpaceVim的配置+ e121:undefined variable:g:spacevim global config path
  4. Visual Studio 2008 当页面进行调试时,IE8浏览器显示的是空白页面?
  5. 利用UltraEdit将十六进制转换成ASCII 字符串(调试查看内存有用哦)
  6. 忍辱负重的小白兔们 - 验收准则的意义
  7. PHP+jquery 树状菜单
  8. 在PDA设备上安装和部署 SQL Server Compac 3.5(官方版)
  9. VXLAN Ethernet Virtual Private Network集中式和分布式网关实验(华为设备)
  10. webpack-md5-hash问题记录
  11. 42. Element hasChildNodes() 方法
  12. LINUX编译OPENJDK:unsupported cpu xxx
  13. 确定有限自动机DFA
  14. python求学生成绩平均值_Python学习心得2:求平均值
  15. python实现C4.5
  16. matlab在常微分方程的应用,MATLAB在求解常微分方程中的应用
  17. Win10系统更新后开机密码错误怎么解决?
  18. alpinestars与丹尼斯_丹尼斯 VS A星,两虎相争骑士得利
  19. Mybatis系列全解(五):全网最全!详解Mybatis的Mapper映射文件
  20. 河南单招计算机专业专科学校排名2015,河南省单招大专学校排名榜 哪个学校好...

热门文章

  1. 在C程序中显示八进制数前缀0和十六进制前缀0x
  2. Shader学习17——序列帧动画
  3. Au:轨道种类及操作基础
  4. pc端引入微信公众号文章
  5. 手机信息备份和恢复系统
  6. [信息学奥赛一本通][POJ 2251]地牢大师
  7. 计算机word打不原因什么意思,电脑上Word无法进行打印的原因分析和解决方法
  8. 星星之火-43:无线通信中复用技术的物理原理---空间复用、时分多址TDM、频分复用FDM、正交频分复用OFDM、空分复用MIMO、码分复用CDM
  9. 华为桌面计算机丢了,电脑数据丢失怎么办?手把手教你如何恢复删除的文件
  10. SAP GRC – 企业风险合规治理 深入浅出