Convolutional Neural Network
MLPの次はCNNについて習うと思います。畳み込みニューラルネットワークと書くとなんだか語感があれなのですが、パーセプトロンと同じく人間の視野から思想を得ていたと思います。
画像を主に対象とするものです。画像データ(WidthxHightxChannel)を入力し、画像より小さいフィルターをスライドさせながら適用し、再度「画像」を出力とします。この時出力される「画像」は、フィルターのサイズにもよりますが、一般的には入力された画像のより小さく(WidthxHightが小さい)、Channelは多くなります。フィルターを繰り返し適用すればするほど、きちんと学習ができたモデルであれば、何らかの抽象的な表現空間を得ているはずです。
視覚的に非常にわかりやすい例が作成されています。
過去に一度畳み込みは実装しましたが、今のFortLearnerには入っていません。
Convolution
初めて学術的な用語として畳み込みを使ったのは、関数の畳み込みでした。画像を例えばWxHxC(WidthxHightxChannelの並びです。フレームワークにより並びが異なるので、気を付ける必要があります。RGBの並びが違うよりはましな気がします)を入力として、フィルターをWxHxCx$N_F$とすると、出力される画像は、$W_F$x$H_F$x$N_F$となります。ここで、$W_F$と$H_F$は以下で与えられます。
W_F(H_F) = \frac{W(H) - W_F(H_F)}{S}
$S$はストライドの大きさで、フィルターをいずれかの位置で適用した後、次に適用する位置は何ピクセルずれた位置であるかを指定します。大きくすればするほど出力画像は小さくなります。小さいままでは、出力画像から十分に小さい(~抽象的な表現?)が得られるまで時間がかかり、あまり大きな値では、畳み込みごとの各ピクセルの依存関係がなくなってしまいます。
単純に実装してしまうと4重ループになってしまいます。深層学習ではミニバッチ学習(CNNでは一度に複数枚の画像を投入する)を行うので、CNNの入力は WidthxHightxChannelxBatch の並びで(PytorchやTensorflowではBatchが一番最初に来ます。多分RowMajorだからだと思います。Batchのループは独立に適用できるので、最も内側に配置すべきです。FortranはColumnMajorのため最も外です。初めてPytorchの並びを見たときにはRowMajor/ColumnMajorは知らなかったのですが、なんてわかりにくいんだと思いました)、フィルターを$W_F$x$H_F$x$C$x$N_F$です。ループ構造としては(並びは最適でないと思います)、
- ミニバッチループ(Batch)
- フィルターループ($C_F$)
- Widthループ($W_F$)
- Hightループ($H_F$)
のようになります。これは当然非常に重いですが、3重ループに軽減する方法があります。ゼロからつくるDeepLearningの1巻に解説があります。im2colという変換で、画像とフィルタを画像の形式に変換し、畳み込み処理を行列積に変えてしまいます。Kmeansなどでもふれたとおり行列積は非常に高度に最適化が施されているので、相性が良いのですが、元のデータに加え行列化したデータを作成されるため、メモリの消費が激しくなります。
ちなみにConvolutionは画像だけでなく、時系列データに使われることもあります。時系列を1行しかない画像とみなせばそのまま適用できます。
画像に関しては長らくCNNのみが用いられてきましたが、MLPMixerやViTなどのモデルも出てきて、少なくともほかの選択肢も出てきたようです。
以上