Language Model QAT Using Quark and Trainer#
This document provides examples of Quantization-Aware Training (QAT) for language models using Quark.
Note
For information on accessing Quark PyTorch examples, refer to Accessing PyTorch Examples.
This example and the relevant files are available at /torch/language_modeling/llm_qat.
Note
For the 2-bit full-weight QAD (Quantization-Aware Distillation) pipeline —
distilling a 2-bit student from a BF16 teacher and exporting a packed int2
model — see README_QAD_2BIT.md in ../llm_qad (the QAD examples live in
examples/torch/language_modeling/llm_qad).
Note
For the 2-bit LoRA + knowledge-distillation pipeline — attaching LoRA
adapters to a 2-bit PTQ student, distilling from a BF16 teacher, and exporting
a factored or Quark-native packed uint2 model — see README_LORA_KD_2BIT.md
in lora_kd_2bit (examples/torch/language_modeling/llm_qat/lora_kd_2bit).
Supported Models#
Model Name |
WEIGHT-ONLY (INT4.g128) |
|---|---|
microsoft/Phi-3-mini-4k-instruct |
✓ |
THUDM/chatglm3-6b |
✓ |
Preparation#
Please install the required packages before running QAT by executing pip install -r requirements.txt. To evaluate the model, install the necessary dependencies by running pip install -r ../llm_eval/requirements.txt.
If an NCCL timeout error occurs while saving the model during the program’s execution, you can try installing the accelerate==1.4.0 version to resolve it.
(Optional) For LLM models, download the Hugging Face checkpoint.
QAT Scripts#
You can run the following Python scripts in the examples/torch/language_modeling/llm_qat path. Here, Phi-3-mini-4k-instruct is used as an example.
Recipe 1: QAT Finetuning ChatGLM and Export to Safetensors using FSDP#
The configuration variable ONLY_TRAIN_SCALING_FACTOR determines whether to only make the scaling factor trainable, while keeping other parameters frozen.
This recipe uses the default optimizer adamw_8bit, which can reduce GPU memory usage. The default attention implementation is now SDPA, but ChatGLM does not support SDPA, so --attn_implementation must be set to eager.
SECONDS=0
log_file=${log_dir}/llm_qat_${model_name}_finetune.log
output_dir="./quantized_model/chatglm_6b"
NUM_GPUS=4
BATCH_SIZE_PER_GPU=2
TOTAL_BATCH_SIZE=32
GRADIENT_ACC_STEPS=$(($TOTAL_BATCH_SIZE/$NUM_GPUS/$BATCH_SIZE_PER_GPU))
FSDP_CONFIG=./fsdp_configs/chatglm_fsdp_config.json
NUM_EPOCHS=5
LR=2e-5
MAX_SEQ_LEN=512
CUDA_VISIBLE_DEVICES=0,1,2,3 accelerate launch --num_processes=${NUM_GPUS} main.py \
--fsdp "full_shard auto_wrap" \
--fsdp_config ${FSDP_CONFIG} \
--model ${MODEL_DIR} \
--model_trust_remote_code \
--attn_implementation eager \
--quant_scheme w_uint4_asym \
--group_size 128 \
--finetune_dataset wikitext \
--num_train_epochs ${NUM_EPOCHS} \
--learning_rate ${LR} \
--finetune_seqlen ${MAX_SEQ_LEN} \
--per_device_train_batch_size ${BATCH_SIZE_PER_GPU} \
--per_device_eval_batch_size ${BATCH_SIZE_PER_GPU} \
--model_export hf_format \
--output_dir $finetune_checkpoint \
--model_export_dir ${output_dir} \
--save_only_model true \
--load_best_model_at_end false \
--gradient_accumulation_steps ${GRADIENT_ACC_STEPS} \
--skip_evaluation 2>&1| tee $log_file
date -ud "@$SECONDS" "+Time elapsed: %H:%M:%S" |tee -a ${log_file}
TOTAL_TIME=$((TOTAL_TIME+SECONDS))
Recipe 2: Reload and Evaluate QAT Finetuned Model#
SECONDS=0
log_file=${log_dir}/llm_qat_${model_name}_test_finetuned.log
EVAL_BATCH=4
export CUDA_VISIBLE_DEVICES=5
EVAL_TASK=wikitext,winogrande,mmlu
EVAL_OUTPUT_PATH=./${model_name}_${EVAL_TASK//,/_}_quantized_eval_results
python main.py \
--model ${MODEL_DIR} \
--output_dir $finetune_checkpoint \
--model_trust_remote_code \
--skip_finetune \
--model_reload \
--import_model_dir $output_dir \
--eval_result_output_path ${EVAL_OUTPUT_PATH} \
--per_device_eval_batch_size ${EVAL_BATCH} \
--eval_task ${EVAL_TASK} 2>&1| tee $log_file
date -ud "@$SECONDS" "+Time elapsed: %H:%M:%S" | tee -a ${log_file}
TOTAL_TIME=$((TOTAL_TIME+SECONDS))
Recipe 3: Evaluate Original Non-Quantized Model#
EVAL_TASK=wikitext,winogrande,mmlu
EVAL_OUTPUT_PATH=./${model_name}_${EVAL_TASK//,/_}_non_quantized_eval_results
SECONDS=0
EVAL_BATCH=4
log_file=${log_dir}/llm_qat_${model_name}_test_bf16.log
export CUDA_VISIBLE_DEVICES=4
python main.py \
--model ${MODEL_DIR} \
--output_dir $finetune_checkpoint \
--model_trust_remote_code \
--skip_quantization \
--skip_finetune \
--eval_result_output_path ${EVAL_OUTPUT_PATH} \
--per_device_eval_batch_size ${EVAL_BATCH} \
--eval_task ${EVAL_TASK} 2>&1| tee ${log_file}
date -ud "@$SECONDS" "+Time elapsed: %H:%M:%S" |tee -a ${log_file}
TOTAL_TIME=$((TOTAL_TIME+SECONDS))
Results on Phi-3-mini-4k-instruct#
Model Name |
Wikitext PPL (LLM harness) |
MMLU |
Winogrande |
|---|---|---|---|
BF16 |
9.4911 |
70.03 |
73.88 |
QAT Trainer |
11.3928 |
67.05 |
71.27 |
Results on ChatGLM3-6B#
Model Name |
Wikitext PPL (LLM harness) |
MMLU |
Winogrande |
|---|---|---|---|
BF16 |
53.6559 |
50.51 |
62.98 |
QAT Trainer |
57.1710 |
50.24 |
64.25 |