参考

https://cv-tricks.com/image-segmentation/transpose-convolution-in-tensorflow/

https://zhuanlan.zhihu.com/p/32414293

目标

现在我们要将3×6的图象转变为6×12的图象,即已知upscale_factor=2。

目标结果:

align_corners=True

align_corners=False


1. 计算卷积核大小

bilinear = get_bilinear_filter([4,4,1,1,],2)
print(bilinear)
array([[ 0.0625,  0.1875,  0.1875,  0.0625],[ 0.1875,  0.5625,  0.5625,  0.1875],[ 0.1875,  0.5625,  0.5625,  0.1875],[ 0.0625,  0.1875,  0.1875,  0.0625]])

filter_shape是卷积核的形状,由
kernel_size=2∗upscale_factor−upscale_factor%2kernel\_size = 2*upscale\_factor - upscale\_factor\%2kernel_size=2∗upscale_factor−upscale_factor%2
计算得到,filter_shape=[4,4,1,1]。

import numpy as np
def get_bilinear_filter(filter_shape, upscale_factor):##filter_shape is [width, height, num_in_channels, num_out_channels]kernel_size = 2*upscale_factor - upscale_factor%2### Centre location of the filter for which value is calculatedif kernel_size % 2 == 1:centre_location = upscale_factor - 1else:centre_location = upscale_factor - 0.5bilinear = np.zeros([filter_shape[0], filter_shape[1]], dtype='float32')for x in range(filter_shape[0]):for y in range(filter_shape[1]):##Interpolation Calculationvalue = (1 - abs((x - centre_location)/ upscale_factor)) * (1 - abs((y - centre_location)/ upscale_factor))bilinear[x, y] = valuereturn bilinear

2. deconvolution计算得到6×12的目标图象

  • deconvolution操作首先要在3×6的图像上(对应上图中第1张图像)不同像素间进行插0的操作,即得到5×11的图象(第2张图像的中间部分)。

该5×11的图象要与已知是4×4的卷积核(第2个箭头上的卷积核)进行步长为1卷积,得到目标6×12的图象(第3张图像),计算得到padding为2。用 0 padding后,得到第2张图像。

卷积核的取值上面已经由代码得到,下面用示意图给出卷积核中4个位置的数值的具体计算方法,其他12个位置的计算类似:

右图卷积核作用在左图中虚线框出的4×4区域时,真正有效的卷积核参数是填充色为红色的4个位置的参数。采样点为centre_location = upscale_factor - 0.5=3/2,即为下图中的红色点:


以上就是在高分辨率图像上做卷积核不变的卷积运算得到双线性插值后图像的方法。这种方法采样点的取法为:

#3*6图像
bottom = tf.constant([[1,2,3,4,5,6],[7,8,9,10,11,12],[13,14,15,16,17,18]], dtype='float32')
bottom = tf.reshape(bottom, [1, 3, 6, 1])
weights = tf.reshape(bilinear, [4, 4, 1, 1])
stride = upscale_factor
strides = [1, stride, stride, 1]
deconv = tf.nn.conv2d_transpose(bottom, weights, [1,6,12,1],strides, padding='SAME')
with tf.Session() as sess:print("deconv: ", deconv.eval())

可以验证opencv中的imresize方法采样点也是这种取法,但是它不是直接用 0 padding,而是由边界的像素点决定padding数值。所以cv2.resize的计算结果和tf.nn.conv2d_transpose的计算结果不同。

完整代码

