JinghuiLuAstronaut commited on
Commit
90cb42a
·
verified ·
1 Parent(s): c452b27

Add files using upload-large-folder tool

Browse files
Files changed (20) hide show
  1. LTA_openwebtext_dualt/docs/lta_samples/metrics_20260508/mauve_step124k_n64_meta.json +19 -0
  2. LTA_openwebtext_dualt/logs/infer/lta_owt_classic_fullvocab_bert_c1024_len1024_large_d1024_l24_h16_ff4096_lr2e-4_gbs2048_2node8gpu_1m_save10k_t-20260522101129-lwll5_latest_step0012000_shard03_gpu3_b32.log +10 -0
  3. LTA_openwebtext_dualt/logs/infer/lta_owt_lm1bclassic_fullvocab_bert_c1024_len1024_elfLdim_d1280_l32_h16_ff5120_lr3e-4_gbs512_2node8gpu_1m_save10k_t-20260522071024-s2ss5_latest_step0001000_shard00_gpu0_b16.log +18 -0
  4. LTA_openwebtext_dualt/logs/owt_bert_absrope_time4_Cv_to_2v_mask1_sameT_gumbel_sde_watch/infer_lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525_step_0010000.log +136 -0
  5. LTA_openwebtext_dualt/logs/owt_bert_absrope_time4_Cv_to_2v_mask1_sameT_gumbel_sde_watch/infer_lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525_step_0030000.log +136 -0
  6. LTA_openwebtext_dualt/logs/owt_bert_absrope_time4_Cv_to_2v_mask1_sameT_gumbel_sde_watch/infer_lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525_step_0070000.log +136 -0
  7. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/__init__.py +852 -0
  8. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/convert_slow_tokenizer.py +2151 -0
  9. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/core_model_loading.py +1557 -0
  10. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/debug_utils.py +348 -0
  11. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/feature_extraction_utils.py +672 -0
  12. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/image_processing_base.py +494 -0
  13. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/biogpt/modular_biogpt.py +509 -0
  14. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/biogpt/tokenization_biogpt.py +329 -0
  15. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/mpnet/__init__.py +28 -0
  16. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/mpnet/tokenization_mpnet.py +195 -0
  17. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/time_series_utils.py +225 -0
  18. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/trainer_pt_utils.py +1336 -0
  19. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/trainer_seq2seq.py +392 -0
  20. LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/training_args_seq2seq.py +94 -0
LTA_openwebtext_dualt/docs/lta_samples/metrics_20260508/mauve_step124k_n64_meta.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "sets": {
3
+ "gen_s64_c256_raw": 64,
4
+ "gen_s64_c256_detok": 64,
5
+ "gen_s64_c1024_raw": 64,
6
+ "gen_s64_c1024_detok": 64,
7
+ "gen_s128_c256_raw": 64,
8
+ "gen_s128_c256_detok": 64,
9
+ "gen_s128_c1024_raw": 64,
10
+ "gen_s128_c1024_detok": 64,
11
+ "gen_s512_c256_raw": 64,
12
+ "gen_s512_c256_detok": 64,
13
+ "gen_s512_c1024_raw": 64,
14
+ "gen_s512_c1024_detok": 64,
15
+ "ref_raw": 64,
16
+ "ref_detok": 64
17
+ },
18
+ "feature_max_len": 256
19
+ }
LTA_openwebtext_dualt/logs/infer/lta_owt_classic_fullvocab_bert_c1024_len1024_large_d1024_l24_h16_ff4096_lr2e-4_gbs2048_2node8gpu_1m_save10k_t-20260522101129-lwll5_latest_step0012000_shard03_gpu3_b32.log ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ [ckpt] runs/lta_owt_classic_fullvocab_bert_c1024_len1024_large_d1024_l24_h16_ff4096_lr2e-4_gbs2048_2node8gpu_1m_save10k_t-20260522101129-lwll5/latest.pt step=12000
2
+ [decode] steps128_c1024_t1p45 generated 32/256
3
+ [decode] steps128_c1024_t1p45 generated 64/256
4
+ [decode] steps128_c1024_t1p45 generated 96/256
5
+ [decode] steps128_c1024_t1p45 generated 128/256
6
+ [decode] steps128_c1024_t1p45 generated 160/256
7
+ [decode] steps128_c1024_t1p45 generated 192/256
8
+ [decode] steps128_c1024_t1p45 generated 224/256
9
+ [decode] steps128_c1024_t1p45 generated 256/256
10
+ [summary] {"name": "steps128_c1024_t1p45", "step": 12000, "decode_steps": 128, "concentration_max": 1024.0, "raw_genppl": 1.0503456907382835, "stripped_genppl": 1.0503386596724937, "sample_entropy": 0.014470211366880415, "distinct_1": 0.000743865966796875, "distinct_2": 0.0018672104105571848, "top_token_mass": 0.5355873107910156, "raw_kept": 256, "stripped_kept": 256}
LTA_openwebtext_dualt/logs/infer/lta_owt_lm1bclassic_fullvocab_bert_c1024_len1024_elfLdim_d1280_l32_h16_ff5120_lr3e-4_gbs512_2node8gpu_1m_save10k_t-20260522071024-s2ss5_latest_step0001000_shard00_gpu0_b16.log ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [ckpt] runs/lta_owt_lm1bclassic_fullvocab_bert_c1024_len1024_elfLdim_d1280_l32_h16_ff5120_lr3e-4_gbs512_2node8gpu_1m_save10k_t-20260522071024-s2ss5/latest.pt step=1000
2
+ [decode] steps128_c1024_t1p45 generated 16/256
3
+ [decode] steps128_c1024_t1p45 generated 32/256
4
+ [decode] steps128_c1024_t1p45 generated 48/256
5
+ [decode] steps128_c1024_t1p45 generated 64/256
6
+ [decode] steps128_c1024_t1p45 generated 80/256
7
+ [decode] steps128_c1024_t1p45 generated 96/256
8
+ [decode] steps128_c1024_t1p45 generated 112/256
9
+ [decode] steps128_c1024_t1p45 generated 128/256
10
+ [decode] steps128_c1024_t1p45 generated 144/256
11
+ [decode] steps128_c1024_t1p45 generated 160/256
12
+ [decode] steps128_c1024_t1p45 generated 176/256
13
+ [decode] steps128_c1024_t1p45 generated 192/256
14
+ [decode] steps128_c1024_t1p45 generated 208/256
15
+ [decode] steps128_c1024_t1p45 generated 224/256
16
+ [decode] steps128_c1024_t1p45 generated 240/256
17
+ [decode] steps128_c1024_t1p45 generated 256/256
18
+ [summary] {"name": "steps128_c1024_t1p45", "step": 1000, "decode_steps": 128, "concentration_max": 1024.0, "raw_genppl": 52.971949182498236, "stripped_genppl": 53.54618185025198, "sample_entropy": 2.891760849210235, "distinct_1": 0.007476806640625, "distinct_2": 0.05039558895405669, "top_token_mass": 0.12990951538085938, "raw_kept": 256, "stripped_kept": 256}
LTA_openwebtext_dualt/logs/owt_bert_absrope_time4_Cv_to_2v_mask1_sameT_gumbel_sde_watch/infer_lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525_step_0010000.log ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [watch-gumbel] 2026-05-26_00:10:07 infer runs/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0010000.pt -> docs/lta_samples/metrics_20260525/owt_bert_absrope_time4_Cv_to_2v_mask1_sameT_sde_gumbel_topp0p95_tau1p0_to_0p2_blend_c30522_61044_n128/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0010000
2
+ [load] runs/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0010000.pt
3
+ [ckpt] step=10000
4
+ [sde] generated 2/128
5
+ [sde] generated 4/128
6
+ [sde] generated 6/128
7
+ [sde] generated 8/128
8
+ [sde] generated 10/128
9
+ [sde] generated 12/128
10
+ [sde] generated 14/128
11
+ [sde] generated 16/128
12
+ [sde] generated 18/128
13
+ [sde] generated 20/128
14
+ [sde] generated 22/128
15
+ [sde] generated 24/128
16
+ [sde] generated 26/128
17
+ [sde] generated 28/128
18
+ [sde] generated 30/128
19
+ [sde] generated 32/128
20
+ [sde] generated 34/128
21
+ [sde] generated 36/128
22
+ [sde] generated 38/128
23
+ [sde] generated 40/128
24
+ [sde] generated 42/128
25
+ [sde] generated 44/128
26
+ [sde] generated 46/128
27
+ [sde] generated 48/128
28
+ [sde] generated 50/128
29
+ [sde] generated 52/128
30
+ [sde] generated 54/128
31
+ [sde] generated 56/128
32
+ [sde] generated 58/128
33
+ [sde] generated 60/128
34
+ [sde] generated 62/128
35
+ [sde] generated 64/128
36
+ [sde] generated 66/128
37
+ [sde] generated 68/128
38
+ [sde] generated 70/128
39
+ [sde] generated 72/128
40
+ [sde] generated 74/128
41
+ [sde] generated 76/128
42
+ [sde] generated 78/128
43
+ [sde] generated 80/128
44
+ [sde] generated 82/128
45
+ [sde] generated 84/128
46
+ [sde] generated 86/128
47
+ [sde] generated 88/128
48
+ [sde] generated 90/128
49
+ [sde] generated 92/128
50
+ [sde] generated 94/128
51
+ [sde] generated 96/128
52
+ [sde] generated 98/128
53
+ [sde] generated 100/128
54
+ [sde] generated 102/128
55
+ [sde] generated 104/128
56
+ [sde] generated 106/128
57
+ [sde] generated 108/128
58
+ [sde] generated 110/128
59
+ [sde] generated 112/128
60
+ [sde] generated 114/128
61
+ [sde] generated 116/128
62
+ [sde] generated 118/128
63
+ [sde] generated 120/128
64
+ [sde] generated 122/128
65
+ [sde] generated 124/128
66
+ [sde] generated 126/128
67
+ [sde] generated 128/128
68
+ [score] loading scorer: /e2e-data/evad-tech-vla/wanghan58/models/flowtext_scorers/gpt2-large-standard
69
+ [summary] {
70
+ "type": "summary",
71
+ "checkpoint": "runs/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0010000.pt",
72
+ "step": 10000,
73
+ "decode": {
74
+ "decode_rule": "dirichlet_resample_sde",
75
+ "steps": 128,
76
+ "model_t_mode": "support_t",
77
+ "mean_mode": "endpoint_only",
78
+ "anchor_gamma": 1.0,
79
+ "endpoint_floor": 0.0,
80
+ "concentration_min": 30522.0,
81
+ "concentration_max": 61044.0,
82
+ "endpoint_temp": 1.45,
83
+ "endpoint_temp_start": null,
84
+ "endpoint_temp_end": null,
85
+ "endpoint_projection": "gumbel_softmax",
86
+ "endpoint_top_k": 0,
87
+ "endpoint_top_p": 0.95,
88
+ "gumbel_tau_start": 1.0,
89
+ "gumbel_tau_end": 0.2,
90
+ "gumbel_noise_scale_start": 1.0,
91
+ "gumbel_noise_scale_end": 1.0,
92
+ "ban_special_tokens": false,
93
+ "banned_endpoint_ids": [],
94
+ "support_power": 1.0,
95
+ "semantic_power": 1.0,
96
+ "noise_init": "dirichlet",
97
+ "noise_sigma": -1.0,
98
+ "noise_dirichlet_concentration": 30522.0,
99
+ "sde_resample": "dirichlet",
100
+ "logistic_normal_sigma_min": 0.18,
101
+ "logistic_normal_sigma_max": 3.0,
102
+ "logistic_normal_tau_min": 0.65,
103
+ "logistic_normal_tau_max": 1.0,
104
+ "final_from": "blend_0.5",
105
+ "n_samples": 128,
106
+ "seed": 20260524
107
+ },
108
+ "raw_genppl": {
109
+ "ppl": 53.80050601358846,
110
+ "nll_per_token": 3.9852828725805423,
111
+ "tokens": 129920,
112
+ "kept_samples": 128,
113
+ "total_samples": 128,
114
+ "empty_rate": 0.0,
115
+ "skipped_samples": 0
116
+ },
117
+ "stripped_genppl": {
118
+ "ppl": 53.471395293223054,
119
+ "nll_per_token": 3.9791468434999775,
120
+ "tokens": 129582,
121
+ "kept_samples": 128,
122
+ "total_samples": 128,
123
+ "empty_rate": 0.0,
124
+ "skipped_samples": 0
125
+ },
126
+ "diversity": {
127
+ "sample_entropy": 3.385070142597378,
128
+ "unique_tokens": 4431,
129
+ "token_count": 131072,
130
+ "distinct_1": 0.03380584716796875,
131
+ "distinct_2": 0.23287054007820138,
132
+ "top_token_mass": 0.1092987060546875
133
+ }
134
+ }
135
+ [done] docs/lta_samples/metrics_20260525/owt_bert_absrope_time4_Cv_to_2v_mask1_sameT_sde_gumbel_topp0p95_tau1p0_to_0p2_blend_c30522_61044_n128/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0010000/sde_steps128_samples128_scored.jsonl
136
+ [watch-gumbel] 2026-05-26_00:17:01 done step_0010000
LTA_openwebtext_dualt/logs/owt_bert_absrope_time4_Cv_to_2v_mask1_sameT_gumbel_sde_watch/infer_lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525_step_0030000.log ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [watch-gumbel] 2026-05-26_03:55:20 infer runs/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0030000.pt -> docs/lta_samples/metrics_20260525/owt_bert_absrope_time4_Cv_to_2v_mask1_sameT_sde_gumbel_topp0p95_tau1p0_to_0p2_blend_c30522_61044_n128/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0030000
2
+ [load] runs/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0030000.pt
3
+ [ckpt] step=30000
4
+ [sde] generated 2/128
5
+ [sde] generated 4/128
6
+ [sde] generated 6/128
7
+ [sde] generated 8/128
8
+ [sde] generated 10/128
9
+ [sde] generated 12/128
10
+ [sde] generated 14/128
11
+ [sde] generated 16/128
12
+ [sde] generated 18/128
13
+ [sde] generated 20/128
14
+ [sde] generated 22/128
15
+ [sde] generated 24/128
16
+ [sde] generated 26/128
17
+ [sde] generated 28/128
18
+ [sde] generated 30/128
19
+ [sde] generated 32/128
20
+ [sde] generated 34/128
21
+ [sde] generated 36/128
22
+ [sde] generated 38/128
23
+ [sde] generated 40/128
24
+ [sde] generated 42/128
25
+ [sde] generated 44/128
26
+ [sde] generated 46/128
27
+ [sde] generated 48/128
28
+ [sde] generated 50/128
29
+ [sde] generated 52/128
30
+ [sde] generated 54/128
31
+ [sde] generated 56/128
32
+ [sde] generated 58/128
33
+ [sde] generated 60/128
34
+ [sde] generated 62/128
35
+ [sde] generated 64/128
36
+ [sde] generated 66/128
37
+ [sde] generated 68/128
38
+ [sde] generated 70/128
39
+ [sde] generated 72/128
40
+ [sde] generated 74/128
41
+ [sde] generated 76/128
42
+ [sde] generated 78/128
43
+ [sde] generated 80/128
44
+ [sde] generated 82/128
45
+ [sde] generated 84/128
46
+ [sde] generated 86/128
47
+ [sde] generated 88/128
48
+ [sde] generated 90/128
49
+ [sde] generated 92/128
50
+ [sde] generated 94/128
51
+ [sde] generated 96/128
52
+ [sde] generated 98/128
53
+ [sde] generated 100/128
54
+ [sde] generated 102/128
55
+ [sde] generated 104/128
56
+ [sde] generated 106/128
57
+ [sde] generated 108/128
58
+ [sde] generated 110/128
59
+ [sde] generated 112/128
60
+ [sde] generated 114/128
61
+ [sde] generated 116/128
62
+ [sde] generated 118/128
63
+ [sde] generated 120/128
64
+ [sde] generated 122/128
65
+ [sde] generated 124/128
66
+ [sde] generated 126/128
67
+ [sde] generated 128/128
68
+ [score] loading scorer: /e2e-data/evad-tech-vla/wanghan58/models/flowtext_scorers/gpt2-large-standard
69
+ [summary] {
70
+ "type": "summary",
71
+ "checkpoint": "runs/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0030000.pt",
72
+ "step": 30000,
73
+ "decode": {
74
+ "decode_rule": "dirichlet_resample_sde",
75
+ "steps": 128,
76
+ "model_t_mode": "support_t",
77
+ "mean_mode": "endpoint_only",
78
+ "anchor_gamma": 1.0,
79
+ "endpoint_floor": 0.0,
80
+ "concentration_min": 30522.0,
81
+ "concentration_max": 61044.0,
82
+ "endpoint_temp": 1.45,
83
+ "endpoint_temp_start": null,
84
+ "endpoint_temp_end": null,
85
+ "endpoint_projection": "gumbel_softmax",
86
+ "endpoint_top_k": 0,
87
+ "endpoint_top_p": 0.95,
88
+ "gumbel_tau_start": 1.0,
89
+ "gumbel_tau_end": 0.2,
90
+ "gumbel_noise_scale_start": 1.0,
91
+ "gumbel_noise_scale_end": 1.0,
92
+ "ban_special_tokens": false,
93
+ "banned_endpoint_ids": [],
94
+ "support_power": 1.0,
95
+ "semantic_power": 1.0,
96
+ "noise_init": "dirichlet",
97
+ "noise_sigma": -1.0,
98
+ "noise_dirichlet_concentration": 30522.0,
99
+ "sde_resample": "dirichlet",
100
+ "logistic_normal_sigma_min": 0.18,
101
+ "logistic_normal_sigma_max": 3.0,
102
+ "logistic_normal_tau_min": 0.65,
103
+ "logistic_normal_tau_max": 1.0,
104
+ "final_from": "blend_0.5",
105
+ "n_samples": 128,
106
+ "seed": 20260524
107
+ },
108
+ "raw_genppl": {
109
+ "ppl": 21.470644084562533,
110
+ "nll_per_token": 3.0666866107216952,
111
+ "tokens": 113304,
112
+ "kept_samples": 128,
113
+ "total_samples": 128,
114
+ "empty_rate": 0.0,
115
+ "skipped_samples": 0
116
+ },
117
+ "stripped_genppl": {
118
+ "ppl": 21.081648656576114,
119
+ "nll_per_token": 3.048402930129953,
120
+ "tokens": 112565,
121
+ "kept_samples": 128,
122
+ "total_samples": 128,
123
+ "empty_rate": 0.0,
124
+ "skipped_samples": 0
125
+ },
126
+ "diversity": {
127
+ "sample_entropy": 2.3329561700076784,
128
+ "unique_tokens": 2179,
129
+ "token_count": 131072,
130
+ "distinct_1": 0.01662445068359375,
131
+ "distinct_2": 0.09946236559139784,
132
+ "top_token_mass": 0.200408935546875
133
+ }
134
+ }
135
+ [done] docs/lta_samples/metrics_20260525/owt_bert_absrope_time4_Cv_to_2v_mask1_sameT_sde_gumbel_topp0p95_tau1p0_to_0p2_blend_c30522_61044_n128/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0030000/sde_steps128_samples128_scored.jsonl
136
+ [watch-gumbel] 2026-05-26_04:02:12 done step_0030000
LTA_openwebtext_dualt/logs/owt_bert_absrope_time4_Cv_to_2v_mask1_sameT_gumbel_sde_watch/infer_lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525_step_0070000.log ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [watch-gumbel] 2026-05-26_11:25:14 infer runs/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0070000.pt -> docs/lta_samples/metrics_20260525/owt_bert_absrope_time4_Cv_to_2v_mask1_sameT_sde_gumbel_topp0p95_tau1p0_to_0p2_blend_c30522_61044_n128/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0070000
2
+ [load] runs/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0070000.pt
3
+ [ckpt] step=70000
4
+ [sde] generated 2/128
5
+ [sde] generated 4/128
6
+ [sde] generated 6/128
7
+ [sde] generated 8/128
8
+ [sde] generated 10/128
9
+ [sde] generated 12/128
10
+ [sde] generated 14/128
11
+ [sde] generated 16/128
12
+ [sde] generated 18/128
13
+ [sde] generated 20/128
14
+ [sde] generated 22/128
15
+ [sde] generated 24/128
16
+ [sde] generated 26/128
17
+ [sde] generated 28/128
18
+ [sde] generated 30/128
19
+ [sde] generated 32/128
20
+ [sde] generated 34/128
21
+ [sde] generated 36/128
22
+ [sde] generated 38/128
23
+ [sde] generated 40/128
24
+ [sde] generated 42/128
25
+ [sde] generated 44/128
26
+ [sde] generated 46/128
27
+ [sde] generated 48/128
28
+ [sde] generated 50/128
29
+ [sde] generated 52/128
30
+ [sde] generated 54/128
31
+ [sde] generated 56/128
32
+ [sde] generated 58/128
33
+ [sde] generated 60/128
34
+ [sde] generated 62/128
35
+ [sde] generated 64/128
36
+ [sde] generated 66/128
37
+ [sde] generated 68/128
38
+ [sde] generated 70/128
39
+ [sde] generated 72/128
40
+ [sde] generated 74/128
41
+ [sde] generated 76/128
42
+ [sde] generated 78/128
43
+ [sde] generated 80/128
44
+ [sde] generated 82/128
45
+ [sde] generated 84/128
46
+ [sde] generated 86/128
47
+ [sde] generated 88/128
48
+ [sde] generated 90/128
49
+ [sde] generated 92/128
50
+ [sde] generated 94/128
51
+ [sde] generated 96/128
52
+ [sde] generated 98/128
53
+ [sde] generated 100/128
54
+ [sde] generated 102/128
55
+ [sde] generated 104/128
56
+ [sde] generated 106/128
57
+ [sde] generated 108/128
58
+ [sde] generated 110/128
59
+ [sde] generated 112/128
60
+ [sde] generated 114/128
61
+ [sde] generated 116/128
62
+ [sde] generated 118/128
63
+ [sde] generated 120/128
64
+ [sde] generated 122/128
65
+ [sde] generated 124/128
66
+ [sde] generated 126/128
67
+ [sde] generated 128/128
68
+ [score] loading scorer: /e2e-data/evad-tech-vla/wanghan58/models/flowtext_scorers/gpt2-large-standard
69
+ [summary] {
70
+ "type": "summary",
71
+ "checkpoint": "runs/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0070000.pt",
72
+ "step": 70000,
73
+ "decode": {
74
+ "decode_rule": "dirichlet_resample_sde",
75
+ "steps": 128,
76
+ "model_t_mode": "support_t",
77
+ "mean_mode": "endpoint_only",
78
+ "anchor_gamma": 1.0,
79
+ "endpoint_floor": 0.0,
80
+ "concentration_min": 30522.0,
81
+ "concentration_max": 61044.0,
82
+ "endpoint_temp": 1.45,
83
+ "endpoint_temp_start": null,
84
+ "endpoint_temp_end": null,
85
+ "endpoint_projection": "gumbel_softmax",
86
+ "endpoint_top_k": 0,
87
+ "endpoint_top_p": 0.95,
88
+ "gumbel_tau_start": 1.0,
89
+ "gumbel_tau_end": 0.2,
90
+ "gumbel_noise_scale_start": 1.0,
91
+ "gumbel_noise_scale_end": 1.0,
92
+ "ban_special_tokens": false,
93
+ "banned_endpoint_ids": [],
94
+ "support_power": 1.0,
95
+ "semantic_power": 1.0,
96
+ "noise_init": "dirichlet",
97
+ "noise_sigma": -1.0,
98
+ "noise_dirichlet_concentration": 30522.0,
99
+ "sde_resample": "dirichlet",
100
+ "logistic_normal_sigma_min": 0.18,
101
+ "logistic_normal_sigma_max": 3.0,
102
+ "logistic_normal_tau_min": 0.65,
103
+ "logistic_normal_tau_max": 1.0,
104
+ "final_from": "blend_0.5",
105
+ "n_samples": 128,
106
+ "seed": 20260524
107
+ },
108
+ "raw_genppl": {
109
+ "ppl": 21.699089745306775,
110
+ "nll_per_token": 3.0772703124457186,
111
+ "tokens": 104346,
112
+ "kept_samples": 128,
113
+ "total_samples": 128,
114
+ "empty_rate": 0.0,
115
+ "skipped_samples": 0
116
+ },
117
+ "stripped_genppl": {
118
+ "ppl": 21.233841891724488,
119
+ "nll_per_token": 3.055596224567827,
120
+ "tokens": 103372,
121
+ "kept_samples": 128,
122
+ "total_samples": 128,
123
+ "empty_rate": 0.0,
124
+ "skipped_samples": 0
125
+ },
126
+ "diversity": {
127
+ "sample_entropy": 2.022683447836131,
128
+ "unique_tokens": 2725,
129
+ "token_count": 131072,
130
+ "distinct_1": 0.02079010009765625,
131
+ "distinct_2": 0.08386791300097751,
132
+ "top_token_mass": 0.23024749755859375
133
+ }
134
+ }
135
+ [done] docs/lta_samples/metrics_20260525/owt_bert_absrope_time4_Cv_to_2v_mask1_sameT_sde_gumbel_topp0p95_tau1p0_to_0p2_blend_c30522_61044_n128/lta_owt_bert_absrope_time4_dirichlet_len1024_Cv_to_2v_mask1_sameT_gbs512_b32_8gpu_1m_save10k_20260525/step_0070000/sde_steps128_samples128_scored.jsonl
136
+ [watch-gumbel] 2026-05-26_11:32:05 done step_0070000
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/__init__.py ADDED
@@ -0,0 +1,852 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # When adding a new object to this init, remember to add it twice: once inside the `_import_structure` dictionary and
16
+ # once inside the `if TYPE_CHECKING` branch. The `TYPE_CHECKING` should have import statements as usual, but they are
17
+ # only there for type checking. The `_import_structure` is a dictionary submodule to list of object names, and is used
18
+ # to defer the actual importing for when the objects are requested. This way `import transformers` provides the names
19
+ # in the namespace without actually importing anything (and especially none of the backends).
20
+
21
+ __version__ = "5.9.0"
22
+
23
+ import importlib
24
+ import sys
25
+ import types
26
+ from pathlib import Path
27
+ from typing import TYPE_CHECKING
28
+
29
+ # Check the dependencies satisfy the minimal versions required.
30
+ from . import dependency_versions_check
31
+ from .utils import (
32
+ OptionalDependencyNotAvailable,
33
+ _LazyModule,
34
+ is_essentia_available,
35
+ is_g2p_en_available,
36
+ is_librosa_available,
37
+ is_mistral_common_available,
38
+ is_mlx_available,
39
+ is_numba_available,
40
+ is_pretty_midi_available,
41
+ )
42
+
43
+ # Note: the following symbols are deliberately exported with `as`
44
+ # so that mypy, pylint or other static linters can recognize them,
45
+ # given that they are not exported using `__all__` in this file.
46
+ from .utils import is_bitsandbytes_available as is_bitsandbytes_available
47
+ from .utils import is_scipy_available as is_scipy_available
48
+ from .utils import is_sentencepiece_available as is_sentencepiece_available
49
+ from .utils import is_speech_available as is_speech_available
50
+ from .utils import is_timm_available as is_timm_available
51
+ from .utils import is_tokenizers_available as is_tokenizers_available
52
+ from .utils import is_torch_available as is_torch_available
53
+ from .utils import is_torchaudio_available as is_torchaudio_available
54
+ from .utils import is_torchvision_available as is_torchvision_available
55
+ from .utils import is_vision_available as is_vision_available
56
+ from .utils import logging as logging
57
+ from .utils.import_utils import define_import_structure
58
+
59
+
60
+ logger = logging.get_logger(__name__) # pylint: disable=invalid-name
61
+
62
+ # Base objects, independent of any specific backend
63
+ _import_structure = {
64
+ "audio_utils": [],
65
+ "cli": [],
66
+ "configuration_utils": ["PreTrainedConfig", "PretrainedConfig"],
67
+ "convert_slow_tokenizers_checkpoints_to_fast": [],
68
+ "data": [
69
+ "DataProcessor",
70
+ "InputExample",
71
+ "InputFeatures",
72
+ "SingleSentenceClassificationProcessor",
73
+ "SquadExample",
74
+ "SquadFeatures",
75
+ "SquadV1Processor",
76
+ "SquadV2Processor",
77
+ "glue_compute_metrics",
78
+ "glue_convert_examples_to_features",
79
+ "glue_output_modes",
80
+ "glue_processors",
81
+ "glue_tasks_num_labels",
82
+ "squad_convert_examples_to_features",
83
+ "xnli_compute_metrics",
84
+ "xnli_output_modes",
85
+ "xnli_processors",
86
+ "xnli_tasks_num_labels",
87
+ ],
88
+ "data.data_collator": [
89
+ "DataCollator",
90
+ "DataCollatorForLanguageModeling",
91
+ "DataCollatorForMultipleChoice",
92
+ "DataCollatorForPermutationLanguageModeling",
93
+ "DataCollatorForSeq2Seq",
94
+ "DataCollatorForSOP",
95
+ "DataCollatorForTokenClassification",
96
+ "DataCollatorForWholeWordMask",
97
+ "DataCollatorWithFlattening",
98
+ "DataCollatorWithPadding",
99
+ "DefaultDataCollator",
100
+ "default_data_collator",
101
+ ],
102
+ "data.metrics": [],
103
+ "data.processors": [],
104
+ "debug_utils": [],
105
+ "dependency_versions_check": [],
106
+ "dependency_versions_table": [],
107
+ "dynamic_module_utils": [],
108
+ "feature_extraction_sequence_utils": ["SequenceFeatureExtractor"],
109
+ "feature_extraction_utils": ["BatchFeature", "FeatureExtractionMixin"],
110
+ "file_utils": [],
111
+ "generation": [
112
+ "AsyncTextIteratorStreamer",
113
+ "CompileConfig",
114
+ "ContinuousBatchingConfig",
115
+ "GenerationConfig",
116
+ "TextIteratorStreamer",
117
+ "TextStreamer",
118
+ "WatermarkingConfig",
119
+ ],
120
+ "hf_argparser": ["HfArgumentParser"],
121
+ "hyperparameter_search": [],
122
+ "image_processing_utils_fast": [],
123
+ "image_transforms": [],
124
+ "integrations": [
125
+ "is_clearml_available",
126
+ "is_comet_available",
127
+ "is_dvclive_available",
128
+ "is_neptune_available",
129
+ "is_optuna_available",
130
+ "is_ray_available",
131
+ "is_ray_tune_available",
132
+ "is_swanlab_available",
133
+ "is_tensorboard_available",
134
+ "is_trackio_available",
135
+ "is_wandb_available",
136
+ ],
137
+ "loss": [],
138
+ "pipelines": [
139
+ "AnyToAnyPipeline",
140
+ "AudioClassificationPipeline",
141
+ "AutomaticSpeechRecognitionPipeline",
142
+ "CsvPipelineDataFormat",
143
+ "DepthEstimationPipeline",
144
+ "DocumentQuestionAnsweringPipeline",
145
+ "FeatureExtractionPipeline",
146
+ "FillMaskPipeline",
147
+ "ImageClassificationPipeline",
148
+ "ImageFeatureExtractionPipeline",
149
+ "ImageSegmentationPipeline",
150
+ "ImageTextToTextPipeline",
151
+ "JsonPipelineDataFormat",
152
+ "KeypointMatchingPipeline",
153
+ "MaskGenerationPipeline",
154
+ "NerPipeline",
155
+ "ObjectDetectionPipeline",
156
+ "PipedPipelineDataFormat",
157
+ "Pipeline",
158
+ "PipelineDataFormat",
159
+ "TableQuestionAnsweringPipeline",
160
+ "TextClassificationPipeline",
161
+ "TextGenerationPipeline",
162
+ "TextToAudioPipeline",
163
+ "TokenClassificationPipeline",
164
+ "VideoClassificationPipeline",
165
+ "ZeroShotAudioClassificationPipeline",
166
+ "ZeroShotClassificationPipeline",
167
+ "ZeroShotImageClassificationPipeline",
168
+ "ZeroShotObjectDetectionPipeline",
169
+ "pipeline",
170
+ ],
171
+ "processing_utils": [
172
+ "AudioKwargs",
173
+ "ImagesKwargs",
174
+ "ProcessingKwargs",
175
+ "ProcessorMixin",
176
+ "TextKwargs",
177
+ "VideosKwargs",
178
+ ],
179
+ "quantizers": [],
180
+ "testing_utils": [],
181
+ "tokenization_python": ["PreTrainedTokenizer", "PythonBackend"],
182
+ "tokenization_utils": [],
183
+ "tokenization_utils_base": [
184
+ "AddedToken",
185
+ "BatchEncoding",
186
+ "CharSpan",
187
+ "PreTrainedTokenizerBase",
188
+ "TokenSpan",
189
+ ],
190
+ "tokenization_utils_fast": [],
191
+ "tokenization_utils_sentencepiece": ["SentencePieceBackend"],
192
+ "trainer_callback": [
193
+ "DefaultFlowCallback",
194
+ "EarlyStoppingCallback",
195
+ "PrinterCallback",
196
+ "ProgressCallback",
197
+ "TrainerCallback",
198
+ "TrainerControl",
199
+ "TrainerState",
200
+ ],
201
+ "trainer_utils": [
202
+ "EvalPrediction",
203
+ "IntervalStrategy",
204
+ "SchedulerType",
205
+ "enable_full_determinism",
206
+ "set_seed",
207
+ ],
208
+ "training_args": ["TrainingArguments"],
209
+ "training_args_seq2seq": ["Seq2SeqTrainingArguments"],
210
+ "utils": [
211
+ "CONFIG_NAME",
212
+ "MODEL_CARD_NAME",
213
+ "SPIECE_UNDERLINE",
214
+ "WEIGHTS_NAME",
215
+ "TensorType",
216
+ "add_end_docstrings",
217
+ "add_start_docstrings",
218
+ "is_apex_available",
219
+ "is_av_available",
220
+ "is_bitsandbytes_available",
221
+ "is_datasets_available",
222
+ "is_faiss_available",
223
+ "is_matplotlib_available",
224
+ "is_mlx_available",
225
+ "is_phonemizer_available",
226
+ "is_psutil_available",
227
+ "is_py3nvml_available",
228
+ "is_pyctcdecode_available",
229
+ "is_sacremoses_available",
230
+ "is_scipy_available",
231
+ "is_sentencepiece_available",
232
+ "is_sklearn_available",
233
+ "is_speech_available",
234
+ "is_timm_available",
235
+ "is_tokenizers_available",
236
+ "is_torch_available",
237
+ "is_torch_hpu_available",
238
+ "is_torch_mlu_available",
239
+ "is_torch_musa_available",
240
+ "is_torch_neuroncore_available",
241
+ "is_torch_npu_available",
242
+ "is_torchvision_available",
243
+ "is_torch_xla_available",
244
+ "is_torch_xpu_available",
245
+ "is_vision_available",
246
+ "logging",
247
+ ],
248
+ "utils.import_utils": ["requires_backends"],
249
+ "utils.kernel_config": ["KernelConfig"],
250
+ "utils.quantization_config": [
251
+ "AqlmConfig",
252
+ "AutoRoundConfig",
253
+ "AwqConfig",
254
+ "BitNetQuantConfig",
255
+ "BitsAndBytesConfig",
256
+ "CompressedTensorsConfig",
257
+ "EetqConfig",
258
+ "FbgemmFp8Config",
259
+ "FineGrainedFP8Config",
260
+ "FourOverSixConfig",
261
+ "FPQuantConfig",
262
+ "GPTQConfig",
263
+ "HiggsConfig",
264
+ "HqqConfig",
265
+ "MetalConfig",
266
+ "Mxfp4Config",
267
+ "QuantoConfig",
268
+ "QuarkConfig",
269
+ "SinqConfig",
270
+ "SpQRConfig",
271
+ "TorchAoConfig",
272
+ "VptqConfig",
273
+ ],
274
+ "video_utils": [],
275
+ }
276
+
277
+ # tokenizers-backed objects
278
+ try:
279
+ if not is_tokenizers_available():
280
+ raise OptionalDependencyNotAvailable()
281
+ except OptionalDependencyNotAvailable:
282
+ from .utils import dummy_tokenizers_objects
283
+
284
+ _import_structure["utils.dummy_tokenizers_objects"] = [
285
+ name for name in dir(dummy_tokenizers_objects) if not name.startswith("_")
286
+ ]
287
+ else:
288
+ # Fast tokenizers structure
289
+ _import_structure["tokenization_utils_tokenizers"] = [
290
+ "PreTrainedTokenizerFast",
291
+ "TokenizersBackend",
292
+ ]
293
+
294
+
295
+ try:
296
+ if not (is_sentencepiece_available() and is_tokenizers_available()):
297
+ raise OptionalDependencyNotAvailable()
298
+ except OptionalDependencyNotAvailable:
299
+ from .utils import dummy_sentencepiece_and_tokenizers_objects
300
+
301
+ _import_structure["utils.dummy_sentencepiece_and_tokenizers_objects"] = [
302
+ name for name in dir(dummy_sentencepiece_and_tokenizers_objects) if not name.startswith("_")
303
+ ]
304
+ else:
305
+ _import_structure["convert_slow_tokenizer"] = [
306
+ "SLOW_TO_FAST_CONVERTERS",
307
+ "convert_slow_tokenizer",
308
+ ]
309
+
310
+ try:
311
+ if not (is_mistral_common_available()):
312
+ raise OptionalDependencyNotAvailable()
313
+ except OptionalDependencyNotAvailable:
314
+ from .utils import dummy_mistral_common_objects
315
+
316
+ _import_structure["utils.dummy_mistral_common_objects"] = [
317
+ name for name in dir(dummy_mistral_common_objects) if not name.startswith("_")
318
+ ]
319
+ else:
320
+ _import_structure["tokenization_mistral_common"] = ["MistralCommonBackend"]
321
+
322
+ # Vision-specific objects
323
+ try:
324
+ if not is_vision_available():
325
+ raise OptionalDependencyNotAvailable()
326
+ except OptionalDependencyNotAvailable:
327
+ from .utils import dummy_vision_objects
328
+
329
+ _import_structure["utils.dummy_vision_objects"] = [
330
+ name for name in dir(dummy_vision_objects) if not name.startswith("_")
331
+ ]
332
+ else:
333
+ _import_structure["image_processing_backends"] = ["PilBackend"]
334
+ _import_structure["image_processing_base"] = ["ImageProcessingMixin"]
335
+ _import_structure["image_processing_utils"] = ["BaseImageProcessor"]
336
+ _import_structure["image_utils"] = ["ImageFeatureExtractionMixin"]
337
+
338
+ try:
339
+ if not is_torchvision_available():
340
+ raise OptionalDependencyNotAvailable()
341
+ except OptionalDependencyNotAvailable:
342
+ from .utils import dummy_torchvision_objects
343
+
344
+ _import_structure["utils.dummy_torchvision_objects"] = [
345
+ name for name in dir(dummy_torchvision_objects) if not name.startswith("_")
346
+ ]
347
+ else:
348
+ _import_structure.setdefault("image_processing_backends", [])
349
+ _import_structure["image_processing_backends"] += ["TorchvisionBackend"]
350
+ _import_structure["video_processing_utils"] = ["BaseVideoProcessor"]
351
+
352
+ # PyTorch-backed objects
353
+ try:
354
+ if not is_torch_available():
355
+ raise OptionalDependencyNotAvailable()
356
+ except OptionalDependencyNotAvailable:
357
+ from .utils import dummy_pt_objects
358
+
359
+ _import_structure["utils.dummy_pt_objects"] = [name for name in dir(dummy_pt_objects) if not name.startswith("_")]
360
+ else:
361
+ _import_structure["model_debugging_utils"] = [
362
+ "model_addition_debugger_context",
363
+ ]
364
+ _import_structure["activations"] = []
365
+ _import_structure["cache_utils"] = [
366
+ "CacheLayerMixin",
367
+ "DynamicLayer",
368
+ "StaticLayer",
369
+ "StaticSlidingWindowLayer",
370
+ "QuantoQuantizedLayer",
371
+ "HQQQuantizedLayer",
372
+ "Cache",
373
+ "DynamicCache",
374
+ "EncoderDecoderCache",
375
+ "QuantizedCache",
376
+ "StaticCache",
377
+ ]
378
+ _import_structure["data.datasets"] = [
379
+ "GlueDataset",
380
+ "GlueDataTrainingArguments",
381
+ "SquadDataset",
382
+ "SquadDataTrainingArguments",
383
+ ]
384
+ _import_structure["generation"].extend(
385
+ [
386
+ "AlternatingCodebooksLogitsProcessor",
387
+ "BayesianDetectorConfig",
388
+ "BayesianDetectorModel",
389
+ "ClassifierFreeGuidanceLogitsProcessor",
390
+ "ContinuousBatchingManager",
391
+ "ContinuousMixin",
392
+ "EncoderNoRepeatNGramLogitsProcessor",
393
+ "EncoderRepetitionPenaltyLogitsProcessor",
394
+ "EosTokenCriteria",
395
+ "EpsilonLogitsWarper",
396
+ "MinPLogitsWarper",
397
+ "EtaLogitsWarper",
398
+ "ExponentialDecayLengthPenalty",
399
+ "ForcedBOSTokenLogitsProcessor",
400
+ "ForcedEOSTokenLogitsProcessor",
401
+ "GenerationMixin",
402
+ "InfNanRemoveLogitsProcessor",
403
+ "LogitNormalization",
404
+ "LogitsProcessor",
405
+ "LogitsProcessorList",
406
+ "MaxLengthCriteria",
407
+ "MaxTimeCriteria",
408
+ "MinLengthLogitsProcessor",
409
+ "MinNewTokensLengthLogitsProcessor",
410
+ "NoBadWordsLogitsProcessor",
411
+ "NoRepeatNGramLogitsProcessor",
412
+ "PrefixConstrainedLogitsProcessor",
413
+ "RepetitionPenaltyLogitsProcessor",
414
+ "SequenceBiasLogitsProcessor",
415
+ "StoppingCriteria",
416
+ "StoppingCriteriaList",
417
+ "StopStringCriteria",
418
+ "SuppressTokensAtBeginLogitsProcessor",
419
+ "SuppressTokensLogitsProcessor",
420
+ "SynthIDTextWatermarkDetector",
421
+ "SynthIDTextWatermarkingConfig",
422
+ "SynthIDTextWatermarkLogitsProcessor",
423
+ "TemperatureLogitsWarper",
424
+ "TopHLogitsWarper",
425
+ "TopKLogitsWarper",
426
+ "TopPLogitsWarper",
427
+ "TypicalLogitsWarper",
428
+ "UnbatchedClassifierFreeGuidanceLogitsProcessor",
429
+ "WatermarkDetector",
430
+ "WatermarkLogitsProcessor",
431
+ "WhisperTimeStampLogitsProcessor",
432
+ ]
433
+ )
434
+
435
+ # PyTorch domain libraries integration
436
+ _import_structure["integrations.executorch"] = [
437
+ "TorchExportableModuleWithStaticCache",
438
+ "convert_and_export_with_cache",
439
+ ]
440
+
441
+ _import_structure["core_model_loading"] = [
442
+ "Chunk",
443
+ "Concatenate",
444
+ "ConversionOps",
445
+ "MergeModulelist",
446
+ "PermuteForRope",
447
+ "SplitModulelist",
448
+ "WeightConverter",
449
+ ]
450
+ _import_structure["modeling_flash_attention_utils"] = []
451
+ _import_structure["modeling_layers"] = ["GradientCheckpointingLayer"]
452
+ _import_structure["modeling_outputs"] = []
453
+ _import_structure["backbone_utils"] = ["BackboneConfigMixin", "BackboneMixin"]
454
+ _import_structure["modeling_rope_utils"] = ["ROPE_INIT_FUNCTIONS", "dynamic_rope_update", "RopeParameters"]
455
+ _import_structure["modeling_utils"] = ["PreTrainedModel", "AttentionInterface"]
456
+ _import_structure["masking_utils"] = ["AttentionMaskInterface"]
457
+ _import_structure["optimization"] = [
458
+ "Adafactor",
459
+ "get_constant_schedule",
460
+ "get_constant_schedule_with_warmup",
461
+ "get_cosine_schedule_with_warmup",
462
+ "get_cosine_with_hard_restarts_schedule_with_warmup",
463
+ "get_cosine_with_min_lr_schedule_with_warmup",
464
+ "get_cosine_with_min_lr_schedule_with_warmup_lr_rate",
465
+ "get_greedy_schedule",
466
+ "get_inverse_sqrt_schedule",
467
+ "get_linear_schedule_with_warmup",
468
+ "get_polynomial_decay_schedule_with_warmup",
469
+ "get_reduce_on_plateau_schedule",
470
+ "get_scheduler",
471
+ "get_wsd_schedule",
472
+ "GreedyLR",
473
+ ]
474
+ _import_structure["pytorch_utils"] = ["Conv1D", "apply_chunking_to_forward"]
475
+ _import_structure["time_series_utils"] = []
476
+ _import_structure["trainer"] = ["Trainer"]
477
+ _import_structure["trainer_pt_utils"] = ["torch_distributed_zero_first"]
478
+ _import_structure["trainer_seq2seq"] = ["Seq2SeqTrainer"]
479
+
480
+
481
+ # Direct imports for type-checking
482
+ if TYPE_CHECKING:
483
+ # All modeling imports
484
+ # Models
485
+ from .backbone_utils import BackboneConfigMixin, BackboneMixin
486
+ from .cache_utils import Cache as Cache
487
+ from .cache_utils import DynamicCache as DynamicCache
488
+ from .cache_utils import DynamicLayer as DynamicLayer
489
+ from .cache_utils import EncoderDecoderCache as EncoderDecoderCache
490
+ from .cache_utils import HQQQuantizedLayer as HQQQuantizedLayer
491
+ from .cache_utils import QuantizedCache as QuantizedCache
492
+ from .cache_utils import QuantoQuantizedLayer as QuantoQuantizedLayer
493
+ from .cache_utils import StaticCache as StaticCache
494
+ from .cache_utils import StaticLayer as StaticLayer
495
+ from .cache_utils import StaticSlidingWindowLayer as StaticSlidingWindowLayer
496
+ from .configuration_utils import PreTrainedConfig as PreTrainedConfig
497
+ from .configuration_utils import PretrainedConfig as PretrainedConfig
498
+ from .convert_slow_tokenizer import SLOW_TO_FAST_CONVERTERS as SLOW_TO_FAST_CONVERTERS
499
+ from .convert_slow_tokenizer import convert_slow_tokenizer as convert_slow_tokenizer
500
+ from .core_model_loading import Chunk as Chunk
501
+ from .core_model_loading import Concatenate as Concatenate
502
+ from .core_model_loading import ConversionOps as ConversionOps
503
+ from .core_model_loading import MergeModulelist as MergeModulelist
504
+ from .core_model_loading import PermuteForRope as PermuteForRope
505
+ from .core_model_loading import SplitModulelist as SplitModulelist
506
+ from .core_model_loading import WeightConverter as WeightConverter
507
+
508
+ # Data
509
+ from .data import DataProcessor as DataProcessor
510
+ from .data import InputExample as InputExample
511
+ from .data import InputFeatures as InputFeatures
512
+ from .data import SingleSentenceClassificationProcessor as SingleSentenceClassificationProcessor
513
+ from .data import SquadExample as SquadExample
514
+ from .data import SquadFeatures as SquadFeatures
515
+ from .data import SquadV1Processor as SquadV1Processor
516
+ from .data import SquadV2Processor as SquadV2Processor
517
+ from .data import glue_compute_metrics as glue_compute_metrics
518
+ from .data import glue_convert_examples_to_features as glue_convert_examples_to_features
519
+ from .data import glue_output_modes as glue_output_modes
520
+ from .data import glue_processors as glue_processors
521
+ from .data import glue_tasks_num_labels as glue_tasks_num_labels
522
+ from .data import squad_convert_examples_to_features as squad_convert_examples_to_features
523
+ from .data import xnli_compute_metrics as xnli_compute_metrics
524
+ from .data import xnli_output_modes as xnli_output_modes
525
+ from .data import xnli_processors as xnli_processors
526
+ from .data import xnli_tasks_num_labels as xnli_tasks_num_labels
527
+ from .data.data_collator import DataCollator as DataCollator
528
+ from .data.data_collator import DataCollatorForLanguageModeling as DataCollatorForLanguageModeling
529
+ from .data.data_collator import DataCollatorForMultipleChoice as DataCollatorForMultipleChoice
530
+ from .data.data_collator import (
531
+ DataCollatorForPermutationLanguageModeling as DataCollatorForPermutationLanguageModeling,
532
+ )
533
+ from .data.data_collator import DataCollatorForSeq2Seq as DataCollatorForSeq2Seq
534
+ from .data.data_collator import DataCollatorForSOP as DataCollatorForSOP
535
+ from .data.data_collator import DataCollatorForTokenClassification as DataCollatorForTokenClassification
536
+ from .data.data_collator import DataCollatorForWholeWordMask as DataCollatorForWholeWordMask
537
+ from .data.data_collator import DataCollatorWithFlattening as DataCollatorWithFlattening
538
+ from .data.data_collator import DataCollatorWithPadding as DataCollatorWithPadding
539
+ from .data.data_collator import DefaultDataCollator as DefaultDataCollator
540
+ from .data.data_collator import default_data_collator as default_data_collator
541
+ from .data.datasets import GlueDataset as GlueDataset
542
+ from .data.datasets import GlueDataTrainingArguments as GlueDataTrainingArguments
543
+ from .data.datasets import SquadDataset as SquadDataset
544
+ from .data.datasets import SquadDataTrainingArguments as SquadDataTrainingArguments
545
+ from .feature_extraction_sequence_utils import SequenceFeatureExtractor as SequenceFeatureExtractor
546
+
547
+ # Feature Extractor
548
+ from .feature_extraction_utils import BatchFeature as BatchFeature
549
+ from .feature_extraction_utils import FeatureExtractionMixin as FeatureExtractionMixin
550
+
551
+ # Generation
552
+ from .generation import AlternatingCodebooksLogitsProcessor as AlternatingCodebooksLogitsProcessor
553
+ from .generation import AsyncTextIteratorStreamer as AsyncTextIteratorStreamer
554
+ from .generation import BayesianDetectorConfig as BayesianDetectorConfig
555
+ from .generation import BayesianDetectorModel as BayesianDetectorModel
556
+ from .generation import ClassifierFreeGuidanceLogitsProcessor as ClassifierFreeGuidanceLogitsProcessor
557
+ from .generation import CompileConfig as CompileConfig
558
+ from .generation import ContinuousBatchingConfig as ContinuousBatchingConfig
559
+ from .generation import ContinuousBatchingManager as ContinuousBatchingManager
560
+ from .generation import ContinuousMixin as ContinuousMixin
561
+ from .generation import EncoderNoRepeatNGramLogitsProcessor as EncoderNoRepeatNGramLogitsProcessor
562
+ from .generation import EncoderRepetitionPenaltyLogitsProcessor as EncoderRepetitionPenaltyLogitsProcessor
563
+ from .generation import EosTokenCriteria as EosTokenCriteria
564
+ from .generation import EpsilonLogitsWarper as EpsilonLogitsWarper
565
+ from .generation import EtaLogitsWarper as EtaLogitsWarper
566
+ from .generation import ExponentialDecayLengthPenalty as ExponentialDecayLengthPenalty
567
+ from .generation import ForcedBOSTokenLogitsProcessor as ForcedBOSTokenLogitsProcessor
568
+ from .generation import ForcedEOSTokenLogitsProcessor as ForcedEOSTokenLogitsProcessor
569
+ from .generation import GenerationConfig as GenerationConfig
570
+ from .generation import GenerationMixin as GenerationMixin
571
+ from .generation import InfNanRemoveLogitsProcessor as InfNanRemoveLogitsProcessor
572
+ from .generation import LogitNormalization as LogitNormalization
573
+ from .generation import LogitsProcessor as LogitsProcessor
574
+ from .generation import LogitsProcessorList as LogitsProcessorList
575
+ from .generation import MaxLengthCriteria as MaxLengthCriteria
576
+ from .generation import MaxTimeCriteria as MaxTimeCriteria
577
+ from .generation import MinLengthLogitsProcessor as MinLengthLogitsProcessor
578
+ from .generation import MinNewTokensLengthLogitsProcessor as MinNewTokensLengthLogitsProcessor
579
+ from .generation import MinPLogitsWarper as MinPLogitsWarper
580
+ from .generation import NoBadWordsLogitsProcessor as NoBadWordsLogitsProcessor
581
+ from .generation import NoRepeatNGramLogitsProcessor as NoRepeatNGramLogitsProcessor
582
+ from .generation import PrefixConstrainedLogitsProcessor as PrefixConstrainedLogitsProcessor
583
+ from .generation import RepetitionPenaltyLogitsProcessor as RepetitionPenaltyLogitsProcessor
584
+ from .generation import SequenceBiasLogitsProcessor as SequenceBiasLogitsProcessor
585
+ from .generation import StoppingCriteria as StoppingCriteria
586
+ from .generation import StoppingCriteriaList as StoppingCriteriaList
587
+ from .generation import StopStringCriteria as StopStringCriteria
588
+ from .generation import SuppressTokensAtBeginLogitsProcessor as SuppressTokensAtBeginLogitsProcessor
589
+ from .generation import SuppressTokensLogitsProcessor as SuppressTokensLogitsProcessor
590
+ from .generation import SynthIDTextWatermarkDetector as SynthIDTextWatermarkDetector
591
+ from .generation import SynthIDTextWatermarkingConfig as SynthIDTextWatermarkingConfig
592
+ from .generation import SynthIDTextWatermarkLogitsProcessor as SynthIDTextWatermarkLogitsProcessor
593
+ from .generation import TemperatureLogitsWarper as TemperatureLogitsWarper
594
+ from .generation import TextIteratorStreamer as TextIteratorStreamer
595
+ from .generation import TextStreamer as TextStreamer
596
+ from .generation import TopHLogitsWarper as TopHLogitsWarper
597
+ from .generation import TopKLogitsWarper as TopKLogitsWarper
598
+ from .generation import TopPLogitsWarper as TopPLogitsWarper
599
+ from .generation import TypicalLogitsWarper as TypicalLogitsWarper
600
+ from .generation import (
601
+ UnbatchedClassifierFreeGuidanceLogitsProcessor as UnbatchedClassifierFreeGuidanceLogitsProcessor,
602
+ )
603
+ from .generation import WatermarkDetector as WatermarkDetector
604
+ from .generation import WatermarkingConfig as WatermarkingConfig
605
+ from .generation import WatermarkLogitsProcessor as WatermarkLogitsProcessor
606
+ from .generation import WhisperTimeStampLogitsProcessor as WhisperTimeStampLogitsProcessor
607
+ from .hf_argparser import HfArgumentParser as HfArgumentParser
608
+ from .image_processing_backends import PilBackend as PilBackend
609
+ from .image_processing_backends import TorchvisionBackend as TorchvisionBackend
610
+ from .image_processing_base import ImageProcessingMixin as ImageProcessingMixin
611
+ from .image_processing_utils import BaseImageProcessor as BaseImageProcessor
612
+ from .image_utils import ImageFeatureExtractionMixin as ImageFeatureExtractionMixin
613
+
614
+ # Integrations
615
+ from .integrations import is_clearml_available as is_clearml_available
616
+ from .integrations import is_comet_available as is_comet_available
617
+ from .integrations import is_dvclive_available as is_dvclive_available
618
+ from .integrations import is_neptune_available as is_neptune_available
619
+ from .integrations import is_optuna_available as is_optuna_available
620
+ from .integrations import is_ray_available as is_ray_available
621
+ from .integrations import is_ray_tune_available as is_ray_tune_available
622
+ from .integrations import is_swanlab_available as is_swanlab_available
623
+ from .integrations import is_tensorboard_available as is_tensorboard_available
624
+ from .integrations import is_trackio_available as is_trackio_available
625
+ from .integrations import is_wandb_available as is_wandb_available
626
+ from .integrations.executorch import TorchExportableModuleWithStaticCache as TorchExportableModuleWithStaticCache
627
+ from .integrations.executorch import convert_and_export_with_cache as convert_and_export_with_cache
628
+ from .masking_utils import AttentionMaskInterface as AttentionMaskInterface
629
+ from .model_debugging_utils import model_addition_debugger_context as model_addition_debugger_context
630
+ from .modeling_layers import GradientCheckpointingLayer as GradientCheckpointingLayer
631
+ from .modeling_rope_utils import ROPE_INIT_FUNCTIONS as ROPE_INIT_FUNCTIONS
632
+ from .modeling_rope_utils import RopeParameters as RopeParameters
633
+ from .modeling_rope_utils import dynamic_rope_update as dynamic_rope_update
634
+ from .modeling_utils import AttentionInterface as AttentionInterface
635
+ from .modeling_utils import PreTrainedModel as PreTrainedModel
636
+ from .models import *
637
+ from .models.timm_wrapper import TimmWrapperImageProcessor as TimmWrapperImageProcessor
638
+
639
+ # Optimization
640
+ from .optimization import Adafactor as Adafactor
641
+ from .optimization import GreedyLR as GreedyLR
642
+ from .optimization import get_constant_schedule as get_constant_schedule
643
+ from .optimization import get_constant_schedule_with_warmup as get_constant_schedule_with_warmup
644
+ from .optimization import get_cosine_schedule_with_warmup as get_cosine_schedule_with_warmup
645
+ from .optimization import (
646
+ get_cosine_with_hard_restarts_schedule_with_warmup as get_cosine_with_hard_restarts_schedule_with_warmup,
647
+ )
648
+ from .optimization import (
649
+ get_cosine_with_min_lr_schedule_with_warmup as get_cosine_with_min_lr_schedule_with_warmup,
650
+ )
651
+ from .optimization import (
652
+ get_cosine_with_min_lr_schedule_with_warmup_lr_rate as get_cosine_with_min_lr_schedule_with_warmup_lr_rate,
653
+ )
654
+ from .optimization import get_greedy_schedule as get_greedy_schedule
655
+ from .optimization import get_inverse_sqrt_schedule as get_inverse_sqrt_schedule
656
+ from .optimization import get_linear_schedule_with_warmup as get_linear_schedule_with_warmup
657
+ from .optimization import get_polynomial_decay_schedule_with_warmup as get_polynomial_decay_schedule_with_warmup
658
+ from .optimization import get_scheduler as get_scheduler
659
+ from .optimization import get_wsd_schedule as get_wsd_schedule
660
+
661
+ # Pipelines
662
+ from .pipelines import AnyToAnyPipeline as AnyToAnyPipeline
663
+ from .pipelines import AudioClassificationPipeline as AudioClassificationPipeline
664
+ from .pipelines import AutomaticSpeechRecognitionPipeline as AutomaticSpeechRecognitionPipeline
665
+ from .pipelines import CsvPipelineDataFormat as CsvPipelineDataFormat
666
+ from .pipelines import DepthEstimationPipeline as DepthEstimationPipeline
667
+ from .pipelines import DocumentQuestionAnsweringPipeline as DocumentQuestionAnsweringPipeline
668
+ from .pipelines import FeatureExtractionPipeline as FeatureExtractionPipeline
669
+ from .pipelines import FillMaskPipeline as FillMaskPipeline
670
+ from .pipelines import ImageClassificationPipeline as ImageClassificationPipeline
671
+ from .pipelines import ImageFeatureExtractionPipeline as ImageFeatureExtractionPipeline
672
+ from .pipelines import ImageSegmentationPipeline as ImageSegmentationPipeline
673
+ from .pipelines import ImageTextToTextPipeline as ImageTextToTextPipeline
674
+ from .pipelines import JsonPipelineDataFormat as JsonPipelineDataFormat
675
+ from .pipelines import KeypointMatchingPipeline as KeypointMatchingPipeline
676
+ from .pipelines import MaskGenerationPipeline as MaskGenerationPipeline
677
+ from .pipelines import NerPipeline as NerPipeline
678
+ from .pipelines import ObjectDetectionPipeline as ObjectDetectionPipeline
679
+ from .pipelines import PipedPipelineDataFormat as PipedPipelineDataFormat
680
+ from .pipelines import Pipeline as Pipeline
681
+ from .pipelines import PipelineDataFormat as PipelineDataFormat
682
+ from .pipelines import TableQuestionAnsweringPipeline as TableQuestionAnsweringPipeline
683
+ from .pipelines import TextClassificationPipeline as TextClassificationPipeline
684
+ from .pipelines import TextGenerationPipeline as TextGenerationPipeline
685
+ from .pipelines import TextToAudioPipeline as TextToAudioPipeline
686
+ from .pipelines import TokenClassificationPipeline as TokenClassificationPipeline
687
+ from .pipelines import VideoClassificationPipeline as VideoClassificationPipeline
688
+ from .pipelines import ZeroShotAudioClassificationPipeline as ZeroShotAudioClassificationPipeline
689
+ from .pipelines import ZeroShotClassificationPipeline as ZeroShotClassificationPipeline
690
+ from .pipelines import ZeroShotImageClassificationPipeline as ZeroShotImageClassificationPipeline
691
+ from .pipelines import ZeroShotObjectDetectionPipeline as ZeroShotObjectDetectionPipeline
692
+ from .pipelines import pipeline as pipeline
693
+ from .processing_utils import AudioKwargs as AudioKwargs
694
+ from .processing_utils import ImagesKwargs as ImagesKwargs
695
+ from .processing_utils import ProcessingKwargs as ProcessingKwargs
696
+ from .processing_utils import ProcessorMixin as ProcessorMixin
697
+ from .processing_utils import TextKwargs as TextKwargs
698
+ from .processing_utils import VideosKwargs as VideosKwargs
699
+ from .pytorch_utils import Conv1D as Conv1D
700
+ from .pytorch_utils import apply_chunking_to_forward as apply_chunking_to_forward
701
+
702
+ # Tokenization
703
+ from .tokenization_python import PreTrainedTokenizer as PreTrainedTokenizer
704
+ from .tokenization_python import PythonBackend as PythonBackend
705
+ from .tokenization_utils_base import AddedToken as AddedToken
706
+ from .tokenization_utils_base import BatchEncoding as BatchEncoding
707
+ from .tokenization_utils_base import CharSpan as CharSpan
708
+ from .tokenization_utils_base import PreTrainedTokenizerBase as PreTrainedTokenizerBase
709
+ from .tokenization_utils_base import TokenSpan as TokenSpan
710
+
711
+ # Tokenization
712
+ from .tokenization_utils_sentencepiece import SentencePieceBackend as SentencePieceBackend
713
+ from .tokenization_utils_tokenizers import PreTrainedTokenizerFast as PreTrainedTokenizerFast
714
+ from .tokenization_utils_tokenizers import (
715
+ TokenizersBackend as TokenizersBackend,
716
+ )
717
+
718
+ # Trainer
719
+ from .trainer import Trainer as Trainer
720
+ from .trainer_callback import DefaultFlowCallback as DefaultFlowCallback
721
+ from .trainer_callback import EarlyStoppingCallback as EarlyStoppingCallback
722
+ from .trainer_callback import PrinterCallback as PrinterCallback
723
+ from .trainer_callback import ProgressCallback as ProgressCallback
724
+ from .trainer_callback import TrainerCallback as TrainerCallback
725
+ from .trainer_callback import TrainerControl as TrainerControl
726
+ from .trainer_callback import TrainerState as TrainerState
727
+ from .trainer_pt_utils import torch_distributed_zero_first as torch_distributed_zero_first
728
+ from .trainer_seq2seq import Seq2SeqTrainer as Seq2SeqTrainer
729
+ from .trainer_utils import EvalPrediction as EvalPrediction
730
+ from .trainer_utils import IntervalStrategy as IntervalStrategy
731
+ from .trainer_utils import SchedulerType as SchedulerType
732
+ from .trainer_utils import enable_full_determinism as enable_full_determinism
733
+ from .trainer_utils import set_seed as set_seed
734
+ from .training_args import TrainingArguments as TrainingArguments
735
+ from .training_args_seq2seq import Seq2SeqTrainingArguments as Seq2SeqTrainingArguments
736
+
737
+ # Files and general utilities
738
+ from .utils import CONFIG_NAME as CONFIG_NAME
739
+ from .utils import MODEL_CARD_NAME as MODEL_CARD_NAME
740
+ from .utils import SPIECE_UNDERLINE as SPIECE_UNDERLINE
741
+ from .utils import WEIGHTS_NAME as WEIGHTS_NAME
742
+ from .utils import TensorType as TensorType
743
+ from .utils import add_end_docstrings as add_end_docstrings
744
+ from .utils import add_start_docstrings as add_start_docstrings
745
+ from .utils import is_apex_available as is_apex_available
746
+ from .utils import is_av_available as is_av_available
747
+ from .utils import is_datasets_available as is_datasets_available
748
+ from .utils import is_faiss_available as is_faiss_available
749
+ from .utils import is_matplotlib_available as is_matplotlib_available
750
+ from .utils import is_phonemizer_available as is_phonemizer_available
751
+ from .utils import is_psutil_available as is_psutil_available
752
+ from .utils import is_py3nvml_available as is_py3nvml_available
753
+ from .utils import is_pyctcdecode_available as is_pyctcdecode_available
754
+ from .utils import is_sacremoses_available as is_sacremoses_available
755
+ from .utils import is_sklearn_available as is_sklearn_available
756
+ from .utils import is_torch_hpu_available as is_torch_hpu_available
757
+ from .utils import is_torch_mlu_available as is_torch_mlu_available
758
+ from .utils import is_torch_musa_available as is_torch_musa_available
759
+ from .utils import is_torch_neuroncore_available as is_torch_neuroncore_available
760
+ from .utils import is_torch_npu_available as is_torch_npu_available
761
+ from .utils import is_torch_xla_available as is_torch_xla_available
762
+ from .utils import is_torch_xpu_available as is_torch_xpu_available
763
+ from .utils.import_utils import requires_backends
764
+ from .utils.kernel_config import KernelConfig as KernelConfig
765
+
766
+ # Quantization config
767
+ from .utils.quantization_config import AqlmConfig as AqlmConfig
768
+ from .utils.quantization_config import AutoRoundConfig as AutoRoundConfig
769
+ from .utils.quantization_config import AwqConfig as AwqConfig
770
+ from .utils.quantization_config import BitNetQuantConfig as BitNetQuantConfig
771
+ from .utils.quantization_config import BitsAndBytesConfig as BitsAndBytesConfig
772
+ from .utils.quantization_config import CompressedTensorsConfig as CompressedTensorsConfig
773
+ from .utils.quantization_config import EetqConfig as EetqConfig
774
+ from .utils.quantization_config import FbgemmFp8Config as FbgemmFp8Config
775
+ from .utils.quantization_config import FineGrainedFP8Config as FineGrainedFP8Config
776
+ from .utils.quantization_config import FourOverSixConfig as FourOverSixConfig
777
+ from .utils.quantization_config import FPQuantConfig as FPQuantConfig
778
+ from .utils.quantization_config import GPTQConfig as GPTQConfig
779
+ from .utils.quantization_config import HiggsConfig as HiggsConfig
780
+ from .utils.quantization_config import HqqConfig as HqqConfig
781
+ from .utils.quantization_config import MetalConfig as MetalConfig
782
+ from .utils.quantization_config import QuantoConfig as QuantoConfig
783
+ from .utils.quantization_config import QuarkConfig as QuarkConfig
784
+ from .utils.quantization_config import SinqConfig as SinqConfig
785
+ from .utils.quantization_config import SpQRConfig as SpQRConfig
786
+ from .utils.quantization_config import TorchAoConfig as TorchAoConfig
787
+ from .utils.quantization_config import VptqConfig as VptqConfig
788
+ from .video_processing_utils import BaseVideoProcessor as BaseVideoProcessor
789
+ else:
790
+ _import_structure = {k: set(v) for k, v in _import_structure.items()}
791
+
792
+ import_structure = define_import_structure(Path(__file__).parent / "models", prefix="models")
793
+ import_structure[frozenset({})].update(_import_structure)
794
+
795
+ sys.modules[__name__] = _LazyModule(
796
+ __name__,
797
+ globals()["__file__"],
798
+ import_structure,
799
+ module_spec=__spec__,
800
+ extra_objects={"__version__": __version__},
801
+ )
802
+
803
+ def _create_module_alias(alias: str, target: str) -> None:
804
+ """
805
+ Lazily redirect legacy module paths to their replacements without importing heavy deps.
806
+ """
807
+ module = types.ModuleType(alias)
808
+ module.__doc__ = f"Alias module for backward compatibility with `{target}`."
809
+ # Set __file__ explicitly so that inspect.py's hasattr(module, '__file__') check
810
+ # never falls through to __getattr__ and triggers a premature (possibly circular) import.
811
+ module.__file__ = None
812
+
813
+ def _get_target():
814
+ return importlib.import_module(target, __name__)
815
+
816
+ module.__getattr__ = lambda name: getattr(_get_target(), name)
817
+ module.__dir__ = lambda: dir(_get_target())
818
+
819
+ sys.modules[alias] = module
820
+ setattr(sys.modules[__name__], alias.rsplit(".", 1)[-1], module)
821
+
822
+ _create_module_alias(f"{__name__}.tokenization_utils_fast", ".tokenization_utils_tokenizers")
823
+ _create_module_alias(f"{__name__}.tokenization_utils", ".tokenization_utils_sentencepiece")
824
+ _create_module_alias(f"{__name__}.image_processing_utils_fast", ".image_processing_backends")
825
+
826
+ for _proc_file in sorted((Path(__file__).parent / "models").rglob("image_processing_*.py")):
827
+ _model = _proc_file.parent.name
828
+ _module = _proc_file.stem
829
+ _target = f".models.{_model}.{_module}"
830
+ _create_module_alias(f"{__name__}.models.{_model}.{_module}_fast", _target)
831
+
832
+ # Also map XImageProcessorFast -> XImageProcessor for backward compat with old class names.
833
+ def getattr_factory(target):
834
+ def _getattr(name):
835
+ new_name = name.removesuffix("Fast")
836
+ logger.warning(
837
+ "Accessing `%s` from `%s`. Returning `%s` instead. Behavior may be "
838
+ "different and this alias will be removed in future versions.",
839
+ name,
840
+ target,
841
+ new_name,
842
+ )
843
+ return getattr(importlib.import_module(target, __name__), new_name)
844
+
845
+ return _getattr
846
+
847
+ sys.modules[f"{__name__}.models.{_model}.{_module}_fast"].__getattr__ = getattr_factory(_target)
848
+
849
+ if not is_torch_available():
850
+ logger.warning_advice(
851
+ "PyTorch was not found. Models won't be available and only tokenizers, configuration and file/data utilities can be used."
852
+ )
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/convert_slow_tokenizer.py ADDED
@@ -0,0 +1,2151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2018 The HuggingFace Inc. team.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """
15
+ Utilities to convert slow tokenizers in their fast tokenizers counterparts.
16
+
17
+ All the conversions are grouped here to gather SentencePiece dependencies outside of the fast tokenizers files and
18
+ allow to make our dependency on SentencePiece optional.
19
+ """
20
+
21
+ import warnings
22
+ from collections.abc import Collection
23
+ from functools import lru_cache
24
+
25
+ from packaging import version
26
+ from tokenizers import AddedToken, Regex, Tokenizer, decoders, normalizers, pre_tokenizers, processors
27
+ from tokenizers.models import BPE, Unigram, WordPiece
28
+ from tqdm import tqdm
29
+
30
+ from .utils import is_protobuf_available, is_sentencepiece_available, logging, requires_backends
31
+ from .utils.import_utils import PROTOBUF_IMPORT_ERROR
32
+
33
+
34
+ logger = logging.get_logger(__name__)
35
+
36
+ MBART_LANGUAGES = [
37
+ "ar_AR",
38
+ "cs_CZ",
39
+ "de_DE",
40
+ "en_XX",
41
+ "es_XX",
42
+ "et_EE",
43
+ "fi_FI",
44
+ "fr_XX",
45
+ "gu_IN",
46
+ "hi_IN",
47
+ "it_IT",
48
+ "ja_XX",
49
+ "kk_KZ",
50
+ "ko_KR",
51
+ "lt_LT",
52
+ "lv_LV",
53
+ "my_MM",
54
+ "ne_NP",
55
+ "nl_XX",
56
+ "ro_RO",
57
+ "ru_RU",
58
+ "si_LK",
59
+ "tr_TR",
60
+ "vi_VN",
61
+ "zh_CN",
62
+ ]
63
+
64
+ MBART50_LANGUAGES = MBART_LANGUAGES + [
65
+ "af_ZA",
66
+ "az_AZ",
67
+ "bn_IN",
68
+ "fa_IR",
69
+ "he_IL",
70
+ "hr_HR",
71
+ "id_ID",
72
+ "ka_GE",
73
+ "km_KH",
74
+ "mk_MK",
75
+ "ml_IN",
76
+ "mn_MN",
77
+ "mr_IN",
78
+ "pl_PL",
79
+ "ps_AF",
80
+ "pt_XX",
81
+ "sv_SE",
82
+ "sw_KE",
83
+ "ta_IN",
84
+ "te_IN",
85
+ "th_TH",
86
+ "tl_XX",
87
+ "uk_UA",
88
+ "ur_PK",
89
+ "xh_ZA",
90
+ "gl_ES",
91
+ "sl_SI",
92
+ ]
93
+
94
+
95
+ def import_protobuf(error_message=""):
96
+ if is_sentencepiece_available():
97
+ from sentencepiece import sentencepiece_model_pb2
98
+
99
+ return sentencepiece_model_pb2
100
+ if is_protobuf_available():
101
+ import google.protobuf
102
+
103
+ if version.parse(google.protobuf.__version__) < version.parse("4.0.0"):
104
+ from transformers.utils import sentencepiece_model_pb2
105
+ else:
106
+ from transformers.utils import sentencepiece_model_pb2_new as sentencepiece_model_pb2
107
+ return sentencepiece_model_pb2
108
+ else:
109
+ raise ImportError(PROTOBUF_IMPORT_ERROR.format(error_message))
110
+
111
+
112
+ def _get_prepend_scheme(add_prefix_space: bool, original_tokenizer) -> str:
113
+ if add_prefix_space:
114
+ prepend_scheme = "always"
115
+ if not getattr(original_tokenizer, "legacy", True):
116
+ prepend_scheme = "first"
117
+ else:
118
+ prepend_scheme = "never"
119
+ return prepend_scheme
120
+
121
+
122
+ def generate_merges(vocab, vocab_scores, skip_tokens: Collection[str] | None = None):
123
+ skip_tokens = set(skip_tokens) if skip_tokens is not None else set()
124
+ reverse = vocab_scores is not None
125
+ vocab_scores = dict(vocab_scores) if reverse else vocab
126
+
127
+ merges = []
128
+ for merge, piece_score in vocab_scores.items():
129
+ if merge in skip_tokens:
130
+ continue
131
+ local = []
132
+ for index in range(1, len(merge)):
133
+ piece_l, piece_r = merge[:index], merge[index:]
134
+ if piece_l in skip_tokens or piece_r in skip_tokens:
135
+ continue
136
+ if piece_l in vocab and piece_r in vocab:
137
+ local.append((piece_l, piece_r, piece_score))
138
+ local = sorted(local, key=lambda x: (vocab[x[0]], vocab[x[1]]))
139
+ merges.extend(local)
140
+
141
+ merges = sorted(merges, key=lambda val: (val[2], len(val[0]), len(val[1])), reverse=reverse)
142
+ merges = [(val[0], val[1]) for val in merges]
143
+ return merges
144
+
145
+
146
+ class SentencePieceExtractor:
147
+ """
148
+ Extractor implementation for SentencePiece trained models. https://github.com/google/sentencepiece
149
+ """
150
+
151
+ def __init__(self, model: str):
152
+ requires_backends(self, "sentencepiece")
153
+ requires_backends(self, "protobuf")
154
+
155
+ # from .utils import sentencepiece_model_pb2 as model_pb2
156
+ model_pb2 = import_protobuf()
157
+
158
+ m = model_pb2.ModelProto()
159
+ with open(model, "rb") as f:
160
+ m.ParseFromString(f.read())
161
+ self.proto = m
162
+
163
+ def extract(self, model_type, **kwargs) -> tuple[dict[str, int], list[tuple]]:
164
+ """
165
+ By default will return vocab and merges with respect to their order, by sending `vocab_scores` we're going to
166
+ order the merges with respect to the piece scores instead.
167
+ """
168
+ self.proto.trainer_spec.unk_id
169
+ if model_type is None:
170
+ from tokenizers.models import BPE, Unigram
171
+
172
+ model_type = Unigram if self.proto.trainer_spec.model_type == 1 else BPE
173
+ vocab = [(piece.piece, piece.score) for piece in self.proto.pieces]
174
+
175
+ if model_type.__name__ != "BPE":
176
+ kwargs["unk_id"] = self.proto.trainer_spec.unk_id
177
+ kwargs["vocab"] = vocab
178
+ else:
179
+ from .tokenization_utils_base import generate_merges
180
+
181
+ vocab = {word: i for i, (word, score) in enumerate(vocab)}
182
+ merges = generate_merges(vocab)
183
+ kwargs["vocab"] = vocab
184
+ kwargs["merges"] = merges
185
+
186
+ # control tokens are special
187
+ # user defined symbols are not
188
+ # both user and control tokens are AddedTokens
189
+ # Add user defined symbols (type == 4) from sentencepiece (https://github.com/google/sentencepiece/blob/6225e08edb2577757163b3f5dbba4c0b670ef445/src/sentencepiece_model.proto#L299C29-L299C33)
190
+ spm_added_tokens = [(id, p.piece, p.type == 3) for id, p in enumerate(self.proto.pieces) if p.type in [3, 4]]
191
+ kwargs["additional_special_tokens"] = [
192
+ AddedToken(token, normalized=False, special=special)
193
+ for id, token, special in sorted(spm_added_tokens, key=lambda x: x[0])
194
+ ]
195
+ kwargs["_spm_precompiled_charsmap"] = getattr(self.proto.normalizer_spec, "precompiled_charsmap", None)
196
+ return kwargs
197
+
198
+
199
+ class GemmaSentencePieceExtractor(SentencePieceExtractor):
200
+ def extract(self, vocab_scores=None) -> tuple[dict[str, int], list[tuple]]:
201
+ """
202
+ By default will return vocab and merges with respect to their order, by sending `vocab_scores` we're going to
203
+ order the merges with respect to the piece scores instead.
204
+ """
205
+ sp = self.sp
206
+ vocab = {sp.id_to_piece(index): index for index in range(sp.GetPieceSize())}
207
+
208
+ # If "\t" is missing in the vocab, we have to do this to support merges
209
+ # "<0x09>" is the bytefallback for `\t`
210
+ if "\t" not in vocab:
211
+ vocab["\t"] = vocab.get("<0x09>")
212
+ merges = generate_merges(vocab, vocab_scores)
213
+ return vocab, merges
214
+
215
+
216
+ def check_number_comma(piece: str) -> bool:
217
+ return len(piece) < 2 or piece[-1] != "," or not piece[-2].isdigit()
218
+
219
+
220
+ class Converter:
221
+ def __init__(self, original_tokenizer):
222
+ self.original_tokenizer = original_tokenizer
223
+
224
+ def converted(self) -> Tokenizer:
225
+ raise NotImplementedError()
226
+
227
+
228
+ class BertConverter(Converter):
229
+ def converted(self) -> Tokenizer:
230
+ vocab = self.original_tokenizer.vocab
231
+ tokenizer = Tokenizer(WordPiece(vocab, unk_token=str(self.original_tokenizer.unk_token)))
232
+
233
+ tokenize_chinese_chars = False
234
+ strip_accents = False
235
+ do_lower_case = False
236
+ if hasattr(self.original_tokenizer, "basic_tokenizer"):
237
+ tokenize_chinese_chars = self.original_tokenizer.basic_tokenizer.tokenize_chinese_chars
238
+ strip_accents = self.original_tokenizer.basic_tokenizer.strip_accents
239
+ do_lower_case = self.original_tokenizer.basic_tokenizer.do_lower_case
240
+
241
+ tokenizer.normalizer = normalizers.BertNormalizer(
242
+ clean_text=True,
243
+ handle_chinese_chars=tokenize_chinese_chars,
244
+ strip_accents=strip_accents,
245
+ lowercase=do_lower_case,
246
+ )
247
+ tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
248
+
249
+ cls = str(self.original_tokenizer.cls_token)
250
+ sep = str(self.original_tokenizer.sep_token)
251
+ cls_token_id = self.original_tokenizer.cls_token_id
252
+ sep_token_id = self.original_tokenizer.sep_token_id
253
+
254
+ tokenizer.post_processor = processors.TemplateProcessing(
255
+ single=f"{cls}:0 $A:0 {sep}:0",
256
+ pair=f"{cls}:0 $A:0 {sep}:0 $B:1 {sep}:1",
257
+ special_tokens=[
258
+ (cls, cls_token_id),
259
+ (sep, sep_token_id),
260
+ ],
261
+ )
262
+ tokenizer.decoder = decoders.WordPiece(prefix="##")
263
+
264
+ return tokenizer
265
+
266
+
267
+ class SplinterConverter(Converter):
268
+ def converted(self) -> Tokenizer:
269
+ vocab = self.original_tokenizer.vocab
270
+ tokenizer = Tokenizer(WordPiece(vocab, unk_token=str(self.original_tokenizer.unk_token)))
271
+
272
+ tokenize_chinese_chars = False
273
+ strip_accents = False
274
+ do_lower_case = False
275
+ if hasattr(self.original_tokenizer, "basic_tokenizer"):
276
+ tokenize_chinese_chars = self.original_tokenizer.basic_tokenizer.tokenize_chinese_chars
277
+ strip_accents = self.original_tokenizer.basic_tokenizer.strip_accents
278
+ do_lower_case = self.original_tokenizer.basic_tokenizer.do_lower_case
279
+
280
+ tokenizer.normalizer = normalizers.BertNormalizer(
281
+ clean_text=True,
282
+ handle_chinese_chars=tokenize_chinese_chars,
283
+ strip_accents=strip_accents,
284
+ lowercase=do_lower_case,
285
+ )
286
+ tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
287
+
288
+ cls = str(self.original_tokenizer.cls_token)
289
+ sep = str(self.original_tokenizer.sep_token)
290
+ question = str(self.original_tokenizer.question_token)
291
+ dot = "."
292
+ cls_token_id = self.original_tokenizer.cls_token_id
293
+ sep_token_id = self.original_tokenizer.sep_token_id
294
+ question_token_id = self.original_tokenizer.question_token_id
295
+ dot_token_id = self.original_tokenizer.convert_tokens_to_ids(".")
296
+
297
+ if self.original_tokenizer.padding_side == "right":
298
+ pair = f"{cls}:0 $A:0 {question} {dot} {sep}:0 $B:1 {sep}:1"
299
+ else:
300
+ pair = f"{cls}:0 $A:0 {sep}:0 $B:1 {question} {dot} {sep}:1"
301
+
302
+ tokenizer.post_processor = processors.TemplateProcessing(
303
+ single=f"{cls}:0 $A:0 {sep}:0",
304
+ pair=pair,
305
+ special_tokens=[
306
+ (cls, cls_token_id),
307
+ (sep, sep_token_id),
308
+ (question, question_token_id),
309
+ (dot, dot_token_id),
310
+ ],
311
+ )
312
+ tokenizer.decoder = decoders.WordPiece(prefix="##")
313
+
314
+ return tokenizer
315
+
316
+
317
+ class FunnelConverter(Converter):
318
+ def converted(self) -> Tokenizer:
319
+ vocab = self.original_tokenizer.vocab
320
+ tokenizer = Tokenizer(WordPiece(vocab, unk_token=str(self.original_tokenizer.unk_token)))
321
+
322
+ tokenize_chinese_chars = False
323
+ strip_accents = False
324
+ do_lower_case = False
325
+ if hasattr(self.original_tokenizer, "basic_tokenizer"):
326
+ tokenize_chinese_chars = self.original_tokenizer.basic_tokenizer.tokenize_chinese_chars
327
+ strip_accents = self.original_tokenizer.basic_tokenizer.strip_accents
328
+ do_lower_case = self.original_tokenizer.basic_tokenizer.do_lower_case
329
+
330
+ tokenizer.normalizer = normalizers.BertNormalizer(
331
+ clean_text=True,
332
+ handle_chinese_chars=tokenize_chinese_chars,
333
+ strip_accents=strip_accents,
334
+ lowercase=do_lower_case,
335
+ )
336
+ tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
337
+
338
+ cls = str(self.original_tokenizer.cls_token)
339
+ sep = str(self.original_tokenizer.sep_token)
340
+ cls_token_id = self.original_tokenizer.cls_token_id
341
+ sep_token_id = self.original_tokenizer.sep_token_id
342
+
343
+ tokenizer.post_processor = processors.TemplateProcessing(
344
+ single=f"{cls}:2 $A:0 {sep}:0", # token_type_id is 2 for Funnel transformer
345
+ pair=f"{cls}:2 $A:0 {sep}:0 $B:1 {sep}:1",
346
+ special_tokens=[
347
+ (cls, cls_token_id),
348
+ (sep, sep_token_id),
349
+ ],
350
+ )
351
+ tokenizer.decoder = decoders.WordPiece(prefix="##")
352
+
353
+ return tokenizer
354
+
355
+
356
+ class MPNetConverter(Converter):
357
+ def converted(self) -> Tokenizer:
358
+ vocab = self.original_tokenizer.vocab
359
+ tokenizer = Tokenizer(WordPiece(vocab, unk_token=str(self.original_tokenizer.unk_token)))
360
+
361
+ tokenize_chinese_chars = False
362
+ strip_accents = False
363
+ do_lower_case = False
364
+ if hasattr(self.original_tokenizer, "basic_tokenizer"):
365
+ tokenize_chinese_chars = self.original_tokenizer.basic_tokenizer.tokenize_chinese_chars
366
+ strip_accents = self.original_tokenizer.basic_tokenizer.strip_accents
367
+ do_lower_case = self.original_tokenizer.basic_tokenizer.do_lower_case
368
+
369
+ tokenizer.normalizer = normalizers.BertNormalizer(
370
+ clean_text=True,
371
+ handle_chinese_chars=tokenize_chinese_chars,
372
+ strip_accents=strip_accents,
373
+ lowercase=do_lower_case,
374
+ )
375
+ tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
376
+
377
+ cls = str(self.original_tokenizer.cls_token)
378
+ sep = str(self.original_tokenizer.sep_token)
379
+ cls_token_id = self.original_tokenizer.cls_token_id
380
+ sep_token_id = self.original_tokenizer.sep_token_id
381
+
382
+ tokenizer.post_processor = processors.TemplateProcessing(
383
+ single=f"{cls}:0 $A:0 {sep}:0",
384
+ pair=f"{cls}:0 $A:0 {sep}:0 {sep}:0 $B:1 {sep}:1", # MPNet uses two [SEP] tokens
385
+ special_tokens=[
386
+ (cls, cls_token_id),
387
+ (sep, sep_token_id),
388
+ ],
389
+ )
390
+ tokenizer.decoder = decoders.WordPiece(prefix="##")
391
+
392
+ return tokenizer
393
+
394
+
395
+ class OpenAIGPTConverter(Converter):
396
+ def converted(self) -> Tokenizer:
397
+ vocab = self.original_tokenizer.encoder
398
+ merges = list(self.original_tokenizer.bpe_ranks.keys())
399
+ unk_token = self.original_tokenizer.unk_token
400
+
401
+ tokenizer = Tokenizer(
402
+ BPE(
403
+ vocab=vocab,
404
+ merges=merges,
405
+ dropout=None,
406
+ unk_token=str(unk_token),
407
+ end_of_word_suffix="</w>",
408
+ fuse_unk=False,
409
+ )
410
+ )
411
+
412
+ if tokenizer.token_to_id(str(unk_token)) is not None:
413
+ tokenizer.add_special_tokens([str(unk_token)])
414
+
415
+ tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True)
416
+ tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
417
+ tokenizer.decoder = decoders.BPEDecoder(suffix="</w>")
418
+
419
+ return tokenizer
420
+
421
+
422
+ class GPT2Converter(Converter):
423
+ def converted(self, vocab: dict[str, int] | None = None, merges: list[tuple[str, str]] | None = None) -> Tokenizer:
424
+ if not vocab:
425
+ vocab = self.original_tokenizer.encoder
426
+ if not merges:
427
+ merges = list(self.original_tokenizer.bpe_ranks)
428
+
429
+ tokenizer = Tokenizer(
430
+ BPE(
431
+ vocab=vocab,
432
+ merges=merges,
433
+ dropout=None,
434
+ continuing_subword_prefix="",
435
+ end_of_word_suffix="",
436
+ fuse_unk=False,
437
+ )
438
+ )
439
+
440
+ add_prefix_space = getattr(self.original_tokenizer, "add_prefix_space", False)
441
+ tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=add_prefix_space)
442
+ tokenizer.decoder = decoders.ByteLevel()
443
+ if getattr(self.original_tokenizer, "add_bos_token", False):
444
+ bos = self.original_tokenizer.bos_token
445
+ bos_token_id = self.original_tokenizer.bos_token_id
446
+ tokenizer.post_processor = processors.TemplateProcessing(
447
+ single=f"{bos}:0 $A:0",
448
+ pair=f"{bos}:0 $A:0 $B:1",
449
+ special_tokens=[
450
+ (bos, bos_token_id),
451
+ ],
452
+ )
453
+ else:
454
+ # XXX trim_offsets=False actually means this post_processor doesn't
455
+ # really do anything.
456
+ tokenizer.post_processor = processors.ByteLevel(trim_offsets=False)
457
+ return tokenizer
458
+
459
+
460
+ class HerbertConverter(Converter):
461
+ def converted(self) -> Tokenizer:
462
+ tokenizer_info_str = "#version:"
463
+ token_suffix = "</w>"
464
+
465
+ vocab = self.original_tokenizer.encoder
466
+ merges = list(self.original_tokenizer.bpe_ranks.keys())
467
+ if tokenizer_info_str in merges[0][0]:
468
+ merges = merges[1:]
469
+
470
+ tokenizer = Tokenizer(
471
+ BPE(
472
+ vocab,
473
+ merges,
474
+ dropout=None,
475
+ unk_token=self.original_tokenizer.unk_token,
476
+ end_of_word_suffix=token_suffix,
477
+ )
478
+ )
479
+
480
+ tokenizer.normalizer = normalizers.BertNormalizer(lowercase=False, strip_accents=False)
481
+ tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
482
+ tokenizer.decoder = decoders.BPEDecoder(suffix=token_suffix)
483
+ tokenizer.post_processor = processors.BertProcessing(
484
+ sep=(self.original_tokenizer.sep_token, self.original_tokenizer.sep_token_id),
485
+ cls=(self.original_tokenizer.cls_token, self.original_tokenizer.cls_token_id),
486
+ )
487
+
488
+ return tokenizer
489
+
490
+
491
+ class Qwen2Converter(Converter):
492
+ def converted(self, vocab: dict[str, int] | None = None, merges: list[tuple[str, str]] | None = None) -> Tokenizer:
493
+ if not vocab:
494
+ vocab = self.original_tokenizer.encoder
495
+ if not merges:
496
+ merges = list(self.original_tokenizer.bpe_ranks.keys())
497
+
498
+ tokenizer = Tokenizer(
499
+ BPE(
500
+ vocab=vocab,
501
+ merges=merges,
502
+ dropout=None,
503
+ unk_token=None,
504
+ continuing_subword_prefix="",
505
+ end_of_word_suffix="",
506
+ fuse_unk=False,
507
+ byte_fallback=False,
508
+ )
509
+ )
510
+
511
+ tokenizer.normalizer = normalizers.NFC()
512
+
513
+ tokenizer.pre_tokenizer = pre_tokenizers.Sequence(
514
+ [
515
+ pre_tokenizers.Split(
516
+ Regex(
517
+ r"""(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+"""
518
+ ),
519
+ behavior="isolated",
520
+ invert=False,
521
+ ),
522
+ pre_tokenizers.ByteLevel(
523
+ add_prefix_space=getattr(self.original_tokenizer, "add_prefix_space", False),
524
+ use_regex=False,
525
+ ),
526
+ ]
527
+ )
528
+
529
+ tokenizer.decoder = decoders.ByteLevel()
530
+ tokenizer.post_processor = processors.ByteLevel(trim_offsets=False)
531
+
532
+ return tokenizer
533
+
534
+
535
+ class RobertaConverter(Converter):
536
+ def converted(self) -> Tokenizer:
537
+ ot = self.original_tokenizer
538
+ vocab = ot.encoder
539
+ merges = list(ot.bpe_ranks.keys())
540
+
541
+ tokenizer = Tokenizer(
542
+ BPE(
543
+ vocab=vocab,
544
+ merges=merges,
545
+ dropout=None,
546
+ continuing_subword_prefix="",
547
+ end_of_word_suffix="",
548
+ fuse_unk=False,
549
+ )
550
+ )
551
+
552
+ tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=ot.add_prefix_space)
553
+ tokenizer.decoder = decoders.ByteLevel()
554
+ tokenizer.post_processor = processors.RobertaProcessing(
555
+ sep=(ot.sep_token, ot.sep_token_id),
556
+ cls=(ot.cls_token, ot.cls_token_id),
557
+ add_prefix_space=ot.add_prefix_space,
558
+ trim_offsets=True, # True by default on Roberta (historical)
559
+ )
560
+
561
+ return tokenizer
562
+
563
+
564
+ class RoFormerConverter(Converter):
565
+ def converted(self) -> Tokenizer:
566
+ from .models.roformer.tokenization_utils import JiebaPreTokenizer
567
+
568
+ vocab = self.original_tokenizer.vocab
569
+ tokenizer = Tokenizer(WordPiece(vocab, unk_token=str(self.original_tokenizer.unk_token)))
570
+
571
+ strip_accents = False
572
+ do_lower_case = False
573
+ if hasattr(self.original_tokenizer, "basic_tokenizer"):
574
+ strip_accents = self.original_tokenizer.basic_tokenizer.strip_accents
575
+ do_lower_case = self.original_tokenizer.basic_tokenizer.do_lower_case
576
+
577
+ tokenizer.normalizer = normalizers.BertNormalizer(
578
+ clean_text=True,
579
+ handle_chinese_chars=False,
580
+ strip_accents=strip_accents,
581
+ lowercase=do_lower_case,
582
+ )
583
+ tokenizer.pre_tokenizer = pre_tokenizers.PreTokenizer.custom(JiebaPreTokenizer(vocab))
584
+
585
+ cls = str(self.original_tokenizer.cls_token)
586
+ sep = str(self.original_tokenizer.sep_token)
587
+ cls_token_id = self.original_tokenizer.cls_token_id
588
+ sep_token_id = self.original_tokenizer.sep_token_id
589
+
590
+ tokenizer.post_processor = processors.TemplateProcessing(
591
+ single=f"{cls}:0 $A:0 {sep}:0",
592
+ pair=f"{cls}:0 $A:0 {sep}:0 $B:1 {sep}:1",
593
+ special_tokens=[
594
+ (cls, cls_token_id),
595
+ (sep, sep_token_id),
596
+ ],
597
+ )
598
+ tokenizer.decoder = decoders.WordPiece(prefix="##")
599
+
600
+ return tokenizer
601
+
602
+
603
+ class DebertaConverter(Converter):
604
+ def converted(self) -> Tokenizer:
605
+ ot = self.original_tokenizer
606
+ vocab = ot.encoder
607
+ merges = list(ot.bpe_ranks.keys())
608
+
609
+ tokenizer = Tokenizer(
610
+ BPE(
611
+ vocab=vocab,
612
+ merges=merges,
613
+ dropout=None,
614
+ continuing_subword_prefix="",
615
+ end_of_word_suffix="",
616
+ fuse_unk=False,
617
+ )
618
+ )
619
+
620
+ tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=ot.add_prefix_space)
621
+ tokenizer.decoder = decoders.ByteLevel()
622
+ tokenizer.post_processor = processors.TemplateProcessing(
623
+ single="[CLS]:0 $A:0 [SEP]:0",
624
+ pair="[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",
625
+ special_tokens=[
626
+ ("[CLS]", self.original_tokenizer.convert_tokens_to_ids("[CLS]")),
627
+ ("[SEP]", self.original_tokenizer.convert_tokens_to_ids("[SEP]")),
628
+ ],
629
+ )
630
+
631
+ return tokenizer
632
+
633
+
634
+ class SpmConverter(Converter):
635
+ handle_byte_fallback = False
636
+ SpmExtractor = SentencePieceExtractor
637
+ special_tokens = {}
638
+
639
+ @staticmethod
640
+ def build_tokenizer_from_spm_proto(proto, vocab, merges=None):
641
+ """
642
+ Similar to convert_from_spm method, but used only when there is no `model_type` class, i.e. there is no matching class in `TOKENIZERS_MAPPING` and we just create a tokenizer instead of extracting stuff from the sentencepiece file
643
+ """
644
+ byte_fallback = proto.trainer_spec.byte_fallback
645
+ unk_piece = proto.trainer_spec.unk_piece
646
+ precompiled_charsmap = proto.normalizer_spec.precompiled_charsmap
647
+
648
+ # model
649
+ if isinstance(vocab, dict):
650
+ tokenizer = Tokenizer(
651
+ BPE(
652
+ vocab=vocab,
653
+ merges=merges or [],
654
+ unk_token=unk_piece,
655
+ fuse_unk=True,
656
+ byte_fallback=byte_fallback,
657
+ dropout=None,
658
+ )
659
+ )
660
+ elif isinstance(vocab, list) and vocab and isinstance(vocab[0], tuple | list):
661
+ tokenizer = Tokenizer(
662
+ Unigram(
663
+ vocab=vocab,
664
+ unk_id=proto.trainer_spec.unk_id,
665
+ byte_fallback=byte_fallback,
666
+ )
667
+ )
668
+ else:
669
+ return None
670
+
671
+ # normalizer
672
+ _normalizers = [normalizers.Replace(" ", "▁")]
673
+ if precompiled_charsmap:
674
+ _normalizers.insert(0, normalizers.Precompiled(precompiled_charsmap))
675
+ tokenizer.normalizer = normalizers.Sequence(_normalizers)
676
+
677
+ # decoder
678
+ if byte_fallback:
679
+ tokenizer.decoder = decoders.Sequence(
680
+ [decoders.Replace("▁", " "), decoders.ByteFallback(), decoders.Fuse()]
681
+ )
682
+ else:
683
+ tokenizer.decoder = decoders.Sequence([decoders.Replace("▁", " ")])
684
+
685
+ return tokenizer
686
+
687
+ @classmethod
688
+ def convert_from_spm(cls, vocab=None, **kwargs):
689
+ """
690
+ Hook used when converting directly from a SentencePiece model without a slow tokenizer instance.
691
+ By default, return kwargs unchanged.
692
+ """
693
+ if vocab is not None:
694
+ kwargs["vocab"] = vocab
695
+ return kwargs
696
+
697
+ def __init__(self, *args):
698
+ requires_backends(self, "protobuf")
699
+
700
+ super().__init__(*args)
701
+
702
+ # from .utils import sentencepiece_model_pb2 as model_pb2
703
+ model_pb2 = import_protobuf()
704
+
705
+ m = model_pb2.ModelProto()
706
+ with open(self.original_tokenizer.vocab_file, "rb") as f:
707
+ m.ParseFromString(f.read())
708
+ self.proto = m
709
+
710
+ if self.proto.trainer_spec.byte_fallback and not self.handle_byte_fallback:
711
+ warnings.warn(
712
+ "The sentencepiece tokenizer that you are converting to a fast tokenizer uses the byte fallback option"
713
+ " which is not implemented in the fast tokenizers. In practice this means that the fast version of the"
714
+ " tokenizer can produce unknown tokens whereas the sentencepiece version would have converted these "
715
+ "unknown tokens into a sequence of byte tokens matching the original piece of text."
716
+ )
717
+
718
+ def vocab(self, proto):
719
+ return [(piece.piece, piece.score) for piece in proto.pieces]
720
+
721
+ def unk_id(self, proto):
722
+ return proto.trainer_spec.unk_id
723
+
724
+ def tokenizer(self, proto):
725
+ model_type = proto.trainer_spec.model_type
726
+ vocab_scores = self.vocab(proto)
727
+
728
+ if model_type == 1:
729
+ tokenizer = Tokenizer(
730
+ Unigram(
731
+ vocab_scores,
732
+ unk_id=self.unk_id(proto),
733
+ byte_fallback=self.handle_byte_fallback,
734
+ )
735
+ )
736
+
737
+ elif model_type == 2:
738
+ _, merges = self.SpmExtractor(self.original_tokenizer.vocab_file).extract(vocab_scores)
739
+ bpe_vocab = {word: i for i, (word, score) in enumerate(vocab_scores)}
740
+ tokenizer = Tokenizer(
741
+ BPE(
742
+ bpe_vocab,
743
+ merges,
744
+ unk_token=proto.trainer_spec.unk_piece,
745
+ fuse_unk=True,
746
+ byte_fallback=self.handle_byte_fallback,
747
+ dropout=None,
748
+ )
749
+ )
750
+
751
+ else:
752
+ raise Exception(
753
+ "You're trying to run a `Unigram` model but you're file was trained with a different algorithm"
754
+ )
755
+
756
+ # control tokens are special
757
+ # user defined symbols are not
758
+ # both user and control tokens are AddedTokens
759
+ # Add user defined symbols (type == 4) from sentencepiece (https://github.com/google/sentencepiece/blob/6225e08edb2577757163b3f5dbba4c0b670ef445/src/sentencepiece_model.proto#L299C29-L299C33)
760
+ spm_added_tokens = [
761
+ (id, p.piece, p.type == 3 or p.piece in self.special_tokens)
762
+ for id, p in enumerate(proto.pieces)
763
+ if p.type in [3, 4]
764
+ ]
765
+ tokenizer.add_tokens(
766
+ [
767
+ AddedToken(token, normalized=False, special=special)
768
+ for id, token, special in sorted(spm_added_tokens, key=lambda x: x[0])
769
+ ]
770
+ )
771
+
772
+ return tokenizer
773
+
774
+ def normalizer(self, proto):
775
+ precompiled_charsmap = proto.normalizer_spec.precompiled_charsmap
776
+ _normalizers = [
777
+ normalizers.Strip(left=False, right=True), # stripping is important
778
+ normalizers.Replace(Regex(" {2,}"), "▁"),
779
+ ]
780
+ if not precompiled_charsmap:
781
+ return normalizers.Sequence(_normalizers)
782
+ else:
783
+ return normalizers.Sequence([normalizers.Precompiled(precompiled_charsmap)] + _normalizers)
784
+
785
+ def pre_tokenizer(self, replacement, add_prefix_space):
786
+ prepend_scheme = _get_prepend_scheme(add_prefix_space, self.original_tokenizer)
787
+ return pre_tokenizers.Metaspace(replacement=replacement, prepend_scheme=prepend_scheme)
788
+
789
+ def post_processor(self):
790
+ return None
791
+
792
+ def decoder(self, replacement, add_prefix_space):
793
+ prepend_scheme = _get_prepend_scheme(add_prefix_space, self.original_tokenizer)
794
+ return decoders.Metaspace(replacement=replacement, prepend_scheme=prepend_scheme)
795
+
796
+ def converted(self) -> Tokenizer:
797
+ tokenizer = self.tokenizer(self.proto)
798
+
799
+ # Tokenizer assemble
800
+ normalizer = self.normalizer(self.proto)
801
+ if normalizer is not None:
802
+ tokenizer.normalizer = normalizer
803
+
804
+ replacement = "▁"
805
+ add_prefix_space = True
806
+ if hasattr(self.original_tokenizer, "add_prefix_space"):
807
+ add_prefix_space = self.original_tokenizer.add_prefix_space
808
+
809
+ pre_tokenizer = self.pre_tokenizer(replacement, add_prefix_space)
810
+ if pre_tokenizer is not None:
811
+ tokenizer.pre_tokenizer = pre_tokenizer
812
+
813
+ tokenizer.decoder = self.decoder(replacement, add_prefix_space)
814
+ post_processor = self.post_processor()
815
+ if post_processor:
816
+ tokenizer.post_processor = post_processor
817
+
818
+ return tokenizer
819
+
820
+
821
+ class AlbertConverter(SpmConverter):
822
+ def vocab(self, proto):
823
+ return [
824
+ (piece.piece, piece.score) if check_number_comma(piece.piece) else (piece.piece, piece.score - 100)
825
+ for piece in proto.pieces
826
+ ]
827
+
828
+ def normalizer(self, proto):
829
+ list_normalizers = [
830
+ normalizers.Replace("``", '"'),
831
+ normalizers.Replace("''", '"'),
832
+ ]
833
+ if not self.original_tokenizer.keep_accents:
834
+ list_normalizers.append(normalizers.NFKD())
835
+ list_normalizers.append(normalizers.StripAccents())
836
+ if self.original_tokenizer.do_lower_case:
837
+ list_normalizers.append(normalizers.Lowercase())
838
+
839
+ precompiled_charsmap = proto.normalizer_spec.precompiled_charsmap
840
+
841
+ if precompiled_charsmap:
842
+ list_normalizers.append(normalizers.Precompiled(precompiled_charsmap))
843
+
844
+ list_normalizers.append(normalizers.Replace(Regex(" {2,}"), " "))
845
+ return normalizers.Sequence(list_normalizers)
846
+
847
+ def post_processor(self):
848
+ return processors.TemplateProcessing(
849
+ single="[CLS]:0 $A:0 [SEP]:0",
850
+ pair="[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",
851
+ special_tokens=[
852
+ ("[CLS]", self.original_tokenizer.convert_tokens_to_ids("[CLS]")),
853
+ ("[SEP]", self.original_tokenizer.convert_tokens_to_ids("[SEP]")),
854
+ ],
855
+ )
856
+
857
+
858
+ class BarthezConverter(SpmConverter):
859
+ def unk_id(self, proto):
860
+ unk_id = 3
861
+ return unk_id
862
+
863
+ def post_processor(self):
864
+ return processors.TemplateProcessing(
865
+ single="<s> $A </s>",
866
+ pair="<s> $A </s> </s> $B </s>",
867
+ special_tokens=[
868
+ ("<s>", self.original_tokenizer.convert_tokens_to_ids("<s>")),
869
+ ("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
870
+ ],
871
+ )
872
+
873
+
874
+ class CamembertConverter(SpmConverter):
875
+ def vocab(self, proto):
876
+ vocab = [
877
+ ("<s>NOTUSED", 0.0),
878
+ ("<pad>", 0.0),
879
+ ("</s>NOTUSED", 0.0),
880
+ ("<unk>", 0.0),
881
+ ("<unk>NOTUSED", -100),
882
+ ]
883
+ # We down-grade the original SentencePiece by -100 to avoid using it and use our added token instead
884
+ vocab += [(piece.piece, piece.score) for piece in proto.pieces[1:]]
885
+ vocab += [("<mask>", 0.0)]
886
+ return vocab
887
+
888
+ def unk_id(self, proto):
889
+ # See vocab unk position
890
+ return 3
891
+
892
+ def post_processor(self):
893
+ return processors.TemplateProcessing(
894
+ single="<s> $A </s>",
895
+ pair="<s> $A </s> </s> $B </s>",
896
+ special_tokens=[
897
+ ("<s>", self.original_tokenizer.convert_tokens_to_ids("<s>")),
898
+ ("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
899
+ ],
900
+ )
901
+
902
+ @classmethod
903
+ def convert_from_spm(cls, vocab=None, **kwargs):
904
+ pad_token = str(kwargs.get("pad_token", "<pad>"))
905
+ unk_token = str(kwargs.get("unk_token", "<unk>"))
906
+ mask_token = str(kwargs.get("mask_token", "<mask>"))
907
+
908
+ vocab_list = [
909
+ ("<s>NOTUSED", 0.0),
910
+ (pad_token, 0.0),
911
+ ("</s>NOTUSED", 0.0),
912
+ (unk_token, 0.0),
913
+ ("<unk>NOTUSED", -100.0),
914
+ ]
915
+ if vocab is not None:
916
+ vocab_list.extend(list(vocab)[1:])
917
+ vocab_list.append((mask_token, 0.0))
918
+ kwargs["vocab"] = vocab_list
919
+ return kwargs
920
+
921
+
922
+ class DebertaV2Converter(SpmConverter):
923
+ def pre_tokenizer(self, replacement, add_prefix_space):
924
+ list_pretokenizers = []
925
+ if self.original_tokenizer.split_by_punct:
926
+ list_pretokenizers.append(pre_tokenizers.Punctuation(behavior="isolated"))
927
+ prepend_scheme = _get_prepend_scheme(add_prefix_space, self.original_tokenizer)
928
+ list_pretokenizers.append(pre_tokenizers.Metaspace(replacement=replacement, prepend_scheme=prepend_scheme))
929
+ return pre_tokenizers.Sequence(list_pretokenizers)
930
+
931
+ def normalizer(self, proto):
932
+ list_normalizers = []
933
+ if self.original_tokenizer.do_lower_case:
934
+ list_normalizers.append(normalizers.Lowercase())
935
+ list_normalizers.append(normalizers.Strip())
936
+
937
+ precompiled_charsmap = proto.normalizer_spec.precompiled_charsmap
938
+ if precompiled_charsmap:
939
+ list_normalizers.append(normalizers.Precompiled(precompiled_charsmap))
940
+ list_normalizers.append(normalizers.Replace(Regex(" {2,}"), " "))
941
+
942
+ return normalizers.Sequence(list_normalizers)
943
+
944
+ def post_processor(self):
945
+ return processors.TemplateProcessing(
946
+ single="[CLS]:0 $A:0 [SEP]:0",
947
+ pair="[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",
948
+ special_tokens=[
949
+ ("[CLS]", self.original_tokenizer.convert_tokens_to_ids("[CLS]")),
950
+ ("[SEP]", self.original_tokenizer.convert_tokens_to_ids("[SEP]")),
951
+ ],
952
+ )
953
+
954
+
955
+ class MBartConverter(SpmConverter):
956
+ def vocab(self, proto):
957
+ vocab = [
958
+ ("<s>", 0.0),
959
+ ("<pad>", 0.0),
960
+ ("</s>", 0.0),
961
+ ("<unk>", 0.0),
962
+ ]
963
+ vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
964
+ vocab += [
965
+ ("ar_AR", 0.0),
966
+ ("cs_CZ", 0.0),
967
+ ("de_DE", 0.0),
968
+ ("en_XX", 0.0),
969
+ ("es_XX", 0.0),
970
+ ("et_EE", 0.0),
971
+ ("fi_FI", 0.0),
972
+ ("fr_XX", 0.0),
973
+ ("gu_IN", 0.0),
974
+ ("hi_IN", 0.0),
975
+ ("it_IT", 0.0),
976
+ ("ja_XX", 0.0),
977
+ ("kk_KZ", 0.0),
978
+ ("ko_KR", 0.0),
979
+ ("lt_LT", 0.0),
980
+ ("lv_LV", 0.0),
981
+ ("my_MM", 0.0),
982
+ ("ne_NP", 0.0),
983
+ ("nl_XX", 0.0),
984
+ ("ro_RO", 0.0),
985
+ ("ru_RU", 0.0),
986
+ ("si_LK", 0.0),
987
+ ("tr_TR", 0.0),
988
+ ("vi_VN", 0.0),
989
+ ("zh_CN", 0.0),
990
+ ]
991
+ vocab += [("<mask>", 0.0)]
992
+ return vocab
993
+
994
+ def unk_id(self, proto):
995
+ return 3
996
+
997
+ def post_processor(self):
998
+ return processors.TemplateProcessing(
999
+ single="$A </s> en_XX",
1000
+ pair="$A $B </s> en_XX",
1001
+ special_tokens=[
1002
+ ("en_XX", self.original_tokenizer.convert_tokens_to_ids("en_XX")),
1003
+ ("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
1004
+ ],
1005
+ )
1006
+
1007
+ @classmethod
1008
+ def convert_from_spm(cls, vocab=None, **kwargs):
1009
+ bos_token = str(kwargs.get("bos_token", "<s>"))
1010
+ pad_token = str(kwargs.get("pad_token", "<pad>"))
1011
+ eos_token = str(kwargs.get("eos_token", "</s>"))
1012
+ unk_token = str(kwargs.get("unk_token", "<unk>"))
1013
+ mask_token = str(kwargs.get("mask_token", "<mask>"))
1014
+
1015
+ vocab_list = [
1016
+ (bos_token, 0.0),
1017
+ (pad_token, 0.0),
1018
+ (eos_token, 0.0),
1019
+ (unk_token, 0.0),
1020
+ ]
1021
+ if vocab is not None:
1022
+ vocab_list.extend(list(vocab)[3:])
1023
+ vocab_list.extend((lang_code, 0.0) for lang_code in MBART_LANGUAGES)
1024
+ vocab_list.append((mask_token, 0.0))
1025
+ kwargs["vocab"] = vocab_list
1026
+ return kwargs
1027
+
1028
+
1029
+ class MBart50Converter(SpmConverter):
1030
+ def vocab(self, proto):
1031
+ vocab = [
1032
+ ("<s>", 0.0),
1033
+ ("<pad>", 0.0),
1034
+ ("</s>", 0.0),
1035
+ ("<unk>", 0.0),
1036
+ ]
1037
+ vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
1038
+ vocab += [("ar_AR", 0.0), ("cs_CZ", 0.0), ("de_DE", 0.0), ("en_XX", 0.0), ("es_XX", 0.0), ("et_EE", 0.0), ("fi_FI", 0.0), ("fr_XX", 0.0), ("gu_IN", 0.0), ("hi_IN", 0.0), ("it_IT", 0.0), ("ja_XX", 0.0), ("kk_KZ", 0.0), ("ko_KR", 0.0), ("lt_LT", 0.0), ("lv_LV", 0.0), ("my_MM", 0.0), ("ne_NP", 0.0), ("nl_XX", 0.0), ("ro_RO", 0.0), ("ru_RU", 0.0), ("si_LK", 0.0), ("tr_TR", 0.0), ("vi_VN", 0.0), ("zh_CN", 0.0), ("af_ZA", 0.0), ("az_AZ", 0.0), ("bn_IN", 0.0), ("fa_IR", 0.0), ("he_IL", 0.0), ("hr_HR", 0.0), ("id_ID", 0.0), ("ka_GE", 0.0), ("km_KH", 0.0), ("mk_MK", 0.0), ("ml_IN", 0.0), ("mn_MN", 0.0), ("mr_IN", 0.0), ("pl_PL", 0.0), ("ps_AF", 0.0), ("pt_XX", 0.0), ("sv_SE", 0.0), ("sw_KE", 0.0), ("ta_IN", 0.0), ("te_IN", 0.0), ("th_TH", 0.0), ("tl_XX", 0.0), ("uk_UA", 0.0), ("ur_PK", 0.0), ("xh_ZA", 0.0), ("gl_ES", 0.0), ("sl_SI", 0.0)] # fmt: skip
1039
+ vocab += [("<mask>", 0.0)]
1040
+ return vocab
1041
+
1042
+ def unk_id(self, proto):
1043
+ return 3
1044
+
1045
+ def post_processor(self):
1046
+ return processors.TemplateProcessing(
1047
+ single="en_XX $A </s>",
1048
+ pair="en_XX $A $B </s>",
1049
+ special_tokens=[
1050
+ ("en_XX", self.original_tokenizer.convert_tokens_to_ids("en_XX")),
1051
+ ("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
1052
+ ],
1053
+ )
1054
+
1055
+ @classmethod
1056
+ def convert_from_spm(cls, vocab=None, **kwargs):
1057
+ cls_token = str(kwargs.get("cls_token", "<s>"))
1058
+ pad_token = str(kwargs.get("pad_token", "<pad>"))
1059
+ eos_token = str(kwargs.get("eos_token", "</s>"))
1060
+ unk_token = str(kwargs.get("unk_token", "<unk>"))
1061
+ mask_token = str(kwargs.get("mask_token", "<mask>"))
1062
+
1063
+ vocab_list = [
1064
+ (cls_token, 0.0),
1065
+ (pad_token, 0.0),
1066
+ (eos_token, 0.0),
1067
+ (unk_token, 0.0),
1068
+ ]
1069
+ if vocab is not None:
1070
+ vocab_list.extend(list(vocab)[3:])
1071
+ vocab_list.extend((lang_code, 0.0) for lang_code in MBART50_LANGUAGES)
1072
+ vocab_list.append((mask_token, 0.0))
1073
+ kwargs["vocab"] = vocab_list
1074
+ return kwargs
1075
+
1076
+
1077
+ class NllbConverter(SpmConverter):
1078
+ def vocab(self, proto):
1079
+ vocab = [
1080
+ ("<s>", 0.0),
1081
+ ("<pad>", 0.0),
1082
+ ("</s>", 0.0),
1083
+ ("<unk>", 0.0),
1084
+ ]
1085
+ vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
1086
+ return vocab
1087
+
1088
+ def unk_id(self, proto):
1089
+ return 3
1090
+
1091
+ def post_processor(self):
1092
+ return processors.TemplateProcessing(
1093
+ single="eng_Latn $A </s>",
1094
+ pair="eng_Latn $A $B </s>",
1095
+ special_tokens=[
1096
+ ("eng_Latn", self.original_tokenizer.convert_tokens_to_ids("eng_Latn")),
1097
+ ("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
1098
+ ],
1099
+ )
1100
+
1101
+ @classmethod
1102
+ def convert_from_spm(cls, vocab=None, **kwargs):
1103
+ bos_token = str(kwargs.get("bos_token", "<s>"))
1104
+ pad_token = str(kwargs.get("pad_token", "<pad>"))
1105
+ eos_token = str(kwargs.get("eos_token", "</s>"))
1106
+ unk_token = str(kwargs.get("unk_token", "<unk>"))
1107
+
1108
+ reordered_vocab = {
1109
+ bos_token: 0,
1110
+ pad_token: 1,
1111
+ eos_token: 2,
1112
+ unk_token: 3,
1113
+ }
1114
+ if vocab is not None:
1115
+ tokens = vocab.keys() if isinstance(vocab, dict) else [tok for tok, _ in vocab]
1116
+ for token in tokens:
1117
+ if token in reordered_vocab:
1118
+ continue
1119
+ reordered_vocab[token] = len(reordered_vocab)
1120
+ kwargs["vocab"] = reordered_vocab
1121
+ return kwargs
1122
+
1123
+
1124
+ class SeamlessM4TConverter(SpmConverter):
1125
+ def vocab(self, proto):
1126
+ vocab = [
1127
+ ("<pad>", 0.0),
1128
+ ("<unk>", 0.0),
1129
+ ("<s>", 0.0),
1130
+ ("</s>", 0.0),
1131
+ ]
1132
+ vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
1133
+ return vocab
1134
+
1135
+ def unk_id(self, proto):
1136
+ return self.original_tokenizer.unk_token_id
1137
+
1138
+ def post_processor(self):
1139
+ return processors.TemplateProcessing(
1140
+ single="__eng__ $A </s>",
1141
+ pair="__eng__ $A $B </s>",
1142
+ special_tokens=[
1143
+ ("__eng__", self.original_tokenizer.convert_tokens_to_ids("__eng__")),
1144
+ ("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
1145
+ ],
1146
+ )
1147
+
1148
+
1149
+ class XLMRobertaConverter(SpmConverter):
1150
+ def vocab(self, proto):
1151
+ vocab = [
1152
+ ("<s>", 0.0),
1153
+ ("<pad>", 0.0),
1154
+ ("</s>", 0.0),
1155
+ ("<unk>", 0.0),
1156
+ ]
1157
+ vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
1158
+ vocab += [("<mask>", 0.0)]
1159
+ return vocab
1160
+
1161
+ def unk_id(self, proto):
1162
+ unk_id = 3
1163
+ return unk_id
1164
+
1165
+ def post_processor(self):
1166
+ return processors.TemplateProcessing(
1167
+ single="<s> $A </s>",
1168
+ pair="<s> $A </s> </s> $B </s>",
1169
+ special_tokens=[
1170
+ ("<s>", self.original_tokenizer.convert_tokens_to_ids("<s>")),
1171
+ ("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
1172
+ ],
1173
+ )
1174
+
1175
+ @classmethod
1176
+ def convert_from_spm(cls, vocab=None, **kwargs):
1177
+ bos_token = str(kwargs.get("bos_token", "<s>"))
1178
+ pad_token = str(kwargs.get("pad_token", "<pad>"))
1179
+ eos_token = str(kwargs.get("eos_token", "</s>"))
1180
+ unk_token = str(kwargs.get("unk_token", "<unk>"))
1181
+ mask_token = str(kwargs.get("mask_token", "<mask>"))
1182
+
1183
+ vocab_list = [
1184
+ (bos_token, 0.0),
1185
+ (pad_token, 0.0),
1186
+ (eos_token, 0.0),
1187
+ (unk_token, 0.0),
1188
+ ]
1189
+ if vocab is not None:
1190
+ vocab_list.extend(list(vocab)[3:])
1191
+ vocab_list.append((mask_token, 0.0))
1192
+ kwargs["vocab"] = vocab_list
1193
+ return kwargs
1194
+
1195
+
1196
+ class XLNetConverter(SpmConverter):
1197
+ def vocab(self, proto):
1198
+ return [
1199
+ (piece.piece, piece.score) if check_number_comma(piece.piece) else (piece.piece, piece.score - 100)
1200
+ for piece in proto.pieces
1201
+ ]
1202
+
1203
+ def normalizer(self, proto):
1204
+ list_normalizers = [
1205
+ normalizers.Replace("``", '"'),
1206
+ normalizers.Replace("''", '"'),
1207
+ ]
1208
+ if not self.original_tokenizer.keep_accents:
1209
+ list_normalizers.append(normalizers.NFKD())
1210
+ list_normalizers.append(normalizers.StripAccents())
1211
+ if self.original_tokenizer.do_lower_case:
1212
+ list_normalizers.append(normalizers.Lowercase())
1213
+
1214
+ precompiled_charsmap = proto.normalizer_spec.precompiled_charsmap
1215
+
1216
+ if precompiled_charsmap:
1217
+ list_normalizers.append(normalizers.Precompiled(precompiled_charsmap))
1218
+
1219
+ list_normalizers.append(normalizers.Replace(Regex(" {2,}"), " "))
1220
+ return normalizers.Sequence(list_normalizers)
1221
+
1222
+ def post_processor(self):
1223
+ return processors.TemplateProcessing(
1224
+ single="$A:0 <sep>:0 <cls>:2",
1225
+ pair="$A:0 <sep>:0 $B:1 <sep>:1 <cls>:2",
1226
+ special_tokens=[
1227
+ ("<sep>", self.original_tokenizer.convert_tokens_to_ids("<sep>")),
1228
+ ("<cls>", self.original_tokenizer.convert_tokens_to_ids("<cls>")),
1229
+ ],
1230
+ )
1231
+
1232
+
1233
+ class ReformerConverter(SpmConverter):
1234
+ pass
1235
+
1236
+
1237
+ class RemBertConverter(SpmConverter):
1238
+ # Inspired from AlbertConverter
1239
+ def normalizer(self, proto):
1240
+ list_normalizers = [
1241
+ normalizers.Replace("``", '"'),
1242
+ normalizers.Replace("''", '"'),
1243
+ normalizers.Replace(Regex(" {2,}"), " "),
1244
+ ]
1245
+ if not self.original_tokenizer.keep_accents:
1246
+ list_normalizers.append(normalizers.NFKD())
1247
+ list_normalizers.append(normalizers.StripAccents())
1248
+ if self.original_tokenizer.do_lower_case:
1249
+ list_normalizers.append(normalizers.Lowercase())
1250
+
1251
+ precompiled_charsmap = proto.normalizer_spec.precompiled_charsmap
1252
+
1253
+ if precompiled_charsmap:
1254
+ list_normalizers.append(normalizers.Precompiled(precompiled_charsmap))
1255
+
1256
+ return normalizers.Sequence(list_normalizers)
1257
+
1258
+ def post_processor(self):
1259
+ return processors.TemplateProcessing(
1260
+ single="[CLS]:0 $A:0 [SEP]:0",
1261
+ pair="[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",
1262
+ special_tokens=[
1263
+ ("[CLS]", self.original_tokenizer.convert_tokens_to_ids("[CLS]")),
1264
+ ("[SEP]", self.original_tokenizer.convert_tokens_to_ids("[SEP]")),
1265
+ ],
1266
+ )
1267
+
1268
+
1269
+ class BertGenerationConverter(SpmConverter):
1270
+ pass
1271
+
1272
+
1273
+ class PegasusConverter(SpmConverter):
1274
+ def vocab(self, proto):
1275
+ vocab = [
1276
+ (self.original_tokenizer.pad_token, 0.0),
1277
+ (self.original_tokenizer.eos_token, 0.0),
1278
+ ]
1279
+
1280
+ if self.original_tokenizer.mask_token_sent is not None:
1281
+ vocab += [(self.original_tokenizer.mask_token_sent, 0.0)]
1282
+
1283
+ if (
1284
+ self.original_tokenizer.mask_token is not None
1285
+ and self.original_tokenizer.mask_token_id < self.original_tokenizer.offset
1286
+ ):
1287
+ vocab += [(self.original_tokenizer.mask_token, 0.0)]
1288
+
1289
+ vocab += [(f"<unk_{i}>", -100.0) for i in range(2, self.original_tokenizer.offset)]
1290
+ vocab += [(piece.piece, piece.score) for piece in proto.pieces[2:]]
1291
+ return vocab
1292
+
1293
+ @classmethod
1294
+ def convert_from_spm(cls, vocab=None, **kwargs):
1295
+ pad_token = str(kwargs.get("pad_token", "<pad>"))
1296
+ eos_token = str(kwargs.get("eos_token", "</s>"))
1297
+ mask_token = str(kwargs.get("mask_token", "<mask_1>"))
1298
+ mask_token_sent = str(kwargs.get("mask_token_sent", "<mask_2>"))
1299
+
1300
+ vocab_list = [
1301
+ (pad_token, 0.0),
1302
+ (eos_token, 0.0),
1303
+ ]
1304
+ if mask_token != "None":
1305
+ vocab_list.append((mask_token, 0.0))
1306
+ if mask_token_sent != "None" and mask_token_sent != mask_token:
1307
+ vocab_list.append((mask_token_sent, 0.0))
1308
+
1309
+ vocab_list.extend([(f"<unk_{i}>", -100.0) for i in range(2, kwargs.get("offset", 103))])
1310
+ if vocab is not None:
1311
+ vocab_list.extend(list(vocab)[2:])
1312
+ kwargs["vocab"] = vocab_list
1313
+ return kwargs
1314
+
1315
+ def unk_id(self, proto):
1316
+ return proto.trainer_spec.unk_id + self.original_tokenizer.offset
1317
+
1318
+ def pre_tokenizer(self, replacement, add_prefix_space):
1319
+ prepend_scheme = _get_prepend_scheme(add_prefix_space, self.original_tokenizer)
1320
+ return pre_tokenizers.Sequence(
1321
+ [
1322
+ pre_tokenizers.WhitespaceSplit(),
1323
+ pre_tokenizers.Metaspace(replacement=replacement, prepend_scheme=prepend_scheme),
1324
+ ]
1325
+ )
1326
+
1327
+ def post_processor(self):
1328
+ eos = self.original_tokenizer.eos_token
1329
+ special_tokens = [
1330
+ (eos, self.original_tokenizer.eos_token_id),
1331
+ ]
1332
+ return processors.TemplateProcessing(single=["$A", eos], pair=["$A", "$B", eos], special_tokens=special_tokens)
1333
+
1334
+
1335
+ class T5Converter(SpmConverter):
1336
+ def vocab(self, proto):
1337
+ num_extra_ids = self.original_tokenizer._extra_ids
1338
+ vocab = [(piece.piece, piece.score) for piece in proto.pieces]
1339
+ vocab += [(f"<extra_id_{i}>", 0.0) for i in range(num_extra_ids - 1, -1, -1)]
1340
+ return vocab
1341
+
1342
+ def post_processor(self):
1343
+ return processors.TemplateProcessing(
1344
+ single=["$A", "</s>"],
1345
+ pair=["$A", "</s>", "$B", "</s>"],
1346
+ special_tokens=[
1347
+ ("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
1348
+ ],
1349
+ )
1350
+
1351
+ @classmethod
1352
+ def convert_from_spm(cls, vocab=None, **kwargs):
1353
+ extra_ids = kwargs.get("extra_ids", 100)
1354
+ extra_tokens = [f"<extra_id_{i}>" for i in range(extra_ids - 1, -1, -1)]
1355
+ vocab_list = list(vocab) if vocab is not None else []
1356
+ vocab_list.extend((token, 0.0) for token in extra_tokens)
1357
+
1358
+ kwargs.setdefault("additional_special_tokens", extra_tokens)
1359
+ kwargs["vocab"] = vocab_list
1360
+ return kwargs
1361
+
1362
+
1363
+ class UdopConverter(SpmConverter):
1364
+ def post_processor(self):
1365
+ return processors.TemplateProcessing(
1366
+ single=["$A", "</s>"],
1367
+ pair=["$A", "</s>", "$B", "</s>"],
1368
+ special_tokens=[
1369
+ ("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
1370
+ ],
1371
+ )
1372
+
1373
+
1374
+ class WhisperConverter(Converter):
1375
+ def converted(self) -> Tokenizer:
1376
+ vocab = self.original_tokenizer.encoder
1377
+ merges = list(self.original_tokenizer.bpe_ranks.keys())
1378
+
1379
+ tokenizer = Tokenizer(
1380
+ BPE(
1381
+ vocab=vocab,
1382
+ merges=merges,
1383
+ dropout=None,
1384
+ continuing_subword_prefix="",
1385
+ end_of_word_suffix="",
1386
+ fuse_unk=False,
1387
+ )
1388
+ )
1389
+
1390
+ tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=self.original_tokenizer.add_prefix_space)
1391
+ tokenizer.decoder = decoders.ByteLevel()
1392
+
1393
+ prefix_token_ids = self.original_tokenizer.prefix_tokens
1394
+ prefixes = self.original_tokenizer.convert_ids_to_tokens(prefix_token_ids)
1395
+ eos = self.original_tokenizer.eos_token
1396
+ eos_token_id = self.original_tokenizer.eos_token_id
1397
+ prefix_template = " ".join([f"{token}:0" for token in prefixes])
1398
+ tokenizer.post_processor = processors.TemplateProcessing(
1399
+ single=f"{prefix_template} $A:0 {eos}:0",
1400
+ pair=f"{prefix_template} $A:0 $B:1 {eos}:1",
1401
+ special_tokens=[
1402
+ (eos, eos_token_id),
1403
+ *zip(prefixes, prefix_token_ids),
1404
+ ],
1405
+ )
1406
+
1407
+ return tokenizer
1408
+
1409
+
1410
+ class BigBirdConverter(SpmConverter):
1411
+ def post_processor(self):
1412
+ return processors.TemplateProcessing(
1413
+ single="[CLS]:0 $A:0 [SEP]:0",
1414
+ pair="[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",
1415
+ special_tokens=[
1416
+ ("[CLS]", self.original_tokenizer.convert_tokens_to_ids("[CLS]")),
1417
+ ("[SEP]", self.original_tokenizer.convert_tokens_to_ids("[SEP]")),
1418
+ ],
1419
+ )
1420
+
1421
+
1422
+ class CLIPConverter(Converter):
1423
+ def converted(self) -> Tokenizer:
1424
+ vocab = self.original_tokenizer.encoder
1425
+ merges = list(self.original_tokenizer.bpe_ranks.keys())
1426
+ unk_token = self.original_tokenizer.unk_token
1427
+
1428
+ tokenizer = Tokenizer(
1429
+ BPE(
1430
+ vocab=vocab,
1431
+ merges=merges,
1432
+ dropout=None,
1433
+ continuing_subword_prefix="",
1434
+ end_of_word_suffix="</w>",
1435
+ fuse_unk=False,
1436
+ unk_token=str(unk_token),
1437
+ )
1438
+ )
1439
+
1440
+ tokenizer.normalizer = normalizers.Sequence(
1441
+ [normalizers.NFC(), normalizers.Replace(Regex(r"\s+"), " "), normalizers.Lowercase()]
1442
+ )
1443
+ tokenizer.pre_tokenizer = pre_tokenizers.Sequence(
1444
+ [
1445
+ pre_tokenizers.Split(
1446
+ Regex(r"""'s|'t|'re|'ve|'m|'ll|'d|[\p{L}]+|[\p{N}]|[^\s\p{L}\p{N}]+"""),
1447
+ behavior="removed",
1448
+ invert=True,
1449
+ ),
1450
+ pre_tokenizers.ByteLevel(add_prefix_space=False),
1451
+ ]
1452
+ )
1453
+ tokenizer.decoder = decoders.ByteLevel()
1454
+
1455
+ # Hack to have a ByteLevel and TemplateProcessor
1456
+ tokenizer.post_processor = processors.RobertaProcessing(
1457
+ sep=(self.original_tokenizer.eos_token, self.original_tokenizer.eos_token_id),
1458
+ cls=(self.original_tokenizer.bos_token, self.original_tokenizer.bos_token_id),
1459
+ add_prefix_space=False,
1460
+ trim_offsets=False,
1461
+ )
1462
+ return tokenizer
1463
+
1464
+
1465
+ class LayoutLMv2Converter(Converter):
1466
+ def converted(self) -> Tokenizer:
1467
+ vocab = self.original_tokenizer.vocab
1468
+ tokenizer = Tokenizer(WordPiece(vocab, unk_token=str(self.original_tokenizer.unk_token)))
1469
+
1470
+ tokenize_chinese_chars = False
1471
+ strip_accents = False
1472
+ do_lower_case = True
1473
+ if hasattr(self.original_tokenizer, "basic_tokenizer"):
1474
+ tokenize_chinese_chars = self.original_tokenizer.basic_tokenizer.tokenize_chinese_chars
1475
+ strip_accents = self.original_tokenizer.basic_tokenizer.strip_accents
1476
+ do_lower_case = self.original_tokenizer.basic_tokenizer.do_lower_case
1477
+
1478
+ tokenizer.normalizer = normalizers.BertNormalizer(
1479
+ clean_text=True,
1480
+ handle_chinese_chars=tokenize_chinese_chars,
1481
+ strip_accents=strip_accents,
1482
+ lowercase=do_lower_case,
1483
+ )
1484
+ tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
1485
+
1486
+ cls = str(self.original_tokenizer.cls_token)
1487
+ sep = str(self.original_tokenizer.sep_token)
1488
+ cls_token_id = self.original_tokenizer.cls_token_id
1489
+ sep_token_id = self.original_tokenizer.sep_token_id
1490
+
1491
+ tokenizer.post_processor = processors.TemplateProcessing(
1492
+ single=f"{cls}:0 $A:0 {sep}:0",
1493
+ pair=f"{cls}:0 $A:0 {sep}:0 $B:1 {sep}:1",
1494
+ special_tokens=[
1495
+ (cls, cls_token_id),
1496
+ (sep, sep_token_id),
1497
+ ],
1498
+ )
1499
+ tokenizer.decoder = decoders.WordPiece(prefix="##")
1500
+
1501
+ return tokenizer
1502
+
1503
+
1504
+ class BlenderbotConverter(Converter):
1505
+ def converted(self) -> Tokenizer:
1506
+ ot = self.original_tokenizer
1507
+ vocab = ot.encoder
1508
+ merges = list(ot.bpe_ranks.keys())
1509
+
1510
+ tokenizer = Tokenizer(
1511
+ BPE(
1512
+ vocab=vocab,
1513
+ merges=merges,
1514
+ dropout=None,
1515
+ continuing_subword_prefix="",
1516
+ end_of_word_suffix="",
1517
+ fuse_unk=False,
1518
+ )
1519
+ )
1520
+
1521
+ tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=ot.add_prefix_space)
1522
+ tokenizer.decoder = decoders.ByteLevel()
1523
+ tokenizer.post_processor = processors.TemplateProcessing(
1524
+ single=f"$A:0 {ot.eos_token}:0",
1525
+ special_tokens=[
1526
+ (ot.eos_token, ot.eos_token_id),
1527
+ ],
1528
+ )
1529
+
1530
+ return tokenizer
1531
+
1532
+
1533
+ class XGLMConverter(SpmConverter):
1534
+ def vocab(self, proto):
1535
+ vocab = [
1536
+ ("<s>", 0.0),
1537
+ ("<pad>", 0.0),
1538
+ ("</s>", 0.0),
1539
+ ("<unk>", 0.0),
1540
+ ]
1541
+ vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
1542
+ vocab += [("<madeupword0>", 0.0), ("<madeupword1>", 0.0), ("<madeupword2>", 0.0), ("<madeupword3>", 0.0), ("<madeupword4>", 0.0), ("<madeupword5>", 0.0), ("<madeupword6>", 0.0)] # fmt: skip
1543
+ return vocab
1544
+
1545
+ def unk_id(self, proto):
1546
+ unk_id = 3
1547
+ return unk_id
1548
+
1549
+ def post_processor(self):
1550
+ return processors.TemplateProcessing(
1551
+ single="</s> $A",
1552
+ pair="</s> $A </s> </s> $B",
1553
+ special_tokens=[
1554
+ ("<s>", self.original_tokenizer.convert_tokens_to_ids("<s>")),
1555
+ ("</s>", self.original_tokenizer.convert_tokens_to_ids("</s>")),
1556
+ ],
1557
+ )
1558
+
1559
+
1560
+ class GemmaConverter(SpmConverter):
1561
+ handle_byte_fallback = True
1562
+ SpmExtractor = GemmaSentencePieceExtractor
1563
+ # start and end of turn tokens must be marked as special
1564
+ special_tokens = {"<start_of_turn>", "<end_of_turn>"}
1565
+
1566
+ """"
1567
+ split_by_unicode_script: true
1568
+ split_by_number: true
1569
+ split_by_whitespace: true
1570
+ treat_whitespace_as_suffix: false
1571
+ allow_whitespace_only_pieces: true
1572
+ split_digits: true
1573
+ byte_fallback: true
1574
+ """
1575
+
1576
+ def normalizer(self, proto):
1577
+ return normalizers.Replace(" ", "▁")
1578
+
1579
+ def vocab(self, proto):
1580
+ vocab = [
1581
+ (self.original_tokenizer.pad_token, 0.0),
1582
+ (self.original_tokenizer.eos_token, 0.0),
1583
+ (self.original_tokenizer.bos_token, 0.0),
1584
+ ]
1585
+ vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
1586
+
1587
+ # Older gemma tokenizers had a missing tab token, so we fix that here
1588
+ if not any(x[0] == "\t" for x in vocab):
1589
+ override_index = next((i for i, x in enumerate(vocab) if x[0] == "<0x09>"), None)
1590
+ if override_index is not None:
1591
+ vocab[override_index] = ("\t", 0.0)
1592
+
1593
+ return vocab
1594
+
1595
+ def pre_tokenizer(self, replacement, add_prefix_space):
1596
+ return pre_tokenizers.Split(" ", "merged_with_previous")
1597
+
1598
+ def unk_id(self, proto):
1599
+ unk_id = 3
1600
+ return unk_id
1601
+
1602
+ def decoder(self, replacement, add_prefix_space):
1603
+ return decoders.Sequence(
1604
+ [
1605
+ decoders.Replace("▁", " "),
1606
+ decoders.ByteFallback(),
1607
+ decoders.Fuse(),
1608
+ ]
1609
+ )
1610
+
1611
+
1612
+ class LlamaConverter(SpmConverter):
1613
+ handle_byte_fallback = True
1614
+
1615
+ def vocab(self, proto):
1616
+ vocab = [
1617
+ (self.original_tokenizer.convert_ids_to_tokens(0), 0.0),
1618
+ (self.original_tokenizer.convert_ids_to_tokens(1), 0.0),
1619
+ (self.original_tokenizer.convert_ids_to_tokens(2), 0.0),
1620
+ ]
1621
+ vocab += [(piece.piece, piece.score) for piece in proto.pieces[3:]]
1622
+ return vocab
1623
+
1624
+ def unk_id(self, proto):
1625
+ unk_id = 0
1626
+ return unk_id
1627
+
1628
+ def decoder(self, replacement, add_prefix_space):
1629
+ sequence = [
1630
+ decoders.Replace("▁", " "),
1631
+ decoders.ByteFallback(),
1632
+ decoders.Fuse(),
1633
+ ]
1634
+ if add_prefix_space:
1635
+ sequence += [decoders.Strip(content=" ", left=1)]
1636
+ return decoders.Sequence(sequence)
1637
+
1638
+ def normalizer(self, proto):
1639
+ if getattr(self.original_tokenizer, "legacy", True):
1640
+ sequence = []
1641
+ if getattr(self.original_tokenizer, "add_prefix_space", True):
1642
+ sequence += [normalizers.Prepend(prepend="▁")]
1643
+ sequence += [normalizers.Replace(pattern=" ", content="▁")]
1644
+ return normalizers.Sequence(sequence)
1645
+ return None # non-legacy, no normalizer
1646
+
1647
+ def pre_tokenizer(self, replacement, add_prefix_space):
1648
+ if not getattr(self.original_tokenizer, "legacy", True): # non-legacy, we need a replace
1649
+ prepend_scheme = _get_prepend_scheme(add_prefix_space, self.original_tokenizer)
1650
+ return pre_tokenizers.Metaspace(replacement=replacement, prepend_scheme=prepend_scheme, split=False)
1651
+ return None
1652
+
1653
+ def post_processor(self):
1654
+ # the processor is defined in the LlamaTokenizerFast class.
1655
+ return None
1656
+
1657
+
1658
+ class MarkupLMConverter(Converter):
1659
+ def converted(self) -> Tokenizer:
1660
+ ot = self.original_tokenizer
1661
+ vocab = ot.encoder
1662
+ merges = list(ot.bpe_ranks.keys())
1663
+
1664
+ tokenizer = Tokenizer(
1665
+ BPE(
1666
+ vocab=vocab,
1667
+ merges=merges,
1668
+ dropout=None,
1669
+ continuing_subword_prefix="",
1670
+ end_of_word_suffix="",
1671
+ fuse_unk=False,
1672
+ unk_token=self.original_tokenizer.unk_token,
1673
+ )
1674
+ )
1675
+
1676
+ tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=ot.add_prefix_space)
1677
+ tokenizer.decoder = decoders.ByteLevel()
1678
+
1679
+ cls = str(self.original_tokenizer.cls_token)
1680
+ sep = str(self.original_tokenizer.sep_token)
1681
+ cls_token_id = self.original_tokenizer.cls_token_id
1682
+ sep_token_id = self.original_tokenizer.sep_token_id
1683
+
1684
+ tokenizer.post_processor = processors.TemplateProcessing(
1685
+ single=f"{cls} $A {sep}",
1686
+ pair=f"{cls} $A {sep} $B {sep}",
1687
+ special_tokens=[
1688
+ (cls, cls_token_id),
1689
+ (sep, sep_token_id),
1690
+ ],
1691
+ )
1692
+
1693
+ return tokenizer
1694
+
1695
+
1696
+ class MoshiConverter(SpmConverter):
1697
+ handle_byte_fallback = True
1698
+
1699
+ def __init__(self, vocab_file, **kwargs):
1700
+ requires_backends(self, "protobuf")
1701
+
1702
+ Converter.__init__(self, vocab_file)
1703
+
1704
+ # from .utils import sentencepiece_model_pb2 as model_pb2
1705
+ model_pb2 = import_protobuf()
1706
+
1707
+ m = model_pb2.ModelProto()
1708
+ with open(vocab_file, "rb") as f:
1709
+ m.ParseFromString(f.read())
1710
+ self.proto = m
1711
+
1712
+ def normalizer(self, proto):
1713
+ precompiled_charsmap = proto.normalizer_spec.precompiled_charsmap
1714
+ _normalizers = [
1715
+ normalizers.Replace(" ", "▁"),
1716
+ ]
1717
+ if not precompiled_charsmap:
1718
+ return normalizers.Sequence(_normalizers)
1719
+ else:
1720
+ return normalizers.Sequence([normalizers.Precompiled(precompiled_charsmap)] + _normalizers)
1721
+
1722
+ def decoder(self, replacement, add_prefix_space):
1723
+ sequence = [
1724
+ decoders.Replace("▁", " "),
1725
+ decoders.ByteFallback(),
1726
+ decoders.Fuse(),
1727
+ ]
1728
+ if add_prefix_space:
1729
+ sequence += [decoders.Strip(content=" ", left=1)]
1730
+ return decoders.Sequence(sequence)
1731
+
1732
+ def pre_tokenizer(self, replacement, add_prefix_space):
1733
+ prepend_scheme = "first"
1734
+ return pre_tokenizers.Metaspace(replacement=replacement, prepend_scheme=prepend_scheme, split=False)
1735
+
1736
+
1737
+ class HeliumConverter(SpmConverter):
1738
+ handle_byte_fallback = True
1739
+
1740
+ def __init__(self, vocab_file=None, **kwargs):
1741
+ requires_backends(self, "protobuf")
1742
+
1743
+ Converter.__init__(self, vocab_file)
1744
+
1745
+ model_pb2 = import_protobuf()
1746
+
1747
+ m = model_pb2.ModelProto()
1748
+ with open(vocab_file, "rb") as f:
1749
+ m.ParseFromString(f.read())
1750
+ self.proto = m
1751
+
1752
+ def tokenizer(self, proto):
1753
+ vocab_scores = self.vocab(proto)
1754
+ tokenizer = Tokenizer(
1755
+ Unigram(
1756
+ vocab_scores,
1757
+ unk_id=self.unk_id(proto),
1758
+ byte_fallback=self.handle_byte_fallback,
1759
+ )
1760
+ )
1761
+ # control tokens are special
1762
+ # user defined symbols are not
1763
+ # both user and control tokens are AddedTokens
1764
+ # Add user defined symbols (type == 4) from sentencepiece (https://github.com/google/sentencepiece/blob/6225e08edb2577757163b3f5dbba4c0b670ef445/src/sentencepiece_model.proto#L299C29-L299C33)
1765
+ spm_added_tokens = [
1766
+ (id, p.piece, p.type == 3 or p.piece in self.special_tokens)
1767
+ for id, p in enumerate(proto.pieces)
1768
+ if p.type in [3, 4]
1769
+ ]
1770
+ tokenizer.add_tokens(
1771
+ [
1772
+ AddedToken(token, normalized=False, special=special, single_word=True)
1773
+ for id, token, special in sorted(spm_added_tokens, key=lambda x: x[0])
1774
+ ]
1775
+ )
1776
+ tokenizer.add_tokens([AddedToken("\n", normalized=False, special=False)])
1777
+ tokenizer.enable_padding(pad_token="<pad>", pad_id=3)
1778
+ return tokenizer
1779
+
1780
+ def vocab(self, proto):
1781
+ vocab = []
1782
+ for piece in proto.pieces:
1783
+ if piece.piece == "<0x0A>":
1784
+ vocab += [("\n", piece.score)]
1785
+ else:
1786
+ vocab += [(piece.piece, piece.score)]
1787
+ return vocab
1788
+
1789
+ def unk_id(self, proto):
1790
+ unk_id = 0
1791
+ return unk_id
1792
+
1793
+ def decoder(self, replacement, add_prefix_space):
1794
+ sequence = [
1795
+ decoders.Replace("▁", " "),
1796
+ decoders.ByteFallback(),
1797
+ decoders.Fuse(),
1798
+ ]
1799
+ sequence += [decoders.Strip(content=" ", left=1)]
1800
+ return decoders.Sequence(sequence)
1801
+
1802
+ def normalizer(self, proto):
1803
+ return normalizers.Sequence([normalizers.Prepend(" "), normalizers.Replace(r" ", "▁")])
1804
+
1805
+ def pre_tokenizer(self, replacement, add_prefix_space):
1806
+ return pre_tokenizers.Sequence([pre_tokenizers.Split("\n", "contiguous")])
1807
+
1808
+ def post_processor(self):
1809
+ return processors.TemplateProcessing(
1810
+ single=[
1811
+ "<s>",
1812
+ "$A",
1813
+ ],
1814
+ pair=[
1815
+ "<s>",
1816
+ "$A",
1817
+ "<s>",
1818
+ "$B",
1819
+ ],
1820
+ special_tokens=[
1821
+ ("<s>", 1),
1822
+ ],
1823
+ )
1824
+
1825
+
1826
+ class ParakeetConverter(SpmConverter):
1827
+ handle_byte_fallback = True
1828
+
1829
+ def __init__(self, vocab_file=None, *args):
1830
+ self.vocab_file = vocab_file
1831
+
1832
+ requires_backends(self, "protobuf")
1833
+
1834
+ Converter.__init__(self, vocab_file)
1835
+
1836
+ model_pb2 = import_protobuf()
1837
+ m = model_pb2.ModelProto()
1838
+ with open(vocab_file, "rb") as f:
1839
+ m.ParseFromString(f.read())
1840
+ self.proto = m
1841
+
1842
+ def tokenizer(self, proto):
1843
+ vocab_scores = self.vocab(proto)
1844
+
1845
+ bpe_vocab = {word: i for i, (word, score) in enumerate(vocab_scores)}
1846
+ merges = generate_merges(bpe_vocab, vocab_scores)
1847
+ tokenizer = Tokenizer(
1848
+ BPE(
1849
+ bpe_vocab,
1850
+ merges,
1851
+ unk_token=proto.trainer_spec.unk_piece,
1852
+ fuse_unk=True,
1853
+ byte_fallback=self.handle_byte_fallback,
1854
+ dropout=None,
1855
+ )
1856
+ )
1857
+
1858
+ # Add user defined symbols and control tokens from sentencepiece model
1859
+ spm_added_tokens = [
1860
+ (id, p.piece, p.type == 3 or p.piece in self.special_tokens)
1861
+ for id, p in enumerate(proto.pieces)
1862
+ if p.type in [3, 4]
1863
+ ]
1864
+ tokenizer.add_tokens(
1865
+ [
1866
+ AddedToken(token, normalized=False, special=special)
1867
+ for id, token, special in sorted(spm_added_tokens, key=lambda x: x[0])
1868
+ ]
1869
+ )
1870
+
1871
+ return tokenizer
1872
+
1873
+
1874
+ def bytes_to_unicode():
1875
+ """
1876
+ Returns list of utf-8 byte and a mapping to unicode strings. We specifically avoids mapping to whitespace/control
1877
+ characters the bpe code barfs on.
1878
+
1879
+ The reversible bpe codes work on unicode strings. This means you need a large # of unicode characters in your vocab
1880
+ if you want to avoid UNKs. When you're at something like a 10B token dataset you end up needing around 5K for
1881
+ decent coverage. This is a significant percentage of your normal, say, 32K bpe vocab. To avoid that, we want lookup
1882
+ tables between utf-8 bytes and unicode strings.
1883
+ """
1884
+ bs = (
1885
+ list(range(ord("!"), ord("~") + 1)) + list(range(ord("¡"), ord("¬") + 1)) + list(range(ord("®"), ord("ÿ") + 1))
1886
+ )
1887
+ cs = bs[:]
1888
+ n = 0
1889
+ for b in range(2**8):
1890
+ if b not in bs:
1891
+ bs.append(b)
1892
+ cs.append(2**8 + n)
1893
+ n += 1
1894
+ cs = [chr(n) for n in cs]
1895
+ return dict(zip(bs, cs))
1896
+
1897
+
1898
+ class TikTokenConverter:
1899
+ """
1900
+ A general tiktoken converter.
1901
+ """
1902
+
1903
+ def __init__(
1904
+ self,
1905
+ vocab_file=None,
1906
+ pattern=r"""(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}{1,3}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+""",
1907
+ add_prefix_space=False,
1908
+ extra_special_tokens=None,
1909
+ **kwargs,
1910
+ ):
1911
+ self.vocab_file = vocab_file
1912
+ self.pattern = pattern
1913
+ self.add_prefix_space = add_prefix_space
1914
+ self.extra_special_tokens = (
1915
+ extra_special_tokens.keys() if isinstance(extra_special_tokens, dict) else extra_special_tokens
1916
+ )
1917
+
1918
+ def extract_vocab_merges_from_model(self, tiktoken_url: str):
1919
+ try:
1920
+ from tiktoken.load import load_tiktoken_bpe
1921
+ except Exception:
1922
+ raise ValueError(
1923
+ "`tiktoken` is required to read a `tiktoken` file. Install it with `pip install tiktoken`."
1924
+ )
1925
+
1926
+ bpe_ranks = load_tiktoken_bpe(tiktoken_url)
1927
+ byte_encoder = bytes_to_unicode()
1928
+
1929
+ def token_bytes_to_string(b):
1930
+ return "".join([byte_encoder[ord(char)] for char in b.decode("latin-1")])
1931
+
1932
+ merges = []
1933
+ vocab = {}
1934
+ for token, rank in bpe_ranks.items():
1935
+ vocab[token_bytes_to_string(token)] = rank
1936
+ if len(token) == 1:
1937
+ continue
1938
+ local = []
1939
+ for index in range(1, len(token)):
1940
+ piece_l, piece_r = token[:index], token[index:]
1941
+ if piece_l in bpe_ranks and piece_r in bpe_ranks and (piece_l + piece_r) in bpe_ranks:
1942
+ local.append((piece_l, piece_r, rank))
1943
+ local = sorted(local, key=lambda x: (bpe_ranks[x[0]], bpe_ranks[x[1]]), reverse=False)
1944
+ merges.extend(local)
1945
+ merges = sorted(merges, key=lambda val: val[2], reverse=False)
1946
+ merges = [(token_bytes_to_string(val[0]), token_bytes_to_string(val[1])) for val in merges]
1947
+ return vocab, merges
1948
+
1949
+ def tokenizer(self):
1950
+ vocab_scores, merges = self.extract_vocab_merges_from_model(self.vocab_file)
1951
+ tokenizer = Tokenizer(BPE(vocab_scores, merges, fuse_unk=False))
1952
+ if hasattr(tokenizer.model, "ignore_merges"):
1953
+ tokenizer.model.ignore_merges = True
1954
+ return tokenizer
1955
+
1956
+ def converted(self) -> Tokenizer:
1957
+ tokenizer = self.tokenizer()
1958
+ tokenizer.pre_tokenizer = pre_tokenizers.Sequence(
1959
+ [
1960
+ pre_tokenizers.Split(Regex(self.pattern), behavior="isolated", invert=False),
1961
+ pre_tokenizers.ByteLevel(add_prefix_space=self.add_prefix_space, use_regex=False),
1962
+ ]
1963
+ )
1964
+ tokenizer.decoder = decoders.ByteLevel()
1965
+
1966
+ if self.extra_special_tokens is not None:
1967
+ tokenizer.add_special_tokens(
1968
+ [AddedToken(token, normalized=False, special=True) for token in self.extra_special_tokens]
1969
+ )
1970
+
1971
+ tokenizer.post_processor = processors.ByteLevel(trim_offsets=False)
1972
+
1973
+ return tokenizer
1974
+
1975
+
1976
+ class MistralConverter:
1977
+ def __init__(
1978
+ self,
1979
+ vocab_file=None,
1980
+ pattern=r"""(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}{1,3}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+""",
1981
+ add_prefix_space=False,
1982
+ additional_special_tokens=None,
1983
+ **kwargs,
1984
+ ):
1985
+ self.vocab_file = vocab_file
1986
+ self.pattern = pattern
1987
+ self.add_prefix_space = add_prefix_space
1988
+ self.additional_special_tokens = (
1989
+ additional_special_tokens.keys()
1990
+ if isinstance(additional_special_tokens, dict)
1991
+ else additional_special_tokens
1992
+ )
1993
+
1994
+ def extract_vocab_merges_from_model(self, tiktoken_url: str):
1995
+ import base64
1996
+ import json
1997
+
1998
+ with open(self.vocab_file, "r", encoding="utf-8") as f:
1999
+ untyped = json.load(f)
2000
+ self.pattern = untyped["config"]["pattern"]
2001
+ self.additional_special_tokens = [
2002
+ AddedToken(k["token_str"], special=k["is_control"]) for k in untyped["special_tokens"]
2003
+ ]
2004
+ bpe_ranks = untyped["vocab"]
2005
+ byte_encoder = bytes_to_unicode()
2006
+
2007
+ @lru_cache
2008
+ def token_bytes_to_string(b):
2009
+ return "".join([byte_encoder[ord(char)] for char in b.decode("latin-1")])
2010
+
2011
+ merges = []
2012
+ vocab = {}
2013
+ for idx, token in enumerate(self.additional_special_tokens):
2014
+ vocab[token.content] = idx
2015
+ bpe_ranks = [base64.b64decode(k["token_bytes"]) for k in bpe_ranks]
2016
+ rank_set = set(bpe_ranks)
2017
+ token_to_rank = {token: rank for rank, token in enumerate(bpe_ranks)}
2018
+ for rank, token in enumerate(tqdm(bpe_ranks, desc="Converting tekken.json to tokenizer.json")):
2019
+ vocab[token_bytes_to_string(token)] = rank
2020
+ if len(token) == 1:
2021
+ continue
2022
+ local = []
2023
+ for index in range(1, len(token)):
2024
+ piece_l, piece_r = token[:index], token[index:]
2025
+ if piece_l in rank_set and piece_r in rank_set and (piece_l + piece_r) in rank_set:
2026
+ local.append((piece_l, piece_r, rank))
2027
+ local = sorted(local, key=lambda x: (token_to_rank[x[0]], token_to_rank[x[1]]), reverse=False)
2028
+ merges.extend(local)
2029
+ merges = sorted(merges, key=lambda val: val[2], reverse=False)
2030
+ merges = [(token_bytes_to_string(val[0]), token_bytes_to_string(val[1])) for val in merges]
2031
+ return vocab, merges
2032
+
2033
+ def tokenizer(self):
2034
+ vocab_scores, merges = self.extract_vocab_merges_from_model(self.vocab_file)
2035
+ tokenizer = Tokenizer(BPE(vocab_scores, merges, fuse_unk=False))
2036
+ if hasattr(tokenizer.model, "ignore_merges"):
2037
+ tokenizer.model.ignore_merges = True
2038
+ return tokenizer
2039
+
2040
+ def converted(self) -> Tokenizer:
2041
+ tokenizer = self.tokenizer()
2042
+ tokenizer.pre_tokenizer = pre_tokenizers.Sequence(
2043
+ [
2044
+ pre_tokenizers.Split(Regex(self.pattern), behavior="isolated", invert=False),
2045
+ pre_tokenizers.ByteLevel(add_prefix_space=self.add_prefix_space, use_regex=False),
2046
+ ]
2047
+ )
2048
+ tokenizer.decoder = decoders.ByteLevel()
2049
+
2050
+ tokenizer.add_tokens(self.additional_special_tokens)
2051
+ tokenizer.post_processor = processors.ByteLevel(trim_offsets=False)
2052
+
2053
+ return tokenizer
2054
+
2055
+
2056
+ SLOW_TO_FAST_CONVERTERS = {
2057
+ "AlbertTokenizer": AlbertConverter,
2058
+ "BartTokenizer": RobertaConverter,
2059
+ "BarthezTokenizer": BarthezConverter,
2060
+ "BertTokenizer": BertConverter,
2061
+ "BigBirdTokenizer": BigBirdConverter,
2062
+ "BlenderbotTokenizer": BlenderbotConverter,
2063
+ "CamembertTokenizer": CamembertConverter,
2064
+ "CLIPTokenizer": CLIPConverter,
2065
+ "CodeGenTokenizer": GPT2Converter,
2066
+ "ConvBertTokenizer": BertConverter,
2067
+ "DebertaTokenizer": DebertaConverter,
2068
+ "DebertaV2Tokenizer": DebertaV2Converter,
2069
+ "DistilBertTokenizer": BertConverter,
2070
+ "DPRReaderTokenizer": BertConverter,
2071
+ "DPRQuestionEncoderTokenizer": BertConverter,
2072
+ "DPRContextEncoderTokenizer": BertConverter,
2073
+ "ElectraTokenizer": BertConverter,
2074
+ "FNetTokenizer": AlbertConverter,
2075
+ "FunnelTokenizer": FunnelConverter,
2076
+ "GPT2Tokenizer": GPT2Converter,
2077
+ "HerbertTokenizer": HerbertConverter,
2078
+ "LayoutLMTokenizer": BertConverter,
2079
+ "LayoutLMv2Tokenizer": BertConverter,
2080
+ "LayoutLMv3Tokenizer": RobertaConverter,
2081
+ "LayoutXLMTokenizer": XLMRobertaConverter,
2082
+ "LongformerTokenizer": RobertaConverter,
2083
+ "LEDTokenizer": RobertaConverter,
2084
+ "LxmertTokenizer": BertConverter,
2085
+ "MarkupLMTokenizer": MarkupLMConverter,
2086
+ "MBartTokenizer": MBartConverter,
2087
+ "MBart50Tokenizer": MBart50Converter,
2088
+ "MPNetTokenizer": MPNetConverter,
2089
+ "MobileBertTokenizer": BertConverter,
2090
+ "MvpTokenizer": RobertaConverter,
2091
+ "NllbTokenizer": NllbConverter,
2092
+ "OpenAIGPTTokenizer": OpenAIGPTConverter,
2093
+ "PegasusTokenizer": PegasusConverter,
2094
+ "Qwen2Tokenizer": Qwen2Converter,
2095
+ "ReformerTokenizer": ReformerConverter,
2096
+ "RemBertTokenizer": RemBertConverter,
2097
+ "RobertaTokenizer": RobertaConverter,
2098
+ "RoFormerTokenizer": RoFormerConverter,
2099
+ "SeamlessM4TTokenizer": SeamlessM4TConverter,
2100
+ "SqueezeBertTokenizer": BertConverter,
2101
+ "T5Tokenizer": T5Converter,
2102
+ "UdopTokenizer": UdopConverter,
2103
+ "WhisperTokenizer": WhisperConverter,
2104
+ "XLMRobertaTokenizer": XLMRobertaConverter,
2105
+ "XLNetTokenizer": XLNetConverter,
2106
+ "SplinterTokenizer": SplinterConverter,
2107
+ "XGLMTokenizer": XGLMConverter,
2108
+ "LlamaTokenizer": LlamaConverter,
2109
+ "CodeLlamaTokenizer": LlamaConverter,
2110
+ "GemmaTokenizer": GemmaConverter,
2111
+ "Phi3Tokenizer": LlamaConverter,
2112
+ }
2113
+
2114
+
2115
+ def convert_slow_tokenizer(transformer_tokenizer, from_tiktoken=False) -> Tokenizer:
2116
+ """
2117
+ Utilities to convert a slow tokenizer instance in a fast tokenizer instance.
2118
+
2119
+ Args:
2120
+ transformer_tokenizer ([`~tokenization_utils_base.PreTrainedTokenizer`]):
2121
+ Instance of a slow tokenizer to convert in the backend tokenizer for
2122
+ [`~tokenization_utils_base.PreTrainedTokenizerFast`].
2123
+ from_tiktoken (bool, optional): Whether to use the `tiktoken` library to convert the tokenizer instead of sentencepiece.
2124
+ Defaults to False.
2125
+
2126
+ Return:
2127
+ A instance of [`~tokenizers.Tokenizer`] to be used as the backend tokenizer of a
2128
+ [`~tokenization_utils_base.PreTrainedTokenizerFast`]
2129
+ """
2130
+
2131
+ tokenizer_class_name = transformer_tokenizer.__class__.__name__
2132
+ if tokenizer_class_name in SLOW_TO_FAST_CONVERTERS and not from_tiktoken:
2133
+ converter_class = SLOW_TO_FAST_CONVERTERS[tokenizer_class_name]
2134
+ return converter_class(transformer_tokenizer).converted()
2135
+ elif transformer_tokenizer.vocab_file.endswith("tekken.json"):
2136
+ transformer_tokenizer.original_tokenizer = transformer_tokenizer
2137
+ logger.info("Converting from Mistral tekken.json")
2138
+ return MistralConverter(transformer_tokenizer.vocab_file).converted()
2139
+ else:
2140
+ try:
2141
+ logger.info("Converting from Tiktoken")
2142
+ return TikTokenConverter(
2143
+ vocab_file=transformer_tokenizer.vocab_file,
2144
+ extra_special_tokens=transformer_tokenizer.extra_special_tokens,
2145
+ ).converted()
2146
+ except Exception:
2147
+ raise ValueError(
2148
+ f"Converting from SentencePiece and Tiktoken failed, if a converter for SentencePiece is available, provide a model path "
2149
+ f"with a SentencePiece tokenizer.model file."
2150
+ f"Currently available slow->fast converters: {list(SLOW_TO_FAST_CONVERTERS.keys())}"
2151
+ )
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/core_model_loading.py ADDED
@@ -0,0 +1,1557 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2025 The HuggingFace Inc. team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """Core helpers for loading model checkpoints."""
15
+
16
+ from __future__ import annotations
17
+
18
+ import math
19
+ import os
20
+ import re
21
+ import traceback
22
+ from abc import abstractmethod
23
+ from collections import defaultdict
24
+ from collections.abc import Callable
25
+ from concurrent.futures import Future, ThreadPoolExecutor
26
+ from contextlib import contextmanager
27
+ from copy import deepcopy
28
+ from itertools import chain
29
+ from typing import TYPE_CHECKING, Any
30
+
31
+ import torch
32
+
33
+ from .integrations.accelerate import get_device, offload_weight
34
+ from .integrations.tensor_parallel import ALL_PARALLEL_STYLES
35
+ from .utils import is_env_variable_true
36
+ from .utils.loading_report import LoadStateDictInfo
37
+ from .utils.logging import get_logger, tqdm
38
+
39
+
40
+ _torch_distributed_available = torch.distributed.is_available()
41
+
42
+ if TYPE_CHECKING:
43
+ from .integrations.tensor_parallel import TensorParallelLayer
44
+ from .modeling_utils import LoadStateDictConfig, PreTrainedModel
45
+ from .quantizers import HfQuantizer
46
+
47
+
48
+ logger = get_logger(__name__)
49
+
50
+
51
+ def build_glob_alternation(
52
+ globs: list[WeightRenaming | WeightConverter | str],
53
+ ) -> tuple[re.Pattern, dict[str, str], dict[str, str]]:
54
+ """
55
+ Build a single alternation regex with one named group per glob.
56
+ """
57
+ src_group_to_glob: dict[str, str] = {}
58
+ tgt_group_to_glob: dict[str, str] = {}
59
+ branches: list[str] = []
60
+ i = 0
61
+ for glob in globs:
62
+ if isinstance(glob, (WeightRenaming, WeightConverter)):
63
+ for src in glob.source_patterns:
64
+ group_name = f"g{i}"
65
+ src_group_to_glob[group_name] = src
66
+ i += 1
67
+ body = src.replace("*", r".*")
68
+ branches.append(f"(?P<{group_name}>{body})")
69
+ tgt_group_to_glob[group_name] = glob.target_patterns[0] # we index with the first target
70
+ else:
71
+ group_name = f"g{i}"
72
+ src_group_to_glob[group_name] = glob
73
+ i += 1
74
+ body = glob
75
+ body = body.replace("*", r".*")
76
+ branches.append(f"(?P<{group_name}>{body})")
77
+ tgt_group_to_glob[group_name] = glob
78
+
79
+ alternation = re.compile("|".join(branches))
80
+ return alternation, src_group_to_glob, tgt_group_to_glob
81
+
82
+
83
+ class ConversionOps:
84
+ """Base class for weight conversion operations."""
85
+
86
+ def __repr__(self):
87
+ if hasattr(self, "dim"):
88
+ return f"{self.__class__.__name__}(dim={self.dim})"
89
+ else:
90
+ return f"{self.__class__.__name__}"
91
+
92
+ @abstractmethod
93
+ def convert(
94
+ self, input_dict: dict[str, Any], source_patterns: list[str], target_patterns: list[str], **kwargs
95
+ ) -> dict[str, list[torch.Tensor]]:
96
+ raise NotImplementedError
97
+
98
+ @property
99
+ def reverse_op(self) -> ConversionOps:
100
+ raise NotImplementedError
101
+
102
+
103
+ class _IdentityOp(ConversionOps):
104
+ """Pass-through reverse op for dequantize operations.
105
+
106
+ Dequantized weights are already in their target dtype and should be
107
+ saved as-is without any conversion.
108
+ """
109
+
110
+ def convert(self, input_dict: dict[str, Any], **kwargs) -> dict[str, Any]:
111
+ return input_dict
112
+
113
+
114
+ class Chunk(ConversionOps):
115
+ """Split a tensor along `dim` into equally sized chunks."""
116
+
117
+ def __init__(self, dim: int = 0):
118
+ self.dim = dim
119
+
120
+ @torch.no_grad
121
+ def convert(
122
+ self, input_dict: dict[str, torch.Tensor], source_patterns: list[str], target_patterns: list[str], **kwargs
123
+ ) -> dict[str, torch.Tensor]:
124
+ tensors = next(iter(input_dict.values()))
125
+ tensor = tensors[0] if isinstance(tensors, list) else tensors
126
+ targets = self.get_target_patterns(input_dict, target_patterns)
127
+ sizes = len(targets)
128
+ chunks = torch.chunk(tensor, sizes, dim=self.dim)
129
+ return dict(zip(targets, chunks))
130
+
131
+ def get_target_patterns(self, input_dict: dict, target_patterns: list[str]) -> list[str]:
132
+ # Here we always return the target patterns
133
+ if len(input_dict) > 1 or len(target_patterns) == 1:
134
+ raise ValueError("Undefined Operation encountered!")
135
+ return target_patterns
136
+
137
+ @property
138
+ def reverse_op(self) -> ConversionOps:
139
+ return Concatenate(self.dim)
140
+
141
+
142
+ class Concatenate(ConversionOps):
143
+ """Concatenate tensors along `dim`."""
144
+
145
+ def __init__(self, dim: int = 0):
146
+ self.dim = dim
147
+
148
+ @torch.no_grad
149
+ def convert(
150
+ self,
151
+ input_dict: dict[str, list[torch.Tensor]],
152
+ source_patterns: list[str],
153
+ target_patterns: list[str],
154
+ **kwargs,
155
+ ) -> dict[str, torch.Tensor]:
156
+ target_pattern = self.get_target_pattern(target_patterns)
157
+ all_tensors = []
158
+ # Very important to keep the relative order of the source patterns here, so we iterate over them not the
159
+ # input directly as it's unordered! Skip patterns that prior ops in the chain (e.g. `Fp8Dequantize`)
160
+ # have already consumed and dropped from `input_dict`.
161
+ for source_pattern in source_patterns:
162
+ if source_pattern not in input_dict:
163
+ continue
164
+ # Immediately free the input_dict, so that we do not keep many copies simultaneously - otherwise we have to
165
+ # wait for this function to return to be able to clean-up, which will not get garbage collected as fast as if
166
+ # everything is freed right now
167
+ tensors = input_dict.pop(source_pattern)
168
+ if isinstance(tensors, list):
169
+ all_tensors.extend(tensors)
170
+ else:
171
+ all_tensors.append(tensors)
172
+ return {target_pattern: torch.cat(all_tensors, dim=self.dim)}
173
+
174
+ def get_target_pattern(self, target_patterns: list[str]) -> str:
175
+ # Here we always return the target pattern
176
+ if len(target_patterns) > 1:
177
+ raise ValueError("Undefined Operation encountered!")
178
+ return target_patterns[0]
179
+
180
+ @property
181
+ def reverse_op(self) -> ConversionOps:
182
+ return Chunk(self.dim)
183
+
184
+
185
+ class MergeModulelist(ConversionOps):
186
+ """
187
+ Merge a list of tensors into a single tensor along the first dimension.
188
+ We explicitly define this because for EP or TP you want to make sure you know what you are doing!
189
+
190
+ """
191
+
192
+ def __init__(self, dim: int = 0):
193
+ self.dim = dim
194
+
195
+ @torch.no_grad
196
+ def convert(
197
+ self,
198
+ input_dict: dict[str, list[torch.Tensor]],
199
+ source_patterns: list[str],
200
+ target_patterns: list[str],
201
+ **kwargs,
202
+ ) -> dict[str, torch.Tensor]:
203
+ input_size = len(input_dict)
204
+ merged: dict[str, torch.Tensor] = {}
205
+ for source_pattern in list(input_dict.keys()):
206
+ # Immediately free the input dict, so that we do not keep many copies simultaneously - otherwise we have to
207
+ # wait for this function to return to be able to clean-up, and if the size of the input_dict is larger than 1
208
+ # (such as the MoEs' gate_proj/up_proj merging), we are wasting quite some memory
209
+ tensors = input_dict.pop(source_pattern)
210
+ target_pattern = self.get_target_pattern(input_size, source_pattern, target_patterns)
211
+ merged[target_pattern] = torch.stack(tensors, dim=self.dim)
212
+ return merged
213
+
214
+ def get_target_pattern(self, input_size: int, source_pattern: str, target_patterns: list[str]) -> str:
215
+ # Here it's a single operation, so we use the target
216
+ if input_size == 1:
217
+ if len(target_patterns) == 1:
218
+ return target_patterns[0]
219
+ else:
220
+ raise ValueError("Undefined Operation encountered!")
221
+ # Here it's the first operation in a chain, so we use the source as they were replaced before in the chain
222
+ else:
223
+ return source_pattern
224
+
225
+ @property
226
+ def reverse_op(self) -> ConversionOps:
227
+ return SplitModulelist(self.dim)
228
+
229
+
230
+ class SplitModulelist(ConversionOps):
231
+ """Inverse of `MergeModulelist` using explicit split sizes per group."""
232
+
233
+ def __init__(self, dim: int = 0):
234
+ self.dim = dim
235
+
236
+ @torch.no_grad
237
+ def convert(
238
+ self, input_dict: dict[str, torch.Tensor], source_patterns: list[str], target_patterns: list[str], **kwargs
239
+ ) -> dict[str, torch.Tensor]:
240
+ all_tensors = {}
241
+ for source_pattern, tensors in input_dict.items():
242
+ tensor = tensors[0] if isinstance(tensors, list) else tensors
243
+ # We split in the number of tensors present in the given dim
244
+ sizes = tensor.size(self.dim)
245
+ targets = self.get_target_patterns(input_dict, source_pattern, target_patterns, sizes)
246
+ chunks = torch.chunk(tensor, sizes, dim=self.dim)
247
+ # We squeeze each chunk here as well to make sure to give them their original shape
248
+ all_tensors.update({target: chunk.squeeze() for target, chunk in zip(targets, chunks)})
249
+ return all_tensors
250
+
251
+ def get_target_patterns(
252
+ self, input_dict: dict, source_pattern: str, target_patterns: list[str], sizes: int
253
+ ) -> list[str]:
254
+ # Here it's a single operation, so we use the target
255
+ if len(input_dict) == 1:
256
+ if len(target_patterns) == 1:
257
+ return [target_patterns[0].replace("*", f"{i}") for i in range(sizes)]
258
+ else:
259
+ raise ValueError("Undefined Operation encountered!")
260
+ # Here it's the last operation in a chain, so we use the source as they were replaced before in the chain
261
+ else:
262
+ return [source_pattern.replace("*", f"{i}") for i in range(sizes)]
263
+
264
+ @property
265
+ def reverse_op(self) -> ConversionOps:
266
+ return MergeModulelist(self.dim)
267
+
268
+
269
+ class Transpose(ConversionOps):
270
+ """
271
+ Transposes the given tensor along dim0 and dim1.
272
+ """
273
+
274
+ def __init__(self, dim0: int = 0, dim1: int = 1, check_dims: bool = False):
275
+ self.dim0 = dim0
276
+ self.dim1 = dim1
277
+ self.check_dims = check_dims
278
+
279
+ @torch.no_grad
280
+ def convert(
281
+ self, input_dict: dict[str, torch.Tensor], source_patterns: list[str], target_patterns: list[str], **kwargs
282
+ ) -> dict[str, torch.Tensor]:
283
+ target_pattern = self.get_target_pattern(input_dict, source_patterns, target_patterns)
284
+ tensors = next(iter(input_dict.values()))
285
+ tensor = tensors[0] if isinstance(tensors, list) else tensors
286
+ # In this case, always transpose
287
+ if not self.check_dims:
288
+ return {target_pattern: torch.transpose(tensor, dim0=self.dim0, dim1=self.dim1).contiguous()}
289
+ # In this case, check the shapes before transposing
290
+ else:
291
+ # NOTE: this rely on the first param name, so cannot be used for many-to-one operation
292
+ expected_shape = kwargs["model"].get_parameter(kwargs["full_layer_name"]).shape
293
+ # The shapes are the same: do NOT transpose
294
+ if tensor.shape == expected_shape:
295
+ return {target_pattern: tensor}
296
+ else:
297
+ return {target_pattern: torch.transpose(tensor, dim0=self.dim0, dim1=self.dim1).contiguous()}
298
+
299
+ def get_target_pattern(
300
+ self, input_dict: dict[str, torch.Tensor], source_patterns: list[str], target_patterns: list[str]
301
+ ) -> str:
302
+ if len(input_dict) != 1:
303
+ raise ValueError("Undefined Operation encountered!")
304
+ # Here it's the first operation of a chain, so return the source
305
+ if len(target_patterns) > 1:
306
+ if len(source_patterns) == 1:
307
+ return source_patterns[0]
308
+ else:
309
+ raise ValueError("Undefined Operation encountered!")
310
+ # Here it's the only operation, or the last operation in a chain, so we return the target
311
+ else:
312
+ return target_patterns[0]
313
+
314
+ @property
315
+ def reverse_op(self) -> ConversionOps:
316
+ return Transpose(dim0=self.dim1, dim1=self.dim0, check_dims=self.check_dims)
317
+
318
+
319
+ class Conv3dToLinear(ConversionOps):
320
+ """Conv3d weights → flattened Linear layout."""
321
+
322
+ def __init__(self, in_channels: int, kernel_size: tuple[int, int, int]):
323
+ self.in_channels = in_channels
324
+ self.kernel_size = kernel_size
325
+
326
+ @staticmethod
327
+ def _get_target_pattern(
328
+ input_dict: dict[str, torch.Tensor], source_patterns: list[str], target_patterns: list[str]
329
+ ) -> str:
330
+ if len(input_dict) != 1:
331
+ raise ValueError("Undefined Operation encountered!")
332
+ if len(target_patterns) > 1:
333
+ if len(source_patterns) == 1:
334
+ return source_patterns[0]
335
+ else:
336
+ raise ValueError("Undefined Operation encountered!")
337
+ return target_patterns[0]
338
+
339
+ @torch.no_grad
340
+ def convert(
341
+ self, input_dict: dict[str, torch.Tensor], source_patterns: list[str], target_patterns: list[str], **kwargs
342
+ ) -> dict[str, torch.Tensor]:
343
+ target_pattern = self._get_target_pattern(input_dict, source_patterns, target_patterns)
344
+ tensors = next(iter(input_dict.values()))
345
+ tensor = tensors[0] if isinstance(tensors, list) else tensors
346
+
347
+ if tensor.ndim == 5:
348
+ tensor = tensor.reshape(tensor.shape[0], -1).contiguous()
349
+ elif tensor.ndim != 2:
350
+ raise ValueError(f"Conv3dToLinear expects a 5D or 2D tensor, got {tensor.ndim}D")
351
+
352
+ return {target_pattern: tensor}
353
+
354
+ @property
355
+ def reverse_op(self) -> ConversionOps:
356
+ return LinearToConv3d(in_channels=self.in_channels, kernel_size=self.kernel_size)
357
+
358
+
359
+ class LinearToConv3d(ConversionOps):
360
+ """Flattened Linear weights → Conv3d layout."""
361
+
362
+ def __init__(self, in_channels: int, kernel_size: tuple[int, int, int]):
363
+ self.in_channels = in_channels
364
+ self.kernel_size = kernel_size
365
+
366
+ @torch.no_grad
367
+ def convert(
368
+ self, input_dict: dict[str, torch.Tensor], source_patterns: list[str], target_patterns: list[str], **kwargs
369
+ ) -> dict[str, torch.Tensor]:
370
+ target_pattern = Conv3dToLinear._get_target_pattern(input_dict, source_patterns, target_patterns)
371
+ tensors = next(iter(input_dict.values()))
372
+ tensor = tensors[0] if isinstance(tensors, list) else tensors
373
+
374
+ target_shape = (tensor.shape[0], self.in_channels, *self.kernel_size)
375
+ if tensor.numel() != math.prod(target_shape):
376
+ raise ValueError(f"Cannot reshape tensor with shape {tensor.shape} into {target_shape}")
377
+
378
+ return {target_pattern: tensor.reshape(target_shape).contiguous()}
379
+
380
+ @property
381
+ def reverse_op(self) -> ConversionOps:
382
+ return Conv3dToLinear(in_channels=self.in_channels, kernel_size=self.kernel_size)
383
+
384
+
385
+ class PermuteForRope(ConversionOps):
386
+ """
387
+ Applies the permutation required to convert complex RoPE weights to the split sin/cos format.
388
+ """
389
+
390
+ def __init__(self):
391
+ pass
392
+
393
+ def _apply(self, tensor: torch.Tensor) -> torch.Tensor:
394
+ dim1, dim2 = tensor.shape
395
+ n_heads = self.config.getattr("num_attention_heads", 1)
396
+
397
+ tensor = tensor.view(n_heads, dim1 // n_heads // 2, 2, dim2)
398
+ tensor = tensor.transpose(1, 2).reshape(dim1, dim2)
399
+ return tensor
400
+
401
+ @torch.no_grad
402
+ def convert(
403
+ self,
404
+ input_dict: dict[str, list[torch.Tensor]],
405
+ source_patterns: list[str],
406
+ target_patterns: list[str],
407
+ config,
408
+ **kwargs,
409
+ ) -> dict[str, list[torch.Tensor]]:
410
+ self.config = config
411
+ output: dict[str, list[torch.Tensor]] = {}
412
+ for key, tensors in input_dict.items():
413
+ if len(tensors) != 1:
414
+ raise ValueError("PermuteForRope expects a single tensor per key.")
415
+ output[key] = [self._apply(tensors[0])]
416
+ return output
417
+
418
+
419
+ class ErnieFuseAndSplitTextVisionExperts(ConversionOps):
420
+ r"""
421
+ Special operation that splits a module list over all keys and fuses over the number of original modules.
422
+
423
+ Example with 2 original modules "Gate" and "Up" with 2 target keys "Text" and "Vision":
424
+
425
+ ModuleList 1 ModuleList 2
426
+ [ Gate ] [ Up ]
427
+ | | | |
428
+ [Gate_Text] [Gate_Vision] [Up_Text] [Up_Vision]
429
+ \ \ / /
430
+ \ \ / /
431
+ \ / \ /
432
+ \ / \ /
433
+ [GateUp_Text] [GateUp_Vision]
434
+
435
+ The splits are equal and are defined by the amount of target keys.
436
+ The final fusions are defined by the amount of original module lists.
437
+ """
438
+
439
+ def __init__(self, stack_dim: int = 0, concat_dim: int = 1):
440
+ self.stack_dim = stack_dim
441
+ self.concat_dim = concat_dim
442
+
443
+ def split_list_into_chunks(self, tensor_list: list[torch.Tensor], chunks: int = 2):
444
+ split_size = math.ceil(len(tensor_list) / chunks) # best effort split size
445
+ return [tensor_list[i * split_size : (i + 1) * split_size] for i in range(chunks)]
446
+
447
+ @torch.no_grad()
448
+ def convert(
449
+ self,
450
+ input_dict: dict[str, list[torch.Tensor]],
451
+ source_patterns: list[str],
452
+ target_patterns: list[str],
453
+ config,
454
+ **kwargs,
455
+ ) -> dict[str, list[torch.Tensor]]:
456
+ valid_keys = input_dict.keys()
457
+ split_and_fused = defaultdict(list)
458
+ for key in source_patterns:
459
+ if key not in valid_keys:
460
+ raise ValueError(
461
+ f"Expected pattern {key} in collected tensors but only found tensors for: {valid_keys}"
462
+ )
463
+
464
+ tensors = input_dict.get(key, [])
465
+ split_tensor_lists = self.split_list_into_chunks(tensors, chunks=len(target_patterns))
466
+ stacked_tensors = (torch.stack(tensor_group, dim=self.stack_dim) for tensor_group in split_tensor_lists)
467
+ for idx, tensor_group in enumerate(stacked_tensors):
468
+ split_and_fused[target_patterns[idx]].append(tensor_group)
469
+
470
+ for k, v in split_and_fused.items():
471
+ split_and_fused[k] = torch.cat(v, dim=self.concat_dim)
472
+
473
+ return split_and_fused
474
+
475
+ @property
476
+ def reverse_op(self) -> ConversionOps:
477
+ return ErnieSplitAndDecoupleTextVisionExperts(stack_dim=self.stack_dim, concat_dim=self.concat_dim)
478
+
479
+
480
+ class ErnieSplitAndDecoupleTextVisionExperts(ConversionOps):
481
+ r"""
482
+ Special operation that splits a fused module list over all original modules and
483
+ then decouples them into a mixed module list each over all keys.
484
+
485
+ Example with 2 original modules "Gate" and "Up" with 2 target keys "Text" and "Vision":
486
+
487
+ [GateUp_Text] [GateUp_Vision]
488
+ / \ / \
489
+ / \ / \
490
+ / / \ \
491
+ / / \ \
492
+ [Gate_Text] [Gate_Vision] [Up_Text] [Up_Vision]
493
+ | | | |
494
+ [ Gate ] [ Up ]
495
+ ModuleList 1 ModuleList 2
496
+
497
+ The splits are equal and are defined by the amount of original module lists.
498
+ The final decoupled module lists are defined by the amount of keys.
499
+ """
500
+
501
+ def __init__(self, stack_dim: int = 0, concat_dim: int = 1):
502
+ self.stack_dim = stack_dim
503
+ self.concat_dim = concat_dim
504
+
505
+ @torch.no_grad()
506
+ def convert(
507
+ self,
508
+ input_dict: dict[str, list[torch.Tensor]],
509
+ source_patterns: list[str],
510
+ target_patterns: list[str],
511
+ config,
512
+ **kwargs,
513
+ ) -> dict[str, list[torch.Tensor]]:
514
+ fused_modules = len(target_patterns)
515
+ valid_keys = input_dict.keys()
516
+ split_tensors = []
517
+ for key in source_patterns:
518
+ if key not in valid_keys:
519
+ raise ValueError(
520
+ f"Expected pattern {key} in collected tensors but only found tensors for: {valid_keys}"
521
+ )
522
+
523
+ # Assuming that we get single sized lists here to index with 0
524
+ split_tensors.append(input_dict[key][0].chunk(fused_modules, dim=self.concat_dim))
525
+
526
+ decoupled = {}
527
+ for idx, key in enumerate(target_patterns):
528
+ tensor_groups = [
529
+ list(torch.unbind(tensor_group[idx], dim=self.stack_dim)) for tensor_group in split_tensors
530
+ ]
531
+ tensor_list = list(chain.from_iterable(tensor_groups))
532
+ targets = [key.replace("*", f"{i}") for i in range(len(tensor_list))]
533
+ decoupled |= dict(zip(targets, tensor_list))
534
+
535
+ return decoupled
536
+
537
+ @property
538
+ def reverse_op(self) -> ConversionOps:
539
+ return ErnieFuseAndSplitTextVisionExperts(stack_dim=self.stack_dim, concat_dim=self.concat_dim)
540
+
541
+
542
+ def process_target_pattern(pattern: str) -> tuple[str, str | None]:
543
+ """
544
+ Process a target pattern for reverse mapping (when targets become sources).
545
+
546
+ This handles several edge cases in checkpoint conversion mappings:
547
+ - Removes `^` prefix and `$` suffix (start/end of string anchors)
548
+ - Removes negative lookahead/lookbehind assertions
549
+ - Detects capturing groups and replaces them with `\\1` backreference
550
+
551
+ Args:
552
+ pattern: The target pattern to process for reverse mapping.
553
+
554
+ Returns:
555
+ A tuple of (processed_pattern, captured_group) where captured_group is
556
+ the original capturing group found (e.g., "(encoder|decoder)") or None.
557
+ """
558
+ # Some mapping contains `^` to notify start of string when matching -> remove it during reverse mapping
559
+ pattern = pattern.removeprefix("^")
560
+ # Some mapping contains `$` to notify end of string when matching -> remove it during reverse mapping
561
+ pattern = pattern.removesuffix("$")
562
+ # Remove negative lookahead/behind if any. This is ugly but needed for reverse mapping of
563
+ # Qwen2.5, Sam3, Ernie4.5 VL MoE! It needs to be non greedy in case there are several
564
+ pattern = re.sub(r"\(\?.+?\)?\)", "", pattern)
565
+ # Remove the backslash for literal dots
566
+ pattern = pattern.replace(r"\.", ".")
567
+ # Allow capturing groups in patterns, i.e. to add/remove a prefix to all keys (e.g. timm_wrapper, sam3)
568
+ capturing_group_match = re.search(r"\(.+?\)", pattern)
569
+ captured_group = None
570
+ if capturing_group_match:
571
+ captured_group = capturing_group_match.group(0)
572
+ pattern = pattern.replace(captured_group, r"\1", 1)
573
+ return pattern, captured_group
574
+
575
+
576
+ def process_source_pattern(source_pattern: str, target_pattern: str) -> str:
577
+ """
578
+ Process a source pattern for reverse mapping (when sources become targets).
579
+ This is useful because usually if the original source (so now the target in reverse mode) had a `^` or `$`
580
+ to restrict to start/end of string, we should do the same in reverse mode. This is why this method in conditioned
581
+ on the target pattern, we want to do it only for pairs (source, target) when the original source (so the current target
582
+ in reverse mode) had it.
583
+ """
584
+ if target_pattern.startswith("^"):
585
+ source_pattern = f"^{source_pattern}" if not source_pattern.startswith("^") else source_pattern
586
+ if target_pattern.endswith("$"):
587
+ source_pattern = f"{source_pattern}$" if not source_pattern.endswith("$") else source_pattern
588
+
589
+ return source_pattern
590
+
591
+
592
+ class WeightTransform:
593
+ # Restrict the attributes that can be attached
594
+ __slots__ = (
595
+ "source_patterns",
596
+ "target_patterns",
597
+ "compiled_sources",
598
+ "distributed_operation",
599
+ "quantization_operation",
600
+ "collected_tensors",
601
+ "layer_targets",
602
+ "_original_source_patterns",
603
+ "_original_target_patterns",
604
+ "_was_used",
605
+ "scope_prefix",
606
+ )
607
+
608
+ def __init__(self, source_patterns: str | list[str], target_patterns: str | list[str]):
609
+ self.source_patterns: list[str] = source_patterns
610
+ self.target_patterns: list[str] = target_patterns
611
+ # Those are needed to be able to reverse correctly the transform, as the patterns may be processed
612
+ self._original_source_patterns = self.source_patterns.copy()
613
+ self._original_target_patterns = self.target_patterns.copy()
614
+
615
+ # Init fields that will be used during conversion
616
+ self.distributed_operation: TensorParallelLayer | None = None
617
+ self.quantization_operation: ConversionOps | None = None
618
+ self.collected_tensors: dict[str, list[Future]] = defaultdict(list)
619
+ self.layer_targets: dict[str, set[str]] = defaultdict(set)
620
+
621
+ # Flag to notice if the Transform was used
622
+ self._was_used = False
623
+ # Optional prefix scope: when set, this transform only applies to keys starting with
624
+ # `scope_prefix + "."`, stripping / re-attaching the prefix around the pattern match.
625
+ self.scope_prefix: str | None = None
626
+
627
+ # We need to process a few exceptions here when instantiating the reverse mapping (i.e. the targets become
628
+ # sources, and sources become targets). The issues lie in the sources usually, so here we need to check the
629
+ # targets for the reversed mapping
630
+
631
+ # Process target_patterns: detect capturing groups and replace with \1
632
+ # Store the original capturing group patterns for reverse mapping
633
+ target_capturing_groups: list[str] = []
634
+ for i, pattern in enumerate(self.target_patterns):
635
+ self.target_patterns[i], captured_group = process_target_pattern(pattern)
636
+ if captured_group is not None:
637
+ target_capturing_groups.append(captured_group)
638
+
639
+ # Validate that we only have one unique capturing group pattern across all targets
640
+ # This ensures deterministic reverse mapping when sources have \1 backreferences
641
+ unique_capturing_groups = set(target_capturing_groups)
642
+ if len(unique_capturing_groups) > 1:
643
+ raise ValueError(
644
+ f"Multiple different capturing groups found in target_patterns: {unique_capturing_groups}. "
645
+ f"All target patterns must use the same capturing group pattern."
646
+ )
647
+ unique_capturing_group = unique_capturing_groups.pop() if unique_capturing_groups else None
648
+
649
+ # We also need to check capturing groups in the sources during reverse mapping (e.g. timm_wrapper, sam3)
650
+ for i, pattern in enumerate(self.source_patterns):
651
+ # Replace capturing groups
652
+ if r"\1" in pattern:
653
+ if unique_capturing_group is None:
654
+ raise ValueError(
655
+ f"Source pattern '{pattern}' contains \\1 backreference, but no capturing groups "
656
+ f"found in target_patterns."
657
+ )
658
+ # Use the unique capturing group from target_patterns for all sources
659
+ pattern = pattern.replace(r"\1", unique_capturing_group, 1)
660
+ # Potentially process a bit more for consistency - only if they are consistent pairs, i.e. the length is the same
661
+ if len(self.source_patterns) == len(self.target_patterns):
662
+ pattern = process_source_pattern(pattern, self._original_target_patterns[i])
663
+ self.source_patterns[i] = pattern
664
+
665
+ # Construct the regex we will use to rename keys from the sources to the targets
666
+ branches = []
667
+ for i, source_pattern in enumerate(self.source_patterns):
668
+ group_name = f"g{i}"
669
+ pattern = source_pattern.replace(".*.", r"\..*\.")
670
+ branches.append(f"(?P<{group_name}>{pattern})")
671
+ self.compiled_sources = re.compile("|".join(branches))
672
+
673
+ def __repr__(self):
674
+ return f"{self.__class__.__name__}(source_patterns={self.source_patterns}, target_patterns={self.target_patterns})"
675
+
676
+ def __setattr__(self, name, value):
677
+ if name in ("source_patterns", "target_patterns"):
678
+ # We do not allow to re-set the patterns, as they are linked between each other and changing one
679
+ # without the other can mess-up with the capturing groups/compiled sources
680
+ if hasattr(self, name):
681
+ raise ValueError(f"Cannot assign to field {name}, you should create a new instance")
682
+ # Switch str to list
683
+ elif isinstance(value, str):
684
+ value = [value]
685
+ object.__setattr__(self, name, value)
686
+
687
+ def add_tensor(self, target_key: str, source_key: str, source_pattern: str, future: Future):
688
+ self.collected_tensors[source_pattern].append(future)
689
+ self.layer_targets[target_key].add(source_key)
690
+
691
+ def _scoped_match(self, source_key: str) -> tuple[str | None, str, re.Match[str]] | None:
692
+ """
693
+ Apply `scope_prefix` stripping (if any), then match `compiled_sources` against the suffix.
694
+
695
+ Returns `(prefix_dot, key_to_match, match_object)` when a branch matches, where `prefix_dot` is `None`
696
+ if `scope_prefix` is unset, else `f"{scope_prefix}."`. Returns `None` when out of scope or unmatched.
697
+ """
698
+ prefix_dot = None
699
+ key_to_match = source_key
700
+ if self.scope_prefix is not None:
701
+ prefix_dot = self.scope_prefix + "."
702
+ if not source_key.startswith(prefix_dot):
703
+ return None
704
+ key_to_match = source_key[len(prefix_dot) :]
705
+
706
+ match_object = self.compiled_sources.search(key_to_match)
707
+ if match_object is None:
708
+ return None
709
+ return (prefix_dot, key_to_match, match_object)
710
+
711
+ def rename_source_key(self, source_key: str) -> tuple[str, str | None]:
712
+ """
713
+ Return a tuple (renamed_key, source_pattern_producing_the_match).
714
+ Try renaming `source_key` according to the source and target patterns of the current WeightTransform.
715
+ In case of a one-to-many transform, i.e. we have several target patterns, the matching source pattern
716
+ will be replaced by the first of all the target patterns (they are then correctly expanded in the Operations).
717
+ """
718
+ matched = self._scoped_match(source_key)
719
+ if matched is None:
720
+ return source_key, None
721
+
722
+ prefix_dot, key_to_match, match_object = matched
723
+
724
+ # We have a match, so the Transform was used
725
+ self._was_used = True
726
+
727
+ # Find the source that produced the match (it's the first group that matched, as the search stops after first branch match)
728
+ matching_group_name = next(name for name, val in match_object.groupdict().items() if val is not None)
729
+ source_pattern_that_matched = self.source_patterns[int(matching_group_name[1:])]
730
+ # If we matched, we always replace with the first target pattern, in case we have several (one to many transform)
731
+ replacement = self.target_patterns[0]
732
+ # Allow capturing groups in patterns, i.e. to add a prefix to all keys (e.g. timm_wrapper, sam3).
733
+ # Backreferences `\1..\9` in the target are substituted from the matched source pattern's
734
+ # inner capturing groups, indexed off the matched named group so they stay correct under the
735
+ # `(?P<g0>...)|(?P<g1>...)|...` alternation `compiled_sources` builds.
736
+ if re.search(r"\\\d", replacement):
737
+ group_start = self.compiled_sources.groupindex[matching_group_name]
738
+ replacement = re.sub(
739
+ r"\\(\d+)",
740
+ lambda m: match_object.group(group_start + int(m.group(1))),
741
+ replacement,
742
+ )
743
+ renamed_key = key_to_match.replace(match_object.group(0), replacement, 1)
744
+ if prefix_dot is not None:
745
+ renamed_key = prefix_dot + renamed_key
746
+ return renamed_key, source_pattern_that_matched
747
+
748
+ def reverse_transform(self) -> WeightTransform:
749
+ """Reverse the current `WeightTransform` instance, to be able to save with the opposite weight transformations."""
750
+ # TODO: check this and relax when quantizer have `reverse_op`
751
+ if self.quantization_operation is not None:
752
+ raise ValueError("Cannot reverse the transform with TP or quantization")
753
+
754
+ kwargs = {}
755
+ # Add the reverse ops if applicable (it needs to be provided at __init__)
756
+ if hasattr(self, "operations"):
757
+ # All reverse ops, in reverse order
758
+ kwargs["operations"] = [op.reverse_op for op in self.operations[::-1]]
759
+
760
+ reverse_transform = self.__class__(
761
+ source_patterns=self._original_target_patterns, target_patterns=self._original_source_patterns, **kwargs
762
+ )
763
+ reverse_transform.scope_prefix = self.scope_prefix
764
+ return reverse_transform
765
+
766
+ def materialize_tensors(self) -> dict[str, list[torch.Tensor]]:
767
+ """
768
+ Materialize all the tensors that were saved in `self.collected_tensors`. This function removes them from the
769
+ internal attribute to avoid keeping them in memory during the different `self.convert` operations, and return
770
+ a new dictionary (otherwise we use more memory than needed during loading).
771
+
772
+ We basically have 3 cases here:
773
+ - async loading (default): the tensors are Future instances that we need to wait for
774
+ - sync loading: the tensors are Callable, we need to call the Callable to actually load them from disk
775
+ - saving: the tensors are already torch.Tensor instances (the existing model weights)
776
+ """
777
+ collected_tensors = {}
778
+ for key in list(self.collected_tensors.keys()):
779
+ # Remove from internal attribute
780
+ tensors = self.collected_tensors.pop(key)
781
+ # Async loading
782
+ if isinstance(tensors[0], Future):
783
+ tensors = [future.result() for future in tensors if future.result() is not None]
784
+ # Sync loading
785
+ elif callable(tensors[0]):
786
+ tensors = [func() for func in tensors]
787
+ # Add them to the new dictionary
788
+ collected_tensors[key] = tensors
789
+
790
+ return collected_tensors
791
+
792
+ def was_used(self) -> bool:
793
+ """
794
+ Return whether the current Transform matched any weights during loading/saving. This is needed as some
795
+ weight renaming transforms are not bijective, i.e. if we drop/add full parts of a name with PrefixChange, we
796
+ lose some informations that we cannot get back if we don't know if the Transform was used before already (say we
797
+ have a prefix to drop, we need to know whether the checkpoints we loaded before contained the said prefix or not
798
+ before adding it back, or not, during saving).
799
+ """
800
+ return self._was_used
801
+
802
+
803
+ class WeightRenaming(WeightTransform):
804
+ # Special case of WeightTransform that only renames keys without any conversion.
805
+
806
+ # Needs to be empty, otherwise the class will not be slotted
807
+ __slots__ = ()
808
+
809
+ def convert(
810
+ self,
811
+ layer_name: str,
812
+ model=None,
813
+ config=None,
814
+ hf_quantizer=None,
815
+ loading_info: LoadStateDictInfo | None = None,
816
+ ):
817
+ # Collect the tensors here - we use a new dictionary to avoid keeping them in memory in the internal
818
+ # attribute during the whole process
819
+ collected_tensors = self.materialize_tensors()
820
+
821
+ # Perform renaming op (for a simple WeightRenaming, `self.source_patterns` and `self.target_patterns` can
822
+ # only be of length 1, and are actually the full key names - we also have only 1 single related tensor)
823
+ target_key = self.target_patterns[0]
824
+ collected_tensors = {target_key: collected_tensors[self.source_patterns[0]]}
825
+
826
+ if hf_quantizer is not None and self.quantization_operation is not None:
827
+ with log_conversion_errors(
828
+ layer_name, loading_info, (len(collected_tensors), layer_name), self.quantization_operation
829
+ ):
830
+ collected_tensors = self.quantization_operation.convert(
831
+ collected_tensors,
832
+ source_patterns=self.source_patterns,
833
+ target_patterns=self.target_patterns,
834
+ full_layer_name=target_key,
835
+ model=model,
836
+ config=config,
837
+ missing_keys=loading_info.missing_keys if loading_info else None,
838
+ )
839
+
840
+ return collected_tensors
841
+
842
+
843
+ class PrefixChange(WeightRenaming):
844
+ """
845
+ Special case of WeightRenaming, used to simplify adding/removing full parts of a weight name. The regexes
846
+ that are needed for such operations are complex, so this is a much easier API for such cases.
847
+ """
848
+
849
+ __slots__ = (
850
+ "prefix_to_add",
851
+ "prefix_to_remove",
852
+ "model_prefix",
853
+ )
854
+
855
+ def __init__(
856
+ self, prefix_to_add: str | None = None, prefix_to_remove: str | None = None, model_prefix: str | None = None
857
+ ):
858
+ if (prefix_to_add is None) ^ (prefix_to_remove is not None):
859
+ raise ValueError("You must provide only one of `prefix_to_add` and `prefix_to_remove`")
860
+
861
+ self.prefix_to_add = prefix_to_add
862
+ self.prefix_to_remove = prefix_to_remove
863
+ self.model_prefix = "" if model_prefix is None else model_prefix
864
+ prefix = rf"{self.model_prefix}\." if self.model_prefix != "" else ""
865
+
866
+ if prefix_to_add is not None:
867
+ super().__init__(
868
+ # We use a lookbehind to avoid adding the prefix if we detect that it's already present
869
+ source_patterns=rf"^{prefix}(?:(?!{prefix_to_add}\.))(.+)$",
870
+ target_patterns=rf"{prefix}{prefix_to_add}\.\1",
871
+ )
872
+ else:
873
+ super().__init__(source_patterns=rf"^{prefix}{prefix_to_remove}\.(.+)$", target_patterns=rf"{prefix}\1")
874
+
875
+ def reverse_transform(self) -> WeightTransform:
876
+ """Reverse the current `WeightTransform` instance, to be able to save with the opposite weight transformations."""
877
+ # TODO: check this and relax when quantizer have `reverse_op`
878
+ if self.quantization_operation is not None:
879
+ raise ValueError("Cannot reverse the transform with TP or quantization")
880
+
881
+ # Only one of the 2 can ever be used, so 1 is always None
882
+ result = PrefixChange(
883
+ prefix_to_add=self.prefix_to_remove, prefix_to_remove=self.prefix_to_add, model_prefix=self.model_prefix
884
+ )
885
+ result.scope_prefix = self.scope_prefix
886
+ return result
887
+
888
+
889
+ # List of classes that are known to be able to use m:n
890
+ _INTERNAL_MANY_TO_MANY_CONVERSIONS = (
891
+ ErnieFuseAndSplitTextVisionExperts,
892
+ ErnieSplitAndDecoupleTextVisionExperts,
893
+ )
894
+
895
+
896
+ class WeightConverter(WeightTransform):
897
+ __slots__ = ("operations",)
898
+
899
+ def __init__(
900
+ self, source_patterns: str | list[str], target_patterns: str | list[str], operations: list[ConversionOps]
901
+ ):
902
+ super().__init__(source_patterns, target_patterns)
903
+ self.operations: list[ConversionOps] = operations
904
+
905
+ if bool(len(self.source_patterns) - 1) + bool(len(self.target_patterns) - 1) >= 2:
906
+ # We allow many-to-many only if we use an internal operation that can handle it
907
+ if not any(isinstance(op, _INTERNAL_MANY_TO_MANY_CONVERSIONS) for op in self.operations):
908
+ raise ValueError(
909
+ f"source keys={self.source_patterns}, target_patterns={self.target_patterns} but you can only have one to many, one to one or many to one."
910
+ )
911
+ if not self.operations:
912
+ raise ValueError("WeightConverter requires at least one operation.")
913
+
914
+ def convert(
915
+ self,
916
+ layer_name: str,
917
+ model=None,
918
+ config=None,
919
+ hf_quantizer=None,
920
+ loading_info: LoadStateDictInfo | None = None,
921
+ ):
922
+ # Collect the tensors here - we use a new dictionary to avoid keeping them in memory in the internal
923
+ # attribute during the whole process
924
+ collected_tensors = self.materialize_tensors()
925
+
926
+ for op in self.operations:
927
+ with log_conversion_errors(layer_name, loading_info, (len(collected_tensors), layer_name), op):
928
+ collected_tensors = op.convert(
929
+ collected_tensors,
930
+ source_patterns=self.source_patterns,
931
+ target_patterns=self.target_patterns,
932
+ # Additional kwargs, usually not used
933
+ full_layer_name=layer_name,
934
+ model=model,
935
+ config=config,
936
+ missing_keys=loading_info.missing_keys if loading_info else None,
937
+ )
938
+
939
+ # Tensors are returned from ops with the target patterns, we need to expand them to full name.
940
+ # This means we need to grab the prefix and suffix to add to every target key
941
+ full_name = layer_name
942
+ if ".*." in layer_name:
943
+ full_name = layer_name.replace(".*.", ".0.")
944
+
945
+ try:
946
+ prefix, _, suffix = next(full_name.partition(k) for k in collected_tensors.keys() if k in full_name)
947
+ # Rename the tensors
948
+ collected_tensors = {prefix + k + suffix: v for k, v in collected_tensors.items()}
949
+ # some quantizers need to already rename in `convert` as they cannot only rely on prefix and suffix
950
+ except StopIteration:
951
+ pass
952
+
953
+ if hf_quantizer is not None and self.quantization_operation is not None:
954
+ with log_conversion_errors(
955
+ layer_name, loading_info, (len(collected_tensors), layer_name), self.quantization_operation
956
+ ):
957
+ collected_tensors = self.quantization_operation.convert(
958
+ collected_tensors,
959
+ source_patterns=self.source_patterns,
960
+ target_patterns=self.target_patterns,
961
+ full_layer_name=layer_name,
962
+ config=config,
963
+ model=model,
964
+ missing_keys=loading_info.missing_keys if loading_info else None,
965
+ )
966
+ return collected_tensors
967
+
968
+
969
+ # For I/O bound operations (i.e. here reading files), it is better to have fewer threads, e.g. 4 is a good default.
970
+ # Having too many is actually harming performances quite a lot, i.e. using 16 can sometimes lead to taking TWICE
971
+ # as much time to load the same model
972
+ GLOBAL_WORKERS = min(4, os.cpu_count() or 4)
973
+
974
+
975
+ def _materialize_copy(tensor: torch.Tensor, device=None, dtype=None) -> torch.Tensor:
976
+ # This slicing is what actually loads the tensor from the safetensors slice object
977
+ tensor = tensor[...]
978
+ if dtype is not None or device is not None:
979
+ tensor = tensor.to(device=device, dtype=dtype)
980
+ return tensor
981
+
982
+
983
+ def spawn_materialize(
984
+ thread_pool: ThreadPoolExecutor | None,
985
+ tensor: torch.Tensor,
986
+ device=None,
987
+ dtype=None,
988
+ ) -> Future | Callable:
989
+ """Materialize a tensor from file asynchronously if `thread_pool` is provided, or return a Callable that will
990
+ load the tensor synchronously when called."""
991
+
992
+ def _job():
993
+ return _materialize_copy(tensor, device, dtype)
994
+
995
+ if thread_pool is not None:
996
+ return thread_pool.submit(_job)
997
+ else:
998
+ # Return the Callable here, not the Tensor itself, so we actually delay loading to avoid saturating cpu
999
+ # memory during Conversion
1000
+ return _job
1001
+
1002
+
1003
+ def spawn_tp_materialize(
1004
+ thread_pool: ThreadPoolExecutor | None, tensor: torch.Tensor, sharding_method, tensor_idx, device=None, dtype=None
1005
+ ) -> Future | Callable:
1006
+ """Materialize and shard a tensor (according to the TP-plan) from file asynchronously if `thread_pool` is provided, or
1007
+ return a Callable that will load the tensor synchronously when called."""
1008
+
1009
+ def _job():
1010
+ return sharding_method.shard_tensor(tensor, tensor_idx=tensor_idx, device=device, dtype=dtype)
1011
+
1012
+ if thread_pool is not None:
1013
+ return thread_pool.submit(_job)
1014
+ else:
1015
+ # Return the Callable here, not the Tensor itself, so we actually delay loading to avoid saturating cpu
1016
+ # memory during Conversion
1017
+ return _job
1018
+
1019
+
1020
+ def dot_natural_key(s: str):
1021
+ """Sort key for state-dict names: split on `"."` and sort digits numerically
1022
+ and strings alphabetically. We emit a tuple at each point to sort ints
1023
+ first and strings second to avoid int-string comparison failures.
1024
+ """
1025
+ parts = []
1026
+ for part in s.split("."):
1027
+ if part.isdigit():
1028
+ parts.append((0, int(part)))
1029
+ else:
1030
+ parts.append((1, part))
1031
+ return parts
1032
+
1033
+
1034
+ @contextmanager
1035
+ def log_conversion_errors(
1036
+ first_target_key: str,
1037
+ loading_info: LoadStateDictInfo | None,
1038
+ extras: Any = None,
1039
+ op: list[ConversionOps] | ConversionOps | None = None,
1040
+ ):
1041
+ """Catch all exceptions during `convert` calls, and log the errors for later. Re-raise a `SkipParameters` exception
1042
+ that will be caught later to skip the parameters that raised the original Exception."""
1043
+ try:
1044
+ yield
1045
+ except Exception as e:
1046
+ # During reverse mapping, we do not log and skip errors
1047
+ if loading_info is None:
1048
+ raise e
1049
+
1050
+ def _format_op_name(curr_op: list[ConversionOps] | ConversionOps | None) -> str | None:
1051
+ if curr_op is None:
1052
+ return None
1053
+ if isinstance(curr_op, (list, tuple, set)):
1054
+ names = [o.__class__.__name__ for o in curr_op if o is not None]
1055
+ if not names:
1056
+ return None
1057
+ return ", ".join(names)
1058
+ return curr_op.__class__.__name__
1059
+
1060
+ op_name = _format_op_name(op)
1061
+
1062
+ tb_str = "".join(traceback.format_exception(type(e), e, e.__traceback__))
1063
+ if isinstance(extras, tuple) and len(extras) == 2:
1064
+ length, target_keys = extras
1065
+ descriptor = f"{op_name} " if op_name else ""
1066
+ loading_info.conversion_errors[first_target_key] = (
1067
+ f"{tb_str}{e}\nError: {descriptor}on tensors destined for {target_keys}. Ckpt contains: {length}"
1068
+ )
1069
+ elif isinstance(extras, str):
1070
+ suffix = f" via {op_name}" if op_name else ""
1071
+ loading_info.conversion_errors[first_target_key] = (
1072
+ f"{tb_str}{e}\nError{suffix} when processing parameter {extras}"
1073
+ )
1074
+ elif extras is None and op_name:
1075
+ loading_info.conversion_errors[first_target_key] = f"{op_name}: {e}"
1076
+ else:
1077
+ loading_info.conversion_errors[first_target_key] = f"{extras} |Error: {e}"
1078
+
1079
+ # Raise a specific Exception that we can catch easily
1080
+ raise SkipParameters()
1081
+
1082
+
1083
+ def set_param_for_module(
1084
+ model: PreTrainedModel,
1085
+ target_name: str,
1086
+ param_value: torch.Tensor,
1087
+ loading_info: LoadStateDictInfo,
1088
+ distributed_operation: TensorParallelLayer | None,
1089
+ hf_quantizer: HfQuantizer,
1090
+ ):
1091
+ module_path, _, param_name = target_name.rpartition(".")
1092
+ module_obj = model.get_submodule(module_path) if module_path else model
1093
+
1094
+ if param_name == torch.nn.modules.module._EXTRA_STATE_KEY_SUFFIX:
1095
+ module_obj.set_extra_state(param_value)
1096
+ loading_info.missing_keys.discard(target_name)
1097
+ return
1098
+
1099
+ ref = getattr(module_obj, param_name)
1100
+ if ref is None:
1101
+ loading_info.unexpected_keys.add(target_name)
1102
+ else:
1103
+ if not isinstance(param_value, torch.nn.Parameter):
1104
+ if param_name not in module_obj._buffers:
1105
+ param_value = torch.nn.Parameter(param_value, requires_grad=param_value.is_floating_point())
1106
+
1107
+ # Remove from missing keys (it's either mismatched, or all good)
1108
+ loading_info.missing_keys.discard(target_name)
1109
+
1110
+ # Determine expected shape: for TP, use sharded shape; otherwise, use full shape
1111
+ if distributed_operation is not None:
1112
+ expected_shape = torch.Size(distributed_operation.get_expected_sharded_shape(ref.shape))
1113
+ else:
1114
+ expected_shape = ref.shape
1115
+
1116
+ if ref is not None and param_value.shape != expected_shape and hf_quantizer is None:
1117
+ loading_info.mismatched_keys.add((target_name, param_value.shape, expected_shape))
1118
+ else:
1119
+ # super important otherwise _init_weight will re-init the param
1120
+ param_value._is_hf_initialized = True
1121
+ setattr(module_obj, param_name, param_value)
1122
+ if distributed_operation is not None:
1123
+ distributed_operation.update_module_attributes(module_obj)
1124
+
1125
+
1126
+ def offload_and_maybe_resave_param(
1127
+ target_name: str,
1128
+ param: torch.Tensor,
1129
+ loading_info: LoadStateDictInfo,
1130
+ disk_offload_folder: str,
1131
+ disk_offload_index: dict,
1132
+ applied_ops: WeightConverter | WeightRenaming,
1133
+ ) -> dict:
1134
+ """Takes care of correctly offloading `param`. If it's not already present in the `disk_offload_index`, or if any
1135
+ WeightConverter operations have been applied, it will resave the new parameter. Otherwise, it will use the original
1136
+ `disk_offload_index` for this given param."""
1137
+ # We need to remove from missing keys
1138
+ loading_info.missing_keys.discard(target_name)
1139
+ # If not already offloaded, or if we applied any special Operation except Renaming, we need to re-save
1140
+ if target_name not in disk_offload_index or isinstance(applied_ops, WeightConverter):
1141
+ disk_offload_index = offload_weight(param, target_name, disk_offload_folder, disk_offload_index)
1142
+ return disk_offload_index
1143
+
1144
+
1145
+ class SkipParameters(Exception):
1146
+ """Control-flow sentinel: abort processing of the current parameters only (that were supposed to be created
1147
+ by a WeightConverter)."""
1148
+
1149
+ pass
1150
+
1151
+
1152
+ def rename_source_key(
1153
+ source_key: str,
1154
+ weight_renamings: list[WeightRenaming],
1155
+ weight_converters: list[WeightConverter],
1156
+ prefix: str | None = None,
1157
+ meta_state_dict: dict | None = None,
1158
+ ) -> tuple[str, str | None]:
1159
+ """
1160
+ Rename a checkpoint key by first applying all `WeightRenaming`s, then at most one `WeightConverter`.
1161
+
1162
+ A renaming and a converter may act on the same key in that order: the renaming normalises the
1163
+ key into the namespace the converter expects. The reverse holds on the save path (converter
1164
+ first, then renaming). There is no need for a converter-then-rename order because converters
1165
+ act only on specific leaf patterns; no subsequent renamings should ever target their output.
1166
+
1167
+ Args:
1168
+ source_key (`str`):
1169
+ The original checkpoint key to rename.
1170
+ weight_renamings (`list[WeightRenaming]`):
1171
+ Applied in order; every matching renaming fires (they may chain).
1172
+ weight_converters (`list[WeightConverter]`):
1173
+ Applied after all renamings; at most one may match. Subsequent converters are skipped.
1174
+ prefix (`str`, *optional*):
1175
+ Base-model prefix to add or strip when both `prefix` and `meta_state_dict` are given.
1176
+ meta_state_dict (`dict`, *optional*):
1177
+ Meta state dict used to decide whether `prefix` should be added or stripped.
1178
+
1179
+ Returns:
1180
+ `tuple[str, str | None]`: The renamed key and the matched converter's source pattern
1181
+ (or `None` if no converter matched).
1182
+ """
1183
+ renamed_key = source_key
1184
+ # 1. apply all renamings in turns (if multiple match, it's the responsibility of the mappings to make sure they
1185
+ # are coherent)
1186
+ for renaming in weight_renamings:
1187
+ renamed_key, _ = renaming.rename_source_key(renamed_key)
1188
+
1189
+ # 2. apply renaming through weight conversions on the key if we have any WeightConverter (here we stop after
1190
+ # the first match, as we assume only 1 converter can match any source key)
1191
+ source_pattern = None
1192
+ for converter in weight_converters:
1193
+ renamed_key, source_pattern = converter.rename_source_key(renamed_key)
1194
+ if source_pattern is not None:
1195
+ break
1196
+
1197
+ # 3. check if we need to add or remove prefix if necessary (only during loading, not saving)
1198
+ if prefix is not None and meta_state_dict is not None:
1199
+ if (
1200
+ renamed_key.startswith(prefix)
1201
+ and meta_state_dict.get(re.sub(f"^{prefix}.", "", renamed_key, count=1)) is not None
1202
+ ):
1203
+ renamed_key = re.sub(f"^{prefix}.", "", renamed_key, count=1)
1204
+ elif meta_state_dict.get(f"{prefix}.{renamed_key}") is not None:
1205
+ renamed_key = f"{prefix}.{renamed_key}"
1206
+
1207
+ return renamed_key, source_pattern
1208
+
1209
+
1210
+ def convert_and_load_state_dict_in_model(
1211
+ model: PreTrainedModel,
1212
+ state_dict: dict[str, Any],
1213
+ load_config: LoadStateDictConfig,
1214
+ tp_plan: dict[str, str] | None,
1215
+ disk_offload_index: dict | None = None,
1216
+ ):
1217
+ r"""
1218
+ We build a mapping from the keys obtained by renaming each of the checkpoint keys according to the weight_mapping rules.
1219
+ Then we load the tensors into the model, applying any conversion operations as needed.
1220
+
1221
+ The `param_name_to_load` will look like this:
1222
+ {
1223
+ "model.layers.0.attention.q.weight": # Notice here there is only the first key of the target keys
1224
+ WeightConverter(
1225
+ source_patterns=["qkv"],
1226
+ target_patterns=["q", "k","v"],
1227
+ operations=[Chunk(dim=0, chunks=3)]),
1228
+ collected_tensors={
1229
+ "qkv": [Future]},
1230
+ layer_targets={
1231
+ "model.layers.0.attention.q.weight": {"model.layers.0.attention.qkv.weight"},
1232
+ "model.layers.0.attention.k.weight": {"model.layers.0.attention.qkv.weight"},
1233
+ "model.layers.0.attention.v.weight": {"model.layers.0.attention.qkv.weight"},
1234
+ }
1235
+ ),
1236
+ ...
1237
+ }
1238
+
1239
+ We make sure that the keys are the full keys. The only "nit" here is that 1 key can map to multiple target keys (e.g. qkv -> q, k, v).
1240
+ In that case the weight converter will take care of doing the appropriate renaming.
1241
+
1242
+ For example for:
1243
+ ```python
1244
+ WeightConverter(
1245
+ source_patterns=["mlp.experts.*.gate_proj.weight","mlp.experts.*.up_proj.weight"],
1246
+ target_patterns="mlp.experts.gate_up_proj",
1247
+ operations=[MergeModulelist(dim=0), Concatenate(dim=1)],
1248
+ )
1249
+ ```
1250
+ we would have the following collected tensors:
1251
+ ```python
1252
+ collected_tensors = {
1253
+ "mlp.experts.*.gate_proj.weight": [Future, Future, Future, Future, Future, Future, Future, Future],
1254
+ "mlp.experts.*.up_proj.weight": [Future, Future, Future, Future, Future, Future, Future, Future],
1255
+ }
1256
+ ```
1257
+ The first op, `MergeModulelist`, would stack the 8 tensors of each source but will not "rename" them into the fused target name.
1258
+ The second op, `Concatenate`, would then rename the fused tensor into the final target name.
1259
+
1260
+ If we want to split `qkv` we would have:
1261
+ ```python
1262
+ collected_tensors = {
1263
+ "attention.qkv.weight": [Future], # here its the full SOURCE keys.
1264
+ }
1265
+ ```
1266
+ The `Chunk` operation would then split the single tensor into 3 and rename them accordingly and update the collected tensors to:
1267
+ ```python
1268
+ realized_values = {
1269
+ "attention.q.weight": [Tensor],
1270
+ "attention.k.weight": [Tensor],
1271
+ "attention.v.weight": [Tensor],
1272
+ }
1273
+ ```
1274
+
1275
+ Now that this is done, we can quantize / dequantize accordingly the collected_tensors.
1276
+
1277
+ For some quantization methods, we need to gather different tensors:
1278
+
1279
+ ```python
1280
+ # for "medmekk/llama-3.2-1b-float8-torchao"
1281
+ WeightConverter(
1282
+ source_patterns=[":qdata", ":scale"],
1283
+ target_patterns="",
1284
+ operations=[TorchaoDeserialize()],
1285
+ )
1286
+ ```
1287
+ This will collect all tensors that have the same prefix, but end with `:qdata` or `:scale`. This will give us:
1288
+ ```python
1289
+ all_weight_mapping = {
1290
+ "model.layers.13.self_attn.o_proj.weight": WeightConverter(
1291
+ source_patterns=[":qdata", ":scale"],
1292
+ target_patterns="",
1293
+ operations=[TorchaoDeserialize()],
1294
+ collected_tensors={
1295
+ ":qdata": [Future],
1296
+ ":scale": [Future],
1297
+ },
1298
+ ...
1299
+ }
1300
+ ```
1301
+
1302
+ """
1303
+ prefix = model.base_model_prefix
1304
+ tp_plan = tp_plan or {}
1305
+ device_map = load_config.device_map or {"": "cpu"}
1306
+ hf_quantizer = load_config.hf_quantizer
1307
+ dtype = load_config.dtype
1308
+ device_mesh = load_config.device_mesh
1309
+ disk_offload_folder = load_config.disk_offload_folder
1310
+ offload_buffers = load_config.offload_buffers
1311
+ dtype_plan = load_config.dtype_plan or {}
1312
+ weight_mapping = load_config.weight_mapping or []
1313
+ meta_model_state_dict = model.state_dict()
1314
+ model_buffers = {k for k, _ in model.named_buffers()}
1315
+
1316
+ # We start from all missing keys, and we will remove/add them from the proper containers as loading advances
1317
+ loading_info = LoadStateDictInfo(
1318
+ missing_keys=set(meta_model_state_dict.keys()),
1319
+ unexpected_keys=set(),
1320
+ mismatched_keys=set(),
1321
+ conversion_errors={},
1322
+ error_msgs=[],
1323
+ )
1324
+
1325
+ # We use threading by default, if not explicitly deactivated via env variable. If we have to offload,
1326
+ # we cannot use it either to control the memory as we are under memory constraints, so we need to be sequential.
1327
+ # When doing on-the-fly quantization, we also use sync loading to avoid worker threads loading full-precision
1328
+ # tensors to GPU faster than the main thread can quantize them, which would cause a large memory spike.
1329
+ has_on_the_fly_quantization = hf_quantizer is not None and not hf_quantizer.pre_quantized
1330
+ if (
1331
+ is_env_variable_true("HF_DEACTIVATE_ASYNC_LOAD")
1332
+ or "disk" in device_map.values()
1333
+ or has_on_the_fly_quantization
1334
+ ):
1335
+ thread_pool = None
1336
+ else:
1337
+ thread_pool = ThreadPoolExecutor(max_workers=GLOBAL_WORKERS)
1338
+
1339
+ renamings = [entry for entry in weight_mapping if isinstance(entry, WeightRenaming)]
1340
+ converters = [entry for entry in weight_mapping if isinstance(entry, WeightConverter)]
1341
+ param_name_to_load: dict[str, WeightRenaming | WeightConverter] = {}
1342
+
1343
+ # build '(?P<g0>.*.*\\.block_sparse_moe\\..*)' and group to source {'g0': '*.block_sparse_moe.'}
1344
+ # and target to source {'g0': '*.mlp.'}. This allows us to quickly find which pattern matched.
1345
+ if tp_plan != {}:
1346
+ tp_plan_alt, tp_plan_by_group_name, _ = build_glob_alternation(list(tp_plan.keys()))
1347
+ if dtype_plan != {}:
1348
+ dtype_policy_alt, dtype_policy_by_group_name, _ = build_glob_alternation(list(dtype_plan.keys()))
1349
+
1350
+ pattern_to_converter = {k: converter for converter in converters for k in converter.source_patterns}
1351
+
1352
+ state_dict = sorted(state_dict.items(), key=lambda kv: dot_natural_key(kv[0]))
1353
+ for original_key, tensor in state_dict:
1354
+ # 1. Rename the key according to all renaming and weight conversion patterns.
1355
+ renamed_key, source_pattern = rename_source_key(
1356
+ original_key, renamings, converters, prefix=prefix, meta_state_dict=meta_model_state_dict
1357
+ )
1358
+ if renamed_key not in meta_model_state_dict and original_key in meta_model_state_dict:
1359
+ # Key should probably not have been renamed but we might need the `prefix` to be added.
1360
+ renamed_key, source_pattern = rename_source_key(
1361
+ original_key, [], [], prefix=prefix, meta_state_dict=meta_model_state_dict
1362
+ )
1363
+
1364
+ # 2. finally, collect the tensor into the proper converter
1365
+ if renamed_key in meta_model_state_dict:
1366
+ empty_param = meta_model_state_dict.get(renamed_key)
1367
+ # If we enter here, we have a WeightConverter operation to perform
1368
+ if source_pattern is not None:
1369
+ new_converter = deepcopy(pattern_to_converter[source_pattern])
1370
+ # each target key gets its own converter instance
1371
+ mapping = param_name_to_load.setdefault(renamed_key, new_converter)
1372
+ # Otherwise, only potential renaming
1373
+ else:
1374
+ mapping = param_name_to_load.setdefault(renamed_key, WeightRenaming(original_key, renamed_key))
1375
+ source_pattern = original_key
1376
+
1377
+ # 3. Handle dtype casting
1378
+ needs_quantization = (
1379
+ hf_quantizer
1380
+ and not hf_quantizer.pre_quantized
1381
+ and hf_quantizer.param_needs_quantization(model, renamed_key)
1382
+ )
1383
+ if needs_quantization:
1384
+ mapping.quantization_operation = hf_quantizer.get_quantize_ops()
1385
+
1386
+ _dtype = dtype
1387
+ if (
1388
+ hf_quantizer
1389
+ and hf_quantizer.pre_quantized
1390
+ and (
1391
+ original_key != renamed_key
1392
+ or not (
1393
+ tensor.get_dtype().startswith(("F", "BF"))
1394
+ if hasattr(tensor, "get_dtype")
1395
+ else tensor.is_floating_point()
1396
+ )
1397
+ )
1398
+ ):
1399
+ # if the key was renamed as it is not available in the state dict otherwise, it means that we are deserializing it,
1400
+ # so we need to make sure to load the tensor with the same dtype from the checkpoint
1401
+ # TODO: make the condition more srict for native fp8 model such as qwen2moe fp8
1402
+ _dtype = None
1403
+ elif dtype_plan != {} and dtype_policy_alt.search(renamed_key):
1404
+ matched_dtype_pattern = dtype_policy_alt.search(renamed_key)
1405
+ if matched_dtype_pattern is not None:
1406
+ _dtype = dtype_plan[dtype_policy_by_group_name[matched_dtype_pattern.lastgroup]]
1407
+ elif empty_param is not None and empty_param.dtype != _dtype:
1408
+ _dtype = empty_param.dtype # usually correct when initializing
1409
+
1410
+ # 4. Handle TP sharding or device_map placement
1411
+ future_or_tensor = None
1412
+ if device_mesh and tp_plan:
1413
+ if matched_tp_pattern := tp_plan_alt.search(renamed_key):
1414
+ matched_tp_pattern = tp_plan_by_group_name[matched_tp_pattern.lastgroup]
1415
+ if getattr(mapping, "distributed_operation", None) is None:
1416
+ tp_layer = ALL_PARALLEL_STYLES[model.tp_plan[matched_tp_pattern]].__class__
1417
+ mapping.distributed_operation = tp_layer(
1418
+ device_mesh=device_mesh, rank=device_mesh.get_local_rank(), empty_param=empty_param.clone()
1419
+ )
1420
+ shard_index = (
1421
+ len(mapping.collected_tensors.get(source_pattern, []))
1422
+ if isinstance(mapping, WeightConverter) and isinstance(mapping.operations[0], MergeModulelist)
1423
+ else None
1424
+ )
1425
+ future_or_tensor = spawn_tp_materialize(
1426
+ thread_pool,
1427
+ tensor,
1428
+ mapping.distributed_operation,
1429
+ shard_index,
1430
+ device_map[""],
1431
+ _dtype,
1432
+ )
1433
+
1434
+ if future_or_tensor is None:
1435
+ param_device = get_device(device_map, renamed_key, valid_torch_device=True)
1436
+ future_or_tensor = spawn_materialize(thread_pool, tensor, param_device, _dtype)
1437
+
1438
+ mapping.add_tensor(renamed_key, original_key, source_pattern, future_or_tensor)
1439
+ elif source_pattern is not None: # add all target keys as unexpected
1440
+ mapping = pattern_to_converter[source_pattern]
1441
+ for k in mapping.target_patterns:
1442
+ loading_info.unexpected_keys.add(renamed_key.replace(mapping.target_patterns[0], k))
1443
+ else:
1444
+ loading_info.unexpected_keys.add(renamed_key)
1445
+
1446
+ try:
1447
+ for first_param_name, mapping in tqdm(param_name_to_load.items(), desc="Loading weights"):
1448
+ try:
1449
+ realized_value = mapping.convert(
1450
+ first_param_name,
1451
+ model=model,
1452
+ config=model.config,
1453
+ hf_quantizer=hf_quantizer,
1454
+ loading_info=loading_info,
1455
+ )
1456
+ for target_name, param in realized_value.items():
1457
+ param = param[0] if isinstance(param, list) else param
1458
+ param_device = get_device(device_map, target_name)
1459
+ # Offloading support
1460
+ if param_device == "disk" and (target_name not in model_buffers or offload_buffers):
1461
+ disk_offload_index = offload_and_maybe_resave_param(
1462
+ target_name, param, loading_info, disk_offload_folder, disk_offload_index, mapping
1463
+ )
1464
+ else:
1465
+ set_param_for_module(
1466
+ model,
1467
+ target_name,
1468
+ param,
1469
+ loading_info,
1470
+ mapping.distributed_operation,
1471
+ hf_quantizer,
1472
+ )
1473
+
1474
+ # Cleanup all the tensors that were gathered before next iteration
1475
+ del realized_value
1476
+
1477
+ except SkipParameters:
1478
+ continue
1479
+
1480
+ # Close the pool, independently of whether the code was interrupted or finished successfully
1481
+ finally:
1482
+ if thread_pool is not None:
1483
+ # `cancel_futures=True` in case the program was interrupted, to avoid wasting time on exit
1484
+ thread_pool.shutdown(wait=False, cancel_futures=True)
1485
+
1486
+ # Keep the current weight conversion mapping for later saving (in case it was coming directly from the user), but
1487
+ # only if it was used, i.e. it matched any weight from the checkpoints
1488
+ model_specific_conversions = [conversion for conversion in weight_mapping if conversion.was_used()]
1489
+ model._weight_conversions = model_specific_conversions
1490
+
1491
+ return loading_info, disk_offload_index
1492
+
1493
+
1494
+ def revert_weight_conversion(model: PreTrainedModel, state_dict: dict[str, torch.Tensor]):
1495
+ """
1496
+ Revert the conversion mapping that was used to load the model with `from_pretrained`, or the default one
1497
+ if the model was created in another way and is part of the default mappings.
1498
+ """
1499
+ weight_conversions = getattr(model, "_weight_conversions", None)
1500
+ # In this case, the model was not created with `from_pretrained` -> let's check if it's in the hardcoded
1501
+ # mappings, and recreate the mapping from there if it is
1502
+ if weight_conversions is None:
1503
+ from .conversion_mapping import get_model_conversion_mapping
1504
+
1505
+ # Do not resave with the legacy renaming, if present
1506
+ weight_conversions = get_model_conversion_mapping(model, add_legacy=False)
1507
+ # If the model had no `_weight_conversions` attached, drop any PrefixChange transform - this is because the
1508
+ # model was almost surely instantiated from scratch (at least not from `from_pretrained`), and PrefixChange with
1509
+ # `prefix_to_remove` would otherwise add a unwanted prefix (as we dont have any information about whether the prefix
1510
+ # was there or not during load)
1511
+ weight_conversions = [x for x in weight_conversions if not isinstance(x, PrefixChange)]
1512
+ weight_conversions = weight_conversions if len(weight_conversions) > 0 else None
1513
+
1514
+ # We did not find any operations to perform -> quick escape
1515
+ if weight_conversions is None:
1516
+ return state_dict
1517
+
1518
+ # Important: we need to revert the order here, so that potential conversions from submodels are performed first
1519
+ weight_conversions = weight_conversions[::-1]
1520
+
1521
+ # Two-phase save: first reverse converters, then reverse renamings. Relies on the rule that
1522
+ # WeightRenamings never operate on WeightConverter outputs (see WeightTransform docstring).
1523
+ inverted_transforms = [transform.reverse_transform() for transform in weight_conversions]
1524
+ inverted_converters = [transform for transform in inverted_transforms if isinstance(transform, WeightConverter)]
1525
+ inverted_renamings = [transform for transform in inverted_transforms if not isinstance(transform, WeightConverter)]
1526
+ pattern_to_converter = {
1527
+ pattern: converter for converter in inverted_converters for pattern in converter.source_patterns
1528
+ }
1529
+
1530
+ conversion_mapping: dict[str, WeightTransform] = {}
1531
+ state_dict = sorted(state_dict.items(), key=lambda kv: dot_natural_key(kv[0]))
1532
+ for original_key, tensor in state_dict:
1533
+ # `converter_key`: key after phase-1 (converter namespace, used as layer_name by convert()).
1534
+ # `checkpoint_key`: key after phase-2 (final saved name, layer_name for plain renamings).
1535
+ converter_key, matched_pattern = rename_source_key(original_key, [], inverted_converters)
1536
+ checkpoint_key, _ = rename_source_key(converter_key, inverted_renamings, [])
1537
+
1538
+ if matched_pattern is not None:
1539
+ # Bucket under converter_key so all sibling inputs land in the same converter instance.
1540
+ mapping = conversion_mapping.setdefault(converter_key, deepcopy(pattern_to_converter[matched_pattern]))
1541
+ else:
1542
+ mapping = conversion_mapping.setdefault(checkpoint_key, WeightRenaming(original_key, checkpoint_key))
1543
+ matched_pattern = original_key
1544
+
1545
+ mapping.add_tensor(checkpoint_key, original_key, matched_pattern, tensor)
1546
+
1547
+ new_state_dict = {}
1548
+ for layer_name, mapping in conversion_mapping.items():
1549
+ realized = mapping.convert(layer_name, model=model, config=model.config)
1550
+ for target_name, param in realized.items():
1551
+ param = param[0] if isinstance(param, list) else param
1552
+ if isinstance(mapping, WeightConverter):
1553
+ # Bring converter outputs from converter namespace into checkpoint namespace.
1554
+ target_name, _ = rename_source_key(target_name, inverted_renamings, [])
1555
+ new_state_dict[target_name] = param
1556
+
1557
+ return new_state_dict
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/debug_utils.py ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import collections
16
+
17
+ from .utils import ExplicitEnum, is_torch_available, logging
18
+
19
+
20
+ if is_torch_available():
21
+ import torch
22
+
23
+
24
+ logger = logging.get_logger(__name__)
25
+
26
+
27
+ class DebugUnderflowOverflow:
28
+ """
29
+ This debug class helps detect and understand where the model starts getting very large or very small, and more
30
+ importantly `nan` or `inf` weight and activation elements.
31
+
32
+ There are 2 working modes:
33
+
34
+ 1. Underflow/overflow detection (default)
35
+ 2. Specific batch absolute min/max tracing without detection
36
+
37
+ Mode 1: Underflow/overflow detection
38
+
39
+ To activate the underflow/overflow detection, initialize the object with the model :
40
+
41
+ ```python
42
+ debug_overflow = DebugUnderflowOverflow(model)
43
+ ```
44
+
45
+ then run the training as normal and if `nan` or `inf` gets detected in at least one of the weight, input or output
46
+ elements this module will throw an exception and will print `max_frames_to_save` frames that lead to this event,
47
+ each frame reporting
48
+
49
+ 1. the fully qualified module name plus the class name whose `forward` was run
50
+ 2. the absolute min and max value of all elements for each module weights, and the inputs and output
51
+
52
+ For example, here is the header and the last few frames in detection report for `google/mt5-small` run in fp16
53
+ mixed precision :
54
+
55
+ ```
56
+ Detected inf/nan during batch_number=0
57
+ Last 21 forward frames:
58
+ abs min abs max metadata
59
+ [...]
60
+ encoder.block.2.layer.1.DenseReluDense.wi_0 Linear
61
+ 2.17e-07 4.50e+00 weight
62
+ 1.79e-06 4.65e+00 input[0]
63
+ 2.68e-06 3.70e+01 output
64
+ encoder.block.2.layer.1.DenseReluDense.wi_1 Linear
65
+ 8.08e-07 2.66e+01 weight
66
+ 1.79e-06 4.65e+00 input[0]
67
+ 1.27e-04 2.37e+02 output
68
+ encoder.block.2.layer.1.DenseReluDense.wo Linear
69
+ 1.01e-06 6.44e+00 weight
70
+ 0.00e+00 9.74e+03 input[0]
71
+ 3.18e-04 6.27e+04 output
72
+ encoder.block.2.layer.1.DenseReluDense T5DenseGatedGeluDense
73
+ 1.79e-06 4.65e+00 input[0]
74
+ 3.18e-04 6.27e+04 output
75
+ encoder.block.2.layer.1.dropout Dropout
76
+ 3.18e-04 6.27e+04 input[0]
77
+ 0.00e+00 inf output
78
+ ```
79
+
80
+ You can see here, that `T5DenseGatedGeluDense.forward` resulted in output activations, whose absolute max value was
81
+ around 62.7K, which is very close to fp16's top limit of 64K. In the next frame we have `Dropout` which
82
+ renormalizes the weights, after it zeroed some of the elements, which pushes the absolute max value to more than
83
+ 64K, and we get an overflow.
84
+
85
+ As you can see it's the previous frames that we need to look into when the numbers start going into very large for
86
+ fp16 numbers.
87
+
88
+ The tracking is done in a forward hook, which gets invoked immediately after `forward` has completed.
89
+
90
+ By default the last 21 frames are printed. You can change the default to adjust for your needs. For example :
91
+
92
+ ```python
93
+ debug_overflow = DebugUnderflowOverflow(model, max_frames_to_save=100)
94
+ ```
95
+
96
+ To validate that you have set up this debugging feature correctly, and you intend to use it in a training that
97
+ may take hours to complete, first run it with normal tracing enabled for one of a few batches as explained in
98
+ the next section.
99
+
100
+
101
+ Mode 2. Specific batch absolute min/max tracing without detection
102
+
103
+ The second work mode is per-batch tracing with the underflow/overflow detection feature turned off.
104
+
105
+ Let's say you want to watch the absolute min and max values for all the ingredients of each `forward` call of a
106
+ given batch, and only do that for batches 1 and 3. Then you instantiate this class as :
107
+
108
+ ```python
109
+ debug_overflow = DebugUnderflowOverflow(model, trace_batch_nums=[1, 3])
110
+ ```
111
+
112
+ And now full batches 1 and 3 will be traced using the same format as explained above. Batches are 0-indexed.
113
+
114
+ This is helpful if you know that the program starts misbehaving after a certain batch number, so you can
115
+ fast-forward right to that area.
116
+
117
+
118
+ Early stopping:
119
+
120
+ You can also specify the batch number after which to stop the training, with :
121
+
122
+ ```python
123
+ debug_overflow = DebugUnderflowOverflow(model, trace_batch_nums=[1, 3], abort_after_batch_num=3)
124
+ ```
125
+
126
+ This feature is mainly useful in the tracing mode, but you can use it for any mode.
127
+
128
+
129
+ **Performance**:
130
+
131
+ As this module measures absolute `min`/``max` of each weight of the model on every forward it'll slow the training
132
+ down. Therefore remember to turn it off once the debugging needs have been met.
133
+
134
+ Args:
135
+ model (`nn.Module`):
136
+ The model to debug.
137
+ max_frames_to_save (`int`, *optional*, defaults to 21):
138
+ How many frames back to record
139
+ trace_batch_nums(`list[int]`, *optional*, defaults to `[]`):
140
+ Which batch numbers to trace (turns detection off)
141
+ abort_after_batch_num (`int``, *optional*):
142
+ Whether to abort after a certain batch number has finished
143
+ """
144
+
145
+ def __init__(self, model, max_frames_to_save=21, trace_batch_nums=None, abort_after_batch_num=None):
146
+ if trace_batch_nums is None:
147
+ trace_batch_nums = []
148
+ self.model = model
149
+ self.trace_batch_nums = trace_batch_nums
150
+ self.abort_after_batch_num = abort_after_batch_num
151
+
152
+ # keep a LIFO buffer of frames to dump as soon as inf/nan is encountered to give context to the problem emergence
153
+ self.frames = collections.deque([], max_frames_to_save)
154
+ self.frame = []
155
+ self.batch_number = 0
156
+ self.total_calls = 0
157
+ self.detected_overflow = False
158
+ self.prefix = " "
159
+
160
+ self.analyse_model()
161
+
162
+ self.register_forward_hook()
163
+
164
+ def save_frame(self, frame=None):
165
+ if frame is not None:
166
+ self.expand_frame(frame)
167
+ self.frames.append("\n".join(self.frame))
168
+ self.frame = [] # start a new frame
169
+
170
+ def expand_frame(self, line):
171
+ self.frame.append(line)
172
+
173
+ def trace_frames(self):
174
+ print("\n".join(self.frames))
175
+ self.frames = []
176
+
177
+ def reset_saved_frames(self):
178
+ self.frames = []
179
+
180
+ def dump_saved_frames(self):
181
+ print(f"\nDetected inf/nan during batch_number={self.batch_number}")
182
+ print(f"Last {len(self.frames)} forward frames:")
183
+ print(f"{'abs min':8} {'abs max':8} metadata")
184
+ print("\n".join(self.frames))
185
+ print("\n\n")
186
+ self.frames = []
187
+
188
+ def analyse_model(self):
189
+ # extract the fully qualified module names, to be able to report at run time. e.g.:
190
+ # encoder.block.2.layer.0.SelfAttention.o
191
+ #
192
+ # for shared weights only the first shared module name will be registered
193
+ self.module_names = {m: name for name, m in self.model.named_modules()}
194
+ # self.longest_module_name = max(len(v) for v in self.module_names.values())
195
+
196
+ def analyse_variable(self, var, ctx):
197
+ if torch.is_tensor(var):
198
+ self.expand_frame(get_abs_min_max(var, ctx))
199
+ if detect_overflow(var, ctx):
200
+ self.detected_overflow = True
201
+ elif var is None:
202
+ self.expand_frame(f"{'None':>17} {ctx}")
203
+ else:
204
+ self.expand_frame(f"{'not a tensor':>17} {ctx}")
205
+
206
+ def batch_start_frame(self):
207
+ self.expand_frame(f"\n\n{self.prefix} *** Starting batch number={self.batch_number} ***")
208
+ self.expand_frame(f"{'abs min':8} {'abs max':8} metadata")
209
+
210
+ def batch_end_frame(self):
211
+ self.expand_frame(f"{self.prefix} *** Finished batch number={self.batch_number - 1} ***\n\n")
212
+
213
+ def create_frame(self, module, input, output):
214
+ self.expand_frame(f"{self.prefix} {self.module_names[module]} {module.__class__.__name__}")
215
+
216
+ # params
217
+ for name, p in module.named_parameters(recurse=False):
218
+ self.analyse_variable(p, name)
219
+
220
+ # inputs
221
+ if isinstance(input, tuple):
222
+ for i, x in enumerate(input):
223
+ self.analyse_variable(x, f"input[{i}]")
224
+ else:
225
+ self.analyse_variable(input, "input")
226
+
227
+ # outputs
228
+ if isinstance(output, tuple):
229
+ for i, x in enumerate(output):
230
+ # possibly a tuple of tuples
231
+ if isinstance(x, tuple):
232
+ for j, y in enumerate(x):
233
+ self.analyse_variable(y, f"output[{i}][{j}]")
234
+ else:
235
+ self.analyse_variable(x, f"output[{i}]")
236
+ else:
237
+ self.analyse_variable(output, "output")
238
+
239
+ self.save_frame()
240
+
241
+ def register_forward_hook(self):
242
+ self.model.apply(self._register_forward_hook)
243
+
244
+ def _register_forward_hook(self, module):
245
+ module.register_forward_hook(self.forward_hook)
246
+
247
+ def forward_hook(self, module, input, output):
248
+ # - input is a tuple of packed inputs (could be non-Tensors)
249
+ # - output could be a Tensor or a tuple of Tensors and non-Tensors
250
+
251
+ last_frame_of_batch = False
252
+
253
+ trace_mode = self.batch_number in self.trace_batch_nums
254
+ if trace_mode:
255
+ self.reset_saved_frames()
256
+
257
+ if self.total_calls == 0:
258
+ self.batch_start_frame()
259
+ self.total_calls += 1
260
+
261
+ # count batch numbers - the very first forward hook of the batch will be called when the
262
+ # batch completes - i.e. it gets called very last - we know this batch has finished
263
+ if module == self.model:
264
+ self.batch_number += 1
265
+ last_frame_of_batch = True
266
+
267
+ self.create_frame(module, input, output)
268
+
269
+ # if last_frame_of_batch:
270
+ # self.batch_end_frame()
271
+
272
+ if trace_mode:
273
+ self.trace_frames()
274
+
275
+ if last_frame_of_batch:
276
+ self.batch_start_frame()
277
+
278
+ if self.detected_overflow and not trace_mode:
279
+ self.dump_saved_frames()
280
+
281
+ # now we can abort, as it's pointless to continue running
282
+ raise ValueError(
283
+ "DebugUnderflowOverflow: inf/nan detected, aborting as there is no point running further. "
284
+ "Please scroll up above this traceback to see the activation values prior to this event."
285
+ )
286
+
287
+ # abort after certain batch if requested to do so
288
+ if self.abort_after_batch_num is not None and self.batch_number > self.abort_after_batch_num:
289
+ raise ValueError(
290
+ f"DebugUnderflowOverflow: aborting after {self.batch_number} batches due to"
291
+ f" `abort_after_batch_num={self.abort_after_batch_num}` arg"
292
+ )
293
+
294
+
295
+ def get_abs_min_max(var, ctx):
296
+ abs_var = var.abs()
297
+ return f"{abs_var.min():8.2e} {abs_var.max():8.2e} {ctx}"
298
+
299
+
300
+ def detect_overflow(var, ctx):
301
+ """
302
+ Report whether the tensor contains any `nan` or `inf` entries.
303
+
304
+ This is useful for detecting overflows/underflows and best to call right after the function that did some math that
305
+ modified the tensor in question.
306
+
307
+ This function contains a few other helper features that you can enable and tweak directly if you want to track
308
+ various other things.
309
+
310
+ Args:
311
+ var: the tensor variable to check
312
+ ctx: the message to print as a context
313
+
314
+ Return:
315
+ `True` if `inf` or `nan` was detected, `False` otherwise
316
+ """
317
+ detected = False
318
+ if torch.isnan(var).any().item():
319
+ detected = True
320
+ print(f"{ctx} has nans")
321
+ if torch.isinf(var).any().item():
322
+ detected = True
323
+ print(f"{ctx} has infs")
324
+
325
+ # if needed to monitor large elements can enable the following
326
+ if 0: # and detected:
327
+ n100 = var[torch.ge(var.abs(), 100)]
328
+ if n100.numel() > 0:
329
+ print(f"{ctx}: n100={n100.numel()}")
330
+ n1000 = var[torch.ge(var.abs(), 1000)]
331
+ if n1000.numel() > 0:
332
+ print(f"{ctx}: n1000={n1000.numel()}")
333
+ n10000 = var[torch.ge(var.abs(), 10000)]
334
+ if n10000.numel() > 0:
335
+ print(f"{ctx}: n10000={n10000.numel()}")
336
+
337
+ if 0:
338
+ print(f"min={var.min():9.2e} max={var.max():9.2e}")
339
+
340
+ if 0:
341
+ print(f"min={var.min():9.2e} max={var.max():9.2e} var={var.var():9.2e} mean={var.mean():9.2e} ({ctx})")
342
+
343
+ return detected
344
+
345
+
346
+ class DebugOption(ExplicitEnum):
347
+ UNDERFLOW_OVERFLOW = "underflow_overflow"
348
+ TPU_METRICS_DEBUG = "tpu_metrics_debug"
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/feature_extraction_utils.py ADDED
@@ -0,0 +1,672 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2021 The HuggingFace Inc. team.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """
15
+ Feature extraction saving/loading class for common feature extractors.
16
+ """
17
+
18
+ import copy
19
+ import json
20
+ import os
21
+ from collections import UserDict
22
+ from typing import TYPE_CHECKING, Any, TypeVar, Union
23
+
24
+ import numpy as np
25
+ from huggingface_hub import create_repo, is_offline_mode
26
+
27
+ from .dynamic_module_utils import custom_object_save
28
+ from .utils import (
29
+ FEATURE_EXTRACTOR_NAME,
30
+ PROCESSOR_NAME,
31
+ PushToHubMixin,
32
+ TensorType,
33
+ _is_tensor_or_array_like,
34
+ copy_func,
35
+ is_numpy_array,
36
+ is_torch_available,
37
+ is_torch_device,
38
+ is_torch_dtype,
39
+ logging,
40
+ requires_backends,
41
+ safe_load_json_file,
42
+ )
43
+ from .utils.hub import cached_file
44
+
45
+
46
+ if TYPE_CHECKING:
47
+ from .feature_extraction_sequence_utils import SequenceFeatureExtractor
48
+
49
+
50
+ logger = logging.get_logger(__name__)
51
+
52
+ PreTrainedFeatureExtractor = Union["SequenceFeatureExtractor"]
53
+
54
+ # type hinting: specifying the type of feature extractor class that inherits from FeatureExtractionMixin
55
+ SpecificFeatureExtractorType = TypeVar("SpecificFeatureExtractorType", bound="FeatureExtractionMixin")
56
+
57
+
58
+ class BatchFeature(UserDict):
59
+ r"""
60
+ Holds the output of the [`~SequenceFeatureExtractor.pad`] and feature extractor specific `__call__` methods.
61
+
62
+ This class is derived from a python dictionary and can be used as a dictionary.
63
+
64
+ Args:
65
+ data (`dict`, *optional*):
66
+ Dictionary of lists/arrays/tensors returned by the __call__/pad methods ('input_values', 'attention_mask',
67
+ etc.).
68
+ tensor_type (`Union[None, str, TensorType]`, *optional*):
69
+ You can give a tensor_type here to convert the lists of integers in PyTorch/Numpy Tensors at
70
+ initialization.
71
+ skip_tensor_conversion (`list[str]` or `set[str]`, *optional*):
72
+ List or set of keys that should NOT be converted to tensors, even when `tensor_type` is specified.
73
+ """
74
+
75
+ def __init__(
76
+ self,
77
+ data: dict[str, Any] | None = None,
78
+ tensor_type: None | str | TensorType = None,
79
+ skip_tensor_conversion: list[str] | set[str] | None = None,
80
+ ):
81
+ super().__init__(data)
82
+ self.skip_tensor_conversion = skip_tensor_conversion
83
+ self.convert_to_tensors(tensor_type=tensor_type)
84
+
85
+ def __getitem__(self, item: str) -> Any:
86
+ """
87
+ If the key is a string, returns the value of the dict associated to `key` ('input_values', 'attention_mask',
88
+ etc.).
89
+ """
90
+ if isinstance(item, str):
91
+ return self.data[item]
92
+ else:
93
+ raise KeyError("Indexing with integers is not available when using Python based feature extractors")
94
+
95
+ def __getattr__(self, item: str):
96
+ try:
97
+ return self.data[item]
98
+ except KeyError:
99
+ raise AttributeError
100
+
101
+ def __getstate__(self):
102
+ return {"data": self.data}
103
+
104
+ def __setstate__(self, state):
105
+ if "data" in state:
106
+ self.data = state["data"]
107
+
108
+ def _get_is_as_tensor_fns(self, tensor_type: str | TensorType | None = None):
109
+ if tensor_type is None:
110
+ return None, None
111
+
112
+ # Convert to TensorType
113
+ if not isinstance(tensor_type, TensorType):
114
+ tensor_type = TensorType(tensor_type)
115
+
116
+ if tensor_type == TensorType.PYTORCH:
117
+ if not is_torch_available():
118
+ raise ImportError("Unable to convert output to PyTorch tensors format, PyTorch is not installed.")
119
+ import torch
120
+
121
+ def as_tensor(value):
122
+ if torch.is_tensor(value):
123
+ return value
124
+
125
+ # stack list of tensors if tensor_type is PyTorch (# torch.tensor() does not support list of tensors)
126
+ if isinstance(value, (list, tuple)) and len(value) > 0 and torch.is_tensor(value[0]):
127
+ return torch.stack(value)
128
+
129
+ # convert list of numpy arrays to numpy array (stack) if tensor_type is Numpy
130
+ if isinstance(value, (list, tuple)) and len(value) > 0:
131
+ if isinstance(value[0], np.ndarray):
132
+ value = np.array(value)
133
+ elif (
134
+ isinstance(value[0], (list, tuple))
135
+ and len(value[0]) > 0
136
+ and isinstance(value[0][0], np.ndarray)
137
+ ):
138
+ value = np.array(value)
139
+ if isinstance(value, np.ndarray):
140
+ return torch.from_numpy(value)
141
+ else:
142
+ return torch.tensor(value)
143
+
144
+ is_tensor = torch.is_tensor
145
+ else:
146
+
147
+ def as_tensor(value, dtype=None):
148
+ if isinstance(value, (list, tuple)) and isinstance(value[0], (list, tuple, np.ndarray)):
149
+ value_lens = [len(val) for val in value]
150
+ if len(set(value_lens)) > 1 and dtype is None:
151
+ # we have a ragged list so handle explicitly
152
+ value = as_tensor([np.asarray(val) for val in value], dtype=object)
153
+ return np.asarray(value, dtype=dtype)
154
+
155
+ is_tensor = is_numpy_array
156
+ return is_tensor, as_tensor
157
+
158
+ def convert_to_tensors(
159
+ self,
160
+ tensor_type: str | TensorType | None = None,
161
+ skip_tensor_conversion: list[str] | set[str] | None = None,
162
+ ):
163
+ """
164
+ Convert the inner content to tensors.
165
+
166
+ Args:
167
+ tensor_type (`str` or [`~utils.TensorType`], *optional*):
168
+ The type of tensors to use. If `str`, should be one of the values of the enum [`~utils.TensorType`]. If
169
+ `None`, no modification is done.
170
+ skip_tensor_conversion (`list[str]` or `set[str]`, *optional*):
171
+ List or set of keys that should NOT be converted to tensors, even when `tensor_type` is specified.
172
+
173
+ Note:
174
+ Values that don't have an array-like structure (e.g., strings, dicts, lists of strings) are
175
+ automatically skipped and won't be converted to tensors. Ragged arrays (lists of arrays with
176
+ different lengths) are still attempted, though they may raise errors during conversion.
177
+ """
178
+ if tensor_type is None:
179
+ return self
180
+
181
+ is_tensor, as_tensor = self._get_is_as_tensor_fns(tensor_type)
182
+ skip_tensor_conversion = (
183
+ skip_tensor_conversion if skip_tensor_conversion is not None else self.skip_tensor_conversion
184
+ )
185
+
186
+ # Do the tensor conversion in batch
187
+ for key, value in self.items():
188
+ # Skip keys explicitly marked for no conversion
189
+ if skip_tensor_conversion and key in skip_tensor_conversion:
190
+ continue
191
+
192
+ # Skip values that are not array-like
193
+ if not _is_tensor_or_array_like(value):
194
+ continue
195
+
196
+ try:
197
+ if not is_tensor(value):
198
+ tensor = as_tensor(value)
199
+ self[key] = tensor
200
+ except Exception as e:
201
+ if key == "overflowing_values":
202
+ raise ValueError(
203
+ f"Unable to create tensor for '{key}' with overflowing values of different lengths. "
204
+ f"Original error: {str(e)}"
205
+ ) from e
206
+ raise ValueError(
207
+ f"Unable to convert output '{key}' (type: {type(value).__name__}) to tensor: {str(e)}\n"
208
+ f"You can try:\n"
209
+ f" 1. Use padding=True to ensure all outputs have the same shape\n"
210
+ f" 2. Set return_tensors=None to return Python objects instead of tensors"
211
+ ) from e
212
+
213
+ return self
214
+
215
+ def to(self, *args, **kwargs) -> "BatchFeature":
216
+ """
217
+ Send all values to device by calling `v.to(*args, **kwargs)` (PyTorch only). This should support casting in
218
+ different `dtypes` and sending the `BatchFeature` to a different `device`.
219
+
220
+ Args:
221
+ args (`Tuple`):
222
+ Will be passed to the `to(...)` function of the tensors.
223
+ kwargs (`Dict`, *optional*):
224
+ Will be passed to the `to(...)` function of the tensors.
225
+ To enable asynchronous data transfer, set the `non_blocking` flag in `kwargs` (defaults to `False`).
226
+
227
+ Returns:
228
+ [`BatchFeature`]: The same instance after modification.
229
+ """
230
+ requires_backends(self, ["torch"])
231
+ import torch
232
+
233
+ device = kwargs.get("device")
234
+ non_blocking = kwargs.get("non_blocking", False)
235
+ # Check if the args are a device or a dtype
236
+ if device is None and len(args) > 0:
237
+ # device should be always the first argument
238
+ arg = args[0]
239
+ if is_torch_dtype(arg):
240
+ # The first argument is a dtype
241
+ pass
242
+ elif isinstance(arg, str) or is_torch_device(arg) or isinstance(arg, int):
243
+ device = arg
244
+ else:
245
+ # it's something else
246
+ raise ValueError(f"Attempting to cast a BatchFeature to type {str(arg)}. This is not supported.")
247
+
248
+ # We cast only floating point tensors to avoid issues with tokenizers casting `LongTensor` to `FloatTensor`
249
+ def maybe_to(v):
250
+ # check if v is a floating point tensor
251
+ if isinstance(v, torch.Tensor) and torch.is_floating_point(v):
252
+ # cast and send to device
253
+ return v.to(*args, **kwargs)
254
+ elif isinstance(v, torch.Tensor) and device is not None:
255
+ return v.to(device=device, non_blocking=non_blocking)
256
+ # recursively handle lists and tuples
257
+ elif isinstance(v, (list, tuple)):
258
+ return type(v)(maybe_to(item) for item in v)
259
+ else:
260
+ return v
261
+
262
+ self.data = {k: maybe_to(v) for k, v in self.items()}
263
+ return self
264
+
265
+
266
+ class FeatureExtractionMixin(PushToHubMixin):
267
+ """
268
+ This is a feature extraction mixin used to provide saving/loading functionality for sequential and audio feature
269
+ extractors.
270
+ """
271
+
272
+ _auto_class = None
273
+
274
+ def __init__(self, **kwargs):
275
+ """Set elements of `kwargs` as attributes."""
276
+ # Pop "processor_class", it should not be saved in feature extractor config
277
+ kwargs.pop("processor_class", None)
278
+ # Additional attributes without default values
279
+ for key, value in kwargs.items():
280
+ try:
281
+ setattr(self, key, value)
282
+ except AttributeError as err:
283
+ logger.error(f"Can't set {key} with value {value} for {self}")
284
+ raise err
285
+
286
+ @classmethod
287
+ def from_pretrained(
288
+ cls: type[SpecificFeatureExtractorType],
289
+ pretrained_model_name_or_path: str | os.PathLike,
290
+ cache_dir: str | os.PathLike | None = None,
291
+ force_download: bool = False,
292
+ local_files_only: bool = False,
293
+ token: str | bool | None = None,
294
+ revision: str = "main",
295
+ **kwargs,
296
+ ) -> SpecificFeatureExtractorType:
297
+ r"""
298
+ Instantiate a type of [`~feature_extraction_utils.FeatureExtractionMixin`] from a feature extractor, *e.g.* a
299
+ derived class of [`SequenceFeatureExtractor`].
300
+
301
+ Args:
302
+ pretrained_model_name_or_path (`str` or `os.PathLike`):
303
+ This can be either:
304
+
305
+ - a string, the *model id* of a pretrained feature_extractor hosted inside a model repo on
306
+ huggingface.co.
307
+ - a path to a *directory* containing a feature extractor file saved using the
308
+ [`~feature_extraction_utils.FeatureExtractionMixin.save_pretrained`] method, e.g.,
309
+ `./my_model_directory/`.
310
+ - a path to a saved feature extractor JSON *file*, e.g.,
311
+ `./my_model_directory/preprocessor_config.json`.
312
+ cache_dir (`str` or `os.PathLike`, *optional*):
313
+ Path to a directory in which a downloaded pretrained model feature extractor should be cached if the
314
+ standard cache should not be used.
315
+ force_download (`bool`, *optional*, defaults to `False`):
316
+ Whether or not to force to (re-)download the feature extractor files and override the cached versions
317
+ if they exist.
318
+ proxies (`dict[str, str]`, *optional*):
319
+ A dictionary of proxy servers to use by protocol or endpoint, e.g., `{'http': 'foo.bar:3128',
320
+ 'http://hostname': 'foo.bar:4012'}.` The proxies are used on each request.
321
+ token (`str` or `bool`, *optional*):
322
+ The token to use as HTTP bearer authorization for remote files. If `True`, or not specified, will use
323
+ the token generated when running `hf auth login` (stored in `~/.huggingface`).
324
+ revision (`str`, *optional*, defaults to `"main"`):
325
+ The specific model version to use. It can be a branch name, a tag name, or a commit id, since we use a
326
+ git-based system for storing models and other artifacts on huggingface.co, so `revision` can be any
327
+ identifier allowed by git.
328
+
329
+
330
+ <Tip>
331
+
332
+ To test a pull request you made on the Hub, you can pass `revision="refs/pr/<pr_number>"`.
333
+
334
+ </Tip>
335
+
336
+ return_unused_kwargs (`bool`, *optional*, defaults to `False`):
337
+ If `False`, then this function returns just the final feature extractor object. If `True`, then this
338
+ functions returns a `Tuple(feature_extractor, unused_kwargs)` where *unused_kwargs* is a dictionary
339
+ consisting of the key/value pairs whose keys are not feature extractor attributes: i.e., the part of
340
+ `kwargs` which has not been used to update `feature_extractor` and is otherwise ignored.
341
+ kwargs (`dict[str, Any]`, *optional*):
342
+ The values in kwargs of any keys which are feature extractor attributes will be used to override the
343
+ loaded values. Behavior concerning key/value pairs whose keys are *not* feature extractor attributes is
344
+ controlled by the `return_unused_kwargs` keyword parameter.
345
+
346
+ Returns:
347
+ A feature extractor of type [`~feature_extraction_utils.FeatureExtractionMixin`].
348
+
349
+ Examples:
350
+
351
+ ```python
352
+ # We can't instantiate directly the base class *FeatureExtractionMixin* nor *SequenceFeatureExtractor* so let's show the examples on a
353
+ # derived class: *Wav2Vec2FeatureExtractor*
354
+ feature_extractor = Wav2Vec2FeatureExtractor.from_pretrained(
355
+ "facebook/wav2vec2-base-960h"
356
+ ) # Download feature_extraction_config from huggingface.co and cache.
357
+ feature_extractor = Wav2Vec2FeatureExtractor.from_pretrained(
358
+ "./test/saved_model/"
359
+ ) # E.g. feature_extractor (or model) was saved using *save_pretrained('./test/saved_model/')*
360
+ feature_extractor = Wav2Vec2FeatureExtractor.from_pretrained("./test/saved_model/preprocessor_config.json")
361
+ feature_extractor = Wav2Vec2FeatureExtractor.from_pretrained(
362
+ "facebook/wav2vec2-base-960h", return_attention_mask=False, foo=False
363
+ )
364
+ assert feature_extractor.return_attention_mask is False
365
+ feature_extractor, unused_kwargs = Wav2Vec2FeatureExtractor.from_pretrained(
366
+ "facebook/wav2vec2-base-960h", return_attention_mask=False, foo=False, return_unused_kwargs=True
367
+ )
368
+ assert feature_extractor.return_attention_mask is False
369
+ assert unused_kwargs == {"foo": False}
370
+ ```"""
371
+ kwargs["cache_dir"] = cache_dir
372
+ kwargs["force_download"] = force_download
373
+ kwargs["local_files_only"] = local_files_only
374
+ kwargs["revision"] = revision
375
+
376
+ if token is not None:
377
+ kwargs["token"] = token
378
+
379
+ feature_extractor_dict, kwargs = cls.get_feature_extractor_dict(pretrained_model_name_or_path, **kwargs)
380
+
381
+ return cls.from_dict(feature_extractor_dict, **kwargs)
382
+
383
+ def save_pretrained(self, save_directory: str | os.PathLike, push_to_hub: bool = False, **kwargs):
384
+ """
385
+ Save a feature_extractor object to the directory `save_directory`, so that it can be re-loaded using the
386
+ [`~feature_extraction_utils.FeatureExtractionMixin.from_pretrained`] class method.
387
+
388
+ Args:
389
+ save_directory (`str` or `os.PathLike`):
390
+ Directory where the feature extractor JSON file will be saved (will be created if it does not exist).
391
+ push_to_hub (`bool`, *optional*, defaults to `False`):
392
+ Whether or not to push your model to the Hugging Face model hub after saving it. You can specify the
393
+ repository you want to push to with `repo_id` (will default to the name of `save_directory` in your
394
+ namespace).
395
+ kwargs (`dict[str, Any]`, *optional*):
396
+ Additional key word arguments passed along to the [`~utils.PushToHubMixin.push_to_hub`] method.
397
+ """
398
+ if os.path.isfile(save_directory):
399
+ raise AssertionError(f"Provided path ({save_directory}) should be a directory, not a file")
400
+
401
+ os.makedirs(save_directory, exist_ok=True)
402
+
403
+ if push_to_hub:
404
+ commit_message = kwargs.pop("commit_message", None)
405
+ repo_id = kwargs.pop("repo_id", save_directory.split(os.path.sep)[-1])
406
+ repo_id = create_repo(repo_id, exist_ok=True, **kwargs).repo_id
407
+ files_timestamps = self._get_files_timestamps(save_directory)
408
+
409
+ # If we have a custom config, we copy the file defining it in the folder and set the attributes so it can be
410
+ # loaded from the Hub.
411
+ if self._auto_class is not None:
412
+ custom_object_save(self, save_directory, config=self)
413
+
414
+ # If we save using the predefined names, we can load using `from_pretrained`
415
+ output_feature_extractor_file = os.path.join(save_directory, FEATURE_EXTRACTOR_NAME)
416
+
417
+ self.to_json_file(output_feature_extractor_file)
418
+ logger.info(f"Feature extractor saved in {output_feature_extractor_file}")
419
+
420
+ if push_to_hub:
421
+ self._upload_modified_files(
422
+ save_directory,
423
+ repo_id,
424
+ files_timestamps,
425
+ commit_message=commit_message,
426
+ token=kwargs.get("token"),
427
+ )
428
+
429
+ return [output_feature_extractor_file]
430
+
431
+ @classmethod
432
+ def get_feature_extractor_dict(
433
+ cls, pretrained_model_name_or_path: str | os.PathLike, **kwargs
434
+ ) -> tuple[dict[str, Any], dict[str, Any]]:
435
+ """
436
+ From a `pretrained_model_name_or_path`, resolve to a dictionary of parameters, to be used for instantiating a
437
+ feature extractor of type [`~feature_extraction_utils.FeatureExtractionMixin`] using `from_dict`.
438
+
439
+ Parameters:
440
+ pretrained_model_name_or_path (`str` or `os.PathLike`):
441
+ The identifier of the pre-trained checkpoint from which we want the dictionary of parameters.
442
+
443
+ Returns:
444
+ `tuple[Dict, Dict]`: The dictionary(ies) that will be used to instantiate the feature extractor object.
445
+ """
446
+ cache_dir = kwargs.pop("cache_dir", None)
447
+ force_download = kwargs.pop("force_download", False)
448
+ proxies = kwargs.pop("proxies", None)
449
+ subfolder = kwargs.pop("subfolder", None)
450
+ token = kwargs.pop("token", None)
451
+ local_files_only = kwargs.pop("local_files_only", False)
452
+ revision = kwargs.pop("revision", None)
453
+
454
+ from_pipeline = kwargs.pop("_from_pipeline", None)
455
+ from_auto_class = kwargs.pop("_from_auto", False)
456
+
457
+ user_agent = {"file_type": "feature extractor", "from_auto_class": from_auto_class}
458
+ if from_pipeline is not None:
459
+ user_agent["using_pipeline"] = from_pipeline
460
+
461
+ if is_offline_mode() and not local_files_only:
462
+ logger.info("Offline mode: forcing local_files_only=True")
463
+ local_files_only = True
464
+
465
+ pretrained_model_name_or_path = str(pretrained_model_name_or_path)
466
+ is_local = os.path.isdir(pretrained_model_name_or_path)
467
+ if os.path.isdir(pretrained_model_name_or_path):
468
+ feature_extractor_file = os.path.join(pretrained_model_name_or_path, FEATURE_EXTRACTOR_NAME)
469
+ if os.path.isfile(pretrained_model_name_or_path):
470
+ resolved_feature_extractor_file = pretrained_model_name_or_path
471
+ resolved_processor_file = None
472
+ is_local = True
473
+ else:
474
+ feature_extractor_file = FEATURE_EXTRACTOR_NAME
475
+ try:
476
+ # Load from local folder or from cache or download from model Hub and cache
477
+ resolved_processor_file = cached_file(
478
+ pretrained_model_name_or_path,
479
+ filename=PROCESSOR_NAME,
480
+ cache_dir=cache_dir,
481
+ force_download=force_download,
482
+ proxies=proxies,
483
+ local_files_only=local_files_only,
484
+ token=token,
485
+ user_agent=user_agent,
486
+ revision=revision,
487
+ subfolder=subfolder,
488
+ _raise_exceptions_for_missing_entries=False,
489
+ )
490
+ resolved_feature_extractor_file = cached_file(
491
+ pretrained_model_name_or_path,
492
+ filename=feature_extractor_file,
493
+ cache_dir=cache_dir,
494
+ force_download=force_download,
495
+ proxies=proxies,
496
+ local_files_only=local_files_only,
497
+ token=token,
498
+ user_agent=user_agent,
499
+ revision=revision,
500
+ subfolder=subfolder,
501
+ _raise_exceptions_for_missing_entries=False,
502
+ )
503
+ except OSError:
504
+ # Raise any environment error raise by `cached_file`. It will have a helpful error message adapted to
505
+ # the original exception.
506
+ raise
507
+ except Exception:
508
+ # For any other exception, we throw a generic error.
509
+ raise OSError(
510
+ f"Can't load feature extractor for '{pretrained_model_name_or_path}'. If you were trying to load"
511
+ " it from 'https://huggingface.co/models', make sure you don't have a local directory with the"
512
+ f" same name. Otherwise, make sure '{pretrained_model_name_or_path}' is the correct path to a"
513
+ f" directory containing a {FEATURE_EXTRACTOR_NAME} file"
514
+ )
515
+
516
+ # Load feature_extractor dict. Priority goes as (nested config if found -> image processor config)
517
+ # We are downloading both configs because almost all models have a `processor_config.json` but
518
+ # not all of these are nested. We need to check if it was saved recebtly as nested or if it is legacy style
519
+ feature_extractor_dict = None
520
+ if resolved_processor_file is not None:
521
+ processor_dict = safe_load_json_file(resolved_processor_file)
522
+ if "feature_extractor" in processor_dict or "audio_processor" in processor_dict:
523
+ feature_extractor_dict = processor_dict.get("feature_extractor", processor_dict.get("audio_processor"))
524
+
525
+ if resolved_feature_extractor_file is not None and feature_extractor_dict is None:
526
+ feature_extractor_dict = safe_load_json_file(resolved_feature_extractor_file)
527
+
528
+ if feature_extractor_dict is None:
529
+ raise OSError(
530
+ f"Can't load feature extractor for '{pretrained_model_name_or_path}'. If you were trying to load"
531
+ " it from 'https://huggingface.co/models', make sure you don't have a local directory with the"
532
+ f" same name. Otherwise, make sure '{pretrained_model_name_or_path}' is the correct path to a"
533
+ f" directory containing a {feature_extractor_file} file"
534
+ )
535
+
536
+ if is_local:
537
+ logger.info(f"loading configuration file {resolved_feature_extractor_file}")
538
+ else:
539
+ logger.info(
540
+ f"loading configuration file {feature_extractor_file} from cache at {resolved_feature_extractor_file}"
541
+ )
542
+
543
+ return feature_extractor_dict, kwargs
544
+
545
+ @classmethod
546
+ def from_dict(
547
+ cls, feature_extractor_dict: dict[str, Any], **kwargs
548
+ ) -> Union["FeatureExtractionMixin", tuple["FeatureExtractionMixin", dict[str, Any]]]:
549
+ """
550
+ Instantiates a type of [`~feature_extraction_utils.FeatureExtractionMixin`] from a Python dictionary of
551
+ parameters.
552
+
553
+ Args:
554
+ feature_extractor_dict (`dict[str, Any]`):
555
+ Dictionary that will be used to instantiate the feature extractor object. Such a dictionary can be
556
+ retrieved from a pretrained checkpoint by leveraging the
557
+ [`~feature_extraction_utils.FeatureExtractionMixin.to_dict`] method.
558
+ kwargs (`dict[str, Any]`):
559
+ Additional parameters from which to initialize the feature extractor object.
560
+
561
+ Returns:
562
+ [`~feature_extraction_utils.FeatureExtractionMixin`]: The feature extractor object instantiated from those
563
+ parameters.
564
+ """
565
+ return_unused_kwargs = kwargs.pop("return_unused_kwargs", False)
566
+
567
+ # Update feature_extractor with kwargs if needed
568
+ to_remove = []
569
+ for key, value in kwargs.items():
570
+ if key in feature_extractor_dict:
571
+ feature_extractor_dict[key] = value
572
+ to_remove.append(key)
573
+ for key in to_remove:
574
+ kwargs.pop(key, None)
575
+
576
+ feature_extractor = cls(**feature_extractor_dict)
577
+
578
+ logger.info(f"Feature extractor {feature_extractor}")
579
+ if return_unused_kwargs:
580
+ return feature_extractor, kwargs
581
+ else:
582
+ return feature_extractor
583
+
584
+ def to_dict(self) -> dict[str, Any]:
585
+ """
586
+ Serializes this instance to a Python dictionary. Returns:
587
+ `dict[str, Any]`: Dictionary of all the attributes that make up this configuration instance.
588
+ """
589
+ output = copy.deepcopy(self.__dict__)
590
+ output["feature_extractor_type"] = self.__class__.__name__
591
+ if "mel_filters" in output:
592
+ del output["mel_filters"]
593
+ if "window" in output:
594
+ del output["window"]
595
+ return output
596
+
597
+ @classmethod
598
+ def from_json_file(cls, json_file: str | os.PathLike) -> "FeatureExtractionMixin":
599
+ """
600
+ Instantiates a feature extractor of type [`~feature_extraction_utils.FeatureExtractionMixin`] from the path to
601
+ a JSON file of parameters.
602
+
603
+ Args:
604
+ json_file (`str` or `os.PathLike`):
605
+ Path to the JSON file containing the parameters.
606
+
607
+ Returns:
608
+ A feature extractor of type [`~feature_extraction_utils.FeatureExtractionMixin`]: The feature_extractor
609
+ object instantiated from that JSON file.
610
+ """
611
+ with open(json_file, encoding="utf-8") as reader:
612
+ text = reader.read()
613
+ feature_extractor_dict = json.loads(text)
614
+ return cls(**feature_extractor_dict)
615
+
616
+ def to_json_string(self) -> str:
617
+ """
618
+ Serializes this instance to a JSON string.
619
+
620
+ Returns:
621
+ `str`: String containing all the attributes that make up this feature_extractor instance in JSON format.
622
+ """
623
+ dictionary = self.to_dict()
624
+
625
+ for key, value in dictionary.items():
626
+ if isinstance(value, np.ndarray):
627
+ dictionary[key] = value.tolist()
628
+
629
+ return json.dumps(dictionary, indent=2, sort_keys=True) + "\n"
630
+
631
+ def to_json_file(self, json_file_path: str | os.PathLike):
632
+ """
633
+ Save this instance to a JSON file.
634
+
635
+ Args:
636
+ json_file_path (`str` or `os.PathLike`):
637
+ Path to the JSON file in which this feature_extractor instance's parameters will be saved.
638
+ """
639
+ with open(json_file_path, "w", encoding="utf-8") as writer:
640
+ writer.write(self.to_json_string())
641
+
642
+ def __repr__(self):
643
+ return f"{self.__class__.__name__} {self.to_json_string()}"
644
+
645
+ @classmethod
646
+ def register_for_auto_class(cls, auto_class="AutoFeatureExtractor"):
647
+ """
648
+ Register this class with a given auto class. This should only be used for custom feature extractors as the ones
649
+ in the library are already mapped with `AutoFeatureExtractor`.
650
+
651
+
652
+
653
+ Args:
654
+ auto_class (`str` or `type`, *optional*, defaults to `"AutoFeatureExtractor"`):
655
+ The auto class to register this new feature extractor with.
656
+ """
657
+ if not isinstance(auto_class, str):
658
+ auto_class = auto_class.__name__
659
+
660
+ import transformers.models.auto as auto_module
661
+
662
+ if not hasattr(auto_module, auto_class):
663
+ raise ValueError(f"{auto_class} is not a valid auto class.")
664
+
665
+ cls._auto_class = auto_class
666
+
667
+
668
+ FeatureExtractionMixin.push_to_hub = copy_func(FeatureExtractionMixin.push_to_hub)
669
+ if FeatureExtractionMixin.push_to_hub.__doc__ is not None:
670
+ FeatureExtractionMixin.push_to_hub.__doc__ = FeatureExtractionMixin.push_to_hub.__doc__.format(
671
+ object="feature extractor", object_class="AutoFeatureExtractor", object_files="feature extractor file"
672
+ )
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/image_processing_base.py ADDED
@@ -0,0 +1,494 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 The HuggingFace Inc. team.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import copy
16
+ import json
17
+ import os
18
+ from typing import Any, TypeVar
19
+
20
+ import numpy as np
21
+ from huggingface_hub import create_repo, is_offline_mode
22
+
23
+ from .dynamic_module_utils import custom_object_save
24
+ from .feature_extraction_utils import BatchFeature as BaseBatchFeature
25
+ from .image_utils import is_valid_image, load_image
26
+ from .utils import (
27
+ IMAGE_PROCESSOR_NAME,
28
+ PROCESSOR_NAME,
29
+ PushToHubMixin,
30
+ copy_func,
31
+ logging,
32
+ safe_load_json_file,
33
+ )
34
+ from .utils.hub import cached_file
35
+
36
+
37
+ ImageProcessorType = TypeVar("ImageProcessorType", bound="ImageProcessingMixin")
38
+
39
+
40
+ logger = logging.get_logger(__name__)
41
+
42
+
43
+ # TODO: Move BatchFeature to be imported by both image_processing_utils and image_processing_utils_fast
44
+ # We override the class string here, but logic is the same.
45
+ class BatchFeature(BaseBatchFeature):
46
+ r"""
47
+ Holds the output of the image processor specific `__call__` methods.
48
+
49
+ This class is derived from a python dictionary and can be used as a dictionary.
50
+
51
+ Args:
52
+ data (`dict`):
53
+ Dictionary of lists/arrays/tensors returned by the __call__ method ('pixel_values', etc.).
54
+ tensor_type (`Union[None, str, TensorType]`, *optional*):
55
+ You can give a tensor_type here to convert the lists of integers in PyTorch/Numpy Tensors at
56
+ initialization.
57
+ """
58
+
59
+
60
+ # TODO: (Amy) - factor out the common parts of this and the feature extractor
61
+ class ImageProcessingMixin(PushToHubMixin):
62
+ """
63
+ This is an image processor mixin used to provide saving/loading functionality for sequential and image feature
64
+ extractors.
65
+ """
66
+
67
+ _auto_class = None
68
+
69
+ def __init__(self, **kwargs):
70
+ """Set elements of `kwargs` as attributes."""
71
+ # This key was saved while we still used `XXXFeatureExtractor` for image processing. Now we use
72
+ # `XXXImageProcessor`, this attribute and its value are misleading.
73
+ kwargs.pop("feature_extractor_type", None)
74
+ # Pop "processor_class", should not be saved with image processing config anymore
75
+ kwargs.pop("processor_class", None)
76
+ # Additional attributes without default values
77
+ for key, value in kwargs.items():
78
+ try:
79
+ setattr(self, key, value)
80
+ except AttributeError as err:
81
+ logger.error(f"Can't set {key} with value {value} for {self}")
82
+ raise err
83
+
84
+ @classmethod
85
+ def from_pretrained(
86
+ cls: type[ImageProcessorType],
87
+ pretrained_model_name_or_path: str | os.PathLike,
88
+ cache_dir: str | os.PathLike | None = None,
89
+ force_download: bool = False,
90
+ local_files_only: bool = False,
91
+ token: str | bool | None = None,
92
+ revision: str = "main",
93
+ **kwargs,
94
+ ) -> ImageProcessorType:
95
+ r"""
96
+ Instantiate a type of [`~image_processing_utils.ImageProcessingMixin`] from an image processor.
97
+
98
+ Args:
99
+ pretrained_model_name_or_path (`str` or `os.PathLike`):
100
+ This can be either:
101
+
102
+ - a string, the *model id* of a pretrained image_processor hosted inside a model repo on
103
+ huggingface.co.
104
+ - a path to a *directory* containing a image processor file saved using the
105
+ [`~image_processing_utils.ImageProcessingMixin.save_pretrained`] method, e.g.,
106
+ `./my_model_directory/`.
107
+ - a path to a saved image processor JSON *file*, e.g.,
108
+ `./my_model_directory/preprocessor_config.json`.
109
+ cache_dir (`str` or `os.PathLike`, *optional*):
110
+ Path to a directory in which a downloaded pretrained model image processor should be cached if the
111
+ standard cache should not be used.
112
+ force_download (`bool`, *optional*, defaults to `False`):
113
+ Whether or not to force to (re-)download the image processor files and override the cached versions if
114
+ they exist.
115
+ proxies (`dict[str, str]`, *optional*):
116
+ A dictionary of proxy servers to use by protocol or endpoint, e.g., `{'http': 'foo.bar:3128',
117
+ 'http://hostname': 'foo.bar:4012'}.` The proxies are used on each request.
118
+ token (`str` or `bool`, *optional*):
119
+ The token to use as HTTP bearer authorization for remote files. If `True`, or not specified, will use
120
+ the token generated when running `hf auth login` (stored in `~/.huggingface`).
121
+ revision (`str`, *optional*, defaults to `"main"`):
122
+ The specific model version to use. It can be a branch name, a tag name, or a commit id, since we use a
123
+ git-based system for storing models and other artifacts on huggingface.co, so `revision` can be any
124
+ identifier allowed by git.
125
+
126
+
127
+ <Tip>
128
+
129
+ To test a pull request you made on the Hub, you can pass `revision="refs/pr/<pr_number>"`.
130
+
131
+ </Tip>
132
+
133
+ return_unused_kwargs (`bool`, *optional*, defaults to `False`):
134
+ If `False`, then this function returns just the final image processor object. If `True`, then this
135
+ functions returns a `Tuple(image_processor, unused_kwargs)` where *unused_kwargs* is a dictionary
136
+ consisting of the key/value pairs whose keys are not image processor attributes: i.e., the part of
137
+ `kwargs` which has not been used to update `image_processor` and is otherwise ignored.
138
+ subfolder (`str`, *optional*, defaults to `""`):
139
+ In case the relevant files are located inside a subfolder of the model repo on huggingface.co, you can
140
+ specify the folder name here.
141
+ kwargs (`dict[str, Any]`, *optional*):
142
+ The values in kwargs of any keys which are image processor attributes will be used to override the
143
+ loaded values. Behavior concerning key/value pairs whose keys are *not* image processor attributes is
144
+ controlled by the `return_unused_kwargs` keyword parameter.
145
+
146
+ Returns:
147
+ A image processor of type [`~image_processing_utils.ImageProcessingMixin`].
148
+
149
+ Examples:
150
+
151
+ ```python
152
+ # We can't instantiate directly the base class *ImageProcessingMixin* so let's show the examples on a
153
+ # derived class: *CLIPImageProcessor*
154
+ image_processor = CLIPImageProcessor.from_pretrained(
155
+ "openai/clip-vit-base-patch32"
156
+ ) # Download image_processing_config from huggingface.co and cache.
157
+ image_processor = CLIPImageProcessor.from_pretrained(
158
+ "./test/saved_model/"
159
+ ) # E.g. image processor (or model) was saved using *save_pretrained('./test/saved_model/')*
160
+ image_processor = CLIPImageProcessor.from_pretrained("./test/saved_model/preprocessor_config.json")
161
+ image_processor = CLIPImageProcessor.from_pretrained(
162
+ "openai/clip-vit-base-patch32", do_normalize=False, foo=False
163
+ )
164
+ assert image_processor.do_normalize is False
165
+ image_processor, unused_kwargs = CLIPImageProcessor.from_pretrained(
166
+ "openai/clip-vit-base-patch32", do_normalize=False, foo=False, return_unused_kwargs=True
167
+ )
168
+ assert image_processor.do_normalize is False
169
+ assert unused_kwargs == {"foo": False}
170
+ ```"""
171
+ kwargs["cache_dir"] = cache_dir
172
+ kwargs["force_download"] = force_download
173
+ kwargs["local_files_only"] = local_files_only
174
+ kwargs["revision"] = revision
175
+
176
+ if token is not None:
177
+ kwargs["token"] = token
178
+
179
+ image_processor_dict, kwargs = cls.get_image_processor_dict(pretrained_model_name_or_path, **kwargs)
180
+
181
+ return cls.from_dict(image_processor_dict, **kwargs)
182
+
183
+ def save_pretrained(self, save_directory: str | os.PathLike, push_to_hub: bool = False, **kwargs):
184
+ """
185
+ Save an image processor object to the directory `save_directory`, so that it can be re-loaded using the
186
+ [`~image_processing_utils.ImageProcessingMixin.from_pretrained`] class method.
187
+
188
+ Args:
189
+ save_directory (`str` or `os.PathLike`):
190
+ Directory where the image processor JSON file will be saved (will be created if it does not exist).
191
+ push_to_hub (`bool`, *optional*, defaults to `False`):
192
+ Whether or not to push your model to the Hugging Face model hub after saving it. You can specify the
193
+ repository you want to push to with `repo_id` (will default to the name of `save_directory` in your
194
+ namespace).
195
+ kwargs (`dict[str, Any]`, *optional*):
196
+ Additional key word arguments passed along to the [`~utils.PushToHubMixin.push_to_hub`] method.
197
+ """
198
+ if os.path.isfile(save_directory):
199
+ raise AssertionError(f"Provided path ({save_directory}) should be a directory, not a file")
200
+
201
+ os.makedirs(save_directory, exist_ok=True)
202
+
203
+ if push_to_hub:
204
+ commit_message = kwargs.pop("commit_message", None)
205
+ repo_id = kwargs.pop("repo_id", save_directory.split(os.path.sep)[-1])
206
+ repo_id = create_repo(repo_id, exist_ok=True, **kwargs).repo_id
207
+ files_timestamps = self._get_files_timestamps(save_directory)
208
+
209
+ # If we have a custom config, we copy the file defining it in the folder and set the attributes so it can be
210
+ # loaded from the Hub.
211
+ if self._auto_class is not None:
212
+ custom_object_save(self, save_directory, config=self)
213
+
214
+ # If we save using the predefined names, we can load using `from_pretrained`
215
+ output_image_processor_file = os.path.join(save_directory, IMAGE_PROCESSOR_NAME)
216
+
217
+ self.to_json_file(output_image_processor_file)
218
+ logger.info(f"Image processor saved in {output_image_processor_file}")
219
+
220
+ if push_to_hub:
221
+ self._upload_modified_files(
222
+ save_directory,
223
+ repo_id,
224
+ files_timestamps,
225
+ commit_message=commit_message,
226
+ token=kwargs.get("token"),
227
+ )
228
+
229
+ return [output_image_processor_file]
230
+
231
+ @classmethod
232
+ def get_image_processor_dict(
233
+ cls, pretrained_model_name_or_path: str | os.PathLike, **kwargs
234
+ ) -> tuple[dict[str, Any], dict[str, Any]]:
235
+ """
236
+ From a `pretrained_model_name_or_path`, resolve to a dictionary of parameters, to be used for instantiating a
237
+ image processor of type [`~image_processor_utils.ImageProcessingMixin`] using `from_dict`.
238
+
239
+ Parameters:
240
+ pretrained_model_name_or_path (`str` or `os.PathLike`):
241
+ The identifier of the pre-trained checkpoint from which we want the dictionary of parameters.
242
+ subfolder (`str`, *optional*, defaults to `""`):
243
+ In case the relevant files are located inside a subfolder of the model repo on huggingface.co, you can
244
+ specify the folder name here.
245
+ image_processor_filename (`str`, *optional*, defaults to `"config.json"`):
246
+ The name of the file in the model directory to use for the image processor config.
247
+
248
+ Returns:
249
+ `tuple[Dict, Dict]`: The dictionary(ies) that will be used to instantiate the image processor object.
250
+ """
251
+ cache_dir = kwargs.pop("cache_dir", None)
252
+ force_download = kwargs.pop("force_download", False)
253
+ proxies = kwargs.pop("proxies", None)
254
+ token = kwargs.pop("token", None)
255
+ local_files_only = kwargs.pop("local_files_only", False)
256
+ revision = kwargs.pop("revision", None)
257
+ subfolder = kwargs.pop("subfolder", "")
258
+ image_processor_filename = kwargs.pop("image_processor_filename", IMAGE_PROCESSOR_NAME)
259
+
260
+ from_pipeline = kwargs.pop("_from_pipeline", None)
261
+ from_auto_class = kwargs.pop("_from_auto", False)
262
+
263
+ user_agent = {"file_type": "image processor", "from_auto_class": from_auto_class}
264
+ if from_pipeline is not None:
265
+ user_agent["using_pipeline"] = from_pipeline
266
+
267
+ if is_offline_mode() and not local_files_only:
268
+ logger.info("Offline mode: forcing local_files_only=True")
269
+ local_files_only = True
270
+
271
+ pretrained_model_name_or_path = str(pretrained_model_name_or_path)
272
+ is_local = os.path.isdir(pretrained_model_name_or_path)
273
+ if os.path.isdir(pretrained_model_name_or_path):
274
+ image_processor_file = os.path.join(pretrained_model_name_or_path, image_processor_filename)
275
+ if os.path.isfile(pretrained_model_name_or_path):
276
+ resolved_image_processor_file = pretrained_model_name_or_path
277
+ resolved_processor_file = None
278
+ is_local = True
279
+ else:
280
+ image_processor_file = image_processor_filename
281
+ try:
282
+ resolved_processor_file = cached_file(
283
+ pretrained_model_name_or_path,
284
+ filename=PROCESSOR_NAME,
285
+ cache_dir=cache_dir,
286
+ force_download=force_download,
287
+ proxies=proxies,
288
+ local_files_only=local_files_only,
289
+ token=token,
290
+ user_agent=user_agent,
291
+ revision=revision,
292
+ subfolder=subfolder,
293
+ _raise_exceptions_for_missing_entries=False,
294
+ )
295
+ resolved_image_processor_file = cached_file(
296
+ pretrained_model_name_or_path,
297
+ filename=image_processor_file,
298
+ cache_dir=cache_dir,
299
+ force_download=force_download,
300
+ proxies=proxies,
301
+ local_files_only=local_files_only,
302
+ token=token,
303
+ user_agent=user_agent,
304
+ revision=revision,
305
+ subfolder=subfolder,
306
+ _raise_exceptions_for_missing_entries=False,
307
+ )
308
+ except OSError:
309
+ # Raise any environment error raise by `cached_file`. It will have a helpful error message adapted to
310
+ # the original exception.
311
+ raise
312
+ except Exception:
313
+ # For any other exception, we throw a generic error.
314
+ raise OSError(
315
+ f"Can't load image processor for '{pretrained_model_name_or_path}'. If you were trying to load"
316
+ " it from 'https://huggingface.co/models', make sure you don't have a local directory with the"
317
+ f" same name. Otherwise, make sure '{pretrained_model_name_or_path}' is the correct path to a"
318
+ f" directory containing a {image_processor_filename} file"
319
+ )
320
+
321
+ # Load image_processor dict. Priority goes as (nested config if found -> image processor config)
322
+ # We are downloading both configs because almost all models have a `processor_config.json` but
323
+ # not all of these are nested. We need to check if it was saved recebtly as nested or if it is legacy style
324
+ image_processor_dict = None
325
+ if resolved_processor_file is not None:
326
+ processor_dict = safe_load_json_file(resolved_processor_file)
327
+ if "image_processor" in processor_dict:
328
+ image_processor_dict = processor_dict["image_processor"]
329
+
330
+ if resolved_image_processor_file is not None and image_processor_dict is None:
331
+ image_processor_dict = safe_load_json_file(resolved_image_processor_file)
332
+
333
+ if image_processor_dict is None:
334
+ raise OSError(
335
+ f"Can't load image processor for '{pretrained_model_name_or_path}'. If you were trying to load"
336
+ " it from 'https://huggingface.co/models', make sure you don't have a local directory with the"
337
+ f" same name. Otherwise, make sure '{pretrained_model_name_or_path}' is the correct path to a"
338
+ f" directory containing a {image_processor_filename} file"
339
+ )
340
+
341
+ if is_local:
342
+ logger.info(f"loading configuration file {resolved_image_processor_file}")
343
+ else:
344
+ logger.info(
345
+ f"loading configuration file {image_processor_file} from cache at {resolved_image_processor_file}"
346
+ )
347
+
348
+ return image_processor_dict, kwargs
349
+
350
+ @classmethod
351
+ def from_dict(cls, image_processor_dict: dict[str, Any], **kwargs):
352
+ """
353
+ Instantiates a type of [`~image_processing_utils.ImageProcessingMixin`] from a Python dictionary of parameters.
354
+
355
+ Args:
356
+ image_processor_dict (`dict[str, Any]`):
357
+ Dictionary that will be used to instantiate the image processor object. Such a dictionary can be
358
+ retrieved from a pretrained checkpoint by leveraging the
359
+ [`~image_processing_utils.ImageProcessingMixin.to_dict`] method.
360
+ kwargs (`dict[str, Any]`):
361
+ Additional parameters from which to initialize the image processor object.
362
+
363
+ Returns:
364
+ [`~image_processing_utils.ImageProcessingMixin`]: The image processor object instantiated from those
365
+ parameters.
366
+ """
367
+ image_processor_dict = image_processor_dict.copy()
368
+ return_unused_kwargs = kwargs.pop("return_unused_kwargs", False)
369
+ image_processor_dict.update({k: v for k, v in kwargs.items() if k in cls.valid_kwargs.__annotations__})
370
+ image_processor = cls(**image_processor_dict)
371
+
372
+ # Apply extra kwargs to instance (BC for remote code, e.g. phi4_multimodal)
373
+ extra_keys = []
374
+ for key in reversed(list(kwargs.keys())):
375
+ if hasattr(image_processor, key) and key not in cls.valid_kwargs.__annotations__:
376
+ setattr(image_processor, key, kwargs.pop(key, None))
377
+ extra_keys.append(key)
378
+ if extra_keys:
379
+ logger.warning_once(
380
+ f"Image processor {cls.__name__}: kwargs {extra_keys} were applied for backward compatibility. "
381
+ f"To avoid this warning, add them to valid_kwargs: create a custom TypedDict extending "
382
+ f"ImagesKwargs with these keys and set it as the `valid_kwargs` class attribute."
383
+ )
384
+
385
+ logger.info(f"Image processor {image_processor}")
386
+ if return_unused_kwargs:
387
+ return image_processor, kwargs
388
+ else:
389
+ return image_processor
390
+
391
+ def to_dict(self) -> dict[str, Any]:
392
+ """
393
+ Serializes this instance to a Python dictionary.
394
+
395
+ Returns:
396
+ `dict[str, Any]`: Dictionary of all the attributes that make up this image processor instance.
397
+ """
398
+ output = copy.deepcopy(self.__dict__)
399
+ output["image_processor_type"] = self.__class__.__name__
400
+
401
+ return output
402
+
403
+ @classmethod
404
+ def from_json_file(cls, json_file: str | os.PathLike):
405
+ """
406
+ Instantiates a image processor of type [`~image_processing_utils.ImageProcessingMixin`] from the path to a JSON
407
+ file of parameters.
408
+
409
+ Args:
410
+ json_file (`str` or `os.PathLike`):
411
+ Path to the JSON file containing the parameters.
412
+
413
+ Returns:
414
+ A image processor of type [`~image_processing_utils.ImageProcessingMixin`]: The image_processor object
415
+ instantiated from that JSON file.
416
+ """
417
+ with open(json_file, encoding="utf-8") as reader:
418
+ text = reader.read()
419
+ image_processor_dict = json.loads(text)
420
+ return cls(**image_processor_dict)
421
+
422
+ def to_json_string(self) -> str:
423
+ """
424
+ Serializes this instance to a JSON string.
425
+
426
+ Returns:
427
+ `str`: String containing all the attributes that make up this feature_extractor instance in JSON format.
428
+ """
429
+ dictionary = self.to_dict()
430
+
431
+ for key, value in dictionary.items():
432
+ if isinstance(value, np.ndarray):
433
+ dictionary[key] = value.tolist()
434
+
435
+ return json.dumps(dictionary, indent=2, sort_keys=True) + "\n"
436
+
437
+ def to_json_file(self, json_file_path: str | os.PathLike):
438
+ """
439
+ Save this instance to a JSON file.
440
+
441
+ Args:
442
+ json_file_path (`str` or `os.PathLike`):
443
+ Path to the JSON file in which this image_processor instance's parameters will be saved.
444
+ """
445
+ with open(json_file_path, "w", encoding="utf-8") as writer:
446
+ writer.write(self.to_json_string())
447
+
448
+ def __repr__(self):
449
+ return f"{self.__class__.__name__} {self.to_json_string()}"
450
+
451
+ @classmethod
452
+ def register_for_auto_class(cls, auto_class="AutoImageProcessor"):
453
+ """
454
+ Register this class with a given auto class. This should only be used for custom image processors as the ones
455
+ in the library are already mapped with `AutoImageProcessor `.
456
+
457
+
458
+
459
+ Args:
460
+ auto_class (`str` or `type`, *optional*, defaults to `"AutoImageProcessor "`):
461
+ The auto class to register this new image processor with.
462
+ """
463
+ if not isinstance(auto_class, str):
464
+ auto_class = auto_class.__name__
465
+
466
+ import transformers.models.auto as auto_module
467
+
468
+ if not hasattr(auto_module, auto_class):
469
+ raise ValueError(f"{auto_class} is not a valid auto class.")
470
+
471
+ cls._auto_class = auto_class
472
+
473
+ def fetch_images(self, image_url_or_urls: str | list[str] | list[list[str]]):
474
+ """
475
+ Convert a single or a list of urls into the corresponding `PIL.Image` objects.
476
+
477
+ If a single url is passed, the return value will be a single object. If a list is passed a list of objects is
478
+ returned.
479
+ """
480
+ if isinstance(image_url_or_urls, (list, tuple)):
481
+ return [self.fetch_images(x) for x in image_url_or_urls]
482
+ elif isinstance(image_url_or_urls, str):
483
+ return load_image(image_url_or_urls)
484
+ elif is_valid_image(image_url_or_urls):
485
+ return image_url_or_urls
486
+ else:
487
+ raise TypeError(f"only a single or a list of entries is supported but got type={type(image_url_or_urls)}")
488
+
489
+
490
+ ImageProcessingMixin.push_to_hub = copy_func(ImageProcessingMixin.push_to_hub)
491
+ if ImageProcessingMixin.push_to_hub.__doc__ is not None:
492
+ ImageProcessingMixin.push_to_hub.__doc__ = ImageProcessingMixin.push_to_hub.__doc__.format(
493
+ object="image processor", object_class="AutoImageProcessor", object_files="image processor file"
494
+ )
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/biogpt/modular_biogpt.py ADDED
@@ -0,0 +1,509 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2022 The HuggingFace Team and Microsoft Research AI4Science All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """PyTorch BioGPT model."""
15
+
16
+ import math
17
+
18
+ import torch
19
+ import torch.nn as nn
20
+ from torch.nn import BCEWithLogitsLoss, CrossEntropyLoss, MSELoss
21
+
22
+ from ...activations import ACT2FN
23
+ from ...cache_utils import Cache, DynamicCache
24
+ from ...generation import GenerationMixin
25
+ from ...masking_utils import create_causal_mask
26
+ from ...modeling_outputs import (
27
+ BaseModelOutputWithPastAndCrossAttentions,
28
+ CausalLMOutputWithCrossAttentions,
29
+ SequenceClassifierOutputWithPast,
30
+ TokenClassifierOutput,
31
+ )
32
+ from ...modeling_utils import PreTrainedModel
33
+ from ...processing_utils import Unpack
34
+ from ...utils import (
35
+ TransformersKwargs,
36
+ auto_docstring,
37
+ can_return_tuple,
38
+ logger,
39
+ )
40
+ from ...utils.generic import merge_with_config_defaults
41
+ from ...utils.output_capturing import capture_outputs
42
+ from ..bart.modeling_bart import (
43
+ BartAttention,
44
+ BartDecoderLayer,
45
+ BartScaledWordEmbedding,
46
+ )
47
+ from ..opt.modeling_opt import OPTLearnedPositionalEmbedding
48
+ from .configuration_biogpt import BioGptConfig
49
+
50
+
51
+ class BioGptLearnedPositionalEmbedding(OPTLearnedPositionalEmbedding):
52
+ def forward(
53
+ self,
54
+ attention_mask: torch.LongTensor,
55
+ past_key_values_length: int = 0,
56
+ position_ids: torch.LongTensor | None = None,
57
+ ):
58
+ """`input_ids_shape` is expected to be [bsz x seqlen]."""
59
+ return super().forward(attention_mask, past_key_values_length, position_ids)
60
+
61
+
62
+ class BioGptScaledWordEmbedding(BartScaledWordEmbedding):
63
+ pass
64
+
65
+
66
+ class BioGptAttention(BartAttention):
67
+ pass
68
+
69
+
70
+ class BioGptDecoderLayer(BartDecoderLayer):
71
+ def __init__(self, config: BioGptConfig, layer_idx: int | None = None):
72
+ super().__init__(config)
73
+ self.embed_dim = config.hidden_size
74
+
75
+ self.self_attn = BioGptAttention(
76
+ embed_dim=self.embed_dim,
77
+ num_heads=config.num_attention_heads,
78
+ dropout=config.attention_probs_dropout_prob,
79
+ is_decoder=True,
80
+ is_causal=True,
81
+ config=config,
82
+ layer_idx=layer_idx,
83
+ )
84
+ self.dropout = config.hidden_dropout_prob
85
+ self.activation_fn = ACT2FN[config.hidden_act]
86
+
87
+ self.fc1 = nn.Linear(self.embed_dim, config.intermediate_size)
88
+ self.fc2 = nn.Linear(config.intermediate_size, self.embed_dim)
89
+
90
+ del self.encoder_attn
91
+ del self.encoder_attn_layer_norm
92
+
93
+ def forward(
94
+ self,
95
+ hidden_states: torch.Tensor,
96
+ attention_mask: torch.Tensor | None = None,
97
+ past_key_values: Cache | None = None,
98
+ use_cache: bool | None = True,
99
+ position_ids: torch.LongTensor | None = None,
100
+ **kwargs: Unpack[TransformersKwargs],
101
+ ) -> torch.Tensor:
102
+ """
103
+ Args:
104
+ hidden_states (`torch.FloatTensor`): input to the layer of shape `(batch, seq_len, embed_dim)`
105
+ attention_mask (`torch.FloatTensor`): attention mask of size
106
+ `(batch, 1, tgt_len, src_len)` where padding elements are indicated by very large negative values.
107
+ past_key_values (`Cache`): cached past key and value projection states
108
+ """
109
+ residual = hidden_states
110
+
111
+ hidden_states = self.self_attn_layer_norm(hidden_states)
112
+
113
+ # Self Attention
114
+ hidden_states, _ = self.self_attn(
115
+ hidden_states=hidden_states,
116
+ past_key_values=past_key_values,
117
+ attention_mask=attention_mask,
118
+ position_ids=position_ids,
119
+ **kwargs,
120
+ )
121
+ hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
122
+ hidden_states = residual + hidden_states
123
+
124
+ # Fully Connected
125
+ residual = hidden_states
126
+ hidden_states = self.final_layer_norm(hidden_states)
127
+ hidden_states = self.fc1(hidden_states)
128
+ hidden_states = self.activation_fn(hidden_states)
129
+ hidden_states = nn.functional.dropout(hidden_states, p=self.activation_dropout, training=self.training)
130
+ hidden_states = self.fc2(hidden_states)
131
+ hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
132
+ hidden_states = residual + hidden_states
133
+
134
+ return hidden_states
135
+
136
+
137
+ @auto_docstring
138
+ class BioGptPreTrainedModel(PreTrainedModel):
139
+ config: BioGptConfig
140
+ base_model_prefix = "biogpt"
141
+ supports_gradient_checkpointing = True
142
+ _supports_flash_attn = True
143
+ _supports_sdpa = True
144
+ _supports_flex_attn = True
145
+ _can_compile_fullgraph = True
146
+ _can_record_outputs = {
147
+ "hidden_states": BioGptDecoderLayer,
148
+ "attentions": BioGptAttention,
149
+ }
150
+
151
+
152
+ @auto_docstring
153
+ class BioGptModel(BioGptPreTrainedModel):
154
+ def __init__(self, config: BioGptConfig):
155
+ super().__init__(config)
156
+ self.config = config
157
+ self.layerdrop = config.layerdrop
158
+ self.dropout = config.hidden_dropout_prob
159
+ self.embed_dim = config.hidden_size
160
+ self.padding_idx = config.pad_token_id
161
+ embed_scale = math.sqrt(config.hidden_size) if config.scale_embedding else 1.0
162
+
163
+ self.embed_tokens = BioGptScaledWordEmbedding(
164
+ config.vocab_size, self.embed_dim, self.padding_idx, embed_scale=embed_scale
165
+ )
166
+ self.embed_positions = BioGptLearnedPositionalEmbedding(config.max_position_embeddings, self.embed_dim)
167
+
168
+ self.layers = nn.ModuleList([BioGptDecoderLayer(config, layer_idx=i) for i in range(config.num_hidden_layers)])
169
+ self.layer_norm = nn.LayerNorm(self.embed_dim)
170
+
171
+ self.gradient_checkpointing = False
172
+ # Initialize weights and apply final processing
173
+ self.post_init()
174
+
175
+ @merge_with_config_defaults
176
+ @capture_outputs
177
+ @auto_docstring
178
+ def forward(
179
+ self,
180
+ input_ids: torch.LongTensor | None = None,
181
+ attention_mask: torch.FloatTensor | None = None,
182
+ inputs_embeds: torch.FloatTensor | None = None,
183
+ past_key_values: Cache | None = None,
184
+ use_cache: bool | None = None,
185
+ position_ids: torch.LongTensor | None = None,
186
+ **kwargs: Unpack[TransformersKwargs],
187
+ ) -> tuple | BaseModelOutputWithPastAndCrossAttentions:
188
+ if (input_ids is None) ^ (inputs_embeds is not None):
189
+ raise ValueError("You cannot specify both decoder_input_ids and decoder_inputs_embeds at the same time")
190
+
191
+ if inputs_embeds is None:
192
+ inputs_embeds = self.embed_tokens(input_ids)
193
+
194
+ # initialize past_key_values
195
+ if use_cache and past_key_values is None:
196
+ past_key_values = DynamicCache(config=self.config)
197
+
198
+ batch_size, seq_length = inputs_embeds.size()[:-1]
199
+ past_key_values_length = past_key_values.get_seq_length() if past_key_values is not None else 0
200
+
201
+ if attention_mask is None:
202
+ # required mask seq length can be calculated via length of past cache
203
+ mask_seq_length = past_key_values_length + seq_length
204
+ attention_mask = torch.ones(batch_size, mask_seq_length, device=inputs_embeds.device)
205
+
206
+ self_attn_cache = past_key_values
207
+
208
+ causal_mask = create_causal_mask(
209
+ config=self.config,
210
+ inputs_embeds=inputs_embeds,
211
+ attention_mask=attention_mask,
212
+ past_key_values=self_attn_cache,
213
+ )
214
+
215
+ # embed positions
216
+ if position_ids is None:
217
+ position_ids = torch.arange(seq_length, device=inputs_embeds.device) + past_key_values_length
218
+ position_ids = position_ids.unsqueeze(0)
219
+
220
+ positions = self.embed_positions(attention_mask, past_key_values_length, position_ids=position_ids)
221
+ hidden_states = inputs_embeds + positions
222
+ hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
223
+
224
+ for idx, decoder_layer in enumerate(self.layers):
225
+ if self.training:
226
+ dropout_probability = torch.rand([])
227
+ if dropout_probability < self.layerdrop:
228
+ continue
229
+
230
+ hidden_states = decoder_layer(
231
+ hidden_states,
232
+ attention_mask=causal_mask,
233
+ past_key_values=past_key_values,
234
+ use_cache=use_cache,
235
+ position_ids=position_ids,
236
+ **kwargs,
237
+ )
238
+
239
+ hidden_states = self.layer_norm(hidden_states)
240
+
241
+ return BaseModelOutputWithPastAndCrossAttentions(
242
+ last_hidden_state=hidden_states,
243
+ past_key_values=past_key_values,
244
+ )
245
+
246
+
247
+ @auto_docstring(
248
+ custom_intro="""
249
+ BioGPT Model with a `language modeling` head on top for CLM fine-tuning.
250
+ """
251
+ )
252
+ class BioGptForCausalLM(BioGptPreTrainedModel, GenerationMixin):
253
+ _tied_weights_keys = {"output_projection.weight": "biogpt.embed_tokens.weight"}
254
+
255
+ def __init__(self, config):
256
+ super().__init__(config)
257
+
258
+ self.biogpt = BioGptModel(config)
259
+ self.output_projection = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
260
+
261
+ # Initialize weights and apply final processing
262
+ self.post_init()
263
+
264
+ def get_output_embeddings(self):
265
+ return self.output_projection
266
+
267
+ def set_output_embeddings(self, new_embeddings):
268
+ self.output_projection = new_embeddings
269
+
270
+ @can_return_tuple
271
+ @auto_docstring
272
+ def forward(
273
+ self,
274
+ input_ids: torch.LongTensor | None = None,
275
+ attention_mask: torch.FloatTensor | None = None,
276
+ inputs_embeds: torch.FloatTensor | None = None,
277
+ past_key_values: Cache | None = None,
278
+ labels: torch.LongTensor | None = None,
279
+ use_cache: bool | None = None,
280
+ position_ids: torch.LongTensor | None = None,
281
+ logits_to_keep: int | torch.Tensor = 0,
282
+ **kwargs: Unpack[TransformersKwargs],
283
+ ) -> tuple | CausalLMOutputWithCrossAttentions:
284
+ r"""
285
+ labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
286
+ Labels for language modeling. Note that the labels **are shifted** inside the model, i.e. you can set
287
+ `labels = input_ids` Indices are selected in `[-100, 0, ..., config.vocab_size]` All labels set to `-100`
288
+ are ignored (masked), the loss is only computed for labels in `[0, ..., config.vocab_size]`
289
+ """
290
+ outputs = self.biogpt(
291
+ input_ids,
292
+ attention_mask=attention_mask,
293
+ inputs_embeds=inputs_embeds,
294
+ past_key_values=past_key_values,
295
+ use_cache=use_cache,
296
+ position_ids=position_ids,
297
+ **kwargs,
298
+ )
299
+
300
+ hidden_states = outputs[0]
301
+ slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
302
+ logits = self.output_projection(hidden_states[:, slice_indices, :])
303
+
304
+ loss = None
305
+ if labels is not None:
306
+ loss = self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size, **kwargs)
307
+
308
+ return CausalLMOutputWithCrossAttentions(
309
+ loss=loss,
310
+ logits=logits,
311
+ past_key_values=outputs.past_key_values,
312
+ hidden_states=outputs.hidden_states,
313
+ attentions=outputs.attentions,
314
+ cross_attentions=outputs.cross_attentions,
315
+ )
316
+
317
+
318
+ @auto_docstring
319
+ class BioGptForTokenClassification(BioGptPreTrainedModel):
320
+ def __init__(self, config):
321
+ super().__init__(config)
322
+ self.num_labels = config.num_labels
323
+
324
+ self.biogpt = BioGptModel(config)
325
+ if hasattr(config, "classifier_dropout") and config.classifier_dropout is not None:
326
+ classifier_dropout = config.classifier_dropout
327
+ else:
328
+ classifier_dropout = config.hidden_dropout_prob
329
+ self.dropout = nn.Dropout(classifier_dropout)
330
+ self.classifier = nn.Linear(config.hidden_size, config.num_labels)
331
+
332
+ self.post_init()
333
+
334
+ @can_return_tuple
335
+ @auto_docstring
336
+ def forward(
337
+ self,
338
+ input_ids: torch.LongTensor | None = None,
339
+ token_type_ids: torch.LongTensor | None = None,
340
+ attention_mask: torch.FloatTensor | None = None,
341
+ past_key_values: Cache | None = None,
342
+ inputs_embeds: torch.FloatTensor | None = None,
343
+ labels: torch.LongTensor | None = None,
344
+ use_cache: bool | None = None,
345
+ position_ids: torch.LongTensor | None = None,
346
+ **kwargs,
347
+ ) -> tuple | TokenClassifierOutput:
348
+ r"""
349
+ labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
350
+ Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
351
+ config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
352
+ `config.num_labels > 1` a classification loss is computed (Cross-Entropy).
353
+ """
354
+ transformer_outputs = self.biogpt(
355
+ input_ids,
356
+ past_key_values=past_key_values,
357
+ attention_mask=attention_mask,
358
+ inputs_embeds=inputs_embeds,
359
+ use_cache=use_cache,
360
+ position_ids=position_ids,
361
+ **kwargs,
362
+ )
363
+
364
+ hidden_states = transformer_outputs[0]
365
+ hidden_states = self.dropout(hidden_states)
366
+ logits = self.classifier(hidden_states)
367
+
368
+ loss = None
369
+ if labels is not None:
370
+ loss_fct = CrossEntropyLoss()
371
+ if attention_mask is not None:
372
+ active_loss = attention_mask.view(-1) == 1
373
+ active_logits = logits.view(-1, self.num_labels)
374
+ active_labels = torch.where(
375
+ active_loss, labels.view(-1), torch.tensor(loss_fct.ignore_index).type_as(labels)
376
+ )
377
+ loss = loss_fct(active_logits, active_labels)
378
+ else:
379
+ loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
380
+
381
+ return TokenClassifierOutput(
382
+ loss=loss,
383
+ logits=logits,
384
+ hidden_states=transformer_outputs.hidden_states,
385
+ attentions=transformer_outputs.attentions,
386
+ )
387
+
388
+
389
+ @auto_docstring(
390
+ custom_intro="""
391
+ The BioGpt Model transformer with a sequence classification head on top (linear layer).
392
+
393
+ [`BioGptForSequenceClassification`] uses the last token in order to do the classification, as other causal models
394
+ (e.g. GPT-2) do.
395
+
396
+ Since it does classification on the last token, it is required to know the position of the last token. If a
397
+ `pad_token_id` is defined in the configuration, it finds the last token that is not a padding token in each row. If
398
+ no `pad_token_id` is defined, it simply takes the last value in each row of the batch. Since it cannot guess the
399
+ padding tokens when `inputs_embeds` are passed instead of `input_ids`, it does the same (take the last value in
400
+ each row of the batch).
401
+ """
402
+ )
403
+ class BioGptForSequenceClassification(BioGptPreTrainedModel):
404
+ def __init__(self, config: BioGptConfig):
405
+ super().__init__(config)
406
+ self.num_labels = config.num_labels
407
+ self.biogpt = BioGptModel(config)
408
+ self.score = nn.Linear(config.hidden_size, self.num_labels, bias=False)
409
+
410
+ # Initialize weights and apply final processing
411
+ self.post_init()
412
+
413
+ @can_return_tuple
414
+ @auto_docstring
415
+ def forward(
416
+ self,
417
+ input_ids: torch.LongTensor | None = None,
418
+ attention_mask: torch.FloatTensor | None = None,
419
+ past_key_values: Cache | None = None,
420
+ inputs_embeds: torch.FloatTensor | None = None,
421
+ labels: torch.LongTensor | None = None,
422
+ use_cache: bool | None = None,
423
+ position_ids: torch.LongTensor | None = None,
424
+ logits_to_keep: int | torch.Tensor = 0,
425
+ **kwargs,
426
+ ) -> tuple | SequenceClassifierOutputWithPast:
427
+ r"""
428
+ labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
429
+ Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
430
+ config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
431
+ `config.num_labels > 1` a classification loss is computed (Cross-Entropy).
432
+ """
433
+ transformer_outputs = self.biogpt(
434
+ input_ids,
435
+ past_key_values=past_key_values,
436
+ attention_mask=attention_mask,
437
+ inputs_embeds=inputs_embeds,
438
+ use_cache=use_cache,
439
+ position_ids=position_ids,
440
+ **kwargs,
441
+ )
442
+ hidden_states = transformer_outputs[0]
443
+ slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
444
+ logits = self.score(hidden_states[:, slice_indices, :])
445
+
446
+ if input_ids is not None:
447
+ batch_size, sequence_length = input_ids.shape[:2]
448
+ else:
449
+ batch_size, sequence_length = inputs_embeds.shape[:2]
450
+
451
+ if self.config.pad_token_id is None:
452
+ sequence_length = -1
453
+ else:
454
+ if input_ids is not None:
455
+ sequence_length = (torch.ne(input_ids, self.config.pad_token_id).sum(-1) - 1).to(logits.device)
456
+ else:
457
+ sequence_length = -1
458
+ logger.warning_once(
459
+ f"{self.__class__.__name__} will not detect padding tokens in `inputs_embeds`. Results may be "
460
+ "unexpected if using padding tokens in conjunction with `inputs_embeds.`"
461
+ )
462
+
463
+ pooled_logits = logits[torch.arange(batch_size, device=logits.device), sequence_length]
464
+
465
+ loss = None
466
+ if labels is not None:
467
+ if self.config.problem_type is None:
468
+ if self.num_labels == 1:
469
+ self.config.problem_type = "regression"
470
+ elif self.num_labels > 1 and (labels.dtype == torch.long or labels.dtype == torch.int):
471
+ self.config.problem_type = "single_label_classification"
472
+ else:
473
+ self.config.problem_type = "multi_label_classification"
474
+
475
+ if self.config.problem_type == "regression":
476
+ loss_fct = MSELoss()
477
+ if self.num_labels == 1:
478
+ loss = loss_fct(pooled_logits.squeeze(), labels.squeeze())
479
+ else:
480
+ loss = loss_fct(pooled_logits, labels)
481
+ elif self.config.problem_type == "single_label_classification":
482
+ loss_fct = CrossEntropyLoss()
483
+ loss = loss_fct(pooled_logits.view(-1, self.num_labels), labels.view(-1))
484
+ elif self.config.problem_type == "multi_label_classification":
485
+ loss_fct = BCEWithLogitsLoss()
486
+ loss = loss_fct(pooled_logits, labels)
487
+
488
+ return SequenceClassifierOutputWithPast(
489
+ loss=loss,
490
+ logits=pooled_logits,
491
+ past_key_values=transformer_outputs.past_key_values,
492
+ hidden_states=transformer_outputs.hidden_states,
493
+ attentions=transformer_outputs.attentions,
494
+ )
495
+
496
+ def get_input_embeddings(self):
497
+ return self.biogpt.embed_tokens
498
+
499
+ def set_input_embeddings(self, value):
500
+ self.biogpt.embed_tokens = value
501
+
502
+
503
+ __all__ = [
504
+ "BioGptForCausalLM",
505
+ "BioGptForTokenClassification",
506
+ "BioGptForSequenceClassification",
507
+ "BioGptModel",
508
+ "BioGptPreTrainedModel",
509
+ ]
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/biogpt/tokenization_biogpt.py ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2022 The HuggingFace Team and Microsoft Research AI4Science. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """Tokenization classes for BioGPT."""
15
+
16
+ import json
17
+ import os
18
+
19
+ from ...tokenization_python import PreTrainedTokenizer
20
+ from ...utils import logging
21
+
22
+
23
+ logger = logging.get_logger(__name__)
24
+
25
+ VOCAB_FILES_NAMES = {
26
+ "vocab_file": "vocab.json",
27
+ "merges_file": "merges.txt",
28
+ }
29
+
30
+
31
+ def get_pairs(word):
32
+ """
33
+ Return set of symbol pairs in a word. word is represented as tuple of symbols (symbols being variable-length
34
+ strings)
35
+ """
36
+ pairs = set()
37
+ prev_char = word[0]
38
+ for char in word[1:]:
39
+ pairs.add((prev_char, char))
40
+ prev_char = char
41
+ return pairs
42
+
43
+
44
+ class BioGptTokenizer(PreTrainedTokenizer):
45
+ """
46
+ Construct an FAIRSEQ Transformer tokenizer. Moses tokenization followed by Byte-Pair Encoding.
47
+
48
+ This tokenizer inherits from [`PreTrainedTokenizer`] which contains most of the main methods. Users should refer to
49
+ this superclass for more information regarding those methods.
50
+
51
+ Args:
52
+ vocab_file (`str`):
53
+ Path to the vocabulary file.
54
+ merges_file (`str`):
55
+ Merges file.
56
+ unk_token (`str`, *optional*, defaults to `"<unk>"`):
57
+ The unknown token. A token that is not in the vocabulary cannot be converted to an ID and is set to be this
58
+ token instead.
59
+ bos_token (`str`, *optional*, defaults to `"<s>"`):
60
+ The beginning of sequence token that was used during pretraining. Can be used a sequence classifier token.
61
+
62
+ <Tip>
63
+
64
+ When building a sequence using special tokens, this is not the token that is used for the beginning of
65
+ sequence. The token used is the `cls_token`.
66
+
67
+ </Tip>
68
+
69
+ eos_token (`str`, *optional*, defaults to `"</s>"`):
70
+ The end of sequence token.
71
+
72
+ <Tip>
73
+
74
+ When building a sequence using special tokens, this is not the token that is used for the end of sequence.
75
+ The token used is the `sep_token`.
76
+
77
+ </Tip>
78
+
79
+ sep_token (`str`, *optional*, defaults to `"</s>"`):
80
+ The separator token, which is used when building a sequence from multiple sequences, e.g. two sequences for
81
+ sequence classification or for a text and a question for question answering. It is also used as the last
82
+ token of a sequence built with special tokens.
83
+ pad_token (`str`, *optional*, defaults to `"<pad>"`):
84
+ The token used for padding, for example when batching sequences of different lengths.
85
+ """
86
+
87
+ vocab_files_names = VOCAB_FILES_NAMES
88
+ model_input_names = ["input_ids", "attention_mask"]
89
+
90
+ def __init__(
91
+ self,
92
+ vocab_file,
93
+ merges_file,
94
+ unk_token="<unk>",
95
+ bos_token="<s>",
96
+ eos_token="</s>",
97
+ sep_token="</s>",
98
+ pad_token="<pad>",
99
+ **kwargs,
100
+ ):
101
+ try:
102
+ import sacremoses
103
+ except ImportError:
104
+ raise ImportError(
105
+ "You need to install sacremoses to use BioGptTokenizer. "
106
+ "See https://pypi.org/project/sacremoses/ for installation."
107
+ )
108
+
109
+ self.lang = "en"
110
+ self.sm = sacremoses
111
+ # cache of sm.MosesTokenizer instance
112
+ self.cache_moses_tokenizer = {}
113
+ self.cache_moses_detokenizer = {}
114
+
115
+ """ Initialisation"""
116
+ with open(vocab_file, encoding="utf-8") as vocab_handle:
117
+ self.encoder = json.load(vocab_handle)
118
+ self.decoder = {v: k for k, v in self.encoder.items()}
119
+ with open(merges_file, encoding="utf-8") as merges_handle:
120
+ merges = merges_handle.read().split("\n")[:-1]
121
+ merges = [tuple(merge.split()[:2]) for merge in merges]
122
+ self.bpe_ranks = dict(zip(merges, range(len(merges))))
123
+ self.cache = {}
124
+
125
+ super().__init__(
126
+ bos_token=bos_token,
127
+ eos_token=eos_token,
128
+ sep_token=sep_token,
129
+ unk_token=unk_token,
130
+ pad_token=pad_token,
131
+ **kwargs,
132
+ )
133
+
134
+ @property
135
+ def vocab_size(self):
136
+ """Returns vocab size"""
137
+ return len(self.encoder)
138
+
139
+ def get_vocab(self):
140
+ return dict(self.encoder, **self.added_tokens_encoder)
141
+
142
+ def moses_tokenize(self, text, lang):
143
+ if lang not in self.cache_moses_tokenizer:
144
+ moses_tokenizer = self.sm.MosesTokenizer(lang=lang)
145
+ self.cache_moses_tokenizer[lang] = moses_tokenizer
146
+ return self.cache_moses_tokenizer[lang].tokenize(
147
+ text, aggressive_dash_splits=True, return_str=False, escape=True
148
+ )
149
+
150
+ def moses_detokenize(self, tokens, lang):
151
+ if lang not in self.cache_moses_detokenizer:
152
+ moses_detokenizer = self.sm.MosesDetokenizer(lang=lang)
153
+ self.cache_moses_detokenizer[lang] = moses_detokenizer
154
+ return self.cache_moses_detokenizer[lang].detokenize(tokens)
155
+
156
+ def bpe(self, token):
157
+ word = tuple(token[:-1]) + (token[-1] + "</w>",)
158
+ if token in self.cache:
159
+ return self.cache[token]
160
+ pairs = get_pairs(word)
161
+
162
+ if not pairs:
163
+ return token + "</w>"
164
+
165
+ while True:
166
+ bigram = min(pairs, key=lambda pair: self.bpe_ranks.get(pair, float("inf")))
167
+ if bigram not in self.bpe_ranks:
168
+ break
169
+ first, second = bigram
170
+ new_word = []
171
+ i = 0
172
+ while i < len(word):
173
+ try:
174
+ j = word.index(first, i)
175
+ except ValueError:
176
+ new_word.extend(word[i:])
177
+ break
178
+ else:
179
+ new_word.extend(word[i:j])
180
+ i = j
181
+
182
+ if word[i] == first and i < len(word) - 1 and word[i + 1] == second:
183
+ new_word.append(first + second)
184
+ i += 2
185
+ else:
186
+ new_word.append(word[i])
187
+ i += 1
188
+ new_word = tuple(new_word)
189
+ word = new_word
190
+ if len(word) == 1:
191
+ break
192
+ else:
193
+ pairs = get_pairs(word)
194
+ word = " ".join(word)
195
+ if word == "\n </w>":
196
+ word = "\n</w>"
197
+ self.cache[token] = word
198
+ return word
199
+
200
+ def _tokenize(self, text, bypass_tokenizer=False):
201
+ """Returns a tokenized string."""
202
+ if bypass_tokenizer:
203
+ text = text.split()
204
+ else:
205
+ text = self.moses_tokenize(text, self.lang)
206
+
207
+ split_tokens = []
208
+ for token in text:
209
+ if token:
210
+ split_tokens.extend(list(self.bpe(token).split(" ")))
211
+
212
+ return split_tokens
213
+
214
+ def _convert_token_to_id(self, token):
215
+ """Converts a token (str) in an id using the vocab."""
216
+ return self.encoder.get(token, self.encoder.get(self.unk_token))
217
+
218
+ def _convert_id_to_token(self, index):
219
+ """Converts an index (integer) in a token (str) using the vocab."""
220
+ return self.decoder.get(index, self.unk_token)
221
+
222
+ def convert_tokens_to_string(self, tokens):
223
+ """Converts a sequence of tokens (string) in a single string."""
224
+ # remove BPE
225
+ tokens = [t.replace(" ", "").replace("</w>", " ") for t in tokens]
226
+ tokens = "".join(tokens).split()
227
+ # detokenize
228
+ text = self.moses_detokenize(tokens, self.lang)
229
+ return text
230
+
231
+ def build_inputs_with_special_tokens(
232
+ self, token_ids_0: list[int], token_ids_1: list[int] | None = None
233
+ ) -> list[int]:
234
+ """
235
+ Build model inputs from a sequence or a pair of sequence for sequence classification tasks by concatenating and
236
+ adding special tokens. A BioGPT sequence has the following format:
237
+
238
+ - single sequence: `</s> X `
239
+ - pair of sequences: `</s> A </s> B `
240
+
241
+ Args:
242
+ token_ids_0 (`List[int]`):
243
+ List of IDs to which the special tokens will be added.
244
+ token_ids_1 (`List[int]`, *optional*):
245
+ Optional second list of IDs for sequence pairs.
246
+
247
+ Returns:
248
+ `List[int]`: List of [input IDs](../glossary#input-ids) with the appropriate special tokens.
249
+ """
250
+ if token_ids_1 is None:
251
+ return [self.sep_token_id] + token_ids_0
252
+ sep = [self.sep_token_id]
253
+ return sep + token_ids_0 + sep + token_ids_1
254
+
255
+ def get_special_tokens_mask(
256
+ self, token_ids_0: list[int], token_ids_1: list[int] | None = None, already_has_special_tokens: bool = False
257
+ ) -> list[int]:
258
+ """
259
+ Retrieve sequence ids from a token list that has no special tokens added. This method is called when adding
260
+ special tokens using the tokenizer `prepare_for_model` method.
261
+
262
+ Args:
263
+ token_ids_0 (`List[int]`):
264
+ List of IDs.
265
+ token_ids_1 (`List[int]`, *optional*):
266
+ Optional second list of IDs for sequence pairs.
267
+ already_has_special_tokens (`bool`, *optional*, defaults to `False`):
268
+ Whether or not the token list is already formatted with special tokens for the model.
269
+
270
+ Returns:
271
+ `List[int]`: A list of integers in the range [0, 1]: 1 for a special token, 0 for a sequence token.
272
+ """
273
+ if already_has_special_tokens:
274
+ return super().get_special_tokens_mask(
275
+ token_ids_0=token_ids_0, token_ids_1=token_ids_1, already_has_special_tokens=True
276
+ )
277
+ # no bos used in fairseq
278
+ if token_ids_1 is not None:
279
+ return [1] + ([0] * len(token_ids_0)) + [1] + ([0] * len(token_ids_1))
280
+ return [1] + ([0] * len(token_ids_0))
281
+
282
+ def save_vocabulary(self, save_directory: str, filename_prefix: str | None = None) -> tuple[str]:
283
+ if not os.path.isdir(save_directory):
284
+ logger.error(f"Vocabulary path ({save_directory}) should be a directory")
285
+ return
286
+ vocab_file = os.path.join(
287
+ save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"]
288
+ )
289
+ merge_file = os.path.join(
290
+ save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["merges_file"]
291
+ )
292
+
293
+ with open(vocab_file, "w", encoding="utf-8") as f:
294
+ f.write(json.dumps(self.encoder, indent=2, sort_keys=True, ensure_ascii=False) + "\n")
295
+
296
+ index = 0
297
+ with open(merge_file, "w", encoding="utf-8") as writer:
298
+ for bpe_tokens, token_index in sorted(self.bpe_ranks.items(), key=lambda kv: kv[1]):
299
+ if index != token_index:
300
+ logger.warning(
301
+ f"Saving vocabulary to {merge_file}: BPE merge indices are not consecutive."
302
+ " Please check that the tokenizer is not corrupted!"
303
+ )
304
+ index = token_index
305
+ writer.write(" ".join(bpe_tokens) + "\n")
306
+ index += 1
307
+
308
+ return vocab_file, merge_file
309
+
310
+ def __getstate__(self):
311
+ state = self.__dict__.copy()
312
+ state["sm"] = None
313
+ return state
314
+
315
+ def __setstate__(self, d):
316
+ self.__dict__ = d
317
+
318
+ try:
319
+ import sacremoses
320
+ except ImportError:
321
+ raise ImportError(
322
+ "You need to install sacremoses to use XLMTokenizer. "
323
+ "See https://pypi.org/project/sacremoses/ for installation."
324
+ )
325
+
326
+ self.sm = sacremoses
327
+
328
+
329
+ __all__ = ["BioGptTokenizer"]
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/mpnet/__init__.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2024 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ from typing import TYPE_CHECKING
15
+
16
+ from ...utils import _LazyModule
17
+ from ...utils.import_utils import define_import_structure
18
+
19
+
20
+ if TYPE_CHECKING:
21
+ from .configuration_mpnet import *
22
+ from .modeling_mpnet import *
23
+ from .tokenization_mpnet import *
24
+ else:
25
+ import sys
26
+
27
+ _file = globals()["__file__"]
28
+ sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/mpnet/tokenization_mpnet.py ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2018 The HuggingFace Inc. team, Microsoft Corporation.
2
+ # Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Tokenization classes for MPNet."""
16
+
17
+ from tokenizers import Tokenizer, decoders, normalizers, pre_tokenizers, processors
18
+ from tokenizers.models import WordPiece
19
+
20
+ from ...tokenization_python import AddedToken
21
+ from ...tokenization_utils_tokenizers import TokenizersBackend
22
+ from ...utils import logging
23
+
24
+
25
+ logger = logging.get_logger(__name__)
26
+
27
+ VOCAB_FILES_NAMES = {"vocab_file": "vocab.txt", "tokenizer_file": "tokenizer.json"}
28
+
29
+
30
+ class MPNetTokenizer(TokenizersBackend):
31
+ r"""
32
+ Construct a MPNet tokenizer (backed by HuggingFace's *tokenizers* library). Based on WordPiece.
33
+
34
+ This tokenizer inherits from [`TokenizersBackend`] which contains most of the main methods. Users should
35
+ refer to this superclass for more information regarding those methods.
36
+
37
+ Args:
38
+ vocab (`str` or `dict[str, int]`, *optional*):
39
+ Dictionary mapping tokens to their IDs. If not provided, an empty vocab is initialized.
40
+ do_lower_case (`bool`, *optional*, defaults to `True`):
41
+ Whether or not to lowercase the input when tokenizing.
42
+ bos_token (`str`, *optional*, defaults to `"<s>"`):
43
+ The beginning of sequence token that was used during pretraining. Can be used a sequence classifier token.
44
+
45
+ <Tip>
46
+
47
+ When building a sequence using special tokens, this is not the token that is used for the beginning of
48
+ sequence. The token used is the `cls_token`.
49
+
50
+ </Tip>
51
+
52
+ eos_token (`str`, *optional*, defaults to `"</s>"`):
53
+ The end of sequence token.
54
+
55
+ <Tip>
56
+
57
+ When building a sequence using special tokens, this is not the token that is used for the end of sequence.
58
+ The token used is the `sep_token`.
59
+
60
+ </Tip>
61
+
62
+ sep_token (`str`, *optional*, defaults to `"</s>"`):
63
+ The separator token, which is used when building a sequence from multiple sequences, e.g. two sequences for
64
+ sequence classification or for a text and a question for question answering. It is also used as the last
65
+ token of a sequence built with special tokens.
66
+ cls_token (`str`, *optional*, defaults to `"<s>"`):
67
+ The classifier token which is used when doing sequence classification (classification of the whole sequence
68
+ instead of per-token classification). It is the first token of the sequence when built with special tokens.
69
+ unk_token (`str`, *optional*, defaults to `"[UNK]"`):
70
+ The unknown token. A token that is not in the vocabulary cannot be converted to an ID and is set to be this
71
+ token instead.
72
+ pad_token (`str`, *optional*, defaults to `"<pad>"`):
73
+ The token used for padding, for example when batching sequences of different lengths.
74
+ mask_token (`str`, *optional*, defaults to `"<mask>"`):
75
+ The token used for masking values. This is the token used when training this model with masked language
76
+ modeling. This is the token which the model will try to predict.
77
+ tokenize_chinese_chars (`bool`, *optional*, defaults to `True`):
78
+ Whether or not to tokenize Chinese characters. This should likely be deactivated for Japanese (see [this
79
+ issue](https://github.com/huggingface/transformers/issues/328)).
80
+ strip_accents (`bool`, *optional*):
81
+ Whether or not to strip all accents. If this option is not specified, then it will be determined by the
82
+ value for `lowercase` (as in the original BERT).
83
+ """
84
+
85
+ vocab_files_names = VOCAB_FILES_NAMES
86
+ model_input_names = ["input_ids", "attention_mask"]
87
+ model = WordPiece
88
+
89
+ def __init__(
90
+ self,
91
+ vocab: str | dict[str, int] | None = None,
92
+ do_lower_case=True,
93
+ bos_token="<s>",
94
+ eos_token="</s>",
95
+ sep_token="</s>",
96
+ cls_token="<s>",
97
+ unk_token="[UNK]",
98
+ pad_token="<pad>",
99
+ mask_token="<mask>",
100
+ tokenize_chinese_chars=True,
101
+ strip_accents=None,
102
+ **kwargs,
103
+ ):
104
+ # Initialize vocab
105
+ self._vocab = vocab if vocab is not None else {}
106
+
107
+ # Initialize the tokenizer with WordPiece model
108
+ self._tokenizer = Tokenizer(WordPiece(self._vocab, unk_token=str(unk_token)))
109
+
110
+ # Set normalizer based on MPNetConverter logic
111
+ self._tokenizer.normalizer = normalizers.BertNormalizer(
112
+ clean_text=True,
113
+ handle_chinese_chars=tokenize_chinese_chars,
114
+ strip_accents=strip_accents,
115
+ lowercase=do_lower_case,
116
+ )
117
+
118
+ # Set pre-tokenizer
119
+ self._tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()
120
+
121
+ # Set decoder
122
+ self._tokenizer.decoder = decoders.WordPiece(prefix="##")
123
+
124
+ # Store do_lower_case for later use
125
+ self.do_lower_case = do_lower_case
126
+
127
+ # Handle special token initialization
128
+ bos_token = AddedToken(bos_token, lstrip=False, rstrip=False) if isinstance(bos_token, str) else bos_token
129
+ eos_token = AddedToken(eos_token, lstrip=False, rstrip=False) if isinstance(eos_token, str) else eos_token
130
+ sep_token = AddedToken(sep_token, lstrip=False, rstrip=False) if isinstance(sep_token, str) else sep_token
131
+ cls_token = AddedToken(cls_token, lstrip=False, rstrip=False) if isinstance(cls_token, str) else cls_token
132
+ unk_token = AddedToken(unk_token, lstrip=False, rstrip=False) if isinstance(unk_token, str) else unk_token
133
+ pad_token = AddedToken(pad_token, lstrip=False, rstrip=False) if isinstance(pad_token, str) else pad_token
134
+
135
+ # Mask token behave like a normal word, i.e. include the space before it
136
+ mask_token = AddedToken(mask_token, lstrip=True, rstrip=False) if isinstance(mask_token, str) else mask_token
137
+
138
+ super().__init__(
139
+ do_lower_case=do_lower_case,
140
+ bos_token=bos_token,
141
+ eos_token=eos_token,
142
+ sep_token=sep_token,
143
+ cls_token=cls_token,
144
+ unk_token=unk_token,
145
+ pad_token=pad_token,
146
+ mask_token=mask_token,
147
+ tokenize_chinese_chars=tokenize_chinese_chars,
148
+ strip_accents=strip_accents,
149
+ **kwargs,
150
+ )
151
+
152
+ # Set post_processor after super().__init__ to ensure we have token IDs
153
+ cls_str = str(self.cls_token)
154
+ sep_str = str(self.sep_token)
155
+ cls_token_id = self.cls_token_id if self.cls_token_id is not None else 0
156
+ sep_token_id = self.sep_token_id if self.sep_token_id is not None else 2
157
+
158
+ self._tokenizer.post_processor = processors.TemplateProcessing(
159
+ single=f"{cls_str}:0 $A:0 {sep_str}:0",
160
+ pair=f"{cls_str}:0 $A:0 {sep_str}:0 {sep_str}:0 $B:1 {sep_str}:1", # MPNet uses two [SEP] tokens
161
+ special_tokens=[
162
+ (cls_str, cls_token_id),
163
+ (sep_str, sep_token_id),
164
+ ],
165
+ )
166
+
167
+ @property
168
+ def mask_token(self) -> str:
169
+ """
170
+ `str`: Mask token, to use when training a model with masked-language modeling. Log an error if used while not
171
+ having been set.
172
+
173
+ MPNet tokenizer has a special mask token to be usable in the fill-mask pipeline. The mask token will greedily
174
+ comprise the space before the *<mask>*.
175
+ """
176
+ if self._mask_token is None:
177
+ if self.verbose:
178
+ logger.error("Using mask_token, but it is not set yet.")
179
+ return None
180
+ return str(self._mask_token)
181
+
182
+ @mask_token.setter
183
+ def mask_token(self, value):
184
+ """
185
+ Overriding the default behavior of the mask token to have it eat the space before it.
186
+
187
+ This is needed to preserve backward compatibility with all the previously used models based on MPNet.
188
+ """
189
+ # Mask token behave like a normal word, i.e. include the space before it
190
+ # So we set lstrip to True
191
+ value = AddedToken(value, lstrip=True, rstrip=False) if isinstance(value, str) else value
192
+ self._mask_token = value
193
+
194
+
195
+ __all__ = ["MPNetTokenizer"]
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/time_series_utils.py ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023 The HuggingFace Inc. team.
2
+ # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """
16
+ Time series distributional output classes and utilities.
17
+ """
18
+
19
+ from collections.abc import Callable
20
+
21
+ import torch
22
+ from torch import nn
23
+ from torch.distributions import (
24
+ AffineTransform,
25
+ Distribution,
26
+ Independent,
27
+ NegativeBinomial,
28
+ Normal,
29
+ StudentT,
30
+ TransformedDistribution,
31
+ )
32
+
33
+
34
+ class AffineTransformed(TransformedDistribution):
35
+ def __init__(self, base_distribution: Distribution, loc=None, scale=None, event_dim=0):
36
+ self.scale = 1.0 if scale is None else scale
37
+ self.loc = 0.0 if loc is None else loc
38
+
39
+ super().__init__(base_distribution, [AffineTransform(loc=self.loc, scale=self.scale, event_dim=event_dim)])
40
+
41
+ @property
42
+ def mean(self):
43
+ """
44
+ Returns the mean of the distribution.
45
+ """
46
+ return self.base_dist.mean * self.scale + self.loc
47
+
48
+ @property
49
+ def variance(self):
50
+ """
51
+ Returns the variance of the distribution.
52
+ """
53
+ return self.base_dist.variance * self.scale**2
54
+
55
+ @property
56
+ def stddev(self):
57
+ """
58
+ Returns the standard deviation of the distribution.
59
+ """
60
+ return self.variance.sqrt()
61
+
62
+
63
+ class ParameterProjection(nn.Module):
64
+ def __init__(
65
+ self, in_features: int, args_dim: dict[str, int], domain_map: Callable[..., tuple[torch.Tensor]], **kwargs
66
+ ) -> None:
67
+ super().__init__(**kwargs)
68
+ self.args_dim = args_dim
69
+ self.proj = nn.ModuleList([nn.Linear(in_features, dim) for dim in args_dim.values()])
70
+ self.domain_map = domain_map
71
+
72
+ def forward(self, x: torch.Tensor) -> tuple[torch.Tensor]:
73
+ params_unbounded = [proj(x) for proj in self.proj]
74
+
75
+ return self.domain_map(*params_unbounded)
76
+
77
+
78
+ class LambdaLayer(nn.Module):
79
+ def __init__(self, function):
80
+ super().__init__()
81
+ self.function = function
82
+
83
+ def forward(self, x, *args):
84
+ return self.function(x, *args)
85
+
86
+
87
+ class DistributionOutput:
88
+ distribution_class: type
89
+ in_features: int
90
+ args_dim: dict[str, int]
91
+
92
+ def __init__(self, dim: int = 1) -> None:
93
+ self.dim = dim
94
+ self.args_dim = {k: dim * self.args_dim[k] for k in self.args_dim}
95
+
96
+ def _base_distribution(self, distr_args):
97
+ if self.dim == 1:
98
+ return self.distribution_class(*distr_args)
99
+ else:
100
+ return Independent(self.distribution_class(*distr_args), 1)
101
+
102
+ def distribution(
103
+ self,
104
+ distr_args,
105
+ loc: torch.Tensor | None = None,
106
+ scale: torch.Tensor | None = None,
107
+ ) -> Distribution:
108
+ distr = self._base_distribution(distr_args)
109
+ if loc is None and scale is None:
110
+ return distr
111
+ else:
112
+ return AffineTransformed(distr, loc=loc, scale=scale, event_dim=self.event_dim)
113
+
114
+ @property
115
+ def event_shape(self) -> tuple:
116
+ r"""
117
+ Shape of each individual event contemplated by the distributions that this object constructs.
118
+ """
119
+ return () if self.dim == 1 else (self.dim,)
120
+
121
+ @property
122
+ def event_dim(self) -> int:
123
+ r"""
124
+ Number of event dimensions, i.e., length of the `event_shape` tuple, of the distributions that this object
125
+ constructs.
126
+ """
127
+ return len(self.event_shape)
128
+
129
+ @property
130
+ def value_in_support(self) -> float:
131
+ r"""
132
+ A float that will have a valid numeric value when computing the log-loss of the corresponding distribution. By
133
+ default 0.0. This value will be used when padding data series.
134
+ """
135
+ return 0.0
136
+
137
+ def get_parameter_projection(self, in_features: int) -> nn.Module:
138
+ r"""
139
+ Return the parameter projection layer that maps the input to the appropriate parameters of the distribution.
140
+ """
141
+ return ParameterProjection(
142
+ in_features=in_features,
143
+ args_dim=self.args_dim,
144
+ domain_map=LambdaLayer(self.domain_map),
145
+ )
146
+
147
+ def domain_map(self, *args: torch.Tensor):
148
+ r"""
149
+ Converts arguments to the right shape and domain. The domain depends on the type of distribution, while the
150
+ correct shape is obtained by reshaping the trailing axis in such a way that the returned tensors define a
151
+ distribution of the right event_shape.
152
+ """
153
+ raise NotImplementedError()
154
+
155
+ @staticmethod
156
+ def squareplus(x: torch.Tensor) -> torch.Tensor:
157
+ r"""
158
+ Helper to map inputs to the positive orthant by applying the square-plus operation. Reference:
159
+ https://twitter.com/jon_barron/status/1387167648669048833
160
+ """
161
+ return (x + torch.sqrt(torch.square(x) + 4.0)) / 2.0
162
+
163
+
164
+ class StudentTOutput(DistributionOutput):
165
+ """
166
+ Student-T distribution output class.
167
+ """
168
+
169
+ args_dim: dict[str, int] = {"df": 1, "loc": 1, "scale": 1}
170
+ distribution_class: type = StudentT
171
+
172
+ @classmethod
173
+ def domain_map(cls, df: torch.Tensor, loc: torch.Tensor, scale: torch.Tensor):
174
+ scale = cls.squareplus(scale).clamp_min(torch.finfo(scale.dtype).eps)
175
+ df = 2.0 + cls.squareplus(df)
176
+ return df.squeeze(-1), loc.squeeze(-1), scale.squeeze(-1)
177
+
178
+
179
+ class NormalOutput(DistributionOutput):
180
+ """
181
+ Normal distribution output class.
182
+ """
183
+
184
+ args_dim: dict[str, int] = {"loc": 1, "scale": 1}
185
+ distribution_class: type = Normal
186
+
187
+ @classmethod
188
+ def domain_map(cls, loc: torch.Tensor, scale: torch.Tensor):
189
+ scale = cls.squareplus(scale).clamp_min(torch.finfo(scale.dtype).eps)
190
+ return loc.squeeze(-1), scale.squeeze(-1)
191
+
192
+
193
+ class NegativeBinomialOutput(DistributionOutput):
194
+ """
195
+ Negative Binomial distribution output class.
196
+ """
197
+
198
+ args_dim: dict[str, int] = {"total_count": 1, "logits": 1}
199
+ distribution_class: type = NegativeBinomial
200
+
201
+ @classmethod
202
+ def domain_map(cls, total_count: torch.Tensor, logits: torch.Tensor):
203
+ total_count = cls.squareplus(total_count)
204
+ return total_count.squeeze(-1), logits.squeeze(-1)
205
+
206
+ def _base_distribution(self, distr_args) -> Distribution:
207
+ total_count, logits = distr_args
208
+ if self.dim == 1:
209
+ return self.distribution_class(total_count=total_count, logits=logits)
210
+ else:
211
+ return Independent(self.distribution_class(total_count=total_count, logits=logits), 1)
212
+
213
+ # Overwrites the parent class method. We cannot scale using the affine
214
+ # transformation since negative binomial should return integers. Instead
215
+ # we scale the parameters.
216
+ def distribution(
217
+ self, distr_args, loc: torch.Tensor | None = None, scale: torch.Tensor | None = None
218
+ ) -> Distribution:
219
+ total_count, logits = distr_args
220
+
221
+ if scale is not None:
222
+ # See scaling property of Gamma.
223
+ logits += scale.log()
224
+
225
+ return self._base_distribution((total_count, logits))
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/trainer_pt_utils.py ADDED
@@ -0,0 +1,1336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020-present the HuggingFace Inc. team.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """
15
+ Torch utilities for the Trainer class.
16
+ """
17
+
18
+ import contextlib
19
+ import copy
20
+ import datetime
21
+ import io
22
+ import json
23
+ import math
24
+ import os
25
+ import re
26
+ import sys
27
+ import warnings
28
+ from collections.abc import Iterator, Mapping
29
+ from contextlib import contextmanager
30
+ from dataclasses import dataclass, field
31
+ from itertools import chain
32
+ from logging import StreamHandler
33
+ from typing import Any
34
+
35
+ import numpy as np
36
+ import torch
37
+ import torch.distributed as dist
38
+ from packaging import version
39
+ from torch import nn
40
+ from torch.utils.data import Dataset, IterableDataset, RandomSampler, Sampler
41
+ from torch.utils.data.distributed import DistributedSampler
42
+
43
+ from .integrations.deepspeed import is_deepspeed_zero3_enabled
44
+ from .tokenization_utils_base import BatchEncoding
45
+ from .utils import (
46
+ is_sagemaker_mp_enabled,
47
+ is_torch_available,
48
+ is_torch_xla_available,
49
+ is_training_run_on_sagemaker,
50
+ logging,
51
+ )
52
+
53
+
54
+ if is_training_run_on_sagemaker():
55
+ logging.add_handler(StreamHandler(sys.stdout))
56
+
57
+ if is_torch_xla_available():
58
+ import torch_xla.runtime as xr
59
+
60
+ if is_torch_available():
61
+ from torch.optim.lr_scheduler import LRScheduler
62
+
63
+
64
+ logger = logging.get_logger(__name__)
65
+
66
+
67
+ def get_dataloader_sampler(dataloader):
68
+ if hasattr(dataloader, "batch_sampler") and dataloader.batch_sampler is not None:
69
+ return get_dataloader_sampler(dataloader.batch_sampler)
70
+ elif hasattr(dataloader, "sampler"):
71
+ return dataloader.sampler
72
+
73
+
74
+ def atleast_1d(tensor_or_array: torch.Tensor | np.ndarray):
75
+ if isinstance(tensor_or_array, torch.Tensor):
76
+ tensor_or_array = torch.atleast_1d(tensor_or_array)
77
+ else:
78
+ tensor_or_array = np.atleast_1d(tensor_or_array)
79
+ return tensor_or_array
80
+
81
+
82
+ def torch_pad_and_concatenate(tensor1, tensor2, padding_index=-100):
83
+ """Concatenates `tensor1` and `tensor2` on first axis, applying padding on the second if necessary."""
84
+ tensor1 = atleast_1d(tensor1)
85
+ tensor2 = atleast_1d(tensor2)
86
+
87
+ if len(tensor1.shape) == 1 or tensor1.shape[1] == tensor2.shape[1]:
88
+ return torch.cat((tensor1, tensor2), dim=0)
89
+
90
+ # Let's figure out the new shape
91
+ new_shape = (tensor1.shape[0] + tensor2.shape[0], max(tensor1.shape[1], tensor2.shape[1])) + tensor1.shape[2:]
92
+
93
+ # Now let's fill the result tensor
94
+ result = tensor1.new_full(new_shape, padding_index)
95
+ result[: tensor1.shape[0], : tensor1.shape[1]] = tensor1
96
+ result[tensor1.shape[0] :, : tensor2.shape[1]] = tensor2
97
+ return result
98
+
99
+
100
+ def numpy_pad_and_concatenate(array1, array2, padding_index=-100):
101
+ """Concatenates `array1` and `array2` on first axis, applying padding on the second if necessary."""
102
+ array1 = atleast_1d(array1)
103
+ array2 = atleast_1d(array2)
104
+
105
+ if len(array1.shape) == 1 or array1.shape[1] == array2.shape[1]:
106
+ return np.concatenate((array1, array2), axis=0)
107
+
108
+ # Let's figure out the new shape
109
+ new_shape = (array1.shape[0] + array2.shape[0], max(array1.shape[1], array2.shape[1])) + array1.shape[2:]
110
+
111
+ # Now let's fill the result tensor
112
+ result = np.full_like(array1, padding_index, shape=new_shape)
113
+ result[: array1.shape[0], : array1.shape[1]] = array1
114
+ result[array1.shape[0] :, : array2.shape[1]] = array2
115
+ return result
116
+
117
+
118
+ def nested_concat(tensors, new_tensors, padding_index=-100):
119
+ """
120
+ Concat the `new_tensors` to `tensors` on the first dim and pad them on the second if needed. Works for tensors or
121
+ nested list/tuples/dict of tensors.
122
+ """
123
+ if not (isinstance(tensors, torch.Tensor) and isinstance(new_tensors, torch.Tensor)):
124
+ assert type(tensors) is type(new_tensors), (
125
+ f"Expected `tensors` and `new_tensors` to have the same type but found {type(tensors)} and {type(new_tensors)}."
126
+ )
127
+ if isinstance(tensors, (list, tuple)):
128
+ return type(tensors)(nested_concat(t, n, padding_index=padding_index) for t, n in zip(tensors, new_tensors))
129
+ elif isinstance(tensors, torch.Tensor):
130
+ return torch_pad_and_concatenate(tensors, new_tensors, padding_index=padding_index)
131
+ elif isinstance(tensors, Mapping):
132
+ return type(tensors)(
133
+ {k: nested_concat(t, new_tensors[k], padding_index=padding_index) for k, t in tensors.items()}
134
+ )
135
+ elif isinstance(tensors, np.ndarray):
136
+ return numpy_pad_and_concatenate(tensors, new_tensors, padding_index=padding_index)
137
+ else:
138
+ raise TypeError(f"Unsupported type for concatenation: got {type(tensors)}")
139
+
140
+
141
+ def find_batch_size(tensors):
142
+ """
143
+ Find the first dimension of a tensor in a nested list/tuple/dict of tensors.
144
+ """
145
+ if isinstance(tensors, (list, tuple)):
146
+ for t in tensors:
147
+ result = find_batch_size(t)
148
+ if result is not None:
149
+ return result
150
+ elif isinstance(tensors, Mapping):
151
+ for value in tensors.values():
152
+ result = find_batch_size(value)
153
+ if result is not None:
154
+ return result
155
+ elif isinstance(tensors, (torch.Tensor, np.ndarray)):
156
+ return tensors.shape[0] if len(tensors.shape) >= 1 else None
157
+
158
+
159
+ def nested_numpify(tensors):
160
+ "Numpify `tensors` (even if it's a nested list/tuple/dict of tensors)."
161
+ if isinstance(tensors, (list, tuple)):
162
+ return type(tensors)(nested_numpify(t) for t in tensors)
163
+ if isinstance(tensors, Mapping):
164
+ return type(tensors)({k: nested_numpify(t) for k, t in tensors.items()})
165
+
166
+ t = tensors.cpu()
167
+ if t.dtype == torch.bfloat16:
168
+ # As of Numpy 1.21.4, NumPy does not support bfloat16 (see
169
+ # https://github.com/numpy/numpy/blob/a47ecdea856986cd60eabbd53265c2ca5916ad5d/doc/source/user/basics.types.rst ).
170
+ # Until Numpy adds bfloat16, we must convert float32.
171
+ t = t.to(torch.float32)
172
+ return t.numpy()
173
+
174
+
175
+ def nested_detach(tensors):
176
+ "Detach `tensors` (even if it's a nested list/tuple/dict of tensors)."
177
+ if isinstance(tensors, (list, tuple)):
178
+ return type(tensors)(nested_detach(t) for t in tensors)
179
+ elif isinstance(tensors, Mapping):
180
+ return type(tensors)({k: nested_detach(t) for k, t in tensors.items()})
181
+ return tensors.detach() if isinstance(tensors, torch.Tensor) else tensors
182
+
183
+
184
+ def nested_xla_mesh_reduce(tensors, name):
185
+ if is_torch_xla_available():
186
+ import torch_xla.core.xla_model as xm
187
+
188
+ if isinstance(tensors, (list, tuple)):
189
+ return type(tensors)(nested_xla_mesh_reduce(t, f"{name}_{i}") for i, t in enumerate(tensors))
190
+ if isinstance(tensors, Mapping):
191
+ return type(tensors)(
192
+ {k: nested_xla_mesh_reduce(t, f"{name}_{i}") for i, (k, t) in enumerate(tensors.items())}
193
+ )
194
+
195
+ tensors = atleast_1d(tensors)
196
+ return xm.mesh_reduce(name, tensors, torch.cat)
197
+ else:
198
+ raise ImportError("Torch xla must be installed to use `nested_xla_mesh_reduce`")
199
+
200
+
201
+ def distributed_concat(tensor: Any, num_total_examples: int | None = None) -> Any:
202
+ try:
203
+ if isinstance(tensor, (tuple, list)):
204
+ return type(tensor)(distributed_concat(t, num_total_examples) for t in tensor)
205
+ if isinstance(tensor, Mapping):
206
+ return type(tensor)({k: distributed_concat(t, num_total_examples) for k, t in tensor.items()})
207
+ tensor = atleast_1d(tensor).contiguous()
208
+ output_tensors = [tensor.clone() for _ in range(dist.get_world_size())]
209
+ dist.all_gather(output_tensors, tensor)
210
+ concat = torch.cat(output_tensors, dim=0)
211
+
212
+ # truncate the dummy elements added by SequentialDistributedSampler
213
+ if num_total_examples is not None:
214
+ concat = concat[:num_total_examples]
215
+ return concat
216
+ except AssertionError:
217
+ raise AssertionError("Not currently using distributed training")
218
+
219
+
220
+ def nested_gather(tensors, parallel_mode, name=None):
221
+ """
222
+ Gather value of `tensors` (tensor or list/tuple of nested tensors) across processes.
223
+ """
224
+ from .training_args import ParallelMode
225
+
226
+ if tensors is None:
227
+ return
228
+ if is_torch_xla_available():
229
+ if name is None:
230
+ name = "nested_gather"
231
+ tensors = nested_xla_mesh_reduce(tensors, name)
232
+ elif is_sagemaker_mp_enabled():
233
+ tensors = smp_gather(tensors)
234
+ elif parallel_mode == ParallelMode.DISTRIBUTED:
235
+ tensors = distributed_concat(tensors)
236
+ return tensors
237
+
238
+
239
+ def is_attention_mask_causal(attention_mask):
240
+ """
241
+ Check if an attention mask is causal (compatible with causal attention).
242
+
243
+ Context parallelism only supports causal attention patterns. This function
244
+ checks if the provided attention mask is compatible.
245
+
246
+ Args:
247
+ attention_mask (`torch.Tensor`): The attention mask to check.
248
+
249
+ Returns:
250
+ `bool`: True if the mask is causal or compatible with causal attention.
251
+ """
252
+ if attention_mask is None:
253
+ return True # No mask is considered causal (model uses default causal masking)
254
+
255
+ # Handle different mask dimensions
256
+ if attention_mask.dim() == 2:
257
+ # (batch_size, seq_len) - standard padding mask, compatible with causal attention
258
+ return True
259
+ elif attention_mask.dim() in [3, 4]:
260
+ # (batch_size, seq_len, seq_len) or (batch_size, num_heads, seq_len, seq_len)
261
+ # Check if it's lower triangular (causal)
262
+ seq_len = attention_mask.shape[-1]
263
+ if seq_len <= 1:
264
+ return True # Single token or empty is always causal
265
+
266
+ # Take first batch and head (if 4D) for checking pattern
267
+ if attention_mask.dim() == 4:
268
+ mask = attention_mask[0, 0] # First batch, first head
269
+ else:
270
+ mask = attention_mask[0] # First batch
271
+
272
+ # Check if upper triangular part is masked (should be 0 or very negative for causal)
273
+ upper_triangular = torch.triu(mask, diagonal=1)
274
+
275
+ # For causal masks, upper triangular should be 0 or very negative (like -inf)
276
+ # Use a reasonable threshold to handle float precision issues
277
+ is_causal = torch.all(upper_triangular <= 1e-6) or torch.all(upper_triangular < -1e4)
278
+ return is_causal.item() if isinstance(is_causal, torch.Tensor) else is_causal
279
+
280
+ # For unknown dimensions, be conservative and reject
281
+ return False
282
+
283
+
284
+ def distributed_broadcast_scalars(
285
+ scalars: list[int | float],
286
+ num_total_examples: int | None = None,
287
+ device: torch.device | None = torch.device("cuda"),
288
+ ) -> torch.Tensor:
289
+ try:
290
+ tensorized_scalar = torch.tensor(scalars, device=device)
291
+ output_tensors = [tensorized_scalar.clone() for _ in range(dist.get_world_size())]
292
+ dist.all_gather(output_tensors, tensorized_scalar)
293
+ concat = torch.cat(output_tensors, dim=0)
294
+
295
+ # truncate the dummy elements added by SequentialDistributedSampler
296
+ if num_total_examples is not None:
297
+ concat = concat[:num_total_examples]
298
+ return concat
299
+ except AssertionError:
300
+ raise AssertionError("Not currently using distributed training")
301
+
302
+
303
+ def reissue_pt_warnings(caught_warnings):
304
+ # Reissue warnings
305
+ if len(caught_warnings) > 1:
306
+ for w in caught_warnings:
307
+ if w.category is not UserWarning:
308
+ warnings.warn(w.message, w.category)
309
+
310
+
311
+ @contextmanager
312
+ def torch_distributed_zero_first(local_rank: int):
313
+ """
314
+ Decorator to make all processes in distributed training wait for each local_master to do something.
315
+
316
+ Args:
317
+ local_rank (`int`): The rank of the local process.
318
+ """
319
+ if local_rank not in [-1, 0]:
320
+ dist.barrier()
321
+ yield
322
+ if local_rank == 0:
323
+ dist.barrier()
324
+
325
+
326
+ class DistributedSamplerWithLoop(DistributedSampler):
327
+ """
328
+ Like a torch.utils.data.distributed.DistributedSampler` but loops at the end back to the beginning of the shuffled
329
+ samples to make each process have a round multiple of batch_size samples.
330
+
331
+ Args:
332
+ dataset (`torch.utils.data.Dataset`):
333
+ Dataset used for sampling.
334
+ batch_size (`int`):
335
+ The batch size used with this sampler
336
+ kwargs (`dict[str, Any]`, *optional*):
337
+ All other keyword arguments passed to `DistributedSampler`.
338
+ """
339
+
340
+ def __init__(self, dataset, batch_size, **kwargs):
341
+ super().__init__(dataset, **kwargs)
342
+ self.batch_size = batch_size
343
+
344
+ def __iter__(self):
345
+ indices = list(super().__iter__())
346
+ remainder = 0 if len(indices) % self.batch_size == 0 else self.batch_size - len(indices) % self.batch_size
347
+ # DistributedSampler already added samples from the beginning to make the number of samples a round multiple
348
+ # of the world size, so we skip those.
349
+ start_remainder = 1 if self.rank < len(self.dataset) % self.num_replicas else 0
350
+ indices += indices[start_remainder : start_remainder + remainder]
351
+ return iter(indices)
352
+
353
+
354
+ class EvalLoopContainer:
355
+ """
356
+ Container to store intermediate results of evaluation loop.
357
+
358
+ Args:
359
+ do_nested_concat (`bool`, *optional*, defaults to `True`):
360
+ If set to `True`, each iteration will recursively concatenate a new object containing tensors to
361
+ the existing stored tensors, provided that the structure of the existing object and the new one
362
+ are identical. If set to `False`, all newly added tensors will be stored in a list.
363
+ padding_index (`int`, *optional*, defaults to -100):
364
+ Value used to pad tensors of different shapes when `do_nested_concat=True`.
365
+ """
366
+
367
+ def __init__(self, do_nested_concat: bool = True, padding_index: int = -100):
368
+ self.do_nested_concat = do_nested_concat
369
+ self.padding_index = padding_index
370
+ self.tensors = None
371
+ self.arrays = None
372
+
373
+ def add(self, tensors) -> None:
374
+ """Add tensors to the stored objects. If `do_nested_concat=True`, the tensors will be concatenated recursively."""
375
+ if self.tensors is None:
376
+ self.tensors = tensors if self.do_nested_concat else [tensors]
377
+ elif self.do_nested_concat:
378
+ self.tensors = nested_concat(self.tensors, tensors, padding_index=self.padding_index)
379
+ else:
380
+ self.tensors.append(tensors)
381
+
382
+ def to_cpu_and_numpy(self) -> None:
383
+ """Move tensors in stored objects to CPU and convert them to numpy arrays."""
384
+
385
+ # Check if we have something to add, if not just return
386
+ if self.tensors is None:
387
+ return
388
+
389
+ new_arrays = nested_numpify(self.tensors)
390
+ if self.arrays is None:
391
+ self.arrays = new_arrays
392
+ elif self.do_nested_concat:
393
+ self.arrays = nested_concat(self.arrays, new_arrays, padding_index=self.padding_index)
394
+ else:
395
+ self.arrays.extend(new_arrays)
396
+
397
+ # reset device tensors after adding to cpu
398
+ self.tensors = None
399
+
400
+ def get_arrays(self):
401
+ """Returns the numpified and moved to CPU stored objects."""
402
+ self.to_cpu_and_numpy()
403
+ return self.arrays
404
+
405
+
406
+ def get_tpu_sampler(dataset: torch.utils.data.Dataset, batch_size: int):
407
+ if xr.world_size() <= 1:
408
+ return RandomSampler(dataset)
409
+ return DistributedSampler(dataset, num_replicas=xr.world_size(), rank=xr.global_ordinal())
410
+
411
+
412
+ def nested_new_like(arrays, num_samples, padding_index=-100):
413
+ """Create the same nested structure as `arrays` with a first dimension always at `num_samples`."""
414
+ if isinstance(arrays, (list, tuple)):
415
+ return type(arrays)(nested_new_like(x, num_samples) for x in arrays)
416
+ return np.full_like(arrays, padding_index, shape=(num_samples, *arrays.shape[1:]))
417
+
418
+
419
+ def expand_like(arrays, new_seq_length, padding_index=-100):
420
+ """Expand the `arrays` so that the second dimension grows to `new_seq_length`. Uses `padding_index` for padding."""
421
+ result = np.full_like(arrays, padding_index, shape=(arrays.shape[0], new_seq_length) + arrays.shape[2:])
422
+ result[:, : arrays.shape[1]] = arrays
423
+ return result
424
+
425
+
426
+ def nested_truncate(tensors, limit):
427
+ "Truncate `tensors` at `limit` (even if it's a nested list/tuple/dict of tensors)."
428
+ if isinstance(tensors, (list, tuple)):
429
+ return type(tensors)(nested_truncate(t, limit) for t in tensors)
430
+ if isinstance(tensors, Mapping):
431
+ return type(tensors)({k: nested_truncate(t, limit) for k, t in tensors.items()})
432
+
433
+ return tensors[:limit]
434
+
435
+
436
+ @dataclass
437
+ class LabelSmoother:
438
+ """
439
+ Adds label-smoothing on a pre-computed output from a Transformers model.
440
+
441
+ Args:
442
+ epsilon (`float`, *optional*, defaults to 0.1):
443
+ The label smoothing factor.
444
+ ignore_index (`int`, *optional*, defaults to -100):
445
+ The index in the labels to ignore when computing the loss.
446
+ """
447
+
448
+ epsilon: float = 0.1
449
+ ignore_index: int = -100
450
+
451
+ def __call__(self, model_output, labels, shift_labels=False):
452
+ logits = model_output["logits"] if isinstance(model_output, dict) else model_output[0]
453
+ if shift_labels:
454
+ logits = logits[..., :-1, :].contiguous()
455
+ labels = labels[..., 1:].contiguous()
456
+
457
+ log_probs = -nn.functional.log_softmax(logits, dim=-1)
458
+ if labels.dim() == log_probs.dim() - 1:
459
+ labels = labels.unsqueeze(-1)
460
+
461
+ padding_mask = labels.eq(self.ignore_index)
462
+ # In case the ignore_index is -100, the gather will fail, so we replace labels by 0. The padding_mask
463
+ # will ignore them in any case.
464
+ labels = torch.clamp(labels, min=0)
465
+ nll_loss = log_probs.gather(dim=-1, index=labels)
466
+ # works for fp16 input tensor too, by internally upcasting it to fp32
467
+ smoothed_loss = log_probs.sum(dim=-1, keepdim=True, dtype=torch.float32)
468
+
469
+ nll_loss.masked_fill_(padding_mask, 0.0)
470
+ smoothed_loss.masked_fill_(padding_mask, 0.0)
471
+
472
+ # Take the mean over the label dimensions, then divide by the number of active elements (i.e. not-padded):
473
+ num_active_elements = padding_mask.numel() - padding_mask.long().sum()
474
+ nll_loss = nll_loss.sum() / num_active_elements
475
+ smoothed_loss = smoothed_loss.sum() / (num_active_elements * log_probs.shape[-1])
476
+ return (1 - self.epsilon) * nll_loss + self.epsilon * smoothed_loss
477
+
478
+
479
+ def get_length_grouped_indices(lengths, batch_size, mega_batch_mult=None, generator=None):
480
+ """
481
+ Return a list of indices so that each slice of `batch_size` consecutive indices correspond to elements of similar
482
+ lengths. To do this, the indices are:
483
+
484
+ - randomly permuted
485
+ - grouped in mega-batches of size `mega_batch_mult * batch_size`
486
+ - sorted by length in each mega-batch
487
+
488
+ The result is the concatenation of all mega-batches, with the batch of `batch_size` containing the element of
489
+ maximum length placed first, so that an OOM happens sooner rather than later.
490
+ """
491
+ # Default for mega_batch_mult: 50 or the number to get 4 megabatches, whichever is smaller.
492
+ if mega_batch_mult is None:
493
+ mega_batch_mult = min(len(lengths) // (batch_size * 4), 50)
494
+ # Just in case, for tiny datasets
495
+ if mega_batch_mult == 0:
496
+ mega_batch_mult = 1
497
+
498
+ # We need to use torch for the random part as a distributed sampler will set the random seed for torch.
499
+ indices = torch.randperm(len(lengths), generator=generator)
500
+ megabatch_size = mega_batch_mult * batch_size
501
+ megabatches = [indices[i : i + megabatch_size].tolist() for i in range(0, len(lengths), megabatch_size)]
502
+ megabatches = [sorted(megabatch, key=lambda i: lengths[i], reverse=True) for megabatch in megabatches]
503
+
504
+ # The rest is to get the biggest batch first.
505
+ # Since each megabatch is sorted by descending length, the longest element is the first
506
+ megabatch_maximums = [lengths[megabatch[0]] for megabatch in megabatches]
507
+ max_idx = torch.argmax(torch.tensor(megabatch_maximums)).item()
508
+ # Switch to put the longest element in first position
509
+ megabatches[0][0], megabatches[max_idx][0] = megabatches[max_idx][0], megabatches[0][0]
510
+
511
+ return [i for megabatch in megabatches for i in megabatch]
512
+
513
+
514
+ class LengthGroupedSampler(Sampler):
515
+ r"""
516
+ Sampler that samples indices in a way that groups together features of the dataset of roughly the same length while
517
+ keeping a bit of randomness.
518
+ """
519
+
520
+ def __init__(
521
+ self,
522
+ batch_size: int,
523
+ dataset: Dataset | None = None,
524
+ lengths: list[int] | None = None,
525
+ model_input_name: str | None = None,
526
+ generator=None,
527
+ ):
528
+ if dataset is None and lengths is None:
529
+ raise ValueError("One of dataset and lengths must be provided.")
530
+
531
+ self.batch_size = batch_size
532
+ if lengths is None:
533
+ model_input_name = model_input_name if model_input_name is not None else "input_ids"
534
+ if not isinstance(dataset[0], (dict, BatchEncoding)) or model_input_name not in dataset[0]:
535
+ raise ValueError(
536
+ "Can only automatically infer lengths for datasets whose items are dictionaries with an "
537
+ f"'{model_input_name}' key."
538
+ )
539
+ lengths = [len(feature[model_input_name]) for feature in dataset]
540
+ elif isinstance(lengths, torch.Tensor):
541
+ logger.info(
542
+ "If lengths is a torch.Tensor, LengthGroupedSampler will be slow. Converting lengths to list[int]..."
543
+ )
544
+ lengths = lengths.tolist()
545
+
546
+ self.lengths = lengths
547
+ self.generator = generator
548
+
549
+ def __len__(self):
550
+ return len(self.lengths)
551
+
552
+ def __iter__(self):
553
+ indices = get_length_grouped_indices(self.lengths, self.batch_size, generator=self.generator)
554
+ return iter(indices)
555
+
556
+
557
+ class DistributedLengthGroupedSampler(DistributedSampler):
558
+ r"""
559
+ Distributed Sampler that samples indices in a way that groups together features of the dataset of roughly the same
560
+ length while keeping a bit of randomness.
561
+ """
562
+
563
+ # Copied and adapted from PyTorch DistributedSampler.
564
+ def __init__(
565
+ self,
566
+ batch_size: int,
567
+ dataset: Dataset | None = None,
568
+ num_replicas: int | None = None,
569
+ rank: int | None = None,
570
+ seed: int = 0,
571
+ drop_last: bool = False,
572
+ lengths: list[int] | None = None,
573
+ model_input_name: str | None = None,
574
+ ):
575
+ if dataset is None and lengths is None:
576
+ raise ValueError("One of dataset and lengths must be provided.")
577
+ if num_replicas is None:
578
+ if not dist.is_available():
579
+ raise RuntimeError("Requires distributed package to be available")
580
+ num_replicas = dist.get_world_size()
581
+ if rank is None:
582
+ if not dist.is_available():
583
+ raise RuntimeError("Requires distributed package to be available")
584
+ rank = dist.get_rank()
585
+
586
+ self.batch_size = batch_size
587
+ self.num_replicas = num_replicas
588
+ self.rank = rank
589
+ self.epoch = 0
590
+ self.drop_last = drop_last
591
+
592
+ if lengths is None:
593
+ model_input_name = model_input_name if model_input_name is not None else "input_ids"
594
+ if not isinstance(dataset[0], (dict, BatchEncoding)) or model_input_name not in dataset[0]:
595
+ raise ValueError(
596
+ "Can only automatically infer lengths for datasets whose items are dictionaries with an "
597
+ f"'{model_input_name}' key."
598
+ )
599
+ lengths = [len(feature[model_input_name]) for feature in dataset]
600
+ elif isinstance(lengths, torch.Tensor):
601
+ logger.info(
602
+ "If lengths is a torch.Tensor, DistributedLengthGroupedSampler will be slow. Converting lengths to"
603
+ " list[int]..."
604
+ )
605
+ lengths = lengths.tolist()
606
+
607
+ self.lengths = lengths
608
+
609
+ # If the dataset length is evenly divisible by # of replicas, then there
610
+ # is no need to drop any data, since the dataset will be split equally.
611
+ if self.drop_last and len(self.lengths) % self.num_replicas != 0:
612
+ # Split to nearest available length that is evenly divisible.
613
+ # This is to ensure each rank receives the same amount of data when
614
+ # using this Sampler.
615
+ self.num_samples = math.ceil((len(self.lengths) - self.num_replicas) / self.num_replicas)
616
+ else:
617
+ self.num_samples = math.ceil(len(self.lengths) / self.num_replicas)
618
+ self.total_size = self.num_samples * self.num_replicas
619
+ self.seed = seed
620
+
621
+ def __iter__(self) -> Iterator:
622
+ # Deterministically shuffle based on epoch and seed
623
+ g = torch.Generator()
624
+ g.manual_seed(self.seed + self.epoch)
625
+ indices = get_length_grouped_indices(self.lengths, self.batch_size, generator=g)
626
+
627
+ if not self.drop_last:
628
+ # add extra samples to make it evenly divisible
629
+ indices += indices[: (self.total_size - len(indices))]
630
+ else:
631
+ # remove tail of data to make it evenly divisible
632
+ indices = indices[: self.total_size]
633
+ assert len(indices) == self.total_size
634
+
635
+ # subsample
636
+ indices = indices[self.rank : self.total_size : self.num_replicas]
637
+ assert len(indices) == self.num_samples
638
+
639
+ return iter(indices)
640
+
641
+
642
+ class ShardSampler(Sampler):
643
+ """
644
+ Sampler that shards batches between several processes. Dispatches indices batch by batch: on 2 processes with batch
645
+ size 4, the first two batches are `[0, 1, 2, 3, 4, 5, 6, 7]` and `[8, 9, 10, 11, 12, 13, 14, 15]`, which shard into
646
+ `[0, 1, 2, 3]` and `[8, 9, 10, 11]` for GPU-0 and `[4, 5, 6, 7]` and `[12, 13, 14, 15]` for GPU-1.
647
+
648
+ The sampler thus yields `[0, 1, 2, 3, 8, 9, 10, 11]` on GPU-0 and `[4, 5, 6, 7, 12, 13, 14, 15]` on GPU-1.
649
+ """
650
+
651
+ def __init__(
652
+ self,
653
+ dataset: Dataset,
654
+ batch_size: int = 1,
655
+ drop_last: bool = False,
656
+ num_processes: int = 1,
657
+ process_index: int = 0,
658
+ ):
659
+ self.dataset = dataset
660
+ self.batch_size = batch_size
661
+ self.drop_last = drop_last
662
+ self.num_processes = num_processes
663
+ self.process_index = process_index
664
+
665
+ self.total_batch_size = total_batch_size = batch_size * num_processes
666
+
667
+ num_batches = len(dataset) // total_batch_size if drop_last else math.ceil(len(dataset) / total_batch_size)
668
+ self.total_num_samples = num_batches * total_batch_size
669
+
670
+ def __iter__(self):
671
+ indices = list(range(len(self.dataset)))
672
+
673
+ # Add extra samples to make it evenly divisible. While loop is there in the edge case we have a tiny dataset
674
+ # and it needs to be done several times.
675
+ while len(indices) < self.total_num_samples:
676
+ indices += indices[: (self.total_num_samples - len(indices))]
677
+
678
+ result = []
679
+ for batch_start in range(self.batch_size * self.process_index, self.total_num_samples, self.total_batch_size):
680
+ result += indices[batch_start : batch_start + self.batch_size]
681
+
682
+ return iter(result)
683
+
684
+ def __len__(self):
685
+ # Each shard only sees a fraction of total_num_samples.
686
+ return self.total_num_samples // self.num_processes
687
+
688
+
689
+ class IterableDatasetShard(IterableDataset):
690
+ """
691
+ Wraps a PyTorch `IterableDataset` to generate samples for one of the processes only. Instances of this class will
692
+ always yield a number of samples that is a round multiple of the actual batch size (which is `batch_size x
693
+ num_processes`). Depending on the value of the `drop_last` attribute, it will either stop the iteration at the
694
+ first batch that would be too small or loop with indices from the beginning.
695
+
696
+ On two processes with an iterable dataset yielding of `[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]` with a batch size of
697
+ 2:
698
+
699
+ - the shard on process 0 will yield `[0, 1, 4, 5, 8, 9]` so will see batches `[0, 1]`, `[4, 5]`, `[8, 9]`
700
+ - the shard on process 1 will yield `[2, 3, 6, 7, 10, 11]` so will see batches `[2, 3]`, `[6, 7]`, `[10, 11]`
701
+
702
+ <Tip warning={true}>
703
+
704
+ If your IterableDataset implements some randomization that needs to be applied the same way on all processes
705
+ (for instance, a shuffling), you should use a `torch.Generator` in a `generator` attribute of the `dataset` to
706
+ generate your random numbers and call the [`~trainer_pt_utils.IterableDatasetShard.set_epoch`] method of this
707
+ object. It will set the seed of this `generator` to `seed + epoch` on all processes before starting the
708
+ iteration. Alternatively, you can also implement a `set_epoch()` method in your iterable dataset to deal with
709
+ this.
710
+
711
+ </Tip>
712
+
713
+ Args:
714
+ dataset (`torch.utils.data.IterableDataset`):
715
+ The batch sampler to split in several shards.
716
+ batch_size (`int`, *optional*, defaults to 1):
717
+ The size of the batches per shard.
718
+ drop_last (`bool`, *optional*, defaults to `False`):
719
+ Whether or not to drop the last incomplete batch or complete the last batches by using the samples from the
720
+ beginning.
721
+ num_processes (`int`, *optional*, defaults to 1):
722
+ The number of processes running concurrently.
723
+ process_index (`int`, *optional*, defaults to 0):
724
+ The index of the current process.
725
+ seed (`int`, *optional*, defaults to 0):
726
+ A random seed that will be used for the random number generation in
727
+ [`~trainer_pt_utils.IterableDatasetShard.set_epoch`].
728
+ """
729
+
730
+ def __init__(
731
+ self,
732
+ dataset: IterableDataset,
733
+ batch_size: int = 1,
734
+ drop_last: bool = False,
735
+ num_processes: int = 1,
736
+ process_index: int = 0,
737
+ seed: int = 0,
738
+ ):
739
+ self.dataset = dataset
740
+ self.batch_size = batch_size
741
+ self.drop_last = drop_last
742
+ self.num_processes = num_processes
743
+ self.process_index = process_index
744
+ self.seed = seed
745
+ self.epoch = 0
746
+ self.num_examples = 0
747
+
748
+ def set_epoch(self, epoch):
749
+ self.epoch = epoch
750
+ if hasattr(self.dataset, "set_epoch"):
751
+ self.dataset.set_epoch(epoch)
752
+
753
+ def __iter__(self):
754
+ self.num_examples = 0
755
+ if (
756
+ not hasattr(self.dataset, "set_epoch")
757
+ and hasattr(self.dataset, "generator")
758
+ and isinstance(self.dataset.generator, torch.Generator)
759
+ ):
760
+ self.dataset.generator.manual_seed(self.seed + self.epoch)
761
+ real_batch_size = self.batch_size * self.num_processes
762
+ process_slice = range(self.process_index * self.batch_size, (self.process_index + 1) * self.batch_size)
763
+
764
+ first_batch = None
765
+ current_batch = []
766
+ for element in self.dataset:
767
+ self.num_examples += 1
768
+ current_batch.append(element)
769
+ # Wait to have a full batch before yielding elements.
770
+ if len(current_batch) == real_batch_size:
771
+ for i in process_slice:
772
+ yield current_batch[i]
773
+ if first_batch is None:
774
+ first_batch = current_batch.copy()
775
+ current_batch = []
776
+
777
+ # Finished if drop_last is True, otherwise complete the last batch with elements from the beginning.
778
+ if not self.drop_last and len(current_batch) > 0:
779
+ if first_batch is None:
780
+ first_batch = current_batch.copy()
781
+ while len(current_batch) < real_batch_size:
782
+ current_batch += first_batch
783
+ for i in process_slice:
784
+ yield current_batch[i]
785
+
786
+ def __len__(self):
787
+ # Will raise an error if the underlying dataset is not sized.
788
+ if self.drop_last:
789
+ return (len(self.dataset) // (self.batch_size * self.num_processes)) * self.batch_size
790
+ else:
791
+ return math.ceil(len(self.dataset) / (self.batch_size * self.num_processes)) * self.batch_size
792
+
793
+
794
+ def _secs2timedelta(secs):
795
+ """
796
+ Convert seconds to hh:mm:ss.msec, msecs rounded to 2 decimal places.
797
+ """
798
+
799
+ msec = int(abs(secs - int(secs)) * 100)
800
+ return f"{datetime.timedelta(seconds=int(secs))}.{msec:02d}"
801
+
802
+
803
+ def metrics_format(metrics: dict[str, float]) -> dict[str, float]:
804
+ """
805
+ Reformat Trainer metrics values to a human-readable format.
806
+
807
+ Args:
808
+ metrics (`dict[str, float]`):
809
+ The metrics returned from train/evaluate/predict
810
+
811
+ Returns:
812
+ metrics (`dict[str, float]`): The reformatted metrics
813
+ """
814
+
815
+ metrics_copy = metrics.copy()
816
+ for k, v in metrics_copy.items():
817
+ if "_mem_" in k:
818
+ metrics_copy[k] = f"{v >> 20}MB"
819
+ elif "_runtime" in k:
820
+ metrics_copy[k] = _secs2timedelta(v)
821
+ elif k == "total_flos":
822
+ metrics_copy[k] = f"{int(v) >> 30}GF"
823
+ elif isinstance(metrics_copy[k], float):
824
+ metrics_copy[k] = round(v, 4)
825
+
826
+ return metrics_copy
827
+
828
+
829
+ # Trainer helper method: imported into the Trainer class and used as a method (takes `self` as first argument).
830
+ def log_metrics(self, split, metrics):
831
+ """
832
+ Log metrics in a specially formatted way.
833
+
834
+ Under distributed environment this is done only for a process with rank 0.
835
+
836
+ Args:
837
+ split (`str`):
838
+ Mode/split name: one of `train`, `eval`, `test`
839
+ metrics (`dict[str, float]`):
840
+ The metrics returned from train/evaluate/predictmetrics: metrics dict
841
+
842
+ Notes on memory reports:
843
+
844
+ In order to get memory usage report you need to install `psutil`. You can do that with `pip install psutil`.
845
+
846
+ Now when this method is run, you will see a report that will include:
847
+
848
+ ```
849
+ init_mem_cpu_alloc_delta = 1301MB
850
+ init_mem_cpu_peaked_delta = 154MB
851
+ init_mem_gpu_alloc_delta = 230MB
852
+ init_mem_gpu_peaked_delta = 0MB
853
+ train_mem_cpu_alloc_delta = 1345MB
854
+ train_mem_cpu_peaked_delta = 0MB
855
+ train_mem_gpu_alloc_delta = 693MB
856
+ train_mem_gpu_peaked_delta = 7MB
857
+ ```
858
+
859
+ **Understanding the reports:**
860
+
861
+ - the first segment, e.g., `train__`, tells you which stage the metrics are for. Reports starting with `init_`
862
+ will be added to the first stage that gets run. So that if only evaluation is run, the memory usage for the
863
+ `__init__` will be reported along with the `eval_` metrics.
864
+ - the third segment, is either `cpu` or `gpu`, tells you whether it's the general RAM or the gpu0 memory
865
+ metric.
866
+ - `*_alloc_delta` - is the difference in the used/allocated memory counter between the end and the start of the
867
+ stage - it can be negative if a function released more memory than it allocated.
868
+ - `*_peaked_delta` - is any extra memory that was consumed and then freed - relative to the current allocated
869
+ memory counter - it is never negative. When you look at the metrics of any stage you add up `alloc_delta` +
870
+ `peaked_delta` and you know how much memory was needed to complete that stage.
871
+
872
+ The reporting happens only for process of rank 0 and gpu 0 (if there is a gpu). Typically this is enough since the
873
+ main process does the bulk of work, but it could be not quite so if model parallel is used and then other GPUs may
874
+ use a different amount of gpu memory. This is also not the same under DataParallel where gpu0 may require much more
875
+ memory than the rest since it stores the gradient and optimizer states for all participating GPUs. Perhaps in the
876
+ future these reports will evolve to measure those too.
877
+
878
+ The CPU RAM metric measures RSS (Resident Set Size) includes both the memory which is unique to the process and the
879
+ memory shared with other processes. It is important to note that it does not include swapped out memory, so the
880
+ reports could be imprecise.
881
+
882
+ The CPU peak memory is measured using a sampling thread. Due to python's GIL it may miss some of the peak memory if
883
+ that thread didn't get a chance to run when the highest memory was used. Therefore this report can be less than
884
+ reality. Using `tracemalloc` would have reported the exact peak memory, but it doesn't report memory allocations
885
+ outside of python. So if some C++ CUDA extension allocated its own memory it won't be reported. And therefore it
886
+ was dropped in favor of the memory sampling approach, which reads the current process memory usage.
887
+
888
+ The GPU allocated and peak memory reporting is done with `torch.cuda.memory_allocated()` and
889
+ `torch.cuda.max_memory_allocated()`. This metric reports only "deltas" for pytorch-specific allocations, as
890
+ `torch.cuda` memory management system doesn't track any memory allocated outside of pytorch. For example, the very
891
+ first cuda call typically loads CUDA kernels, which may take from 0.5 to 2GB of GPU memory.
892
+
893
+ Note that this tracker doesn't account for memory allocations outside of [`Trainer`]'s `__init__`, `train`,
894
+ `evaluate` and `predict` calls.
895
+
896
+ Because `evaluation` calls may happen during `train`, we can't handle nested invocations because
897
+ `torch.cuda.max_memory_allocated` is a single counter, so if it gets reset by a nested eval call, `train`'s tracker
898
+ will report incorrect info. If this [pytorch issue](https://github.com/pytorch/pytorch/issues/16266) gets resolved
899
+ it will be possible to change this class to be re-entrant. Until then we will only track the outer level of
900
+ `train`, `evaluate` and `predict` methods. Which means that if `eval` is called during `train`, it's the latter
901
+ that will account for its memory usage and that of the former.
902
+
903
+ This also means that if any other tool that is used along the [`Trainer`] calls
904
+ `torch.cuda.reset_peak_memory_stats`, the gpu peak memory stats could be invalid. And the [`Trainer`] will disrupt
905
+ the normal behavior of any such tools that rely on calling `torch.cuda.reset_peak_memory_stats` themselves.
906
+
907
+ For best performance you may want to consider turning the memory profiling off for production runs.
908
+ """
909
+ if not self.is_world_process_zero():
910
+ return
911
+
912
+ print(f"***** {split} metrics *****")
913
+ metrics_formatted = metrics_format(metrics)
914
+ k_width = max(len(str(x)) for x in metrics_formatted)
915
+ v_width = max(len(str(x)) for x in metrics_formatted.values())
916
+ for key in sorted(metrics_formatted.keys()):
917
+ print(f" {key: <{k_width}} = {metrics_formatted[key]:>{v_width}}")
918
+
919
+
920
+ # Trainer helper method
921
+ def save_metrics(self, split, metrics, combined=True):
922
+ """
923
+ Save metrics into a json file for that split, e.g. `train_results.json`.
924
+
925
+ Under distributed environment this is done only for a process with rank 0.
926
+
927
+ Args:
928
+ split (`str`):
929
+ Mode/split name: one of `train`, `eval`, `test`, `all`
930
+ metrics (`dict[str, float]`):
931
+ The metrics returned from train/evaluate/predict
932
+ combined (`bool`, *optional*, defaults to `True`):
933
+ Creates combined metrics by updating `all_results.json` with metrics of this call
934
+
935
+ To understand the metrics please read the docstring of [`~Trainer.log_metrics`]. The only difference is that raw
936
+ unformatted numbers are saved in the current method.
937
+
938
+ """
939
+ if not self.is_world_process_zero():
940
+ return
941
+
942
+ path = os.path.join(self.args.output_dir, f"{split}_results.json")
943
+ with open(path, "w") as f:
944
+ json.dump(metrics, f, indent=4, sort_keys=True)
945
+
946
+ if combined:
947
+ path = os.path.join(self.args.output_dir, "all_results.json")
948
+ if os.path.exists(path):
949
+ with open(path) as f:
950
+ all_metrics = json.load(f)
951
+ else:
952
+ all_metrics = {}
953
+
954
+ all_metrics.update(metrics)
955
+ with open(path, "w") as f:
956
+ json.dump(all_metrics, f, indent=4, sort_keys=True)
957
+
958
+
959
+ # Trainer helper method
960
+ def save_state(self):
961
+ """
962
+ Saves the Trainer state, since Trainer.save_model saves only the tokenizer with the model.
963
+
964
+ Under distributed environment this is done only for a process with rank 0.
965
+ """
966
+ if not self.is_world_process_zero():
967
+ return
968
+
969
+ path = os.path.join(self.args.output_dir, "trainer_state.json")
970
+ self.state.save_to_json(path)
971
+
972
+
973
+ # Trainer helper method
974
+ def get_num_trainable_parameters(self) -> int:
975
+ """
976
+ Get the number of trainable parameters.
977
+ """
978
+ return sum(p.numel() for p in self.model.parameters() if p.requires_grad)
979
+
980
+
981
+ # Trainer helper method
982
+ def get_learning_rates(self) -> list[float]:
983
+ """
984
+ Returns the learning rate of each parameter from self.optimizer.
985
+ """
986
+ if self.optimizer is None:
987
+ raise ValueError("Trainer optimizer is None, please make sure you have setup the optimizer before.")
988
+ return [group["lr"] for group in self.optimizer.param_groups]
989
+
990
+
991
+ # Trainer helper method
992
+ def get_optimizer_group(self, param: str | torch.nn.parameter.Parameter | None = None):
993
+ """
994
+ Returns optimizer group for a parameter if given, else returns all optimizer groups for params.
995
+
996
+ Args:
997
+ param (`str` or `torch.nn.parameter.Parameter`, *optional*):
998
+ The parameter for which optimizer group needs to be returned.
999
+ """
1000
+ if self.optimizer is None:
1001
+ raise ValueError("Trainer optimizer is None, please make sure you have setup the optimizer before.")
1002
+ if param is not None:
1003
+ for group in self.optimizer.param_groups:
1004
+ if param in group["params"]:
1005
+ return group
1006
+ return [group["params"] for group in self.optimizer.param_groups]
1007
+
1008
+
1009
+ def get_model_param_count(model, trainable_only=False):
1010
+ """
1011
+ Calculate model's total param count. If trainable_only is True then count only those requiring grads.
1012
+ """
1013
+ if is_deepspeed_zero3_enabled():
1014
+
1015
+ def numel(p):
1016
+ return p.ds_numel if hasattr(p, "ds_numel") else p.numel()
1017
+
1018
+ else:
1019
+
1020
+ def numel(p):
1021
+ return p.numel()
1022
+
1023
+ return sum(numel(p) for p in model.parameters() if not trainable_only or p.requires_grad)
1024
+
1025
+
1026
+ def get_parameter_names(model, forbidden_layer_types, forbidden_layer_names=None):
1027
+ """
1028
+ Returns the names of the model parameters that are not inside a forbidden layer.
1029
+ """
1030
+ forbidden_layer_patterns = (
1031
+ [re.compile(pattern) for pattern in forbidden_layer_names] if forbidden_layer_names is not None else []
1032
+ )
1033
+ result = []
1034
+ for name, child in model.named_children():
1035
+ child_params = get_parameter_names(child, forbidden_layer_types, forbidden_layer_names)
1036
+ result += [
1037
+ f"{name}.{n}"
1038
+ for n in child_params
1039
+ if not isinstance(child, tuple(forbidden_layer_types))
1040
+ and not any(pattern.search(f"{name}.{n}".lower()) for pattern in forbidden_layer_patterns)
1041
+ ]
1042
+ # Add model specific parameters that are not in any child
1043
+ result += [
1044
+ k for k in model._parameters if not any(pattern.search(k.lower()) for pattern in forbidden_layer_patterns)
1045
+ ]
1046
+
1047
+ return result
1048
+
1049
+
1050
+ def get_module_class_from_name(module, name):
1051
+ """
1052
+ Gets a class from a module by its name.
1053
+
1054
+ Args:
1055
+ module (`torch.nn.Module`): The module to get the class from.
1056
+ name (`str`): The name of the class.
1057
+ """
1058
+ modules_children = list(module.children())
1059
+ if module.__class__.__name__ == name:
1060
+ return module.__class__
1061
+ elif len(modules_children) == 0:
1062
+ return
1063
+ else:
1064
+ for child_module in modules_children:
1065
+ module_class = get_module_class_from_name(child_module, name)
1066
+ if module_class is not None:
1067
+ return module_class
1068
+
1069
+
1070
+ def remove_dummy_checkpoint(is_main_process, output_dir, filenames):
1071
+ if is_main_process:
1072
+ for filename in filenames:
1073
+ file = os.path.join(output_dir, filename)
1074
+ if os.path.isfile(file):
1075
+ os.remove(file)
1076
+
1077
+
1078
+ if is_sagemaker_mp_enabled():
1079
+ import smdistributed.modelparallel.torch as smp
1080
+
1081
+ @smp.step()
1082
+ def smp_forward_backward(model, inputs, gradient_accumulation_steps=1):
1083
+ outputs = model(**inputs)
1084
+ loss = outputs["loss"] if isinstance(outputs, dict) else outputs[0]
1085
+ loss /= gradient_accumulation_steps
1086
+ model.backward(loss)
1087
+ return loss
1088
+
1089
+ @smp.step()
1090
+ def smp_forward_only(model, inputs):
1091
+ return model(**inputs)
1092
+
1093
+ def smp_gather(tensor):
1094
+ if isinstance(tensor, (list, tuple)):
1095
+ return type(tensor)(smp_gather(t) for t in tensor)
1096
+ elif isinstance(tensor, dict):
1097
+ return type(tensor)({k: smp_gather(v) for k, v in tensor.items()})
1098
+ elif not isinstance(tensor, torch.Tensor):
1099
+ raise TypeError(
1100
+ f"Can't gather the values of type {type(tensor)}, only of nested list/tuple/dicts of tensors."
1101
+ )
1102
+ all_tensors = smp.allgather(tensor, smp.CommGroup.DP_GROUP)
1103
+ all_tensors = [atleast_1d(t) for t in all_tensors]
1104
+ return torch.cat([t.cpu() for t in all_tensors], dim=0)
1105
+
1106
+ def smp_nested_concat(tensor):
1107
+ if isinstance(tensor, (list, tuple)):
1108
+ return type(tensor)(smp_nested_concat(t) for t in tensor)
1109
+ elif isinstance(tensor, dict):
1110
+ return type(tensor)({k: smp_nested_concat(v) for k, v in tensor.items()})
1111
+ # It doesn't seem possible to check here if `tensor` is a StepOutput because StepOutput lives in `smp.step`
1112
+ # which is also the name of the decorator so Python is confused.
1113
+ return tensor.detach().concat().cpu()
1114
+
1115
+
1116
+ @dataclass
1117
+ class AcceleratorConfig:
1118
+ """
1119
+ A subset of arguments relating to the underlying [`accelerate.Accelerator`]
1120
+ implementation utilized in the `Trainer` that can be customized.
1121
+ Mostly relating to data.
1122
+
1123
+ Parameters:
1124
+ split_batches (`bool`, *optional*, defaults to `False`):
1125
+ Whether or not the accelerator should split the batches yielded by the dataloaders across the devices. If
1126
+ `True` the actual batch size used will be the same on any kind of distributed processes, but it must be a
1127
+ round multiple of the `num_processes` you are using. If `False`, actual batch size used will be the one set
1128
+ in your script multiplied by the number of processes.
1129
+ dispatch_batches (`bool`, *optional*):
1130
+ If set to `True`, the dataloader prepared by the Accelerator is only iterated through on the main process
1131
+ and then the batches are split and broadcast to each process. Will default to `True` for `DataLoader` whose
1132
+ underlying dataset is an `IterableDataset`, `False` otherwise.
1133
+ even_batches (`bool`, *optional*, defaults to `True`):
1134
+ If set to `True`, in cases where the total batch size across all processes does not exactly divide the
1135
+ dataset, samples at the start of the dataset will be duplicated so the batch can be divided equally among
1136
+ all workers.
1137
+ use_seedable_sampler (`bool`, *optional*, defaults to `True`):
1138
+ Whether or not use a fully seedable random sampler ([`accelerate.data_loader.SeedableRandomSampler`]). Ensures
1139
+ training results are fully reproducible using a different sampling technique. While seed-to-seed results
1140
+ may differ, on average the differences are negligible when using multiple different seeds to compare. Should
1141
+ also be ran with [`~utils.set_seed`] for the best results.
1142
+ gradient_accumulation_kwargs (`dict`, *optional*):
1143
+ Additional kwargs to configure gradient accumulation, see [`accelerate.utils.GradientAccumulationPlugin`].
1144
+ Any of the following (optional) keys are acceptable:
1145
+ num_steps (`int`): Will take precedence over [`~.TrainingArguments.gradient_accumulation_steps`] if
1146
+ the latter is set to 1, otherwise an exception will be raised.
1147
+ sync_each_batch (`bool`): Whether to synchronize the gradients at each data batch.
1148
+ The [`accelerate.utils.GradientAccumulationPlugin`] default is `False`.
1149
+ non_blocking (`bool`, *optional*, defaults to `False`):
1150
+ Whether to use non-blocking CUDA calls to help minimize synchronization during
1151
+ distributed training with prepared `DataLoader` inputs being moved to device.
1152
+ Best if used with `pin_memory=True` in the `TrainingArguments`.
1153
+ use_configured_state (`bool*, *optional*, defaults to `False`):
1154
+ Whether or not to use a pre-configured `AcceleratorState` or `PartialState` defined
1155
+ before calling `TrainingArguments`. If `True`, an `Accelerator` or `PartialState`
1156
+ must be initialized. May lead to issues using sweeps or hyperparameter tuning.
1157
+
1158
+ """
1159
+
1160
+ # Data related arguments
1161
+ split_batches: bool = field(
1162
+ default=False,
1163
+ metadata={
1164
+ "help": "Whether or not the accelerator should split the batches yielded by the dataloaders across the devices. If"
1165
+ " `True` the actual batch size used will be the same on any kind of distributed processes, but it must be a"
1166
+ " round multiple of the `num_processes` you are using. If `False`, actual batch size used will be the one set"
1167
+ " in your script multiplied by the number of processes."
1168
+ },
1169
+ )
1170
+ dispatch_batches: bool | None = field(
1171
+ default=None,
1172
+ metadata={
1173
+ "help": "If set to `True`, the dataloader prepared by the Accelerator is only iterated through on the main process"
1174
+ " and then the batches are split and broadcast to each process. Will default to `True` for `DataLoader` whose"
1175
+ " underlying dataset is an `IterableDataslet`, `False` otherwise."
1176
+ },
1177
+ )
1178
+ even_batches: bool = field(
1179
+ default=True,
1180
+ metadata={
1181
+ "help": "If set to `True`, in cases where the total batch size across all processes does not exactly divide the"
1182
+ " dataset, samples at the start of the dataset will be duplicated so the batch can be divided equally among"
1183
+ " all workers."
1184
+ },
1185
+ )
1186
+ use_seedable_sampler: bool = field(
1187
+ default=True,
1188
+ metadata={
1189
+ "help": "Whether or not use a fully seedable random sampler ([`accelerate.data_loader.SeedableRandomSampler`])."
1190
+ "Ensures training results are fully reproducible using a different sampling technique. "
1191
+ "While seed-to-seed results may differ, on average the differences are negligible when using"
1192
+ "multiple different seeds to compare. Should also be ran with [`~utils.set_seed`] for the best results."
1193
+ },
1194
+ )
1195
+
1196
+ non_blocking: bool = field(
1197
+ default=False,
1198
+ metadata={
1199
+ "help": "Whether to use non-blocking CUDA calls to help minimize synchronization during "
1200
+ "distributed training with prepared `DataLoader` inputs being moved to device. "
1201
+ "Best if used with `pin_memory=True` in the `TrainingArguments`. Requires accelerate "
1202
+ "v0.30.0."
1203
+ },
1204
+ )
1205
+
1206
+ gradient_accumulation_kwargs: dict | None = field(
1207
+ default=None,
1208
+ metadata={
1209
+ "help": "Additional kwargs to configure gradient accumulation, see [`accelerate.utils.GradientAccumulationPlugin`]. "
1210
+ "Any of the following (optional) keys are acceptable: "
1211
+ " num_steps (`int`): Will take precedence over [`~.TrainingArguments.gradient_accumulation_steps`] if "
1212
+ " the latter is set to 1, otherwise an exception will be raised. "
1213
+ " sync_each_batch (`bool`): Whether to synchronize the gradients at each data batch. "
1214
+ " The [`accelerate.utils.GradientAccumulationPlugin`] default is `False`."
1215
+ },
1216
+ )
1217
+ use_configured_state: bool = field(
1218
+ default=False,
1219
+ metadata={
1220
+ "help": "Whether or not to use a pre-configured `AcceleratorState` or `PartialState` defined before calling `TrainingArguments`."
1221
+ "If `True`, an `Accelerator` or `PartialState` must be initialized. May lead to issues using sweeps or hyperparameter tuning."
1222
+ },
1223
+ )
1224
+
1225
+ @classmethod
1226
+ def from_json_file(cls, json_file):
1227
+ # Check if exists
1228
+ open_file = io.open if os.path.exists(json_file) else open
1229
+ with open_file(json_file, "r", encoding="utf-8") as f:
1230
+ config_dict = json.load(f)
1231
+ # Check for keys and load sensible defaults
1232
+ extra_keys = sorted(key for key in config_dict if key not in cls.__dataclass_fields__)
1233
+ if len(extra_keys) > 0:
1234
+ raise ValueError(
1235
+ f"The config file at {json_file} had unknown keys ({extra_keys}), please try upgrading your `transformers`"
1236
+ " version or fix (and potentially remove these keys) from your config file."
1237
+ )
1238
+ return cls(**config_dict)
1239
+
1240
+ def to_dict(self):
1241
+ return copy.deepcopy(self.__dict__)
1242
+
1243
+ def pop(self, key, default=None):
1244
+ return self.__dict__.pop(key, default)
1245
+
1246
+
1247
+ class LayerWiseDummyOptimizer(torch.optim.Optimizer):
1248
+ """
1249
+ For Layer-wise optimizers such as GaLoRE optimizer, the optimization
1250
+ step is already done through the post gradient hooks. Therefore
1251
+ the trick is to create a dummy optimizer that can take arbitrary
1252
+ args and kwargs and return a no-op during training.
1253
+
1254
+ Initial idea from @hiyouga in LLaMA-Factory:
1255
+ https://github.com/hiyouga/LLaMA-Factory/commit/8664262cde3919e10eaecbd66e8c5d356856362e#diff-ebe08ab14496dfb9e06075f0fdd36799ef6d1535cc4dd4715b74c4e3e06fe3ba
1256
+ """
1257
+
1258
+ def __init__(self, optimizer_dict=None, **kwargs):
1259
+ dummy_tensor = torch.randn(1, 1)
1260
+ self.optimizer_dict = optimizer_dict
1261
+ super().__init__([dummy_tensor], {"lr": kwargs.get("lr", 1e-03)})
1262
+
1263
+ def zero_grad(self, set_to_none: bool = True) -> None:
1264
+ pass
1265
+
1266
+ def step(self, closure=None) -> float | None:
1267
+ pass
1268
+
1269
+
1270
+ class LayerWiseDummyScheduler(LRScheduler):
1271
+ """
1272
+ For Layer-wise optimizers such as GaLoRE optimizer, the optimization and scheduling step
1273
+ are already done through the post gradient hooks. Therefore
1274
+ the trick is to create a dummy scheduler that can take arbitrary
1275
+ args and kwargs and return a no-op during training.
1276
+ """
1277
+
1278
+ def __init__(self, *args, **kwargs):
1279
+ self.default_lr = kwargs["lr"]
1280
+ optimizer = LayerWiseDummyOptimizer(**kwargs)
1281
+ last_epoch = -1
1282
+ super().__init__(optimizer, last_epoch)
1283
+
1284
+ def get_lr(self):
1285
+ # default value
1286
+ lrs = [self.default_lr]
1287
+
1288
+ # we take each lr in the parameters if they exist, assumes the optimizer to be the `LayerWiseDummyOptimizer`
1289
+ if self.optimizer is not None:
1290
+ param_wise_lrs = [
1291
+ [group["lr"] for group in optim.param_groups] for optim in self.optimizer.optimizer_dict.values()
1292
+ ]
1293
+ lrs = list(chain(*param_wise_lrs))
1294
+
1295
+ return lrs
1296
+
1297
+ def _get_closed_form_lr(self):
1298
+ return self.base_lrs
1299
+
1300
+
1301
+ def set_rng_state_for_device(device_name, device_module, checkpoint_rng_state, is_distributed):
1302
+ """Helper to set RNG state for a specific device type (CUDA, NPU, MLU, MUSA)"""
1303
+ device_state_key = device_name.lower()
1304
+ err_template = "Didn't manage to set back the RNG states of the {backend} because of the following error:\n {exception}\nThis won't yield the same results as if the training had not been interrupted."
1305
+ try:
1306
+ if is_distributed:
1307
+ device_module.random.set_rng_state_all(checkpoint_rng_state[device_state_key])
1308
+ else:
1309
+ device_module.random.set_rng_state(checkpoint_rng_state[device_state_key])
1310
+ except Exception as e:
1311
+ # Log error if setting RNG state fails
1312
+ logger.error(err_template.format(backend=device_name, exception=e))
1313
+
1314
+
1315
+ def safe_globals():
1316
+ """
1317
+ Context manager to allowlist numpy objects for torch.load with weights_only=True.
1318
+
1319
+ Starting from version 2.4 PyTorch introduces a check for the objects loaded
1320
+ with torch.load(weights_only=True). Starting from 2.6 weights_only=True becomes
1321
+ a default and requires allowlisting of objects being loaded.
1322
+
1323
+ See: https://github.com/pytorch/pytorch/pull/137602
1324
+ See: https://pytorch.org/docs/stable/notes/serialization.html#torch.serialization.add_safe_globals
1325
+ See: https://github.com/huggingface/accelerate/pull/3036
1326
+ """
1327
+ if version.parse(torch.__version__).release < version.parse("2.6").release:
1328
+ return contextlib.nullcontext()
1329
+
1330
+ np_core = np._core if version.parse(np.__version__) >= version.parse("2.0.0") else np.core
1331
+ allowlist = [np_core.multiarray._reconstruct, np.ndarray, np.dtype]
1332
+ # numpy >1.25 defines numpy.dtypes.UInt32DType, but below works for
1333
+ # all versions of numpy
1334
+ allowlist += [type(np.dtype(np.uint32))]
1335
+
1336
+ return torch.serialization.safe_globals(allowlist)
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/trainer_seq2seq.py ADDED
@@ -0,0 +1,392 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import contextlib
16
+ from collections.abc import Callable
17
+ from copy import deepcopy
18
+ from pathlib import Path
19
+ from typing import TYPE_CHECKING, Any, Optional, Union
20
+
21
+ import torch
22
+ from torch import nn
23
+ from torch.utils.data import Dataset
24
+
25
+ from .generation.configuration_utils import GenerationConfig
26
+ from .integrations.deepspeed import is_deepspeed_zero3_enabled
27
+ from .integrations.fsdp import is_fsdp_managed_module
28
+ from .trainer import Trainer
29
+ from .utils import is_datasets_available, logging
30
+
31
+
32
+ if torch.distributed.is_available():
33
+ from torch.distributed.fsdp import FullyShardedDataParallel
34
+
35
+ if is_datasets_available():
36
+ import datasets
37
+
38
+ if TYPE_CHECKING:
39
+ from torch.utils.data import IterableDataset
40
+
41
+ from .data.data_collator import DataCollator
42
+ from .feature_extraction_utils import FeatureExtractionMixin
43
+ from .image_processing_utils import BaseImageProcessor
44
+ from .modeling_utils import PreTrainedModel
45
+ from .processing_utils import ProcessorMixin
46
+ from .tokenization_utils_base import PreTrainedTokenizerBase
47
+ from .trainer_callback import TrainerCallback
48
+ from .trainer_utils import EvalPrediction, PredictionOutput
49
+ from .training_args import TrainingArguments
50
+
51
+
52
+ logger = logging.get_logger(__name__)
53
+
54
+
55
+ class Seq2SeqTrainer(Trainer):
56
+ def __init__(
57
+ self,
58
+ model: Union["PreTrainedModel", nn.Module] | None = None,
59
+ args: Optional["TrainingArguments"] = None,
60
+ data_collator: Optional["DataCollator"] = None,
61
+ train_dataset: Union[Dataset, "IterableDataset", "datasets.Dataset"] | None = None,
62
+ eval_dataset: Dataset | dict[str, Dataset] | None = None,
63
+ processing_class: Union[
64
+ "PreTrainedTokenizerBase", "BaseImageProcessor", "FeatureExtractionMixin", "ProcessorMixin"
65
+ ]
66
+ | None = None,
67
+ model_init: Callable[[], "PreTrainedModel"] | None = None,
68
+ compute_loss_func: Callable | None = None,
69
+ compute_metrics: Callable[["EvalPrediction"], dict] | None = None,
70
+ callbacks: list["TrainerCallback"] | None = None,
71
+ optimizers: tuple[torch.optim.Optimizer | None, torch.optim.lr_scheduler.LambdaLR | None] = (None, None),
72
+ preprocess_logits_for_metrics: Callable[[torch.Tensor, torch.Tensor], torch.Tensor] | None = None,
73
+ ):
74
+ super().__init__(
75
+ model=model,
76
+ args=args,
77
+ data_collator=data_collator,
78
+ train_dataset=train_dataset,
79
+ eval_dataset=eval_dataset,
80
+ processing_class=processing_class,
81
+ model_init=model_init,
82
+ compute_loss_func=compute_loss_func,
83
+ compute_metrics=compute_metrics,
84
+ callbacks=callbacks,
85
+ optimizers=optimizers,
86
+ preprocess_logits_for_metrics=preprocess_logits_for_metrics,
87
+ )
88
+
89
+ # Override self.model.generation_config if a GenerationConfig is specified in args.
90
+ # Priority: args.generation_config > model.generation_config > default GenerationConfig.
91
+ if self.args.generation_config is not None:
92
+ gen_config = self.load_generation_config(self.args.generation_config)
93
+ self.model.generation_config = gen_config
94
+
95
+ @staticmethod
96
+ def load_generation_config(gen_config_arg: str | GenerationConfig) -> GenerationConfig:
97
+ """
98
+ Loads a `~generation.GenerationConfig` from the `Seq2SeqTrainingArguments.generation_config` arguments.
99
+
100
+ Args:
101
+ gen_config_arg (`str` or [`~generation.GenerationConfig]`):
102
+ `Seq2SeqTrainingArguments.generation_config` argument.
103
+
104
+ Returns:
105
+ A `~generation.GenerationConfig`.
106
+ """
107
+
108
+ # GenerationConfig provided, nothing to do
109
+ if isinstance(gen_config_arg, GenerationConfig):
110
+ gen_config = deepcopy(gen_config_arg)
111
+ else:
112
+ # str or Path
113
+ pretrained_model_name = Path(gen_config_arg) if isinstance(gen_config_arg, str) else gen_config_arg
114
+ config_file_name = None
115
+
116
+ # Figuring if it is path pointing to a file, pointing to a directory or else a model id or URL
117
+ # This step is required in order to determine config_file_name
118
+ if pretrained_model_name.is_file():
119
+ config_file_name = pretrained_model_name.name
120
+ pretrained_model_name = pretrained_model_name.parent
121
+ # dir path
122
+ elif pretrained_model_name.is_dir():
123
+ pass
124
+ # model id or URL
125
+ else:
126
+ pretrained_model_name = gen_config_arg
127
+
128
+ gen_config = GenerationConfig.from_pretrained(pretrained_model_name, config_file_name)
129
+
130
+ # Strict validation to fail early. `GenerationConfig.save_pretrained()`, run at the end of training, throws
131
+ # an exception if there are warnings at validation time.
132
+ try:
133
+ gen_config.validate(strict=True)
134
+ except ValueError as exc:
135
+ raise ValueError(str(exc) + "\n\nFix these issues to train your model.")
136
+
137
+ return gen_config
138
+
139
+ def evaluate(
140
+ self,
141
+ eval_dataset: Dataset | None = None,
142
+ ignore_keys: list[str] | None = None,
143
+ metric_key_prefix: str = "eval",
144
+ **gen_kwargs,
145
+ ) -> dict[str, float]:
146
+ """
147
+ Run evaluation and returns metrics.
148
+
149
+ The calling script will be responsible for providing a method to compute metrics, as they are task-dependent
150
+ (pass it to the init `compute_metrics` argument).
151
+
152
+ You can also subclass and override this method to inject custom behavior.
153
+
154
+ Args:
155
+ eval_dataset (`Dataset`, *optional*):
156
+ Pass a dataset if you wish to override `self.eval_dataset`. If it is an [`~datasets.Dataset`], columns
157
+ not accepted by the `model.forward()` method are automatically removed. It must implement the `__len__`
158
+ method.
159
+ ignore_keys (`list[str]`, *optional*):
160
+ A list of keys in the output of your model (if it is a dictionary) that should be ignored when
161
+ gathering predictions.
162
+ metric_key_prefix (`str`, *optional*, defaults to `"eval"`):
163
+ An optional prefix to be used as the metrics key prefix. For example the metrics "bleu" will be named
164
+ "eval_bleu" if the prefix is `"eval"` (default)
165
+ max_length (`int`, *optional*):
166
+ The maximum target length to use when predicting with the generate method.
167
+ num_beams (`int`, *optional*):
168
+ Number of beams for beam search that will be used when predicting with the generate method. 1 means no
169
+ beam search.
170
+ gen_kwargs:
171
+ Additional `generate` specific kwargs.
172
+
173
+ Returns:
174
+ A dictionary containing the evaluation loss and the potential metrics computed from the predictions. The
175
+ dictionary also contains the epoch number which comes from the training state.
176
+ """
177
+
178
+ gen_kwargs = gen_kwargs.copy()
179
+
180
+ # Use legacy argument setting if a) the option is not explicitly passed; and b) the argument is set in the
181
+ # training args
182
+ if (
183
+ gen_kwargs.get("max_length") is None
184
+ and gen_kwargs.get("max_new_tokens") is None
185
+ and self.args.generation_max_length is not None
186
+ ):
187
+ gen_kwargs["max_length"] = self.args.generation_max_length
188
+ if gen_kwargs.get("num_beams") is None and self.args.generation_num_beams is not None:
189
+ gen_kwargs["num_beams"] = self.args.generation_num_beams
190
+ # We don't want to drop samples in general
191
+ self.gather_function = self.accelerator.gather
192
+ self._gen_kwargs = gen_kwargs
193
+ return super().evaluate(eval_dataset, ignore_keys=ignore_keys, metric_key_prefix=metric_key_prefix)
194
+
195
+ def predict(
196
+ self,
197
+ test_dataset: Dataset,
198
+ ignore_keys: list[str] | None = None,
199
+ metric_key_prefix: str = "test",
200
+ **gen_kwargs,
201
+ ) -> "PredictionOutput":
202
+ """
203
+ Run prediction and returns predictions and potential metrics.
204
+
205
+ Depending on the dataset and your use case, your test dataset may contain labels. In that case, this method
206
+ will also return metrics, like in `evaluate()`.
207
+
208
+ Args:
209
+ test_dataset (`Dataset`):
210
+ Dataset to run the predictions on. If it is a [`~datasets.Dataset`], columns not accepted by the
211
+ `model.forward()` method are automatically removed. Has to implement the method `__len__`
212
+ ignore_keys (`list[str]`, *optional*):
213
+ A list of keys in the output of your model (if it is a dictionary) that should be ignored when
214
+ gathering predictions.
215
+ metric_key_prefix (`str`, *optional*, defaults to `"eval"`):
216
+ An optional prefix to be used as the metrics key prefix. For example the metrics "bleu" will be named
217
+ "eval_bleu" if the prefix is `"eval"` (default)
218
+ max_length (`int`, *optional*):
219
+ The maximum target length to use when predicting with the generate method.
220
+ num_beams (`int`, *optional*):
221
+ Number of beams for beam search that will be used when predicting with the generate method. 1 means no
222
+ beam search.
223
+ gen_kwargs:
224
+ Additional `generate` specific kwargs.
225
+
226
+ <Tip>
227
+
228
+ If your predictions or labels have different sequence lengths (for instance because you're doing dynamic
229
+ padding in a token classification task) the predictions will be padded (on the right) to allow for
230
+ concatenation into one array. The padding index is -100.
231
+
232
+ </Tip>
233
+
234
+ Returns: *NamedTuple* A namedtuple with the following keys:
235
+
236
+ - predictions (`np.ndarray`): The predictions on `test_dataset`.
237
+ - label_ids (`np.ndarray`, *optional*): The labels (if the dataset contained some).
238
+ - metrics (`dict[str, float]`, *optional*): The potential dictionary of metrics (if the dataset contained
239
+ labels).
240
+ """
241
+
242
+ gen_kwargs = gen_kwargs.copy()
243
+
244
+ # Use legacy argument setting if a) the option is not explicitly passed; and b) the argument is set in the
245
+ # training args
246
+ if (
247
+ gen_kwargs.get("max_length") is None
248
+ and gen_kwargs.get("max_new_tokens") is None
249
+ and self.args.generation_max_length is not None
250
+ ):
251
+ gen_kwargs["max_length"] = self.args.generation_max_length
252
+ if gen_kwargs.get("num_beams") is None and self.args.generation_num_beams is not None:
253
+ gen_kwargs["num_beams"] = self.args.generation_num_beams
254
+ self.gather_function = self.accelerator.gather
255
+ self._gen_kwargs = gen_kwargs
256
+
257
+ return super().predict(test_dataset, ignore_keys=ignore_keys, metric_key_prefix=metric_key_prefix)
258
+
259
+ def prediction_step(
260
+ self,
261
+ model: nn.Module,
262
+ inputs: dict[str, torch.Tensor | Any],
263
+ prediction_loss_only: bool,
264
+ ignore_keys: list[str] | None = None,
265
+ **gen_kwargs,
266
+ ) -> tuple[float | None, torch.Tensor | None, torch.Tensor | None]:
267
+ """
268
+ Perform an evaluation step on `model` using `inputs`.
269
+
270
+ Subclass and override to inject custom behavior.
271
+
272
+ Args:
273
+ model (`nn.Module`):
274
+ The model to evaluate.
275
+ inputs (`dict[str, Union[torch.Tensor, Any]]`):
276
+ The inputs and targets of the model.
277
+
278
+ The dictionary will be unpacked before being fed to the model. Most models expect the targets under the
279
+ argument `labels`. Check your model's documentation for all accepted arguments.
280
+ prediction_loss_only (`bool`):
281
+ Whether or not to return the loss only.
282
+ gen_kwargs:
283
+ Additional `generate` specific kwargs.
284
+
285
+ Return:
286
+ tuple[Optional[float], Optional[torch.Tensor], Optional[torch.Tensor]]: A tuple with the loss, logits and
287
+ labels (each being optional).
288
+ """
289
+
290
+ if not self.args.predict_with_generate or prediction_loss_only:
291
+ return super().prediction_step(
292
+ model, inputs, prediction_loss_only=prediction_loss_only, ignore_keys=ignore_keys
293
+ )
294
+
295
+ has_labels = "labels" in inputs
296
+ inputs = self._prepare_inputs(inputs)
297
+
298
+ # Priority (handled in generate):
299
+ # non-`None` gen_kwargs > model.generation_config > default GenerationConfig()
300
+ if len(gen_kwargs) == 0 and hasattr(self, "_gen_kwargs"):
301
+ gen_kwargs = self._gen_kwargs.copy()
302
+ if "num_beams" in gen_kwargs and gen_kwargs["num_beams"] is None:
303
+ gen_kwargs.pop("num_beams")
304
+ if "max_length" in gen_kwargs and gen_kwargs["max_length"] is None:
305
+ gen_kwargs.pop("max_length")
306
+
307
+ default_synced_gpus = is_deepspeed_zero3_enabled() or is_fsdp_managed_module(self.model)
308
+ gen_kwargs["synced_gpus"] = gen_kwargs.get("synced_gpus", default_synced_gpus)
309
+
310
+ generation_inputs = inputs.copy()
311
+ # If the `decoder_input_ids` was created from `labels`, evict the former, so that the model can freely generate
312
+ # (otherwise, it would continue generating from the padded `decoder_input_ids`)
313
+ if (
314
+ "labels" in generation_inputs
315
+ and "decoder_input_ids" in generation_inputs
316
+ and generation_inputs["labels"].shape == generation_inputs["decoder_input_ids"].shape
317
+ ):
318
+ generation_inputs = {
319
+ k: v for k, v in inputs.items() if k not in ("decoder_input_ids", "decoder_attention_mask")
320
+ }
321
+
322
+ summon_full_params_context = (
323
+ FullyShardedDataParallel.summon_full_params(self.model)
324
+ if torch.distributed.is_available() and isinstance(self.model, FullyShardedDataParallel)
325
+ else contextlib.nullcontext()
326
+ )
327
+
328
+ with summon_full_params_context:
329
+ generated_tokens = self.model.generate(**generation_inputs, **gen_kwargs)
330
+
331
+ # Temporary hack to ensure the generation config is not initialized for each iteration of the evaluation loop
332
+ # TODO: remove this hack when the legacy code that initializes generation_config from a model config is
333
+ # removed in https://github.com/huggingface/transformers/blob/98d88b23f54e5a23e741833f1e973fdf600cc2c5/src/transformers/generation/utils.py#L1183
334
+ if self.model.generation_config._from_model_config:
335
+ self.model.generation_config._from_model_config = False
336
+
337
+ # Retrieves GenerationConfig from model.generation_config
338
+ # Update with defaults because earlier the generation config used to be init
339
+ # with default values. Now we init it with `None` and keep defaults for BC
340
+ gen_config = self.model.generation_config
341
+ default_gen_config = gen_config._get_default_generation_params()
342
+ gen_config.update(**default_gen_config, defaults_only=True)
343
+ # in case the batch is shorter than max length, the output should be padded
344
+ if generated_tokens.shape[-1] < gen_config.max_length:
345
+ generated_tokens = self._pad_tensors_to_max_len(generated_tokens, gen_config.max_length)
346
+ elif gen_config.max_new_tokens is not None and generated_tokens.shape[-1] < gen_config.max_new_tokens + 1:
347
+ generated_tokens = self._pad_tensors_to_max_len(generated_tokens, gen_config.max_new_tokens + 1)
348
+
349
+ with torch.no_grad():
350
+ if has_labels:
351
+ with self.compute_loss_context_manager():
352
+ outputs = model(**inputs)
353
+ if self.label_smoother is not None:
354
+ loss = self.label_smoother(outputs, inputs["labels"]).detach().mean()
355
+ else:
356
+ loss = (outputs["loss"] if isinstance(outputs, dict) else outputs[0]).detach().mean()
357
+ else:
358
+ loss = None
359
+
360
+ if self.args.prediction_loss_only:
361
+ return loss, None, None
362
+
363
+ if has_labels:
364
+ labels = inputs["labels"]
365
+ if labels.shape[-1] < gen_config.max_length:
366
+ labels = self._pad_tensors_to_max_len(labels, gen_config.max_length)
367
+ elif gen_config.max_new_tokens is not None and labels.shape[-1] < gen_config.max_new_tokens + 1:
368
+ labels = self._pad_tensors_to_max_len(labels, gen_config.max_new_tokens + 1)
369
+ else:
370
+ labels = None
371
+
372
+ return loss, generated_tokens, labels
373
+
374
+ def _pad_tensors_to_max_len(self, tensor, max_length):
375
+ if self.processing_class is not None and hasattr(self.processing_class, "pad_token_id"):
376
+ # If PAD token is not defined at least EOS token has to be defined
377
+ pad_token_id = (
378
+ self.processing_class.pad_token_id
379
+ if self.processing_class.pad_token_id is not None
380
+ else self.processing_class.eos_token_id
381
+ )
382
+ else:
383
+ if getattr(self.model.config, "pad_token_id", None) is not None:
384
+ pad_token_id = self.model.config.pad_token_id
385
+ else:
386
+ raise ValueError("Pad_token_id must be set in the configuration of the model, in order to pad tensors")
387
+
388
+ padded_tensor = pad_token_id * torch.ones(
389
+ (tensor.shape[0], max_length), dtype=tensor.dtype, device=tensor.device
390
+ )
391
+ padded_tensor[:, : tensor.shape[-1]] = tensor
392
+ return padded_tensor
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/training_args_seq2seq.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import logging
16
+ from dataclasses import dataclass, field
17
+ from pathlib import Path
18
+
19
+ from .generation.configuration_utils import GenerationConfig
20
+ from .training_args import TrainingArguments
21
+ from .utils import add_start_docstrings
22
+
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ @dataclass
28
+ @add_start_docstrings(TrainingArguments.__doc__)
29
+ class Seq2SeqTrainingArguments(TrainingArguments):
30
+ """
31
+ sortish_sampler (`bool`, *optional*, defaults to `False`):
32
+ Whether to use a *sortish sampler* or not. Only possible if the underlying datasets are *Seq2SeqDataset*
33
+ for now but will become generally available in the near future.
34
+
35
+ It sorts the inputs according to lengths in order to minimize the padding size, with a bit of randomness
36
+ for the training set.
37
+ predict_with_generate (`bool`, *optional*, defaults to `False`):
38
+ Whether to use generate to calculate generative metrics (ROUGE, BLEU).
39
+ generation_max_length (`int`, *optional*):
40
+ The `max_length` to use on each evaluation loop when `predict_with_generate=True`. Will default to the
41
+ `max_length` value of the model configuration.
42
+ generation_num_beams (`int`, *optional*):
43
+ The `num_beams` to use on each evaluation loop when `predict_with_generate=True`. Will default to the
44
+ `num_beams` value of the model configuration.
45
+ generation_config (`str` or `Path` or [`~generation.GenerationConfig`], *optional*):
46
+ Allows to load a [`~generation.GenerationConfig`] from the `from_pretrained` method. This can be either:
47
+
48
+ - a string, the *model id* of a pretrained model configuration hosted inside a model repo on
49
+ huggingface.co.
50
+ - a path to a *directory* containing a configuration file saved using the
51
+ [`~GenerationConfig.save_pretrained`] method, e.g., `./my_model_directory/`.
52
+ - a [`~generation.GenerationConfig`] object.
53
+ """ # fmt: skip # Prevent Ruff from altering the indentation
54
+
55
+ sortish_sampler: bool = field(default=False, metadata={"help": "Whether to use SortishSampler or not."})
56
+ predict_with_generate: bool = field(
57
+ default=False, metadata={"help": "Whether to use generate to calculate generative metrics (ROUGE, BLEU)."}
58
+ )
59
+ generation_max_length: int | None = field(
60
+ default=None,
61
+ metadata={
62
+ "help": (
63
+ "The `max_length` to use on each evaluation loop when `predict_with_generate=True`. Will default "
64
+ "to the `max_length` value of the model configuration."
65
+ )
66
+ },
67
+ )
68
+ generation_num_beams: int | None = field(
69
+ default=None,
70
+ metadata={
71
+ "help": (
72
+ "The `num_beams` to use on each evaluation loop when `predict_with_generate=True`. Will default "
73
+ "to the `num_beams` value of the model configuration."
74
+ )
75
+ },
76
+ )
77
+ generation_config: str | Path | GenerationConfig | None = field(
78
+ default=None,
79
+ metadata={
80
+ "help": "Model id, file path or url pointing to a GenerationConfig json file, to use during prediction."
81
+ },
82
+ )
83
+
84
+ def to_dict(self):
85
+ """
86
+ Serializes this instance while replace `Enum` by their values and `GenerationConfig` by dictionaries (for JSON
87
+ serialization support). It obfuscates the token values by removing their value.
88
+ """
89
+ # filter out fields that are defined as field(init=False)
90
+ d = super().to_dict()
91
+ for k, v in d.items():
92
+ if isinstance(v, GenerationConfig):
93
+ d[k] = v.to_dict()
94
+ return d