Project: s41467-025-57183-0 | Function: forward (python)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Post-deployment training forward pass that simulates CIM hardware behavior with bit-slicing and multi-stage quantization. Implements the core algorithm for hardware-aware neural network inference.

**KEY TERMS:** {
  "input_int": "quantized input data",
  "weight_int": "quantized weight data",
  "bit_index": "bit slicing index",
  "out_bit_value": "partial convolution result",
  "out_s": "output scale accumulation"
}

**CONTEXT CODE:**     
    def init_quantizer(self):
        input_quant_config = self.quantization_config['input']
        weight_quant_config = self.quantization_config['weight']
        output_quant_config = self.quantization_config['output'] 
        # init input quantizer
        if self.layer_name in input_quant_config.keys():
            current_in_quant_config = input_quant_config[self.layer_name]
        else:
            current_in_quant_config = input_quant_config['default']
        self.input_quantizer = get_act_quantizer(current_in_quant_config)
        # init weight quantizer
        if self.layer_name in weight_quant_config.keys():
            current_w_quant_config = weight_quant_config[self.layer_name]
        else:
            current_w_quant_config = weight_quant_config['default']
        self.weight_quantizer = get_weight_quantizer(current_w_quant_config)
        # init output quantizer
        if self.layer_name in output_quant_config.keys():
            current_out_quant_config = output_quant_config[self.layer_name]
        else:
            current_out_quant_config = output_quant_config['default']
        self.output_quantizer = get_act_quantizer(current_out_quant_config)
            
    def get_int_weight(self):
        weight_int, scale = self.weight_quantizer.get_int(self.weight)
        return weight_int, scale

    def init_weight_scale(self):
        # init weight scale
        if isinstance(self.weight_quantizer, LSQ_weight_quantizer):
            self.weight_quantizer.init_scale(self.weight)
        
    
    def get_params(self):
        d = {}
        d['weight_int'] = self.get_int_weight()[0].cpu()
        input_s = self.input_quantizer.get_scale()
        weight_s = self.weight_quantizer.get_scale()
        output_s  = self.output_quantizer.get_scale()
        d['soft_total_scale'] = (input_s * weight_s / output_s).detach().cpu()
        d['input_scale'] = input_s
        d['weight_scale'] = weight_s    
        d['output_scale'] = output_s
        d['input_bit'] = self.input_quantizer.bit
        d['weight_bit'] = self.weight_quantizer.bit
        d['output_bit'] = self.output_quantizer.bit
        d['bias'] = self.bias
        return d
        
    def forward(self, input):
        """
        Post-deployment training forward pass with CIM hardware simulation.

        This function implements the core post-deployment training algorithm that simulates
        computing-in-memory hardware behavior through bit-slicing and multi-stage quantization.
        It performs hardware-aware neural network inference as described in the OpenCIMTC paper,
        enabling accurate simulation of CIM system constraints during training and deployment.

        Args:
            input (torch.Tensor): Input tensor for convolution operation

        Returns:
            torch.Tensor: Output tensor after CIM-aware quantized convolution

        Raises:
            NotImplementedError: Function has been masked for testing purposes
        """
        raise NotImplementedError("This function has been masked for testing purposes")

class ConvTranspose2dPDT(nn.ConvTranspose2d):
    def __init__(self, in_channels, out_channels, kernel_size, stride,
                 padding, output_padding, groups, bias, dilation, layer_name, quantization_config ):
        super(ConvTranspose2dPDT, self).__init__(in_channels, out_channels, kernel_size, stride, 
                                        padding = padding, output_padding=output_padding, groups=groups, bias=bias, dilation=dilation)
        assert layer_name is not None 
        assert quantization_config is not None
        self.layer_name = layer_name
        self.quantization_config = quantization_config
        self.init_quantizer()
    
    def init_quantizer(self):
        input_quant_config = self.quantization_config['input']
        weight_quant_config = self.quantization_config['weight']
        output_quant_config = self.quantization_config['output'] 
        # init input quantizer
        if self.layer_name in input_quant_config.keys():
            current_in_quant_config = input_quant_config[self.layer_name]
        else:
            current_in_quant_config = input_quant_config['default']
        self.input_quantizer = get_act_quantizer(current_in_quant_config)
        # init weight quantizer
        if self.layer_name in weight_quant_config.keys():
            current_w_quant_config = weight_quant_config[self.layer_name]
        else:
            current_w_quant_config = weight_quant_config['default']
        self.weight_quantizer = get_weight_quantizer(current_w_quant_config)
        
        # init output quantizer
        if self.layer_name in output_quant_config.keys():
            current_out_quant_config = output_quant_config[self.layer_name]
        else:
            current_out_quant_config = output_quant_config['default']
        self.output_quantizer = get_act_quantizer(current_out_quant_config)
            
    def get_int_weight(self):
        weight_int, scale = self.weight_quantizer.get_int(self.weight)
        return weight_int, scale

    def init_weight_scale(self):
        # init weight scale
        if isinstance(self.weight_quantizer, LSQ_weight_quantizer):
            self.weight_quantizer.init_scale(self.weight)
    
    def get_params(self):
        d = {}
        d['weight_int'] = self.get_int_weight()[0].cpu()
        input_s = self.input_quantizer.get_scale()
        weight_s = self.weight_quantizer.get_scale()
        output_s  = self.output_quantizer.get_scale()
        d['soft_total_scale'] = (input_s * weight_s / output_s).detach().cpu()
        d['input_scale'] = input_s
        d['weight_scale'] = weight_s    
        d['output_scale'] = output_s
        d['input_bit'] = self.input_quantizer.bit
        d['weight_bit'] = self.weight_quantizer.bit
        d['output_bit'] = self.output_quantizer.bit
        d['bias'] = self.bias
        return d
        
    def forward(self, input):
        # quantize inputs
        input_int, input_s = self.input_quantizer(input)
        # quantize weights
        weight_int, weight_s = self.weight_quantizer(self.weight)
        # calculat  output
        out_int = 0
        out_s = 0
        out_value_list = []
        input_bit = self.input_quantizer.bit
        bit_length = input_bit - 1
        for bit_index in range(bit_length):
            input_bit_value = train_multi_bit(input_int, 1, bit_index, bit_length)
            out_bit_value = self._conv_forward(input_bit_value * input_s, weight_int * weight_s)
            out_bit_int, out_bit_s = self.output_quantizer(out_bit_value)
            # 
            out_value_list.append(out_bit_value)
            # sum out_s, out_int
            out_int += out_bit_int * 2**(bit_index)
            out_s += out_bit_s


Complete the function implementation replacing "raise NotImplementedError".