关于tensorflow lite量化代码、论文和文档不一致的问题

Question about inconsistency between tensorflow lite quantization code, paper and documentation

在google发表的this论文(Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference)中描述了量化方案如下:

其中,

M = S1 * S2 / S3

S1、S2和S3分别是输入和输出的尺度.

S1(和零点Z1)和S2(和零点 Z2) 可以很容易地确定,无论是“离线”还是“在线”。但是 S3(和零点 Z3)呢?这些参数取决于“实际”输出比例(即没有量化的 float 值)。但是输出比例在计算之前是未知的。

根据tensorflow documentation:

At inference, weights are converted from 8-bits of precision to floating point and computed using floating-point kernels. This conversion is done once and cached to reduce latency.

但是下面的code说的是不同的东西:

  tensor_utils::BatchQuantizeFloats(
      input_ptr, batch_size, input_size, quant_data, scaling_factors_ptr,
      input_offset_ptr, params->asymmetric_quantize_inputs);
  for (int b = 0; b < batch_size; ++b) {
    // Incorporate scaling of the filter.
    scaling_factors_ptr[b] *= filter->params.scale;
  }

  // Compute output += weight * quantized_input
  int32_t* scratch = GetTensorData<int32_t>(accum_scratch);
  tensor_utils::MatrixBatchVectorMultiplyAccumulate(
      filter_data, num_units, input_size, quant_data, scaling_factors_ptr,
      batch_size, GetTensorData<float>(output), /*per_channel_scale=*/nullptr,
      input_offset_ptr, scratch, row_sums_ptr, &data->compute_row_sums,
      CpuBackendContext::GetFromContext(context));

这里可以看到:

  scaling_factors_ptr[b] *= filter->params.scale;

我认为这意味着:

  1. S1 * S2 计算出来。
  2. 权重仍然是整数。只是最后的结果是浮点数。
  3. 好像S3和Z3不用计算。但如果是这样的话,最后的float结果怎么可能接近未量化的结果呢?

论文、文档和代码之间的这种不一致让我很困惑。我说不出我错过了什么。谁能帮帮我?

让我回答我自己的问题。突然间我看到了我错过的东西 骑自行车。上面问题中的代码来自函数 tflite::ops::builtin::fully_connected::EvalHybrid()。这里的 名字已经说明了一切!矩阵乘法输出的值为 在论文的 2.2 节中表示为 r3。就方程而言 (2) 在 2.2 节中,我们有:

如果我们想得到矩阵乘法的浮点数结果,我们可以使用2.2节中的等式(4),然后将结果转换回浮点数,或者我们可以使用等式(3)的左边替换为r3,如:

如果我们选择所有的零点都是0,那么上面的公式就变成:

这正是 EvalHybrid() 所做的(暂时忽略偏差)。原来这篇论文给出了量化算法的概述,而实现使用了不同的变体。