こんにちは,怠惰人間です.前から少し日にちは空きましたが,tensorflow2系の使い方に関して,説明を行っていこうと思います.
前回解説しましたが,tensorflow 2系では,高級APIがKerasに統一化されました.そのため,今回は,Kerasの使い方,特にネットワークの作成方法に関して解説していこうと思います.
また,今回からこのページにはプログラムの重要箇所のみアップして,プログラムの全体像(動作可能なもの)はGoogle Colabで用意してあるので,実際の動作はそちらで確認してみてください!
今回のページのGoogle Colabはこちらです!
・Kerasの概要
まず初めに,Kerasでネットワークを学習->実行するには以下のステップを経由する必要があります.
今回は,上記のリストの内容を1つずつ解説していこうと思います.
1. ライブラリのインポート
利便性のために,tensorflow.keras.layerは「as」で短くしておくほうがいいと思います.
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
from tensorflow.keras.datasets import mnist
2. データセットの用意
今回は,mnistを使用していこうと思います.手書き数字のデータセットで,1画像のサイズは(28×28)と小さいあれですね.
# Mnistのダウンロード
(x_train,y_train),(x_test,y_test)=mnist.load_data()
ちなみに,今回はkerasのデータセットを使用していますが,tesnorflowにも「tensorflow_dataset」という似たような機能が存在しています.kerasのデータセット提供機能との違いは主に出力形式ですね.「keras.datasets」はnumpy形式でデータを提供するのに対し,「tensorflow_dataset」はtensorflow.dataset形式(後の回で説明します)で提供されます.使用感は,「keras.datasets」のほうが楽に使えますが,利便性などでは「tensorflow_dataset」が勝っているといったような印象ですね.
3. ネットワーク作成
Kerasには2種類のネットワーク作成方法が存在します.それぞれ
というもので,簡単に言うと,初級者用と上級者用のモデル構成方法になります.この2つは飽く迄ネットワークの構成方法の違いでしかないので,それ以外(学習等)の動作には影響しませんが,大きな違いが存在します.
・Sequential API
まず,Sequential APIの特徴を示します
- Functionalよりも簡単にネットワークが作成可能
- 見やすい(可読性が高い)
- 1入力1出力のネットワークしか作成できない
- ネットワークを分岐できない(ResBlockなどは作れない)
個人的には,Sequential APIは1入力1出力のネットワークしか作成できなかったり,ネットワークを分岐できないなどといったデメリットが存在するため,基本的に使用することは少ない印象です.別の回で説明する自作レイヤを使用すると,上記の弱点のうち,ネットワークを分岐できないという問題はある程度カバーすることができますが,それでも,次に紹介するFunctional APIのほうが使い勝手がいいですね.(Functional APIはtensorflow 1.X likeだからという側面もある)
では,実際にSequential APIを使用した際のネットワークの例を見ていきましょう.
#方法1
model=tf.keras.Sequential([
layers.Flatten(input_shape=x_train[0].shape),
layers.Dense(128,activation="relu"),
layers.Dense(10,activation="softmax")
])
ちなみに,別の書き方でこのような記載方法もあります.どちらにせよ,動作は同じです.
#方法2
model=tf.keras.Sequential()
model.add(layers.Flatten(input_shape=x_train[0].shape))
model.add(layers.Dense(128,activation="relu"))
model.add(layers.Dense(10,activation="softmax"))
どちらかというと,方法1のほうがSequential API likeだと個人的には感じます.方法2は何というか,Functional APIに書き方が似ているんですよね.
・Functional API
Functional APIはtensorflow 1系の記法にかなり近く,以下のように記述します.
input=layers.Input(shape=x_train[0].shape)
x=layers.Flatten()(input)
x=layers.Dense(128,activation="relu")(x)
output=layers.Dense(10,activation="softmax")(x)
model=keras.Model(inputs=input,outputs=output)
「layer.hoge(XXX)(YYY)」のような独特の記法をしていますが,慣れれば案外平気です.ちなみに,hogeの例でいう(XXX)の部分で,そのレイヤ(e.g. CNN)の設定をし,(YYY)でレイヤへの入力を決定します.
ちなみに,Functionalでは,この(YYY)の部分が存在するおかげでネットワークの分岐が可能となっています.どういうことかというと,以下のようなイメージですね.
input1=layers.Input(shape=(~~))
input2=layers.Input(shape=(~~))
x1,x2=layer.分岐処理(~~)(input1)
x2=layer.処理A(~~)(x2)
x1=layer.結合処理(~~)(x1,x2)
x1=layer.処理B(~~)(x1)
x3=layer.処理C(~~)(input2,x2)
output1=layers.処理D(~~)(x1)
output2=layers.処理E(~~)(x2)
output3=layers.処理F(~~)(x3)
model=keras.Model(inputs=[input1,input2],outputs=[output1,output2,output3])
この例を図に示すと,
のようになっています.見ればわかりますが,ネットワークが途中で分岐していますね.(YYY)に複数の入力を入れることが可能なので,このようなことができるのです.
入力を自由に操作できないSequential APIでは,このような操作はできません.
2021/02/12追記
Google Colabのほうに,複数入出力のやり方を追加しておきました.
4. ネットワークのコンパイル
コンパイル作業とは,作成したネットワークと損失関数,オプティマイザを関連付ける作業です.以下のように1命令で済みます.
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
また,モデルのコンパイルを行うと,ネットワークの可視化を行えるようになります.可視化は以下のように行います.
model.summary()
出力はこのようになります.
5. ネットワークの学習
ネットワークの学習も,kerasは非常に単純で,「fit」メソッドを呼び出すだけで済みます.
result=model.fit(x_train,y_train,validation_split=0.2,epochs=5)
今回は非常に少ない設定で学習を行っていますが,「fit」関数には多くの引数が存在するため,気になった人は,公式のページを確認してみてもいいかもしれません.
6. ネットワークのテスト
テストデータでの評価もこれまた楽で,また1命令で済みます.
evaluate_result=model.evaluate(x_test,y_test)
なお,この関数の実行結果は,このようになります.
313/313 [==============================] - 1s 2ms/step - loss: 0.3445 - accuracy: 0.9329
Mnistは非常にシンプルなデータなので,Dense(Fully Connected)レイヤだけで精度もかなり出ていることが分かりますね.
・まとめ
かなり適当にまとめてしまった感もありますが,簡単な使い方は分かるかと思います.疑問に思った部分は,自分でColabをいじくりまわしてもいいかもしれませんね.
- Kerasには「Sequential」と「Functional」の2種類のネットワーク作成方法がある
- 「Sequential」は初心者向けで見やすいコードが書ける
- 「Functional」は複数の入出力の設定とネットワーク内での分岐が可能