ディープラーニングの「全結合層」は、Neural Network Consoleの場合は「Affine」レイヤーにあたります。
Affineは、Neural Network Consoleレイヤーリファレンスには、こう説明されてます。
全ての入力値から、OutShapeプロパティで指定する全ての出力ニューロンへの結合を持つ全結合層です。
o = Wi+b
(iは入力、oは出力、Wは重み、bはバイアス項を示す)
なるほど。
Affineってのは、「o = Wi+b」という計算をした結果を、出力する役目で、その計算は「全ての入力値」から「全ての出力」への結合をもつ・・ということはわかります。
この説明だけで、上記の計算式
o = Wi+b (iは入力、oは出力、Wは重み、bはバイアス項を示す)
で「全ての入力値から全ての出力への結合」になることが、パッとわかる方は、続けて読む必要はないです(笑)
わからない方だけ、続きをどうぞ。
上記の「o = Wi+b」の式に登場する「o」も「W」も「i」も行列データです。
行列データってこんな感じのやつです。
見やすくするため「6×6」のサイズの例にしてます。
Wiは、この行列どうしの掛け算を意味しますが、単純な「W × i」ではありません。
「W」と「i」の内積(ドット積)という特殊な方法で計算します。
行列の内積(ドット積)計算の仕方を説明します。
計算する過程を、さらに見やすくするため、2×2の行列の例にしてます。
左側の行(横)と右側の列(縦)を掛け合わせて足して、結果の数値をもとめるのが、行列の内積計算です。
例えば、上の例だと。
左上の「19」は、「(1 × 5) + (2 × 7)」。
左下の「43」は、「(3 × 5) + (4 × 7)」
右上の「22」は、「(1 × 6) + (2 × 8)」
右下の「50」は、「(3 × 6) + (4 × 8)」
と計算してるわけです。
ちなみに、全結合層の「+b」は「Wi」の結果に固定値の行列データ「b」を足します。
この「b」は、Wiの結果が極端に小さな値でエラーになるとかを防ぐための保険みたいなものと考えるとわかりやすいです。
こういう行列同士の「Wi+b 」みたいな演算のことを「Affine変換」というみたいで、
だからレイヤーの名前が「Affine」なのです。
上記計算例は「2 × 2」の行列で計算しました。
それを見て「全結合じゃねーじゃないか」と思った人、当たりです。
上記例だと、左側の上2つ、下2つずつしか一度に計算してませんから、「全結合」いにはなってません。
全結合にするには1次元にして計算する必要があります。
例えば、(28,28,1)=幅28×高さ28×1チャンネルのデータなら、一旦 28×28×1=>784のサイズの1次元・・以下のようなイメージに変換するわけです。
1次元にすると全結合になるイメージをつかむため、超シンプルなモデルで計算してみます。(784とかで書くと、とても見づらいので)
用意したのは、以下の2×3の小さな行列2つです。
これを、一次元に変換すると、以下のようになります。
これにウエイトを掛け合わせて出力するサイズは「3」にします。
かけあわせるW(ウエイト)は、単純化のため全部0.5にしてやっていますが、別に全部が同じ数字である必要などありません。
まず、入力①のほう。
結果の128は「0*0.5+255*0.5+0*0.5+0*0.5+0*0.5+0*0.5」で計算して求めています。横×縦の計算ですから、1次元だと一度の計算で左側の全部が対象になるため「入力すべてと、ウエイトを掛け合わせる」=「全結合」になるわけです。
これがマニュアルに書いてある「全ての入力値から、OutShapeプロパティで指定する全ての出力ニューロンへの結合を持つ」のイメージです。
続けて、入力②の方も計算してみます。
こちらは、「0*0.5+0*0.5+0*0.5+0*0.5+255*0.5+0*0.5」で128です。
じゃあ。
こうすることで何がうれしいのかというと、2つのデータを単純比較するのではなく、「特徴」を抽出して似ている=ほぼ同じという比較ができるようになることです。
具体例でいうと、1次元に変換する前は、上記の入力①と入力②こんな感じなので、単純比較すると、まったく違うデータになります。
でも上記のように、1次元展開して全結合で計算をすることで、入力①②にあった位置関係のずれによる誤差を吸収して「0が5つと255がひとつで構成されている」という共通の特徴を際立たせて「似ている=ほぼ同じ」判定に結び付ける「ひとつの方法論」になりえるのは、イメージできると思います。
もちろん、上記は極端で何ら実用性のない例で、あくまでイメージでしかありませんけど、数学的な説明でモヤモヤしてた部分が、こういうイメージを持てたことで、すっと腹に落ちたという経験をふまえて、あえて、こんな整理の仕方をしてみました。
邪道?かもしれませんけど。
さて、ここからは、行列計算の基本的なルールについて補足しときます。
上にでてきた
この図で、なんで1行6列の入力、1行3列の出力に対して、真ん中が6行3列になっているのか?について、行列演算の基本ルールをふまえて説明しておきます。
すでに知っている方はスキップしてください。
基本ルールは2つです。
- 行列の内積計算は、左側が「2行3列」なら「3行2列」みたいに内側の数が一致してないと計算できません。
- 出力サイズは、「2行3列」×「3行2列」なら「2行2列」になるみたいに、外側の数で決まります。
これを、図にするとこんな感じになります。
なので。
入力が「6」。
出力を「3」。
そう決めた時点で、掛け合わせる相手(真ん中)は「6行3列」に決まるわけです。
今回は、こんなところで。
ではでは。