Instructions to use LittleBitLLM/littlebit with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use LittleBitLLM/littlebit with Transformers:
# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("LittleBitLLM/littlebit", device_map="auto") - Notebooks
- Google Colab
- Kaggle
LittleBit: recipe and throughput (weights coming soon)
Browse files- README.md +94 -0
- assets/banner.png +0 -0
- recipe/eval.sh +25 -0
- recipe/patches/eval-import-fix.patch +20 -0
- recipe/patches/teacher-on-gpu.patch +44 -0
- recipe/setup.sh +65 -0
- recipe/train.sh +70 -0
- recipe/zero3_nooffload.json +45 -0
README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: cc-by-nc-4.0
|
| 3 |
+
base_model: Qwen/Qwen3-8B
|
| 4 |
+
base_model_relation: quantized
|
| 5 |
+
library_name: transformers
|
| 6 |
+
tags: [littlebit, littlebit-2, sub-1-bit, quantization, qat, qwen3]
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+

|
| 10 |
+
|
| 11 |
+
# LittleBit
|
| 12 |
+
|
| 13 |
+
**Big models. Little bits.** Sub-1-bit Qwen3 models built with LittleBit-2:
|
| 14 |
+
binarized latent factorization, recovered by distillation from the original model.
|
| 15 |
+
|
| 16 |
+
> **Status: weights coming soon.** This repo holds the training recipe and measured
|
| 17 |
+
> throughput. Model weights and eval results will be added here when the first full
|
| 18 |
+
> training run finishes. Follow [@LittleBit_llm](https://x.com/LittleBit_llm) for updates.
|
| 19 |
+
|
| 20 |
+
> Independent community project. Not affiliated with or endorsed by Samsung Research.
|
| 21 |
+
> Built on the LittleBit method and code by Lee, Kim, You & Kim ([SamsungLabs/LittleBit](https://github.com/SamsungLabs/LittleBit)).
|
| 22 |
+
|
| 23 |
+
## Planned releases
|
| 24 |
+
|
| 25 |
+
| Model | Base | Target bpw | Status |
|
| 26 |
+
|---|---|---|---|
|
| 27 |
+
| littlebit-qwen3-4b | Qwen/Qwen3-4B | 0.55 | planned |
|
| 28 |
+
| littlebit-qwen3-8b | Qwen/Qwen3-8B | 0.55 | planned |
|
| 29 |
+
| littlebit-qwen3-14b | Qwen/Qwen3-14B | 0.55 | planned |
|
| 30 |
+
|
| 31 |
+
Bits per weight apply to linear layers. Embeddings and `lm_head` stay BF16.
|
| 32 |
+
|
| 33 |
+
## Method
|
| 34 |
+
|
| 35 |
+
Each linear layer `W` is approximated as `sign(U) · diag(h·g·ℓ) · sign(V)ᵀ`:
|
| 36 |
+
low-rank latent factors binarized to ±1, plus three thin learned scale vectors.
|
| 37 |
+
|
| 38 |
+
1. **Latent factorization:** SVD splits each linear layer into rank-r factors sized to the bit budget.
|
| 39 |
+
2. **Joint-ITQ rotation (LittleBit-2):** aligns the factors with the binary hypercube before training. It folds into the factors, so it adds no inference cost.
|
| 40 |
+
3. **SmoothSign binarization:** a smooth surrogate gradient keeps the sign step trainable.
|
| 41 |
+
4. **Residual compensation:** a second binarized path learns what the first one missed.
|
| 42 |
+
5. **Distillation:** quantization-aware training on C4 + WikiText-2 (seq len 2048), with the BF16 model as teacher (logit KL + layer-to-layer MSE).
|
| 43 |
+
|
| 44 |
+
## Measured throughput
|
| 45 |
+
|
| 46 |
+
Measured on RunPod with the recipe in [`recipe/`](recipe/). One step = 4 sequences × 2048 tokens.
|
| 47 |
+
One epoch of the C4-shard-0 + WikiText-2 mix is about 20,750 steps with the Qwen3 tokenizer.
|
| 48 |
+
|
| 49 |
+
| Model | GPU | Sec / step | Peak VRAM | One-time init (SVD + Joint-ITQ) | Est. 1 epoch |
|
| 50 |
+
|---|---|---:|---:|---:|---:|
|
| 51 |
+
| Qwen3-0.6B @ 0.55 bpw | 1× H100 80GB | 1.03 | — | ~2.3 min | ~6 h |
|
| 52 |
+
| Qwen3-8B @ 0.55 bpw | 1× H200 141GB | 2.84 | ~107 GB | ~14 min | ~16.5 h |
|
| 53 |
+
|
| 54 |
+
Qwen3-8B does not fit on a single 80 GB GPU: about 3.7B latent parameters are trainable,
|
| 55 |
+
and their optimizer state alone exceeds the memory. Use a 141 GB GPU or ≥ 2 GPUs with ZeRO-3.
|
| 56 |
+
|
| 57 |
+
## Recipe
|
| 58 |
+
|
| 59 |
+
[`recipe/`](recipe/) runs the official LittleBit code on a RunPod GPU pod:
|
| 60 |
+
|
| 61 |
+
- `setup.sh`: clones SamsungLabs/LittleBit at a pinned commit, applies the patches, and installs dependencies (`transformers==4.51.*`, DeepSpeed).
|
| 62 |
+
- `train.sh`: runs QAT. Defaults: Qwen3-8B, 0.55 bpw, LittleBit-2 init, SmoothSign, residual. Override settings with env vars (`MODEL_ID`, `EFF_BIT`, `EPOCHS`, `NUM_GPUS`, …).
|
| 63 |
+
- `eval.sh`: measures WikiText-2/C4 perplexity and zero-shot accuracy (lm-eval).
|
| 64 |
+
- `zero3_nooffload.json`: multi-GPU ZeRO-3 config without CPU offload.
|
| 65 |
+
- `patches/teacher-on-gpu.patch`: keeps the teacher on GPU instead of ZeRO-3 CPU offload (`--teacher_offload False`).
|
| 66 |
+
- `patches/eval-import-fix.patch`: fixes a circular import between lm-eval, transformers, and DeepSpeed in `eval.py`.
|
| 67 |
+
|
| 68 |
+
```bash
|
| 69 |
+
bash recipe/setup.sh
|
| 70 |
+
MODEL_ID=Qwen/Qwen3-8B EFF_BIT=0.55 EPOCHS=1 bash recipe/train.sh
|
| 71 |
+
CKPT=/workspace/outputs/littlebit-qwen3-8b-0.55bpw bash recipe/eval.sh
|
| 72 |
+
```
|
| 73 |
+
|
| 74 |
+
## License
|
| 75 |
+
|
| 76 |
+
CC BY-NC 4.0 (non-commercial), inherited from the LittleBit code. Released weights
|
| 77 |
+
are also subject to the base model's license (Qwen3: Apache 2.0).
|
| 78 |
+
|
| 79 |
+
## Citation
|
| 80 |
+
|
| 81 |
+
```bibtex
|
| 82 |
+
@inproceedings{lee2025littlebit,
|
| 83 |
+
title = {LittleBit: Ultra Low-Bit Quantization via Latent Factorization},
|
| 84 |
+
author = {Lee, Banseok and Kim, Dongkyu and You, Youngcheon and Kim, Youngmin},
|
| 85 |
+
booktitle = {NeurIPS},
|
| 86 |
+
year = {2025}
|
| 87 |
+
}
|
| 88 |
+
@inproceedings{lee2026littlebit2,
|
| 89 |
+
title = {LittleBit-2: Maximizing the Spectral Energy Gain in Sub-1-Bit LLMs via Latent Geometry Alignment},
|
| 90 |
+
author = {Lee, Banseok and Kim, Youngmin},
|
| 91 |
+
booktitle = {ICML},
|
| 92 |
+
year = {2026}
|
| 93 |
+
}
|
| 94 |
+
```
|
assets/banner.png
ADDED
|
recipe/eval.sh
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# Evaluate a trained LittleBit checkpoint (perplexity + zero-shot).
|
| 3 |
+
# CKPT=/workspace/outputs/Qwen2.5-0.5B-1.0bpw bash eval.sh
|
| 4 |
+
# Set FP_BASELINE=1 with CKPT=<hf model id> to score the original FP16 model.
|
| 5 |
+
set -euo pipefail
|
| 6 |
+
|
| 7 |
+
WORKDIR="${WORKDIR:-/workspace}"
|
| 8 |
+
CKPT="${CKPT:?set CKPT to a checkpoint dir or HF model id}"
|
| 9 |
+
ZEROSHOT="${ZEROSHOT:-boolq,piqa,hellaswag,winogrande,arc_easy,arc_challenge,openbookqa}"
|
| 10 |
+
|
| 11 |
+
export HF_HOME="$WORKDIR/hf_cache"
|
| 12 |
+
# shellcheck disable=SC1091
|
| 13 |
+
source "$WORKDIR/venv/bin/activate"
|
| 14 |
+
cd "$WORKDIR/LittleBit"
|
| 15 |
+
mkdir -p "$WORKDIR/logs"
|
| 16 |
+
|
| 17 |
+
EXTRA=()
|
| 18 |
+
if [ "${FP_BASELINE:-0}" = "1" ]; then EXTRA+=(--fp_eval True); fi
|
| 19 |
+
|
| 20 |
+
CUDA_VISIBLE_DEVICES=0 python eval.py \
|
| 21 |
+
--model_id "$CKPT" \
|
| 22 |
+
--seqlen 2048 \
|
| 23 |
+
--ppl_task wikitext2,c4 \
|
| 24 |
+
--zeroshot_task "$ZEROSHOT" \
|
| 25 |
+
"${EXTRA[@]}" 2>&1 | tee "$WORKDIR/logs/eval-$(basename "$CKPT")-$(date +%Y%m%d-%H%M).log"
|
recipe/patches/eval-import-fix.patch
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
diff --git a/eval.py b/eval.py
|
| 2 |
+
index 446b1ed..84b3355 100644
|
| 3 |
+
--- a/eval.py
|
| 4 |
+
+++ b/eval.py
|
| 5 |
+
@@ -4,6 +4,15 @@ import json
|
| 6 |
+
import torch
|
| 7 |
+
import torch._dynamo
|
| 8 |
+
import torch.nn as nn
|
| 9 |
+
+
|
| 10 |
+
+# Import deepspeed before lm_eval/transformers (as main.py does). Otherwise
|
| 11 |
+
+# transformers.modeling_utils imports deepspeed mid-init and deepspeed's
|
| 12 |
+
+# import of transformers.models.opt hits a circular import.
|
| 13 |
+
+try:
|
| 14 |
+
+ import deepspeed # noqa: F401
|
| 15 |
+
+except ImportError:
|
| 16 |
+
+ pass
|
| 17 |
+
+
|
| 18 |
+
from lm_eval import evaluator
|
| 19 |
+
from tqdm import tqdm
|
| 20 |
+
from transformers import AutoTokenizer, AutoModelForCausalLM
|
recipe/patches/teacher-on-gpu.patch
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
diff --git a/main.py b/main.py
|
| 2 |
+
index d5f6810..d30ecb2 100644
|
| 3 |
+
--- a/main.py
|
| 4 |
+
+++ b/main.py
|
| 5 |
+
@@ -83,6 +83,9 @@ def get_args():
|
| 6 |
+
|
| 7 |
+
parser.add_argument("--use_itq", type=str2bool, default=False)
|
| 8 |
+
parser.add_argument("--itq_n_iter", type=int, default=50)
|
| 9 |
+
+ parser.add_argument("--teacher_offload", type=str2bool, default=True,
|
| 10 |
+
+ help="True: teacher via DeepSpeed ZeRO-3 with CPU param offload (upstream). "
|
| 11 |
+
+ "False: full bf16 teacher copy resident on each GPU (faster, needs VRAM).")
|
| 12 |
+
|
| 13 |
+
args = parser.parse_args()
|
| 14 |
+
|
| 15 |
+
@@ -142,7 +145,29 @@ def load_student_model(args, device_map, torch_dtype):
|
| 16 |
+
return model
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
+def load_teacher_on_gpu(args, torch_dtype):
|
| 20 |
+
+ local_rank = int(os.environ.get("LOCAL_RANK", 0))
|
| 21 |
+
+ device = torch.device(f"cuda:{local_rank}")
|
| 22 |
+
+
|
| 23 |
+
+ teacher_model = AutoModelForCausalLM.from_pretrained(
|
| 24 |
+
+ args.model_id,
|
| 25 |
+
+ torch_dtype=torch_dtype,
|
| 26 |
+
+ low_cpu_mem_usage=True,
|
| 27 |
+
+ trust_remote_code=True,
|
| 28 |
+
+ ).to(device)
|
| 29 |
+
+ teacher_model.eval()
|
| 30 |
+
+ for param in teacher_model.parameters():
|
| 31 |
+
+ param.requires_grad = False
|
| 32 |
+
+ teacher_model.config.use_cache = False
|
| 33 |
+
+
|
| 34 |
+
+ logger.info(f"Teacher resident on {device} (no offload)")
|
| 35 |
+
+ return teacher_model
|
| 36 |
+
+
|
| 37 |
+
+
|
| 38 |
+
def load_teacher_model(args, num_gpus, torch_dtype, config_path="configs/zero3_inference.json"):
|
| 39 |
+
+ if not args.teacher_offload:
|
| 40 |
+
+ return load_teacher_on_gpu(args, torch_dtype)
|
| 41 |
+
+
|
| 42 |
+
with open(config_path, 'r') as f:
|
| 43 |
+
config = json.load(f)
|
| 44 |
+
|
recipe/setup.sh
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# One-time setup for LittleBit on a RunPod GPU pod.
|
| 3 |
+
# Run from the pod terminal: bash /workspace/runpod/setup.sh
|
| 4 |
+
set -euo pipefail
|
| 5 |
+
|
| 6 |
+
WORKDIR="${WORKDIR:-/workspace}"
|
| 7 |
+
REPO_DIR="$WORKDIR/LittleBit"
|
| 8 |
+
VENV_DIR="$WORKDIR/venv"
|
| 9 |
+
|
| 10 |
+
# Keep every cache on the persistent volume so it survives pod restarts.
|
| 11 |
+
export HF_HOME="$WORKDIR/hf_cache"
|
| 12 |
+
export PIP_CACHE_DIR="$WORKDIR/pip_cache"
|
| 13 |
+
|
| 14 |
+
echo ">> GPU check"
|
| 15 |
+
nvidia-smi --query-gpu=name,memory.total --format=csv || { echo "No NVIDIA GPU found"; exit 1; }
|
| 16 |
+
|
| 17 |
+
echo ">> System packages (mpi4py needs OpenMPI headers)"
|
| 18 |
+
apt-get update -qq && apt-get install -y -qq libopenmpi-dev git >/dev/null
|
| 19 |
+
|
| 20 |
+
if [ ! -d "$REPO_DIR" ]; then
|
| 21 |
+
echo ">> Cloning LittleBit"
|
| 22 |
+
git clone https://github.com/SamsungLabs/LittleBit.git "$REPO_DIR"
|
| 23 |
+
# Pin the commit the patches were written against.
|
| 24 |
+
git -C "$REPO_DIR" checkout -q 42d658b
|
| 25 |
+
fi
|
| 26 |
+
|
| 27 |
+
echo ">> Applying local patches"
|
| 28 |
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
| 29 |
+
for p in "$SCRIPT_DIR"/patches/*.patch; do
|
| 30 |
+
if git -C "$REPO_DIR" apply --reverse --check "$p" 2>/dev/null; then
|
| 31 |
+
echo " already applied: $(basename "$p")"
|
| 32 |
+
else
|
| 33 |
+
git -C "$REPO_DIR" apply "$p" && echo " applied: $(basename "$p")"
|
| 34 |
+
fi
|
| 35 |
+
done
|
| 36 |
+
|
| 37 |
+
echo ">> Python venv (inherits the pod's preinstalled CUDA torch)"
|
| 38 |
+
python3 -m venv --system-site-packages "$VENV_DIR"
|
| 39 |
+
# shellcheck disable=SC1091
|
| 40 |
+
source "$VENV_DIR/bin/activate"
|
| 41 |
+
pip install -q --upgrade pip
|
| 42 |
+
|
| 43 |
+
# requirements.txt pins torch==2.6.0, which would replace the pod's CUDA build.
|
| 44 |
+
# Install everything except torch, then the versions the README asks for.
|
| 45 |
+
grep -viE '^torch(==|$)' "$REPO_DIR/requirements.txt" > /tmp/req-notorch.txt
|
| 46 |
+
pip install -q -r /tmp/req-notorch.txt
|
| 47 |
+
pip install -q "transformers==4.51.*" deepspeed wandb
|
| 48 |
+
|
| 49 |
+
echo ">> Sanity check"
|
| 50 |
+
python - <<'PY'
|
| 51 |
+
import torch, transformers, deepspeed
|
| 52 |
+
print("torch", torch.__version__, "cuda", torch.version.cuda, "available", torch.cuda.is_available())
|
| 53 |
+
print("transformers", transformers.__version__, "deepspeed", deepspeed.__version__)
|
| 54 |
+
for i in range(torch.cuda.device_count()):
|
| 55 |
+
print(" gpu", i, torch.cuda.get_device_name(i))
|
| 56 |
+
assert torch.cuda.is_available(), "CUDA not available"
|
| 57 |
+
PY
|
| 58 |
+
|
| 59 |
+
cat <<EOF
|
| 60 |
+
|
| 61 |
+
Setup done. Next:
|
| 62 |
+
export HF_TOKEN=hf_xxx # needed for gated models like Llama-2
|
| 63 |
+
export WANDB_API_KEY=xxx # optional; without it, REPORT=tensorboard is used
|
| 64 |
+
bash $WORKDIR/runpod/train.sh
|
| 65 |
+
EOF
|
recipe/train.sh
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# LittleBit QAT training on RunPod. Override any setting via env vars, e.g.
|
| 3 |
+
# MODEL_ID=Qwen/Qwen3-14B EFF_BIT=0.55 EPOCHS=5 bash train.sh
|
| 4 |
+
set -euo pipefail
|
| 5 |
+
|
| 6 |
+
WORKDIR="${WORKDIR:-/workspace}"
|
| 7 |
+
REPO_DIR="$WORKDIR/LittleBit"
|
| 8 |
+
|
| 9 |
+
MODEL_ID="${MODEL_ID:-Qwen/Qwen3-8B}"
|
| 10 |
+
EFF_BIT="${EFF_BIT:-0.55}" # bits per weight: 1.0, 0.55, 0.3, 0.1 ...
|
| 11 |
+
EPOCHS="${EPOCHS:-1.0}" # paper uses 5.0
|
| 12 |
+
BATCH="${BATCH:-2}" # Qwen3's 151k vocab makes KD logits large
|
| 13 |
+
GRAD_ACCUM="${GRAD_ACCUM:-2}"
|
| 14 |
+
LR="${LR:-4e-05}"
|
| 15 |
+
USE_ITQ="${USE_ITQ:-True}" # True = LittleBit-2 init (Joint-ITQ)
|
| 16 |
+
TEACHER_OFFLOAD="${TEACHER_OFFLOAD:-False}" # False = teacher stays on GPU (faster, patched)
|
| 17 |
+
NUM_GPUS="${NUM_GPUS:-$(nvidia-smi -L | wc -l)}"
|
| 18 |
+
MODEL_SLUG="$(basename "$MODEL_ID" | tr '[:upper:]' '[:lower:]')"
|
| 19 |
+
RUN_NAME="${RUN_NAME:-littlebit-${MODEL_SLUG}-${EFF_BIT}bpw}"
|
| 20 |
+
SAVE_DIR="${SAVE_DIR:-$WORKDIR/outputs}"
|
| 21 |
+
|
| 22 |
+
if [ -z "${REPORT:-}" ]; then
|
| 23 |
+
if [ -n "${WANDB_API_KEY:-}" ]; then REPORT=wandb; else REPORT=tensorboard; fi
|
| 24 |
+
fi
|
| 25 |
+
|
| 26 |
+
export HF_HOME="$WORKDIR/hf_cache"
|
| 27 |
+
# shellcheck disable=SC1091
|
| 28 |
+
source "$WORKDIR/venv/bin/activate"
|
| 29 |
+
cd "$REPO_DIR"
|
| 30 |
+
mkdir -p "$WORKDIR/logs"
|
| 31 |
+
LOG="$WORKDIR/logs/train-$RUN_NAME-$(date +%Y%m%d-%H%M).log"
|
| 32 |
+
|
| 33 |
+
ARGS=(
|
| 34 |
+
--model_id "$MODEL_ID"
|
| 35 |
+
--dataset c4_wiki
|
| 36 |
+
--data_root "$WORKDIR/data"
|
| 37 |
+
--save_dir "$SAVE_DIR"
|
| 38 |
+
--f_name "$RUN_NAME"
|
| 39 |
+
--run_name "$RUN_NAME"
|
| 40 |
+
--num_train_epochs "$EPOCHS"
|
| 41 |
+
--per_device_train_batch_size "$BATCH"
|
| 42 |
+
--gradient_accumulation_steps "$GRAD_ACCUM"
|
| 43 |
+
--lr "$LR"
|
| 44 |
+
--warmup_ratio 0.02
|
| 45 |
+
--report "$REPORT"
|
| 46 |
+
--quant_func SmoothSign
|
| 47 |
+
--quant_mod LittleBitLinear
|
| 48 |
+
--residual True
|
| 49 |
+
--eff_bit "$EFF_BIT"
|
| 50 |
+
--kv_factor 1.0
|
| 51 |
+
--min_split_dim 8
|
| 52 |
+
--l2l_loss_scale 10.0
|
| 53 |
+
--use_itq "$USE_ITQ"
|
| 54 |
+
--teacher_offload "$TEACHER_OFFLOAD"
|
| 55 |
+
)
|
| 56 |
+
# Multi-GPU: ZeRO-3 sharding. Default keeps optimizer/params on GPU (fast);
|
| 57 |
+
# set DS_CONFIG=configs/zero3.json for upstream CPU offload (slow, less VRAM).
|
| 58 |
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
| 59 |
+
DS_CONFIG="${DS_CONFIG:-$SCRIPT_DIR/zero3_nooffload.json}"
|
| 60 |
+
if [ "$NUM_GPUS" -gt 1 ]; then
|
| 61 |
+
ARGS+=(--ds_config_path "$DS_CONFIG")
|
| 62 |
+
fi
|
| 63 |
+
|
| 64 |
+
# Always go through the deepspeed launcher: it sets LOCAL_RANK, which main.py
|
| 65 |
+
# needs to place the student on a concrete GPU (plain `python -m main` passes
|
| 66 |
+
# device_map="auto" to model.to(), which fails).
|
| 67 |
+
echo ">> $RUN_NAME on $NUM_GPUS GPU(s), log: $LOG"
|
| 68 |
+
deepspeed --num_gpus="$NUM_GPUS" main.py "${ARGS[@]}" 2>&1 | tee "$LOG"
|
| 69 |
+
|
| 70 |
+
echo ">> Checkpoint: $SAVE_DIR/$RUN_NAME"
|
recipe/zero3_nooffload.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"bf16": {
|
| 3 |
+
"enabled": true
|
| 4 |
+
},
|
| 5 |
+
|
| 6 |
+
"optimizer": {
|
| 7 |
+
"type": "AdamW",
|
| 8 |
+
"params": {
|
| 9 |
+
"lr": "auto",
|
| 10 |
+
"betas": "auto",
|
| 11 |
+
"eps": "auto",
|
| 12 |
+
"weight_decay": "auto"
|
| 13 |
+
}
|
| 14 |
+
},
|
| 15 |
+
|
| 16 |
+
"scheduler": {
|
| 17 |
+
"type": "WarmupCosineLR",
|
| 18 |
+
"params": {
|
| 19 |
+
"total_num_steps": "auto",
|
| 20 |
+
"warmup_min_ratio": 0,
|
| 21 |
+
"warmup_num_steps": "auto",
|
| 22 |
+
"cos_min_ratio": 0.0001,
|
| 23 |
+
"warmup_type": "linear"
|
| 24 |
+
}
|
| 25 |
+
},
|
| 26 |
+
|
| 27 |
+
"zero_optimization": {
|
| 28 |
+
"stage": 3,
|
| 29 |
+
"overlap_comm": true,
|
| 30 |
+
"contiguous_gradients": true,
|
| 31 |
+
"sub_group_size": 1e9,
|
| 32 |
+
"reduce_bucket_size": 5e8,
|
| 33 |
+
"stage3_prefetch_bucket_size": 5e8,
|
| 34 |
+
"stage3_param_persistence_threshold": 1e6,
|
| 35 |
+
"stage3_max_live_parameters": 1e9,
|
| 36 |
+
"stage3_max_reuse_distance": 1e9,
|
| 37 |
+
"stage3_gather_16bit_weights_on_model_save": true
|
| 38 |
+
},
|
| 39 |
+
|
| 40 |
+
"gradient_accumulation_steps": "auto",
|
| 41 |
+
"gradient_clipping": "auto",
|
| 42 |
+
"train_batch_size": "auto",
|
| 43 |
+
"train_micro_batch_size_per_gpu": "auto",
|
| 44 |
+
"wall_clock_breakdown": false
|
| 45 |
+
}
|