マラリア細胞検知を題材に、TensorFlowの3つのモデル構築方法を解説
はじめに
TensorFlow には、モデルの定義方法が3つ存在します。
それぞれの方法を用いて、マラリア細胞の検知する LeNet ライクなモデルを構築する。
完全なコードは以下にアップロードした。この記事では重要な部分だけ説明する。
データセット
データセットは以下を用いる。
画像のサイズを揃えて正規化を行う。
import tensorflow_datasets as tfds
import tensorflow as tf
IM_SIZE = 224
@tf.function
def resize(image, label):
return tf.image.resize(image, (IM_SIZE, IM_SIZE))/255.0, label
dataset, dataset_info = tfds.load('malaria', with_info=True, as_supervised=True, shuffle_files = True, split=['train'])
dataset = dataset[0].map(resize, num_parallel_calls=tf.data.experimental.AUTOTUNE)
Sequential モデル
Sequential は、各レイヤーに一つの入力と一つの出力があるニューラルネットワークのモデルを簡単に構築出来る。
コードを以下に示す。
lenet_model = tf.keras.Sequential([
InputLayer(input_shape = (IM_SIZE, IM_SIZE, 3)),
Conv2D(filters = N_FILTERS , kernel_size = KERNEL_SIZE, strides = N_STRIDES , padding='valid',
activation = 'relu',kernel_regularizer = L2(REGULARIZATION_RATE)),
BatchNormalization(),
MaxPool2D (pool_size = POOL_SIZE, strides= N_STRIDES*2),
Dropout(rate = DROPOUT_RATE ),
Conv2D(filters = N_FILTERS*2 + 4, kernel_size = KERNEL_SIZE, strides=N_STRIDES, padding='valid',
activation = 'relu', kernel_regularizer = L2(REGULARIZATION_RATE)),
BatchNormalization(),
MaxPool2D (pool_size = POOL_SIZE, strides= N_STRIDES*2),
Flatten(),
Dense( CONFIGURATION['N_DENSE_1'], activation = "relu"),
BatchNormalization(),
Dropout(rate = DROPOUT_RATE),
Dense( CONFIGURATION['N_DENSE_2'], activation = "relu"),
BatchNormalization(),
Dense(1, activation = "sigmoid"),
])
lenet_model.summary()
画像を CNN で変換し全結合層で推論を行う。このような基本的な画像検知モデルを作成するのに Sequential は適している。ただ、入力や出力が複数あったり途中で分岐したりするモデルを Sequential で作成することは出来ない。このような複雑なモデル定義するには、次に説明する Functional API を用いる。
Functional API
Functional API はより複雑なモデルを定義するのに使用出来る。今回は Sequential で構築出来るモデルであるため、Functional API を使用するメリットはない。
コードを以下に示す。
func_input = Input(shape=(IM_SIZE, IM_SIZE, 3), name='input')
x = Conv2D(filters = N_FILTERS , kernel_size = KERNEL_SIZE, strides = N_STRIDES , padding='valid',
activation = 'relu',kernel_regularizer = L2(REGULARIZATION_RATE))(func_input)
x = BatchNormalization()(x)
x = MaxPool2D (pool_size = POOL_SIZE, strides= N_STRIDES*2)(x)
x = Dropout(rate = DROPOUT_RATE )(x)
x = Conv2D(filters = N_FILTERS*2 + 4, kernel_size = KERNEL_SIZE, strides=N_STRIDES, padding='valid',
activation = 'relu', kernel_regularizer = L2(REGULARIZATION_RATE))(x)
x = BatchNormalization()(x)
x = MaxPool2D (pool_size = POOL_SIZE, strides= N_STRIDES*2)(x)
x = Flatten()(x)
x = Dense( CONFIGURATION['N_DENSE_1'], activation = "relu")(x)
x = BatchNormalization()(x)
x = Dropout(rate = DROPOUT_RATE)(x)
x = Dense( CONFIGURATION['N_DENSE_2'], activation = "relu")(x)
x = BatchNormalization()(x)
output = Dense(1, activation = "sigmoid")(x)
functional_lenet_model = Model(func_input, output, name = "Feature_Extractor")
functional_lenet_model.summary()
出力を順番に入力に加えてくことで、非巡回有向グラフを作成出来る。ただ、RNN のような巡回を持つモデルは Functional API を用いて作成出来ない。より複雑なモデルを定義したい場合は、次に説明するクラスを用いる。
モデルクラス
クラスはより複雑なモデルを定義するのに使用出来る。Layer を継承して再帰的なレイヤーを定義することで、Functional API より複雑なモデルを作成可能である。今回は Sequential で構築出来るモデルであるため、クラス使用するメリットはない。
コードを以下に示す。
class Lenet(Model):
def __init__(self):
super(Lenet, self).__init__()
self.conv1 = Conv2D(filters = N_FILTERS , kernel_size = KERNEL_SIZE, strides = N_STRIDES , padding='valid',
activation = 'relu',kernel_regularizer = L2(REGULARIZATION_RATE))
self.batch_norm1 = BatchNormalization()
self.max_pool1 = MaxPool2D (pool_size = POOL_SIZE, strides= N_STRIDES*2)
self.conv2 = Conv2D(filters = N_FILTERS*2 + 4, kernel_size = KERNEL_SIZE, strides=N_STRIDES, padding='valid',
activation = 'relu', kernel_regularizer = L2(REGULARIZATION_RATE))
self.batch_norm2 = BatchNormalization()
self.max_pool2 = MaxPool2D (pool_size = POOL_SIZE, strides= N_STRIDES*2)
self.flatten = Flatten()
self.dense1 = Dense( CONFIGURATION['N_DENSE_1'], activation = "relu")
self.batch_norm3 = BatchNormalization()
self.dropout1 = Dropout(rate = DROPOUT_RATE)
self.dense2 = Dense( CONFIGURATION['N_DENSE_2'], activation = "relu")
self.batch_norm4 = BatchNormalization()
self.dense3 = Dense(1, activation = "sigmoid")
def call(self, inputs):
x = self.conv1(inputs)
x = self.batch_norm1(x)
x = self.max_pool1(x)
x = self.dropout1(x)
x = self.conv2(x)
x = self.batch_norm2(x)
x = self.max_pool2(x)
x = self.flatten(x)
x = self.dense1(x)
x = self.batch_norm3(x)
x = self.dropout1(x)
x = self.dense2(x)
x = self.batch_norm4(x)
x = self.dense3(x)
return x
class_lenet_model = Lenet()
class_lenet_model.build(input_shape=(None, IM_SIZE, IM_SIZE, 3))
class_lenet_model.summary()
__init__
でレイヤーを定義して、call
でモデルの処理を定義する。call
内で Sequential を用いてモデルを構築することも可能である。
おわりに
Sequential と Functional API とクラスを用いて TensorFlow のモデルを作成する方法について解説した。
Discussion