| 58 | } |
| 59 | |
| 60 | HQQQuantizer::QuantizationResult HQQQuantizer::quantize( |
| 61 | const std::vector<float>& weights) { |
| 62 | |
| 63 | QuantizationResult result; |
| 64 | result.config = mConfig; |
| 65 | |
| 66 | int total_elements = weights.size(); |
| 67 | result.elementSize = total_elements; |
| 68 | |
| 69 | // 计算分组数量 |
| 70 | int num_groups = (total_elements + mConfig.group_size - 1) / mConfig.group_size; |
| 71 | std::shared_ptr<MNN::Tensor> wrap(Tensor::create<float>({num_groups, mConfig.group_size}, (void*)weights.data())); |
| 72 | auto ctx = Global<modelConfig>::Get()->compressInfo; |
| 73 | ctx->startOptimize(); |
| 74 | auto W = Variable::create(Express::Expr::create(wrap.get(), false)); |
| 75 | // TODO: Optimize Express Interface to avoid extra operation |
| 76 | if (ctx->accelerateType != MNN_FORWARD_CPU) { |
| 77 | // Turn VARP to GPU |
| 78 | W = W + _Scalar<float>(0.0f); |
| 79 | W.fix(VARP::CONSTANT); |
| 80 | } |
| 81 | auto minW = _ReduceMin(W, {1}, true); |
| 82 | auto maxW = _ReduceMax(W, {1}, true); |
| 83 | int qmin = 0; |
| 84 | int qmax = (1 << (mConfig.bits)) - 1; |
| 85 | auto threadHold = _Scalar<float>(1.0f / (float)(qmax - qmin)); |
| 86 | auto scale = _Relu6((maxW-minW)*threadHold, 0.0000001f, std::numeric_limits<float>::max()); |
| 87 | auto scaleRev = _Scalar<float>(1.0f) / scale; |
| 88 | auto zero = scaleRev * _Negative(minW); |
| 89 | Variable::compute({scaleRev, zero}); |
| 90 | scaleRev.fix(VARP::CONSTANT); |
| 91 | zero.fix(VARP::CONSTANT); |
| 92 | if (mConfig.optimize) { |
| 93 | optimize(scaleRev, zero, W); |
| 94 | } |
| 95 | // Turn uint -> int, sub 1<<(bit-1) |
| 96 | scale = _Reciprocal(scaleRev); |
| 97 | minW = _Negative(zero * scale); |
| 98 | qmin = -(1 << (mConfig.bits-1)); |
| 99 | qmax = (1 << (mConfig.bits-1)) - 1; |
| 100 | auto qw = (W - minW) * scaleRev + _Scalar<float>((float)qmin); |
| 101 | qw = _Relu6(_Round(qw), qmin, qmax); |
| 102 | qw = _Cast<int8_t>(qw); |
| 103 | result.SZ = _Concat({minW, scale}, -1); |
| 104 | result.QW = qw; |
| 105 | Variable::compute({result.SZ, result.QW}); |
| 106 | result.SZ.fix(VARP::CONSTANT); |
| 107 | result.QW.fix(VARP::CONSTANT); |
| 108 | ctx->endOptimize(); |
| 109 | |
| 110 | return result; |
| 111 | } |
| 112 | |
| 113 | void HQQQuantizer::optimize(MNN::Express::VARP& S, MNN::Express::VARP& Z, VARP WF) { |
| 114 | int qmin = 0; |
no test coverage detected