Capsule Networksの理解— AIの魅力的な新しいアーキテクチャ

アレックス・レイノルズによる「科学」

たたみ込みニューラルネットワークは驚くべき仕事をしましたが、問題に根ざしています。私たちは新しいソリューションや改善について考え始めました。そして今、カプセルに入ってください。

以前、カプセルネットワークがこれらの従来の問題のいくつかとどのように戦うかについて簡単に説明しました。過去数か月間、私はすべてのものをカプセルに浸していました。私たち全員がカプセルが実際にどのように機能するかをより深く理解しようとする時だと思います。

わかりやすくするために、各レイヤーで何が起こっているかを確認できる視覚化ツールを作成しました。これは、ネットワークの単純な実装とペアになっています。すべては、GitHubのここにあります。

これがCapsNetアーキテクチャです。まだ意味がわからなくても心配しないでください。思いつく限りの詳細を含めて、レイヤーごとに説明します。

パート0:入力

CapsNetへの入力は、ニューラルネットに供給される実際の画像です。この例では、入力画像は高さ28ピクセル、幅28ピクセルです。しかし、画像は実際には3次元であり、3次元にはカラーチャンネルが含まれています。

この例の画像は白黒なので、カラーチャンネルは1つだけです。慣れ親しんでいるほとんどの画像には、赤緑青用の3つまたは4つのチャネルがあり、場合によってはアルファ用の追加のチャネルまたは透明度があります。

これらのピクセルはそれぞれ、0〜255の値として表され、28x28x1マトリックス[28、28、1]に格納されます。ピクセルが明るいほど、値は大きくなります。

パート1a:畳み込み

CapsNetの最初の部分は、従来の畳み込み層です。畳み込み層とは何ですか、どのように機能し、その目的は何ですか?

目標は、エッジや曲線など、入力画像から非常に基本的な機能を抽出することです。

どうすればこれができますか?

エッジについて考えてみましょう。

画像上のいくつかの点を見ると、パターンを拾い始めることができます。私たちが見ているポイントの左右の色に注目してください:

ポイントがエッジの場合、それらの差が大きいことに気付くかもしれません。

255-114 = 141
114-153 = -39
153-153 = 0
255-255 = 0

画像の各ピクセルを調べて、その値をその左右のピクセルの差の値に置き換えたらどうなりますか?理論的には、画像はエッジを除いてすべて黒になります。

これを行うには、画像内のすべてのピクセルをループ処理します。

画像のピクセルの場合{
  result [pixel] = image [pixel-1]-image [pixel + 1]
}

しかし、これはあまり効率的ではありません。代わりに、「畳み込み」と呼ばれるものを使用できます。技術的には、「相互相関」ですが、誰もが畳み込みと呼ぶのが好きです。

畳み込みは基本的にループと同じことを行いますが、行列演算を利用します。

畳み込みは、画像の隅に小さな「ウィンドウ」を並べることによって行われ、その領域のピクセルのみを見ることができます。次に、画像内のすべてのピクセルにわたってウィンドウをスライドさせ、各ピクセルに一連の重みを乗算してから、そのウィンドウ内にあるすべての値を加算します。

このウィンドウは、「カーネル」と呼ばれる重みのマトリックスです。

気にするのは2ピクセルだけですが、ウィンドウをラップすると、それらの間にピクセルがカプセル化されます。

窓:
┌──────────────────────────────────────┐
│left_pixel middle_pixel right_pixel│
└──────────────────────────────────────┘

これらのピクセルを乗算して、合計が求めている値になるようにする重みのセットを考えることができますか?

窓:
┌──────────────────────────────────────┐
│left_pixel middle_pixel right_pixel│
└──────────────────────────────────────┘
(w1 * 255)+(w2 * 255)+(w3 * 114)= 141

下のネタバレ!

 │││
 │││
 │││
 │││
 │││
\│/ \│/ \│/
 V V V

次のようなことができます。

窓:
┌──────────────────────────────────────┐
│left_pixel middle_pixel right_pixel│
└──────────────────────────────────────┘
(1 * 255)+(0 * 255)+(-1 * 114)= 141

これらの重みにより、カーネルは次のようになります。

カーネル= [1 0 -1]

ただし、カーネルは一般に正方形です。そのため、次のようにゼロを追加することができます。

カーネル= [
  [0 0 0]
  [1 0 -1]
  [0 0 0]
]

畳み込みの動作を確認するための素晴らしいgifは次のとおりです。

注:出力の次元は、カーネルのサイズに1を足した分だけ小さくなります。例:(7 — 3)+ 1 = 5(これについては次のセクションで詳しく説明します)

作成したカーネルで畳み込みを行った後の元の画像は次のとおりです。

