Pythonでデータ分析する次の一歩(ディープ・ラーニング、Keras編)

2019-05-21 (火) 18:04:00 (93d) | Topic path: Top / 機械学習 / Pythonでデータ分析する次の一歩(ディープ・ラーニング、Keras編)

はじめに

Kerasはディープ・ラーニング・ライブラリーのTensorFlowを使用するためのライブラリーです。

インストール

ここでは、Anacondaに追加する形でインストールします。

まず、Anaconda Navigatorを起動し、Environmentsを表示します。

nolink

次に、base (root)の横の三角形をクリックし、メニューを表示します。

nolink

メニューから、Open Terminalを選び、ターミナルを開きます。

nolink

ターミナルを開いたら、念の為、CondaとMatplotlibをアップデートします。

conda update conda
conda update matplotlib

CondaとMatplotlibをアップデートしたら、Kerasをインストールします。 TensorFlowはKerasと一緒にインストールされます。

conda install keras

使い方

ライブラリーの読み込み

ライブラリー名は keras です。

import keras

ライブラリーを読み込んで、次のようなメッセージが出てきたら、準備はできています。

Using TensorFlow backend.

データの準備

まず、scikit-learnに付属しているIrisデータセットを例題として使います。 説明変数は花びらの長さ、幅、萼(がく)片の長さ、幅の4つ、目的変数はSetosaを表す0、Versicolorを表す1、Virginicaを表す2の3種類です。

from sklearn import datasets
iris = datasets.load_iris()
X = iris.data
y = iris.target
print(X)
print(y)
[[5.1 3.5 1.4 0.2]
 [4.9 3.  1.4 0.2]
 [4.7 3.2 1.3 0.2]
 ...
 [6.5 3.  5.2 2. ]
 [6.2 3.4 5.4 2.3]
 [5.9 3.  5.1 1.8]]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2]

説明変数が4つあることから、入力層のユニット数は4になります。 目的変数が3種類あることから、出力層のユニット数は3になります。

ただし、分類器の予測モデルでは、目的変数はOne hotベクトルにしておく必要があります。

Kerasに、One hotベクトルに変換するためのto_categoricalメソッドが用意されています。

from keras.utils import np_utils
y = np_utils.to_categorical(y)
print(y)
[[1. 0. 0.]
 [1. 0. 0.]
 [1. 0. 0.]
 ...
 [0. 0. 1.]
 [0. 0. 1.]
 [0. 0. 1.]]

予測モデル学習器の生成

Kerasを使うことで、ディープ・ラーニング・ライブラリーのTensorFlowをscikit-learnと同じように使えます。

ディープ・ラーニングというのは、ニューラル・ネットワークの中間層が2つ以上のものです。 ここでは、基本的な全結合の4層モデル(入力層、中間層2つ、出力層)を作成する例を示します。

まず、シーケンシャル・モデルの入れ物を作成します。

from keras.models import Sequential
model = Sequential()

次に、入力層と1つ目の中間層を追加します。

from keras.layers import Dense
model.add(Dense(units=16, activation='relu', input_dim=4))

Dense は全結合のレイヤーです。 units はこのレイヤーのユニット数、activation は活性化関数(ここではランプ関数 ReLU)を表します。 input_dim オプションは入力層のユニット数を表し、最初の中間層だけに指定します。 説明変数が4つなので、入力層のユニット数は4です。

続いて、2つ目の中間層を追加します。

model.add(Dense(units=8, activation='relu'))

最後に、出力層を追加します。

model.add(Dense(units=3, activation='softmax'))

分類用なので、出力層の活性化関数をソフトマックスにしています。 出力が3種類なので、出力層のユニット数は3です。 (回帰用の場合は、出力層の活性化関数を線形 activation='linear' にします。)

全てのレイヤーを追加したら、モデルをコンパイルします。

model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])

loss は損失関数、optimizer は最適化手法、metrics は評価尺度を表します。 ここでは、分類用なので、損失関数はカテゴリカル・クロスエントロピー categorical_crossentropy、評価尺度は精度 accuracy にしています。 最適化手法は、最もシンプルな確率的勾配法 SGD にしています。

ニューラル・ネットワークの学習

scikit-learnと同じように、fitメソッドで学習します。