import numpy as np
import tensorflow as tf
def get_bilinear_filter(filter_shape, upscale_factor):##filter_shape is [width, height, num_in_channels, num_out_channels]kernel_size = 2*upscale_factor - upscale_factor%2### Centre location of the filter for which value is calculatedif kernel_size % 2 == 1:centre_location = upscale_factor - 1else:centre_location = upscale_factor - 0.5bilinear = np.zeros([filter_shape[0], filter_shape[1]], dtype='float32')for x in range(filter_shape[0]):for y in range(filter_shape[1]):##Interpolation Calculationvalue = (1 - abs((x - centre_location)/ upscale_factor)) * (1 - abs((y - centre_location)/ upscale_factor))bilinear[x, y] = valuereturn bilinearupscale_factor =2
bilinear = get_bilinear_filter([4,4,1,1,],2)
print(bilinear)#3*6图像
bottom = tf.constant([[1,2,3,4,5,6],[7,8,9,10,11,12],[13,14,15,16,17,18]], dtype='float32')
bottom = tf.reshape(bottom, [1, 3, 6, 1])
weights = tf.reshape(bilinear, [4, 4, 1, 1])
stride = upscale_factor
strides = [1, stride, stride, 1]
deconv = tf.nn.conv2d_transpose(bottom, weights, [1,6,12,1],strides, padding='SAME')
print(deconv)
# with tf.Session() as sess:# print("deconv: ", deconv.eval())

附录1:tf 反卷积实现:4×4 到8×8

反卷积的weight是:

[[0.0625 0.1875 0.1875 0.0625][0.1875 0.5625 0.5625 0.1875][0.1875 0.5625 0.5625 0.1875][0.0625 0.1875 0.1875 0.0625]]
import numpy as np
import tensorflow as tf
def get_bilinear_filter(filter_shape, upscale_factor):##filter_shape is [width, height, num_in_channels, num_out_channels]kernel_size = 2*upscale_factor - upscale_factor%2### Centre location of the filter for which value is calculatedif kernel_size % 2 == 1:centre_location = upscale_factor - 1else:centre_location = upscale_factor - 0.5bilinear = np.zeros([filter_shape[0], filter_shape[1]], dtype='float32')for x in range(filter_shape[0]):for y in range(filter_shape[1]):##Interpolation Calculationvalue = (1 - abs((x - centre_location)/ upscale_factor)) * (1 - abs((y - centre_location)/ upscale_factor))bilinear[x, y] = valuereturn bilinearupscale_factor =2
bilinear = get_bilinear_filter([4,4,1,1,],2)
print(bilinear)#3*6图像
bottom = tf.constant([[0.,  1.,  2.,  3.],[4.,  5.,  6.,  7.],[8.,  9., 10., 11.],[12., 13., 14., 15.]], dtype='float32')
bottom = tf.reshape(bottom, [1, 4, 4, 1])
weights = tf.reshape(bilinear, [4, 4, 1, 1])
stride = upscale_factor
strides = [1, stride, stride, 1]
deconv = tf.nn.conv2d_transpose(bottom, weights, [1,8,8,1],strides, padding='SAME')
print(deconv)
with tf.Session() as sess:print("deconv: ", deconv.eval())ouuu =  tf.image.resize_images(bottom, [6,12], method=tf.image.ResizeMethod.BILINEAR, align_corners=True)print(ouuu)
with tf.Session() as sess:print("deconv: ", ouuu.eval())

附录2:pytorch 反卷积实现:4×4 到8×8

from torch import nn
from torch.nn import init
from torch.autograd import Variable
import torchimport numpy as np
def get_bilinear_filter(filter_shape, upscale_factor):##filter_shape is [width, height, num_in_channels, num_out_channels]kernel_size = 2*upscale_factor - upscale_factor%2### Centre location of the filter for which value is calculatedif kernel_size % 2 == 1:centre_location = upscale_factor - 1else:centre_location = upscale_factor - 0.5bilinear = np.zeros([filter_shape[0], filter_shape[1]], dtype='float32')for x in range(filter_shape[0]):for y in range(filter_shape[1]):##Interpolation Calculationvalue = (1 - abs((x - centre_location)/ upscale_factor)) * (1 - abs((y - centre_location)/ upscale_factor))bilinear[x, y] = valuereturn bilinear# kernel_size=2∗upscale_factor−upscale_factor%2
upscale_factor =2
bilinear = get_bilinear_filter([4,4,1,1,],upscale_factor)inputv = torch.arange(4*4).view(1, 1, 4, 4).float()
print(inputv)# inputv = N,Cin​,Hin​,Win​
dconv = nn.ConvTranspose2d(in_channels=1, out_channels= 1,  kernel_size=4, stride=2, padding=1,output_padding=0, bias= False)
# Hout​=(Hin​−1)×stride[0]−2×padding[0]+dilation[0]×(kernel_size[0]−1)+output_padding[0]+1
# https://pytorch.org/docs/stable/generated/torch.nn.ConvTranspose2d.htmlbilinear = torch.reshape(torch.from_numpy (bilinear), [1, 1, 4, 4])#NHWC
print(bilinear.shape) # 先创建一个自定义权值的Tensor,这里为了方便将所有权值设为1
dconv.weight=torch.nn.Parameter(bilinear)
print(dconv.weight.shape)# print(inputv)
print(dconv(inputv)) # torch.Size([1, 1, 8, 8])
print(dconv.weight)

