===== ===========这篇博客主要是讲解 ConvTranspose1d ===========================

从 Conv1d到 ConvTranspose1d-系列(1) 讲述的 Conv1d 的计算过程。在语音合成中会经常用到 ConvTranspose1d。接下来,还是尽可能傻瓜式的给出 ConvTranspose1d 的计算流程。

  1. 首先给出 Conv1d 和 ConvTranspose1d 的计算示意图,这个图非常之重要,后面的计算流程都是参考下面这个图。
     

上面是一个 y计算x的流程,下图是2个输入,求 x 的过程

下面这段话是解释 Conv1d 和 ConvTranspose1d 的计算过程,加红加粗以体现重要性

conv1d 是多个输入对应1个输出,如上面第一幅图的 [x1,x2,x3] -> y1(这里面的x1,x2,x3就是 Conv1d的输入,y1 是输出)

ConvTranspose1d 的是一个输入,对应多个输出,如上图 y1->[x1,x2,x3](这里面的x1,x2,x3就是 ConvTranspose1d的输出,y1 是输入)

Conv1d 在面前已经讲过了,这里主要说,其中 stride padding 都是在输入 [x1,x2,x3]上面进行操作的。

但是,然而,butConvTranspose1d函数的stride padding 是在输出 [x1,x2,x3] 上面进行操作的,跟 ConvTranspose1d 的输入 y 没有关系。

也就是说,在知道输入 y 时,可以计算出输出 x 是多少(公式: 

Lout=(Lin−1)×stride−2×padding+dilation×(kernel_size−1)+output_padding+1

来自 <ConvTranspose1d — PyTorch 1.13 documentation> )

其实也就是 Conv1d 知道了输出,计算输入长度(conv1d输出长度公式见: Conv1d — PyTorch 1.13 documentation)。

假设输入 y 的长度是yn,输出x长度是 xn,那么 ConvTranspose1d 中的 stride 和 padding 都是在 xn 上进行操作的,不在 yn 上面进行操作。

下面用简单代码一步一步地,傻瓜式的说明 ConvTranspose1d 的计算过程。Talk is Cheap, Show the code!

import torch

import torch.nn as nn

#转置卷积

k = 3

dconv1 = nn.ConvTranspose1d(1, 1, kernel_size=k, stride=1, padding=0, output_padding=0, bias=False)

dconv1.weight.data = torch.ones(1,1,k)

x = torch.ones(1, 1, 4)

print('=====dconv1=====')

for name, l in dconv1.named_parameters():

    print('{}={}'.format(name, l.data))

x3 = dconv1(x)

print(x3)

  • 上面是一个输入为 [y1, y2, y3, y4] = [1,1,1,1] 的信号,卷积核是 [w1,w2,w3] = [1,1,1],stride = 1,没有 padding 和 bias。计算流程:

首先计算ConvTranspose1d的输出,即 x 的长度是 6(公式上面贴出来了),那么给出输入和输出的关系题如下:

这里面并没给出箭头,是想说明的是如果是Conv1d,也就是 x->y,那么根据多对一,y1 = x1w1 + x2w2 +x3w3(Conv1d 系列已经说清楚了),如果是 ConvTranspose1d,就是从 y->x,根据多对一,那么就有

y1 * w1 = x1,  y1 * w2 = x2, y1 * w3 = x3, [y1] -> [x1,x2,x3],但是 [y2]->[x2,x3,x4],也就是 y1 和 y2 都对x2有贡献,因此只需要将这俩的共现加起来即可,即 x2 = y1 * w2 + y2 * w1,同理 y1,y2,y3 都对 x3 有贡献,x3 = y1 * w3 + y2 * w2 + y3 * w1。其他的以此类推(这里也可以根据Conv1d的计算流程进行反推。y1 = x1w1 + x2w2 +x3w3, y2 = x2*w1 + x3 * w2 +x4 * w3,这里面y1和y2的计算都用到了x2,因此在ConvTranspose1d计算中,  y1 和 y2 都对x2有贡献,即 x2 = y1 * w2 + y2 * w1 )

综上得到上述结果是即 [1,2,3,3,2,1]。用pytorch 验证结果如下:

  • 还是按照老套路,假设上面代码只修改 padding = 1,其他不变,代码如下:

dconv1 = nn.ConvTranspose1d(1, 1, kernel_size=k, stride=1, padding=1, output_padding=0, bias=False)

第一步:计算输出长度=4

第二步:画出输出和输入的对应关系如下图:

上图中 [x1,x2,x3,x4]是我们要求的结果,这个的输出左右有两个 padding。这就是:

但是,然而,butConvTranspose1d函数的stride padding 是在输出 [x1,x2,x3] 上面进行操作的,跟 ConvTranspose1d 的输入 y 没有关系。

那个Padding你可以想想 Conv1d的计算过程,y1 是 padding + x1 + x2 才得到 y1,现在反过来计算即可。很容易就能计算出 [x1,x2,x3,x4] = [2,3,3,2],那两个 padding 是啥结果不重要。用pytorch 验证之:

  • 还是按照老套路,假设上面代码的基础上只修改 stride = 2,其他不变,代码如下:

dconv1 = nn.ConvTranspose1d(1, 1, kernel_size=k, stride=2, padding=1, output_padding=0, bias=False)

第一步:输出长度 = 7

第二步:画出输入输出的关系图如下图:

首先画出[x1,x2,x3,x4,x5,x6,x7],由于 padding = 1,因此两天增加一个 padding。Conv1d 计算 y1 的结果是 y1 = padding * w1 + x1 * w2 + x2 *w3,  由于 stride = 2, 因此 y2 = x2 * w1 + x3 * w2 + x4 * w3。现在要反过来计算 x1, x2, x3, x4, x5, x6,x7 等,就是x1 = y1 * w2, conv1d 计算中 x2 对 y1 和 y2 都有贡献,反过来就是 y1和 y2 的都要对 x2 都要有贡献,即 x2 = y1 * w3 + w1 * y2.

上述结果是:[1,2,1,2,1,2,1]; pytorch 验证:

注:上面的 padding 和 stride 操作都是在输出(即x)上操作的。重要的事情说第三遍:

但是,然而,butConvTranspose1d函数的stride padding 是在输出 [x1,x2,x3] 上面进行操作的,跟 ConvTranspose1d 的输入 y 没有关系。

后面再补上 dilation 等操作的结果。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