def pack(self, iweight, izeros, scales, g_idx=None):
        """Pack int8 weight and zeros to int4 and int8 respectively.

        iweight, izeros and scales must have out_features as the first dimension
        iweight, izeros must be uint8 tensors with each holding 4bit values
        """
        # pylint: disable=W0201
        # shapes for packing
        n, k = iweight.shape
        block_size = self.group_size
        blob_size = block_size // 2
        k_blocks = (k + block_size - 1) // block_size

        padded_k = k_blocks * block_size
        pad_len = padded_k - k
        if pad_len > 0:
            iweight = torch.nn.functional.pad(iweight, (0, pad_len), value=0)

        # pack the weight
        packed_weight = (iweight[:, 0::2] & 0xF) | ((iweight[:, 1::2] & 0xF) << 4)
        self.qweight = packed_weight.reshape(n, k_blocks, blob_size).contiguous()

        # pad to make the K dimension even
        izeros = torch.nn.functional.pad(izeros, (0, izeros.shape[-1] & 1), value=0)
        # pack the zeros
        packed_zeros = (izeros[:, 0::2] & 0xF) | ((izeros[:, 1::2] & 0xF) << 4)
        self.qzeros = packed_zeros.flatten().contiguous()

        self.scales = scales.flatten().contiguous()

        self.g_idx = g_idx
Pack int8 weight and zeros to int4 and int8 respectively.

        iweight, izeros and scales must have out_features as the first dimension
        iweight, izeros must be uint8 tensors with each holding 4bit values
        
olive/common/hf/quant.py