# 論文閱讀 : SmoothQuant
## 主要重點整理
#### 背景與挑戰
- 大型語言模型(LLMs)雖然效能優異,但**運算與記憶體資源消耗巨大**。
- 量化是降低成本與加速推理的常用技術。
- 現有方法難以在**維持準確率**與**硬體效率**之間取得平衡。
**主要貢獻:提出 SmoothQuant 方法**
* **類型**:Post-training Quantization(PTQ),不需再訓練。
* **特點**:
* **訓練後量化**,無需額外微調。
* 同時對 **權重(weights)與啟動值(activations)進行 INT8 量化(W8A8)**。
* 適用於各類 LLM,包括:OPT、BLOOM、GLM、MT-NLG、LLaMA 1/2、Falcon、Mistral、Mixtral。
* **核心技術**:
* **觀察**:權重較容易量化,啟動值較難。
* **創新點**:透過**數學等價轉換**,將啟動值的量化困難度「遷移」到權重,達到平滑 activation 的效果。
* 效能
* 實現最多 **1.56× 推理加速**與 **2× 記憶體縮減**。
* 幾乎**不影響模型準確率**。
* 支援單節點推理 530B 模型,**大幅降低 LLM 部署門檻與成本**。
## Introduction
* LLMs(如 GPT-3)具有卓越效能,但**推論成本與延遲極高**:
* 例如 GPT-3(175B 參數)需 **至少 350GB 記憶體**(FP16),需 8×A6000 或 5×A100 才能執行推理。
* 高記憶體與計算需求會造成 **延遲過高**,無法滿足實際應用。
#### 解決方法:量化
* **使用低位元整數(如 INT8)對權重與啟動值量化**:
* 降低記憶體用量、頻寬需求。
* 加速計算密集操作(如 GEMM、BMM)。
* INT8 通常可**節省 50% 記憶體,提升近 2× 吞吐**。
#### 挑戰
* 雖然 CNN 或小型 transformer(如 BERT)可以有效量化,但:
* **大型 LLM 的 activation 含有大量 outliers**,難以量化。
* 尤其在模型規模 >6.7B 時,activation 中會出現極端值,導致準確率下降。
### 現有方法比較
| 方法 | 概要說明 | 限制 |
| -------------- | ------------------------------------------------- | ------------------------ |
| **ZeroQuant** | 動態 per-token activation 量化 + group-wise weight 量化 | 無法維持如 OPT-175B 等超大模型的準確率 |
| **LLM.int8()** | 混合精度(outlier 留在 FP16,其餘為 INT8) | 實作複雜,對硬體加速器不友善 |
### 提出方法:SmoothQuant

#### 核心創新
* **觀察**:儘管 activation 難以量化,不同 token 在各 channel 間變化趨勢相似。
* **方法**:
* 離線階段使用**通道級縮放轉換(per-channel scaling)**,將 activation 的極端值平滑處理。
* **將 activation 的量化難度「數學等價地遷移」給 weights**,使整體更易量化。
#### 相容性與效率
* SmoothQuant 是**通用、訓練後、無需額外微調**的 PTQ 方法。
* 相容多種量化方案,提供三種效率等級設定(O1–O3)。
#### 實驗與應用成效
* 支援多種大型模型(OPT-175B、BLOOM-176B、GLM-130B、MT-NLG-530B)。
* 在 PyTorch 上實測可達:
* **最多 1.51× 推理速度提升**
* **最多 1.96× 記憶體減少**
* 整合進 FasterTransformer 框架:
* 提升至 **1.56× speedup**、**記憶體減半**
* 甚至能讓 **530B 模型在單一 8-GPU 節點中部署**
## Preliminaries
### 量化數學定義(整數型均勻量化(Integer Uniform Quantization))
$$
\bar{\mathbf{X}}^{\text{INT8}} = \left\lceil \frac{\mathbf{X^{\text{FP16}}}}{\Delta} \right\rfloor, \quad \Delta = \frac{\max(|\mathbf{X}|)}{2^{N-1}-1}
$$
* $\mathbf{X}$:原始浮點張量。
* $\bar{\mathbf{X}}$:量化後的 INT8 張量。
* $\Delta$:量化 step size。
* $N$:位元數(本研究為 8 位元)。
* 假設為 **對稱量化**(symmetric, centered at 0);非對稱(asymmetric)量化則可加上 zero-point。
#### Step size 的估算方式
* **Static Quantization**:離線使用校準資料(calibration set)估算 activations 的 $\Delta$。
* **Dynamic Quantization**:於執行時(runtime)根據 activations 統計動態計算 $\Delta$。
### 量化粒度(Granularity)

