Summary
utils/convert-hf-to-gguf-bitnet.py accepts --outtype i2_s for every architecture, but the I2_S packing code path exists only in BitnetModel (architecture BitNetForCausalLM). For the LlamaForCausalLM BitNet checkpoints listed as supported in the README (tiiuae/Falcon3-*-1.58bit, tiiuae/Falcon-E-*), LlamaModel.write_tensors unpacks the offline-quantized ternary weights and stores them as F16, without any warning. The result is a valid but full-size GGUF (14.9 GB for Falcon3-7B instead of ~2.7 GB) with no I2_S tensors, while the metadata still claims an I2_S file type.
Since llama-quantize in this tree has no I2_S ftype either (#619), there is currently no way to obtain an I2_S GGUF for the Falcon 1.58-bit models from their HF checkpoints.
Environment
microsoft/BitNet at 0b341e5 (current main), submodule 3rdparty/llama.cpp at 390c3077
- macOS 26.5.2, Apple M2 Pro, Python 3.14.7,
gguf installed from 3rdparty/llama.cpp/gguf-py (as done by setup_env.py)
Steps to reproduce
hf download tiiuae/Falcon3-7B-Instruct-1.58bit --local-dir models/Falcon3-7B-Instruct-1.58bit
python utils/convert-hf-to-gguf-bitnet.py models/Falcon3-7B-Instruct-1.58bit --outtype i2_s
Converter log (every linear weight):
INFO:hf-to-gguf:blk.0.ffn_down.weight, torch.uint8 --> F16, shape = {23040, 3072}
INFO:hf-to-gguf:blk.0.attn_q.weight, torch.uint8 --> F16, shape = {3072, 3072}
...
INFO:gguf.gguf_writer:models/Falcon3-7B-Instruct-1.58bit/ggml-model-i2_s.gguf: n_tensors = 255, total_size = 14.9G
Resulting file (read with gguf.GGUFReader): tensor types {F16: 198, F32: 57}, zero I2_S tensors, general.file_type = 40. The same converter run on microsoft/bitnet-b1.58-2B-4T-bf16 correctly produces 210 I2_S tensors, so the difference is the architecture, not the input format (the Falcon checkpoint is offline-quantized: uint8 packed weights + weight_scale tensors, 196 of them, which LlamaModel does unpack correctly).
Root cause
LlamaModel.write_tensors (utils/convert-hf-to-gguf-bitnet.py, from line 776) handles the offline-quantized weights (unpack at ~line 800, scale_map), but its quantization dispatch only has TL1 and TL2 branches (lines ~869-878) followed by else: # default to float16 for quantized tensors (~line 880).
- The
I2_S branch (quantize_to_i2_s(data, override_scale=...)) exists only in BitnetModel.write_tensors (line 1164).
ftype_map / --outtype (lines 1216, 1237) accept i2_s regardless of the model class, so the request is silently downgraded to F16.
Suggested fix
Port the I2_S branch from BitnetModel.write_tensors to LlamaModel.write_tensors (the ternary values and scale_map are already available there, so quantize_to_i2_s(data, override_scale=scale) is a small change), or make the converter fail loudly when --outtype i2_s is requested for a class that cannot produce it. Related: #619 (conversion flow / missing I2_S in llama-quantize), #550 (Falcon3 TL2 support in setup_env.py), #616 (LlamaModel dequantization), #620 (general.file_type value).
Summary
utils/convert-hf-to-gguf-bitnet.pyaccepts--outtype i2_sfor every architecture, but the I2_S packing code path exists only inBitnetModel(architectureBitNetForCausalLM). For theLlamaForCausalLMBitNet checkpoints listed as supported in the README (tiiuae/Falcon3-*-1.58bit,tiiuae/Falcon-E-*),LlamaModel.write_tensorsunpacks the offline-quantized ternary weights and stores them as F16, without any warning. The result is a valid but full-size GGUF (14.9 GB for Falcon3-7B instead of ~2.7 GB) with no I2_S tensors, while the metadata still claims an I2_S file type.Since
llama-quantizein this tree has noI2_Sftype either (#619), there is currently no way to obtain an I2_S GGUF for the Falcon 1.58-bit models from their HF checkpoints.Environment
microsoft/BitNetat0b341e5(currentmain), submodule3rdparty/llama.cppat390c3077ggufinstalled from3rdparty/llama.cpp/gguf-py(as done bysetup_env.py)Steps to reproduce
Converter log (every linear weight):
Resulting file (read with
gguf.GGUFReader): tensor types{F16: 198, F32: 57}, zeroI2_Stensors,general.file_type = 40. The same converter run onmicrosoft/bitnet-b1.58-2B-4T-bf16correctly produces 210 I2_S tensors, so the difference is the architecture, not the input format (the Falcon checkpoint is offline-quantized:uint8packed weights +weight_scaletensors, 196 of them, whichLlamaModeldoes unpack correctly).Root cause
LlamaModel.write_tensors(utils/convert-hf-to-gguf-bitnet.py, from line 776) handles the offline-quantized weights (unpack at ~line 800,scale_map), but its quantization dispatch only hasTL1andTL2branches (lines ~869-878) followed byelse: # default to float16 for quantized tensors(~line 880).I2_Sbranch (quantize_to_i2_s(data, override_scale=...)) exists only inBitnetModel.write_tensors(line 1164).ftype_map/--outtype(lines 1216, 1237) accepti2_sregardless of the model class, so the request is silently downgraded to F16.Suggested fix
Port the
I2_Sbranch fromBitnetModel.write_tensorstoLlamaModel.write_tensors(the ternary values andscale_mapare already available there, soquantize_to_i2_s(data, override_scale=scale)is a small change), or make the converter fail loudly when--outtype i2_sis requested for a class that cannot produce it. Related: #619 (conversion flow / missingI2_Sinllama-quantize), #550 (Falcon3 TL2 support insetup_env.py), #616 (LlamaModeldequantization), #620 (general.file_typevalue).