code: def convert_q4(
      src_name, dst_name, model, fout, n_head, permute=False
  ):
      qzeros = model[f"{src_name}.qzeros"].numpy()
      zeros = qzeros_to_zeros(qzeros).T
      scales = model[f"{src_name}.scales"].numpy().T
      g_idx = model[f"{src_name}.g_idx"].numpy()
      qweight = model[f"{src_name}.qweight"].numpy().T  # transpose
  
      # Q4_1 does not support bias; good thing the bias is always all zeros.
      # Act-order is not supported.
      invalidInputError(
          np.all(g_idx[:-1] <= g_idx[1:]),
          "Act-order is not supported, please use a no act-order model.",
      )
      ftype = 3  # Q4_1
  
      # Each int32 item is actually 8 int4 items packed together, and it's transposed.
      shape = (qweight.shape[0], qweight.shape[1] * 8)
  
      print(
          "Processing Q4 variable: " + src_name + " with shape: ", shape
      )
  
      # The output format has the int4 weights in groups of 32 rather than 8.
      # It looks like this:
      # For each row:
      #   For each group of 32 columns:
      #     - addend (float32, 4 bytes)
      #     - scale (float32, 4 bytes)
      #     - weights (int4 * 32, 16 bytes)
      # Note that in the input, the scales and addends are shared between all
      # the columns in a row, so we end up wasting quite a bit of memory with
      # repeated scales and addends.
  
      addends = -zeros * scales  # flip sign
  
      # Since the output format is mixed between integers and floats, we have
      # to hackily view the floats as int32s just so numpy will let us
      # concatenate them.
      addends_view = np.asarray(addends, dtype=np.float16).view(
          dtype=np.int16
      )
      scales_view = np.asarray(scales, dtype=np.float16).view(
          dtype=np.int16
      )
  
      # Split into groups of 8 columns (i.e. 64 columns of quantized data):
      # TODO: Only support act-order=false
      expanded = expandToInt4(
          qweight.reshape([qweight.shape[0], qweight.shape[1] // 8, 8])
      )
      grouped = to_ggml_int16(expanded)
  
      # Repeat addends and scales:
      if addends_view.shape[1] == grouped.shape[1]:
          addends_rep = np.atleast_3d(addends_view)
          scales_rep = np.atleast_3d(scales_view)
      else:
          addends_rep = np.atleast_3d(addends_view).repeat(
              grouped.shape[1] // addends_view.shape[1], axis=1
          )
          scales_rep = np.atleast_3d(scales_view).repeat(
              grouped.shape[1] // scales_view.shape[1], axis=1
          )
  
      blob = np.concatenate(
          [scales_rep, addends_rep, grouped], axis=2, casting="no"
      )
  
      if permute:
          # Permute some rows to undo the permutation done by convert_llama_weights_to_hf.py.
          # This can be done after the above conversion because it doesn't affect column order/layout.
          blob = (
              blob.reshape(
                  n_head, 2, shape[0] // n_head // 2, *blob.shape[1:]
              )
              .swapaxes(1, 2)
              .reshape(blob.shape)
          )
  
      # header
      write_header(fout, shape, dst_name, ftype)  # ftype = Q4_1
  
      # data
      blob.tofile(fout)
  
file_path: BigDL/python/llm/src/bigdl/llm/gptq/convert/convert_gptq_to_ggml.py
imports: import os
  import re
  import sys
  import json
  import warnings
  import struct
  import numpy
  import torch
  from sentencepiece import SentencePieceProcessor
  from pathlib import Path
  from bigdl.llm.utils.common.log4Error import invalidInputError
label_desc: Use image node_id 6 for calling a global function with example usage: convert_q4(src_name, dst_name, model, fout, n_head, permute) without return types