| 類型 | 說明 |
| --------------- | -------------------------------------------- |
| **Per-tensor** | 全張量使用一個單一 step size,實作簡單,但誤差大。 |
| **Per-channel** | 每個輸出通道用不同 step size,適用於 weight。 |
| **Per-token** | 每個 token 的 activation 使用不同 step size,精細但開銷大。 |
| **Group-wise** | 以 channel 群組為單位,為 per-channel 的粗略版本。 |
### 選擇 W8A8(Weights + Activations 都 INT8)?
* 在 Transformer 中,典型的運算為:
$$
\mathbf{Y} = \mathbf{X} \cdot \mathbf{W}
$$
其中 $\mathbf{X}$ 為 activation、$\mathbf{W}$ 為 weight。
* 只量化權重(W8)雖可節省空間,但不能用 **INT8 kernel** 加速。
* 為達成高效率推理,**需要 W8A8,才能使用硬體加速器上的 INT8 GEMM kernel**(如 NVIDIA GPU、Intel CPU 等支援)。
### 問題核心:LLM 的 Activation 難以量化
#### 關鍵觀察與挑戰
1. **Activations 比 Weights 更難量化**
* 權重的分布通常較平坦且容易近似。
* 過去研究已成功將 weights 量化為 INT8 / INT4,幾乎不影響準確率。
* Activation 則具有極端值(outliers),導致難以壓縮而不損失資訊。
2. Activation 中的 Outliers 對量化傷害極大
* 少數 outliers 可高達其他值的 **100 倍**,導致:
* 計算 step size 時會被 outlier 主導 → 非 outlier 值的有效量化位數(bits)急劇下降。
* 比如 channel 中最大值為 $m_i$,整體最大為 $m$,則有效 bits 變成 $2^8 \cdot \frac{m_i}{m}$,有些 channel 實際只有 2–3 級別。
3. **Outliers 只出現在固定少數 Channels 且持續出現**
* 若某 channel 有 outlier,會在所有 token 中持續存在。
* → channel 內部變異小,但不同 channel 間變異大。
### 現有應對方式比較
| 量化策略 | 說明與效果 | 限制 |
| ------------------------------------------------- | ------------------------------ | ----------------------------- |
| **Per-tensor** | 全 tensor 一個 step size,最簡單 | 受 outlier 影響最大,誤差大 |
| **Per-token** | 為每個 token 用不同 step size | 仍無法解決 outlier 集中在 channel 的問題 |
| **Per-channel** | 每個 output channel 一個 step size | 效果好,但不相容硬體 |
| **Simulated per-channel activation quantization** | 能接近 FP16 精度 | 僅限於模擬,實際不易部署 |
#### Per-channel Activation 量化難部署
* 雖然 per-channel 最能降低 activation 的誤差,但:
* 不符合現有硬體(如 NVIDIA Tensor Core)上 **INT8 GEMM 的執行路徑**。
* 這些硬體需要高速矩陣乘法序列,中間不能插入低速操作(如 rescale)。
* 可行的硬體友善量化方式:
* 僅在矩陣乘法外部進行縮放(scaling):
$$
\mathbf{Y} = \text{diag}(\Delta_X) \cdot (\bar{X}^{\text{INT8}} \cdot \bar{W}^{\text{INT8}}) \cdot \text{diag}(\Delta_W)
$$
→ 只允許在 token 維度(activations 的 $T$)或 output channel 維度(weights 的 $C\_o$)上做 scaling。
### 小結
* **Activation 的 outliers 是 LLM 量化的主要瓶頸**,會造成低有效位數與精度下降。
* **Per-channel activation quantization 是理想方案,但不適用於現有硬體。**
* 因此,現有方案(如 LLM.int8()、ZeroQuant)採用折衷的 per-token 量化,但仍無法有效解決根本問題。
* 本研究提出的 SmoothQuant 就是為了解決這個困境:**在硬體可接受的範圍內,達成類似 per-channel 效果的量化方式。**
## 論文核心方法論
### **核心想法:轉換張量來遷移量化困難**

