426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
175 lines
6.4 KiB
Python
175 lines
6.4 KiB
Python
"""Apply FP8 (E4M3) weight quantization to a fine-tuned Eliza-1/Gemma checkpoint.
|
|
|
|
Wraps :mod:`torchao.float8` per the recipe in
|
|
https://pytorch.org/torchao/main/api_ref_quantization.html — converts every
|
|
``nn.Linear`` to its FP8 equivalent and saves the resulting safetensors so
|
|
that vLLM (or TensorRT-LLM) can serve it via ``--quantization fp8``.
|
|
|
|
Compute capability:
|
|
|
|
* Hopper (sm_90, sm_90a) and Datacenter Blackwell (sm_100, B100/B200)
|
|
have native FP8 tensor cores. Use this path.
|
|
* Consumer Blackwell (RTX PRO 5000/6000 → sm_120) does **not** have
|
|
a vendor-blessed FP8-Marlin path in vLLM yet (the matmul falls
|
|
through to W8A16 emulation). On these targets prefer
|
|
PolarQuant + AWQ-Marlin (``polarquant_apply.py``) — the script
|
|
will exit 2 with an actionable message instead of producing weights
|
|
that won't accelerate.
|
|
* The fp8 cast itself is a one-shot transform; ``--calibration`` is
|
|
accepted for CLI parity with the other quantizers but unused
|
|
(E4M3 conversion is data-free, similar to PolarQuant).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import logging
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import torch
|
|
|
|
_HERE = Path(__file__).resolve().parent
|
|
if str(_HERE) not in sys.path:
|
|
sys.path.insert(0, str(_HERE))
|
|
|
|
from _common import ( # noqa: E402
|
|
load_model_and_tokenizer,
|
|
save_model,
|
|
write_sidecar,
|
|
)
|
|
|
|
logging.basicConfig(
|
|
level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s"
|
|
)
|
|
log = logging.getLogger("fp8_apply")
|
|
|
|
# Compute-capability gate. Anything below sm_90 lacks native FP8 tensor cores;
|
|
# anything in the consumer Blackwell sm_120 family lacks a usable Marlin path
|
|
# in current vLLM/TensorRT-LLM and falls back to W8A16 emulation that is slower
|
|
# than bf16. Allow only sm_90/sm_90a/sm_100 (Datacenter Blackwell B100/B200).
|
|
_FP8_OK_MAJORS = {9, 10}
|
|
|
|
|
|
def _detect_fp8_capability() -> tuple[bool, str]:
|
|
"""Return (ok, reason). Reason is a human-readable string for both paths."""
|
|
if not torch.cuda.is_available():
|
|
return False, "CUDA not available — FP8 conversion needs a GPU device."
|
|
major, minor = torch.cuda.get_device_capability(0)
|
|
name = torch.cuda.get_device_name(0)
|
|
if major not in _FP8_OK_MAJORS:
|
|
return (
|
|
False,
|
|
f"GPU {name!r} is sm_{major}{minor} — native FP8 tensor cores "
|
|
"require sm_90 (Hopper H100/H200) or sm_100 (Datacenter Blackwell "
|
|
"B100/B200). Consumer Blackwell sm_120 (RTX PRO 5000/6000) lacks a "
|
|
"vendor-blessed FP8-Marlin path in current vLLM. Use AWQ-Marlin via "
|
|
"scripts/quantization/polarquant_apply.py instead.",
|
|
)
|
|
return True, f"sm_{major}{minor} device {name!r} supports native FP8."
|
|
|
|
|
|
def _convert_linears_to_fp8(model: torch.nn.Module) -> int:
|
|
"""Run torchao's FP8 conversion in place. Returns number of layers converted.
|
|
|
|
``torchao.float8.convert_to_float8_training`` (used here as a one-shot
|
|
inference cast) walks every ``nn.Linear`` and swaps it for a
|
|
``Float8Linear`` whose weight is stored as E4M3 + per-tensor scale.
|
|
save_pretrained handles the safetensors layout.
|
|
"""
|
|
try:
|
|
from torchao.float8 import (
|
|
Float8LinearConfig,
|
|
convert_to_float8_training,
|
|
)
|
|
except ImportError as exc:
|
|
raise SystemExit(
|
|
"torchao>=0.7 is required for FP8 conversion. Install via "
|
|
"`uv pip install torchao` (or pin in pyproject.toml's `train` "
|
|
"extra). Underlying error: " + str(exc)
|
|
) from exc
|
|
|
|
cfg = Float8LinearConfig(
|
|
# E4M3 is the de-facto inference choice (higher dynamic range
|
|
# for activations than E5M2 at the same exponent count).
|
|
cast_config_weight={"target_dtype": torch.float8_e4m3fn},
|
|
cast_config_input={"target_dtype": torch.float8_e4m3fn},
|
|
cast_config_grad_output={"target_dtype": torch.float8_e5m2},
|
|
)
|
|
|
|
n_before = sum(1 for m in model.modules() if isinstance(m, torch.nn.Linear))
|
|
convert_to_float8_training(model, config=cfg)
|
|
n_after_fp8 = sum(
|
|
1
|
|
for m in model.modules()
|
|
if type(m).__name__.endswith("Float8Linear")
|
|
)
|
|
log.info(
|
|
"converted %d/%d linears to Float8Linear (E4M3)",
|
|
n_after_fp8,
|
|
n_before,
|
|
)
|
|
return n_after_fp8
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
ap = argparse.ArgumentParser(description=__doc__.split("\n\n", 1)[0])
|
|
ap.add_argument(
|
|
"--model",
|
|
required=True,
|
|
help="HF repo id or local path. LoRA adapter dirs are merged automatically.",
|
|
)
|
|
ap.add_argument("--output", required=True, type=Path)
|
|
ap.add_argument(
|
|
"--calibration",
|
|
type=Path,
|
|
default=None,
|
|
help="Accepted for CLI parity; unused (E4M3 conversion is data-free).",
|
|
)
|
|
ap.add_argument("--calibration-samples", type=int, default=128)
|
|
ap.add_argument("--device", default="cuda")
|
|
ap.add_argument("--dry-run", action="store_true")
|
|
args = ap.parse_args(argv)
|
|
|
|
if args.dry_run:
|
|
ok, reason = _detect_fp8_capability() if torch.cuda.is_available() else (
|
|
False,
|
|
"dry-run on a host without CUDA — capability check skipped.",
|
|
)
|
|
print(json.dumps({**vars(args), "fp8_ok": ok, "reason": reason}, indent=2, default=str))
|
|
return 0
|
|
|
|
ok, reason = _detect_fp8_capability()
|
|
if not ok:
|
|
log.error("FP8 capability check failed: %s", reason)
|
|
return 2
|
|
|
|
out_dir = Path(args.output)
|
|
model, tok = load_model_and_tokenizer(args.model, device_map=args.device)
|
|
n_converted = _convert_linears_to_fp8(model)
|
|
|
|
save_model(model, tok, out_dir)
|
|
|
|
sidecar = {
|
|
"method": "fp8_e4m3",
|
|
"library": "torchao.float8",
|
|
"source_model": args.model,
|
|
"n_layers_converted": n_converted,
|
|
"compute_capability": list(torch.cuda.get_device_capability(0)),
|
|
"device_name": torch.cuda.get_device_name(0),
|
|
"notes": (
|
|
"FP8 (E4M3) weights produced via torchao.float8. Serve with "
|
|
"vLLM `--quantization fp8` (Hopper H100/H200 or Datacenter "
|
|
"Blackwell B100/B200). Consumer Blackwell sm_120 has no "
|
|
"FP8-Marlin path in vLLM today; prefer AWQ-Marlin/PolarQuant."
|
|
),
|
|
}
|
|
sidecar_path = write_sidecar(out_dir, "fp8.json", sidecar)
|
|
log.info("wrote %s", sidecar_path)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|