49
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

無から始めるKeras 第3回

Last updated at Posted at 2017-06-02

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

前回のおさらい

前回は雑なデータセットを作って雑に学習させた。

入力は 5 次元で、要素がそれぞれ 0 以上 1 未満。出力は 1 次元で、入力の要素の和が 2.5 以下だったら -1、2.5 より大きかったら 1。いわゆる「2 クラス分類」をする。

データセットは以下のように作った。出力の方は 0 or 1 にしてから 2 をかけて -1 している(-1 か 1 になる)。

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

モデルは以下のようにした。活性化関数には -1 から 1 を値域としてとれる tanh を使って、損失には符号に対してよく利くヒンジ損失を使った。

model = Sequential([Dense(20, input_dim=5, activation='tanh'), Dense(1, activation='tanh')])
model.compile('adam', 'hinge', metrics=['accuracy'])

Sequential モデルとは

第 1 回でも述べたように、Sequential モデルは単純に、今の層のそれぞれのノードに、前の層の全ノードから矢印を引っ張ってくるイメージである。
確かにこれでもニューラルネットワークとして機能するのだが、ちょっとおもしろくない。

これを解決するのが Functional API である。なんか 2 つのニューラルネットワークの出力を入れてみたり、レイヤーを共有してみたりと、結構複雑なことができるようになる。

Functional API とは

前回と同じ形のニューラルネットワークを作ってみよう。
同じ形なので作るのが無意味な雰囲気がするが、そこは練習である。

Functional API は簡単に言えば「矢印のつなぎ方をぐちゃぐちゃにできる」ものである。Sequential モデルでは A → B → C という形でしかできなかった。
でも Functional API では

A
 ↘
  C → D → E
 ↗
B

みたいなことができるようになる。今回はやらないけど。

Functional API を使う

入力層

まずは入力の層。

from keras.layers import Input, Dense
from keras.models import Model

inputs = Input(shape=(5,))

この Input という名前の層なのだが、残念ながらドキュメントがない。

shape は入力の次元を表している。
(5,) という表記は Python を知らないとなんやねんという感じだが、ただ単純に 5 という要素だけもつ Tuple(配列みたいなもの)である。カンマがあるので複数要素があるように見えるが、要素は 1 個である。カンマがないとただの数値と見分けがつかないからなのだが、本当にクソ記法だと思う。Python はこういうところが嫌い。

隠れ層

x = Dense(20, activation='tanh')(inputs)

ノード数が20で、入力が inputs であるような層。

dense は「密な」という意味だが、前の層のすべてのノードから、この層のすべてのノードに対して、すべての矢印を引っ張るので、そういう意味で密なんだと思う。

出力層

predictions = Dense(1, activation='tanh')(x)

こちらは隠れ層とほぼ同じ。説明はいらないでしょう。

Functional API の意味付け

Functional(関数型)というのはどういうことか。

よく見ると Dense はそのインスタンスを関数呼び出ししていることがわかる。
ドキュメントには、レイヤーのインスタンスを関数呼び出しすると、テンソルが返ると書いてある。

そもそもニューラルネットワークというのは、おおよそテンソル積(もっと単純化すれば行列積)である。
入力ベクトルに行列をかけて、さらに行列をかけて……というのがそもそもの本質になる。
1 回層を通り抜けることが、1 回行列をかけるのとだいたい同じ意味になる。
その行列(テンソル)をかけ合わせるイメージを、関数呼び出しと照らし合わせている。

関数呼び出しをすると、入力したテンソルが、指定した意味合いをもって変形されて、またテンソルとなって出力される。そういう感じのイメージでとらえるとわかりやすい気がする。

まったく厳密なことを言っていないのでアレだけど。

ちなみに Input レイヤーだけはそもそもテンソルが返ってくる(ので関数呼び出しがいらない)。

今回のプログラムまとめ

import numpy as np
from keras.layers import Input, Dense
from keras.models import Model

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

inputs = Input(shape=(5,))
x = Dense(20, activation='tanh')(inputs)
predictions = Dense(1, activation='tanh')(x)

model = Model(input=inputs, output=predictions)
model.compile('adam', 'hinge', metrics=['accuracy'])
model.fit(data, labels, nb_epoch=150, validation_split=0.2)

test = np.random.rand(200, 5)
predict = np.sign(model.predict(test).flatten())
real = (np.sum(test, axis=1) > 2.5) * 2 - 1
print(sum(predict == real) / 200.0)

書き方以外は第 2 回とまったく同じなので、ほぼ同じ精度が出ると思う。

49
44
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
49
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?