acext User Guide (v1.6.1)
For reference purposes, internal network links in the source code are retained. External users cannot access these links. Contact your PDS account manager if you have any questions.
acext provides high-performance operator implementations for Processor for AI and HPC (PPU) using quantization algorithms. It is distributed as a Python wheel package. The acext source code is available to customers and partners. You can use these operators during PPU adaptation to accelerate your business workloads.
Open-source code repository:
https://code.alibaba-inc.com/ppu_open_source/acext1. How to Use acext
1.1 Use acext with vLLM or SGLang
Starting with PPU_SDK version 1.6, acext is no longer released with PPU_SDK and is instead distributed as a Python wheel package. For frameworks that depend on acext, such as vLLM and SGLang, after you install the acext wheel package (pip install acext), you can use acext in one of the following two ways:
For SGLang ≥ 0.4.10 and vLLM ≥ 0.10.0: The framework loads acext automatically. No extra steps are required.
For SGLang < 0.4.10 or vLLM < 0.10.0: Set four environment variables to locate the dynamic libraries.
### Append shared library load path
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:$(python -c "import sysconfig; print(sysconfig.get_path('purelib'))")/lib"
### Config ACEXT LUT path
export ACEXT_GEMM_CONFIG_DIR="$(python -c "import sysconfig; print(sysconfig.get_path('purelib'))")/include/acext/lut/"
### For vLLM versions earlier than 0.10.0
export ACEXT_OP_PATH="$(python -c "import sysconfig; print(sysconfig.get_path('purelib'))")/lib/libacext_op.so"
### For SGLang versions earlier than 0.4.10
export ACEXT_THOP_LIB_PATH="$(python -c "import sysconfig; print(sysconfig.get_path('purelib'))")/lib/th_op/libth_op.so"Note: For backward compatibility, current PTG images still include acext dynamic libraries and header files in PPU_SDK. Therefore, using acext with vLLM or SGLang works without issues in current PTG images. However, future releases may switch entirely to a wheel-based installation.
1.2 Supported APIs
acext provides quantization algorithm capabilities through header files and compiled libraries. The header file structure supports fpAintB mixed-precision quantization, w8a8 quantization, and MoE GEMM functionality. To use acext, include the interface header acext.h and link against libacext.so.

