(self, graph: BaseGraph, **kwargs)
| 76 | super().__init__(name='PPQ Passive Parameter Quantization') |
| 77 | |
| 78 | def optimize(self, graph: BaseGraph, **kwargs) -> None: |
| 79 | |
| 80 | def check_state(state: QuantizationStates): |
| 81 | return state in { |
| 82 | QuantizationStates.PASSIVE, |
| 83 | QuantizationStates.ACTIVATED, |
| 84 | QuantizationStates.BAKED, |
| 85 | QuantizationStates.OVERLAPPED |
| 86 | } |
| 87 | |
| 88 | for op in graph.operations.values(): |
| 89 | if not isinstance(op, QuantableOperation): continue |
| 90 | |
| 91 | if op.type in {'Conv', 'ConvTranspose', 'Gemm'} and self.process_bias: |
| 92 | # inputs are [input value, weight, bias(optional)] |
| 93 | if op.num_of_input == 3: |
| 94 | i_cfg, w_cfg, b_cfg = op.config.input_quantization_config |
| 95 | if b_cfg.state not in {QuantizationStates.PASSIVE, QuantizationStates.PASSIVE_INIT}: continue |
| 96 | |
| 97 | # PATCH 2022.07.29 有的时候 bias 是个多维的东西,此时要求前面的维度都是1 |
| 98 | bias = op.inputs[-1].value |
| 99 | if bias is None: raise ValueError(f'Bias Varaible {op.inputs[-1].name} must be a constant. ' |
| 100 | 'Please check it again.') |
| 101 | |
| 102 | assert bias.numel() == bias.shape[-1], ( |
| 103 | f'For op {op.name}, expect Bias shape to be {[bias.numel()]}, ' |
| 104 | f'however {bias.shape} was given') |
| 105 | op.inputs[-1].value = bias.squeeze() |
| 106 | # PATCH 2022.08.02 只有一个数的 bias 经过 squeeze 会变成零维的, 再给它多加一维补回来 |
| 107 | if op.inputs[-1].value.ndim == 0 and op.inputs[-1].value.numel() == 1: |
| 108 | op.inputs[-1].value = op.inputs[-1].value.unsqueeze(0) |
| 109 | |
| 110 | if not check_state(i_cfg.state): |
| 111 | raise PermissionError(f'Can not quantize bias of layer {op.name}, ' |
| 112 | 'cause input has not been correctly quantized.') |
| 113 | |
| 114 | b_cfg.scale = w_cfg.scale * i_cfg.scale |
| 115 | b_cfg.state = QuantizationStates.PASSIVE |
| 116 | b_cfg.offset = torch.zeros_like(b_cfg.scale) |
| 117 | assert not b_cfg.policy.has_property(QuantizationProperty.ASYMMETRICAL), ( |
| 118 | 'Passive parameter does not support ASYMMETRICAL quantization') |
| 119 | |
| 120 | if op.type in {'Clip'} and self.process_clip: |
| 121 | # inputs are [input value, min[optional], max[optional]] |
| 122 | i_cfg = op.config.input_quantization_config[0] |
| 123 | |
| 124 | if not check_state(i_cfg.state): |
| 125 | raise PermissionError(f'Can not quantize clip value of layer {op.name}, ' |
| 126 | 'cause input has not been correctly quantized.') |
| 127 | |
| 128 | for config in op.config.input_quantization_config[1: ]: |
| 129 | config.master_by = i_cfg |
| 130 | config.visibility = self.clip_visiblity |
| 131 | |
| 132 | if op.type in {'Pad'} and self.process_pad: |
| 133 | # inputs are [input value, pad[shape-related], pad value[optional]] |
| 134 | if op.num_of_input != 3: continue |
| 135 | i_cfg = op.config.input_quantization_config[0] |
nothing calls this directly
no test coverage detected