model.fit(X, y, epochs=10, batch_size=150)
Epoch 1/10
150/150 [==============================] - 0s 35us/step - loss: 0.0539 - acc: 0.9733
Epoch 2/10
150/150 [==============================] - 0s 39us/step - loss: 0.0539 - acc: 0.9733
Epoch 3/10
150/150 [==============================] - 0s 38us/step - loss: 0.0539 - acc: 0.9733
Epoch 4/10
150/150 [==============================] - 0s 74us/step - loss: 0.0538 - acc: 0.9733
Epoch 5/10
150/150 [==============================] - 0s 23us/step - loss: 0.0538 - acc: 0.9733
Epoch 6/10
150/150 [==============================] - 0s 82us/step - loss: 0.0537 - acc: 0.9733
Epoch 7/10
150/150 [==============================] - 0s 39us/step - loss: 0.0537 - acc: 0.9733
Epoch 8/10
150/150 [==============================] - 0s 57us/step - loss: 0.0536 - acc: 0.9733
Epoch 9/10
150/150 [==============================] - 0s 46us/step - loss: 0.0536 - acc: 0.9733
Epoch 10/10
150/150 [==============================] - 0s 121us/step - loss: 0.0536 - acc: 0.9733

epochs は事例全体に対して何回繰り返し学習するか、batch_size は重みの更新をいくつの事例ごとに行うかを表します。 Irisデータセットには事例が150個含まれているので、ここでは150事例ごとに10回重みを更新しています。 (batch_size=1 にすると、1事例ごとに、1,500回重みを更新します。)

学習した予測モデルの評価

scikit-learnと同じように、evaluateメソッドで評価します。

score = model.evaluate(X, y, batch_size=150)
print(model.metrics_names)
print(score)
150/150 [==============================] - 0s 14us/step
['loss', 'acc']
[0.053536947816610336, 0.9733333587646484]

ここでは、訓練データを用いて予測モデルを評価していますが、本来は、訓練データとは別に検証データを用意して評価します。

損失が0.053、精度が0.973でした。

学習した予測モデルによる予測

scikit-learnと同じように、predictメソッドで予測します。

出力層はユニットごとに値を出力する、つまり出力は150行3列の行列になるので、argmaxメソッドで行ごとに最大値を持つインデックス番号を求めます。

import numpy as np
p = np.argmax(model.predict(X), axis=1)
print(p)
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 2 1
 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2]

畳み込みディープ・ニューラル・ネットワーク (CDNN) による画像分類

手書き文字認識のMNISTデータセットを用いて、畳み込みディープ・ニューラル・ネットワークを使って画像分類をやってみます。

まずはデータセットをダウンロドします。

from keras.datasets import mnist
(X_train, y_train), (X_test, y_test) = mnist.load_data()
Downloading data from https://s3.amazonaws.com/img-datasets/mnist.npz
11493376/11490434 [==============================] - 136s 12us/step

訓練データには縦横28ピクセルのモノクロ画像が6万枚入っています。

print(X_train.shape)
print(y_train)
(60000, 28, 28)
[5 0 4 ... 5 6 8]

一般的な画像データはRGBなど複数のチャンネルを持っていますが、MNISTデータセットはモノクロ画像なので1チャンネルしかありません。 そのため、MNISTデータセットでは1つの画像が1つの行列だけで表現されています。 複数のチャンネルを持つ一般的な画像データは3階テンソルによって表されるため、MNISTデータセットを6万個の画像データ(3階テンソル)からなる4階テンソルに変形しておく必要があります。

そこで、訓練データを (画像枚数, 横ピクセル数, 縦ピクセル数, チャンネル数) という形に変形します。

X_train = X_train.reshape(60000, 28, 28, 1)

Irisデータセットと同じように、目的変数をOne hotベクトルに変換します。

from keras.utils import np_utils
y_train = np_utils.to_categorical(y_train)
print(y_train)
[[0. 0. 0. ... 0. 0. 0.]
 [1. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 ...
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 1. 0.]]

データの準備ができたので、次はモデルを作成します。

from keras.models import Sequential
model = Sequential()

最初の畳み込み層を追加します。

from keras.layers import Conv2D
model.add(Conv2D(filters=32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1)))