### **平滑 Activation、重配 Weight,保持等價性**
SmoothQuant 的做法是:
> **對 activation 每個 channel 做縮放(平滑),同時用反向比例縮放 weights,保持線性層運算等價性。**
數學上轉換為:
$$
\mathbf{Y} = (\mathbf{X} \cdot \text{diag}(\mathbf{s})^{-1}) \cdot (\text{diag}(\mathbf{s}) \cdot \mathbf{W}) = \hat{\mathbf{X}} \cdot \hat{\mathbf{W}}
$$
其中:
* $\mathbf{s}$:每個 channel 的「平滑因子 smoothing factor」
* $\hat{\mathbf{X}}$:平滑過的 activation,更適合量化
* $\hat{\mathbf{W}}$:重配過的 weight
**優點**
* 可將 activation 中的 outlier 平滑掉,讓 quantization bits 有效利用
* 運算仍與原模型相同(數學等價)
### **s 的選擇會決定 quantization 的誤差分佈**
若單純選擇:
* $\mathbf{s}_j = \max(|\mathbf{X}_j|)$:將所有難度丟給 weights(會讓 weights 難量化)
* $\mathbf{s}_j = 1 / \max(|\mathbf{W}_j|)$:則 activation 會難量化
**最佳策略是「均分難度」**
### **提出平衡控制因子 α(migration strength)**

$$
\mathbf{s}_j = \frac{\max(|\mathbf{X}_j|)^{\alpha}}{\max(|\mathbf{W}_j|)^{1-\alpha}}
$$
* $\alpha \in [0, 1]$ 控制平衡比例
* $\alpha = 0.5$:activation 和 weights 各承擔一半
* $\alpha > 0.5$:activation outlier 多 → 多轉移給 weights
* 實驗結果:
* **OPT / BLOOM**:用 $\alpha = 0.5$ 效果最佳
* **GLM-130B**:outlier 多,$\alpha = 0.75$ 效果較好
效果是讓 activation 和 weight 在量化前具有「相似的最大值」,使 quantizer bits 被平均分配,量化誤差減少。
### 實作方式與優化
* smoothing factor 可**離線提前融合到前一層的線性運算中**(如 Linear, LayerNorm):
* 不增加額外 kernel call → 無推理效能損失
* 若遇到 residual 結構,也可加上殘差支路的額外縮放
### 應用在 Transformer 上

