У меня есть пользовательская модель CNN (классификатор изображений), обученная с помощью оценщика TensorFlow, и я собираюсь использовать ее в приложении для iOS после преобразования в модель TensorFlowLite.
Моя модель имеет несколько выпадающих слоев, а также слои пакетной нормализации.Чтобы избежать ошибок преобразования и удалить эти выпадающие слои в процессе optimize_for_inference
, я сохранил eval_graph.pbtxt
отдельно от файлов контрольных точек, чтобы использовать его в freeze_graph
.
Все отлично работает в freeze_graph
, и optimize_for_inference
также не выдает ошибок.Однако после импорта файлов с замороженной и оптимизированной моделями (оба .pb
) в тензорную доску для проверки я обнаружил:
замороженную модель перед оптимизацией
модель после оптимизации
Кажется optimize_for_inference
удаленные фигурыинформация о входном тензорном слое, что не так, если я замораживаю модель с графиком, сохраненным в режиме обучения (по умолчанию graph.pbtxt
), и оптимизирую его.
Среды:
- Tensorflow 1.8.0 для обучения;
- Tensorflow 1.13.1 для преобразования;
Коды, как указано ниже:
Отрывок model_fn, довольно обычный:
def cnn_model_fn(features, labels, mode, params):
"""Model function for CNN."""
# Input Layer, images aleady reshaped before feed in;
net = tf.placeholder_with_default(
features['Pixels'],
(None, 48, 48, 1),
name='input_tensor'
)
# bn-1
net = tf.layers.batch_normalization(
inputs=net,
training=mode == tf.estimator.ModeKeys.TRAIN
)
# conv2d-1
net = tf.layers.conv2d(
inputs=net,
filters=32,
kernel_size=[3, 3],
padding='same',
activation=tf.nn.relu
)
# conv2ds, dropouts, poolings, bns...
# CONV2Ds -> DENSEs
# 48 pixels pooled three times (kernel_sizes=2, strides=2), and final conv2d has 128 neurons;
net = tf.reshape(net, [-1, 6 * 6 * 128])
# bn-4
net = tf.layers.batch_normalization(
inputs=net,
training=mode == tf.estimator.ModeKeys.TRAIN
)
# dense-1
net = tf.layers.dense(
inputs=net,
units=256,
kernel_regularizer=keras.regularizers.l2(0.001),
activation=tf.nn.relu
)
# denses, logits, nothing special...
# In prediction:
if mode == tf.estimator.ModeKeys.PREDICT:
return tf.estimator.EstimatorSpec(...)
# In evaluation:
if mode == tf.estimator.ModeKeys.EVAL:
# hook for saving graph in eval mode, this graph will be used in freezing & optimizing process;
eval_finish_hook = EvalFinishHook()
eval_finish_hook.model_dir = params['model_dir']
return tf.estimator.EstimatorSpec(
...,
evaluation_hooks=[eval_finish_hook]
)
# In training:
if mode == tf.estimator.ModeKeys.TRAIN:
return tf.estimator.EstimatorSpec(...)
и пользовательский класс eval hook:
class EvalFinishHook(tf.train.SessionRunHook):
model_dir = '.'
_saver = None
def begin(self):
self._saver = tf.train.Saver()
super().begin()
def end(self, session):
dst_dir = self.model_dir + 'eval_ckpt'
self._saver.save(sess=session, save_path=dst_dir + '/eval.ckpt')
tf.train.write_graph(session.graph.as_graph_def(), dst_dir, 'eval_graph.pbtxt')
super().end(session)
стоп-кадр и оптимизация:
# freeze graph
echo "freezing checkpoint ${best_step}..."
freeze_graph \
--input_graph=${input_graph} \
--input_checkpoint=${input_checkpoint} \
--input_binary=false \
--output_graph=${frozen_model} \
--output_node_names=${output_names} \
# optimize for inference
echo "optimizing..."
/path/to/bazel-bin/tensorflow/python/tools/optimize_for_inference \
--input=${frozen_model} \
--output=${optimized_model} \
--frozen_graph=True \
--input_names=${input_names} \
--output_names=${output_names}
ошибка бросков toco:
# convert to tflite
echo "converting..."
toco \
--graph_def_file=${optimized_model} \
--input_format=TENSORFLOW_GRAPHDEF \
--output_format=TFLITE \
--inference_type=FLOAT \
--input_type=FLOAT \
--input_arrays=${input_names} \
--output_arrays=${output_names} \
--input_shapes=1,48,48,1 \
--output_file=${tflite_model}
# error info
Check failed: dim_x == dim_y (128 vs. 4608)Dimensions must match
Эта ошибка кажется разумной, так как формы 1 и 2 форм неизвестны.
Почему?