注意:本答案是针对TensorFlow 1.x编写的,在TensorFlow 2.x中,其概念和核心思想仍然相同,但本答案中的命令可能已经过时。
TF-Lite机制使得检查图形并获取内部节点的中间值的整个过程有些棘手。另一个回答建议使用的
get_tensor(...)
方法不起作用。
如何可视化TF-Lite推理图?
可以使用
visualize.py脚本在
TensorFlow Lite repository中可视化TensorFlow Lite模型。您只需:
我的TF模型中的节点是否在TF-Lite中有相应的节点?
不是!实际上,TF-Lite可以修改您的图形使其更加优化。以下是TF-Lite文档中关于此的一些说明:
许多TensorFlow操作可以通过TensorFlow Lite进行处理,即使它们没有直接等效项。这适用于可以从图形中简单删除的操作(tf.identity),可以替换为张量的操作(tf.placeholder)或融合到更复杂的操作中(tf.nn.bias_add)。即使某些支持的操作有时也可以通过其中一个这些过程之一进行删除。
此外,TF-Lite API目前不允许获取节点对应关系;很难解释TF-Lite的内部格式。因此,您无法获取任何想要的节点的中间输出,即使没有下面的另一个问题...
我能获取一些TF-Lite节点的中间值吗?
不行! 在这里,我将解释为什么 get_tensor(...)
在TF-Lite中无法工作。假设在内部表示中,图包含3个张量,以及一些中间的密集操作(节点)(您可以认为tensor1
是模型输入,tensor3
是输出)。在推理此特定图时,TF-Lite 仅需要 2个缓冲区,让我们来展示一下。
首先,使用tensor1
通过应用dense
操作来计算tensor2
。这只需要2个缓冲区来存储值:
dense dense
[tensor1] -------> [tensor2] -------> [tensor3]
^^^^^^^ ^^^^^^^
bufferA bufferB
其次,使用存储在bufferB
中的tensor2
的值来计算tensor3
...但是等等!我们不再需要bufferA
,所以让我们用它来存储tensor3
的值:
dense dense
[tensor1] -------> [tensor2] -------> [tensor3]
^^^^^^^ ^^^^^^^
bufferB bufferA
现在是棘手的部分。
tensor1
的“输出值”仍将指向
bufferA
,它现在保存着
tensor3
的值。因此,如果您为第一个张量调用
get_tensor(...)
,您将得到不正确的值。甚至该方法的
文档也声明:
此函数不能用于读取中间结果。
如何解决这个问题?
Easy but limited way. You can specify the names of the nodes, output tensors of which you want to get the values of during conversion:
tflite_convert \
--
--output_arrays="output_node,intermediate/node/n1,intermediate/node/n2"
Hard but flexible way. You can compile TF-Lite with Bazel (using this instruction). Then you can actually inject some logging code to Interpreter::Invoke()
in the file tensorflow/lite/interpreter.cc
. An ugly hack, but it works.
cd
进入正确的文件夹并且只bazel build
需要的项目。你不必构建整个TF,只需构建TFLite(甚至TFLite的部分)。每次构建只需要2-3分钟,所以我可以快速迭代。 - Chan Kha Vu