我正在尝试对卷积神经网络使用量化,以减少从 FP32 位数据类型到 Int16 数据类型的内存占用。问题是我得到的结果很差,因为这是我第一次使用这种表示形式,所以我对正确的实现有一些疑问。
首先,我使用以下函数(均匀量化)对输入数据和权重进行量化:
#define FXP 16
int16_t quantize(float a, int fxp){
int32_t maxVal = ((1 << (FXP-1)) - 1);
int32_t value = a * (1 << fxp); //mapping
//rounding
if (a>=0){
value += 0.5f;
}else{
value -= 0.5f;
}
//clipping
if(value > maxVal){
return (int16_t)maxVal;
}else if(value < -maxVal){
return -(int16_t)maxVal;
}else{
return (int16_t)value;
}
}
int16_t value = quantize(test_data[i],10);
在这种情况下,我使用的是 Q5.10 格式(从我掌握的数据来看,它似乎是最适合使用的格式)。一旦所有数字都被转换,网络中的算术(乘法和加法/减法——例如在卷积中使用)以这种方式实现:
for(int k=0; k<output_fea; k++){
int32_t accumulator = 0;
for(int l=minimum; l<maximum; l++){
for(int j=0; j<input_fea; j++){
accumulator += (data[l][j]*weights[k][l][j] + (1<<((FXP_VALUE-1))))>>FXP_VALUE; //both data and weights array are int16_t
}
}
//before going from int32_t to int16_t
if(accumulator>INT16_MAX){
accumulator=INT16_MAX;
}else if(accumulator<INT16_MIN){
accumulator=INT16_MIN;
}
result[i][k] = (int16_t)ReLU(accumulator); //result is int16_t
}
}
我做的对吗?我可以采取任何措施来改善结果并减少近似值吗?
我正在考虑为每一层使用不同的比例因子,但我不明白如何在乘法和加法/减法中考虑到这一点。例如,如果我在第一层中使用 Q2.14 作为权重,使用 Q5.10 作为数据,我必须将乘法的结果重新缩放到一个通用的比例,但是我该如何选择合适的比例以及我应该如何重新缩放该结果
您应该通过舍入和裁剪来检查您的值中引入了多少误差。继续使用浮点值,但只引入四舍五入;然后只介绍剪裁;然后介绍两者。您的结果中引入了多少错误?
此外,关于定点格式:即使它 seems 使用的最佳格式,也许它不是最好的。尝试不同的格式;检查每种格式的结果错误。尝试在不同的计算阶段(即不同的层)使用不同的格式。每个应用程序都有自己的问题,因此您必须凭直觉了解舍入和裁剪(分别)对结果的影响程度。
如果您的结果对舍入误差非常敏感,您可能希望对某些阶段使用
int16
,对其他阶段使用 float32
。