---
# System prepended metadata

title: '論文閱讀 : GPTQ'

---

# 論文閱讀 : GPTQ
[論文連結](https://arxiv.org/pdf/2210.17323)
## 研究動機
- GPT/OPT 等大型預訓練語言模型雖然表現卓越，但 推論成本極高，常需多張高效能 GPU。
- 現有模型壓縮技術在應對這些 超大規模模型（如 GPT-175B）時效能與適用性受限。
- 方法核心
    - GPTQ 是一種新的 一次性（one-shot）權重量化方法。
    - 基於 近似二階資訊（approximate second-order information）。
    - 能有效將 GPT-175B 的權重量化至 3 或 4 bit，且 準確率幾乎無損。
    - 可在 約 4 小時 / 4 張 GPU 完成 175B 模型的量化。
- 壓縮效能
    - 相比以往的 one-shot 量化方法，壓縮率提升超過 2 倍。
    - 首次實現將 GPT-175B 單卡執行生成任務。
- 推論加速
    - 相比 FP16 模型，推論加速比：
        - NVIDIA A100：3.25 倍
        - NVIDIA A6000：4.5 倍
- 極端量化：
    - 也可應用在 2-bit 或 ternary（-1, 0, 1） 等極端情境，仍有可接受準確度。

### 現有壓縮技術的限制
- 傳統方法如稀疏化（sparsity）、剪枝（pruning）、或 retraining-based 量化成本過高，不適用於百億參數模型。
- 一次性（one-shot）後訓練量化（Post-Training Quantization, PTQ） 是一條可行方向：
    - 無需 retraining。
    - 但目前 PTQ 方案多數 僅能處理 8-bit 精度。
    - 先前的 work 如 RTN（round-to-nearest）在高壓縮比（如 3-bit）下 準確度大幅下降。

![image](https://hackmd.io/_uploads/SkClt_PLge.png)

## Related Work 
### 量化方法分類
- 兩大類量化方法：
    - 訓練中量化（Quantization-aware Training, QAT）
    - 在 retraining / finetuning 時量化參數。
    - 利用可微分的近似 rounding 操作（如 STE）。
    - 成本高、不適合百億參數模型。
- 後訓練量化（Post-training Quantization, PTQ）
    - 對 已訓練模型直接量化，只需少量資料與數小時計算。
    - 適合 無法 retrain 的超大模型（GPTQ 聚焦此類方法）。
### 大型語言模型的量化方法現況
**目前主流應用於 GPT-175B 或 BLOOM 類大型模型的方案包括：**

| 方法             | 技術概述與限制                                                                         |
| -------------- | ------------------------------------------------------------------------------- |
| **ZeroQuant**  | 使用 RTN（round-to-nearest）搭配 layer-wise distillation，但僅支持到 **1.3B** 模型；已耗時 \~3 小時 |
| **LLM.int8()** | 發現 activation outlier 是問題根源，保留部分 feature dimension 為高精度解決此問題                    |
| **nuQmm**      | 開發基於 binary-coding 的自定義 GPU kernel，以提升運算效率 

## Background 
### Layer-Wise Quantization（逐層量化）
- GPTQ 採用 逐層處理、層內優化 的後訓練量化策略，這與先前的 PTQ 方法類似（如 AdaRound、OBQ 等）。
- 基本目標為：對每個線性層，找到量化後權重 $\widehat{\mathbf{W}}$，使其對輸出誤差最小：

$$
\arg\min_{\widehat{\mathbf{W}}} \, \|\mathbf{W} \mathbf{X} - \widehat{\mathbf{W}} \mathbf{X}\|_2^2
$$
* 條件假設：

  * 量化 grid（即可選取的值）在優化前就已固定。
      * Quantization Grid : 定義「哪些值是允許的」。這些可被選擇的離散值
          * GPTQ 的流程會先為每一層的權重矩陣 $\mathbf{W}$ 決定一組固定的 quantization grid，接下來就只能從這組值中選出近似的替代值。
  * 權重可以自由移動至任一 grid 上的點（非固定 mapping）。
      * 每個權重不是「被迫」選最接近的格點，而是可以選擇任一格點，以最小化整體輸出誤差（通常是 layer 的 output MSE）。由一個全局最小誤差策略來決定該選哪個。

### Optimal Brain Quantization (OBQ) 方法簡介
**GPTQ 的技術建立於 OBQ 方法之上**
#### OBQ 的基本邏輯
- 逐行（row-wise）處理權重矩陣 $\mathbf{W}$。
    - 假設你有一個線性層的權重矩陣 $\mathbf{W}$，它的 shape 是 $(\text{out_features}, \text{in_features})$，也就是：
        - 一共有很多行，每一行 $\mathbf{w}$ 是對應一個輸出神經元的權重向量。
        - 先處理第 1 行 $\mathbf{w}\_1$（一個 output neuron 的權重），
        - 再處理第 2 行 $\mathbf{w}\_2$，
        - 以此類推。
- 對每一行 $\mathbf{w}$，每次只量化一個權重 $w_q$，並同時調整其餘尚未量化的權重（set $F$）以補償誤差。
    1. 假設這一行 $\mathbf{w}$ 有 10 個權重：$[w_1, w_2, ..., w_{10}]$
    2. 一開始都還是 full-precision 的（例如 float16），我們稱尚未量化的集合為 $F$（initially 是全體）。
    3. OBQ 每次只挑選一個「最適合先量化的權重」$w\_q$，這個選擇是根據量化後造成的 **誤差與補償能力** 來決定的（透過 Hessian 計算）。
    4. 一旦決定量化 $w\_q$，就會：
        - 把 $w\_q$ 量化到 grid 上的某個點（例如從 0.37 → 0.5）。
        - 同時根據公式計算一個補償量 $\boldsymbol{\delta}\_F$，**即時修正尚未量化的其餘權重**，讓整體 layer output 誤差最小化。
        - 然後把 $w\_q$ 從 $F$ 中移除，進入下一輪，直到這一行的所有權重都被量化。
- 使用二階資訊（Hessian）來決定最佳要量化的權重與補償更新量：
$$
w_q = \arg\min_{w_q} \frac{(\text{quant}(w_q) - w_q)^2}{[\mathbf{H}^{-1}]_{qq}}
$$

$$
\boldsymbol{\delta}_F = - \frac{w_q - \text{quant}(w_q)}{[\mathbf{H}^{-1}]_{qq}} \cdot (\mathbf{H}^{-1})_{:, q}
$$
其中 $\mathbf{H} = 2\mathbf{X}\_F\mathbf{X}\_F^\top$ 是 Hessian。

- 每次量化完一個 $w\_q$ 後，更新 Hessian 的逆矩陣：
$$
\mathbf{H}^{-1}_{-q} = \left(\mathbf{H}^{-1} - \frac{1}{[\mathbf{H}^{-1}]_{qq}} \mathbf{H}^{-1}_{:, q} \mathbf{H}^{-1}_{q, :} \right)_{-p}
$$


## The GPTQ Algorithm

### **Step 1：任意順序量化的洞察（Arbitrary Order Insight）**
* **OBQ 做法**：原本是根據「當下誤差最小」的方式，**貪婪（greedy）地選擇下一個要量化的權重**。
* **GPTQ 發現**：其實對於大型、參數多的 layer，「照固定順序」量化的效果 **幾乎跟 greedy order 一樣好**。
    * 解釋 : 被量化順序較後的「大誤差權重」，雖然最後才量化，但**此時已經沒剩多少可補償的權重**，所以效果也差不多。
    * 只要固定任意順序（如按列順序量化），**整體誤差差不了太多**。

#### 好處
- 原本 OBQ 是「每一行（row）各自做量化順序決策」，所以會產生 **每行一套自己的未量化權重集合 $F$ 和對應的 Hessian $\mathbf{H}\_F$**。
- 改為 **所有行共用同一個量化順序**（例如「第 1 列的所有 row weight 先量化」→「再量化第 2 列的所有 row weight」……）。
- 因為 $\mathbf{H}\_F$ **只與輸入 $\mathbf{X}\_F$ 有關**（所有行共享同一組輸入），因此：
    - $\mathbf{H}\_F^{-1}$ 可共用
    - **只需做 $d\_\text{col}$ 次更新，而不是 $d\_\text{row} \cdot d\_\text{col}$ 次。**

#### 結果
* GPTQ 量化計算量由：

$$
O(d_\text{row} \cdot d_\text{col}^3) \quad \Rightarrow \quad O(\max\{ d_\text{row} \cdot d_\text{col}^2, \; d_\text{col}^3 \})
$$

* 計算量減少了 **$\min{d\_\text{row}, d\_\text{col}}$ 倍**，對大型模型來說是數個數量級的加速。


### 更新 Hessian 的實作瓶頸
### Compute-to-Memory Ratio 過低：
### 解決方法 : Lazy Batch Updates（延遲批次更新） 
* 以公式：

  $$
  \mathbf{H}_{-q}^{-1} = \left( \mathbf{H}^{-1} - \frac{1}{[\mathbf{H}^{-1}]_{qq}} \mathbf{H}^{-1}_{:, q} \cdot \mathbf{H}^{-1}_{q, :} \right)_{-q}
  $$

  為例，

  * 雖然每次只需做幾個 FLOPs，
  * 但要對整個 $\mathbf{H}^{-1}$ 做更新（記憶體讀寫開銷大），導致 **運算速度被記憶體頻寬限制住**，GPU 無法發揮效能。

#### 作法
* 一次處理 $B = 128$ 個欄位（columns）：

  * 暫時**只更新 $B \times B$ 的區塊（block）**，在 $\mathbf{H}^{-1}$ 中只動用相關區域。
* 處理完這一批之後，再做一次完整的「全域」更新：

  * 更新整體的 $\mathbf{H}^{-1}$ 和 $\mathbf{W}$（權重矩陣）。

#### 使用的多權重更新公式（Batch 版 OBQ 更新）
給定一批欄位索引集合 $Q$，更新如下：

#### 1. 多個權重的補償更新量（原來是單個 $\delta\_F$，現在是 vector）：

$$
\boldsymbol{\delta}_F = -(\mathbf{w}_Q - \text{quant}(\mathbf{w}_Q)) \cdot ([\mathbf{H}_F^{-1}]_{QQ})^{-1} \cdot (\mathbf{H}_F^{-1})_{:, Q}
$$

#### 2. 多欄位的 inverse 更新：

$$
\mathbf{H}_{-Q}^{-1} = \left( \mathbf{H}^{-1} - \mathbf{H}^{-1}_{:, Q} \cdot ([\mathbf{H}^{-1}]_{QQ})^{-1} \cdot \mathbf{H}^{-1}_{Q, :} \right)_{-Q}
$$

這是原本 rank-1 的 outer product 更新，推廣成了 **rank-k 的更新（k 是 batch size）**
- 對於 GPT-175B 級別模型，實際速度提升約 10 倍（order of magnitude）



### Cholesky Reformulation
#### 觀察
* 在執行大模型（數十億參數以上）時，會出現：
  * $\mathbf{H}^{-1}$（Hessian 的 inverse）**變成非正定矩陣（indefinite）**
  * 導致量化過程中出現錯誤更新方向，**產生非常差的結果**
* 原因是：
  * **不斷重複更新** inverse（例如 group update 的公式）會累積浮點誤差
  * 尤其是涉及矩陣反轉與 outer product 的地方
* 在每次量化單個權重 $w\_q$ 時，我們其實**只需要 $\mathbf{H}\_F^{-1}$ 的第 $q$ 行**
* 所以不必儲存整個 $\mathbf{H}^{-1}$，而是可以：
  * **預先使用更穩定的方法只算需要的部分**
  * 並減少動態更新帶來的誤差

#### 實務觀察
* 小模型（< 1B 參數）可以透過簡單的 **對角線加小常數（dampening）** 避免這個問題
  * 做法是將 $\mathbf{H}$ 改為：$\mathbf{H} + \lambda \mathbf{I}$
  * 論文選擇 $\lambda = 0.01 \times \text{mean}(\text{diag}(\mathbf{H}))$
* 但對於大型模型（如 OPT-175B），這個方法已不足以保證穩定性


#### 關鍵 insight：

* 之前的 inverse 更新（inv-update）：

  $$
  \mathbf{H}_{-q}^{-1} = \mathbf{H}^{-1} - \frac{1}{[\mathbf{H}^{-1}]_{qq}} \mathbf{H}^{-1}_{:, q} \mathbf{H}^{-1}_{q, :}
  $$

  實際上和 Cholesky 分解的行為非常接近。

* Cholesky 分解可以穩定地取出矩陣的各行資訊，尤其適合處理 **對稱正定矩陣 $\mathbf{H}$**
#### GPTQ 改進方式

* 使用 **Cholesky kernel** 預先分解 $\mathbf{H}$，產出所有需要的行（尤其是主對角線起始的每一行）
* 所得資訊足以支持量化所需的所有誤差與補償計算
* 搭配輕度 dampening（仍加 $\lambda$）

![image](https://hackmd.io/_uploads/B1bQX9PIee.png)

## 實驗驗證
GPTQ 實驗設計包含:
1. **小模型比較**（ResNet、BERT-base、OPT-125M）→ 驗證精度與其他高準確量化法一致。
2. **大型模型延展性** → 測試 GPTQ 能否處理 BLOOM / OPT 全系列（包含 175B）。
3. **Perplexity 評估** → 語言生成任務的量化效果。
4. **Zero-shot 任務測試** → 驗證量化後的泛化能力。
5. **GPU 實務表現** → 實測能在 **單張 A100 GPU 上完成整個量化流程**。
6. **校準資料（calibration data）**:
    - 使用 C4 corpus 中的隨機 128 段文本（每段 2048 token）。
    - 全為 **非任務特定（task-agnostic）** → 完全 zero-shot。
7. 每次只載入一個 Transformer block（6 層）進行 Hessian 累積與量化。
8. 每完成一個 block 的量化，就把資料傳回，用來產生下一個 block 的輸入 → 提升效能且不耗太多記憶體。

### 對照方法
| 方法                              | 說明                           |
| ------------------------------- | ---------------------------- |
| **RTN**（round-to-nearest）       | LLM.int8() 使用的方法；速度快但精度一般    |
| **AdaRound / BRECQ / AdaQuant** | 高準確度、需大量 SGD 或優化步驟；在大型模型上不可行 |
| **OBQ**                         | GPTQ 的前身；精度高但不可擴展到數十億參數等級    |
| GPTQ                         | 同樣精度但可處理 175B 模型，只需幾小時       |


### 小模型測試結果（Quantizing Small Models）
![image](https://hackmd.io/_uploads/H1lODGjIge.png)

| 模型                       | GPTQ 表現                                   |
| ------------------------ | ----------------------------------------- |
| **ResNet-18 / 50**       | 4-bit 準確率與最佳方法持平，3-bit 稍弱但仍可接受（見 Table 1） |
| **BERT-base / OPT-125M** | GPTQ 與 OBQ 精度接近，有時甚至略優                    |
| **執行時間**                 | GPTQ 只需 **1 分鐘內**，其他方法通常需 **近 1 小時**      |

### GPTQ 對大型模型的運行時間（Runtime）

| 模型         | GPTQ 量化時間（單張 A100） |
| ---------- | ------------------ |
| OPT-13B    | 20.9 分鐘            |
| OPT-30B    | 44.9 分鐘            |
| OPT-66B    | 1.6 小時             |
| OPT-175B   | 4.2 小時             |
| BLOOM-176B | 3.8 小時             |

與之對比：
* **ZeroQuant-LKD**（類似 LLM.int8）→ 1.3B 模型需 3 小時

  * 若線性外推，175B 模型可能需要數百小時（甚至數週）
* **AdaRound / BRECQ** → 使用 SGD，開銷更高，不可行

GPTQ 為目前唯一能**在數小時內量化百億級模型**的高精度方法。


## 實驗：語言生成任務與 175B 級模型的表現
壓縮 OPT 與 BLOOM 全系列模型（最大至 175B / 176B）至 3-bit 和 4-bit，並在語言生成任務中比較 GPTQ 與傳統量化方法（如 RTN）的效能差異。
### 測試資料集
- WikiText-2
- Penn Treebank (PTB)：小型英文語料庫
- C4：大規模網頁語料，較泛用
- LAMBADA（LAMB.↑）：long-range 文本填空任務，指標為正確率 ↑

### GPTQ 對 OPT 模型的表現（WikiText-2）
![image](https://hackmd.io/_uploads/rJIQYfo8el.png)

結果可觀察
- 4-bit 模式下，幾乎無損失（0.03~0.2），RTN 則下降明顯。
- 3-bit 下，GPTQ 仍可用，而 RTN 幾乎全面崩潰（Perplexity 炸裂 > 1000）。
- 越大的模型（除了 OPT-66B）→ 越容易量化，這對於實際應用非常有利。

### GPTQ 對 BLOOM 模型的表現（WikiText-2）
![image](https://hackmd.io/_uploads/SJVyqGjLlx.png)

結果可觀察
- GPTQ 在 3-bit 和 4-bit 下均優於 RTN。
- BLOOM 整體上 比 OPT 更容易量化，推測模型內部更穩定（例如較少 dead units）。

### 模型越大越容易壓縮？
結果顯示
- 大模型（如 OPT-175B、BLOOM-176B）比小模型更容易量化且維持精度。
- OPT-66B 是例外，因為前幾層存在許多 "dead units"（神經元沒有啟動），導致難以壓縮。

### 175B 級模型實驗總結
![image](https://hackmd.io/_uploads/HJdF9fsUel.png)
- GPTQ 在 4-bit 時幾乎與原始模型一致，甚至在某些任務（如 LAMBADA）上有微小提升。
- RTN 在高壓縮下精度快速惡化，甚至完全不可用（如 3-bit）。

## 實用性加速
![image](https://hackmd.io/_uploads/SyMKnfj8gg.png)

### 案例：OPT-175B 在 3-bit 下的部署
* **總記憶體需求：63GB**
  * 3-bit 量化權重
  * Embedding + output layer 維持 FP16（未量化）
  * 加上 2048 token 的 KV-cache：約 9GB
* 每次生成 1 個 token，需要大量的 matrix-vector 運算，瓶頸來自記憶體頻寬，不是計算單位

### token latency 實驗（序列長度 128）
- 越便宜的 GPU（如 A6000）頻寬越小 → GPTQ 的記憶體節省效果越明顯

### 零樣本任務效能分析
![image](https://hackmd.io/_uploads/BypGpGsUxl.png)
**任務**：
* LAMBADA（long-range completion）
* ARC-Easy / ARC-Challenge（推理與邏輯）
* PIQA（物理常識）

**結果:**
* **4-bit 下 GPTQ 與 RTN 都還可以使用**
* **3-bit 下只有 GPTQ 保持可用，RTN 完全崩潰**
* GPTQ 跨多種任務皆穩定

## 結論
- GPTQ 方法總結
    - 基於近似二階資訊的後訓練量化，針對百億到千億參數級模型（如 OPT-175B、BLOOM-176B）。
    - 可將模型精度壓縮至 3 – 4 bit，精度幾乎無損，並實現顯著的可用性與推理加速。
    - 端到端加速：動態反量化核減少記憶體帶寬瓶頸，Token 生成速度提升 3× – 4.5×。
    - 在 2-bit、甚至 ternary 情況下仍保持合理效能。
- 限制
    - 未量化 activation，僅 focus 於權重；激活量化和運算核優化是後續可推進的方向。


## 附錄
## 背景複習

對一個 layer 的某一行權重 $\mathbf{w} \in \mathbb{R}^d$ 進行量化，使得 layer output 誤差最小。

目標誤差是：

$$
\min_{\widehat{\mathbf{w}}} \| \mathbf{w}^\top \mathbf{X} - \widehat{\mathbf{w}}^\top \mathbf{X} \|_2^2
$$

也就是：

$$
\min_{\widehat{\mathbf{w}}} \| (\mathbf{w} - \widehat{\mathbf{w}})^\top \mathbf{X} \|_2^2 = \| \Delta \mathbf{w}^\top \mathbf{X} \|_2^2
$$

令 $\Delta \mathbf{w} = \mathbf{w} - \widehat{\mathbf{w}}$ 是誤差向量。

---

## Step 1: 寫成二次誤差形式（Quadratic Loss）

$$
L(\Delta \mathbf{w}) = \| \Delta \mathbf{w}^\top \mathbf{X} \|_2^2 = \Delta \mathbf{w}^\top \mathbf{X} \mathbf{X}^\top \Delta \mathbf{w}
$$

這是標準的 quadratic form，對應的 Hessian 就是：

$$
\mathbf{H} = 2 \mathbf{X} \mathbf{X}^\top
$$

這邊取 2 是因為數學上 $L = \frac{1}{2} \Delta w^\top H \Delta w$ 時微分比較乾淨，不影響最小化目標。

---

## Step 2: 只量化一個 $w\_q$，其他還是 float

我們要選出一個「最該先量化的參數 $w\_q$」並補償其他沒被量化的權重 $w\_f$（$f \in F$）。

所以要看：如果量化 $w\_q \rightarrow \hat{w}\_q$，會造成多少影響？我們希望挑那個「對總誤差影響最小」的 $w\_q$。

---

## Step 3: 推出哪個權重最值得先量化

考慮原始的 quadratic 誤差項，根據二階泰勒展開，若你只動一個權重 $w\_q$，造成的誤差會是：

$$
L \approx \frac{1}{2} (\text{quant}(w_q) - w_q)^2 \cdot H_{qq}
$$

但我們不想重算 $H$，所以改用逆矩陣 $H^{-1}$，我們可以得到一個標準化誤差：

$$
\frac{(\text{quant}(w_q) - w_q)^2}{[\mathbf{H}^{-1}]_{qq}}
$$

這就是 GPTQ/OBQ 用的 **最小化誤差選擇指標**。
越小，表示你能「很便宜地量化掉這個參數」，而且後面能補償得很好。

所以：

$$
w_q = \arg\min_{q} \frac{(\text{quant}(w_q) - w_q)^2}{[\mathbf{H}^{-1}]_{qq}}
$$

---

## Step 4: 計算如何補償剩下權重（誤差分散）

一旦量化了 $w\_q$，我們希望其他權重能做些微調，來彌補這次量化帶來的誤差。

「在保持 $\Delta w\_q$ 為已知值的情況下，如何調整其餘 $\Delta w\_f$ 來讓整體誤差最小？」

解法是：

$$
\boldsymbol{\delta}_F = - \frac{w_q - \text{quant}(w_q)}{[\mathbf{H}^{-1}]_{qq}} \cdot (\mathbf{H}^{-1})_{:, q}
$$

這是 **高斯消去法** + **最小平方誤差補償** 的結果。
意思 : 固定了 $w\_q$，其他權重怎麼調整才能讓誤差降低最快。