いくつかのエッジが欠落していることに気付くかもしれません。具体的には、水平方向のもの。それらを強調するには、上下のピクセルを調べる別のカーネルが必要です。このような:

カーネル= [
  [0 1 0]
  [0 0 0]
  [0 -1 0]
]

また、これらのカーネルは両方とも、他の角度のエッジやぼやけたエッジではうまく機能しません。そのため、多くのカーネルを使用します(CapsNet実装では、256個のカーネルを使用します)。そして、カーネルは通常、より小さな空間を確保するために大きくなります(カーネルは9x9になります)。

これは、モデルのトレーニング後のカーネルの1つです。それほど明白ではありませんが、これはエッジ検出器のより大きなバージョンであり、より堅牢で、明るい部分から暗い部分へのエッジのみを検出します。

カーネル= [
  [0.02 -0.01 0.01 -0.05 -0.08 -0.14 -0.16 -0.22 -0.02]
  [0.01 0.02 0.03 0.02 0.00 -0.06 -0.14 -0.28 0.03]
  [0.03 0.01 0.02 0.01 0.03 0.01 -0.11 -0.22 -0.08]
  [0.03 -0.01 -0.02 0.01 0.04 0.07 -0.11 -0.24 -0.05]
  [-0.01 -0.02 -0.02 0.01 0.06 0.12 -0.13 -0.31 0.04]
  [-0.05 -0.02 0.00 0.05 0.08 0.14 -0.17 -0.29 0.08]
  [-0.06 0.02 0.00 0.07 0.07 0.04 -0.18 -0.10 0.05]
  [-0.06 0.01 0.04 0.05 0.03 -0.01 -0.10 -0.07 0.00]
  [-0.04 0.00 0.04 0.05 0.02 -0.04 -0.02 -0.05 0.04]
]

注:値は非常に大きいため、たとえば0.01783941を丸めました

幸いなことに、このカーネルのコレクションを手で選ぶ必要はありません。それがトレーニングの目的です。カーネルはすべて空の状態(またはランダムな状態)で始まり、出力を必要なものに近づける方向に微調整を続けます。

これが256カーネルが最終的にどのように見えるかです(消化しやすいようにピクセルとして色付けしました)。数値が負の値であるほど、それらは青くなります。 0は緑、正は黄色です。

256カーネル(9x9)

これらのすべてのカーネルで画像をフィルタリングすると、256個の出力画像の太いスタックになります。

パート1b:ReLU

ReLU(正式にはRectified Linear Unit)は複雑に聞こえるかもしれませんが、実際には非常に単純です。 ReLUは、値を受け取るアクティベーション関数です。負の場合はゼロになり、正の場合は同じままです。

コード内:

x = max(0、x)

そしてグラフとして:

この関数を畳み込みのすべての出力に適用します。

なぜこれを行うのですか?レイヤーの出力に何らかの活性化関数を適用しない場合、ニューラルネット全体を線形関数として説明できます。これは、私たちが行っているこのようなことはすべて無意味であることを意味します。

非線形性を追加すると、あらゆる種類の関数を記述することができます。適用できる機能にはさまざまな種類がありますが、ReLUは実行するのが非常に安いため、最も人気があります。

ReLU Conv1レイヤーの出力は次のとおりです。

256出力(20x20ピクセル)

パート2a:PrimaryCaps

PrimaryCapsレイヤーは通常の畳み込みレイヤーとして始まりますが、今回は以前の畳み込みからの256出力のスタックを畳み込んでいます。したがって、9x9カーネルを使用する代わりに、9x9x256カーネルを使用します。

それで、私たちは正確に何を探していますか?

畳み込みの最初の層では、単純なエッジと曲線を探していました。ここで、先ほど見つけたエッジから、少し複雑な形状を探しています。

今回の「ストライド」は2です。つまり、一度に1ピクセルずつ移動する代わりに、2のステップを踏むことになります。入力のサイズをより迅速に削減できるように、より大きなストライドが選択されます。

注:出力の次元は通常12ですが、ストライドのために2で除算します。例:((20 — 9)+ 1)/ 2 = 6

出力をさらに256回コンボリューションします。したがって、256個の6x6出力のスタックになります。

しかし、今回はお粗末な平凡な数字だけでは満足していません。

スタックを32デッキに分割し、各デッキに8枚のカードを配置します。

このデッキを「カプセル層」と呼ぶことができます。

各カプセル層には36個の「カプセル」があります。

あなたが追いついているなら(そして数学の知恵であるなら)、それは各カプセルが8つの値の配列を持っていることを意味します。これが「ベクター」と呼ばれるものです。

私が話していることは次のとおりです。

これらの「カプセル」は新しいピクセルです。