Conv2D は2次元の畳み込み層です。 units は畳み込み層のユニット数、kernel_size は畳み込みカーネルのサイズです。 input_shape は入力の形 (横ピクセル数, 縦ピクセル数, チャンネル数) で、最初の畳み込み層にだけ指定します。

続いて、2層目の畳み込み層を追加します。

model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu'))

この後に、プーリング層を追加します。

from keras.layers import MaxPooling2D
model.add(MaxPooling2D(pool_size=(2, 2)))

MaxPooling2D は2次元のMaxプーリング層です。 pooling_size はプーリングのサイズを表します。

ここで、ドロップアウトします。

from keras.layers import Dropout
model.add(Dropout(rate=0.25))

Dropoutはドロップアウトを表現しています。 レイヤーと同じように追加されていますが、レイヤーではありません。 rate はドロップする割合を表します。

次に、特徴を1次元にします。

from keras.layers import Flatten
model.add(Flatten())

1次元にしたユニットから全結合した中間層を加え、ドロップアウトします。

from keras.layers import Dense
model.add(Dense(units=128, activation='relu'))
model.add(Dropout(rate=0.5))

最後に、出力層を追加します。

model.add(Dense(units=10, activation='softmax'))

10クラス分類問題なので出力層のユニット数は10、活性化関数はソフトマックスです。

全てのレイヤーを追加したら、コンパイルします。

model.compile(loss='categorical_crossentropy', optimizer='adadelta', metrics=['accuracy'])

損失はカテゴリカル・エントロピー、最適化アルゴリズムはAdaDelta、評価尺度は精度を指定します。

コンパイルしたら、学習します。

model.fit(X_train, y_train, epochs=12, batch_size=128)
Epoch 1/12
60000/60000 [==============================] - 139s 2ms/step - loss: 2.4267 - acc: 0.7931
Epoch 2/12
60000/60000 [==============================] - 133s 2ms/step - loss: 0.1273 - acc: 0.9639
Epoch 3/12
60000/60000 [==============================] - 129s 2ms/step - loss: 0.0933 - acc: 0.9730
Epoch 4/12
60000/60000 [==============================] - 128s 2ms/step - loss: 0.0744 - acc: 0.9784
Epoch 5/12
60000/60000 [==============================] - 145s 2ms/step - loss: 0.0629 - acc: 0.9811
Epoch 6/12
60000/60000 [==============================] - 138s 2ms/step - loss: 0.0535 - acc: 0.9848
Epoch 7/12
60000/60000 [==============================] - 133s 2ms/step - loss: 0.0490 - acc: 0.9855
Epoch 8/12
60000/60000 [==============================] - 133s 2ms/step - loss: 0.0436 - acc: 0.9868
Epoch 9/12
60000/60000 [==============================] - 146s 2ms/step - loss: 0.0407 - acc: 0.9882
Epoch 10/12
60000/60000 [==============================] - 132s 2ms/step - loss: 0.0356 - acc: 0.9893
Epoch 11/12
60000/60000 [==============================] - 134s 2ms/step - loss: 0.0340 - acc: 0.9897
Epoch 12/12
60000/60000 [==============================] - 139s 2ms/step - loss: 0.0311 - acc: 0.9907

学習したら、評価します。

まず、テスト・データの形を確認します。

print(X_test.shape)
(10000, 28, 28)

訓練データと同じように、説明変数と目的変数を変形し、評価します。

X_test = X_test.reshape(10000, 28, 28, 1)
y_test = np_utils.to_categorical(y_test)
model.evaluate(X_test, y_test)
10000/10000 [==============================] - 10s 979us/step
[0.04123013794525614, 0.9888]

損失は0.041、精度は0.989でした。

出力は10,000行10列の行列になるので、Irisデータセットのときと同じように、argmaxメソッドを使って行ごとに最大値のインデックス番号を求めます。

p = np.argmax(model.predict(X_test), axis=1)
print(p)
[7 2 1 ... 4 5 6]

参考文献

添付ファイル: fileopen_terminal.png 11件 [詳細] fileenvironments.png 10件 [詳細] fileanaconda.png 11件 [詳細]
トップ   編集 凍結解除 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS