Caffeを使ったCNNによる手書き文字分類 [2] - CNNの構造と学習の仕組み

blog.li.nu >
この記事が役に立ったら
前回、ディープラーニングにおけるデータセットの重要性について説明しました。 さらに、CNNが識別器として動作するためには、訓練という過程が必要であり、それには多数の訓練データとその正解データが必要であることを述べました。 加えて、実際の未知画像に対してもどれくらい適応可能なのかを知るために、正答率の目安を知るためのデータ、つまりテストデータとその正解データも必要なことを説明しました。
 ここでの目的は、手書き文字の分類をMNISTというデータセットを使い行うことですが、実際にこのデータセットを使って学習をさせるには、CNNの構造を定義する必要があります。 そこでこの記事では、CNNの構造を簡単に説明します。もし動くコードが先に欲しくて、中身がどうなっているかは後回しで構わない、あるいは興味がない人は、この記事は飛ばして次に行っても構いません。
 おそらく他のインターネット記事に多くあるように、単に動くコードを説明するだけであれば、この記事にあるような動作の説明はいらないと思います。 しかしながら、CNNの分野においては、理論的というよりは試行錯誤的、半ば職人芸的に構造やパラメータを決定しているのが現状です。 つまり、もしうまくいかなかった場合、一体どのパラメータがどういう意味なのかを知らなければ何の方針も立たず途方に暮れることになってしまいます。 この記事では、そういった事情も踏まえ、できる限り数式で議論することは避けながらも、それぞれの要素の動作、および各パラメータについての紹介も行います。

CNNの構造

典型的なCNNの構造を以下の図に示します。
何も知らないと、いきなりこれを見て怖気づきそう(特に右の方の○に大量の線が引いてある部分)ですが、気にする必要はありません。 結局上のような構造を生成の上、計算くれるのはCaffeであり、あなたはこの恐ろしく複雑に見える処理を自分で書く必要がないのです。
 一番簡単にCNNの構造を分けるのであれば、青色の枠線で囲まれた2ブロックです。 この枠線の中身にある変な物体たち、特に○の集まりは気になるでしょうが、実用上詳しい仕組みを説明するのは後回しでも構いません。 CNNに限らず、一番重要なのはそのシステムでは何が入力され、何が得られるのかであり、まずはその点を押さえましょう。
 例として、前回から使っている「人」「犬」「猫」の判別をしたいのだとしましょう。上の画像もそれに応じた作りになっているのですが、まず入力は何らかの物体が写っている写真です。 上の画像では人が写っています。CNNはこのように画像を直接入力として受け付けます。ただし、仕組み上画像サイズは一定でなければならないので注意が必要です。 しかしながら、それは実用上の些細な問題であり、もし入力する画像サイズが一定でないのなら、単純に全ての画像を拡大縮小してCNNに入力すればよいだけのことです。 あるいは、大きな画像の中から、判定したい必要な場所だけを切り抜くということも考えられるかもしれません。 このように、CNNの入力にふさわしい形に画像を加工する作業のことを正規化と呼びます。CNNは一定サイズに正規化された画像を受け取ります。
 画像を受け取ると、CNNは内部にあるパラメータに沿って特定の計算を次々と行います。最初のブロックは、いわば「特徴抽出部」といえるもので、 その画像が人なのか、犬なのか、あるいは猫なのかを判定するために必要な視覚的情報を入力画像から抽出するという役割を持ちます。具体的に何をしているかは少しだけあとで紹介します。
 一方で、後ろの○が並んでいる奇妙な部分はいわば「識別部」といえるものであり、抽出された情報をもとに、この情報は一体人、犬、猫のどれにあたるのかを所定の計算によって判断、つまりパターンを分類します。 その結果、判定結果、つまり出力は「確率」という形で出てきます。これは、全ての用意されたカテゴリについて確率が出てきて、合計すると100%になるような仕組みです。 例えば上の画像を入力すると、人である確率は80%、犬である確率は10%、猫である確率は10%といった具合です。これを受けて、確率が最も高い「人間」を答えであるとします。 これがCNNによるクラス分類の大まかな流れです。

この項のまとめ

