傻瓜式讲解Conv1D家族-系列2-ConvTranspose1d
===== ===========这篇博客主要是讲解 ConvTranspose1d ===========================
从 Conv1d到 ConvTranspose1d-系列(1) 讲述的 Conv1d 的计算过程。在语音合成中会经常用到 ConvTranspose1d。接下来,还是尽可能傻瓜式的给出 ConvTranspose1d 的计算流程。
- 首先给出 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]上面进行操作的。
但是,然而,but,ConvTranspose1d函数的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。这就是:
但是,然而,but,ConvTranspose1d函数的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)上操作的。重要的事情说第三遍:
但是,然而,but,ConvTranspose1d函数的stride 和 padding 是在输出 [x1,x2,x3] 上面进行操作的,跟 ConvTranspose1d 的输入 y 没有关系。
后面再补上 dilation 等操作的结果。
更多推荐
所有评论(0)