[ 機械学習 ] MNISTデータの画像認識実装(ライブラリ不使用) 1.知識まとめ~データの準備まで

[ 機械学習 ] MNISTデータの画像認識実装(ライブラリ不使用) 1.知識まとめ~データの準備まで

本記事では、学習機能を伴ったニューラルネットワークを作成し、実際に画像認識を行なってみます。

機械学習のライブラリを使用した場合は比較的簡単にネットワークを作成することができますが、今回の目的は機械学習についての理解を深めることにあるため、基本的にライブラリは使用せずにネットワークを作成していきます。

ライブラリを使用しての実装は、また次の記事などで行なっていきます。

ここまでのまとめ

いきなりまとめと言うのもおかしな話ですが、今までいくつか機械学習における機能についての解説を行なってきたのでそのまとめを最初に行いたいと思います。

ニューラルネットワーク

機械学習では、パーセプトロン・モデルにヒントを得たニューラルネットワークと言うプログラム構造を利用します。
パーセプトロンには入力層と出力層しか有りませんが、ニューラルネットワークにはさらにその間に多数の隠れ層と呼ばれるノードが存在し、さらに複雑な処理を行うことができるのでした。

[ 機械学習 ] 2層ニューラルネットワークの実装 (簡易版)

重みとバイアス

パーセプトロンにしてもニューラルネットワークにしても、入力が層から層へ渡される時には、重みを掛け合わせてバイアスを足し上げる、と言う処理が行われます。
これら重みとバイアスを、パラメータと呼びます。パラメータを調整することでモデルの出力値が変動しますので、モデルを最適化するにはこれらのパラメータを変化させることが必要になります。

[ 機械学習 ] 単層パーセプトロンの実装

活性化関数

ニューロンには、前の層からの出力に重みを掛け合わせバイアスを足し上げたものが渡されます。
この値を次のニューロンに渡す前に、各ニューロンはこれに対して活性化処理を行います。この時使用されるのが活性化関数です。
隠れ層間のやり取りではシグモイド関数やReLU関数など入力値を分散させる活性化関数が用いられ、隠れ層と出力層間では、値を確率に変換するソフトマックス関数などが用いられます。

[ 機械学習 ] 活性化関数の実装 (ステップ関数、シグモイド関数、ReLU関数、ソフトマックス関数)

 

損失関数

モデルが出力した値が適切な値であるかを判断するためには、その出力と正解データを比較する必要が有ります。この比較処理において、どれだけモデル出力が適切であるかを判定するものが損失関数です。モデル出力と正解データが大きく乖離している時には損失は大きくなり、逆に出力と正解が近しければ近しいほど損失は小さくなります。

[ 機械学習 ] 損失関数の実装 (二乗和誤差, 交差エントロピー誤差)

 

学習(パラメータ最適化)

損失が大きい場合、損失を小さくするためにモデルを調整します。モデルの出力は重みとバイアスと言うパラメータに依存していますから、モデルの調整とは即ち、パラメータを最適化することに同義となります。
パラメータの最適化は、勾配法と言う手法で持って行われます。これは、各パラメータに関する損失関数の微分を行い、その時得られる微分値(勾配)とは逆の方向に各パラメータを更新することで、徐々に損失が小さくなるようなパラメータを獲得する、と言うものです。

[ 機械学習 ] パラメータを最適化する技術 -勾配法

 

 

3層ニューラルネットワークの仕様

では、以上を踏まえて3層のニューラルネットワークを実装していきたいと思います。
実装する前に、作成するネットワークの仕様について確認しておきます。

以前、2層のニューラルネットワークを実装しましたが、今期はさらに隠れ層を1層増やしていることと、学習を機能を追加することでパラメータを自動で最適化することができる点で以前のものとは差異があります。

 

今回扱うデータは、MNIST と呼ばれる手書き文字データです。
これを使用してモデルを作成し、手書き文字を認識できるようにします。

入力データ仕様

名称:MNIST
全データ数:70000
データ形状:28 x 28 の画像データ
データ性質:1 ~ 9 の手書き文字データ

出力データ仕様

出力:読み込んだデータが 1 ~9 のどの文字であるかを判定する確率

