【问题标题】:TF-Lite: PReLU works incorrectly after converting pb model to tfliteTF-Lite:将 pb 模型转换为 tflite 后 PReLU 工作不正确
【发布时间】:2018-09-12 03:37:19
【问题描述】:

在 pb 模型中,我有一个PRelu 层。因为tflite 没有PRelu OP,所以我将PRelu 转换为Relu 如下:

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

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

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

有什么问题吗?

【问题讨论】:

  • 嗨@xhsoldier。最新的 tflite 解决了这个问题。顺便说一句,你是如何处理 pnet 的可变输入大小的?谢谢
  • @HoaVu,为了简单地解决这个问题,将 PRelu 更改为 Max(x, 0) + alphas* Min(0, x)
  • 我的意思是另一个问题。 TFLite 需要固定的具体输入大小,而 pnet 可以处理输入图像的许多缩放版本。

标签: tensorflow keras tensorflow-lite tensorflow2.0


【解决方案1】:

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

【讨论】:

  • 我用x和0之间的max min op替换了PRelu,也解决了这个问题,容易多了。
  • @xhsoldier 发布答案后,我意识到...... TF-Lite 中没有“Abs”操作。所以我现在使用的也是minmax ops。
【解决方案2】:

要简单地解决此问题,请将 PRelu 更改为 Max(x, 0) + alphas* Min(0, x)

【讨论】:

    猜你喜欢
    • 2021-08-05
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 2018-09-07
    • 2020-12-03
    • 2019-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多