単一のピクセルでは、そのスポットにエッジが見つかったかどうかの信頼性しか保存できませんでした。数値が大きいほど、信頼性が高くなります。

カプセルを使用すると、場所ごとに8つの値を保存できます。これにより、その場所に形状が見つかったかどうかだけでなく、より多くの情報を保存することができます。しかし、他にどのような情報を保存したいのでしょうか?

下の形を見るとき、そのことについて教えてください。他の人にそれを再描画する方法を教えなければならず、彼らはそれを見ることができなかった場合、あなたは何と言いますか?

この画像は非常に基本的なものであるため、形状を説明するために必要な詳細はほんのわずかです。

  • 形状の種類
  • ポジション
  • 回転
  • サイズ

これらを「インスタンス化パラメーター」と呼ぶことができます。より複雑な画像では、さらに詳細が必要になります。ポーズ(位置、サイズ、方向)、変形、速度、アルベド、色相、テクスチャなどを含めることができます。

エッジ検出用のカーネルを作成したとき、特定の角度でしか機能しなかったことを覚えているかもしれません。各角度にカーネルが必要でした。エッジを記述する方法は非常に少ないため、エッジを処理するときにそれを回避できます。形状のレベルに到達したら、長方形、楕円、三角形などのすべての角度にカーネルを使用したくありません。 3次元の回転と照明のような機能を備えたより複雑な形状を扱うと、扱いにくくなり、さらに悪化します。

これが、従来のニューラルネットが目に見えない回転をうまく処理できない理由の1つです。

エッジからシェイプへ、シェイプからオブジェクトへと進むにつれて、この追加の有用な情報を保存するスペースがもっとあればいいのですが。

2つのカプセルレイヤー(1つは長方形、もう1つは三角形)と2つの従来のピクセル出力の簡単な比較を次に示します。

従来の2Dまたは3Dベクトルと同様に、このベクトルには角度と長さがあります。長さは確率を表し、角度はインスタンス化パラメーターを表します。上記の例では、角度は実際に形状の角度と一致していますが、通常はそうではありません。

これらのベクトルは8次元であるため、実際には、上記のようなベクトルを視覚化することは現実的ではありません(または少なくとも簡単ではありません)。

この追加情報はすべてカプセルに収められているので、アイデアはそれらから画像を再作成できるはずです。

素晴らしく聞こえますが、どのようにしてネットワークを実際にこれらのことを学びたいと思い込むのでしょうか?

従来のCNNをトレーニングする場合、モデルが適切な分類を予測するかどうかのみを考慮します。カプセルネットワークでは、「再構築」と呼ばれるものがあります。再構築では、作成したベクトルを取得し、このベクトルのみを指定して元の入力画像を再作成します。次に、再構成が元の画像とどれだけ一致するかに基づいてモデルをグレーディングします。

これについては次のセクションで詳しく説明しますが、簡単な例を示します。

パート2b:スカッシュ

カプセルを取得したら、別の非線形関数(ReLUなど)を実行しますが、今回は方程式がもう少し複雑になります。この関数は、角度ではなくベクトルの長さのみが変更されるように、ベクトルの値をスケーリングします。これにより、ベクトルを0から1の間で作成できるため、実際の確率になります。

これは、潰れた後のカプセルベクトルの長さです。この時点では、各カプセルが探しているものを推測することはほとんど不可能です。

各ピクセルは実際には長さ8のベクトルであることに注意してください

パート3:契約によるルーティング

次のステップは、次のレベルに送信する情報を決定することです。従来のネットワークでは、おそらく「最大プーリング」のようなことを行います。最大プーリングは、領域内の最もアクティブなピクセルを次のレイヤーに渡すだけでサイズを縮小する方法です。

ただし、カプセルネットワークでは、合意によるルーティングと呼ばれる処理を行います。この最良の例は、この優れたビデオでオーレリアンジェロンが説明した船と家の例です。各カプセルは、それ自体に基づいて次のレイヤーのアクティベーションを予測しようとします。

これらの予測を見て、どのオブジェクトを次のレイヤーに渡すことを選択しますか(入力を知らない)。おそらく、ボートでしょう?長方形のカプセルと三角形のカプセルの両方が、ボートがどのように見えるかについて同意します。しかし、彼らは家がどのように見えるかについて同意していないので、オブジェクトが家である可能性はほとんどありません。

合意によるルーティングでは、有用な情報のみを渡し、結果にノイズを追加するだけのデータを破棄します。これにより、最大プーリングのように最大数を選択するよりもはるかに賢い選択ができます。

従来のネットワークでは、見当違いの機能は気になりません。

カプセルネットワークでは、機能が互いに一致しません。

うまくいけば、それは直感的に機能します。しかし、数学はどのように機能しますか?

