image.png

    1. // 对卷积进行量化
    2. int QuantizeConvPerChannel(const float* weight, const int size, const float* bias, int8_t* quantizedWeight,
    3. int32_t* quantizedBias, float* scale, const std::vector<float>& inputScale,
    4. const std::vector<float>& outputScale, std::string method, bool mergeChannel) {
    5. const int inputChannels = inputScale.size();
    6. const int outputChannels = outputScale.size();
    7. const int icXoc = inputChannels * outputChannels;
    8. DCHECK(size % icXoc == 0) << "Input Data Size Error!";
    9. std::vector<float> quantizedWeightScale(outputChannels);
    10. float inputScalexWeight = 1.0f;
    11. // 默认为true
    12. if (mergeChannel) {
    13. if (method == "MAX_ABS"){
    14. SymmetricQuantizeWeight(weight, size, quantizedWeight, quantizedWeightScale.data(), outputChannels);
    15. }
    16. else if (method == "ADMM") {
    17. QuantizeWeightADMM(weight, size, quantizedWeight, quantizedWeightScale.data(), outputChannels);
    18. }
    19. // 输入scale
    20. inputScalexWeight = inputScale[0];
    21. } else {
    22. const int kernelSize = size / icXoc;
    23. const int ocStride = size / outputChannels;
    24. std::vector<float> weightMultiByInputScale(size);
    25. for (int oc = 0; oc < outputChannels; ++oc) {
    26. for (int ic = 0; ic < inputChannels; ++ic) {
    27. for (int i = 0; i < kernelSize; ++i) {
    28. const int index = oc * ocStride + ic * kernelSize + i;
    29. weightMultiByInputScale[index] = inputScale[ic] * weight[index];
    30. }
    31. }
    32. }
    33. if (method == "MAX_ABS"){
    34. SymmetricQuantizeWeight(weightMultiByInputScale.data(), size, quantizedWeight, quantizedWeightScale.data(), outputChannels);
    35. }
    36. else if (method == "ADMM") {
    37. QuantizeWeightADMM(weightMultiByInputScale.data(), size, quantizedWeight, quantizedWeightScale.data(), outputChannels);
    38. }
    39. }
    40. for (int i = 0; i < outputChannels; ++i) {
    41. if (outputScale[i] == 0) {
    42. scale[i] = 0.0f;
    43. } else {
    44. // 计算最终scale
    45. scale[i] = inputScalexWeight * quantizedWeightScale[i] / outputScale[0];
    46. }
    47. }
    48. // bias量化为int32
    49. if (bias) {
    50. for (int i = 0; i < outputChannels; ++i) {
    51. if (inputScalexWeight == 0 || quantizedWeightScale[i] == 0) {
    52. quantizedBias[i] = 0;
    53. } else {
    54. quantizedBias[i] = static_cast<int32_t>(bias[i] / (inputScalexWeight * quantizedWeightScale[i]));
    55. }
    56. }
    57. }
    58. return 0;
    59. }
    60. // 对深度卷积进行量化,类似之前的
    61. int QuantizeDepthwiseConv(const float* weight, const int size, const float* bias, int8_t* quantizedWeight,
    62. int32_t* quantizedBias, float* scale, const std::vector<float>& inputScale,
    63. const std::vector<float>& outputScale, std::string method) {
    64. const int inputChannels = inputScale.size();
    65. const int outputChannels = outputScale.size();
    66. DCHECK(inputChannels == outputChannels) << "Input Data Size Error!";
    67. std::vector<float> quantizedWeightScale(inputChannels);
    68. if (method == "MAX_ABS") {
    69. SymmetricQuantizeWeight(weight, size, quantizedWeight, quantizedWeightScale.data(), inputChannels);
    70. }
    71. else if (method == "ADMM") {
    72. QuantizeWeightADMM(weight, size, quantizedWeight, quantizedWeightScale.data(), inputChannels);
    73. }
    74. for (int c = 0; c < inputChannels; ++c) {
    75. const int index = c;
    76. if (outputScale[c] == 0) {
    77. scale[index] = 0.0f;
    78. } else {
    79. scale[index] = inputScale[c] * quantizedWeightScale[c] / outputScale[c];
    80. }
    81. }
    82. if (bias) {
    83. for (int i = 0; i < outputChannels; ++i) {
    84. if (inputScale[i] == 0 || quantizedWeightScale[i] == 0) {
    85. quantizedBias[i] = 0;
    86. } else {
    87. quantizedBias[i] = static_cast<int32_t>(bias[i] / (inputScale[i] * quantizedWeightScale[i]));
    88. }
    89. }
    90. }
    91. return 0;
    92. }
    1. // weight format is [co, ci, kh, kw]
    2. int SymmetricQuantizeWeight(const float* weight, const int size, int8_t* quantizedWeight, float* scale,
    3. const int channels) {
    4. DCHECK((size % channels) == 0) << "weight size error!";
    5. const int channelStride = size / channels;
    6. const int quantizedMaxValue = 127;
    7. for (int c = 0; c < channels; ++c) {
    8. const auto weightChannelStart = weight + c * channelStride;
    9. auto quantizedWeightChannelStart = quantizedWeight + c * channelStride;
    10. auto minmaxValue = std::minmax_element(weightChannelStart, weightChannelStart + channelStride);
    11. // 计算数据maxabs
    12. const float dataAbsMax = std::max(std::abs(*minmaxValue.first), std::abs(*minmaxValue.second));
    13. float scaleDataToInt8 = 1.0f;
    14. if (dataAbsMax == 0) {
    15. scale[c] = 0.0f;
    16. } else {
    17. // 统计scale
    18. scale[c] = dataAbsMax / quantizedMaxValue;
    19. scaleDataToInt8 = quantizedMaxValue / dataAbsMax;
    20. }
    21. for (int i = 0; i < channelStride; ++i) {
    22. // 将量化后的参数保存
    23. const int32_t quantizedInt8Value = static_cast<int32_t>(roundf(weightChannelStart[i] * scaleDataToInt8));
    24. quantizedWeightChannelStart[i] =
    25. std::min(quantizedMaxValue, std::max(-quantizedMaxValue, quantizedInt8Value));
    26. }
    27. }
    28. return 0;
    29. }