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