OAID / Tengine

Tengine is a lite, high performance, modular inference engine for embedded device
Apache License 2.0
4.64k stars 998 forks source link

量化工具有个小bug #1027

Open LeiWang1999 opened 3 years ago

LeiWang1999 commented 3 years ago

情况说明

比如我现在的graph里有一个输出channel只为1的卷积层,在进行int8量化的时候,所有的量化参数都是保存在scale_list里:

// quant_save_graph.cpp
            for (int ch = 0; ch < channel_num; ch++)
            {
                for (int j = 0; j < cstep; j++)
                {
                    if (weight_data[ch * cstep + j] == 0 || weight_scale_list[ch] == 0)
                        i8_weight_data[ch * cstep + j] = 0;
                    else
                    {
                        float int8_data = round(weight_data[ch * cstep + j] / weight_scale_list[ch]);
                        int8_data = int8_data > 127.f ? 127.f : int8_data;
                        int8_data = int8_data < -127.f ? -127.f : int8_data;
                        i8_weight_data[ch * cstep + j] = int8_t(int8_data);
                    }
                }
            }

            weight_tensor->scale_list = weight_scale_list;
            weight_tensor->zp_list = weight_zp_list;
            weight_tensor->data_type = TENGINE_DT_INT8;
            weight_tensor->elem_size = sizeof(int8_t); // int8, signed char
            weight_tensor->data = i8_weight_data;
            weight_tensor->quant_param_num = channel_num;

Tengine现在的设计大部分都是分两块的,当output channel为1的时候,存储在scale里、其他情况都存储在scale_list里。而这里的逻辑是无论channel数为多少都会存在scale_list里,但是在量化完成之后 save_graph 阶段,这个时候量化的scale是存储在scale_list里的而不是scale,这样会导致dump成文件的时候保存了无效的值:

        if (v_qtparams->v_num == 1)
        {
            TM2_QuantParam qtparam;
            qtparam.scale = tensor->scale;
            qtparam.zero_point = tensor->zero_point;
            v_qtparams->offsets[0] = WriteTmObject(start_ptr, cur_pos, &qtparam, sizeof(TM2_QuantParam));
        }
        else if (v_qtparams->v_num > 1)
        {
            for (unsigned int i = 0; i < v_qtparams->v_num; i++)
            {
                TM2_QuantParam qtparam;
                qtparam.zero_point = tensor->zp_list[i];
                qtparam.scale = tensor->scale_list[i];

                v_qtparams->offsets[i] = WriteTmObject(start_ptr, cur_pos, &qtparam, sizeof(TM2_QuantParam));
            }
        }

可以考虑在下次的时候换一波血,把scale这个机制取消了,直接用scale_list就可以。

sunny-yellow commented 3 years ago

Did this bug has already fix?

ShiquanYu commented 3 years ago

@LeiWang1999 @BUG1989 大佬们,这个问题会引起输入为灰度图的模型量化精度奔溃吗