code: def lsq_plus_clamp_round(
      target: torch.Tensor, target_space: QuantizationTargetSpace
  ):
      qmax: int = target_space.qmax
      qmin: int = target_space.qmin
      if target_space._scaler is not None:
          scale = target_space._scaler.expand(target_space.scale, target_space.shape, keepdim=True)  # type: ignore
          zero_point = target_space._scaler.expand(target_space.zero_point, target_space.shape, keepdim=True)  # type: ignore
      else:
          scale = target_space.scale
          zero_point = target_space.zero_point
  
      class LSQPlusClampRound(torch.autograd.Function):
          @staticmethod
          def forward(
              ctx: Any,
              target: torch.Tensor,
              scale: torch.Tensor,
              zero_point: torch.Tensor,
          ):
              ctx.save_for_backward(target, scale, zero_point)
              new_target = torch.clamp(
                  target / scale + zero_point, qmin, qmax
              )
              dequantized_target = (
                  torch.round(new_target) - zero_point
              ) * scale
  
              return dequantized_target
  
          @staticmethod
          def backward(ctx: Any, grad_output: Any) -> Any:
              target, scale, zero_point = ctx.saved_tensors
              grad_scale_factor = (
                  1.0 / ((qmax * target.numel()) ** 0.5)
                  if (qmax * target.numel()) ** 0.5 != 0
                  else 1.0
              )
              #
              q_target = target / scale
              # compute index
              ind_neg = ((q_target + zero_point) < qmin).float()
              ind_pos = ((q_target + zero_point) > qmax).float()
              ind_mid = 1.0 - ind_neg.float() - ind_pos.float()
              # scale gradient
              grad_scale = (
                  (
                      ind_neg * (qmin - zero_point)
                      + ind_pos * (qmax - zero_point)
                      + ind_mid
                      * (
                          -q_target
                          - zero_point
                          + torch.round(q_target + zero_point)
                      )
                  )
                  * grad_output
                  * grad_scale_factor
              )
              # zero_point gradient
              grad_zp = (
                  ind_neg * -scale + ind_pos * -scale + ind_mid * 0.0
              ) * grad_output
              # target gradient
              grad_target = grad_output * ind_mid
  
              if target_space._scaler is None:
                  grad_scale = grad_scale.sum().expand(scale.size())
                  grad_zp = grad_zp.sum().expand(zero_point.size())
  
              return grad_target, grad_scale, grad_zp
  
      return LSQPlusClampRound.apply(target, scale, zero_point)
  
imports: from typing import Any
  import torch
  from .target_space import PruningTargetSpace, QuantizationTargetSpace, TargetSpace, TargetType
label_desc: Use image node_id 3 for calling a global function with example usage: lsq_plus_clamp_round(target, target_space) and returns: LSQPlusClampRound, dequantized_target, grad_target,  grad_scale,  grad_zp