特徴抽出部

 特徴抽出部は、先ほど紹介したように、入力された画像から、判断するために必要な情報(特徴量)を抽出します。
 特徴量という言葉については難しく考える必要はなく、例えばトマトときゅうりを判別したいとき、丸さや赤さといったものを画像から数値化しても、それは特徴量であるといえます。 従来の方法では、この特徴量というものに何を採用すればよいかあらかじめ規定しておき、それを取り出すための方法を人間が手作りで考える必要がありましたが、例えば今例にした赤さとか丸さというのは根拠もなく直感的に考えただけの指標であり、しかもそれらを具体的にどうコンピュータにわかる形で算出すればいいかすらも自明ではありません。 つまり、特徴量の抽出は思うほど簡単なことではありません。
 しかし、CNNは、訓練される過程で、適切な特徴量を自動で獲得できるよう自分でパラメータを変更していきます。 人間が手作りしたわけではないので、結果抽出された特徴量に赤さや丸さといった情報があるのかについては明らかではないものの、CNNは目的の物体をうまく判別できるような形で情報を抽出できるのです。
 特徴抽出部は、具体的には、畳み込み層、プーリング層というものが何回か連なることにより構成されています。 畳み込み層ではその名前の通りの「畳み込み」と呼ばれる処理を行い、情報を抽出します。 一方でその後のプーリング層は、畳み込み層で得られた情報を要約するとともに、位置に対する不変性、つまり、多少物体が周囲に移動していても、同じ物体だと識別できる能力を強める役割があります。 必ずそうしなければならないルールはどこにもありませんが、典型的なCNNでは、畳み込み層とプーリング層をひとつのペアとして、それを何回か繰り返して特徴抽出を行います。 その結果、この繰り返しをすればするほど、出力層に近づくにつれ、色や形といった明らかな視覚的情報ではなく、より抽象的な情報を抽出されるようになります。 ただし、層を追加すると、より多くのメモリを必要とするので、層は無制限に追加してよいわけではなく、メモリの制限とも相談しながら層の深さや層のパラメータを決定する必要があります。 あまりに層の数を欲張ったネットワークにしてしまうと、例えば入力がたった128x128というサイズしかないのに GeForce GTX TITAN X (12GB) でもメモリ不足といった事態に簡単に陥ります。

この項のまとめ

畳み込みフィルタ

 先ほど、特徴抽出部には畳み込み層とプーリング層の2種類があり、基本的には「畳み込み層→プーリング層」を1つの組として、これが何回か繰り返されると説明しました。 次に、この2つの層はどのように違っているのか、つまりどんな感じの処理をしているのかを、数式を極力出さないという方針上、非常に粗い説明にはなりますが、見てみましょう。
 畳み込み層が行っているのは、画像処理の世界でいう「畳み込みフィルタ」という処理に大変近い処理ですが、OpenCVで遊んだことがない人にとっては畳み込みという言葉もフィルタという言葉にも馴染みがないかと思います。
 フィルタとは、文字通り情報のふるい分けを行うことであり、ある情報から不要な情報を取り除いて必要な情報を残すことを言います。逆に言えば欲しい情報を抽出するということです。 特に、「畳み込み」という計算で画像全体を処理していくタイプのフィルタは「畳み込みフィルタ」と呼ばれています。今後、単に畳み込みフィルタを「フィルタ」と呼びます。
 典型的なフィルタ($3 \times 3$サイズのフィルタ)を以下に示します。
それぞれのマスは、画像でいう1ピクセルに相当するものと思ってください。つまり、3ピクセルの幅と3ピクセルの高さを持つフィルタが上の図です。 縦横サイズは違っていても計算の定義上何ら問題ありませんが、扱いやすいことから、よほどの理由がない限り形は正方形です。 そのため、今後この記事でも単にサイズ $n$ のフィルタといえば、$n \times n$ ピクセルの大きさを持つフィルタのことを指すものとします。
 上の数字は、マイナスでもプラスでも自由な値が入ります。この値に沿って、所定の方法で計算(畳み込み)を実施すると、フィルタの出力が得られます。 このとき、上のパラメータをうまく選ぶと、特定の機能をもたせることができることが知られています。 特にその中でも重要な機能を持つ有名なものには名前がついていて、例えば上のフィルタは「横方向微分フィルタ」という名前がついており、 横方向のエッジ検出する機能(画素の濃淡の差が大きい場所がどこかを強調する役割)を持っています。
img.png
例えばこれが元の画像であるとき、背景は白なので、フォルダアイコンの境界線や文字のあたりがエッジに相当する場所だろうという見当がつきます。
out.png
これが実際の横方向微分の実行結果です。確かに、色の変化が著しい場所のみが白く浮き上がっている様子が理解できます。 横方向なので、その一方で縦方向のエッジにはあまり反応しないことも理解できます。もちろん、この逆パターンの縦方向フィルタもあります。
 なお、上の結果は上で示したフィルタではなく横方向のソーベルフィルタというものを使っていますが、パラメータが違うだけで原理は全く一緒です。 これはOpenCVの手助けを借りた以下のコードで簡単に同じことができます。縦方向にしたい場合は cv2.Sobel の「1,0」を「0,1」にすればいいだけです。
