Add files using upload-large-folder tool
Browse files- LTA_openwebtext_dualt/docs/lta_samples/metrics_20260508/mauve_step124k_n64_meta.json +19 -0
- 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
- 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
- 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
- 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
- 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
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/__init__.py +852 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/convert_slow_tokenizer.py +2151 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/core_model_loading.py +1557 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/debug_utils.py +348 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/feature_extraction_utils.py +672 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/image_processing_base.py +494 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/biogpt/modular_biogpt.py +509 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/biogpt/tokenization_biogpt.py +329 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/mpnet/__init__.py +28 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/mpnet/tokenization_mpnet.py +195 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/time_series_utils.py +225 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/trainer_pt_utils.py +1336 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/trainer_seq2seq.py +392 -0
- 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
|