一維卷積
一維卷積主要用作降維或者升維。以下所有例子都以語音/NLP的場景講述,輸入的矩陣為batch x T x d。T為一個(gè)batch中語音的最長時(shí)間(短的語音會(huì)加padding),d為特征的維度。一維卷積的作用是對特征進(jìn)行降維/升維。
torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
in_channels: 輸入的通道數(shù)
out_channels:輸出的通道數(shù)
kernel_size:卷積核的大小
stride:每次移動(dòng)卷積核的間距
padding:每個(gè)邊padding的元素?cái)?shù)
dilation:空洞卷積的參數(shù)
groups:分組卷積的組數(shù)
最普通的卷積操作
nn.Conv1d(in_channels=256, out_channels=100, kernel_size=2)
# 輸出的特征
input = torch.randn(32, 35, 256)
# 加padding是為了讓卷積之后的時(shí)間維度不變
padding = nn.ConstantPad2d((1, 0, 0, 0,), 0)
# 由于一維卷積是對最后一維操作的,所以得轉(zhuǎn)置后面兩維
input = input.transpose(2, 1)
# 先轉(zhuǎn)置,后padding,這樣padding就加在了時(shí)間維度了
input = padding(input)
# 卷積之后還得恢復(fù)到原來的維度
output = conv1(input).transpose(2, 1)
print(output.shape) # torch.Size([32, 35, 100])
從結(jié)果可以發(fā)現(xiàn),我只把最后的維度從256變成了100。一維卷積的卷積核實(shí)際上是[in_channels , kernel_size]

一維卷積示意圖
分組卷積
空洞卷積
二維卷積
一維卷積是只在某一個(gè)維度上操作,而二維卷積是在兩個(gè)維度上操作。
一維卷積的輸入是三維的,而二維卷積的輸入是四維的。
class Net(nn.Module):
def __init__(self, idim, odim):
super(Net, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(1, odim, 4, 2), # 1為輸入通道數(shù),odim為輸出通道數(shù),kernel為(4,4),stride為(2,2)
nn.ReLU(),
nn.Conv2d(odim, odim, 3, 2), # kernel為(3,3),stride為(2,2)
nn.ReLU()
)
# print((((idim - 1) // 2 - 1) // 2))
self.out = nn.Sequential(
nn.Linear(odim * ((((idim - 4) // 2 + 1) - 3) // 2 + 1), odim)
)
def forward(self, x):
# 輸入通道為1
x = x.unsqueeze(1)
print('x:', x.shape)
y = self.conv(x)
print(y.shape)
b, c, t, f = y.size()
# 將輸出的通道數(shù)和時(shí)間維度交換,通過全連接轉(zhuǎn)換特征維度
o = self.out(y.transpose(1, 2).contiguous().view(b, t, c * f))
print(o.shape)
x = torch.ones(32, 100, 320)
model = Net(320, 512)
print(model)
model(x)
# 輸出為 torch.Size([32, 24, 512])
通過二維卷積操作,可以將時(shí)間長度減少了4倍,特征維度從320映射到了512
輸出維度的計(jì)算方法:
輸入的矩陣: T x d
Filter: F x F
步長: S x S
padding: P x P
則輸出的矩陣大小為 ((T-F+2P)/S+1) x ((d-F+2P)/S)+1

二維卷積。每個(gè)filter在時(shí)間和特征維度上都要移動(dòng)