PyTorchバージョン:1.9.0
Conv1d
のコンストラクターに指定しないといけないパラメータは順番に下記三つあります。
- 入力チャネル数(
in_channels
) - 出力チャネル数(
out_channels
) - カーネルサイズ(
kernel_size
)
例えば、下記のソースコードは入力チャネル数2、出力チャネル数3、カーネルサイズ5のConv1d
インスタンスを作成します。
from torch import nn
conv1d = nn.Conv1d(2,3,5)
オブジェクト作成できたら、初期化された重みとバイアスが確認できます。
>>> conv1d.weight.shape
torch.Size([3, 2, 5])
>>> conv1d.weight
Parameter containing:
tensor([[[ 0.2594, -0.2927, 0.3010, -0.3144, -0.0263],
[ 0.1818, 0.1792, -0.1513, 0.0448, 0.2669]],
[[-0.1189, 0.1470, -0.1873, -0.1977, 0.0357],
[ 0.1807, 0.0479, 0.2231, -0.2369, -0.1685]],
[[ 0.0283, 0.0707, 0.0137, -0.0436, -0.2092],
[ 0.1842, 0.2262, -0.1358, -0.1469, 0.0953]]], requires_grad=True)
>>> conv1d.bias
Parameter containing:
tensor([ 0.1507, -0.0665, 0.2158], requires_grad=True)
作成されたインスタンスconv1d
を使うために、畳み込みの入力配列を用意しましょう。入力配列は三次元でなければなりません。
- 一次元目のサイズ:バッチサイズ(
batch_size
) - 二次元目のサイズ:入力チャネル数、
conv1d
インスタンスを作成したときに指定した入力チャネル数と一致しないといけません - 三次元目のサイズ:一件のデータの長さ、例えば、音声の場合、時間軸のサンプル(フレーム)数が一般的でしょう
>>> import torch
>>> x = torch.rand(4,2,6)
>>> x
tensor([[[0.8598, 0.9945, 0.8397, 0.0875, 0.1347, 0.2212],
[0.9039, 0.9663, 0.2980, 0.4002, 0.8641, 0.1295]],
[[0.6044, 0.1435, 0.9415, 0.6749, 0.1406, 0.5504],
[0.5129, 0.1664, 0.3843, 0.5065, 0.4144, 0.2583]],
[[0.9566, 0.8054, 0.3213, 0.8039, 0.4228, 0.9182],
[0.8417, 0.0937, 0.0542, 0.2004, 0.9569, 0.3480]],
[[0.7783, 0.7377, 0.9412, 0.3135, 0.7974, 0.1117],
[0.5227, 0.1919, 0.0875, 0.8341, 0.0841, 0.1266]]])
畳み込みの計算結果を確認しましょう。
>>> y = conv1d(x)
>>> y.shape
torch.Size([4, 3, 2])
>>> y
tensor([[[ 0.8454, 0.3828],
[-0.1566, -0.0447],
[ 0.6581, 0.3289]],
[[ 0.5311, 0.1668],
[-0.4254, -0.0599],
[ 0.2421, 0.1869]],
[[ 0.4219, 0.4825],
[-0.3059, -0.5375],
[ 0.4113, -0.0433]],
[[ 0.4764, -0.1308],
[-0.3490, -0.0444],
[ 0.1357, 0.1910]]], grad_fn=<SqueezeBackward1>)
次に上記の計算結果をどう導き出すかを説明します。
入力配列x
のバッチサイズは4です。即ち、四件のデータがあります。畳み込み演算はx[0]
、x[1]
、x[2]
とx[3]
にそれぞれ行われて、y[0]
、y[1]
、y[2]
とy[3]
が得られました。
conv1d.weight[0]
とconv1d.bias[0]
はy[:,0]
(出力チャネル0)に対応します。
>>> conv1d.weight[0]
tensor([[ 0.2594, -0.2927, 0.3010, -0.3144, -0.0263],
[ 0.1818, 0.1792, -0.1513, 0.0448, 0.2669]],
grad_fn=<SelectBackward>)
>>> conv1d.weight[0,0]
tensor([ 0.2594, -0.2927, 0.3010, -0.3144, -0.0263], grad_fn=<SelectBackward>)
>>> y[0,0] # 0件目データに対して、チャネル0の出力
tensor([0.8454, 0.3828], grad_fn=<SelectBackward>)
>>> x[0,0,0:5].dot(conv1d.weight[0,0]) + x[0,1,0:5].dot(conv1d.weight[0,1]) + conv1d.bias[0]
tensor(0.8454, grad_fn=<AddBackward0>)
>>> x[0,0,1:6].dot(conv1d.weight[0,0]) + x[0,1,1:6].dot(conv1d.weight[0,1]) + conv1d.bias[0]
tensor(0.3828, grad_fn=<AddBackward0>)
>>> y[1,0] # 1件目データに対して、チャネル0の出力
tensor([0.5311, 0.1668], grad_fn=<SelectBackward>)
>>> x[1,0,0:5].dot(conv1d.weight[0,0]) + x[1,1,0:5].dot(conv1d.weight[0,1]) + conv1d.bias[0]
tensor(0.5311, grad_fn=<AddBackward0>)
>>> x[1,0,1:6].dot(conv1d.weight[0,0]) + x[1,1,1:6].dot(conv1d.weight[0,1]) + conv1d.bias[0]
tensor(0.1668, grad_fn=<AddBackward0>)
conv1d.weight[1]
とconv1d.bias[1]
はy[:,1]
(出力チャネル1)に対応します。
>>> y[0,1] # 0件目データに対して、チャネル1の出力
tensor([-0.1566, -0.0447], grad_fn=<SelectBackward>)
>>> x[0,0,0:5].dot(conv1d.weight[1,0]) + x[0,1,0:5].dot(conv1d.weight[1,1]) + conv1d.bias[1]
tensor(-0.1566, grad_fn=<AddBackward0>)
>>> x[0,0,1:6].dot(conv1d.weight[1,0]) + x[0,1,1:6].dot(conv1d.weight[1,1]) + conv1d.bias[1]
tensor(-0.0447, grad_fn=<AddBackward0>)
>>> y[1,1] # 1件目データに対して、チャネル1の出力
tensor([-0.4254, -0.0599], grad_fn=<SelectBackward>)
>>> x[1,0,0:5].dot(conv1d.weight[1,0]) + x[1,1,0:5].dot(conv1d.weight[1,1]) + conv1d.bias[1]
tensor(-0.4254, grad_fn=<AddBackward0>)
>>> x[1,0,1:6].dot(conv1d.weight[1,0]) + x[1,1,1:6].dot(conv1d.weight[1,1]) + conv1d.bias[1]
tensor(-0.0599, grad_fn=<AddBackward0>)