Caffe restretto 动态量化
主要记录下DYNAMIC_FIXED_POINT模式下对Lenet5的量化过程。
参考 https://blog.csdn.net/xiaoxiaowenqiang/article/details/81713131
①.输入数据为test_data
,在不同batch的数据下,推理iteration
遍,得出网络运行在FLOAT32
下的基本精度。
// Run the reference floating point network on validation set to find baseline
// accuracy.
Net<float>* net_val = new Net<float>(model_, caffe::TEST);
net_val->CopyTrainedLayersFrom(weights_);
float accuracy;
RunForwardBatches(this->iterations_, net_val, &accuracy); //this->iterations在运行时输入
test_score_baseline_ = accuracy;
②.输入数据为train_data
, 网络在不同batch的数据下推理10
遍,得出网络中层类型为Convolution
和InnerProduct
的 top blob
、bottom blob
,weight_param
中数据的最大绝对值,其中权重数据不包括bias
。
void Net<Dtype>::RangeInLayers(vector<string>* layer_name,
vector<Dtype>* max_in, vector<Dtype>* max_out, vector<Dtype>* max_param) {
// Initialize vector elements, if needed.
if(layer_name->size()==0) {
for (int layer_id = 0; layer_id < layers_.size(); ++layer_id) {
if (strcmp(layers_[layer_id]->type(), "Convolution") == 0 ||
strcmp(layers_[layer_id]->type(), "InnerProduct") == 0) {
layer_name->push_back(this->layer_names()[layer_id]);
max_in->push_back(0);
max_out->push_back(0);
max_param->push_back(0);
}
}
}
// Find maximal values.
int index = 0;
Dtype max_val;
for (int layer_id = 0; layer_id < layers_.size(); ++layer_id) {
if (strcmp(layers_[layer_id]->type(), "Convolution") == 0 ||
strcmp(layers_[layer_id]->type(), "InnerProduct") == 0) {
max_val = findMax(bottom_vecs_[layer_id][0]);
max_in->at(index) = std::max(max_in->at(index), max_val);
max_val = findMax(top_vecs_[layer_id][0]);
max_out->at(index) = std::max(max_out->at(index), max_val);
// Consider the weights only, ignore the bias
max_val = findMax(&(*layers_[layer_id]->blobs()[0]));
max_param->at(index) = std::max(max_param->at(index), max_val);
index++;
}
}
}
下面列出第一次推理和推理十次后,统计的各个blob中的数据最大绝对值
推理一次
Tables | max_in | max_out | max_params |
---|---|---|---|
Conv1 | 0.99609375 | 3.49374723 | 0.612441599 |
Conv2 | 3.49374723 | 11.2924623 | 0.257983446 |
ip1 | 9.2909193 | 10.6955347 | 0.0975953862 |
ip2 | 10.6955347 | 26.3756752 | 0.25352037 |
推理十次
Tables | max_in | max_out | max_params |
---|---|---|---|
Conv1 | 0.99609375 | 3.58768392 | 0.612441599 |
Conv2 | 3.5301609 | 11.5329533 | 0.257983446 |
ip1 | 10.1861591 | 12.5225191 | 0.0975953862 |
ip2 | 12.5225191 | 29.3337383 | 0.25352037 |
依据上表数据得出每层的输入特征图,卷积权值,输出特征图的整数位宽和小数位宽。
fl
表示数据小数位宽,il
表示整数位宽,bw(bit_width)
表示定点数据位宽。
定点数据范围:
在量化模式下推理的量化过程如下:
template <typename Dtype>// 模板类型 Dtype
void BaseRistrettoLayer<Dtype>::Trim2FixedPoint_cpu(
Dtype* data, // 数据起始指针
const int cnt, // 数据数量
const int bit_width,// 量化总位宽
const int rounding, // 取整策略
int fl) // 小数位量化位宽
{
// 计算定点数据范围
Dtype max_data = (pow(2, bit_width - 1) - 1) * pow(2, -fl);
Dtype min_data = -pow(2, bit_width - 1) * pow(2, -fl);
for (int index = 0; index < cnt; ++index)// 遍历每一个需要量化的数据
{
// Saturate data 上下溢出处理
data[index] = std::max(std::min(data[index], max_data), min_data);
// Round data
data[index] /= pow(2, -fl);// 放大小数部分 对应的位宽倍数
{
case QuantizationParameter_Rounding_NEAREST:
data[index] = round(data[index]);// 最近偶数取整
break;
case QuantizationParameter_Rounding_STOCHASTIC:
data[index] = floor(data[index] + RandUniform_cpu());// 随机取整
break;
default:
break;
}
data[index] *= pow(2, -fl);// 最后再反量化会小数 缩小对应的位宽倍数
}
}
上溢处理:等于定点最大值
下溢处理:等于定点最小值
rounding_scheme
量化的舍入方案:
a. 最近偶数(NEAREST)
b. 随机舍入(STOCHASTIC)
默认使用方案A
具体计算举例:
Data=3.5301609 ,符号位1位,整数位2位 ,小数位13位
data_temp = 3.5301609 * 2^13 = 28919.0780928
round(data_temp) = 28919
Data_quant = 28919 / 2^13 = 3.5301513671875
网友评论