2

在 pb 模型中,我有一个PRelu层。因为tflite没有PReluOP,所以我将其转换PReluRelu

 pos = relu(x)
 neg = - alphas * relu(-x)
 return pos + neg

转换为tflite模型时,PRelu将替换为relu负 OP。但是在转换时,relu两个负运算之间的负运算运算被删除toco。转换后的模型如下所示:

pos = relu(x)
neg = -alphas * (-x)
return pos + neg

任何问题?

4

2 回答 2

3

Tensorflow Lite 将激活函数与操作本身融合,因此Relu操作将从图中删除。从文档中引用(也提到了关于tf.nn.relu):

请注意,其中许多操作没有 TensorFlow Lite 等效项,并且如果它们不能被省略或融合,则相应的模型将无法转换。


让我们看看它是什么意思。您上面的 TensorFlow 中的 PReLU 代码,使用TensorBoard进行可视化,如下所示(原始图):

conv --> relu ---------------------\
     \-> neg -> relu -> mul -> neg --> add

然而,由于 TfLite 将Relu操作与前一个操作融合在一起(更多在docs中),它会尝试做这样的事情(注意这[A+B]是一个融合层AB操作):

[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在离线模式下修改图形。

于 2018-09-27T14:59:51.390 回答
1

为了简单地解决这个问题,将 PRelu 更改为 Max(x, 0) + alphas* Min(0, x)

于 2018-09-29T09:22:39.887 回答