h34v7 commited on
Commit
0e0e96d
·
verified ·
1 Parent(s): 228875f

Upload dequantize_to_bf16.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. dequantize_to_bf16.py +102 -0
dequantize_to_bf16.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Dequantize a bitsandbytes NF4 model to standard bf16/fp16 weights.
4
+
5
+ Usage:
6
+ python dequantize_to_bf16.py # uses current directory
7
+ python dequantize_to_bf16.py --input ./final-9b --output ./final-9b-bf16 --dtype bf16
8
+
9
+ Requires: torch, transformers, bitsandbytes, safetensors
10
+ """
11
+
12
+ import argparse
13
+ import gc
14
+ import os
15
+ import torch
16
+ import safetensors.torch
17
+ from transformers import AutoModelForCausalLM, AutoConfig
18
+ from bitsandbytes.nn import Linear4bit
19
+
20
+
21
+ def dequantize_linear4bit(module: Linear4bit) -> torch.nn.Linear:
22
+ """Convert a Linear4bit module to a standard nn.Linear with dequantized weights."""
23
+ weight = module.weight
24
+ # Dequantize the 4-bit weight
25
+ if weight.quant_state is not None:
26
+ dequantized = module.dequantize(weight)
27
+ else:
28
+ # Fallback: extract via bnb.functional
29
+ import bitsandbytes.functional as bnb
30
+ dequantized = bnb.functional.dequantize_4bit(
31
+ weight.data,
32
+ weight.quant_state
33
+ )
34
+
35
+ out_features, in_features = dequantized.shape
36
+ new_linear = torch.nn.Linear(in_features, out_features, bias=module.bias is not None)
37
+ new_linear.weight.data = dequantized.contiguous()
38
+ if module.bias is not None:
39
+ new_linear.bias.data = module.bias.contiguous()
40
+ return new_linear
41
+
42
+
43
+ def dequantize_model(
44
+ input_dir: str,
45
+ output_dir: str,
46
+ dtype: str = "bf16",
47
+ ):
48
+ device = "cpu"
49
+ torch_dtype = torch.bfloat16 if dtype == "bf16" else torch.float16
50
+
51
+ print(f"[*] Loading NF4 model from {input_dir} on CPU...")
52
+ model = AutoModelForCausalLM.from_pretrained(
53
+ input_dir,
54
+ device_map=device,
55
+ torch_dtype=torch_dtype,
56
+ )
57
+ print(f" Loaded {sum(p.numel() for p in model.parameters()):,} total params")
58
+
59
+ print("[*] Dequantizing Linear4bit modules...")
60
+ for name, module in model.named_modules():
61
+ if isinstance(module, Linear4bit):
62
+ parent_name = ".".join(name.split(".")[:-1])
63
+ child_name = name.split(".")[-1]
64
+ if parent_name:
65
+ parent = model.get_submodule(parent_name)
66
+ else:
67
+ parent = model
68
+ new_linear = dequantize_linear4bit(module)
69
+ setattr(parent, child_name, new_linear)
70
+ print(f" ✓ {name}")
71
+
72
+ print(f"[*] Collecting state dict ({dtype})...")
73
+ state_dict = model.state_dict()
74
+ state_dict = {k: v.to(dtype=torch_dtype, device="cpu") for k, v in state_dict.items()}
75
+
76
+ os.makedirs(output_dir, exist_ok=True)
77
+
78
+ print(f"[*] Saving to {output_dir}...")
79
+ safetensors.torch.save_file(state_dict, os.path.join(output_dir, "model.safetensors"))
80
+
81
+ # Copy config files
82
+ import shutil
83
+ for f in ["config.json", "tokenizer.json", "tokenizer_config.json",
84
+ "generation_config.json", "chat_template.jinja"]:
85
+ src = os.path.join(input_dir, f)
86
+ if os.path.exists(src):
87
+ shutil.copy2(src, os.path.join(output_dir, f))
88
+
89
+ print(f"[✓] Done! Model saved to {output_dir}")
90
+ print(f" Size: {sum(os.path.getsize(os.path.join(output_dir, f)) for f in os.listdir(output_dir) if os.path.isfile(os.path.join(output_dir, f))) / 1e9:.1f} GB")
91
+ print(f" Dtype: {dtype}")
92
+ print(f" Usage: AutoModelForCausalLM.from_pretrained('{output_dir}')")
93
+
94
+
95
+ if __name__ == "__main__":
96
+ parser = argparse.ArgumentParser(description="Dequantize NF4 model to bf16/fp16")
97
+ parser.add_argument("--input", default=".", help="Input NF4 model directory")
98
+ parser.add_argument("--output", default="./dequantized", help="Output directory")
99
+ parser.add_argument("--dtype", choices=["bf16", "fp16"], default="bf16",
100
+ help="Target dtype (default: bf16)")
101
+ args = parser.parse_args()
102
+ dequantize_model(args.input, args.output, args.dtype)