import cv2

img = cv2.imread("img.png",0)
out = cv2.Sobel(img, cv2.CV_64F,1,0,ksize=3)
cv2.imwrite("out.png", out)
"img.png"と"out.png"は、自分で適用したいファイルの場所、保存先のファイルの場所へそれぞれ書き換えましょう。 これで、フィルタは縦、横一定のサイズを持った数字の集まりであり、数字の組み合わせ方によって画像から特定の特徴量が抽出できることもなんとなく分かったかと思います。 CNNは、上に書いたようなフィルタのそれぞれのマスの数字が更新可能なパラメータになっていて、訓練される過程で自ずと分類に必要な特徴量が抽出できるよう、このパラメータを更新していくのです。
 次に畳み込みの計算についてですが、簡単なイメージだけつかんでおきましょう。
乱暴に書けばこのような感じです。先ほどのフィルタは赤い枠にしてあります。このフィルタが画像左端から右端までをスキャン(走査)します。 それが終わると、次は1ピクセル下にずれて同じことをやります。これを、一番下に達するまで繰り返します。 なお、上の画像についてですが、本当はフィルタの1マスは画像の1ピクセルに相当するものです。上のものは明らかに画像の1ピクセルと対応しておらず、厳密には正しくないので注意してください。 ただ、イメージ自体は十分に理解できるかと思います。
 以下の例でもう少しわかりやすくイメージを掴んでみましょう。ご存知の通り、画像は色の三原色、赤、緑、青の3つのチャンネルから成り立っています。 色の情報がない、単に光の濃淡のみが記録された画像、つまり世間一般にいう白黒画像はグレイスケール画像と呼ばれており、以下はグレイスケール画像に対してフィルタを適用する場合を考えます。 (が、カラー画像もグレイスケールの1チャンネルに対して、チャンネル数が3に増えるだけで考え方は一緒です)
最初に、フィルタは画像の一番左上の $3 \times 3$ マスの領域に作用します。画像の対応する場所にフィルタを載せてみましょう。
このようになるでしょう。見難くなるので、フィルタの値は右下に小さく書くようにしました。 次に、それぞれのマスにある値同士を掛け算します。
計算結果は矢印で右に示しました。 最後に、全部の値を足します。すると3とマイナス3が同じ数あって、残りは0なので0になることがわかるでしょう。 このときの計算結果「0」が、一番左上の場所に対するフィルタの計算結果です。なので、処理後の一番左上の画素値は「0」であることがわかりました。 このように、決まった並びの数字の列と、もう1つの同じ並びを持つ別の数字の列において、対応する要素同士をかけた結果を足し合わせたものを内積といいます。
 次に結果を1つずつ記録していきましょう。なお、図でわかるように、フィルタを画像の中に収められる範囲で計算をすると、上下左右とも1マスずつ小さくなります。実用上はここが一番重要な知識です。 フィルタの処理結果は全部で9個得られることが事前に分かるので、$9\times 9$のマスを作っておきましょう。
次も同じように計算すると、赤く?になっている場所は$-6$であることが確かめられます。あとはこの手順に沿って、もうひとつ右にフィルタをずらし、次に下に1マス降りて・・・とすれば、フィルタによる処理が完了します。 このような一連の計算のことを畳み込みといいます。 数式で書くと非常にわかりにくいのですが、計算の原理はこのように単純で、「1点の値を決めるのに周りの値を使う」のが畳み込みの特徴です。 現在見ている場所の処理結果を決定するために、$3 \times 3$ といった局所的な領域を考慮していきます。
 これをCNNの仕組みの中で見てみると、最初は局所的な領域(特定の方向のエッジなど、簡単な色形の情報)を見ながら判断をするわけですが、畳み込み層とプーリング層を通っていくうちに、 次第に見る領域の範囲が(画像が縮むので相対的に)大きくなっていき、判断される情報も単純な形などではない、より抽象的なものになっていくのです。 なお、フィルタのサイズが大きいと、より広い領域を見ながら判断できるようになりますが、見ての通り$3 \times 3$のフィルタの時点でたった1点を決定するのに9回も掛け算をしてそれを全部足し算しています。 なので、計算コストの問題やメモリのから、CNNにおいてはむやみにフィルタのサイズは大きくできません。 これも決まりではないですが、一般的なCNNの場合、最初は大きめのフィルタにして、奥の層に行くほどサイズを縮めていくのが一般的です。
 最後に、CNNの実用上重要な部分についてです。上の具体的な計算方法は忘れても問題ありませんが、知識として次の2つは知っておいた方がよいでしょう。  1つめは対称性によるものです。もしサイズが奇数なら、上の図で見てきたようにぴったり周囲平等に見ることができますが、偶数だと上下左右どこか必ずほかよりも見渡せないところが出てきます。 この理由から、特別な理由がない限りはフィルタのサイズは奇数(3,5,7,9,...)にしておきましょう。これはCNNに限った話ではなく、普通の画像処理においても同じことです。
 2つめはフィルタサイズが奇数ならという話ですが、処理後の画像サイズは $(n-1)/2$ だけ周囲が小さくなります。 本当はフィルタの中心を画像の左上に合わせ、画像の右下がフィルタの中心になるまで同じことをやれば処理後もサイズは不変ですが、こうすると面倒なことがおきます。 それは、画像をはみ出た場所の画素値がないということです。適当な値で処理して埋める方法(パディング)もありますが、このことから、通常はスタート地点をフィルタがちょうど左上に収まる場所からにします。 つまり、サイズが3の時は、中心から見て上下左右1マス分、5の時は2マス分、7の時は3マス分処理できない点が出てくるということを意味します。このことから、式で書けば画像は $(n-1)/2$ だけ小さくなるのです。

