
PyTorchのConv1dをコードで理解する:ステップバイステップガイド
この記事では、PyTorchのConv1dを深く理解するために、その仕組みと使い方を具体的な例を交えながら解説します。
本記事は全内容無料でご覧いただけますが、ご購入いただいた方には、同じ内容に対応するGoogle Colabノートブックをご提供しています。応援いただけますと、継続的な執筆の励みになります。
PyTorchバージョン:2.1.1
Conv1dは、一次元データ(例:時系列データ、音声信号)に対して畳み込み演算を行うためのPyTorchの関数です。公式ドキュメントはこちらです。
ステップ1:Conv1dインスタンスの作成
Conv1dを使うには、まずインスタンスを作成する必要があります。インスタンス作成時に指定する主要なパラメータは以下の3つです。
入力チャネル数 (in_channels): 入力データのチャネル数を指定します。例えば、モノラル音声なら1、ステレオ音声なら2となります。
出力チャネル数 (out_channels): 畳み込み演算によって出力されるデータのチャネル数を指定します。これは、畳み込みフィルターの数を意味します。
カーネルサイズ (kernel_size): 畳み込みフィルターのサイズを指定します。
例えば、入力チャネル数2、出力チャネル数3、カーネルサイズ5の`Conv1d`インスタンスは以下のように作成します。
from torch import nn
conv1d = nn.Conv1d(2, 3, 5)
ステップ2:重みとバイアスの確認
インスタンスを作成すると、畳み込み演算に用いられる重みとバイアスが自動的に初期化されます。これらの値は、学習を通して最適化されます。
>>> conv1d.weight.shape
torch.Size([3, 2, 5])
>>> conv1d.weight
Parameter containing:
tensor([[[-0.1458, -0.1183, 0.2923, -0.1471, 0.1843],
[ 0.0537, -0.0794, -0.0925, -0.1160, 0.1079]],
[[ 0.1938, -0.2256, 0.2889, 0.0061, 0.2513],
[-0.0034, 0.1902, -0.2750, -0.2157, -0.2768]],
[[-0.2985, 0.2475, -0.1458, -0.1502, 0.1150],
[-0.0302, -0.2750, 0.0309, 0.0301, 0.1593]]], requires_grad=True)
>>> conv1d.bias
Parameter containing:
tensor([ 0.0108, 0.0044, -0.1034], requires_grad=True)
`conv1d.weight`は、各フィルターの重みを表すテンソルです。その形状は(出力チャネル数, 入力チャネル数, カーネルサイズ)となっています。
`conv1d.bias`は、各フィルターのバイアスを表すテンソルです。その形状は(出力チャネル数)となっています。
ステップ3:入力データの準備
`Conv1d`への入力データは3次元配列である必要があります:
1次元目: バッチサイズ (`batch_size`) を表します。これは、一度に処理するデータサンプル数を意味します。
2次元目: 入力チャネル数を表します。これは、`Conv1d`インスタンスを作成した時に指定した`in_channels`と一致する必要があります。
3次元目: 一つのデータサンプルの長さを表します。例えば、音声データであれば、時間軸のサンプル数(フレーム数)が一般的です。
>>> import torch
>>> x = torch.rand(4, 2, 6) # バッチサイズ4, 入力チャネル数2, データ長6のランダムデータ
>>> x
tensor([[[0.4075, 0.7187, 0.3654, 0.0438, 0.7582, 0.2001],
[0.4827, 0.8339, 0.0611, 0.7037, 0.9492, 0.3649]],
[[0.2127, 0.1981, 0.9238, 0.7077, 0.7603, 0.4736],
[0.1320, 0.3239, 0.9727, 0.7413, 0.6587, 0.3458]],
[[0.0699, 0.5684, 0.6536, 0.0973, 0.7945, 0.4898],
[0.8851, 0.1858, 0.8446, 0.6994, 0.5246, 0.2806]],
[[0.8436, 0.2575, 0.7026, 0.9220, 0.3713, 0.2914],
[0.1779, 0.3406, 0.7813, 0.4116, 0.6296, 0.7159]]])
ステップ4: 畳み込み演算の実行
準備した入力データ`x`を`conv1d`に渡すことで、畳み込み演算が実行されます。その後、畳み込みの計算結果を確認してみましょう。
>>> y = conv1d(x)
>>> y.shape
torch.Size([4, 3, 2])
>>> y
tensor([[[ 0.0815, -0.2949],
[-0.0567, -0.3616],
[-0.0895, -0.2583]],
[[ 0.1389, -0.1125],
[-0.0853, -0.0951],
[-0.2073, -0.2764]],
[[ 0.1867, -0.2998],
[-0.2171, -0.0999],
[ 0.0507, -0.3443]],
[[-0.0740, 0.0812],
[-0.0019, -0.0620],
[-0.4520, -0.2426]]], grad_fn=<ConvolutionBackward0>)
出力データ`y`は、(バッチサイズ, 出力チャネル数, 出力データ長) の3次元テンソルになります。次のステップに、これらの計算がどのように行われたかを説明します。
ステップ5: 計算結果の詳細
入力テンソル`x`のバッチサイズは4なので、4つのデータがあります。よって、`y`の1次元の長さも4になります。即ち、それぞれのデータに対して畳み込み演算を行い、出力`y[0]`から`y[3]`が得られます。
畳み込み演算は出力チャンネルごとに行われます。それぞれの出力チャンネルに専属のカーネルとバイアスが対応します。例えば、`conv1d.weight[0]`と`conv1d.bias[0]`は出力チャネル0(`y[:,0]`)に対応します。つまり、出力チャンネルと同じ数だけのカーネルとバイアスが存在します。
各出力チャンネルの畳み込み演算以下のように行われます:
カーネルが入力データ上を移動(スライド)
カーネルと入力データの要素ごとの積の和を計算
バイアスを加算
出力の1要素は以下の計算で得られます:
y[バッチ番号, 出力チャネル番号, 出力データ位置] =
sum(x[バッチ番号, 入力チャネル0, 入力データ位置:入力データ位置+カーネルサイズ] @ conv1d.weight[出力チャネル番号, 入力チャネル0]) +
sum(x[バッチ番号, 入力チャネル1, 入力データ位置:入力データ位置+カーネルサイズ] @ conv1d.weight[出力チャネル番号, 入力チャネル1]) +
... +
conv1d.bias[出力チャネル番号]
`@`は行列の内積を表します。`A @ B`は`A.dot(B)`と同じです。
出力サイズは以下の公式で計算されます:
出力長 = (入力長 - カーネルサイズ + 1)
例えば、`y[0, 0, 0]`は以下のように計算されます。
>>> y[0,0,0] # 0番目のデータ, 0番目の出力チャネル, 0番目の出力データ位置
tensor(0.0815, grad_fn=<SelectBackward0>)
>>> x[0,0,0:5] @ conv1d.weight[0,0] + x[0,1,0:5] @ conv1d.weight[0,1] + conv1d.bias[0]
tensor(0.0815, grad_fn=<AddBackward0>)
`y[0, 0, 1]`は以下のように計算されます。
>>> y[0,0,1] # 0番目のデータ, 0番目の出力チャネル, 1番目の出力データ位置
tensor(-0.2949, grad_fn=<SelectBackward0>)
>>> x[0,0,1:6] @ conv1d.weight[0,0] + x[0,1,1:6] @ conv1d.weight[0,1] + conv1d.bias[0]
tensor(-0.2949, grad_fn=<AddBackward0>)
上記のように、`Conv1d`は入力データに対して畳み込み演算を行い、新しい特徴マップを出力します。この特徴マップは、音声認識や自然言語処理など、様々なタスクに利用されます。
【ご購入いただいた方へ】 こちらのGoogle Colabノートブックには、本記事で解説した内容のすべてのコードと実行結果が含まれています。実際に手を動かしながら学習できますので、ぜひご活用ください。
この記事が気に入ったらチップで応援してみませんか?