我需要调试它的行为,在第一步就得到了相当令人困惑的结果。当我输入全零张量后,我期望在第一个Conv2D之后得到一个仅包含Conv2D偏置值的张量(因为所有卷积核元素都被乘以零),但实际上我得到的是一个包含一些随机数据的张量,以下是代码片段:
def test_graph(path=PATH_DEFAULT): interp = tf.lite.Interpreter(path) interp.allocate_tensors() input_details = interp.get_input_details() in_idx = input_details[0]['index'] zeros = np.zeros(shape=(1, 256, 256, 3), dtype=np.float32) interp.set_tensor(in_idx, zeros) interp.invoke() # 第一个conv2d操作的输出索引是3(见netron图片) after_conv_2d = interp.get_tensor(3) # 偏置的形状只是[输出通道数] n, h, w, c = after_conv_2d.shape # 如果我们输入全零张量,我们可以期望得到的唯一值是偏置值 # 因为在这种情况下所有卷积核元素都被乘以零 uniq_vals_cnt = len(np.unique(after_conv_2d)) assert uniq_vals_cnt <= c, f"输出中有{uniq_vals_cnt}个值,应该<= {c}"
输出:
AssertionError: 输出中有287928个值,应该<= 24
有人能帮我解答我的困惑吗?
回答:
看来我假设可以从解释器中获取任何中间张量是错误的,我们只能对输出进行操作,尽管解释器不会抛出错误,并且对于与非输出张量相关的索引也会返回正确形状的张量。
调试此类图的一种方法是将所有张量设为输出,但最简单的方法可能是将tflite
文件转换为pb
,使用toco
,然后再将pb
转换回tflite
,并指定新的输出。不过这种方法并非理想,因为toco
对tflite -> pb
转换的支持在1.9版本后被移除,使用之前的版本可能会在某些图上失败(在我这里就失败了)。
更多信息请见:tflite: get_tensor on non-output tensors gives random values