見出し画像

TensorFlowを使って物体認識Webアプリを作ってみる①

TensorFlowで物体認識をやるにあたって、まずはTensorFlow2.xに慣れようと思い、チュートリアル(エキスパート用)をやってみた。擦られ尽くしてるとは思うけど、自分がわからないなと思ったことをまとめました。

TensorFlow2.xについて

TensorFlow2.xで変わったことはたくさんあると思うけど、Eager Execution(即時実行)がデフォルトになったことは1つ大きな変更点だと思う。

まず実行方法の種類には"Define-and-run""Define-by-run"とがある。

・Define-and-run:まずネットワークの定義してから実行時に値を流すことで結果を得る

・Define-by-run:ネットワークの定義と計算を同時に行う

つまりEager Executionとは、Define-and-runとして動くということ。TensorFlow1.xはDefine-and-runを採用していたが、TensorFlow2.xからはDefine-by-runがデフォルトとなった。

このおかげで直感的にわかりやすくなったり、デバッグしやすくなったりといったメリットがある。

TensorFlow 2.0チュートリアルやってみた

パッケージのインポート。

import tensorflow as tf
from tensorflow.keras.layers import Conv2D, Dense, Flatten
from tensorflow.keras import Model

MNISTのデータセットを読み込む。

#MNISTのデータセットをロード
mnist = tf.keras.datasets.mnist
(x_train, x_test), (y_train, y_test) = mnist.load_data()

データセットを成形する。

#画像データを正規化
x_train, x_test = x_train / 255.0, x_test / 255.0

#(W, H) -> (W, H, C)に拡張
x_train = x_train[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]

train_ds = tf.data.Dataset.from_tensor_slices((x_train, y_train)).shuffle(10000).batch(32)
test_ds = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)

keras APIのModelクラスを継承して自作のモデルクラスを作成する。

class MyModel(Model):
   #レイヤを定義
   def __init__(self):
       super(Model, self).__init__()
       self.conv = Conv2D(32, 3, activation='relu', name='conv')
       self.flatten = Flatten(name='flatten')
       self.dence = Dense(128, activation='relu', name='dence')
       self.output = Dense(10, activation='softmax', name='output')

   #データの伝搬を定義
   def call(self, x):
       x = self.conv(x)
       x = self.flatten(x)
       x = self.dence(x)
       return self.output(x)

自作モデルのインスタンス作成。

#モデル作成
model = MyModel()

学習用にloss関数と最適化アルゴリズムを設定する。

#loss関数
loss_object = tf.keras.losses.SparseCategoricalCrossentropy()

#最適化アルゴリズム
optimizer = tf.keras.optimizers.Adam()

学習用とテスト用にlossと精度のメトリクスを設定する。

train_loss = tf.keras.metrics.Mean(name='train_loss')
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')
test_loss = tf.keras.metrics.Mean(name='test_loss')
test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='test_accuracy')

学習処理は関数として定義する。最初はイマイチわからなかったけどここを見たら結構理解できた。会員登録(無料)が必要だけど。

#学習ステップ
@tf.function
def train_step(images, labels):
   #テープにlossを記録していくイメージ
   with tf.GradientTape() as tape:
       predictions = model(images)
       loss = loss_object(labels, predictions)
   #テープに記録されたlossから勾配を計算する
   gradient = tape.gradient(loss, model.trainable_variables)
   #計算した勾配に従ってモデル内の重みを更新する
   optimizer.apply_gradients(zip(gradient, model.trainable_variables))

   train_loss(loss)
   train_accuracy(labels, predictions)

"@tf.function"のデコレータを使うことで実行時に毎回グラフを構築するのではなく、静的に構築して使い回すことができるようになるので学習のような何度も実行される処理では実行時間が短縮できる。

評価処理の部分も学習時と同様に"@tf.function"を使って記述する。推論してlossを求めるのも学習時と一緒。

#テストステップ
@tf.function
def test_step(images, labels):
   predictions = model(images)
   loss = loss_object(labels, predictions)
   test_loss(loss)
   test_accuracy(labels, predictions)

ようやく作成したモデルの学習&評価をしていく。エポックごとにさっき作った学習用関数と評価用関数を呼び出せばいいだけ。ただしエポックごとにメトリクスをリセットする必要があるので、lossや精度をグラフとして出力したい場合はリストを作ってappendしていくといい。(今回はやってないけど)

#エポック数の設定
EPOCHS = 5

for epoch in range(EPOCHS):
   #学習させる
   for images, labels in train_ds:
       train_step(images, labels)

   #1エポックごとに評価
   for test_images, test_labels in test_ds:
       test_step(test_images, test_labels)

   #学習&評価結果を出力
   template = 'Epoch: {}, Loss : {}, Accuracy : {}, Test Loss : {}, Test Accuracy : {}'
   print(template.format(  epoch+1, 
                           train_loss.result(), 
                           train_accuracy.result()*100, 
                           test_loss.result(), 
                           test_accuracy.result()*100))

   #1エポックごとにメトリクスをリセットする
   train_loss.reset_states()
   train_accuracy.reset_states()
   test_loss.reset_states()
   test_accuracy.reset_states()

ちなみにkeras APIのModelクラスには作成したモデルの各レイヤを出力してくれる便利なsummaryメソッドが準備されている。

>>>model.summary()

Model: "my_model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv (Conv2D)                multiple                  320       
_________________________________________________________________
flatten (Flatten)            multiple                  0         
_________________________________________________________________
dence (Dense)                multiple                  2769024   
_________________________________________________________________
output (Dense)               multiple                  1290      
=================================================================
Total params: 2,770,634
Trainable params: 2,770,634
Non-trainable params: 0
_________________________________________________________________​

これから実際に自作モデルを作って物体認識していくときは、train.pyに学習と評価部分を実装して、model.pyに自作モデルクラスを書いておくとスッキリしていい。

これでTensorFlow2.xの書き方について理解できできたので、次回は自作モデルの中身をいじって精度を上げてみようと思う。



この記事が気に入ったらサポートをしてみませんか?