Tensorflow Lite объединяет функцию активации с самой операцией, поэтому Relu
ops будут удалены из графика.Цитата из документации (в которой также упоминается tf.nn.relu
):
Обратите внимание, что многие из этих операций не имеют эквивалентов TensorFlow Lite и соответствующая модель не будет конвертируемой, еслиони не могут быть исключены или слиты.
Давайте посмотрим, что это значит.Приведенный выше код PReLU в TensorFlow, визуализированный с использованием TensorBoard , выглядит следующим образом (график ORIGINAL ):
conv --> relu ---------------------\
\-> neg -> relu -> mul -> neg --> add
Однако из-за того, что TfLiteобъединяет операции Relu
с предыдущей операцией (подробнее в документы ), TRY создаст что-то вроде этого (обратите внимание, что [A+B]
представляет собой сплавленный слой A
и B
ops):
[conv+relu] -----------------------------\
\-> [neg+relu] -> mul -> neg --> add
Но, поскольку операция neg
(унарный минус) не имеет функции активации, что ACTUALLY происходит внутри внешнего вида TF-Liteкак следующее (это было проверено мной на версии 1.9.0
):
[conv+relu] ----------------------\
\-> neg -> mul -> neg --> add
Так что, это не имеет смысла!
Моя личная работа заключается в следующем(учитывая, что у вас уже есть обученная модель *.pb
и вы не хотите переобучать новую модель только потому, что архитектура изменилась):
def tflite_tolerant_prelu(_x, alpha, name_scope):
with tf.name_scope(name_scope):
alpha = tf.constant(alpha, name='alpha')
return tf.maximum(_x, 0) + alpha * tf.minimum(_x, 0)
def replace_prelu(graph, prelu_block_name, tensor_before, tensor_after):
alpha = graph.get_tensor_by_name(os.path.join(prelu_block_name, 'alpha:0'))
with tf.Session() as sess:
alpha_val = alpha.eval()
new_prelu = tflite_tolerant_prelu(tensor_before,
alpha_val, prelu_block_name + '_new')
tf.contrib.graph_editor.swap_inputs(tensor_after.op, [new_prelu])
before = mtcnn_graph.get_tensor_by_name('pnet/conv1/BiasAdd:0')
after = mtcnn_graph.get_tensor_by_name('pnet/pool1:0')
replace_prelu(mtcnn_graph, 'pnet/PReLU1', before, after)
Этот код использовался для передачи MTCNN от TensorFlow до TensorFlow Lite.Выглядит немного некрасиво (определенно нужно, чтобы он выглядел чище), но он полностью функционален и выполняет свою работу.Обратите внимание, что я использовал инструмент редактора графиков tensorflow.contrib.graph_editor
, чтобы изменить график в автономном режиме.