畳み込み層

 以上を踏まえた上で畳み込み層について簡単に説明します。これまで説明したのは一般的な画像処理における畳み込みフィルタの振るまいでしたが、畳み込み層はこれに加えてもう少し手の込んだことをやっています。
これが構造の図ですが、畳み込み層は上の模式図からも分かるように、今見てきたフィルタが何枚も集まって1つの畳み込み層を形成しています。 一般にはその枚数が多いほどより多くの種類の特徴量を抽出できることになりますが、枚数が多すぎると莫大なメモリを消費するので、やはり1000枚2000枚といったフィルタの枚数は気軽には設定できません。 これも決まりではありませんが、一般的には64,128,192,256...といったコンピュータ的にきりのいい枚数に設定されていることが多いようです。もちろん50や100でもよいでしょう。
 実際の畳み込み層の振る舞いについて見ていきます。入力はカラー画像、つまり3チャンネル(3つの縦、横サイズが同一の数字の行列)だとしましょう。これに対する1枚のフィルタの挙動は次のとおりです。
図のように、入力は3つのチャンネルがあるわけですが、先ほど書いた畳み込み処理をそれぞれに適用し、3つの出力が得られます。
 次に、1枚のフィルタに対して得られた3枚の出力を「圧縮」します。どうやるかというと、全部重ねあわせて、対応する点で3枚の値をそれぞれ合計します。
なお、本当はただ和を取るだけではなく、バイアスと呼ばれる変数も付加しますが、ここでは省略します。
 以上から、1枚のフィルタでできるのは1枚の出力であることがわかりました。 言い方を変えれば、入力時点でのチャンネルが100であろうが、100000であろうが、畳み込み層のフィルタの枚数が$k$枚なら、出力も$k$チャンネルになることを意味しています。実用上はこの知識が重要です。

この項のまとめ

プーリング層

 プーリング層は、すでにいくらか書いているように、決まった領域の値をひとまとめにし、位置に対する感度を低くするかわり、位置変化に対する認識能力を上げるための層です。 プーリングという処理にはいくつか種類がありますが、多くの場合は以下に説明するMAXプーリングというものが使われます。
 やはり言葉で全部説明するより図があったほうがよいので、図で見てみます。
このような画像に、プーリングを適用したいとします。プーリング層においては、サイズ$n$およびストライド$s$というパラメータが問題になります。 前者はフィルタ同様、局所的な領域を見るわけですが、その時に見る領域の広さを表していて、ストライドは移動するときの幅、つまり粗さを示しています。 例えばストライドが2のときは、1マスではなく2マスずれながら計算が行われるということです。 ここでは、サイズが2でストライドが2だとしましょう。
すると、上の図のようになります。サイズが2なので$2 \times 2$の領域を見て、ストライドが2なので2ずつずれていきます。 MAXプーリングの場合、それぞれの囲まれた領域の中で、最も大きい値をその領域の値にします。 つまり、上の例の場合、「3,3,3,3」という$2 \times 2$の画像が出来上がり、これが出力です。 これを、畳み込み層から得られた枚数全てに対して適用します。そのため、畳み込み層の出力枚数とプーリング層の出力枚数は同じです。
 なお、実用上重要な知識としては、ストライド$s$の分だけ出力サイズが小さくなります。つまり、画像は約$1/s$(「約」と付けたのは、奇数サイズの場合はちょうど半分にはならないため)に縮小します。 また、見ての通り、フィルタと違って更新可能なパラメータが出てこないので、特に訓練により更新されるパラメータはありません。

この項のまとめ

識別部

 上記の特徴抽出部にて抽出された特徴量を使って、その画像がどのカテゴリに属するかを判断する、つまりパターン分類を行うのが後半の識別部です。 専門用語では「多層パーセプトロン」(multi-layer perceptron)と呼ばれる分類器がここに入っています。 CNNにおいては、この多層パーセプトロンにおける1つ1つの層のことを全結合層(fully connected layer)と呼んでいます。 これらを総合すると、CNNとは、入力画像に対し、「畳み込み層」「プーリング層」の繰り返しにより特徴量を抽出した後、「全結合層」の繰り返しによりパターン分類を行うシステムということができるでしょう。 
再びCNNの構造の図を出しますが、○が縦にずっと並んでいるもの1列をひとつの全結合層と数えます。そして、それぞれ一つ一つの○のことをユニット(unit)またはニューロン(neuron)と呼びます。 後者は、ニューラルネットが動物の脳の働きを真似て作られたものであることから、神経細胞を意味するニューロンになぞらえて名づけたものです。ここではユニットと呼びます。
 一番最後の全結合層は出力を直接出すので出力層(output layer)と呼ばれていて、先ほど説明したように、それぞれ対応するカテゴリである確率がそこに出てきます。 そのため、ここはカテゴリの数と一致している必要があります。例えば、犬、猫、人の判断をしたい場合は、出力層のユニットの数は3でなければなりません。 このことから、我々はCNNであらかじめ何を判別させたいのか決めておかなければなりません。 これは、言い換えると、例えば犬、猫、人を判断するように訓練されたネットワークならば、猿の画像を入れても勝手に猿を新しいカテゴリとしては認識してくれず、強制的に犬・猫・人のどれかとして出力することを意味します。 もし猿も認識させたいのならば、出力層のユニットの数は4つにしておき、かつ猿の画像を含む訓練用データセットにより訓練を行っている必要があります。

この項のまとめ

全結合層

 全結合層の振る舞いをもう少しだけ詳しく見てみます。まず、全結合層はユニット(○)が複数個一列に並んで構成されています。 この数は、出力層の場合は分類したいカテゴリと一致する必要があるものの、それ以外の場合は特に決まりはありません。なので、500個や1024個、4096個といった数を自分で決めて用意します。
 図とその名前でなんとなく想像がつくように、1つのユニットは、前の層の全てのユニットと結合されています。 例えば1番目の全結合層のユニットの数が1024の場合、2番目の全結合層のユニットは、それぞれが1番目の全結合層の1024個とつながっています。 したがって、2番目の全結合層にたった4個しかユニットがなくても、$1024 \times 4 = 4096$ 個もの結合を有することになります。 前回紹介した、1000種類のカテゴリを分類することが目的の A.Krizhevsky らによる AlexNet は、出力層の直前で、4096個のユニットをもつ全結合層を2つも重ねているため、この部分だけで$4096^2 = 16777216$ 個という、莫大な数の結合を持っていることになります。 そして、その結合一つ一つに対して更新可能なパラメータ(重み, weight)が割り当てられています。つまり、ここだけで1600万個ものパラメータがあるというわけです。
 全結合層の計算は単純です。一般の場合でも同じなので、3つのユニットを持つ層1から3つのユニットを持つ層2へどのように情報が伝達されるかを見てみます。
模式図としてはこのように書けるでしょう。それぞれのユニットは、前の層、あるいは次の層の全てのユニットと結合をしています。そして、1つの結合につき専用の更新可能なパラメータ、つまり重みが割り当てられています。 図の場合は、$3 \times 3 = 9$ 個の重みが存在しています。
第二層の1つめのユニットを計算したい場合はこう書けます。ここで1つめ、2つめのユニットというのは、図で見た時に上から1つめ、2つめであることに対応するものとします。 それぞれに専用の更新可能なパラメータ、重みがあるわけですが、これは$w_{ij}$という風に書いてあります。 例えば $w_{21}$ というのは、第一層の2番目のユニットから第二層の1番目のユニットに対する重みという意味です。
 これではわかりにくいので、出力と重みを実際の数字に置き換えて確認します。
このとき、現在注目している第二層の1番目のユニットの入力は、前の層のそれぞれのユニットの出力と重みをかけあわせ、足し算したものになります。 畳み込み層の時にも出てきた「内積」という計算です。 例えば上の場合、第二層の1番目のユニットは
$1 \times 5 + 1 \times 1 + 4 \times 4 = 22$
という値を受け取るわけです。
 ただし、実際には、1つのユニット計算する際、パラメータはこの3つに対して1つ増えます。 それは、よりネットワークの表現力を高めるため、バイアスと呼ばれる「原点からの浮き」のようなものを表す要素が、こうして計算された値に加えられているからです。 よく直線の方程式を $y=ax+b$ とか書いたと思いますが、この時の $b$ のようなものです。 このバイアスも、1つのユニットごとに専用でパラメータとして用意されるため、結局、第二層のユニット1つ1つが、第一層からの出力に対する重み3つとバイアス1つの合計4つの更新可能なパラメータを持つことがわかります。
 こうしてユニットの入力値を「重みとの内積+バイアス」によって得た後、最後に活性化関数(activation function)と呼ばれる関数に通して出力とします。 簡単に言うと活性化関数を通すことで「出力を複雑化」しています。専門用語で言うと「非線形性」というのを高めています。 これによって何が嬉しくなるかですが、これも簡単に言えば「ネットワークの表現力が向上」するのです。 つまり、そのままユニットの入力値を出力にした場合、人と犬と猫を分けられるような計算が再現できないかもしれないところ、活性化関数を挟んで表現力を向上させることで、再現できやすくしています。

この項のまとめ

活性化関数

 活性化関数をユニットの入力に対して適用することで、最終的な出力にします。これにより、ネットワークの表現力を高める働きがあります。 しかしながら、関数なら何でもよいかというとそうでもなく、うまく訓練ができるようないくつかの関数が知られており、それらが主に用いられます。 典型的な多クラス分類CNNを操作する限り、知っておかなければならない関数は2つで、それはReLUと呼ばれる関数と、ソフトマックスと呼ばれる関数です。
 ReLUとは、Rectified Linear Unit の頭文字をとったもので、名前が難しそうですが非常に簡単です。 それは単純に、入力が0より大きければそのまま出力とし、0より小さければ0にして出力するというものです。 無理やり式で書くと
$y = \max(0,x)$
です。多クラス分類の場合、従来はシグモイド関数 $f(x) = 1/(1+e^{-x})$ と呼ばれるものが使われてきましたが、ReLU関数の方がうまく学習ができることから、こちらが主流となりました。 面倒な場合は、「とりあえずReLUとかいうものを指定しておけば大丈夫」とだけ覚えておいてください。
 一方でソフトマックス関数は、出力層に対してのみ用いられる特別な活性化関数で、その層の出力値の組み合わせを確率に変換します。 今までの計算は単純な掛け算足し算で、出力が必ず 0〜1、全部足したら 1 になる確率として出てくる保証は全くありません。 なので、出力値を 0〜1、その層の出力値を全部足せば 1 (100%) になるよう変換するための関数がソフトマックス関数というわけです。 特別な活性化関数と書いたのは、通常活性化関数はユニットの入力に対して作用する1変数関数なのですが、ソフトマックスはその層の全部の値を考慮して各ユニットの値を決めているからです。 細かい話は忘れるにしても、「とりあえず出力はソフトマックスという名前の関数、あとはReLUという名前の関数にしておけば大丈夫」とだけ覚えておいてください。
 なお、畳み込み層、プーリング層についても活性化関数は同様な原理で適用可能ですが、こちらの場合、プーリング層自体が活性化関数的な役割(非線形性の付与)を持っていることから、必ずしもこれらに活性化関数を通す必要はないようです。 実際、Caffeの場合、明示的に書かない限りは畳み込み層とプーリング層、全結合層に活性化関数は適用されず、各サンプルでも、ほとんどの場合、全結合層以外の層に活性化関数は使っていないようです(詳細はこちら)。

この項のまとめ

ここまでのまとめ

ここまでで、以下に示す典型的な多クラス分類CNNの構造、および各設定項目について説明しました。
また、CNNは分類を行うために必要な情報である特徴量を画像から抽出する特徴抽出部と、それらの特徴量を元にパターン分類を行う識別部に分かれることを説明し、 特徴抽出部においては、畳み込みフィルタを任意枚数備えた畳み込み層、位置に対する感度を下げるかわりに位置変化に対する認識能力を向上させるプーリング層からなることを説明しました。 そして特に畳み込み層は、主に奇数サイズで正方形のフィルタが複数枚あり、その枚数と同じだけの出力画像が得られ、また畳み込みという演算は、処理後の各点の値を決定するのに他の点の値も考慮する計算であることを説明した後、 プーリング層においては、一定のサイズの領域ごとの最大値を代表値とするMAXプーリングを用いるのが主であり、その刻み幅(ストライド)に応じて出力サイズが小さくなることを説明しました。
 一方で識別部は多層パーセプトロンと呼ばれる識別器からなっており、中身は全結合層が複数連なっているものであることを説明しました。 全結合層の各ユニットは前の層の全てのユニットと結合を持ち、それぞれにパラメータが独立に割り当てられていて、そのパラメータと前の層の出力とで計算を行った後、活性化関数と呼ばれる関数を通すことでネットワークの表現力を高めることを説明しました。 最後に、活性化関数は主にReLUという関数が用いられ、出力層は確率にするためソフトマックスと呼ばれる関数が用いられていることを説明しました。

