Ошибка "Размеры должны совпадать" при преобразовании tflite в toco - PullRequest
2 голосов
/ 13 мая 2019

У меня есть пользовательская модель CNN (классификатор изображений), обученная с помощью оценщика TensorFlow, и я собираюсь использовать ее в приложении для iOS после преобразования в модель TensorFlowLite.

Моя модель имеет несколько выпадающих слоев, а также слои пакетной нормализации.Чтобы избежать ошибок преобразования и удалить эти выпадающие слои в процессе optimize_for_inference, я сохранил eval_graph.pbtxt отдельно от файлов контрольных точек, чтобы использовать его в freeze_graph.

Все отлично работает в freeze_graph, и optimize_for_inference также не выдает ошибок.Однако после импорта файлов с замороженной и оптимизированной моделями (оба .pb) в тензорную доску для проверки я обнаружил:

замороженную модель перед оптимизацией freezed model before optimization

модель после оптимизации model after optimization

Кажется 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 форм неизвестны.

Почему?

Ответы [ 4 ]

3 голосов
/ 14 мая 2019

Да, должно быть после плотного:

model.add(Dense(.., ..))
model.add(BatchNormalization())
model.add(Activation(...))
model.add(Dropout(...))
2 голосов
/ 13 мая 2019

optimize_for_inference удаляет выпадающие слои из графика как случайные, обычно используется выпадение на входах. Поэтому ответ может быть ДА.

bazel-bin/tensorflow/python/tools/optimize_for_inference \ 
--input=/tf_files/retrained_graph.pb \ 
--output=/tf_files/optimized_graph.pb \ 
--input_names={} \ 
--output_names=result

Давайте попробуем выполнить пользовательскую реализацию с RandomUniform, FLOOR, TensorFlowShape, TensorFlowSwitch, TensorFlowMerge, чтобы отключить ошибку.

Ссылка: Регуляризация отсева

1 голос
/ 14 мая 2019

ну, похоже, что своп bn-4 и dense-1 отключает ошибку. Таким образом, нормализация партии должна произойти ПОСЛЕ плотного в этом случае (скажем, сразу за conv2d-> плотное изменение формы).

0 голосов
/ 14 мая 2019

Вы должны использовать eval.pbtxt, когда вы используете замороженный график вместо graph.pbtxt.

Пожалуйста, дайте проверить тензор потока / модели

Итак, давайте заменим «None» как ноль для первого измерения, а для остальных заменим размер вектора / матрицы описания. Другой момент заключается в соблюдении правила умножения матриц, которое гласит, что количество столбцов первого операнда должно соответствовать количеству строк второго операнда.

Если вам это поможет, примите ответ.

...