{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 畳み込み層" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "全結合層の問題点は、データの形状が無視されること\n", "\n", "例えば画像の場合、縦、横、チャンネル(RGB)の3次元の形状を持っているが、全結合層に入力する際には、データを1次元にする必要がある。\n", "(MNISTデータの場合は、1ピクセルずつを左上から?順に入れてましたね)\n", "\n", "そのため、例えば隣接するピクセルについての情報をくみ取ることが難しい。\n", "\n", "畳み込み層の場合は3次元のデータとしての形状を維持しながら、ニューロン間のデータの受け渡しをすることができる。\n", "\n", "CNNでは、入力データを「**入力特徴マップ** (input feature map)」、出力データを「**出力特徴マップ** (output feature map)」と言い、合わせて「**特徴マップ** (feature map)」という場合がある。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 畳み込み演算\n", "\n", "画像処理でいう「フィルター演算」に相当 \n", "文献によれば「カーネル」という言葉で表現される場合がある。\n", "\n", "畳み込み演算は、入力データに対してフィルターのウィンドウを一定の間隔でスライドさせながら適用していきます。ここでは縦、横を持つ2次元のデータで見てきましょう。\n", "\n", "![](../draw.io/images.drawio-2-Convolution.svg)\n", "\n", "フィルターの要素と入力の要素を乗算し、その和を入れる。\n", "この計算を**積和演算**という。\n", "\n", "CNNの場合、「重み」はフィルターのパラメータです。「バイアス」もあります。\n", "\n", "バイアスはフィルターで計算した後に、各マス目に加算します。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## パディング\n", "\n", "次の畳み込み層の処理を行う前に、入力データの周囲に固定のデータを埋める。これを「**パディング** (padding)」という。\n", "\n", "![](../draw.io/images.drawio-2-padding.svg)\n", "\n", "パディングによって、次の計算の出力サイズを調整します。\n", "\n", "畳み込み演算は何度も行うと、出力サイズはどんどん小さくなり、最終的な出力サイズが1になってしまうかもしれません。この事態を回避するためにも、パディングを使います。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ストライド\n", "フィルターを適用する位置の間隔を **ストライド** といいます。\n", "\n", "7×7の画像に対し、3×3のフィルターを1ピクセル毎に計算した場合、ストライドは1、出力は5×5になります\n", "\n", "ストライドが2になると、7×7の画像の出力は3×3になります。\n", "\n", "![](../draw.io/images.drawio-2-Stride.svg)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "入力サイズ、フィルターサイズ、パディング、ストライドから、出力サイズを計算する式は以下です:\n", "\n", "入力サイズを(H, W), フィルターサイズを(FH, FW), パディングをP, ストライドをS とすると、出力サイズを(OW, OH)は\n", "$$\n", "OH = \\frac{H+2P-FH}{S} + 1\n", "$$\n", "$$\n", "OW = \\frac{W+2P-FW}{S} + 1\n", "$$" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OH = 5.0\n", "OW = 5.0\n" ] } ], "source": [ "H = 7\n", "W = 7\n", "FH = 3\n", "FW = 3\n", "P = 0\n", "S = 1\n", "\n", "OH = (H + 2*P - FH) / S + 1\n", "OW = (W + 2*P - FW) / S + 1\n", "\n", "print(f\"OH = {OH}\")\n", "print(f\"OW = {OW}\")" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OH = 3.0\n", "OW = 3.0\n" ] } ], "source": [ "H = 7\n", "W = 7\n", "FH = 3\n", "FW = 3\n", "P = 0\n", "S = 2\n", "\n", "OH = (H + 2*P - FH) / S + 1\n", "OW = (W + 2*P - FW) / S + 1\n", "\n", "print(f\"OH = {OH}\")\n", "print(f\"OW = {OW}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ただし、大きさやストライドなどによっては、出力結果が小数点になってしまうこともある" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OH = 2.333333333333333\n", "OW = 2.333333333333333\n" ] } ], "source": [ "H = 7\n", "W = 7\n", "FH = 3\n", "FW = 3\n", "P = 0\n", "S = 3\n", "\n", "OH = (H + 2*P - FH) / S + 1\n", "OW = (W + 2*P - FW) / S + 1\n", "\n", "print(f\"OH = {OH}\")\n", "print(f\"OW = {OW}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "そのため、小数点以下が出てしまっている場合はエラーを出す、などの対策が必要です" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3次元データの畳み込み演算\n", "\n", "3次元データの畳み込み演算は、直方体のブロックで考えるとわかりやすいです。\n", "\n", "例えば、チャンネル数をC, 高さをH、横幅をWのデータは (C, H, W)と表現することができます。\n", "\n", "同様に、フィルターも(C, FH, FW)と書くことができます。フィルターのチャンネルは入力データの大きさと同一にする必要があるため、FCと表現しません。\n", "\n", "しかし出力結果がチャンネル方向にも持つ場合は、どうすればよいでしょうか?\n", "\n", "答えは、フィルターを増やすことです。(C, FH, FW)のフィルターをFN個増やすと、出力データにもFN個チャンネルを持たせることができます (FN, OH, OW)。\n", "\n", "\n", "----\n", "\n", "ここまでが、畳み込み演算による重み(フィルター)の計算でした。畳み込み演算にはバイアスも存在します。\n", "\n", "バイアスはチャンネル数の数だけ存在します(FN, 1, 1)。畳み込み演算の結果(FN, OH, OW)に対して加算します。\n", "\n", "## 畳み込み演算のバッチ処理\n", "\n", "畳み込み演算も、バッチ処理ができます。\n", "\n", "バッチ処理を行う場合、C, H, Wの3次元データから、N個という4次元のデータとして計算します。\n", "\n", "N個の入力データはそのまま、N個の出力データとなりますが、計算回数は1回になります。" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.3" } }, "nbformat": 4, "nbformat_minor": 4 }