erata commited on
Commit
d0da4dc
·
verified ·
1 Parent(s): 3ae5da9

Upload folder using huggingface_hub

Browse files
Files changed (40) hide show
  1. .gitattributes +1 -0
  2. README.md +141 -3
  3. added_tokens.json +28 -0
  4. chat_template.jinja +89 -0
  5. global_step1850/bf16_zero_pp_rank_0_mp_rank_00_optim_states.pt +3 -0
  6. global_step1850/bf16_zero_pp_rank_1_mp_rank_00_optim_states.pt +3 -0
  7. global_step1850/bf16_zero_pp_rank_2_mp_rank_00_optim_states.pt +3 -0
  8. global_step1850/bf16_zero_pp_rank_3_mp_rank_00_optim_states.pt +3 -0
  9. global_step1850/bf16_zero_pp_rank_4_mp_rank_00_optim_states.pt +3 -0
  10. global_step1850/bf16_zero_pp_rank_5_mp_rank_00_optim_states.pt +3 -0
  11. global_step1850/bf16_zero_pp_rank_6_mp_rank_00_optim_states.pt +3 -0
  12. global_step1850/bf16_zero_pp_rank_7_mp_rank_00_optim_states.pt +3 -0
  13. global_step1850/zero_pp_rank_0_mp_rank_00_model_states.pt +3 -0
  14. global_step1850/zero_pp_rank_1_mp_rank_00_model_states.pt +3 -0
  15. global_step1850/zero_pp_rank_2_mp_rank_00_model_states.pt +3 -0
  16. global_step1850/zero_pp_rank_3_mp_rank_00_model_states.pt +3 -0
  17. global_step1850/zero_pp_rank_4_mp_rank_00_model_states.pt +3 -0
  18. global_step1850/zero_pp_rank_5_mp_rank_00_model_states.pt +3 -0
  19. global_step1850/zero_pp_rank_6_mp_rank_00_model_states.pt +3 -0
  20. global_step1850/zero_pp_rank_7_mp_rank_00_model_states.pt +3 -0
  21. latest +1 -0
  22. merges.txt +0 -0
  23. pytorch_model.bin +3 -0
  24. rng_state_0.pth +3 -0
  25. rng_state_1.pth +3 -0
  26. rng_state_2.pth +3 -0
  27. rng_state_3.pth +3 -0
  28. rng_state_4.pth +3 -0
  29. rng_state_5.pth +3 -0
  30. rng_state_6.pth +3 -0
  31. rng_state_7.pth +3 -0
  32. scheduler.pt +3 -0
  33. sft_qwen_var_classifier.py +728 -0
  34. special_tokens_map.json +31 -0
  35. tokenizer.json +3 -0
  36. tokenizer_config.json +239 -0
  37. trainer_state.json +1847 -0
  38. training_args.bin +3 -0
  39. vocab.json +0 -0
  40. zero_to_fp32.py +760 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,3 +1,141 @@
