feat: use transformers built-in BnB loading with device_map=cpu

This commit is contained in:
Christian Medina
2026-07-02 20:27:06 -04:00
parent 11f9c3a56c
commit a23ecc49f0

View File

@@ -1,84 +1,45 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Properly quantize model to BnB 4-bit using BnB API.""" """Quantize bf16 model to BnB 4-bit using transformers' built-in mechanism."""
import argparse import argparse
import gc import gc
import torch import torch
from pathlib import Path from pathlib import Path
from transformers import AutoModelForCausalLM, AutoConfig from transformers import AutoModelForCausalLM, BitsAndBytesConfig
def quantize_model(model_path, output_path): def quantize_model(model_path, output_path):
"""Load bf16 model, properly quantize to BnB 4-bit, save.""" """Load bf16 model, quantize to BnB 4-bit, save."""
print(f"Loading model from: {model_path}") print(f"Loading model from: {model_path}")
# Load with BnB quantization config and device_map="cpu"
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
)
print("Loading with BnB 4-bit quantization to CPU...")
model = AutoModelForCausalLM.from_pretrained( model = AutoModelForCausalLM.from_pretrained(
model_path, model_path,
quantization_config=bnb_config,
device_map="cpu", device_map="cpu",
torch_dtype=torch.bfloat16, torch_dtype=torch.float16,
trust_remote_code=True, trust_remote_code=True,
low_cpu_mem_usage=True, low_cpu_mem_usage=True,
) )
print(f"✓ Model loaded to CPU (~70GB bf16)") print("✓ Model loaded with BnB 4-bit to CPU")
# Count parameters # Check if model is actually quantized
total_params = sum(p.numel() for p in model.parameters()) bnb_modules = sum(
print(f" Total parameters: {total_params / 1e9:.2f}B") 1 for m in model.modules()
if hasattr(m, 'weight') and hasattr(m.weight, 'quant_state')
# Quantize using BnB's actual API
print("\nQuantizing with BnB 4-bit...")
from bitsandbytes.nn import Linear4bit
from torch import nn
quantized_count = 0
for name, module in list(model.named_modules()):
if isinstance(module, nn.Linear) and 'lm_head' not in name:
# Create new Linear4bit
new_module = Linear4bit(
module.in_features,
module.out_features,
bias=module.bias is not None,
compute_dtype=torch.float16,
quant_type='nf4',
) )
print(f" BnB quantized modules: {bnb_modules}")
# Copy weights - Linear4bit will quantize on first forward # Save model
with torch.no_grad():
new_module.weight = nn.Parameter(module.weight.data.clone())
if module.bias is not None:
new_module.bias = nn.Parameter(module.bias.data.clone())
# Replace in model
layers = name.split('.')
parent = model
for layer in layers[:-1]:
parent = getattr(parent, layer)
setattr(parent, layers[-1], new_module)
quantized_count += 1
print(f"✓ Replaced {quantized_count} Linear layers with Linear4bit")
# Force quantization by running a dummy forward pass
print(" Forcing quantization with dummy input...")
dummy_input = torch.randn(1, 32, model.config.hidden_size)
with torch.no_grad():
try:
model(dummy_input)
except Exception as e:
print(f" (Dummy forward may fail, but weights should be quantized)")
# Count quantized parameters
bnb_params = sum(
1 for p in model.parameters()
if hasattr(p, 'quant_state') and p.quant_state is not None
)
print(f" Quantized modules: {bnb_params}")
# Save model config
print(f"\nSaving to: {output_path}") print(f"\nSaving to: {output_path}")
model.config.save_pretrained(output_path)
# Save weights
model.save_pretrained(output_path) model.save_pretrained(output_path)
print("✓ Model saved") print("✓ Model saved")