目次
- 全結合層(Affine)
- Neural Network ConsoleでいうAffineレイヤー=全結合層
- Affine(全結合層)が利用するのは行列データ
- 行列の掛け算は「内積計算」を使います
- 全結合にするには一次元への変換が必要
- 全結合で計算すると何がいいのか
- おまけ:行列計算の基本的なルールを補足
全結合層(Affine)
専門用語を極力使わず、多少の不正確さは目をつぶっても、なんとなくイメージできることを目標にして整理します。
まず、ニューラルネットワークで学習する流れをざっくり図にしてみました。
ニューラルネットワークの目的のひとつとして「既存の正解がわかっているデータで勉強(学習)して、未知のデータから、正解が導けるようになること」があります。
ポイントはどうやって「勉強(学習)」するか?ですが、ニューラルネットワークでは、それを「計算」でやってます。
どういうことかというと。
既存の正解のわかっている入力データにたいして、パラメータ(重み)をかけあわせる計算を行い、その結果をもとに答えを出して、答え合わせを行い、間違ってたら、正解に近づけるようにパラメータ(重み)を少し修正するみたいなことを延々と繰り返して、もっとも。正解に近い結果を計算で求められる確率の高いパラメータ(重み)の値を決めていく・・のを学習と呼んでいるわけです。
上記の図は、それをごく簡易的に書いてます。
上記の図では「計算して結果を整えて、それを次の入力にする」部分を1回しか書いてませんが、実際は、そこが何層にもわかって繰り返されることで、学習の精度をあげようというのが、ニューラルネットワークであり、ディープラーニングなどと言われるゆえんということです。
ここで①の「計算(入力×重み+α)」部分にあたるのが「全結合層(Affine)」だと、まずはご理解ください。
Neural Network ConsoleでいうAffineレイヤー=全結合層
Neural Network Consoleのマニュアル(レイヤーリファレンス)を見てみます。
Neural Network Consoleでの「Affine」レイヤーが「全結合層」にあたります。
Affineは、Neural Network Consoleレイヤーリファレンスには、こう説明されてます。
全ての入力値から、OutShapeプロパティで指定する全ての出力ニューロンへの結合を持つ全結合層です。
o = Wi+b
(iは入力、oは出力、Wは重み、bはバイアス項を示す)
Affineは、「o = Wi+b」という計算結果を、出力する役目でありますが、その計算が具体的に何をしているのか?がイメージできるようにざっくり整理したいと思います。
Affine(全結合層)が利用するのは行列データ
まず、大前提が、上記の「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列」に決まるわけです。
今回は、こんなところで。
ではでは。
PS:他の部品(レイヤー)については、以下にまとめてます。