茨城エンジニアのPython開発日記

茨城のITベンチャー企業ではたらく2年目エンジニア。Pythonで色々なものを作成中。

論文読んでAIつくるぞ会(第2回) ~Tensorflow KerasのSequential APIとFunctional APIに挑戦~

ブログから記事を見つけたい場合はこちら

ブログ地図 - 茨城エンジニアのPython開発日記

ブログ地図(大) - 茨城エンジニアのPython開発日記
ブログから記事を見つけたい場合はこちら


こんにちは、開発メンバーのKです。

 

今回は朝7:20からみんなで勉強会でした。休日の早起きは気分が良い。

 

前回から方針が変わり、

Tensorflow 2.xでAI関連の論文を実装するぞ!

というモチベーションでお勉強することになりました。

 

それにあたり、進める手順として以下のようにしようと、決まりました。

[1] TensorFlow でひながたNNを作る

[2] いろいろ変えられるようになる

[3] Semantic Segmentation のひながたを作る

[4] 論文を読む

[5] 論文をTensorFlowで再現

 

さて、今回は上記の [1]、[2]をやりました。

 

以下、目次です。

 

0. CondaでTensorflow-gpu 2.xを導入

 以下の手順でTensorflow-gpuを入れました。

なお、OSはWindows 10です。

0-1. Conda で仮想環境を作る

コマンドプロンプト上で以下のコマンドを入力

> conda create -n myenv python=3.7
> conda activate myenv

# 最初、python 3.8.x を入れていたのですが、tensorflow-gpuを入れるときに低いバージョンにしてと怒られたので、python 3.7.x を入れました。

0-2. tensorflow-gpuのインストール

仮想環境が立ち上がった状態でコマンドプロンプト上で以下のコマンドを入力

> conda install -c anaconda tensorflow-gpu

0-3. tensorflowのバージョン確認

コマンドプロンプト上で以下を入力

> python
>>> import tensorflow as tf
>>> print(tf.__version__)

これで入っているバージョンが確認できます。おそらくtensorflowの 2.x が入っていることでしょう。

0-4. tensorflowでGPUを認識しているか確認*1

コマンドプロンプト上で以下を入力

> python
>>> from tensorflow.python.client import device_lib
>>> device_lib.list_local_devices()

"GPU"が表示されていればOK!

 

1. MNISTを学習するためのソースをSequential APIで実装

 Tensorflowの公式のチュートリアル*2を参考に、Sequential APIでMNISTデータセットを学習させてみました。
チュートリアルを丸パクリではつまらないので、全結合だけでなくConvolutionも入れてみました。

Sequential APIで自分のモデルを作る場合、model.add でどんどんlayerを追加していくようです。それだけで簡単にモデルを構築できちゃいます。
しかし、Sequential APIはlayerを積み重ねることしができず、branchを分けるようなことはできません。そのため、ResNetやU-NetのようにSkip Connectionがあるモデルは実装できないと思います。
また、入力と出力は1つのテンソルのみです。Lossを複数定義することは出来ないでしょう。

以下、実際に作ったソースコードです。

import tensorflow as tf


# グラボのメモリが不足してる時ばこれをいれる
physical_devices = tf.config.list_physical_devices('GPU')
try:
  tf.config.experimental.set_memory_growth(physical_devices[0], True)
except:
  # Invalid device or cannot modify virtual devices once initialized.
  pass


# エポック、バッチサイズの設定
epochs = 20
batch_size = 128


# mnistデータセットのロード
mnist = tf.keras.datasets.mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0  # 画像のpixelの値は0~255なので0.0~1.0に正規化

# 入力画像をreshape
# 入力は(batch数, 幅, 高さ, チャネル)を想定しているが、x_trainは(batch数, 幅, 高さ)となっているのでReshape
x_train = x_train.reshape(x_train.shape[0], x_train.shape[1], x_train.shape[2], 1)
x_test  = x_test.reshape(x_test.shape[0],   x_test.shape[1],  x_test.shape[2], 1)
input_shape = (x_train.shape[1], x_train.shape[2], 1)