ネットワーク仕様

入力層
:70000 * 0.8 行 (70000データのうち、8割程度を抜き出して訓練用データとして扱う)
:784列 (ニューラルネットワークでは多次元データを扱えないため、28 * 28 の配列を reshape して784に変換する)

隠れ層:3層
⇨1層目:ニューロン数10:活性化関数=シグモイド
⇨2層目:ニューロン数10:活性化関数=シグモイド
⇨3層目:ニューロン数10:活性化関数=ソフトマックス

出力層:1行10列(各列がそれぞれの数値に対する判定確率となる)

 

実装

ではここから実装を行なっていきます。
いつもより長くなってしまうので、4部構成にしてプログラムを作成していきたいと思います。
構成は次の通りになります。

  1. データの準備
  2. モデルの定義
  3. 学習の実行
  4. 画像の判定実験

このうち、本記事では 1.データの準備 までを取り扱います。

1:データの準備

ここで行なう処理は、概ね次の通りです。

  1. MNISTデータの呼び出し
    今回扱う MNIST データですが、これは sklearn という機械学習用のライブラリから取得しています。ここから取得したデータは、70000*784 の構成を持っています。もともとの画像データは 28px * 28px 構成なのですが、ニューラルネットワークでは1次元構成に修正する必要があるため、sklearn側がすでにこのreshape処理を行なってくれています。
  2. 画像データの標準化
    読み込んだ画像データの数値のばらつきを小さくします。画像データの各数値は、8バイトの情報量を持っているので 0 ~ 255 の値を取ります。大きい数字を扱うメリットはないので、これを 255 で除算してやることで、 0 ~ 1 の数値範囲に縮小してやります。
  3. 正解データの行列化
    読み込んだ正解データは、それにひもづく画像データが 0 ~ 9 のいずれであるかを示す数値データを持っています(‘0’ や ‘3’ など)。今回作成するニューラルネットワークの出力は行列になりますので、この数値表現を行列での表現に変換してやります。

各処理による結果は printメソッドで可視化できるようにしていますので、コードの最下部をご覧ください。

(1) まず、画像データを確認します。今回の画像データは、 70000行784列(28*28) で構成されていることがわかります。

(2) ここに存在するデータの値範囲を見てみると、最小0 ~ 最大255 で分布していることがわかるので、データ全体を最大値の 255 で除算することにより値範囲を 0.0 ~ 1.0 に縮小しています。

(3) 次に正解データの構成を確認します。正解データは 70000 列のデータになっています。ここではそれぞれの値が、70000枚の画像がなんの数字であるかを示すデータになっています。

(4) ここから重複を取り除くと、正解データは 0.0 ~ 9.0 の範囲に分布していることがわかります。つまり、70000枚の画像は 0 ~ 9 のいずれかに振り分けられていることがわかります。

(5) ニューラルネットワークの出力は行列とする仕様としているので、この正解データをネットワークに合わせて変換します。
元々の正解データは、正解 0 ならば [ 0.0 ] 、正解 3 ならば [ 3.0 ] を値として持っています。これを、1行10列かつ 0 か 1 の数値で表現するように変換します。(これを one-hot-encoding と言います)
つまり、正解 0 は [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.] という形(0 番目の数字が1なので正解0)に、
正解 3 は [0. 0. 0. 1. 0. 0. 0. 0. 0. 0.] という形(4番目の数字が1なので正解3)になります。

(6) 最後に、データを訓練用データとテスト用データに分割します。これは学習が適切に行えているかを判定するために行う分割です。今回はテストデータを2割程度に設定するので、学習に使用される画像データは 70000 * 0.8 となります。

 

データの準備で行う処理については以上です。
ここから先の処理については、また次の記事で扱おうと思います。

なお今回扱う画像データですが、プログラム上では単なる配列でしか表現されていません。
が、matplotlib を使用すればこれをグラフ上に描画することができます。
上のコードにはサンプル画像の表示処理も混ぜ込んでありますが、実行してみると次のようなグラフが表示されます。

これが画像データであり、正解データがこれらの画像がなんの数字を示すかを表す(これは0と3)わけです。

 

 

以上。

MachineLearningカテゴリの最新記事