【深層学習】Chainerでクラス分類してみた

機械学習

こんにちは!エンジニアのオオイシです。

今回は、Chainerというライブラリでニューラルネットワークによるクラス分類を試してみたので、紹介して行きたいと思います。

ニューラルネットワークとは何たるか?についての詳細は、ググるとたくさん出てくるので、今回は、

アヤメ(iris)のサンプルデータを使ったニューラルネットワークを実装して、学習させてみました。

記事内容の全体の流れは、

  • ニューラルネットワークについてざっくり整理
  • サンプルデータのアヤメ(iris)の中身を確認
  • Chainerとは?
  • 解説しながらChainerで実装してみる

となります。

サンプルデータのアヤメ(iris)の中身を確認

扱うデータはディープラーニングなどでお馴染みのアヤメ(iris)のサンプルデータです。

ディープラーニングのためのサンプルデータは、UCI(データセットを集めているサイト)が有名です。

今回は、機械学習ライブラリのScikit-learnkからも得られるので、こちらを使います。

アヤメの「ガクの長さ」や「花弁の幅」などの特徴とアヤメの種類のデータが149件入っています。

sepal_length ガクの長さ
sepal_width ガクの幅
petal_length 花弁の長さ
petal_width 花弁の幅

アヤメの種類は「0,1,2」で分類されています。

  • 0 -> setosa(セトナ)
  • 1 -> versicolour(バージカラー)
  • 2 -> virginica(バージニカ)

ニューラルネットワークについてざっくり整理

ニューラルネットワークやディープラーニングについて調べたことがある人は、おそらく、次のような図をみたことがあると思います。

上の図は、xは入力層、yは出力層になり、右から左へ計算した結果、70%の確率でセトナであることを表しています

ニューラルネットワークでは、正しい答えyを求めるために、入力変数xから最適な重み(w)を見つけていく処理を繰り返します。

右から左へ計算していくことを順伝播といい、右から左への計算を逆伝播といいます。

順伝播では、u1 = W1x + b(バイアス)で計算していき、中間層の中では活性化関数を通します。

逆伝播は、仮に、計算した結果が0.1だったら期待値0.7とは大きな乖離がありますよね?

そこで、最適になる重み(w)になるように、右から左へ計算していきます。

逆伝播の計算方法は難しいのでここでは説明できませんが、

  • SGD(Stochastic Gradient Descent : 確率的勾配降下法)
  • Adam(Adaptive moment estimation)

が有名です。

これから説明するChainerでは、この難しい計算をやってくれるライブラリ(Optimaizer)がそろっています!

Chainerとは?

Chainerとは、pythonで実行するニューラルネットワークの国産ライブラリです。

導入が簡単で、GPUに対応し、シンプルに実装できることが特徴です。

kerasTensorflowに移行する際にもChainerを覚えて置けばスムーズに移行しやすいと言われています。

また、画像認識(ChainerCV)や深層強化学習(Chainer RL)のための、より特化したChainerファミリーというものもあるので実用でも使えます。

Chainerでクラス分類を実装してみる

実装の流れ

今回は、アヤメを使ったニューラルネットワークを実装するためのプログラムを作成していきます。

処理の流れは、

  1. Irisサンプルデータの読み込み
  2. モデルを作成(上記図の5層→3層をつなぎ合わせたネットーワーク)
  3. 訓練データと検証データを7:3の割合で分割
  4. Optimizerの設定(パラメータを調整)
  5. Itaratorの設定 (分割して効率よく学習するためのミニバッチ)
  6. Updaterの設定(OptimizerとItaratorを使って重みの更新)
  7. Extentionsの設定(学習中の計算結果の過程を出力)
  8. Trainerの設定(上記の設定をまとめて、学習回数を設定)
  9. Trainerで学習を実行

といった流れになります。

これらを次項で実装していきましょう。

Irisサンプルデータの読み込み

はじめに、scikit-learn の datasets からirisデータを読み込みます。

読み込んだデータは入力データ(data)と出力データ(label)で別々の変数に格納します。

Chainerは64bitは扱ってくれないので32bitに変換します。

モデルを作成(ニューラルネットワークの定義)

まずは、クラスの作成です。

__init__メソッドでは、入力層、中間層、出力層とそれらをつなぎ合わせるモデルの構造を定義します。

__call__メソッドでは、順伝播のネットワークを定義します。

chainer.functions as F は、機械学習でなどで使う関数群が定義されていて、代表的なものに、シグモイド関数やソフトマックス関数があります。

中間層から出力層へ伝播する時の、損失関数として、今回はRelu関数を使っていました。

実際の学習データは線形であることは稀なので、非線形に対応しておきます。

chainer.links as Lは、入力層、中間層、出力層の各層をリンクしてネットワークを定義方法がまとめられています。

今回は、L.Linear(層結合層)を使いました。

最後に、ニューラルネットワークのモデルとして定義するために、作成したモデルを次のように実装します。

訓練データと検証データに分割

ここでは、訓練データと検証データを7:3で分割します。

split_dataset_randomの第3引数にseed=1 としているのは、ランダムにする結果が毎回同じになるように固定するためです。

Optimizerの設定

Optimaizerは、逆伝播する時の重み(w)のパラメータの最適化アルゴリズムです。

今回は、SGD(確率的勾配効果法)を使いました。

SGDは、学習データの中のからランダムに一つの値を決めて、誤差をもとめる微分をします。

Itaratorの設定

学習データが100万件などのたくさんのある特に、100万件全てが学習させた上で、パラメータを計算するととても処理時間がかかります。

そのため、ミニバッチと言われる方法で、10件とか100件などに区切ってパラメータを更新していくためにIteratorを使います。

今回は、SerialIterator という、順番にデータを取り出す基礎的な物を使います。

Updaterの設定

Updaterその名の通り、パラメータを更新するために利用します。

引数に学習データとOptimaizerとCPUとGPUのどちらを使って計算するかを表すdeviceを指定します。

TrainerとExtentionsの設定

Trainerもその名の通り、学習を実行するために利用します。

TrainerはUpdaterとエポック数を指定します。

エポック数とは、パラメータを更新する回数のことで順伝播、逆電波を行き来する回数です。

エポック数が多すぎる場合は過学習となって、逆に精度が低くなるので注意しましょう。

学習の実行

学習の実行はtrainer.run() 実行するだけです。

実行結果をみてみましょう。

学習の精度(main/accuracy)を見ると 96% の確率で学習結果が得られました。

グラフでもみてみましょう。

学習精度は右肩上がりになっています。

損失(main/loss)もみてみましょう。

このように右下下がりになっているので、正解との誤差がすなくなっているのがわかると思います。

まとめ

今回はChainerを使ったニューラルネットワークのうち、学習の部分について紹介しました。

次回は、このモデルを使った予測部分について解説していきます。