> 將 W8A8 應用於所有 compute-heavy operator(Linear / BMM),其餘仍保持 FP16:
| 模組類型 | 處理方式 |
| ------------------- | ------- |
| Linear / BMM | W8A8 量化 |
| Softmax / LayerNorm | 保持 FP16 |
| 激活函數(ReLU 等) | 保持 FP16 |
## Experiments
### Baseline 方法比較
| Baseline 方法 | 說明 |
| ------------------- | ------------------------------------------------- |
| W8A8 Naive | 權重與 activation 都簡單地量化為 INT8,無特殊處理 |
| ZeroQuant | 動態 per-token activation 量化 + group-wise weight 量化 |
| LLM.int8() | 混合精度策略:對 outlier 留 FP16,其餘用 INT8 |
| Outlier Suppression | 用縮放方式降低 activation 中的極端值,改善量化精度 |
此外,SmoothQuant 提供三種效率 / 準確度等級(O1 \~ O3),**可視為一種 orthogonal augmentation strategy**,可搭配多種量化策略使用。
### **實驗模型與評估任務**
| 模型 | 評估任務(Zero-shot) |
| ----------- | --------------------------------------------------------------------- |
| OPT | LAMBADA, HellaSwag, PIQA, WinoGrande, OpenBookQA, RTE, COPA, WikiText |
| BLOOM | 同上 |
| GLM-130B | LAMBADA, MMLU, MNLI, QNLI(因部分 benchmark 出現在訓練資料中) |
| MT-NLG 530B | 用於展示 scalability,首次在單節點上部署超過 500B 的模型 |
* OPT/BLOOM 使用 `lm-eval-harness` 工具進行自動化評測。
* GLM-130B 使用官方評測工具。
* 主要觀察的是 **量化前後的相對性能變化**,非絕對分數。
### **Activation Smoothing(平滑設定)**
| 模型族群 | 適合的 α 值(遷移強度) | 原因 |
| ----------- | ------------- | --------------------------- |
| OPT / BLOOM | α = 0.5 | activation 難度中等,平均分配最穩定 |
| GLM-130B | α = 0.75 | activation outlier 多,需要更多平滑 |
* 使用 **Pile validation set** 中隨機抽取的 512 筆樣本進行:
* smoothing factor 的估算
* static quantization step 的校準(Calibration)
* 校準一次後,應用於所有 downstream 任務,驗證其泛化性與 zero-shot 表現。
### **實作與部署細節**
| 框架 | 用途 | 實作方式 |
| --------------------- | ------------- | ----------------------------------- |
| PyTorch (Huggingface) | 概念驗證原型 | 自訂 INT8 Linear 與 BMM 模組 |
| FasterTransformer | 高效能部署環境(如伺服器) | 使用 CUTLASS INT8 GEMM 核心取代 FP16 運算模組 |
* 在兩個框架中,都替換原本的 FP16 模組為 INT8 實作版本。
* 重點:**不需額外訓練、能直接部署在 INT8 支援的硬體上,如 NVIDIA Tensor Cores**
### 實驗結果整理

| 方法 | 表現 |
| -------------------------------------- | ---------------------------------------- |
| **SmoothQuant** | 在所有量化策略下均可 **匹配 FP16 精度** |
| **LLM.int8()** | 也能保留精度,但**需要浮點表示 outliers**,導致延遲變高 |
| W8A8 / ZeroQuant / Outlier Suppression | 幾乎失效,輸出接近隨機 → 證明 LLM 的 activation 很難直接量化 |
**結論**:SmoothQuant 是唯一能在不犧牲精度、又不增加延遲的情況下成功量化 OPT-175B 的方法。
### 不同模型的量化難度比較

| 模型 | 量化難度 | SmoothQuant 表現 | 備註 |
| ---------- | ---- | ----------------------------- | -------------------------------- |
| BLOOM-176B | 易 | O1/O2 完美匹配 FP16,O3 精度僅下降 0.8% | activation 分布較穩定 |
| GLM-130B | 難 | O1 可匹配 FP16,O3 下降 1%,仍大勝其他方法 | 遇到更多 outliers,採用 top-2% clipping |
### 各種模型規模都穩定
* OPT 系列(從小到大)皆經過測試
* 圖表 7 結果顯示:
* **SmoothQuant 在所有規模下都能達到與 FP16 幾乎一致的準確率**
* 適用於從 1.3B 到 175B 等級的 LLM
### **Instruction-Tuned LLM**

* 測試對象:**OPT-IML-30B**
* 資料集:WikiText-2、LAMBADA
* SmoothQuant 表現:
* 成功保持精度,W8A8 量化可穩定使用
* 備註:
* 雖然是 instruction-tuned,但架構與 pretraining 相近 → 方法仍然適用
### **LLaMA 模型**

* 實驗對象:LLaMA 1 系列
* 觀察:
* LLaMA activation 的 outlier 現象 **比 OPT / BLOOM 輕微**
* SmoothQuant 依然可以做到 **W8A8 量化,且幾乎無性能損失**
### **更多新模型:LLaMA-2, Falcon, Mistral, Mixtral**

結論:SmoothQuant 是一個具 **架構廣泛適用性** 的量化方法,**連 MoE 模型都能保持效能**
### Speedup, Memory Saving

