code: def pack(self, linear, scales, zeros, g_idx=None):
      g_idx = (
          g_idx.clone()
          if g_idx is not None
          else torch.tensor(
              [i // self.groupsize for i in range(self.infeatures)],
              dtype=torch.int32,
          )
      )
  
      scales = scales.t().contiguous()
      zeros = zeros.t().contiguous()
      scale_zeros = zeros * scales
      half_scales = scales.clone().half()
      # print("scale shape ", scales.shape, scale_zeros.shape, linear.weight.shape)
      self.scales = scales.clone().half()
      if linear.bias is not None:
          self.bias = linear.bias.clone().half()
  
      wn = 8
      pbits = 32
      ptype = torch.int32
      unsign_type = np.uint32
      sign_type = np.int32
  
      intweight = []
      for idx in range(self.infeatures):
          intweight.append(
              torch.round(
                  (linear.weight.data[:, idx] + scale_zeros[g_idx[idx]])
                  / half_scales[g_idx[idx]]
              ).to(ptype)[:, None]
          )
      intweight = torch.cat(intweight, dim=1)
      intweight = intweight.t().contiguous()
      intweight = intweight.numpy().astype(unsign_type)
      qweight = np.zeros(
          (intweight.shape[0] // pbits * self.bits, intweight.shape[1]),
          dtype=unsign_type,
      )
  
      i = 0
      row = 0
  
      while row < qweight.shape[0]:
          if self.bits in [2, 4, 8]:
              for j in range(i, i + (pbits // self.bits)):
                  qweight[row] |= intweight[j] << (self.bits * (j - i))
              i += pbits // self.bits
              row += 1
          else:
              raise NotImplementedError(
                  "Only 2,4,8 bits are supported."
              )
      qweight = qweight.astype(sign_type)
      qweight1 = torch.from_numpy(qweight)
      qweight1 = qweight1.contiguous()  # .to("cuda")
      self.qweight.data.copy_(qweight1)
  
      qzeros = np.zeros(
          (zeros.shape[0], zeros.shape[1] // pbits * self.bits),
          dtype=unsign_type,
      )
      zeros -= 1
      zeros = zeros.numpy().astype(unsign_type)
      i = 0
      col = 0
      while col < qzeros.shape[1]:
          if self.bits in [2, 4, 8]:
              for j in range(i, i + (pbits // self.bits)):
                  qzeros[:, col] |= zeros[:, j] << (self.bits * (j - i))
              i += pbits // self.bits
              col += 1
          else:
              raise NotImplementedError(
                  "Only 2,4,8 bits are supported."
              )
      qzeros = qzeros.astype(sign_type)
      qzeros = torch.from_numpy(qzeros)
      qzeros = qzeros
      self.qzeros.data.copy_(qzeros)
  
      if torch.equal(self.g_idx.to(g_idx.device), g_idx):
          self.g_idx = None
      else:
          self.g_idx = g_idx
  
imports: import math
  import warnings
  from typing import List, Union
  import numpy
  import torch
  import torch.distributed
  import torch.nn
  from torch.distributed import ProcessGroup
  from colossalai.lazy import LazyInitContext
  from colossalai.shardformer.layer import ParallelModule
  from .gptq_op import CaiGPTQLinearOp
label_desc: Use image node_id 2 for calling the CaiQuantLinear obj's underlying member method code with example usage: obj.pack(linear, scales, zeros, g_idx) without return types