予測する10の異なる数字クラスがあります。

0、1、2、3、4、5、6、7、8、9

注:ボートと家の例では、2つのオブジェクトを予測していましたが、現在は10を予測しています。

ボートや家の例とは異なり、予測は実際には画像ではありません。代わりに、画像を記述するベクトルを予測しようとしています。

各クラスのカプセルの予測は、そのベクトルに、予測しようとしている各クラスの重みのマトリックスを掛けることによって行われます。

32個のカプセル層があり、各カプセル層には36個のカプセルがあることに注意してください。つまり、合計1,152カプセルです。

cap_1 * weight_for_0 =予測
cap_1 * weight_for_1 =予測
cap_1 * weight_for_2 =予測
cap_1 * ...
cap_1 * weight_for_9 =予測
cap_2 * weight_for_0 =予測
cap_2 * weight_for_1 =予測
cap_2 * weight_for_2 =予測
cap_2 * ...
cap_2 * weight_for_9 =予測
...
cap_1152 * weight_for_0 =予測
cap_1152 * weight_for_1 =予測
cap_1152 * weight_for_2 =予測
cap_1152 * ...
cap_1152 * weight_for_9 =予測

最終的に11,520の予測のリストになります。

各重みは実際には16x8行列であるため、各予測はカプセルベクトルとこの重み行列の間の行列乗算です。

ご覧のとおり、予測は16度のベクトルです。

16はどこから来たのですか?オリジナルのカプセルが8個だったように、それはIt意的な選択です。

しかし、ネットワークの奥深くに行くほどカプセルの次元数を増やしたいことに注意する必要があります。これは直感的に理にかなっているはずです。なぜなら、深くなるほど機能が複雑になり、それらを再作成するために必要なパラメータが増えるからです。たとえば、人の目だけでなく顔全体を説明するためにより多くの情報が必要になります。

次のステップは、これらの11,520の予測のうち、どれが最も一致するかを把握することです。

高次元のベクトルの観点から考えると、これに対する解決策を視覚化することは困難です。正気のために、ベクトルが2次元空間の単なる点であるふりをすることから始めましょう。

すべてのポイントの平均を計算することから始めます。各ポイントは、同じ重要性で始まります。

その後、平均から各ポイント間の距離を測定できます。ポイントが平均から離れるほど、そのポイントの重要性は低くなります。

次に、ポイントの重要性を考慮して、平均を再計算します。

最終的にこのサイクルを3回繰り返します。

ご覧のように、このサイクルを経て、他の人と同意しないポイントは消え始めます。最高の同意ポイントは、最高のアクティベーションを持つ次のレイヤーに渡されます。

パート4:DigitCaps

合意後、10の16次元ベクトルが作成され、各桁に1つのベクトルが作成されます。このマトリックスは最終予測です。ベクトルの長さは、見つかった数字の信頼度です。長ければ長いほど良いです。ベクトルを使用して、入力画像の再構成を生成することもできます。

これは、4の入力でベクトルの長さがどのように見えるかです。

5番目のブロックは最も明るく、高い信頼性を意味します。 0が最初のクラスであり、4が予測クラスであることを忘れないでください。

パート5:再構成

実装の再構築部分はあまり面白くありません。完全に接続されたほんの数層です。しかし、再構築自体は非常にクールで楽しいものです。

ベクトルから4つの入力を再構成すると、次のようになります。

スライダー(ベクトル)を操作すると、各次元が4にどのように影響するかがわかります。

さまざまな入力で遊んでスライダーが再構成にどのように影響するかを確認するために、視覚化リポジトリを複製することをお勧めします。

git clone https://github.com/bourdakos1/CapsNet-Visualization.git
cd CapsNet-可視化
pip install -r requirements.txt

ツールを実行します。

python run_visualization.py

次に、ブラウザーでhttp:// localhost:5000を指定します。

最終的な考え

カプセルネットワークからの再構築は素晴らしいと思います。現在のモデルは単純な数字のみでトレーニングされていますが、より大きなデータセットでトレーニングされた成熟したアーキテクチャが達成できる可能性を思い浮かべます。

より複雑な画像の再構成ベクトルを操作すると、どのように影響されるかを知りたいと思います。そのため、私の次のプロジェクトは、カプセルネットワークをCIFARおよびsmallNORBデータセットと連携させることです。

読んでくれてありがとう!ご不明な点がございましたら、bourdakos1 @ gmail.comまでお気軽にお問い合わせください。LinkedInで私と連絡を取るか、MediumとTwitterで私に従ってください。

この記事がお役に立てば、拍手gaveを送って共有し、他の人が見つけられるようにすれば大いに意味があります!下にコメントを残してください。