---
# System prepended metadata

title: '論文閱讀 : SmoothQuant'

---

# 論文閱讀 : 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
![image](https://hackmd.io/_uploads/BkT4kY2Ugg.png)

#### 核心創新

* **觀察**：儘管 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）
![image](https://hackmd.io/_uploads/SJTv4t3Ueg.png)

| 類型              | 說明                                           |
| --------------- | -------------------------------------------- |
| **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 效果的量化方式。** 

## 論文核心方法論
### **核心想法：轉換張量來遷移量化困難**
![image](https://hackmd.io/_uploads/ByTN1j38lx.png)

### **平滑 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）**
![image](https://hackmd.io/_uploads/Byluyj38eg.png)

$$
\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 上
![image](https://hackmd.io/_uploads/SkIxei2Leg.png)
> 將 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**

### 實驗結果整理
![image](https://hackmd.io/_uploads/Hkw9GonLxx.png)
| 方法                                     | 表現                                       |
| -------------------------------------- | ---------------------------------------- |
| **SmoothQuant**                        | 在所有量化策略下均可 **匹配 FP16 精度**                |
| **LLM.int8()**                         | 也能保留精度，但**需要浮點表示 outliers**，導致延遲變高       |
| W8A8 / ZeroQuant / Outlier Suppression | 幾乎失效，輸出接近隨機 → 證明 LLM 的 activation 很難直接量化 |

**結論**：SmoothQuant 是唯一能在不犧牲精度、又不增加延遲的情況下成功量化 OPT-175B 的方法。

### 不同模型的量化難度比較
![image](https://hackmd.io/_uploads/rkiHFsh8le.png)
| 模型         | 量化難度 | 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**
![image](https://hackmd.io/_uploads/HkeRFonIxx.png)
* 測試對象：**OPT-IML-30B**
* 資料集：WikiText-2、LAMBADA
* SmoothQuant 表現：
  * 成功保持精度，W8A8 量化可穩定使用
* 備註：
  * 雖然是 instruction-tuned，但架構與 pretraining 相近 → 方法仍然適用
    
### **LLaMA 模型**
![image](https://hackmd.io/_uploads/BJEQ5ih8xx.png)
* 實驗對象：LLaMA 1 系列
* 觀察：
  * LLaMA activation 的 outlier 現象 **比 OPT / BLOOM 輕微**
  * SmoothQuant 依然可以做到 **W8A8 量化，且幾乎無性能損失**
    
### **更多新模型：LLaMA-2, Falcon, Mistral, Mixtral**
![image](https://hackmd.io/_uploads/S1DO5jn8ex.png)
結論：SmoothQuant 是一個具 **架構廣泛適用性** 的量化方法，**連 MoE 模型都能保持效能**
    
    
### Speedup, Memory Saving
![image](https://hackmd.io/_uploads/Byq2ionUgg.png)
#### 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 可平行）
![image](https://hackmd.io/_uploads/By6Xni3Uxl.png)
| 模型             | SmoothQuant-O3 效果                                      |
| -------------- | ------------------------------------------------------ |
| OPT-13B / 30B  | 單 GPU 加速最多可達 **1.56×**                                 |
| OPT-66B / 175B | 可使用**一半的 GPU 數量達到相同或更快的 latency**（例：OPT-175B 僅需 4 GPU） |
| 記憶體使用       | 降低至原來的 **約 1/2**，利於在資源有限的伺服器上部署大型模型                    |
    
### Decoding 階段效能（逐 token 預測）
![image](https://hackmd.io/_uploads/B1w9633Ilg.png)
| 比較項目                 | SmoothQuant vs. FP16    |
| -------------------- | ----------------------- |
| Per-token latency | 最多可減少 **1.42× latency** |
| 記憶體               | 同樣可節省 **約一半的記憶體使用量**    |

### Ablation Study
### Quantization Scheme 粒度對效能的影響
![image](https://hackmd.io/_uploads/SkXgbT3Uee.png)
| 粒度級別（O1 → O3）        | 越粗 → latency 越低                           |
| -------------------- | ----------------------------------------- |
| Dynamic Quantization | 有 runtime overhead（需要在線計算 scale）          |
| Static Quantization  | **推薦**（速度更快，尤其適合部署）                       |
| Overall 建議           | **使用 O3（per-tensor static）在可接受精度損失下效能最佳** |

### 遷移強度 α 的選擇（activation ↔ weight 難度平衡）
![image](https://hackmd.io/_uploads/rJ2AZThUxl.png)

| α 值          | 量化難點           | 效果               |
| ------------ | -------------- | ---------------- |
| < 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 之間 → 都比較好量化，誤差小