ChunPom’s diary

数学、物理、機械学習に関する話題。あと院試、資格、大学入試まで。

異なるネットワークを並列したニューラルネットの構築法

kerasでは、直列でどんどん中間層をつなげていく例はよくあるが、並列で異なるネットワークあるいは中間層をつなげる例はあまり少ないので紹介する。

まずは必要なライブラリのインポートと学習データの構築。0~1の乱数5個でできた入力ベクトルを500回分生成する。出力としては、ベクトルの成分和が5/2より大きくなるなら1、そうでないなら-1とする。

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

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


次にモデルを構築する。入力はもちろん5個の成分のベクトルだが、それを分割して前3つと後ろ2つで異なるネットワークに接続し、その出力を統合してから全結合層を通すモデルを考える。分割はlambdaによる範囲指定、統合はconcatenateを用いるのがミソ。

inputs=Input(shape=(5,))
x1 = Lambda(lambda x:x[:,:3],output_shape=(3,))(inputs)
x2 = Lambda(lambda x:x[:,3:],output_shape=(2,))(inputs)

x1_1 = Dense(20, activation='tanh')(x1)
x2_1 = Dense(20, activation='sigmoid')(x2)
x=Concatenate(axis=-1)([x1_1,x2_1])
y=Dense(1, activation='tanh')(x)

ここで、前3つにはtanh、後ろ3つにはsigmoidを活性化関数とする別々の全結合層を指定した。また、この出力を統合し、tanhを活性化関数とする全結合層を用いた。

次にモデルの学習と、テストデータによる検証を実施する。

model = Model(inputs,y)
model.compile('adam', 'hinge', metrics=['accuracy'])
model.fit(data, labels, epochs=200, validation_split=0.1)

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

テストデータは、学習データと同様に新たな100個の入力ベクトルを生成することで生成した。

最後に構築したモデルの構成図をpydotを用いて出力しよう。pydot環境は①graphvizhttp://www.graphviz.org/download/からダウンロード→②ダウンロードされたgraphvizのbinフォルダのパスをシステム環境変数に追加→③コマンドブロンプト開きpipによりgraphvizとpydotをインストールの手順でOK。pydotが使用できるようになったら、以下のようにモデルの構成図を画像に出力する。

from keras.utils import plot_model
plot_model(model,to_file="model.png")

f:id:ChunPom:20210415230236p:plain