#### PyTorch 實作(單 GPU,OPT-6.7B \~ OPT-30B)
| 比較項目 | SmoothQuant-O3 vs. FP16 |
| ---------------- | -------------------------------------------- |
| Latency | 最多可達 **1.51× 加速**(在 OPT-30B、seq=256 時) |
| 記憶體 | 幾乎 **節省一半的 GPU 記憶體用量** |
| 對比 LLM.int8() | LLM.int8() 雖保留精度,但速度比 FP16 還慢,因其混合精度處理產生額外開銷 |
#### FasterTransformer 實作(多 GPU 可平行)

| 模型 | SmoothQuant-O3 效果 |
| -------------- | ------------------------------------------------------ |
| OPT-13B / 30B | 單 GPU 加速最多可達 **1.56×** |
| OPT-66B / 175B | 可使用**一半的 GPU 數量達到相同或更快的 latency**(例:OPT-175B 僅需 4 GPU) |
| 記憶體使用 | 降低至原來的 **約 1/2**,利於在資源有限的伺服器上部署大型模型 |
### Decoding 階段效能(逐 token 預測)

| 比較項目 | SmoothQuant vs. FP16 |
| -------------------- | ----------------------- |
| Per-token latency | 最多可減少 **1.42× latency** |
| 記憶體 | 同樣可節省 **約一半的記憶體使用量** |
### Ablation Study
### Quantization Scheme 粒度對效能的影響

| 粒度級別(O1 → O3) | 越粗 → latency 越低 |
| -------------------- | ----------------------------------------- |
| Dynamic Quantization | 有 runtime overhead(需要在線計算 scale) |
| Static Quantization | **推薦**(速度更快,尤其適合部署) |
| Overall 建議 | **使用 O3(per-tensor static)在可接受精度損失下效能最佳** |
### 遷移強度 α 的選擇(activation ↔ weight 難度平衡)

