Help us understand the problem. What is going on with this article?

無から始めるKeras 第1回

More than 3 years have passed since last update.

無から始める Keras のもくじはこちら

無とは

Kerasの知識どころか、ニューラルネット、さらにはPythonすらもわからない状態ではじめるKeras。
Python3だけはインストールしてあるものとする(これは環境によって違うのでググってください)。

まずはともあれインストール。

$ sudo pip3 install tensorflow keras

そしてPythonを起動。

$ python3

対話型のほうがやりやすい気がする。

配列を作る

配列はNumPyで扱う。遅くないので。

import numpy as np
array = np.array([0.1,0.2,0.3])

配列が作れた。1行目はライブラリを読み込むので使う時は常に必要(それはそう)。

二次元も作れる。行列における行方向(横向き)が内側の配列になる。下なら

\begin{pmatrix}0.1 & 0.2 & 0.3 \\ 0.4 & 0.6 & 0.8\end{pmatrix}

を表す。

array = np.array([[0.1,0.2,0.3], [0.4,0.6,0.8]])

零行列、すべての要素が1の行列、単位行列は以下の通り。(a,b,c,...) で配列の要素数を示せる。Python的にはタプル。

array = np.zeros((2,3))
array = np.ones((3,1))
array = np.identity(5) # sizeは(5,5)

ランダム行列も作っとこう。

array = np.random.rand(3,2) # 0以上1未満の一様分布
array = np.random.randn(5,4) # 平均0、分散1の正規分布
array = np.random.randint(0, 5, size=(2,3)) # 0以上5未満の離散一様分布

ここまでは練習。

データセットを作る

学習をしてみたいので、とにかくデータセットを作ってみる。

data = np.random.rand(250,5)
labels = (np.sum(data, axis=1) > 2.5) * 1

1行目のデータは、5次元のデータを250個作っただけ。
2行目のラベルは、250個の各データに対して5次元の和をとり、それが2.5より大きいときに1となる(そうでないときは0となる)ような配列。

これを使って、適当な5次元の配列を入力したら、その和が2.5より大きいときに1と教えてくれるニューラルネットを作ろうという話。

データセットを整形する

2クラスの出力があるので、実際にはワンホットであってほしい。
つまり、1つの(5次元)入力に対して出力は2次元で、入力の和が2.5以下だと [1,0] に、2.5より大きいと [0,1] になって欲しいというわけだ。

そういうようなラベル付けをするために、Kerasの機能を使う。importするときにログが吐かれるけどおおよそ気にしなくていいはず。

from keras.utils import np_utils
labels = np_utils.to_categorical(labels)

こうすると、labels は2次元の配列250個になる。

ニューラルネットを作る

Sequentialはただ層を積み上げるだけの単純なモデル。1層前の出力をそのまま入力する感じ。ノード間にはすべてエッジを引く形(当然抜くこともできるが省略)。
今回は中間層1層(入力層・隠れ層・出力層)としてみる。

from keras.models import Sequential
from keras.layers import Dense, Activation
model = Sequential()

次に入力層―隠れ層を入れる。Denseというレイヤーをとりあえず使う。5個のノードからそれぞれ20本矢印が出てきて、次の層のノードが20個であることを示す。
ノード数は入力データの次元数と一致する必要がある(当然である)。

model.add(Dense(20, input_dim=5))

次は活性化関数を入れてみよう。20個のノードそれぞれに対して5つの数値が入ってくるが、その5つの数値の重み付け和(+バイアス)を適当にとって最後に関数をかける。そのときの関数が活性化関数である。今回はランプ関数。

model.add(Activation('relu'))

この2つは Dense(20, input_dim=5, activation='relu') でまとめても同じだと思う。

次は隠れ層―出力層。20個のノードから(活性化関数が適用されたあと)それぞれ値がやってくる。出力は2次元で、ノードにやってきた20個の値に対して重み付き和とソフトマックス関数を適用する。カテゴリ判別にはソフトマックス関数がいいらしい。

model.add(Dense(2, activation='softmax'))

図にすると下みたいな感じ(20個もノードを書くのが面倒なので10個にした)。一般的なニューラルネットワークの図とは違うけど、説明用にアレンジしてみた。

本当はDenseもActivationもレイヤー(層)を表すのだが、なんとなく「つなぐもの」をイメージしたほうがわかりやすい気がした。

名称未設定.001.jpeg

コンパイル

学習の前に、コンパイルを行う。

1つめは最適化関数、2つめは損失関数、3つめは評価指標のリスト。とりあえずありがちなものを使う。

model.compile('rmsprop', 'categorical_crossentropy', metrics=['accuracy'])

いざ学習

nb_epoch は回数。validation_split は検証に使うデータの割合(全体のデータを学習に使わず、8割のみを学習に使って、残りの2割を評価に使う)。

model.fit(data, labels, nb_epoch=300, validation_split=0.2)

学習できたかな。

未知データの予測

実際に動いているか試す。

test = np.random.rand(200, 5)
predict = np.argmax(model.predict(test), axis=1)
real = (np.sum(test, axis=1) > 2.5) * 1
sum(predict == real) / 200.0

おおよそ98%くらいの精度で判別できている。まあこんな簡単な条件だし。
ちなみに学習を回さずに判別させると50%くらいになる。まあ適当にやって当たる確率は50%なので。

今回のプログラムまとめ

モデルを定義するときに同時にレイヤーも積み重ねている。

import numpy as np
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense, Activation

data = np.random.rand(250,5)
labels = np_utils.to_categorical((np.sum(data, axis=1) > 2.5) * 1)
model = Sequential([Dense(20, input_dim=5), Activation('relu'), Dense(2, activation='softmax')])
model.compile('rmsprop', 'categorical_crossentropy', metrics=['accuracy'])
model.fit(data, labels, nb_epoch=300, validation_split=0.2)

test = np.random.rand(200, 5)
predict = np.argmax(model.predict(test), axis=1)
real = (np.sum(test, axis=1) > 2.5) * 1
print(sum(predict == real) / 200.0)
Ishotihadus
チノちゃんを愛でてゆきたい。
https://www.ishotihadus.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away