1- use std:: path:: PathBuf ;
2- use serde:: Deserialize ;
3- use bincode:: serde:: encode_to_vec;
4- use bincode:: config:: standard;
5- use bitnet_tools:: constants:: { workspace_root, CONFIG_JSON , SAFETENSORS_FILE } ;
6- use std:: time:: Instant ;
7- use rayon:: prelude:: * ;
8-
9- pub mod packer;
10- pub mod source;
11-
12- #[ derive( Deserialize ) ]
13- struct PartialConfig {
14- num_hidden_layers : usize ,
15- }
16-
17- /// Programmatic API to run the BitNet conversion pipeline.
18- /// Returns the path to the output packed model file on success.
19- pub fn convert_model_on_disk ( input_dir : & str , output_dir : & str ) -> Result < PathBuf , Box < dyn std:: error:: Error > > {
20- let start = Instant :: now ( ) ;
21- let input_path = workspace_root ( ) . join ( input_dir) ;
22- let output_path = workspace_root ( ) . join ( output_dir) ;
23- std:: fs:: create_dir_all ( & output_path) ?;
24- println ! ( "[CONVERT] Loading config from: {}" , input_path. join( CONFIG_JSON ) . display( ) ) ;
25- let t0 = Instant :: now ( ) ;
26- let config_str = std:: fs:: read_to_string ( input_path. join ( CONFIG_JSON ) ) ?;
27- let config: PartialConfig = serde_json:: from_str ( & config_str) ?;
28- println ! ( "[CONVERT] Loaded config in {:.2?}" , t0. elapsed( ) ) ;
29- println ! ( "[CONVERT] Loading safetensors from: {}" , input_path. join( SAFETENSORS_FILE ) . display( ) ) ;
30- let t1 = Instant :: now ( ) ;
31- let source = source:: ModelSource :: SafetensorsFile (
32- input_path. join ( SAFETENSORS_FILE ) . to_str ( ) . unwrap ( ) . to_string ( ) ,
33- ) ;
34- let tensor_map = source. load_tensors ( ) ?;
35- println ! ( "[CONVERT] Loaded safetensors in {:.2?}" , t1. elapsed( ) ) ;
36- println ! ( "[CONVERT] Packing weights..." ) ;
37- let t2 = Instant :: now ( ) ;
38- let record = packer:: convert_model ( tensor_map, config. num_hidden_layers , true ) ?;
39- println ! ( "[CONVERT] Packed weights in {:.2?}" , t2. elapsed( ) ) ;
40- println ! ( "[CONVERT] Writing model as per-block files to: {}" , output_path. display( ) ) ;
41- let t3 = Instant :: now ( ) ;
42- // Save embedding
43- let embedding_path = output_path. join ( "embedding.bin" ) ;
44- let embedding_bytes = encode_to_vec ( & record. embedding , standard ( ) ) ?;
45- std:: fs:: write ( & embedding_path, & embedding_bytes) ?;
46- // Save norm
47- let norm_path = output_path. join ( "norm.bin" ) ;
48- let norm_bytes = encode_to_vec ( & record. norm , standard ( ) ) ?;
49- std:: fs:: write ( & norm_path, & norm_bytes) ?;
50- // Save lm_head
51- let lm_head_path = output_path. join ( "lm_head.bin" ) ;
52- let lm_head_bytes = encode_to_vec ( & record. lm_head , standard ( ) ) ?;
53- std:: fs:: write ( & lm_head_path, & lm_head_bytes) ?;
54- // Save each block in parallel
55- record. blocks . par_iter ( ) . enumerate ( ) . for_each ( |( i, block) | {
56- let block_path = output_path. join ( format ! ( "block_{}.bin" , i) ) ;
57- let block_bytes = encode_to_vec ( block, standard ( ) ) . expect ( "Failed to encode block" ) ;
58- std:: fs:: write ( & block_path, & block_bytes) . expect ( "Failed to write block file" ) ;
59- } ) ;
60- println ! ( "[CONVERT] Wrote all model parts in {:.2?}" , t3. elapsed( ) ) ;
61- println ! ( "[CONVERT] Total conversion time: {:.2?}" , start. elapsed( ) ) ;
62- Ok ( output_path)
1+ use std:: path:: PathBuf ;
2+ use serde:: Deserialize ;
3+ use bincode:: serde:: encode_to_vec;
4+ use bincode:: config:: standard;
5+ use bitnet_tools:: constants:: { workspace_root, CONFIG_JSON , SAFETENSORS_FILE } ;
6+ use std:: time:: Instant ;
7+ use rayon:: prelude:: * ;
8+
9+ pub mod packer;
10+ pub mod source;
11+
12+ #[ derive( Deserialize ) ]
13+ struct PartialConfig {
14+ num_hidden_layers : usize ,
15+ }
16+
17+ /// Programmatic API to run the BitNet conversion pipeline.
18+ /// Returns the path to the output packed model file on success.
19+ pub fn convert_model_on_disk ( input_dir : & str , output_dir : & str ) -> Result < PathBuf , Box < dyn std:: error:: Error > > {
20+ let start = Instant :: now ( ) ;
21+ let input_path = workspace_root ( ) . join ( input_dir) ;
22+ let output_path = workspace_root ( ) . join ( output_dir) ;
23+ std:: fs:: create_dir_all ( & output_path) ?;
24+ println ! ( "[CONVERT] Loading config from: {}" , input_path. join( CONFIG_JSON ) . display( ) ) ;
25+ let t0 = Instant :: now ( ) ;
26+ let config_str = std:: fs:: read_to_string ( input_path. join ( CONFIG_JSON ) ) ?;
27+ let config: PartialConfig = serde_json:: from_str ( & config_str) ?;
28+ println ! ( "[CONVERT] Loaded config in {:.2?}" , t0. elapsed( ) ) ;
29+ println ! ( "[CONVERT] Loading safetensors from: {}" , input_path. join( SAFETENSORS_FILE ) . display( ) ) ;
30+ let t1 = Instant :: now ( ) ;
31+ let source = source:: ModelSource :: SafetensorsFile (
32+ input_path. join ( SAFETENSORS_FILE ) . to_str ( ) . unwrap ( ) . to_string ( ) ,
33+ ) ;
34+ let tensor_map = source. load_tensors ( ) ?;
35+ println ! ( "[CONVERT] Loaded safetensors in {:.2?}" , t1. elapsed( ) ) ;
36+ println ! ( "[CONVERT] Packing weights..." ) ;
37+ let t2 = Instant :: now ( ) ;
38+ let record = packer:: convert_model ( tensor_map, config. num_hidden_layers , true ) ?;
39+ println ! ( "[CONVERT] Packed weights in {:.2?}" , t2. elapsed( ) ) ;
40+ println ! ( "[CONVERT] Writing model as per-block files to: {}" , output_path. display( ) ) ;
41+ let t3 = Instant :: now ( ) ;
42+ // Save embedding
43+ let embedding_path = output_path. join ( "embedding.bin" ) ;
44+ let embedding_bytes = encode_to_vec ( & record. embedding , standard ( ) ) ?;
45+ std:: fs:: write ( & embedding_path, & embedding_bytes) ?;
46+ // Save norm
47+ let norm_path = output_path. join ( "norm.bin" ) ;
48+ let norm_bytes = encode_to_vec ( & record. norm , standard ( ) ) ?;
49+ std:: fs:: write ( & norm_path, & norm_bytes) ?;
50+ // Save lm_head
51+ let lm_head_path = output_path. join ( "lm_head.bin" ) ;
52+ let lm_head_bytes = encode_to_vec ( & record. lm_head , standard ( ) ) ?;
53+ std:: fs:: write ( & lm_head_path, & lm_head_bytes) ?;
54+ // Save each block in parallel
55+ record. blocks . par_iter ( ) . enumerate ( ) . for_each ( |( i, block) | {
56+ let block_path = output_path. join ( format ! ( "block_{}.bin" , i) ) ;
57+ let block_bytes = encode_to_vec ( block, standard ( ) ) . expect ( "Failed to encode block" ) ;
58+ std:: fs:: write ( & block_path, & block_bytes) . expect ( "Failed to write block file" ) ;
59+ } ) ;
60+ println ! ( "[CONVERT] Wrote all model parts in {:.2?}" , t3. elapsed( ) ) ;
61+ println ! ( "[CONVERT] Total conversion time: {:.2?}" , start. elapsed( ) ) ;
62+ Ok ( output_path)
6363}
0 commit comments