機械学習
この演習では、ニューラル・ネットワークのバックプロパゲーションのアルゴリズムを実装し、それを手書き数字の認識のタスクに適用します。 プログラミング演習を始める前に、ビデオ講義を見て、関連トピックの復習の問題を完了することを強くお勧めします。
演習を開始するには、スターター・コードをダウンロードし、演習を行うディレクトリーにその内容を解凍する必要があります。
必要に応じて、この演習を開始する前にOctave/MATLABのcd
コマンドを使用して、このディレクトリーに移動してください。
また、コースウェブサイトの「環境設定手順」にOctave/MATLABをインストールするための手順も記載されています。
ex4.m
- 演習の手順を示すOctave/MATLABスクリプトex4data1.mat
- 手書きの数字のトレーニング・セットex4weights.mat
- 演習4のニューラル・ネットワーク・パラメーターsubmit.m
- 解答をサーバーに送信するスクリプトdisplayData.m
- データセットを可視化するための関数fmincg.m
- 最小化ルーチンの関数(fminunc
と同様)sigmoid.m
- シグモイド関数computeNumericalGradient.m
- 数値的に勾配を計算するcheckNNGradients.m
- 勾配の確認に役立つ機能debugInitializeWeights.m
- ウェイトを初期化する関数predict.m
- ニューラル・ネットワークの予測関数- [*]
sigmoidGradient.m
- シグモイド関数の勾配を計算する - [*]
randInitializeWeights.m
- ランダムにウェイトを初期化する - [*]
nnCostFunction.m
- ニューラル・ネットワークのコスト関数
* はあなたが完了する必要があるものを示しています
演習では、スクリプトex4.m
を使用します。
このスクリプトは、問題に対するデータセットをセットアップし、あなたが実装する関数を呼び出します。
このスクリプトを変更する必要はありません。
この課題の指示に従って、他のファイルの関数を変更することだけが求められています。
このコースの演習では、数値計算に適した高度なプログラミング言語であるOctave(※1)またはMATLABを使用します。 OctaveまたはMATLABがインストールされていない場合は、コースWebサイトのEnvironment Setup Instructionsのインストール手順を参照してください。
Octave/MATLABコマンドラインでは、help
の後に関数名を入力すると、組み込み関数のドキュメントが表示されます。
たとえば、help plot
はプロットのヘルプ情報を表示します。
Octave関数の詳細なドキュメントは、Octaveのドキュメントページにあります。
MATLABのドキュメントは、MATLABのドキュメントページにあります。
また、オンライン・ディスカッションを使用して、他の学生との演習について話し合うことを強く推奨します。 しかし、他人が書いたソースコードを見たり、他の人とソースコードを共有したりしないでください。
※1:Octaveは、MATLABの無料の代替ソフトウェアです。 プログラミング演習は、OctaveとMATLABのどちらでも使用できます。
前回の演習では、ニューラル・ネットワーク用のフィードフォワード・プロパゲーションを実装し、手書き数字の予測のために、それを与えられたウェイトとともに使用しました。 この演習では、バックプロパゲーションのアルゴリズムを実装して、ニューラル・ネットワークのパラメーターを学習します。
提供されたスクリプトex4.m
は、この演習を段階的に手助けします。
ex4.m
の最初のパートでは、関数displayData
を呼び出すことによって、データをロードし、2次元プロット上(図1)に表示します。
図1:データセットのサンプル
これは、前の演習で使用したデータセットと同じデータセットです。
ex4data1.mat
には5000個のトレーニング・サンプルがあり、各トレーニング・サンプルは数字の20×20ピクセルのグレースケール画像です。
各ピクセルは、その位置におけるグレースケール強度を示す浮動小数点数によって表されます。
20×20グリッドのピクセルは、400次元のベクトルに「アンロール」(展開)されます。
これらのトレーニング・サンプルは、それぞれデータ行列の1行になります。
つまり、各行が手書きの数字画像のトレーニング・サンプルである5000×400の行列X
が与えられます。
トレーニング・セットの2番目の部分は、トレーニング・セットのラベルを含む5000次元のベクトルy
です。
ゼロインデックスがないOctave/MATLABインデックスとの互換性を高めるために、数字の0を10にマッピングしました。
したがって、数字の「0」は「10」とラベル付けされ、数字の「1」〜「9」はそのままの順序で「1」〜「9」とラベル付けされます。
この課題のニューラル・ネットワークを図2に示します。
3つの層(入力層、隠れ層および出力層)を有します。
入力は、数字の画像のピクセル値であることを思い出してください。
イメージのサイズは20×20であるため、入力層ユニットは400個となります(常に+1を出力する追加のバイアスユニットは数えません)。
トレーニング・データは、ex4.m
スクリプトによって変数X
およびy
にロードされます。
すでにトレーニングされた一連のネットワーク・パラメーター(、)が提供されています。
これらはex4weights.mat
に格納され、ex4.m
によってTheta1
とTheta2
にロードされます。
パラメーターは、第2層に25ユニット、出力ユニット10個(10桁のクラスに対応)のニューラル・ネットワーク用にサイズが決められています。
% ファイルから保存された行列をロードする
load('ex4weights.mat');
% 行列Theta1とTheta2がワークスペースにロードされます
% Theta1のサイズは25 x 401です
% Theta2のサイズは10 x 26です
図2: ニューラル・ネットワークモデル
ここでは、ニューラル・ネットワークのコスト関数と勾配を実装します。
まず、コストを返すためにnnCostFunction.m
のコードを完成させます。
ニューラル・ネットワークのコスト関数(正則化なし)は、以下であることを思い出してください。
ここで、図2に示すようにが計算され、は可能なラベルの総数です。
なお、は番目の出力ユニットのアクティベーション(出力値)です。
また、元のラベル(変数y
内の)はであるのに対して、ニューラル・ネットワークをトレーニングする目的で、0または1の値だけを含むベクトルとしてラベルを実装し直す必要があることを思い出してください。
つまり、
たとえば、が数字5の画像である場合、対応する(コスト関数とともに使用する必要があります)は、の10次元ベクトルであり、他の要素はすべて0です。 すべてのサンプルに対してを計算し、コストを合計するフィードフォワード計算を実装する必要があります。 あなたのコードは、任意の数のラベルを持つ任意のサイズのデータセットに対しても機能するはずです (少なくとものラベルがあると仮定できます)。
行列X
の行にサンプルが含まれています(つまり、X(i,:)
は番目のトレーニング・サンプルで、のベクトルで表されます)。
nnCostFunction.m
のコードを完成させるには、X
の行列に1の列を追加する必要があります。
ニューラル・ネットワークの各ユニットのパラメーターは、Theta1
とTheta2
の1行で表されます。
特に、Theta1
の1行目は、2番目の層の最初の隠れユニットに対応します。
サンプルに対してforループを使用すると、コストを計算できます。
完了したら、ex4.m
は、ロードされたTheta1
とTheta2
のパラメーターのセットを使用してnnCostFunction
を呼び出します。
コストは約0.287629
です。
ここで解答を提出する必要があります。
ニューラル・ネットワークの正則化されたコスト関数は、以下によって与えられます。
ニューラル・ネットワークは入力層、隠れ層、出力層の3つの層しか持たないと仮定できます。
しかし、あなたのコードは、任意の数の入力ユニット、隠れユニット、出力ユニットに対して機能するはずです。
明確にするために上記の指標をとに明示していますが、コードは一般にとの任意のサイズで機能するはずです。
バイアスに対応する項を正則化すべきではないことに注意してください。
Theta1
とTheta2
が行列の場合、これは各行列の最初の列に対応します。
これで、コスト関数に正則化を追加できたはずです。
まず、既存のnnCostFunction.m
を使用して非正則化コスト関数を計算し、その後、正則化項に対するコストを追加することができます。
完了したら、ex4.m
は、ロードされたパラメーターのセットTheta1
とTheta2
、およびを使用して、nnCostFunction
を呼び出します。
コストは約0.383770
です。
この演習では、バックプロパゲーションのアルゴリズムを実装して、ニューラル・ネットワークのコスト関数の勾配を計算します。
grad
に対して適切な値を返すように、nnCostFunction.m
を完成する必要があります。
勾配を計算すると、fmincg
などの高度なオプティマイザーを使用してコスト関数を最小化することにより、ニューラル・ネットワークをトレーニングすることができます。
最初にバックプロパゲーションのアルゴリズムを実装して、(正則化されていない)ニューラル・ネットワークのパラメーターの勾配を計算します。
正則化されていないケースの勾配の計算が正しいことを確認したら、正則化されたニューラル・ネットワークの勾配を実装します。
演習のこのパートを始めるために、まずシグモイド勾配関数を実装します。シグモイド関数の勾配は、次のように計算できます。
ここで
完了したら、Octave/MATLABコマンドラインでsigmoidGradient(z)
を呼び出して、いくつかの値をテストしてみてください。
z
(の絶対値)が大きな値(正と負の両方で)であれば勾配は0に近い値に、z = 0
であれば勾配は正確に0.25
になるはずです。
コードはベクトルと行列でも動作する必要があります。
行列の場合、作成した関数はすべての要素に対してシグモイド勾配関数を実行する必要があります。
ここで解答を提出する必要があります。
ニューラル・ネットワークをトレーニングする場合、対称性の破壊のためにパラメーターをランダムに初期化することが重要です。
ランダムな初期化のための1つの効果的な方策は、の値をにすることです。
を使うべきです(※2)。
この値の範囲は、パラメーターを小さく保ち、学習をより効率的にします。
あなたがすべきことは、randInitializeWeights.m
を完成させてのウェイトを初期化することです。
ファイルを変更し、次のコードを入力します。
% ウェイトを小さい値にランダムに初期化する
epsilon_init = 0.12;
W = rand(L_out, 1 + L_in) * 2 * epsilon_init - epsilon_init;
この演習では、コードを提出する必要はありません。
※2:を選択するための1つの効果的な戦略は、ネットワークのユニット数を基にすることです。 の良い選択は、であり、ここで、とは、に隣接する層のユニットの数です。
図3: バックプロパゲーションの更新
では、バックプロパゲーションのアルゴリズムを実装しましょう。 バックプロパゲーションのアルゴリズムの背後にある直観は、次の通りであることを思い出してください。 トレーニング・サンプル(、)が与えられた場合、ネットワーク全体のすべてのアクティベーションを計算するために、まず「フォワードパス(forward pass)」を実行します(仮説の出力値を含んでいます)。 次に、層の各ノードに対して、誤差項を計算します。 誤差項は、出力における誤差についてノードがどれくらい責任を持っていたかを測定するものです。
出力ノードについては、ネットワークのアクティベーションと真の目標値の差を直接測定し、それを使ってを定義することができます(3層は出力層なので)。 隠れユニットについては、()層のノードの誤差項の加重平均に基づいてを計算します。
詳細については、ここにバックプロパゲーションのアルゴリズムがあります(図3にも示されています)。
一度に1つのサンプルを処理するループ内に、手順1~4を実装する必要があります。
具体的には、番目のトレーニング・サンプル(、)の計算を実行するforループ(for t = 1:m
)の中に、以下の手順1~4を実装します。
手順5は、累積された勾配をで除算して、ニューラル・ネットワークのコスト関数の勾配を得ます。
-
入力層の値()を番目のトレーニング・サンプルに設定します。 フィードフォワード・パスを実行し、2層と3層のアクティベーション(、、、)を計算します。 層と層のアクティベーションのベクトルにもバイアスユニットが含まれていることを保証するために、+1の項を追加する必要があります。 Octave/MATLABでは、
a_1
が列ベクトルの場合、1を加算するとa_1 = [1; a_1]
です。 -
ここで、は、現在のトレーニング・サンプルがクラス()に属するか、またはそれが異なるクラス()に属するかを示します。 このタスクに役立つ論理的な配列があります(前回のプログラミング演習で説明しました)。
-
次の式を使用して、このサンプルの勾配を累積します。
をスキップまたは取り除く必要があることに注意してください。 Octave/MATLABでは、を取り除くことは、
delta_2 = delta_2(2:end)
に相当します。 -
累積された勾配をで割ることにより、(正則化されていない)ニューラル・ネットワークのコスト関数の勾配を得ることができます。
バックプロパゲーションのアルゴリズムは、フィードフォワードおよびコスト関数を正しく完成させた後で実装すべきです。
バックプロパゲーションのアルゴリズムを実装する際に、size
関数を使用して、次元の不一致エラー(Octave/MATLABのnonconformant arguments
エラー)が発生した場合は、作業している変数のサイズを出力すると便利です。
バックプロパゲーションのアルゴリズムを実装すると、スクリプトex4.m
は、実装した勾配チェックを実行します。
勾配チェックは、実装したコードが勾配を正しく計算していることを確認できます。
ニューラル・ネットワークで、コスト関数を最小にしています。 パラメーターの勾配チェックを実行するために、パラメーター、を長いベクトルに「アンロール」することが考えられます。 そうすることで、コスト関数をと考えることができ、次の勾配チェックの手順を使用することができます。
確証はないがを計算するはずの関数があり、 が正しい微分値を出力しているかどうかを確認したいとします。
とすると、その番目の要素がだけ増加されている点を除けば、はと同じです。 同様に、は、番目の要素がだけ減少したベクトルに対応します。 各について、の正しさを次のように数値で検証することができます。
これらの2つの値が互いに近似する程度は、の詳細さに依存します。
しかし、と仮定すると、通常、上記の左辺と右辺は少なくとも4桁の有効数字で一致します(そして多くの場合、さらに多くの桁で一致します)。
computeNumericalGradient.m
の数値的勾配を計算する関数を実装しました。
ファイルを変更する必要はありませんが、どのように動作するかを理解するために、コードを確認してください。
ex4.m
の次のステップでは、与えられた関数checkNNGradients.m
を実行します。
この関数は、勾配のチェックに使用される小さなニューラル・ネットワークとデータセットを作成します。
バックプロパゲーションの実装が正しい場合は、1e-9より小さい相対的な差があるはずです。
勾配チェックを実行するときは、比較的少数の入力ユニットと隠れユニットを持つ小さなニューラル・ネットワークを使用する方がはるかに効率的です。
の各次元はコスト関数の2つの評価を必要とし、これは高価になる可能性があります。
関数checkNNGradients
の中のコードは、勾配チェックのためにcomputeNumericalGradient
とともに使用される小さくランダムなモデルとデータセットを作成します。
さらに、勾配計算が正しいことを確信したら、学習アルゴリズムを実行する前に勾配チェックをオフにする必要があります。
勾配チェックは、コストと勾配を計算しているすべての関数で機能します。
具体的には、同じcomputeNumericalGradient.m
関数を使用して、他の演習の勾配の実装が正しいかどうかを確認することもできます
(ロジスティック回帰のコスト関数など)。
実装したコスト関数が(正則化されていない)ニューラル・ネットワークのコスト関数の勾配チェックをパスしたら、ニューラル・ネットワークの勾配関数(バックプロパゲーション)を提出する必要があります。
バックプロパゲーションのアルゴリズムを正常に実装したら、勾配に正則化を追加します。 正則化を含めるために、バックプロパゲーションを使用して勾配を計算した後で、これを付加項として追加できることになります。
具体的には、バックプロパゲーションを使用してを計算した後で、以下を使用して正則化を追加する必要があります。
バイアス項に使用されるの最初の列を正則化すべきではないことに注意してください。 さらに、パラメーターにおいて、は1からインデックスされ、は0からインデックス付けされます。したがって、
少し紛らわしいですが、Octave/MATLABでのインデックス付けは1から始まります(との両方で)。
したがって、Theta1(2,1)
は実際にに対応します(つまり、上記行列の第2行、第1列)。
今度は、正則化を考慮に入れて、nnCostFunction
のgrad
を計算するコードを修正してください。
完了後、ex4.m
スクリプトは、実装の勾配チェックを実行します。
コードが正しければ、1e-9より小さい相対的な差異が見られるはずです。
ここで解答を提出する必要があります。
ニューラル・ネットワークのコスト関数と勾配の計算を正常に実装した後の、ex4.m
スクリプトの次のステップでは、fmincg
を使用して適切なパラメーターを学習します。
トレーニングが完了したら、ex4.m
スクリプトは適切なサンプルの割合を計算することによって、分類器のトレーニング精度を報告します。
実装が正しい場合、報告されたトレーニングの精度は約95.3
%です(これは、ランダム初期化のために約1%変化する可能性があります)。
より多くの反復でニューラル・ネットワークをトレーニングすることにより、より高いトレーニング精度を得ることが可能です。
反復回数を増やしたり(たとえば、MaxIter
を400に設定)、正規化パラメーターを変更して、ニューラル・ネットワークをトレーニングすることをお勧めします。
正しい学習設定であれば、ニューラル・ネットワークをトレーニング・セットに完全にフィットさせることができます。
ニューラル・ネットワークが何を学習しているかを理解する方法の一つは、隠れユニットによってどのような表現がキャプチャーされたかを可視化することです。 平たく言えば、特定の隠れユニットが与えられた場合、それが何を計算するかを可視化する1つの方法は、それが活性化する(すなわち、アクティベーション値を1に近づける)入力を見つけることです。 トレーニングしたニューラル・ネットワークでは、の番目の行は、番目の隠れユニットのパラメーターを表す401次元ベクトルです。 バイアス項を取り除くと、各入力ピクセルから隠れユニットまでの重みを表す400次元のベクトルが得られます。
したがって、隠れユニットによって捕捉された「表現」を可視化する1つの方法は、この400次元のベクトルを20×20画像に再形成して表示することです(※3)。
ex4.m
の次のステップでは、displayData
関数を使用してこれを行い、25個のユニットを持つ画像(図4と同様)を表示します。
各ユニットは、ネットワーク内の1つの隠れユニットに対応しています。
トレーニングされたネットワークでは、隠れユニットは入力のストロークやその他のパターンを探す検出器に大まかに対応していることが分かります。
図4:隠れユニットの可視化
※3:これは、入力に対して「ノルム」制約が与えられていること(すなわち、)と、隠れユニットに対して最も高いアクティベーションを与える入力を見つけることと等価であることが分かります。
この演習では、ニューラル・ネットワークのさまざまな学習設定を試して、正則化パラメーターとトレーニングステップ数(fmincg
を使用する場合のMaxIter
オプション)によってニューラル・ネットワークのパフォーマンスがどのように変化するかを確認します。
ニューラル・ネットワークは非常に複雑な決定境界を形成することができる非常に強力なモデルです。
正則化がなければ、ニューラル・ネットワークはトレーニング・セットを「オーバーフィット」する可能性があり、トレーニング・セットの100%に近い精度を得ることができますが、それまで見たことのない新しいサンプルには適合しません。
正則化を小さな値に、MaxIter
パラメーターをより多くの反復回数に設定して、確認ができます。
学習パラメーターとMaxIter
を変更すると、隠れユニットの可視化の変化を自分で確認することもできます。
これらのオプション(非評価)の演習問題の解答を提出する必要はありません。
この課題が完了したら、送信機能を使用して解答を我々のサーバーに送信してください。 以下は、この演習の各パートの得点の内訳です。
パート | 提出するファイル | 点数 |
---|---|---|
フィードフォワードとコスト関数 | nnCostFunction.m |
30 点 |
正則化コスト関数 | nnCostFunction.m |
15 点 |
シグモイド勾配 | sigmoidGradient.m |
5 点 |
ニューラルネット勾配関数(バックプロパゲーション) | nnCostFunction.m |
40 点 |
正則化勾配 | nnCostFunction.m |
10 点 |
合計点 | 100 点 |
解答を複数回提出することは許可されており、最高のスコアのみを考慮に入れます。