誤差関数

 ここまでの説明は、CNNに画像を入力した時、どのような出力が得られるかという話でした。 前回も書いたように、CNNは、そのように出した出力と、理想の出力値との違いを数値化してパラメータを自動更新することで未知データに対応できるようになっていきます。
 例えば人、犬、猫を分類したい場合、出力は3つあり、それぞれ人である確率が0〜1 (100%)、犬である確率が0〜1, 猫である確率が0〜1として、3つ合わせると1.0(100%)になるような形で出力されます。 もちろん犬と猫を迷った場合は $[0, 0.4, 0.6]$ といった類の出力もあり得ます。もし答えが猫ならば、理想の答えは $[0, 0, 1]$ のはずです。 そこで、現在のパラメータにおいて得られた出力と理想の答えとの違いを誤差関数(loss function)というもので数値化させます。
 訓練用のデータセットがあるとき、全部のデータを通した時の誤差の合計が小さければ小さいほど、理想のネットワーク、つまりうまくネットワークが学習できているといえます。 なぜなら、理想のデータと同一なら、誤差は生じない、つまり0だからです。 そのため、我々は何らかの形で誤差関数を定義して誤差の大きさを算出し、それを小さくする、つまり最小化させる必要があります。 結局のところ、答えと全く一緒であれば0、違えば違うほど大きければよいので、誤差関数として様々な形態が考えられますが、画像分類においては交差エントロピー誤差関数(cross-entropy loss function)と呼ばれるものが用いられます。 詳しく書くと数式が出てきてしまうので省略しますが、交差エントロピー誤差関数を最小化することは「画像を入力した時、理想の答えが得られる見込み」を最も大きくすることに相当します。 Caffeを使う限りは、この関数について詳しく立ち入る必要はないので、ここではやはり「交差エントロピー誤差関数とかいうもので間違いを数値化している」とだけ覚えておきましょう。

この項のまとめ

勾配降下法(GD)

入力データと理想のデータ、つまり正解データとの誤差を数値化したものが誤差関数ですが、それともとに、その誤差関数を小さくなるようパラメータを更新しなければなりません。 つまり、適当に決まっていた重みやバイアスといったパラメータの値を、誤差が小さくなるように変化させる必要があるということです。
 実は、この誤差を小さくできる方法が存在します。それが勾配降下法 (gradient descent method)です。略して GD とも呼ばれます。 簡単に言うと、誤差関数 $E$ に対する勾配 $-\nabla E$ というものを計算をしますが、$\nabla$が顔文字の口にしか見ない人は、別にそれでも実用上はかまいません。 勾配というものは、勾配をとる点からみて、わずかに進んだとき、幾何的に関数が最も小さくなるような方向を向くベクトル(方向を持った矢印)になることが知られています。 意味がわからない場合は、放物線 $y=x^2$ を思い浮かべてみてください。この関数の勾配を取ると、関数を図形に見立てた時、現在地点に対して必ず小さくなる方向、つまり現在地点から、確実に標高の低い場所に降りられるための次の1歩の方向が分かるという意味です。 そこで、この勾配に対して適当に小さな値 $\varepsilon$ をかけ、現在のパラメータに $-\varepsilon \nabla E$ を加えることで、誤差関数は必ず小さくなるというのが勾配降下法です。
 $-\nabla E$ で小さくなるなら、そのまま足すか、むしろ小さな値でなく100や1000をかけて足せばいいと思ったのであればそれは間違いです。 なぜなら、勾配というのは微分の一種であり、現在地点から「わずかに」進んだ時、確実に標高を下げられるというものだからです。 したがって、進む量を「1歩」にするために $\varepsilon$ という小さい値をかける必要があります。この値はいくつであるべきだというものはなく、場合によって自分で適当に設定するパラメータ(ハイパーパラメータ)です。 CNNでは0.01や0.001といった値が良いスタート地点になるでしょう。ニューラルネットの世界では、このパラメータを学習率(learning rate)と呼びます。 この値が大きすぎると、必ずしも誤差関数が小さくなるとは限らないので誤差が全く減らない現象に遭遇する、つまり学習がそもそもできないおそれがあります。 逆に小さすぎる場合、学習はできるでしょうが、無駄に進みが遅く、時間を要してしまうという悪影響が考えられます。最初は適当な値を設定しておき、もし学習が遅かったりする場合は、自分で値を調節して妥協ラインを見つけましょう。
 一応、$\nabla$が顔文字ではなくてベクトルの微分記号であることを知っている人のために、これは比較的手短に説明できるため、学習率が微少でなければならない理由を書いておきます。分からない場合は読み飛ばしてもなんら問題ありません(今後二度と使わないので)。
