線形層#

ニューラルネットワークの文脈において,線形層(linear layer) または 全結合層(fully-connected layer) は入力行列 \(\boldsymbol{x} \in \mathbb{R}^{B \times D_{in}}\) に対して,重み行列 \(\boldsymbol{W} \in \mathbb{R}^{D_{out} \times D_{in}}\) との行列計算を行い,バイアス項 \(\boldsymbol{b} \in \mathbb{R}^{D_{out}}\) を足し合わせる以下の線形変換を行う層である.

\[ \boldsymbol{h} = \boldsymbol{x} \boldsymbol{W}^\top + \boldsymbol{b} \]

ここで,\(D_{in}\)\(D_{out}\) は入出力の 特徴次元 とも呼ばれ,線形層の出力 \(\boldsymbol{h}\) は行列計算からも明らかであるように \(B \times D_{out}\) 次元である.\(B\) は一般的にミニバッチサイズを示す.線形層から構成されるMulti-Layer Perceptron(MLP)では,この重みとバイアスを誤差逆伝播法から学習する.

線形層の詳細#

行列計算の復習のために,線形層の詳細な計算を確認する.入力行列,重み行列,バイアス項を要素単位で表記すると次のようになる.

\[\begin{split} \boldsymbol{x} = \left[\begin{array}{cccc} x_{11} & x_{12} & \cdots & x_{1D_{in}} \\ x_{21} & x_{22} & \cdots & x_{2D_{in}} \\ \vdots & \vdots & & \vdots \\ x_{B1} & x_{B2} & \cdots & x_{BD_{in}} \end{array}\right], \boldsymbol{W}^\top = \left[\begin{array}{cccc} w_{11} & w_{21} & \cdots & w_{D_{out}1} \\ w_{12} & w_{22} & \cdots & w_{D_{out}2} \\ \vdots & \vdots & & \vdots \\ w_{1D_{in}} & w_{2D_{in}} & \cdots & w_{D_{out}D_{in}} \end{array}\right] \boldsymbol{b} = \left[\begin{array}{c} b_1 \\ b_2 \\ \vdots \\ b_{D_{out}} \end{array}\right] \end{split}\]

これらを基に線形変換を書くと

\[\begin{split} \begin{align} \boldsymbol{h} &= \left[\begin{array}{cccc} \textcolor{#0099ff}{x_{11}} & \textcolor{#0099ff}{x_{12}} & \cdots & \textcolor{#0099ff}{x_{1D_{in}}} \\ x_{21} & x_{22} & \cdots & x_{2D_{in}} \\ \vdots & \vdots & & \vdots \\ x_{B1} & x_{B2} & \cdots & x_{BD_{in}} \end{array}\right] \left[\begin{array}{cccc} \textcolor{#0099ff}{w_{11}} & w_{21} & \cdots & w_{D_{out}1} \\ \textcolor{#0099ff}{w_{12}} & w_{22} & \cdots & w_{D_{out}2} \\ \vdots & \vdots & & \vdots \\ \textcolor{#0099ff}{w_{1D_{in}}} & w_{2D_{in}} & \cdots & w_{D_{out}D_{in}} \end{array}\right] + \left[\begin{array}{c} \textcolor{#0099ff}{b_1} \\ b_2 \\ \vdots \\ b_{D_{out}} \end{array}\right] \\ &= \left[\begin{array}{cccc} \textcolor{#cc0000}{h_{11}} & h_{12} & \cdots & h_{1D_{out}} \\ h_{21} & h_{22} & \cdots & h_{2D_{out}} \\ \vdots & \vdots & & \vdots \\ h_{B1} & h_{B2} & \cdots & h_{BD_{out}} \end{array}\right] \end{align} \end{split}\]

となる.色をつけた出力行列 \(\boldsymbol{h}\) の要素 \(h_{11}\) は,入力行列 \(\boldsymbol{x}\) の第1行と,転置された重み行列 \(\boldsymbol{W}^\top\) の第1列の各要素の積の総和に,バイアス項 \(b_1\) を加えたものとして表され,

\[ h_{11} = x_{11} w_{11} + x_{12} w_{12} + x_{13} w_{13} + \cdots + x_{1D_{in}} w_{1D_{in}} + b_1 \]

と書ける.これは一つの入力ベクトル \(\boldsymbol{x}_1\) と対応する結合重み \(\boldsymbol{w}_1\) との内積とも解釈できる.

\[ h_{11} = (\boldsymbol{x}_1, \boldsymbol{w}_1) + b_1 \]

これをすべてのサンプルと全次元にわたって計算するのが線形層である.

線形層の実装#

PyTorchを使って線形層の計算を確認する.PyTorchの線形層 torch.nn.Linear

torch.nn.Linear(in_features, out_features, bias=True, device=None, dtype=None)

で作成することができる.ここで,in_features が入力の特徴次元 \(D_{in}\) であり,out_features が出力の特徴次元 \(D_{out}\) である.biasの引数でバイアスの有無を選択できる.

以下がランダムに初期化した入力を線形層に適用したときのプログラム例である.次元と引数を確認されたい.

import torch
import torch.nn as nn

x = torch.randn(4, 3) # print(x.shape) -> torch.Size(128,20])
fc_layer = nn.Linear(3, 2) 
h = fc_layer(x) # print(h.shape) -> torch.Size([20,10])

線形層の重みとバイアスは以下のように出力できる.

fc_layer.weight
Parameter containing:
tensor([[ 0.1665, -0.4180, -0.1584],
        [-0.2164,  0.1564, -0.1722]], requires_grad=True)
fc_layer.bias
Parameter containing:
tensor([0.0071, 0.5529], requires_grad=True)

行列の計算からもわかるように,適切に入出力の次元が設定できないと行列計算時にエラーが発生する..shapeを使って計算対象の形状を適宜確認すると良い.