首页 > 试题广场 >

对称INT8量化方案

[编程题]对称INT8量化方案
  • 热度指数:734 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
在嵌入式设备上运行神经网络推理时,由于硬件资源有限,通常需要将浮点参数压缩为低比特整数表示,以减少存储开销和加速计算。

本题要求你实现一种对称INT8量化方案,分别对激活矩阵 A 和参数矩阵 B 进行量化,然后在整数域完成矩阵乘法,最后还原为浮点结果并输出。
 具体规则如下: 
1. 原始矩阵 激活矩阵 A 的维度为 M*K,其中每一行代表一个样本向量。参数矩阵 B 的维度为 K*N,其中每一列代表一个输出通道。 
2. 量化过程 
(1) 对激活矩阵 A 按行量化(per-sample) 对第 i 行,先计算缩放因子: s_A^{(i)} = \frac{\max_{k \in [1,K]} |A_{i,k}|}{127} 再对每个元素量化: Q_A^{(i,k)} = clip(round(A_{i,k} / s_A^{(i)}), -127, 127) 
(2) 对参数矩阵 B 按列量化(per-channel) 对第 j 列,先计算缩放因子: s_B^{(j)} = \frac{\max_{k \in [1,K]} |B_{k,j}|}{127} 再对每个元素量化: Q_B^{(k,j)} = clip(round(B_{k,j} / s_B^{(j)}), -127, 127) 
注意: 
round 采用 Python round() 的逻辑,即银行家舍入(四舍六入五取偶)。
非 0.5 的情况遵循常规四舍五入;恰好 0.5 时舍入到最接近的偶数。 - clip(x, -127, 127) 将 x 限制在 [-127, 127] 范围内。 
3. 量化矩阵乘法 先在整数域计算乘积(结果为INT32): Y_int32^{(i,j)} = sum_{k=1}^{K} Q_A^{(i,k)} * Q_B^{(k,j)} 然后乘以对应的缩放因子还原为浮点数: Y_fp32^{(i,j)} = Y_int32^{(i,j)} * s_A^{(i)} * s_B^{(j)}

输入描述:
从标准输入读取,依次给出矩阵 A 和矩阵 B。

对于每个矩阵,第一行为两个整数表示行数和列数,随后若干行为矩阵元素(浮点数),同一行内元素以空格分隔。


输出描述:
输出还原后的浮点结果矩阵,每个元素四舍五入保留两位小数(建议使用 Python 的 format(num, '.2f') 处理)。同一行内元素以单个空格分隔,行首行尾不要有多余空格。
示例1

输入

1 3
2.0 -1.0 3.0
3 1
1.0
-2.0
0.5

输出

5.52

说明

激活矩阵 A 为 1*3 矩阵 [2.0, -1.0, 3.0],参数矩阵 B 为 3*1 矩阵 [[1.0], [-2.0], [0.5]]。

对 A 按行量化:该行绝对值最大为 3.0,缩放因子 s_A = 3.0/127。量化后 Q_A = [round(84.67), round(-42.33), round(127.0)] = [85, -42, 127]。

对 B 按列量化:该列绝对值最大为 2.0,缩放因子 s_B = 2.0/127。量化后 Q_B = [round(63.5), round(-127.0), round(31.75)] = [64, -127, 32]。注意 round(63.5) = 64(银行家舍入,取偶数)。

整数域乘法:Y_int32 = 85*64 + (-42)*(-127) + 127*32 = 5440 + 5334 + 4064 = 14838。

还原:Y_fp32 = 14838 * (3.0/127) * (2.0/127) = 5.52(四舍五入到两位小数)。
示例2

输入

3 2
10.0 -5.0
0.0 8.0
-3.0 -3.0
2 2
4.0 -6.0
2.0 7.0

输出

29.84 -95.35
16.13 56.00
-18.05 -2.98

说明

A 有3个样本向量,B 有2个输出通道。对 A 逐行、对 B 逐列分别计算缩放因子和量化值,在整数域完成矩阵乘法后,乘以对应的行缩放因子和列缩放因子还原为浮点数。

备注:
本题由牛友@Charles 整理上传
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <unordered_set>
#include <cmath>
using namespace std;
int M,K,N;
int banker_round(double x)
{
    int sign = x<0?-1:1;
    int y =abs(x)*10;
    double res= abs(x*10.0)-y;
    int z=y%10;
    y/=10;
    if(z<5){
        return sign*y;
    }else if(z>5){
        return sign*(y+1);
    }else{
        if(res>0){
            return sign*(y+1);
        }else{
            if(y%2==1){
                return sign*(y+1);
            }
            else{
                
                return sign*y;
            }
        }
    }

}
void matrix_mul(vector<vector<int>>& a,vector<vector<int>>& b,vector<vector<int>>& c)
{
    for(int i=0;i<M;i++)
    {
        for(int j=0;j<N;j++)
        {
            int sum=0;
            for(int k=0;k<K;k++)
            {
                sum+=a[i][k]*b[k][j];
            }
            c[i][j]=sum;
        }
    }
}
int main() {
    
    cin>>M>>K;
    vector<vector<double>> a(M,vector<double>(K));
    vector<double> sa(M);
    for(int i=0;i<M;i++)
    {
        double mx=-1e9;
        for(int j=0;j<K;j++)
        {
            cin>>a[i][j];
            mx=max(mx,abs(a[i][j]));
        }
        sa[i]=mx/127.0;
    }
    cin>>K>>N;
    vector<double> sb(N);
    vector<vector<double>> b(K,vector<double>(N));
     for(int i=0;i<K;i++)
    {
        for(int j=0;j<N;j++)
        {
            cin>>b[i][j];
        }
    }
     for(int j=0;j<N;j++)
    {
        double mx=-1e9;
        for(int i=0;i<K;i++)
        {
            mx=max(mx,abs(b[i][j]));
        }
        sb[j]=mx/127.0;
    }
    vector<vector<int>> q_a(M,vector<int>(K));
    vector<vector<int>> q_b(K,vector<int>(N));
    vector<vector<int>> q_c(M,vector<int>(N));
    for(int i=0;i<M;i++)
    {
        for(int j=0;j<K;j++)
        {
            q_a[i][j]=banker_round(a[i][j]/sa[i]);
        }
    }
    
    for(int j=0;j<N;j++)
    {
        for(int i=0;i<K;i++)
            q_b[i][j]=banker_round(b[i][j]/sb[j]);
    }
    
    // for(int i=0;i<M;i++)
    // {
    //     for(int j=0;j<K;j++)
    //     {
    //         cout<<q_a[i][j]<<" ";
    //     }
    //     cout<<endl;
    // }
    // for(int i=0;i<K;i++)
    // {
    //     for(int j=0;j<N;j++)
    //     {
    //         cout<<q_b[i][j]<<" ";
    //     }
    //     cout<<endl;
    // }
    matrix_mul(q_a,q_b,q_c);
    for(int i=0;i<M;i++)
    {
        for(int j=0;j<N;j++)
        {
            double val = (double)q_c[i][j]*sa[i]*sb[j];
            if(abs(val)<=0.004)val=0.00;
            printf("%.2f ",val);
        }
        cout<<endl;
    }


    return 0;
}
// 64 位输出请用 printf("%lld")


发表于 2026-04-17 21:23:30 回复(0)