在pb模型中,我有一个PRelu
层。因为tflite
没有PRelu
OP,所以我将PRelu
转换为Relu
就像这样:
pos = relu(x)
neg = - alphas * relu(-x)
return pos + neg
转换为tflite
模型时,PRelu
将由relu
和负OP代替。但是在转换时,两个负数op之间的负数relu
op被toco
丢弃。转换后的模型如下所示:
pos = relu(x)
neg = -alphas * (-x)
return pos + neg
有什么问题吗?
答案 0 :(得分:2)
Tensorflow Lite将激活功能与op本身融合在一起,因此Relu
ops将被从图中删除。来自documentation的引用(还提到了tf.nn.relu
):
请注意,其中许多操作没有TensorFlow Lite等效项,并且如果无法消除或融合它们,则相应的模型将无法转换。
让我们看看它的含义。上面使用TensorBoard可视化的TensorFlow中的PReLU代码如下(原始图):
conv --> relu ---------------------\
\-> neg -> relu -> mul -> neg --> add
但是,由于TfLite将Relu
的操作与先前的操作(在docs中有更多的操作)融合在一起,因此 TRY 会进行如下操作(请注意[A+B]
是A
和B
操作的融合层):
[conv+relu] -----------------------------\
\-> [neg+relu] -> mul -> neg --> add
但是,由于neg
操作(一元减)没有设计上的激活功能,因此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
来以离线模式修改图形。
答案 1 :(得分:1)
要简单地解决此问题,请将PRelu更改为 Max(x,0)+ alphas * Min(0,x)