{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "WI5th8d51aUs" }, "source": [ "# FABQ-RC: Fisher-Adaptive Binary Quantization with Residual Codebooks\n", "\n", "
\n", "Zach Maronek · Research Notebook · April 2026\n", "
\n", "\n", "---\n", "\n", "## The Problem Fixed Blocksizes Get Wrong\n", "\n", "Every 1-bit quantization method — Q1_0_g128, BiLLM, GPTQ — uses a single blocksize for all layers. But weight distributions aren't uniform. A layer with homogeneous weights (e.g., embedding projections) can tolerate 256-wide blocks. A layer with heterogeneous weights (e.g., attention projections) needs 16-wide blocks to preserve important weight combinations.\n", "\n", "**A single blocksize is always the wrong compromise for some layers.**\n", "\n", "FABQ-RC fixes this with four innovations:\n", "\n", "| Stage | Innovation |\n", "|-------|-----------|\n", "| 1. Fisher-Weighted Importance | Which channels actually matter for loss? |\n", "| 2. Mixed-Precision Allocation | int8 for critical channels, binary for the rest |\n", "| 3. Adaptive Blocksize | Per-layer blocksize selection, not global |\n", "| 4. Residual Codebook | k-means corrects systematic binary bias |\n", "\n", "**Target:** ~1.15–1.20 bpw, beating BiLLM on quality\n", "\n", "---\n", "**Contents:** [1. Setup](#1) · [2. Method](#2) · [3. Implementation](#3) · [4. Evaluation](#4) · [5. Results Dashboard](#5) · [6. Starfire Integration](#6)" ] }, { "cell_type": "markdown", "metadata": { "id": "5vwJTc0-1aUu" }, "source": [ "\n", "## 1. Setup & Imports\n", "\n", "*Running on A100 80GB · ~1-2 hours total*" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "5A5ciM4c1aUv", "outputId": "d304a518-5b1d-46d3-8b78-17050ae38128" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Installing build dependencies ... \u001b[?25l\u001b[?25hdone\n", " Getting requirements to build wheel ... \u001b[?25l\u001b[?25hdone\n", " Preparing metadata (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n", "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m60.7/60.7 MB\u001b[0m \u001b[31m43.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m:00:01\u001b[0m00:01\u001b[0m\n", "\u001b[?25h Building wheel for transformers (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n", "✅ Device: cuda\n", "✅ GPU: NVIDIA A100-SXM4-80GB\n", "✅ VRAM: 85.1 GB\n" ] } ], "source": [ "# Core dependencies\n", "!pip install -q git+https://github.com/huggingface/transformers.git torch accelerate bitsandbytes scikit-learn\n", "!pip install -q pandas numpy tqdm matplotlib seaborn datasets\n", "\n", "import os, math, json, time\n", "import numpy as np\n", "import torch\n", "import torch.nn as nn\n", "import torch.nn.functional as F\n", "from torch.utils.data import DataLoader\n", "from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline\n", "from sklearn.cluster import MiniBatchKMeans\n", "from sklearn.decomposition import PCA\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "from tqdm.auto import tqdm\n", "import warnings\n", "warnings.filterwarnings('ignore')\n", "\n", "DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'\n", "os.environ['TOKENIZERS_PARALLELISM'] = 'false'\n", "\n", "print(f\"✅ Device: {DEVICE}\")\n", "if torch.cuda.is_available():\n", " print(f\"✅ GPU: {torch.cuda.get_device_name(0)}\")\n", " print(f\"✅ VRAM: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f} GB\")" ] }, { "cell_type": "markdown", "metadata": { "id": "cPsRms0K1aUv" }, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": { "id": "JTxvoEQl1aUw" }, "source": [ "\n", "## 2. The FABQ-RC Method\n", "\n", "### 2.1 Why Fisher Information > Hessian > Magnitude\n", "\n", "Quantization importance can be measured three ways:\n", "\n", "| Metric | What it measures | Problem |\n", "|--------|-----------------|---------|\n", "| **Magnitude** | Weight absolute value | Big weights aren't always important |\n", "| **Hessian** | Loss curvature at current θ | Local only, expensive to compute |\n", "| **Fisher** | Expected gradient² over data | Captures average importance, tractable |\n", "\n", "FABQ-RC uses Fisher Information because it's the most directly tied to loss impact from quantization.\n", "\n", "```\n", "F_i ≈ (1/N) Σ_n (∂L_n / ∂w_i)² — gradient² as Fisher proxy\n", "```\n", "\n", "### 2.2 Four Stages Visualized\n", "\n", "```\n", " ┌───────────────────────────────────┐\n", " │ FP32 WEIGHTS │\n", " └──────────────┬────────────────────┘\n", " ▼\n", " ┌─────────────────────────────────────┐\n", " Stage 1 │ FISHER-WEIGHTED CHANNEL IMPORTANCE │\n", " │ Per output channel: F_j = Σ(grad²) │\n", " │ Sort channels descending by F_j │\n", " └──────────────┬────────────────────┘\n", " ▼\n", " ┌─────────────────────────────────────┐\n", " Stage 2 │ MIXED-PRECISION CORE ALLOCATION │\n", " │ Top 5% channels → int8 (preserve) │\n", " │ Bottom 95% → binary ±1 (compact) │\n", " └──────────────┬────────────────────┘\n", " ▼\n", " ┌─────────────────────────────────────┐\n", " Stage 3 │ ADAPTIVE BLOCKSIZE SELECTION │\n", " │ Sweep {16, 32, 64, 128, 256} │\n", " │ Pick blocksize minimizing recon err│\n", " └──────────────┬────────────────────┘\n", " ▼\n", " ┌─────────────────────────────────────┐\n", " Stage 4 │ RESIDUAL CODEBOOK │\n", " │ r = W - Ŵ (quantization residual) │\n", " │ k-means on residual blocks │\n", " │ 256 centroids, shared across layers│\n", " └──────────────┬────────────────────┘\n", " ▼\n", " ┌─────────────────────────────────────┐\n", " │ FABQ-RC QUANTIZED MODEL │\n", " │ ~1.15–1.20 bits/parameter │\n", " └─────────────────────────────────────┘\n", "```\n", "\n", "### 2.3 Why the Residual Codebook Beats Linear Approximation\n", "\n", "BiLLM approximates residuals as a linear function of the weight value. This misses nonlinear systematic errors that binary quantization introduces.\n", "\n", "FABQ-RC's k-means codebook:\n", "- **Non-linear**: No assumption about functional form\n", "- **Discrate**: Captures arbitrary residual patterns\n", "- **Shared**: One codebook across all layers (same blocksize → same residual structure)\n", "- **Compact**: 256 × 128 × 4 bytes = 128KB overhead, negligible" ] }, { "cell_type": "markdown", "metadata": { "id": "IxruUrRh1aUw" }, "source": [ "\n", "## 3. Implementation\n", "\n", "### 3.1 Load Model & Prepare Calibration Data" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "id": "HLI_6src1aUw" }, "outputs": [ { "ename": "TimeoutException", "evalue": "Requesting secret HF_TOKEN timed out. Secrets can only be fetched when running from the Colab UI.", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTimeoutException\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_603/3208678808.py\u001b[0m in \u001b[0;36m