结果均为:

tensor([[[[ 0.0000,  0.1875,  0.5625,  0.9375,  1.3125,  1.6875,  2.0625,1.6875],[ 0.7500,  1.2500,  1.7500,  2.2500,  2.7500,  3.2500,  3.7500,3.0000],[ 2.2500,  3.2500,  3.7500,  4.2500,  4.7500,  5.2500,  5.7500,4.5000],[ 3.7500,  5.2500,  5.7500,  6.2500,  6.7500,  7.2500,  7.7500,6.0000],[ 5.2500,  7.2500,  7.7500,  8.2500,  8.7500,  9.2500,  9.7500,7.5000],[ 6.7500,  9.2500,  9.7500, 10.2500, 10.7500, 11.2500, 11.7500,9.0000],[ 8.2500, 11.2500, 11.7500, 12.2500, 12.7500, 13.2500, 13.7500,10.5000],[ 6.7500,  9.1875,  9.5625,  9.9375, 10.3125, 10.6875, 11.0625,8.4375]]]]

附录3: F.grid_sample 双线性插值实现:4×4 到8×8

import torch.nn.functional as F
import torch
inputv = torch.arange(4*4).view(1, 1, 4, 4).float()
print(inputv.shape)
'''
输出尺寸为(1,1,4,4)
输出为:tensor([[[[ 0.,  1.,  2.,  3.],[ 4.,  5.,  6.,  7.],[ 8.,  9., 10., 11.],[12., 13., 14., 15.]]]])
'''
# 生成grid,这个grid大小为(1,8,8,2),空间尺寸而言是原输入图片的两倍。
d = torch.linspace(-1,1, 8)
meshx, meshy = torch.meshgrid((d, d))
grid = torch.stack((meshy, meshx), 2)
grid = grid.unsqueeze(0) # add batch dim
print(grid.shape)# inputv.shape : [B,C,H_in,W_in]
# grid.shape: [B,H_out,W_out,2]
# output: [B,C,H_out,W_out]
# 进行双线性采样,其中指定align_corners=True保证了输出的整个图片的角边像素与原输入的一致性。
output = F.grid_sample(inputv, grid,align_corners=True)
print(output)
output = torch.nn.functional.upsample_bilinear(inputv,  scale_factor=2)
print(output.shape)output = F.interpolate(inputv, scale_factor=2, mode='bilinear', align_corners=True)
print(output)

结果有差异???

tensor([[[[ 0.0000,  0.4286,  0.8571,  1.2857,  1.7143,  2.1429,  2.5714,3.0000],[ 1.7143,  2.1429,  2.5714,  3.0000,  3.4286,  3.8571,  4.2857,4.7143],[ 3.4286,  3.8571,  4.2857,  4.7143,  5.1429,  5.5714,  6.0000,6.4286],[ 5.1429,  5.5714,  6.0000,  6.4286,  6.8571,  7.2857,  7.7143,8.1429],[ 6.8571,  7.2857,  7.7143,  8.1429,  8.5714,  9.0000,  9.4286,9.8571],[ 8.5714,  9.0000,  9.4286,  9.8571, 10.2857, 10.7143, 11.1429,11.5714],[10.2857, 10.7143, 11.1429, 11.5714, 12.0000, 12.4286, 12.8571,13.2857],[12.0000, 12.4286, 12.8571, 13.2857, 13.7143, 14.1429, 14.5714,15.0000]]]])

1×512×1×1 使用反卷积实现双线性插值到 1×512×32×32

欢迎指正错误:

from torch import nn
from torch.nn import init
from torch.autograd import Variable
import torchimport numpy as np
def get_bilinear_filter(filter_shape, upscale_factor):##filter_shape is [width, height, num_in_channels, num_out_channels]kernel_size = 2*upscale_factor - upscale_factor%2### Centre location of the filter for which value is calculatedif kernel_size % 2 == 1:centre_location = upscale_factor - 1else:centre_location = upscale_factor - 0.5bilinear = np.zeros([filter_shape[0], filter_shape[1]], dtype='float32')for x in range(filter_shape[0]):for y in range(filter_shape[1]):##Interpolation Calculationvalue = (1 - abs((x - centre_location)/ upscale_factor)) * (1 - abs((y - centre_location)/ upscale_factor))bilinear[x, y] = valuereturn bilinear# kernel_size=2∗upscale_factor−upscale_factor%2
upscale_factor =32
bilinear = get_bilinear_filter([64,64,1,1,],upscale_factor)
print(bilinear)
inputv = torch.arange(512*1*1).view(1, 512, 1, 1).float()
print(inputv.shape)# inputv = N,Cin​,Hin​,Win​
dconv = nn.ConvTranspose2d(in_channels=1, out_channels= 1,  kernel_size=64, stride=1, padding=16,output_padding=0, bias= False,padding_mode='zeros')# Hout​=(Hin​−1)×stride[0]−2×padding[0]+dilation[0]×(kernel_size[0]−1)+output_padding[0]+1
# https://pytorch.org/docs/stable/generated/torch.nn.ConvTranspose2d.htmlbilinear = torch.reshape(torch.from_numpy (bilinear), [1, 1, 64, 64])#NHWC
print(bilinear.shape) # 先创建一个自定义权值的Tensor,这里为了方便将所有权值设为1
dconv.weight=torch.nn.Parameter(bilinear)
print(dconv.weight.shape)save = torch.arange(512*32*32).view(1, 512, 32, 32).float()
for i in range(512):inputvsin = torch.reshape(inputv[0][i], [1, 1, 1, 1])#NHWC# print(inputvsin)# print(dconv(inputvsin).shape) # torch.Size([1, 1, 8, 8])# print(dconv(inputvsin)) # torch.Size([1, 1, 8, 8])save[0][i]=dconv(inputvsin)
print(save)
print(save.shape)import torch.nn.functional as F
output = F.interpolate(inputv, scale_factor=32, mode='bilinear', align_corners=False)# : nearest | linear | bilinear | bicubic | trilinear (got near)
print(output)
print(output.shape)

和pytorch的api的结果有较大差异

ConvTranspose2d 使用 0 padding,一般的线性插值由边界的像素点决定padding数值。所以ConvTranspose2d 的计算结果和interpolate的计算结果不同。

上采样卷积转置的deconvolution方法实现双线性插值,代码实现,结果不一样相关推荐

  1. html5 微信返回按钮,《解决微信内置浏览器返回上一页强制刷新问题方法》(示例代码)...

    微信内置浏览器在返回上一页面,且上一页面包含AJAX代码时,页面就会被强制刷新,极度影响用户体验.而我们想要的效果是:返回上一页面时,页面还停留在原来的状态,AJAX获取到的数据还在,滚动条也在原来的 ...

  2. 反卷积(Deconvolution)、上采样(UNSampling)与上池化(UnPooling)加入自己的思考(pytorch函数)(二)

    ps之前写过反卷积(Deconvolution).上采样(UNSampling)与上池化(UnPooling)加入自己的思考(一),不过那是东拼西凑出来的别人的东西就是稍微加入点自己的理解.今天在看代 ...

  3. 反卷积(Deconvolution)、上采样(UNSampling)与上池化(UnPooling)加入自己的思考(pytorch函数)(三)

    ps:最近在做分割在github上找代码看模型时老发现尺度从小到大那部分,有的是采用上采样(双线性插值)+卷积,有的用反卷积.为什么不相同能,我查阅相关资料发现这位知乎大神根据外网大佬文章总结原因.知 ...

  4. Caffe实现上采样(upsample)方法总结

    引言 CNN的下采样(subsample)在几乎所有的模型结构中都会出现,比如stride>1的卷积操作,pooling操作,都会减少特征图的长宽,起到下采样的效果.与之相对的就是上采样(ups ...

  5. 卷积 反卷积 上采样 下采样 区别

    1.卷积 就是利用卷积核  步长前进 卷积整个图片 2.反卷积 反卷积的具体操作 原图输入尺寸为[1,3,3,3]对应[batch_size,channels,width,height] 反卷积tco ...

  6. 【三维深度学习】基于片元的渐进式三维点云上采样模型

    点云上采样对于从稀疏三维数据重建稠密三维点云十分有效.但面对非规则.无需.稀疏.噪声和不完整的点云结构,图像领域的超分辨.补全.稀疏加密等方法无法直接用于点云上采样中.PointNet系列方法基于全连 ...

  7. 如何在IOS平台上使用js直接调用OC方法(转)

    转自:http://cocos2d-x.org/docs/manual/framework/html5/v3/reflection-oc/zh 在Cocos2d-JS v3.0 RC2中,与Andro ...

  8. 如何给caffe添加upsample层(上采样层)

     原版的caffe1.0并不支持上采样层,此处教大家如何添加自定义上采样层 首先在此处下载upsample的代码: https://github.com/SeanQ88/caffe_upsample ...

  9. 反卷积(Deconvolution)、上采样(UNSampling)与上池化(UnPooling)加入自己的思考(tensorflow函数)(一)

    ps 之前是做分类的根本就是没有很深的接触反卷积(Deconvolution).上采样(UNSampling)与上池化(UnPooling)等,要写这个主要是我在找unet代码时候发现反卷积这一步正常 ...

  10. 反卷积(Deconvolution)上采样(Upsampling)上池化(Unpooling)的区别——附翻译

    http://blog.csdn.net/u012949263/article/details/54379996 提供了英文版 Question: Deconvolution networks use ...

最新文章

  1. python数据模型的意义_Python 数据模型
  2. mac下Android开发环境配置
  3. 1.8 分割字符串(spilt())
  4. NYOJ 716 River Crossing(动态规划)
  5. api可以主动采集用户数据吗_现在的前端框架全是通过API获得数据,如何记录用户登录状态?...
  6. kali安装pip3
  7. es6=unicode码详解
  8. spring boot(5)---RestTemplate请求HTTP(1)
  9. 查看window重启日志
  10. android非空验证,Android 非空格式验证框架
  11. Unix/Linux的内存映射
  12. AMQ学习笔记 - 16. 确认机制的测试
  13. div居中和table居中,jQuery获取下拉列表值
  14. 1124 Raffle for Weibo Followers(20 分)
  15. icmp数据包BE、LE解释
  16. 【Unity】Obi插件系列(三)—— Collisions
  17. C++对齐输出(左对齐和右对齐)
  18. 简单教学 apache 配置 Expire/Cache-Control 头
  19. android横屏竖屏设置
  20. 联通集团入选混改试点:电联合并已无希望

热门文章

  1. windows开发——配置pthread.h头文件
  2. 【ArcGIS|空间分析|网络分析】9 使用位置分配选择最佳商店位置
  3. word中设置论文中英文参考文献对齐方法
  4. 实习踩坑之路:ElasticSearch搜索出来了不是自己的数据?Elastic会像MyBatisPlus一样会帮我们做判断null的操作么?分片精确度如何控制?
  5. Boost.Python.ArgumentError: Python argument types in错误解决及Boost安装配置
  6. Android View框架总结(三)View工作原理
  7. java商品类别如何与价格对应_java编写程序实现某超市商品查价功能。从键盘输入商品号,显示对应的商品价格,以“n”结束查询。...
  8. centos7安装mysql允许远程连接_Centos7安装mysql8.0,开启远程访问
  9. 背景虚化_背景虚化的效果用手机怎么拍?原来这样简单
  10. pycharm写python三个双引号_Pycharm中批量添加单引号,双引号的方法(爬虫Headers中批量加引号)...