代码之家  ›  专栏  ›  技术社区  ›  mrgloom

理解tf.contrib.lite公司.TFLiteConverter量化参数

  •  0
  • mrgloom  · 技术社区  · 7 年前

    我尝试在将tensorflow模型转换为tflite模型时使用UINT8量化:

    如果使用 post_training_quantize = True ,模型大小比原来的fp32模型低4倍,所以我假设模型权重是uint8,但是当我加载模型并通过 interpreter_aligner.get_input_details()[0]['dtype'] 是浮动32。量化模型的输出与原始模型基本相同。

    converter = tf.contrib.lite.TFLiteConverter.from_frozen_graph(
            graph_def_file='tflite-models/tf_model.pb',
            input_arrays=input_node_names,
            output_arrays=output_node_names)
    converter.post_training_quantize = True
    tflite_model = converter.convert()
    

    print(interpreter_aligner.get_input_details())
    print(interpreter_aligner.get_output_details())
    [{'name': 'input_1_1', 'index': 47, 'shape': array([  1, 128, 128,   3], dtype=int32), 'dtype': <class 'numpy.float32'>, 'quantization': (0.0, 0)}]
    [{'name': 'global_average_pooling2d_1_1/Mean', 'index': 45, 'shape': array([  1, 156], dtype=int32), 'dtype': <class 'numpy.float32'>, 'quantization': (0.0, 0)}]
    

    另一个选择是显式指定更多参数: 模型大小比原来的fp32模型低4倍,模型输入类型是uint8,但模型输出更像垃圾。

    converter = tf.contrib.lite.TFLiteConverter.from_frozen_graph(
            graph_def_file='tflite-models/tf_model.pb',
            input_arrays=input_node_names,
            output_arrays=output_node_names)
    converter.post_training_quantize = True
    converter.inference_type = tf.contrib.lite.constants.QUANTIZED_UINT8
    converter.quantized_input_stats = {input_node_names[0]: (0.0, 255.0)}  # (mean, stddev)
    converter.default_ranges_stats = (-100, +100)
    tflite_model = converter.convert()
    

    转换模型的输入/输出:

    [{'name': 'input_1_1', 'index': 47, 'shape': array([  1, 128, 128,   3], dtype=int32), 'dtype': <class 'numpy.uint8'>, 'quantization': (0.003921568859368563, 0)}]
    [{'name': 'global_average_pooling2d_1_1/Mean', 'index': 45, 'shape': array([  1, 156], dtype=int32), 'dtype': <class 'numpy.uint8'>, 'quantization': (0.7843137383460999, 128)}]
    

    1. 发生了什么事 训练后量化=真
    2. 如何估计第二种情况下的平均值、标准差和范围参数?
    3. 看来第二种情况下模型推理速度更快,是不是取决于模型输入是uint8?
    4. 'quantization': (0.0, 0) 在第一种情况下 'quantization': (0.003921568859368563, 0) , 'quantization': (0.7843137383460999, 128) 第二种情况?
    5. converter.default_ranges_stats ?

    找到问题4的答案 What does 'quantization' mean in interpreter.get_input_details()?

    0 回复  |  直到 7 年前
        1
  •  7
  •   MohamedEzz    6 年前

    在tf1.14中,这似乎只是量化存储在磁盘上的.tflite文件中的权重。这本身不会将推理模式设置为量化推理。

    float32 但是模型权重是量化的(使用 post_training_quantize=True )为了降低磁盘大小,在运行时更快地加载模型。

    如何估计第二种情况下的平均值、标准差和范围参数?

    许多人对这些文件感到困惑。让我解释一下我在研究之后得出的结论:

    1. 相等的 TF库和文档中的表单/表示:
      • (一) (mean, std_dev)
      • (zero_point, scale)
      • (三) (min,max)
    2. B)和A)的换算:
      • std_dev = 1.0 / scale
      • mean = zero_point
    3. 从C)转换为A):
      • mean = 255.0*min / (min - max)
      • std_dev = 255.0 / (max - min)
      • 说明:量化统计是用于将范围(0255)映射到任意范围的参数,可以从以下两个等式开始: min / std_dev + mean = 0 和 max / std_dev + mean = 255 ,然后根据数学推导得出上述换算公式
    4. 从A)到C)的转换:
      • min = - mean * std_dev
      • max = (255 - mean) * std_dev

    回答您的问题:,如果您的输入图像具有:

    • 量程(0255)则 mean = 0, std_dev = 1
    • mean = 127.5, std_dev = 127.5
    • 范围(0,1),然后 mean = 0, std_dev = 255

    看来第二种情况下模型推理速度更快,是不是取决于模型输入是uint8?

    是的,可能。然而,量化模型通常较慢,除非您使用特定硬件的矢量化指令。TFLite被优化为为ARM处理器运行那些专门的指令。从tf1.14或1.15开始,如果你在本地机器x86intel或AMD上运行它,那么如果量化模型运行得更快,我会感到惊讶。[更新:TFLite的路线图上增加了对x86矢量化指令的一流支持,使量化推理比浮点运算更快]

    什么是“量化”:(0.0,0)(在第一种情况下)和“量化”:(0.0039215688593685563,0),“量化”:(0.7843137383460999,128)在第二种情况下?

    这里的格式是 quantization: (scale, zero_point)

    在你的第一个例子中,你只激活了 训练后量化=真 null ,表示为 (0,0) .

    inference_type = tf.contrib.lite.constants.QUANTIZED_UINT8 . 所以你有输入和输出的量化参数,在进入模型的过程中,你需要把你的浮点输入转换成uint8,在输出的时候把uint8输出转换成浮点输出。

    • 在输入时,执行转换: uint8_array = (float_array / std_dev) + mean
    • 在输出时,执行转换: float_array = (uint8_array.astype(np.float32) - mean) * std_dev
    • astype(float32)在python中,这是获得正确计算所必需的
    • scale 而不是 std_dev

    quantization_stats = (mean, std_dev) ,的 get_output_details 会回来的 量化:(刻度,零点) ,不仅形式不同(比例与标准偏差),而且顺序也不同!

    现在为了理解这些量化参数的输入和输出值,让我们用上面的公式来推导实际值的范围( )你的输入和输出。利用上述公式,我们得到:

    • 输入范围: min = 0, max=1 (是你通过提供 quantized_input_stats = {input_node_names[0]: (0.0, 255.0)} # (mean, stddev) )
    • 输出范围: min = -100.39, max=99.6
        2
  •  5
  •   Aleksandr Kondratyev    7 年前

    1) 看到了吗 documantation conventional 采用量化方法。

    2) 如果您的模型已经使用规范化的[-1.0,1.0]输入进行训练,则应该设置 converter.quantized_input_stats = {input_node_names[0]: (128, 127)} (0.003921568859368563, 0) mean 从0到255的整数值,映射到浮点0.0f。 std_dev 为255/(float_max-float_min)。这将解决一个可能的问题

    3) Uint8神经网络推理速度大约是float32推理速度的2倍(基于设备)

    推荐文章