はじめに
kerasではVGGなどのpretrained modelを簡単に利用できます。
一方、tensorflowにはpretrained modelが含まれていないため、
ネットワーク定義やweightをどこかから入手してくる必要があり、面倒です。
(TFLearnやTF-Slimには含まれているようですが、tensorflowのラッパーはkerasだけでお腹いっぱいです)
そこで本記事では、kerasのpretrained modelをtensorflowで利用してfinetuningする方法を紹介します。
参考ページ
http://zachmoshe.com/2017/11/11/use-keras-models-with-tf.html
https://github.com/JihongJu/keras-fcn/blob/master/keras_fcn/metrics.py
pretrained modelをkerasのみで利用する
まずは、pretrained modelをkerasのみで利用するコードを紹介します。
このコードについてはネット上にいくらでも情報が落ちているので、説明は省略します。
from tensorflow.python.keras.datasets import cifar10
from tensorflow.python.keras.applications.vgg16 import VGG16
from tensorflow.python.keras.models import Model
from tensorflow.python.keras.layers import Dense
from tensorflow.python.keras import optimizers
# param
hidden_units = 1024
output_units = 10
# data
(x_train, t_train), (x_test, t_test) = cifar10.load_data()
x_train = x_train.astype('float32') / 255.0
x_test = x_test.astype('float32') / 255.0
t_train = t_train.flatten()
t_test = t_test.flatten()
# model
base_model = VGG16(weights='imagenet',
include_top=False,
pooling='avg')
h = base_model.output
h = Dense(hidden_units, activation='relu')(h)
y = Dense(output_units, activation='softmax')(h)
model = Model(inputs=base_model.input, outputs=y)
# trainable variables
for layer in base_model.layers:
layer.trainable = False
# loss and optimizer
model.compile(loss = 'sparse_categorical_crossentropy',
optimizer = optimizers.SGD(lr=0.01),
metrics=['accuracy'])
# training
model.fit(x_train, t_train, epochs=5, batch_size=50)
pretrained modelをtensorflowで利用する
次に、本題のpretrained modelをtensorflowで利用するコードを紹介します。
from tensorflow.python.keras.datasets import cifar10
from tensorflow.python.keras.applications.vgg16 import VGG16
from tensorflow.python.keras.models import Model
from tensorflow.python.keras.layers import Dense
from tensorflow.python.keras import backend as K
import numpy as np
import tensorflow as tf
# param
hidden_units = 1024
output_units = 10
# data
(x_train, t_train), (x_test, t_test) = cifar10.load_data()
x_train = x_train.astype('float32') / 255.0
x_test = x_test.astype('float32') / 255.0
t_train = t_train.flatten()
t_test = t_test.flatten()
# model
base_model = VGG16(weights='imagenet',
include_top=False,
pooling='avg')
x = tf.placeholder(tf.float32, [None, x_train.shape[1], x_train.shape[2], x_train.shape[3]])
t = tf.placeholder(tf.int64, [None, ])
h = base_model(x)
h = tf.layers.dense(h, hidden_units, activation='relu')
y = tf.layers.dense(h, output_units)
# trainable & uninitialized variables
uninitialized_variables = [v for v in tf.global_variables() \
if not hasattr(v, '_keras_initialized') or not v._keras_initialized]
# loss and optimizer
ops = dict()
ops['loss'] = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(labels=t, logits=y))
correct = tf.equal(tf.argmax(y, 1), t)
ops['accuracy'] = tf.reduce_mean(tf.cast(correct, "float"))
opt = tf.train.GradientDescentOptimizer(learning_rate=0.01)
ops['train_step'] = opt.minimize(ops['loss'], var_list=uninitialized_variables)
# initialization
sess = K.get_session()
sess.run(tf.variables_initializer(uninitialized_variables))
# training
epochs = 5
batch_size = 50
data_num = x_train.shape[0]
for epoch in range(epochs):
loss_sum = 0
accuracy_sum = 0
shuffle_idx = np.random.permutation(data_num)
for idx in range(0, data_num, batch_size):
x_batch = x_train[shuffle_idx[
idx : idx + batch_size if idx + batch_size < data_num else data_num]]
t_batch = t_train[shuffle_idx[
idx : idx + batch_size if idx + batch_size < data_num else data_num]]
ops_value = sess.run(ops, feed_dict = {x:x_batch, t:t_batch})
loss_sum += ops_value['loss'] * x_batch.shape[0]
accuracy_sum += ops_value['accuracy'] * x_batch.shape[0]
print('\repoch : {} {}/{} train_loss : {} train_accuracy : {}'.format( \
epoch, idx, data_num, loss_sum / (idx + x_batch.shape[0]), accuracy_sum / (idx + x_batch.shape[0])), end="")
print()
それでは、肝となる部分を解説していきます。
trainable & uninitialized variables
uninitialized_variables = \
[v for v in tf.global_variables() if not hasattr(v, '_keras_initialized') or not v._keras_initialized]
この部分では、VGGのpretrainedな層以外のvariablesを抽出します。
trainable variablesを指定して最適化
ops['train_step'] = opt.minimize(ops['loss'], var_list=uninitialized_variables)
上記抽出したvariablesをtrainable variablesとして指定して最適化を行います。
uninitialized variablesのみを初期化
sess.run(tf.variables_initializer(uninitialized_variables))
抽出したvariablesのみを初期化します。
初期化によく使われるglobal_variables_initializer()で初期化すると、pretrained weightも初期化されてしまいます。
注意点
kerasはtensorflowに統合されたもの(tensorflow.python.keras)を利用した方が良いです。
tensorflowとは別にインストールしたkerasだとバージョンの組み合わせによっては上記コードが動かないようです。
おわりに
上記の方法でkerasのpretrained modelをtensorflowで利用することができます。
kerasがtensorflowに統合されたことですし、keras+tensorflowでコーディングを簡略化していきたいですね。