Tensorflow Lite 将激活函数与操作本身融合,因此Relu 操作将从图中删除。来自documentation 的引用(也提到了tf.nn.relu):
请注意,其中许多操作没有 TensorFlow Lite 等效项,如果无法省略或融合,则相应的模型将无法转换。
让我们看看它是什么意思。您上面的 TensorFlow 中的 PReLU 代码,使用 TensorBoard 可视化,如下所示(ORIGINAL 图):
conv --> relu ---------------------\
\-> neg -> relu -> mul -> neg --> add
但是,由于 TfLite 将 Relu 操作与之前的操作融合在一起(更多内容在 docs 中),它会尝试做出这样的事情(注意 [A+B]是A 和B ops 的融合层):
[conv+relu] -----------------------------\
\-> [neg+relu] -> mul -> neg --> add
但是,由于neg 操作(一元减号)在设计上没有激活功能,所以 ACTUALLY 在 TF-Lite 中发生的情况如下所示(这是我自己在版本 @987654335 上测试的@):
[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 在离线模式下修改图形。