# モデル構築
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape))
model.add(tf.keras.layers.Conv2D(64, kernel_size=(3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Dropout(0.25))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(128, activation='relu'))
model.add(tf.keras.layers.Dropout(0.5))
model.add(tf.keras.layers.Dense(10, activation='softmax'))


model.summary()


# 損失関数
loss_fn = tf.keras.losses.sparse_categorical_crossentropy

model.compile(optimizer='adam', # 最適化アルゴリズム
              loss=loss_fn,     # 損失関数
              metrics=['accuracy'])

# 学習
model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=epochs,
          verbose=1,
          validation_data=(x_test, y_test))

# 評価
score = model.evaluate(x_test,  y_test, verbose=0)

print('Test loss:', score[0])
print('Test accuracy:', score[1])

# save model
model.save("model_mnist_cnn.h5")

 

2. MNISTを学習するためのソースをFunctional APIで実装

 こちらもTensorflowの公式サイト*3を参考にソースコードを作りました。1 で作ったSequential APIのモデル構造はそのままに、Functional APIの書き方で書きました。

Functional APIで自分のモデルを作る場合、まるで関数の数式を書くようにlayerを追加できます。

例えば、y=f(x)という数式で考えると、
x: 入力のテンソル
f: 自分で設定したレイヤ (<-- tf.keras.layers.Conv2D() とか tf.keras.layers.Dense() とか)
y: 出力のテンソル
という意味になります。だからこれをつなげて、
y1=f1(x)
y2=f2(y1)
y3=f3(y2)
...
と書けばOKです。

Functional APIでは、Sequential APIでは出来ない"layerのbranchを分けること"や"入力と出力を複数用意すること"ができます。これを使えるようになれば、論文に書かれているモデルを実装するときに障害がかなりなくなります。

 

以下、実際に作ったソースコードです。

import tensorflow as tf


# グラボのメモリが不足してる時ばこれをいれる
physical_devices = tf.config.list_physical_devices('GPU')
try:
  tf.config.experimental.set_memory_growth(physical_devices[0], True)
except:
  # Invalid device or cannot modify virtual devices once initialized.
  pass


# エポック、バッチサイズの設定
epochs = 20
batch_size = 128


# mnistデータセットのロード
mnist = tf.keras.datasets.mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0  # 画像のpixelの値は0~255なので0.0~1.0に正規化

# 入力画像をreshape
# 入力は(batch数, 幅, 高さ, チャネル)を想定しているが、x_trainは(batch数, 幅, 高さ)となっているのでReshape
x_train = x_train.reshape(x_train.shape[0], x_train.shape[1], x_train.shape[2], 1)
x_test  = x_test.reshape(x_test.shape[0],   x_test.shape[1],  x_test.shape[2], 1)
input_shape = (x_train.shape[1], x_train.shape[2], 1)

# モデル構築
mnist_inputs = tf.keras.Input(shape=input_shape, name='mnist_input')
conv_1 = tf.keras.layers.Conv2D(32, kernel_size=(3, 3), activation='relu')(mnist_inputs)
conv_2 = tf.keras.layers.Conv2D(64, kernel_size=(3, 3), activation='relu')(conv_1)
conv_2 = tf.keras.layers.Dropout(0.25)(conv_2)
pool_3 = tf.keras.layers.MaxPooling2D(pool_size=(2, 2))(conv_2)
flat_4 = tf.keras.layers.Flatten()(pool_3)
dense_5 = tf.keras.layers.Dense(128, activation='relu')(flat_4)
dense_5 = tf.keras.layers.Dropout(0.5)(dense_5)
mnist_outputs = tf.keras.layers.Dense(10, activation='softmax')(dense_5)

model = tf.keras.Model(inputs=mnist_inputs, outputs=mnist_outputs, name="mnist_model")


model.summary()


# 損失関数
loss_fn = tf.keras.losses.sparse_categorical_crossentropy

model.compile(optimizer='adam', # 最適化アルゴリズム
              loss=loss_fn,     # 損失関数
              metrics=['accuracy'])

# 学習
model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=epochs,
          verbose=1,
          validation_data=(x_test, y_test))

# 評価
score = model.evaluate(x_test,  y_test, verbose=0)

print('Test loss:', score[0])
print('Test accuracy:', score[1])

# save model
model.save("model_mnist_func_cnn.h5")

 

3. 次回は何をやるか

今回の勉強会で

[1] TensorFlow でひながたNNを作る

[2] いろいろ変えられるようになる

が終わったので、次回は

[3] Semantic Segmentation のひながたを作る

をやる予定です。

(次回もみんなで早起きする予定)

 

それではまた次回!