1.2.1 fpAintB GEMM
The fpA_intB_gemm.h header file implements mixed-precision quantization where matrix A is floating-point and matrix B is an integer. Three template parameters allow you to specify the exact types for A and B, and the quantization algorithm to use.
template <typename T, typename WeightType, cutlass::WeightOnlyQuantOp QuantOp>
class CutlassFpAIntBGemmRunner : public virtual CutlassFpAIntBGemmRunnerInterface
{
public:
CutlassFpAIntBGemmRunner();
~CutlassFpAIntBGemmRunner();
void gemm(const void* A, const void* B, const void* weight_scales, void* C, int m, int n, int k,
tkc::CutlassGemmConfig gemmConfig, char* workspace_ptr, const size_t workspace_bytes,
cudaStream_t stream) override;
void gemm(const void* A, const void* B, const void* weight_scales, const void* weight_zero_points,
const void* biases, void* C, int m, int n, int k, const int group_size, tkc::CutlassGemmConfig gemmConfig,
char* workspace_ptr, const size_t workspace_bytes, cudaStream_t stream) override;
// Returns desired workspace size in bytes.
size_t getWorkspaceSize(const int m, const int n, const int k) override;
tkc::CutlassGemmConfig getChosenConfig(const void* A,
const void* B,
const void* weight_scales,
const void* weight_zero_points,
const void* biases,
void* C,
int m,
int n,
int k,
const int group_size,
char* workspace_ptr,
const size_t workspace_bytes,
cudaStream_t stream) override;
};
template <typename ActType, WeightOnlyQuantType QType, cutlass::WeightOnlyQuantOp QuantOp>
std::shared_ptr<CutlassFpAIntBGemmRunnerInterface> createFpAIntBGemmRunner();1.2.2 w8a8 GEMM
The int8_gemm.h header file implements quantization where both matrices A and B are integers. The template parameter T specifies the output data type.
template <typename T>
class CutlassInt8GemmRunner : public virtual CutlassInt8GemmRunnerInterface
{
public:
CutlassInt8GemmRunner();
~CutlassInt8GemmRunner();
void gemm(const void* A, const void* B, tk::QuantMode quantOption, const float* alphaCol, const float* alphaRow,
void* C, int m, int n, int k, tkc::CutlassGemmConfig gemmConfig, char* workspacePtr,
const size_t workspaceBytes, cudaStream_t stream) override;
// Returns desired workspace size in bytes.
size_t getWorkspaceSize(const int m, const int n, const int k) override;
std::vector<tkc::CutlassGemmConfig> getConfigs() const override;
tkc::CutlassGemmConfig getChosenConfig(const void* A, const void* B, tk::QuantMode quantOption,
const float* alphaCol, const float* alphaRow, void* C, int m, int n, int k, char* workspacePtr,
const size_t workspaceBytes, cudaStream_t stream);
};1.2.3 MoE GEMM
The moe_kernel.h header file provides the APIs required to call MoE GEMM kernels.
template<typename T, /*The type used for activations/scales/compute*/
typename WeightType, /* The type for the MoE weights */
cutlass::WeightOnlyQuantOp QuantOp,
typename Enable = void>
class CutlassMoeFCRunner: public CutlassMoeFCRunnerInterface {
public:
CutlassMoeFCRunner() = default;
~CutlassMoeFCRunner() override = default;
//for rtp-llm
void runMoe(const void* input_activations_void, const float* gating_output, const float *gating_output_with_bias,
const void* fc1_expert_weights_void, const void* fc1_scales_void, const void* fc1_zeros_void, const void* fc1_expert_biases_void,
ActivationType fc1_activation_type, const void* fc2_expert_weights_void, const void* fc2_scales_void, const void* fc2_zeros_void,
const void* fc2_expert_biases_void, const int num_rows, const int hidden_size, const int inter_size,
const int num_experts, const int k, const int group_size, char* workspace_ptr, void* final_output_void, void* fc2_result_void,
const bool* finished, const int active_rows, void* expert_scales_void,
int* expanded_source_row_to_expanded_dest_row, int* expert_for_source_row, MOEParallelismConfig parallelism_config,
MOEExpertScaleNormalizationMode normalization_mode, cudaStream_t stream) override;
// for vLLM
void fused_moe(const void* input_activations_void, const float* gating_output, const float* gating_output_with_bias,
const void* fc1_expert_weights_void, const void* fc1_scales_void, const void* fc1_zeros_void, const void* fc1_expert_biases_void,
void* a1_scale_void, ActivationType fc1_activation_type, const void* fc2_expert_weights_void, const void* fc2_scales_void,
const void* fc2_zeros_void, const void* fc2_expert_biases_void, void* a2_scale_void, const int num_tokens, const int hidden_size,
const int inter_size, const int num_experts, const int k, const int group_size, char* workspace_ptr, void* final_output_void,
void* fc2_result_void, const bool* finished, const int active_rows, const void* expert_scales_void,
int* expanded_source_row_to_expanded_dest_row, const int* expert_for_source_row, MOEParallelismConfig parallelism_config,
MOEExpertScaleNormalizationMode normalization_mode, cudaStream_t stream) override;acext also provides MoE-related PyTorch operators:
torch.ops.moe_unit_ops.gating_softmax
torch.ops.moe_unit_ops.grouped_gemm_bias
torch.ops.moe_unit_ops.run_moe_fc
For usage examples, see acext/tests/th_moe.py.
1.2.4 DeepGEMM
PyTorch operators:
torch.ops.moe_unit_ops.grouped_gemm_nt_contiguous
torch.ops.moe_unit_ops.grouped_gemm_nt_masked
For usage examples, see acext/tests/th_group_gemm.py.
For the C++ API, see the corresponding Python implementation.
1.3 Supported Quantization Algorithms
Quantization algorithms reduce memory usage and improve performance by compressing model weights (W) and activations (A) before matrix multiplication. Different kernel variants support different precision combinations for W and A. The following is a brief overview of each algorithm and its support status in acext.
All code examples assume a matrix multiplication of A (M×K) and W (K×N) that produces an M×N result.
1.3.1 Int8 Weight-only (W8A16)
Int8 weight-only is the simplest quantization method. It quantizes weights column-wise into int8 values, with one scale factor per column. If the original weights are fp16, this method reduces memory usage by half. Because less data is loaded from memory, performance improves in memory-bound scenarios compared to native fp16 computation.
Example code:
// Prepare data: act, weight, scales, and output
......
// Create FpAIntBGemmRunner with A=half, B=int8, and PER_COLUMN_SCALE_ONLY quantization
auto runner = createFpAIntBGemmRunner<half, WeightOnlyQuantType::Int8b, cutlass::WeightOnlyQuantOp::PER_COLUMN_SCALE_ONLY>();
// Preprocess weights for mixed-precision GEMM
preprocess_weights_for_mixed_gemm(preprocessed_quantized_weight, row_major_quantized_weight, {k, n}, QuantType::INT8_WEIGHT_ONLY);
// Allocate workspace
char* ws_ptr = nullptr;
const int ws_bytes = runner->getWorkspaceSize(m, n, k);
cudaMalloc(&ws_ptr, ws_bytes);
// Choose optimal kernel config
gemmConfig = runner->getChosenConfig(p_act, p_weight, p_scales, nullptr, nullptr,
p_out, m, n, k, k, reinterpret_cast<char*>(ws_ptr),
ws_bytes, stream);
// Run quantized kernel; result stored in out
runner->gemm(p_act, p_weight, p_scales, p_out, m, n, k, gemmConfig, ws_ptr, ws_bytes, stream);1.3.2 Int4 Weight-only (W4A16)
Int4 weight-only uses the same principle as Int8 weight-only but stores weights in a 4-bit format. This further reduces memory usage to one-quarter of the fp16 memory usage and boosts performance, but at the cost of lower accuracy.
Example code:
// Prepare data: act, weight, scales, and output
......
// Create FpAIntBGemmRunner with A=half, B=int4, and PER_COLUMN_SCALE_ONLY quantization
auto runner = createFpAIntBGemmRunner<half, WeightOnlyQuantType::Int4b, cutlass::WeightOnlyQuantOp::PER_COLUMN_SCALE_ONLY>();
// Preprocess weights for mixed-precision GEMM
preprocess_weights_for_mixed_gemm(preprocessed_quantized_weight, row_major_quantized_weight, {k, n}, QuantType::PACKED_INT4_WEIGHT_ONLY);
// Allocate workspace
char* ws_ptr = nullptr;
const int ws_bytes = runner->getWorkspaceSize(m, n, k);
cudaMalloc(&ws_ptr, ws_bytes);
// Choose optimal kernel config
gemmConfig = runner->getChosenConfig(p_act, p_weight, p_scales, nullptr, nullptr,
p_out, m, n, k, k, reinterpret_cast<char*>(ws_ptr),
ws_bytes, stream);
// Run quantized kernel; result stored in out
runner->gemm(p_act, p_weight, p_scales, p_out, m, n, k, gemmConfig, ws_ptr, ws_bytes, stream);1.3.3 Int4 Groupwise (W4A16)
While Int4 weight-only saves memory and speeds up computation, its low precision causes large quantization errors. Groupwise quantization solves this issue by dividing each column into groups (for example, a group size of 64 or 128) and assigning one scale factor per group instead of per column.
In practice (for example, with AWQ or GPTQ), models are fine-tuned on datasets to produce quantized int4 weights. Asymmetric quantization may also introduce zero-point offsets (zeros and bias).
Example code:
// Prepare data: act, weight, scales, and output
......
// Create FpAIntBGemmRunner with A=half, B=int8, and FINEGRAINED_SCALE_ONLY quantization
auto runner = createFpAIntBGemmRunner<half, WeightOnlyQuantType::Int8b, cutlass::WeightOnlyQuantOp::FINEGRAINED_SCALE_ONLY>();
// Preprocess weights for mixed-precision GEMM
preprocess_weights_for_mixed_gemm(preprocessed_quantized_weight, row_major_quantized_weight, {k, n}, QuantType::PACKED_INT4_WEIGHT_ONLY);
// Allocate workspace
char* ws_ptr = nullptr;
const int ws_bytes = runner->getWorkspaceSize(m, n, k);
cudaMalloc(&ws_ptr, ws_bytes);
// Choose optimal kernel config
gemmConfig = runner->getChosenConfig(p_act, p_weight, p_scales, p_zeros, p_bias,
p_out, m, n, k, groupsize, reinterpret_cast<char*>(ws_ptr),
ws_bytes, stream);
// Run quantized kernel; result stored in out
runner->gemm(p_act, p_weight, p_scales, p_zeros, p_bias, p_out, m, n, k, groupsize, gemmConfig, ws_ptr, ws_bytes, stream);1.3.4 SmoothQuant (W8A8)
fpAintB uses mixed-precision quantization where weights are integers, but they are dequantized to float before computation and then passed to the TensorCore. In contrast, W8A8 keeps both weights and activations as integers, which enables full integer TensorCore execution and delivers better compute throughput.
SmoothQuant is the quantization algorithm that uses W8A8 kernels. For more information, see https://github.com/mit-han-lab/smoothquant.
W8A8 can be divided into four variants based on whether matrix A uses PerToken quantization (each row shares a set of quantization parameters) and matrix B uses PerChannel quantization (each column shares a set), as opposed to the default PerTensor method where the entire matrix shares one set of parameters. The four variants are PerTensorPerTensor, PerTensorPerChannel, PerTokenPerTensor, and PerTokenPerChannel.

acext implements all four W8A8 variants. You can use them as follows:
// Choose one of the four W8A8 variants:
QuantMode quant_mode = QuantMode::fromDescription(false, false, false, false); // A_PerTensor_W_PerTensor
QuantMode quant_mode = QuantMode::fromDescription(false, false, false, true); // A_PerTensor_W_PerChannel
QuantMode quant_mode = QuantMode::fromDescription(false, false, true, false); // A_PerToken_W_PerTensor
QuantMode quant_mode = QuantMode::fromDescription(false, false, true, true); // A_PerToken_W_PerChannel
// Prepare data: act, weight, scales, and output
......
// Create W8A8 runner
auto runner = std::make_shared<acext::kernels::cutlass_kernels::CutlassInt8GemmRunner<half>>();
// Allocate workspace
int ws_bytes = runner->getWorkspaceSize(m, n, k);
char* ws_ptr = nullptr;
if (ws_bytes)
cudaMalloc(&ws_ptr, ws_bytes);
// Choose kernel config
const auto gemmConfig = runner->getChosenConfig(p_act, p_weight, quant_mode,
reinterpret_cast<const float*>(p_scales_channels),
reinterpret_cast<const float*>(p_scales_tokens),
p_out, m, n, k, ws_ptr, ws_bytes, stream);
// Execute kernel; result stored in out
runner->gemm(p_act, p_weight, quant_mode,
reinterpret_cast<const float*>(p_scales_channels),
reinterpret_cast<const float*>(p_scales_tokens),
p_out, m, n, k, gemmConfig, ws_ptr, ws_bytes, stream);
1.4 Quantization Kernel Performance
We measured performance across 22 large language models using various N and K dimensions. We ran GEMM operations with different batch sizes (M) and computed the speedup relative to the cuBLAS fp16 baseline.

Performance notes:
FpAintB is a weight-only quantization method. It reduces weight memory bandwidth, which improves performance in memory-bound cases. However, it adds a dequantization step. Therefore, for large batch sizes where the workload becomes compute-bound, the quantized version may underperform the non-quantized version.
W8A8 uses int8 Tensor Cores. With large batch sizes, it fully leverages the higher compute throughput of int8 Tensor Cores.
2. acext Quantization Integration (vLLM)
We integrated acext into vLLM to support multiple quantization algorithms on PPU.
vLLM 0.4.2 source code:
https://code.alibaba-inc.com/ppu_open_source/vllm/tree/v0.4.2/vLLM 0.3.3 source code:
https://code.alibaba-inc.com/ppu_open_source/vllm/tree/v0.3.3/All performance and accuracy results provided below were obtained using vLLM 0.4.2 with large language models.
2.1 Add Int8 Weight-only Support
2.1.1 AutoWOQ
To apply quantization, you must convert the original fp16 or bf16 model weights to the int8 format.
We provide AutoWOQ for this conversion. Its components are shown below:

AutoWOQForCausalLM serves as a unified entry point for all large language models, similar to the Auto classes in Hugging Face. It accepts the model weight path and automatically detects the model type to instantiate the correct WOQForCausalLM subclass. All subclasses inherit from BaseWOQForCausalLM, which implements the core quantization logic, including symmetric quantization using acext.
You can use AutoWOQ as follows:
# Configure quantization: 8-bit or 4-bit
quantize_config = BaseQuantizeConfig(
bits=8, # Quantize model to 8-bit
)
# Load unquantized weights (Hugging Face format). By default, loads onto CPU.
model = AutoWOQForCausalLM.from_pretrained(model_path, quantize_config, trust_remote_code=args.trust_remote_code)
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
# Quantize model. Applies symmetric quantization to linear layers based on model type.
model.quantize()
# Save quantized model and tokenizer to specified location.
quant_path = args.output
model.save_quantized(quant_path)
tokenizer.save_pretrained(quant_path)2.1.2 Enable WOQ Quantization
After you generate WOQ-quantized weights, you can add weight-only quantization support to vLLM. When you use WOQ weights, you must explicitly set `quantization="weightonly"` when you initialize the LLM object.
# Create an LLM.
llm = LLM(model=model_path, quantization="weightonly")vLLM will then automatically create quantized tensor parameters for linear layers and invoke mixed-precision kernels at runtime.
As shown in the following figure, a Transformer block in vLLM contains green linear layers that use weight-only quantization.

These linear layers are initialized using WeightOnlyLinearMethod. This method loads quantized weights and invokes the acext quantization kernels at runtime. Because acext relies on CUTLASS for kernel acceleration, weights must be pre-reordered. Currently, this reordering happens once at system startup and accounts for the number of GPUs.
class WeightOnlyLinearMethod(LinearMethodBase):
# Set quantization configuration
def __init__(self, quant_config: WeightOnlyConfig):
self.quant_config = quant_config
# Initialize weights: create int8 weight tensors and load quantized weights from WOQ
def create_weights(self, input_size_per_partition: int,
output_size_per_partition: int, input_size: int,
output_size: int,
params_dtype: torch.dtype) -> Dict[str, Any]:
qweight = Parameter(
torch.empty(
input_size_per_partition,
output_size_per_partition,
device="cuda",
dtype=torch.int8,
),
requires_grad=False,
)
scales = Parameter(
torch.empty(
output_size_per_partition,
device="cuda",
dtype=params_dtype,
),
requires_grad=False,
)
# Instantiate acext's WeightOnlyQuantMatmul class to call mixed-precision kernels later
try:
self.weightOnlyMatmul = ops.WeightOnlyQuantMatmul()
except AttributeError as e:
raise AttributeError(
"WeightOnlyQuantMatmul kernels could not be imported. If you built vLLM "
"from source, make sure BUILD_WEIGHTONLY_KERNELS=1 was set.") from e
woq_state = WOQState.UNINITIALIZED
......
# Apply weights at runtime using acext's quantization kernel
def apply_weights(self,
weights: Dict[str, torch.Tensor],
x: torch.Tensor,
bias: Optional[torch.Tensor] = None) -> torch.Tensor:
# Online weight preprocessing (done once at startup)
if weights["woq_state"] == WOQState.UNINITIALIZED:
qweight_cpu = weights["qweight"].cpu()
qweight_cpu = preprocess_weights_for_mixed_gemm(qweight_cpu, torch.int8, False, False)
weights["qweight"] = qweight_cpu.cuda()
weights["woq_state"] = WOQState.READY
qweight = weights["qweight"]
scales = weights["scales"]
return self.weightOnlyMatmul.weightonly_gemm(x, qweight, scales, bias)2.1.3 Run WOQ Models
To enable weight-only quantization support, compile vLLM with BUILD_WEIGHTONLY_KERNELS=1.
# Compile vLLM
cd vllm
BUILD_WEIGHTONLY_KERNELS=1 python setup.py develop
# Run offline inference with a quantized model
python examples/offline_inference.py --model /path/to/Llama-2-7b-hf-woq/ -q weightonly --trust-remote-codeOutput:

2.2 Add AWQ/GPTQ Quantization Support (Optimized)
2.2.1 Optimize AWQ/GPTQ Inference
AWQ and GPTQ are natively supported in vLLM and both use int4 quantization.
For more information, see https://docs.vllm.ai/en/latest/quantization/auto_awq.html.
However, the current AWQ/GPTQ implementation in vLLM only reduces the memory footprint and does not improve the inference speed compared to fp16.

We improved AWQ/GPTQ inference using the mixed-precision kernels of acext. These kernels deliver measurable speedups. Because acext requires specific weight layouts, original AWQ weights must be preprocessed before you can call acext.
By adding acext weightonly_groupwise_gemm support to vLLM, you can accelerate AWQ inference while retaining the original AWQ weights. The preprocessing runs once before the weights are first used.

The same flow also applies to GPTQ quantization.
Similar to WOQ, weight processing is currently performed online, which causes a long startup delay for vLLM. An offline processing method will be supported in a future release.
2.2.2 Fast AWQ/GPTQ Inference
This optimization is still under active development. It is disabled by default in vLLM. To enable it, set the `USE_FAST_AWQ=1` or `USE_FAST_GPTQ=1` environment variable.
You can use the following command line to invoke the FastAWQ flow, which accelerates AWQ quantization with acext.
USE_FAST_AWQ=1 python offline_inference.py --model /ppusw/share/LLM_Weights/Llama-2-7b-hf-awq -q awq --trust-remote-codeFastAWQ produces outputs that are identical to standard AWQ, but with faster performance.

2.3 acext Supports fused MoE
We added acext backend support to vLLM 0.8.3 and 0.8.5 to support bf16 and w8a8-int8-channel modes. For a code reference, see the following:
https://code.alibaba-inc.com/ppu_open_source/vllm/tree/v0.8.5_ppu_1v5.1_releaseThis integration includes three main changes:
2.3.1 Build acext Backend
In `acext_moe_func.cu`, we added the acext backend using the AcextFusedMoe class to call acext APIs. We then registered these as Python APIs using csrc/moe/moe_ops.h and csrc/torch_bindings.cpp.
API | Features |
acext_fusedmoe_warpper | Call acext backend to execute fused MoE |
get_acext_fusedmoe_status_wrapper | Check if current model config supports acext backend. Returns 0 if supported. |
acext_get_version | Return acext library version (int). Current version: 1050100. |
2.3.2 Modify fused MoE Layer
In the fused_moe.py file, you can add a call to `acext` within the implementation of `fused_experts_impl`. First, you can use ops.get_acext_fusedmoe_status() to check whether the current model configuration is suitable for the `acext` backend. If it is not suitable, the `triton` backend is called. If the return value is acext_fusedmoe_status = 0, you can use ops.acext_fusedmoe_wrapper() to call the `acext` implementation of `fused_moe`.
2.3.3 Add W8A8Int8MoEMethod (for w8a8-int8-channel)
In `compressed_tensors_moe.py`, we added the CompressedTensorsW8A8Int8MoEMethod class to load w8a8-int8-channel weights and run the corresponding MoE layer.
2.4 Supported Large Language Models
Model | WeightOnly | AWQ | GPTQ | N_K Shape |
Llama-2-7b-hf | Y | Y | Y | 12288 4096 4096 11008 22016 4096 4096 4096 |
Llama-2-13b-hf | Y | Y | Y | 5120 5120 27648 5120 5120 13824 15360 5120 |
Llama-2-70b-hf (8GPUS) | Y | Y | Y | 8192 3584 8192 1024 1280 8192 7168 8192 |
Meta-Llama-3-8B | Y | Y | Y | 6144 4096 4096 14336 28672 4096 4096 4096 |
Meta-Llama-3-70B (8GPUS) | N | Y | N | 8192 3584 8192 1024 1280 8192 7168 8192 |
Baichuan-7b | Y | Y | Y | 12288 4096 4096 11008 22016 4096 4096 4096 |
Baichuan-13b | Y | Y | Y | 5120 5120 5120 13696 27392 5120 15360 5120 |
Baichuan2-7b | Y | Y | Y | 12288 4096 4096 11008 22016 4096 4096 4096 |
Baichuan2-13b | Y | Y | Y | 5120 5120 5120 13696 27392 5120 15360 5120 |
Chatglm2-6b | Y | N | N | 4608 4096 4096 13696 27392 4096 4096 4096 |
Chatglm3-6b | Y | N | N | 4608 4096 4096 13696 27392 4096 4096 4096 |
Qwen-7b | Y | Y | Y | 12288 4096 4096 11008 22016 4096 4096 4096 |
Qwen-14b | Y | Y | Y | 5120 5120 5120 13696 27392 5120 15360 5120 |
Qwen-72b (8GPUS) | Y | Y | Y | 6144 8192 8192 1024 8192 3072 3072 8192 |
Falcon-7b | Y | N | N | 4544 4544 4672 4544 18176 4544 4544 18176 |
Falcon-40b (8GPUS) | Y | N | Y | 8192 4096 8192 1024 1152 8192 4096 8192 |
Gemma-7b | Y | N | N | 49152 3072 12288 3072 3072 24576 3072 4096 |
Mistral-7b | Y | Y | Y | 6144 4096 4096 14336 28672 4096 4096 4096 |
Mpt-7B | Y | N | Y | 12288 4096 4096 16384 4096 4096 16384 4096 |
Mixtral-8x7b (8GPUS) | Y | Y | N | 4096 512 8 4096 768 4096 |
Mixtral-8x22b (8GPUS) | Y | Y | N | 8 6144 1024 6144 6144 768 |
2.4.1 Known Issues
2.4.1.1 Weight Conversion Issues
WOQ model conversion issues:
Model | Comments |
Chatglm2-6b | When AutoWOQ quantizes ChatGLM weights, the generated tokenizer_config.json must be replaced with the original file to avoid compatibility issues—a known community issue. Manually copy it after conversion. |
Chatglm3-6b |
AWQ model conversion issues:
Model | Comments |
Chatglm2-6b | TypeError: chatglm isn't supported yet. |
Chatglm3-6b | TypeError: chatglm isn't supported yet. |
Falcon-7b | TypeError: FalconDecoderLayer.forward() missing 1 required positional argument: 'alibi' |
Falcon-40b | TypeError: FalconDecoderLayer.forward() missing 1 required positional argument: 'alibi' |
Mpt-7B | AttributeError: 'NoneType' object has no attribute 'bool' |
GPTQ model conversion issues:
Model | Comments |
Chatglm2-6b | TypeError: chatglm isn't supported yet. |
Chatglm3-6b | TypeError: chatglm isn't supported yet. |
Falcon-7b | AssertionError assert infeatures % self.group_size == 0 |
Meta-Llama-3-70B | torch._C._LinAlgError: linalg.cholesky: The factorization could not be completed because the input is not positive-definite (the leading minor of order 27024 is not positive-definite). |
Mixtral-8x7b | ZeroDivisionError: float division by zero |
Mixtral-8x22b | ZeroDivisionError: float division by zero |
2.4.1.2 Runtime Issues
Results for Meta-Llama-3-70B-woq show anomalies.

Gemma-7b-awq fails at runtime.

Some models experience a significant loss in accuracy on MMLU with AWQ/GPTQ quantization. For example, LLaMA2-7B:

Validation on A100 GPUs confirms that the poor performance of these models is caused by the AWQ/GPTQ quantization algorithms, a finding that is also reflected in the MMLU scores measured on A100 GPUs. For example, the MMLU scores obtained by running Llama-2-7b with AWQ and GPTQ on an A100 are consistent with the PPU scores.


2.5 Model Quantization Performance
Various methods and metrics are used to measure the inference performance of Large Language Models (LLMs).
We tested generation-phase throughput under fixed conditions: batch sizes (1, 2, 4, and 8), input lengths (32, 512, 1024, and 2048), and an output length of 128. This test reflects real-world benefits, such as reduced latency in online inference.
The following table shows the throughput speedups for each quantization method compared to the fp16 baseline.

2.5.1 Detailed Performance Data
2.6 Model Quantization Accuracy (MMLU)
We use the lm-evaluation-harness framework to run large language model inference and test the scores on the MMLU dataset to evaluate the accuracy of our quantized models.
https://github.com/EleutherAI/lm-evaluation-harness
2.6.1 Running steps
# If your setuptools version is too low, upgrade it first.
# pip3 install --upgrade pip setuptools
# For the following reason, we need to restrict setuptools to version 69.5.1:
# https://github.com/vllm-project/vllm/issues/4961
git clone https://github.com/EleutherAI/lm-evaluation-harness
# If you encounter issues running the MMLU test, it might be version-related. Try switching to this commit we have tested:
# git reset --hard e5e5ee0cb629c9c88165292d1b4bf34623392d33
cd lm-evaluation-harness
pip install -e .
# Use the Hugging Face proxy.
export HF_ENDPOINT=https://hf-mirror.com
# Use lm_eval for MMLU inference.
lm_eval --model vllm --model_args pretrained=/ppusw/datasets/huggingface/Llama-2-7b-hf --tasks mmlu --batch_size auto --num_fewshot 5
# If you still have issues downloading the dataset after using the proxy, it is because the following file hardcodes the Hugging Face download URL:
# /root/.cache/huggingface/modules/datasets_modules/datasets/hails--mmlu_no_train/b7d5f7f21003c21be079f11495ee011332b980bd1cd7e70cc740e8c079e5bda2/mmlu_no_train.py
# Modify the URL in this file to point to hf-mirror.2.6.2 Inference results
You can set `num-fewshot` to control the few-shot parameter. A higher value increases the runtime but may yield a higher score.
Without `num_fewshot`, the test runs quickly (in minutes) and scores 41.3.

With `num_fewshot=5`, the test runs slowly (in hours) but scores higher at 45.9.

This matches the result shown on the website.

2.6.3 MMLU accuracy for different quantization methods
We use the MMLU score from fp16 inference as the baseline. By applying different quantization methods during inference, we can obtain post-quantization MMLU scores and compare them to the baseline to calculate the MMLU loss.
The following table shows the MMLU scores (few-shot 0) and MMLU loss relative to fp16 for different models and quantization methods.
Gray cells indicate methods that are not supported in the current version (PPU Release 1.3). Red cells indicate methods with inference bugs.
3. Compile and Run from Source
3.1 Compilation
acext depends on the PPU version of CUTLASS. First, download acext, and then download the PPU version of CUTLASS.
# Fetch code from ppu_open_source
git clone -b sail_v1.6.1 https://code.alibaba-inc.com/ppu_open_source/acext
cd acext
git clone -b sail_v1.6.1 https://code.alibaba-inc.com/ppu_open_source/cutlassYou can compile and install acext in one of two ways.
Compile and install acext separately.
# Compile & install: in acext rm -rf build && mkdir build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_PYT=ON cmake --build . -- -j${nproc} cmake --build . --target install -j${nproc}Compile and install the acext wheel package.
python -m build --wheel --no-isolation -v pip install dist/*.whl
If you choose the wheel package installation, after you install the wheel, you must run the following commands to copy the acext dynamic library and header files to the PPU_SDK directory. This ensures that vLLM/SGLang cmake can find them:
cp $(python -c "import sysconfig; print(sysconfig.get_path('purelib'))")/lib/libacext.so $PPU_SDK/lib/
cp -r $(python -c "import sysconfig; print(sysconfig.get_path('purelib'))")/include/acext $PPU_SDK/include/3.2 Running
3.2.1 Run unit tests
cd build
# Unit test for a16w8/a16w4 quant gemm
python ../tests/test_woq_gemm.py
# Unit test for a8w8 quant gemm
python ../tests/th_int8_gemm.py
# Unit test for MoE
python ../tests/th_moe.py3.2.2 Run performance tests
cd build
# Run FpAintB benchmark. Default M, N, K is (1, 5120, 5120). You can specify M, N, K as command-line arguments.
./benchmark/benchmark_fpAintB
# Run w8a8 benchmark. Default M, N, K is (1, 5120, 5120). You can specify M, N, K as command-line arguments.
./benchmark/benchmark_w8a8
# Iterate through all M, N, K values to run the benchmark and generate a unified CSV report.
cd benchmark
python run_benchmark.py