(ctx, tensor: torch.Tensor, scales: torch.Tensor,
offsets: torch.Tensor, channel_axis: int,
quant_min: int, quant_max: int,
rounding: RoundingPolicy)
| 65 | """ |
| 66 | @ staticmethod |
| 67 | def forward(ctx, tensor: torch.Tensor, scales: torch.Tensor, |
| 68 | offsets: torch.Tensor, channel_axis: int, |
| 69 | quant_min: int, quant_max: int, |
| 70 | rounding: RoundingPolicy) -> torch.Tensor: |
| 71 | scales, offsets = scales.to(tensor.device), offsets.to(tensor.device) |
| 72 | |
| 73 | if not PPQ_CONFIG.USING_CUDA_KERNEL or not tensor.is_cuda: |
| 74 | # generate a shape that likes [1, 1, -1, 1], the only -1 is at channel axe. |
| 75 | shape = [1 if axis != channel_axis else -1 for axis in range(tensor.ndim)] |
| 76 | scale, offset = scales.view(shape), offsets.view(shape) |
| 77 | |
| 78 | tensor = ppq_tensor_round((tensor / scale), rounding) + offset |
| 79 | tensor = torch.clamp(tensor, quant_min, quant_max) |
| 80 | tensor = (tensor - offset) * scale |
| 81 | return tensor |
| 82 | else: |
| 83 | from ppq.core import CUDA |
| 84 | quantized = CUDA.LinearQuantize_C( |
| 85 | tensor=tensor, |
| 86 | scales=scales, |
| 87 | offsets=offsets, |
| 88 | channel_axis=channel_axis, |
| 89 | minimum=quant_min, |
| 90 | maximum=quant_max, |
| 91 | rounding=rounding.value) |
| 92 | return quantized |
| 93 | |
| 94 | @ staticmethod |
| 95 | def backward(ctx, dy: torch.Tensor): |
nothing calls this directly
no test coverage detected