| α 值 | 量化難點 | 效果 |
| ------------ | -------------- | ---------------- |
| < 0.4 | activation 難量化 | 精度下降 |
| > 0.6 | weight 難量化 | 精度下降 |
| 0.4 \~ 0.6 | 平衡最適 | **最佳量化效果(誤差最小)** |
### 總結
| 維度 | SmoothQuant-O3 結果 |
| ---------- | ----------------------------------------------- |
| 推理加速 | 最多提升 **1.56×(FasterTransformer)**;比 LLM.int8 快 |
| 記憶體使用 | **節省約 2× GPU 記憶體**,支援更大模型部署 |
| 可擴展性 | **530B 模型首次實現單節點部署(8×A100)** |
| 實作容易 | 完全 post-training;支援 PyTorch 與 FasterTransformer |
| 精度維持 | 各種模型與任務下,精度 **接近 FP16 baseline**,遠優於其他 INT8 方法 |
| 消融分析結果明確 | α 在 0.4–0.6 之間最穩定,O3 粒度最適合實務部署 |
## 結論
### SmoothQuant 是一種高準確率、高效率的 **後訓練量化方法(Post-Training Quantization, PTQ)**,其核心優勢包括:
### 1. **同時量化權重與 activation(W8A8)**
* 能針對 LLM 中 **所有矩陣乘法(GEMMs)** 進行 INT8 量化
* 精度幾乎與 FP16 相當(lossless)
* 適用模型規模涵蓋 **小型到超大型(高達 530B 參數)**
---
### 2. **極大化部署效率**
* 相較於以往混合精度(如 LLM.int8)的方法:
* **推理速度提升高達 1.56×**
* **記憶體使用量減半**
* 支援主流部署框架:
* PyTorch(研究原型)
* FasterTransformer(生產環境)
---
### 3. **轉變 LLM 推理門檻**
* 不需重新訓練(訓練後量化)
* 不需修改 CUDA 核心或特殊硬體
* 可直接用現成 INT8 kernel 加速(如 CUTLASS GEMM)
## 附註
### SmoothQuant 與 GPTQ 比較整理
| 面向 | GPTQ | SmoothQuant |
| ----- | ------------------------------ | --------------------------------- |
| 量化對象 | 只量化 weights(activation = FP16) | 同時量化 weights + activations(W8A8) |
| 支援階段 | 只支援生成(batch=1) | 支援 context + decoding,支援 batching |
| 記憶體節省 | 主要減少權重 loading | 還能減少 KV cache 記憶體 |
| 精度保持 | 需精細調參與 retrain | Post-training、快速部署 |
| 整合潛力 | 可與 SmoothQuant 結合為 W4A4 | 可搭 GPTQ 改良 weight 端量化 |
### Per-channel Activation
對每個 activation 的 channel(特徵維度)使用不同的 scale(Δ)。
#### 現代硬體的設計偏好「大批次、規則、整齊的計算」
* 像 NVIDIA GPU 上的 **Tensor Cores**、Intel CPU 上的 **AVX / VNNI** 都針對 **固定形狀的矩陣乘法(GEMM)** 做了高度優化。
* 它們偏好這種流程:
```
INT8 activation × INT8 weight → INT32 結果 → 統一 scale 還原回 FP16 / FP32
```
* 這樣可以保證整個 kernel 連續、無條件分支、批次並行。
#### Per-channel 代表你必須「每個 channel 用不同 scale」,等於要插入額外操作:
* 若 activation 是 per-channel scale,就不能直接把 activation 傳進 GEMM,你得「先對每一行(或列)做縮放」。
* 這表示你得執行:
```
dequant(scale_i * x_i) for each i
```
→ 在硬體上需要額外的 **逐 channel 乘法(FMA)指令**,這無法與 GEMM 並行,**會造成瓶頸與效率損失**。
### s 的選擇會決定 quantization 的誤差分佈
考慮一層 Linear Layer:
$$
\mathbf{Y} = \mathbf{X} \cdot \mathbf{W}
$$
假設:
* Activation $\mathbf{X} \in \mathbb{R}^{2 \times 2}$
* Weight $\mathbf{W} \in \mathbb{R}^{2 \times 2}$
#### Activation channel 1 的數值(有 outlier):
```
X[:, 1] = [1.0, 100.0] → max = 100
```
#### Weight channel 1 的數值:
```
W[:, 1] = [0.2, 0.3] → max = 0.3
```
#### 若使用 $s_j = \max(|X_j|) = 100$
* **平滑後的 activation**:
$$
\hat{X} = X / 100 = [0.01, 1.0]
$$
非常平坦、容易量化(數值都落在 0~1)
* **相應放大的 weight**(乘上 100):
$$
\hat{W} = W \cdot 100 = [20, 30]
$$
權重變得超大,導致:
* 權重的最大值 = 30,非 outlier channel 變小,**scale 會被 outlier 主導**。
* → INT8 量化會浪費 bits 在極大值上,其他值只能被擠壓在低 bit 範圍,導致量化誤差大。
結果:**activation 好量化,但 weights 變成難量化,準確率掉很多。**
#### 若使用 $s_j = 1 / \max(|W_j|) = 1 / 0.3 \approx 3.33$
* **平滑後的 activation**:
$$
\hat{X} = X / 3.33 = [0.3, 30]
$$
outlier 還是很明顯(30),仍然主導最大值。
* **相應的 weight**:
$$
\hat{W} = W \cdot 3.33 = [0.67, 1.0]
$$
權重仍在小範圍內,容易量化。
結果:**weights 好量化,但 activation 仍然有嚴重 outlier,難量化,仍導致精度損失。**
#### 平衡兩邊 → 用 α
例如使用:
$$
s_j = \frac{\max(|X_j|)^{0.5}}{\max(|W_j|)^{0.5}}
$$
延續上面例子:
* $\max(|X_j|) = 100$, $\max(|W_j|) = 0.3$
計算:
$$
s_j = \frac{100^{0.5}}{0.3^{0.5}} = \frac{10}{\sqrt{0.3}} \approx 10 / 0.55 \approx 18.2
$$
* Activation 除以 18.2:
$$
[1.0, 100.0] → [0.055, 5.49]
$$
* Weight 乘以 18.2:
$$
[0.2, 0.3] → [3.64, 5.46]
$$
結果:activation 與 weight 的最大值都在 5\~6 之間 → 都比較好量化,誤差小