$\nabla f$はその定義から微少移動を示すベクトルである $d\boldmath{r}$との内積を取ると、スカラー関数 $f$ の全微分になることが知られています。すなわち
$df = \nabla f \cdot d \boldmath{r}$
と書くことができます。ただし、微少移動量というのは数学で議論する際の便利な記号にすぎず、コンピュータで実現するなら具体的な値を指定する必要があります。 そこで、具体的に移動する量を $d \boldmath{r} = -\varepsilon \nabla f$ と選ぶと、誤差関数の微少変化量に相当する $df$ は
$df = - \varepsilon |\nabla f|^2$
と書けます。つまり、 $ |d \boldmath{r}|$ が微少量とみなせる限りは、全微分 $df$ は必ず負になるため、誤差関数が減少することが保証されます。 これを微少量にするために $\varepsilon$ は小さくなければならない、ということです。大きくなってしまうと、そもそも内積の結果が全微分 $df$ に一致するという前提が崩れるため、誤差関数が減ることは保証されなくなります。

この項のまとめ

確率的勾配降下法(SGD)

 これで自動でパラメータが更新できるようになってめでたしかというと、そうはいきません。確かにこれで訓練はできるのですが、訓練データの数を考えてみてください。 今回の場合、MNISTでも訓練データは60,000点あります。つまり、60,000個分全体の誤差を計算しないと誤差の減る方向が分からないといっているのです。 この計算量は莫大で、しかもデータ自体、メモリに収まりきらないおそれがあります。
 そこで、その問題を解決するため、ニューラルネットでは確率的勾配降下法 (stochastic gradient descent method) 略して SGD と呼ばれる方法が採用されています。 全部のデータを使えば誤差が小さく方向がわかるが、それではメモリや計算量コストの問題があります。 SGDは、全データの中から少数のサンプルだけを抜き出し、その時の誤差を全体の誤差とみなしてパラメータを更新する方法です。 パラメータ更新の計算コストが小さく、学習の際のメモリ消費量が押さえられるという利点があります。
 また、例えば60,000点ある中の64点だけ抜き出して全体の誤差としたのでは、明らかに全体を確実に代表できる保証もないので、パラメータが思いもよらぬ風に更新される可能性があります。 これは必ずしも悪いことではなく、もちろん誤差が増えてしまうことも多々ありますが、落とし穴にハマって本当の底ではないところで行き詰まってしまった場合でも、偶然に抜け出せる可能性があることを意味します。
 この時の全体を代表させる一定数、上の例で言う64という数のことをバッチ数(batch size)と呼びます。バッチ数64の場合は、64個に対して誤差を計算し、その64個毎に同時にパラメータも更新するというわけです。 この1セットのことを1バッチと呼びます。バッチ対して、データセット全体、上の例の場合でいう60,000個のことを1エポックと呼びます。
 なお、SGDによりパラメータは更新できるのですが、一般に何十万、何百万またはそれ以上のパラメータがあるニューラルネットワークに対してこの誤差関数の勾配を計算することは容易ではありません。 実際には勾配が個別に直接計算されているのではなく、誤差逆伝搬法(バックプロパゲーション)というテクニックにより、勾配を間接的に単純計算で高速に求めてパラメータを更新しています。 勾配を求めるための変数が出力層から得られ、次にその値を使うことで出力層の手前の勾配を求めるための変数が得られ・・・というように、出力から入力に向けて勾配が求まるために、このような名前が付いています。 ここでは数学やコンピュータアルゴリズムを習得することが目的ではないので、概説的な内容にとどめておきます。実用上はバッチサイズのことさえ知っておけば後は忘れても十分です。

この項のまとめ

今回のまとめ

 これでCNNの構造と学習の際に必要なハイパーパラメータについてひと通り紹介しました。次は、実際にCaffeが読み込める形式(prototxt)でそれらを書いていきます。

その他の記事

コメント

名前 :
電子メール :
URL :
コメント