1
- ---
2
- license: mit
3
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ base_model: Qwen/Qwen3-4B
4
+ tags:
5
+ - SAT
6
+ - combinatorial-optimization
7
+ - classification
8
+ - cube-and-conquer
9
+ - data-augmentation
10
+ language:
11
+ - en
12
+ pipeline_tag: text-classification
13
+ ---
14
+
15
+ # Qwen3-4B-SAT-VarSelector-Sym-Aug
16
+
17
+ A Qwen3-4B model fine-tuned for **SAT branching variable selection** using **symmetry-based data augmentation**.
18
+
19
+ ## Model Description
20
+
21
+ This model predicts which variable to branch/cube on next, given a SAT CNF formula state. It was trained with **5x augmented data** using CNF symmetry transformations, achieving **21.8% top-1 accuracy** (vs 19% for Qwen3-0.6B).
22
+
23
+ ### Architecture
24
+
25
+ - **Base**: `Qwen/Qwen3-4B` (causal language model)
26
+ - **Head**: LayerNorm → Linear(hidden_size, 601)
27
+ - **Max Variables**: 600
28
+ - **Pooling**: Last non-pad token hidden state
29
+ - **Masking**: Invalid variables (not in CNF) are masked to -10000 before softmax
30
+ - **Size**: ~8GB (bfloat16)
31
+
32
+ ### Training with Symmetry Augmentation
33
+
34
+ This model was trained with **5x data augmentation** using semantically-safe CNF transformations:
35
+
36
+ | Augmentation | Description | Effect |
37
+ |-------------|-------------|--------|
38
+ | **Variable Permutation** | Bijective remapping of variable IDs | Prevents memorizing specific variable numbers |
39
+ | **Clause Shuffling** | Random reordering of clauses | Teaches position-independence |
40
+ | **Literal Reordering** | Shuffle literals within clauses | Token-level variation |
41
+ | **Polarity Flipping** | Flip signs of random variable subset | Teaches structural vs. polarity features |
42
+
43
+ ### Training Details
44
+
45
+ | Parameter | Value |
46
+ |-----------|-------|
47
+ | Original training samples | 8,110 |
48
+ | Augmented training samples | **40,550** (5x) |
49
+ | Validation samples | 902 (unaugmented) |
50
+ | Epochs | 3 |
51
+ | Hardware | 8×H100 GPUs |
52
+ | Training framework | DeepSpeed ZeRO-3 |
53
+ | Peak learning rate | 5e-6 |
54
+ | Training time | ~4 hours |
55
+ | Best checkpoint | Step 1850 (epoch 2.92) |
56
+
57
+ ### Performance Comparison
58
+
59
+ | Model | Parameters | Training Data | Top-1 Accuracy |
60
+ |-------|-----------|--------------|----------------|
61
+ | Qwen3-0.6B (baseline) | 600M | 8,110 samples | ~12% |
62
+ | Qwen3-0.6B (augmented) | 600M | 40,550 samples | ~19% |
63
+ | **Qwen3-4B (augmented)** | **4B** | **40,550 samples** | **~22%** |
64
+
65
+ ### Training Curve Highlights
66
+
67
+ - Peak accuracy: **22.0%** at epoch 2.76
68
+ - Final accuracy: **21.8%** at epoch 2.92
69
+ - Eval loss: 3.35 (vs 3.37 for 0.6B)
70
+
71
+ ## Usage
72
+
73
+ ```python
74
+ import torch
75
+ from transformers import AutoTokenizer
76
+ from sft_qwen_var_classifier import QwenVarClassifier, cnf_valid_mask
77
+
78
+ # Load model
79
+ model = QwenVarClassifier("Qwen/Qwen3-4B", max_vars=600)
80
+ state_dict = torch.load("pytorch_model.bin", map_location="cpu")
81
+ model.load_state_dict(state_dict, strict=False)
82
+ model = model.to("cuda", dtype=torch.bfloat16)
83
+ model.eval()
84
+
85
+ # Load tokenizer
86
+ tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-4B")
87
+
88
+ # Prepare CNF input
89
+ cnf_text = """p cnf 100 250
90
+ 1 -2 3 0
91
+ -1 2 -4 0
92
+ ...
93
+ """
94
+
95
+ # Tokenize
96
+ inputs = tokenizer(cnf_text, return_tensors="pt", truncation=True, max_length=8192)
97
+ inputs = {k: v.to("cuda") for k, v in inputs.items()}
98
+
99
+ # Get valid variable mask
100
+ valid_mask = torch.tensor([cnf_valid_mask(cnf_text, max_vars=600)], dtype=torch.bool, device="cuda")
101
+
102
+ # Predict
103
+ with torch.no_grad():
104
+ outputs = model(**inputs)
105
+ logits = outputs["logits"]
106
+ logits = logits.masked_fill(~valid_mask, -1e4)
107
+ predicted_var = logits.argmax(dim=-1).item()
108
+
109
+ print(f"Predicted branching variable: {predicted_var}")
110
+ ```
111
+
112
+ ## Files
113
+
114
+ - `pytorch_model.bin` - Model weights (~8GB, bfloat16)
115
+ - `sft_qwen_var_classifier.py` - Model class definition (required for loading)
116
+
117
+ ## When to Use This Model
118
+
119
+ - **Higher accuracy** than 0.6B version (+3pp)
120
+ - **Production use** when accuracy matters more than speed
121
+ - **Cube-and-Conquer** style SAT solving
122
+
123
+ ## Limitations
124
+
125
+ - Maximum 600 variables
126
+ - Maximum 8192 tokens for CNF input
127
+ - Larger model size (~8GB vs 1.2GB for 0.6B)
128
+ - Slower inference (~6x slower than 0.6B)
129
+
130
+ ## Related Models
131
+
132
+ - [Qwen3-0.6B-SAT-VarSelector-Sym-Aug](https://huggingface.co/Yale-ROSE/Qwen3-0.6B-SAT-VarSelector-Sym-Aug) - Smaller, faster version
133
+ - [Qwen3-0.6B-SAT-VarSelector](https://huggingface.co/Yale-ROSE/Qwen3-0.6B-SAT-VarSelector) - Non-augmented baseline
134
+
135
+ ## Citation
136
+
137
+ If you use this model, please cite the Transformer-CnC paper.
138
+
139
+ ## License
140
+
141
+ Apache 2.0
added_tokens.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "</think>": 151668,
3
+ "</tool_call>": 151658,
4
+ "</tool_response>": 151666,
5
+ "<think>": 151667,
6
+ "<tool_call>": 151657,
7
+ "<tool_response>": 151665,
8
+ "<|box_end|>": 151649,
9
+ "<|box_start|>": 151648,
10
+ "<|endoftext|>": 151643,
11
+ "<|file_sep|>": 151664,
12
+ "<|fim_middle|>": 151660,
13
+ "<|fim_pad|>": 151662,
14
+ "<|fim_prefix|>": 151659,
15
+ "<|fim_suffix|>": 151661,
16
+ "<|im_end|>": 151645,
17
+ "<|im_start|>": 151644,
18
+ "<|image_pad|>": 151655,
19
+ "<|object_ref_end|>": 151647,
20
+ "<|object_ref_start|>": 151646,
21
+ "<|quad_end|>": 151651,
22
+ "<|quad_start|>": 151650,
23
+ "<|repo_name|>": 151663,
24
+ "<|video_pad|>": 151656,
25
+ "<|vision_end|>": 151653,
26
+ "<|vision_pad|>": 151654,
27
+ "<|vision_start|>": 151652
28
+ }
chat_template.jinja ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- if tools %}
2
+ {{- '<|im_start|>system\n' }}
3
+ {%- if messages[0].role == 'system' %}
4
+ {{- messages[0].content + '\n\n' }}
5
+ {%- endif %}
6
+ {{- "# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
7
+ {%- for tool in tools %}
8
+ {{- "\n" }}
9
+ {{- tool | tojson }}
10
+ {%- endfor %}
11
+ {{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }}
12
+ {%- else %}
13
+ {%- if messages[0].role == 'system' %}
14
+ {{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' }}
15
+ {%- endif %}
16
+ {%- endif %}
17
+ {%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
18
+ {%- for message in messages[::-1] %}
19
+ {%- set index = (messages|length - 1) - loop.index0 %}
20
+ {%- if ns.multi_step_tool and message.role == "user" and message.content is string and not(message.content.startswith('<tool_response>') and message.content.endswith('</tool_response>')) %}
21
+ {%- set ns.multi_step_tool = false %}
22
+ {%- set ns.last_query_index = index %}
23
+ {%- endif %}
24
+ {%- endfor %}
25
+ {%- for message in messages %}
26
+ {%- if message.content is string %}
27
+ {%- set content = message.content %}
28
+ {%- else %}
29
+ {%- set content = '' %}
30
+ {%- endif %}
31
+ {%- if (message.role == "user") or (message.role == "system" and not loop.first) %}
32
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }}
33
+ {%- elif message.role == "assistant" %}
34
+ {%- set reasoning_content = '' %}
35
+ {%- if message.reasoning_content is string %}
36
+ {%- set reasoning_content = message.reasoning_content %}
37
+ {%- else %}
38
+ {%- if '</think>' in content %}
39
+ {%- set reasoning_content = content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
40
+ {%- set content = content.split('</think>')[-1].lstrip('\n') %}
41
+ {%- endif %}
42
+ {%- endif %}
43
+ {%- if loop.index0 > ns.last_query_index %}
44
+ {%- if loop.last or (not loop.last and reasoning_content) %}
45
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content.strip('\n') + '\n</think>\n\n' + content.lstrip('\n') }}
46
+ {%- else %}
47
+ {{- '<|im_start|>' + message.role + '\n' + content }}
48
+ {%- endif %}
49
+ {%- else %}
50
+ {{- '<|im_start|>' + message.role + '\n' + content }}
51
+ {%- endif %}
52
+ {%- if message.tool_calls %}
53
+ {%- for tool_call in message.tool_calls %}
54
+ {%- if (loop.first and content) or (not loop.first) %}
55
+ {{- '\n' }}
56
+ {%- endif %}
57
+ {%- if tool_call.function %}
58
+ {%- set tool_call = tool_call.function %}
59
+ {%- endif %}
60
+ {{- '<tool_call>\n{"name": "' }}
61
+ {{- tool_call.name }}
62
+ {{- '", "arguments": ' }}
63
+ {%- if tool_call.arguments is string %}
64
+ {{- tool_call.arguments }}
65
+ {%- else %}
66
+ {{- tool_call.arguments | tojson }}
67
+ {%- endif %}
68
+ {{- '}\n</tool_call>' }}
69
+ {%- endfor %}
70
+ {%- endif %}
71
+ {{- '<|im_end|>\n' }}
72
+ {%- elif message.role == "tool" %}
73
+ {%- if loop.first or (messages[loop.index0 - 1].role != "tool") %}
74
+ {{- '<|im_start|>user' }}
75
+ {%- endif %}
76
+ {{- '\n<tool_response>\n' }}
77
+ {{- content }}
78
+ {{- '\n</tool_response>' }}
79
+ {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
80
+ {{- '<|im_end|>\n' }}
81
+ {%- endif %}
82
+ {%- endif %}
83
+ {%- endfor %}
84
+ {%- if add_generation_prompt %}
85
+ {{- '<|im_start|>assistant\n' }}
86
+ {%- if enable_thinking is defined and enable_thinking is false %}
87
+ {{- '<think>\n\n</think>\n\n' }}
88
+ {%- endif %}
89
+ {%- endif %}
global_step1850/bf16_zero_pp_rank_0_mp_rank_00_optim_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c51231ebe4b8426dd0bdcfcb45cf25cbcdcd2afb93f07aea0798d8aeacb6e053
3
+ size 6036024113
global_step1850/bf16_zero_pp_rank_1_mp_rank_00_optim_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fc81f84e951c367b1cd2c67cd022b94a3e5ada90aa16c3e2721a2053c3353d34
3
+ size 6036024113
global_step1850/bf16_zero_pp_rank_2_mp_rank_00_optim_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0aff15f92f1036630cc320d2821a8c388f8f995dcaf2a7e96e23b62b0b9cf605
3
+ size 6036024113
global_step1850/bf16_zero_pp_rank_3_mp_rank_00_optim_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:39ac2975e94199ce82bd8c62825d5721f59503f4a90d3995a558b50817586cce
3
+ size 6036024113
global_step1850/bf16_zero_pp_rank_4_mp_rank_00_optim_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:aa4d67c46ffc45204b36233962bd0cd57df1c1f8f7e312d7c91feafd210edd27
3
+ size 6036024113
global_step1850/bf16_zero_pp_rank_5_mp_rank_00_optim_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b71d6b542df0dcb8221a4bc139f9513ac13bbf82ce56804c49c9dcd047d96aa9
3
+ size 6036024113
global_step1850/bf16_zero_pp_rank_6_mp_rank_00_optim_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b40cfc55a382847efd4ef0c146a3d2ef5b472ce81eae74cce224cef3d8605525
3
+ size 6036024113
global_step1850/bf16_zero_pp_rank_7_mp_rank_00_optim_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b5cdeb33c6b57d649f1891ded0a84035558453d8ba181730662864e957de75f8
3
+ size 6036024113
global_step1850/zero_pp_rank_0_mp_rank_00_model_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:64465a4d5e0217b0cdc248228bc8425585621fa2e9a783b3cf86e4819cb54f0f
3
+ size 216003
global_step1850/zero_pp_rank_1_mp_rank_00_model_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1a246966307ada579325b581361de6ffbc6a7910d8a52f53fd655cc60963e772
3
+ size 215939
global_step1850/zero_pp_rank_2_mp_rank_00_model_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:667666ca35ab3dace19eabf2bf187e7d67a3fa79dfed1f998518a4d71078b6d4
3
+ size 215939
global_step1850/zero_pp_rank_3_mp_rank_00_model_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5c27700b5c0c918d9a6b1e52c329bfefc0c4c9372571cd8f89cbe0e3bf217b55
3
+ size 215939
global_step1850/zero_pp_rank_4_mp_rank_00_model_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f88416d25cf6f0fdaf382fc5e077e253777e6396544b871ddcea8db4e233980f
3
+ size 215939
global_step1850/zero_pp_rank_5_mp_rank_00_model_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:be9855cd706265e7433910e7e9bb83062232648ad24570c164cf82cafbb30db9
3
+ size 215939
global_step1850/zero_pp_rank_6_mp_rank_00_model_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:272914bd5050b781620bc972ed9d2be19135c4812c6e5782fa9116380f5086ff
3
+ size 215939
global_step1850/zero_pp_rank_7_mp_rank_00_model_states.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8e3b5c17b9816baf942bed9baaf2bb5849f0c35b6a48d1774b7f263d7aaed1a3
3
+ size 215939
latest ADDED
@@ -0,0 +1 @@
 
 
1
+ global_step1850
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
pytorch_model.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4b6776571c92782a911cd00901cd952e7e88491fc7d1eaf741d8401da40b7cac
3
+ size 8048161023
rng_state_0.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1cda6d24b28d9c72f826f6320c3b3c4895ae791a450cbc0a49cef3dbabb47b22
3
+ size 16325
rng_state_1.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ac5774343b3e9af9f98c6b34ac6cd59da75d7a000ba55d978b626b5a518c62ce
3
+ size 16389
rng_state_2.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0d4ebd1026a19ecc47e4adf5776d5dc16ffbf82b1a0920dba81c32f1e6847972
3
+ size 16389
rng_state_3.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1c4c9780e7d0bc34ae1a630315bdb4132898fca227ab35076c257fdc493ccbcc
3
+ size 16389
rng_state_4.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:db3d8046220ffc80777256849210a5f9849d9cdc015da416d62d0365ac7913af
3
+ size 16389
rng_state_5.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e0fce36685b8a5f63ccaaeb7be2e585659cc7cb591395edba11a00f80a266b1b
3
+ size 16389
rng_state_6.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f07577852f18ee444c0dd215e12c7d10eec5e0bedf4e1a13b3792eb77d980180
3
+ size 16389
rng_state_7.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:92be095c17967628e2fa00701c040d012e25b4d85f2ac9d639f3d9e45ff7d956
3
+ size 16389
scheduler.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:650c5117e69d01cf250e2e0489ef173b403968de9a7d0bb1df029d8ab26f39a3
3
+ size 1465
sft_qwen_var_classifier.py ADDED
@@ -0,0 +1,728 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Qwen Variable Classifier for SAT Cube-and-Conquer
3
+
4
+ This script trains a transformer-based policy to select the next branching variable
5
+ for SAT (Boolean Satisfiability) solving using the Cube-and-Conquer approach.
6
+
7
+ == Problem Overview ==
8
+ In Cube-and-Conquer SAT solving, we split a hard SAT problem into subproblems ("cubes")
9
+ by choosing variables to branch on. The quality of variable selection significantly
10
+ affects solving performance. This model learns to predict good branching variables
11
+ from expert demonstrations.
12
+
13
+ == Architecture ==
14
+ - Backbone: Qwen3-4B (pretrained causal language model)
15
+ - Head: LayerNorm + Linear classifier over variable IDs (1 to max_vars)
16
+ - The model reads a CNF formula as text and outputs logits for each possible variable
17
+
18
+ == Training Approach ==
19
+ - Supervised Fine-Tuning (SFT) on expert variable choices
20
+ - Masked classification: only variables appearing in the CNF are valid choices
21
+ - Loss: Cross-entropy with invalid variable logits masked to -infinity
22
+
23
+ == Data Format ==
24
+ JSONL with fields:
25
+ - "cnf": DIMACS-format CNF text (e.g., "p cnf 100 200\n1 -2 3 0\n...")
26
+ - "label": integer variable ID to branch on (1 to max_vars)
27
+ """
28
+
29
+ import os
30
+ import argparse
31
+ from dataclasses import dataclass
32
+ from typing import Any, Dict, List
33
+ import numpy as np
34
+ import torch
35
+ import torch.nn as nn
36
+ import torch.nn.functional as F
37
+ from datasets import load_dataset
38
+ from transformers import (
39
+ AutoConfig,
40
+ AutoTokenizer,
41
+ AutoModelForCausalLM,
42
+ TrainingArguments,
43
+ Trainer,
44
+ set_seed,
45
+ )
46
+
47
+
48
+ # =============================================================================
49
+ # DEBUG FLAG: Set to True to enable verbose debug output, False to disable
50
+ # Can also be controlled via environment variable: DEBUG_TRAINING=1
51
+ # =============================================================================
52
+ DEBUG_TRAINING = os.environ.get("DEBUG_TRAINING", "0") == "1"
53
+
54
+
55
+ # =============================================================================
56
+ # CNF PARSING: Extract valid variables from DIMACS CNF text
57
+ # =============================================================================
58
+
59
+ def cnf_valid_mask(cnf_text: str, max_vars: int) -> List[int]:
60
+ """
61
+ Build a binary mask indicating which variable IDs appear in the CNF.
62
+
63
+ This is crucial for masked classification:
64
+ - A variable that doesn't appear in the (simplified) CNF cannot be branched on
65
+ - By masking invalid variables, we ensure the model only learns over valid choices
66
+
67
+ Args:
68
+ cnf_text: DIMACS-format CNF string. Format example:
69
+ p cnf 100 200 # header: 100 variables, 200 clauses
70
+ 1 -2 3 0 # clause: (x1 OR NOT x2 OR x3)
71
+ -1 4 0 # clause: (NOT x1 OR x4)
72
+ ...
73
+ max_vars: Maximum variable ID supported (typically 500)
74
+
75
+ Returns:
76
+ List of length (max_vars + 1) where:
77
+ - mask[0] = 0 (unused, variables are 1-indexed)
78
+ - mask[v] = 1 if variable v appears in any clause
79
+ - mask[v] = 0 if variable v does not appear
80
+
81
+ Note: We skip the header line "p cnf ..." to avoid capturing the clause count
82
+ as a valid variable (which was a bug in the original regex-based approach).
83
+ """
84
+ mask = [0] * (max_vars + 1)
85
+
86
+ for line in cnf_text.split('\n'):
87
+ line = line.strip()
88
+
89
+ # Skip empty lines, comment lines (start with 'c'), and header line (starts with 'p')
90
+ # The header "p cnf <num_vars> <num_clauses>" would incorrectly add num_clauses as a variable
91
+ if not line or line.startswith('c') or line.startswith('p'):
92
+ continue
93
+
94
+ # Parse clause: space-separated integers ending with 0
95
+ # Each integer is a literal: positive = variable, negative = negated variable
96
+ # Example: "1 -2 3 0" means (x1 OR NOT x2 OR x3)
97
+ for tok in line.split():
98
+ try:
99
+ lit = int(tok)
100
+ v = abs(lit) # Variable ID is absolute value of literal
101
+ if 1 <= v <= max_vars:
102
+ mask[v] = 1
103
+ except ValueError:
104
+ continue # Skip non-integer tokens (shouldn't happen in valid DIMACS)
105
+
106
+ # Fallback: if no variables found (e.g., truncated/malformed input), allow all
107
+ # This prevents the model from having zero valid outputs
108
+ if sum(mask) == 0:
109
+ for v in range(1, max_vars + 1):
110
+ mask[v] = 1
111
+
112
+ return mask
113
+
114
+
115
+ # =============================================================================
116
+ # MODEL: Qwen backbone with classification head for variable selection
117
+ # =============================================================================
118
+
119
+ class QwenVarClassifier(nn.Module):
120
+ """
121
+ Transformer-based variable classifier for SAT branching.
122
+
123
+ Architecture:
124
+ Input (CNF text)
125
+ → Tokenize
126
+ → Qwen3-4B backbone (frozen initially, fine-tuned with small LR)
127
+ → Extract last token's hidden state (sequence pooling)
128
+ → LayerNorm (stabilizes hidden state magnitude)
129
+ → Linear head (hidden_dim → num_classes)
130
+ → Logits for each variable ID
131
+
132
+ Why this architecture?
133
+ 1. Pretrained LLM backbone understands text structure and can learn CNF patterns
134
+ 2. Last-token pooling: the final token has attended to the entire input
135
+ 3. LayerNorm: Qwen's hidden states have large magnitudes; normalizing prevents
136
+ exploding gradients when combined with randomly-initialized head
137
+ 4. Single linear head: simple, interpretable, efficient
138
+ """
139
+
140
+ def __init__(self, base_model_name: str, max_vars: int):
141
+ """
142
+ Initialize the classifier.
143
+
144
+ Args:
145
+ base_model_name: HuggingFace model ID (e.g., "Qwen/Qwen3-4B")
146
+ max_vars: Maximum variable ID to classify (e.g., 500)
147
+ Output dimension will be max_vars + 1 (index 0 unused)
148
+ """
149
+ super().__init__()
150
+ self.max_vars = max_vars
151
+
152
+ # Load Qwen configuration and enable hidden state output
153
+ cfg = AutoConfig.from_pretrained(base_model_name)
154
+ cfg.output_hidden_states = True # We need hidden states, not just logits
155
+
156
+ # Load pretrained Qwen model
157
+ # Using bfloat16 for memory efficiency on modern GPUs (H100, A100)
158
+ self.backbone = AutoModelForCausalLM.from_pretrained(
159
+ base_model_name,
160
+ config=cfg,
161
+ torch_dtype=torch.bfloat16 if torch.cuda.is_available() else torch.float32,
162
+ )
163
+
164
+ hidden = self.backbone.config.hidden_size # e.g., 2560 for Qwen3-4B
165
+
166
+ # LayerNorm to normalize hidden states before classification
167
+ # This is critical for stable training:
168
+ # - Qwen's hidden states can have large magnitude (std >> 1)
169
+ # - Randomly initialized linear head expects normalized inputs
170
+ # - Without LayerNorm, initial logits can be huge → high loss → exploding gradients
171
+ self.head_ln = nn.LayerNorm(hidden)
172
+
173
+ # Classification head: maps hidden state to variable logits
174
+ # Output shape: [batch, max_vars + 1]
175
+ # Index 0 is unused (variables are 1-indexed in DIMACS)
176
+ self.head = nn.Linear(hidden, max_vars + 1)
177
+
178
+ # Initialize head with standard small weights
179
+ # LayerNorm ensures the input has unit variance, so this init is appropriate
180
+ nn.init.normal_(self.head.weight, std=0.02)
181
+ nn.init.zeros_(self.head.bias)
182
+
183
+ # Expose backbone config for DeepSpeed compatibility
184
+ # DeepSpeed checks model.config.hidden_size for auto-configuration
185
+ self.config = self.backbone.config
186
+
187
+ def forward(self, input_ids, attention_mask, **kwargs):
188
+ """
189
+ Forward pass: CNF tokens → variable logits.
190
+
191
+ Args:
192
+ input_ids: [batch, seq_len] token IDs from tokenizer
193
+ attention_mask: [batch, seq_len] binary mask (1 = real token, 0 = padding)
194
+ **kwargs: ignored (allows passing 'labels' without error during eval)
195
+
196
+ Returns:
197
+ dict with "logits": [batch, max_vars + 1] raw classification logits
198
+ """
199
+ # Run through Qwen backbone
200
+ out = self.backbone(
201
+ input_ids=input_ids,
202
+ attention_mask=attention_mask,
203
+ output_hidden_states=True, # Need hidden states, not LM logits
204
+ use_cache=False, # Disable KV cache (not needed for training)
205
+ )
206
+
207
+ # Get hidden states from the last transformer layer
208
+ # Shape: [batch, seq_len, hidden_dim]
209
+ h = out.hidden_states[-1]
210
+
211
+ # Pool by taking the last non-padding token's hidden state
212
+ # This is the standard approach for causal LMs (like using [CLS] for BERT)
213
+ #
214
+ # Why last token?
215
+ # - In causal attention, each token only sees previous tokens
216
+ # - The last token has attended to the entire input sequence
217
+ # - It's a natural "summary" of the input
218
+ #
219
+ # Compute index of last real token: sum of attention mask minus 1
220
+ last_idx = attention_mask.sum(dim=1) - 1 # [batch]
221
+ last_idx = last_idx.clamp(min=0) # Safety: ensure non-negative
222
+
223
+ # Gather hidden state at the last token position for each batch element
224
+ b = torch.arange(h.size(0), device=h.device)
225
+ pooled = h[b, last_idx] # [batch, hidden_dim]
226
+
227
+ # DEBUG: Check hidden state stats
228
+ if DEBUG_TRAINING:
229
+ if not hasattr(self, '_debug_count'):
230
+ self._debug_count = 0
231
+ if self._debug_count < 3:
232
+ print(f"[DEBUG {self._debug_count}] pooled dtype={pooled.dtype}, mean={pooled.float().mean():.2f}, std={pooled.float().std():.2f}")
233
+ self._debug_count += 1
234
+
235
+ # Normalize hidden states for stable classification
236
+ pooled = self.head_ln(pooled)
237
+
238
+ # DEBUG: Check after LayerNorm
239
+ if DEBUG_TRAINING and hasattr(self, '_debug_count') and self._debug_count <= 3:
240
+ print(f"[DEBUG] after LN: dtype={pooled.dtype}, mean={pooled.float().mean():.4f}, std={pooled.float().std():.4f}")
241
+
242
+ # Project to variable logits
243
+ logits = self.head(pooled) # [batch, max_vars + 1]
244
+
245
+ # DEBUG: Check logits
246
+ if DEBUG_TRAINING and hasattr(self, '_debug_count') and self._debug_count <= 3:
247
+ print(f"[DEBUG] logits: dtype={logits.dtype}, mean={logits.float().mean():.2f}, std={logits.float().std():.2f}, min={logits.float().min():.2f}, max={logits.float().max():.2f}")
248
+
249
+ return {"logits": logits}
250
+
251
+
252
+ # =============================================================================
253
+ # DATA COLLATOR: Batch preparation with padding and mask handling
254
+ # =============================================================================
255
+
256
+ @dataclass
257
+ class Collator:
258
+ """
259
+ Custom data collator for variable classification.
260
+
261
+ Responsibilities:
262
+ 1. Pad variable-length token sequences to the same length within a batch
263
+ 2. Stack labels and valid_mask tensors
264
+ 3. Create proper attention masks for padded sequences
265
+
266
+ Why custom collator?
267
+ - We have custom fields (valid_mask) that need special handling
268
+ - Standard HF collators don't know about our mask format
269
+ """
270
+ tokenizer: Any # Tokenizer for padding configuration
271
+
272
+ def __call__(self, features: List[Dict[str, Any]]) -> Dict[str, torch.Tensor]:
273
+ """
274
+ Collate a list of examples into a batch.
275
+
276
+ Args:
277
+ features: List of dicts, each with:
278
+ - input_ids: List[int] - token IDs
279
+ - attention_mask: List[int] - attention mask
280
+ - label: int - target variable ID
281
+ - valid_mask: List[int] - binary mask of valid variables
282
+
283
+ Returns:
284
+ Dict with batched tensors:
285
+ - input_ids: [batch, max_seq_len]
286
+ - attention_mask: [batch, max_seq_len]
287
+ - labels: [batch]
288
+ - valid_mask: [batch, max_vars + 1]
289
+ """
290
+ # Convert to tensors
291
+ input_ids = [torch.tensor(f["input_ids"], dtype=torch.long) for f in features]
292
+ attention_mask = [torch.tensor(f["attention_mask"], dtype=torch.long) for f in features]
293
+ labels = torch.tensor([f["label"] for f in features], dtype=torch.long)
294
+ valid_mask = torch.tensor([f["valid_mask"] for f in features], dtype=torch.bool)
295
+
296
+ # Pad sequences to same length within batch
297
+ # Using pad_sequence pads shorter sequences with padding_value
298
+ input_ids = torch.nn.utils.rnn.pad_sequence(
299
+ input_ids,
300
+ batch_first=True,
301
+ padding_value=self.tokenizer.pad_token_id
302
+ )
303
+ attention_mask = torch.nn.utils.rnn.pad_sequence(
304
+ attention_mask,
305
+ batch_first=True,
306
+ padding_value=0 # Padding positions get 0 attention
307
+ )
308
+
309
+ return {
310
+ "input_ids": input_ids,
311
+ "attention_mask": attention_mask,
312
+ "labels": labels,
313
+ "valid_mask": valid_mask,
314
+ }
315
+
316
+
317
+ # =============================================================================
318
+ # TRAINER: Custom loss computation with variable masking
319
+ # =============================================================================
320
+
321
+ class MaskedVarTrainer(Trainer):
322
+ """
323
+ Custom HuggingFace Trainer with masked cross-entropy loss.
324
+
325
+ The key modification: before computing cross-entropy, we mask out logits
326
+ for invalid variables (those not appearing in the CNF). This ensures:
327
+ 1. The model cannot predict invalid variables
328
+ 2. No gradient flows to invalid variable logits
329
+ 3. Training focuses only on distinguishing valid choices
330
+
331
+ NOTE on displayed metrics:
332
+ - 'loss' shown by Trainer is summed across GPUs (loss × world_size)
333
+ We add 'true_loss' which is the actual per-sample loss
334
+ - 'grad_norm' is the L2 norm across ALL ~4B parameters BEFORE clipping
335
+ Values of 100-200 are normal for large models; it gets clipped to max_grad_norm
336
+ """
337
+
338
+ def __init__(self, *args, max_vars: int, **kwargs):
339
+ """
340
+ Args:
341
+ max_vars: Maximum variable ID (for sanity checking labels)
342
+ *args, **kwargs: Passed to parent Trainer
343
+ """
344
+ super().__init__(*args, **kwargs)
345
+ self.max_vars = max_vars
346
+ self._accumulated_loss = 0.0
347
+ self._loss_count = 0
348
+
349
+ def compute_loss(self, model, inputs, return_outputs=False, num_items_in_batch=None):
350
+ """
351
+ Compute masked cross-entropy loss for variable classification.
352
+
353
+ Algorithm:
354
+ 1. Extract labels and valid_mask from inputs
355
+ 2. Forward pass to get logits
356
+ 3. Set logits for invalid variables to -inf (or -1e4 for bf16 stability)
357
+ 4. Compute cross-entropy loss
358
+
359
+ Args:
360
+ model: The QwenVarClassifier
361
+ inputs: Dict with input_ids, attention_mask, labels, valid_mask
362
+ return_outputs: If True, return (loss, outputs) tuple
363
+ num_items_in_batch: Unused (for API compatibility)
364
+
365
+ Returns:
366
+ loss: Scalar loss value, or (loss, outputs) tuple if return_outputs=True
367
+ """
368
+ # Get labels and mask (don't pop - prediction_loop needs labels for compute_metrics)
369
+ labels = inputs.get("labels") # [batch]
370
+ valid_mask = inputs.get("valid_mask") # [batch, max_vars + 1] boolean
371
+
372
+ # Remove from inputs for model.forward (which doesn't expect them)
373
+ model_inputs = {k: v for k, v in inputs.items() if k not in ["labels", "valid_mask"]}
374
+
375
+ # Forward pass
376
+ outputs = model(**model_inputs)
377
+ logits = outputs["logits"] # [batch, max_vars + 1]
378
+
379
+ # DEBUG: Check if label is in valid_mask
380
+ if DEBUG_TRAINING:
381
+ if not hasattr(self, '_loss_debug_count'):
382
+ self._loss_debug_count = 0
383
+ if self._loss_debug_count < 5:
384
+ for i, (lbl, vmask) in enumerate(zip(labels, valid_mask)):
385
+ label_in_mask = vmask[lbl].item()
386
+ valid_count = vmask.sum().item()
387
+ logit_at_label = logits[i, lbl].item()
388
+ print(f"[LOSS DEBUG {self._loss_debug_count}] label={lbl.item()}, in_mask={label_in_mask}, valid_vars={valid_count}, logit_at_label={logit_at_label:.2f}")
389
+ self._loss_debug_count += 1
390
+
391
+ # Mask invalid variables by setting their logits to a large negative value
392
+ # After softmax, these will have probability ≈ 0
393
+ #
394
+ # Why -1e4 instead of -inf or -1e9?
395
+ # - bfloat16 has limited dynamic range
396
+ # - -1e9 can cause NaN issues when computing softmax/cross-entropy
397
+ # - -1e4 is small enough to give ~0 probability while staying numerically stable
398
+ logits = logits.masked_fill(~valid_mask.to(logits.device), -1e4)
399
+
400
+ # Sanity check: labels must be valid variable IDs (1 to max_vars)
401
+ # This catches data bugs early
402
+ if torch.any(labels <= 0) or torch.any(labels > self.max_vars):
403
+ bad = labels[(labels <= 0) | (labels > self.max_vars)].detach().cpu().tolist()
404
+ raise ValueError(f"Out-of-range labels detected (showing up to 20): {bad[:20]}")
405
+
406
+ # DEBUG: Check logit at label after masking
407
+ if DEBUG_TRAINING and hasattr(self, '_loss_debug_count') and self._loss_debug_count <= 5:
408
+ for i, lbl in enumerate(labels):
409
+ masked_logit = logits[i, lbl].item()
410
+ print(f"[LOSS DEBUG] after mask: logit_at_label={masked_logit:.2f}")
411
+
412
+ # Standard cross-entropy loss
413
+ # PyTorch's cross_entropy expects logits, not probabilities
414
+ loss = F.cross_entropy(logits, labels.to(logits.device))
415
+
416
+ # Track true loss for accurate logging
417
+ self._accumulated_loss += loss.item()
418
+ self._loss_count += 1
419
+
420
+ # DEBUG: Print loss
421
+ if DEBUG_TRAINING and hasattr(self, '_loss_debug_count') and self._loss_debug_count <= 5:
422
+ print(f"[LOSS DEBUG] loss={loss.item():.2f}")
423
+
424
+ # Return masked logits in outputs (so compute_metrics gets properly masked predictions)
425
+ masked_outputs = {"logits": logits}
426
+ return (loss, masked_outputs) if return_outputs else loss
427
+
428
+ def prediction_step(self, model, inputs, prediction_loss_only, ignore_keys=None):
429
+ """
430
+ Override prediction_step to properly return loss and logits for evaluation.
431
+
432
+ The default HF Trainer prediction_step doesn't work well with custom compute_loss,
433
+ so we implement our own that properly computes masked loss and returns logits.
434
+ """
435
+ model.eval()
436
+
437
+ with torch.no_grad():
438
+ # Get labels and mask
439
+ labels = inputs.get("labels")
440
+ valid_mask = inputs.get("valid_mask")
441
+
442
+ # Forward pass
443
+ model_inputs = {k: v for k, v in inputs.items() if k not in ["labels", "valid_mask"]}
444
+ outputs = model(**model_inputs)
445
+ logits = outputs["logits"]
446
+
447
+ # Mask invalid variables
448
+ logits = logits.masked_fill(~valid_mask.to(logits.device), -1e4)
449
+
450
+ # Compute loss
451
+ loss = F.cross_entropy(logits, labels.to(logits.device))
452
+
453
+ # Return (loss, logits, labels) - this is what compute_metrics expects
454
+ return (loss, logits.detach(), labels.detach())
455
+
456
+ def log(self, logs: Dict[str, float], start_time: float = None) -> None:
457
+ """
458
+ Override log to add true_loss and ensure eval metrics are logged to W&B.
459
+
460
+ The default 'loss' in HF Trainer is summed across GPUs in DDP/DeepSpeed.
461
+ We track the actual per-sample loss and report it as 'true_loss'.
462
+ """
463
+ if self._loss_count > 0:
464
+ # Calculate true average loss on this device
465
+ true_loss = self._accumulated_loss / self._loss_count
466
+ logs["true_loss"] = round(true_loss, 4)
467
+
468
+ # Reset for next logging interval
469
+ self._accumulated_loss = 0.0
470
+ self._loss_count = 0
471
+
472
+ # Let HF Trainer handle W&B logging - it manages step ordering correctly
473
+ super().log(logs, start_time)
474
+
475
+
476
+ def compute_metrics(eval_pred):
477
+ """
478
+ Compute accuracy for evaluation.
479
+
480
+ Args:
481
+ eval_pred: (logits, labels) from Trainer's prediction_loop
482
+ - logits: [num_samples, max_vars + 1] (already masked with -1e4 for invalid vars)
483
+ - labels: [num_samples]
484
+
485
+ Returns:
486
+ Dict with "accuracy" (Trainer will prefix with "eval_")
487
+
488
+ Note: eval_loss is computed automatically by Trainer from prediction_step's loss.
489
+ We don't need to compute it here.
490
+
491
+ Since invalid variables have logits ≈ -1e4, argmax will naturally avoid them.
492
+ """
493
+ logits, labels = eval_pred
494
+
495
+ # Accuracy: argmax prediction vs true label
496
+ preds = np.argmax(logits, axis=-1)
497
+ accuracy = float((preds == labels).mean())
498
+
499
+ return {"accuracy": accuracy}
500
+
501
+
502
+ def get_wandb_report_to():
503
+ """
504
+ Determine if this process should log to W&B.
505
+
506
+ Only the main process (rank 0) should log to W&B to avoid creating multiple runs.
507
+ Other ranks should not log to any external service.
508
+
509
+ Returns:
510
+ ["wandb"] for rank 0, [] for other ranks
511
+ """
512
+ local_rank = int(os.environ.get("LOCAL_RANK", 0))
513
+
514
+ if local_rank == 0:
515
+ return ["wandb"]
516
+ else:
517
+ return []
518
+
519
+
520
+ # =============================================================================
521
+ # MAIN: Training pipeline
522
+ # =============================================================================
523
+
524
+ def main():
525
+ """
526
+ Main training function.
527
+
528
+ Pipeline:
529
+ 1. Parse command line arguments
530
+ 2. Load tokenizer and datasets
531
+ 3. Preprocess: tokenize CNF text, compute valid masks
532
+ 4. Initialize model with pretrained backbone + new classification head
533
+ 5. Configure training (optimizer, scheduler, logging, etc.)
534
+ 6. Train and evaluate
535
+ """
536
+ ap = argparse.ArgumentParser(
537
+ description="Train a Qwen-based variable classifier for SAT branching"
538
+ )
539
+
540
+ # Model and data arguments
541
+ ap.add_argument("--model_name", type=str, default="Qwen/Qwen3-4B",
542
+ help="HuggingFace model ID for the backbone")
543
+ ap.add_argument("--train_jsonl", type=str, required=True,
544
+ help="Path to training data (JSONL with 'cnf' and 'label' fields)")
545
+ ap.add_argument("--valid_jsonl", type=str, required=True,
546
+ help="Path to validation data (same format)")
547
+ ap.add_argument("--output_dir", type=str, default="./out_qwen_var_sft",
548
+ help="Directory for checkpoints and logs")
549
+ ap.add_argument("--max_vars", type=int, default=500,
550
+ help="Maximum variable ID (determines output dimension)")
551
+ ap.add_argument("--max_length", type=int, default=8192,
552
+ help="Maximum sequence length in tokens (truncates longer CNFs)")
553
+ ap.add_argument("--seed", type=int, default=0,
554
+ help="Random seed for reproducibility")
555
+
556
+ # Training hyperparameters
557
+ ap.add_argument("--per_device_train_batch_size", type=int, default=1,
558
+ help="Batch size per GPU for training")
559
+ ap.add_argument("--per_device_eval_batch_size", type=int, default=1,
560
+ help="Batch size per GPU for evaluation")
561
+ ap.add_argument("--gradient_accumulation_steps", type=int, default=8,
562
+ help="Accumulate gradients over this many steps (effective batch = this * batch_size * num_gpus)")
563
+ ap.add_argument("--learning_rate", type=float, default=5e-6,
564
+ help="Peak learning rate (after warmup). Lower than typical fine-tuning due to classification head")
565
+ ap.add_argument("--num_train_epochs", type=float, default=3.0,
566
+ help="Total training epochs")
567
+ ap.add_argument("--warmup_ratio", type=float, default=0.03,
568
+ help="Fraction of training steps for learning rate warmup")
569
+ ap.add_argument("--weight_decay", type=float, default=0.0,
570
+ help="Weight decay (L2 regularization)")
571
+ ap.add_argument("--logging_steps", type=int, default=10,
572
+ help="Log training metrics every N steps")
573
+ ap.add_argument("--eval_steps", type=int, default=200,
574
+ help="Evaluate every N steps")
575
+ ap.add_argument("--save_steps", type=int, default=200,
576
+ help="Save checkpoint every N steps")
577
+ ap.add_argument("--report_to", type=str, default="wandb",
578
+ choices=["wandb", "tensorboard", "none"],
579
+ help="Logging backend")
580
+ ap.add_argument("--deepspeed", type=str, default=None,
581
+ help="Path to DeepSpeed config JSON for distributed training")
582
+ ap.add_argument("--resume_from_checkpoint", type=str, default=None,
583
+ help="Path to checkpoint directory to resume from. If a directory is given, "
584
+ "the latest checkpoint in that directory will be used.")
585
+
586
+ args = ap.parse_args()
587
+
588
+ # Set random seeds for reproducibility
589
+ set_seed(args.seed)
590
+
591
+ # Load tokenizer
592
+ # Qwen uses a byte-level BPE tokenizer
593
+ tok = AutoTokenizer.from_pretrained(args.model_name, use_fast=True)
594
+ if tok.pad_token is None:
595
+ # Qwen doesn't have a dedicated pad token; use eos as pad
596
+ tok.pad_token = tok.eos_token
597
+
598
+ # Load datasets from JSONL files
599
+ ds = load_dataset(
600
+ "json",
601
+ data_files={"train": args.train_jsonl, "validation": args.valid_jsonl},
602
+ )
603
+
604
+ def preprocess(ex):
605
+ """
606
+ Preprocess a single example.
607
+
608
+ Steps:
609
+ 1. Tokenize the CNF text
610
+ 2. Compute valid variable mask
611
+ 3. Return features for training
612
+
613
+ Args:
614
+ ex: Dict with 'cnf' (str) and 'label' (int)
615
+
616
+ Returns:
617
+ Dict with input_ids, attention_mask, label, valid_mask
618
+ """
619
+ cnf = ex["cnf"]
620
+ label = int(ex["label"])
621
+
622
+ # Tokenize CNF text
623
+ # No special prompt/instruction - the model learns to interpret raw CNF
624
+ enc = tok(
625
+ cnf,
626
+ truncation=True,
627
+ max_length=args.max_length,
628
+ padding=False # We handle padding in the collator
629
+ )
630
+
631
+ return {
632
+ "input_ids": enc["input_ids"],
633
+ "attention_mask": enc["attention_mask"],
634
+ "label": label,
635
+ "valid_mask": cnf_valid_mask(cnf, args.max_vars),
636
+ }
637
+
638
+ # Apply preprocessing to all examples
639
+ # remove_columns drops original fields (cnf, label) since we've extracted what we need
640
+ ds = ds.map(preprocess, remove_columns=ds["train"].column_names)
641
+
642
+ # Initialize model
643
+ model = QwenVarClassifier(args.model_name, max_vars=args.max_vars)
644
+
645
+ # Enable gradient checkpointing to save memory on long sequences
646
+ # This trades compute for memory by recomputing activations during backward pass
647
+ model.backbone.gradient_checkpointing_enable()
648
+
649
+ # Configure W&B logging (only rank 0 logs to avoid duplicate runs)
650
+ report_to = get_wandb_report_to()
651
+
652
+ # Configure training
653
+ training_args = TrainingArguments(
654
+ output_dir=args.output_dir,
655
+ overwrite_output_dir=True,
656
+
657
+ # Precision settings for modern GPUs
658
+ bf16=True, # Use bfloat16 for training (good for H100/A100)
659
+ tf32=True, # Enable TF32 for faster matmuls on Ampere+
660
+
661
+ # Batch configuration
662
+ per_device_train_batch_size=args.per_device_train_batch_size,
663
+ per_device_eval_batch_size=args.per_device_eval_batch_size,
664
+ gradient_accumulation_steps=args.gradient_accumulation_steps,
665
+
666
+ # Optimizer settings
667
+ learning_rate=args.learning_rate,
668
+ warmup_ratio=args.warmup_ratio,
669
+ num_train_epochs=args.num_train_epochs,
670
+ weight_decay=args.weight_decay,
671
+
672
+ # Gradient clipping for training stability
673
+ # Clips gradient norm to this value if it exceeds it
674
+ # This prevents exploding gradients from destabilizing training
675
+ max_grad_norm=1.0,
676
+
677
+ # Logging and evaluation
678
+ logging_steps=args.logging_steps,
679
+ eval_strategy="steps",
680
+ eval_steps=args.eval_steps,
681
+
682
+ # Checkpointing - keep best checkpoints based on validation accuracy
683
+ save_strategy="steps",
684
+ save_steps=args.save_steps,
685
+ save_total_limit=3, # Keep best 3 checkpoints
686
+ load_best_model_at_end=True, # Load best checkpoint at end of training
687
+ metric_for_best_model="eval_accuracy", # Use validation accuracy to determine best
688
+ greater_is_better=True, # Higher accuracy is better
689
+
690
+ # Logging backend
691
+ report_to=report_to,
692
+ run_name=os.environ.get("WANDB_RUN_NAME", "qwen-var-sft") if args.report_to == "wandb" else None,
693
+ logging_dir=os.path.join(args.output_dir, "logs"),
694
+
695
+ # Important: don't remove valid_mask column (we need it in compute_loss)
696
+ remove_unused_columns=False,
697
+
698
+ # DDP settings (for multi-GPU)
699
+ ddp_find_unused_parameters=False,
700
+
701
+ # DeepSpeed for efficient distributed training
702
+ deepspeed=args.deepspeed,
703
+
704
+ # Use pickle format for saving (safetensors has issues with some weight tying configs)
705
+ save_safetensors=False,
706
+ )
707
+
708
+ # Create trainer with custom loss computation
709
+ trainer = MaskedVarTrainer(
710
+ model=model,
711
+ args=training_args,
712
+ train_dataset=ds["train"],
713
+ eval_dataset=ds["validation"],
714
+ tokenizer=tok,
715
+ data_collator=Collator(tok),
716
+ compute_metrics=compute_metrics,
717
+ max_vars=args.max_vars,
718
+ )
719
+
720
+ # Train! (resume from checkpoint if specified)
721
+ trainer.train(resume_from_checkpoint=args.resume_from_checkpoint)
722
+
723
+ # Final evaluation
724
+ trainer.evaluate()
725
+
726
+
727
+ if __name__ == "__main__":
728
+ main()
special_tokens_map.json ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ "<|im_start|>",
4
+ "<|im_end|>",
5
+ "<|object_ref_start|>",
6
+ "<|object_ref_end|>",
7
+ "<|box_start|>",
8
+ "<|box_end|>",
9
+ "<|quad_start|>",
10
+ "<|quad_end|>",
11
+ "<|vision_start|>",
12
+ "<|vision_end|>",
13
+ "<|vision_pad|>",
14
+ "<|image_pad|>",
15
+ "<|video_pad|>"
16
+ ],
17
+ "eos_token": {
18
+ "content": "<|im_end|>",
19
+ "lstrip": false,
20
+ "normalized": false,
21
+ "rstrip": false,
22
+ "single_word": false
23
+ },
24
+ "pad_token": {
25
+ "content": "<|endoftext|>",
26
+ "lstrip": false,
27
+ "normalized": false,
28
+ "rstrip": false,
29
+ "single_word": false
30
+ }
31
+ }
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b7a6a993d40b42d517297bb247ff66679e5bc9dd7a5143be0620faf210b42861
3
+ size 11422753
tokenizer_config.json ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_bos_token": false,
3
+ "add_prefix_space": false,
4
+ "added_tokens_decoder": {
5
+ "151643": {
6
+ "content": "<|endoftext|>",
7
+ "lstrip": false,
8
+ "normalized": false,
9
+ "rstrip": false,
10
+ "single_word": false,
11
+ "special": true
12
+ },
13
+ "151644": {
14
+ "content": "<|im_start|>",
15
+ "lstrip": false,
16
+ "normalized": false,
17
+ "rstrip": false,
18
+ "single_word": false,
19
+ "special": true
20
+ },
21
+ "151645": {
22
+ "content": "<|im_end|>",
23
+ "lstrip": false,
24
+ "normalized": false,
25
+ "rstrip": false,
26
+ "single_word": false,
27
+ "special": true
28
+ },
29
+ "151646": {
30
+ "content": "<|object_ref_start|>",
31
+ "lstrip": false,
32
+ "normalized": false,
33
+ "rstrip": false,
34
+ "single_word": false,
35
+ "special": true
36
+ },
37
+ "151647": {
38
+ "content": "<|object_ref_end|>",
39
+ "lstrip": false,
40
+ "normalized": false,
41
+ "rstrip": false,
42
+ "single_word": false,
43
+ "special": true
44
+ },
45
+ "151648": {
46
+ "content": "<|box_start|>",
47
+ "lstrip": false,
48
+ "normalized": false,
49
+ "rstrip": false,
50
+ "single_word": false,
51
+ "special": true
52
+ },
53
+ "151649": {
54
+ "content": "<|box_end|>",
55
+ "lstrip": false,
56
+ "normalized": false,
57
+ "rstrip": false,
58
+ "single_word": false,
59
+ "special": true
60
+ },
61
+ "151650": {
62
+ "content": "<|quad_start|>",
63
+ "lstrip": false,
64
+ "normalized": false,
65
+ "rstrip": false,
66
+ "single_word": false,
67
+ "special": true
68
+ },
69
+ "151651": {
70
+ "content": "<|quad_end|>",
71
+ "lstrip": false,
72
+ "normalized": false,
73
+ "rstrip": false,
74
+ "single_word": false,
75
+ "special": true
76
+ },
77
+ "151652": {
78
+ "content": "<|vision_start|>",
79
+ "lstrip": false,
80
+ "normalized": false,
81
+ "rstrip": false,
82
+ "single_word": false,
83
+ "special": true
84
+ },
85
+ "151653": {
86
+ "content": "<|vision_end|>",
87
+ "lstrip": false,
88
+ "normalized": false,
89
+ "rstrip": false,
90
+ "single_word": false,
91
+ "special": true
92
+ },
93
+ "151654": {
94
+ "content": "<|vision_pad|>",
95
+ "lstrip": false,
96
+ "normalized": false,
97
+ "rstrip": false,
98
+ "single_word": false,
99
+ "special": true
100
+ },
101
+ "151655": {
102
+ "content": "<|image_pad|>",
103
+ "lstrip": false,
104
+ "normalized": false,
105
+ "rstrip": false,
106
+ "single_word": false,
107
+ "special": true
108
+ },
109
+ "151656": {
110
+ "content": "<|video_pad|>",
111
+ "lstrip": false,
112
+ "normalized": false,
113
+ "rstrip": false,
114
+ "single_word": false,
115
+ "special": true
116
+ },
117
+ "151657": {
118
+ "content": "<tool_call>",
119
+ "lstrip": false,
120
+ "normalized": false,
121
+ "rstrip": false,
122
+ "single_word": false,
123
+ "special": false
124
+ },
125
+ "151658": {
126
+ "content": "</tool_call>",
127
+ "lstrip": false,
128
+ "normalized": false,
129
+ "rstrip": false,
130
+ "single_word": false,
131
+ "special": false
132
+ },
133
+ "151659": {
134
+ "content": "<|fim_prefix|>",
135
+ "lstrip": false,
136
+ "normalized": false,
137
+ "rstrip": false,
138
+ "single_word": false,
139
+ "special": false
140
+ },
141
+ "151660": {
142
+ "content": "<|fim_middle|>",
143
+ "lstrip": false,
144
+ "normalized": false,
145
+ "rstrip": false,
146
+ "single_word": false,
147
+ "special": false
148
+ },
149
+ "151661": {
150
+ "content": "<|fim_suffix|>",
151
+ "lstrip": false,
152
+ "normalized": false,
153
+ "rstrip": false,
154
+ "single_word": false,
155
+ "special": false
156
+ },
157
+ "151662": {
158
+ "content": "<|fim_pad|>",
159
+ "lstrip": false,
160
+ "normalized": false,
161
+ "rstrip": false,
162
+ "single_word": false,
163
+ "special": false
164
+ },
165
+ "151663": {
166
+ "content": "<|repo_name|>",
167
+ "lstrip": false,
168
+ "normalized": false,
169
+ "rstrip": false,
170
+ "single_word": false,
171
+ "special": false
172
+ },
173
+ "151664": {
174
+ "content": "<|file_sep|>",
175
+ "lstrip": false,
176
+ "normalized": false,
177
+ "rstrip": false,
178
+ "single_word": false,
179
+ "special": false
180
+ },
181
+ "151665": {
182
+ "content": "<tool_response>",
183
+ "lstrip": false,
184
+ "normalized": false,
185
+ "rstrip": false,
186
+ "single_word": false,
187
+ "special": false
188
+ },
189
+ "151666": {
190
+ "content": "</tool_response>",
191
+ "lstrip": false,
192
+ "normalized": false,
193
+ "rstrip": false,
194
+ "single_word": false,
195
+ "special": false
196
+ },
197
+ "151667": {
198
+ "content": "<think>",
199
+ "lstrip": false,
200
+ "normalized": false,
201
+ "rstrip": false,
202
+ "single_word": false,
203
+ "special": false
204
+ },
205
+ "151668": {
206
+ "content": "</think>",
207
+ "lstrip": false,
208
+ "normalized": false,
209
+ "rstrip": false,
210
+ "single_word": false,
211
+ "special": false
212
+ }
213
+ },
214
+ "additional_special_tokens": [
215
+ "<|im_start|>",
216
+ "<|im_end|>",
217
+ "<|object_ref_start|>",
218
+ "<|object_ref_end|>",
219
+ "<|box_start|>",
220
+ "<|box_end|>",
221
+ "<|quad_start|>",
222
+ "<|quad_end|>",
223
+ "<|vision_start|>",
224
+ "<|vision_end|>",
225
+ "<|vision_pad|>",
226
+ "<|image_pad|>",
227
+ "<|video_pad|>"
228
+ ],
229
+ "bos_token": null,
230
+ "clean_up_tokenization_spaces": false,
231
+ "eos_token": "<|im_end|>",
232
+ "errors": "replace",
233
+ "extra_special_tokens": {},
234
+ "model_max_length": 131072,
235
+ "pad_token": "<|endoftext|>",
236
+ "split_special_tokens": false,
237
+ "tokenizer_class": "Qwen2Tokenizer",
238
+ "unk_token": null
239
+ }
trainer_state.json ADDED
@@ -0,0 +1,1847 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "best_global_step": 1750,
3
+ "best_metric": 0.21951219512195122,
4
+ "best_model_checkpoint": "out_qwen_4b_sft_augmented/checkpoint-1750",
5
+ "epoch": 2.9185243637798384,
6
+ "eval_steps": 50,
7
+ "global_step": 1850,
8
+ "is_hyper_param_search": false,
9
+ "is_local_process_zero": true,
10
+ "is_world_process_zero": true,
11
+ "log_history": [
12
+ {
13
+ "epoch": 0.015782205563227462,
14
+ "grad_norm": 324.9078480271927,
15
+ "learning_rate": 2.3560209424083772e-07,
16
+ "loss": 36.8443,
17
+ "step": 10,
18
+ "true_loss": 4.5233
19
+ },
20
+ {
21
+ "epoch": 0.031564411126454923,
22
+ "grad_norm": 168.6194251999255,
23
+ "learning_rate": 4.973821989528796e-07,
24
+ "loss": 36.0645,
25
+ "step": 20,
26
+ "true_loss": 4.3899
27
+ },
28
+ {
29
+ "epoch": 0.04734661668968238,
30
+ "grad_norm": 192.6442003874084,
31
+ "learning_rate": 7.591623036649215e-07,
32
+ "loss": 37.1343,
33
+ "step": 30,
34
+ "true_loss": 4.7917
35
+ },
36
+ {
37
+ "epoch": 0.06312882225290985,
38
+ "grad_norm": 169.69405108448686,
39
+ "learning_rate": 1.0209424083769635e-06,
40
+ "loss": 35.8286,
41
+ "step": 40,
42
+ "true_loss": 4.5888
43
+ },
44
+ {
45
+ "epoch": 0.0789110278161373,
46
+ "grad_norm": 177.6752080525516,
47
+ "learning_rate": 1.2827225130890052e-06,
48
+ "loss": 35.1516,
49
+ "step": 50,
50
+ "true_loss": 4.1833
51
+ },
52
+ {
53
+ "epoch": 0.0789110278161373,
54
+ "eval_accuracy": 0.02328159645232816,
55
+ "eval_loss": 4.40457820892334,
56
+ "eval_runtime": 23.7263,
57
+ "eval_samples_per_second": 38.017,
58
+ "eval_steps_per_second": 4.763,
59
+ "step": 50
60
+ },
61
+ {
62
+ "epoch": 0.09469323337936476,
63
+ "grad_norm": 175.29116271759068,
64
+ "learning_rate": 1.5445026178010472e-06,
65
+ "loss": 34.7314,
66
+ "step": 60,
67
+ "true_loss": 4.224
68
+ },
69
+ {
70
+ "epoch": 0.11047543894259222,
71
+ "grad_norm": 753.0264561952334,
72
+ "learning_rate": 1.8062827225130891e-06,
73
+ "loss": 33.9206,
74
+ "step": 70,
75
+ "true_loss": 4.0565
76
+ },
77
+ {
78
+ "epoch": 0.1262576445058197,
79
+ "grad_norm": 200.47588314223879,
80
+ "learning_rate": 2.068062827225131e-06,
81
+ "loss": 34.0037,
82
+ "step": 80,
83
+ "true_loss": 4.3621
84
+ },
85
+ {
86
+ "epoch": 0.14203985006904715,
87
+ "grad_norm": 164.18077066091436,
88
+ "learning_rate": 2.329842931937173e-06,
89
+ "loss": 33.3705,
90
+ "step": 90,
91
+ "true_loss": 4.1432
92
+ },
93
+ {
94
+ "epoch": 0.1578220556322746,
95
+ "grad_norm": 144.60587833889255,
96
+ "learning_rate": 2.591623036649215e-06,
97
+ "loss": 33.3276,
98
+ "step": 100,
99
+ "true_loss": 4.1424
100
+ },
101
+ {
102
+ "epoch": 0.1578220556322746,
103
+ "eval_accuracy": 0.043237250554323724,
104
+ "eval_loss": 4.096348285675049,
105
+ "eval_runtime": 23.3422,
106
+ "eval_samples_per_second": 38.643,
107
+ "eval_steps_per_second": 4.841,
108
+ "step": 100
109
+ },
110
+ {
111
+ "epoch": 0.17360426119550207,
112
+ "grad_norm": 270.635578631285,
113
+ "learning_rate": 2.853403141361257e-06,
114
+ "loss": 32.6581,
115
+ "step": 110,
116
+ "true_loss": 4.1497
117
+ },
118
+ {
119
+ "epoch": 0.18938646675872953,
120
+ "grad_norm": 100.33088317059614,
121
+ "learning_rate": 3.115183246073299e-06,
122
+ "loss": 32.8629,
123
+ "step": 120,
124
+ "true_loss": 4.1273
125
+ },
126
+ {
127
+ "epoch": 0.20516867232195699,
128
+ "grad_norm": 108.96506382691295,
129
+ "learning_rate": 3.3769633507853404e-06,
130
+ "loss": 33.0279,
131
+ "step": 130,
132
+ "true_loss": 4.1729
133
+ },
134
+ {
135
+ "epoch": 0.22095087788518444,
136
+ "grad_norm": 101.57985399798042,
137
+ "learning_rate": 3.6387434554973826e-06,
138
+ "loss": 33.3713,
139
+ "step": 140,
140
+ "true_loss": 4.2379
141
+ },
142
+ {
143
+ "epoch": 0.2367330834484119,
144
+ "grad_norm": 109.81214136700734,
145
+ "learning_rate": 3.900523560209425e-06,
146
+ "loss": 33.2539,
147
+ "step": 150,
148
+ "true_loss": 4.388
149
+ },
150
+ {
151
+ "epoch": 0.2367330834484119,
152
+ "eval_accuracy": 0.04434589800443459,
153
+ "eval_loss": 4.049750328063965,
154
+ "eval_runtime": 23.5037,
155
+ "eval_samples_per_second": 38.377,
156
+ "eval_steps_per_second": 4.808,
157
+ "step": 150
158
+ },
159
+ {
160
+ "epoch": 0.2525152890116394,
161
+ "grad_norm": 131.31761293379333,
162
+ "learning_rate": 4.1623036649214665e-06,
163
+ "loss": 32.8656,
164
+ "step": 160,
165
+ "true_loss": 4.1088
166
+ },
167
+ {
168
+ "epoch": 0.26829749457486685,
169
+ "grad_norm": 93.21133961816744,
170
+ "learning_rate": 4.424083769633508e-06,
171
+ "loss": 32.7579,
172
+ "step": 170,
173
+ "true_loss": 4.092
174
+ },
175
+ {
176
+ "epoch": 0.2840797001380943,
177
+ "grad_norm": 99.10049214777489,
178
+ "learning_rate": 4.68586387434555e-06,
179
+ "loss": 32.777,
180
+ "step": 180,
181
+ "true_loss": 4.1288
182
+ },
183
+ {
184
+ "epoch": 0.29986190570132176,
185
+ "grad_norm": 103.48370344024212,
186
+ "learning_rate": 4.947643979057592e-06,
187
+ "loss": 32.983,
188
+ "step": 190,
189
+ "true_loss": 3.9901
190
+ },
191
+ {
192
+ "epoch": 0.3156441112645492,
193
+ "grad_norm": 101.42410788589872,
194
+ "learning_rate": 4.976621858562245e-06,
195
+ "loss": 32.8281,
196
+ "step": 200,
197
+ "true_loss": 4.1047
198
+ },
199
+ {
200
+ "epoch": 0.3156441112645492,
201
+ "eval_accuracy": 0.06873614190687362,
202
+ "eval_loss": 4.009181022644043,
203
+ "eval_runtime": 23.3653,
204
+ "eval_samples_per_second": 38.604,
205
+ "eval_steps_per_second": 4.836,
206
+ "step": 200
207
+ },
208
+ {
209
+ "epoch": 0.3314263168277767,
210
+ "grad_norm": 83.2901468921201,
211
+ "learning_rate": 4.94739918176505e-06,
212
+ "loss": 33.1028,
213
+ "step": 210,
214
+ "true_loss": 4.0052
215
+ },
216
+ {
217
+ "epoch": 0.34720852239100414,
218
+ "grad_norm": 170.23336077552057,
219
+ "learning_rate": 4.9181765049678555e-06,
220
+ "loss": 32.644,
221
+ "step": 220,
222
+ "true_loss": 4.1984
223
+ },
224
+ {
225
+ "epoch": 0.3629907279542316,
226
+ "grad_norm": 73.10967930914595,
227
+ "learning_rate": 4.888953828170661e-06,
228
+ "loss": 32.9998,
229
+ "step": 230,
230
+ "true_loss": 4.1035
231
+ },
232
+ {
233
+ "epoch": 0.37877293351745905,
234
+ "grad_norm": 75.66187004852954,
235
+ "learning_rate": 4.859731151373466e-06,
236
+ "loss": 32.6017,
237
+ "step": 240,
238
+ "true_loss": 3.9774
239
+ },
240
+ {
241
+ "epoch": 0.3945551390806865,
242
+ "grad_norm": 101.5303291876841,
243
+ "learning_rate": 4.830508474576272e-06,
244
+ "loss": 32.5215,
245
+ "step": 250,
246
+ "true_loss": 4.107
247
+ },
248
+ {
249
+ "epoch": 0.3945551390806865,
250
+ "eval_accuracy": 0.07095343680709534,
251
+ "eval_loss": 3.933732271194458,
252
+ "eval_runtime": 23.3822,
253
+ "eval_samples_per_second": 38.576,
254
+ "eval_steps_per_second": 4.833,
255
+ "step": 250
256
+ },
257
+ {
258
+ "epoch": 0.41033734464391397,
259
+ "grad_norm": 87.68390524050062,
260
+ "learning_rate": 4.801285797779077e-06,
261
+ "loss": 32.8537,
262
+ "step": 260,
263
+ "true_loss": 4.0852
264
+ },
265
+ {
266
+ "epoch": 0.42611955020714143,
267
+ "grad_norm": 83.56798040873913,
268
+ "learning_rate": 4.772063120981883e-06,
269
+ "loss": 32.452,
270
+ "step": 270,
271
+ "true_loss": 4.1138
272
+ },
273
+ {
274
+ "epoch": 0.4419017557703689,
275
+ "grad_norm": 76.69106361052454,
276
+ "learning_rate": 4.742840444184687e-06,
277
+ "loss": 31.8737,
278
+ "step": 280,
279
+ "true_loss": 3.8671
280
+ },
281
+ {
282
+ "epoch": 0.45768396133359635,
283
+ "grad_norm": 79.70560950668154,
284
+ "learning_rate": 4.713617767387494e-06,
285
+ "loss": 32.1678,
286
+ "step": 290,
287
+ "true_loss": 3.9949
288
+ },
289
+ {
290
+ "epoch": 0.4734661668968238,
291
+ "grad_norm": 77.14726547694464,
292
+ "learning_rate": 4.684395090590298e-06,
293
+ "loss": 32.2324,
294
+ "step": 300,
295
+ "true_loss": 4.1541
296
+ },
297
+ {
298
+ "epoch": 0.4734661668968238,
299
+ "eval_accuracy": 0.07206208425720621,
300
+ "eval_loss": 3.944307804107666,
301
+ "eval_runtime": 24.0666,
302
+ "eval_samples_per_second": 37.479,
303
+ "eval_steps_per_second": 4.695,
304
+ "step": 300
305
+ },
306
+ {
307
+ "epoch": 0.4892483724600513,
308
+ "grad_norm": 74.39357075334843,
309
+ "learning_rate": 4.655172413793104e-06,
310
+ "loss": 32.7538,
311
+ "step": 310,
312
+ "true_loss": 3.9691
313
+ },
314
+ {
315
+ "epoch": 0.5050305780232788,
316
+ "grad_norm": 69.2140729496397,
317
+ "learning_rate": 4.625949736995909e-06,
318
+ "loss": 32.241,
319
+ "step": 320,
320
+ "true_loss": 4.1026
321
+ },
322
+ {
323
+ "epoch": 0.5208127835865062,
324
+ "grad_norm": 76.34039893901215,
325
+ "learning_rate": 4.596727060198715e-06,
326
+ "loss": 32.7047,
327
+ "step": 330,
328
+ "true_loss": 4.2664
329
+ },
330
+ {
331
+ "epoch": 0.5365949891497337,
332
+ "grad_norm": 76.48584051124504,
333
+ "learning_rate": 4.56750438340152e-06,
334
+ "loss": 32.2899,
335
+ "step": 340,
336
+ "true_loss": 4.1581
337
+ },
338
+ {
339
+ "epoch": 0.5523771947129611,
340
+ "grad_norm": 75.38836139042635,
341
+ "learning_rate": 4.5382817066043256e-06,
342
+ "loss": 32.8474,
343
+ "step": 350,
344
+ "true_loss": 4.0243
345
+ },
346
+ {
347
+ "epoch": 0.5523771947129611,
348
+ "eval_accuracy": 0.07317073170731707,
349
+ "eval_loss": 3.8937127590179443,
350
+ "eval_runtime": 23.6141,
351
+ "eval_samples_per_second": 38.198,
352
+ "eval_steps_per_second": 4.785,
353
+ "step": 350
354
+ },
355
+ {
356
+ "epoch": 0.5681594002761886,
357
+ "grad_norm": 85.00115390444991,
358
+ "learning_rate": 4.509059029807131e-06,
359
+ "loss": 31.7532,
360
+ "step": 360,
361
+ "true_loss": 3.988
362
+ },
363
+ {
364
+ "epoch": 0.583941605839416,
365
+ "grad_norm": 76.08205167618928,
366
+ "learning_rate": 4.479836353009936e-06,
367
+ "loss": 31.7753,
368
+ "step": 370,
369
+ "true_loss": 3.9777
370
+ },
371
+ {
372
+ "epoch": 0.5997238114026435,
373
+ "grad_norm": 68.74246027512453,
374
+ "learning_rate": 4.450613676212742e-06,
375
+ "loss": 31.4578,
376
+ "step": 380,
377
+ "true_loss": 3.9916
378
+ },
379
+ {
380
+ "epoch": 0.6155060169658709,
381
+ "grad_norm": 71.81332443942438,
382
+ "learning_rate": 4.4213909994155465e-06,
383
+ "loss": 32.0656,
384
+ "step": 390,
385
+ "true_loss": 4.1254
386
+ },
387
+ {
388
+ "epoch": 0.6312882225290984,
389
+ "grad_norm": 71.77472037885094,
390
+ "learning_rate": 4.392168322618352e-06,
391
+ "loss": 32.2929,
392
+ "step": 400,
393
+ "true_loss": 3.8869
394
+ },
395
+ {
396
+ "epoch": 0.6312882225290984,
397
+ "eval_accuracy": 0.1130820399113082,
398
+ "eval_loss": 3.7887723445892334,
399
+ "eval_runtime": 23.904,
400
+ "eval_samples_per_second": 37.734,
401
+ "eval_steps_per_second": 4.727,
402
+ "step": 400
403
+ },
404
+ {
405
+ "epoch": 0.647070428092326,
406
+ "grad_norm": 71.4147738866297,
407
+ "learning_rate": 4.3629456458211574e-06,
408
+ "loss": 31.9759,
409
+ "step": 410,
410
+ "true_loss": 3.9893
411
+ },
412
+ {
413
+ "epoch": 0.6628526336555534,
414
+ "grad_norm": 73.99693807240743,
415
+ "learning_rate": 4.333722969023963e-06,
416
+ "loss": 31.8449,
417
+ "step": 420,
418
+ "true_loss": 3.9648
419
+ },
420
+ {
421
+ "epoch": 0.6786348392187809,
422
+ "grad_norm": 74.124412349921,
423
+ "learning_rate": 4.304500292226768e-06,
424
+ "loss": 31.9984,
425
+ "step": 430,
426
+ "true_loss": 3.8608
427
+ },
428
+ {
429
+ "epoch": 0.6944170447820083,
430
+ "grad_norm": 80.24673254296576,
431
+ "learning_rate": 4.275277615429574e-06,
432
+ "loss": 31.8185,
433
+ "step": 440,
434
+ "true_loss": 4.033
435
+ },
436
+ {
437
+ "epoch": 0.7101992503452358,
438
+ "grad_norm": 83.65131551190922,
439
+ "learning_rate": 4.246054938632379e-06,
440
+ "loss": 31.7604,
441
+ "step": 450,
442
+ "true_loss": 3.9851
443
+ },
444
+ {
445
+ "epoch": 0.7101992503452358,
446
+ "eval_accuracy": 0.11862527716186252,
447
+ "eval_loss": 3.731326103210449,
448
+ "eval_runtime": 23.8861,
449
+ "eval_samples_per_second": 37.762,
450
+ "eval_steps_per_second": 4.731,
451
+ "step": 450
452
+ },
453
+ {
454
+ "epoch": 0.7259814559084632,
455
+ "grad_norm": 82.91785549569512,
456
+ "learning_rate": 4.216832261835184e-06,
457
+ "loss": 31.9212,
458
+ "step": 460,
459
+ "true_loss": 4.0262
460
+ },
461
+ {
462
+ "epoch": 0.7417636614716907,
463
+ "grad_norm": 77.3700837190592,
464
+ "learning_rate": 4.18760958503799e-06,
465
+ "loss": 31.558,
466
+ "step": 470,
467
+ "true_loss": 3.9037
468
+ },
469
+ {
470
+ "epoch": 0.7575458670349181,
471
+ "grad_norm": 79.2567711758356,
472
+ "learning_rate": 4.158386908240795e-06,
473
+ "loss": 31.9821,
474
+ "step": 480,
475
+ "true_loss": 3.9674
476
+ },
477
+ {
478
+ "epoch": 0.7733280725981456,
479
+ "grad_norm": 79.15209026205977,
480
+ "learning_rate": 4.1291642314436e-06,
481
+ "loss": 31.6287,
482
+ "step": 490,
483
+ "true_loss": 4.0236
484
+ },
485
+ {
486
+ "epoch": 0.789110278161373,
487
+ "grad_norm": 82.91621808879624,
488
+ "learning_rate": 4.0999415546464065e-06,
489
+ "loss": 31.1936,
490
+ "step": 500,
491
+ "true_loss": 3.8798
492
+ },
493
+ {
494
+ "epoch": 0.789110278161373,
495
+ "eval_accuracy": 0.1419068736141907,
496
+ "eval_loss": 3.6688694953918457,
497
+ "eval_runtime": 23.5535,
498
+ "eval_samples_per_second": 38.296,
499
+ "eval_steps_per_second": 4.798,
500
+ "step": 500
501
+ },
502
+ {
503
+ "epoch": 0.8048924837246005,
504
+ "grad_norm": 81.33416413304444,
505
+ "learning_rate": 4.070718877849211e-06,
506
+ "loss": 31.9352,
507
+ "step": 510,
508
+ "true_loss": 3.9601
509
+ },
510
+ {
511
+ "epoch": 0.8206746892878279,
512
+ "grad_norm": 84.38809367146038,
513
+ "learning_rate": 4.0414962010520166e-06,
514
+ "loss": 31.4177,
515
+ "step": 520,
516
+ "true_loss": 4.0845
517
+ },
518
+ {
519
+ "epoch": 0.8364568948510555,
520
+ "grad_norm": 71.30053276240011,
521
+ "learning_rate": 4.012273524254822e-06,
522
+ "loss": 31.7603,
523
+ "step": 530,
524
+ "true_loss": 3.997
525
+ },
526
+ {
527
+ "epoch": 0.8522391004142829,
528
+ "grad_norm": 80.60566610130194,
529
+ "learning_rate": 3.9830508474576275e-06,
530
+ "loss": 31.2764,
531
+ "step": 540,
532
+ "true_loss": 3.8168
533
+ },
534
+ {
535
+ "epoch": 0.8680213059775104,
536
+ "grad_norm": 91.53898913592603,
537
+ "learning_rate": 3.953828170660433e-06,
538
+ "loss": 31.4915,
539
+ "step": 550,
540
+ "true_loss": 3.9316
541
+ },
542
+ {
543
+ "epoch": 0.8680213059775104,
544
+ "eval_accuracy": 0.1419068736141907,
545
+ "eval_loss": 3.6105031967163086,
546
+ "eval_runtime": 23.4993,
547
+ "eval_samples_per_second": 38.384,
548
+ "eval_steps_per_second": 4.809,
549
+ "step": 550
550
+ },
551
+ {
552
+ "epoch": 0.8838035115407378,
553
+ "grad_norm": 80.87596019476308,
554
+ "learning_rate": 3.924605493863238e-06,
555
+ "loss": 31.1347,
556
+ "step": 560,
557
+ "true_loss": 3.7968
558
+ },
559
+ {
560
+ "epoch": 0.8995857171039653,
561
+ "grad_norm": 80.68070986181071,
562
+ "learning_rate": 3.895382817066044e-06,
563
+ "loss": 31.7808,
564
+ "step": 570,
565
+ "true_loss": 3.9588
566
+ },
567
+ {
568
+ "epoch": 0.9153679226671927,
569
+ "grad_norm": 82.14608732630818,
570
+ "learning_rate": 3.8661601402688484e-06,
571
+ "loss": 31.0608,
572
+ "step": 580,
573
+ "true_loss": 3.9779
574
+ },
575
+ {
576
+ "epoch": 0.9311501282304202,
577
+ "grad_norm": 79.11284293573352,
578
+ "learning_rate": 3.836937463471655e-06,
579
+ "loss": 30.9633,
580
+ "step": 590,
581
+ "true_loss": 4.0027
582
+ },
583
+ {
584
+ "epoch": 0.9469323337936476,
585
+ "grad_norm": 74.83038134855214,
586
+ "learning_rate": 3.8077147866744598e-06,
587
+ "loss": 31.2218,
588
+ "step": 600,
589
+ "true_loss": 3.8863
590
+ },
591
+ {
592
+ "epoch": 0.9469323337936476,
593
+ "eval_accuracy": 0.1419068736141907,
594
+ "eval_loss": 3.6132075786590576,
595
+ "eval_runtime": 24.0285,
596
+ "eval_samples_per_second": 37.539,
597
+ "eval_steps_per_second": 4.703,
598
+ "step": 600
599
+ },
600
+ {
601
+ "epoch": 0.9627145393568751,
602
+ "grad_norm": 77.6288128447819,
603
+ "learning_rate": 3.7784921098772652e-06,
604
+ "loss": 31.104,
605
+ "step": 610,
606
+ "true_loss": 3.8553
607
+ },
608
+ {
609
+ "epoch": 0.9784967449201026,
610
+ "grad_norm": 78.73674435660126,
611
+ "learning_rate": 3.7492694330800707e-06,
612
+ "loss": 31.4592,
613
+ "step": 620,
614
+ "true_loss": 3.8146
615
+ },
616
+ {
617
+ "epoch": 0.99427895048333,
618
+ "grad_norm": 84.19142784542193,
619
+ "learning_rate": 3.7200467562828757e-06,
620
+ "loss": 31.4694,
621
+ "step": 630,
622
+ "true_loss": 3.8633
623
+ },
624
+ {
625
+ "epoch": 1.0094693233379364,
626
+ "grad_norm": 83.97120538549059,
627
+ "learning_rate": 3.6908240794856816e-06,
628
+ "loss": 29.9569,
629
+ "step": 640,
630
+ "true_loss": 3.9506
631
+ },
632
+ {
633
+ "epoch": 1.0252515289011639,
634
+ "grad_norm": 78.03329090311782,
635
+ "learning_rate": 3.6616014026884866e-06,
636
+ "loss": 30.6145,
637
+ "step": 650,
638
+ "true_loss": 3.8972
639
+ },
640
+ {
641
+ "epoch": 1.0252515289011639,
642
+ "eval_accuracy": 0.13303769401330376,
643
+ "eval_loss": 3.5806682109832764,
644
+ "eval_runtime": 23.4297,
645
+ "eval_samples_per_second": 38.498,
646
+ "eval_steps_per_second": 4.823,
647
+ "step": 650
648
+ },
649
+ {
650
+ "epoch": 1.0410337344643914,
651
+ "grad_norm": 90.48371602841107,
652
+ "learning_rate": 3.6323787258912916e-06,
653
+ "loss": 30.3281,
654
+ "step": 660,
655
+ "true_loss": 4.0951
656
+ },
657
+ {
658
+ "epoch": 1.056815940027619,
659
+ "grad_norm": 80.37129983569977,
660
+ "learning_rate": 3.6031560490940975e-06,
661
+ "loss": 30.4516,
662
+ "step": 670,
663
+ "true_loss": 4.0298
664
+ },
665
+ {
666
+ "epoch": 1.0725981455908462,
667
+ "grad_norm": 89.0421974632656,
668
+ "learning_rate": 3.5739333722969025e-06,
669
+ "loss": 30.5053,
670
+ "step": 680,
671
+ "true_loss": 3.838
672
+ },
673
+ {
674
+ "epoch": 1.0883803511540737,
675
+ "grad_norm": 87.6238382263665,
676
+ "learning_rate": 3.544710695499708e-06,
677
+ "loss": 30.1458,
678
+ "step": 690,
679
+ "true_loss": 3.4672
680
+ },
681
+ {
682
+ "epoch": 1.1041625567173012,
683
+ "grad_norm": 93.33199336725635,
684
+ "learning_rate": 3.5154880187025135e-06,
685
+ "loss": 29.9857,
686
+ "step": 700,
687
+ "true_loss": 3.8479
688
+ },
689
+ {
690
+ "epoch": 1.1041625567173012,
691
+ "eval_accuracy": 0.1574279379157428,
692
+ "eval_loss": 3.5641186237335205,
693
+ "eval_runtime": 23.6052,
694
+ "eval_samples_per_second": 38.212,
695
+ "eval_steps_per_second": 4.787,
696
+ "step": 700
697
+ },
698
+ {
699
+ "epoch": 1.1199447622805287,
700
+ "grad_norm": 92.22724838108498,
701
+ "learning_rate": 3.486265341905319e-06,
702
+ "loss": 29.8985,
703
+ "step": 710,
704
+ "true_loss": 3.6761
705
+ },
706
+ {
707
+ "epoch": 1.1357269678437563,
708
+ "grad_norm": 84.13971221580583,
709
+ "learning_rate": 3.457042665108124e-06,
710
+ "loss": 30.7157,
711
+ "step": 720,
712
+ "true_loss": 3.6518
713
+ },
714
+ {
715
+ "epoch": 1.1515091734069836,
716
+ "grad_norm": 85.8960190061776,
717
+ "learning_rate": 3.42781998831093e-06,
718
+ "loss": 30.2104,
719
+ "step": 730,
720
+ "true_loss": 3.7526
721
+ },
722
+ {
723
+ "epoch": 1.167291378970211,
724
+ "grad_norm": 86.69215126012148,
725
+ "learning_rate": 3.398597311513735e-06,
726
+ "loss": 29.405,
727
+ "step": 740,
728
+ "true_loss": 4.0226
729
+ },
730
+ {
731
+ "epoch": 1.1830735845334386,
732
+ "grad_norm": 87.86033437742292,
733
+ "learning_rate": 3.3693746347165403e-06,
734
+ "loss": 30.511,
735
+ "step": 750,
736
+ "true_loss": 3.7897
737
+ },
738
+ {
739
+ "epoch": 1.1830735845334386,
740
+ "eval_accuracy": 0.14523281596452328,
741
+ "eval_loss": 3.493298292160034,
742
+ "eval_runtime": 23.8274,
743
+ "eval_samples_per_second": 37.856,
744
+ "eval_steps_per_second": 4.742,
745
+ "step": 750
746
+ },
747
+ {
748
+ "epoch": 1.198855790096666,
749
+ "grad_norm": 111.93866332819323,
750
+ "learning_rate": 3.3401519579193458e-06,
751
+ "loss": 29.8573,
752
+ "step": 760,
753
+ "true_loss": 3.7307
754
+ },
755
+ {
756
+ "epoch": 1.2146379956598934,
757
+ "grad_norm": 78.19039410059621,
758
+ "learning_rate": 3.310929281122151e-06,
759
+ "loss": 30.2595,
760
+ "step": 770,
761
+ "true_loss": 3.7585
762
+ },
763
+ {
764
+ "epoch": 1.230420201223121,
765
+ "grad_norm": 136.24794475282891,
766
+ "learning_rate": 3.2817066043249562e-06,
767
+ "loss": 30.1392,
768
+ "step": 780,
769
+ "true_loss": 3.6031
770
+ },
771
+ {
772
+ "epoch": 1.2462024067863484,
773
+ "grad_norm": 83.26617285476617,
774
+ "learning_rate": 3.252483927527762e-06,
775
+ "loss": 29.7774,
776
+ "step": 790,
777
+ "true_loss": 3.8831
778
+ },
779
+ {
780
+ "epoch": 1.261984612349576,
781
+ "grad_norm": 82.12832696286748,
782
+ "learning_rate": 3.223261250730567e-06,
783
+ "loss": 30.2729,
784
+ "step": 800,
785
+ "true_loss": 3.7239
786
+ },
787
+ {
788
+ "epoch": 1.261984612349576,
789
+ "eval_accuracy": 0.15964523281596452,
790
+ "eval_loss": 3.5300114154815674,
791
+ "eval_runtime": 23.4485,
792
+ "eval_samples_per_second": 38.467,
793
+ "eval_steps_per_second": 4.819,
794
+ "step": 800
795
+ },
796
+ {
797
+ "epoch": 1.2777668179128034,
798
+ "grad_norm": 90.3512257461839,
799
+ "learning_rate": 3.194038573933372e-06,
800
+ "loss": 30.1961,
801
+ "step": 810,
802
+ "true_loss": 3.784
803
+ },
804
+ {
805
+ "epoch": 1.2935490234760307,
806
+ "grad_norm": 84.55475078707286,
807
+ "learning_rate": 3.164815897136178e-06,
808
+ "loss": 29.3181,
809
+ "step": 820,
810
+ "true_loss": 3.5114
811
+ },
812
+ {
813
+ "epoch": 1.3093312290392582,
814
+ "grad_norm": 89.4992221052368,
815
+ "learning_rate": 3.135593220338983e-06,
816
+ "loss": 30.2988,
817
+ "step": 830,
818
+ "true_loss": 3.7831
819
+ },
820
+ {
821
+ "epoch": 1.3251134346024858,
822
+ "grad_norm": 92.43123125189919,
823
+ "learning_rate": 3.1063705435417885e-06,
824
+ "loss": 30.0873,
825
+ "step": 840,
826
+ "true_loss": 3.8634
827
+ },
828
+ {
829
+ "epoch": 1.340895640165713,
830
+ "grad_norm": 89.04832868320074,
831
+ "learning_rate": 3.0771478667445944e-06,
832
+ "loss": 30.2665,
833
+ "step": 850,
834
+ "true_loss": 3.8983
835
+ },
836
+ {
837
+ "epoch": 1.340895640165713,
838
+ "eval_accuracy": 0.16851441241685144,
839
+ "eval_loss": 3.462191343307495,
840
+ "eval_runtime": 23.8924,
841
+ "eval_samples_per_second": 37.753,
842
+ "eval_steps_per_second": 4.73,
843
+ "step": 850
844
+ },
845
+ {
846
+ "epoch": 1.3566778457289406,
847
+ "grad_norm": 92.16494941680725,
848
+ "learning_rate": 3.0479251899473994e-06,
849
+ "loss": 29.7738,
850
+ "step": 860,
851
+ "true_loss": 4.0234
852
+ },
853
+ {
854
+ "epoch": 1.372460051292168,
855
+ "grad_norm": 85.57074344764075,
856
+ "learning_rate": 3.0187025131502045e-06,
857
+ "loss": 30.0651,
858
+ "step": 870,
859
+ "true_loss": 3.7162
860
+ },
861
+ {
862
+ "epoch": 1.3882422568553956,
863
+ "grad_norm": 97.12213474754635,
864
+ "learning_rate": 2.9894798363530103e-06,
865
+ "loss": 30.0534,
866
+ "step": 880,
867
+ "true_loss": 3.969
868
+ },
869
+ {
870
+ "epoch": 1.404024462418623,
871
+ "grad_norm": 85.14532114581857,
872
+ "learning_rate": 2.9602571595558154e-06,
873
+ "loss": 30.1717,
874
+ "step": 890,
875
+ "true_loss": 3.8654
876
+ },
877
+ {
878
+ "epoch": 1.4198066679818504,
879
+ "grad_norm": 89.01307343902022,
880
+ "learning_rate": 2.931034482758621e-06,
881
+ "loss": 30.2877,
882
+ "step": 900,
883
+ "true_loss": 3.6224
884
+ },
885
+ {
886
+ "epoch": 1.4198066679818504,
887
+ "eval_accuracy": 0.16186252771618626,
888
+ "eval_loss": 3.4574382305145264,
889
+ "eval_runtime": 23.3454,
890
+ "eval_samples_per_second": 38.637,
891
+ "eval_steps_per_second": 4.84,
892
+ "step": 900
893
+ },
894
+ {
895
+ "epoch": 1.435588873545078,
896
+ "grad_norm": 87.24388793474637,
897
+ "learning_rate": 2.9018118059614263e-06,
898
+ "loss": 30.8903,
899
+ "step": 910,
900
+ "true_loss": 3.8262
901
+ },
902
+ {
903
+ "epoch": 1.4513710791083054,
904
+ "grad_norm": 84.04918766102597,
905
+ "learning_rate": 2.8725891291642317e-06,
906
+ "loss": 29.8196,
907
+ "step": 920,
908
+ "true_loss": 3.918
909
+ },
910
+ {
911
+ "epoch": 1.4671532846715327,
912
+ "grad_norm": 83.16951966482195,
913
+ "learning_rate": 2.8433664523670368e-06,
914
+ "loss": 29.6097,
915
+ "step": 930,
916
+ "true_loss": 3.4664
917
+ },
918
+ {
919
+ "epoch": 1.4829354902347602,
920
+ "grad_norm": 96.29394268139959,
921
+ "learning_rate": 2.8141437755698426e-06,
922
+ "loss": 29.7147,
923
+ "step": 940,
924
+ "true_loss": 3.6577
925
+ },
926
+ {
927
+ "epoch": 1.4987176957979877,
928
+ "grad_norm": 101.35324066409235,
929
+ "learning_rate": 2.7849210987726477e-06,
930
+ "loss": 29.4593,
931
+ "step": 950,
932
+ "true_loss": 3.6391
933
+ },
934
+ {
935
+ "epoch": 1.4987176957979877,
936
+ "eval_accuracy": 0.15188470066518847,
937
+ "eval_loss": 3.448209762573242,
938
+ "eval_runtime": 23.74,
939
+ "eval_samples_per_second": 37.995,
940
+ "eval_steps_per_second": 4.76,
941
+ "step": 950
942
+ },
943
+ {
944
+ "epoch": 1.5144999013612153,
945
+ "grad_norm": 91.01958083657513,
946
+ "learning_rate": 2.7556984219754535e-06,
947
+ "loss": 29.4563,
948
+ "step": 960,
949
+ "true_loss": 3.5778
950
+ },
951
+ {
952
+ "epoch": 1.5302821069244428,
953
+ "grad_norm": 94.87158519297142,
954
+ "learning_rate": 2.7264757451782586e-06,
955
+ "loss": 29.8641,
956
+ "step": 970,
957
+ "true_loss": 3.9124
958
+ },
959
+ {
960
+ "epoch": 1.5460643124876703,
961
+ "grad_norm": 84.01959219280997,
962
+ "learning_rate": 2.697253068381064e-06,
963
+ "loss": 29.8265,
964
+ "step": 980,
965
+ "true_loss": 3.5047
966
+ },
967
+ {
968
+ "epoch": 1.5618465180508976,
969
+ "grad_norm": 91.64799353240991,
970
+ "learning_rate": 2.6680303915838695e-06,
971
+ "loss": 29.858,
972
+ "step": 990,
973
+ "true_loss": 3.701
974
+ },
975
+ {
976
+ "epoch": 1.577628723614125,
977
+ "grad_norm": 88.05009850532113,
978
+ "learning_rate": 2.638807714786675e-06,
979
+ "loss": 29.9069,
980
+ "step": 1000,
981
+ "true_loss": 3.6317
982
+ },
983
+ {
984
+ "epoch": 1.577628723614125,
985
+ "eval_accuracy": 0.14412416851441243,
986
+ "eval_loss": 3.4386119842529297,
987
+ "eval_runtime": 24.0921,
988
+ "eval_samples_per_second": 37.44,
989
+ "eval_steps_per_second": 4.69,
990
+ "step": 1000
991
+ },
992
+ {
993
+ "epoch": 1.5934109291773524,
994
+ "grad_norm": 88.61468815912133,
995
+ "learning_rate": 2.60958503798948e-06,
996
+ "loss": 29.7709,
997
+ "step": 1010,
998
+ "true_loss": 3.6406
999
+ },
1000
+ {
1001
+ "epoch": 1.60919313474058,
1002
+ "grad_norm": 85.25549864190619,
1003
+ "learning_rate": 2.580362361192286e-06,
1004
+ "loss": 29.8656,
1005
+ "step": 1020,
1006
+ "true_loss": 4.0205
1007
+ },
1008
+ {
1009
+ "epoch": 1.6249753403038074,
1010
+ "grad_norm": 95.17123739206981,
1011
+ "learning_rate": 2.551139684395091e-06,
1012
+ "loss": 29.3146,
1013
+ "step": 1030,
1014
+ "true_loss": 3.7517
1015
+ },
1016
+ {
1017
+ "epoch": 1.640757545867035,
1018
+ "grad_norm": 94.05266971651754,
1019
+ "learning_rate": 2.521917007597896e-06,
1020
+ "loss": 29.5985,
1021
+ "step": 1040,
1022
+ "true_loss": 3.8767
1023
+ },
1024
+ {
1025
+ "epoch": 1.6565397514302624,
1026
+ "grad_norm": 84.23330948930467,
1027
+ "learning_rate": 2.4926943308007014e-06,
1028
+ "loss": 29.6116,
1029
+ "step": 1050,
1030
+ "true_loss": 3.6806
1031
+ },
1032
+ {
1033
+ "epoch": 1.6565397514302624,
1034
+ "eval_accuracy": 0.1574279379157428,
1035
+ "eval_loss": 3.4331889152526855,
1036
+ "eval_runtime": 24.0418,
1037
+ "eval_samples_per_second": 37.518,
1038
+ "eval_steps_per_second": 4.7,
1039
+ "step": 1050
1040
+ },
1041
+ {
1042
+ "epoch": 1.67232195699349,
1043
+ "grad_norm": 95.80967931580453,
1044
+ "learning_rate": 2.463471654003507e-06,
1045
+ "loss": 29.4546,
1046
+ "step": 1060,
1047
+ "true_loss": 3.5296
1048
+ },
1049
+ {
1050
+ "epoch": 1.6881041625567172,
1051
+ "grad_norm": 89.21975858244956,
1052
+ "learning_rate": 2.4342489772063123e-06,
1053
+ "loss": 29.4728,
1054
+ "step": 1070,
1055
+ "true_loss": 3.8411
1056
+ },
1057
+ {
1058
+ "epoch": 1.7038863681199448,
1059
+ "grad_norm": 93.36233191510571,
1060
+ "learning_rate": 2.4050263004091177e-06,
1061
+ "loss": 29.5254,
1062
+ "step": 1080,
1063
+ "true_loss": 3.7742
1064
+ },
1065
+ {
1066
+ "epoch": 1.7196685736831723,
1067
+ "grad_norm": 107.3636400374849,
1068
+ "learning_rate": 2.375803623611923e-06,
1069
+ "loss": 29.5684,
1070
+ "step": 1090,
1071
+ "true_loss": 3.6389
1072
+ },
1073
+ {
1074
+ "epoch": 1.7354507792463996,
1075
+ "grad_norm": 1304.6259656582167,
1076
+ "learning_rate": 2.3465809468147286e-06,
1077
+ "loss": 29.638,
1078
+ "step": 1100,
1079
+ "true_loss": 3.7105
1080
+ },
1081
+ {
1082
+ "epoch": 1.7354507792463996,
1083
+ "eval_accuracy": 0.16518847006651885,
1084
+ "eval_loss": 3.4311046600341797,
1085
+ "eval_runtime": 23.6704,
1086
+ "eval_samples_per_second": 38.107,
1087
+ "eval_steps_per_second": 4.774,
1088
+ "step": 1100
1089
+ },
1090
+ {
1091
+ "epoch": 1.751232984809627,
1092
+ "grad_norm": 96.2130469861494,
1093
+ "learning_rate": 2.3173582700175337e-06,
1094
+ "loss": 29.3766,
1095
+ "step": 1110,
1096
+ "true_loss": 3.67
1097
+ },
1098
+ {
1099
+ "epoch": 1.7670151903728546,
1100
+ "grad_norm": 95.92673596052384,
1101
+ "learning_rate": 2.288135593220339e-06,
1102
+ "loss": 29.3919,
1103
+ "step": 1120,
1104
+ "true_loss": 3.8554
1105
+ },
1106
+ {
1107
+ "epoch": 1.782797395936082,
1108
+ "grad_norm": 88.05948564467495,
1109
+ "learning_rate": 2.2589129164231446e-06,
1110
+ "loss": 29.2821,
1111
+ "step": 1130,
1112
+ "true_loss": 3.7715
1113
+ },
1114
+ {
1115
+ "epoch": 1.7985796014993096,
1116
+ "grad_norm": 90.55869365935298,
1117
+ "learning_rate": 2.22969023962595e-06,
1118
+ "loss": 29.7986,
1119
+ "step": 1140,
1120
+ "true_loss": 3.6651
1121
+ },
1122
+ {
1123
+ "epoch": 1.8143618070625371,
1124
+ "grad_norm": 94.20405819159555,
1125
+ "learning_rate": 2.2004675628287555e-06,
1126
+ "loss": 29.8496,
1127
+ "step": 1150,
1128
+ "true_loss": 3.7782
1129
+ },
1130
+ {
1131
+ "epoch": 1.8143618070625371,
1132
+ "eval_accuracy": 0.16186252771618626,
1133
+ "eval_loss": 3.4140689373016357,
1134
+ "eval_runtime": 24.0501,
1135
+ "eval_samples_per_second": 37.505,
1136
+ "eval_steps_per_second": 4.699,
1137
+ "step": 1150
1138
+ },
1139
+ {
1140
+ "epoch": 1.8301440126257644,
1141
+ "grad_norm": 87.96745013401917,
1142
+ "learning_rate": 2.171244886031561e-06,
1143
+ "loss": 29.5695,
1144
+ "step": 1160,
1145
+ "true_loss": 3.8398
1146
+ },
1147
+ {
1148
+ "epoch": 1.845926218188992,
1149
+ "grad_norm": 92.10246815773178,
1150
+ "learning_rate": 2.142022209234366e-06,
1151
+ "loss": 29.8099,
1152
+ "step": 1170,
1153
+ "true_loss": 3.9006
1154
+ },
1155
+ {
1156
+ "epoch": 1.8617084237522192,
1157
+ "grad_norm": 83.12415816117908,
1158
+ "learning_rate": 2.1127995324371714e-06,
1159
+ "loss": 30.2325,
1160
+ "step": 1180,
1161
+ "true_loss": 3.623
1162
+ },
1163
+ {
1164
+ "epoch": 1.8774906293154467,
1165
+ "grad_norm": 107.24249122552868,
1166
+ "learning_rate": 2.083576855639977e-06,
1167
+ "loss": 29.8222,
1168
+ "step": 1190,
1169
+ "true_loss": 3.5215
1170
+ },
1171
+ {
1172
+ "epoch": 1.8932728348786743,
1173
+ "grad_norm": 91.4088303372265,
1174
+ "learning_rate": 2.054354178842782e-06,
1175
+ "loss": 29.498,
1176
+ "step": 1200,
1177
+ "true_loss": 3.653
1178
+ },
1179
+ {
1180
+ "epoch": 1.8932728348786743,
1181
+ "eval_accuracy": 0.16851441241685144,
1182
+ "eval_loss": 3.4037177562713623,
1183
+ "eval_runtime": 23.8616,
1184
+ "eval_samples_per_second": 37.801,
1185
+ "eval_steps_per_second": 4.736,
1186
+ "step": 1200
1187
+ },
1188
+ {
1189
+ "epoch": 1.9090550404419018,
1190
+ "grad_norm": 100.69059595068175,
1191
+ "learning_rate": 2.0251315020455873e-06,
1192
+ "loss": 29.1097,
1193
+ "step": 1210,
1194
+ "true_loss": 3.5445
1195
+ },
1196
+ {
1197
+ "epoch": 1.9248372460051293,
1198
+ "grad_norm": 96.05062058766768,
1199
+ "learning_rate": 1.995908825248393e-06,
1200
+ "loss": 29.5919,
1201
+ "step": 1220,
1202
+ "true_loss": 3.6302
1203
+ },
1204
+ {
1205
+ "epoch": 1.9406194515683568,
1206
+ "grad_norm": 89.1551204065743,
1207
+ "learning_rate": 1.9666861484511982e-06,
1208
+ "loss": 29.0917,
1209
+ "step": 1230,
1210
+ "true_loss": 3.5472
1211
+ },
1212
+ {
1213
+ "epoch": 1.956401657131584,
1214
+ "grad_norm": 101.09204426369772,
1215
+ "learning_rate": 1.9374634716540037e-06,
1216
+ "loss": 28.8413,
1217
+ "step": 1240,
1218
+ "true_loss": 3.8083
1219
+ },
1220
+ {
1221
+ "epoch": 1.9721838626948116,
1222
+ "grad_norm": 105.57133293543227,
1223
+ "learning_rate": 1.908240794856809e-06,
1224
+ "loss": 29.533,
1225
+ "step": 1250,
1226
+ "true_loss": 3.7014
1227
+ },
1228
+ {
1229
+ "epoch": 1.9721838626948116,
1230
+ "eval_accuracy": 0.17516629711751663,
1231
+ "eval_loss": 3.385300397872925,
1232
+ "eval_runtime": 23.5478,
1233
+ "eval_samples_per_second": 38.305,
1234
+ "eval_steps_per_second": 4.799,
1235
+ "step": 1250
1236
+ },
1237
+ {
1238
+ "epoch": 1.987966068258039,
1239
+ "grad_norm": 96.01274952042326,
1240
+ "learning_rate": 1.8790181180596146e-06,
1241
+ "loss": 29.2844,
1242
+ "step": 1260,
1243
+ "true_loss": 3.8112
1244
+ },
1245
+ {
1246
+ "epoch": 2.0031564411126457,
1247
+ "grad_norm": 94.04158733000145,
1248
+ "learning_rate": 1.8497954412624196e-06,
1249
+ "loss": 27.161,
1250
+ "step": 1270,
1251
+ "true_loss": 3.399
1252
+ },
1253
+ {
1254
+ "epoch": 2.0189386466758728,
1255
+ "grad_norm": 113.00306213639786,
1256
+ "learning_rate": 1.820572764465225e-06,
1257
+ "loss": 27.5121,
1258
+ "step": 1280,
1259
+ "true_loss": 3.5377
1260
+ },
1261
+ {
1262
+ "epoch": 2.0347208522391003,
1263
+ "grad_norm": 128.85739550143202,
1264
+ "learning_rate": 1.7913500876680305e-06,
1265
+ "loss": 27.3831,
1266
+ "step": 1290,
1267
+ "true_loss": 3.3378
1268
+ },
1269
+ {
1270
+ "epoch": 2.0505030578023278,
1271
+ "grad_norm": 135.357215369742,
1272
+ "learning_rate": 1.7621274108708358e-06,
1273
+ "loss": 28.0219,
1274
+ "step": 1300,
1275
+ "true_loss": 3.6161
1276
+ },
1277
+ {
1278
+ "epoch": 2.0505030578023278,
1279
+ "eval_accuracy": 0.17849223946784923,
1280
+ "eval_loss": 3.400832414627075,
1281
+ "eval_runtime": 24.2954,
1282
+ "eval_samples_per_second": 37.126,
1283
+ "eval_steps_per_second": 4.651,
1284
+ "step": 1300
1285
+ },
1286
+ {
1287
+ "epoch": 2.0662852633655553,
1288
+ "grad_norm": 133.18820676570508,
1289
+ "learning_rate": 1.7329047340736412e-06,
1290
+ "loss": 27.7807,
1291
+ "step": 1310,
1292
+ "true_loss": 3.5333
1293
+ },
1294
+ {
1295
+ "epoch": 2.082067468928783,
1296
+ "grad_norm": 132.12454176042834,
1297
+ "learning_rate": 1.7036820572764467e-06,
1298
+ "loss": 27.6285,
1299
+ "step": 1320,
1300
+ "true_loss": 3.122
1301
+ },
1302
+ {
1303
+ "epoch": 2.0978496744920103,
1304
+ "grad_norm": 121.63901914437486,
1305
+ "learning_rate": 1.674459380479252e-06,
1306
+ "loss": 27.2663,
1307
+ "step": 1330,
1308
+ "true_loss": 3.2256
1309
+ },
1310
+ {
1311
+ "epoch": 2.113631880055238,
1312
+ "grad_norm": 137.06803144579217,
1313
+ "learning_rate": 1.6452367036820574e-06,
1314
+ "loss": 27.6847,
1315
+ "step": 1340,
1316
+ "true_loss": 3.3579
1317
+ },
1318
+ {
1319
+ "epoch": 2.1294140856184653,
1320
+ "grad_norm": 127.41062741726843,
1321
+ "learning_rate": 1.6160140268848628e-06,
1322
+ "loss": 27.7085,
1323
+ "step": 1350,
1324
+ "true_loss": 3.45
1325
+ },
1326
+ {
1327
+ "epoch": 2.1294140856184653,
1328
+ "eval_accuracy": 0.18070953436807094,
1329
+ "eval_loss": 3.376422643661499,
1330
+ "eval_runtime": 23.8791,
1331
+ "eval_samples_per_second": 37.774,
1332
+ "eval_steps_per_second": 4.732,
1333
+ "step": 1350
1334
+ },
1335
+ {
1336
+ "epoch": 2.1451962911816924,
1337
+ "grad_norm": 121.2757103113971,
1338
+ "learning_rate": 1.586791350087668e-06,
1339
+ "loss": 27.6917,
1340
+ "step": 1360,
1341
+ "true_loss": 3.3579
1342
+ },
1343
+ {
1344
+ "epoch": 2.16097849674492,
1345
+ "grad_norm": 128.57906764071424,
1346
+ "learning_rate": 1.5575686732904735e-06,
1347
+ "loss": 26.6196,
1348
+ "step": 1370,
1349
+ "true_loss": 3.2661
1350
+ },
1351
+ {
1352
+ "epoch": 2.1767607023081474,
1353
+ "grad_norm": 144.7381021633525,
1354
+ "learning_rate": 1.528345996493279e-06,
1355
+ "loss": 28.1214,
1356
+ "step": 1380,
1357
+ "true_loss": 3.5539
1358
+ },
1359
+ {
1360
+ "epoch": 2.192542907871375,
1361
+ "grad_norm": 145.5114518133331,
1362
+ "learning_rate": 1.4991233196960842e-06,
1363
+ "loss": 27.5329,
1364
+ "step": 1390,
1365
+ "true_loss": 3.5611
1366
+ },
1367
+ {
1368
+ "epoch": 2.2083251134346025,
1369
+ "grad_norm": 137.75864220522647,
1370
+ "learning_rate": 1.4699006428988897e-06,
1371
+ "loss": 27.6466,
1372
+ "step": 1400,
1373
+ "true_loss": 3.4073
1374
+ },
1375
+ {
1376
+ "epoch": 2.2083251134346025,
1377
+ "eval_accuracy": 0.18514412416851442,
1378
+ "eval_loss": 3.3832011222839355,
1379
+ "eval_runtime": 23.5091,
1380
+ "eval_samples_per_second": 38.368,
1381
+ "eval_steps_per_second": 4.807,
1382
+ "step": 1400
1383
+ },
1384
+ {
1385
+ "epoch": 2.22410731899783,
1386
+ "grad_norm": 132.61505430150723,
1387
+ "learning_rate": 1.4406779661016951e-06,
1388
+ "loss": 27.1518,
1389
+ "step": 1410,
1390
+ "true_loss": 3.4681
1391
+ },
1392
+ {
1393
+ "epoch": 2.2398895245610575,
1394
+ "grad_norm": 140.85574741341603,
1395
+ "learning_rate": 1.4114552893045006e-06,
1396
+ "loss": 27.7041,
1397
+ "step": 1420,
1398
+ "true_loss": 3.6406
1399
+ },
1400
+ {
1401
+ "epoch": 2.255671730124285,
1402
+ "grad_norm": 245.85007563586552,
1403
+ "learning_rate": 1.3822326125073058e-06,
1404
+ "loss": 27.6303,
1405
+ "step": 1430,
1406
+ "true_loss": 3.5352
1407
+ },
1408
+ {
1409
+ "epoch": 2.2714539356875125,
1410
+ "grad_norm": 577.1875021093457,
1411
+ "learning_rate": 1.3530099357101113e-06,
1412
+ "loss": 28.509,
1413
+ "step": 1440,
1414
+ "true_loss": 3.5396
1415
+ },
1416
+ {
1417
+ "epoch": 2.28723614125074,
1418
+ "grad_norm": 147.03022521178113,
1419
+ "learning_rate": 1.3237872589129167e-06,
1420
+ "loss": 27.6055,
1421
+ "step": 1450,
1422
+ "true_loss": 3.4989
1423
+ },
1424
+ {
1425
+ "epoch": 2.28723614125074,
1426
+ "eval_accuracy": 0.18514412416851442,
1427
+ "eval_loss": 3.4081857204437256,
1428
+ "eval_runtime": 24.0487,
1429
+ "eval_samples_per_second": 37.507,
1430
+ "eval_steps_per_second": 4.699,
1431
+ "step": 1450
1432
+ },
1433
+ {
1434
+ "epoch": 2.303018346813967,
1435
+ "grad_norm": 158.25616293531198,
1436
+ "learning_rate": 1.2945645821157218e-06,
1437
+ "loss": 27.6877,
1438
+ "step": 1460,
1439
+ "true_loss": 3.6034
1440
+ },
1441
+ {
1442
+ "epoch": 2.3188005523771946,
1443
+ "grad_norm": 155.95509000199831,
1444
+ "learning_rate": 1.2653419053185272e-06,
1445
+ "loss": 27.8664,
1446
+ "step": 1470,
1447
+ "true_loss": 3.5089
1448
+ },
1449
+ {
1450
+ "epoch": 2.334582757940422,
1451
+ "grad_norm": 146.83540699519045,
1452
+ "learning_rate": 1.2361192285213327e-06,
1453
+ "loss": 27.413,
1454
+ "step": 1480,
1455
+ "true_loss": 3.5116
1456
+ },
1457
+ {
1458
+ "epoch": 2.3503649635036497,
1459
+ "grad_norm": 141.1565994249431,
1460
+ "learning_rate": 1.2068965517241381e-06,
1461
+ "loss": 27.1606,
1462
+ "step": 1490,
1463
+ "true_loss": 3.426
1464
+ },
1465
+ {
1466
+ "epoch": 2.366147169066877,
1467
+ "grad_norm": 159.8393327569506,
1468
+ "learning_rate": 1.1776738749269434e-06,
1469
+ "loss": 27.7131,
1470
+ "step": 1500,
1471
+ "true_loss": 3.3148
1472
+ },
1473
+ {
1474
+ "epoch": 2.366147169066877,
1475
+ "eval_accuracy": 0.19623059866962306,
1476
+ "eval_loss": 3.372471332550049,
1477
+ "eval_runtime": 23.4809,
1478
+ "eval_samples_per_second": 38.414,
1479
+ "eval_steps_per_second": 4.812,
1480
+ "step": 1500
1481
+ },
1482
+ {
1483
+ "epoch": 2.3819293746301047,
1484
+ "grad_norm": 168.70353622158657,
1485
+ "learning_rate": 1.1484511981297488e-06,
1486
+ "loss": 26.9731,
1487
+ "step": 1510,
1488
+ "true_loss": 3.3077
1489
+ },
1490
+ {
1491
+ "epoch": 2.397711580193332,
1492
+ "grad_norm": 163.63685602929394,
1493
+ "learning_rate": 1.1192285213325543e-06,
1494
+ "loss": 27.206,
1495
+ "step": 1520,
1496
+ "true_loss": 3.2603
1497
+ },
1498
+ {
1499
+ "epoch": 2.4134937857565593,
1500
+ "grad_norm": 171.43412737818744,
1501
+ "learning_rate": 1.0900058445353595e-06,
1502
+ "loss": 26.3347,
1503
+ "step": 1530,
1504
+ "true_loss": 3.2123
1505
+ },
1506
+ {
1507
+ "epoch": 2.4292759913197868,
1508
+ "grad_norm": 167.19508362270676,
1509
+ "learning_rate": 1.0607831677381648e-06,
1510
+ "loss": 27.482,
1511
+ "step": 1540,
1512
+ "true_loss": 3.4389
1513
+ },
1514
+ {
1515
+ "epoch": 2.4450581968830143,
1516
+ "grad_norm": 165.6072657994525,
1517
+ "learning_rate": 1.0315604909409702e-06,
1518
+ "loss": 26.6002,
1519
+ "step": 1550,
1520
+ "true_loss": 3.4554
1521
+ },
1522
+ {
1523
+ "epoch": 2.4450581968830143,
1524
+ "eval_accuracy": 0.1984478935698448,
1525
+ "eval_loss": 3.3719024658203125,
1526
+ "eval_runtime": 23.4592,
1527
+ "eval_samples_per_second": 38.45,
1528
+ "eval_steps_per_second": 4.817,
1529
+ "step": 1550
1530
+ },
1531
+ {
1532
+ "epoch": 2.460840402446242,
1533
+ "grad_norm": 173.48714728794272,
1534
+ "learning_rate": 1.0023378141437757e-06,
1535
+ "loss": 27.0777,
1536
+ "step": 1560,
1537
+ "true_loss": 3.4451
1538
+ },
1539
+ {
1540
+ "epoch": 2.4766226080094693,
1541
+ "grad_norm": 169.41551174748028,
1542
+ "learning_rate": 9.731151373465811e-07,
1543
+ "loss": 27.1345,
1544
+ "step": 1570,
1545
+ "true_loss": 3.3625
1546
+ },
1547
+ {
1548
+ "epoch": 2.492404813572697,
1549
+ "grad_norm": 179.8847072240023,
1550
+ "learning_rate": 9.438924605493864e-07,
1551
+ "loss": 27.0216,
1552
+ "step": 1580,
1553
+ "true_loss": 3.2843
1554
+ },
1555
+ {
1556
+ "epoch": 2.5081870191359243,
1557
+ "grad_norm": 166.02108936347767,
1558
+ "learning_rate": 9.146697837521917e-07,
1559
+ "loss": 26.7401,
1560
+ "step": 1590,
1561
+ "true_loss": 3.2657
1562
+ },
1563
+ {
1564
+ "epoch": 2.523969224699152,
1565
+ "grad_norm": 454.3584387218693,
1566
+ "learning_rate": 8.854471069549972e-07,
1567
+ "loss": 26.1234,
1568
+ "step": 1600,
1569
+ "true_loss": 3.3808
1570
+ },
1571
+ {
1572
+ "epoch": 2.523969224699152,
1573
+ "eval_accuracy": 0.20288248337028825,
1574
+ "eval_loss": 3.380685567855835,
1575
+ "eval_runtime": 24.1535,
1576
+ "eval_samples_per_second": 37.344,
1577
+ "eval_steps_per_second": 4.678,
1578
+ "step": 1600
1579
+ },
1580
+ {
1581
+ "epoch": 2.5397514302623794,
1582
+ "grad_norm": 164.3488500545829,
1583
+ "learning_rate": 8.562244301578025e-07,
1584
+ "loss": 26.6329,
1585
+ "step": 1610,
1586
+ "true_loss": 3.4502
1587
+ },
1588
+ {
1589
+ "epoch": 2.555533635825607,
1590
+ "grad_norm": 224.71536684248224,
1591
+ "learning_rate": 8.270017533606079e-07,
1592
+ "loss": 27.4489,
1593
+ "step": 1620,
1594
+ "true_loss": 3.4381
1595
+ },
1596
+ {
1597
+ "epoch": 2.571315841388834,
1598
+ "grad_norm": 189.92117872676408,
1599
+ "learning_rate": 7.977790765634133e-07,
1600
+ "loss": 27.2729,
1601
+ "step": 1630,
1602
+ "true_loss": 3.3647
1603
+ },
1604
+ {
1605
+ "epoch": 2.5870980469520615,
1606
+ "grad_norm": 172.51933992524627,
1607
+ "learning_rate": 7.685563997662187e-07,
1608
+ "loss": 27.1534,
1609
+ "step": 1640,
1610
+ "true_loss": 3.5251
1611
+ },
1612
+ {
1613
+ "epoch": 2.602880252515289,
1614
+ "grad_norm": 166.6926362336406,
1615
+ "learning_rate": 7.393337229690241e-07,
1616
+ "loss": 26.9745,
1617
+ "step": 1650,
1618
+ "true_loss": 3.3921
1619
+ },
1620
+ {
1621
+ "epoch": 2.602880252515289,
1622
+ "eval_accuracy": 0.2006651884700665,
1623
+ "eval_loss": 3.3468966484069824,
1624
+ "eval_runtime": 23.7179,
1625
+ "eval_samples_per_second": 38.03,
1626
+ "eval_steps_per_second": 4.764,
1627
+ "step": 1650
1628
+ },
1629
+ {
1630
+ "epoch": 2.6186624580785165,
1631
+ "grad_norm": 160.91931691807488,
1632
+ "learning_rate": 7.101110461718295e-07,
1633
+ "loss": 26.7737,
1634
+ "step": 1660,
1635
+ "true_loss": 3.4577
1636
+ },
1637
+ {
1638
+ "epoch": 2.634444663641744,
1639
+ "grad_norm": 181.67048483012417,
1640
+ "learning_rate": 6.808883693746347e-07,
1641
+ "loss": 26.7581,
1642
+ "step": 1670,
1643
+ "true_loss": 3.2471
1644
+ },
1645
+ {
1646
+ "epoch": 2.6502268692049715,
1647
+ "grad_norm": 217.44579386829224,
1648
+ "learning_rate": 6.516656925774401e-07,
1649
+ "loss": 26.4481,
1650
+ "step": 1680,
1651
+ "true_loss": 3.0002
1652
+ },
1653
+ {
1654
+ "epoch": 2.6660090747681986,
1655
+ "grad_norm": 195.64586609651414,
1656
+ "learning_rate": 6.224430157802455e-07,
1657
+ "loss": 26.7862,
1658
+ "step": 1690,
1659
+ "true_loss": 3.1025
1660
+ },
1661
+ {
1662
+ "epoch": 2.681791280331426,
1663
+ "grad_norm": 179.8032160582305,
1664
+ "learning_rate": 5.93220338983051e-07,
1665
+ "loss": 27.108,
1666
+ "step": 1700,
1667
+ "true_loss": 3.1252
1668
+ },
1669
+ {
1670
+ "epoch": 2.681791280331426,
1671
+ "eval_accuracy": 0.2017738359201774,
1672
+ "eval_loss": 3.3589749336242676,
1673
+ "eval_runtime": 23.6074,
1674
+ "eval_samples_per_second": 38.208,
1675
+ "eval_steps_per_second": 4.787,
1676
+ "step": 1700
1677
+ },
1678
+ {
1679
+ "epoch": 2.6975734858946536,
1680
+ "grad_norm": 189.69952810255015,
1681
+ "learning_rate": 5.639976621858563e-07,
1682
+ "loss": 26.6985,
1683
+ "step": 1710,
1684
+ "true_loss": 3.3933
1685
+ },
1686
+ {
1687
+ "epoch": 2.713355691457881,
1688
+ "grad_norm": 242.2858845486621,
1689
+ "learning_rate": 5.347749853886616e-07,
1690
+ "loss": 26.7437,
1691
+ "step": 1720,
1692
+ "true_loss": 3.1209
1693
+ },
1694
+ {
1695
+ "epoch": 2.7291378970211086,
1696
+ "grad_norm": 185.37642956971033,
1697
+ "learning_rate": 5.05552308591467e-07,
1698
+ "loss": 26.7456,
1699
+ "step": 1730,
1700
+ "true_loss": 3.1121
1701
+ },
1702
+ {
1703
+ "epoch": 2.744920102584336,
1704
+ "grad_norm": 201.70311652816994,
1705
+ "learning_rate": 4.763296317942724e-07,
1706
+ "loss": 26.8516,
1707
+ "step": 1740,
1708
+ "true_loss": 3.397
1709
+ },
1710
+ {
1711
+ "epoch": 2.7607023081475637,
1712
+ "grad_norm": 181.35331376149924,
1713
+ "learning_rate": 4.4710695499707774e-07,
1714
+ "loss": 27.6208,
1715
+ "step": 1750,
1716
+ "true_loss": 3.6422
1717
+ },
1718
+ {
1719
+ "epoch": 2.7607023081475637,
1720
+ "eval_accuracy": 0.21951219512195122,
1721
+ "eval_loss": 3.3623762130737305,
1722
+ "eval_runtime": 23.6173,
1723
+ "eval_samples_per_second": 38.192,
1724
+ "eval_steps_per_second": 4.785,
1725
+ "step": 1750
1726
+ },
1727
+ {
1728
+ "epoch": 2.776484513710791,
1729
+ "grad_norm": 207.9779142213798,
1730
+ "learning_rate": 4.1788427819988314e-07,
1731
+ "loss": 26.674,
1732
+ "step": 1760,
1733
+ "true_loss": 3.221
1734
+ },
1735
+ {
1736
+ "epoch": 2.7922667192740187,
1737
+ "grad_norm": 203.7549680190773,
1738
+ "learning_rate": 3.8866160140268854e-07,
1739
+ "loss": 26.5723,
1740
+ "step": 1770,
1741
+ "true_loss": 3.2956
1742
+ },
1743
+ {
1744
+ "epoch": 2.808048924837246,
1745
+ "grad_norm": 196.13189611302036,
1746
+ "learning_rate": 3.594389246054939e-07,
1747
+ "loss": 26.4406,
1748
+ "step": 1780,
1749
+ "true_loss": 3.4648
1750
+ },
1751
+ {
1752
+ "epoch": 2.8238311304004737,
1753
+ "grad_norm": 198.30227589105047,
1754
+ "learning_rate": 3.3021624780829924e-07,
1755
+ "loss": 26.1588,
1756
+ "step": 1790,
1757
+ "true_loss": 3.2933
1758
+ },
1759
+ {
1760
+ "epoch": 2.839613335963701,
1761
+ "grad_norm": 199.85226446602726,
1762
+ "learning_rate": 3.0099357101110464e-07,
1763
+ "loss": 26.2669,
1764
+ "step": 1800,
1765
+ "true_loss": 3.2296
1766
+ },
1767
+ {
1768
+ "epoch": 2.839613335963701,
1769
+ "eval_accuracy": 0.2073170731707317,
1770
+ "eval_loss": 3.3512346744537354,
1771
+ "eval_runtime": 23.6919,
1772
+ "eval_samples_per_second": 38.072,
1773
+ "eval_steps_per_second": 4.77,
1774
+ "step": 1800
1775
+ },
1776
+ {
1777
+ "epoch": 2.8553955415269283,
1778
+ "grad_norm": 217.9595424207247,
1779
+ "learning_rate": 2.7177089421391004e-07,
1780
+ "loss": 26.0995,
1781
+ "step": 1810,
1782
+ "true_loss": 3.0267
1783
+ },
1784
+ {
1785
+ "epoch": 2.871177747090156,
1786
+ "grad_norm": 222.64507007990645,
1787
+ "learning_rate": 2.425482174167154e-07,
1788
+ "loss": 25.9481,
1789
+ "step": 1820,
1790
+ "true_loss": 3.4288
1791
+ },
1792
+ {
1793
+ "epoch": 2.8869599526533833,
1794
+ "grad_norm": 201.21510324225665,
1795
+ "learning_rate": 2.1332554061952078e-07,
1796
+ "loss": 25.9752,
1797
+ "step": 1830,
1798
+ "true_loss": 3.1737
1799
+ },
1800
+ {
1801
+ "epoch": 2.902742158216611,
1802
+ "grad_norm": 192.09070144987018,
1803
+ "learning_rate": 1.8410286382232613e-07,
1804
+ "loss": 26.059,
1805
+ "step": 1840,
1806
+ "true_loss": 3.024
1807
+ },
1808
+ {
1809
+ "epoch": 2.9185243637798384,
1810
+ "grad_norm": 940.254161469039,
1811
+ "learning_rate": 1.5488018702513153e-07,
1812
+ "loss": 25.8304,
1813
+ "step": 1850,
1814
+ "true_loss": 2.8998
1815
+ },
1816
+ {
1817
+ "epoch": 2.9185243637798384,
1818
+ "eval_accuracy": 0.21840354767184036,
1819
+ "eval_loss": 3.3478667736053467,
1820
+ "eval_runtime": 23.6868,
1821
+ "eval_samples_per_second": 38.08,
1822
+ "eval_steps_per_second": 4.771,
1823
+ "step": 1850
1824
+ }
1825
+ ],
1826
+ "logging_steps": 10,
1827
+ "max_steps": 1902,
1828
+ "num_input_tokens_seen": 0,
1829
+ "num_train_epochs": 3,
1830
+ "save_steps": 50,
1831
+ "stateful_callbacks": {
1832
+ "TrainerControl": {
1833
+ "args": {
1834
+ "should_epoch_stop": false,
1835
+ "should_evaluate": false,
1836
+ "should_log": false,
1837
+ "should_save": true,
1838
+ "should_training_stop": false
1839
+ },
1840
+ "attributes": {}
1841
+ }
1842
+ },
1843
+ "total_flos": 0.0,
1844
+ "train_batch_size": 1,
1845
+ "trial_name": null,
1846
+ "trial_params": null
1847
+ }
training_args.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6ef326857202175de846b7a9b400ab5118100fabc46f9e836eb5cd734f7d1cd7
3
+ size 7249
vocab.json ADDED
The diff for this file is too large to render. See raw diff
 
zero_to_fp32.py ADDED
@@ -0,0 +1,760 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+
3
+ # Copyright (c) Microsoft Corporation.
4
+ # SPDX-License-Identifier: Apache-2.0
5
+
6
+ # DeepSpeed Team
7
+
8
+ # This script extracts fp32 consolidated weights from a zero 1, 2 and 3 DeepSpeed checkpoints. It gets
9
+ # copied into the top level checkpoint dir, so the user can easily do the conversion at any point in
10
+ # the future. Once extracted, the weights don't require DeepSpeed and can be used in any
11
+ # application.
12
+ #
13
+ # example:
14
+ # python zero_to_fp32.py . output_dir/
15
+ # or
16
+ # python zero_to_fp32.py . output_dir/ --safe_serialization
17
+
18
+ import argparse
19
+ import torch
20
+ import glob
21
+ import math
22
+ import os
23
+ import re
24
+ import gc
25
+ import json
26
+ import numpy as np
27
+ from tqdm import tqdm
28
+ from collections import OrderedDict
29
+ from dataclasses import dataclass
30
+
31
+ # while this script doesn't use deepspeed to recover data, since the checkpoints are pickled with
32
+ # DeepSpeed data structures it has to be available in the current python environment.
33
+ from deepspeed.utils import logger
34
+ from deepspeed.checkpoint.constants import (DS_VERSION, OPTIMIZER_STATE_DICT, SINGLE_PARTITION_OF_FP32_GROUPS,
35
+ FP32_FLAT_GROUPS, ZERO_STAGE, PARTITION_COUNT, PARAM_SHAPES, BUFFER_NAMES,
36
+ FROZEN_PARAM_SHAPES, FROZEN_PARAM_FRAGMENTS)
37
+
38
+
39
+ @dataclass
40
+ class zero_model_state:
41
+ buffers: dict()
42
+ param_shapes: dict()
43
+ shared_params: list
44
+ ds_version: int
45
+ frozen_param_shapes: dict()
46
+ frozen_param_fragments: dict()
47
+
48
+
49
+ debug = 0
50
+
51
+ # load to cpu
52
+ device = torch.device('cpu')
53
+
54
+
55
+ def atoi(text):
56
+ return int(text) if text.isdigit() else text
57
+
58
+
59
+ def natural_keys(text):
60
+ '''
61
+ alist.sort(key=natural_keys) sorts in human order
62
+ http://nedbatchelder.com/blog/200712/human_sorting.html
63
+ (See Toothy's implementation in the comments)
64
+ '''
65
+ return [atoi(c) for c in re.split(r'(\d+)', text)]
66
+
67
+
68
+ def get_model_state_file(checkpoint_dir, zero_stage):
69
+ if not os.path.isdir(checkpoint_dir):
70
+ raise FileNotFoundError(f"Directory '{checkpoint_dir}' doesn't exist")
71
+
72
+ # there should be only one file
73
+ if zero_stage <= 2:
74
+ file = os.path.join(checkpoint_dir, "mp_rank_00_model_states.pt")
75
+ elif zero_stage == 3:
76
+ file = os.path.join(checkpoint_dir, "zero_pp_rank_0_mp_rank_00_model_states.pt")
77
+
78
+ if not os.path.exists(file):
79
+ raise FileNotFoundError(f"can't find model states file at '{file}'")
80
+
81
+ return file
82
+
83
+
84
+ def get_checkpoint_files(checkpoint_dir, glob_pattern):
85
+ # XXX: need to test that this simple glob rule works for multi-node setup too
86
+ ckpt_files = sorted(glob.glob(os.path.join(checkpoint_dir, glob_pattern)), key=natural_keys)
87
+
88
+ if len(ckpt_files) == 0:
89
+ raise FileNotFoundError(f"can't find {glob_pattern} files in directory '{checkpoint_dir}'")
90
+
91
+ return ckpt_files
92
+
93
+
94
+ def get_optim_files(checkpoint_dir):
95
+ return get_checkpoint_files(checkpoint_dir, "*_optim_states.pt")
96
+
97
+
98
+ def get_model_state_files(checkpoint_dir):
99
+ return get_checkpoint_files(checkpoint_dir, "*_model_states.pt")
100
+
101
+
102
+ def parse_model_states(files):
103
+ zero_model_states = []
104
+ for file in files:
105
+ state_dict = torch.load(file, map_location=device, weights_only=False)
106
+
107
+ if BUFFER_NAMES not in state_dict:
108
+ raise ValueError(f"{file} is not a model state checkpoint")
109
+ buffer_names = state_dict[BUFFER_NAMES]
110
+ if debug:
111
+ print("Found buffers:", buffer_names)
112
+
113
+ # recover just the buffers while restoring them to fp32 if they were saved in fp16
114
+ buffers = {k: v.float() for k, v in state_dict["module"].items() if k in buffer_names}
115
+ param_shapes = state_dict[PARAM_SHAPES]
116
+
117
+ # collect parameters that are included in param_shapes
118
+ param_names = []
119
+ for s in param_shapes:
120
+ for name in s.keys():
121
+ param_names.append(name)
122
+
123
+ # update with frozen parameters
124
+ frozen_param_shapes = state_dict.get(FROZEN_PARAM_SHAPES, None)
125
+ if frozen_param_shapes is not None:
126
+ if debug:
127
+ print(f"Found frozen_param_shapes: {frozen_param_shapes}")
128
+ param_names += list(frozen_param_shapes.keys())
129
+
130
+ # handle shared params
131
+ shared_params = [[k, v] for k, v in state_dict["shared_params"].items()]
132
+
133
+ ds_version = state_dict.get(DS_VERSION, None)
134
+
135
+ frozen_param_fragments = state_dict.get(FROZEN_PARAM_FRAGMENTS, None)
136
+
137
+ z_model_state = zero_model_state(buffers=buffers,
138
+ param_shapes=param_shapes,
139
+ shared_params=shared_params,
140
+ ds_version=ds_version,
141
+ frozen_param_shapes=frozen_param_shapes,
142
+ frozen_param_fragments=frozen_param_fragments)
143
+ zero_model_states.append(z_model_state)
144
+
145
+ return zero_model_states
146
+
147
+
148
+ def parse_optim_states(files, ds_checkpoint_dir):
149
+ total_files = len(files)
150
+ state_dicts = []
151
+ for f in tqdm(files, desc='Loading checkpoint shards'):
152
+ state_dict = torch.load(f, map_location=device, mmap=True, weights_only=False)
153
+ # immediately discard the potentially huge 2 optimizer states as we only care for fp32 master weights
154
+ # and also handle the case where it was already removed by another helper script
155
+ state_dict["optimizer_state_dict"].pop("optimizer_state_dict", None)
156
+ state_dicts.append(state_dict)
157
+
158
+ if ZERO_STAGE not in state_dicts[0][OPTIMIZER_STATE_DICT]:
159
+ raise ValueError(f"{files[0]} is not a zero checkpoint")
160
+ zero_stage = state_dicts[0][OPTIMIZER_STATE_DICT][ZERO_STAGE]
161
+ world_size = state_dicts[0][OPTIMIZER_STATE_DICT][PARTITION_COUNT]
162
+
163
+ # For ZeRO-2 each param group can have different partition_count as data parallelism for expert
164
+ # parameters can be different from data parallelism for non-expert parameters. So we can just
165
+ # use the max of the partition_count to get the dp world_size.
166
+
167
+ if type(world_size) is list:
168
+ world_size = max(world_size)
169
+
170
+ if world_size != total_files:
171
+ raise ValueError(
172
+ f"Expected {world_size} of '*_optim_states.pt' under '{ds_checkpoint_dir}' but found {total_files} files. "
173
+ "Possibly due to an overwrite of an old checkpoint, or a checkpoint didn't get saved by one or more processes."
174
+ )
175
+
176
+ # the groups are named differently in each stage
177
+ if zero_stage <= 2:
178
+ fp32_groups_key = SINGLE_PARTITION_OF_FP32_GROUPS
179
+ elif zero_stage == 3:
180
+ fp32_groups_key = FP32_FLAT_GROUPS
181
+ else:
182
+ raise ValueError(f"unknown zero stage {zero_stage}")
183
+
184
+ fp32_flat_groups = [state_dicts[i][OPTIMIZER_STATE_DICT][fp32_groups_key] for i in range(len(state_dicts))]
185
+ return zero_stage, world_size, fp32_flat_groups
186
+
187
+
188
+ def _get_fp32_state_dict_from_zero_checkpoint(ds_checkpoint_dir, exclude_frozen_parameters):
189
+ """
190
+ Returns fp32 state_dict reconstructed from ds checkpoint
191
+
192
+ Args:
193
+ - ``ds_checkpoint_dir``: path to the deepspeed checkpoint folder (where the optimizer files are)
194
+
195
+ """
196
+ print(f"Processing zero checkpoint '{ds_checkpoint_dir}'")
197
+
198
+ optim_files = get_optim_files(ds_checkpoint_dir)
199
+ zero_stage, world_size, fp32_flat_groups = parse_optim_states(optim_files, ds_checkpoint_dir)
200
+ print(f"Detected checkpoint of type zero stage {zero_stage}, world_size: {world_size}")
201
+
202
+ model_files = get_model_state_files(ds_checkpoint_dir)
203
+
204
+ zero_model_states = parse_model_states(model_files)
205
+ print(f'Parsing checkpoint created by deepspeed=={zero_model_states[0].ds_version}')
206
+
207
+ if zero_stage <= 2:
208
+ return _get_fp32_state_dict_from_zero2_checkpoint(world_size, fp32_flat_groups, zero_model_states,
209
+ exclude_frozen_parameters)
210
+ elif zero_stage == 3:
211
+ return _get_fp32_state_dict_from_zero3_checkpoint(world_size, fp32_flat_groups, zero_model_states,
212
+ exclude_frozen_parameters)
213
+
214
+
215
+ def _zero2_merge_frozen_params(state_dict, zero_model_states):
216
+ if zero_model_states[0].frozen_param_shapes is None or len(zero_model_states[0].frozen_param_shapes) == 0:
217
+ return
218
+
219
+ frozen_param_shapes = zero_model_states[0].frozen_param_shapes
220
+ frozen_param_fragments = zero_model_states[0].frozen_param_fragments
221
+
222
+ if debug:
223
+ num_elem = sum(s.numel() for s in frozen_param_shapes.values())
224
+ print(f'rank 0: {FROZEN_PARAM_SHAPES}.numel = {num_elem}')
225
+
226
+ wanted_params = len(frozen_param_shapes)
227
+ wanted_numel = sum(s.numel() for s in frozen_param_shapes.values())
228
+ avail_numel = sum([p.numel() for p in frozen_param_fragments.values()])
229
+ print(f'Frozen params: Have {avail_numel} numels to process.')
230
+ print(f'Frozen params: Need {wanted_numel} numels in {wanted_params} params')
231
+
232
+ total_params = 0
233
+ total_numel = 0
234
+ for name, shape in frozen_param_shapes.items():
235
+ total_params += 1
236
+ unpartitioned_numel = shape.numel()
237
+ total_numel += unpartitioned_numel
238
+
239
+ state_dict[name] = frozen_param_fragments[name]
240
+
241
+ if debug:
242
+ print(f"{name} full shape: {shape} unpartitioned numel {unpartitioned_numel} ")
243
+
244
+ print(f"Reconstructed Frozen fp32 state dict with {total_params} params {total_numel} elements")
245
+
246
+
247
+ def _has_callable(obj, fn):
248
+ attr = getattr(obj, fn, None)
249
+ return callable(attr)
250
+
251
+
252
+ def _zero2_merge_trainable_params(state_dict, world_size, fp32_flat_groups, zero_model_states):
253
+ param_shapes = zero_model_states[0].param_shapes
254
+
255
+ # Reconstruction protocol:
256
+ #
257
+ # XXX: document this
258
+
259
+ if debug:
260
+ for i in range(world_size):
261
+ for j in range(len(fp32_flat_groups[0])):
262
+ print(f"{FP32_FLAT_GROUPS}[{i}][{j}].shape={fp32_flat_groups[i][j].shape}")
263
+
264
+ # XXX: memory usage doubles here (zero2)
265
+ num_param_groups = len(fp32_flat_groups[0])
266
+ merged_single_partition_of_fp32_groups = []
267
+ for i in range(num_param_groups):
268
+ merged_partitions = [sd[i] for sd in fp32_flat_groups]
269
+ full_single_fp32_vector = torch.cat(merged_partitions, 0)
270
+ merged_single_partition_of_fp32_groups.append(full_single_fp32_vector)
271
+ avail_numel = sum(
272
+ [full_single_fp32_vector.numel() for full_single_fp32_vector in merged_single_partition_of_fp32_groups])
273
+
274
+ if debug:
275
+ wanted_params = sum([len(shapes) for shapes in param_shapes])
276
+ wanted_numel = sum([sum(shape.numel() for shape in shapes.values()) for shapes in param_shapes])
277
+ # not asserting if there is a mismatch due to possible padding
278
+ print(f"Have {avail_numel} numels to process.")
279
+ print(f"Need {wanted_numel} numels in {wanted_params} params.")
280
+
281
+ # params
282
+ # XXX: for huge models that can't fit into the host's RAM we will have to recode this to support
283
+ # out-of-core computing solution
284
+ total_numel = 0
285
+ total_params = 0
286
+ for shapes, full_single_fp32_vector in zip(param_shapes, merged_single_partition_of_fp32_groups):
287
+ offset = 0
288
+ avail_numel = full_single_fp32_vector.numel()
289
+ for name, shape in shapes.items():
290
+
291
+ unpartitioned_numel = shape.numel() if _has_callable(shape, 'numel') else math.prod(shape)
292
+ total_numel += unpartitioned_numel
293
+ total_params += 1
294
+
295
+ if debug:
296
+ print(f"{name} full shape: {shape} unpartitioned numel {unpartitioned_numel} ")
297
+ state_dict[name] = full_single_fp32_vector.narrow(0, offset, unpartitioned_numel).view(shape)
298
+ offset += unpartitioned_numel
299
+
300
+ # Z2 started to align to 2*world_size to improve nccl performance. Therefore both offset and
301
+ # avail_numel can differ by anywhere between 0..2*world_size. Due to two unrelated complex
302
+ # paddings performed in the code it's almost impossible to predict the exact numbers w/o the
303
+ # live optimizer object, so we are checking that the numbers are within the right range
304
+ align_to = 2 * world_size
305
+
306
+ def zero2_align(x):
307
+ return align_to * math.ceil(x / align_to)
308
+
309
+ if debug:
310
+ print(f"original offset={offset}, avail_numel={avail_numel}")
311
+
312
+ offset = zero2_align(offset)
313
+ avail_numel = zero2_align(avail_numel)
314
+
315
+ if debug:
316
+ print(f"aligned offset={offset}, avail_numel={avail_numel}")
317
+
318
+ # Sanity check
319
+ if offset != avail_numel:
320
+ raise ValueError(f"consumed {offset} numels out of {avail_numel} - something is wrong")
321
+
322
+ print(f"Reconstructed fp32 state dict with {total_params} params {total_numel} elements")
323
+
324
+
325
+ def _get_fp32_state_dict_from_zero2_checkpoint(world_size, fp32_flat_groups, zero_model_states,
326
+ exclude_frozen_parameters):
327
+ state_dict = OrderedDict()
328
+
329
+ # buffers
330
+ buffers = zero_model_states[0].buffers
331
+ state_dict.update(buffers)
332
+ if debug:
333
+ print(f"added {len(buffers)} buffers")
334
+
335
+ if not exclude_frozen_parameters:
336
+ _zero2_merge_frozen_params(state_dict, zero_model_states)
337
+
338
+ _zero2_merge_trainable_params(state_dict, world_size, fp32_flat_groups, zero_model_states)
339
+
340
+ # recover shared parameters
341
+ for pair in zero_model_states[0].shared_params:
342
+ if pair[1] in state_dict:
343
+ state_dict[pair[0]] = state_dict[pair[1]]
344
+
345
+ return state_dict
346
+
347
+
348
+ def zero3_partitioned_param_info(unpartitioned_numel, world_size):
349
+ remainder = unpartitioned_numel % world_size
350
+ padding_numel = (world_size - remainder) if remainder else 0
351
+ partitioned_numel = math.ceil(unpartitioned_numel / world_size)
352
+ return partitioned_numel, padding_numel
353
+
354
+
355
+ def _zero3_merge_frozen_params(state_dict, world_size, zero_model_states):
356
+ if zero_model_states[0].frozen_param_shapes is None or len(zero_model_states[0].frozen_param_shapes) == 0:
357
+ return
358
+
359
+ if debug:
360
+ for i in range(world_size):
361
+ num_elem = sum(s.numel() for s in zero_model_states[i].frozen_param_fragments.values())
362
+ print(f'rank {i}: {FROZEN_PARAM_SHAPES}.numel = {num_elem}')
363
+
364
+ frozen_param_shapes = zero_model_states[0].frozen_param_shapes
365
+ wanted_params = len(frozen_param_shapes)
366
+ wanted_numel = sum(s.numel() for s in frozen_param_shapes.values())
367
+ avail_numel = sum([p.numel() for p in zero_model_states[0].frozen_param_fragments.values()]) * world_size
368
+ print(f'Frozen params: Have {avail_numel} numels to process.')
369
+ print(f'Frozen params: Need {wanted_numel} numels in {wanted_params} params')
370
+
371
+ total_params = 0
372
+ total_numel = 0
373
+ for name, shape in zero_model_states[0].frozen_param_shapes.items():
374
+ total_params += 1
375
+ unpartitioned_numel = shape.numel()
376
+ total_numel += unpartitioned_numel
377
+
378
+ param_frags = tuple(model_state.frozen_param_fragments[name] for model_state in zero_model_states)
379
+ state_dict[name] = torch.cat(param_frags, 0).narrow(0, 0, unpartitioned_numel).view(shape)
380
+
381
+ partitioned_numel, partitioned_padding_numel = zero3_partitioned_param_info(unpartitioned_numel, world_size)
382
+
383
+ if debug:
384
+ print(
385
+ f"Frozen params: {total_params} {name} full shape: {shape} partition0 numel={partitioned_numel} partitioned_padding_numel={partitioned_padding_numel}"
386
+ )
387
+
388
+ print(f"Reconstructed Frozen fp32 state dict with {total_params} params {total_numel} elements")
389
+
390
+
391
+ class GatheredTensor:
392
+ """
393
+ A pseudo tensor that collects partitioned weights.
394
+ It is more memory efficient when there are multiple groups.
395
+ """
396
+
397
+ def __init__(self, flat_groups, flat_groups_offset, offset, partitioned_numel, shape):
398
+ self.flat_groups = flat_groups
399
+ self.flat_groups_offset = flat_groups_offset
400
+ self.offset = offset
401
+ self.partitioned_numel = partitioned_numel
402
+ self.shape = shape
403
+ self.dtype = self.flat_groups[0][0].dtype
404
+
405
+ def contiguous(self):
406
+ """
407
+ Merge partitioned weights from flat_groups into a single tensor.
408
+ """
409
+ end_idx = self.offset + self.partitioned_numel
410
+ world_size = len(self.flat_groups)
411
+ pad_flat_param_chunks = []
412
+
413
+ for rank_i in range(world_size):
414
+ # for each rank, we need to collect weights from related group/groups
415
+ flat_groups_at_rank_i = self.flat_groups[rank_i]
416
+ start_group_id = None
417
+ end_group_id = None
418
+ for group_id in range(len(self.flat_groups_offset)):
419
+ if self.flat_groups_offset[group_id] <= self.offset < self.flat_groups_offset[group_id + 1]:
420
+ start_group_id = group_id
421
+ if self.flat_groups_offset[group_id] < end_idx <= self.flat_groups_offset[group_id + 1]:
422
+ end_group_id = group_id
423
+ break
424
+ # collect weights from related group/groups
425
+ for group_id in range(start_group_id, end_group_id + 1):
426
+ flat_tensor = flat_groups_at_rank_i[group_id]
427
+ start_offset = self.offset - self.flat_groups_offset[group_id]
428
+ end_offset = min(end_idx, self.flat_groups_offset[group_id + 1]) - self.flat_groups_offset[group_id]
429
+ pad_flat_param_chunks.append(flat_tensor[start_offset:end_offset])
430
+
431
+ # collect weights from all ranks
432
+ pad_flat_param = torch.cat(pad_flat_param_chunks, dim=0)
433
+ param = pad_flat_param[:self.shape.numel()].view(self.shape).contiguous()
434
+ return param
435
+
436
+
437
+ def _zero3_merge_trainable_params(state_dict, world_size, fp32_flat_groups, zero_model_states):
438
+ param_shapes = zero_model_states[0].param_shapes
439
+ avail_numel = sum([flat_group.numel() for flat_group in fp32_flat_groups[0]]) * world_size
440
+
441
+ # Reconstruction protocol: For zero3 we need to zip the partitions together at boundary of each
442
+ # param, re-consolidating each param, while dealing with padding if any
443
+
444
+ # merge list of dicts, preserving order
445
+ param_shapes = {k: v for d in param_shapes for k, v in d.items()}
446
+
447
+ if debug:
448
+ for i in range(world_size):
449
+ print(f"{FP32_FLAT_GROUPS}[{i}].shape={fp32_flat_groups[i].shape}")
450
+
451
+ wanted_params = len(param_shapes)
452
+ wanted_numel = sum(shape.numel() for shape in param_shapes.values())
453
+ # not asserting if there is a mismatch due to possible padding
454
+ avail_numel = fp32_flat_groups[0].numel() * world_size
455
+ print(f"Trainable params: Have {avail_numel} numels to process.")
456
+ print(f"Trainable params: Need {wanted_numel} numels in {wanted_params} params.")
457
+
458
+ # params
459
+ # XXX: for huge models that can't fit into the host's RAM we will have to recode this to support
460
+ # out-of-core computing solution
461
+ offset = 0
462
+ total_numel = 0
463
+ total_params = 0
464
+ flat_groups_offset = [0] + list(np.cumsum([flat_tensor.numel() for flat_tensor in fp32_flat_groups[0]]))
465
+ for name, shape in tqdm(param_shapes.items(), desc='Gathering sharded weights'):
466
+ unpartitioned_numel = shape.numel()
467
+ total_numel += unpartitioned_numel
468
+ total_params += 1
469
+ partitioned_numel, partitioned_padding_numel = zero3_partitioned_param_info(unpartitioned_numel, world_size)
470
+
471
+ if debug:
472
+ print(
473
+ f"Trainable params: {total_params} {name} full shape: {shape} partition0 numel={partitioned_numel} partitioned_padding_numel={partitioned_padding_numel}"
474
+ )
475
+
476
+ # memory efficient tensor
477
+ tensor = GatheredTensor(fp32_flat_groups, flat_groups_offset, offset, partitioned_numel, shape)
478
+ state_dict[name] = tensor
479
+ offset += partitioned_numel
480
+
481
+ offset *= world_size
482
+
483
+ # Sanity check
484
+ if offset != avail_numel:
485
+ raise ValueError(f"consumed {offset} numels out of {avail_numel} - something is wrong")
486
+
487
+ print(f"Reconstructed Trainable fp32 state dict with {total_params} params {total_numel} elements")
488
+
489
+
490
+ def _get_fp32_state_dict_from_zero3_checkpoint(world_size, fp32_flat_groups, zero_model_states,
491
+ exclude_frozen_parameters):
492
+ state_dict = OrderedDict()
493
+
494
+ # buffers
495
+ buffers = zero_model_states[0].buffers
496
+ state_dict.update(buffers)
497
+ if debug:
498
+ print(f"added {len(buffers)} buffers")
499
+
500
+ if not exclude_frozen_parameters:
501
+ _zero3_merge_frozen_params(state_dict, world_size, zero_model_states)
502
+
503
+ _zero3_merge_trainable_params(state_dict, world_size, fp32_flat_groups, zero_model_states)
504
+
505
+ # recover shared parameters
506
+ for pair in zero_model_states[0].shared_params:
507
+ if pair[1] in state_dict:
508
+ state_dict[pair[0]] = state_dict[pair[1]]
509
+
510
+ return state_dict
511
+
512
+
513
+ def to_torch_tensor(state_dict, return_empty_tensor=False):
514
+ """
515
+ Convert state_dict of GatheredTensor to torch tensor
516
+ """
517
+ torch_state_dict = {}
518
+ converted_tensors = {}
519
+ for name, tensor in state_dict.items():
520
+ tensor_id = id(tensor)
521
+ if tensor_id in converted_tensors: # shared tensors
522
+ shared_tensor = torch_state_dict[converted_tensors[tensor_id]]
523
+ torch_state_dict[name] = shared_tensor
524
+ else:
525
+ converted_tensors[tensor_id] = name
526
+ if return_empty_tensor:
527
+ torch_state_dict[name] = torch.empty(tensor.shape, dtype=tensor.dtype)
528
+ else:
529
+ torch_state_dict[name] = tensor.contiguous()
530
+ return torch_state_dict
531
+
532
+
533
+ def get_fp32_state_dict_from_zero_checkpoint(checkpoint_dir,
534
+ tag=None,
535
+ exclude_frozen_parameters=False,
536
+ lazy_mode=False):
537
+ """
538
+ Convert ZeRO 2 or 3 checkpoint into a single fp32 consolidated state_dict that can be loaded with
539
+ ``load_state_dict()`` and used for training without DeepSpeed or shared with others, for example
540
+ via a model hub.
541
+
542
+ Args:
543
+ - ``checkpoint_dir``: path to the desired checkpoint folder
544
+ - ``tag``: checkpoint tag used as a unique identifier for checkpoint. If not provided will attempt to load tag in 'latest' file. e.g., ``global_step14``
545
+ - ``exclude_frozen_parameters``: exclude frozen parameters
546
+ - ``lazy_mode``: get state_dict in lazy mode. It returns a dict of pesduo tensor instead of torch tensor, which is more memory efficient.
547
+ Convert the pesduo tensor to torch tensor by ``.contiguous()``
548
+
549
+ Returns:
550
+ - pytorch ``state_dict``
551
+
552
+ A typical usage might be ::
553
+
554
+ from deepspeed.utils.zero_to_fp32 import get_fp32_state_dict_from_zero_checkpoint
555
+ # do the training and checkpoint saving
556
+ state_dict = get_fp32_state_dict_from_zero_checkpoint(checkpoint_dir) # already on cpu
557
+ model = model.cpu() # move to cpu
558
+ model.load_state_dict(state_dict)
559
+ # submit to model hub or save the model to share with others
560
+
561
+ In this example the ``model`` will no longer be usable in the deepspeed context of the same
562
+ application. i.e. you will need to re-initialize the deepspeed engine, since
563
+ ``model.load_state_dict(state_dict)`` will remove all the deepspeed magic from it.
564
+
565
+ If you want it all done for you, use ``load_state_dict_from_zero_checkpoint`` instead.
566
+
567
+ Note: the above usage may not work if your application doesn't have sufficient free CPU memory.
568
+ You may need to use the offline approach using the ``zero_to_fp32.py`` script that is saved with
569
+ the checkpoint. Or you can load state_dict in lazy mode ::
570
+
571
+ from deepspeed.utils.zero_to_fp32 import get_fp32_state_dict_from_zero_checkpoint
572
+ state_dict = get_fp32_state_dict_from_zero_checkpoint(checkpoint_dir, lazy_mode=True) # not on cpu
573
+ for name, lazy_tensor in state_dict.item():
574
+ tensor = lazy_tensor.contiguous() # to cpu
575
+ print(name, tensor)
576
+ # del tensor to release memory if it no longer in use
577
+ """
578
+ if tag is None:
579
+ latest_path = os.path.join(checkpoint_dir, 'latest')
580
+ if os.path.isfile(latest_path):
581
+ with open(latest_path, 'r') as fd:
582
+ tag = fd.read().strip()
583
+ else:
584
+ raise ValueError(f"Unable to find 'latest' file at {latest_path}")
585
+
586
+ ds_checkpoint_dir = os.path.join(checkpoint_dir, tag)
587
+
588
+ if not os.path.isdir(ds_checkpoint_dir):
589
+ raise FileNotFoundError(f"Directory '{ds_checkpoint_dir}' doesn't exist")
590
+
591
+ state_dict = _get_fp32_state_dict_from_zero_checkpoint(ds_checkpoint_dir, exclude_frozen_parameters)
592
+ if lazy_mode:
593
+ return state_dict
594
+ else:
595
+ return to_torch_tensor(state_dict)
596
+
597
+
598
+ def convert_zero_checkpoint_to_fp32_state_dict(checkpoint_dir,
599
+ output_dir,
600
+ max_shard_size="5GB",
601
+ safe_serialization=False,
602
+ tag=None,
603
+ exclude_frozen_parameters=False):
604
+ """
605
+ Convert ZeRO 2 or 3 checkpoint into a single fp32 consolidated ``state_dict`` file that can be
606
+ loaded with ``torch.load(file)`` + ``load_state_dict()`` and used for training without DeepSpeed.
607
+
608
+ Args:
609
+ - ``checkpoint_dir``: path to the desired checkpoint folder. (one that contains the tag-folder, like ``global_step14``)
610
+ - ``output_dir``: directory to the pytorch fp32 state_dict output files
611
+ - ``max_shard_size``: the maximum size for a checkpoint before being sharded, default value is 5GB
612
+ - ``safe_serialization``: whether to save the model using `safetensors` or the traditional PyTorch way (that uses `pickle`).
613
+ - ``tag``: checkpoint tag used as a unique identifier for checkpoint. If not provided will attempt to load tag in the file named ``latest`` in the checkpoint folder, e.g., ``global_step14``
614
+ - ``exclude_frozen_parameters``: exclude frozen parameters
615
+ """
616
+
617
+ # Dependency pre-check
618
+ if safe_serialization:
619
+ try:
620
+ from safetensors.torch import save_file
621
+ except ImportError:
622
+ print('If you want to use `safe_serialization`, please `pip install safetensors`')
623
+ raise
624
+ if max_shard_size is not None:
625
+ try:
626
+ from huggingface_hub import split_torch_state_dict_into_shards
627
+ except ImportError:
628
+ print('If you want to use `max_shard_size`, please `pip install huggingface_hub`')
629
+ raise
630
+
631
+ # Convert zero checkpoint to state_dict
632
+ state_dict = get_fp32_state_dict_from_zero_checkpoint(checkpoint_dir,
633
+ tag,
634
+ exclude_frozen_parameters,
635
+ lazy_mode=True)
636
+
637
+ # Shard the model if it is too big.
638
+ weights_name = "model.safetensors" if safe_serialization else "pytorch_model.bin"
639
+ if max_shard_size is not None:
640
+ filename_pattern = weights_name.replace(".bin", "{suffix}.bin").replace(".safetensors", "{suffix}.safetensors")
641
+ # an memory-efficient approach for sharding
642
+ empty_state_dict = to_torch_tensor(state_dict, return_empty_tensor=True)
643
+ state_dict_split = split_torch_state_dict_into_shards(empty_state_dict,
644
+ filename_pattern=filename_pattern,
645
+ max_shard_size=max_shard_size)
646
+ else:
647
+ from collections import namedtuple
648
+ StateDictSplit = namedtuple("StateDictSplit", ["is_sharded", "filename_to_tensors"])
649
+ state_dict_split = StateDictSplit(is_sharded=False,
650
+ filename_to_tensors={weights_name: list(state_dict.keys())})
651
+
652
+ # Save the model by shard
653
+ os.makedirs(output_dir, exist_ok=True)
654
+ filename_to_tensors = state_dict_split.filename_to_tensors.items()
655
+ for shard_file, tensors in tqdm(filename_to_tensors, desc="Saving checkpoint shards"):
656
+ shard_state_dict = {tensor_name: state_dict[tensor_name] for tensor_name in tensors}
657
+ shard_state_dict = to_torch_tensor(shard_state_dict)
658
+ output_path = os.path.join(output_dir, shard_file)
659
+ if safe_serialization:
660
+ save_file(shard_state_dict, output_path, metadata={"format": "pt"})
661
+ else:
662
+ torch.save(shard_state_dict, output_path)
663
+ # release the memory of current shard
664
+ for tensor_name in list(shard_state_dict.keys()):
665
+ del state_dict[tensor_name]
666
+ del shard_state_dict[tensor_name]
667
+ del shard_state_dict
668
+ gc.collect()
669
+
670
+ # Save index if sharded
671
+ if state_dict_split.is_sharded:
672
+ index = {
673
+ "metadata": state_dict_split.metadata,
674
+ "weight_map": state_dict_split.tensor_to_filename,
675
+ }
676
+ save_index_file = "model.safetensors.index.json" if safe_serialization else "pytorch_model.bin.index.json"
677
+ save_index_file = os.path.join(output_dir, save_index_file)
678
+ with open(save_index_file, "w", encoding="utf-8") as f:
679
+ content = json.dumps(index, indent=2, sort_keys=True) + "\n"
680
+ f.write(content)
681
+
682
+
683
+ def load_state_dict_from_zero_checkpoint(model, checkpoint_dir, tag=None):
684
+ """
685
+ 1. Put the provided model to cpu
686
+ 2. Convert ZeRO 2 or 3 checkpoint into a single fp32 consolidated ``state_dict``
687
+ 3. Load it into the provided model
688
+
689
+ Args:
690
+ - ``model``: the model object to update
691
+ - ``checkpoint_dir``: path to the desired checkpoint folder. (one that contains the tag-folder, like ``global_step14``)
692
+ - ``tag``: checkpoint tag used as a unique identifier for checkpoint. If not provided will attempt to load tag in the file named ``latest`` in the checkpoint folder, e.g., ``global_step14``
693
+
694
+ Returns:
695
+ - ``model`: modified model
696
+
697
+ Make sure you have plenty of CPU memory available before you call this function. If you don't
698
+ have enough use the ``zero_to_fp32.py`` utility to do the conversion. You will find it
699
+ conveniently placed for you in the checkpoint folder.
700
+
701
+ A typical usage might be ::
702
+
703
+ from deepspeed.utils.zero_to_fp32 import load_state_dict_from_zero_checkpoint
704
+ model = load_state_dict_from_zero_checkpoint(trainer.model, checkpoint_dir)
705
+ # submit to model hub or save the model to share with others
706
+
707
+ Note, that once this was run, the ``model`` will no longer be usable in the deepspeed context
708
+ of the same application. i.e. you will need to re-initialize the deepspeed engine, since
709
+ ``model.load_state_dict(state_dict)`` will remove all the deepspeed magic from it.
710
+
711
+ """
712
+ logger.info("Extracting fp32 weights")
713
+ state_dict = get_fp32_state_dict_from_zero_checkpoint(checkpoint_dir, tag)
714
+
715
+ logger.info("Overwriting model with fp32 weights")
716
+ model = model.cpu()
717
+ model.load_state_dict(state_dict, strict=False)
718
+
719
+ return model
720
+
721
+
722
+ if __name__ == "__main__":
723
+ parser = argparse.ArgumentParser()
724
+ parser.add_argument("checkpoint_dir",
725
+ type=str,
726
+ help="path to the desired checkpoint folder, e.g., path/checkpoint-12")
727
+ parser.add_argument("output_dir",
728
+ type=str,
729
+ help="directory to the pytorch fp32 state_dict output files"
730
+ "(e.g. path/checkpoint-12-output/)")
731
+ parser.add_argument(
732
+ "--max_shard_size",
733
+ type=str,
734
+ default="5GB",
735
+ help="The maximum size for a checkpoint before being sharded. Checkpoints shard will then be each of size"
736
+ "lower than this size. If expressed as a string, needs to be digits followed by a unit (like `5MB`"
737
+ "We default it to 5GB in order for models to be able to run easily on free-tier google colab instances"
738
+ "without CPU OOM issues.")
739
+ parser.add_argument(
740
+ "--safe_serialization",
741
+ default=False,
742
+ action='store_true',
743
+ help="Whether to save the model using `safetensors` or the traditional PyTorch way (that uses `pickle`).")
744
+ parser.add_argument("-t",
745
+ "--tag",
746
+ type=str,
747
+ default=None,
748
+ help="checkpoint tag used as a unique identifier for checkpoint. e.g., global_step1")
749
+ parser.add_argument("--exclude_frozen_parameters", action='store_true', help="exclude frozen parameters")
750
+ parser.add_argument("-d", "--debug", action='store_true', help="enable debug")
751
+ args = parser.parse_args()
752
+
753
+ debug = args.debug
754
+
755
+ convert_zero_checkpoint_to_fp32_state_dict(args.checkpoint_dir,
756
+ args.output_dir,
757
+ max_shard_size=args.max_shard_size,
758
+ safe_serialization=args.safe_serialization,
759
+ tag=args.tag,
760
+ exclude_frozen_parameters=args.exclude_frozen_parameters)