如何解决如何手动实现pytorch卷积的填充 torch.nn.functional.padinput,padding_size,mode ='constant',value = 0: tensorflow.padinput,padding_size,mode ='CONSTANT',name = None,constant_values = 0 output_size =input_size-1 stride +kerenel_size-1
我试图将一些pytorch代码移植到tensorflow 2.0,并且很难弄清楚如何在两者之间转换卷积函数。这两个库处理填充的方式是症结所在。基本上,我想了解如何手动生成pytorch在后台进行的填充,以便将其转换为tensorflow。
如果我不进行任何填充,下面的代码将起作用,但是一旦添加任何填充,我就无法弄清楚如何使这两种实现相匹配。
output_padding = SOME NUMBER
padding = SOME OTHER NUMBER
strides = 128
tensor = np.random.rand(2,258,249)
filters = np.random.rand(258,1,256)
out_torch = F.conv_transpose1d(
torch.from_numpy(tensor).float(),torch.from_numpy(filters).float(),stride=strides,padding=padding,output_padding=output_padding)
def pytorch_transpose_conv1d(inputs,filters,strides,padding,output_padding):
N,L_in = inputs.shape[0],inputs.shape[2]
out_channels,kernel_size = filters.shape[1],filters.shape[2]
time_out = (L_in - 1) * strides - 2 * padding + (kernel_size - 1) + output_padding + 1
padW = (kernel_size - 1) - padding
# HOW DO I PAD HERE TO GET THE SAME OUTPUT AS IN PYTORCH
inputs = tf.pad(inputs,[(?,?),(?,?)])
return tf.nn.conv1d_transpose(
inputs,tf.transpose(filters,perm=(2,0)),output_shape=(N,out_channels,time_out),strides=strides,padding="VALID",data_format="NCW")
out_tf = pytorch_transpose_conv1d(tensor,output_padding)
assert np.allclose(out_tf.numpy(),out_torch.numpy())
解决方法
填充
要在 Pytorch 和 Tensorflow 之间翻译卷积和转置卷积函数(使用填充 padding ),我们需要先了解F.pad()
和tf.pad()
函数。
torch.nn.functional.pad(input,padding_size,mode ='constant',value = 0):
-
padding size
:从last dimension
开始逐步描述填充某些输入尺寸所用的填充大小。 - 仅填充输入张量的
last dimension
,然后pad的格式为((padding_left,padding_right) - 填充
last 3 dimensions
,(padding_left,padding_right,padding_top,padding_bottom,padding_front,padding_back)
tensorflow.pad(input,padding_size,mode ='CONSTANT',name = None,constant_values = 0)
-
padding_size
:是形状为[n,2]
的整数张量,其中n是张量的秩。对于输入的每个维度D,paddings [D,0]指示在该维度中张量的内容之前要添加多少个值,而paddings[D,1]
指示在该维度中张量的内容之后要添加多少个值。
这是代表F.pad和tf.pad 等效项的表,以及输入张量的输出张量[[[1,1],[1,1]]]
的形状为(1,2,2)
卷积填充
现在让我们转到卷积层中的PyTorch填充
-
F.conv1d(input,...,padding,...):
- 填充控制
both sides
上隐式填充的数量,以填充点数。 -
padding=(size)
应用F.pad(input,[size,size])
,即填充最后一个尺寸,其尺寸(尺寸,大小)等于tf.pad(input,[[0,0],[0,size]])
- 填充控制
-
F.conv2d(input,...,padding,...):
-
padding=(size)
应用F.pad(input,size,size])
,即填充最后2 个维度,其(大小,大小)等于tf.pad(input,size],size]])
-
padding=(size1,size2)
应用F.pad(input,[size2,size2,size1,size1])
,它等效于tf.pad(input,[size1,size1],size2]])
-
转置卷积中的填充
转置卷积层中的PyTorch填充
- F.conv_transpose1d(input,...,padding,output_padding,...):
-
dilation * (kernel_size - 1) - padding
填充将添加到输入中每个维度的both
侧。
在 -
transposed
可被视为分配fake
的{{1}}输出 -
removed
控制添加到输出形状一侧的其他尺寸 - 检查 this 以了解
output_padding
中transpose convolution
期间到底发生了什么。 - 这是计算转置卷积输出大小的公式:
Padding
卷积中的 -
output_size =(input_size-1) stride +(kerenel_size-1)+ 1 + output_padding-2 padding
代码
转置卷积
pytorch
结果
import torch
import torch.nn as nn
import torch.nn.functional as F
import tensorflow as tf
import numpy as np
# to stop tf checkfailed error not relevent to actual code
import os
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"] = "1"
def tconv(tensor,filters,output_padding=0,padding=0,strides=1):
'''
tensor : input tensor of shape (batch_size,channels,W) i.e (NCW)
filters : input kernel of shape (in_ch,out_ch,kernel_size)
output_padding : single number must be smaller than either stride or dilation
padding : single number should be less or equal to ((valid output size + output padding) // 2)
strides : single number
'''
bs,in_ch,W = tensor.shape
in_ch,k_sz = filters.shape
out_torch = F.conv_transpose1d(torch.from_numpy(tensor).float(),torch.from_numpy(filters).float(),stride=strides,padding=padding,output_padding=output_padding)
out_torch = out_torch.numpy()
# output_size = (input_size - 1)*stride + (kerenel_size - 1) + 1 + output_padding - 2*padding
# valid out size -> padding=0,output_padding=0
# -> valid_out_size = (input_size - 1)*stride + (kerenel_size - 1) + 1
out_size = (W - 1)*strides + (k_sz - 1) + 1
# input shape -> (batch_size,W,in_ch) and filters shape -> (kernel_size,in_ch) for tf conv
valid_tf = tf.nn.conv1d_transpose(np.transpose(tensor,axes=(0,1)),np.transpose(filters,axes=(2,1,0)),output_shape=(bs,out_size,out_ch),strides=strides,padding='VALID',data_format='NWC')
# output padding
tf_outpad = tf.pad(valid_tf,output_padding],0]])
# NWC to NCW
tf_outpad = np.transpose(tf_outpad,(0,1))
# padding -> input,begin,shape -> remove `padding` elements on both side
out_tf = tf.slice(tf_outpad,padding],[bs,tf_outpad.shape[2]-2*padding])
out_tf = np.array(out_tf)
print('output size(tf,torch):',out_tf.shape,out_torch.shape)
# print('out_torch:\n',out_torch)
# print('out_tf:\n',out_tf)
print('outputs are close:',np.allclose(out_tf,out_torch))
tensor = np.random.rand(2,7)
filters = np.random.rand(1,3)
tconv(tensor,output_padding=2,padding=5,strides=3)
一些有用的链接:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。