def test_fc(): filt = FcFilterDim(3, 3, 3, 1) params = FcParameters("test", filt=filt) weights_q = QType(16, 2, True) in_q = QType(16, 2, True) acc_q = QType(16, 4, True) calc_q = QType(16, 4, True) qrec = FilterQuantizationRecord(in_qs=[in_q], out_qs=[in_q], calc_q=calc_q, acc_q=acc_q, biases_q=None, weights_q=weights_q) weights = weights_q.quantize(np.full([3, 1, 3, 3], 1.0)) input_ = in_q.quantize(np.arange(9)).reshape([1, 3, 3]) in_dims = Dim.named(c=1, h=3, w=3).impose_order(['c', 'h', 'w']) out_dims = params.get_output_size([in_dims]) output_ = linear(params, in_dims, out_dims[0], input_, weights, None, qrec=qrec) output_ = in_q.dequantize(output_) assert np.array_equal(output_, [[[36]], [[36]], [[36]]])
def test_conf2d_q2(caplog): caplog.set_level(logging.INFO) weights_q = QType(16, 1, True) weights = weights_q.quantize(np.full([1, 1, 2, 2], 1.0)) filt = Conv2DFilterDim(2, 2, 1, 1) stride = StrideDim(1) pad = PadDim.valid() dilation = DilationDim(1) params = Conv2DParameters("test", filt=filt, stride=stride, padding=pad, dilation=dilation, in_dims_hint=[['c', 'h', 'w']], out_dims_hint=[['c', 'h', 'w']]) in_q = QType(16, 0, True) calc_q = QType(weights_q.bits + in_q.bits, weights_q.q + in_q.q, True) qrec = FilterQuantizationRecord(in_qs=[in_q], out_qs=[in_q], weights_q=weights_q, acc_q=calc_q, calc_q=calc_q) input_ = in_q.quantize(np.full([1, 2, 2], 1.0)) in_dims = Dim.named(c=1, h=2, w=2).impose_order(['c', 'h', 'w']) out_dims = params.get_output_size([in_dims]) output_ = conv2d(params, in_dims, out_dims[0], input_, weights, None, qrec=qrec) output_ = in_q.dequantize(output_) assert np.array_equal(output_, [[[4.]]])
def test_conf2d_depth_q(): calc_q = QType(32, 9, True) biases_q = acc_q = out_q = QType(16, 4, True) weights_q = QType(16, 4, True) in_q = QType(16, 5, True) # TF Lite depthwise convolution biases = np.full([2], 0.5) qbiases = biases_q.quantize(biases) weights = np.full([3, 3], 0.5) weights = np.repeat(weights, 2).reshape([1, 3, 3, 2]) qweights = weights_q.quantize(weights) filt = Conv2DFilterDim(3, 3, 2, 1).impose_order(["in_c", "h", "w", "out_c"]) stride = StrideDim(1) pad = PadDim(0) dilation = DilationDim(1) params = Conv2DParameters("test", filt=filt, stride=stride, padding=pad, dilation=dilation, groups=1, multiplier=2, tf_depthwise=True, in_dims_hint=[['c', 'h', 'w']], out_dims_hint=[['c', 'h', 'w']]) qrec = FilterQuantizationRecord(in_qs=[in_q], out_qs=[out_q], weights_q=weights_q, biases_q=biases_q, acc_q=acc_q, calc_q=calc_q) input_ = np.full([1, 4, 4], 2) qinput_ = in_q.quantize(input_) in_dims = Dim.named(c=1, h=4, w=4).impose_order(['c', 'h', 'w']) out_dims = params.get_output_size([in_dims]) output_ = conv2d(params, in_dims, out_dims[0], input_, weights, biases) qoutput_ = conv2d(params, in_dims, out_dims[0], qinput_, qweights, qbiases, qrec=qrec) dqoutput_ = out_q.dequantize(qoutput_) assert np.array_equal(output_, dqoutput_)
def test_activation(): in_q = QType(16, 13, True) input_ = in_q.quantize(np.array([-1.2, 0.5, 0.5, -0.6])).reshape([4, 1, 1]) in_dims = Dim.named(c=4, h=1, w=1).impose_order(['c', 'h', 'w']) params = ActivationParameters("test") qrec = QuantizationRecord([in_q], [in_q]) out_dims = params.get_output_size([in_dims]) output_ = activation(params, in_dims, out_dims[0], input_, qrec=qrec) output_ = in_q.dequantize(output_) assert np.array_equal(output_, [[[0]], [[0.5]], [[0.5]], [[0]]])
def test_concat_q(): in_q = QType(16, 1, True) inputs = [ in_q.quantize(np.full([1, 2, 2], 1.0)), in_q.quantize(np.full([2, 2, 2], 2.0)) ] in_dims = [ Dim.named(c=1, h=2, w=2).impose_order(['c', 'h', 'w']), Dim.named(c=1, h=2, w=2).impose_order(['c', 'h', 'w']) ] params = ConcatParameters("test", axis=0) out_dims = params.get_output_size(in_dims) output_ = concat(params, in_dims, out_dims[0], inputs) assert np.array_equal(output_, np.concatenate(inputs, 0))
def test_max_pool_q(): filt = PoolFilterDim(2, 2) stride = StrideDim(1) pad = PadDim(0) params = PoolingParameters("test", filt=filt, stride=stride, padding=pad, pool_type="max") in_q = QType(16, 0, True) qrec = QuantizationRecord([in_q], [in_q]) input_ = in_q.quantize(np.arange(9)).reshape([1, 3, 3]) in_dims = Dim.named(c=1, h=3, w=3).impose_order(['c', 'h', 'w']) out_dims = params.get_output_size([in_dims]) output_ = max_pool(params, in_dims, out_dims[0], input_) output_ = in_q.dequantize(output_) assert np.array_equal(output_, [[[4, 5], [7, 8]]])
def new_load_filter_parameters(cls, G, params, input_tensor, weights_node, bias_node, output_tensor, opts, dw_to_pw=False): weights_node.meta['filter_params'] = True bias_node.meta['filter_params'] = True # if quantizaton is not loaded then the constants will already be dequantized if dw_to_pw: # Conv has been converted from depthwise to pointwise so reorder the weights tensor weights_node.value = np.transpose(weights_node.value, cls.TF_LITE_DW_FILTER_TRANSPOSE) weights_node.dims = Dim.unnamed(weights_node.value.shape) if not opts.get('load_quantization'): return wqtype = weights_node.qtype if wqtype is None: LOG.warning('quantization is missing on node %s', params.name) return # scale weights as requested. change asymmetric scaling to symmetric if wqtype.is_asymmetric: if opts.get('rescale_perchannel'): wqtype = cls.get_weights_qtype_by_channel(params, weights_node) else: wqtype = cls.get_weights_qtype_by_tensor(weights_node) else: if opts.get('rescale_perchannel'): if len(wqtype.scale) != params.filter.out_c: wqtype = cls.get_weights_qtype_by_channel( params, weights_node) else: if len(wqtype.scale) > 1: wqtype = cls.get_weights_qtype_by_tensor(weights_node) iqtype = input_tensor.qtype # correct input qtype to symmetric tensor scaled if iqtype.is_asymmetric or len(iqtype.scale) > 1: iqtype = QType.from_min_max_sq(min_val=iqtype.min_val, max_val=iqtype.max_val) else: iqtype = deepcopy(iqtype) oqtype = output_tensor.qtype # correct output qtype to symmetric tensor scaled if oqtype.is_asymmetric or len(oqtype.scale) > 1: oqtype = QType.from_min_max_sq(min_val=oqtype.min_val, max_val=oqtype.max_val) else: oqtype = deepcopy(iqtype) dqbias = bias_node.dqvalue bias_scale = (iqtype.scale * wqtype.scale).astype(np.float32) bqtype = QType(dtype=np.int32, scale=bias_scale) # NOTE: In some tensorflow graphs the biases are hugely negative or hugely # positive. I've never seen this without a relun after and the weights on # these channels were 0. Actually they should be pruned. bias_node.value = bqtype.quantize(dqbias) bias_node.qtype = bqtype if dw_to_pw and wqtype.quantized_dimension: wqtype.quantized_dimension = 0 mulbiases_q = MultMulBiasScaleQType.from_filter( iqtype, wqtype, oqtype, params) qrec = MultScalableFilterQuantizationRecord( in_qs=[iqtype, wqtype, bqtype], out_qs=[oqtype], mul_biases_q=mulbiases_q) # now set the quantization records on the node and its constants G.quantization[NodeId(params)] = qrec G.quantization[NodeId(weights_node)] = MultConstantQuantizationRecord( out_qs=[deepcopy(wqtype)]) G.quantization[NodeId(bias_node)] = MultConstantQuantizationRecord( out_qs=[deepcopy(bqtype)])