Add files using upload-large-folder tool
Browse files- LTA_openwebtext_dualt/logs/owt_bert_absrope_time4_len128_C1_to_1024_mask1_sameT_every1k_dualline_watch/infer_lta_owt_bert_absrope_time4_dirichlet_len128_C1_to_1024_mask1_sameT_gbs512_b32_4gpu_1m_save1k_20260525_step_0002000.log +199 -0
- LTA_openwebtext_dualt/logs/owt_bert_absrope_time4_len128_C1_to_1024_mask1_sameT_every1k_dualline_watch/infer_lta_owt_bert_absrope_time4_dirichlet_len128_C1_to_1024_mask1_sameT_gbs512_b32_4gpu_1m_save1k_20260525_step_0020000.log +199 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/polynomial/tests/test_chebyshev.py +619 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/polynomial/tests/test_classes.py +600 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/polynomial/tests/test_hermite.py +555 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/polynomial/tests/test_hermite_e.py +556 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/polynomial/tests/test_polynomial.py +611 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/testing/print_coercion_tables.py +200 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/conditional_detr/image_processing_conditional_detr.py +1083 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/conditional_detr/image_processing_pil_conditional_detr.py +1135 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/conditional_detr/modeling_conditional_detr.py +1866 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/conditional_detr/modular_conditional_detr.py +1122 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/mra/configuration_mra.py +76 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/sam_hq/configuration_sam_hq.py +193 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/runs/owt_t5_elftokenized_full_len1024_C1_to_1024_pow1_d768_l12_h12_gbs512_2x8gpu_50ep_lr4e3_ema0p9999_elfopt_not5_bottleneck128_unfixed_norm_stateprobadd_selfcond_ce_fast_20260610_020108/step_108000.pt +3 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/runs/owt_t5_elftokenized_full_len1024_C1_to_1024_pow1_d768_l12_h12_gbs512_2x8gpu_50ep_lr4e3_ema0p9999_elfopt_not5_bottleneck128_unfixed_norm_stateprobadd_selfcond_ce_fast_20260610_020108/step_127000.pt +3 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/runs/owt_t5_elftokenized_full_len1024_C1_to_1024_pow1_d768_l12_h12_gbs512_2x8gpu_50ep_lr4e3_ema0p9999_elfopt_not5_bottleneck128_unfixed_norm_stateprobadd_selfcond_ce_fast_20260610_020108/step_180000.pt +3 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/runs/owt_t5_elftokenized_full_len1024_C1_to_1024_pow1_d768_l12_h12_gbs512_2x8gpu_50ep_lr4e3_ema0p9999_elfopt_not5_bottleneck128_unfixed_norm_stateprobadd_selfcond_ce_fast_20260610_020108/step_190000.pt +3 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/runs/owt_t5_elftokenized_full_len1024_C1_to_1024_pow1_d768_l12_h12_gbs512_2x8gpu_50ep_lr4e3_ema0p9999_elfopt_not5_bottleneck128_unfixed_norm_stateprobadd_selfcond_ce_fast_20260610_020108/step_248000.pt +3 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/runs/owt_t5_elftokenized_full_len1024_C1_to_1024_pow1_d768_l12_h12_gbs512_2x8gpu_50ep_lr4e3_ema0p9999_elfopt_not5_bottleneck128_unfixed_norm_stateprobadd_selfcond_ce_fast_20260610_020108/step_274000.pt +3 -0
LTA_openwebtext_dualt/logs/owt_bert_absrope_time4_len128_C1_to_1024_mask1_sameT_every1k_dualline_watch/infer_lta_owt_bert_absrope_time4_dirichlet_len128_C1_to_1024_mask1_sameT_gbs512_b32_4gpu_1m_save1k_20260525_step_0002000.log
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[watch-dualline] 2026-05-25_23:10:32 infer runs/lta_owt_bert_absrope_time4_dirichlet_len128_C1_to_1024_mask1_sameT_gbs512_b32_4gpu_1m_save1k_20260525/step_0002000.pt -> docs/lta_samples/metrics_20260525/owt_bert_absrope_time4_len128_C1_to_1024_mask1_sameT_every1k_dualline_dirres_c1_1024_n128/lta_owt_bert_absrope_time4_dirichlet_len128_C1_to_1024_mask1_sameT_gbs512_b32_4gpu_1m_save1k_20260525/step_0002000
|
| 2 |
+
[decode] max_len=128 generated=1/128
|
| 3 |
+
[decode] max_len=128 generated=2/128
|
| 4 |
+
[decode] max_len=128 generated=3/128
|
| 5 |
+
[decode] max_len=128 generated=4/128
|
| 6 |
+
[decode] max_len=128 generated=5/128
|
| 7 |
+
[decode] max_len=128 generated=6/128
|
| 8 |
+
[decode] max_len=128 generated=7/128
|
| 9 |
+
[decode] max_len=128 generated=8/128
|
| 10 |
+
[decode] max_len=128 generated=9/128
|
| 11 |
+
[decode] max_len=128 generated=10/128
|
| 12 |
+
[decode] max_len=128 generated=11/128
|
| 13 |
+
[decode] max_len=128 generated=12/128
|
| 14 |
+
[decode] max_len=128 generated=13/128
|
| 15 |
+
[decode] max_len=128 generated=14/128
|
| 16 |
+
[decode] max_len=128 generated=15/128
|
| 17 |
+
[decode] max_len=128 generated=16/128
|
| 18 |
+
[decode] max_len=128 generated=17/128
|
| 19 |
+
[decode] max_len=128 generated=18/128
|
| 20 |
+
[decode] max_len=128 generated=19/128
|
| 21 |
+
[decode] max_len=128 generated=20/128
|
| 22 |
+
[decode] max_len=128 generated=21/128
|
| 23 |
+
[decode] max_len=128 generated=22/128
|
| 24 |
+
[decode] max_len=128 generated=23/128
|
| 25 |
+
[decode] max_len=128 generated=24/128
|
| 26 |
+
[decode] max_len=128 generated=25/128
|
| 27 |
+
[decode] max_len=128 generated=26/128
|
| 28 |
+
[decode] max_len=128 generated=27/128
|
| 29 |
+
[decode] max_len=128 generated=28/128
|
| 30 |
+
[decode] max_len=128 generated=29/128
|
| 31 |
+
[decode] max_len=128 generated=30/128
|
| 32 |
+
[decode] max_len=128 generated=31/128
|
| 33 |
+
[decode] max_len=128 generated=32/128
|
| 34 |
+
[decode] max_len=128 generated=33/128
|
| 35 |
+
[decode] max_len=128 generated=34/128
|
| 36 |
+
[decode] max_len=128 generated=35/128
|
| 37 |
+
[decode] max_len=128 generated=36/128
|
| 38 |
+
[decode] max_len=128 generated=37/128
|
| 39 |
+
[decode] max_len=128 generated=38/128
|
| 40 |
+
[decode] max_len=128 generated=39/128
|
| 41 |
+
[decode] max_len=128 generated=40/128
|
| 42 |
+
[decode] max_len=128 generated=41/128
|
| 43 |
+
[decode] max_len=128 generated=42/128
|
| 44 |
+
[decode] max_len=128 generated=43/128
|
| 45 |
+
[decode] max_len=128 generated=44/128
|
| 46 |
+
[decode] max_len=128 generated=45/128
|
| 47 |
+
[decode] max_len=128 generated=46/128
|
| 48 |
+
[decode] max_len=128 generated=47/128
|
| 49 |
+
[decode] max_len=128 generated=48/128
|
| 50 |
+
[decode] max_len=128 generated=49/128
|
| 51 |
+
[decode] max_len=128 generated=50/128
|
| 52 |
+
[decode] max_len=128 generated=51/128
|
| 53 |
+
[decode] max_len=128 generated=52/128
|
| 54 |
+
[decode] max_len=128 generated=53/128
|
| 55 |
+
[decode] max_len=128 generated=54/128
|
| 56 |
+
[decode] max_len=128 generated=55/128
|
| 57 |
+
[decode] max_len=128 generated=56/128
|
| 58 |
+
[decode] max_len=128 generated=57/128
|
| 59 |
+
[decode] max_len=128 generated=58/128
|
| 60 |
+
[decode] max_len=128 generated=59/128
|
| 61 |
+
[decode] max_len=128 generated=60/128
|
| 62 |
+
[decode] max_len=128 generated=61/128
|
| 63 |
+
[decode] max_len=128 generated=62/128
|
| 64 |
+
[decode] max_len=128 generated=63/128
|
| 65 |
+
[decode] max_len=128 generated=64/128
|
| 66 |
+
[decode] max_len=128 generated=65/128
|
| 67 |
+
[decode] max_len=128 generated=66/128
|
| 68 |
+
[decode] max_len=128 generated=67/128
|
| 69 |
+
[decode] max_len=128 generated=68/128
|
| 70 |
+
[decode] max_len=128 generated=69/128
|
| 71 |
+
[decode] max_len=128 generated=70/128
|
| 72 |
+
[decode] max_len=128 generated=71/128
|
| 73 |
+
[decode] max_len=128 generated=72/128
|
| 74 |
+
[decode] max_len=128 generated=73/128
|
| 75 |
+
[decode] max_len=128 generated=74/128
|
| 76 |
+
[decode] max_len=128 generated=75/128
|
| 77 |
+
[decode] max_len=128 generated=76/128
|
| 78 |
+
[decode] max_len=128 generated=77/128
|
| 79 |
+
[decode] max_len=128 generated=78/128
|
| 80 |
+
[decode] max_len=128 generated=79/128
|
| 81 |
+
[decode] max_len=128 generated=80/128
|
| 82 |
+
[decode] max_len=128 generated=81/128
|
| 83 |
+
[decode] max_len=128 generated=82/128
|
| 84 |
+
[decode] max_len=128 generated=83/128
|
| 85 |
+
[decode] max_len=128 generated=84/128
|
| 86 |
+
[decode] max_len=128 generated=85/128
|
| 87 |
+
[decode] max_len=128 generated=86/128
|
| 88 |
+
[decode] max_len=128 generated=87/128
|
| 89 |
+
[decode] max_len=128 generated=88/128
|
| 90 |
+
[decode] max_len=128 generated=89/128
|
| 91 |
+
[decode] max_len=128 generated=90/128
|
| 92 |
+
[decode] max_len=128 generated=91/128
|
| 93 |
+
[decode] max_len=128 generated=92/128
|
| 94 |
+
[decode] max_len=128 generated=93/128
|
| 95 |
+
[decode] max_len=128 generated=94/128
|
| 96 |
+
[decode] max_len=128 generated=95/128
|
| 97 |
+
[decode] max_len=128 generated=96/128
|
| 98 |
+
[decode] max_len=128 generated=97/128
|
| 99 |
+
[decode] max_len=128 generated=98/128
|
| 100 |
+
[decode] max_len=128 generated=99/128
|
| 101 |
+
[decode] max_len=128 generated=100/128
|
| 102 |
+
[decode] max_len=128 generated=101/128
|
| 103 |
+
[decode] max_len=128 generated=102/128
|
| 104 |
+
[decode] max_len=128 generated=103/128
|
| 105 |
+
[decode] max_len=128 generated=104/128
|
| 106 |
+
[decode] max_len=128 generated=105/128
|
| 107 |
+
[decode] max_len=128 generated=106/128
|
| 108 |
+
[decode] max_len=128 generated=107/128
|
| 109 |
+
[decode] max_len=128 generated=108/128
|
| 110 |
+
[decode] max_len=128 generated=109/128
|
| 111 |
+
[decode] max_len=128 generated=110/128
|
| 112 |
+
[decode] max_len=128 generated=111/128
|
| 113 |
+
[decode] max_len=128 generated=112/128
|
| 114 |
+
[decode] max_len=128 generated=113/128
|
| 115 |
+
[decode] max_len=128 generated=114/128
|
| 116 |
+
[decode] max_len=128 generated=115/128
|
| 117 |
+
[decode] max_len=128 generated=116/128
|
| 118 |
+
[decode] max_len=128 generated=117/128
|
| 119 |
+
[decode] max_len=128 generated=118/128
|
| 120 |
+
[decode] max_len=128 generated=119/128
|
| 121 |
+
[decode] max_len=128 generated=120/128
|
| 122 |
+
[decode] max_len=128 generated=121/128
|
| 123 |
+
[decode] max_len=128 generated=122/128
|
| 124 |
+
[decode] max_len=128 generated=123/128
|
| 125 |
+
[decode] max_len=128 generated=124/128
|
| 126 |
+
[decode] max_len=128 generated=125/128
|
| 127 |
+
[decode] max_len=128 generated=126/128
|
| 128 |
+
[decode] max_len=128 generated=127/128
|
| 129 |
+
[decode] max_len=128 generated=128/128
|
| 130 |
+
[
|
| 131 |
+
{
|
| 132 |
+
"checkpoint": "runs/lta_owt_bert_absrope_time4_dirichlet_len128_C1_to_1024_mask1_sameT_gbs512_b32_4gpu_1m_save1k_20260525/step_0002000.pt",
|
| 133 |
+
"ckpt_step": 2000,
|
| 134 |
+
"max_len": 128,
|
| 135 |
+
"decode_rule": "dual_line_resample",
|
| 136 |
+
"support_power": 1.0,
|
| 137 |
+
"semantic_power": 1.5,
|
| 138 |
+
"steps": 128,
|
| 139 |
+
"c_min": 1.0,
|
| 140 |
+
"c_max": 1024.0,
|
| 141 |
+
"anchor_mode": "state",
|
| 142 |
+
"model_t_mode": "flow",
|
| 143 |
+
"time_schedule": "uniform",
|
| 144 |
+
"time_logit_mean": -1.5,
|
| 145 |
+
"time_logit_std": 0.8,
|
| 146 |
+
"time_power": 2.0,
|
| 147 |
+
"input_noise_scale": 0.0,
|
| 148 |
+
"input_noise_until": 1.0,
|
| 149 |
+
"input_noise_dirichlet_concentration": 1.0,
|
| 150 |
+
"endpoint_softening": "none",
|
| 151 |
+
"endpoint_soft_power": 2.0,
|
| 152 |
+
"endpoint_soft_min_conf": 0.0,
|
| 153 |
+
"endpoint_soft_max_conf": 1.0,
|
| 154 |
+
"soft_target_decode_mode": "off",
|
| 155 |
+
"soft_target_power": 1.0,
|
| 156 |
+
"soft_target_min_conf": 0.0,
|
| 157 |
+
"soft_target_max_conf": 1.0,
|
| 158 |
+
"soft_target_debias_start": 0.7,
|
| 159 |
+
"final_from": "blend",
|
| 160 |
+
"final_decode": "argmax",
|
| 161 |
+
"final_sample_temp": 1.0,
|
| 162 |
+
"final_top_k": 0,
|
| 163 |
+
"final_top_p": 1.0,
|
| 164 |
+
"commit_mode": "off",
|
| 165 |
+
"commit_conf_threshold": 0.0,
|
| 166 |
+
"commit_margin_threshold": 0.0,
|
| 167 |
+
"commit_start": 0.0,
|
| 168 |
+
"commit_min_ratio": 0.0,
|
| 169 |
+
"commit_max_ratio": 1.0,
|
| 170 |
+
"commit_power": 2.0,
|
| 171 |
+
"commit_freq_max_frac": 0.08,
|
| 172 |
+
"early_temp": 2.8,
|
| 173 |
+
"late_temp": 1.45,
|
| 174 |
+
"temp_end": 0.55,
|
| 175 |
+
"temp_power": 1.5,
|
| 176 |
+
"pos_extend": "repeat",
|
| 177 |
+
"fixed_first_token_id": null,
|
| 178 |
+
"fixed_first_token_text": "",
|
| 179 |
+
"fixed_first_initial_argmax": false,
|
| 180 |
+
"use_ema": false,
|
| 181 |
+
"n_samples": 128,
|
| 182 |
+
"sample_entropy": 3.3561476456891333,
|
| 183 |
+
"unique_tokens": 1724,
|
| 184 |
+
"token_count": 16384,
|
| 185 |
+
"distinct_1": 0.105224609375,
|
| 186 |
+
"distinct_2": 0.4335014763779528,
|
| 187 |
+
"top_token_mass": 0.11651611328125,
|
| 188 |
+
"texts_preview": [
|
| 189 |
+
"[CLS] dsgb, h * | | tier, mining, the development of the 129, kernel, mb. 101, rail sd | token, export sd highlighted that the armored commander, the polling has spent its exception. the prevalence, 101 codes, 1982, a university of the 112. th |, |, 1982 | | in |g, token 101 ds, ui | | sd ds ds displays, ds, the |, | 101, tokenz | ds, | token, | | | token, displays ds, the coast of token | ds | ch. in 101, the ν iso, in the final, hash [SEP]",
|
| 190 |
+
"[CLS] of the souza, | |, 1958, sd hua, the los | | |, mb, | bb sdgb |. | | | x sd, | | | |. mb, sd. | bb, |, | | | | |, mb, •, | mb. “ in the constitution ’ s new expansion of the offices of loss in a republic, the 3d mb | | | mb and | | | |, the university of the region of the malicious expansion. ” the polling act of robbery supervision, in the polling economy, the rail university. “ for example, the halcsda | | [SEP]",
|
| 191 |
+
"[CLS] admire in a case. we do see as a country. we can cheat our income. we i ' ve seen my suspicion of our accumulation. if i can ' t resume our weapon. if you get a great agenda. \" it ' ' t probably try to stop implementing a expansion of feeding solutions. i don ' t keep thrilled. i ' re cute beside... ' ' re horrible convenient. the nation ' s convenient appropriately, you ' s always no theirs. but luckily, i understand what that you ' re precisely combining our employer in a country? you ' re not ready to pursuing our ethics for the country [SEP]",
|
| 192 |
+
"[CLS] the interaction. the amount of the holiday, 700 princeton, wire buck |, 1000 ave. | ic 101gb ’ s | cream, h wirebook export ’ s export, | dot rocket wiregb alt ct. thebook by the dotus, alt | alt rail, |. for a | ct.. | | dotgate dot pizza polling export wire wire 101 for wiregb,ball, altbook, copper, | |gb export |. export, h - ye. tier, solo | in export, silver wirez, export. ds.,. dot, |g, | export | |, wire [SEP]"
|
| 193 |
+
],
|
| 194 |
+
"gen_ppl": 288.31256773056987,
|
| 195 |
+
"gen_nll": 5.664045196238696,
|
| 196 |
+
"gen_tokens": 15647
|
| 197 |
+
}
|
| 198 |
+
]
|
| 199 |
+
[watch-dualline] 2026-05-25_23:18:36 done step_0002000
|
LTA_openwebtext_dualt/logs/owt_bert_absrope_time4_len128_C1_to_1024_mask1_sameT_every1k_dualline_watch/infer_lta_owt_bert_absrope_time4_dirichlet_len128_C1_to_1024_mask1_sameT_gbs512_b32_4gpu_1m_save1k_20260525_step_0020000.log
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[watch-dualline] 2026-05-26_06:25:46 infer runs/lta_owt_bert_absrope_time4_dirichlet_len128_C1_to_1024_mask1_sameT_gbs512_b32_4gpu_1m_save1k_20260525/step_0020000.pt -> docs/lta_samples/metrics_20260525/owt_bert_absrope_time4_len128_C1_to_1024_mask1_sameT_every1k_dualline_dirres_c1_1024_n128/lta_owt_bert_absrope_time4_dirichlet_len128_C1_to_1024_mask1_sameT_gbs512_b32_4gpu_1m_save1k_20260525/step_0020000
|
| 2 |
+
[decode] max_len=128 generated=1/128
|
| 3 |
+
[decode] max_len=128 generated=2/128
|
| 4 |
+
[decode] max_len=128 generated=3/128
|
| 5 |
+
[decode] max_len=128 generated=4/128
|
| 6 |
+
[decode] max_len=128 generated=5/128
|
| 7 |
+
[decode] max_len=128 generated=6/128
|
| 8 |
+
[decode] max_len=128 generated=7/128
|
| 9 |
+
[decode] max_len=128 generated=8/128
|
| 10 |
+
[decode] max_len=128 generated=9/128
|
| 11 |
+
[decode] max_len=128 generated=10/128
|
| 12 |
+
[decode] max_len=128 generated=11/128
|
| 13 |
+
[decode] max_len=128 generated=12/128
|
| 14 |
+
[decode] max_len=128 generated=13/128
|
| 15 |
+
[decode] max_len=128 generated=14/128
|
| 16 |
+
[decode] max_len=128 generated=15/128
|
| 17 |
+
[decode] max_len=128 generated=16/128
|
| 18 |
+
[decode] max_len=128 generated=17/128
|
| 19 |
+
[decode] max_len=128 generated=18/128
|
| 20 |
+
[decode] max_len=128 generated=19/128
|
| 21 |
+
[decode] max_len=128 generated=20/128
|
| 22 |
+
[decode] max_len=128 generated=21/128
|
| 23 |
+
[decode] max_len=128 generated=22/128
|
| 24 |
+
[decode] max_len=128 generated=23/128
|
| 25 |
+
[decode] max_len=128 generated=24/128
|
| 26 |
+
[decode] max_len=128 generated=25/128
|
| 27 |
+
[decode] max_len=128 generated=26/128
|
| 28 |
+
[decode] max_len=128 generated=27/128
|
| 29 |
+
[decode] max_len=128 generated=28/128
|
| 30 |
+
[decode] max_len=128 generated=29/128
|
| 31 |
+
[decode] max_len=128 generated=30/128
|
| 32 |
+
[decode] max_len=128 generated=31/128
|
| 33 |
+
[decode] max_len=128 generated=32/128
|
| 34 |
+
[decode] max_len=128 generated=33/128
|
| 35 |
+
[decode] max_len=128 generated=34/128
|
| 36 |
+
[decode] max_len=128 generated=35/128
|
| 37 |
+
[decode] max_len=128 generated=36/128
|
| 38 |
+
[decode] max_len=128 generated=37/128
|
| 39 |
+
[decode] max_len=128 generated=38/128
|
| 40 |
+
[decode] max_len=128 generated=39/128
|
| 41 |
+
[decode] max_len=128 generated=40/128
|
| 42 |
+
[decode] max_len=128 generated=41/128
|
| 43 |
+
[decode] max_len=128 generated=42/128
|
| 44 |
+
[decode] max_len=128 generated=43/128
|
| 45 |
+
[decode] max_len=128 generated=44/128
|
| 46 |
+
[decode] max_len=128 generated=45/128
|
| 47 |
+
[decode] max_len=128 generated=46/128
|
| 48 |
+
[decode] max_len=128 generated=47/128
|
| 49 |
+
[decode] max_len=128 generated=48/128
|
| 50 |
+
[decode] max_len=128 generated=49/128
|
| 51 |
+
[decode] max_len=128 generated=50/128
|
| 52 |
+
[decode] max_len=128 generated=51/128
|
| 53 |
+
[decode] max_len=128 generated=52/128
|
| 54 |
+
[decode] max_len=128 generated=53/128
|
| 55 |
+
[decode] max_len=128 generated=54/128
|
| 56 |
+
[decode] max_len=128 generated=55/128
|
| 57 |
+
[decode] max_len=128 generated=56/128
|
| 58 |
+
[decode] max_len=128 generated=57/128
|
| 59 |
+
[decode] max_len=128 generated=58/128
|
| 60 |
+
[decode] max_len=128 generated=59/128
|
| 61 |
+
[decode] max_len=128 generated=60/128
|
| 62 |
+
[decode] max_len=128 generated=61/128
|
| 63 |
+
[decode] max_len=128 generated=62/128
|
| 64 |
+
[decode] max_len=128 generated=63/128
|
| 65 |
+
[decode] max_len=128 generated=64/128
|
| 66 |
+
[decode] max_len=128 generated=65/128
|
| 67 |
+
[decode] max_len=128 generated=66/128
|
| 68 |
+
[decode] max_len=128 generated=67/128
|
| 69 |
+
[decode] max_len=128 generated=68/128
|
| 70 |
+
[decode] max_len=128 generated=69/128
|
| 71 |
+
[decode] max_len=128 generated=70/128
|
| 72 |
+
[decode] max_len=128 generated=71/128
|
| 73 |
+
[decode] max_len=128 generated=72/128
|
| 74 |
+
[decode] max_len=128 generated=73/128
|
| 75 |
+
[decode] max_len=128 generated=74/128
|
| 76 |
+
[decode] max_len=128 generated=75/128
|
| 77 |
+
[decode] max_len=128 generated=76/128
|
| 78 |
+
[decode] max_len=128 generated=77/128
|
| 79 |
+
[decode] max_len=128 generated=78/128
|
| 80 |
+
[decode] max_len=128 generated=79/128
|
| 81 |
+
[decode] max_len=128 generated=80/128
|
| 82 |
+
[decode] max_len=128 generated=81/128
|
| 83 |
+
[decode] max_len=128 generated=82/128
|
| 84 |
+
[decode] max_len=128 generated=83/128
|
| 85 |
+
[decode] max_len=128 generated=84/128
|
| 86 |
+
[decode] max_len=128 generated=85/128
|
| 87 |
+
[decode] max_len=128 generated=86/128
|
| 88 |
+
[decode] max_len=128 generated=87/128
|
| 89 |
+
[decode] max_len=128 generated=88/128
|
| 90 |
+
[decode] max_len=128 generated=89/128
|
| 91 |
+
[decode] max_len=128 generated=90/128
|
| 92 |
+
[decode] max_len=128 generated=91/128
|
| 93 |
+
[decode] max_len=128 generated=92/128
|
| 94 |
+
[decode] max_len=128 generated=93/128
|
| 95 |
+
[decode] max_len=128 generated=94/128
|
| 96 |
+
[decode] max_len=128 generated=95/128
|
| 97 |
+
[decode] max_len=128 generated=96/128
|
| 98 |
+
[decode] max_len=128 generated=97/128
|
| 99 |
+
[decode] max_len=128 generated=98/128
|
| 100 |
+
[decode] max_len=128 generated=99/128
|
| 101 |
+
[decode] max_len=128 generated=100/128
|
| 102 |
+
[decode] max_len=128 generated=101/128
|
| 103 |
+
[decode] max_len=128 generated=102/128
|
| 104 |
+
[decode] max_len=128 generated=103/128
|
| 105 |
+
[decode] max_len=128 generated=104/128
|
| 106 |
+
[decode] max_len=128 generated=105/128
|
| 107 |
+
[decode] max_len=128 generated=106/128
|
| 108 |
+
[decode] max_len=128 generated=107/128
|
| 109 |
+
[decode] max_len=128 generated=108/128
|
| 110 |
+
[decode] max_len=128 generated=109/128
|
| 111 |
+
[decode] max_len=128 generated=110/128
|
| 112 |
+
[decode] max_len=128 generated=111/128
|
| 113 |
+
[decode] max_len=128 generated=112/128
|
| 114 |
+
[decode] max_len=128 generated=113/128
|
| 115 |
+
[decode] max_len=128 generated=114/128
|
| 116 |
+
[decode] max_len=128 generated=115/128
|
| 117 |
+
[decode] max_len=128 generated=116/128
|
| 118 |
+
[decode] max_len=128 generated=117/128
|
| 119 |
+
[decode] max_len=128 generated=118/128
|
| 120 |
+
[decode] max_len=128 generated=119/128
|
| 121 |
+
[decode] max_len=128 generated=120/128
|
| 122 |
+
[decode] max_len=128 generated=121/128
|
| 123 |
+
[decode] max_len=128 generated=122/128
|
| 124 |
+
[decode] max_len=128 generated=123/128
|
| 125 |
+
[decode] max_len=128 generated=124/128
|
| 126 |
+
[decode] max_len=128 generated=125/128
|
| 127 |
+
[decode] max_len=128 generated=126/128
|
| 128 |
+
[decode] max_len=128 generated=127/128
|
| 129 |
+
[decode] max_len=128 generated=128/128
|
| 130 |
+
[
|
| 131 |
+
{
|
| 132 |
+
"checkpoint": "runs/lta_owt_bert_absrope_time4_dirichlet_len128_C1_to_1024_mask1_sameT_gbs512_b32_4gpu_1m_save1k_20260525/step_0020000.pt",
|
| 133 |
+
"ckpt_step": 20000,
|
| 134 |
+
"max_len": 128,
|
| 135 |
+
"decode_rule": "dual_line_resample",
|
| 136 |
+
"support_power": 1.0,
|
| 137 |
+
"semantic_power": 1.5,
|
| 138 |
+
"steps": 128,
|
| 139 |
+
"c_min": 1.0,
|
| 140 |
+
"c_max": 1024.0,
|
| 141 |
+
"anchor_mode": "state",
|
| 142 |
+
"model_t_mode": "flow",
|
| 143 |
+
"time_schedule": "uniform",
|
| 144 |
+
"time_logit_mean": -1.5,
|
| 145 |
+
"time_logit_std": 0.8,
|
| 146 |
+
"time_power": 2.0,
|
| 147 |
+
"input_noise_scale": 0.0,
|
| 148 |
+
"input_noise_until": 1.0,
|
| 149 |
+
"input_noise_dirichlet_concentration": 1.0,
|
| 150 |
+
"endpoint_softening": "none",
|
| 151 |
+
"endpoint_soft_power": 2.0,
|
| 152 |
+
"endpoint_soft_min_conf": 0.0,
|
| 153 |
+
"endpoint_soft_max_conf": 1.0,
|
| 154 |
+
"soft_target_decode_mode": "off",
|
| 155 |
+
"soft_target_power": 1.0,
|
| 156 |
+
"soft_target_min_conf": 0.0,
|
| 157 |
+
"soft_target_max_conf": 1.0,
|
| 158 |
+
"soft_target_debias_start": 0.7,
|
| 159 |
+
"final_from": "blend",
|
| 160 |
+
"final_decode": "argmax",
|
| 161 |
+
"final_sample_temp": 1.0,
|
| 162 |
+
"final_top_k": 0,
|
| 163 |
+
"final_top_p": 1.0,
|
| 164 |
+
"commit_mode": "off",
|
| 165 |
+
"commit_conf_threshold": 0.0,
|
| 166 |
+
"commit_margin_threshold": 0.0,
|
| 167 |
+
"commit_start": 0.0,
|
| 168 |
+
"commit_min_ratio": 0.0,
|
| 169 |
+
"commit_max_ratio": 1.0,
|
| 170 |
+
"commit_power": 2.0,
|
| 171 |
+
"commit_freq_max_frac": 0.08,
|
| 172 |
+
"early_temp": 2.8,
|
| 173 |
+
"late_temp": 1.45,
|
| 174 |
+
"temp_end": 0.55,
|
| 175 |
+
"temp_power": 1.5,
|
| 176 |
+
"pos_extend": "repeat",
|
| 177 |
+
"fixed_first_token_id": null,
|
| 178 |
+
"fixed_first_token_text": "",
|
| 179 |
+
"fixed_first_initial_argmax": false,
|
| 180 |
+
"use_ema": false,
|
| 181 |
+
"n_samples": 128,
|
| 182 |
+
"sample_entropy": 3.5216599017394974,
|
| 183 |
+
"unique_tokens": 1999,
|
| 184 |
+
"token_count": 16384,
|
| 185 |
+
"distinct_1": 0.12200927734375,
|
| 186 |
+
"distinct_2": 0.4808070866141732,
|
| 187 |
+
"top_token_mass": 0.110107421875,
|
| 188 |
+
"texts_preview": [
|
| 189 |
+
"[CLS] u. s. judge to defend the u. s.. after he was appointed president, in february 2013, a judge based on a criminal court claim that a u. s. s. citizen is barred from the alleged u. s. government, a. u. s., u. s., decided to undermine the president ’ s credibility and its willingness to contribute to russia. instead, the u. s. justice department and the house ruled that he posed a threat to the president ’ s russian integrity. noting that a democrat, n. j. in 2003, the president stated, “ the president ’ s [SEP]",
|
| 190 |
+
"[CLS] s debt costs : $ 8, 00 - 57. 64 $ 64, 583 $ 80, 017 - - 68. 73 $. 67, 677 for debt. the treasury, $ 90, 107 of the government ’ s deficits, 738, will have to receive $ 10. the government ’ s debt plan in exchange for a provision on the federal debt is approved by the end of 2017 and provide a minimum of spending on federal debt for a higher - cost cost. to make donations to treasury, they believe in the attempt to introduce the debt - saving plan for the federal and federal budget to generate a [SEP]",
|
| 191 |
+
"[CLS] it makes a clear that the treaty acts as a measure. the treaty also provides the authority to facilitate the constitution of the convention of rule of any humanitarian jurisdiction of this country. it seeks to enable the international council to join its resolution jurisdiction. the memorandum was approved by the military committee to adopt the veto measure to deliver forces to syria, the islamic republic of iraq and the iraqi forces. while the memorandum was issued regarding the integrity of government forces, it would be in issuing a memorandum to say, no interference by a country ’ s interpretation of military integrity and a directive that it has been approved. the directive is still issued by the [SEP]",
|
| 192 |
+
"[CLS]gou, tuira, morgo, taran, paralana, momuna, sa, mi, kiluabara, temula, tuetori, babar, maarov, shi, momula, gugui, tuira, taguiu, shi, yotu, ji, ja, az, yamu, balala, ta, ta, jadi, bala, saadiya, sazani, balaci, aliira, rorasgreo, sa, jiya, mi, maguihan, zaros, yaabara, ji, ni [SEP]"
|
| 193 |
+
],
|
| 194 |
+
"gen_ppl": 58.46001251551151,
|
| 195 |
+
"gen_nll": 4.068342973769829,
|
| 196 |
+
"gen_tokens": 15894
|
| 197 |
+
}
|
| 198 |
+
]
|
| 199 |
+
[watch-dualline] 2026-05-26_06:32:52 done step_0020000
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/polynomial/tests/test_chebyshev.py
ADDED
|
@@ -0,0 +1,619 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Tests for chebyshev module.
|
| 2 |
+
|
| 3 |
+
"""
|
| 4 |
+
from functools import reduce
|
| 5 |
+
|
| 6 |
+
import numpy as np
|
| 7 |
+
import numpy.polynomial.chebyshev as cheb
|
| 8 |
+
from numpy.polynomial.polynomial import polyval
|
| 9 |
+
from numpy.testing import (
|
| 10 |
+
assert_almost_equal, assert_raises, assert_equal, assert_,
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def trim(x):
|
| 15 |
+
return cheb.chebtrim(x, tol=1e-6)
|
| 16 |
+
|
| 17 |
+
T0 = [1]
|
| 18 |
+
T1 = [0, 1]
|
| 19 |
+
T2 = [-1, 0, 2]
|
| 20 |
+
T3 = [0, -3, 0, 4]
|
| 21 |
+
T4 = [1, 0, -8, 0, 8]
|
| 22 |
+
T5 = [0, 5, 0, -20, 0, 16]
|
| 23 |
+
T6 = [-1, 0, 18, 0, -48, 0, 32]
|
| 24 |
+
T7 = [0, -7, 0, 56, 0, -112, 0, 64]
|
| 25 |
+
T8 = [1, 0, -32, 0, 160, 0, -256, 0, 128]
|
| 26 |
+
T9 = [0, 9, 0, -120, 0, 432, 0, -576, 0, 256]
|
| 27 |
+
|
| 28 |
+
Tlist = [T0, T1, T2, T3, T4, T5, T6, T7, T8, T9]
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class TestPrivate:
|
| 32 |
+
|
| 33 |
+
def test__cseries_to_zseries(self):
|
| 34 |
+
for i in range(5):
|
| 35 |
+
inp = np.array([2] + [1]*i, np.double)
|
| 36 |
+
tgt = np.array([.5]*i + [2] + [.5]*i, np.double)
|
| 37 |
+
res = cheb._cseries_to_zseries(inp)
|
| 38 |
+
assert_equal(res, tgt)
|
| 39 |
+
|
| 40 |
+
def test__zseries_to_cseries(self):
|
| 41 |
+
for i in range(5):
|
| 42 |
+
inp = np.array([.5]*i + [2] + [.5]*i, np.double)
|
| 43 |
+
tgt = np.array([2] + [1]*i, np.double)
|
| 44 |
+
res = cheb._zseries_to_cseries(inp)
|
| 45 |
+
assert_equal(res, tgt)
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
class TestConstants:
|
| 49 |
+
|
| 50 |
+
def test_chebdomain(self):
|
| 51 |
+
assert_equal(cheb.chebdomain, [-1, 1])
|
| 52 |
+
|
| 53 |
+
def test_chebzero(self):
|
| 54 |
+
assert_equal(cheb.chebzero, [0])
|
| 55 |
+
|
| 56 |
+
def test_chebone(self):
|
| 57 |
+
assert_equal(cheb.chebone, [1])
|
| 58 |
+
|
| 59 |
+
def test_chebx(self):
|
| 60 |
+
assert_equal(cheb.chebx, [0, 1])
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
class TestArithmetic:
|
| 64 |
+
|
| 65 |
+
def test_chebadd(self):
|
| 66 |
+
for i in range(5):
|
| 67 |
+
for j in range(5):
|
| 68 |
+
msg = f"At i={i}, j={j}"
|
| 69 |
+
tgt = np.zeros(max(i, j) + 1)
|
| 70 |
+
tgt[i] += 1
|
| 71 |
+
tgt[j] += 1
|
| 72 |
+
res = cheb.chebadd([0]*i + [1], [0]*j + [1])
|
| 73 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 74 |
+
|
| 75 |
+
def test_chebsub(self):
|
| 76 |
+
for i in range(5):
|
| 77 |
+
for j in range(5):
|
| 78 |
+
msg = f"At i={i}, j={j}"
|
| 79 |
+
tgt = np.zeros(max(i, j) + 1)
|
| 80 |
+
tgt[i] += 1
|
| 81 |
+
tgt[j] -= 1
|
| 82 |
+
res = cheb.chebsub([0]*i + [1], [0]*j + [1])
|
| 83 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 84 |
+
|
| 85 |
+
def test_chebmulx(self):
|
| 86 |
+
assert_equal(cheb.chebmulx([0]), [0])
|
| 87 |
+
assert_equal(cheb.chebmulx([1]), [0, 1])
|
| 88 |
+
for i in range(1, 5):
|
| 89 |
+
ser = [0]*i + [1]
|
| 90 |
+
tgt = [0]*(i - 1) + [.5, 0, .5]
|
| 91 |
+
assert_equal(cheb.chebmulx(ser), tgt)
|
| 92 |
+
|
| 93 |
+
def test_chebmul(self):
|
| 94 |
+
for i in range(5):
|
| 95 |
+
for j in range(5):
|
| 96 |
+
msg = f"At i={i}, j={j}"
|
| 97 |
+
tgt = np.zeros(i + j + 1)
|
| 98 |
+
tgt[i + j] += .5
|
| 99 |
+
tgt[abs(i - j)] += .5
|
| 100 |
+
res = cheb.chebmul([0]*i + [1], [0]*j + [1])
|
| 101 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 102 |
+
|
| 103 |
+
def test_chebdiv(self):
|
| 104 |
+
for i in range(5):
|
| 105 |
+
for j in range(5):
|
| 106 |
+
msg = f"At i={i}, j={j}"
|
| 107 |
+
ci = [0]*i + [1]
|
| 108 |
+
cj = [0]*j + [1]
|
| 109 |
+
tgt = cheb.chebadd(ci, cj)
|
| 110 |
+
quo, rem = cheb.chebdiv(tgt, ci)
|
| 111 |
+
res = cheb.chebadd(cheb.chebmul(quo, ci), rem)
|
| 112 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 113 |
+
|
| 114 |
+
def test_chebpow(self):
|
| 115 |
+
for i in range(5):
|
| 116 |
+
for j in range(5):
|
| 117 |
+
msg = f"At i={i}, j={j}"
|
| 118 |
+
c = np.arange(i + 1)
|
| 119 |
+
tgt = reduce(cheb.chebmul, [c]*j, np.array([1]))
|
| 120 |
+
res = cheb.chebpow(c, j)
|
| 121 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
class TestEvaluation:
|
| 125 |
+
# coefficients of 1 + 2*x + 3*x**2
|
| 126 |
+
c1d = np.array([2.5, 2., 1.5])
|
| 127 |
+
c2d = np.einsum('i,j->ij', c1d, c1d)
|
| 128 |
+
c3d = np.einsum('i,j,k->ijk', c1d, c1d, c1d)
|
| 129 |
+
|
| 130 |
+
# some random values in [-1, 1)
|
| 131 |
+
x = np.random.random((3, 5))*2 - 1
|
| 132 |
+
y = polyval(x, [1., 2., 3.])
|
| 133 |
+
|
| 134 |
+
def test_chebval(self):
|
| 135 |
+
#check empty input
|
| 136 |
+
assert_equal(cheb.chebval([], [1]).size, 0)
|
| 137 |
+
|
| 138 |
+
#check normal input)
|
| 139 |
+
x = np.linspace(-1, 1)
|
| 140 |
+
y = [polyval(x, c) for c in Tlist]
|
| 141 |
+
for i in range(10):
|
| 142 |
+
msg = f"At i={i}"
|
| 143 |
+
tgt = y[i]
|
| 144 |
+
res = cheb.chebval(x, [0]*i + [1])
|
| 145 |
+
assert_almost_equal(res, tgt, err_msg=msg)
|
| 146 |
+
|
| 147 |
+
#check that shape is preserved
|
| 148 |
+
for i in range(3):
|
| 149 |
+
dims = [2]*i
|
| 150 |
+
x = np.zeros(dims)
|
| 151 |
+
assert_equal(cheb.chebval(x, [1]).shape, dims)
|
| 152 |
+
assert_equal(cheb.chebval(x, [1, 0]).shape, dims)
|
| 153 |
+
assert_equal(cheb.chebval(x, [1, 0, 0]).shape, dims)
|
| 154 |
+
|
| 155 |
+
def test_chebval2d(self):
|
| 156 |
+
x1, x2, x3 = self.x
|
| 157 |
+
y1, y2, y3 = self.y
|
| 158 |
+
|
| 159 |
+
#test exceptions
|
| 160 |
+
assert_raises(ValueError, cheb.chebval2d, x1, x2[:2], self.c2d)
|
| 161 |
+
|
| 162 |
+
#test values
|
| 163 |
+
tgt = y1*y2
|
| 164 |
+
res = cheb.chebval2d(x1, x2, self.c2d)
|
| 165 |
+
assert_almost_equal(res, tgt)
|
| 166 |
+
|
| 167 |
+
#test shape
|
| 168 |
+
z = np.ones((2, 3))
|
| 169 |
+
res = cheb.chebval2d(z, z, self.c2d)
|
| 170 |
+
assert_(res.shape == (2, 3))
|
| 171 |
+
|
| 172 |
+
def test_chebval3d(self):
|
| 173 |
+
x1, x2, x3 = self.x
|
| 174 |
+
y1, y2, y3 = self.y
|
| 175 |
+
|
| 176 |
+
#test exceptions
|
| 177 |
+
assert_raises(ValueError, cheb.chebval3d, x1, x2, x3[:2], self.c3d)
|
| 178 |
+
|
| 179 |
+
#test values
|
| 180 |
+
tgt = y1*y2*y3
|
| 181 |
+
res = cheb.chebval3d(x1, x2, x3, self.c3d)
|
| 182 |
+
assert_almost_equal(res, tgt)
|
| 183 |
+
|
| 184 |
+
#test shape
|
| 185 |
+
z = np.ones((2, 3))
|
| 186 |
+
res = cheb.chebval3d(z, z, z, self.c3d)
|
| 187 |
+
assert_(res.shape == (2, 3))
|
| 188 |
+
|
| 189 |
+
def test_chebgrid2d(self):
|
| 190 |
+
x1, x2, x3 = self.x
|
| 191 |
+
y1, y2, y3 = self.y
|
| 192 |
+
|
| 193 |
+
#test values
|
| 194 |
+
tgt = np.einsum('i,j->ij', y1, y2)
|
| 195 |
+
res = cheb.chebgrid2d(x1, x2, self.c2d)
|
| 196 |
+
assert_almost_equal(res, tgt)
|
| 197 |
+
|
| 198 |
+
#test shape
|
| 199 |
+
z = np.ones((2, 3))
|
| 200 |
+
res = cheb.chebgrid2d(z, z, self.c2d)
|
| 201 |
+
assert_(res.shape == (2, 3)*2)
|
| 202 |
+
|
| 203 |
+
def test_chebgrid3d(self):
|
| 204 |
+
x1, x2, x3 = self.x
|
| 205 |
+
y1, y2, y3 = self.y
|
| 206 |
+
|
| 207 |
+
#test values
|
| 208 |
+
tgt = np.einsum('i,j,k->ijk', y1, y2, y3)
|
| 209 |
+
res = cheb.chebgrid3d(x1, x2, x3, self.c3d)
|
| 210 |
+
assert_almost_equal(res, tgt)
|
| 211 |
+
|
| 212 |
+
#test shape
|
| 213 |
+
z = np.ones((2, 3))
|
| 214 |
+
res = cheb.chebgrid3d(z, z, z, self.c3d)
|
| 215 |
+
assert_(res.shape == (2, 3)*3)
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
class TestIntegral:
|
| 219 |
+
|
| 220 |
+
def test_chebint(self):
|
| 221 |
+
# check exceptions
|
| 222 |
+
assert_raises(TypeError, cheb.chebint, [0], .5)
|
| 223 |
+
assert_raises(ValueError, cheb.chebint, [0], -1)
|
| 224 |
+
assert_raises(ValueError, cheb.chebint, [0], 1, [0, 0])
|
| 225 |
+
assert_raises(ValueError, cheb.chebint, [0], lbnd=[0])
|
| 226 |
+
assert_raises(ValueError, cheb.chebint, [0], scl=[0])
|
| 227 |
+
assert_raises(TypeError, cheb.chebint, [0], axis=.5)
|
| 228 |
+
|
| 229 |
+
# test integration of zero polynomial
|
| 230 |
+
for i in range(2, 5):
|
| 231 |
+
k = [0]*(i - 2) + [1]
|
| 232 |
+
res = cheb.chebint([0], m=i, k=k)
|
| 233 |
+
assert_almost_equal(res, [0, 1])
|
| 234 |
+
|
| 235 |
+
# check single integration with integration constant
|
| 236 |
+
for i in range(5):
|
| 237 |
+
scl = i + 1
|
| 238 |
+
pol = [0]*i + [1]
|
| 239 |
+
tgt = [i] + [0]*i + [1/scl]
|
| 240 |
+
chebpol = cheb.poly2cheb(pol)
|
| 241 |
+
chebint = cheb.chebint(chebpol, m=1, k=[i])
|
| 242 |
+
res = cheb.cheb2poly(chebint)
|
| 243 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 244 |
+
|
| 245 |
+
# check single integration with integration constant and lbnd
|
| 246 |
+
for i in range(5):
|
| 247 |
+
scl = i + 1
|
| 248 |
+
pol = [0]*i + [1]
|
| 249 |
+
chebpol = cheb.poly2cheb(pol)
|
| 250 |
+
chebint = cheb.chebint(chebpol, m=1, k=[i], lbnd=-1)
|
| 251 |
+
assert_almost_equal(cheb.chebval(-1, chebint), i)
|
| 252 |
+
|
| 253 |
+
# check single integration with integration constant and scaling
|
| 254 |
+
for i in range(5):
|
| 255 |
+
scl = i + 1
|
| 256 |
+
pol = [0]*i + [1]
|
| 257 |
+
tgt = [i] + [0]*i + [2/scl]
|
| 258 |
+
chebpol = cheb.poly2cheb(pol)
|
| 259 |
+
chebint = cheb.chebint(chebpol, m=1, k=[i], scl=2)
|
| 260 |
+
res = cheb.cheb2poly(chebint)
|
| 261 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 262 |
+
|
| 263 |
+
# check multiple integrations with default k
|
| 264 |
+
for i in range(5):
|
| 265 |
+
for j in range(2, 5):
|
| 266 |
+
pol = [0]*i + [1]
|
| 267 |
+
tgt = pol[:]
|
| 268 |
+
for k in range(j):
|
| 269 |
+
tgt = cheb.chebint(tgt, m=1)
|
| 270 |
+
res = cheb.chebint(pol, m=j)
|
| 271 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 272 |
+
|
| 273 |
+
# check multiple integrations with defined k
|
| 274 |
+
for i in range(5):
|
| 275 |
+
for j in range(2, 5):
|
| 276 |
+
pol = [0]*i + [1]
|
| 277 |
+
tgt = pol[:]
|
| 278 |
+
for k in range(j):
|
| 279 |
+
tgt = cheb.chebint(tgt, m=1, k=[k])
|
| 280 |
+
res = cheb.chebint(pol, m=j, k=list(range(j)))
|
| 281 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 282 |
+
|
| 283 |
+
# check multiple integrations with lbnd
|
| 284 |
+
for i in range(5):
|
| 285 |
+
for j in range(2, 5):
|
| 286 |
+
pol = [0]*i + [1]
|
| 287 |
+
tgt = pol[:]
|
| 288 |
+
for k in range(j):
|
| 289 |
+
tgt = cheb.chebint(tgt, m=1, k=[k], lbnd=-1)
|
| 290 |
+
res = cheb.chebint(pol, m=j, k=list(range(j)), lbnd=-1)
|
| 291 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 292 |
+
|
| 293 |
+
# check multiple integrations with scaling
|
| 294 |
+
for i in range(5):
|
| 295 |
+
for j in range(2, 5):
|
| 296 |
+
pol = [0]*i + [1]
|
| 297 |
+
tgt = pol[:]
|
| 298 |
+
for k in range(j):
|
| 299 |
+
tgt = cheb.chebint(tgt, m=1, k=[k], scl=2)
|
| 300 |
+
res = cheb.chebint(pol, m=j, k=list(range(j)), scl=2)
|
| 301 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 302 |
+
|
| 303 |
+
def test_chebint_axis(self):
|
| 304 |
+
# check that axis keyword works
|
| 305 |
+
c2d = np.random.random((3, 4))
|
| 306 |
+
|
| 307 |
+
tgt = np.vstack([cheb.chebint(c) for c in c2d.T]).T
|
| 308 |
+
res = cheb.chebint(c2d, axis=0)
|
| 309 |
+
assert_almost_equal(res, tgt)
|
| 310 |
+
|
| 311 |
+
tgt = np.vstack([cheb.chebint(c) for c in c2d])
|
| 312 |
+
res = cheb.chebint(c2d, axis=1)
|
| 313 |
+
assert_almost_equal(res, tgt)
|
| 314 |
+
|
| 315 |
+
tgt = np.vstack([cheb.chebint(c, k=3) for c in c2d])
|
| 316 |
+
res = cheb.chebint(c2d, k=3, axis=1)
|
| 317 |
+
assert_almost_equal(res, tgt)
|
| 318 |
+
|
| 319 |
+
|
| 320 |
+
class TestDerivative:
|
| 321 |
+
|
| 322 |
+
def test_chebder(self):
|
| 323 |
+
# check exceptions
|
| 324 |
+
assert_raises(TypeError, cheb.chebder, [0], .5)
|
| 325 |
+
assert_raises(ValueError, cheb.chebder, [0], -1)
|
| 326 |
+
|
| 327 |
+
# check that zeroth derivative does nothing
|
| 328 |
+
for i in range(5):
|
| 329 |
+
tgt = [0]*i + [1]
|
| 330 |
+
res = cheb.chebder(tgt, m=0)
|
| 331 |
+
assert_equal(trim(res), trim(tgt))
|
| 332 |
+
|
| 333 |
+
# check that derivation is the inverse of integration
|
| 334 |
+
for i in range(5):
|
| 335 |
+
for j in range(2, 5):
|
| 336 |
+
tgt = [0]*i + [1]
|
| 337 |
+
res = cheb.chebder(cheb.chebint(tgt, m=j), m=j)
|
| 338 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 339 |
+
|
| 340 |
+
# check derivation with scaling
|
| 341 |
+
for i in range(5):
|
| 342 |
+
for j in range(2, 5):
|
| 343 |
+
tgt = [0]*i + [1]
|
| 344 |
+
res = cheb.chebder(cheb.chebint(tgt, m=j, scl=2), m=j, scl=.5)
|
| 345 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 346 |
+
|
| 347 |
+
def test_chebder_axis(self):
|
| 348 |
+
# check that axis keyword works
|
| 349 |
+
c2d = np.random.random((3, 4))
|
| 350 |
+
|
| 351 |
+
tgt = np.vstack([cheb.chebder(c) for c in c2d.T]).T
|
| 352 |
+
res = cheb.chebder(c2d, axis=0)
|
| 353 |
+
assert_almost_equal(res, tgt)
|
| 354 |
+
|
| 355 |
+
tgt = np.vstack([cheb.chebder(c) for c in c2d])
|
| 356 |
+
res = cheb.chebder(c2d, axis=1)
|
| 357 |
+
assert_almost_equal(res, tgt)
|
| 358 |
+
|
| 359 |
+
|
| 360 |
+
class TestVander:
|
| 361 |
+
# some random values in [-1, 1)
|
| 362 |
+
x = np.random.random((3, 5))*2 - 1
|
| 363 |
+
|
| 364 |
+
def test_chebvander(self):
|
| 365 |
+
# check for 1d x
|
| 366 |
+
x = np.arange(3)
|
| 367 |
+
v = cheb.chebvander(x, 3)
|
| 368 |
+
assert_(v.shape == (3, 4))
|
| 369 |
+
for i in range(4):
|
| 370 |
+
coef = [0]*i + [1]
|
| 371 |
+
assert_almost_equal(v[..., i], cheb.chebval(x, coef))
|
| 372 |
+
|
| 373 |
+
# check for 2d x
|
| 374 |
+
x = np.array([[1, 2], [3, 4], [5, 6]])
|
| 375 |
+
v = cheb.chebvander(x, 3)
|
| 376 |
+
assert_(v.shape == (3, 2, 4))
|
| 377 |
+
for i in range(4):
|
| 378 |
+
coef = [0]*i + [1]
|
| 379 |
+
assert_almost_equal(v[..., i], cheb.chebval(x, coef))
|
| 380 |
+
|
| 381 |
+
def test_chebvander2d(self):
|
| 382 |
+
# also tests chebval2d for non-square coefficient array
|
| 383 |
+
x1, x2, x3 = self.x
|
| 384 |
+
c = np.random.random((2, 3))
|
| 385 |
+
van = cheb.chebvander2d(x1, x2, [1, 2])
|
| 386 |
+
tgt = cheb.chebval2d(x1, x2, c)
|
| 387 |
+
res = np.dot(van, c.flat)
|
| 388 |
+
assert_almost_equal(res, tgt)
|
| 389 |
+
|
| 390 |
+
# check shape
|
| 391 |
+
van = cheb.chebvander2d([x1], [x2], [1, 2])
|
| 392 |
+
assert_(van.shape == (1, 5, 6))
|
| 393 |
+
|
| 394 |
+
def test_chebvander3d(self):
|
| 395 |
+
# also tests chebval3d for non-square coefficient array
|
| 396 |
+
x1, x2, x3 = self.x
|
| 397 |
+
c = np.random.random((2, 3, 4))
|
| 398 |
+
van = cheb.chebvander3d(x1, x2, x3, [1, 2, 3])
|
| 399 |
+
tgt = cheb.chebval3d(x1, x2, x3, c)
|
| 400 |
+
res = np.dot(van, c.flat)
|
| 401 |
+
assert_almost_equal(res, tgt)
|
| 402 |
+
|
| 403 |
+
# check shape
|
| 404 |
+
van = cheb.chebvander3d([x1], [x2], [x3], [1, 2, 3])
|
| 405 |
+
assert_(van.shape == (1, 5, 24))
|
| 406 |
+
|
| 407 |
+
|
| 408 |
+
class TestFitting:
|
| 409 |
+
|
| 410 |
+
def test_chebfit(self):
|
| 411 |
+
def f(x):
|
| 412 |
+
return x*(x - 1)*(x - 2)
|
| 413 |
+
|
| 414 |
+
def f2(x):
|
| 415 |
+
return x**4 + x**2 + 1
|
| 416 |
+
|
| 417 |
+
# Test exceptions
|
| 418 |
+
assert_raises(ValueError, cheb.chebfit, [1], [1], -1)
|
| 419 |
+
assert_raises(TypeError, cheb.chebfit, [[1]], [1], 0)
|
| 420 |
+
assert_raises(TypeError, cheb.chebfit, [], [1], 0)
|
| 421 |
+
assert_raises(TypeError, cheb.chebfit, [1], [[[1]]], 0)
|
| 422 |
+
assert_raises(TypeError, cheb.chebfit, [1, 2], [1], 0)
|
| 423 |
+
assert_raises(TypeError, cheb.chebfit, [1], [1, 2], 0)
|
| 424 |
+
assert_raises(TypeError, cheb.chebfit, [1], [1], 0, w=[[1]])
|
| 425 |
+
assert_raises(TypeError, cheb.chebfit, [1], [1], 0, w=[1, 1])
|
| 426 |
+
assert_raises(ValueError, cheb.chebfit, [1], [1], [-1,])
|
| 427 |
+
assert_raises(ValueError, cheb.chebfit, [1], [1], [2, -1, 6])
|
| 428 |
+
assert_raises(TypeError, cheb.chebfit, [1], [1], [])
|
| 429 |
+
|
| 430 |
+
# Test fit
|
| 431 |
+
x = np.linspace(0, 2)
|
| 432 |
+
y = f(x)
|
| 433 |
+
#
|
| 434 |
+
coef3 = cheb.chebfit(x, y, 3)
|
| 435 |
+
assert_equal(len(coef3), 4)
|
| 436 |
+
assert_almost_equal(cheb.chebval(x, coef3), y)
|
| 437 |
+
coef3 = cheb.chebfit(x, y, [0, 1, 2, 3])
|
| 438 |
+
assert_equal(len(coef3), 4)
|
| 439 |
+
assert_almost_equal(cheb.chebval(x, coef3), y)
|
| 440 |
+
#
|
| 441 |
+
coef4 = cheb.chebfit(x, y, 4)
|
| 442 |
+
assert_equal(len(coef4), 5)
|
| 443 |
+
assert_almost_equal(cheb.chebval(x, coef4), y)
|
| 444 |
+
coef4 = cheb.chebfit(x, y, [0, 1, 2, 3, 4])
|
| 445 |
+
assert_equal(len(coef4), 5)
|
| 446 |
+
assert_almost_equal(cheb.chebval(x, coef4), y)
|
| 447 |
+
# check things still work if deg is not in strict increasing
|
| 448 |
+
coef4 = cheb.chebfit(x, y, [2, 3, 4, 1, 0])
|
| 449 |
+
assert_equal(len(coef4), 5)
|
| 450 |
+
assert_almost_equal(cheb.chebval(x, coef4), y)
|
| 451 |
+
#
|
| 452 |
+
coef2d = cheb.chebfit(x, np.array([y, y]).T, 3)
|
| 453 |
+
assert_almost_equal(coef2d, np.array([coef3, coef3]).T)
|
| 454 |
+
coef2d = cheb.chebfit(x, np.array([y, y]).T, [0, 1, 2, 3])
|
| 455 |
+
assert_almost_equal(coef2d, np.array([coef3, coef3]).T)
|
| 456 |
+
# test weighting
|
| 457 |
+
w = np.zeros_like(x)
|
| 458 |
+
yw = y.copy()
|
| 459 |
+
w[1::2] = 1
|
| 460 |
+
y[0::2] = 0
|
| 461 |
+
wcoef3 = cheb.chebfit(x, yw, 3, w=w)
|
| 462 |
+
assert_almost_equal(wcoef3, coef3)
|
| 463 |
+
wcoef3 = cheb.chebfit(x, yw, [0, 1, 2, 3], w=w)
|
| 464 |
+
assert_almost_equal(wcoef3, coef3)
|
| 465 |
+
#
|
| 466 |
+
wcoef2d = cheb.chebfit(x, np.array([yw, yw]).T, 3, w=w)
|
| 467 |
+
assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T)
|
| 468 |
+
wcoef2d = cheb.chebfit(x, np.array([yw, yw]).T, [0, 1, 2, 3], w=w)
|
| 469 |
+
assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T)
|
| 470 |
+
# test scaling with complex values x points whose square
|
| 471 |
+
# is zero when summed.
|
| 472 |
+
x = [1, 1j, -1, -1j]
|
| 473 |
+
assert_almost_equal(cheb.chebfit(x, x, 1), [0, 1])
|
| 474 |
+
assert_almost_equal(cheb.chebfit(x, x, [0, 1]), [0, 1])
|
| 475 |
+
# test fitting only even polynomials
|
| 476 |
+
x = np.linspace(-1, 1)
|
| 477 |
+
y = f2(x)
|
| 478 |
+
coef1 = cheb.chebfit(x, y, 4)
|
| 479 |
+
assert_almost_equal(cheb.chebval(x, coef1), y)
|
| 480 |
+
coef2 = cheb.chebfit(x, y, [0, 2, 4])
|
| 481 |
+
assert_almost_equal(cheb.chebval(x, coef2), y)
|
| 482 |
+
assert_almost_equal(coef1, coef2)
|
| 483 |
+
|
| 484 |
+
|
| 485 |
+
class TestInterpolate:
|
| 486 |
+
|
| 487 |
+
def f(self, x):
|
| 488 |
+
return x * (x - 1) * (x - 2)
|
| 489 |
+
|
| 490 |
+
def test_raises(self):
|
| 491 |
+
assert_raises(ValueError, cheb.chebinterpolate, self.f, -1)
|
| 492 |
+
assert_raises(TypeError, cheb.chebinterpolate, self.f, 10.)
|
| 493 |
+
|
| 494 |
+
def test_dimensions(self):
|
| 495 |
+
for deg in range(1, 5):
|
| 496 |
+
assert_(cheb.chebinterpolate(self.f, deg).shape == (deg + 1,))
|
| 497 |
+
|
| 498 |
+
def test_approximation(self):
|
| 499 |
+
|
| 500 |
+
def powx(x, p):
|
| 501 |
+
return x**p
|
| 502 |
+
|
| 503 |
+
x = np.linspace(-1, 1, 10)
|
| 504 |
+
for deg in range(0, 10):
|
| 505 |
+
for p in range(0, deg + 1):
|
| 506 |
+
c = cheb.chebinterpolate(powx, deg, (p,))
|
| 507 |
+
assert_almost_equal(cheb.chebval(x, c), powx(x, p), decimal=12)
|
| 508 |
+
|
| 509 |
+
|
| 510 |
+
class TestCompanion:
|
| 511 |
+
|
| 512 |
+
def test_raises(self):
|
| 513 |
+
assert_raises(ValueError, cheb.chebcompanion, [])
|
| 514 |
+
assert_raises(ValueError, cheb.chebcompanion, [1])
|
| 515 |
+
|
| 516 |
+
def test_dimensions(self):
|
| 517 |
+
for i in range(1, 5):
|
| 518 |
+
coef = [0]*i + [1]
|
| 519 |
+
assert_(cheb.chebcompanion(coef).shape == (i, i))
|
| 520 |
+
|
| 521 |
+
def test_linear_root(self):
|
| 522 |
+
assert_(cheb.chebcompanion([1, 2])[0, 0] == -.5)
|
| 523 |
+
|
| 524 |
+
|
| 525 |
+
class TestGauss:
|
| 526 |
+
|
| 527 |
+
def test_100(self):
|
| 528 |
+
x, w = cheb.chebgauss(100)
|
| 529 |
+
|
| 530 |
+
# test orthogonality. Note that the results need to be normalized,
|
| 531 |
+
# otherwise the huge values that can arise from fast growing
|
| 532 |
+
# functions like Laguerre can be very confusing.
|
| 533 |
+
v = cheb.chebvander(x, 99)
|
| 534 |
+
vv = np.dot(v.T * w, v)
|
| 535 |
+
vd = 1/np.sqrt(vv.diagonal())
|
| 536 |
+
vv = vd[:, None] * vv * vd
|
| 537 |
+
assert_almost_equal(vv, np.eye(100))
|
| 538 |
+
|
| 539 |
+
# check that the integral of 1 is correct
|
| 540 |
+
tgt = np.pi
|
| 541 |
+
assert_almost_equal(w.sum(), tgt)
|
| 542 |
+
|
| 543 |
+
|
| 544 |
+
class TestMisc:
|
| 545 |
+
|
| 546 |
+
def test_chebfromroots(self):
|
| 547 |
+
res = cheb.chebfromroots([])
|
| 548 |
+
assert_almost_equal(trim(res), [1])
|
| 549 |
+
for i in range(1, 5):
|
| 550 |
+
roots = np.cos(np.linspace(-np.pi, 0, 2*i + 1)[1::2])
|
| 551 |
+
tgt = [0]*i + [1]
|
| 552 |
+
res = cheb.chebfromroots(roots)*2**(i-1)
|
| 553 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 554 |
+
|
| 555 |
+
def test_chebroots(self):
|
| 556 |
+
assert_almost_equal(cheb.chebroots([1]), [])
|
| 557 |
+
assert_almost_equal(cheb.chebroots([1, 2]), [-.5])
|
| 558 |
+
for i in range(2, 5):
|
| 559 |
+
tgt = np.linspace(-1, 1, i)
|
| 560 |
+
res = cheb.chebroots(cheb.chebfromroots(tgt))
|
| 561 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 562 |
+
|
| 563 |
+
def test_chebtrim(self):
|
| 564 |
+
coef = [2, -1, 1, 0]
|
| 565 |
+
|
| 566 |
+
# Test exceptions
|
| 567 |
+
assert_raises(ValueError, cheb.chebtrim, coef, -1)
|
| 568 |
+
|
| 569 |
+
# Test results
|
| 570 |
+
assert_equal(cheb.chebtrim(coef), coef[:-1])
|
| 571 |
+
assert_equal(cheb.chebtrim(coef, 1), coef[:-3])
|
| 572 |
+
assert_equal(cheb.chebtrim(coef, 2), [0])
|
| 573 |
+
|
| 574 |
+
def test_chebline(self):
|
| 575 |
+
assert_equal(cheb.chebline(3, 4), [3, 4])
|
| 576 |
+
|
| 577 |
+
def test_cheb2poly(self):
|
| 578 |
+
for i in range(10):
|
| 579 |
+
assert_almost_equal(cheb.cheb2poly([0]*i + [1]), Tlist[i])
|
| 580 |
+
|
| 581 |
+
def test_poly2cheb(self):
|
| 582 |
+
for i in range(10):
|
| 583 |
+
assert_almost_equal(cheb.poly2cheb(Tlist[i]), [0]*i + [1])
|
| 584 |
+
|
| 585 |
+
def test_weight(self):
|
| 586 |
+
x = np.linspace(-1, 1, 11)[1:-1]
|
| 587 |
+
tgt = 1./(np.sqrt(1 + x) * np.sqrt(1 - x))
|
| 588 |
+
res = cheb.chebweight(x)
|
| 589 |
+
assert_almost_equal(res, tgt)
|
| 590 |
+
|
| 591 |
+
def test_chebpts1(self):
|
| 592 |
+
#test exceptions
|
| 593 |
+
assert_raises(ValueError, cheb.chebpts1, 1.5)
|
| 594 |
+
assert_raises(ValueError, cheb.chebpts1, 0)
|
| 595 |
+
|
| 596 |
+
#test points
|
| 597 |
+
tgt = [0]
|
| 598 |
+
assert_almost_equal(cheb.chebpts1(1), tgt)
|
| 599 |
+
tgt = [-0.70710678118654746, 0.70710678118654746]
|
| 600 |
+
assert_almost_equal(cheb.chebpts1(2), tgt)
|
| 601 |
+
tgt = [-0.86602540378443871, 0, 0.86602540378443871]
|
| 602 |
+
assert_almost_equal(cheb.chebpts1(3), tgt)
|
| 603 |
+
tgt = [-0.9238795325, -0.3826834323, 0.3826834323, 0.9238795325]
|
| 604 |
+
assert_almost_equal(cheb.chebpts1(4), tgt)
|
| 605 |
+
|
| 606 |
+
def test_chebpts2(self):
|
| 607 |
+
#test exceptions
|
| 608 |
+
assert_raises(ValueError, cheb.chebpts2, 1.5)
|
| 609 |
+
assert_raises(ValueError, cheb.chebpts2, 1)
|
| 610 |
+
|
| 611 |
+
#test points
|
| 612 |
+
tgt = [-1, 1]
|
| 613 |
+
assert_almost_equal(cheb.chebpts2(2), tgt)
|
| 614 |
+
tgt = [-1, 0, 1]
|
| 615 |
+
assert_almost_equal(cheb.chebpts2(3), tgt)
|
| 616 |
+
tgt = [-1, -0.5, .5, 1]
|
| 617 |
+
assert_almost_equal(cheb.chebpts2(4), tgt)
|
| 618 |
+
tgt = [-1.0, -0.707106781187, 0, 0.707106781187, 1.0]
|
| 619 |
+
assert_almost_equal(cheb.chebpts2(5), tgt)
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/polynomial/tests/test_classes.py
ADDED
|
@@ -0,0 +1,600 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Test inter-conversion of different polynomial classes.
|
| 2 |
+
|
| 3 |
+
This tests the convert and cast methods of all the polynomial classes.
|
| 4 |
+
|
| 5 |
+
"""
|
| 6 |
+
import operator as op
|
| 7 |
+
from numbers import Number
|
| 8 |
+
|
| 9 |
+
import pytest
|
| 10 |
+
import numpy as np
|
| 11 |
+
from numpy.polynomial import (
|
| 12 |
+
Polynomial, Legendre, Chebyshev, Laguerre, Hermite, HermiteE)
|
| 13 |
+
from numpy.testing import (
|
| 14 |
+
assert_almost_equal, assert_raises, assert_equal, assert_,
|
| 15 |
+
)
|
| 16 |
+
from numpy.polynomial.polyutils import RankWarning
|
| 17 |
+
|
| 18 |
+
#
|
| 19 |
+
# fixtures
|
| 20 |
+
#
|
| 21 |
+
|
| 22 |
+
classes = (
|
| 23 |
+
Polynomial, Legendre, Chebyshev, Laguerre,
|
| 24 |
+
Hermite, HermiteE
|
| 25 |
+
)
|
| 26 |
+
classids = tuple(cls.__name__ for cls in classes)
|
| 27 |
+
|
| 28 |
+
@pytest.fixture(params=classes, ids=classids)
|
| 29 |
+
def Poly(request):
|
| 30 |
+
return request.param
|
| 31 |
+
|
| 32 |
+
#
|
| 33 |
+
# helper functions
|
| 34 |
+
#
|
| 35 |
+
random = np.random.random
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def assert_poly_almost_equal(p1, p2, msg=""):
|
| 39 |
+
try:
|
| 40 |
+
assert_(np.all(p1.domain == p2.domain))
|
| 41 |
+
assert_(np.all(p1.window == p2.window))
|
| 42 |
+
assert_almost_equal(p1.coef, p2.coef)
|
| 43 |
+
except AssertionError:
|
| 44 |
+
msg = f"Result: {p1}\nTarget: {p2}"
|
| 45 |
+
raise AssertionError(msg)
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
#
|
| 49 |
+
# Test conversion methods that depend on combinations of two classes.
|
| 50 |
+
#
|
| 51 |
+
|
| 52 |
+
Poly1 = Poly
|
| 53 |
+
Poly2 = Poly
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def test_conversion(Poly1, Poly2):
|
| 57 |
+
x = np.linspace(0, 1, 10)
|
| 58 |
+
coef = random((3,))
|
| 59 |
+
|
| 60 |
+
d1 = Poly1.domain + random((2,))*.25
|
| 61 |
+
w1 = Poly1.window + random((2,))*.25
|
| 62 |
+
p1 = Poly1(coef, domain=d1, window=w1)
|
| 63 |
+
|
| 64 |
+
d2 = Poly2.domain + random((2,))*.25
|
| 65 |
+
w2 = Poly2.window + random((2,))*.25
|
| 66 |
+
p2 = p1.convert(kind=Poly2, domain=d2, window=w2)
|
| 67 |
+
|
| 68 |
+
assert_almost_equal(p2.domain, d2)
|
| 69 |
+
assert_almost_equal(p2.window, w2)
|
| 70 |
+
assert_almost_equal(p2(x), p1(x))
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def test_cast(Poly1, Poly2):
|
| 74 |
+
x = np.linspace(0, 1, 10)
|
| 75 |
+
coef = random((3,))
|
| 76 |
+
|
| 77 |
+
d1 = Poly1.domain + random((2,))*.25
|
| 78 |
+
w1 = Poly1.window + random((2,))*.25
|
| 79 |
+
p1 = Poly1(coef, domain=d1, window=w1)
|
| 80 |
+
|
| 81 |
+
d2 = Poly2.domain + random((2,))*.25
|
| 82 |
+
w2 = Poly2.window + random((2,))*.25
|
| 83 |
+
p2 = Poly2.cast(p1, domain=d2, window=w2)
|
| 84 |
+
|
| 85 |
+
assert_almost_equal(p2.domain, d2)
|
| 86 |
+
assert_almost_equal(p2.window, w2)
|
| 87 |
+
assert_almost_equal(p2(x), p1(x))
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
#
|
| 91 |
+
# test methods that depend on one class
|
| 92 |
+
#
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def test_identity(Poly):
|
| 96 |
+
d = Poly.domain + random((2,))*.25
|
| 97 |
+
w = Poly.window + random((2,))*.25
|
| 98 |
+
x = np.linspace(d[0], d[1], 11)
|
| 99 |
+
p = Poly.identity(domain=d, window=w)
|
| 100 |
+
assert_equal(p.domain, d)
|
| 101 |
+
assert_equal(p.window, w)
|
| 102 |
+
assert_almost_equal(p(x), x)
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def test_basis(Poly):
|
| 106 |
+
d = Poly.domain + random((2,))*.25
|
| 107 |
+
w = Poly.window + random((2,))*.25
|
| 108 |
+
p = Poly.basis(5, domain=d, window=w)
|
| 109 |
+
assert_equal(p.domain, d)
|
| 110 |
+
assert_equal(p.window, w)
|
| 111 |
+
assert_equal(p.coef, [0]*5 + [1])
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def test_fromroots(Poly):
|
| 115 |
+
# check that requested roots are zeros of a polynomial
|
| 116 |
+
# of correct degree, domain, and window.
|
| 117 |
+
d = Poly.domain + random((2,))*.25
|
| 118 |
+
w = Poly.window + random((2,))*.25
|
| 119 |
+
r = random((5,))
|
| 120 |
+
p1 = Poly.fromroots(r, domain=d, window=w)
|
| 121 |
+
assert_equal(p1.degree(), len(r))
|
| 122 |
+
assert_equal(p1.domain, d)
|
| 123 |
+
assert_equal(p1.window, w)
|
| 124 |
+
assert_almost_equal(p1(r), 0)
|
| 125 |
+
|
| 126 |
+
# check that polynomial is monic
|
| 127 |
+
pdom = Polynomial.domain
|
| 128 |
+
pwin = Polynomial.window
|
| 129 |
+
p2 = Polynomial.cast(p1, domain=pdom, window=pwin)
|
| 130 |
+
assert_almost_equal(p2.coef[-1], 1)
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def test_bad_conditioned_fit(Poly):
|
| 134 |
+
|
| 135 |
+
x = [0., 0., 1.]
|
| 136 |
+
y = [1., 2., 3.]
|
| 137 |
+
|
| 138 |
+
# check RankWarning is raised
|
| 139 |
+
with pytest.warns(RankWarning) as record:
|
| 140 |
+
Poly.fit(x, y, 2)
|
| 141 |
+
assert record[0].message.args[0] == "The fit may be poorly conditioned"
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def test_fit(Poly):
|
| 145 |
+
|
| 146 |
+
def f(x):
|
| 147 |
+
return x*(x - 1)*(x - 2)
|
| 148 |
+
x = np.linspace(0, 3)
|
| 149 |
+
y = f(x)
|
| 150 |
+
|
| 151 |
+
# check default value of domain and window
|
| 152 |
+
p = Poly.fit(x, y, 3)
|
| 153 |
+
assert_almost_equal(p.domain, [0, 3])
|
| 154 |
+
assert_almost_equal(p(x), y)
|
| 155 |
+
assert_equal(p.degree(), 3)
|
| 156 |
+
|
| 157 |
+
# check with given domains and window
|
| 158 |
+
d = Poly.domain + random((2,))*.25
|
| 159 |
+
w = Poly.window + random((2,))*.25
|
| 160 |
+
p = Poly.fit(x, y, 3, domain=d, window=w)
|
| 161 |
+
assert_almost_equal(p(x), y)
|
| 162 |
+
assert_almost_equal(p.domain, d)
|
| 163 |
+
assert_almost_equal(p.window, w)
|
| 164 |
+
p = Poly.fit(x, y, [0, 1, 2, 3], domain=d, window=w)
|
| 165 |
+
assert_almost_equal(p(x), y)
|
| 166 |
+
assert_almost_equal(p.domain, d)
|
| 167 |
+
assert_almost_equal(p.window, w)
|
| 168 |
+
|
| 169 |
+
# check with class domain default
|
| 170 |
+
p = Poly.fit(x, y, 3, [])
|
| 171 |
+
assert_equal(p.domain, Poly.domain)
|
| 172 |
+
assert_equal(p.window, Poly.window)
|
| 173 |
+
p = Poly.fit(x, y, [0, 1, 2, 3], [])
|
| 174 |
+
assert_equal(p.domain, Poly.domain)
|
| 175 |
+
assert_equal(p.window, Poly.window)
|
| 176 |
+
|
| 177 |
+
# check that fit accepts weights.
|
| 178 |
+
w = np.zeros_like(x)
|
| 179 |
+
z = y + random(y.shape)*.25
|
| 180 |
+
w[::2] = 1
|
| 181 |
+
p1 = Poly.fit(x[::2], z[::2], 3)
|
| 182 |
+
p2 = Poly.fit(x, z, 3, w=w)
|
| 183 |
+
p3 = Poly.fit(x, z, [0, 1, 2, 3], w=w)
|
| 184 |
+
assert_almost_equal(p1(x), p2(x))
|
| 185 |
+
assert_almost_equal(p2(x), p3(x))
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
def test_equal(Poly):
|
| 189 |
+
p1 = Poly([1, 2, 3], domain=[0, 1], window=[2, 3])
|
| 190 |
+
p2 = Poly([1, 1, 1], domain=[0, 1], window=[2, 3])
|
| 191 |
+
p3 = Poly([1, 2, 3], domain=[1, 2], window=[2, 3])
|
| 192 |
+
p4 = Poly([1, 2, 3], domain=[0, 1], window=[1, 2])
|
| 193 |
+
assert_(p1 == p1)
|
| 194 |
+
assert_(not p1 == p2)
|
| 195 |
+
assert_(not p1 == p3)
|
| 196 |
+
assert_(not p1 == p4)
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
def test_not_equal(Poly):
|
| 200 |
+
p1 = Poly([1, 2, 3], domain=[0, 1], window=[2, 3])
|
| 201 |
+
p2 = Poly([1, 1, 1], domain=[0, 1], window=[2, 3])
|
| 202 |
+
p3 = Poly([1, 2, 3], domain=[1, 2], window=[2, 3])
|
| 203 |
+
p4 = Poly([1, 2, 3], domain=[0, 1], window=[1, 2])
|
| 204 |
+
assert_(not p1 != p1)
|
| 205 |
+
assert_(p1 != p2)
|
| 206 |
+
assert_(p1 != p3)
|
| 207 |
+
assert_(p1 != p4)
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def test_add(Poly):
|
| 211 |
+
# This checks commutation, not numerical correctness
|
| 212 |
+
c1 = list(random((4,)) + .5)
|
| 213 |
+
c2 = list(random((3,)) + .5)
|
| 214 |
+
p1 = Poly(c1)
|
| 215 |
+
p2 = Poly(c2)
|
| 216 |
+
p3 = p1 + p2
|
| 217 |
+
assert_poly_almost_equal(p2 + p1, p3)
|
| 218 |
+
assert_poly_almost_equal(p1 + c2, p3)
|
| 219 |
+
assert_poly_almost_equal(c2 + p1, p3)
|
| 220 |
+
assert_poly_almost_equal(p1 + tuple(c2), p3)
|
| 221 |
+
assert_poly_almost_equal(tuple(c2) + p1, p3)
|
| 222 |
+
assert_poly_almost_equal(p1 + np.array(c2), p3)
|
| 223 |
+
assert_poly_almost_equal(np.array(c2) + p1, p3)
|
| 224 |
+
assert_raises(TypeError, op.add, p1, Poly([0], domain=Poly.domain + 1))
|
| 225 |
+
assert_raises(TypeError, op.add, p1, Poly([0], window=Poly.window + 1))
|
| 226 |
+
if Poly is Polynomial:
|
| 227 |
+
assert_raises(TypeError, op.add, p1, Chebyshev([0]))
|
| 228 |
+
else:
|
| 229 |
+
assert_raises(TypeError, op.add, p1, Polynomial([0]))
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
def test_sub(Poly):
|
| 233 |
+
# This checks commutation, not numerical correctness
|
| 234 |
+
c1 = list(random((4,)) + .5)
|
| 235 |
+
c2 = list(random((3,)) + .5)
|
| 236 |
+
p1 = Poly(c1)
|
| 237 |
+
p2 = Poly(c2)
|
| 238 |
+
p3 = p1 - p2
|
| 239 |
+
assert_poly_almost_equal(p2 - p1, -p3)
|
| 240 |
+
assert_poly_almost_equal(p1 - c2, p3)
|
| 241 |
+
assert_poly_almost_equal(c2 - p1, -p3)
|
| 242 |
+
assert_poly_almost_equal(p1 - tuple(c2), p3)
|
| 243 |
+
assert_poly_almost_equal(tuple(c2) - p1, -p3)
|
| 244 |
+
assert_poly_almost_equal(p1 - np.array(c2), p3)
|
| 245 |
+
assert_poly_almost_equal(np.array(c2) - p1, -p3)
|
| 246 |
+
assert_raises(TypeError, op.sub, p1, Poly([0], domain=Poly.domain + 1))
|
| 247 |
+
assert_raises(TypeError, op.sub, p1, Poly([0], window=Poly.window + 1))
|
| 248 |
+
if Poly is Polynomial:
|
| 249 |
+
assert_raises(TypeError, op.sub, p1, Chebyshev([0]))
|
| 250 |
+
else:
|
| 251 |
+
assert_raises(TypeError, op.sub, p1, Polynomial([0]))
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
def test_mul(Poly):
|
| 255 |
+
c1 = list(random((4,)) + .5)
|
| 256 |
+
c2 = list(random((3,)) + .5)
|
| 257 |
+
p1 = Poly(c1)
|
| 258 |
+
p2 = Poly(c2)
|
| 259 |
+
p3 = p1 * p2
|
| 260 |
+
assert_poly_almost_equal(p2 * p1, p3)
|
| 261 |
+
assert_poly_almost_equal(p1 * c2, p3)
|
| 262 |
+
assert_poly_almost_equal(c2 * p1, p3)
|
| 263 |
+
assert_poly_almost_equal(p1 * tuple(c2), p3)
|
| 264 |
+
assert_poly_almost_equal(tuple(c2) * p1, p3)
|
| 265 |
+
assert_poly_almost_equal(p1 * np.array(c2), p3)
|
| 266 |
+
assert_poly_almost_equal(np.array(c2) * p1, p3)
|
| 267 |
+
assert_poly_almost_equal(p1 * 2, p1 * Poly([2]))
|
| 268 |
+
assert_poly_almost_equal(2 * p1, p1 * Poly([2]))
|
| 269 |
+
assert_raises(TypeError, op.mul, p1, Poly([0], domain=Poly.domain + 1))
|
| 270 |
+
assert_raises(TypeError, op.mul, p1, Poly([0], window=Poly.window + 1))
|
| 271 |
+
if Poly is Polynomial:
|
| 272 |
+
assert_raises(TypeError, op.mul, p1, Chebyshev([0]))
|
| 273 |
+
else:
|
| 274 |
+
assert_raises(TypeError, op.mul, p1, Polynomial([0]))
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
def test_floordiv(Poly):
|
| 278 |
+
c1 = list(random((4,)) + .5)
|
| 279 |
+
c2 = list(random((3,)) + .5)
|
| 280 |
+
c3 = list(random((2,)) + .5)
|
| 281 |
+
p1 = Poly(c1)
|
| 282 |
+
p2 = Poly(c2)
|
| 283 |
+
p3 = Poly(c3)
|
| 284 |
+
p4 = p1 * p2 + p3
|
| 285 |
+
c4 = list(p4.coef)
|
| 286 |
+
assert_poly_almost_equal(p4 // p2, p1)
|
| 287 |
+
assert_poly_almost_equal(p4 // c2, p1)
|
| 288 |
+
assert_poly_almost_equal(c4 // p2, p1)
|
| 289 |
+
assert_poly_almost_equal(p4 // tuple(c2), p1)
|
| 290 |
+
assert_poly_almost_equal(tuple(c4) // p2, p1)
|
| 291 |
+
assert_poly_almost_equal(p4 // np.array(c2), p1)
|
| 292 |
+
assert_poly_almost_equal(np.array(c4) // p2, p1)
|
| 293 |
+
assert_poly_almost_equal(2 // p2, Poly([0]))
|
| 294 |
+
assert_poly_almost_equal(p2 // 2, 0.5*p2)
|
| 295 |
+
assert_raises(
|
| 296 |
+
TypeError, op.floordiv, p1, Poly([0], domain=Poly.domain + 1))
|
| 297 |
+
assert_raises(
|
| 298 |
+
TypeError, op.floordiv, p1, Poly([0], window=Poly.window + 1))
|
| 299 |
+
if Poly is Polynomial:
|
| 300 |
+
assert_raises(TypeError, op.floordiv, p1, Chebyshev([0]))
|
| 301 |
+
else:
|
| 302 |
+
assert_raises(TypeError, op.floordiv, p1, Polynomial([0]))
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
def test_truediv(Poly):
|
| 306 |
+
# true division is valid only if the denominator is a Number and
|
| 307 |
+
# not a python bool.
|
| 308 |
+
p1 = Poly([1,2,3])
|
| 309 |
+
p2 = p1 * 5
|
| 310 |
+
|
| 311 |
+
for stype in np.ScalarType:
|
| 312 |
+
if not issubclass(stype, Number) or issubclass(stype, bool):
|
| 313 |
+
continue
|
| 314 |
+
s = stype(5)
|
| 315 |
+
assert_poly_almost_equal(op.truediv(p2, s), p1)
|
| 316 |
+
assert_raises(TypeError, op.truediv, s, p2)
|
| 317 |
+
for stype in (int, float):
|
| 318 |
+
s = stype(5)
|
| 319 |
+
assert_poly_almost_equal(op.truediv(p2, s), p1)
|
| 320 |
+
assert_raises(TypeError, op.truediv, s, p2)
|
| 321 |
+
for stype in [complex]:
|
| 322 |
+
s = stype(5, 0)
|
| 323 |
+
assert_poly_almost_equal(op.truediv(p2, s), p1)
|
| 324 |
+
assert_raises(TypeError, op.truediv, s, p2)
|
| 325 |
+
for s in [tuple(), list(), dict(), bool(), np.array([1])]:
|
| 326 |
+
assert_raises(TypeError, op.truediv, p2, s)
|
| 327 |
+
assert_raises(TypeError, op.truediv, s, p2)
|
| 328 |
+
for ptype in classes:
|
| 329 |
+
assert_raises(TypeError, op.truediv, p2, ptype(1))
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
def test_mod(Poly):
|
| 333 |
+
# This checks commutation, not numerical correctness
|
| 334 |
+
c1 = list(random((4,)) + .5)
|
| 335 |
+
c2 = list(random((3,)) + .5)
|
| 336 |
+
c3 = list(random((2,)) + .5)
|
| 337 |
+
p1 = Poly(c1)
|
| 338 |
+
p2 = Poly(c2)
|
| 339 |
+
p3 = Poly(c3)
|
| 340 |
+
p4 = p1 * p2 + p3
|
| 341 |
+
c4 = list(p4.coef)
|
| 342 |
+
assert_poly_almost_equal(p4 % p2, p3)
|
| 343 |
+
assert_poly_almost_equal(p4 % c2, p3)
|
| 344 |
+
assert_poly_almost_equal(c4 % p2, p3)
|
| 345 |
+
assert_poly_almost_equal(p4 % tuple(c2), p3)
|
| 346 |
+
assert_poly_almost_equal(tuple(c4) % p2, p3)
|
| 347 |
+
assert_poly_almost_equal(p4 % np.array(c2), p3)
|
| 348 |
+
assert_poly_almost_equal(np.array(c4) % p2, p3)
|
| 349 |
+
assert_poly_almost_equal(2 % p2, Poly([2]))
|
| 350 |
+
assert_poly_almost_equal(p2 % 2, Poly([0]))
|
| 351 |
+
assert_raises(TypeError, op.mod, p1, Poly([0], domain=Poly.domain + 1))
|
| 352 |
+
assert_raises(TypeError, op.mod, p1, Poly([0], window=Poly.window + 1))
|
| 353 |
+
if Poly is Polynomial:
|
| 354 |
+
assert_raises(TypeError, op.mod, p1, Chebyshev([0]))
|
| 355 |
+
else:
|
| 356 |
+
assert_raises(TypeError, op.mod, p1, Polynomial([0]))
|
| 357 |
+
|
| 358 |
+
|
| 359 |
+
def test_divmod(Poly):
|
| 360 |
+
# This checks commutation, not numerical correctness
|
| 361 |
+
c1 = list(random((4,)) + .5)
|
| 362 |
+
c2 = list(random((3,)) + .5)
|
| 363 |
+
c3 = list(random((2,)) + .5)
|
| 364 |
+
p1 = Poly(c1)
|
| 365 |
+
p2 = Poly(c2)
|
| 366 |
+
p3 = Poly(c3)
|
| 367 |
+
p4 = p1 * p2 + p3
|
| 368 |
+
c4 = list(p4.coef)
|
| 369 |
+
quo, rem = divmod(p4, p2)
|
| 370 |
+
assert_poly_almost_equal(quo, p1)
|
| 371 |
+
assert_poly_almost_equal(rem, p3)
|
| 372 |
+
quo, rem = divmod(p4, c2)
|
| 373 |
+
assert_poly_almost_equal(quo, p1)
|
| 374 |
+
assert_poly_almost_equal(rem, p3)
|
| 375 |
+
quo, rem = divmod(c4, p2)
|
| 376 |
+
assert_poly_almost_equal(quo, p1)
|
| 377 |
+
assert_poly_almost_equal(rem, p3)
|
| 378 |
+
quo, rem = divmod(p4, tuple(c2))
|
| 379 |
+
assert_poly_almost_equal(quo, p1)
|
| 380 |
+
assert_poly_almost_equal(rem, p3)
|
| 381 |
+
quo, rem = divmod(tuple(c4), p2)
|
| 382 |
+
assert_poly_almost_equal(quo, p1)
|
| 383 |
+
assert_poly_almost_equal(rem, p3)
|
| 384 |
+
quo, rem = divmod(p4, np.array(c2))
|
| 385 |
+
assert_poly_almost_equal(quo, p1)
|
| 386 |
+
assert_poly_almost_equal(rem, p3)
|
| 387 |
+
quo, rem = divmod(np.array(c4), p2)
|
| 388 |
+
assert_poly_almost_equal(quo, p1)
|
| 389 |
+
assert_poly_almost_equal(rem, p3)
|
| 390 |
+
quo, rem = divmod(p2, 2)
|
| 391 |
+
assert_poly_almost_equal(quo, 0.5*p2)
|
| 392 |
+
assert_poly_almost_equal(rem, Poly([0]))
|
| 393 |
+
quo, rem = divmod(2, p2)
|
| 394 |
+
assert_poly_almost_equal(quo, Poly([0]))
|
| 395 |
+
assert_poly_almost_equal(rem, Poly([2]))
|
| 396 |
+
assert_raises(TypeError, divmod, p1, Poly([0], domain=Poly.domain + 1))
|
| 397 |
+
assert_raises(TypeError, divmod, p1, Poly([0], window=Poly.window + 1))
|
| 398 |
+
if Poly is Polynomial:
|
| 399 |
+
assert_raises(TypeError, divmod, p1, Chebyshev([0]))
|
| 400 |
+
else:
|
| 401 |
+
assert_raises(TypeError, divmod, p1, Polynomial([0]))
|
| 402 |
+
|
| 403 |
+
|
| 404 |
+
def test_roots(Poly):
|
| 405 |
+
d = Poly.domain * 1.25 + .25
|
| 406 |
+
w = Poly.window
|
| 407 |
+
tgt = np.linspace(d[0], d[1], 5)
|
| 408 |
+
res = np.sort(Poly.fromroots(tgt, domain=d, window=w).roots())
|
| 409 |
+
assert_almost_equal(res, tgt)
|
| 410 |
+
# default domain and window
|
| 411 |
+
res = np.sort(Poly.fromroots(tgt).roots())
|
| 412 |
+
assert_almost_equal(res, tgt)
|
| 413 |
+
|
| 414 |
+
|
| 415 |
+
def test_degree(Poly):
|
| 416 |
+
p = Poly.basis(5)
|
| 417 |
+
assert_equal(p.degree(), 5)
|
| 418 |
+
|
| 419 |
+
|
| 420 |
+
def test_copy(Poly):
|
| 421 |
+
p1 = Poly.basis(5)
|
| 422 |
+
p2 = p1.copy()
|
| 423 |
+
assert_(p1 == p2)
|
| 424 |
+
assert_(p1 is not p2)
|
| 425 |
+
assert_(p1.coef is not p2.coef)
|
| 426 |
+
assert_(p1.domain is not p2.domain)
|
| 427 |
+
assert_(p1.window is not p2.window)
|
| 428 |
+
|
| 429 |
+
|
| 430 |
+
def test_integ(Poly):
|
| 431 |
+
P = Polynomial
|
| 432 |
+
# Check defaults
|
| 433 |
+
p0 = Poly.cast(P([1*2, 2*3, 3*4]))
|
| 434 |
+
p1 = P.cast(p0.integ())
|
| 435 |
+
p2 = P.cast(p0.integ(2))
|
| 436 |
+
assert_poly_almost_equal(p1, P([0, 2, 3, 4]))
|
| 437 |
+
assert_poly_almost_equal(p2, P([0, 0, 1, 1, 1]))
|
| 438 |
+
# Check with k
|
| 439 |
+
p0 = Poly.cast(P([1*2, 2*3, 3*4]))
|
| 440 |
+
p1 = P.cast(p0.integ(k=1))
|
| 441 |
+
p2 = P.cast(p0.integ(2, k=[1, 1]))
|
| 442 |
+
assert_poly_almost_equal(p1, P([1, 2, 3, 4]))
|
| 443 |
+
assert_poly_almost_equal(p2, P([1, 1, 1, 1, 1]))
|
| 444 |
+
# Check with lbnd
|
| 445 |
+
p0 = Poly.cast(P([1*2, 2*3, 3*4]))
|
| 446 |
+
p1 = P.cast(p0.integ(lbnd=1))
|
| 447 |
+
p2 = P.cast(p0.integ(2, lbnd=1))
|
| 448 |
+
assert_poly_almost_equal(p1, P([-9, 2, 3, 4]))
|
| 449 |
+
assert_poly_almost_equal(p2, P([6, -9, 1, 1, 1]))
|
| 450 |
+
# Check scaling
|
| 451 |
+
d = 2*Poly.domain
|
| 452 |
+
p0 = Poly.cast(P([1*2, 2*3, 3*4]), domain=d)
|
| 453 |
+
p1 = P.cast(p0.integ())
|
| 454 |
+
p2 = P.cast(p0.integ(2))
|
| 455 |
+
assert_poly_almost_equal(p1, P([0, 2, 3, 4]))
|
| 456 |
+
assert_poly_almost_equal(p2, P([0, 0, 1, 1, 1]))
|
| 457 |
+
|
| 458 |
+
|
| 459 |
+
def test_deriv(Poly):
|
| 460 |
+
# Check that the derivative is the inverse of integration. It is
|
| 461 |
+
# assumes that the integration has been checked elsewhere.
|
| 462 |
+
d = Poly.domain + random((2,))*.25
|
| 463 |
+
w = Poly.window + random((2,))*.25
|
| 464 |
+
p1 = Poly([1, 2, 3], domain=d, window=w)
|
| 465 |
+
p2 = p1.integ(2, k=[1, 2])
|
| 466 |
+
p3 = p1.integ(1, k=[1])
|
| 467 |
+
assert_almost_equal(p2.deriv(1).coef, p3.coef)
|
| 468 |
+
assert_almost_equal(p2.deriv(2).coef, p1.coef)
|
| 469 |
+
# default domain and window
|
| 470 |
+
p1 = Poly([1, 2, 3])
|
| 471 |
+
p2 = p1.integ(2, k=[1, 2])
|
| 472 |
+
p3 = p1.integ(1, k=[1])
|
| 473 |
+
assert_almost_equal(p2.deriv(1).coef, p3.coef)
|
| 474 |
+
assert_almost_equal(p2.deriv(2).coef, p1.coef)
|
| 475 |
+
|
| 476 |
+
|
| 477 |
+
def test_linspace(Poly):
|
| 478 |
+
d = Poly.domain + random((2,))*.25
|
| 479 |
+
w = Poly.window + random((2,))*.25
|
| 480 |
+
p = Poly([1, 2, 3], domain=d, window=w)
|
| 481 |
+
# check default domain
|
| 482 |
+
xtgt = np.linspace(d[0], d[1], 20)
|
| 483 |
+
ytgt = p(xtgt)
|
| 484 |
+
xres, yres = p.linspace(20)
|
| 485 |
+
assert_almost_equal(xres, xtgt)
|
| 486 |
+
assert_almost_equal(yres, ytgt)
|
| 487 |
+
# check specified domain
|
| 488 |
+
xtgt = np.linspace(0, 2, 20)
|
| 489 |
+
ytgt = p(xtgt)
|
| 490 |
+
xres, yres = p.linspace(20, domain=[0, 2])
|
| 491 |
+
assert_almost_equal(xres, xtgt)
|
| 492 |
+
assert_almost_equal(yres, ytgt)
|
| 493 |
+
|
| 494 |
+
|
| 495 |
+
def test_pow(Poly):
|
| 496 |
+
d = Poly.domain + random((2,))*.25
|
| 497 |
+
w = Poly.window + random((2,))*.25
|
| 498 |
+
tgt = Poly([1], domain=d, window=w)
|
| 499 |
+
tst = Poly([1, 2, 3], domain=d, window=w)
|
| 500 |
+
for i in range(5):
|
| 501 |
+
assert_poly_almost_equal(tst**i, tgt)
|
| 502 |
+
tgt = tgt * tst
|
| 503 |
+
# default domain and window
|
| 504 |
+
tgt = Poly([1])
|
| 505 |
+
tst = Poly([1, 2, 3])
|
| 506 |
+
for i in range(5):
|
| 507 |
+
assert_poly_almost_equal(tst**i, tgt)
|
| 508 |
+
tgt = tgt * tst
|
| 509 |
+
# check error for invalid powers
|
| 510 |
+
assert_raises(ValueError, op.pow, tgt, 1.5)
|
| 511 |
+
assert_raises(ValueError, op.pow, tgt, -1)
|
| 512 |
+
|
| 513 |
+
|
| 514 |
+
def test_call(Poly):
|
| 515 |
+
P = Polynomial
|
| 516 |
+
d = Poly.domain
|
| 517 |
+
x = np.linspace(d[0], d[1], 11)
|
| 518 |
+
|
| 519 |
+
# Check defaults
|
| 520 |
+
p = Poly.cast(P([1, 2, 3]))
|
| 521 |
+
tgt = 1 + x*(2 + 3*x)
|
| 522 |
+
res = p(x)
|
| 523 |
+
assert_almost_equal(res, tgt)
|
| 524 |
+
|
| 525 |
+
|
| 526 |
+
def test_cutdeg(Poly):
|
| 527 |
+
p = Poly([1, 2, 3])
|
| 528 |
+
assert_raises(ValueError, p.cutdeg, .5)
|
| 529 |
+
assert_raises(ValueError, p.cutdeg, -1)
|
| 530 |
+
assert_equal(len(p.cutdeg(3)), 3)
|
| 531 |
+
assert_equal(len(p.cutdeg(2)), 3)
|
| 532 |
+
assert_equal(len(p.cutdeg(1)), 2)
|
| 533 |
+
assert_equal(len(p.cutdeg(0)), 1)
|
| 534 |
+
|
| 535 |
+
|
| 536 |
+
def test_truncate(Poly):
|
| 537 |
+
p = Poly([1, 2, 3])
|
| 538 |
+
assert_raises(ValueError, p.truncate, .5)
|
| 539 |
+
assert_raises(ValueError, p.truncate, 0)
|
| 540 |
+
assert_equal(len(p.truncate(4)), 3)
|
| 541 |
+
assert_equal(len(p.truncate(3)), 3)
|
| 542 |
+
assert_equal(len(p.truncate(2)), 2)
|
| 543 |
+
assert_equal(len(p.truncate(1)), 1)
|
| 544 |
+
|
| 545 |
+
|
| 546 |
+
def test_trim(Poly):
|
| 547 |
+
c = [1, 1e-6, 1e-12, 0]
|
| 548 |
+
p = Poly(c)
|
| 549 |
+
assert_equal(p.trim().coef, c[:3])
|
| 550 |
+
assert_equal(p.trim(1e-10).coef, c[:2])
|
| 551 |
+
assert_equal(p.trim(1e-5).coef, c[:1])
|
| 552 |
+
|
| 553 |
+
|
| 554 |
+
def test_mapparms(Poly):
|
| 555 |
+
# check with defaults. Should be identity.
|
| 556 |
+
d = Poly.domain
|
| 557 |
+
w = Poly.window
|
| 558 |
+
p = Poly([1], domain=d, window=w)
|
| 559 |
+
assert_almost_equal([0, 1], p.mapparms())
|
| 560 |
+
#
|
| 561 |
+
w = 2*d + 1
|
| 562 |
+
p = Poly([1], domain=d, window=w)
|
| 563 |
+
assert_almost_equal([1, 2], p.mapparms())
|
| 564 |
+
|
| 565 |
+
|
| 566 |
+
def test_ufunc_override(Poly):
|
| 567 |
+
p = Poly([1, 2, 3])
|
| 568 |
+
x = np.ones(3)
|
| 569 |
+
assert_raises(TypeError, np.add, p, x)
|
| 570 |
+
assert_raises(TypeError, np.add, x, p)
|
| 571 |
+
|
| 572 |
+
|
| 573 |
+
#
|
| 574 |
+
# Test class method that only exists for some classes
|
| 575 |
+
#
|
| 576 |
+
|
| 577 |
+
|
| 578 |
+
class TestInterpolate:
|
| 579 |
+
|
| 580 |
+
def f(self, x):
|
| 581 |
+
return x * (x - 1) * (x - 2)
|
| 582 |
+
|
| 583 |
+
def test_raises(self):
|
| 584 |
+
assert_raises(ValueError, Chebyshev.interpolate, self.f, -1)
|
| 585 |
+
assert_raises(TypeError, Chebyshev.interpolate, self.f, 10.)
|
| 586 |
+
|
| 587 |
+
def test_dimensions(self):
|
| 588 |
+
for deg in range(1, 5):
|
| 589 |
+
assert_(Chebyshev.interpolate(self.f, deg).degree() == deg)
|
| 590 |
+
|
| 591 |
+
def test_approximation(self):
|
| 592 |
+
|
| 593 |
+
def powx(x, p):
|
| 594 |
+
return x**p
|
| 595 |
+
|
| 596 |
+
x = np.linspace(0, 2, 10)
|
| 597 |
+
for deg in range(0, 10):
|
| 598 |
+
for t in range(0, deg + 1):
|
| 599 |
+
p = Chebyshev.interpolate(powx, deg, domain=[0, 2], args=(t,))
|
| 600 |
+
assert_almost_equal(p(x), powx(x, t), decimal=11)
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/polynomial/tests/test_hermite.py
ADDED
|
@@ -0,0 +1,555 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Tests for hermite module.
|
| 2 |
+
|
| 3 |
+
"""
|
| 4 |
+
from functools import reduce
|
| 5 |
+
|
| 6 |
+
import numpy as np
|
| 7 |
+
import numpy.polynomial.hermite as herm
|
| 8 |
+
from numpy.polynomial.polynomial import polyval
|
| 9 |
+
from numpy.testing import (
|
| 10 |
+
assert_almost_equal, assert_raises, assert_equal, assert_,
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
H0 = np.array([1])
|
| 14 |
+
H1 = np.array([0, 2])
|
| 15 |
+
H2 = np.array([-2, 0, 4])
|
| 16 |
+
H3 = np.array([0, -12, 0, 8])
|
| 17 |
+
H4 = np.array([12, 0, -48, 0, 16])
|
| 18 |
+
H5 = np.array([0, 120, 0, -160, 0, 32])
|
| 19 |
+
H6 = np.array([-120, 0, 720, 0, -480, 0, 64])
|
| 20 |
+
H7 = np.array([0, -1680, 0, 3360, 0, -1344, 0, 128])
|
| 21 |
+
H8 = np.array([1680, 0, -13440, 0, 13440, 0, -3584, 0, 256])
|
| 22 |
+
H9 = np.array([0, 30240, 0, -80640, 0, 48384, 0, -9216, 0, 512])
|
| 23 |
+
|
| 24 |
+
Hlist = [H0, H1, H2, H3, H4, H5, H6, H7, H8, H9]
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def trim(x):
|
| 28 |
+
return herm.hermtrim(x, tol=1e-6)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class TestConstants:
|
| 32 |
+
|
| 33 |
+
def test_hermdomain(self):
|
| 34 |
+
assert_equal(herm.hermdomain, [-1, 1])
|
| 35 |
+
|
| 36 |
+
def test_hermzero(self):
|
| 37 |
+
assert_equal(herm.hermzero, [0])
|
| 38 |
+
|
| 39 |
+
def test_hermone(self):
|
| 40 |
+
assert_equal(herm.hermone, [1])
|
| 41 |
+
|
| 42 |
+
def test_hermx(self):
|
| 43 |
+
assert_equal(herm.hermx, [0, .5])
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class TestArithmetic:
|
| 47 |
+
x = np.linspace(-3, 3, 100)
|
| 48 |
+
|
| 49 |
+
def test_hermadd(self):
|
| 50 |
+
for i in range(5):
|
| 51 |
+
for j in range(5):
|
| 52 |
+
msg = f"At i={i}, j={j}"
|
| 53 |
+
tgt = np.zeros(max(i, j) + 1)
|
| 54 |
+
tgt[i] += 1
|
| 55 |
+
tgt[j] += 1
|
| 56 |
+
res = herm.hermadd([0]*i + [1], [0]*j + [1])
|
| 57 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 58 |
+
|
| 59 |
+
def test_hermsub(self):
|
| 60 |
+
for i in range(5):
|
| 61 |
+
for j in range(5):
|
| 62 |
+
msg = f"At i={i}, j={j}"
|
| 63 |
+
tgt = np.zeros(max(i, j) + 1)
|
| 64 |
+
tgt[i] += 1
|
| 65 |
+
tgt[j] -= 1
|
| 66 |
+
res = herm.hermsub([0]*i + [1], [0]*j + [1])
|
| 67 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 68 |
+
|
| 69 |
+
def test_hermmulx(self):
|
| 70 |
+
assert_equal(herm.hermmulx([0]), [0])
|
| 71 |
+
assert_equal(herm.hermmulx([1]), [0, .5])
|
| 72 |
+
for i in range(1, 5):
|
| 73 |
+
ser = [0]*i + [1]
|
| 74 |
+
tgt = [0]*(i - 1) + [i, 0, .5]
|
| 75 |
+
assert_equal(herm.hermmulx(ser), tgt)
|
| 76 |
+
|
| 77 |
+
def test_hermmul(self):
|
| 78 |
+
# check values of result
|
| 79 |
+
for i in range(5):
|
| 80 |
+
pol1 = [0]*i + [1]
|
| 81 |
+
val1 = herm.hermval(self.x, pol1)
|
| 82 |
+
for j in range(5):
|
| 83 |
+
msg = f"At i={i}, j={j}"
|
| 84 |
+
pol2 = [0]*j + [1]
|
| 85 |
+
val2 = herm.hermval(self.x, pol2)
|
| 86 |
+
pol3 = herm.hermmul(pol1, pol2)
|
| 87 |
+
val3 = herm.hermval(self.x, pol3)
|
| 88 |
+
assert_(len(pol3) == i + j + 1, msg)
|
| 89 |
+
assert_almost_equal(val3, val1*val2, err_msg=msg)
|
| 90 |
+
|
| 91 |
+
def test_hermdiv(self):
|
| 92 |
+
for i in range(5):
|
| 93 |
+
for j in range(5):
|
| 94 |
+
msg = f"At i={i}, j={j}"
|
| 95 |
+
ci = [0]*i + [1]
|
| 96 |
+
cj = [0]*j + [1]
|
| 97 |
+
tgt = herm.hermadd(ci, cj)
|
| 98 |
+
quo, rem = herm.hermdiv(tgt, ci)
|
| 99 |
+
res = herm.hermadd(herm.hermmul(quo, ci), rem)
|
| 100 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 101 |
+
|
| 102 |
+
def test_hermpow(self):
|
| 103 |
+
for i in range(5):
|
| 104 |
+
for j in range(5):
|
| 105 |
+
msg = f"At i={i}, j={j}"
|
| 106 |
+
c = np.arange(i + 1)
|
| 107 |
+
tgt = reduce(herm.hermmul, [c]*j, np.array([1]))
|
| 108 |
+
res = herm.hermpow(c, j)
|
| 109 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
class TestEvaluation:
|
| 113 |
+
# coefficients of 1 + 2*x + 3*x**2
|
| 114 |
+
c1d = np.array([2.5, 1., .75])
|
| 115 |
+
c2d = np.einsum('i,j->ij', c1d, c1d)
|
| 116 |
+
c3d = np.einsum('i,j,k->ijk', c1d, c1d, c1d)
|
| 117 |
+
|
| 118 |
+
# some random values in [-1, 1)
|
| 119 |
+
x = np.random.random((3, 5))*2 - 1
|
| 120 |
+
y = polyval(x, [1., 2., 3.])
|
| 121 |
+
|
| 122 |
+
def test_hermval(self):
|
| 123 |
+
#check empty input
|
| 124 |
+
assert_equal(herm.hermval([], [1]).size, 0)
|
| 125 |
+
|
| 126 |
+
#check normal input)
|
| 127 |
+
x = np.linspace(-1, 1)
|
| 128 |
+
y = [polyval(x, c) for c in Hlist]
|
| 129 |
+
for i in range(10):
|
| 130 |
+
msg = f"At i={i}"
|
| 131 |
+
tgt = y[i]
|
| 132 |
+
res = herm.hermval(x, [0]*i + [1])
|
| 133 |
+
assert_almost_equal(res, tgt, err_msg=msg)
|
| 134 |
+
|
| 135 |
+
#check that shape is preserved
|
| 136 |
+
for i in range(3):
|
| 137 |
+
dims = [2]*i
|
| 138 |
+
x = np.zeros(dims)
|
| 139 |
+
assert_equal(herm.hermval(x, [1]).shape, dims)
|
| 140 |
+
assert_equal(herm.hermval(x, [1, 0]).shape, dims)
|
| 141 |
+
assert_equal(herm.hermval(x, [1, 0, 0]).shape, dims)
|
| 142 |
+
|
| 143 |
+
def test_hermval2d(self):
|
| 144 |
+
x1, x2, x3 = self.x
|
| 145 |
+
y1, y2, y3 = self.y
|
| 146 |
+
|
| 147 |
+
#test exceptions
|
| 148 |
+
assert_raises(ValueError, herm.hermval2d, x1, x2[:2], self.c2d)
|
| 149 |
+
|
| 150 |
+
#test values
|
| 151 |
+
tgt = y1*y2
|
| 152 |
+
res = herm.hermval2d(x1, x2, self.c2d)
|
| 153 |
+
assert_almost_equal(res, tgt)
|
| 154 |
+
|
| 155 |
+
#test shape
|
| 156 |
+
z = np.ones((2, 3))
|
| 157 |
+
res = herm.hermval2d(z, z, self.c2d)
|
| 158 |
+
assert_(res.shape == (2, 3))
|
| 159 |
+
|
| 160 |
+
def test_hermval3d(self):
|
| 161 |
+
x1, x2, x3 = self.x
|
| 162 |
+
y1, y2, y3 = self.y
|
| 163 |
+
|
| 164 |
+
#test exceptions
|
| 165 |
+
assert_raises(ValueError, herm.hermval3d, x1, x2, x3[:2], self.c3d)
|
| 166 |
+
|
| 167 |
+
#test values
|
| 168 |
+
tgt = y1*y2*y3
|
| 169 |
+
res = herm.hermval3d(x1, x2, x3, self.c3d)
|
| 170 |
+
assert_almost_equal(res, tgt)
|
| 171 |
+
|
| 172 |
+
#test shape
|
| 173 |
+
z = np.ones((2, 3))
|
| 174 |
+
res = herm.hermval3d(z, z, z, self.c3d)
|
| 175 |
+
assert_(res.shape == (2, 3))
|
| 176 |
+
|
| 177 |
+
def test_hermgrid2d(self):
|
| 178 |
+
x1, x2, x3 = self.x
|
| 179 |
+
y1, y2, y3 = self.y
|
| 180 |
+
|
| 181 |
+
#test values
|
| 182 |
+
tgt = np.einsum('i,j->ij', y1, y2)
|
| 183 |
+
res = herm.hermgrid2d(x1, x2, self.c2d)
|
| 184 |
+
assert_almost_equal(res, tgt)
|
| 185 |
+
|
| 186 |
+
#test shape
|
| 187 |
+
z = np.ones((2, 3))
|
| 188 |
+
res = herm.hermgrid2d(z, z, self.c2d)
|
| 189 |
+
assert_(res.shape == (2, 3)*2)
|
| 190 |
+
|
| 191 |
+
def test_hermgrid3d(self):
|
| 192 |
+
x1, x2, x3 = self.x
|
| 193 |
+
y1, y2, y3 = self.y
|
| 194 |
+
|
| 195 |
+
#test values
|
| 196 |
+
tgt = np.einsum('i,j,k->ijk', y1, y2, y3)
|
| 197 |
+
res = herm.hermgrid3d(x1, x2, x3, self.c3d)
|
| 198 |
+
assert_almost_equal(res, tgt)
|
| 199 |
+
|
| 200 |
+
#test shape
|
| 201 |
+
z = np.ones((2, 3))
|
| 202 |
+
res = herm.hermgrid3d(z, z, z, self.c3d)
|
| 203 |
+
assert_(res.shape == (2, 3)*3)
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
class TestIntegral:
|
| 207 |
+
|
| 208 |
+
def test_hermint(self):
|
| 209 |
+
# check exceptions
|
| 210 |
+
assert_raises(TypeError, herm.hermint, [0], .5)
|
| 211 |
+
assert_raises(ValueError, herm.hermint, [0], -1)
|
| 212 |
+
assert_raises(ValueError, herm.hermint, [0], 1, [0, 0])
|
| 213 |
+
assert_raises(ValueError, herm.hermint, [0], lbnd=[0])
|
| 214 |
+
assert_raises(ValueError, herm.hermint, [0], scl=[0])
|
| 215 |
+
assert_raises(TypeError, herm.hermint, [0], axis=.5)
|
| 216 |
+
|
| 217 |
+
# test integration of zero polynomial
|
| 218 |
+
for i in range(2, 5):
|
| 219 |
+
k = [0]*(i - 2) + [1]
|
| 220 |
+
res = herm.hermint([0], m=i, k=k)
|
| 221 |
+
assert_almost_equal(res, [0, .5])
|
| 222 |
+
|
| 223 |
+
# check single integration with integration constant
|
| 224 |
+
for i in range(5):
|
| 225 |
+
scl = i + 1
|
| 226 |
+
pol = [0]*i + [1]
|
| 227 |
+
tgt = [i] + [0]*i + [1/scl]
|
| 228 |
+
hermpol = herm.poly2herm(pol)
|
| 229 |
+
hermint = herm.hermint(hermpol, m=1, k=[i])
|
| 230 |
+
res = herm.herm2poly(hermint)
|
| 231 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 232 |
+
|
| 233 |
+
# check single integration with integration constant and lbnd
|
| 234 |
+
for i in range(5):
|
| 235 |
+
scl = i + 1
|
| 236 |
+
pol = [0]*i + [1]
|
| 237 |
+
hermpol = herm.poly2herm(pol)
|
| 238 |
+
hermint = herm.hermint(hermpol, m=1, k=[i], lbnd=-1)
|
| 239 |
+
assert_almost_equal(herm.hermval(-1, hermint), i)
|
| 240 |
+
|
| 241 |
+
# check single integration with integration constant and scaling
|
| 242 |
+
for i in range(5):
|
| 243 |
+
scl = i + 1
|
| 244 |
+
pol = [0]*i + [1]
|
| 245 |
+
tgt = [i] + [0]*i + [2/scl]
|
| 246 |
+
hermpol = herm.poly2herm(pol)
|
| 247 |
+
hermint = herm.hermint(hermpol, m=1, k=[i], scl=2)
|
| 248 |
+
res = herm.herm2poly(hermint)
|
| 249 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 250 |
+
|
| 251 |
+
# check multiple integrations with default k
|
| 252 |
+
for i in range(5):
|
| 253 |
+
for j in range(2, 5):
|
| 254 |
+
pol = [0]*i + [1]
|
| 255 |
+
tgt = pol[:]
|
| 256 |
+
for k in range(j):
|
| 257 |
+
tgt = herm.hermint(tgt, m=1)
|
| 258 |
+
res = herm.hermint(pol, m=j)
|
| 259 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 260 |
+
|
| 261 |
+
# check multiple integrations with defined k
|
| 262 |
+
for i in range(5):
|
| 263 |
+
for j in range(2, 5):
|
| 264 |
+
pol = [0]*i + [1]
|
| 265 |
+
tgt = pol[:]
|
| 266 |
+
for k in range(j):
|
| 267 |
+
tgt = herm.hermint(tgt, m=1, k=[k])
|
| 268 |
+
res = herm.hermint(pol, m=j, k=list(range(j)))
|
| 269 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 270 |
+
|
| 271 |
+
# check multiple integrations with lbnd
|
| 272 |
+
for i in range(5):
|
| 273 |
+
for j in range(2, 5):
|
| 274 |
+
pol = [0]*i + [1]
|
| 275 |
+
tgt = pol[:]
|
| 276 |
+
for k in range(j):
|
| 277 |
+
tgt = herm.hermint(tgt, m=1, k=[k], lbnd=-1)
|
| 278 |
+
res = herm.hermint(pol, m=j, k=list(range(j)), lbnd=-1)
|
| 279 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 280 |
+
|
| 281 |
+
# check multiple integrations with scaling
|
| 282 |
+
for i in range(5):
|
| 283 |
+
for j in range(2, 5):
|
| 284 |
+
pol = [0]*i + [1]
|
| 285 |
+
tgt = pol[:]
|
| 286 |
+
for k in range(j):
|
| 287 |
+
tgt = herm.hermint(tgt, m=1, k=[k], scl=2)
|
| 288 |
+
res = herm.hermint(pol, m=j, k=list(range(j)), scl=2)
|
| 289 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 290 |
+
|
| 291 |
+
def test_hermint_axis(self):
|
| 292 |
+
# check that axis keyword works
|
| 293 |
+
c2d = np.random.random((3, 4))
|
| 294 |
+
|
| 295 |
+
tgt = np.vstack([herm.hermint(c) for c in c2d.T]).T
|
| 296 |
+
res = herm.hermint(c2d, axis=0)
|
| 297 |
+
assert_almost_equal(res, tgt)
|
| 298 |
+
|
| 299 |
+
tgt = np.vstack([herm.hermint(c) for c in c2d])
|
| 300 |
+
res = herm.hermint(c2d, axis=1)
|
| 301 |
+
assert_almost_equal(res, tgt)
|
| 302 |
+
|
| 303 |
+
tgt = np.vstack([herm.hermint(c, k=3) for c in c2d])
|
| 304 |
+
res = herm.hermint(c2d, k=3, axis=1)
|
| 305 |
+
assert_almost_equal(res, tgt)
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
class TestDerivative:
|
| 309 |
+
|
| 310 |
+
def test_hermder(self):
|
| 311 |
+
# check exceptions
|
| 312 |
+
assert_raises(TypeError, herm.hermder, [0], .5)
|
| 313 |
+
assert_raises(ValueError, herm.hermder, [0], -1)
|
| 314 |
+
|
| 315 |
+
# check that zeroth derivative does nothing
|
| 316 |
+
for i in range(5):
|
| 317 |
+
tgt = [0]*i + [1]
|
| 318 |
+
res = herm.hermder(tgt, m=0)
|
| 319 |
+
assert_equal(trim(res), trim(tgt))
|
| 320 |
+
|
| 321 |
+
# check that derivation is the inverse of integration
|
| 322 |
+
for i in range(5):
|
| 323 |
+
for j in range(2, 5):
|
| 324 |
+
tgt = [0]*i + [1]
|
| 325 |
+
res = herm.hermder(herm.hermint(tgt, m=j), m=j)
|
| 326 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 327 |
+
|
| 328 |
+
# check derivation with scaling
|
| 329 |
+
for i in range(5):
|
| 330 |
+
for j in range(2, 5):
|
| 331 |
+
tgt = [0]*i + [1]
|
| 332 |
+
res = herm.hermder(herm.hermint(tgt, m=j, scl=2), m=j, scl=.5)
|
| 333 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 334 |
+
|
| 335 |
+
def test_hermder_axis(self):
|
| 336 |
+
# check that axis keyword works
|
| 337 |
+
c2d = np.random.random((3, 4))
|
| 338 |
+
|
| 339 |
+
tgt = np.vstack([herm.hermder(c) for c in c2d.T]).T
|
| 340 |
+
res = herm.hermder(c2d, axis=0)
|
| 341 |
+
assert_almost_equal(res, tgt)
|
| 342 |
+
|
| 343 |
+
tgt = np.vstack([herm.hermder(c) for c in c2d])
|
| 344 |
+
res = herm.hermder(c2d, axis=1)
|
| 345 |
+
assert_almost_equal(res, tgt)
|
| 346 |
+
|
| 347 |
+
|
| 348 |
+
class TestVander:
|
| 349 |
+
# some random values in [-1, 1)
|
| 350 |
+
x = np.random.random((3, 5))*2 - 1
|
| 351 |
+
|
| 352 |
+
def test_hermvander(self):
|
| 353 |
+
# check for 1d x
|
| 354 |
+
x = np.arange(3)
|
| 355 |
+
v = herm.hermvander(x, 3)
|
| 356 |
+
assert_(v.shape == (3, 4))
|
| 357 |
+
for i in range(4):
|
| 358 |
+
coef = [0]*i + [1]
|
| 359 |
+
assert_almost_equal(v[..., i], herm.hermval(x, coef))
|
| 360 |
+
|
| 361 |
+
# check for 2d x
|
| 362 |
+
x = np.array([[1, 2], [3, 4], [5, 6]])
|
| 363 |
+
v = herm.hermvander(x, 3)
|
| 364 |
+
assert_(v.shape == (3, 2, 4))
|
| 365 |
+
for i in range(4):
|
| 366 |
+
coef = [0]*i + [1]
|
| 367 |
+
assert_almost_equal(v[..., i], herm.hermval(x, coef))
|
| 368 |
+
|
| 369 |
+
def test_hermvander2d(self):
|
| 370 |
+
# also tests hermval2d for non-square coefficient array
|
| 371 |
+
x1, x2, x3 = self.x
|
| 372 |
+
c = np.random.random((2, 3))
|
| 373 |
+
van = herm.hermvander2d(x1, x2, [1, 2])
|
| 374 |
+
tgt = herm.hermval2d(x1, x2, c)
|
| 375 |
+
res = np.dot(van, c.flat)
|
| 376 |
+
assert_almost_equal(res, tgt)
|
| 377 |
+
|
| 378 |
+
# check shape
|
| 379 |
+
van = herm.hermvander2d([x1], [x2], [1, 2])
|
| 380 |
+
assert_(van.shape == (1, 5, 6))
|
| 381 |
+
|
| 382 |
+
def test_hermvander3d(self):
|
| 383 |
+
# also tests hermval3d for non-square coefficient array
|
| 384 |
+
x1, x2, x3 = self.x
|
| 385 |
+
c = np.random.random((2, 3, 4))
|
| 386 |
+
van = herm.hermvander3d(x1, x2, x3, [1, 2, 3])
|
| 387 |
+
tgt = herm.hermval3d(x1, x2, x3, c)
|
| 388 |
+
res = np.dot(van, c.flat)
|
| 389 |
+
assert_almost_equal(res, tgt)
|
| 390 |
+
|
| 391 |
+
# check shape
|
| 392 |
+
van = herm.hermvander3d([x1], [x2], [x3], [1, 2, 3])
|
| 393 |
+
assert_(van.shape == (1, 5, 24))
|
| 394 |
+
|
| 395 |
+
|
| 396 |
+
class TestFitting:
|
| 397 |
+
|
| 398 |
+
def test_hermfit(self):
|
| 399 |
+
def f(x):
|
| 400 |
+
return x*(x - 1)*(x - 2)
|
| 401 |
+
|
| 402 |
+
def f2(x):
|
| 403 |
+
return x**4 + x**2 + 1
|
| 404 |
+
|
| 405 |
+
# Test exceptions
|
| 406 |
+
assert_raises(ValueError, herm.hermfit, [1], [1], -1)
|
| 407 |
+
assert_raises(TypeError, herm.hermfit, [[1]], [1], 0)
|
| 408 |
+
assert_raises(TypeError, herm.hermfit, [], [1], 0)
|
| 409 |
+
assert_raises(TypeError, herm.hermfit, [1], [[[1]]], 0)
|
| 410 |
+
assert_raises(TypeError, herm.hermfit, [1, 2], [1], 0)
|
| 411 |
+
assert_raises(TypeError, herm.hermfit, [1], [1, 2], 0)
|
| 412 |
+
assert_raises(TypeError, herm.hermfit, [1], [1], 0, w=[[1]])
|
| 413 |
+
assert_raises(TypeError, herm.hermfit, [1], [1], 0, w=[1, 1])
|
| 414 |
+
assert_raises(ValueError, herm.hermfit, [1], [1], [-1,])
|
| 415 |
+
assert_raises(ValueError, herm.hermfit, [1], [1], [2, -1, 6])
|
| 416 |
+
assert_raises(TypeError, herm.hermfit, [1], [1], [])
|
| 417 |
+
|
| 418 |
+
# Test fit
|
| 419 |
+
x = np.linspace(0, 2)
|
| 420 |
+
y = f(x)
|
| 421 |
+
#
|
| 422 |
+
coef3 = herm.hermfit(x, y, 3)
|
| 423 |
+
assert_equal(len(coef3), 4)
|
| 424 |
+
assert_almost_equal(herm.hermval(x, coef3), y)
|
| 425 |
+
coef3 = herm.hermfit(x, y, [0, 1, 2, 3])
|
| 426 |
+
assert_equal(len(coef3), 4)
|
| 427 |
+
assert_almost_equal(herm.hermval(x, coef3), y)
|
| 428 |
+
#
|
| 429 |
+
coef4 = herm.hermfit(x, y, 4)
|
| 430 |
+
assert_equal(len(coef4), 5)
|
| 431 |
+
assert_almost_equal(herm.hermval(x, coef4), y)
|
| 432 |
+
coef4 = herm.hermfit(x, y, [0, 1, 2, 3, 4])
|
| 433 |
+
assert_equal(len(coef4), 5)
|
| 434 |
+
assert_almost_equal(herm.hermval(x, coef4), y)
|
| 435 |
+
# check things still work if deg is not in strict increasing
|
| 436 |
+
coef4 = herm.hermfit(x, y, [2, 3, 4, 1, 0])
|
| 437 |
+
assert_equal(len(coef4), 5)
|
| 438 |
+
assert_almost_equal(herm.hermval(x, coef4), y)
|
| 439 |
+
#
|
| 440 |
+
coef2d = herm.hermfit(x, np.array([y, y]).T, 3)
|
| 441 |
+
assert_almost_equal(coef2d, np.array([coef3, coef3]).T)
|
| 442 |
+
coef2d = herm.hermfit(x, np.array([y, y]).T, [0, 1, 2, 3])
|
| 443 |
+
assert_almost_equal(coef2d, np.array([coef3, coef3]).T)
|
| 444 |
+
# test weighting
|
| 445 |
+
w = np.zeros_like(x)
|
| 446 |
+
yw = y.copy()
|
| 447 |
+
w[1::2] = 1
|
| 448 |
+
y[0::2] = 0
|
| 449 |
+
wcoef3 = herm.hermfit(x, yw, 3, w=w)
|
| 450 |
+
assert_almost_equal(wcoef3, coef3)
|
| 451 |
+
wcoef3 = herm.hermfit(x, yw, [0, 1, 2, 3], w=w)
|
| 452 |
+
assert_almost_equal(wcoef3, coef3)
|
| 453 |
+
#
|
| 454 |
+
wcoef2d = herm.hermfit(x, np.array([yw, yw]).T, 3, w=w)
|
| 455 |
+
assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T)
|
| 456 |
+
wcoef2d = herm.hermfit(x, np.array([yw, yw]).T, [0, 1, 2, 3], w=w)
|
| 457 |
+
assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T)
|
| 458 |
+
# test scaling with complex values x points whose square
|
| 459 |
+
# is zero when summed.
|
| 460 |
+
x = [1, 1j, -1, -1j]
|
| 461 |
+
assert_almost_equal(herm.hermfit(x, x, 1), [0, .5])
|
| 462 |
+
assert_almost_equal(herm.hermfit(x, x, [0, 1]), [0, .5])
|
| 463 |
+
# test fitting only even Legendre polynomials
|
| 464 |
+
x = np.linspace(-1, 1)
|
| 465 |
+
y = f2(x)
|
| 466 |
+
coef1 = herm.hermfit(x, y, 4)
|
| 467 |
+
assert_almost_equal(herm.hermval(x, coef1), y)
|
| 468 |
+
coef2 = herm.hermfit(x, y, [0, 2, 4])
|
| 469 |
+
assert_almost_equal(herm.hermval(x, coef2), y)
|
| 470 |
+
assert_almost_equal(coef1, coef2)
|
| 471 |
+
|
| 472 |
+
|
| 473 |
+
class TestCompanion:
|
| 474 |
+
|
| 475 |
+
def test_raises(self):
|
| 476 |
+
assert_raises(ValueError, herm.hermcompanion, [])
|
| 477 |
+
assert_raises(ValueError, herm.hermcompanion, [1])
|
| 478 |
+
|
| 479 |
+
def test_dimensions(self):
|
| 480 |
+
for i in range(1, 5):
|
| 481 |
+
coef = [0]*i + [1]
|
| 482 |
+
assert_(herm.hermcompanion(coef).shape == (i, i))
|
| 483 |
+
|
| 484 |
+
def test_linear_root(self):
|
| 485 |
+
assert_(herm.hermcompanion([1, 2])[0, 0] == -.25)
|
| 486 |
+
|
| 487 |
+
|
| 488 |
+
class TestGauss:
|
| 489 |
+
|
| 490 |
+
def test_100(self):
|
| 491 |
+
x, w = herm.hermgauss(100)
|
| 492 |
+
|
| 493 |
+
# test orthogonality. Note that the results need to be normalized,
|
| 494 |
+
# otherwise the huge values that can arise from fast growing
|
| 495 |
+
# functions like Laguerre can be very confusing.
|
| 496 |
+
v = herm.hermvander(x, 99)
|
| 497 |
+
vv = np.dot(v.T * w, v)
|
| 498 |
+
vd = 1/np.sqrt(vv.diagonal())
|
| 499 |
+
vv = vd[:, None] * vv * vd
|
| 500 |
+
assert_almost_equal(vv, np.eye(100))
|
| 501 |
+
|
| 502 |
+
# check that the integral of 1 is correct
|
| 503 |
+
tgt = np.sqrt(np.pi)
|
| 504 |
+
assert_almost_equal(w.sum(), tgt)
|
| 505 |
+
|
| 506 |
+
|
| 507 |
+
class TestMisc:
|
| 508 |
+
|
| 509 |
+
def test_hermfromroots(self):
|
| 510 |
+
res = herm.hermfromroots([])
|
| 511 |
+
assert_almost_equal(trim(res), [1])
|
| 512 |
+
for i in range(1, 5):
|
| 513 |
+
roots = np.cos(np.linspace(-np.pi, 0, 2*i + 1)[1::2])
|
| 514 |
+
pol = herm.hermfromroots(roots)
|
| 515 |
+
res = herm.hermval(roots, pol)
|
| 516 |
+
tgt = 0
|
| 517 |
+
assert_(len(pol) == i + 1)
|
| 518 |
+
assert_almost_equal(herm.herm2poly(pol)[-1], 1)
|
| 519 |
+
assert_almost_equal(res, tgt)
|
| 520 |
+
|
| 521 |
+
def test_hermroots(self):
|
| 522 |
+
assert_almost_equal(herm.hermroots([1]), [])
|
| 523 |
+
assert_almost_equal(herm.hermroots([1, 1]), [-.5])
|
| 524 |
+
for i in range(2, 5):
|
| 525 |
+
tgt = np.linspace(-1, 1, i)
|
| 526 |
+
res = herm.hermroots(herm.hermfromroots(tgt))
|
| 527 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 528 |
+
|
| 529 |
+
def test_hermtrim(self):
|
| 530 |
+
coef = [2, -1, 1, 0]
|
| 531 |
+
|
| 532 |
+
# Test exceptions
|
| 533 |
+
assert_raises(ValueError, herm.hermtrim, coef, -1)
|
| 534 |
+
|
| 535 |
+
# Test results
|
| 536 |
+
assert_equal(herm.hermtrim(coef), coef[:-1])
|
| 537 |
+
assert_equal(herm.hermtrim(coef, 1), coef[:-3])
|
| 538 |
+
assert_equal(herm.hermtrim(coef, 2), [0])
|
| 539 |
+
|
| 540 |
+
def test_hermline(self):
|
| 541 |
+
assert_equal(herm.hermline(3, 4), [3, 2])
|
| 542 |
+
|
| 543 |
+
def test_herm2poly(self):
|
| 544 |
+
for i in range(10):
|
| 545 |
+
assert_almost_equal(herm.herm2poly([0]*i + [1]), Hlist[i])
|
| 546 |
+
|
| 547 |
+
def test_poly2herm(self):
|
| 548 |
+
for i in range(10):
|
| 549 |
+
assert_almost_equal(herm.poly2herm(Hlist[i]), [0]*i + [1])
|
| 550 |
+
|
| 551 |
+
def test_weight(self):
|
| 552 |
+
x = np.linspace(-5, 5, 11)
|
| 553 |
+
tgt = np.exp(-x**2)
|
| 554 |
+
res = herm.hermweight(x)
|
| 555 |
+
assert_almost_equal(res, tgt)
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/polynomial/tests/test_hermite_e.py
ADDED
|
@@ -0,0 +1,556 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Tests for hermite_e module.
|
| 2 |
+
|
| 3 |
+
"""
|
| 4 |
+
from functools import reduce
|
| 5 |
+
|
| 6 |
+
import numpy as np
|
| 7 |
+
import numpy.polynomial.hermite_e as herme
|
| 8 |
+
from numpy.polynomial.polynomial import polyval
|
| 9 |
+
from numpy.testing import (
|
| 10 |
+
assert_almost_equal, assert_raises, assert_equal, assert_,
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
He0 = np.array([1])
|
| 14 |
+
He1 = np.array([0, 1])
|
| 15 |
+
He2 = np.array([-1, 0, 1])
|
| 16 |
+
He3 = np.array([0, -3, 0, 1])
|
| 17 |
+
He4 = np.array([3, 0, -6, 0, 1])
|
| 18 |
+
He5 = np.array([0, 15, 0, -10, 0, 1])
|
| 19 |
+
He6 = np.array([-15, 0, 45, 0, -15, 0, 1])
|
| 20 |
+
He7 = np.array([0, -105, 0, 105, 0, -21, 0, 1])
|
| 21 |
+
He8 = np.array([105, 0, -420, 0, 210, 0, -28, 0, 1])
|
| 22 |
+
He9 = np.array([0, 945, 0, -1260, 0, 378, 0, -36, 0, 1])
|
| 23 |
+
|
| 24 |
+
Helist = [He0, He1, He2, He3, He4, He5, He6, He7, He8, He9]
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def trim(x):
|
| 28 |
+
return herme.hermetrim(x, tol=1e-6)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class TestConstants:
|
| 32 |
+
|
| 33 |
+
def test_hermedomain(self):
|
| 34 |
+
assert_equal(herme.hermedomain, [-1, 1])
|
| 35 |
+
|
| 36 |
+
def test_hermezero(self):
|
| 37 |
+
assert_equal(herme.hermezero, [0])
|
| 38 |
+
|
| 39 |
+
def test_hermeone(self):
|
| 40 |
+
assert_equal(herme.hermeone, [1])
|
| 41 |
+
|
| 42 |
+
def test_hermex(self):
|
| 43 |
+
assert_equal(herme.hermex, [0, 1])
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class TestArithmetic:
|
| 47 |
+
x = np.linspace(-3, 3, 100)
|
| 48 |
+
|
| 49 |
+
def test_hermeadd(self):
|
| 50 |
+
for i in range(5):
|
| 51 |
+
for j in range(5):
|
| 52 |
+
msg = f"At i={i}, j={j}"
|
| 53 |
+
tgt = np.zeros(max(i, j) + 1)
|
| 54 |
+
tgt[i] += 1
|
| 55 |
+
tgt[j] += 1
|
| 56 |
+
res = herme.hermeadd([0]*i + [1], [0]*j + [1])
|
| 57 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 58 |
+
|
| 59 |
+
def test_hermesub(self):
|
| 60 |
+
for i in range(5):
|
| 61 |
+
for j in range(5):
|
| 62 |
+
msg = f"At i={i}, j={j}"
|
| 63 |
+
tgt = np.zeros(max(i, j) + 1)
|
| 64 |
+
tgt[i] += 1
|
| 65 |
+
tgt[j] -= 1
|
| 66 |
+
res = herme.hermesub([0]*i + [1], [0]*j + [1])
|
| 67 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 68 |
+
|
| 69 |
+
def test_hermemulx(self):
|
| 70 |
+
assert_equal(herme.hermemulx([0]), [0])
|
| 71 |
+
assert_equal(herme.hermemulx([1]), [0, 1])
|
| 72 |
+
for i in range(1, 5):
|
| 73 |
+
ser = [0]*i + [1]
|
| 74 |
+
tgt = [0]*(i - 1) + [i, 0, 1]
|
| 75 |
+
assert_equal(herme.hermemulx(ser), tgt)
|
| 76 |
+
|
| 77 |
+
def test_hermemul(self):
|
| 78 |
+
# check values of result
|
| 79 |
+
for i in range(5):
|
| 80 |
+
pol1 = [0]*i + [1]
|
| 81 |
+
val1 = herme.hermeval(self.x, pol1)
|
| 82 |
+
for j in range(5):
|
| 83 |
+
msg = f"At i={i}, j={j}"
|
| 84 |
+
pol2 = [0]*j + [1]
|
| 85 |
+
val2 = herme.hermeval(self.x, pol2)
|
| 86 |
+
pol3 = herme.hermemul(pol1, pol2)
|
| 87 |
+
val3 = herme.hermeval(self.x, pol3)
|
| 88 |
+
assert_(len(pol3) == i + j + 1, msg)
|
| 89 |
+
assert_almost_equal(val3, val1*val2, err_msg=msg)
|
| 90 |
+
|
| 91 |
+
def test_hermediv(self):
|
| 92 |
+
for i in range(5):
|
| 93 |
+
for j in range(5):
|
| 94 |
+
msg = f"At i={i}, j={j}"
|
| 95 |
+
ci = [0]*i + [1]
|
| 96 |
+
cj = [0]*j + [1]
|
| 97 |
+
tgt = herme.hermeadd(ci, cj)
|
| 98 |
+
quo, rem = herme.hermediv(tgt, ci)
|
| 99 |
+
res = herme.hermeadd(herme.hermemul(quo, ci), rem)
|
| 100 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 101 |
+
|
| 102 |
+
def test_hermepow(self):
|
| 103 |
+
for i in range(5):
|
| 104 |
+
for j in range(5):
|
| 105 |
+
msg = f"At i={i}, j={j}"
|
| 106 |
+
c = np.arange(i + 1)
|
| 107 |
+
tgt = reduce(herme.hermemul, [c]*j, np.array([1]))
|
| 108 |
+
res = herme.hermepow(c, j)
|
| 109 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
class TestEvaluation:
|
| 113 |
+
# coefficients of 1 + 2*x + 3*x**2
|
| 114 |
+
c1d = np.array([4., 2., 3.])
|
| 115 |
+
c2d = np.einsum('i,j->ij', c1d, c1d)
|
| 116 |
+
c3d = np.einsum('i,j,k->ijk', c1d, c1d, c1d)
|
| 117 |
+
|
| 118 |
+
# some random values in [-1, 1)
|
| 119 |
+
x = np.random.random((3, 5))*2 - 1
|
| 120 |
+
y = polyval(x, [1., 2., 3.])
|
| 121 |
+
|
| 122 |
+
def test_hermeval(self):
|
| 123 |
+
#check empty input
|
| 124 |
+
assert_equal(herme.hermeval([], [1]).size, 0)
|
| 125 |
+
|
| 126 |
+
#check normal input)
|
| 127 |
+
x = np.linspace(-1, 1)
|
| 128 |
+
y = [polyval(x, c) for c in Helist]
|
| 129 |
+
for i in range(10):
|
| 130 |
+
msg = f"At i={i}"
|
| 131 |
+
tgt = y[i]
|
| 132 |
+
res = herme.hermeval(x, [0]*i + [1])
|
| 133 |
+
assert_almost_equal(res, tgt, err_msg=msg)
|
| 134 |
+
|
| 135 |
+
#check that shape is preserved
|
| 136 |
+
for i in range(3):
|
| 137 |
+
dims = [2]*i
|
| 138 |
+
x = np.zeros(dims)
|
| 139 |
+
assert_equal(herme.hermeval(x, [1]).shape, dims)
|
| 140 |
+
assert_equal(herme.hermeval(x, [1, 0]).shape, dims)
|
| 141 |
+
assert_equal(herme.hermeval(x, [1, 0, 0]).shape, dims)
|
| 142 |
+
|
| 143 |
+
def test_hermeval2d(self):
|
| 144 |
+
x1, x2, x3 = self.x
|
| 145 |
+
y1, y2, y3 = self.y
|
| 146 |
+
|
| 147 |
+
#test exceptions
|
| 148 |
+
assert_raises(ValueError, herme.hermeval2d, x1, x2[:2], self.c2d)
|
| 149 |
+
|
| 150 |
+
#test values
|
| 151 |
+
tgt = y1*y2
|
| 152 |
+
res = herme.hermeval2d(x1, x2, self.c2d)
|
| 153 |
+
assert_almost_equal(res, tgt)
|
| 154 |
+
|
| 155 |
+
#test shape
|
| 156 |
+
z = np.ones((2, 3))
|
| 157 |
+
res = herme.hermeval2d(z, z, self.c2d)
|
| 158 |
+
assert_(res.shape == (2, 3))
|
| 159 |
+
|
| 160 |
+
def test_hermeval3d(self):
|
| 161 |
+
x1, x2, x3 = self.x
|
| 162 |
+
y1, y2, y3 = self.y
|
| 163 |
+
|
| 164 |
+
#test exceptions
|
| 165 |
+
assert_raises(ValueError, herme.hermeval3d, x1, x2, x3[:2], self.c3d)
|
| 166 |
+
|
| 167 |
+
#test values
|
| 168 |
+
tgt = y1*y2*y3
|
| 169 |
+
res = herme.hermeval3d(x1, x2, x3, self.c3d)
|
| 170 |
+
assert_almost_equal(res, tgt)
|
| 171 |
+
|
| 172 |
+
#test shape
|
| 173 |
+
z = np.ones((2, 3))
|
| 174 |
+
res = herme.hermeval3d(z, z, z, self.c3d)
|
| 175 |
+
assert_(res.shape == (2, 3))
|
| 176 |
+
|
| 177 |
+
def test_hermegrid2d(self):
|
| 178 |
+
x1, x2, x3 = self.x
|
| 179 |
+
y1, y2, y3 = self.y
|
| 180 |
+
|
| 181 |
+
#test values
|
| 182 |
+
tgt = np.einsum('i,j->ij', y1, y2)
|
| 183 |
+
res = herme.hermegrid2d(x1, x2, self.c2d)
|
| 184 |
+
assert_almost_equal(res, tgt)
|
| 185 |
+
|
| 186 |
+
#test shape
|
| 187 |
+
z = np.ones((2, 3))
|
| 188 |
+
res = herme.hermegrid2d(z, z, self.c2d)
|
| 189 |
+
assert_(res.shape == (2, 3)*2)
|
| 190 |
+
|
| 191 |
+
def test_hermegrid3d(self):
|
| 192 |
+
x1, x2, x3 = self.x
|
| 193 |
+
y1, y2, y3 = self.y
|
| 194 |
+
|
| 195 |
+
#test values
|
| 196 |
+
tgt = np.einsum('i,j,k->ijk', y1, y2, y3)
|
| 197 |
+
res = herme.hermegrid3d(x1, x2, x3, self.c3d)
|
| 198 |
+
assert_almost_equal(res, tgt)
|
| 199 |
+
|
| 200 |
+
#test shape
|
| 201 |
+
z = np.ones((2, 3))
|
| 202 |
+
res = herme.hermegrid3d(z, z, z, self.c3d)
|
| 203 |
+
assert_(res.shape == (2, 3)*3)
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
class TestIntegral:
|
| 207 |
+
|
| 208 |
+
def test_hermeint(self):
|
| 209 |
+
# check exceptions
|
| 210 |
+
assert_raises(TypeError, herme.hermeint, [0], .5)
|
| 211 |
+
assert_raises(ValueError, herme.hermeint, [0], -1)
|
| 212 |
+
assert_raises(ValueError, herme.hermeint, [0], 1, [0, 0])
|
| 213 |
+
assert_raises(ValueError, herme.hermeint, [0], lbnd=[0])
|
| 214 |
+
assert_raises(ValueError, herme.hermeint, [0], scl=[0])
|
| 215 |
+
assert_raises(TypeError, herme.hermeint, [0], axis=.5)
|
| 216 |
+
|
| 217 |
+
# test integration of zero polynomial
|
| 218 |
+
for i in range(2, 5):
|
| 219 |
+
k = [0]*(i - 2) + [1]
|
| 220 |
+
res = herme.hermeint([0], m=i, k=k)
|
| 221 |
+
assert_almost_equal(res, [0, 1])
|
| 222 |
+
|
| 223 |
+
# check single integration with integration constant
|
| 224 |
+
for i in range(5):
|
| 225 |
+
scl = i + 1
|
| 226 |
+
pol = [0]*i + [1]
|
| 227 |
+
tgt = [i] + [0]*i + [1/scl]
|
| 228 |
+
hermepol = herme.poly2herme(pol)
|
| 229 |
+
hermeint = herme.hermeint(hermepol, m=1, k=[i])
|
| 230 |
+
res = herme.herme2poly(hermeint)
|
| 231 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 232 |
+
|
| 233 |
+
# check single integration with integration constant and lbnd
|
| 234 |
+
for i in range(5):
|
| 235 |
+
scl = i + 1
|
| 236 |
+
pol = [0]*i + [1]
|
| 237 |
+
hermepol = herme.poly2herme(pol)
|
| 238 |
+
hermeint = herme.hermeint(hermepol, m=1, k=[i], lbnd=-1)
|
| 239 |
+
assert_almost_equal(herme.hermeval(-1, hermeint), i)
|
| 240 |
+
|
| 241 |
+
# check single integration with integration constant and scaling
|
| 242 |
+
for i in range(5):
|
| 243 |
+
scl = i + 1
|
| 244 |
+
pol = [0]*i + [1]
|
| 245 |
+
tgt = [i] + [0]*i + [2/scl]
|
| 246 |
+
hermepol = herme.poly2herme(pol)
|
| 247 |
+
hermeint = herme.hermeint(hermepol, m=1, k=[i], scl=2)
|
| 248 |
+
res = herme.herme2poly(hermeint)
|
| 249 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 250 |
+
|
| 251 |
+
# check multiple integrations with default k
|
| 252 |
+
for i in range(5):
|
| 253 |
+
for j in range(2, 5):
|
| 254 |
+
pol = [0]*i + [1]
|
| 255 |
+
tgt = pol[:]
|
| 256 |
+
for k in range(j):
|
| 257 |
+
tgt = herme.hermeint(tgt, m=1)
|
| 258 |
+
res = herme.hermeint(pol, m=j)
|
| 259 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 260 |
+
|
| 261 |
+
# check multiple integrations with defined k
|
| 262 |
+
for i in range(5):
|
| 263 |
+
for j in range(2, 5):
|
| 264 |
+
pol = [0]*i + [1]
|
| 265 |
+
tgt = pol[:]
|
| 266 |
+
for k in range(j):
|
| 267 |
+
tgt = herme.hermeint(tgt, m=1, k=[k])
|
| 268 |
+
res = herme.hermeint(pol, m=j, k=list(range(j)))
|
| 269 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 270 |
+
|
| 271 |
+
# check multiple integrations with lbnd
|
| 272 |
+
for i in range(5):
|
| 273 |
+
for j in range(2, 5):
|
| 274 |
+
pol = [0]*i + [1]
|
| 275 |
+
tgt = pol[:]
|
| 276 |
+
for k in range(j):
|
| 277 |
+
tgt = herme.hermeint(tgt, m=1, k=[k], lbnd=-1)
|
| 278 |
+
res = herme.hermeint(pol, m=j, k=list(range(j)), lbnd=-1)
|
| 279 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 280 |
+
|
| 281 |
+
# check multiple integrations with scaling
|
| 282 |
+
for i in range(5):
|
| 283 |
+
for j in range(2, 5):
|
| 284 |
+
pol = [0]*i + [1]
|
| 285 |
+
tgt = pol[:]
|
| 286 |
+
for k in range(j):
|
| 287 |
+
tgt = herme.hermeint(tgt, m=1, k=[k], scl=2)
|
| 288 |
+
res = herme.hermeint(pol, m=j, k=list(range(j)), scl=2)
|
| 289 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 290 |
+
|
| 291 |
+
def test_hermeint_axis(self):
|
| 292 |
+
# check that axis keyword works
|
| 293 |
+
c2d = np.random.random((3, 4))
|
| 294 |
+
|
| 295 |
+
tgt = np.vstack([herme.hermeint(c) for c in c2d.T]).T
|
| 296 |
+
res = herme.hermeint(c2d, axis=0)
|
| 297 |
+
assert_almost_equal(res, tgt)
|
| 298 |
+
|
| 299 |
+
tgt = np.vstack([herme.hermeint(c) for c in c2d])
|
| 300 |
+
res = herme.hermeint(c2d, axis=1)
|
| 301 |
+
assert_almost_equal(res, tgt)
|
| 302 |
+
|
| 303 |
+
tgt = np.vstack([herme.hermeint(c, k=3) for c in c2d])
|
| 304 |
+
res = herme.hermeint(c2d, k=3, axis=1)
|
| 305 |
+
assert_almost_equal(res, tgt)
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
class TestDerivative:
|
| 309 |
+
|
| 310 |
+
def test_hermeder(self):
|
| 311 |
+
# check exceptions
|
| 312 |
+
assert_raises(TypeError, herme.hermeder, [0], .5)
|
| 313 |
+
assert_raises(ValueError, herme.hermeder, [0], -1)
|
| 314 |
+
|
| 315 |
+
# check that zeroth derivative does nothing
|
| 316 |
+
for i in range(5):
|
| 317 |
+
tgt = [0]*i + [1]
|
| 318 |
+
res = herme.hermeder(tgt, m=0)
|
| 319 |
+
assert_equal(trim(res), trim(tgt))
|
| 320 |
+
|
| 321 |
+
# check that derivation is the inverse of integration
|
| 322 |
+
for i in range(5):
|
| 323 |
+
for j in range(2, 5):
|
| 324 |
+
tgt = [0]*i + [1]
|
| 325 |
+
res = herme.hermeder(herme.hermeint(tgt, m=j), m=j)
|
| 326 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 327 |
+
|
| 328 |
+
# check derivation with scaling
|
| 329 |
+
for i in range(5):
|
| 330 |
+
for j in range(2, 5):
|
| 331 |
+
tgt = [0]*i + [1]
|
| 332 |
+
res = herme.hermeder(
|
| 333 |
+
herme.hermeint(tgt, m=j, scl=2), m=j, scl=.5)
|
| 334 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 335 |
+
|
| 336 |
+
def test_hermeder_axis(self):
|
| 337 |
+
# check that axis keyword works
|
| 338 |
+
c2d = np.random.random((3, 4))
|
| 339 |
+
|
| 340 |
+
tgt = np.vstack([herme.hermeder(c) for c in c2d.T]).T
|
| 341 |
+
res = herme.hermeder(c2d, axis=0)
|
| 342 |
+
assert_almost_equal(res, tgt)
|
| 343 |
+
|
| 344 |
+
tgt = np.vstack([herme.hermeder(c) for c in c2d])
|
| 345 |
+
res = herme.hermeder(c2d, axis=1)
|
| 346 |
+
assert_almost_equal(res, tgt)
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
class TestVander:
|
| 350 |
+
# some random values in [-1, 1)
|
| 351 |
+
x = np.random.random((3, 5))*2 - 1
|
| 352 |
+
|
| 353 |
+
def test_hermevander(self):
|
| 354 |
+
# check for 1d x
|
| 355 |
+
x = np.arange(3)
|
| 356 |
+
v = herme.hermevander(x, 3)
|
| 357 |
+
assert_(v.shape == (3, 4))
|
| 358 |
+
for i in range(4):
|
| 359 |
+
coef = [0]*i + [1]
|
| 360 |
+
assert_almost_equal(v[..., i], herme.hermeval(x, coef))
|
| 361 |
+
|
| 362 |
+
# check for 2d x
|
| 363 |
+
x = np.array([[1, 2], [3, 4], [5, 6]])
|
| 364 |
+
v = herme.hermevander(x, 3)
|
| 365 |
+
assert_(v.shape == (3, 2, 4))
|
| 366 |
+
for i in range(4):
|
| 367 |
+
coef = [0]*i + [1]
|
| 368 |
+
assert_almost_equal(v[..., i], herme.hermeval(x, coef))
|
| 369 |
+
|
| 370 |
+
def test_hermevander2d(self):
|
| 371 |
+
# also tests hermeval2d for non-square coefficient array
|
| 372 |
+
x1, x2, x3 = self.x
|
| 373 |
+
c = np.random.random((2, 3))
|
| 374 |
+
van = herme.hermevander2d(x1, x2, [1, 2])
|
| 375 |
+
tgt = herme.hermeval2d(x1, x2, c)
|
| 376 |
+
res = np.dot(van, c.flat)
|
| 377 |
+
assert_almost_equal(res, tgt)
|
| 378 |
+
|
| 379 |
+
# check shape
|
| 380 |
+
van = herme.hermevander2d([x1], [x2], [1, 2])
|
| 381 |
+
assert_(van.shape == (1, 5, 6))
|
| 382 |
+
|
| 383 |
+
def test_hermevander3d(self):
|
| 384 |
+
# also tests hermeval3d for non-square coefficient array
|
| 385 |
+
x1, x2, x3 = self.x
|
| 386 |
+
c = np.random.random((2, 3, 4))
|
| 387 |
+
van = herme.hermevander3d(x1, x2, x3, [1, 2, 3])
|
| 388 |
+
tgt = herme.hermeval3d(x1, x2, x3, c)
|
| 389 |
+
res = np.dot(van, c.flat)
|
| 390 |
+
assert_almost_equal(res, tgt)
|
| 391 |
+
|
| 392 |
+
# check shape
|
| 393 |
+
van = herme.hermevander3d([x1], [x2], [x3], [1, 2, 3])
|
| 394 |
+
assert_(van.shape == (1, 5, 24))
|
| 395 |
+
|
| 396 |
+
|
| 397 |
+
class TestFitting:
|
| 398 |
+
|
| 399 |
+
def test_hermefit(self):
|
| 400 |
+
def f(x):
|
| 401 |
+
return x*(x - 1)*(x - 2)
|
| 402 |
+
|
| 403 |
+
def f2(x):
|
| 404 |
+
return x**4 + x**2 + 1
|
| 405 |
+
|
| 406 |
+
# Test exceptions
|
| 407 |
+
assert_raises(ValueError, herme.hermefit, [1], [1], -1)
|
| 408 |
+
assert_raises(TypeError, herme.hermefit, [[1]], [1], 0)
|
| 409 |
+
assert_raises(TypeError, herme.hermefit, [], [1], 0)
|
| 410 |
+
assert_raises(TypeError, herme.hermefit, [1], [[[1]]], 0)
|
| 411 |
+
assert_raises(TypeError, herme.hermefit, [1, 2], [1], 0)
|
| 412 |
+
assert_raises(TypeError, herme.hermefit, [1], [1, 2], 0)
|
| 413 |
+
assert_raises(TypeError, herme.hermefit, [1], [1], 0, w=[[1]])
|
| 414 |
+
assert_raises(TypeError, herme.hermefit, [1], [1], 0, w=[1, 1])
|
| 415 |
+
assert_raises(ValueError, herme.hermefit, [1], [1], [-1,])
|
| 416 |
+
assert_raises(ValueError, herme.hermefit, [1], [1], [2, -1, 6])
|
| 417 |
+
assert_raises(TypeError, herme.hermefit, [1], [1], [])
|
| 418 |
+
|
| 419 |
+
# Test fit
|
| 420 |
+
x = np.linspace(0, 2)
|
| 421 |
+
y = f(x)
|
| 422 |
+
#
|
| 423 |
+
coef3 = herme.hermefit(x, y, 3)
|
| 424 |
+
assert_equal(len(coef3), 4)
|
| 425 |
+
assert_almost_equal(herme.hermeval(x, coef3), y)
|
| 426 |
+
coef3 = herme.hermefit(x, y, [0, 1, 2, 3])
|
| 427 |
+
assert_equal(len(coef3), 4)
|
| 428 |
+
assert_almost_equal(herme.hermeval(x, coef3), y)
|
| 429 |
+
#
|
| 430 |
+
coef4 = herme.hermefit(x, y, 4)
|
| 431 |
+
assert_equal(len(coef4), 5)
|
| 432 |
+
assert_almost_equal(herme.hermeval(x, coef4), y)
|
| 433 |
+
coef4 = herme.hermefit(x, y, [0, 1, 2, 3, 4])
|
| 434 |
+
assert_equal(len(coef4), 5)
|
| 435 |
+
assert_almost_equal(herme.hermeval(x, coef4), y)
|
| 436 |
+
# check things still work if deg is not in strict increasing
|
| 437 |
+
coef4 = herme.hermefit(x, y, [2, 3, 4, 1, 0])
|
| 438 |
+
assert_equal(len(coef4), 5)
|
| 439 |
+
assert_almost_equal(herme.hermeval(x, coef4), y)
|
| 440 |
+
#
|
| 441 |
+
coef2d = herme.hermefit(x, np.array([y, y]).T, 3)
|
| 442 |
+
assert_almost_equal(coef2d, np.array([coef3, coef3]).T)
|
| 443 |
+
coef2d = herme.hermefit(x, np.array([y, y]).T, [0, 1, 2, 3])
|
| 444 |
+
assert_almost_equal(coef2d, np.array([coef3, coef3]).T)
|
| 445 |
+
# test weighting
|
| 446 |
+
w = np.zeros_like(x)
|
| 447 |
+
yw = y.copy()
|
| 448 |
+
w[1::2] = 1
|
| 449 |
+
y[0::2] = 0
|
| 450 |
+
wcoef3 = herme.hermefit(x, yw, 3, w=w)
|
| 451 |
+
assert_almost_equal(wcoef3, coef3)
|
| 452 |
+
wcoef3 = herme.hermefit(x, yw, [0, 1, 2, 3], w=w)
|
| 453 |
+
assert_almost_equal(wcoef3, coef3)
|
| 454 |
+
#
|
| 455 |
+
wcoef2d = herme.hermefit(x, np.array([yw, yw]).T, 3, w=w)
|
| 456 |
+
assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T)
|
| 457 |
+
wcoef2d = herme.hermefit(x, np.array([yw, yw]).T, [0, 1, 2, 3], w=w)
|
| 458 |
+
assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T)
|
| 459 |
+
# test scaling with complex values x points whose square
|
| 460 |
+
# is zero when summed.
|
| 461 |
+
x = [1, 1j, -1, -1j]
|
| 462 |
+
assert_almost_equal(herme.hermefit(x, x, 1), [0, 1])
|
| 463 |
+
assert_almost_equal(herme.hermefit(x, x, [0, 1]), [0, 1])
|
| 464 |
+
# test fitting only even Legendre polynomials
|
| 465 |
+
x = np.linspace(-1, 1)
|
| 466 |
+
y = f2(x)
|
| 467 |
+
coef1 = herme.hermefit(x, y, 4)
|
| 468 |
+
assert_almost_equal(herme.hermeval(x, coef1), y)
|
| 469 |
+
coef2 = herme.hermefit(x, y, [0, 2, 4])
|
| 470 |
+
assert_almost_equal(herme.hermeval(x, coef2), y)
|
| 471 |
+
assert_almost_equal(coef1, coef2)
|
| 472 |
+
|
| 473 |
+
|
| 474 |
+
class TestCompanion:
|
| 475 |
+
|
| 476 |
+
def test_raises(self):
|
| 477 |
+
assert_raises(ValueError, herme.hermecompanion, [])
|
| 478 |
+
assert_raises(ValueError, herme.hermecompanion, [1])
|
| 479 |
+
|
| 480 |
+
def test_dimensions(self):
|
| 481 |
+
for i in range(1, 5):
|
| 482 |
+
coef = [0]*i + [1]
|
| 483 |
+
assert_(herme.hermecompanion(coef).shape == (i, i))
|
| 484 |
+
|
| 485 |
+
def test_linear_root(self):
|
| 486 |
+
assert_(herme.hermecompanion([1, 2])[0, 0] == -.5)
|
| 487 |
+
|
| 488 |
+
|
| 489 |
+
class TestGauss:
|
| 490 |
+
|
| 491 |
+
def test_100(self):
|
| 492 |
+
x, w = herme.hermegauss(100)
|
| 493 |
+
|
| 494 |
+
# test orthogonality. Note that the results need to be normalized,
|
| 495 |
+
# otherwise the huge values that can arise from fast growing
|
| 496 |
+
# functions like Laguerre can be very confusing.
|
| 497 |
+
v = herme.hermevander(x, 99)
|
| 498 |
+
vv = np.dot(v.T * w, v)
|
| 499 |
+
vd = 1/np.sqrt(vv.diagonal())
|
| 500 |
+
vv = vd[:, None] * vv * vd
|
| 501 |
+
assert_almost_equal(vv, np.eye(100))
|
| 502 |
+
|
| 503 |
+
# check that the integral of 1 is correct
|
| 504 |
+
tgt = np.sqrt(2*np.pi)
|
| 505 |
+
assert_almost_equal(w.sum(), tgt)
|
| 506 |
+
|
| 507 |
+
|
| 508 |
+
class TestMisc:
|
| 509 |
+
|
| 510 |
+
def test_hermefromroots(self):
|
| 511 |
+
res = herme.hermefromroots([])
|
| 512 |
+
assert_almost_equal(trim(res), [1])
|
| 513 |
+
for i in range(1, 5):
|
| 514 |
+
roots = np.cos(np.linspace(-np.pi, 0, 2*i + 1)[1::2])
|
| 515 |
+
pol = herme.hermefromroots(roots)
|
| 516 |
+
res = herme.hermeval(roots, pol)
|
| 517 |
+
tgt = 0
|
| 518 |
+
assert_(len(pol) == i + 1)
|
| 519 |
+
assert_almost_equal(herme.herme2poly(pol)[-1], 1)
|
| 520 |
+
assert_almost_equal(res, tgt)
|
| 521 |
+
|
| 522 |
+
def test_hermeroots(self):
|
| 523 |
+
assert_almost_equal(herme.hermeroots([1]), [])
|
| 524 |
+
assert_almost_equal(herme.hermeroots([1, 1]), [-1])
|
| 525 |
+
for i in range(2, 5):
|
| 526 |
+
tgt = np.linspace(-1, 1, i)
|
| 527 |
+
res = herme.hermeroots(herme.hermefromroots(tgt))
|
| 528 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 529 |
+
|
| 530 |
+
def test_hermetrim(self):
|
| 531 |
+
coef = [2, -1, 1, 0]
|
| 532 |
+
|
| 533 |
+
# Test exceptions
|
| 534 |
+
assert_raises(ValueError, herme.hermetrim, coef, -1)
|
| 535 |
+
|
| 536 |
+
# Test results
|
| 537 |
+
assert_equal(herme.hermetrim(coef), coef[:-1])
|
| 538 |
+
assert_equal(herme.hermetrim(coef, 1), coef[:-3])
|
| 539 |
+
assert_equal(herme.hermetrim(coef, 2), [0])
|
| 540 |
+
|
| 541 |
+
def test_hermeline(self):
|
| 542 |
+
assert_equal(herme.hermeline(3, 4), [3, 4])
|
| 543 |
+
|
| 544 |
+
def test_herme2poly(self):
|
| 545 |
+
for i in range(10):
|
| 546 |
+
assert_almost_equal(herme.herme2poly([0]*i + [1]), Helist[i])
|
| 547 |
+
|
| 548 |
+
def test_poly2herme(self):
|
| 549 |
+
for i in range(10):
|
| 550 |
+
assert_almost_equal(herme.poly2herme(Helist[i]), [0]*i + [1])
|
| 551 |
+
|
| 552 |
+
def test_weight(self):
|
| 553 |
+
x = np.linspace(-5, 5, 11)
|
| 554 |
+
tgt = np.exp(-.5*x**2)
|
| 555 |
+
res = herme.hermeweight(x)
|
| 556 |
+
assert_almost_equal(res, tgt)
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/polynomial/tests/test_polynomial.py
ADDED
|
@@ -0,0 +1,611 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Tests for polynomial module.
|
| 2 |
+
|
| 3 |
+
"""
|
| 4 |
+
from functools import reduce
|
| 5 |
+
|
| 6 |
+
import numpy as np
|
| 7 |
+
import numpy.polynomial.polynomial as poly
|
| 8 |
+
import pickle
|
| 9 |
+
from copy import deepcopy
|
| 10 |
+
from numpy.testing import (
|
| 11 |
+
assert_almost_equal, assert_raises, assert_equal, assert_,
|
| 12 |
+
assert_warns, assert_array_equal, assert_raises_regex)
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def trim(x):
|
| 16 |
+
return poly.polytrim(x, tol=1e-6)
|
| 17 |
+
|
| 18 |
+
T0 = [1]
|
| 19 |
+
T1 = [0, 1]
|
| 20 |
+
T2 = [-1, 0, 2]
|
| 21 |
+
T3 = [0, -3, 0, 4]
|
| 22 |
+
T4 = [1, 0, -8, 0, 8]
|
| 23 |
+
T5 = [0, 5, 0, -20, 0, 16]
|
| 24 |
+
T6 = [-1, 0, 18, 0, -48, 0, 32]
|
| 25 |
+
T7 = [0, -7, 0, 56, 0, -112, 0, 64]
|
| 26 |
+
T8 = [1, 0, -32, 0, 160, 0, -256, 0, 128]
|
| 27 |
+
T9 = [0, 9, 0, -120, 0, 432, 0, -576, 0, 256]
|
| 28 |
+
|
| 29 |
+
Tlist = [T0, T1, T2, T3, T4, T5, T6, T7, T8, T9]
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
class TestConstants:
|
| 33 |
+
|
| 34 |
+
def test_polydomain(self):
|
| 35 |
+
assert_equal(poly.polydomain, [-1, 1])
|
| 36 |
+
|
| 37 |
+
def test_polyzero(self):
|
| 38 |
+
assert_equal(poly.polyzero, [0])
|
| 39 |
+
|
| 40 |
+
def test_polyone(self):
|
| 41 |
+
assert_equal(poly.polyone, [1])
|
| 42 |
+
|
| 43 |
+
def test_polyx(self):
|
| 44 |
+
assert_equal(poly.polyx, [0, 1])
|
| 45 |
+
|
| 46 |
+
def test_copy(self):
|
| 47 |
+
x = poly.Polynomial([1, 2, 3])
|
| 48 |
+
y = deepcopy(x)
|
| 49 |
+
assert_equal(x, y)
|
| 50 |
+
|
| 51 |
+
def test_pickle(self):
|
| 52 |
+
x = poly.Polynomial([1, 2, 3])
|
| 53 |
+
y = pickle.loads(pickle.dumps(x))
|
| 54 |
+
assert_equal(x, y)
|
| 55 |
+
|
| 56 |
+
class TestArithmetic:
|
| 57 |
+
|
| 58 |
+
def test_polyadd(self):
|
| 59 |
+
for i in range(5):
|
| 60 |
+
for j in range(5):
|
| 61 |
+
msg = f"At i={i}, j={j}"
|
| 62 |
+
tgt = np.zeros(max(i, j) + 1)
|
| 63 |
+
tgt[i] += 1
|
| 64 |
+
tgt[j] += 1
|
| 65 |
+
res = poly.polyadd([0]*i + [1], [0]*j + [1])
|
| 66 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 67 |
+
|
| 68 |
+
def test_polysub(self):
|
| 69 |
+
for i in range(5):
|
| 70 |
+
for j in range(5):
|
| 71 |
+
msg = f"At i={i}, j={j}"
|
| 72 |
+
tgt = np.zeros(max(i, j) + 1)
|
| 73 |
+
tgt[i] += 1
|
| 74 |
+
tgt[j] -= 1
|
| 75 |
+
res = poly.polysub([0]*i + [1], [0]*j + [1])
|
| 76 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 77 |
+
|
| 78 |
+
def test_polymulx(self):
|
| 79 |
+
assert_equal(poly.polymulx([0]), [0])
|
| 80 |
+
assert_equal(poly.polymulx([1]), [0, 1])
|
| 81 |
+
for i in range(1, 5):
|
| 82 |
+
ser = [0]*i + [1]
|
| 83 |
+
tgt = [0]*(i + 1) + [1]
|
| 84 |
+
assert_equal(poly.polymulx(ser), tgt)
|
| 85 |
+
|
| 86 |
+
def test_polymul(self):
|
| 87 |
+
for i in range(5):
|
| 88 |
+
for j in range(5):
|
| 89 |
+
msg = f"At i={i}, j={j}"
|
| 90 |
+
tgt = np.zeros(i + j + 1)
|
| 91 |
+
tgt[i + j] += 1
|
| 92 |
+
res = poly.polymul([0]*i + [1], [0]*j + [1])
|
| 93 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 94 |
+
|
| 95 |
+
def test_polydiv(self):
|
| 96 |
+
# check zero division
|
| 97 |
+
assert_raises(ZeroDivisionError, poly.polydiv, [1], [0])
|
| 98 |
+
|
| 99 |
+
# check scalar division
|
| 100 |
+
quo, rem = poly.polydiv([2], [2])
|
| 101 |
+
assert_equal((quo, rem), (1, 0))
|
| 102 |
+
quo, rem = poly.polydiv([2, 2], [2])
|
| 103 |
+
assert_equal((quo, rem), ((1, 1), 0))
|
| 104 |
+
|
| 105 |
+
# check rest.
|
| 106 |
+
for i in range(5):
|
| 107 |
+
for j in range(5):
|
| 108 |
+
msg = f"At i={i}, j={j}"
|
| 109 |
+
ci = [0]*i + [1, 2]
|
| 110 |
+
cj = [0]*j + [1, 2]
|
| 111 |
+
tgt = poly.polyadd(ci, cj)
|
| 112 |
+
quo, rem = poly.polydiv(tgt, ci)
|
| 113 |
+
res = poly.polyadd(poly.polymul(quo, ci), rem)
|
| 114 |
+
assert_equal(res, tgt, err_msg=msg)
|
| 115 |
+
|
| 116 |
+
def test_polypow(self):
|
| 117 |
+
for i in range(5):
|
| 118 |
+
for j in range(5):
|
| 119 |
+
msg = f"At i={i}, j={j}"
|
| 120 |
+
c = np.arange(i + 1)
|
| 121 |
+
tgt = reduce(poly.polymul, [c]*j, np.array([1]))
|
| 122 |
+
res = poly.polypow(c, j)
|
| 123 |
+
assert_equal(trim(res), trim(tgt), err_msg=msg)
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
class TestEvaluation:
|
| 127 |
+
# coefficients of 1 + 2*x + 3*x**2
|
| 128 |
+
c1d = np.array([1., 2., 3.])
|
| 129 |
+
c2d = np.einsum('i,j->ij', c1d, c1d)
|
| 130 |
+
c3d = np.einsum('i,j,k->ijk', c1d, c1d, c1d)
|
| 131 |
+
|
| 132 |
+
# some random values in [-1, 1)
|
| 133 |
+
x = np.random.random((3, 5))*2 - 1
|
| 134 |
+
y = poly.polyval(x, [1., 2., 3.])
|
| 135 |
+
|
| 136 |
+
def test_polyval(self):
|
| 137 |
+
#check empty input
|
| 138 |
+
assert_equal(poly.polyval([], [1]).size, 0)
|
| 139 |
+
|
| 140 |
+
#check normal input)
|
| 141 |
+
x = np.linspace(-1, 1)
|
| 142 |
+
y = [x**i for i in range(5)]
|
| 143 |
+
for i in range(5):
|
| 144 |
+
tgt = y[i]
|
| 145 |
+
res = poly.polyval(x, [0]*i + [1])
|
| 146 |
+
assert_almost_equal(res, tgt)
|
| 147 |
+
tgt = x*(x**2 - 1)
|
| 148 |
+
res = poly.polyval(x, [0, -1, 0, 1])
|
| 149 |
+
assert_almost_equal(res, tgt)
|
| 150 |
+
|
| 151 |
+
#check that shape is preserved
|
| 152 |
+
for i in range(3):
|
| 153 |
+
dims = [2]*i
|
| 154 |
+
x = np.zeros(dims)
|
| 155 |
+
assert_equal(poly.polyval(x, [1]).shape, dims)
|
| 156 |
+
assert_equal(poly.polyval(x, [1, 0]).shape, dims)
|
| 157 |
+
assert_equal(poly.polyval(x, [1, 0, 0]).shape, dims)
|
| 158 |
+
|
| 159 |
+
#check masked arrays are processed correctly
|
| 160 |
+
mask = [False, True, False]
|
| 161 |
+
mx = np.ma.array([1, 2, 3], mask=mask)
|
| 162 |
+
res = np.polyval([7, 5, 3], mx)
|
| 163 |
+
assert_array_equal(res.mask, mask)
|
| 164 |
+
|
| 165 |
+
#check subtypes of ndarray are preserved
|
| 166 |
+
class C(np.ndarray):
|
| 167 |
+
pass
|
| 168 |
+
|
| 169 |
+
cx = np.array([1, 2, 3]).view(C)
|
| 170 |
+
assert_equal(type(np.polyval([2, 3, 4], cx)), C)
|
| 171 |
+
|
| 172 |
+
def test_polyvalfromroots(self):
|
| 173 |
+
# check exception for broadcasting x values over root array with
|
| 174 |
+
# too few dimensions
|
| 175 |
+
assert_raises(ValueError, poly.polyvalfromroots,
|
| 176 |
+
[1], [1], tensor=False)
|
| 177 |
+
|
| 178 |
+
# check empty input
|
| 179 |
+
assert_equal(poly.polyvalfromroots([], [1]).size, 0)
|
| 180 |
+
assert_(poly.polyvalfromroots([], [1]).shape == (0,))
|
| 181 |
+
|
| 182 |
+
# check empty input + multidimensional roots
|
| 183 |
+
assert_equal(poly.polyvalfromroots([], [[1] * 5]).size, 0)
|
| 184 |
+
assert_(poly.polyvalfromroots([], [[1] * 5]).shape == (5, 0))
|
| 185 |
+
|
| 186 |
+
# check scalar input
|
| 187 |
+
assert_equal(poly.polyvalfromroots(1, 1), 0)
|
| 188 |
+
assert_(poly.polyvalfromroots(1, np.ones((3, 3))).shape == (3,))
|
| 189 |
+
|
| 190 |
+
# check normal input)
|
| 191 |
+
x = np.linspace(-1, 1)
|
| 192 |
+
y = [x**i for i in range(5)]
|
| 193 |
+
for i in range(1, 5):
|
| 194 |
+
tgt = y[i]
|
| 195 |
+
res = poly.polyvalfromroots(x, [0]*i)
|
| 196 |
+
assert_almost_equal(res, tgt)
|
| 197 |
+
tgt = x*(x - 1)*(x + 1)
|
| 198 |
+
res = poly.polyvalfromroots(x, [-1, 0, 1])
|
| 199 |
+
assert_almost_equal(res, tgt)
|
| 200 |
+
|
| 201 |
+
# check that shape is preserved
|
| 202 |
+
for i in range(3):
|
| 203 |
+
dims = [2]*i
|
| 204 |
+
x = np.zeros(dims)
|
| 205 |
+
assert_equal(poly.polyvalfromroots(x, [1]).shape, dims)
|
| 206 |
+
assert_equal(poly.polyvalfromroots(x, [1, 0]).shape, dims)
|
| 207 |
+
assert_equal(poly.polyvalfromroots(x, [1, 0, 0]).shape, dims)
|
| 208 |
+
|
| 209 |
+
# check compatibility with factorization
|
| 210 |
+
ptest = [15, 2, -16, -2, 1]
|
| 211 |
+
r = poly.polyroots(ptest)
|
| 212 |
+
x = np.linspace(-1, 1)
|
| 213 |
+
assert_almost_equal(poly.polyval(x, ptest),
|
| 214 |
+
poly.polyvalfromroots(x, r))
|
| 215 |
+
|
| 216 |
+
# check multidimensional arrays of roots and values
|
| 217 |
+
# check tensor=False
|
| 218 |
+
rshape = (3, 5)
|
| 219 |
+
x = np.arange(-3, 2)
|
| 220 |
+
r = np.random.randint(-5, 5, size=rshape)
|
| 221 |
+
res = poly.polyvalfromroots(x, r, tensor=False)
|
| 222 |
+
tgt = np.empty(r.shape[1:])
|
| 223 |
+
for ii in range(tgt.size):
|
| 224 |
+
tgt[ii] = poly.polyvalfromroots(x[ii], r[:, ii])
|
| 225 |
+
assert_equal(res, tgt)
|
| 226 |
+
|
| 227 |
+
# check tensor=True
|
| 228 |
+
x = np.vstack([x, 2*x])
|
| 229 |
+
res = poly.polyvalfromroots(x, r, tensor=True)
|
| 230 |
+
tgt = np.empty(r.shape[1:] + x.shape)
|
| 231 |
+
for ii in range(r.shape[1]):
|
| 232 |
+
for jj in range(x.shape[0]):
|
| 233 |
+
tgt[ii, jj, :] = poly.polyvalfromroots(x[jj], r[:, ii])
|
| 234 |
+
assert_equal(res, tgt)
|
| 235 |
+
|
| 236 |
+
def test_polyval2d(self):
|
| 237 |
+
x1, x2, x3 = self.x
|
| 238 |
+
y1, y2, y3 = self.y
|
| 239 |
+
|
| 240 |
+
#test exceptions
|
| 241 |
+
assert_raises_regex(ValueError, 'incompatible',
|
| 242 |
+
poly.polyval2d, x1, x2[:2], self.c2d)
|
| 243 |
+
|
| 244 |
+
#test values
|
| 245 |
+
tgt = y1*y2
|
| 246 |
+
res = poly.polyval2d(x1, x2, self.c2d)
|
| 247 |
+
assert_almost_equal(res, tgt)
|
| 248 |
+
|
| 249 |
+
#test shape
|
| 250 |
+
z = np.ones((2, 3))
|
| 251 |
+
res = poly.polyval2d(z, z, self.c2d)
|
| 252 |
+
assert_(res.shape == (2, 3))
|
| 253 |
+
|
| 254 |
+
def test_polyval3d(self):
|
| 255 |
+
x1, x2, x3 = self.x
|
| 256 |
+
y1, y2, y3 = self.y
|
| 257 |
+
|
| 258 |
+
#test exceptions
|
| 259 |
+
assert_raises_regex(ValueError, 'incompatible',
|
| 260 |
+
poly.polyval3d, x1, x2, x3[:2], self.c3d)
|
| 261 |
+
|
| 262 |
+
#test values
|
| 263 |
+
tgt = y1*y2*y3
|
| 264 |
+
res = poly.polyval3d(x1, x2, x3, self.c3d)
|
| 265 |
+
assert_almost_equal(res, tgt)
|
| 266 |
+
|
| 267 |
+
#test shape
|
| 268 |
+
z = np.ones((2, 3))
|
| 269 |
+
res = poly.polyval3d(z, z, z, self.c3d)
|
| 270 |
+
assert_(res.shape == (2, 3))
|
| 271 |
+
|
| 272 |
+
def test_polygrid2d(self):
|
| 273 |
+
x1, x2, x3 = self.x
|
| 274 |
+
y1, y2, y3 = self.y
|
| 275 |
+
|
| 276 |
+
#test values
|
| 277 |
+
tgt = np.einsum('i,j->ij', y1, y2)
|
| 278 |
+
res = poly.polygrid2d(x1, x2, self.c2d)
|
| 279 |
+
assert_almost_equal(res, tgt)
|
| 280 |
+
|
| 281 |
+
#test shape
|
| 282 |
+
z = np.ones((2, 3))
|
| 283 |
+
res = poly.polygrid2d(z, z, self.c2d)
|
| 284 |
+
assert_(res.shape == (2, 3)*2)
|
| 285 |
+
|
| 286 |
+
def test_polygrid3d(self):
|
| 287 |
+
x1, x2, x3 = self.x
|
| 288 |
+
y1, y2, y3 = self.y
|
| 289 |
+
|
| 290 |
+
#test values
|
| 291 |
+
tgt = np.einsum('i,j,k->ijk', y1, y2, y3)
|
| 292 |
+
res = poly.polygrid3d(x1, x2, x3, self.c3d)
|
| 293 |
+
assert_almost_equal(res, tgt)
|
| 294 |
+
|
| 295 |
+
#test shape
|
| 296 |
+
z = np.ones((2, 3))
|
| 297 |
+
res = poly.polygrid3d(z, z, z, self.c3d)
|
| 298 |
+
assert_(res.shape == (2, 3)*3)
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
class TestIntegral:
|
| 302 |
+
|
| 303 |
+
def test_polyint(self):
|
| 304 |
+
# check exceptions
|
| 305 |
+
assert_raises(TypeError, poly.polyint, [0], .5)
|
| 306 |
+
assert_raises(ValueError, poly.polyint, [0], -1)
|
| 307 |
+
assert_raises(ValueError, poly.polyint, [0], 1, [0, 0])
|
| 308 |
+
assert_raises(ValueError, poly.polyint, [0], lbnd=[0])
|
| 309 |
+
assert_raises(ValueError, poly.polyint, [0], scl=[0])
|
| 310 |
+
assert_raises(TypeError, poly.polyint, [0], axis=.5)
|
| 311 |
+
with assert_warns(DeprecationWarning):
|
| 312 |
+
poly.polyint([1, 1], 1.)
|
| 313 |
+
|
| 314 |
+
# test integration of zero polynomial
|
| 315 |
+
for i in range(2, 5):
|
| 316 |
+
k = [0]*(i - 2) + [1]
|
| 317 |
+
res = poly.polyint([0], m=i, k=k)
|
| 318 |
+
assert_almost_equal(res, [0, 1])
|
| 319 |
+
|
| 320 |
+
# check single integration with integration constant
|
| 321 |
+
for i in range(5):
|
| 322 |
+
scl = i + 1
|
| 323 |
+
pol = [0]*i + [1]
|
| 324 |
+
tgt = [i] + [0]*i + [1/scl]
|
| 325 |
+
res = poly.polyint(pol, m=1, k=[i])
|
| 326 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 327 |
+
|
| 328 |
+
# check single integration with integration constant and lbnd
|
| 329 |
+
for i in range(5):
|
| 330 |
+
scl = i + 1
|
| 331 |
+
pol = [0]*i + [1]
|
| 332 |
+
res = poly.polyint(pol, m=1, k=[i], lbnd=-1)
|
| 333 |
+
assert_almost_equal(poly.polyval(-1, res), i)
|
| 334 |
+
|
| 335 |
+
# check single integration with integration constant and scaling
|
| 336 |
+
for i in range(5):
|
| 337 |
+
scl = i + 1
|
| 338 |
+
pol = [0]*i + [1]
|
| 339 |
+
tgt = [i] + [0]*i + [2/scl]
|
| 340 |
+
res = poly.polyint(pol, m=1, k=[i], scl=2)
|
| 341 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 342 |
+
|
| 343 |
+
# check multiple integrations with default k
|
| 344 |
+
for i in range(5):
|
| 345 |
+
for j in range(2, 5):
|
| 346 |
+
pol = [0]*i + [1]
|
| 347 |
+
tgt = pol[:]
|
| 348 |
+
for k in range(j):
|
| 349 |
+
tgt = poly.polyint(tgt, m=1)
|
| 350 |
+
res = poly.polyint(pol, m=j)
|
| 351 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 352 |
+
|
| 353 |
+
# check multiple integrations with defined k
|
| 354 |
+
for i in range(5):
|
| 355 |
+
for j in range(2, 5):
|
| 356 |
+
pol = [0]*i + [1]
|
| 357 |
+
tgt = pol[:]
|
| 358 |
+
for k in range(j):
|
| 359 |
+
tgt = poly.polyint(tgt, m=1, k=[k])
|
| 360 |
+
res = poly.polyint(pol, m=j, k=list(range(j)))
|
| 361 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 362 |
+
|
| 363 |
+
# check multiple integrations with lbnd
|
| 364 |
+
for i in range(5):
|
| 365 |
+
for j in range(2, 5):
|
| 366 |
+
pol = [0]*i + [1]
|
| 367 |
+
tgt = pol[:]
|
| 368 |
+
for k in range(j):
|
| 369 |
+
tgt = poly.polyint(tgt, m=1, k=[k], lbnd=-1)
|
| 370 |
+
res = poly.polyint(pol, m=j, k=list(range(j)), lbnd=-1)
|
| 371 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 372 |
+
|
| 373 |
+
# check multiple integrations with scaling
|
| 374 |
+
for i in range(5):
|
| 375 |
+
for j in range(2, 5):
|
| 376 |
+
pol = [0]*i + [1]
|
| 377 |
+
tgt = pol[:]
|
| 378 |
+
for k in range(j):
|
| 379 |
+
tgt = poly.polyint(tgt, m=1, k=[k], scl=2)
|
| 380 |
+
res = poly.polyint(pol, m=j, k=list(range(j)), scl=2)
|
| 381 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 382 |
+
|
| 383 |
+
def test_polyint_axis(self):
|
| 384 |
+
# check that axis keyword works
|
| 385 |
+
c2d = np.random.random((3, 4))
|
| 386 |
+
|
| 387 |
+
tgt = np.vstack([poly.polyint(c) for c in c2d.T]).T
|
| 388 |
+
res = poly.polyint(c2d, axis=0)
|
| 389 |
+
assert_almost_equal(res, tgt)
|
| 390 |
+
|
| 391 |
+
tgt = np.vstack([poly.polyint(c) for c in c2d])
|
| 392 |
+
res = poly.polyint(c2d, axis=1)
|
| 393 |
+
assert_almost_equal(res, tgt)
|
| 394 |
+
|
| 395 |
+
tgt = np.vstack([poly.polyint(c, k=3) for c in c2d])
|
| 396 |
+
res = poly.polyint(c2d, k=3, axis=1)
|
| 397 |
+
assert_almost_equal(res, tgt)
|
| 398 |
+
|
| 399 |
+
|
| 400 |
+
class TestDerivative:
|
| 401 |
+
|
| 402 |
+
def test_polyder(self):
|
| 403 |
+
# check exceptions
|
| 404 |
+
assert_raises(TypeError, poly.polyder, [0], .5)
|
| 405 |
+
assert_raises(ValueError, poly.polyder, [0], -1)
|
| 406 |
+
|
| 407 |
+
# check that zeroth derivative does nothing
|
| 408 |
+
for i in range(5):
|
| 409 |
+
tgt = [0]*i + [1]
|
| 410 |
+
res = poly.polyder(tgt, m=0)
|
| 411 |
+
assert_equal(trim(res), trim(tgt))
|
| 412 |
+
|
| 413 |
+
# check that derivation is the inverse of integration
|
| 414 |
+
for i in range(5):
|
| 415 |
+
for j in range(2, 5):
|
| 416 |
+
tgt = [0]*i + [1]
|
| 417 |
+
res = poly.polyder(poly.polyint(tgt, m=j), m=j)
|
| 418 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 419 |
+
|
| 420 |
+
# check derivation with scaling
|
| 421 |
+
for i in range(5):
|
| 422 |
+
for j in range(2, 5):
|
| 423 |
+
tgt = [0]*i + [1]
|
| 424 |
+
res = poly.polyder(poly.polyint(tgt, m=j, scl=2), m=j, scl=.5)
|
| 425 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 426 |
+
|
| 427 |
+
def test_polyder_axis(self):
|
| 428 |
+
# check that axis keyword works
|
| 429 |
+
c2d = np.random.random((3, 4))
|
| 430 |
+
|
| 431 |
+
tgt = np.vstack([poly.polyder(c) for c in c2d.T]).T
|
| 432 |
+
res = poly.polyder(c2d, axis=0)
|
| 433 |
+
assert_almost_equal(res, tgt)
|
| 434 |
+
|
| 435 |
+
tgt = np.vstack([poly.polyder(c) for c in c2d])
|
| 436 |
+
res = poly.polyder(c2d, axis=1)
|
| 437 |
+
assert_almost_equal(res, tgt)
|
| 438 |
+
|
| 439 |
+
|
| 440 |
+
class TestVander:
|
| 441 |
+
# some random values in [-1, 1)
|
| 442 |
+
x = np.random.random((3, 5))*2 - 1
|
| 443 |
+
|
| 444 |
+
def test_polyvander(self):
|
| 445 |
+
# check for 1d x
|
| 446 |
+
x = np.arange(3)
|
| 447 |
+
v = poly.polyvander(x, 3)
|
| 448 |
+
assert_(v.shape == (3, 4))
|
| 449 |
+
for i in range(4):
|
| 450 |
+
coef = [0]*i + [1]
|
| 451 |
+
assert_almost_equal(v[..., i], poly.polyval(x, coef))
|
| 452 |
+
|
| 453 |
+
# check for 2d x
|
| 454 |
+
x = np.array([[1, 2], [3, 4], [5, 6]])
|
| 455 |
+
v = poly.polyvander(x, 3)
|
| 456 |
+
assert_(v.shape == (3, 2, 4))
|
| 457 |
+
for i in range(4):
|
| 458 |
+
coef = [0]*i + [1]
|
| 459 |
+
assert_almost_equal(v[..., i], poly.polyval(x, coef))
|
| 460 |
+
|
| 461 |
+
def test_polyvander2d(self):
|
| 462 |
+
# also tests polyval2d for non-square coefficient array
|
| 463 |
+
x1, x2, x3 = self.x
|
| 464 |
+
c = np.random.random((2, 3))
|
| 465 |
+
van = poly.polyvander2d(x1, x2, [1, 2])
|
| 466 |
+
tgt = poly.polyval2d(x1, x2, c)
|
| 467 |
+
res = np.dot(van, c.flat)
|
| 468 |
+
assert_almost_equal(res, tgt)
|
| 469 |
+
|
| 470 |
+
# check shape
|
| 471 |
+
van = poly.polyvander2d([x1], [x2], [1, 2])
|
| 472 |
+
assert_(van.shape == (1, 5, 6))
|
| 473 |
+
|
| 474 |
+
def test_polyvander3d(self):
|
| 475 |
+
# also tests polyval3d for non-square coefficient array
|
| 476 |
+
x1, x2, x3 = self.x
|
| 477 |
+
c = np.random.random((2, 3, 4))
|
| 478 |
+
van = poly.polyvander3d(x1, x2, x3, [1, 2, 3])
|
| 479 |
+
tgt = poly.polyval3d(x1, x2, x3, c)
|
| 480 |
+
res = np.dot(van, c.flat)
|
| 481 |
+
assert_almost_equal(res, tgt)
|
| 482 |
+
|
| 483 |
+
# check shape
|
| 484 |
+
van = poly.polyvander3d([x1], [x2], [x3], [1, 2, 3])
|
| 485 |
+
assert_(van.shape == (1, 5, 24))
|
| 486 |
+
|
| 487 |
+
def test_polyvandernegdeg(self):
|
| 488 |
+
x = np.arange(3)
|
| 489 |
+
assert_raises(ValueError, poly.polyvander, x, -1)
|
| 490 |
+
|
| 491 |
+
|
| 492 |
+
class TestCompanion:
|
| 493 |
+
|
| 494 |
+
def test_raises(self):
|
| 495 |
+
assert_raises(ValueError, poly.polycompanion, [])
|
| 496 |
+
assert_raises(ValueError, poly.polycompanion, [1])
|
| 497 |
+
|
| 498 |
+
def test_dimensions(self):
|
| 499 |
+
for i in range(1, 5):
|
| 500 |
+
coef = [0]*i + [1]
|
| 501 |
+
assert_(poly.polycompanion(coef).shape == (i, i))
|
| 502 |
+
|
| 503 |
+
def test_linear_root(self):
|
| 504 |
+
assert_(poly.polycompanion([1, 2])[0, 0] == -.5)
|
| 505 |
+
|
| 506 |
+
|
| 507 |
+
class TestMisc:
|
| 508 |
+
|
| 509 |
+
def test_polyfromroots(self):
|
| 510 |
+
res = poly.polyfromroots([])
|
| 511 |
+
assert_almost_equal(trim(res), [1])
|
| 512 |
+
for i in range(1, 5):
|
| 513 |
+
roots = np.cos(np.linspace(-np.pi, 0, 2*i + 1)[1::2])
|
| 514 |
+
tgt = Tlist[i]
|
| 515 |
+
res = poly.polyfromroots(roots)*2**(i-1)
|
| 516 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 517 |
+
|
| 518 |
+
def test_polyroots(self):
|
| 519 |
+
assert_almost_equal(poly.polyroots([1]), [])
|
| 520 |
+
assert_almost_equal(poly.polyroots([1, 2]), [-.5])
|
| 521 |
+
for i in range(2, 5):
|
| 522 |
+
tgt = np.linspace(-1, 1, i)
|
| 523 |
+
res = poly.polyroots(poly.polyfromroots(tgt))
|
| 524 |
+
assert_almost_equal(trim(res), trim(tgt))
|
| 525 |
+
|
| 526 |
+
def test_polyfit(self):
|
| 527 |
+
def f(x):
|
| 528 |
+
return x*(x - 1)*(x - 2)
|
| 529 |
+
|
| 530 |
+
def f2(x):
|
| 531 |
+
return x**4 + x**2 + 1
|
| 532 |
+
|
| 533 |
+
# Test exceptions
|
| 534 |
+
assert_raises(ValueError, poly.polyfit, [1], [1], -1)
|
| 535 |
+
assert_raises(TypeError, poly.polyfit, [[1]], [1], 0)
|
| 536 |
+
assert_raises(TypeError, poly.polyfit, [], [1], 0)
|
| 537 |
+
assert_raises(TypeError, poly.polyfit, [1], [[[1]]], 0)
|
| 538 |
+
assert_raises(TypeError, poly.polyfit, [1, 2], [1], 0)
|
| 539 |
+
assert_raises(TypeError, poly.polyfit, [1], [1, 2], 0)
|
| 540 |
+
assert_raises(TypeError, poly.polyfit, [1], [1], 0, w=[[1]])
|
| 541 |
+
assert_raises(TypeError, poly.polyfit, [1], [1], 0, w=[1, 1])
|
| 542 |
+
assert_raises(ValueError, poly.polyfit, [1], [1], [-1,])
|
| 543 |
+
assert_raises(ValueError, poly.polyfit, [1], [1], [2, -1, 6])
|
| 544 |
+
assert_raises(TypeError, poly.polyfit, [1], [1], [])
|
| 545 |
+
|
| 546 |
+
# Test fit
|
| 547 |
+
x = np.linspace(0, 2)
|
| 548 |
+
y = f(x)
|
| 549 |
+
#
|
| 550 |
+
coef3 = poly.polyfit(x, y, 3)
|
| 551 |
+
assert_equal(len(coef3), 4)
|
| 552 |
+
assert_almost_equal(poly.polyval(x, coef3), y)
|
| 553 |
+
coef3 = poly.polyfit(x, y, [0, 1, 2, 3])
|
| 554 |
+
assert_equal(len(coef3), 4)
|
| 555 |
+
assert_almost_equal(poly.polyval(x, coef3), y)
|
| 556 |
+
#
|
| 557 |
+
coef4 = poly.polyfit(x, y, 4)
|
| 558 |
+
assert_equal(len(coef4), 5)
|
| 559 |
+
assert_almost_equal(poly.polyval(x, coef4), y)
|
| 560 |
+
coef4 = poly.polyfit(x, y, [0, 1, 2, 3, 4])
|
| 561 |
+
assert_equal(len(coef4), 5)
|
| 562 |
+
assert_almost_equal(poly.polyval(x, coef4), y)
|
| 563 |
+
#
|
| 564 |
+
coef2d = poly.polyfit(x, np.array([y, y]).T, 3)
|
| 565 |
+
assert_almost_equal(coef2d, np.array([coef3, coef3]).T)
|
| 566 |
+
coef2d = poly.polyfit(x, np.array([y, y]).T, [0, 1, 2, 3])
|
| 567 |
+
assert_almost_equal(coef2d, np.array([coef3, coef3]).T)
|
| 568 |
+
# test weighting
|
| 569 |
+
w = np.zeros_like(x)
|
| 570 |
+
yw = y.copy()
|
| 571 |
+
w[1::2] = 1
|
| 572 |
+
yw[0::2] = 0
|
| 573 |
+
wcoef3 = poly.polyfit(x, yw, 3, w=w)
|
| 574 |
+
assert_almost_equal(wcoef3, coef3)
|
| 575 |
+
wcoef3 = poly.polyfit(x, yw, [0, 1, 2, 3], w=w)
|
| 576 |
+
assert_almost_equal(wcoef3, coef3)
|
| 577 |
+
#
|
| 578 |
+
wcoef2d = poly.polyfit(x, np.array([yw, yw]).T, 3, w=w)
|
| 579 |
+
assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T)
|
| 580 |
+
wcoef2d = poly.polyfit(x, np.array([yw, yw]).T, [0, 1, 2, 3], w=w)
|
| 581 |
+
assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T)
|
| 582 |
+
# test scaling with complex values x points whose square
|
| 583 |
+
# is zero when summed.
|
| 584 |
+
x = [1, 1j, -1, -1j]
|
| 585 |
+
assert_almost_equal(poly.polyfit(x, x, 1), [0, 1])
|
| 586 |
+
assert_almost_equal(poly.polyfit(x, x, [0, 1]), [0, 1])
|
| 587 |
+
# test fitting only even Polyendre polynomials
|
| 588 |
+
x = np.linspace(-1, 1)
|
| 589 |
+
y = f2(x)
|
| 590 |
+
coef1 = poly.polyfit(x, y, 4)
|
| 591 |
+
assert_almost_equal(poly.polyval(x, coef1), y)
|
| 592 |
+
coef2 = poly.polyfit(x, y, [0, 2, 4])
|
| 593 |
+
assert_almost_equal(poly.polyval(x, coef2), y)
|
| 594 |
+
assert_almost_equal(coef1, coef2)
|
| 595 |
+
|
| 596 |
+
def test_polytrim(self):
|
| 597 |
+
coef = [2, -1, 1, 0]
|
| 598 |
+
|
| 599 |
+
# Test exceptions
|
| 600 |
+
assert_raises(ValueError, poly.polytrim, coef, -1)
|
| 601 |
+
|
| 602 |
+
# Test results
|
| 603 |
+
assert_equal(poly.polytrim(coef), coef[:-1])
|
| 604 |
+
assert_equal(poly.polytrim(coef, 1), coef[:-3])
|
| 605 |
+
assert_equal(poly.polytrim(coef, 2), [0])
|
| 606 |
+
|
| 607 |
+
def test_polyline(self):
|
| 608 |
+
assert_equal(poly.polyline(3, 4), [3, 4])
|
| 609 |
+
|
| 610 |
+
def test_polyline_zero(self):
|
| 611 |
+
assert_equal(poly.polyline(3, 0), [3])
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/testing/print_coercion_tables.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Prints type-coercion tables for the built-in NumPy types
|
| 3 |
+
|
| 4 |
+
"""
|
| 5 |
+
import numpy as np
|
| 6 |
+
from collections import namedtuple
|
| 7 |
+
|
| 8 |
+
# Generic object that can be added, but doesn't do anything else
|
| 9 |
+
class GenericObject:
|
| 10 |
+
def __init__(self, v):
|
| 11 |
+
self.v = v
|
| 12 |
+
|
| 13 |
+
def __add__(self, other):
|
| 14 |
+
return self
|
| 15 |
+
|
| 16 |
+
def __radd__(self, other):
|
| 17 |
+
return self
|
| 18 |
+
|
| 19 |
+
dtype = np.dtype('O')
|
| 20 |
+
|
| 21 |
+
def print_cancast_table(ntypes):
|
| 22 |
+
print('X', end=' ')
|
| 23 |
+
for char in ntypes:
|
| 24 |
+
print(char, end=' ')
|
| 25 |
+
print()
|
| 26 |
+
for row in ntypes:
|
| 27 |
+
print(row, end=' ')
|
| 28 |
+
for col in ntypes:
|
| 29 |
+
if np.can_cast(row, col, "equiv"):
|
| 30 |
+
cast = "#"
|
| 31 |
+
elif np.can_cast(row, col, "safe"):
|
| 32 |
+
cast = "="
|
| 33 |
+
elif np.can_cast(row, col, "same_kind"):
|
| 34 |
+
cast = "~"
|
| 35 |
+
elif np.can_cast(row, col, "unsafe"):
|
| 36 |
+
cast = "."
|
| 37 |
+
else:
|
| 38 |
+
cast = " "
|
| 39 |
+
print(cast, end=' ')
|
| 40 |
+
print()
|
| 41 |
+
|
| 42 |
+
def print_coercion_table(ntypes, inputfirstvalue, inputsecondvalue, firstarray, use_promote_types=False):
|
| 43 |
+
print('+', end=' ')
|
| 44 |
+
for char in ntypes:
|
| 45 |
+
print(char, end=' ')
|
| 46 |
+
print()
|
| 47 |
+
for row in ntypes:
|
| 48 |
+
if row == 'O':
|
| 49 |
+
rowtype = GenericObject
|
| 50 |
+
else:
|
| 51 |
+
rowtype = np.obj2sctype(row)
|
| 52 |
+
|
| 53 |
+
print(row, end=' ')
|
| 54 |
+
for col in ntypes:
|
| 55 |
+
if col == 'O':
|
| 56 |
+
coltype = GenericObject
|
| 57 |
+
else:
|
| 58 |
+
coltype = np.obj2sctype(col)
|
| 59 |
+
try:
|
| 60 |
+
if firstarray:
|
| 61 |
+
rowvalue = np.array([rowtype(inputfirstvalue)], dtype=rowtype)
|
| 62 |
+
else:
|
| 63 |
+
rowvalue = rowtype(inputfirstvalue)
|
| 64 |
+
colvalue = coltype(inputsecondvalue)
|
| 65 |
+
if use_promote_types:
|
| 66 |
+
char = np.promote_types(rowvalue.dtype, colvalue.dtype).char
|
| 67 |
+
else:
|
| 68 |
+
value = np.add(rowvalue, colvalue)
|
| 69 |
+
if isinstance(value, np.ndarray):
|
| 70 |
+
char = value.dtype.char
|
| 71 |
+
else:
|
| 72 |
+
char = np.dtype(type(value)).char
|
| 73 |
+
except ValueError:
|
| 74 |
+
char = '!'
|
| 75 |
+
except OverflowError:
|
| 76 |
+
char = '@'
|
| 77 |
+
except TypeError:
|
| 78 |
+
char = '#'
|
| 79 |
+
print(char, end=' ')
|
| 80 |
+
print()
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def print_new_cast_table(*, can_cast=True, legacy=False, flags=False):
|
| 84 |
+
"""Prints new casts, the values given are default "can-cast" values, not
|
| 85 |
+
actual ones.
|
| 86 |
+
"""
|
| 87 |
+
from numpy.core._multiarray_tests import get_all_cast_information
|
| 88 |
+
|
| 89 |
+
cast_table = {
|
| 90 |
+
-1: " ",
|
| 91 |
+
0: "#", # No cast (classify as equivalent here)
|
| 92 |
+
1: "#", # equivalent casting
|
| 93 |
+
2: "=", # safe casting
|
| 94 |
+
3: "~", # same-kind casting
|
| 95 |
+
4: ".", # unsafe casting
|
| 96 |
+
}
|
| 97 |
+
flags_table = {
|
| 98 |
+
0 : "▗", 7: "█",
|
| 99 |
+
1: "▚", 2: "▐", 4: "▄",
|
| 100 |
+
3: "▜", 5: "▙",
|
| 101 |
+
6: "▟",
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
cast_info = namedtuple("cast_info", ["can_cast", "legacy", "flags"])
|
| 105 |
+
no_cast_info = cast_info(" ", " ", " ")
|
| 106 |
+
|
| 107 |
+
casts = get_all_cast_information()
|
| 108 |
+
table = {}
|
| 109 |
+
dtypes = set()
|
| 110 |
+
for cast in casts:
|
| 111 |
+
dtypes.add(cast["from"])
|
| 112 |
+
dtypes.add(cast["to"])
|
| 113 |
+
|
| 114 |
+
if cast["from"] not in table:
|
| 115 |
+
table[cast["from"]] = {}
|
| 116 |
+
to_dict = table[cast["from"]]
|
| 117 |
+
|
| 118 |
+
can_cast = cast_table[cast["casting"]]
|
| 119 |
+
legacy = "L" if cast["legacy"] else "."
|
| 120 |
+
flags = 0
|
| 121 |
+
if cast["requires_pyapi"]:
|
| 122 |
+
flags |= 1
|
| 123 |
+
if cast["supports_unaligned"]:
|
| 124 |
+
flags |= 2
|
| 125 |
+
if cast["no_floatingpoint_errors"]:
|
| 126 |
+
flags |= 4
|
| 127 |
+
|
| 128 |
+
flags = flags_table[flags]
|
| 129 |
+
to_dict[cast["to"]] = cast_info(can_cast=can_cast, legacy=legacy, flags=flags)
|
| 130 |
+
|
| 131 |
+
# The np.dtype(x.type) is a bit strange, because dtype classes do
|
| 132 |
+
# not expose much yet.
|
| 133 |
+
types = np.typecodes["All"]
|
| 134 |
+
def sorter(x):
|
| 135 |
+
# This is a bit weird hack, to get a table as close as possible to
|
| 136 |
+
# the one printing all typecodes (but expecting user-dtypes).
|
| 137 |
+
dtype = np.dtype(x.type)
|
| 138 |
+
try:
|
| 139 |
+
indx = types.index(dtype.char)
|
| 140 |
+
except ValueError:
|
| 141 |
+
indx = np.inf
|
| 142 |
+
return (indx, dtype.char)
|
| 143 |
+
|
| 144 |
+
dtypes = sorted(dtypes, key=sorter)
|
| 145 |
+
|
| 146 |
+
def print_table(field="can_cast"):
|
| 147 |
+
print('X', end=' ')
|
| 148 |
+
for dt in dtypes:
|
| 149 |
+
print(np.dtype(dt.type).char, end=' ')
|
| 150 |
+
print()
|
| 151 |
+
for from_dt in dtypes:
|
| 152 |
+
print(np.dtype(from_dt.type).char, end=' ')
|
| 153 |
+
row = table.get(from_dt, {})
|
| 154 |
+
for to_dt in dtypes:
|
| 155 |
+
print(getattr(row.get(to_dt, no_cast_info), field), end=' ')
|
| 156 |
+
print()
|
| 157 |
+
|
| 158 |
+
if can_cast:
|
| 159 |
+
# Print the actual table:
|
| 160 |
+
print()
|
| 161 |
+
print("Casting: # is equivalent, = is safe, ~ is same-kind, and . is unsafe")
|
| 162 |
+
print()
|
| 163 |
+
print_table("can_cast")
|
| 164 |
+
|
| 165 |
+
if legacy:
|
| 166 |
+
print()
|
| 167 |
+
print("L denotes a legacy cast . a non-legacy one.")
|
| 168 |
+
print()
|
| 169 |
+
print_table("legacy")
|
| 170 |
+
|
| 171 |
+
if flags:
|
| 172 |
+
print()
|
| 173 |
+
print(f"{flags_table[0]}: no flags, {flags_table[1]}: PyAPI, "
|
| 174 |
+
f"{flags_table[2]}: supports unaligned, {flags_table[4]}: no-float-errors")
|
| 175 |
+
print()
|
| 176 |
+
print_table("flags")
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
if __name__ == '__main__':
|
| 180 |
+
print("can cast")
|
| 181 |
+
print_cancast_table(np.typecodes['All'])
|
| 182 |
+
print()
|
| 183 |
+
print("In these tables, ValueError is '!', OverflowError is '@', TypeError is '#'")
|
| 184 |
+
print()
|
| 185 |
+
print("scalar + scalar")
|
| 186 |
+
print_coercion_table(np.typecodes['All'], 0, 0, False)
|
| 187 |
+
print()
|
| 188 |
+
print("scalar + neg scalar")
|
| 189 |
+
print_coercion_table(np.typecodes['All'], 0, -1, False)
|
| 190 |
+
print()
|
| 191 |
+
print("array + scalar")
|
| 192 |
+
print_coercion_table(np.typecodes['All'], 0, 0, True)
|
| 193 |
+
print()
|
| 194 |
+
print("array + neg scalar")
|
| 195 |
+
print_coercion_table(np.typecodes['All'], 0, -1, True)
|
| 196 |
+
print()
|
| 197 |
+
print("promote_types")
|
| 198 |
+
print_coercion_table(np.typecodes['All'], 0, 0, False, True)
|
| 199 |
+
print("New casting type promotion:")
|
| 200 |
+
print_new_cast_table(can_cast=True, legacy=True, flags=True)
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/conditional_detr/image_processing_conditional_detr.py
ADDED
|
@@ -0,0 +1,1083 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/conditional_detr/modular_conditional_detr.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_conditional_detr.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2022 Microsoft Research Asia and The HuggingFace Inc. team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 10 |
+
# you may not use this file except in compliance with the License.
|
| 11 |
+
# You may obtain a copy of the License at
|
| 12 |
+
#
|
| 13 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 14 |
+
#
|
| 15 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 16 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 17 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 18 |
+
# See the License for the specific language governing permissions and
|
| 19 |
+
# limitations under the License.
|
| 20 |
+
|
| 21 |
+
import pathlib
|
| 22 |
+
from typing import Any, Optional
|
| 23 |
+
|
| 24 |
+
import numpy as np
|
| 25 |
+
import torch
|
| 26 |
+
from torch import nn
|
| 27 |
+
from torchvision.io import read_image
|
| 28 |
+
from torchvision.transforms.v2 import functional as tvF
|
| 29 |
+
|
| 30 |
+
from ...image_processing_backends import TorchvisionBackend
|
| 31 |
+
from ...image_processing_utils import BatchFeature, get_size_dict
|
| 32 |
+
from ...image_transforms import (
|
| 33 |
+
center_to_corners_format,
|
| 34 |
+
corners_to_center_format,
|
| 35 |
+
get_size_with_aspect_ratio,
|
| 36 |
+
safe_squeeze,
|
| 37 |
+
)
|
| 38 |
+
from ...image_utils import (
|
| 39 |
+
IMAGENET_DEFAULT_MEAN,
|
| 40 |
+
IMAGENET_DEFAULT_STD,
|
| 41 |
+
AnnotationFormat,
|
| 42 |
+
AnnotationType,
|
| 43 |
+
ChannelDimension,
|
| 44 |
+
ImageInput,
|
| 45 |
+
PILImageResampling,
|
| 46 |
+
SizeDict,
|
| 47 |
+
get_image_size,
|
| 48 |
+
get_image_size_for_max_height_width,
|
| 49 |
+
get_max_height_width,
|
| 50 |
+
validate_annotations,
|
| 51 |
+
)
|
| 52 |
+
from ...processing_utils import ImagesKwargs, Unpack
|
| 53 |
+
from ...utils import TensorType, auto_docstring, logging
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
logger = logging.get_logger(__name__)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
class ConditionalDetrImageProcessorKwargs(ImagesKwargs, total=False):
|
| 60 |
+
r"""
|
| 61 |
+
format (`str`, *optional*, defaults to `AnnotationFormat.COCO_DETECTION`):
|
| 62 |
+
Data format of the annotations. One of "coco_detection" or "coco_panoptic".
|
| 63 |
+
do_convert_annotations (`bool`, *optional*, defaults to `True`):
|
| 64 |
+
Controls whether to convert the annotations to the format expected by the CONDITIONAL_DETR model. Converts the
|
| 65 |
+
bounding boxes to the format `(center_x, center_y, width, height)` and in the range `[0, 1]`.
|
| 66 |
+
Can be overridden by the `do_convert_annotations` parameter in the `preprocess` method.
|
| 67 |
+
"""
|
| 68 |
+
|
| 69 |
+
format: str | AnnotationFormat
|
| 70 |
+
do_convert_annotations: bool
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
SUPPORTED_ANNOTATION_FORMATS = (AnnotationFormat.COCO_DETECTION, AnnotationFormat.COCO_PANOPTIC)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def binary_mask_to_rle(mask):
|
| 77 |
+
"""
|
| 78 |
+
Converts given binary mask of shape `(height, width)` to the run-length encoding (RLE) format.
|
| 79 |
+
|
| 80 |
+
Args:
|
| 81 |
+
mask (`torch.Tensor` or `numpy.array`):
|
| 82 |
+
A binary mask tensor of shape `(height, width)` where 0 denotes background and 1 denotes the target
|
| 83 |
+
segment_id or class_id.
|
| 84 |
+
Returns:
|
| 85 |
+
`List`: Run-length encoded list of the binary mask. Refer to COCO API for more information about the RLE
|
| 86 |
+
format.
|
| 87 |
+
"""
|
| 88 |
+
from ...utils import is_torch_tensor
|
| 89 |
+
|
| 90 |
+
if is_torch_tensor(mask):
|
| 91 |
+
mask = mask.numpy()
|
| 92 |
+
|
| 93 |
+
pixels = mask.flatten()
|
| 94 |
+
pixels = np.concatenate([[0], pixels, [0]])
|
| 95 |
+
runs = np.where(pixels[1:] != pixels[:-1])[0] + 1
|
| 96 |
+
runs[1::2] -= runs[::2]
|
| 97 |
+
return list(runs)
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def convert_segmentation_to_rle(segmentation):
|
| 101 |
+
"""
|
| 102 |
+
Converts given segmentation map of shape `(height, width)` to the run-length encoding (RLE) format.
|
| 103 |
+
|
| 104 |
+
Args:
|
| 105 |
+
segmentation (`torch.Tensor` or `numpy.array`):
|
| 106 |
+
A segmentation map of shape `(height, width)` where each value denotes a segment or class id.
|
| 107 |
+
Returns:
|
| 108 |
+
`list[List]`: A list of lists, where each list is the run-length encoding of a segment / class id.
|
| 109 |
+
"""
|
| 110 |
+
segment_ids = torch.unique(segmentation)
|
| 111 |
+
|
| 112 |
+
run_length_encodings = []
|
| 113 |
+
for idx in segment_ids:
|
| 114 |
+
mask = torch.where(segmentation == idx, 1, 0)
|
| 115 |
+
rle = binary_mask_to_rle(mask)
|
| 116 |
+
run_length_encodings.append(rle)
|
| 117 |
+
|
| 118 |
+
return run_length_encodings
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def remove_low_and_no_objects(masks, scores, labels, object_mask_threshold, num_labels):
|
| 122 |
+
"""
|
| 123 |
+
Binarize the given masks using `object_mask_threshold`, it returns the associated values of `masks`, `scores` and
|
| 124 |
+
`labels`.
|
| 125 |
+
|
| 126 |
+
Args:
|
| 127 |
+
masks (`torch.Tensor`):
|
| 128 |
+
A tensor of shape `(num_queries, height, width)`.
|
| 129 |
+
scores (`torch.Tensor`):
|
| 130 |
+
A tensor of shape `(num_queries)`.
|
| 131 |
+
labels (`torch.Tensor`):
|
| 132 |
+
A tensor of shape `(num_queries)`.
|
| 133 |
+
object_mask_threshold (`float`):
|
| 134 |
+
A number between 0 and 1 used to binarize the masks.
|
| 135 |
+
Raises:
|
| 136 |
+
`ValueError`: Raised when the first dimension doesn't match in all input tensors.
|
| 137 |
+
Returns:
|
| 138 |
+
`tuple[`torch.Tensor`, `torch.Tensor`, `torch.Tensor`]`: The `masks`, `scores` and `labels` without the region
|
| 139 |
+
< `object_mask_threshold`.
|
| 140 |
+
"""
|
| 141 |
+
if not (masks.shape[0] == scores.shape[0] == labels.shape[0]):
|
| 142 |
+
raise ValueError("mask, scores and labels must have the same shape!")
|
| 143 |
+
|
| 144 |
+
to_keep = labels.ne(num_labels) & (scores > object_mask_threshold)
|
| 145 |
+
|
| 146 |
+
return masks[to_keep], scores[to_keep], labels[to_keep]
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
def check_segment_validity(mask_labels, mask_probs, k, mask_threshold=0.5, overlap_mask_area_threshold=0.8):
|
| 150 |
+
# Get the mask associated with the k class
|
| 151 |
+
mask_k = mask_labels == k
|
| 152 |
+
mask_k_area = mask_k.sum()
|
| 153 |
+
|
| 154 |
+
# Compute the area of all the stuff in query k
|
| 155 |
+
original_area = (mask_probs[k] >= mask_threshold).sum()
|
| 156 |
+
mask_exists = mask_k_area > 0 and original_area > 0
|
| 157 |
+
|
| 158 |
+
# Eliminate disconnected tiny segments
|
| 159 |
+
if mask_exists:
|
| 160 |
+
area_ratio = mask_k_area / original_area
|
| 161 |
+
if not area_ratio.item() > overlap_mask_area_threshold:
|
| 162 |
+
mask_exists = False
|
| 163 |
+
|
| 164 |
+
return mask_exists, mask_k
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def compute_segments(
|
| 168 |
+
mask_probs,
|
| 169 |
+
pred_scores,
|
| 170 |
+
pred_labels,
|
| 171 |
+
mask_threshold: float = 0.5,
|
| 172 |
+
overlap_mask_area_threshold: float = 0.8,
|
| 173 |
+
label_ids_to_fuse: set[int] | None = None,
|
| 174 |
+
target_size: tuple[int, int] | None = None,
|
| 175 |
+
):
|
| 176 |
+
height = mask_probs.shape[1] if target_size is None else target_size[0]
|
| 177 |
+
width = mask_probs.shape[2] if target_size is None else target_size[1]
|
| 178 |
+
|
| 179 |
+
segmentation = torch.zeros((height, width), dtype=torch.int32, device=mask_probs.device)
|
| 180 |
+
segments: list[dict] = []
|
| 181 |
+
|
| 182 |
+
if target_size is not None:
|
| 183 |
+
mask_probs = nn.functional.interpolate(
|
| 184 |
+
mask_probs.unsqueeze(0), size=target_size, mode="bilinear", align_corners=False
|
| 185 |
+
)[0]
|
| 186 |
+
|
| 187 |
+
current_segment_id = 0
|
| 188 |
+
|
| 189 |
+
# Weigh each mask by its prediction score
|
| 190 |
+
mask_probs *= pred_scores.view(-1, 1, 1)
|
| 191 |
+
mask_labels = mask_probs.argmax(0) # [height, width]
|
| 192 |
+
|
| 193 |
+
# Keep track of instances of each class
|
| 194 |
+
stuff_memory_list: dict[str, int] = {}
|
| 195 |
+
for k in range(pred_labels.shape[0]):
|
| 196 |
+
pred_class = pred_labels[k].item()
|
| 197 |
+
should_fuse = pred_class in label_ids_to_fuse
|
| 198 |
+
|
| 199 |
+
# Check if mask exists and large enough to be a segment
|
| 200 |
+
mask_exists, mask_k = check_segment_validity(
|
| 201 |
+
mask_labels, mask_probs, k, mask_threshold, overlap_mask_area_threshold
|
| 202 |
+
)
|
| 203 |
+
|
| 204 |
+
if mask_exists:
|
| 205 |
+
if pred_class in stuff_memory_list:
|
| 206 |
+
current_segment_id = stuff_memory_list[pred_class]
|
| 207 |
+
else:
|
| 208 |
+
current_segment_id += 1
|
| 209 |
+
|
| 210 |
+
# Add current object segment to final segmentation map
|
| 211 |
+
segmentation[mask_k] = current_segment_id
|
| 212 |
+
segment_score = round(pred_scores[k].item(), 6)
|
| 213 |
+
segments.append(
|
| 214 |
+
{
|
| 215 |
+
"id": current_segment_id,
|
| 216 |
+
"label_id": pred_class,
|
| 217 |
+
"was_fused": should_fuse,
|
| 218 |
+
"score": segment_score,
|
| 219 |
+
}
|
| 220 |
+
)
|
| 221 |
+
if should_fuse:
|
| 222 |
+
stuff_memory_list[pred_class] = current_segment_id
|
| 223 |
+
|
| 224 |
+
return segmentation, segments
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
# inspired by https://github.com/facebookresearch/conditional_detr/blob/master/datasets/coco.py#L33
|
| 228 |
+
def convert_coco_poly_to_mask(segmentations, height: int, width: int, device: torch.device) -> torch.Tensor:
|
| 229 |
+
"""
|
| 230 |
+
Convert a COCO polygon annotation to a mask.
|
| 231 |
+
|
| 232 |
+
Args:
|
| 233 |
+
segmentations (`list[list[float]]`):
|
| 234 |
+
List of polygons, each polygon represented by a list of x-y coordinates.
|
| 235 |
+
height (`int`):
|
| 236 |
+
Height of the mask.
|
| 237 |
+
width (`int`):
|
| 238 |
+
Width of the mask.
|
| 239 |
+
"""
|
| 240 |
+
try:
|
| 241 |
+
from pycocotools import mask as coco_mask
|
| 242 |
+
except ImportError:
|
| 243 |
+
raise ImportError("Pycocotools is not installed in your environment.")
|
| 244 |
+
|
| 245 |
+
masks = []
|
| 246 |
+
for polygons in segmentations:
|
| 247 |
+
rles = coco_mask.frPyObjects(polygons, height, width)
|
| 248 |
+
mask = coco_mask.decode(rles)
|
| 249 |
+
if len(mask.shape) < 3:
|
| 250 |
+
mask = mask[..., None]
|
| 251 |
+
mask = torch.as_tensor(mask, dtype=torch.uint8, device=device)
|
| 252 |
+
mask = torch.any(mask, axis=2)
|
| 253 |
+
masks.append(mask)
|
| 254 |
+
if masks:
|
| 255 |
+
masks = torch.stack(masks, axis=0)
|
| 256 |
+
else:
|
| 257 |
+
masks = torch.zeros((0, height, width), dtype=torch.uint8, device=device)
|
| 258 |
+
|
| 259 |
+
return masks
|
| 260 |
+
|
| 261 |
+
|
| 262 |
+
# inspired by https://github.com/facebookresearch/conditional_detr/blob/master/datasets/coco.py#L50
|
| 263 |
+
def prepare_coco_detection_annotation(
|
| 264 |
+
image,
|
| 265 |
+
target,
|
| 266 |
+
return_segmentation_masks: bool = False,
|
| 267 |
+
input_data_format: ChannelDimension | str | None = None,
|
| 268 |
+
):
|
| 269 |
+
"""
|
| 270 |
+
Convert the target in COCO format into the format expected by CONDITIONAL_DETR.
|
| 271 |
+
"""
|
| 272 |
+
image_height, image_width = image.size()[-2:]
|
| 273 |
+
|
| 274 |
+
image_id = target["image_id"]
|
| 275 |
+
image_id = torch.as_tensor([image_id], dtype=torch.int64, device=image.device)
|
| 276 |
+
|
| 277 |
+
# Get all COCO annotations for the given image.
|
| 278 |
+
annotations = target["annotations"]
|
| 279 |
+
classes = []
|
| 280 |
+
area = []
|
| 281 |
+
boxes = []
|
| 282 |
+
keypoints = []
|
| 283 |
+
for obj in annotations:
|
| 284 |
+
if "iscrowd" not in obj or obj["iscrowd"] == 0:
|
| 285 |
+
classes.append(obj["category_id"])
|
| 286 |
+
area.append(obj["area"])
|
| 287 |
+
boxes.append(obj["bbox"])
|
| 288 |
+
if "keypoints" in obj:
|
| 289 |
+
keypoints.append(obj["keypoints"])
|
| 290 |
+
|
| 291 |
+
classes = torch.as_tensor(classes, dtype=torch.int64, device=image.device)
|
| 292 |
+
area = torch.as_tensor(area, dtype=torch.float32, device=image.device)
|
| 293 |
+
iscrowd = torch.zeros_like(classes, dtype=torch.int64, device=image.device)
|
| 294 |
+
# guard against no boxes via resizing
|
| 295 |
+
boxes = torch.as_tensor(boxes, dtype=torch.float32, device=image.device).reshape(-1, 4)
|
| 296 |
+
boxes[:, 2:] += boxes[:, :2]
|
| 297 |
+
boxes[:, 0::2] = boxes[:, 0::2].clip(min=0, max=image_width)
|
| 298 |
+
boxes[:, 1::2] = boxes[:, 1::2].clip(min=0, max=image_height)
|
| 299 |
+
|
| 300 |
+
keep = (boxes[:, 3] > boxes[:, 1]) & (boxes[:, 2] > boxes[:, 0])
|
| 301 |
+
|
| 302 |
+
new_target = {
|
| 303 |
+
"image_id": image_id,
|
| 304 |
+
"class_labels": classes[keep],
|
| 305 |
+
"boxes": boxes[keep],
|
| 306 |
+
"area": area[keep],
|
| 307 |
+
"iscrowd": iscrowd[keep],
|
| 308 |
+
"orig_size": torch.as_tensor([int(image_height), int(image_width)], dtype=torch.int64, device=image.device),
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
if keypoints:
|
| 312 |
+
keypoints = torch.as_tensor(keypoints, dtype=torch.float32, device=image.device)
|
| 313 |
+
# Apply the keep mask here to filter the relevant annotations
|
| 314 |
+
keypoints = keypoints[keep]
|
| 315 |
+
num_keypoints = keypoints.shape[0]
|
| 316 |
+
keypoints = keypoints.reshape((-1, 3)) if num_keypoints else keypoints
|
| 317 |
+
new_target["keypoints"] = keypoints
|
| 318 |
+
|
| 319 |
+
if return_segmentation_masks:
|
| 320 |
+
segmentation_masks = [obj["segmentation"] for obj in annotations]
|
| 321 |
+
masks = convert_coco_poly_to_mask(segmentation_masks, image_height, image_width, device=image.device)
|
| 322 |
+
new_target["masks"] = masks[keep]
|
| 323 |
+
|
| 324 |
+
return new_target
|
| 325 |
+
|
| 326 |
+
|
| 327 |
+
def masks_to_boxes(masks: torch.Tensor) -> torch.Tensor:
|
| 328 |
+
"""
|
| 329 |
+
Compute the bounding boxes around the provided panoptic segmentation masks.
|
| 330 |
+
|
| 331 |
+
Args:
|
| 332 |
+
masks: masks in format `[number_masks, height, width]` where N is the number of masks
|
| 333 |
+
|
| 334 |
+
Returns:
|
| 335 |
+
boxes: bounding boxes in format `[number_masks, 4]` in xyxy format
|
| 336 |
+
"""
|
| 337 |
+
if masks.numel() == 0:
|
| 338 |
+
return torch.zeros((0, 4), device=masks.device)
|
| 339 |
+
|
| 340 |
+
h, w = masks.shape[-2:]
|
| 341 |
+
y = torch.arange(0, h, dtype=torch.float32, device=masks.device)
|
| 342 |
+
x = torch.arange(0, w, dtype=torch.float32, device=masks.device)
|
| 343 |
+
# see https://github.com/pytorch/pytorch/issues/50276
|
| 344 |
+
y, x = torch.meshgrid(y, x, indexing="ij")
|
| 345 |
+
|
| 346 |
+
x_mask = masks * torch.unsqueeze(x, 0)
|
| 347 |
+
x_max = x_mask.view(x_mask.shape[0], -1).max(-1)[0]
|
| 348 |
+
x_min = (
|
| 349 |
+
torch.where(masks, x.unsqueeze(0), torch.tensor(1e8, device=masks.device)).view(masks.shape[0], -1).min(-1)[0]
|
| 350 |
+
)
|
| 351 |
+
|
| 352 |
+
y_mask = masks * torch.unsqueeze(y, 0)
|
| 353 |
+
y_max = y_mask.view(y_mask.shape[0], -1).max(-1)[0]
|
| 354 |
+
y_min = (
|
| 355 |
+
torch.where(masks, y.unsqueeze(0), torch.tensor(1e8, device=masks.device)).view(masks.shape[0], -1).min(-1)[0]
|
| 356 |
+
)
|
| 357 |
+
|
| 358 |
+
return torch.stack([x_min, y_min, x_max, y_max], 1)
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
# 2 functions below adapted from https://github.com/cocodataset/panopticapi/blob/master/panopticapi/utils.py
|
| 362 |
+
# Copyright (c) 2018, Alexander Kirillov
|
| 363 |
+
# All rights reserved.
|
| 364 |
+
def rgb_to_id(color):
|
| 365 |
+
"""
|
| 366 |
+
Converts RGB color to unique ID.
|
| 367 |
+
"""
|
| 368 |
+
if isinstance(color, torch.Tensor) and len(color.shape) == 3:
|
| 369 |
+
if color.dtype == torch.uint8:
|
| 370 |
+
color = color.to(torch.int32)
|
| 371 |
+
return color[:, :, 0] + 256 * color[:, :, 1] + 256 * 256 * color[:, :, 2]
|
| 372 |
+
return int(color[0] + 256 * color[1] + 256 * 256 * color[2])
|
| 373 |
+
|
| 374 |
+
|
| 375 |
+
def prepare_coco_panoptic_annotation(
|
| 376 |
+
image: torch.Tensor,
|
| 377 |
+
target: dict,
|
| 378 |
+
masks_path: str | pathlib.Path,
|
| 379 |
+
return_masks: bool = True,
|
| 380 |
+
input_data_format: ChannelDimension | str = None,
|
| 381 |
+
) -> dict:
|
| 382 |
+
"""
|
| 383 |
+
Prepare a coco panoptic annotation for CONDITIONAL_DETR.
|
| 384 |
+
"""
|
| 385 |
+
image_height, image_width = get_image_size(image, channel_dim=input_data_format)
|
| 386 |
+
annotation_path = pathlib.Path(masks_path) / target["file_name"]
|
| 387 |
+
|
| 388 |
+
new_target = {}
|
| 389 |
+
new_target["image_id"] = torch.as_tensor(
|
| 390 |
+
[target["image_id"] if "image_id" in target else target["id"]], dtype=torch.int64, device=image.device
|
| 391 |
+
)
|
| 392 |
+
new_target["size"] = torch.as_tensor([image_height, image_width], dtype=torch.int64, device=image.device)
|
| 393 |
+
new_target["orig_size"] = torch.as_tensor([image_height, image_width], dtype=torch.int64, device=image.device)
|
| 394 |
+
|
| 395 |
+
if "segments_info" in target:
|
| 396 |
+
masks = read_image(annotation_path).permute(1, 2, 0).to(dtype=torch.int32, device=image.device)
|
| 397 |
+
masks = rgb_to_id(masks)
|
| 398 |
+
|
| 399 |
+
ids = torch.as_tensor([segment_info["id"] for segment_info in target["segments_info"]], device=image.device)
|
| 400 |
+
masks = masks == ids[:, None, None]
|
| 401 |
+
masks = masks.to(torch.bool)
|
| 402 |
+
if return_masks:
|
| 403 |
+
new_target["masks"] = masks
|
| 404 |
+
new_target["boxes"] = masks_to_boxes(masks)
|
| 405 |
+
new_target["class_labels"] = torch.as_tensor(
|
| 406 |
+
[segment_info["category_id"] for segment_info in target["segments_info"]],
|
| 407 |
+
dtype=torch.int64,
|
| 408 |
+
device=image.device,
|
| 409 |
+
)
|
| 410 |
+
new_target["iscrowd"] = torch.as_tensor(
|
| 411 |
+
[segment_info["iscrowd"] for segment_info in target["segments_info"]],
|
| 412 |
+
dtype=torch.int64,
|
| 413 |
+
device=image.device,
|
| 414 |
+
)
|
| 415 |
+
new_target["area"] = torch.as_tensor(
|
| 416 |
+
[segment_info["area"] for segment_info in target["segments_info"]],
|
| 417 |
+
dtype=torch.float32,
|
| 418 |
+
device=image.device,
|
| 419 |
+
)
|
| 420 |
+
|
| 421 |
+
return new_target
|
| 422 |
+
|
| 423 |
+
|
| 424 |
+
@auto_docstring
|
| 425 |
+
class ConditionalDetrImageProcessor(TorchvisionBackend):
|
| 426 |
+
valid_kwargs = ConditionalDetrImageProcessorKwargs
|
| 427 |
+
resample = PILImageResampling.BILINEAR
|
| 428 |
+
image_mean = IMAGENET_DEFAULT_MEAN
|
| 429 |
+
image_std = IMAGENET_DEFAULT_STD
|
| 430 |
+
format = AnnotationFormat.COCO_DETECTION
|
| 431 |
+
do_resize = True
|
| 432 |
+
do_rescale = True
|
| 433 |
+
do_normalize = True
|
| 434 |
+
do_pad = True
|
| 435 |
+
size = {"shortest_edge": 800, "longest_edge": 1333}
|
| 436 |
+
default_to_square = False
|
| 437 |
+
model_input_names = ["pixel_values", "pixel_mask"]
|
| 438 |
+
|
| 439 |
+
def __init__(self, **kwargs: Unpack[ConditionalDetrImageProcessorKwargs]) -> None:
|
| 440 |
+
kwargs.setdefault("do_pad", kwargs.pop("pad_and_return_pixel_mask", self.do_pad))
|
| 441 |
+
|
| 442 |
+
size = kwargs.pop("size", None)
|
| 443 |
+
max_size = None if size is None else kwargs.pop("max_size", 1333)
|
| 444 |
+
size = size if size is not None else {"shortest_edge": 800, "longest_edge": 1333}
|
| 445 |
+
# Convert size dict for backwards compat with max_size parameter
|
| 446 |
+
kwargs["size"] = get_size_dict(size, max_size=max_size, default_to_square=False)
|
| 447 |
+
|
| 448 |
+
# Backwards compatibility
|
| 449 |
+
do_convert_annotations = kwargs.get("do_convert_annotations")
|
| 450 |
+
do_normalize = kwargs.get("do_normalize")
|
| 451 |
+
if do_convert_annotations is None and getattr(self, "do_convert_annotations", None) is None:
|
| 452 |
+
self.do_convert_annotations = do_normalize if do_normalize is not None else self.do_normalize
|
| 453 |
+
|
| 454 |
+
super().__init__(**kwargs)
|
| 455 |
+
|
| 456 |
+
def prepare_annotation(
|
| 457 |
+
self,
|
| 458 |
+
image: torch.Tensor,
|
| 459 |
+
target: dict,
|
| 460 |
+
format: AnnotationFormat | None = None,
|
| 461 |
+
return_segmentation_masks: bool | None = None,
|
| 462 |
+
masks_path: str | pathlib.Path | None = None,
|
| 463 |
+
input_data_format: str | ChannelDimension | None = None,
|
| 464 |
+
) -> dict:
|
| 465 |
+
"""
|
| 466 |
+
Prepare an annotation for feeding into CONDITIONAL_DETR model.
|
| 467 |
+
"""
|
| 468 |
+
format = format if format is not None else self.format
|
| 469 |
+
|
| 470 |
+
if format == AnnotationFormat.COCO_DETECTION:
|
| 471 |
+
return_segmentation_masks = False if return_segmentation_masks is None else return_segmentation_masks
|
| 472 |
+
target = prepare_coco_detection_annotation(
|
| 473 |
+
image, target, return_segmentation_masks, input_data_format=input_data_format
|
| 474 |
+
)
|
| 475 |
+
elif format == AnnotationFormat.COCO_PANOPTIC:
|
| 476 |
+
return_segmentation_masks = True if return_segmentation_masks is None else return_segmentation_masks
|
| 477 |
+
target = prepare_coco_panoptic_annotation(
|
| 478 |
+
image,
|
| 479 |
+
target,
|
| 480 |
+
masks_path=masks_path,
|
| 481 |
+
return_masks=return_segmentation_masks,
|
| 482 |
+
input_data_format=input_data_format,
|
| 483 |
+
)
|
| 484 |
+
else:
|
| 485 |
+
raise ValueError(f"Format {format} is not supported.")
|
| 486 |
+
return target
|
| 487 |
+
|
| 488 |
+
def resize(
|
| 489 |
+
self,
|
| 490 |
+
image: torch.Tensor,
|
| 491 |
+
size: SizeDict,
|
| 492 |
+
resample: Optional["PILImageResampling | tvF.InterpolationMode | int"] = None,
|
| 493 |
+
**kwargs,
|
| 494 |
+
) -> torch.Tensor:
|
| 495 |
+
"""
|
| 496 |
+
Resize the image to the given size. Size can be `min_size` (scalar) or `(height, width)` tuple. If size is an
|
| 497 |
+
int, smaller edge of the image will be matched to this number.
|
| 498 |
+
|
| 499 |
+
Args:
|
| 500 |
+
image (`torch.Tensor`):
|
| 501 |
+
Image to resize.
|
| 502 |
+
size (`SizeDict`):
|
| 503 |
+
Size of the image's `(height, width)` dimensions after resizing. Available options are:
|
| 504 |
+
- `{"height": int, "width": int}`: The image will be resized to the exact size `(height, width)`.
|
| 505 |
+
Do NOT keep the aspect ratio.
|
| 506 |
+
- `{"shortest_edge": int, "longest_edge": int}`: The image will be resized to a maximum size respecting
|
| 507 |
+
the aspect ratio and keeping the shortest edge less or equal to `shortest_edge` and the longest edge
|
| 508 |
+
less or equal to `longest_edge`.
|
| 509 |
+
- `{"max_height": int, "max_width": int}`: The image will be resized to the maximum size respecting the
|
| 510 |
+
aspect ratio and keeping the height less or equal to `max_height` and the width less or equal to
|
| 511 |
+
`max_width`.
|
| 512 |
+
resample (`PILImageResampling | tvF.InterpolationMode | int`, *optional*, defaults to `PILImageResampling.BILINEAR`):
|
| 513 |
+
Resampling filter to use if resizing the image.
|
| 514 |
+
"""
|
| 515 |
+
if size.shortest_edge and size.longest_edge:
|
| 516 |
+
# Resize the image so that the shortest edge or the longest edge is of the given size
|
| 517 |
+
# while maintaining the aspect ratio of the original image.
|
| 518 |
+
new_size = get_size_with_aspect_ratio(image.shape[-2:], size.shortest_edge, size.longest_edge)
|
| 519 |
+
elif size.max_height and size.max_width:
|
| 520 |
+
new_size = get_image_size_for_max_height_width(image.shape[-2:], size.max_height, size.max_width)
|
| 521 |
+
elif size.height and size.width:
|
| 522 |
+
new_size = (size.height, size.width)
|
| 523 |
+
else:
|
| 524 |
+
raise ValueError(
|
| 525 |
+
f"Size must contain 'height' and 'width' keys or 'shortest_edge' and 'longest_edge' keys. Got {size}."
|
| 526 |
+
)
|
| 527 |
+
|
| 528 |
+
image = super().resize(
|
| 529 |
+
image, size=SizeDict(height=new_size[0], width=new_size[1]), resample=resample, **kwargs
|
| 530 |
+
)
|
| 531 |
+
return image
|
| 532 |
+
|
| 533 |
+
def resize_annotation(
|
| 534 |
+
self,
|
| 535 |
+
annotation: dict[str, Any],
|
| 536 |
+
orig_size: tuple[int, int],
|
| 537 |
+
target_size: tuple[int, int],
|
| 538 |
+
threshold: float = 0.5,
|
| 539 |
+
resample: Optional["PILImageResampling | tvF.InterpolationMode | int"] = PILImageResampling.NEAREST,
|
| 540 |
+
):
|
| 541 |
+
"""
|
| 542 |
+
Resizes an annotation to a target size.
|
| 543 |
+
|
| 544 |
+
Args:
|
| 545 |
+
annotation (`dict[str, Any]`):
|
| 546 |
+
The annotation dictionary.
|
| 547 |
+
orig_size (`tuple[int, int]`):
|
| 548 |
+
The original size of the input image.
|
| 549 |
+
target_size (`tuple[int, int]`):
|
| 550 |
+
The target size of the image, as returned by the preprocessing `resize` step.
|
| 551 |
+
threshold (`float`, *optional*, defaults to 0.5):
|
| 552 |
+
The threshold used to binarize the segmentation masks.
|
| 553 |
+
resample (`PILImageResampling | tvF.InterpolationMode | int`, defaults to `tvF.InterpolationMode.NEAREST_EXACT`):
|
| 554 |
+
The resampling filter to use when resizing the masks.
|
| 555 |
+
"""
|
| 556 |
+
ratio_height, ratio_width = [target / orig for target, orig in zip(target_size, orig_size)]
|
| 557 |
+
|
| 558 |
+
new_annotation = {}
|
| 559 |
+
new_annotation["size"] = target_size
|
| 560 |
+
|
| 561 |
+
for key, value in annotation.items():
|
| 562 |
+
if key == "boxes":
|
| 563 |
+
boxes = value
|
| 564 |
+
scaled_boxes = boxes * torch.as_tensor(
|
| 565 |
+
[ratio_width, ratio_height, ratio_width, ratio_height], dtype=torch.float32, device=boxes.device
|
| 566 |
+
)
|
| 567 |
+
new_annotation["boxes"] = scaled_boxes
|
| 568 |
+
elif key == "area":
|
| 569 |
+
area = value
|
| 570 |
+
scaled_area = area * (ratio_width * ratio_height)
|
| 571 |
+
new_annotation["area"] = scaled_area
|
| 572 |
+
elif key == "masks":
|
| 573 |
+
masks = value[:, None]
|
| 574 |
+
masks = [
|
| 575 |
+
super(ConditionalDetrImageProcessor, self).resize(
|
| 576 |
+
mask, size=SizeDict(height=target_size[0], width=target_size[1]), resample=resample
|
| 577 |
+
)
|
| 578 |
+
for mask in masks
|
| 579 |
+
]
|
| 580 |
+
masks = torch.stack(masks).to(torch.float32)
|
| 581 |
+
masks = masks[:, 0] > threshold
|
| 582 |
+
new_annotation["masks"] = masks
|
| 583 |
+
elif key == "size":
|
| 584 |
+
new_annotation["size"] = target_size
|
| 585 |
+
else:
|
| 586 |
+
new_annotation[key] = value
|
| 587 |
+
|
| 588 |
+
return new_annotation
|
| 589 |
+
|
| 590 |
+
def normalize_annotation(self, annotation: dict, image_size: tuple[int, int]) -> dict:
|
| 591 |
+
image_height, image_width = image_size
|
| 592 |
+
norm_annotation = {}
|
| 593 |
+
for key, value in annotation.items():
|
| 594 |
+
if key == "boxes":
|
| 595 |
+
boxes = value
|
| 596 |
+
boxes = corners_to_center_format(boxes)
|
| 597 |
+
boxes /= torch.as_tensor(
|
| 598 |
+
[image_width, image_height, image_width, image_height], dtype=torch.float32, device=boxes.device
|
| 599 |
+
)
|
| 600 |
+
norm_annotation[key] = boxes
|
| 601 |
+
else:
|
| 602 |
+
norm_annotation[key] = value
|
| 603 |
+
return norm_annotation
|
| 604 |
+
|
| 605 |
+
def _update_annotation_for_padded_image(
|
| 606 |
+
self,
|
| 607 |
+
annotation: dict,
|
| 608 |
+
input_image_size: tuple[int, int],
|
| 609 |
+
output_image_size: tuple[int, int],
|
| 610 |
+
padding,
|
| 611 |
+
update_bboxes,
|
| 612 |
+
) -> dict:
|
| 613 |
+
"""
|
| 614 |
+
Update the annotation for a padded image.
|
| 615 |
+
"""
|
| 616 |
+
new_annotation = {}
|
| 617 |
+
new_annotation["size"] = output_image_size
|
| 618 |
+
ratio_height, ratio_width = (input / output for output, input in zip(output_image_size, input_image_size))
|
| 619 |
+
|
| 620 |
+
for key, value in annotation.items():
|
| 621 |
+
if key == "masks":
|
| 622 |
+
masks = value
|
| 623 |
+
masks = tvF.pad(
|
| 624 |
+
masks,
|
| 625 |
+
padding,
|
| 626 |
+
fill=0,
|
| 627 |
+
)
|
| 628 |
+
masks = safe_squeeze(masks, 1)
|
| 629 |
+
new_annotation["masks"] = masks
|
| 630 |
+
elif key == "boxes" and update_bboxes:
|
| 631 |
+
boxes = value
|
| 632 |
+
boxes *= torch.as_tensor([ratio_width, ratio_height, ratio_width, ratio_height], device=boxes.device)
|
| 633 |
+
new_annotation["boxes"] = boxes
|
| 634 |
+
elif key == "size":
|
| 635 |
+
new_annotation["size"] = output_image_size
|
| 636 |
+
else:
|
| 637 |
+
new_annotation[key] = value
|
| 638 |
+
return new_annotation
|
| 639 |
+
|
| 640 |
+
def pad(
|
| 641 |
+
self,
|
| 642 |
+
image: torch.Tensor,
|
| 643 |
+
padded_size: tuple[int, int],
|
| 644 |
+
annotation: dict[str, Any] | None = None,
|
| 645 |
+
update_bboxes: bool = True,
|
| 646 |
+
fill: int = 0,
|
| 647 |
+
):
|
| 648 |
+
original_size = image.size()[-2:]
|
| 649 |
+
padding_bottom = padded_size[0] - original_size[0]
|
| 650 |
+
padding_right = padded_size[1] - original_size[1]
|
| 651 |
+
if padding_bottom < 0 or padding_right < 0:
|
| 652 |
+
raise ValueError(
|
| 653 |
+
f"Padding dimensions are negative. Please make sure that the padded size is larger than the "
|
| 654 |
+
f"original size. Got padded size: {padded_size}, original size: {original_size}."
|
| 655 |
+
)
|
| 656 |
+
if original_size != padded_size:
|
| 657 |
+
padding = [0, 0, padding_right, padding_bottom]
|
| 658 |
+
image = tvF.pad(image, padding, fill=fill)
|
| 659 |
+
if annotation is not None:
|
| 660 |
+
annotation = self._update_annotation_for_padded_image(
|
| 661 |
+
annotation, original_size, padded_size, padding, update_bboxes
|
| 662 |
+
)
|
| 663 |
+
|
| 664 |
+
# Make a pixel mask for the image, where 1 indicates a valid pixel and 0 indicates padding.
|
| 665 |
+
pixel_mask = torch.zeros(padded_size, dtype=torch.int64, device=image.device)
|
| 666 |
+
pixel_mask[: original_size[0], : original_size[1]] = 1
|
| 667 |
+
|
| 668 |
+
return image, pixel_mask, annotation
|
| 669 |
+
|
| 670 |
+
@auto_docstring
|
| 671 |
+
def preprocess(
|
| 672 |
+
self,
|
| 673 |
+
images: ImageInput,
|
| 674 |
+
annotations: AnnotationType | list[AnnotationType] | None = None,
|
| 675 |
+
return_segmentation_masks: bool | None = None,
|
| 676 |
+
masks_path: str | pathlib.Path | None = None,
|
| 677 |
+
**kwargs: Unpack[ConditionalDetrImageProcessorKwargs],
|
| 678 |
+
) -> BatchFeature:
|
| 679 |
+
r"""
|
| 680 |
+
annotations (`AnnotationType` or `list[AnnotationType]`, *optional*):
|
| 681 |
+
Annotations to transform according to the padding that is applied to the images.
|
| 682 |
+
return_segmentation_masks (`bool`, *optional*, defaults to `self.return_segmentation_masks`):
|
| 683 |
+
Whether to return segmentation masks.
|
| 684 |
+
masks_path (`str` or `pathlib.Path`, *optional*):
|
| 685 |
+
Path to the directory containing the segmentation masks.
|
| 686 |
+
"""
|
| 687 |
+
return super().preprocess(images, annotations, return_segmentation_masks, masks_path, **kwargs)
|
| 688 |
+
|
| 689 |
+
def _preprocess(
|
| 690 |
+
self,
|
| 691 |
+
images: list["torch.Tensor"],
|
| 692 |
+
annotations: AnnotationType | list[AnnotationType] | None,
|
| 693 |
+
return_segmentation_masks: bool,
|
| 694 |
+
masks_path: str | pathlib.Path | None,
|
| 695 |
+
do_resize: bool,
|
| 696 |
+
size: SizeDict,
|
| 697 |
+
resample: "PILImageResampling | tvF.InterpolationMode | int | None",
|
| 698 |
+
do_rescale: bool,
|
| 699 |
+
rescale_factor: float,
|
| 700 |
+
do_normalize: bool,
|
| 701 |
+
do_convert_annotations: bool,
|
| 702 |
+
image_mean: float | list[float] | None,
|
| 703 |
+
image_std: float | list[float] | None,
|
| 704 |
+
do_pad: bool,
|
| 705 |
+
pad_size: SizeDict | None,
|
| 706 |
+
format: str | AnnotationFormat | None,
|
| 707 |
+
return_tensors: str | TensorType | None,
|
| 708 |
+
**kwargs,
|
| 709 |
+
) -> BatchFeature:
|
| 710 |
+
"""
|
| 711 |
+
Preprocess an image or a batch of images so that it can be used by the model.
|
| 712 |
+
"""
|
| 713 |
+
if annotations is not None and isinstance(annotations, dict):
|
| 714 |
+
annotations = [annotations]
|
| 715 |
+
|
| 716 |
+
if annotations is not None and len(images) != len(annotations):
|
| 717 |
+
raise ValueError(
|
| 718 |
+
f"The number of images ({len(images)}) and annotations ({len(annotations)}) do not match."
|
| 719 |
+
)
|
| 720 |
+
|
| 721 |
+
format = AnnotationFormat(format)
|
| 722 |
+
if annotations is not None:
|
| 723 |
+
validate_annotations(format, SUPPORTED_ANNOTATION_FORMATS, annotations)
|
| 724 |
+
|
| 725 |
+
if (
|
| 726 |
+
masks_path is not None
|
| 727 |
+
and format == AnnotationFormat.COCO_PANOPTIC
|
| 728 |
+
and not isinstance(masks_path, (pathlib.Path, str))
|
| 729 |
+
):
|
| 730 |
+
raise ValueError(
|
| 731 |
+
"The path to the directory containing the mask PNG files should be provided as a"
|
| 732 |
+
f" `pathlib.Path` or string object, but is {type(masks_path)} instead."
|
| 733 |
+
)
|
| 734 |
+
|
| 735 |
+
data = {}
|
| 736 |
+
|
| 737 |
+
processed_images = []
|
| 738 |
+
processed_annotations = []
|
| 739 |
+
pixel_masks = [] # Initialize pixel_masks here
|
| 740 |
+
for image, annotation in zip(images, annotations if annotations is not None else [None] * len(images)):
|
| 741 |
+
# prepare (COCO annotations as a list of Dict -> CONDITIONAL_DETR target as a single Dict per image)
|
| 742 |
+
if annotations is not None:
|
| 743 |
+
annotation = self.prepare_annotation(
|
| 744 |
+
image,
|
| 745 |
+
annotation,
|
| 746 |
+
format,
|
| 747 |
+
return_segmentation_masks=return_segmentation_masks,
|
| 748 |
+
masks_path=masks_path,
|
| 749 |
+
input_data_format=ChannelDimension.FIRST,
|
| 750 |
+
)
|
| 751 |
+
|
| 752 |
+
if do_resize:
|
| 753 |
+
resized_image = self.resize(image, size=size, resample=resample)
|
| 754 |
+
if annotations is not None:
|
| 755 |
+
annotation = self.resize_annotation(
|
| 756 |
+
annotation,
|
| 757 |
+
orig_size=image.size()[-2:],
|
| 758 |
+
target_size=resized_image.size()[-2:],
|
| 759 |
+
)
|
| 760 |
+
image = resized_image
|
| 761 |
+
# Fused rescale and normalize
|
| 762 |
+
image = self.rescale_and_normalize(image, do_rescale, rescale_factor, do_normalize, image_mean, image_std)
|
| 763 |
+
if do_convert_annotations and annotations is not None:
|
| 764 |
+
annotation = self.normalize_annotation(annotation, get_image_size(image, ChannelDimension.FIRST))
|
| 765 |
+
|
| 766 |
+
processed_images.append(image)
|
| 767 |
+
processed_annotations.append(annotation)
|
| 768 |
+
images = processed_images
|
| 769 |
+
annotations = processed_annotations if annotations is not None else None
|
| 770 |
+
|
| 771 |
+
if do_pad:
|
| 772 |
+
# depends on all resized image shapes so we need another loop
|
| 773 |
+
if pad_size is not None:
|
| 774 |
+
padded_size = (pad_size.height, pad_size.width)
|
| 775 |
+
else:
|
| 776 |
+
padded_size = get_max_height_width(images)
|
| 777 |
+
|
| 778 |
+
padded_images = []
|
| 779 |
+
padded_annotations = []
|
| 780 |
+
for image, annotation in zip(images, annotations if annotations is not None else [None] * len(images)):
|
| 781 |
+
# Pads images and returns their mask: {'pixel_values': ..., 'pixel_mask': ...}
|
| 782 |
+
if padded_size == image.size()[-2:]:
|
| 783 |
+
padded_images.append(image)
|
| 784 |
+
pixel_masks.append(torch.ones(padded_size, dtype=torch.int64, device=image.device))
|
| 785 |
+
padded_annotations.append(annotation)
|
| 786 |
+
continue
|
| 787 |
+
image, pixel_mask, annotation = self.pad(
|
| 788 |
+
image, padded_size, annotation=annotation, update_bboxes=do_convert_annotations
|
| 789 |
+
)
|
| 790 |
+
padded_images.append(image)
|
| 791 |
+
padded_annotations.append(annotation)
|
| 792 |
+
pixel_masks.append(pixel_mask)
|
| 793 |
+
images = padded_images
|
| 794 |
+
annotations = padded_annotations if annotations is not None else None
|
| 795 |
+
data.update({"pixel_mask": torch.stack(pixel_masks, dim=0)})
|
| 796 |
+
|
| 797 |
+
data.update({"pixel_values": torch.stack(images, dim=0)})
|
| 798 |
+
encoded_inputs = BatchFeature(data, tensor_type=return_tensors)
|
| 799 |
+
if annotations is not None:
|
| 800 |
+
encoded_inputs["labels"] = [
|
| 801 |
+
BatchFeature(annotation, tensor_type=return_tensors) for annotation in annotations
|
| 802 |
+
]
|
| 803 |
+
return encoded_inputs
|
| 804 |
+
|
| 805 |
+
def post_process_object_detection(
|
| 806 |
+
self, outputs, threshold: float = 0.5, target_sizes: TensorType | list[tuple] = None, top_k: int = 100
|
| 807 |
+
):
|
| 808 |
+
"""
|
| 809 |
+
Converts the raw output of [`ConditionalDetrForObjectDetection`] into final bounding boxes in (top_left_x,
|
| 810 |
+
top_left_y, bottom_right_x, bottom_right_y) format. Only supports PyTorch.
|
| 811 |
+
|
| 812 |
+
Args:
|
| 813 |
+
outputs ([`ConditionalDetrObjectDetectionOutput`]):
|
| 814 |
+
Raw outputs of the model.
|
| 815 |
+
threshold (`float`, *optional*):
|
| 816 |
+
Score threshold to keep object detection predictions.
|
| 817 |
+
target_sizes (`torch.Tensor` or `list[tuple[int, int]]`, *optional*):
|
| 818 |
+
Tensor of shape `(batch_size, 2)` or list of tuples (`tuple[int, int]`) containing the target size
|
| 819 |
+
(height, width) of each image in the batch. If left to None, predictions will not be resized.
|
| 820 |
+
top_k (`int`, *optional*, defaults to 100):
|
| 821 |
+
Keep only top k bounding boxes before filtering by thresholding.
|
| 822 |
+
|
| 823 |
+
Returns:
|
| 824 |
+
`list[Dict]`: A list of dictionaries, each dictionary containing the scores, labels and boxes for an image
|
| 825 |
+
in the batch as predicted by the model.
|
| 826 |
+
"""
|
| 827 |
+
out_logits, out_bbox = outputs.logits, outputs.pred_boxes
|
| 828 |
+
|
| 829 |
+
if target_sizes is not None:
|
| 830 |
+
if len(out_logits) != len(target_sizes):
|
| 831 |
+
raise ValueError(
|
| 832 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 833 |
+
)
|
| 834 |
+
|
| 835 |
+
prob = out_logits.sigmoid()
|
| 836 |
+
prob = prob.view(out_logits.shape[0], -1)
|
| 837 |
+
k_value = min(top_k, prob.size(1))
|
| 838 |
+
topk_values, topk_indexes = torch.topk(prob, k_value, dim=1)
|
| 839 |
+
scores = topk_values
|
| 840 |
+
topk_boxes = torch.div(topk_indexes, out_logits.shape[2], rounding_mode="floor")
|
| 841 |
+
labels = topk_indexes % out_logits.shape[2]
|
| 842 |
+
boxes = center_to_corners_format(out_bbox)
|
| 843 |
+
boxes = torch.gather(boxes, 1, topk_boxes.unsqueeze(-1).repeat(1, 1, 4))
|
| 844 |
+
|
| 845 |
+
# and from relative [0, 1] to absolute [0, height] coordinates
|
| 846 |
+
if target_sizes is not None:
|
| 847 |
+
if isinstance(target_sizes, list):
|
| 848 |
+
img_h = torch.Tensor([i[0] for i in target_sizes])
|
| 849 |
+
img_w = torch.Tensor([i[1] for i in target_sizes])
|
| 850 |
+
else:
|
| 851 |
+
img_h, img_w = target_sizes.unbind(1)
|
| 852 |
+
scale_fct = torch.stack([img_w, img_h, img_w, img_h], dim=1).to(boxes.device)
|
| 853 |
+
boxes = boxes * scale_fct[:, None, :]
|
| 854 |
+
|
| 855 |
+
results = []
|
| 856 |
+
for s, l, b in zip(scores, labels, boxes):
|
| 857 |
+
score = s[s > threshold]
|
| 858 |
+
label = l[s > threshold]
|
| 859 |
+
box = b[s > threshold]
|
| 860 |
+
results.append({"scores": score, "labels": label, "boxes": box})
|
| 861 |
+
|
| 862 |
+
return results
|
| 863 |
+
|
| 864 |
+
def post_process_semantic_segmentation(self, outputs, target_sizes: list[tuple[int, int]] | None = None):
|
| 865 |
+
"""
|
| 866 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into semantic segmentation maps. Only supports PyTorch.
|
| 867 |
+
|
| 868 |
+
Args:
|
| 869 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 870 |
+
Raw outputs of the model.
|
| 871 |
+
target_sizes (`list[tuple[int, int]]`, *optional*):
|
| 872 |
+
A list of tuples (`tuple[int, int]`) containing the target size (height, width) of each image in the
|
| 873 |
+
batch. If unset, predictions will not be resized.
|
| 874 |
+
Returns:
|
| 875 |
+
`list[torch.Tensor]`:
|
| 876 |
+
A list of length `batch_size`, where each item is a semantic segmentation map of shape (height, width)
|
| 877 |
+
corresponding to the target_sizes entry (if `target_sizes` is specified). Each entry of each
|
| 878 |
+
`torch.Tensor` correspond to a semantic class id.
|
| 879 |
+
"""
|
| 880 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes]
|
| 881 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 882 |
+
|
| 883 |
+
# Conditional DETR does not have a null class, so we use all classes
|
| 884 |
+
masks_classes = class_queries_logits.softmax(dim=-1)
|
| 885 |
+
masks_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 886 |
+
|
| 887 |
+
# Semantic segmentation logits of shape (batch_size, num_classes, height, width)
|
| 888 |
+
segmentation = torch.einsum("bqc, bqhw -> bchw", masks_classes, masks_probs)
|
| 889 |
+
batch_size = class_queries_logits.shape[0]
|
| 890 |
+
|
| 891 |
+
# Resize logits and compute semantic segmentation maps
|
| 892 |
+
if target_sizes is not None:
|
| 893 |
+
if batch_size != len(target_sizes):
|
| 894 |
+
raise ValueError(
|
| 895 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 896 |
+
)
|
| 897 |
+
|
| 898 |
+
semantic_segmentation = []
|
| 899 |
+
for idx in range(batch_size):
|
| 900 |
+
resized_logits = nn.functional.interpolate(
|
| 901 |
+
segmentation[idx].unsqueeze(dim=0), size=target_sizes[idx], mode="bilinear", align_corners=False
|
| 902 |
+
)
|
| 903 |
+
semantic_map = resized_logits[0].argmax(dim=0)
|
| 904 |
+
semantic_segmentation.append(semantic_map)
|
| 905 |
+
else:
|
| 906 |
+
semantic_segmentation = segmentation.argmax(dim=1)
|
| 907 |
+
semantic_segmentation = [semantic_segmentation[i] for i in range(semantic_segmentation.shape[0])]
|
| 908 |
+
|
| 909 |
+
return semantic_segmentation
|
| 910 |
+
|
| 911 |
+
def post_process_instance_segmentation(
|
| 912 |
+
self,
|
| 913 |
+
outputs,
|
| 914 |
+
threshold: float = 0.5,
|
| 915 |
+
mask_threshold: float = 0.5,
|
| 916 |
+
overlap_mask_area_threshold: float = 0.8,
|
| 917 |
+
target_sizes: list[tuple[int, int]] | None = None,
|
| 918 |
+
return_coco_annotation: bool | None = False,
|
| 919 |
+
) -> list[dict]:
|
| 920 |
+
"""
|
| 921 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into instance segmentation predictions. Only supports PyTorch.
|
| 922 |
+
|
| 923 |
+
Args:
|
| 924 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 925 |
+
Raw outputs of the model.
|
| 926 |
+
threshold (`float`, *optional*, defaults to 0.5):
|
| 927 |
+
The probability score threshold to keep predicted instance masks.
|
| 928 |
+
mask_threshold (`float`, *optional*, defaults to 0.5):
|
| 929 |
+
Threshold to use when turning the predicted masks into binary values.
|
| 930 |
+
overlap_mask_area_threshold (`float`, *optional*, defaults to 0.8):
|
| 931 |
+
The overlap mask area threshold to merge or discard small disconnected parts within each binary
|
| 932 |
+
instance mask.
|
| 933 |
+
target_sizes (`list[Tuple]`, *optional*):
|
| 934 |
+
List of length (batch_size), where each list item (`tuple[int, int]]`) corresponds to the requested
|
| 935 |
+
final size (height, width) of each prediction. If unset, predictions will not be resized.
|
| 936 |
+
return_coco_annotation (`bool`, *optional*):
|
| 937 |
+
Defaults to `False`. If set to `True`, segmentation maps are returned in COCO run-length encoding (RLE)
|
| 938 |
+
format.
|
| 939 |
+
Returns:
|
| 940 |
+
`list[Dict]`: A list of dictionaries, one per image, each dictionary containing two keys:
|
| 941 |
+
- **segmentation** -- A tensor of shape `(height, width)` where each pixel represents a `segment_id` or
|
| 942 |
+
`list[List]` run-length encoding (RLE) of the segmentation map if return_coco_annotation is set to
|
| 943 |
+
`True`. Set to `None` if no mask if found above `threshold`.
|
| 944 |
+
- **segments_info** -- A dictionary that contains additional information on each segment.
|
| 945 |
+
- **id** -- An integer representing the `segment_id`.
|
| 946 |
+
- **label_id** -- An integer representing the label / semantic class id corresponding to `segment_id`.
|
| 947 |
+
- **score** -- Prediction score of segment with `segment_id`.
|
| 948 |
+
"""
|
| 949 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes+1]
|
| 950 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 951 |
+
|
| 952 |
+
batch_size = class_queries_logits.shape[0]
|
| 953 |
+
num_labels = class_queries_logits.shape[-1] - 1
|
| 954 |
+
|
| 955 |
+
mask_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 956 |
+
|
| 957 |
+
# Predicted label and score of each query (batch_size, num_queries)
|
| 958 |
+
pred_scores, pred_labels = nn.functional.softmax(class_queries_logits, dim=-1).max(-1)
|
| 959 |
+
|
| 960 |
+
# Loop over items in batch size
|
| 961 |
+
results: list[dict[str, TensorType]] = []
|
| 962 |
+
|
| 963 |
+
for i in range(batch_size):
|
| 964 |
+
mask_probs_item, pred_scores_item, pred_labels_item = remove_low_and_no_objects(
|
| 965 |
+
mask_probs[i], pred_scores[i], pred_labels[i], threshold, num_labels
|
| 966 |
+
)
|
| 967 |
+
|
| 968 |
+
# No mask found
|
| 969 |
+
if mask_probs_item.shape[0] <= 0:
|
| 970 |
+
height, width = target_sizes[i] if target_sizes is not None else mask_probs_item.shape[1:]
|
| 971 |
+
segmentation = torch.zeros((height, width)) - 1
|
| 972 |
+
results.append({"segmentation": segmentation, "segments_info": []})
|
| 973 |
+
continue
|
| 974 |
+
|
| 975 |
+
# Get segmentation map and segment information of batch item
|
| 976 |
+
target_size = target_sizes[i] if target_sizes is not None else None
|
| 977 |
+
segmentation, segments = compute_segments(
|
| 978 |
+
mask_probs=mask_probs_item,
|
| 979 |
+
pred_scores=pred_scores_item,
|
| 980 |
+
pred_labels=pred_labels_item,
|
| 981 |
+
mask_threshold=mask_threshold,
|
| 982 |
+
overlap_mask_area_threshold=overlap_mask_area_threshold,
|
| 983 |
+
label_ids_to_fuse=[],
|
| 984 |
+
target_size=target_size,
|
| 985 |
+
)
|
| 986 |
+
|
| 987 |
+
# Return segmentation map in run-length encoding (RLE) format
|
| 988 |
+
if return_coco_annotation:
|
| 989 |
+
segmentation = convert_segmentation_to_rle(segmentation)
|
| 990 |
+
|
| 991 |
+
results.append({"segmentation": segmentation, "segments_info": segments})
|
| 992 |
+
return results
|
| 993 |
+
|
| 994 |
+
def post_process_panoptic_segmentation(
|
| 995 |
+
self,
|
| 996 |
+
outputs,
|
| 997 |
+
threshold: float = 0.5,
|
| 998 |
+
mask_threshold: float = 0.5,
|
| 999 |
+
overlap_mask_area_threshold: float = 0.8,
|
| 1000 |
+
label_ids_to_fuse: set[int] | None = None,
|
| 1001 |
+
target_sizes: list[tuple[int, int]] | None = None,
|
| 1002 |
+
) -> list[dict]:
|
| 1003 |
+
"""
|
| 1004 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into image panoptic segmentation predictions. Only supports
|
| 1005 |
+
PyTorch.
|
| 1006 |
+
|
| 1007 |
+
Args:
|
| 1008 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 1009 |
+
The outputs from [`ConditionalDetrForSegmentation`].
|
| 1010 |
+
threshold (`float`, *optional*, defaults to 0.5):
|
| 1011 |
+
The probability score threshold to keep predicted instance masks.
|
| 1012 |
+
mask_threshold (`float`, *optional*, defaults to 0.5):
|
| 1013 |
+
Threshold to use when turning the predicted masks into binary values.
|
| 1014 |
+
overlap_mask_area_threshold (`float`, *optional*, defaults to 0.8):
|
| 1015 |
+
The overlap mask area threshold to merge or discard small disconnected parts within each binary
|
| 1016 |
+
instance mask.
|
| 1017 |
+
label_ids_to_fuse (`Set[int]`, *optional*):
|
| 1018 |
+
The labels in this state will have all their instances be fused together. For instance we could say
|
| 1019 |
+
there can only be one sky in an image, but several persons, so the label ID for sky would be in that
|
| 1020 |
+
set, but not the one for person.
|
| 1021 |
+
target_sizes (`list[Tuple]`, *optional*):
|
| 1022 |
+
List of length (batch_size), where each list item (`tuple[int, int]]`) corresponds to the requested
|
| 1023 |
+
final size (height, width) of each prediction in batch. If unset, predictions will not be resized.
|
| 1024 |
+
Returns:
|
| 1025 |
+
`list[Dict]`: A list of dictionaries, one per image, each dictionary containing two keys:
|
| 1026 |
+
- **segmentation** -- a tensor of shape `(height, width)` where each pixel represents a `segment_id` or
|
| 1027 |
+
`None` if no mask if found above `threshold`. If `target_sizes` is specified, segmentation is resized to
|
| 1028 |
+
the corresponding `target_sizes` entry.
|
| 1029 |
+
- **segments_info** -- A dictionary that contains additional information on each segment.
|
| 1030 |
+
- **id** -- an integer representing the `segment_id`.
|
| 1031 |
+
- **label_id** -- An integer representing the label / semantic class id corresponding to `segment_id`.
|
| 1032 |
+
- **was_fused** -- a boolean, `True` if `label_id` was in `label_ids_to_fuse`, `False` otherwise.
|
| 1033 |
+
Multiple instances of the same class / label were fused and assigned a single `segment_id`.
|
| 1034 |
+
- **score** -- Prediction score of segment with `segment_id`.
|
| 1035 |
+
"""
|
| 1036 |
+
|
| 1037 |
+
if label_ids_to_fuse is None:
|
| 1038 |
+
logger.warning_once("`label_ids_to_fuse` unset. No instance will be fused.")
|
| 1039 |
+
label_ids_to_fuse = set()
|
| 1040 |
+
|
| 1041 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes+1]
|
| 1042 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 1043 |
+
|
| 1044 |
+
batch_size = class_queries_logits.shape[0]
|
| 1045 |
+
num_labels = class_queries_logits.shape[-1] - 1
|
| 1046 |
+
|
| 1047 |
+
mask_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 1048 |
+
|
| 1049 |
+
# Predicted label and score of each query (batch_size, num_queries)
|
| 1050 |
+
pred_scores, pred_labels = nn.functional.softmax(class_queries_logits, dim=-1).max(-1)
|
| 1051 |
+
|
| 1052 |
+
# Loop over items in batch size
|
| 1053 |
+
results: list[dict[str, TensorType]] = []
|
| 1054 |
+
|
| 1055 |
+
for i in range(batch_size):
|
| 1056 |
+
mask_probs_item, pred_scores_item, pred_labels_item = remove_low_and_no_objects(
|
| 1057 |
+
mask_probs[i], pred_scores[i], pred_labels[i], threshold, num_labels
|
| 1058 |
+
)
|
| 1059 |
+
|
| 1060 |
+
# No mask found
|
| 1061 |
+
if mask_probs_item.shape[0] <= 0:
|
| 1062 |
+
height, width = target_sizes[i] if target_sizes is not None else mask_probs_item.shape[1:]
|
| 1063 |
+
segmentation = torch.zeros((height, width)) - 1
|
| 1064 |
+
results.append({"segmentation": segmentation, "segments_info": []})
|
| 1065 |
+
continue
|
| 1066 |
+
|
| 1067 |
+
# Get segmentation map and segment information of batch item
|
| 1068 |
+
target_size = target_sizes[i] if target_sizes is not None else None
|
| 1069 |
+
segmentation, segments = compute_segments(
|
| 1070 |
+
mask_probs=mask_probs_item,
|
| 1071 |
+
pred_scores=pred_scores_item,
|
| 1072 |
+
pred_labels=pred_labels_item,
|
| 1073 |
+
mask_threshold=mask_threshold,
|
| 1074 |
+
overlap_mask_area_threshold=overlap_mask_area_threshold,
|
| 1075 |
+
label_ids_to_fuse=label_ids_to_fuse,
|
| 1076 |
+
target_size=target_size,
|
| 1077 |
+
)
|
| 1078 |
+
|
| 1079 |
+
results.append({"segmentation": segmentation, "segments_info": segments})
|
| 1080 |
+
return results
|
| 1081 |
+
|
| 1082 |
+
|
| 1083 |
+
__all__ = ["ConditionalDetrImageProcessor"]
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/conditional_detr/image_processing_pil_conditional_detr.py
ADDED
|
@@ -0,0 +1,1135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/conditional_detr/modular_conditional_detr.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_conditional_detr.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2022 Microsoft Research Asia and The HuggingFace Inc. team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 10 |
+
# you may not use this file except in compliance with the License.
|
| 11 |
+
# You may obtain a copy of the License at
|
| 12 |
+
#
|
| 13 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 14 |
+
#
|
| 15 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 16 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 17 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 18 |
+
# See the License for the specific language governing permissions and
|
| 19 |
+
# limitations under the License.
|
| 20 |
+
|
| 21 |
+
import pathlib
|
| 22 |
+
from typing import Any, Optional
|
| 23 |
+
|
| 24 |
+
import numpy as np
|
| 25 |
+
|
| 26 |
+
from ...image_processing_backends import PilBackend
|
| 27 |
+
from ...image_processing_utils import BatchFeature
|
| 28 |
+
from ...image_transforms import (
|
| 29 |
+
PaddingMode,
|
| 30 |
+
center_to_corners_format,
|
| 31 |
+
corners_to_center_format,
|
| 32 |
+
get_size_with_aspect_ratio,
|
| 33 |
+
pad,
|
| 34 |
+
resize,
|
| 35 |
+
safe_squeeze,
|
| 36 |
+
)
|
| 37 |
+
from ...image_utils import (
|
| 38 |
+
IMAGENET_DEFAULT_MEAN,
|
| 39 |
+
IMAGENET_DEFAULT_STD,
|
| 40 |
+
AnnotationFormat,
|
| 41 |
+
AnnotationType,
|
| 42 |
+
ChannelDimension,
|
| 43 |
+
ImageInput,
|
| 44 |
+
PILImageResampling,
|
| 45 |
+
SizeDict,
|
| 46 |
+
get_image_size,
|
| 47 |
+
get_image_size_for_max_height_width,
|
| 48 |
+
get_max_height_width,
|
| 49 |
+
validate_annotations,
|
| 50 |
+
)
|
| 51 |
+
from ...processing_utils import ImagesKwargs, Unpack
|
| 52 |
+
from ...utils import TensorType, auto_docstring, is_torch_available, is_vision_available, logging, requires_backends
|
| 53 |
+
from ...utils.import_utils import requires
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
if is_vision_available():
|
| 57 |
+
import PIL.Image
|
| 58 |
+
if is_torch_available():
|
| 59 |
+
import torch
|
| 60 |
+
from torch import nn
|
| 61 |
+
|
| 62 |
+
logger = logging.get_logger(__name__)
|
| 63 |
+
|
| 64 |
+
SUPPORTED_ANNOTATION_FORMATS = (AnnotationFormat.COCO_DETECTION, AnnotationFormat.COCO_PANOPTIC)
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
class ConditionalDetrImageProcessorKwargs(ImagesKwargs, total=False):
|
| 68 |
+
r"""
|
| 69 |
+
format (`str`, *optional*, defaults to `AnnotationFormat.COCO_DETECTION`):
|
| 70 |
+
Data format of the annotations. One of "coco_detection" or "coco_panoptic".
|
| 71 |
+
do_convert_annotations (`bool`, *optional*, defaults to `True`):
|
| 72 |
+
Controls whether to convert the annotations to the format expected by the CONDITIONAL_DETR model. Converts the
|
| 73 |
+
bounding boxes to the format `(center_x, center_y, width, height)` and in the range `[0, 1]`.
|
| 74 |
+
Can be overridden by the `do_convert_annotations` parameter in the `preprocess` method.
|
| 75 |
+
"""
|
| 76 |
+
|
| 77 |
+
format: str | AnnotationFormat
|
| 78 |
+
do_convert_annotations: bool
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
# inspired by https://github.com/facebookresearch/conditional_detr/blob/master/datasets/coco.py#L33
|
| 82 |
+
def convert_coco_poly_to_mask(segmentations, height: int, width: int) -> np.ndarray:
|
| 83 |
+
"""
|
| 84 |
+
Convert a COCO polygon annotation to a mask.
|
| 85 |
+
|
| 86 |
+
Args:
|
| 87 |
+
segmentations (`list[list[float]]`):
|
| 88 |
+
List of polygons, each polygon represented by a list of x-y coordinates.
|
| 89 |
+
height (`int`):
|
| 90 |
+
Height of the mask.
|
| 91 |
+
width (`int`):
|
| 92 |
+
Width of the mask.
|
| 93 |
+
"""
|
| 94 |
+
try:
|
| 95 |
+
from pycocotools import mask as coco_mask
|
| 96 |
+
except ImportError:
|
| 97 |
+
raise ImportError("Pycocotools is not installed in your environment.")
|
| 98 |
+
|
| 99 |
+
masks = []
|
| 100 |
+
for polygons in segmentations:
|
| 101 |
+
rles = coco_mask.frPyObjects(polygons, height, width)
|
| 102 |
+
mask = coco_mask.decode(rles)
|
| 103 |
+
if len(mask.shape) < 3:
|
| 104 |
+
mask = mask[..., None]
|
| 105 |
+
mask = np.asarray(mask, dtype=np.uint8)
|
| 106 |
+
mask = np.any(mask, axis=2)
|
| 107 |
+
masks.append(mask)
|
| 108 |
+
if masks:
|
| 109 |
+
masks = np.stack(masks, axis=0)
|
| 110 |
+
else:
|
| 111 |
+
masks = np.zeros((0, height, width), dtype=np.uint8)
|
| 112 |
+
|
| 113 |
+
return masks
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
# inspired by https://github.com/facebookresearch/conditional_detr/blob/master/datasets/coco.py#L50
|
| 117 |
+
def prepare_coco_detection_annotation(
|
| 118 |
+
image,
|
| 119 |
+
target,
|
| 120 |
+
return_segmentation_masks: bool = False,
|
| 121 |
+
input_data_format: ChannelDimension | str | None = None,
|
| 122 |
+
):
|
| 123 |
+
"""
|
| 124 |
+
Convert the target in COCO format into the format expected by CONDITIONAL_DETR.
|
| 125 |
+
"""
|
| 126 |
+
image_height, image_width = get_image_size(image, channel_dim=input_data_format)
|
| 127 |
+
|
| 128 |
+
image_id = target["image_id"]
|
| 129 |
+
image_id = np.asarray([image_id], dtype=np.int64)
|
| 130 |
+
|
| 131 |
+
# Get all COCO annotations for the given image.
|
| 132 |
+
annotations = target["annotations"]
|
| 133 |
+
annotations = [obj for obj in annotations if "iscrowd" not in obj or obj["iscrowd"] == 0]
|
| 134 |
+
|
| 135 |
+
classes = [obj["category_id"] for obj in annotations]
|
| 136 |
+
classes = np.asarray(classes, dtype=np.int64)
|
| 137 |
+
|
| 138 |
+
# for conversion to coco api
|
| 139 |
+
area = np.asarray([obj["area"] for obj in annotations], dtype=np.float32)
|
| 140 |
+
iscrowd = np.asarray([obj.get("iscrowd", 0) for obj in annotations], dtype=np.int64)
|
| 141 |
+
|
| 142 |
+
boxes = [obj["bbox"] for obj in annotations]
|
| 143 |
+
# guard against no boxes via resizing
|
| 144 |
+
boxes = np.asarray(boxes, dtype=np.float32).reshape(-1, 4)
|
| 145 |
+
boxes[:, 2:] += boxes[:, :2]
|
| 146 |
+
boxes[:, 0::2] = boxes[:, 0::2].clip(min=0, max=image_width)
|
| 147 |
+
boxes[:, 1::2] = boxes[:, 1::2].clip(min=0, max=image_height)
|
| 148 |
+
|
| 149 |
+
keep = (boxes[:, 3] > boxes[:, 1]) & (boxes[:, 2] > boxes[:, 0])
|
| 150 |
+
|
| 151 |
+
new_target = {}
|
| 152 |
+
new_target["image_id"] = image_id
|
| 153 |
+
new_target["class_labels"] = classes[keep]
|
| 154 |
+
new_target["boxes"] = boxes[keep]
|
| 155 |
+
new_target["area"] = area[keep]
|
| 156 |
+
new_target["iscrowd"] = iscrowd[keep]
|
| 157 |
+
new_target["orig_size"] = np.asarray([int(image_height), int(image_width)], dtype=np.int64)
|
| 158 |
+
|
| 159 |
+
if annotations and "keypoints" in annotations[0]:
|
| 160 |
+
keypoints = [obj["keypoints"] for obj in annotations]
|
| 161 |
+
# Converting the filtered keypoints list to a numpy array
|
| 162 |
+
keypoints = np.asarray(keypoints, dtype=np.float32)
|
| 163 |
+
# Apply the keep mask here to filter the relevant annotations
|
| 164 |
+
keypoints = keypoints[keep]
|
| 165 |
+
num_keypoints = keypoints.shape[0]
|
| 166 |
+
keypoints = keypoints.reshape((-1, 3)) if num_keypoints else keypoints
|
| 167 |
+
new_target["keypoints"] = keypoints
|
| 168 |
+
|
| 169 |
+
if return_segmentation_masks:
|
| 170 |
+
segmentation_masks = [obj["segmentation"] for obj in annotations]
|
| 171 |
+
masks = convert_coco_poly_to_mask(segmentation_masks, image_height, image_width)
|
| 172 |
+
new_target["masks"] = masks[keep]
|
| 173 |
+
|
| 174 |
+
return new_target
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
def masks_to_boxes(masks: np.ndarray) -> np.ndarray:
|
| 178 |
+
"""
|
| 179 |
+
Compute the bounding boxes around the provided panoptic segmentation masks.
|
| 180 |
+
|
| 181 |
+
Args:
|
| 182 |
+
masks: masks in format `[number_masks, height, width]` where N is the number of masks
|
| 183 |
+
|
| 184 |
+
Returns:
|
| 185 |
+
boxes: bounding boxes in format `[number_masks, 4]` in xyxy format
|
| 186 |
+
"""
|
| 187 |
+
if masks.size == 0:
|
| 188 |
+
return np.zeros((0, 4))
|
| 189 |
+
|
| 190 |
+
h, w = masks.shape[-2:]
|
| 191 |
+
y = np.arange(0, h, dtype=np.float32)
|
| 192 |
+
x = np.arange(0, w, dtype=np.float32)
|
| 193 |
+
# see https://github.com/pytorch/pytorch/issues/50276
|
| 194 |
+
y, x = np.meshgrid(y, x, indexing="ij")
|
| 195 |
+
|
| 196 |
+
x_mask = masks * np.expand_dims(x, axis=0)
|
| 197 |
+
x_max = x_mask.reshape(x_mask.shape[0], -1).max(-1)
|
| 198 |
+
x = np.ma.array(x_mask, mask=~(np.array(masks, dtype=bool)))
|
| 199 |
+
x_min = x.filled(fill_value=1e8)
|
| 200 |
+
x_min = x_min.reshape(x_min.shape[0], -1).min(-1)
|
| 201 |
+
|
| 202 |
+
y_mask = masks * np.expand_dims(y, axis=0)
|
| 203 |
+
y_max = y_mask.reshape(x_mask.shape[0], -1).max(-1)
|
| 204 |
+
y = np.ma.array(y_mask, mask=~(np.array(masks, dtype=bool)))
|
| 205 |
+
y_min = y.filled(fill_value=1e8)
|
| 206 |
+
y_min = y_min.reshape(y_min.shape[0], -1).min(-1)
|
| 207 |
+
|
| 208 |
+
return np.stack([x_min, y_min, x_max, y_max], 1)
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
# 2 functions below adapted from https://github.com/cocodataset/panopticapi/blob/master/panopticapi/utils.py
|
| 212 |
+
# Copyright (c) 2018, Alexander Kirillov
|
| 213 |
+
# All rights reserved.
|
| 214 |
+
def rgb_to_id(color):
|
| 215 |
+
"""
|
| 216 |
+
Converts RGB color to unique ID.
|
| 217 |
+
"""
|
| 218 |
+
if isinstance(color, np.ndarray) and len(color.shape) == 3:
|
| 219 |
+
if color.dtype == np.uint8:
|
| 220 |
+
color = color.astype(np.int32)
|
| 221 |
+
return color[:, :, 0] + 256 * color[:, :, 1] + 256 * 256 * color[:, :, 2]
|
| 222 |
+
return int(color[0] + 256 * color[1] + 256 * 256 * color[2])
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
def prepare_coco_panoptic_annotation(
|
| 226 |
+
image: np.ndarray,
|
| 227 |
+
target: dict,
|
| 228 |
+
masks_path: str | pathlib.Path,
|
| 229 |
+
return_masks: bool = True,
|
| 230 |
+
input_data_format: ChannelDimension | str = None,
|
| 231 |
+
) -> dict:
|
| 232 |
+
"""
|
| 233 |
+
Prepare a coco panoptic annotation for CONDITIONAL_DETR.
|
| 234 |
+
"""
|
| 235 |
+
image_height, image_width = get_image_size(image, channel_dim=input_data_format)
|
| 236 |
+
annotation_path = pathlib.Path(masks_path) / target["file_name"]
|
| 237 |
+
|
| 238 |
+
new_target = {}
|
| 239 |
+
new_target["image_id"] = np.asarray([target["image_id"] if "image_id" in target else target["id"]], dtype=np.int64)
|
| 240 |
+
new_target["size"] = np.asarray([image_height, image_width], dtype=np.int64)
|
| 241 |
+
new_target["orig_size"] = np.asarray([image_height, image_width], dtype=np.int64)
|
| 242 |
+
|
| 243 |
+
if "segments_info" in target:
|
| 244 |
+
masks = np.asarray(PIL.Image.open(annotation_path), dtype=np.uint32)
|
| 245 |
+
masks = rgb_to_id(masks)
|
| 246 |
+
|
| 247 |
+
ids = np.array([segment_info["id"] for segment_info in target["segments_info"]])
|
| 248 |
+
masks = masks == ids[:, None, None]
|
| 249 |
+
masks = masks.astype(np.uint8)
|
| 250 |
+
if return_masks:
|
| 251 |
+
new_target["masks"] = masks
|
| 252 |
+
new_target["boxes"] = masks_to_boxes(masks)
|
| 253 |
+
new_target["class_labels"] = np.array(
|
| 254 |
+
[segment_info["category_id"] for segment_info in target["segments_info"]], dtype=np.int64
|
| 255 |
+
)
|
| 256 |
+
new_target["iscrowd"] = np.asarray(
|
| 257 |
+
[segment_info["iscrowd"] for segment_info in target["segments_info"]], dtype=np.int64
|
| 258 |
+
)
|
| 259 |
+
new_target["area"] = np.asarray(
|
| 260 |
+
[segment_info["area"] for segment_info in target["segments_info"]], dtype=np.float32
|
| 261 |
+
)
|
| 262 |
+
|
| 263 |
+
return new_target
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
# Adapted from transformers.models.conditional_detr.image_processing_conditional_detr.binary_mask_to_rle
|
| 267 |
+
def binary_mask_to_rle(mask):
|
| 268 |
+
"""
|
| 269 |
+
Converts given binary mask of shape `(height, width)` to the run-length encoding (RLE) format.
|
| 270 |
+
|
| 271 |
+
Args:
|
| 272 |
+
mask (`torch.Tensor` or `numpy.array`):
|
| 273 |
+
A binary mask tensor of shape `(height, width)` where 0 denotes background and 1 denotes the target
|
| 274 |
+
segment_id or class_id.
|
| 275 |
+
Returns:
|
| 276 |
+
`List`: Run-length encoded list of the binary mask. Refer to COCO API for more information about the RLE
|
| 277 |
+
format.
|
| 278 |
+
"""
|
| 279 |
+
from ...utils import is_torch_tensor
|
| 280 |
+
|
| 281 |
+
if is_torch_tensor(mask):
|
| 282 |
+
mask = mask.numpy()
|
| 283 |
+
|
| 284 |
+
pixels = mask.flatten()
|
| 285 |
+
pixels = np.concatenate([[0], pixels, [0]])
|
| 286 |
+
runs = np.where(pixels[1:] != pixels[:-1])[0] + 1
|
| 287 |
+
runs[1::2] -= runs[::2]
|
| 288 |
+
return list(runs)
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
# Adapted from transformers.models.conditional_detr.image_processing_conditional_detr.check_segment_validity
|
| 292 |
+
def check_segment_validity(mask_labels, mask_probs, k, mask_threshold=0.5, overlap_mask_area_threshold=0.8):
|
| 293 |
+
# Get the mask associated with the k class
|
| 294 |
+
mask_k = mask_labels == k
|
| 295 |
+
mask_k_area = mask_k.sum()
|
| 296 |
+
|
| 297 |
+
# Compute the area of all the stuff in query k
|
| 298 |
+
original_area = (mask_probs[k] >= mask_threshold).sum()
|
| 299 |
+
mask_exists = mask_k_area > 0 and original_area > 0
|
| 300 |
+
|
| 301 |
+
# Eliminate disconnected tiny segments
|
| 302 |
+
if mask_exists:
|
| 303 |
+
area_ratio = mask_k_area / original_area
|
| 304 |
+
if not area_ratio.item() > overlap_mask_area_threshold:
|
| 305 |
+
mask_exists = False
|
| 306 |
+
|
| 307 |
+
return mask_exists, mask_k
|
| 308 |
+
|
| 309 |
+
|
| 310 |
+
# Adapted from transformers.models.conditional_detr.image_processing_conditional_detr.compute_segments
|
| 311 |
+
def compute_segments(
|
| 312 |
+
mask_probs,
|
| 313 |
+
pred_scores,
|
| 314 |
+
pred_labels,
|
| 315 |
+
mask_threshold: float = 0.5,
|
| 316 |
+
overlap_mask_area_threshold: float = 0.8,
|
| 317 |
+
label_ids_to_fuse: set[int] | None = None,
|
| 318 |
+
target_size: tuple[int, int] | None = None,
|
| 319 |
+
):
|
| 320 |
+
import torch
|
| 321 |
+
from torch import nn
|
| 322 |
+
|
| 323 |
+
height = mask_probs.shape[1] if target_size is None else target_size[0]
|
| 324 |
+
width = mask_probs.shape[2] if target_size is None else target_size[1]
|
| 325 |
+
|
| 326 |
+
segmentation = torch.zeros((height, width), dtype=torch.int32, device=mask_probs.device)
|
| 327 |
+
segments: list[dict] = []
|
| 328 |
+
|
| 329 |
+
if target_size is not None:
|
| 330 |
+
mask_probs = nn.functional.interpolate(
|
| 331 |
+
mask_probs.unsqueeze(0), size=target_size, mode="bilinear", align_corners=False
|
| 332 |
+
)[0]
|
| 333 |
+
|
| 334 |
+
current_segment_id = 0
|
| 335 |
+
|
| 336 |
+
# Weigh each mask by its prediction score
|
| 337 |
+
mask_probs *= pred_scores.view(-1, 1, 1)
|
| 338 |
+
mask_labels = mask_probs.argmax(0) # [height, width]
|
| 339 |
+
|
| 340 |
+
# Keep track of instances of each class
|
| 341 |
+
stuff_memory_list: dict[str, int] = {}
|
| 342 |
+
for k in range(pred_labels.shape[0]):
|
| 343 |
+
pred_class = pred_labels[k].item()
|
| 344 |
+
should_fuse = pred_class in label_ids_to_fuse
|
| 345 |
+
|
| 346 |
+
# Check if mask exists and large enough to be a segment
|
| 347 |
+
mask_exists, mask_k = check_segment_validity(
|
| 348 |
+
mask_labels, mask_probs, k, mask_threshold, overlap_mask_area_threshold
|
| 349 |
+
)
|
| 350 |
+
|
| 351 |
+
if mask_exists:
|
| 352 |
+
if pred_class in stuff_memory_list:
|
| 353 |
+
current_segment_id = stuff_memory_list[pred_class]
|
| 354 |
+
else:
|
| 355 |
+
current_segment_id += 1
|
| 356 |
+
|
| 357 |
+
# Add current object segment to final segmentation map
|
| 358 |
+
segmentation[mask_k] = current_segment_id
|
| 359 |
+
segment_score = round(pred_scores[k].item(), 6)
|
| 360 |
+
segments.append(
|
| 361 |
+
{
|
| 362 |
+
"id": current_segment_id,
|
| 363 |
+
"label_id": pred_class,
|
| 364 |
+
"was_fused": should_fuse,
|
| 365 |
+
"score": segment_score,
|
| 366 |
+
}
|
| 367 |
+
)
|
| 368 |
+
if should_fuse:
|
| 369 |
+
stuff_memory_list[pred_class] = current_segment_id
|
| 370 |
+
|
| 371 |
+
return segmentation, segments
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
# Adapted from transformers.models.conditional_detr.image_processing_conditional_detr.convert_segmentation_to_rle
|
| 375 |
+
def convert_segmentation_to_rle(segmentation):
|
| 376 |
+
"""
|
| 377 |
+
Converts given segmentation map of shape `(height, width)` to the run-length encoding (RLE) format.
|
| 378 |
+
|
| 379 |
+
Args:
|
| 380 |
+
segmentation (`torch.Tensor` or `numpy.array`):
|
| 381 |
+
A segmentation map of shape `(height, width)` where each value denotes a segment or class id.
|
| 382 |
+
Returns:
|
| 383 |
+
`list[List]`: A list of lists, where each list is the run-length encoding of a segment / class id.
|
| 384 |
+
"""
|
| 385 |
+
import torch
|
| 386 |
+
|
| 387 |
+
segment_ids = torch.unique(segmentation)
|
| 388 |
+
|
| 389 |
+
run_length_encodings = []
|
| 390 |
+
for idx in segment_ids:
|
| 391 |
+
mask = torch.where(segmentation == idx, 1, 0)
|
| 392 |
+
rle = binary_mask_to_rle(mask)
|
| 393 |
+
run_length_encodings.append(rle)
|
| 394 |
+
|
| 395 |
+
return run_length_encodings
|
| 396 |
+
|
| 397 |
+
|
| 398 |
+
# Adapted from transformers.models.conditional_detr.image_processing_conditional_detr.remove_low_and_no_objects
|
| 399 |
+
def remove_low_and_no_objects(masks, scores, labels, object_mask_threshold, num_labels):
|
| 400 |
+
"""
|
| 401 |
+
Binarize the given masks using `object_mask_threshold`, it returns the associated values of `masks`, `scores` and
|
| 402 |
+
`labels`.
|
| 403 |
+
|
| 404 |
+
Args:
|
| 405 |
+
masks (`torch.Tensor`):
|
| 406 |
+
A tensor of shape `(num_queries, height, width)`.
|
| 407 |
+
scores (`torch.Tensor`):
|
| 408 |
+
A tensor of shape `(num_queries)`.
|
| 409 |
+
labels (`torch.Tensor`):
|
| 410 |
+
A tensor of shape `(num_queries)`.
|
| 411 |
+
object_mask_threshold (`float`):
|
| 412 |
+
A number between 0 and 1 used to binarize the masks.
|
| 413 |
+
Raises:
|
| 414 |
+
`ValueError`: Raised when the first dimension doesn't match in all input tensors.
|
| 415 |
+
Returns:
|
| 416 |
+
`tuple[`torch.Tensor`, `torch.Tensor`, `torch.Tensor`]`: The `masks`, `scores` and `labels` without the region
|
| 417 |
+
< `object_mask_threshold`.
|
| 418 |
+
"""
|
| 419 |
+
if not (masks.shape[0] == scores.shape[0] == labels.shape[0]):
|
| 420 |
+
raise ValueError("mask, scores and labels must have the same shape!")
|
| 421 |
+
|
| 422 |
+
to_keep = labels.ne(num_labels) & (scores > object_mask_threshold)
|
| 423 |
+
|
| 424 |
+
return masks[to_keep], scores[to_keep], labels[to_keep]
|
| 425 |
+
|
| 426 |
+
|
| 427 |
+
@auto_docstring
|
| 428 |
+
class ConditionalDetrImageProcessorPil(PilBackend):
|
| 429 |
+
resample = PILImageResampling.BILINEAR
|
| 430 |
+
image_mean = IMAGENET_DEFAULT_MEAN
|
| 431 |
+
image_std = IMAGENET_DEFAULT_STD
|
| 432 |
+
format = AnnotationFormat.COCO_DETECTION
|
| 433 |
+
do_resize = True
|
| 434 |
+
do_rescale = True
|
| 435 |
+
do_normalize = True
|
| 436 |
+
do_pad = True
|
| 437 |
+
size = {"shortest_edge": 800, "longest_edge": 1333}
|
| 438 |
+
default_to_square = False
|
| 439 |
+
model_input_names = ["pixel_values", "pixel_mask"]
|
| 440 |
+
valid_kwargs = ConditionalDetrImageProcessorKwargs
|
| 441 |
+
|
| 442 |
+
def __init__(self, **kwargs: Unpack[ConditionalDetrImageProcessorKwargs]) -> None:
|
| 443 |
+
kwargs.setdefault("do_pad", kwargs.pop("pad_and_return_pixel_mask", self.do_pad))
|
| 444 |
+
|
| 445 |
+
size = kwargs.pop("size", None)
|
| 446 |
+
max_size = None if size is None else kwargs.pop("max_size", 1333)
|
| 447 |
+
size = size if size is not None else {"shortest_edge": 800, "longest_edge": 1333}
|
| 448 |
+
# Convert size dict for backwards compat with max_size parameter
|
| 449 |
+
if size is not None:
|
| 450 |
+
from ...image_processing_utils import get_size_dict
|
| 451 |
+
|
| 452 |
+
kwargs["size"] = get_size_dict(size, max_size=max_size, default_to_square=False)
|
| 453 |
+
|
| 454 |
+
# Backwards compatibility
|
| 455 |
+
do_convert_annotations = kwargs.get("do_convert_annotations")
|
| 456 |
+
do_normalize = kwargs.get("do_normalize")
|
| 457 |
+
if do_convert_annotations is None and getattr(self, "do_convert_annotations", None) is None:
|
| 458 |
+
self.do_convert_annotations = do_normalize if do_normalize is not None else self.do_normalize
|
| 459 |
+
|
| 460 |
+
super().__init__(**kwargs)
|
| 461 |
+
|
| 462 |
+
def prepare_annotation(
|
| 463 |
+
self,
|
| 464 |
+
image: np.ndarray,
|
| 465 |
+
target: dict,
|
| 466 |
+
format: AnnotationFormat | None = None,
|
| 467 |
+
return_segmentation_masks: bool | None = None,
|
| 468 |
+
masks_path: str | pathlib.Path | None = None,
|
| 469 |
+
input_data_format: str | ChannelDimension | None = None,
|
| 470 |
+
) -> dict:
|
| 471 |
+
"""
|
| 472 |
+
Prepare an annotation for feeding into CONDITIONAL_DETR model.
|
| 473 |
+
"""
|
| 474 |
+
format = format if format is not None else self.format
|
| 475 |
+
|
| 476 |
+
if format == AnnotationFormat.COCO_DETECTION:
|
| 477 |
+
return_segmentation_masks = False if return_segmentation_masks is None else return_segmentation_masks
|
| 478 |
+
target = prepare_coco_detection_annotation(
|
| 479 |
+
image, target, return_segmentation_masks, input_data_format=input_data_format
|
| 480 |
+
)
|
| 481 |
+
elif format == AnnotationFormat.COCO_PANOPTIC:
|
| 482 |
+
return_segmentation_masks = True if return_segmentation_masks is None else return_segmentation_masks
|
| 483 |
+
target = prepare_coco_panoptic_annotation(
|
| 484 |
+
image,
|
| 485 |
+
target,
|
| 486 |
+
masks_path=masks_path,
|
| 487 |
+
return_masks=return_segmentation_masks,
|
| 488 |
+
input_data_format=input_data_format,
|
| 489 |
+
)
|
| 490 |
+
else:
|
| 491 |
+
raise ValueError(f"Format {format} is not supported.")
|
| 492 |
+
return target
|
| 493 |
+
|
| 494 |
+
def resize(
|
| 495 |
+
self,
|
| 496 |
+
image: np.ndarray,
|
| 497 |
+
size: SizeDict,
|
| 498 |
+
resample: Optional["PILImageResampling"] = None,
|
| 499 |
+
**kwargs,
|
| 500 |
+
) -> np.ndarray:
|
| 501 |
+
"""
|
| 502 |
+
Resize the image to the given size. Size can be `min_size` (scalar) or `(height, width)` tuple. If size is an
|
| 503 |
+
int, smaller edge of the image will be matched to this number.
|
| 504 |
+
|
| 505 |
+
Args:
|
| 506 |
+
image (`np.ndarray`):
|
| 507 |
+
Image to resize.
|
| 508 |
+
size (`SizeDict`):
|
| 509 |
+
Size of the image's `(height, width)` dimensions after resizing. Available options are:
|
| 510 |
+
- `{"height": int, "width": int}`: The image will be resized to the exact size `(height, width)`.
|
| 511 |
+
Do NOT keep the aspect ratio.
|
| 512 |
+
- `{"shortest_edge": int, "longest_edge": int}`: The image will be resized to a maximum size respecting
|
| 513 |
+
the aspect ratio and keeping the shortest edge less or equal to `shortest_edge` and the longest edge
|
| 514 |
+
less or equal to `longest_edge`.
|
| 515 |
+
- `{"max_height": int, "max_width": int}`: The image will be resized to the maximum size respecting the
|
| 516 |
+
aspect ratio and keeping the height less or equal to `max_height` and the width less or equal to
|
| 517 |
+
`max_width`.
|
| 518 |
+
resample (`PILImageResampling`, *optional*, defaults to `PILImageResampling.BILINEAR`):
|
| 519 |
+
Resampling filter to use if resizing the image.
|
| 520 |
+
"""
|
| 521 |
+
resample = resample if resample is not None else self.resample
|
| 522 |
+
|
| 523 |
+
if size.shortest_edge and size.longest_edge:
|
| 524 |
+
# Resize the image so that the shortest edge or the longest edge is of the given size
|
| 525 |
+
# while maintaining the aspect ratio of the original image.
|
| 526 |
+
new_size = get_size_with_aspect_ratio(
|
| 527 |
+
image.shape[-2:],
|
| 528 |
+
size.shortest_edge,
|
| 529 |
+
size.longest_edge or size.shortest_edge,
|
| 530 |
+
)
|
| 531 |
+
elif size.max_height and size.max_width:
|
| 532 |
+
new_size = get_image_size_for_max_height_width(image.shape[-2:], size.max_height, size.max_width)
|
| 533 |
+
elif size.height and size.width:
|
| 534 |
+
new_size = (size.height, size.width)
|
| 535 |
+
else:
|
| 536 |
+
raise ValueError(
|
| 537 |
+
f"Size must contain 'height' and 'width' keys or 'shortest_edge' and 'longest_edge' keys. Got {size}."
|
| 538 |
+
)
|
| 539 |
+
|
| 540 |
+
image = super().resize(
|
| 541 |
+
image,
|
| 542 |
+
size=SizeDict(height=new_size[0], width=new_size[1]),
|
| 543 |
+
resample=resample,
|
| 544 |
+
**kwargs,
|
| 545 |
+
)
|
| 546 |
+
return image
|
| 547 |
+
|
| 548 |
+
def resize_annotation(
|
| 549 |
+
self,
|
| 550 |
+
annotation: dict[str, Any],
|
| 551 |
+
orig_size: tuple[int, int],
|
| 552 |
+
target_size: tuple[int, int],
|
| 553 |
+
threshold: float = 0.5,
|
| 554 |
+
resample: Optional["PILImageResampling"] = PILImageResampling.NEAREST,
|
| 555 |
+
):
|
| 556 |
+
"""
|
| 557 |
+
Resizes an annotation to a target size.
|
| 558 |
+
|
| 559 |
+
Args:
|
| 560 |
+
annotation (`dict[str, Any]`):
|
| 561 |
+
The annotation dictionary.
|
| 562 |
+
orig_size (`tuple[int, int]`):
|
| 563 |
+
The original size of the input image.
|
| 564 |
+
target_size (`tuple[int, int]`):
|
| 565 |
+
The target size of the image, as returned by the preprocessing `resize` step.
|
| 566 |
+
threshold (`float`, *optional*, defaults to 0.5):
|
| 567 |
+
The threshold used to binarize the segmentation masks.
|
| 568 |
+
resample (`PILImageResampling`, defaults to `PILImageResampling.NEAREST`):
|
| 569 |
+
The resampling filter to use when resizing the masks.
|
| 570 |
+
"""
|
| 571 |
+
ratios = tuple(float(s) / float(s_orig) for s, s_orig in zip(target_size, orig_size))
|
| 572 |
+
ratio_height, ratio_width = ratios
|
| 573 |
+
|
| 574 |
+
new_annotation = {}
|
| 575 |
+
new_annotation["size"] = target_size
|
| 576 |
+
|
| 577 |
+
for key, value in annotation.items():
|
| 578 |
+
if key == "boxes":
|
| 579 |
+
boxes = value
|
| 580 |
+
scaled_boxes = boxes * np.asarray(
|
| 581 |
+
[ratio_width, ratio_height, ratio_width, ratio_height], dtype=np.float32
|
| 582 |
+
)
|
| 583 |
+
new_annotation["boxes"] = scaled_boxes
|
| 584 |
+
elif key == "area":
|
| 585 |
+
area = value
|
| 586 |
+
scaled_area = area * (ratio_width * ratio_height)
|
| 587 |
+
new_annotation["area"] = scaled_area
|
| 588 |
+
elif key == "masks":
|
| 589 |
+
masks = value[:, None]
|
| 590 |
+
masks = np.array([resize(mask, target_size, resample=resample) for mask in masks])
|
| 591 |
+
masks = masks.astype(np.float32)
|
| 592 |
+
masks = masks[:, 0] > threshold
|
| 593 |
+
new_annotation["masks"] = masks
|
| 594 |
+
elif key == "size":
|
| 595 |
+
new_annotation["size"] = target_size
|
| 596 |
+
else:
|
| 597 |
+
new_annotation[key] = value
|
| 598 |
+
|
| 599 |
+
return new_annotation
|
| 600 |
+
|
| 601 |
+
def normalize_annotation(self, annotation: dict, image_size: tuple[int, int]) -> dict:
|
| 602 |
+
image_height, image_width = image_size
|
| 603 |
+
norm_annotation = {}
|
| 604 |
+
for key, value in annotation.items():
|
| 605 |
+
if key == "boxes":
|
| 606 |
+
boxes = value
|
| 607 |
+
boxes = corners_to_center_format(boxes)
|
| 608 |
+
boxes /= np.asarray([image_width, image_height, image_width, image_height], dtype=np.float32)
|
| 609 |
+
norm_annotation[key] = boxes
|
| 610 |
+
else:
|
| 611 |
+
norm_annotation[key] = value
|
| 612 |
+
return norm_annotation
|
| 613 |
+
|
| 614 |
+
def _update_annotation_for_padded_image(
|
| 615 |
+
self,
|
| 616 |
+
annotation: dict,
|
| 617 |
+
input_image_size: tuple[int, int],
|
| 618 |
+
output_image_size: tuple[int, int],
|
| 619 |
+
padding,
|
| 620 |
+
update_bboxes,
|
| 621 |
+
) -> dict:
|
| 622 |
+
"""
|
| 623 |
+
Update the annotation for a padded image.
|
| 624 |
+
"""
|
| 625 |
+
new_annotation = {}
|
| 626 |
+
new_annotation["size"] = output_image_size
|
| 627 |
+
ratio_height, ratio_width = (input / output for output, input in zip(output_image_size, input_image_size))
|
| 628 |
+
|
| 629 |
+
for key, value in annotation.items():
|
| 630 |
+
if key == "masks":
|
| 631 |
+
masks = value
|
| 632 |
+
masks = pad(
|
| 633 |
+
masks,
|
| 634 |
+
padding,
|
| 635 |
+
mode=PaddingMode.CONSTANT,
|
| 636 |
+
constant_values=0,
|
| 637 |
+
input_data_format=ChannelDimension.FIRST,
|
| 638 |
+
)
|
| 639 |
+
masks = safe_squeeze(masks, 1)
|
| 640 |
+
new_annotation["masks"] = masks
|
| 641 |
+
elif key == "boxes" and update_bboxes:
|
| 642 |
+
boxes = value
|
| 643 |
+
boxes *= np.asarray(
|
| 644 |
+
[
|
| 645 |
+
input_image_size[1] / output_image_size[1],
|
| 646 |
+
input_image_size[0] / output_image_size[0],
|
| 647 |
+
input_image_size[1] / output_image_size[1],
|
| 648 |
+
input_image_size[0] / output_image_size[0],
|
| 649 |
+
]
|
| 650 |
+
)
|
| 651 |
+
new_annotation["boxes"] = boxes
|
| 652 |
+
elif key == "size":
|
| 653 |
+
new_annotation["size"] = output_image_size
|
| 654 |
+
else:
|
| 655 |
+
new_annotation[key] = value
|
| 656 |
+
return new_annotation
|
| 657 |
+
|
| 658 |
+
def pad(
|
| 659 |
+
self,
|
| 660 |
+
image: np.ndarray,
|
| 661 |
+
padded_size: tuple[int, int],
|
| 662 |
+
annotation: dict[str, Any] | None = None,
|
| 663 |
+
update_bboxes: bool = True,
|
| 664 |
+
fill: int = 0,
|
| 665 |
+
):
|
| 666 |
+
input_height, input_width = get_image_size(image, channel_dim=ChannelDimension.FIRST)
|
| 667 |
+
output_height, output_width = padded_size
|
| 668 |
+
padding_bottom = output_height - input_height
|
| 669 |
+
padding_right = output_width - input_width
|
| 670 |
+
if padding_bottom < 0 or padding_right < 0:
|
| 671 |
+
raise ValueError(
|
| 672 |
+
f"Padding dimensions are negative. Please make sure that the padded size is larger than the "
|
| 673 |
+
f"original size. Got padded size: {padded_size}, original size: {(input_height, input_width)}."
|
| 674 |
+
)
|
| 675 |
+
if (input_height, input_width) != padded_size:
|
| 676 |
+
padding = ((0, padding_bottom), (0, padding_right))
|
| 677 |
+
image = pad(
|
| 678 |
+
image,
|
| 679 |
+
padding,
|
| 680 |
+
mode=PaddingMode.CONSTANT,
|
| 681 |
+
constant_values=fill,
|
| 682 |
+
data_format=ChannelDimension.FIRST,
|
| 683 |
+
input_data_format=ChannelDimension.FIRST,
|
| 684 |
+
)
|
| 685 |
+
if annotation is not None:
|
| 686 |
+
annotation = self._update_annotation_for_padded_image(
|
| 687 |
+
annotation, (input_height, input_width), (output_height, output_width), padding, update_bboxes
|
| 688 |
+
)
|
| 689 |
+
|
| 690 |
+
# Make a pixel mask for the image, where 1 indicates a valid pixel and 0 indicates padding.
|
| 691 |
+
pixel_mask = np.zeros(padded_size, dtype=np.int64)
|
| 692 |
+
pixel_mask[:input_height, :input_width] = 1
|
| 693 |
+
|
| 694 |
+
return image, pixel_mask, annotation
|
| 695 |
+
|
| 696 |
+
@auto_docstring
|
| 697 |
+
def preprocess(
|
| 698 |
+
self,
|
| 699 |
+
images: ImageInput,
|
| 700 |
+
annotations: AnnotationType | list[AnnotationType] | None = None,
|
| 701 |
+
return_segmentation_masks: bool | None = None,
|
| 702 |
+
masks_path: str | pathlib.Path | None = None,
|
| 703 |
+
**kwargs: Unpack[ConditionalDetrImageProcessorKwargs],
|
| 704 |
+
) -> BatchFeature:
|
| 705 |
+
r"""
|
| 706 |
+
annotations (`AnnotationType` or `list[AnnotationType]`, *optional*):
|
| 707 |
+
Annotations to transform according to the padding that is applied to the images.
|
| 708 |
+
return_segmentation_masks (`bool`, *optional*, defaults to `self.return_segmentation_masks`):
|
| 709 |
+
Whether to return segmentation masks.
|
| 710 |
+
masks_path (`str` or `pathlib.Path`, *optional*):
|
| 711 |
+
Path to the directory containing the segmentation masks.
|
| 712 |
+
"""
|
| 713 |
+
return super().preprocess(images, annotations, return_segmentation_masks, masks_path, **kwargs)
|
| 714 |
+
|
| 715 |
+
def _preprocess(
|
| 716 |
+
self,
|
| 717 |
+
images: list[np.ndarray],
|
| 718 |
+
annotations: AnnotationType | list[AnnotationType] | None,
|
| 719 |
+
return_segmentation_masks: bool,
|
| 720 |
+
masks_path: str | pathlib.Path | None,
|
| 721 |
+
do_resize: bool,
|
| 722 |
+
size: SizeDict,
|
| 723 |
+
resample: "PILImageResampling | None",
|
| 724 |
+
do_rescale: bool,
|
| 725 |
+
rescale_factor: float,
|
| 726 |
+
do_normalize: bool,
|
| 727 |
+
do_convert_annotations: bool,
|
| 728 |
+
image_mean: float | list[float] | None,
|
| 729 |
+
image_std: float | list[float] | None,
|
| 730 |
+
do_pad: bool,
|
| 731 |
+
pad_size: SizeDict | None,
|
| 732 |
+
format: str | AnnotationFormat | None,
|
| 733 |
+
return_tensors: str | TensorType | None,
|
| 734 |
+
**kwargs,
|
| 735 |
+
) -> BatchFeature:
|
| 736 |
+
"""
|
| 737 |
+
Preprocess an image or a batch of images so that it can be used by the model.
|
| 738 |
+
"""
|
| 739 |
+
if annotations is not None and isinstance(annotations, dict):
|
| 740 |
+
annotations = [annotations]
|
| 741 |
+
|
| 742 |
+
if annotations is not None and len(images) != len(annotations):
|
| 743 |
+
raise ValueError(
|
| 744 |
+
f"The number of images ({len(images)}) and annotations ({len(annotations)}) do not match."
|
| 745 |
+
)
|
| 746 |
+
|
| 747 |
+
format = AnnotationFormat(format)
|
| 748 |
+
if annotations is not None:
|
| 749 |
+
validate_annotations(format, SUPPORTED_ANNOTATION_FORMATS, annotations)
|
| 750 |
+
|
| 751 |
+
if (
|
| 752 |
+
masks_path is not None
|
| 753 |
+
and format == AnnotationFormat.COCO_PANOPTIC
|
| 754 |
+
and not isinstance(masks_path, (pathlib.Path, str))
|
| 755 |
+
):
|
| 756 |
+
raise ValueError(
|
| 757 |
+
"The path to the directory containing the mask PNG files should be provided as a"
|
| 758 |
+
f" `pathlib.Path` or string object, but is {type(masks_path)} instead."
|
| 759 |
+
)
|
| 760 |
+
|
| 761 |
+
data = {}
|
| 762 |
+
|
| 763 |
+
# Import torch if needed for tensor conversion
|
| 764 |
+
if return_tensors == "pt":
|
| 765 |
+
if not is_torch_available():
|
| 766 |
+
raise ImportError("PyTorch is required for tensor conversion.")
|
| 767 |
+
|
| 768 |
+
processed_images = []
|
| 769 |
+
processed_annotations = []
|
| 770 |
+
pixel_masks = [] # Initialize pixel_masks here
|
| 771 |
+
for image, annotation in zip(images, annotations if annotations is not None else [None] * len(images)):
|
| 772 |
+
# prepare (COCO annotations as a list of Dict -> CONDITIONAL_DETR target as a single Dict per image)
|
| 773 |
+
if annotations is not None:
|
| 774 |
+
annotation = self.prepare_annotation(
|
| 775 |
+
image,
|
| 776 |
+
annotation,
|
| 777 |
+
format,
|
| 778 |
+
return_segmentation_masks=return_segmentation_masks,
|
| 779 |
+
masks_path=masks_path,
|
| 780 |
+
input_data_format=ChannelDimension.FIRST,
|
| 781 |
+
)
|
| 782 |
+
|
| 783 |
+
if do_resize:
|
| 784 |
+
resized_image = self.resize(image, size=size, resample=resample)
|
| 785 |
+
if annotations is not None:
|
| 786 |
+
annotation = self.resize_annotation(
|
| 787 |
+
annotation,
|
| 788 |
+
orig_size=get_image_size(image, channel_dim=ChannelDimension.FIRST),
|
| 789 |
+
target_size=get_image_size(resized_image, channel_dim=ChannelDimension.FIRST),
|
| 790 |
+
)
|
| 791 |
+
image = resized_image
|
| 792 |
+
|
| 793 |
+
if do_rescale:
|
| 794 |
+
image = self.rescale(image, rescale_factor)
|
| 795 |
+
if do_normalize:
|
| 796 |
+
image = self.normalize(image, image_mean, image_std)
|
| 797 |
+
|
| 798 |
+
if do_convert_annotations and annotations is not None:
|
| 799 |
+
annotation = self.normalize_annotation(annotation, get_image_size(image, ChannelDimension.FIRST))
|
| 800 |
+
|
| 801 |
+
processed_images.append(image)
|
| 802 |
+
processed_annotations.append(annotation)
|
| 803 |
+
images = processed_images
|
| 804 |
+
annotations = processed_annotations if annotations is not None else None
|
| 805 |
+
|
| 806 |
+
if do_pad:
|
| 807 |
+
# depends on all resized image shapes so we need another loop
|
| 808 |
+
if pad_size is not None:
|
| 809 |
+
padded_size = (pad_size.height, pad_size.width)
|
| 810 |
+
else:
|
| 811 |
+
padded_size = get_max_height_width(images, input_data_format=ChannelDimension.FIRST)
|
| 812 |
+
|
| 813 |
+
padded_images = []
|
| 814 |
+
padded_annotations = []
|
| 815 |
+
for image, annotation in zip(images, annotations if annotations is not None else [None] * len(images)):
|
| 816 |
+
# Pads images and returns their mask: {'pixel_values': ..., 'pixel_mask': ...}
|
| 817 |
+
image_height, image_width = get_image_size(image, channel_dim=ChannelDimension.FIRST)
|
| 818 |
+
if padded_size == (image_height, image_width):
|
| 819 |
+
padded_images.append(image)
|
| 820 |
+
pixel_masks.append(np.ones(padded_size, dtype=np.int64))
|
| 821 |
+
padded_annotations.append(annotation)
|
| 822 |
+
continue
|
| 823 |
+
image, pixel_mask, annotation = self.pad(
|
| 824 |
+
image, padded_size, annotation=annotation, update_bboxes=do_convert_annotations
|
| 825 |
+
)
|
| 826 |
+
padded_images.append(image)
|
| 827 |
+
padded_annotations.append(annotation)
|
| 828 |
+
pixel_masks.append(pixel_mask)
|
| 829 |
+
images = padded_images
|
| 830 |
+
annotations = padded_annotations if annotations is not None else None
|
| 831 |
+
data.update({"pixel_mask": pixel_masks})
|
| 832 |
+
|
| 833 |
+
data.update({"pixel_values": images})
|
| 834 |
+
encoded_inputs = BatchFeature(data, tensor_type=return_tensors)
|
| 835 |
+
if annotations is not None:
|
| 836 |
+
encoded_inputs["labels"] = [
|
| 837 |
+
BatchFeature(annotation, tensor_type=return_tensors) for annotation in annotations
|
| 838 |
+
]
|
| 839 |
+
return encoded_inputs
|
| 840 |
+
|
| 841 |
+
@requires(backends=("torch",))
|
| 842 |
+
def post_process_object_detection(
|
| 843 |
+
self, outputs, threshold: float = 0.5, target_sizes: TensorType | list[tuple] = None, top_k: int = 100
|
| 844 |
+
):
|
| 845 |
+
"""
|
| 846 |
+
Converts the raw output of [`ConditionalDetrForObjectDetection`] into final bounding boxes in (top_left_x,
|
| 847 |
+
top_left_y, bottom_right_x, bottom_right_y) format. Only supports PyTorch.
|
| 848 |
+
|
| 849 |
+
Args:
|
| 850 |
+
outputs ([`ConditionalDetrObjectDetectionOutput`]):
|
| 851 |
+
Raw outputs of the model.
|
| 852 |
+
threshold (`float`, *optional*):
|
| 853 |
+
Score threshold to keep object detection predictions.
|
| 854 |
+
target_sizes (`torch.Tensor` or `list[tuple[int, int]]`, *optional*):
|
| 855 |
+
Tensor of shape `(batch_size, 2)` or list of tuples (`tuple[int, int]`) containing the target size
|
| 856 |
+
(height, width) of each image in the batch. If left to None, predictions will not be resized.
|
| 857 |
+
top_k (`int`, *optional*, defaults to 100):
|
| 858 |
+
Keep only top k bounding boxes before filtering by thresholding.
|
| 859 |
+
|
| 860 |
+
Returns:
|
| 861 |
+
`list[Dict]`: A list of dictionaries, each dictionary containing the scores, labels and boxes for an image
|
| 862 |
+
in the batch as predicted by the model.
|
| 863 |
+
"""
|
| 864 |
+
requires_backends(self, ["torch"])
|
| 865 |
+
out_logits, out_bbox = outputs.logits, outputs.pred_boxes
|
| 866 |
+
|
| 867 |
+
if target_sizes is not None:
|
| 868 |
+
if len(out_logits) != len(target_sizes):
|
| 869 |
+
raise ValueError(
|
| 870 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 871 |
+
)
|
| 872 |
+
|
| 873 |
+
prob = out_logits.sigmoid()
|
| 874 |
+
prob = prob.view(out_logits.shape[0], -1)
|
| 875 |
+
k_value = min(top_k, prob.size(1))
|
| 876 |
+
topk_values, topk_indexes = torch.topk(prob, k_value, dim=1)
|
| 877 |
+
scores = topk_values
|
| 878 |
+
topk_boxes = torch.div(topk_indexes, out_logits.shape[2], rounding_mode="floor")
|
| 879 |
+
labels = topk_indexes % out_logits.shape[2]
|
| 880 |
+
boxes = center_to_corners_format(out_bbox)
|
| 881 |
+
boxes = torch.gather(boxes, 1, topk_boxes.unsqueeze(-1).repeat(1, 1, 4))
|
| 882 |
+
|
| 883 |
+
# and from relative [0, 1] to absolute [0, height] coordinates
|
| 884 |
+
if target_sizes is not None:
|
| 885 |
+
if isinstance(target_sizes, list):
|
| 886 |
+
img_h = torch.Tensor([i[0] for i in target_sizes])
|
| 887 |
+
img_w = torch.Tensor([i[1] for i in target_sizes])
|
| 888 |
+
else:
|
| 889 |
+
img_h, img_w = target_sizes.unbind(1)
|
| 890 |
+
scale_fct = torch.stack([img_w, img_h, img_w, img_h], dim=1).to(boxes.device)
|
| 891 |
+
boxes = boxes * scale_fct[:, None, :]
|
| 892 |
+
|
| 893 |
+
results = []
|
| 894 |
+
for s, l, b in zip(scores, labels, boxes):
|
| 895 |
+
score = s[s > threshold]
|
| 896 |
+
label = l[s > threshold]
|
| 897 |
+
box = b[s > threshold]
|
| 898 |
+
results.append({"scores": score, "labels": label, "boxes": box})
|
| 899 |
+
|
| 900 |
+
return results
|
| 901 |
+
|
| 902 |
+
@requires(backends=("torch",))
|
| 903 |
+
def post_process_semantic_segmentation(self, outputs, target_sizes: list[tuple[int, int]] | None = None):
|
| 904 |
+
"""
|
| 905 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into semantic segmentation maps. Only supports PyTorch.
|
| 906 |
+
|
| 907 |
+
Args:
|
| 908 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 909 |
+
Raw outputs of the model.
|
| 910 |
+
target_sizes (`list[tuple[int, int]]`, *optional*):
|
| 911 |
+
A list of tuples (`tuple[int, int]`) containing the target size (height, width) of each image in the
|
| 912 |
+
batch. If unset, predictions will not be resized.
|
| 913 |
+
Returns:
|
| 914 |
+
`list[torch.Tensor]`:
|
| 915 |
+
A list of length `batch_size`, where each item is a semantic segmentation map of shape (height, width)
|
| 916 |
+
corresponding to the target_sizes entry (if `target_sizes` is specified). Each entry of each
|
| 917 |
+
`torch.Tensor` correspond to a semantic class id.
|
| 918 |
+
"""
|
| 919 |
+
requires_backends(self, ["torch"])
|
| 920 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes]
|
| 921 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 922 |
+
|
| 923 |
+
# Conditional DETR does not have a null class, so we use all classes
|
| 924 |
+
masks_classes = class_queries_logits.softmax(dim=-1)
|
| 925 |
+
masks_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 926 |
+
|
| 927 |
+
# Semantic segmentation logits of shape (batch_size, num_classes, height, width)
|
| 928 |
+
segmentation = torch.einsum("bqc, bqhw -> bchw", masks_classes, masks_probs)
|
| 929 |
+
batch_size = class_queries_logits.shape[0]
|
| 930 |
+
|
| 931 |
+
# Resize logits and compute semantic segmentation maps
|
| 932 |
+
if target_sizes is not None:
|
| 933 |
+
if batch_size != len(target_sizes):
|
| 934 |
+
raise ValueError(
|
| 935 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 936 |
+
)
|
| 937 |
+
|
| 938 |
+
semantic_segmentation = []
|
| 939 |
+
for idx in range(batch_size):
|
| 940 |
+
resized_logits = nn.functional.interpolate(
|
| 941 |
+
segmentation[idx].unsqueeze(dim=0), size=target_sizes[idx], mode="bilinear", align_corners=False
|
| 942 |
+
)
|
| 943 |
+
semantic_map = resized_logits[0].argmax(dim=0)
|
| 944 |
+
semantic_segmentation.append(semantic_map)
|
| 945 |
+
else:
|
| 946 |
+
semantic_segmentation = segmentation.argmax(dim=1)
|
| 947 |
+
semantic_segmentation = [semantic_segmentation[i] for i in range(semantic_segmentation.shape[0])]
|
| 948 |
+
|
| 949 |
+
return semantic_segmentation
|
| 950 |
+
|
| 951 |
+
@requires(backends=("torch",))
|
| 952 |
+
def post_process_instance_segmentation(
|
| 953 |
+
self,
|
| 954 |
+
outputs,
|
| 955 |
+
threshold: float = 0.5,
|
| 956 |
+
mask_threshold: float = 0.5,
|
| 957 |
+
overlap_mask_area_threshold: float = 0.8,
|
| 958 |
+
target_sizes: list[tuple[int, int]] | None = None,
|
| 959 |
+
return_coco_annotation: bool | None = False,
|
| 960 |
+
) -> list[dict]:
|
| 961 |
+
"""
|
| 962 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into instance segmentation predictions. Only supports PyTorch.
|
| 963 |
+
|
| 964 |
+
Args:
|
| 965 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 966 |
+
Raw outputs of the model.
|
| 967 |
+
threshold (`float`, *optional*, defaults to 0.5):
|
| 968 |
+
The probability score threshold to keep predicted instance masks.
|
| 969 |
+
mask_threshold (`float`, *optional*, defaults to 0.5):
|
| 970 |
+
Threshold to use when turning the predicted masks into binary values.
|
| 971 |
+
overlap_mask_area_threshold (`float`, *optional*, defaults to 0.8):
|
| 972 |
+
The overlap mask area threshold to merge or discard small disconnected parts within each binary
|
| 973 |
+
instance mask.
|
| 974 |
+
target_sizes (`list[Tuple]`, *optional*):
|
| 975 |
+
List of length (batch_size), where each list item (`tuple[int, int]]`) corresponds to the requested
|
| 976 |
+
final size (height, width) of each prediction. If unset, predictions will not be resized.
|
| 977 |
+
return_coco_annotation (`bool`, *optional*):
|
| 978 |
+
Defaults to `False`. If set to `True`, segmentation maps are returned in COCO run-length encoding (RLE)
|
| 979 |
+
format.
|
| 980 |
+
Returns:
|
| 981 |
+
`list[Dict]`: A list of dictionaries, one per image, each dictionary containing two keys:
|
| 982 |
+
- **segmentation** -- A tensor of shape `(height, width)` where each pixel represents a `segment_id` or
|
| 983 |
+
`list[List]` run-length encoding (RLE) of the segmentation map if return_coco_annotation is set to
|
| 984 |
+
`True`. Set to `None` if no mask if found above `threshold`.
|
| 985 |
+
- **segments_info** -- A dictionary that contains additional information on each segment.
|
| 986 |
+
- **id** -- An integer representing the `segment_id`.
|
| 987 |
+
- **label_id** -- An integer representing the label / semantic class id corresponding to `segment_id`.
|
| 988 |
+
- **score** -- Prediction score of segment with `segment_id`.
|
| 989 |
+
"""
|
| 990 |
+
if not is_torch_available():
|
| 991 |
+
raise ImportError("PyTorch is required for post-processing.")
|
| 992 |
+
import torch
|
| 993 |
+
from torch import nn
|
| 994 |
+
|
| 995 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes+1]
|
| 996 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 997 |
+
|
| 998 |
+
batch_size = class_queries_logits.shape[0]
|
| 999 |
+
num_labels = class_queries_logits.shape[-1] - 1
|
| 1000 |
+
|
| 1001 |
+
mask_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 1002 |
+
|
| 1003 |
+
# Predicted label and score of each query (batch_size, num_queries)
|
| 1004 |
+
pred_scores, pred_labels = nn.functional.softmax(class_queries_logits, dim=-1).max(-1)
|
| 1005 |
+
|
| 1006 |
+
# Loop over items in batch size
|
| 1007 |
+
results: list[dict[str, TensorType]] = []
|
| 1008 |
+
|
| 1009 |
+
for i in range(batch_size):
|
| 1010 |
+
mask_probs_item, pred_scores_item, pred_labels_item = remove_low_and_no_objects(
|
| 1011 |
+
mask_probs[i], pred_scores[i], pred_labels[i], threshold, num_labels
|
| 1012 |
+
)
|
| 1013 |
+
|
| 1014 |
+
# No mask found
|
| 1015 |
+
if mask_probs_item.shape[0] <= 0:
|
| 1016 |
+
height, width = target_sizes[i] if target_sizes is not None else mask_probs_item.shape[1:]
|
| 1017 |
+
segmentation = torch.zeros((height, width)) - 1
|
| 1018 |
+
results.append({"segmentation": segmentation, "segments_info": []})
|
| 1019 |
+
continue
|
| 1020 |
+
|
| 1021 |
+
# Get segmentation map and segment information of batch item
|
| 1022 |
+
target_size = target_sizes[i] if target_sizes is not None else None
|
| 1023 |
+
segmentation, segments = compute_segments(
|
| 1024 |
+
mask_probs=mask_probs_item,
|
| 1025 |
+
pred_scores=pred_scores_item,
|
| 1026 |
+
pred_labels=pred_labels_item,
|
| 1027 |
+
mask_threshold=mask_threshold,
|
| 1028 |
+
overlap_mask_area_threshold=overlap_mask_area_threshold,
|
| 1029 |
+
label_ids_to_fuse=[],
|
| 1030 |
+
target_size=target_size,
|
| 1031 |
+
)
|
| 1032 |
+
|
| 1033 |
+
# Return segmentation map in run-length encoding (RLE) format
|
| 1034 |
+
if return_coco_annotation:
|
| 1035 |
+
segmentation = convert_segmentation_to_rle(segmentation)
|
| 1036 |
+
|
| 1037 |
+
results.append({"segmentation": segmentation, "segments_info": segments})
|
| 1038 |
+
return results
|
| 1039 |
+
|
| 1040 |
+
@requires(backends=("torch",))
|
| 1041 |
+
def post_process_panoptic_segmentation(
|
| 1042 |
+
self,
|
| 1043 |
+
outputs,
|
| 1044 |
+
threshold: float = 0.5,
|
| 1045 |
+
mask_threshold: float = 0.5,
|
| 1046 |
+
overlap_mask_area_threshold: float = 0.8,
|
| 1047 |
+
label_ids_to_fuse: set[int] | None = None,
|
| 1048 |
+
target_sizes: list[tuple[int, int]] | None = None,
|
| 1049 |
+
) -> list[dict]:
|
| 1050 |
+
"""
|
| 1051 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into image panoptic segmentation predictions. Only supports
|
| 1052 |
+
PyTorch.
|
| 1053 |
+
|
| 1054 |
+
Args:
|
| 1055 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 1056 |
+
The outputs from [`ConditionalDetrForSegmentation`].
|
| 1057 |
+
threshold (`float`, *optional*, defaults to 0.5):
|
| 1058 |
+
The probability score threshold to keep predicted instance masks.
|
| 1059 |
+
mask_threshold (`float`, *optional*, defaults to 0.5):
|
| 1060 |
+
Threshold to use when turning the predicted masks into binary values.
|
| 1061 |
+
overlap_mask_area_threshold (`float`, *optional*, defaults to 0.8):
|
| 1062 |
+
The overlap mask area threshold to merge or discard small disconnected parts within each binary
|
| 1063 |
+
instance mask.
|
| 1064 |
+
label_ids_to_fuse (`Set[int]`, *optional*):
|
| 1065 |
+
The labels in this state will have all their instances be fused together. For instance we could say
|
| 1066 |
+
there can only be one sky in an image, but several persons, so the label ID for sky would be in that
|
| 1067 |
+
set, but not the one for person.
|
| 1068 |
+
target_sizes (`list[Tuple]`, *optional*):
|
| 1069 |
+
List of length (batch_size), where each list item (`tuple[int, int]]`) corresponds to the requested
|
| 1070 |
+
final size (height, width) of each prediction in batch. If unset, predictions will not be resized.
|
| 1071 |
+
Returns:
|
| 1072 |
+
`list[Dict]`: A list of dictionaries, one per image, each dictionary containing two keys:
|
| 1073 |
+
- **segmentation** -- a tensor of shape `(height, width)` where each pixel represents a `segment_id` or
|
| 1074 |
+
`None` if no mask if found above `threshold`. If `target_sizes` is specified, segmentation is resized to
|
| 1075 |
+
the corresponding `target_sizes` entry.
|
| 1076 |
+
- **segments_info** -- A dictionary that contains additional information on each segment.
|
| 1077 |
+
- **id** -- an integer representing the `segment_id`.
|
| 1078 |
+
- **label_id** -- An integer representing the label / semantic class id corresponding to `segment_id`.
|
| 1079 |
+
- **was_fused** -- a boolean, `True` if `label_id` was in `label_ids_to_fuse`, `False` otherwise.
|
| 1080 |
+
Multiple instances of the same class / label were fused and assigned a single `segment_id`.
|
| 1081 |
+
- **score** -- Prediction score of segment with `segment_id`.
|
| 1082 |
+
"""
|
| 1083 |
+
|
| 1084 |
+
if label_ids_to_fuse is None:
|
| 1085 |
+
logger.warning_once("`label_ids_to_fuse` unset. No instance will be fused.")
|
| 1086 |
+
label_ids_to_fuse = set()
|
| 1087 |
+
|
| 1088 |
+
if not is_torch_available():
|
| 1089 |
+
raise ImportError("PyTorch is required for post-processing.")
|
| 1090 |
+
import torch
|
| 1091 |
+
from torch import nn
|
| 1092 |
+
|
| 1093 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes+1]
|
| 1094 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 1095 |
+
|
| 1096 |
+
batch_size = class_queries_logits.shape[0]
|
| 1097 |
+
num_labels = class_queries_logits.shape[-1] - 1
|
| 1098 |
+
|
| 1099 |
+
mask_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 1100 |
+
|
| 1101 |
+
# Predicted label and score of each query (batch_size, num_queries)
|
| 1102 |
+
pred_scores, pred_labels = nn.functional.softmax(class_queries_logits, dim=-1).max(-1)
|
| 1103 |
+
|
| 1104 |
+
# Loop over items in batch size
|
| 1105 |
+
results: list[dict[str, TensorType]] = []
|
| 1106 |
+
|
| 1107 |
+
for i in range(batch_size):
|
| 1108 |
+
mask_probs_item, pred_scores_item, pred_labels_item = remove_low_and_no_objects(
|
| 1109 |
+
mask_probs[i], pred_scores[i], pred_labels[i], threshold, num_labels
|
| 1110 |
+
)
|
| 1111 |
+
|
| 1112 |
+
# No mask found
|
| 1113 |
+
if mask_probs_item.shape[0] <= 0:
|
| 1114 |
+
height, width = target_sizes[i] if target_sizes is not None else mask_probs_item.shape[1:]
|
| 1115 |
+
segmentation = torch.zeros((height, width)) - 1
|
| 1116 |
+
results.append({"segmentation": segmentation, "segments_info": []})
|
| 1117 |
+
continue
|
| 1118 |
+
|
| 1119 |
+
# Get segmentation map and segment information of batch item
|
| 1120 |
+
target_size = target_sizes[i] if target_sizes is not None else None
|
| 1121 |
+
segmentation, segments = compute_segments(
|
| 1122 |
+
mask_probs=mask_probs_item,
|
| 1123 |
+
pred_scores=pred_scores_item,
|
| 1124 |
+
pred_labels=pred_labels_item,
|
| 1125 |
+
mask_threshold=mask_threshold,
|
| 1126 |
+
overlap_mask_area_threshold=overlap_mask_area_threshold,
|
| 1127 |
+
label_ids_to_fuse=label_ids_to_fuse,
|
| 1128 |
+
target_size=target_size,
|
| 1129 |
+
)
|
| 1130 |
+
|
| 1131 |
+
results.append({"segmentation": segmentation, "segments_info": segments})
|
| 1132 |
+
return results
|
| 1133 |
+
|
| 1134 |
+
|
| 1135 |
+
__all__ = ["ConditionalDetrImageProcessorPil"]
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/conditional_detr/modeling_conditional_detr.py
ADDED
|
@@ -0,0 +1,1866 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/conditional_detr/modular_conditional_detr.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_conditional_detr.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2022 Microsoft Research Asia and The HuggingFace Inc. team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 10 |
+
# you may not use this file except in compliance with the License.
|
| 11 |
+
# You may obtain a copy of the License at
|
| 12 |
+
#
|
| 13 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 14 |
+
#
|
| 15 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 16 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 17 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 18 |
+
# See the License for the specific language governing permissions and
|
| 19 |
+
# limitations under the License.
|
| 20 |
+
import math
|
| 21 |
+
from collections.abc import Callable
|
| 22 |
+
from dataclasses import dataclass
|
| 23 |
+
|
| 24 |
+
import torch
|
| 25 |
+
from torch import nn
|
| 26 |
+
|
| 27 |
+
from ... import initialization as init
|
| 28 |
+
from ...activations import ACT2FN
|
| 29 |
+
from ...backbone_utils import load_backbone
|
| 30 |
+
from ...masking_utils import create_bidirectional_mask
|
| 31 |
+
from ...modeling_layers import GradientCheckpointingLayer
|
| 32 |
+
from ...modeling_outputs import BaseModelOutput, BaseModelOutputWithCrossAttentions, Seq2SeqModelOutput
|
| 33 |
+
from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
|
| 34 |
+
from ...processing_utils import Unpack
|
| 35 |
+
from ...pytorch_utils import compile_compatible_method_lru_cache
|
| 36 |
+
from ...utils import ModelOutput, TransformersKwargs, auto_docstring
|
| 37 |
+
from ...utils.generic import can_return_tuple, merge_with_config_defaults
|
| 38 |
+
from ...utils.output_capturing import OutputRecorder, capture_outputs
|
| 39 |
+
from .configuration_conditional_detr import ConditionalDetrConfig
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
@auto_docstring(
|
| 43 |
+
custom_intro="""
|
| 44 |
+
Base class for outputs of the CONDITIONAL_DETR decoder. This class adds one attribute to BaseModelOutputWithCrossAttentions,
|
| 45 |
+
namely an optional stack of intermediate decoder activations, i.e. the output of each decoder layer, each of them
|
| 46 |
+
gone through a layernorm. This is useful when training the model with auxiliary decoding losses.
|
| 47 |
+
"""
|
| 48 |
+
)
|
| 49 |
+
@dataclass
|
| 50 |
+
class ConditionalDetrDecoderOutput(BaseModelOutputWithCrossAttentions):
|
| 51 |
+
r"""
|
| 52 |
+
cross_attentions (`tuple(torch.FloatTensor)`, *optional*, returned when `output_attentions=True` and `config.add_cross_attention=True` is passed or when `config.output_attentions=True`):
|
| 53 |
+
Tuple of `torch.FloatTensor` (one for each layer) of shape `(batch_size, num_heads, sequence_length,
|
| 54 |
+
sequence_length)`. Attentions weights of the decoder's cross-attention layer, after the attention softmax,
|
| 55 |
+
used to compute the weighted average in the cross-attention heads.
|
| 56 |
+
intermediate_hidden_states (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, num_queries, hidden_size)`, *optional*, returned when `config.auxiliary_loss=True`):
|
| 57 |
+
Intermediate decoder activations, i.e. the output of each decoder layer, each of them gone through a
|
| 58 |
+
layernorm.
|
| 59 |
+
reference_points (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, num_queries, 2 (anchor points))`):
|
| 60 |
+
Reference points (reference points of each layer of the decoder).
|
| 61 |
+
"""
|
| 62 |
+
|
| 63 |
+
intermediate_hidden_states: torch.FloatTensor | None = None
|
| 64 |
+
|
| 65 |
+
reference_points: tuple[torch.FloatTensor] | None = None
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
@auto_docstring(
|
| 69 |
+
custom_intro="""
|
| 70 |
+
Base class for outputs of the CONDITIONAL_DETR encoder-decoder model. This class adds one attribute to Seq2SeqModelOutput,
|
| 71 |
+
namely an optional stack of intermediate decoder activations, i.e. the output of each decoder layer, each of them
|
| 72 |
+
gone through a layernorm. This is useful when training the model with auxiliary decoding losses.
|
| 73 |
+
"""
|
| 74 |
+
)
|
| 75 |
+
@dataclass
|
| 76 |
+
class ConditionalDetrModelOutput(Seq2SeqModelOutput):
|
| 77 |
+
r"""
|
| 78 |
+
last_hidden_state (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 79 |
+
Sequence of hidden-states at the output of the last layer of the decoder of the model.
|
| 80 |
+
intermediate_hidden_states (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, sequence_length, hidden_size)`, *optional*, returned when `config.auxiliary_loss=True`):
|
| 81 |
+
Intermediate decoder activations, i.e. the output of each decoder layer, each of them gone through a
|
| 82 |
+
layernorm.
|
| 83 |
+
reference_points (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, num_queries, 2 (anchor points))`):
|
| 84 |
+
Reference points (reference points of each layer of the decoder).
|
| 85 |
+
"""
|
| 86 |
+
|
| 87 |
+
intermediate_hidden_states: torch.FloatTensor | None = None
|
| 88 |
+
|
| 89 |
+
reference_points: tuple[torch.FloatTensor] | None = None
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
@auto_docstring(
|
| 93 |
+
custom_intro="""
|
| 94 |
+
Output type of [`ConditionalDetrForObjectDetection`].
|
| 95 |
+
"""
|
| 96 |
+
)
|
| 97 |
+
@dataclass
|
| 98 |
+
class ConditionalDetrObjectDetectionOutput(ModelOutput):
|
| 99 |
+
r"""
|
| 100 |
+
loss (`torch.FloatTensor` of shape `(1,)`, *optional*, returned when `labels` are provided)):
|
| 101 |
+
Total loss as a linear combination of a negative log-likehood (cross-entropy) for class prediction and a
|
| 102 |
+
bounding box loss. The latter is defined as a linear combination of the L1 loss and the generalized
|
| 103 |
+
scale-invariant IoU loss.
|
| 104 |
+
loss_dict (`Dict`, *optional*):
|
| 105 |
+
A dictionary containing the individual losses. Useful for logging.
|
| 106 |
+
logits (`torch.FloatTensor` of shape `(batch_size, num_queries, num_classes + 1)`):
|
| 107 |
+
Classification logits (including no-object) for all queries.
|
| 108 |
+
pred_boxes (`torch.FloatTensor` of shape `(batch_size, num_queries, 4)`):
|
| 109 |
+
Normalized boxes coordinates for all queries, represented as (center_x, center_y, width, height). These
|
| 110 |
+
values are normalized in [0, 1], relative to the size of each individual image in the batch (disregarding
|
| 111 |
+
possible padding). You can use [`~ConditionalDetrImageProcessor.post_process_object_detection`] to retrieve the
|
| 112 |
+
unnormalized bounding boxes.
|
| 113 |
+
auxiliary_outputs (`list[Dict]`, *optional*):
|
| 114 |
+
Optional, only returned when auxiliary losses are activated (i.e. `config.auxiliary_loss` is set to `True`)
|
| 115 |
+
and labels are provided. It is a list of dictionaries containing the two above keys (`logits` and
|
| 116 |
+
`pred_boxes`) for each decoder layer.
|
| 117 |
+
last_hidden_state (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 118 |
+
Sequence of hidden-states at the output of the last layer of the decoder of the model.
|
| 119 |
+
"""
|
| 120 |
+
|
| 121 |
+
loss: torch.FloatTensor | None = None
|
| 122 |
+
loss_dict: dict | None = None
|
| 123 |
+
logits: torch.FloatTensor | None = None
|
| 124 |
+
pred_boxes: torch.FloatTensor | None = None
|
| 125 |
+
auxiliary_outputs: list[dict] | None = None
|
| 126 |
+
last_hidden_state: torch.FloatTensor | None = None
|
| 127 |
+
decoder_hidden_states: tuple[torch.FloatTensor] | None = None
|
| 128 |
+
decoder_attentions: tuple[torch.FloatTensor] | None = None
|
| 129 |
+
cross_attentions: tuple[torch.FloatTensor] | None = None
|
| 130 |
+
encoder_last_hidden_state: torch.FloatTensor | None = None
|
| 131 |
+
encoder_hidden_states: tuple[torch.FloatTensor] | None = None
|
| 132 |
+
encoder_attentions: tuple[torch.FloatTensor] | None = None
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
@auto_docstring(
|
| 136 |
+
custom_intro="""
|
| 137 |
+
Output type of [`ConditionalDetrForSegmentation`].
|
| 138 |
+
"""
|
| 139 |
+
)
|
| 140 |
+
@dataclass
|
| 141 |
+
class ConditionalDetrSegmentationOutput(ModelOutput):
|
| 142 |
+
r"""
|
| 143 |
+
loss (`torch.FloatTensor` of shape `(1,)`, *optional*, returned when `labels` are provided)):
|
| 144 |
+
Total loss as a linear combination of a negative log-likehood (cross-entropy) for class prediction and a
|
| 145 |
+
bounding box loss. The latter is defined as a linear combination of the L1 loss and the generalized
|
| 146 |
+
scale-invariant IoU loss.
|
| 147 |
+
loss_dict (`Dict`, *optional*):
|
| 148 |
+
A dictionary containing the individual losses. Useful for logging.
|
| 149 |
+
logits (`torch.FloatTensor` of shape `(batch_size, num_queries, num_classes + 1)`):
|
| 150 |
+
Classification logits (including no-object) for all queries.
|
| 151 |
+
pred_boxes (`torch.FloatTensor` of shape `(batch_size, num_queries, 4)`):
|
| 152 |
+
Normalized boxes coordinates for all queries, represented as (center_x, center_y, width, height). These
|
| 153 |
+
values are normalized in [0, 1], relative to the size of each individual image in the batch (disregarding
|
| 154 |
+
possible padding). You can use [`~ConditionalDetrImageProcessor.post_process_object_detection`] to retrieve the
|
| 155 |
+
unnormalized bounding boxes.
|
| 156 |
+
pred_masks (`torch.FloatTensor` of shape `(batch_size, num_queries, height/4, width/4)`):
|
| 157 |
+
Segmentation masks logits for all queries. See also
|
| 158 |
+
[`~ConditionalDetrImageProcessor.post_process_semantic_segmentation`] or
|
| 159 |
+
[`~ConditionalDetrImageProcessor.post_process_instance_segmentation`]
|
| 160 |
+
[`~ConditionalDetrImageProcessor.post_process_panoptic_segmentation`] to evaluate semantic, instance and panoptic
|
| 161 |
+
segmentation masks respectively.
|
| 162 |
+
auxiliary_outputs (`list[Dict]`, *optional*):
|
| 163 |
+
Optional, only returned when auxiliary losses are activated (i.e. `config.auxiliary_loss` is set to `True`)
|
| 164 |
+
and labels are provided. It is a list of dictionaries containing the two above keys (`logits` and
|
| 165 |
+
`pred_boxes`) for each decoder layer.
|
| 166 |
+
last_hidden_state (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 167 |
+
Sequence of hidden-states at the output of the last layer of the decoder of the model.
|
| 168 |
+
"""
|
| 169 |
+
|
| 170 |
+
loss: torch.FloatTensor | None = None
|
| 171 |
+
loss_dict: dict | None = None
|
| 172 |
+
logits: torch.FloatTensor | None = None
|
| 173 |
+
pred_boxes: torch.FloatTensor | None = None
|
| 174 |
+
pred_masks: torch.FloatTensor | None = None
|
| 175 |
+
auxiliary_outputs: list[dict] | None = None
|
| 176 |
+
last_hidden_state: torch.FloatTensor | None = None
|
| 177 |
+
decoder_hidden_states: tuple[torch.FloatTensor] | None = None
|
| 178 |
+
decoder_attentions: tuple[torch.FloatTensor] | None = None
|
| 179 |
+
cross_attentions: tuple[torch.FloatTensor] | None = None
|
| 180 |
+
encoder_last_hidden_state: torch.FloatTensor | None = None
|
| 181 |
+
encoder_hidden_states: tuple[torch.FloatTensor] | None = None
|
| 182 |
+
encoder_attentions: tuple[torch.FloatTensor] | None = None
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
class ConditionalDetrFrozenBatchNorm2d(nn.Module):
|
| 186 |
+
"""
|
| 187 |
+
BatchNorm2d where the batch statistics and the affine parameters are fixed.
|
| 188 |
+
|
| 189 |
+
Copy-paste from torchvision.misc.ops with added eps before rqsrt, without which any other models than
|
| 190 |
+
torchvision.models.resnet[18,34,50,101] produce nans.
|
| 191 |
+
"""
|
| 192 |
+
|
| 193 |
+
def __init__(self, n):
|
| 194 |
+
super().__init__()
|
| 195 |
+
self.register_buffer("weight", torch.ones(n))
|
| 196 |
+
self.register_buffer("bias", torch.zeros(n))
|
| 197 |
+
self.register_buffer("running_mean", torch.zeros(n))
|
| 198 |
+
self.register_buffer("running_var", torch.ones(n))
|
| 199 |
+
|
| 200 |
+
def _load_from_state_dict(
|
| 201 |
+
self, state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs
|
| 202 |
+
):
|
| 203 |
+
num_batches_tracked_key = prefix + "num_batches_tracked"
|
| 204 |
+
if num_batches_tracked_key in state_dict:
|
| 205 |
+
del state_dict[num_batches_tracked_key]
|
| 206 |
+
|
| 207 |
+
super()._load_from_state_dict(
|
| 208 |
+
state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs
|
| 209 |
+
)
|
| 210 |
+
|
| 211 |
+
def forward(self, x):
|
| 212 |
+
# move reshapes to the beginning
|
| 213 |
+
# to make it user-friendly
|
| 214 |
+
weight = self.weight.reshape(1, -1, 1, 1)
|
| 215 |
+
bias = self.bias.reshape(1, -1, 1, 1)
|
| 216 |
+
running_var = self.running_var.reshape(1, -1, 1, 1)
|
| 217 |
+
running_mean = self.running_mean.reshape(1, -1, 1, 1)
|
| 218 |
+
epsilon = 1e-5
|
| 219 |
+
scale = weight * (running_var + epsilon).rsqrt()
|
| 220 |
+
bias = bias - running_mean * scale
|
| 221 |
+
return x * scale + bias
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
def replace_batch_norm(model):
|
| 225 |
+
r"""
|
| 226 |
+
Recursively replace all `torch.nn.BatchNorm2d` with `ConditionalDetrFrozenBatchNorm2d`.
|
| 227 |
+
|
| 228 |
+
Args:
|
| 229 |
+
model (torch.nn.Module):
|
| 230 |
+
input model
|
| 231 |
+
"""
|
| 232 |
+
for name, module in model.named_children():
|
| 233 |
+
if isinstance(module, nn.BatchNorm2d):
|
| 234 |
+
new_module = ConditionalDetrFrozenBatchNorm2d(module.num_features)
|
| 235 |
+
|
| 236 |
+
if module.weight.device != torch.device("meta"):
|
| 237 |
+
new_module.weight.copy_(module.weight)
|
| 238 |
+
new_module.bias.copy_(module.bias)
|
| 239 |
+
new_module.running_mean.copy_(module.running_mean)
|
| 240 |
+
new_module.running_var.copy_(module.running_var)
|
| 241 |
+
|
| 242 |
+
model._modules[name] = new_module
|
| 243 |
+
|
| 244 |
+
if len(list(module.children())) > 0:
|
| 245 |
+
replace_batch_norm(module)
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
class ConditionalDetrConvEncoder(nn.Module):
|
| 249 |
+
"""
|
| 250 |
+
Convolutional backbone, using either the AutoBackbone API or one from the timm library.
|
| 251 |
+
|
| 252 |
+
nn.BatchNorm2d layers are replaced by ConditionalDetrFrozenBatchNorm2d as defined above.
|
| 253 |
+
|
| 254 |
+
"""
|
| 255 |
+
|
| 256 |
+
def __init__(self, config):
|
| 257 |
+
super().__init__()
|
| 258 |
+
|
| 259 |
+
self.config = config
|
| 260 |
+
|
| 261 |
+
backbone = load_backbone(config)
|
| 262 |
+
self.intermediate_channel_sizes = backbone.channels
|
| 263 |
+
|
| 264 |
+
# replace batch norm by frozen batch norm
|
| 265 |
+
with torch.no_grad():
|
| 266 |
+
replace_batch_norm(backbone)
|
| 267 |
+
|
| 268 |
+
# We used to load with timm library directly instead of the AutoBackbone API
|
| 269 |
+
# so we need to unwrap the `backbone._backbone` module to load weights without mismatch
|
| 270 |
+
is_timm_model = False
|
| 271 |
+
if hasattr(backbone, "_backbone"):
|
| 272 |
+
backbone = backbone._backbone
|
| 273 |
+
is_timm_model = True
|
| 274 |
+
self.model = backbone
|
| 275 |
+
|
| 276 |
+
backbone_model_type = config.backbone_config.model_type
|
| 277 |
+
if "resnet" in backbone_model_type:
|
| 278 |
+
for name, parameter in self.model.named_parameters():
|
| 279 |
+
if is_timm_model:
|
| 280 |
+
if "layer2" not in name and "layer3" not in name and "layer4" not in name:
|
| 281 |
+
parameter.requires_grad_(False)
|
| 282 |
+
else:
|
| 283 |
+
if "stage.1" not in name and "stage.2" not in name and "stage.3" not in name:
|
| 284 |
+
parameter.requires_grad_(False)
|
| 285 |
+
|
| 286 |
+
def forward(self, pixel_values: torch.Tensor, pixel_mask: torch.Tensor):
|
| 287 |
+
# send pixel_values through the model to get list of feature maps
|
| 288 |
+
features = self.model(pixel_values)
|
| 289 |
+
if isinstance(features, dict):
|
| 290 |
+
features = features.feature_maps
|
| 291 |
+
|
| 292 |
+
out = []
|
| 293 |
+
for feature_map in features:
|
| 294 |
+
# downsample pixel_mask to match shape of corresponding feature_map
|
| 295 |
+
mask = nn.functional.interpolate(pixel_mask[None].float(), size=feature_map.shape[-2:]).to(torch.bool)[0]
|
| 296 |
+
out.append((feature_map, mask))
|
| 297 |
+
return out
|
| 298 |
+
|
| 299 |
+
|
| 300 |
+
class ConditionalDetrSinePositionEmbedding(nn.Module):
|
| 301 |
+
"""
|
| 302 |
+
This is a more standard version of the position embedding, very similar to the one used by the Attention is all you
|
| 303 |
+
need paper, generalized to work on images.
|
| 304 |
+
"""
|
| 305 |
+
|
| 306 |
+
def __init__(
|
| 307 |
+
self,
|
| 308 |
+
num_position_features: int = 64,
|
| 309 |
+
temperature: int = 10000,
|
| 310 |
+
normalize: bool = False,
|
| 311 |
+
scale: float | None = None,
|
| 312 |
+
):
|
| 313 |
+
super().__init__()
|
| 314 |
+
if scale is not None and normalize is False:
|
| 315 |
+
raise ValueError("normalize should be True if scale is passed")
|
| 316 |
+
self.num_position_features = num_position_features
|
| 317 |
+
self.temperature = temperature
|
| 318 |
+
self.normalize = normalize
|
| 319 |
+
self.scale = 2 * math.pi if scale is None else scale
|
| 320 |
+
|
| 321 |
+
@staticmethod
|
| 322 |
+
@compile_compatible_method_lru_cache(maxsize=1)
|
| 323 |
+
def build_sine_position_embedding(
|
| 324 |
+
shape: torch.Size,
|
| 325 |
+
device: torch.device | str,
|
| 326 |
+
dtype: torch.dtype,
|
| 327 |
+
num_position_features: int,
|
| 328 |
+
normalize: bool = False,
|
| 329 |
+
scale: float | None = None,
|
| 330 |
+
temperature: int = 10000,
|
| 331 |
+
mask: torch.Tensor | None = None,
|
| 332 |
+
) -> torch.Tensor:
|
| 333 |
+
if mask is None:
|
| 334 |
+
mask = torch.ones((shape[0], shape[2], shape[3]), device=device, dtype=torch.bool)
|
| 335 |
+
y_embed = mask.cumsum(1, dtype=dtype)
|
| 336 |
+
x_embed = mask.cumsum(2, dtype=dtype)
|
| 337 |
+
if normalize:
|
| 338 |
+
eps = 1e-6
|
| 339 |
+
y_embed = y_embed / (y_embed[:, -1:, :] + eps) * scale
|
| 340 |
+
x_embed = x_embed / (x_embed[:, :, -1:] + eps) * scale
|
| 341 |
+
|
| 342 |
+
dim_t = torch.arange(num_position_features, dtype=torch.int64, device=device).to(dtype)
|
| 343 |
+
dim_t = temperature ** (2 * torch.div(dim_t, 2, rounding_mode="floor") / num_position_features)
|
| 344 |
+
|
| 345 |
+
pos_x = x_embed[:, :, :, None] / dim_t
|
| 346 |
+
pos_y = y_embed[:, :, :, None] / dim_t
|
| 347 |
+
pos_x = torch.stack((pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4).flatten(3)
|
| 348 |
+
pos_y = torch.stack((pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4).flatten(3)
|
| 349 |
+
pos = torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2)
|
| 350 |
+
return pos
|
| 351 |
+
|
| 352 |
+
def forward(
|
| 353 |
+
self,
|
| 354 |
+
shape: torch.Size,
|
| 355 |
+
device: torch.device | str,
|
| 356 |
+
dtype: torch.dtype,
|
| 357 |
+
mask: torch.Tensor | None = None,
|
| 358 |
+
) -> torch.Tensor:
|
| 359 |
+
return self.build_sine_position_embedding(
|
| 360 |
+
shape, device, dtype, self.num_position_features, self.normalize, self.scale, self.temperature, mask
|
| 361 |
+
)
|
| 362 |
+
|
| 363 |
+
|
| 364 |
+
class ConditionalDetrLearnedPositionEmbedding(nn.Module):
|
| 365 |
+
"""
|
| 366 |
+
This module learns positional embeddings up to a fixed maximum size.
|
| 367 |
+
"""
|
| 368 |
+
|
| 369 |
+
def __init__(self, embedding_dim=256):
|
| 370 |
+
super().__init__()
|
| 371 |
+
self.row_embeddings = nn.Embedding(50, embedding_dim)
|
| 372 |
+
self.column_embeddings = nn.Embedding(50, embedding_dim)
|
| 373 |
+
|
| 374 |
+
@compile_compatible_method_lru_cache(maxsize=1)
|
| 375 |
+
def forward(
|
| 376 |
+
self,
|
| 377 |
+
shape: torch.Size,
|
| 378 |
+
device: torch.device | str,
|
| 379 |
+
dtype: torch.dtype,
|
| 380 |
+
mask: torch.Tensor | None = None,
|
| 381 |
+
):
|
| 382 |
+
height, width = shape[-2:]
|
| 383 |
+
width_values = torch.arange(width, device=device)
|
| 384 |
+
height_values = torch.arange(height, device=device)
|
| 385 |
+
x_emb = self.column_embeddings(width_values)
|
| 386 |
+
y_emb = self.row_embeddings(height_values)
|
| 387 |
+
pos = torch.cat([x_emb.unsqueeze(0).repeat(height, 1, 1), y_emb.unsqueeze(1).repeat(1, width, 1)], dim=-1)
|
| 388 |
+
pos = pos.permute(2, 0, 1)
|
| 389 |
+
pos = pos.unsqueeze(0)
|
| 390 |
+
pos = pos.repeat(shape[0], 1, 1, 1)
|
| 391 |
+
return pos
|
| 392 |
+
|
| 393 |
+
|
| 394 |
+
def eager_attention_forward(
|
| 395 |
+
module: nn.Module,
|
| 396 |
+
query: torch.Tensor,
|
| 397 |
+
key: torch.Tensor,
|
| 398 |
+
value: torch.Tensor,
|
| 399 |
+
attention_mask: torch.Tensor | None,
|
| 400 |
+
scaling: float | None = None,
|
| 401 |
+
dropout: float = 0.0,
|
| 402 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 403 |
+
):
|
| 404 |
+
if scaling is None:
|
| 405 |
+
scaling = query.size(-1) ** -0.5
|
| 406 |
+
|
| 407 |
+
# Take the dot product between "query" and "key" to get the raw attention scores.
|
| 408 |
+
attn_weights = torch.matmul(query, key.transpose(2, 3)) * scaling
|
| 409 |
+
|
| 410 |
+
if attention_mask is not None:
|
| 411 |
+
attn_weights = attn_weights + attention_mask
|
| 412 |
+
|
| 413 |
+
attn_weights = nn.functional.softmax(attn_weights, dim=-1)
|
| 414 |
+
attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
|
| 415 |
+
|
| 416 |
+
attn_output = torch.matmul(attn_weights, value)
|
| 417 |
+
attn_output = attn_output.transpose(1, 2).contiguous()
|
| 418 |
+
|
| 419 |
+
return attn_output, attn_weights
|
| 420 |
+
|
| 421 |
+
|
| 422 |
+
class ConditionalDetrSelfAttention(nn.Module):
|
| 423 |
+
"""
|
| 424 |
+
Multi-headed self-attention from 'Attention Is All You Need' paper.
|
| 425 |
+
|
| 426 |
+
In CONDITIONAL_DETR, position embeddings are added to both queries and keys (but not values) in self-attention.
|
| 427 |
+
"""
|
| 428 |
+
|
| 429 |
+
def __init__(
|
| 430 |
+
self,
|
| 431 |
+
config: ConditionalDetrConfig,
|
| 432 |
+
hidden_size: int,
|
| 433 |
+
num_attention_heads: int,
|
| 434 |
+
dropout: float = 0.0,
|
| 435 |
+
bias: bool = True,
|
| 436 |
+
):
|
| 437 |
+
super().__init__()
|
| 438 |
+
self.config = config
|
| 439 |
+
self.head_dim = hidden_size // num_attention_heads
|
| 440 |
+
self.scaling = self.head_dim**-0.5
|
| 441 |
+
self.attention_dropout = dropout
|
| 442 |
+
self.is_causal = False
|
| 443 |
+
|
| 444 |
+
self.k_proj = nn.Linear(hidden_size, hidden_size, bias=bias)
|
| 445 |
+
self.v_proj = nn.Linear(hidden_size, hidden_size, bias=bias)
|
| 446 |
+
self.q_proj = nn.Linear(hidden_size, hidden_size, bias=bias)
|
| 447 |
+
self.o_proj = nn.Linear(hidden_size, hidden_size, bias=bias)
|
| 448 |
+
|
| 449 |
+
def forward(
|
| 450 |
+
self,
|
| 451 |
+
hidden_states: torch.Tensor,
|
| 452 |
+
attention_mask: torch.Tensor | None = None,
|
| 453 |
+
position_embeddings: torch.Tensor | None = None,
|
| 454 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 455 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 456 |
+
"""
|
| 457 |
+
Position embeddings are added to both queries and keys (but not values).
|
| 458 |
+
"""
|
| 459 |
+
input_shape = hidden_states.shape[:-1]
|
| 460 |
+
hidden_shape = (*input_shape, -1, self.head_dim)
|
| 461 |
+
|
| 462 |
+
query_key_input = hidden_states + position_embeddings if position_embeddings is not None else hidden_states
|
| 463 |
+
|
| 464 |
+
query_states = self.q_proj(query_key_input).view(hidden_shape).transpose(1, 2)
|
| 465 |
+
key_states = self.k_proj(query_key_input).view(hidden_shape).transpose(1, 2)
|
| 466 |
+
value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 467 |
+
|
| 468 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 469 |
+
self.config._attn_implementation, eager_attention_forward
|
| 470 |
+
)
|
| 471 |
+
|
| 472 |
+
attn_output, attn_weights = attention_interface(
|
| 473 |
+
self,
|
| 474 |
+
query_states,
|
| 475 |
+
key_states,
|
| 476 |
+
value_states,
|
| 477 |
+
attention_mask,
|
| 478 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 479 |
+
scaling=self.scaling,
|
| 480 |
+
**kwargs,
|
| 481 |
+
)
|
| 482 |
+
|
| 483 |
+
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
| 484 |
+
attn_output = self.o_proj(attn_output)
|
| 485 |
+
return attn_output, attn_weights
|
| 486 |
+
|
| 487 |
+
|
| 488 |
+
class ConditionalDetrDecoderSelfAttention(nn.Module):
|
| 489 |
+
"""
|
| 490 |
+
Multi-headed self-attention for Conditional DETR decoder layers.
|
| 491 |
+
|
| 492 |
+
This attention module handles separate content and position projections, which are then combined
|
| 493 |
+
before applying standard self-attention. Position embeddings are added to both queries and keys.
|
| 494 |
+
"""
|
| 495 |
+
|
| 496 |
+
def __init__(
|
| 497 |
+
self,
|
| 498 |
+
config: ConditionalDetrConfig,
|
| 499 |
+
hidden_size: int,
|
| 500 |
+
num_attention_heads: int,
|
| 501 |
+
dropout: float | int = 0.0,
|
| 502 |
+
):
|
| 503 |
+
super().__init__()
|
| 504 |
+
self.config = config
|
| 505 |
+
self.hidden_size = hidden_size
|
| 506 |
+
self.head_dim = hidden_size // num_attention_heads
|
| 507 |
+
self.scaling = self.head_dim**-0.5
|
| 508 |
+
self.attention_dropout = dropout
|
| 509 |
+
self.is_causal = False
|
| 510 |
+
|
| 511 |
+
# Content and position projections
|
| 512 |
+
self.q_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 513 |
+
self.q_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 514 |
+
self.k_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 515 |
+
self.k_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 516 |
+
self.v_proj = nn.Linear(hidden_size, hidden_size)
|
| 517 |
+
self.o_proj = nn.Linear(hidden_size, hidden_size)
|
| 518 |
+
|
| 519 |
+
def forward(
|
| 520 |
+
self,
|
| 521 |
+
hidden_states: torch.Tensor,
|
| 522 |
+
query_position_embeddings: torch.Tensor,
|
| 523 |
+
attention_mask: torch.Tensor | None = None,
|
| 524 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 525 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 526 |
+
"""
|
| 527 |
+
Args:
|
| 528 |
+
hidden_states (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 529 |
+
Input hidden states from the decoder layer.
|
| 530 |
+
query_position_embeddings (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 531 |
+
Position embeddings for queries and keys. Required (unlike standard attention). Processed through
|
| 532 |
+
separate position projections (`q_pos_proj`, `k_pos_proj`) and added to content projections.
|
| 533 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, 1, num_queries, num_queries)`, *optional*):
|
| 534 |
+
Attention mask to avoid attending to padding tokens.
|
| 535 |
+
"""
|
| 536 |
+
input_shape = hidden_states.shape[:-1]
|
| 537 |
+
hidden_shape = (*input_shape, -1, self.head_dim)
|
| 538 |
+
|
| 539 |
+
query_states = (
|
| 540 |
+
(self.q_content_proj(hidden_states) + self.q_pos_proj(query_position_embeddings))
|
| 541 |
+
.view(hidden_shape)
|
| 542 |
+
.transpose(1, 2)
|
| 543 |
+
)
|
| 544 |
+
key_states = (
|
| 545 |
+
(self.k_content_proj(hidden_states) + self.k_pos_proj(query_position_embeddings))
|
| 546 |
+
.view(hidden_shape)
|
| 547 |
+
.transpose(1, 2)
|
| 548 |
+
)
|
| 549 |
+
value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 550 |
+
|
| 551 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 552 |
+
self.config._attn_implementation, eager_attention_forward
|
| 553 |
+
)
|
| 554 |
+
|
| 555 |
+
attn_output, attn_weights = attention_interface(
|
| 556 |
+
self,
|
| 557 |
+
query_states,
|
| 558 |
+
key_states,
|
| 559 |
+
value_states,
|
| 560 |
+
attention_mask,
|
| 561 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 562 |
+
scaling=self.scaling,
|
| 563 |
+
**kwargs,
|
| 564 |
+
)
|
| 565 |
+
|
| 566 |
+
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
| 567 |
+
attn_output = self.o_proj(attn_output)
|
| 568 |
+
return attn_output, attn_weights
|
| 569 |
+
|
| 570 |
+
|
| 571 |
+
class ConditionalDetrDecoderCrossAttention(nn.Module):
|
| 572 |
+
"""
|
| 573 |
+
Multi-headed cross-attention for Conditional DETR decoder layers.
|
| 574 |
+
|
| 575 |
+
This attention module handles the special cross-attention logic in Conditional DETR:
|
| 576 |
+
- Separate content and position projections for queries and keys
|
| 577 |
+
- Concatenation of query sine embeddings with queries (doubling query dimension)
|
| 578 |
+
- Concatenation of key position embeddings with keys (doubling key dimension)
|
| 579 |
+
- Output dimension remains hidden_size despite doubled input dimensions
|
| 580 |
+
"""
|
| 581 |
+
|
| 582 |
+
def __init__(
|
| 583 |
+
self,
|
| 584 |
+
config: ConditionalDetrConfig,
|
| 585 |
+
hidden_size: int,
|
| 586 |
+
num_attention_heads: int,
|
| 587 |
+
dropout: float | int = 0.0,
|
| 588 |
+
):
|
| 589 |
+
super().__init__()
|
| 590 |
+
self.config = config
|
| 591 |
+
self.hidden_size = hidden_size
|
| 592 |
+
self.num_attention_heads = num_attention_heads
|
| 593 |
+
self.head_dim = hidden_size // num_attention_heads
|
| 594 |
+
self.attention_dropout = dropout
|
| 595 |
+
self.is_causal = False
|
| 596 |
+
|
| 597 |
+
# Content and position projections
|
| 598 |
+
self.q_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 599 |
+
self.q_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 600 |
+
self.k_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 601 |
+
self.k_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 602 |
+
self.v_proj = nn.Linear(hidden_size, hidden_size)
|
| 603 |
+
self.q_pos_sine_proj = nn.Linear(hidden_size, hidden_size)
|
| 604 |
+
|
| 605 |
+
# Output projection: input is hidden_size * 2 (from concatenated q/k), output is hidden_size
|
| 606 |
+
self.o_proj = nn.Linear(hidden_size, hidden_size)
|
| 607 |
+
|
| 608 |
+
# Compute scaling for expanded head_dim (q and k have doubled dimensions after concatenation)
|
| 609 |
+
# This matches the original Conditional DETR implementation where embed_dim * 2 is used
|
| 610 |
+
expanded_head_dim = (hidden_size * 2) // num_attention_heads
|
| 611 |
+
self.scaling = expanded_head_dim**-0.5
|
| 612 |
+
|
| 613 |
+
def forward(
|
| 614 |
+
self,
|
| 615 |
+
hidden_states: torch.Tensor,
|
| 616 |
+
encoder_hidden_states: torch.Tensor,
|
| 617 |
+
query_sine_embed: torch.Tensor,
|
| 618 |
+
encoder_position_embeddings: torch.Tensor,
|
| 619 |
+
query_position_embeddings: torch.Tensor | None = None,
|
| 620 |
+
attention_mask: torch.Tensor | None = None,
|
| 621 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 622 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 623 |
+
"""
|
| 624 |
+
Args:
|
| 625 |
+
hidden_states (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 626 |
+
Decoder hidden states (queries).
|
| 627 |
+
encoder_hidden_states (`torch.Tensor` of shape `(batch_size, encoder_seq_len, hidden_size)`):
|
| 628 |
+
Encoder output hidden states (keys and values).
|
| 629 |
+
query_sine_embed (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 630 |
+
Sine position embeddings for queries. **Concatenated** (not added) with query content,
|
| 631 |
+
doubling the query dimension.
|
| 632 |
+
encoder_position_embeddings (`torch.Tensor` of shape `(batch_size, encoder_seq_len, hidden_size)`):
|
| 633 |
+
Position embeddings for keys. **Concatenated** (not added) with key content, doubling the key dimension.
|
| 634 |
+
query_position_embeddings (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 635 |
+
Additional position embeddings. When provided (first layer only), **added** to query content
|
| 636 |
+
before concatenation with `query_sine_embed`. Also causes `encoder_position_embeddings` to be
|
| 637 |
+
added to key content before concatenation.
|
| 638 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, 1, num_queries, encoder_seq_len)`, *optional*):
|
| 639 |
+
Attention mask to avoid attending to padding tokens.
|
| 640 |
+
"""
|
| 641 |
+
query_input_shape = hidden_states.shape[:-1]
|
| 642 |
+
kv_input_shape = encoder_hidden_states.shape[:-1]
|
| 643 |
+
query_hidden_shape = (*query_input_shape, self.num_attention_heads, self.head_dim)
|
| 644 |
+
kv_hidden_shape = (*kv_input_shape, self.num_attention_heads, self.head_dim)
|
| 645 |
+
|
| 646 |
+
# Apply content and position projections
|
| 647 |
+
query_input = self.q_content_proj(hidden_states)
|
| 648 |
+
key_input = self.k_content_proj(encoder_hidden_states)
|
| 649 |
+
value_states = self.v_proj(encoder_hidden_states)
|
| 650 |
+
key_pos = self.k_pos_proj(encoder_position_embeddings)
|
| 651 |
+
|
| 652 |
+
# Combine content and position embeddings
|
| 653 |
+
if query_position_embeddings is not None:
|
| 654 |
+
query_input = query_input + self.q_pos_proj(query_position_embeddings)
|
| 655 |
+
key_input = key_input + key_pos
|
| 656 |
+
|
| 657 |
+
# Reshape and concatenate position embeddings (doubling head_dim)
|
| 658 |
+
query_input = query_input.view(query_hidden_shape)
|
| 659 |
+
key_input = key_input.view(kv_hidden_shape)
|
| 660 |
+
query_sine_embed = self.q_pos_sine_proj(query_sine_embed).view(query_hidden_shape)
|
| 661 |
+
key_pos = key_pos.view(kv_hidden_shape)
|
| 662 |
+
|
| 663 |
+
query_states = torch.cat([query_input, query_sine_embed], dim=-1).view(*query_input_shape, -1)
|
| 664 |
+
key_states = torch.cat([key_input, key_pos], dim=-1).view(*kv_input_shape, -1)
|
| 665 |
+
|
| 666 |
+
# Reshape for attention computation
|
| 667 |
+
expanded_head_dim = query_states.shape[-1] // self.num_attention_heads
|
| 668 |
+
query_states = query_states.view(*query_input_shape, self.num_attention_heads, expanded_head_dim).transpose(
|
| 669 |
+
1, 2
|
| 670 |
+
)
|
| 671 |
+
key_states = key_states.view(*kv_input_shape, self.num_attention_heads, expanded_head_dim).transpose(1, 2)
|
| 672 |
+
value_states = value_states.view(kv_hidden_shape).transpose(1, 2)
|
| 673 |
+
|
| 674 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 675 |
+
self.config._attn_implementation, eager_attention_forward
|
| 676 |
+
)
|
| 677 |
+
|
| 678 |
+
attn_output, attn_weights = attention_interface(
|
| 679 |
+
self,
|
| 680 |
+
query_states,
|
| 681 |
+
key_states,
|
| 682 |
+
value_states,
|
| 683 |
+
attention_mask,
|
| 684 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 685 |
+
scaling=self.scaling,
|
| 686 |
+
**kwargs,
|
| 687 |
+
)
|
| 688 |
+
|
| 689 |
+
attn_output = attn_output.reshape(*query_input_shape, -1).contiguous()
|
| 690 |
+
attn_output = self.o_proj(attn_output)
|
| 691 |
+
return attn_output, attn_weights
|
| 692 |
+
|
| 693 |
+
|
| 694 |
+
class ConditionalDetrMLP(nn.Module):
|
| 695 |
+
def __init__(self, config: ConditionalDetrConfig, hidden_size: int, intermediate_size: int):
|
| 696 |
+
super().__init__()
|
| 697 |
+
self.fc1 = nn.Linear(hidden_size, intermediate_size)
|
| 698 |
+
self.fc2 = nn.Linear(intermediate_size, hidden_size)
|
| 699 |
+
self.activation_fn = ACT2FN[config.activation_function]
|
| 700 |
+
self.activation_dropout = config.activation_dropout
|
| 701 |
+
self.dropout = config.dropout
|
| 702 |
+
|
| 703 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 704 |
+
hidden_states = self.activation_fn(self.fc1(hidden_states))
|
| 705 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.activation_dropout, training=self.training)
|
| 706 |
+
hidden_states = self.fc2(hidden_states)
|
| 707 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 708 |
+
return hidden_states
|
| 709 |
+
|
| 710 |
+
|
| 711 |
+
class ConditionalDetrEncoderLayer(GradientCheckpointingLayer):
|
| 712 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 713 |
+
super().__init__()
|
| 714 |
+
self.hidden_size = config.d_model
|
| 715 |
+
self.self_attn = ConditionalDetrSelfAttention(
|
| 716 |
+
config=config,
|
| 717 |
+
hidden_size=self.hidden_size,
|
| 718 |
+
num_attention_heads=config.encoder_attention_heads,
|
| 719 |
+
dropout=config.attention_dropout,
|
| 720 |
+
)
|
| 721 |
+
self.self_attn_layer_norm = nn.LayerNorm(self.hidden_size)
|
| 722 |
+
self.dropout = config.dropout
|
| 723 |
+
self.mlp = ConditionalDetrMLP(config, self.hidden_size, config.encoder_ffn_dim)
|
| 724 |
+
self.final_layer_norm = nn.LayerNorm(self.hidden_size)
|
| 725 |
+
|
| 726 |
+
def forward(
|
| 727 |
+
self,
|
| 728 |
+
hidden_states: torch.Tensor,
|
| 729 |
+
attention_mask: torch.Tensor,
|
| 730 |
+
spatial_position_embeddings: torch.Tensor | None = None,
|
| 731 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 732 |
+
) -> torch.Tensor:
|
| 733 |
+
"""
|
| 734 |
+
Args:
|
| 735 |
+
hidden_states (`torch.FloatTensor`): input to the layer of shape `(batch, seq_len, hidden_size)`
|
| 736 |
+
attention_mask (`torch.FloatTensor`): attention mask of size
|
| 737 |
+
`(batch, 1, target_len, source_len)` where padding elements are indicated by very large negative
|
| 738 |
+
values.
|
| 739 |
+
spatial_position_embeddings (`torch.FloatTensor`, *optional*):
|
| 740 |
+
Spatial position embeddings (2D positional encodings of image locations), to be added to both
|
| 741 |
+
the queries and keys in self-attention (but not to values).
|
| 742 |
+
"""
|
| 743 |
+
residual = hidden_states
|
| 744 |
+
hidden_states, _ = self.self_attn(
|
| 745 |
+
hidden_states=hidden_states,
|
| 746 |
+
attention_mask=attention_mask,
|
| 747 |
+
position_embeddings=spatial_position_embeddings,
|
| 748 |
+
**kwargs,
|
| 749 |
+
)
|
| 750 |
+
|
| 751 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 752 |
+
hidden_states = residual + hidden_states
|
| 753 |
+
hidden_states = self.self_attn_layer_norm(hidden_states)
|
| 754 |
+
|
| 755 |
+
residual = hidden_states
|
| 756 |
+
hidden_states = self.mlp(hidden_states)
|
| 757 |
+
hidden_states = residual + hidden_states
|
| 758 |
+
hidden_states = self.final_layer_norm(hidden_states)
|
| 759 |
+
|
| 760 |
+
if self.training:
|
| 761 |
+
if not torch.isfinite(hidden_states).all():
|
| 762 |
+
clamp_value = torch.finfo(hidden_states.dtype).max - 1000
|
| 763 |
+
hidden_states = torch.clamp(hidden_states, min=-clamp_value, max=clamp_value)
|
| 764 |
+
|
| 765 |
+
return hidden_states
|
| 766 |
+
|
| 767 |
+
|
| 768 |
+
class ConditionalDetrDecoderLayer(GradientCheckpointingLayer):
|
| 769 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 770 |
+
super().__init__()
|
| 771 |
+
self.hidden_size = config.d_model
|
| 772 |
+
self.self_attn = ConditionalDetrDecoderSelfAttention(
|
| 773 |
+
config=config,
|
| 774 |
+
hidden_size=self.hidden_size,
|
| 775 |
+
num_attention_heads=config.decoder_attention_heads,
|
| 776 |
+
dropout=config.attention_dropout,
|
| 777 |
+
)
|
| 778 |
+
self.dropout = config.dropout
|
| 779 |
+
|
| 780 |
+
self.self_attn_layer_norm = nn.LayerNorm(self.hidden_size)
|
| 781 |
+
self.encoder_attn = ConditionalDetrDecoderCrossAttention(
|
| 782 |
+
config=config,
|
| 783 |
+
hidden_size=self.hidden_size,
|
| 784 |
+
num_attention_heads=config.decoder_attention_heads,
|
| 785 |
+
dropout=config.attention_dropout,
|
| 786 |
+
)
|
| 787 |
+
self.encoder_attn_layer_norm = nn.LayerNorm(self.hidden_size)
|
| 788 |
+
self.mlp = ConditionalDetrMLP(config, self.hidden_size, config.decoder_ffn_dim)
|
| 789 |
+
self.final_layer_norm = nn.LayerNorm(self.hidden_size)
|
| 790 |
+
|
| 791 |
+
def forward(
|
| 792 |
+
self,
|
| 793 |
+
hidden_states: torch.Tensor,
|
| 794 |
+
attention_mask: torch.Tensor | None = None,
|
| 795 |
+
spatial_position_embeddings: torch.Tensor | None = None,
|
| 796 |
+
query_position_embeddings: torch.Tensor | None = None,
|
| 797 |
+
query_sine_embed: torch.Tensor | None = None,
|
| 798 |
+
encoder_hidden_states: torch.Tensor | None = None,
|
| 799 |
+
encoder_attention_mask: torch.Tensor | None = None,
|
| 800 |
+
is_first: bool | None = False,
|
| 801 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 802 |
+
) -> torch.Tensor:
|
| 803 |
+
"""
|
| 804 |
+
Args:
|
| 805 |
+
hidden_states (`torch.FloatTensor`): input to the layer of shape `(seq_len, batch, embed_dim)`
|
| 806 |
+
attention_mask (`torch.FloatTensor`): attention mask of size
|
| 807 |
+
`(batch, 1, target_len, source_len)` where padding elements are indicated by very large negative
|
| 808 |
+
values.
|
| 809 |
+
spatial_position_embeddings (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 810 |
+
Spatial position embeddings (2D positional encodings) that are added to the queries and keys in each self-attention layer.
|
| 811 |
+
query_position_embeddings (`torch.FloatTensor`, *optional*):
|
| 812 |
+
object_queries that are added to the queries and keys
|
| 813 |
+
in the self-attention layer.
|
| 814 |
+
encoder_hidden_states (`torch.FloatTensor`):
|
| 815 |
+
cross attention input to the layer of shape `(seq_len, batch, embed_dim)`
|
| 816 |
+
encoder_attention_mask (`torch.FloatTensor`): encoder attention mask of size
|
| 817 |
+
`(batch, 1, target_len, source_len)` where padding elements are indicated by very large negative
|
| 818 |
+
values.
|
| 819 |
+
output_attentions (`bool`, *optional*):
|
| 820 |
+
Whether or not to return the attentions tensors of all attention layers. See `attentions` under
|
| 821 |
+
returned tensors for more detail.
|
| 822 |
+
"""
|
| 823 |
+
residual = hidden_states
|
| 824 |
+
|
| 825 |
+
hidden_states, _ = self.self_attn(
|
| 826 |
+
hidden_states=hidden_states,
|
| 827 |
+
query_position_embeddings=query_position_embeddings,
|
| 828 |
+
attention_mask=attention_mask,
|
| 829 |
+
**kwargs,
|
| 830 |
+
)
|
| 831 |
+
|
| 832 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 833 |
+
hidden_states = residual + hidden_states
|
| 834 |
+
hidden_states = self.self_attn_layer_norm(hidden_states)
|
| 835 |
+
|
| 836 |
+
if encoder_hidden_states is not None:
|
| 837 |
+
residual = hidden_states
|
| 838 |
+
|
| 839 |
+
hidden_states, _ = self.encoder_attn(
|
| 840 |
+
hidden_states=hidden_states,
|
| 841 |
+
encoder_hidden_states=encoder_hidden_states,
|
| 842 |
+
attention_mask=encoder_attention_mask,
|
| 843 |
+
query_sine_embed=query_sine_embed,
|
| 844 |
+
encoder_position_embeddings=spatial_position_embeddings,
|
| 845 |
+
# Only pass query_position_embeddings for the first layer
|
| 846 |
+
query_position_embeddings=query_position_embeddings if is_first else None,
|
| 847 |
+
**kwargs,
|
| 848 |
+
)
|
| 849 |
+
|
| 850 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 851 |
+
hidden_states = residual + hidden_states
|
| 852 |
+
hidden_states = self.encoder_attn_layer_norm(hidden_states)
|
| 853 |
+
|
| 854 |
+
# Fully Connected
|
| 855 |
+
residual = hidden_states
|
| 856 |
+
hidden_states = self.mlp(hidden_states)
|
| 857 |
+
hidden_states = residual + hidden_states
|
| 858 |
+
hidden_states = self.final_layer_norm(hidden_states)
|
| 859 |
+
|
| 860 |
+
return hidden_states
|
| 861 |
+
|
| 862 |
+
|
| 863 |
+
class ConditionalDetrMLPPredictionHead(nn.Module):
|
| 864 |
+
"""
|
| 865 |
+
Very simple multi-layer perceptron (MLP, also called FFN), used to predict the normalized center coordinates,
|
| 866 |
+
height and width of a bounding box w.r.t. an image.
|
| 867 |
+
|
| 868 |
+
"""
|
| 869 |
+
|
| 870 |
+
def __init__(self, input_dim, hidden_dim, output_dim, num_layers):
|
| 871 |
+
super().__init__()
|
| 872 |
+
self.num_layers = num_layers
|
| 873 |
+
h = [hidden_dim] * (num_layers - 1)
|
| 874 |
+
self.layers = nn.ModuleList(nn.Linear(n, k) for n, k in zip([input_dim] + h, h + [output_dim]))
|
| 875 |
+
|
| 876 |
+
def forward(self, x):
|
| 877 |
+
for i, layer in enumerate(self.layers):
|
| 878 |
+
x = nn.functional.relu(layer(x)) if i < self.num_layers - 1 else layer(x)
|
| 879 |
+
return x
|
| 880 |
+
|
| 881 |
+
|
| 882 |
+
class ConditionalDetrConvBlock(nn.Module):
|
| 883 |
+
"""Basic conv block: Conv3x3 -> GroupNorm -> Activation."""
|
| 884 |
+
|
| 885 |
+
def __init__(self, in_channels: int, out_channels: int, activation: str = "relu"):
|
| 886 |
+
super().__init__()
|
| 887 |
+
self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
|
| 888 |
+
self.norm = nn.GroupNorm(min(8, out_channels), out_channels)
|
| 889 |
+
self.activation = ACT2FN[activation]
|
| 890 |
+
|
| 891 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 892 |
+
return self.activation(self.norm(self.conv(x)))
|
| 893 |
+
|
| 894 |
+
|
| 895 |
+
class ConditionalDetrFPNFusionStage(nn.Module):
|
| 896 |
+
"""Single FPN fusion stage combining low-resolution features with high-resolution FPN features."""
|
| 897 |
+
|
| 898 |
+
def __init__(self, fpn_channels: int, current_channels: int, output_channels: int, activation: str = "relu"):
|
| 899 |
+
super().__init__()
|
| 900 |
+
self.fpn_adapter = nn.Conv2d(fpn_channels, current_channels, kernel_size=1)
|
| 901 |
+
self.refine = ConditionalDetrConvBlock(current_channels, output_channels, activation)
|
| 902 |
+
|
| 903 |
+
def forward(self, features: torch.Tensor, fpn_features: torch.Tensor) -> torch.Tensor:
|
| 904 |
+
"""
|
| 905 |
+
Args:
|
| 906 |
+
features: Current features to upsample, shape (B*Q, current_channels, H_in, W_in)
|
| 907 |
+
fpn_features: FPN features at target resolution, shape (B*Q, fpn_channels, H_out, W_out)
|
| 908 |
+
|
| 909 |
+
Returns:
|
| 910 |
+
Fused and refined features, shape (B*Q, output_channels, H_out, W_out)
|
| 911 |
+
"""
|
| 912 |
+
fpn_features = self.fpn_adapter(fpn_features)
|
| 913 |
+
features = nn.functional.interpolate(features, size=fpn_features.shape[-2:], mode="nearest")
|
| 914 |
+
return self.refine(fpn_features + features)
|
| 915 |
+
|
| 916 |
+
|
| 917 |
+
class ConditionalDetrMaskHeadSmallConv(nn.Module):
|
| 918 |
+
"""
|
| 919 |
+
Segmentation mask head that generates per-query masks using FPN-based progressive upsampling.
|
| 920 |
+
|
| 921 |
+
Combines attention maps (spatial localization) with encoder features (semantics) and progressively
|
| 922 |
+
upsamples through multiple scales, fusing with FPN features for high-resolution detail.
|
| 923 |
+
"""
|
| 924 |
+
|
| 925 |
+
def __init__(
|
| 926 |
+
self,
|
| 927 |
+
input_channels: int,
|
| 928 |
+
fpn_channels: list[int],
|
| 929 |
+
hidden_size: int,
|
| 930 |
+
activation_function: str = "relu",
|
| 931 |
+
):
|
| 932 |
+
super().__init__()
|
| 933 |
+
if input_channels % 8 != 0:
|
| 934 |
+
raise ValueError(f"input_channels must be divisible by 8, got {input_channels}")
|
| 935 |
+
|
| 936 |
+
self.conv1 = ConditionalDetrConvBlock(input_channels, input_channels, activation_function)
|
| 937 |
+
self.conv2 = ConditionalDetrConvBlock(input_channels, hidden_size // 2, activation_function)
|
| 938 |
+
|
| 939 |
+
# Progressive channel reduction: /2 -> /4 -> /8 -> /16
|
| 940 |
+
self.fpn_stages = nn.ModuleList(
|
| 941 |
+
[
|
| 942 |
+
ConditionalDetrFPNFusionStage(
|
| 943 |
+
fpn_channels[0], hidden_size // 2, hidden_size // 4, activation_function
|
| 944 |
+
),
|
| 945 |
+
ConditionalDetrFPNFusionStage(
|
| 946 |
+
fpn_channels[1], hidden_size // 4, hidden_size // 8, activation_function
|
| 947 |
+
),
|
| 948 |
+
ConditionalDetrFPNFusionStage(
|
| 949 |
+
fpn_channels[2], hidden_size // 8, hidden_size // 16, activation_function
|
| 950 |
+
),
|
| 951 |
+
]
|
| 952 |
+
)
|
| 953 |
+
|
| 954 |
+
self.output_conv = nn.Conv2d(hidden_size // 16, 1, kernel_size=3, padding=1)
|
| 955 |
+
|
| 956 |
+
def forward(
|
| 957 |
+
self,
|
| 958 |
+
features: torch.Tensor,
|
| 959 |
+
attention_masks: torch.Tensor,
|
| 960 |
+
fpn_features: list[torch.Tensor],
|
| 961 |
+
) -> torch.Tensor:
|
| 962 |
+
"""
|
| 963 |
+
Args:
|
| 964 |
+
features: Encoder output features, shape (batch_size, hidden_size, H, W)
|
| 965 |
+
attention_masks: Cross-attention maps from decoder, shape (batch_size, num_queries, num_heads, H, W)
|
| 966 |
+
fpn_features: List of 3 FPN features from low to high resolution, each (batch_size, C, H, W)
|
| 967 |
+
|
| 968 |
+
Returns:
|
| 969 |
+
Predicted masks, shape (batch_size * num_queries, 1, output_H, output_W)
|
| 970 |
+
"""
|
| 971 |
+
num_queries = attention_masks.shape[1]
|
| 972 |
+
|
| 973 |
+
# Expand to (batch_size * num_queries) dimension
|
| 974 |
+
features = features.unsqueeze(1).expand(-1, num_queries, -1, -1, -1).flatten(0, 1)
|
| 975 |
+
attention_masks = attention_masks.flatten(0, 1)
|
| 976 |
+
fpn_features = [
|
| 977 |
+
fpn_feat.unsqueeze(1).expand(-1, num_queries, -1, -1, -1).flatten(0, 1) for fpn_feat in fpn_features
|
| 978 |
+
]
|
| 979 |
+
|
| 980 |
+
hidden_states = torch.cat([features, attention_masks], dim=1)
|
| 981 |
+
hidden_states = self.conv1(hidden_states)
|
| 982 |
+
hidden_states = self.conv2(hidden_states)
|
| 983 |
+
|
| 984 |
+
for fpn_stage, fpn_feat in zip(self.fpn_stages, fpn_features):
|
| 985 |
+
hidden_states = fpn_stage(hidden_states, fpn_feat)
|
| 986 |
+
|
| 987 |
+
return self.output_conv(hidden_states)
|
| 988 |
+
|
| 989 |
+
|
| 990 |
+
class ConditionalDetrMHAttentionMap(nn.Module):
|
| 991 |
+
"""This is a 2D attention module, which only returns the attention softmax (no multiplication by value)"""
|
| 992 |
+
|
| 993 |
+
def __init__(
|
| 994 |
+
self,
|
| 995 |
+
hidden_size: int,
|
| 996 |
+
num_attention_heads: int,
|
| 997 |
+
dropout: float = 0.0,
|
| 998 |
+
bias: bool = True,
|
| 999 |
+
):
|
| 1000 |
+
super().__init__()
|
| 1001 |
+
self.head_dim = hidden_size // num_attention_heads
|
| 1002 |
+
self.scaling = self.head_dim**-0.5
|
| 1003 |
+
self.attention_dropout = dropout
|
| 1004 |
+
|
| 1005 |
+
self.q_proj = nn.Linear(hidden_size, hidden_size, bias=bias)
|
| 1006 |
+
self.k_proj = nn.Linear(hidden_size, hidden_size, bias=bias)
|
| 1007 |
+
|
| 1008 |
+
def forward(
|
| 1009 |
+
self, query_states: torch.Tensor, key_states: torch.Tensor, attention_mask: torch.Tensor | None = None
|
| 1010 |
+
):
|
| 1011 |
+
query_hidden_shape = (*query_states.shape[:-1], -1, self.head_dim)
|
| 1012 |
+
key_hidden_shape = (key_states.shape[0], -1, self.head_dim, *key_states.shape[-2:])
|
| 1013 |
+
|
| 1014 |
+
query_states = self.q_proj(query_states).view(query_hidden_shape)
|
| 1015 |
+
key_states = nn.functional.conv2d(
|
| 1016 |
+
key_states, self.k_proj.weight.unsqueeze(-1).unsqueeze(-1), self.k_proj.bias
|
| 1017 |
+
).view(key_hidden_shape)
|
| 1018 |
+
|
| 1019 |
+
batch_size, num_queries, num_heads, head_dim = query_states.shape
|
| 1020 |
+
_, _, _, height, width = key_states.shape
|
| 1021 |
+
query_shape = (batch_size * num_heads, num_queries, head_dim)
|
| 1022 |
+
key_shape = (batch_size * num_heads, height * width, head_dim)
|
| 1023 |
+
attn_weights_shape = (batch_size, num_heads, num_queries, height, width)
|
| 1024 |
+
|
| 1025 |
+
query = query_states.transpose(1, 2).contiguous().view(query_shape)
|
| 1026 |
+
key = key_states.permute(0, 1, 3, 4, 2).contiguous().view(key_shape)
|
| 1027 |
+
|
| 1028 |
+
attn_weights = (
|
| 1029 |
+
(torch.matmul(query * self.scaling, key.transpose(1, 2))).view(attn_weights_shape).transpose(1, 2)
|
| 1030 |
+
)
|
| 1031 |
+
|
| 1032 |
+
if attention_mask is not None:
|
| 1033 |
+
attn_weights = attn_weights + attention_mask
|
| 1034 |
+
|
| 1035 |
+
attn_weights = nn.functional.softmax(attn_weights.flatten(2), dim=-1).view(attn_weights.size())
|
| 1036 |
+
attn_weights = nn.functional.dropout(attn_weights, p=self.attention_dropout, training=self.training)
|
| 1037 |
+
|
| 1038 |
+
return attn_weights
|
| 1039 |
+
|
| 1040 |
+
|
| 1041 |
+
@auto_docstring
|
| 1042 |
+
class ConditionalDetrPreTrainedModel(PreTrainedModel):
|
| 1043 |
+
config: ConditionalDetrConfig
|
| 1044 |
+
base_model_prefix = "model"
|
| 1045 |
+
main_input_name = "pixel_values"
|
| 1046 |
+
input_modalities = ("image",)
|
| 1047 |
+
_no_split_modules = [r"ConditionalDetrConvEncoder", r"ConditionalDetrEncoderLayer", r"ConditionalDetrDecoderLayer"]
|
| 1048 |
+
supports_gradient_checkpointing = True
|
| 1049 |
+
_supports_sdpa = True
|
| 1050 |
+
_supports_flash_attn = True
|
| 1051 |
+
_supports_attention_backend = True
|
| 1052 |
+
_supports_flex_attn = True # Uses create_bidirectional_masks for attention masking
|
| 1053 |
+
_keys_to_ignore_on_load_unexpected = [
|
| 1054 |
+
r"detr\.model\.backbone\.model\.layer\d+\.0\.downsample\.1\.num_batches_tracked"
|
| 1055 |
+
]
|
| 1056 |
+
|
| 1057 |
+
@torch.no_grad()
|
| 1058 |
+
def _init_weights(self, module):
|
| 1059 |
+
std = self.config.init_std
|
| 1060 |
+
xavier_std = self.config.init_xavier_std
|
| 1061 |
+
|
| 1062 |
+
if isinstance(module, ConditionalDetrMaskHeadSmallConv):
|
| 1063 |
+
# ConditionalDetrMaskHeadSmallConv uses kaiming initialization for all its Conv2d layers
|
| 1064 |
+
for m in module.modules():
|
| 1065 |
+
if isinstance(m, nn.Conv2d):
|
| 1066 |
+
init.kaiming_uniform_(m.weight, a=1)
|
| 1067 |
+
if m.bias is not None:
|
| 1068 |
+
init.constant_(m.bias, 0)
|
| 1069 |
+
elif isinstance(module, ConditionalDetrMHAttentionMap):
|
| 1070 |
+
init.zeros_(module.k_proj.bias)
|
| 1071 |
+
init.zeros_(module.q_proj.bias)
|
| 1072 |
+
init.xavier_uniform_(module.k_proj.weight, gain=xavier_std)
|
| 1073 |
+
init.xavier_uniform_(module.q_proj.weight, gain=xavier_std)
|
| 1074 |
+
elif isinstance(module, ConditionalDetrLearnedPositionEmbedding):
|
| 1075 |
+
init.uniform_(module.row_embeddings.weight)
|
| 1076 |
+
init.uniform_(module.column_embeddings.weight)
|
| 1077 |
+
elif isinstance(module, (nn.Linear, nn.Conv2d)):
|
| 1078 |
+
init.normal_(module.weight, mean=0.0, std=std)
|
| 1079 |
+
if module.bias is not None:
|
| 1080 |
+
init.zeros_(module.bias)
|
| 1081 |
+
elif isinstance(module, nn.Embedding):
|
| 1082 |
+
init.normal_(module.weight, mean=0.0, std=std)
|
| 1083 |
+
# Here we need the check explicitly, as we slice the weight in the `zeros_` call, so it looses the flag
|
| 1084 |
+
if module.padding_idx is not None and not getattr(module.weight, "_is_hf_initialized", False):
|
| 1085 |
+
init.zeros_(module.weight[module.padding_idx])
|
| 1086 |
+
elif isinstance(module, (nn.LayerNorm, nn.GroupNorm)):
|
| 1087 |
+
init.ones_(module.weight)
|
| 1088 |
+
init.zeros_(module.bias)
|
| 1089 |
+
|
| 1090 |
+
|
| 1091 |
+
class ConditionalDetrEncoder(ConditionalDetrPreTrainedModel):
|
| 1092 |
+
"""
|
| 1093 |
+
Transformer encoder that processes a flattened feature map from a vision backbone, composed of a stack of
|
| 1094 |
+
[`ConditionalDetrEncoderLayer`] modules.
|
| 1095 |
+
|
| 1096 |
+
Args:
|
| 1097 |
+
config (`ConditionalDetrConfig`): Model configuration object.
|
| 1098 |
+
"""
|
| 1099 |
+
|
| 1100 |
+
_can_record_outputs = {"hidden_states": ConditionalDetrEncoderLayer, "attentions": ConditionalDetrSelfAttention}
|
| 1101 |
+
|
| 1102 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 1103 |
+
super().__init__(config)
|
| 1104 |
+
|
| 1105 |
+
self.dropout = config.dropout
|
| 1106 |
+
self.layers = nn.ModuleList([ConditionalDetrEncoderLayer(config) for _ in range(config.encoder_layers)])
|
| 1107 |
+
|
| 1108 |
+
# Initialize weights and apply final processing
|
| 1109 |
+
self.post_init()
|
| 1110 |
+
|
| 1111 |
+
@merge_with_config_defaults
|
| 1112 |
+
@capture_outputs
|
| 1113 |
+
def forward(
|
| 1114 |
+
self,
|
| 1115 |
+
inputs_embeds=None,
|
| 1116 |
+
attention_mask=None,
|
| 1117 |
+
spatial_position_embeddings=None,
|
| 1118 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 1119 |
+
) -> BaseModelOutput:
|
| 1120 |
+
r"""
|
| 1121 |
+
Args:
|
| 1122 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 1123 |
+
Flattened feature map (output of the backbone + projection layer) that is passed to the encoder.
|
| 1124 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 1125 |
+
Mask to avoid performing attention on padding pixel features. Mask values selected in `[0, 1]`:
|
| 1126 |
+
|
| 1127 |
+
- 1 for pixel features that are real (i.e. **not masked**),
|
| 1128 |
+
- 0 for pixel features that are padding (i.e. **masked**).
|
| 1129 |
+
|
| 1130 |
+
[What are attention masks?](../glossary#attention-mask)
|
| 1131 |
+
spatial_position_embeddings (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 1132 |
+
Spatial position embeddings (2D positional encodings) that are added to the queries and keys in each self-attention layer.
|
| 1133 |
+
"""
|
| 1134 |
+
hidden_states = inputs_embeds
|
| 1135 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 1136 |
+
|
| 1137 |
+
attention_mask = create_bidirectional_mask(
|
| 1138 |
+
config=self.config,
|
| 1139 |
+
inputs_embeds=inputs_embeds,
|
| 1140 |
+
attention_mask=attention_mask,
|
| 1141 |
+
)
|
| 1142 |
+
|
| 1143 |
+
for encoder_layer in self.layers:
|
| 1144 |
+
# we add spatial_position_embeddings as extra input to the encoder_layer
|
| 1145 |
+
hidden_states = encoder_layer(
|
| 1146 |
+
hidden_states, attention_mask, spatial_position_embeddings=spatial_position_embeddings, **kwargs
|
| 1147 |
+
)
|
| 1148 |
+
|
| 1149 |
+
return BaseModelOutput(last_hidden_state=hidden_states)
|
| 1150 |
+
|
| 1151 |
+
|
| 1152 |
+
def encode_sinusoidal_position_embedding(
|
| 1153 |
+
pos_tensor: torch.Tensor,
|
| 1154 |
+
num_pos_feats: int = 128,
|
| 1155 |
+
temperature: int = 10000,
|
| 1156 |
+
) -> torch.Tensor:
|
| 1157 |
+
"""Sinusoidal position embeddings from normalized anchor coordinates.
|
| 1158 |
+
|
| 1159 |
+
Each coordinate in `pos_tensor` is independently encoded with ``num_pos_feats``
|
| 1160 |
+
interleaved sin/cos components; per-coordinate embeddings are concatenated.
|
| 1161 |
+
Handles 2-D ``(x, y)`` and N-D ``(x, y, w, h)`` inputs. For 2-D+ inputs the
|
| 1162 |
+
x and y embeddings are swapped to follow the DETR ``[pos_y, pos_x, ...]`` convention.
|
| 1163 |
+
|
| 1164 |
+
Args:
|
| 1165 |
+
pos_tensor: Normalized coordinates in ``[0, 1]``, shape ``(..., n_coords)``.
|
| 1166 |
+
num_pos_feats: Embedding dimension per coordinate.
|
| 1167 |
+
temperature: Base for the frequency decay.
|
| 1168 |
+
|
| 1169 |
+
Returns:
|
| 1170 |
+
Tensor of shape ``(..., n_coords * num_pos_feats)``, same dtype as input.
|
| 1171 |
+
"""
|
| 1172 |
+
scale = 2 * math.pi
|
| 1173 |
+
dim_t = torch.arange(num_pos_feats, dtype=torch.float32, device=pos_tensor.device)
|
| 1174 |
+
dim_t = temperature ** (2 * torch.div(dim_t, 2, rounding_mode="floor") / num_pos_feats)
|
| 1175 |
+
|
| 1176 |
+
coords = pos_tensor.unbind(-1) # list of (...,) tensors
|
| 1177 |
+
embeddings = [coord[..., None] * scale / dim_t for coord in coords] # each (..., num_pos_feats)
|
| 1178 |
+
embeddings = [
|
| 1179 |
+
torch.stack((e[..., 0::2].sin(), e[..., 1::2].cos()), dim=-1).flatten(-2) for e in embeddings
|
| 1180 |
+
] # each (..., num_pos_feats)
|
| 1181 |
+
|
| 1182 |
+
if len(embeddings) >= 2:
|
| 1183 |
+
embeddings[0], embeddings[1] = embeddings[1], embeddings[0]
|
| 1184 |
+
|
| 1185 |
+
return torch.cat(embeddings, dim=-1).to(pos_tensor.dtype)
|
| 1186 |
+
|
| 1187 |
+
|
| 1188 |
+
class ConditionalDetrDecoder(ConditionalDetrPreTrainedModel):
|
| 1189 |
+
"""
|
| 1190 |
+
Transformer decoder consisting of *config.decoder_layers* layers. Each layer is a [`ConditionalDetrDecoderLayer`].
|
| 1191 |
+
|
| 1192 |
+
The decoder updates the query embeddings through multiple self-attention and cross-attention layers.
|
| 1193 |
+
|
| 1194 |
+
Some small tweaks for Conditional DETR:
|
| 1195 |
+
|
| 1196 |
+
- object_queries and query_position_embeddings are added to the forward pass.
|
| 1197 |
+
- if self.config.auxiliary_loss is set to True, also returns a stack of activations from all decoding layers.
|
| 1198 |
+
|
| 1199 |
+
Args:
|
| 1200 |
+
config: ConditionalDetrConfig
|
| 1201 |
+
"""
|
| 1202 |
+
|
| 1203 |
+
_can_record_outputs = {
|
| 1204 |
+
"hidden_states": ConditionalDetrDecoderLayer,
|
| 1205 |
+
"attentions": OutputRecorder(ConditionalDetrDecoderSelfAttention, layer_name="self_attn", index=1),
|
| 1206 |
+
"cross_attentions": OutputRecorder(ConditionalDetrDecoderCrossAttention, layer_name="encoder_attn", index=1),
|
| 1207 |
+
}
|
| 1208 |
+
|
| 1209 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 1210 |
+
super().__init__(config)
|
| 1211 |
+
self.hidden_size = config.d_model
|
| 1212 |
+
|
| 1213 |
+
self.dropout = config.dropout
|
| 1214 |
+
self.layerdrop = config.decoder_layerdrop
|
| 1215 |
+
|
| 1216 |
+
self.layers = nn.ModuleList([ConditionalDetrDecoderLayer(config) for _ in range(config.decoder_layers)])
|
| 1217 |
+
# in Conditional DETR, the decoder uses layernorm after the last decoder layer output
|
| 1218 |
+
self.layernorm = nn.LayerNorm(config.d_model)
|
| 1219 |
+
|
| 1220 |
+
# query_scale is the FFN applied on f to generate transformation T
|
| 1221 |
+
self.query_scale = ConditionalDetrMLPPredictionHead(self.hidden_size, self.hidden_size, self.hidden_size, 2)
|
| 1222 |
+
self.ref_point_head = ConditionalDetrMLPPredictionHead(self.hidden_size, self.hidden_size, 2, 2)
|
| 1223 |
+
for layer_id in range(config.decoder_layers - 1):
|
| 1224 |
+
# Set q_pos_proj to None for layers after the first (only first layer uses query position embeddings)
|
| 1225 |
+
self.layers[layer_id + 1].encoder_attn.q_pos_proj = None
|
| 1226 |
+
|
| 1227 |
+
# Initialize weights and apply final processing
|
| 1228 |
+
self.post_init()
|
| 1229 |
+
|
| 1230 |
+
@merge_with_config_defaults
|
| 1231 |
+
@capture_outputs
|
| 1232 |
+
def forward(
|
| 1233 |
+
self,
|
| 1234 |
+
inputs_embeds=None,
|
| 1235 |
+
attention_mask=None,
|
| 1236 |
+
encoder_hidden_states=None,
|
| 1237 |
+
encoder_attention_mask=None,
|
| 1238 |
+
spatial_position_embeddings=None,
|
| 1239 |
+
object_queries_position_embeddings=None,
|
| 1240 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 1241 |
+
) -> ConditionalDetrDecoderOutput:
|
| 1242 |
+
r"""
|
| 1243 |
+
Args:
|
| 1244 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 1245 |
+
The query embeddings that are passed into the decoder.
|
| 1246 |
+
|
| 1247 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 1248 |
+
Mask to avoid performing attention on certain queries. Mask values selected in `[0, 1]`:
|
| 1249 |
+
|
| 1250 |
+
- 1 for queries that are **not masked**,
|
| 1251 |
+
- 0 for queries that are **masked**.
|
| 1252 |
+
|
| 1253 |
+
[What are attention masks?](../glossary#attention-mask)
|
| 1254 |
+
encoder_hidden_states (`torch.FloatTensor` of shape `(batch_size, encoder_sequence_length, hidden_size)`, *optional*):
|
| 1255 |
+
Sequence of hidden-states at the output of the last layer of the encoder. Used in the cross-attention
|
| 1256 |
+
of the decoder.
|
| 1257 |
+
encoder_attention_mask (`torch.LongTensor` of shape `(batch_size, encoder_sequence_length)`, *optional*):
|
| 1258 |
+
Mask to avoid performing cross-attention on padding pixel_values of the encoder. Mask values selected
|
| 1259 |
+
in `[0, 1]`:
|
| 1260 |
+
|
| 1261 |
+
- 1 for pixels that are real (i.e. **not masked**),
|
| 1262 |
+
- 0 for pixels that are padding (i.e. **masked**).
|
| 1263 |
+
|
| 1264 |
+
spatial_position_embeddings (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 1265 |
+
Spatial position embeddings that are added to the queries and keys in each cross-attention layer.
|
| 1266 |
+
object_queries_position_embeddings (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 1267 |
+
, *optional*): Position embeddings that are added to the queries and keys in each self-attention layer.
|
| 1268 |
+
"""
|
| 1269 |
+
if inputs_embeds is not None:
|
| 1270 |
+
hidden_states = inputs_embeds
|
| 1271 |
+
|
| 1272 |
+
# expand encoder attention mask
|
| 1273 |
+
if encoder_hidden_states is not None and encoder_attention_mask is not None:
|
| 1274 |
+
# [batch_size, seq_len] -> [batch_size, 1, target_seq_len, source_seq_len]
|
| 1275 |
+
encoder_attention_mask = create_bidirectional_mask(
|
| 1276 |
+
self.config,
|
| 1277 |
+
inputs_embeds,
|
| 1278 |
+
encoder_attention_mask,
|
| 1279 |
+
)
|
| 1280 |
+
|
| 1281 |
+
# optional intermediate hidden states
|
| 1282 |
+
intermediate = () if self.config.auxiliary_loss else None
|
| 1283 |
+
|
| 1284 |
+
reference_points_before_sigmoid = self.ref_point_head(
|
| 1285 |
+
object_queries_position_embeddings
|
| 1286 |
+
) # [num_queries, batch_size, 2]
|
| 1287 |
+
reference_points = reference_points_before_sigmoid.sigmoid().transpose(0, 1)
|
| 1288 |
+
obj_center = reference_points[..., :2].transpose(0, 1)
|
| 1289 |
+
# get sine embedding for the query vector
|
| 1290 |
+
query_sine_embed_before_transformation = encode_sinusoidal_position_embedding(
|
| 1291 |
+
obj_center, num_pos_feats=self.config.d_model // 2
|
| 1292 |
+
)
|
| 1293 |
+
|
| 1294 |
+
for idx, decoder_layer in enumerate(self.layers):
|
| 1295 |
+
if self.training:
|
| 1296 |
+
dropout_probability = torch.rand([])
|
| 1297 |
+
if dropout_probability < self.layerdrop:
|
| 1298 |
+
continue
|
| 1299 |
+
if idx == 0:
|
| 1300 |
+
pos_transformation = 1
|
| 1301 |
+
else:
|
| 1302 |
+
pos_transformation = self.query_scale(hidden_states)
|
| 1303 |
+
# apply transformation
|
| 1304 |
+
query_sine_embed = query_sine_embed_before_transformation * pos_transformation
|
| 1305 |
+
|
| 1306 |
+
hidden_states = decoder_layer(
|
| 1307 |
+
hidden_states,
|
| 1308 |
+
None,
|
| 1309 |
+
spatial_position_embeddings,
|
| 1310 |
+
object_queries_position_embeddings,
|
| 1311 |
+
query_sine_embed,
|
| 1312 |
+
encoder_hidden_states, # as a positional argument for gradient checkpointing
|
| 1313 |
+
encoder_attention_mask=encoder_attention_mask,
|
| 1314 |
+
is_first=(idx == 0),
|
| 1315 |
+
**kwargs,
|
| 1316 |
+
)
|
| 1317 |
+
|
| 1318 |
+
if self.config.auxiliary_loss:
|
| 1319 |
+
hidden_states = self.layernorm(hidden_states)
|
| 1320 |
+
intermediate += (hidden_states,)
|
| 1321 |
+
|
| 1322 |
+
# finally, apply layernorm
|
| 1323 |
+
hidden_states = self.layernorm(hidden_states)
|
| 1324 |
+
|
| 1325 |
+
# stack intermediate decoder activations
|
| 1326 |
+
if self.config.auxiliary_loss:
|
| 1327 |
+
intermediate = torch.stack(intermediate)
|
| 1328 |
+
|
| 1329 |
+
return ConditionalDetrDecoderOutput(
|
| 1330 |
+
last_hidden_state=hidden_states,
|
| 1331 |
+
intermediate_hidden_states=intermediate,
|
| 1332 |
+
reference_points=reference_points,
|
| 1333 |
+
)
|
| 1334 |
+
|
| 1335 |
+
|
| 1336 |
+
@auto_docstring(
|
| 1337 |
+
custom_intro="""
|
| 1338 |
+
The bare CONDITIONAL_DETR Model (consisting of a backbone and encoder-decoder Transformer) outputting raw hidden-states without
|
| 1339 |
+
any specific head on top.
|
| 1340 |
+
"""
|
| 1341 |
+
)
|
| 1342 |
+
class ConditionalDetrModel(ConditionalDetrPreTrainedModel):
|
| 1343 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 1344 |
+
super().__init__(config)
|
| 1345 |
+
|
| 1346 |
+
self.backbone = ConditionalDetrConvEncoder(config)
|
| 1347 |
+
|
| 1348 |
+
if config.position_embedding_type == "sine":
|
| 1349 |
+
self.position_embedding = ConditionalDetrSinePositionEmbedding(config.d_model // 2, normalize=True)
|
| 1350 |
+
elif config.position_embedding_type == "learned":
|
| 1351 |
+
self.position_embedding = ConditionalDetrLearnedPositionEmbedding(config.d_model // 2)
|
| 1352 |
+
else:
|
| 1353 |
+
raise ValueError(f"Not supported {config.position_embedding_type}")
|
| 1354 |
+
self.query_position_embeddings = nn.Embedding(config.num_queries, config.d_model)
|
| 1355 |
+
self.input_projection = nn.Conv2d(self.backbone.intermediate_channel_sizes[-1], config.d_model, kernel_size=1)
|
| 1356 |
+
|
| 1357 |
+
self.encoder = ConditionalDetrEncoder(config)
|
| 1358 |
+
self.decoder = ConditionalDetrDecoder(config)
|
| 1359 |
+
|
| 1360 |
+
# Initialize weights and apply final processing
|
| 1361 |
+
self.post_init()
|
| 1362 |
+
|
| 1363 |
+
def freeze_backbone(self):
|
| 1364 |
+
for _, param in self.backbone.model.named_parameters():
|
| 1365 |
+
param.requires_grad_(False)
|
| 1366 |
+
|
| 1367 |
+
def unfreeze_backbone(self):
|
| 1368 |
+
for _, param in self.backbone.model.named_parameters():
|
| 1369 |
+
param.requires_grad_(True)
|
| 1370 |
+
|
| 1371 |
+
@auto_docstring
|
| 1372 |
+
@can_return_tuple
|
| 1373 |
+
def forward(
|
| 1374 |
+
self,
|
| 1375 |
+
pixel_values: torch.FloatTensor,
|
| 1376 |
+
pixel_mask: torch.LongTensor | None = None,
|
| 1377 |
+
decoder_attention_mask: torch.LongTensor | None = None,
|
| 1378 |
+
encoder_outputs: torch.FloatTensor | None = None,
|
| 1379 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 1380 |
+
decoder_inputs_embeds: torch.FloatTensor | None = None,
|
| 1381 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 1382 |
+
) -> ConditionalDetrModelOutput:
|
| 1383 |
+
r"""
|
| 1384 |
+
decoder_attention_mask (`torch.FloatTensor` of shape `(batch_size, num_queries)`, *optional*):
|
| 1385 |
+
Not used by default. Can be used to mask object queries.
|
| 1386 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 1387 |
+
Optionally, instead of passing the flattened feature map (output of the backbone + projection layer), you
|
| 1388 |
+
can choose to directly pass a flattened representation of an image.
|
| 1389 |
+
decoder_inputs_embeds (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 1390 |
+
Optionally, instead of initializing the queries with a tensor of zeros, you can choose to directly pass an
|
| 1391 |
+
embedded representation.
|
| 1392 |
+
|
| 1393 |
+
Examples:
|
| 1394 |
+
|
| 1395 |
+
```python
|
| 1396 |
+
>>> from transformers import AutoImageProcessor, AutoModel
|
| 1397 |
+
>>> from PIL import Image
|
| 1398 |
+
>>> import httpx
|
| 1399 |
+
>>> from io import BytesIO
|
| 1400 |
+
|
| 1401 |
+
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
| 1402 |
+
>>> with httpx.stream("GET", url) as response:
|
| 1403 |
+
... image = Image.open(BytesIO(response.read()))
|
| 1404 |
+
|
| 1405 |
+
>>> image_processor = AutoImageProcessor.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 1406 |
+
>>> model = AutoModel.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 1407 |
+
|
| 1408 |
+
>>> # prepare image for the model
|
| 1409 |
+
>>> inputs = image_processor(images=image, return_tensors="pt")
|
| 1410 |
+
|
| 1411 |
+
>>> # forward pass
|
| 1412 |
+
>>> outputs = model(**inputs)
|
| 1413 |
+
|
| 1414 |
+
>>> # the last hidden states are the final query embeddings of the Transformer decoder
|
| 1415 |
+
>>> # these are of shape (batch_size, num_queries, hidden_size)
|
| 1416 |
+
>>> last_hidden_states = outputs.last_hidden_state
|
| 1417 |
+
>>> list(last_hidden_states.shape)
|
| 1418 |
+
[1, 300, 256]
|
| 1419 |
+
```"""
|
| 1420 |
+
batch_size, num_channels, height, width = pixel_values.shape
|
| 1421 |
+
device = pixel_values.device
|
| 1422 |
+
|
| 1423 |
+
if pixel_mask is None:
|
| 1424 |
+
pixel_mask = torch.ones(((batch_size, height, width)), device=device)
|
| 1425 |
+
|
| 1426 |
+
# First, sent pixel_values + pixel_mask through Backbone to obtain the features
|
| 1427 |
+
# pixel_values should be of shape (batch_size, num_channels, height, width)
|
| 1428 |
+
# pixel_mask should be of shape (batch_size, height, width)
|
| 1429 |
+
features = self.backbone(pixel_values, pixel_mask)
|
| 1430 |
+
|
| 1431 |
+
# get final feature map and downsampled mask
|
| 1432 |
+
feature_map, mask = features[-1]
|
| 1433 |
+
|
| 1434 |
+
if mask is None:
|
| 1435 |
+
raise ValueError("Backbone does not return downsampled pixel mask")
|
| 1436 |
+
|
| 1437 |
+
# Second, apply 1x1 convolution to reduce the channel dimension to d_model (256 by default)
|
| 1438 |
+
projected_feature_map = self.input_projection(feature_map)
|
| 1439 |
+
|
| 1440 |
+
# Generate position embeddings
|
| 1441 |
+
spatial_position_embeddings = (
|
| 1442 |
+
self.position_embedding(shape=feature_map.shape, device=device, dtype=pixel_values.dtype, mask=mask)
|
| 1443 |
+
.flatten(2)
|
| 1444 |
+
.transpose(1, 2)
|
| 1445 |
+
)
|
| 1446 |
+
|
| 1447 |
+
# Third, flatten the feature map of shape NxCxHxW to NxCxHW, and permute it to NxHWxC
|
| 1448 |
+
# In other words, turn their shape into (batch_size, sequence_length, hidden_size)
|
| 1449 |
+
flattened_features = projected_feature_map.flatten(2).transpose(1, 2)
|
| 1450 |
+
|
| 1451 |
+
flattened_mask = mask.flatten(1)
|
| 1452 |
+
|
| 1453 |
+
# Fourth, sent flattened_features + flattened_mask + spatial_position_embeddings through encoder
|
| 1454 |
+
# flattened_features is a Tensor of shape (batch_size, height*width, hidden_size)
|
| 1455 |
+
# flattened_mask is a Tensor of shape (batch_size, height*width)
|
| 1456 |
+
if encoder_outputs is None:
|
| 1457 |
+
encoder_outputs = self.encoder(
|
| 1458 |
+
inputs_embeds=flattened_features,
|
| 1459 |
+
attention_mask=flattened_mask,
|
| 1460 |
+
spatial_position_embeddings=spatial_position_embeddings,
|
| 1461 |
+
**kwargs,
|
| 1462 |
+
)
|
| 1463 |
+
# If the user passed a tuple for encoder_outputs, we wrap it in a BaseModelOutput
|
| 1464 |
+
elif not isinstance(encoder_outputs, BaseModelOutput):
|
| 1465 |
+
encoder_outputs = BaseModelOutput(
|
| 1466 |
+
last_hidden_state=encoder_outputs[0],
|
| 1467 |
+
hidden_states=encoder_outputs[1] if len(encoder_outputs) > 1 else None,
|
| 1468 |
+
attentions=encoder_outputs[2] if len(encoder_outputs) > 2 else None,
|
| 1469 |
+
)
|
| 1470 |
+
|
| 1471 |
+
# Fifth, sent query embeddings through the decoder (which is conditioned on the encoder output)
|
| 1472 |
+
object_queries_position_embeddings = self.query_position_embeddings.weight.unsqueeze(0).repeat(
|
| 1473 |
+
batch_size, 1, 1
|
| 1474 |
+
)
|
| 1475 |
+
queries = torch.zeros_like(object_queries_position_embeddings)
|
| 1476 |
+
|
| 1477 |
+
# decoder outputs consists of (dec_features, dec_hidden, dec_attn)
|
| 1478 |
+
decoder_outputs = self.decoder(
|
| 1479 |
+
inputs_embeds=queries,
|
| 1480 |
+
attention_mask=None,
|
| 1481 |
+
spatial_position_embeddings=spatial_position_embeddings,
|
| 1482 |
+
object_queries_position_embeddings=object_queries_position_embeddings,
|
| 1483 |
+
encoder_hidden_states=encoder_outputs.last_hidden_state,
|
| 1484 |
+
encoder_attention_mask=flattened_mask,
|
| 1485 |
+
**kwargs,
|
| 1486 |
+
)
|
| 1487 |
+
|
| 1488 |
+
return ConditionalDetrModelOutput(
|
| 1489 |
+
last_hidden_state=decoder_outputs.last_hidden_state,
|
| 1490 |
+
decoder_hidden_states=decoder_outputs.hidden_states,
|
| 1491 |
+
decoder_attentions=decoder_outputs.attentions,
|
| 1492 |
+
cross_attentions=decoder_outputs.cross_attentions,
|
| 1493 |
+
encoder_last_hidden_state=encoder_outputs.last_hidden_state,
|
| 1494 |
+
encoder_hidden_states=encoder_outputs.hidden_states,
|
| 1495 |
+
encoder_attentions=encoder_outputs.attentions,
|
| 1496 |
+
intermediate_hidden_states=decoder_outputs.intermediate_hidden_states,
|
| 1497 |
+
reference_points=decoder_outputs.reference_points,
|
| 1498 |
+
)
|
| 1499 |
+
|
| 1500 |
+
|
| 1501 |
+
def inverse_sigmoid(x, eps=1e-5):
|
| 1502 |
+
x = x.clamp(min=0, max=1)
|
| 1503 |
+
x1 = x.clamp(min=eps)
|
| 1504 |
+
x2 = (1 - x).clamp(min=eps)
|
| 1505 |
+
return torch.log(x1 / x2)
|
| 1506 |
+
|
| 1507 |
+
|
| 1508 |
+
@auto_docstring(
|
| 1509 |
+
custom_intro="""
|
| 1510 |
+
CONDITIONAL_DETR Model (consisting of a backbone and encoder-decoder Transformer) with object detection heads on top, for tasks
|
| 1511 |
+
such as COCO detection.
|
| 1512 |
+
"""
|
| 1513 |
+
)
|
| 1514 |
+
class ConditionalDetrForObjectDetection(ConditionalDetrPreTrainedModel):
|
| 1515 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 1516 |
+
super().__init__(config)
|
| 1517 |
+
|
| 1518 |
+
# CONDITIONAL_DETR encoder-decoder model
|
| 1519 |
+
self.model = ConditionalDetrModel(config)
|
| 1520 |
+
self.class_labels_classifier = nn.Linear(config.d_model, config.num_labels)
|
| 1521 |
+
self.bbox_predictor = ConditionalDetrMLPPredictionHead(
|
| 1522 |
+
input_dim=config.d_model, hidden_dim=config.d_model, output_dim=4, num_layers=3
|
| 1523 |
+
)
|
| 1524 |
+
|
| 1525 |
+
# Initialize weights and apply final processing
|
| 1526 |
+
self.post_init()
|
| 1527 |
+
|
| 1528 |
+
@auto_docstring
|
| 1529 |
+
@can_return_tuple
|
| 1530 |
+
def forward(
|
| 1531 |
+
self,
|
| 1532 |
+
pixel_values: torch.FloatTensor,
|
| 1533 |
+
pixel_mask: torch.LongTensor | None = None,
|
| 1534 |
+
decoder_attention_mask: torch.LongTensor | None = None,
|
| 1535 |
+
encoder_outputs: torch.FloatTensor | None = None,
|
| 1536 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 1537 |
+
decoder_inputs_embeds: torch.FloatTensor | None = None,
|
| 1538 |
+
labels: list[dict] | None = None,
|
| 1539 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 1540 |
+
) -> ConditionalDetrObjectDetectionOutput:
|
| 1541 |
+
r"""
|
| 1542 |
+
decoder_attention_mask (`torch.FloatTensor` of shape `(batch_size, num_queries)`, *optional*):
|
| 1543 |
+
Not used by default. Can be used to mask object queries.
|
| 1544 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 1545 |
+
Optionally, instead of passing the flattened feature map (output of the backbone + projection layer), you
|
| 1546 |
+
can choose to directly pass a flattened representation of an image.
|
| 1547 |
+
decoder_inputs_embeds (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 1548 |
+
Optionally, instead of initializing the queries with a tensor of zeros, you can choose to directly pass an
|
| 1549 |
+
embedded representation.
|
| 1550 |
+
labels (`list[Dict]` of len `(batch_size,)`, *optional*):
|
| 1551 |
+
Labels for computing the bipartite matching loss. List of dicts, each dictionary containing at least the
|
| 1552 |
+
following 2 keys: 'class_labels' and 'boxes' (the class labels and bounding boxes of an image in the batch
|
| 1553 |
+
respectively). The class labels themselves should be a `torch.LongTensor` of len `(number of bounding boxes
|
| 1554 |
+
in the image,)` and the boxes a `torch.FloatTensor` of shape `(number of bounding boxes in the image, 4)`.
|
| 1555 |
+
|
| 1556 |
+
Examples:
|
| 1557 |
+
|
| 1558 |
+
```python
|
| 1559 |
+
>>> from transformers import AutoImageProcessor, AutoModelForObjectDetection
|
| 1560 |
+
>>> from PIL import Image
|
| 1561 |
+
>>> import httpx
|
| 1562 |
+
>>> from io import BytesIO
|
| 1563 |
+
|
| 1564 |
+
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
| 1565 |
+
>>> with httpx.stream("GET", url) as response:
|
| 1566 |
+
... image = Image.open(BytesIO(response.read()))
|
| 1567 |
+
|
| 1568 |
+
>>> image_processor = AutoImageProcessor.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 1569 |
+
>>> model = AutoModelForObjectDetection.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 1570 |
+
|
| 1571 |
+
>>> inputs = image_processor(images=image, return_tensors="pt")
|
| 1572 |
+
|
| 1573 |
+
>>> outputs = model(**inputs)
|
| 1574 |
+
|
| 1575 |
+
>>> # convert outputs (bounding boxes and class logits) to Pascal VOC format (xmin, ymin, xmax, ymax)
|
| 1576 |
+
>>> target_sizes = torch.tensor([image.size[::-1]])
|
| 1577 |
+
>>> results = image_processor.post_process_object_detection(outputs, threshold=0.5, target_sizes=target_sizes)[
|
| 1578 |
+
... 0
|
| 1579 |
+
... ]
|
| 1580 |
+
>>> for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
|
| 1581 |
+
... box = [round(i, 2) for i in box.tolist()]
|
| 1582 |
+
... print(
|
| 1583 |
+
... f"Detected {model.config.id2label[label.item()]} with confidence "
|
| 1584 |
+
... f"{round(score.item(), 3)} at location {box}"
|
| 1585 |
+
... )
|
| 1586 |
+
Detected remote with confidence 0.833 at location [38.31, 72.1, 177.63, 118.45]
|
| 1587 |
+
Detected cat with confidence 0.831 at location [9.2, 51.38, 321.13, 469.0]
|
| 1588 |
+
Detected cat with confidence 0.804 at location [340.3, 16.85, 642.93, 370.95]
|
| 1589 |
+
Detected remote with confidence 0.683 at location [334.48, 73.49, 366.37, 190.01]
|
| 1590 |
+
Detected couch with confidence 0.535 at location [0.52, 1.19, 640.35, 475.1]
|
| 1591 |
+
```"""
|
| 1592 |
+
# First, sent images through CONDITIONAL_DETR base model to obtain encoder + decoder outputs
|
| 1593 |
+
outputs = self.model(
|
| 1594 |
+
pixel_values,
|
| 1595 |
+
pixel_mask=pixel_mask,
|
| 1596 |
+
decoder_attention_mask=decoder_attention_mask,
|
| 1597 |
+
encoder_outputs=encoder_outputs,
|
| 1598 |
+
inputs_embeds=inputs_embeds,
|
| 1599 |
+
decoder_inputs_embeds=decoder_inputs_embeds,
|
| 1600 |
+
**kwargs,
|
| 1601 |
+
)
|
| 1602 |
+
|
| 1603 |
+
sequence_output = outputs[0]
|
| 1604 |
+
|
| 1605 |
+
# class logits + predicted bounding boxes
|
| 1606 |
+
logits = self.class_labels_classifier(sequence_output)
|
| 1607 |
+
|
| 1608 |
+
reference = outputs.reference_points
|
| 1609 |
+
reference_before_sigmoid = inverse_sigmoid(reference).transpose(0, 1)
|
| 1610 |
+
|
| 1611 |
+
hs = sequence_output
|
| 1612 |
+
tmp = self.bbox_predictor(hs)
|
| 1613 |
+
tmp[..., :2] += reference_before_sigmoid
|
| 1614 |
+
pred_boxes = tmp.sigmoid()
|
| 1615 |
+
# pred_boxes = self.bbox_predictor(sequence_output).sigmoid()
|
| 1616 |
+
|
| 1617 |
+
loss, loss_dict, auxiliary_outputs = None, None, None
|
| 1618 |
+
if labels is not None:
|
| 1619 |
+
outputs_class, outputs_coord = None, None
|
| 1620 |
+
if self.config.auxiliary_loss:
|
| 1621 |
+
outputs_coords = []
|
| 1622 |
+
intermediate = outputs.intermediate_hidden_states
|
| 1623 |
+
outputs_class = self.class_labels_classifier(intermediate)
|
| 1624 |
+
for lvl in range(intermediate.shape[0]):
|
| 1625 |
+
tmp = self.bbox_predictor(intermediate[lvl])
|
| 1626 |
+
tmp[..., :2] += reference_before_sigmoid
|
| 1627 |
+
outputs_coord = tmp.sigmoid()
|
| 1628 |
+
outputs_coords.append(outputs_coord)
|
| 1629 |
+
outputs_coord = torch.stack(outputs_coords)
|
| 1630 |
+
loss, loss_dict, auxiliary_outputs = self.loss_function(
|
| 1631 |
+
logits, labels, self.device, pred_boxes, self.config, outputs_class, outputs_coord
|
| 1632 |
+
)
|
| 1633 |
+
|
| 1634 |
+
return ConditionalDetrObjectDetectionOutput(
|
| 1635 |
+
loss=loss,
|
| 1636 |
+
loss_dict=loss_dict,
|
| 1637 |
+
logits=logits,
|
| 1638 |
+
pred_boxes=pred_boxes,
|
| 1639 |
+
auxiliary_outputs=auxiliary_outputs,
|
| 1640 |
+
last_hidden_state=outputs.last_hidden_state,
|
| 1641 |
+
decoder_hidden_states=outputs.decoder_hidden_states,
|
| 1642 |
+
decoder_attentions=outputs.decoder_attentions,
|
| 1643 |
+
cross_attentions=outputs.cross_attentions,
|
| 1644 |
+
encoder_last_hidden_state=outputs.encoder_last_hidden_state,
|
| 1645 |
+
encoder_hidden_states=outputs.encoder_hidden_states,
|
| 1646 |
+
encoder_attentions=outputs.encoder_attentions,
|
| 1647 |
+
)
|
| 1648 |
+
|
| 1649 |
+
# taken from https://github.com/Atten4Vis/conditionalDETR/blob/master/models/conditional_detr.py
|
| 1650 |
+
def _set_aux_loss(self, outputs_class, outputs_coord):
|
| 1651 |
+
return [{"logits": a, "pred_boxes": b} for a, b in zip(outputs_class[:-1], outputs_coord[:-1])]
|
| 1652 |
+
|
| 1653 |
+
|
| 1654 |
+
@auto_docstring(
|
| 1655 |
+
custom_intro="""
|
| 1656 |
+
CONDITIONAL_DETR Model (consisting of a backbone and encoder-decoder Transformer) with a segmentation head on top, for tasks
|
| 1657 |
+
such as COCO panoptic.
|
| 1658 |
+
"""
|
| 1659 |
+
)
|
| 1660 |
+
class ConditionalDetrForSegmentation(ConditionalDetrPreTrainedModel):
|
| 1661 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 1662 |
+
super().__init__(config)
|
| 1663 |
+
|
| 1664 |
+
# object detection model
|
| 1665 |
+
self.conditional_detr = ConditionalDetrForObjectDetection(config)
|
| 1666 |
+
|
| 1667 |
+
# segmentation head
|
| 1668 |
+
hidden_size, number_of_heads = config.d_model, config.encoder_attention_heads
|
| 1669 |
+
intermediate_channel_sizes = self.conditional_detr.model.backbone.intermediate_channel_sizes
|
| 1670 |
+
|
| 1671 |
+
self.mask_head = ConditionalDetrMaskHeadSmallConv(
|
| 1672 |
+
input_channels=hidden_size + number_of_heads,
|
| 1673 |
+
fpn_channels=intermediate_channel_sizes[::-1][-3:],
|
| 1674 |
+
hidden_size=hidden_size,
|
| 1675 |
+
activation_function=config.activation_function,
|
| 1676 |
+
)
|
| 1677 |
+
|
| 1678 |
+
self.bbox_attention = ConditionalDetrMHAttentionMap(hidden_size, number_of_heads, dropout=0.0)
|
| 1679 |
+
# Initialize weights and apply final processing
|
| 1680 |
+
self.post_init()
|
| 1681 |
+
|
| 1682 |
+
@auto_docstring
|
| 1683 |
+
@can_return_tuple
|
| 1684 |
+
def forward(
|
| 1685 |
+
self,
|
| 1686 |
+
pixel_values: torch.FloatTensor,
|
| 1687 |
+
pixel_mask: torch.LongTensor | None = None,
|
| 1688 |
+
decoder_attention_mask: torch.FloatTensor | None = None,
|
| 1689 |
+
encoder_outputs: torch.FloatTensor | None = None,
|
| 1690 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 1691 |
+
decoder_inputs_embeds: torch.FloatTensor | None = None,
|
| 1692 |
+
labels: list[dict] | None = None,
|
| 1693 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 1694 |
+
) -> tuple[torch.FloatTensor] | ConditionalDetrSegmentationOutput:
|
| 1695 |
+
r"""
|
| 1696 |
+
decoder_attention_mask (`torch.FloatTensor` of shape `(batch_size, num_queries)`, *optional*):
|
| 1697 |
+
Mask to avoid performing attention on certain object queries in the decoder. Mask values selected in `[0, 1]`:
|
| 1698 |
+
|
| 1699 |
+
- 1 for queries that are **not masked**,
|
| 1700 |
+
- 0 for queries that are **masked**.
|
| 1701 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 1702 |
+
Kept for backward compatibility, but cannot be used for segmentation, as segmentation requires
|
| 1703 |
+
multi-scale features from the backbone that are not available when bypassing it with inputs_embeds.
|
| 1704 |
+
decoder_inputs_embeds (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 1705 |
+
Optionally, instead of initializing the queries with a tensor of zeros, you can choose to directly pass an
|
| 1706 |
+
embedded representation. Useful for tasks that require custom query initialization.
|
| 1707 |
+
labels (`list[Dict]` of len `(batch_size,)`, *optional*):
|
| 1708 |
+
Labels for computing the bipartite matching loss, DICE/F-1 loss and Focal loss. List of dicts, each
|
| 1709 |
+
dictionary containing at least the following 3 keys: 'class_labels', 'boxes' and 'masks' (the class labels,
|
| 1710 |
+
bounding boxes and segmentation masks of an image in the batch respectively). The class labels themselves
|
| 1711 |
+
should be a `torch.LongTensor` of len `(number of bounding boxes in the image,)`, the boxes a
|
| 1712 |
+
`torch.FloatTensor` of shape `(number of bounding boxes in the image, 4)` and the masks a
|
| 1713 |
+
`torch.FloatTensor` of shape `(number of bounding boxes in the image, height, width)`.
|
| 1714 |
+
|
| 1715 |
+
Examples:
|
| 1716 |
+
|
| 1717 |
+
```python
|
| 1718 |
+
>>> import io
|
| 1719 |
+
>>> import httpx
|
| 1720 |
+
>>> from io import BytesIO
|
| 1721 |
+
>>> from PIL import Image
|
| 1722 |
+
>>> import torch
|
| 1723 |
+
>>> import numpy
|
| 1724 |
+
|
| 1725 |
+
>>> from transformers import AutoImageProcessor, ConditionalDetrForSegmentation
|
| 1726 |
+
>>> from transformers.image_transforms import rgb_to_id
|
| 1727 |
+
|
| 1728 |
+
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
| 1729 |
+
>>> with httpx.stream("GET", url) as response:
|
| 1730 |
+
... image = Image.open(BytesIO(response.read()))
|
| 1731 |
+
|
| 1732 |
+
>>> image_processor = AutoImageProcessor.from_pretrained("facebook/conditional_detr-resnet-50-panoptic")
|
| 1733 |
+
>>> model = ConditionalDetrForSegmentation.from_pretrained("facebook/conditional_detr-resnet-50-panoptic")
|
| 1734 |
+
|
| 1735 |
+
>>> # prepare image for the model
|
| 1736 |
+
>>> inputs = image_processor(images=image, return_tensors="pt")
|
| 1737 |
+
|
| 1738 |
+
>>> # forward pass
|
| 1739 |
+
>>> outputs = model(**inputs)
|
| 1740 |
+
|
| 1741 |
+
>>> # Use the `post_process_panoptic_segmentation` method of the `image_processor` to retrieve post-processed panoptic segmentation maps
|
| 1742 |
+
>>> # Segmentation results are returned as a list of dictionaries
|
| 1743 |
+
>>> result = image_processor.post_process_panoptic_segmentation(outputs, target_sizes=[(300, 500)])
|
| 1744 |
+
|
| 1745 |
+
>>> # A tensor of shape (height, width) where each value denotes a segment id, filled with -1 if no segment is found
|
| 1746 |
+
>>> panoptic_seg = result[0]["segmentation"]
|
| 1747 |
+
>>> panoptic_seg.shape
|
| 1748 |
+
torch.Size([300, 500])
|
| 1749 |
+
>>> # Get prediction score and segment_id to class_id mapping of each segment
|
| 1750 |
+
>>> panoptic_segments_info = result[0]["segments_info"]
|
| 1751 |
+
>>> len(panoptic_segments_info)
|
| 1752 |
+
5
|
| 1753 |
+
```"""
|
| 1754 |
+
|
| 1755 |
+
batch_size, num_channels, height, width = pixel_values.shape
|
| 1756 |
+
device = pixel_values.device
|
| 1757 |
+
|
| 1758 |
+
if pixel_mask is None:
|
| 1759 |
+
pixel_mask = torch.ones((batch_size, height, width), device=device)
|
| 1760 |
+
|
| 1761 |
+
vision_features = self.conditional_detr.model.backbone(pixel_values, pixel_mask)
|
| 1762 |
+
feature_map, mask = vision_features[-1]
|
| 1763 |
+
|
| 1764 |
+
# Apply 1x1 conv to map (batch_size, C, H, W) -> (batch_size, hidden_size, H, W), then flatten to (batch_size, HW, hidden_size)
|
| 1765 |
+
projected_feature_map = self.conditional_detr.model.input_projection(feature_map)
|
| 1766 |
+
flattened_features = projected_feature_map.flatten(2).transpose(1, 2)
|
| 1767 |
+
spatial_position_embeddings = (
|
| 1768 |
+
self.conditional_detr.model.position_embedding(
|
| 1769 |
+
shape=feature_map.shape, device=device, dtype=pixel_values.dtype, mask=mask
|
| 1770 |
+
)
|
| 1771 |
+
.flatten(2)
|
| 1772 |
+
.transpose(1, 2)
|
| 1773 |
+
)
|
| 1774 |
+
flattened_mask = mask.flatten(1)
|
| 1775 |
+
|
| 1776 |
+
if encoder_outputs is None:
|
| 1777 |
+
encoder_outputs = self.conditional_detr.model.encoder(
|
| 1778 |
+
inputs_embeds=flattened_features,
|
| 1779 |
+
attention_mask=flattened_mask,
|
| 1780 |
+
spatial_position_embeddings=spatial_position_embeddings,
|
| 1781 |
+
**kwargs,
|
| 1782 |
+
)
|
| 1783 |
+
|
| 1784 |
+
object_queries_position_embeddings = self.conditional_detr.model.query_position_embeddings.weight.unsqueeze(
|
| 1785 |
+
0
|
| 1786 |
+
).repeat(batch_size, 1, 1)
|
| 1787 |
+
|
| 1788 |
+
# Use decoder_inputs_embeds as queries if provided, otherwise initialize with zeros
|
| 1789 |
+
if decoder_inputs_embeds is not None:
|
| 1790 |
+
queries = decoder_inputs_embeds
|
| 1791 |
+
else:
|
| 1792 |
+
queries = torch.zeros_like(object_queries_position_embeddings)
|
| 1793 |
+
|
| 1794 |
+
decoder_outputs = self.conditional_detr.model.decoder(
|
| 1795 |
+
inputs_embeds=queries,
|
| 1796 |
+
attention_mask=decoder_attention_mask,
|
| 1797 |
+
spatial_position_embeddings=spatial_position_embeddings,
|
| 1798 |
+
object_queries_position_embeddings=object_queries_position_embeddings,
|
| 1799 |
+
encoder_hidden_states=encoder_outputs.last_hidden_state,
|
| 1800 |
+
encoder_attention_mask=flattened_mask,
|
| 1801 |
+
**kwargs,
|
| 1802 |
+
)
|
| 1803 |
+
|
| 1804 |
+
sequence_output = decoder_outputs[0]
|
| 1805 |
+
|
| 1806 |
+
logits = self.conditional_detr.class_labels_classifier(sequence_output)
|
| 1807 |
+
pred_boxes = self.conditional_detr.bbox_predictor(sequence_output).sigmoid()
|
| 1808 |
+
|
| 1809 |
+
height, width = feature_map.shape[-2:]
|
| 1810 |
+
memory = encoder_outputs.last_hidden_state.transpose(1, 2).view(batch_size, self.config.d_model, height, width)
|
| 1811 |
+
attention_mask = flattened_mask.view(batch_size, height, width)
|
| 1812 |
+
|
| 1813 |
+
if attention_mask is not None:
|
| 1814 |
+
min_dtype = torch.finfo(memory.dtype).min
|
| 1815 |
+
attention_mask = torch.where(
|
| 1816 |
+
attention_mask.unsqueeze(1).unsqueeze(1),
|
| 1817 |
+
torch.tensor(0.0, device=memory.device, dtype=memory.dtype),
|
| 1818 |
+
min_dtype,
|
| 1819 |
+
)
|
| 1820 |
+
|
| 1821 |
+
bbox_mask = self.bbox_attention(sequence_output, memory, attention_mask=attention_mask)
|
| 1822 |
+
|
| 1823 |
+
seg_masks = self.mask_head(
|
| 1824 |
+
features=projected_feature_map,
|
| 1825 |
+
attention_masks=bbox_mask,
|
| 1826 |
+
fpn_features=[vision_features[2][0], vision_features[1][0], vision_features[0][0]],
|
| 1827 |
+
)
|
| 1828 |
+
|
| 1829 |
+
pred_masks = seg_masks.view(
|
| 1830 |
+
batch_size, self.conditional_detr.config.num_queries, seg_masks.shape[-2], seg_masks.shape[-1]
|
| 1831 |
+
)
|
| 1832 |
+
|
| 1833 |
+
loss, loss_dict, auxiliary_outputs = None, None, None
|
| 1834 |
+
if labels is not None:
|
| 1835 |
+
outputs_class, outputs_coord = None, None
|
| 1836 |
+
if self.config.auxiliary_loss:
|
| 1837 |
+
intermediate = decoder_outputs.intermediate_hidden_states
|
| 1838 |
+
outputs_class = self.conditional_detr.class_labels_classifier(intermediate)
|
| 1839 |
+
outputs_coord = self.conditional_detr.bbox_predictor(intermediate).sigmoid()
|
| 1840 |
+
loss, loss_dict, auxiliary_outputs = self.loss_function(
|
| 1841 |
+
logits, labels, device, pred_boxes, pred_masks, self.config, outputs_class, outputs_coord
|
| 1842 |
+
)
|
| 1843 |
+
|
| 1844 |
+
return ConditionalDetrSegmentationOutput(
|
| 1845 |
+
loss=loss,
|
| 1846 |
+
loss_dict=loss_dict,
|
| 1847 |
+
logits=logits,
|
| 1848 |
+
pred_boxes=pred_boxes,
|
| 1849 |
+
pred_masks=pred_masks,
|
| 1850 |
+
auxiliary_outputs=auxiliary_outputs,
|
| 1851 |
+
last_hidden_state=decoder_outputs.last_hidden_state,
|
| 1852 |
+
decoder_hidden_states=decoder_outputs.hidden_states,
|
| 1853 |
+
decoder_attentions=decoder_outputs.attentions,
|
| 1854 |
+
cross_attentions=decoder_outputs.cross_attentions,
|
| 1855 |
+
encoder_last_hidden_state=encoder_outputs.last_hidden_state,
|
| 1856 |
+
encoder_hidden_states=encoder_outputs.hidden_states,
|
| 1857 |
+
encoder_attentions=encoder_outputs.attentions,
|
| 1858 |
+
)
|
| 1859 |
+
|
| 1860 |
+
|
| 1861 |
+
__all__ = [
|
| 1862 |
+
"ConditionalDetrForObjectDetection",
|
| 1863 |
+
"ConditionalDetrForSegmentation",
|
| 1864 |
+
"ConditionalDetrModel",
|
| 1865 |
+
"ConditionalDetrPreTrainedModel",
|
| 1866 |
+
]
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/conditional_detr/modular_conditional_detr.py
ADDED
|
@@ -0,0 +1,1122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 Microsoft Research Asia and 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 |
+
import math
|
| 15 |
+
from collections.abc import Callable
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
from torch import nn
|
| 19 |
+
|
| 20 |
+
from ...image_transforms import (
|
| 21 |
+
center_to_corners_format,
|
| 22 |
+
)
|
| 23 |
+
from ...masking_utils import create_bidirectional_mask
|
| 24 |
+
from ...modeling_outputs import (
|
| 25 |
+
BaseModelOutput,
|
| 26 |
+
)
|
| 27 |
+
from ...modeling_utils import ALL_ATTENTION_FUNCTIONS
|
| 28 |
+
from ...processing_utils import Unpack
|
| 29 |
+
from ...utils import (
|
| 30 |
+
TensorType,
|
| 31 |
+
TransformersKwargs,
|
| 32 |
+
auto_docstring,
|
| 33 |
+
logging,
|
| 34 |
+
requires_backends,
|
| 35 |
+
)
|
| 36 |
+
from ...utils.generic import can_return_tuple, merge_with_config_defaults
|
| 37 |
+
from ...utils.import_utils import requires
|
| 38 |
+
from ...utils.output_capturing import OutputRecorder, capture_outputs
|
| 39 |
+
from ..deformable_detr.modeling_deformable_detr import inverse_sigmoid
|
| 40 |
+
from ..detr.image_processing_detr import DetrImageProcessor
|
| 41 |
+
from ..detr.image_processing_pil_detr import DetrImageProcessorPil
|
| 42 |
+
from ..detr.modeling_detr import (
|
| 43 |
+
DetrConvEncoder,
|
| 44 |
+
DetrDecoderLayer,
|
| 45 |
+
DetrDecoderOutput,
|
| 46 |
+
DetrEncoder,
|
| 47 |
+
DetrEncoderLayer,
|
| 48 |
+
DetrForObjectDetection,
|
| 49 |
+
DetrForSegmentation,
|
| 50 |
+
DetrLearnedPositionEmbedding,
|
| 51 |
+
DetrMLP,
|
| 52 |
+
DetrMLPPredictionHead,
|
| 53 |
+
DetrModel,
|
| 54 |
+
DetrModelOutput,
|
| 55 |
+
DetrObjectDetectionOutput,
|
| 56 |
+
DetrPreTrainedModel,
|
| 57 |
+
DetrSegmentationOutput,
|
| 58 |
+
DetrSelfAttention,
|
| 59 |
+
DetrSinePositionEmbedding,
|
| 60 |
+
eager_attention_forward,
|
| 61 |
+
)
|
| 62 |
+
from .configuration_conditional_detr import ConditionalDetrConfig
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
logger = logging.get_logger(__name__)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def encode_sinusoidal_position_embedding(
|
| 69 |
+
pos_tensor: torch.Tensor,
|
| 70 |
+
num_pos_feats: int = 128,
|
| 71 |
+
temperature: int = 10000,
|
| 72 |
+
) -> torch.Tensor:
|
| 73 |
+
"""Sinusoidal position embeddings from normalized anchor coordinates.
|
| 74 |
+
|
| 75 |
+
Each coordinate in `pos_tensor` is independently encoded with ``num_pos_feats``
|
| 76 |
+
interleaved sin/cos components; per-coordinate embeddings are concatenated.
|
| 77 |
+
Handles 2-D ``(x, y)`` and N-D ``(x, y, w, h)`` inputs. For 2-D+ inputs the
|
| 78 |
+
x and y embeddings are swapped to follow the DETR ``[pos_y, pos_x, ...]`` convention.
|
| 79 |
+
|
| 80 |
+
Args:
|
| 81 |
+
pos_tensor: Normalized coordinates in ``[0, 1]``, shape ``(..., n_coords)``.
|
| 82 |
+
num_pos_feats: Embedding dimension per coordinate.
|
| 83 |
+
temperature: Base for the frequency decay.
|
| 84 |
+
|
| 85 |
+
Returns:
|
| 86 |
+
Tensor of shape ``(..., n_coords * num_pos_feats)``, same dtype as input.
|
| 87 |
+
"""
|
| 88 |
+
scale = 2 * math.pi
|
| 89 |
+
dim_t = torch.arange(num_pos_feats, dtype=torch.float32, device=pos_tensor.device)
|
| 90 |
+
dim_t = temperature ** (2 * torch.div(dim_t, 2, rounding_mode="floor") / num_pos_feats)
|
| 91 |
+
|
| 92 |
+
coords = pos_tensor.unbind(-1) # list of (...,) tensors
|
| 93 |
+
embeddings = [coord[..., None] * scale / dim_t for coord in coords] # each (..., num_pos_feats)
|
| 94 |
+
embeddings = [
|
| 95 |
+
torch.stack((e[..., 0::2].sin(), e[..., 1::2].cos()), dim=-1).flatten(-2) for e in embeddings
|
| 96 |
+
] # each (..., num_pos_feats)
|
| 97 |
+
|
| 98 |
+
if len(embeddings) >= 2:
|
| 99 |
+
embeddings[0], embeddings[1] = embeddings[1], embeddings[0]
|
| 100 |
+
|
| 101 |
+
return torch.cat(embeddings, dim=-1).to(pos_tensor.dtype)
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
class ConditionalDetrImageProcessor(DetrImageProcessor):
|
| 105 |
+
def post_process_object_detection(
|
| 106 |
+
self, outputs, threshold: float = 0.5, target_sizes: TensorType | list[tuple] = None, top_k: int = 100
|
| 107 |
+
):
|
| 108 |
+
"""
|
| 109 |
+
Converts the raw output of [`ConditionalDetrForObjectDetection`] into final bounding boxes in (top_left_x,
|
| 110 |
+
top_left_y, bottom_right_x, bottom_right_y) format. Only supports PyTorch.
|
| 111 |
+
|
| 112 |
+
Args:
|
| 113 |
+
outputs ([`ConditionalDetrObjectDetectionOutput`]):
|
| 114 |
+
Raw outputs of the model.
|
| 115 |
+
threshold (`float`, *optional*):
|
| 116 |
+
Score threshold to keep object detection predictions.
|
| 117 |
+
target_sizes (`torch.Tensor` or `list[tuple[int, int]]`, *optional*):
|
| 118 |
+
Tensor of shape `(batch_size, 2)` or list of tuples (`tuple[int, int]`) containing the target size
|
| 119 |
+
(height, width) of each image in the batch. If left to None, predictions will not be resized.
|
| 120 |
+
top_k (`int`, *optional*, defaults to 100):
|
| 121 |
+
Keep only top k bounding boxes before filtering by thresholding.
|
| 122 |
+
|
| 123 |
+
Returns:
|
| 124 |
+
`list[Dict]`: A list of dictionaries, each dictionary containing the scores, labels and boxes for an image
|
| 125 |
+
in the batch as predicted by the model.
|
| 126 |
+
"""
|
| 127 |
+
out_logits, out_bbox = outputs.logits, outputs.pred_boxes
|
| 128 |
+
|
| 129 |
+
if target_sizes is not None:
|
| 130 |
+
if len(out_logits) != len(target_sizes):
|
| 131 |
+
raise ValueError(
|
| 132 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 133 |
+
)
|
| 134 |
+
|
| 135 |
+
prob = out_logits.sigmoid()
|
| 136 |
+
prob = prob.view(out_logits.shape[0], -1)
|
| 137 |
+
k_value = min(top_k, prob.size(1))
|
| 138 |
+
topk_values, topk_indexes = torch.topk(prob, k_value, dim=1)
|
| 139 |
+
scores = topk_values
|
| 140 |
+
topk_boxes = torch.div(topk_indexes, out_logits.shape[2], rounding_mode="floor")
|
| 141 |
+
labels = topk_indexes % out_logits.shape[2]
|
| 142 |
+
boxes = center_to_corners_format(out_bbox)
|
| 143 |
+
boxes = torch.gather(boxes, 1, topk_boxes.unsqueeze(-1).repeat(1, 1, 4))
|
| 144 |
+
|
| 145 |
+
# and from relative [0, 1] to absolute [0, height] coordinates
|
| 146 |
+
if target_sizes is not None:
|
| 147 |
+
if isinstance(target_sizes, list):
|
| 148 |
+
img_h = torch.Tensor([i[0] for i in target_sizes])
|
| 149 |
+
img_w = torch.Tensor([i[1] for i in target_sizes])
|
| 150 |
+
else:
|
| 151 |
+
img_h, img_w = target_sizes.unbind(1)
|
| 152 |
+
scale_fct = torch.stack([img_w, img_h, img_w, img_h], dim=1).to(boxes.device)
|
| 153 |
+
boxes = boxes * scale_fct[:, None, :]
|
| 154 |
+
|
| 155 |
+
results = []
|
| 156 |
+
for s, l, b in zip(scores, labels, boxes):
|
| 157 |
+
score = s[s > threshold]
|
| 158 |
+
label = l[s > threshold]
|
| 159 |
+
box = b[s > threshold]
|
| 160 |
+
results.append({"scores": score, "labels": label, "boxes": box})
|
| 161 |
+
|
| 162 |
+
return results
|
| 163 |
+
|
| 164 |
+
def post_process_semantic_segmentation(self, outputs, target_sizes: list[tuple[int, int]] | None = None):
|
| 165 |
+
"""
|
| 166 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into semantic segmentation maps. Only supports PyTorch.
|
| 167 |
+
|
| 168 |
+
Args:
|
| 169 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 170 |
+
Raw outputs of the model.
|
| 171 |
+
target_sizes (`list[tuple[int, int]]`, *optional*):
|
| 172 |
+
A list of tuples (`tuple[int, int]`) containing the target size (height, width) of each image in the
|
| 173 |
+
batch. If unset, predictions will not be resized.
|
| 174 |
+
Returns:
|
| 175 |
+
`list[torch.Tensor]`:
|
| 176 |
+
A list of length `batch_size`, where each item is a semantic segmentation map of shape (height, width)
|
| 177 |
+
corresponding to the target_sizes entry (if `target_sizes` is specified). Each entry of each
|
| 178 |
+
`torch.Tensor` correspond to a semantic class id.
|
| 179 |
+
"""
|
| 180 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes]
|
| 181 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 182 |
+
|
| 183 |
+
# Conditional DETR does not have a null class, so we use all classes
|
| 184 |
+
masks_classes = class_queries_logits.softmax(dim=-1)
|
| 185 |
+
masks_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 186 |
+
|
| 187 |
+
# Semantic segmentation logits of shape (batch_size, num_classes, height, width)
|
| 188 |
+
segmentation = torch.einsum("bqc, bqhw -> bchw", masks_classes, masks_probs)
|
| 189 |
+
batch_size = class_queries_logits.shape[0]
|
| 190 |
+
|
| 191 |
+
# Resize logits and compute semantic segmentation maps
|
| 192 |
+
if target_sizes is not None:
|
| 193 |
+
if batch_size != len(target_sizes):
|
| 194 |
+
raise ValueError(
|
| 195 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 196 |
+
)
|
| 197 |
+
|
| 198 |
+
semantic_segmentation = []
|
| 199 |
+
for idx in range(batch_size):
|
| 200 |
+
resized_logits = nn.functional.interpolate(
|
| 201 |
+
segmentation[idx].unsqueeze(dim=0), size=target_sizes[idx], mode="bilinear", align_corners=False
|
| 202 |
+
)
|
| 203 |
+
semantic_map = resized_logits[0].argmax(dim=0)
|
| 204 |
+
semantic_segmentation.append(semantic_map)
|
| 205 |
+
else:
|
| 206 |
+
semantic_segmentation = segmentation.argmax(dim=1)
|
| 207 |
+
semantic_segmentation = [semantic_segmentation[i] for i in range(semantic_segmentation.shape[0])]
|
| 208 |
+
|
| 209 |
+
return semantic_segmentation
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
class ConditionalDetrImageProcessorPil(DetrImageProcessorPil):
|
| 213 |
+
@requires(backends=("torch",))
|
| 214 |
+
def post_process_object_detection(
|
| 215 |
+
self, outputs, threshold: float = 0.5, target_sizes: TensorType | list[tuple] = None, top_k: int = 100
|
| 216 |
+
):
|
| 217 |
+
"""
|
| 218 |
+
Converts the raw output of [`ConditionalDetrForObjectDetection`] into final bounding boxes in (top_left_x,
|
| 219 |
+
top_left_y, bottom_right_x, bottom_right_y) format. Only supports PyTorch.
|
| 220 |
+
|
| 221 |
+
Args:
|
| 222 |
+
outputs ([`ConditionalDetrObjectDetectionOutput`]):
|
| 223 |
+
Raw outputs of the model.
|
| 224 |
+
threshold (`float`, *optional*):
|
| 225 |
+
Score threshold to keep object detection predictions.
|
| 226 |
+
target_sizes (`torch.Tensor` or `list[tuple[int, int]]`, *optional*):
|
| 227 |
+
Tensor of shape `(batch_size, 2)` or list of tuples (`tuple[int, int]`) containing the target size
|
| 228 |
+
(height, width) of each image in the batch. If left to None, predictions will not be resized.
|
| 229 |
+
top_k (`int`, *optional*, defaults to 100):
|
| 230 |
+
Keep only top k bounding boxes before filtering by thresholding.
|
| 231 |
+
|
| 232 |
+
Returns:
|
| 233 |
+
`list[Dict]`: A list of dictionaries, each dictionary containing the scores, labels and boxes for an image
|
| 234 |
+
in the batch as predicted by the model.
|
| 235 |
+
"""
|
| 236 |
+
requires_backends(self, ["torch"])
|
| 237 |
+
out_logits, out_bbox = outputs.logits, outputs.pred_boxes
|
| 238 |
+
|
| 239 |
+
if target_sizes is not None:
|
| 240 |
+
if len(out_logits) != len(target_sizes):
|
| 241 |
+
raise ValueError(
|
| 242 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 243 |
+
)
|
| 244 |
+
|
| 245 |
+
prob = out_logits.sigmoid()
|
| 246 |
+
prob = prob.view(out_logits.shape[0], -1)
|
| 247 |
+
k_value = min(top_k, prob.size(1))
|
| 248 |
+
topk_values, topk_indexes = torch.topk(prob, k_value, dim=1)
|
| 249 |
+
scores = topk_values
|
| 250 |
+
topk_boxes = torch.div(topk_indexes, out_logits.shape[2], rounding_mode="floor")
|
| 251 |
+
labels = topk_indexes % out_logits.shape[2]
|
| 252 |
+
boxes = center_to_corners_format(out_bbox)
|
| 253 |
+
boxes = torch.gather(boxes, 1, topk_boxes.unsqueeze(-1).repeat(1, 1, 4))
|
| 254 |
+
|
| 255 |
+
# and from relative [0, 1] to absolute [0, height] coordinates
|
| 256 |
+
if target_sizes is not None:
|
| 257 |
+
if isinstance(target_sizes, list):
|
| 258 |
+
img_h = torch.Tensor([i[0] for i in target_sizes])
|
| 259 |
+
img_w = torch.Tensor([i[1] for i in target_sizes])
|
| 260 |
+
else:
|
| 261 |
+
img_h, img_w = target_sizes.unbind(1)
|
| 262 |
+
scale_fct = torch.stack([img_w, img_h, img_w, img_h], dim=1).to(boxes.device)
|
| 263 |
+
boxes = boxes * scale_fct[:, None, :]
|
| 264 |
+
|
| 265 |
+
results = []
|
| 266 |
+
for s, l, b in zip(scores, labels, boxes):
|
| 267 |
+
score = s[s > threshold]
|
| 268 |
+
label = l[s > threshold]
|
| 269 |
+
box = b[s > threshold]
|
| 270 |
+
results.append({"scores": score, "labels": label, "boxes": box})
|
| 271 |
+
|
| 272 |
+
return results
|
| 273 |
+
|
| 274 |
+
@requires(backends=("torch",))
|
| 275 |
+
def post_process_semantic_segmentation(self, outputs, target_sizes: list[tuple[int, int]] | None = None):
|
| 276 |
+
"""
|
| 277 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into semantic segmentation maps. Only supports PyTorch.
|
| 278 |
+
|
| 279 |
+
Args:
|
| 280 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 281 |
+
Raw outputs of the model.
|
| 282 |
+
target_sizes (`list[tuple[int, int]]`, *optional*):
|
| 283 |
+
A list of tuples (`tuple[int, int]`) containing the target size (height, width) of each image in the
|
| 284 |
+
batch. If unset, predictions will not be resized.
|
| 285 |
+
Returns:
|
| 286 |
+
`list[torch.Tensor]`:
|
| 287 |
+
A list of length `batch_size`, where each item is a semantic segmentation map of shape (height, width)
|
| 288 |
+
corresponding to the target_sizes entry (if `target_sizes` is specified). Each entry of each
|
| 289 |
+
`torch.Tensor` correspond to a semantic class id.
|
| 290 |
+
"""
|
| 291 |
+
requires_backends(self, ["torch"])
|
| 292 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes]
|
| 293 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 294 |
+
|
| 295 |
+
# Conditional DETR does not have a null class, so we use all classes
|
| 296 |
+
masks_classes = class_queries_logits.softmax(dim=-1)
|
| 297 |
+
masks_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 298 |
+
|
| 299 |
+
# Semantic segmentation logits of shape (batch_size, num_classes, height, width)
|
| 300 |
+
segmentation = torch.einsum("bqc, bqhw -> bchw", masks_classes, masks_probs)
|
| 301 |
+
batch_size = class_queries_logits.shape[0]
|
| 302 |
+
|
| 303 |
+
# Resize logits and compute semantic segmentation maps
|
| 304 |
+
if target_sizes is not None:
|
| 305 |
+
if batch_size != len(target_sizes):
|
| 306 |
+
raise ValueError(
|
| 307 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 308 |
+
)
|
| 309 |
+
|
| 310 |
+
semantic_segmentation = []
|
| 311 |
+
for idx in range(batch_size):
|
| 312 |
+
resized_logits = nn.functional.interpolate(
|
| 313 |
+
segmentation[idx].unsqueeze(dim=0), size=target_sizes[idx], mode="bilinear", align_corners=False
|
| 314 |
+
)
|
| 315 |
+
semantic_map = resized_logits[0].argmax(dim=0)
|
| 316 |
+
semantic_segmentation.append(semantic_map)
|
| 317 |
+
else:
|
| 318 |
+
semantic_segmentation = segmentation.argmax(dim=1)
|
| 319 |
+
semantic_segmentation = [semantic_segmentation[i] for i in range(semantic_segmentation.shape[0])]
|
| 320 |
+
|
| 321 |
+
return semantic_segmentation
|
| 322 |
+
|
| 323 |
+
|
| 324 |
+
class ConditionalDetrDecoderOutput(DetrDecoderOutput):
|
| 325 |
+
r"""
|
| 326 |
+
cross_attentions (`tuple(torch.FloatTensor)`, *optional*, returned when `output_attentions=True` and `config.add_cross_attention=True` is passed or when `config.output_attentions=True`):
|
| 327 |
+
Tuple of `torch.FloatTensor` (one for each layer) of shape `(batch_size, num_heads, sequence_length,
|
| 328 |
+
sequence_length)`. Attentions weights of the decoder's cross-attention layer, after the attention softmax,
|
| 329 |
+
used to compute the weighted average in the cross-attention heads.
|
| 330 |
+
intermediate_hidden_states (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, num_queries, hidden_size)`, *optional*, returned when `config.auxiliary_loss=True`):
|
| 331 |
+
Intermediate decoder activations, i.e. the output of each decoder layer, each of them gone through a
|
| 332 |
+
layernorm.
|
| 333 |
+
reference_points (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, num_queries, 2 (anchor points))`):
|
| 334 |
+
Reference points (reference points of each layer of the decoder).
|
| 335 |
+
"""
|
| 336 |
+
|
| 337 |
+
reference_points: tuple[torch.FloatTensor] | None = None
|
| 338 |
+
|
| 339 |
+
|
| 340 |
+
class ConditionalDetrModelOutput(DetrModelOutput):
|
| 341 |
+
r"""
|
| 342 |
+
last_hidden_state (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 343 |
+
Sequence of hidden-states at the output of the last layer of the decoder of the model.
|
| 344 |
+
intermediate_hidden_states (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, sequence_length, hidden_size)`, *optional*, returned when `config.auxiliary_loss=True`):
|
| 345 |
+
Intermediate decoder activations, i.e. the output of each decoder layer, each of them gone through a
|
| 346 |
+
layernorm.
|
| 347 |
+
reference_points (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, num_queries, 2 (anchor points))`):
|
| 348 |
+
Reference points (reference points of each layer of the decoder).
|
| 349 |
+
"""
|
| 350 |
+
|
| 351 |
+
reference_points: tuple[torch.FloatTensor] | None = None
|
| 352 |
+
|
| 353 |
+
|
| 354 |
+
class ConditionalDetrObjectDetectionOutput(DetrObjectDetectionOutput):
|
| 355 |
+
pass
|
| 356 |
+
|
| 357 |
+
|
| 358 |
+
class ConditionalDetrSegmentationOutput(DetrSegmentationOutput):
|
| 359 |
+
pass
|
| 360 |
+
|
| 361 |
+
|
| 362 |
+
class ConditionalDetrConvEncoder(DetrConvEncoder):
|
| 363 |
+
pass
|
| 364 |
+
|
| 365 |
+
|
| 366 |
+
class ConditionalDetrSinePositionEmbedding(DetrSinePositionEmbedding):
|
| 367 |
+
pass
|
| 368 |
+
|
| 369 |
+
|
| 370 |
+
class ConditionalDetrLearnedPositionEmbedding(DetrLearnedPositionEmbedding):
|
| 371 |
+
pass
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
class ConditionalDetrSelfAttention(DetrSelfAttention):
|
| 375 |
+
pass
|
| 376 |
+
|
| 377 |
+
|
| 378 |
+
class ConditionalDetrDecoderSelfAttention(nn.Module):
|
| 379 |
+
"""
|
| 380 |
+
Multi-headed self-attention for Conditional DETR decoder layers.
|
| 381 |
+
|
| 382 |
+
This attention module handles separate content and position projections, which are then combined
|
| 383 |
+
before applying standard self-attention. Position embeddings are added to both queries and keys.
|
| 384 |
+
"""
|
| 385 |
+
|
| 386 |
+
def __init__(
|
| 387 |
+
self,
|
| 388 |
+
config: ConditionalDetrConfig,
|
| 389 |
+
hidden_size: int,
|
| 390 |
+
num_attention_heads: int,
|
| 391 |
+
dropout: float | int = 0.0,
|
| 392 |
+
):
|
| 393 |
+
super().__init__()
|
| 394 |
+
self.config = config
|
| 395 |
+
self.hidden_size = hidden_size
|
| 396 |
+
self.head_dim = hidden_size // num_attention_heads
|
| 397 |
+
self.scaling = self.head_dim**-0.5
|
| 398 |
+
self.attention_dropout = dropout
|
| 399 |
+
self.is_causal = False
|
| 400 |
+
|
| 401 |
+
# Content and position projections
|
| 402 |
+
self.q_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 403 |
+
self.q_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 404 |
+
self.k_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 405 |
+
self.k_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 406 |
+
self.v_proj = nn.Linear(hidden_size, hidden_size)
|
| 407 |
+
self.o_proj = nn.Linear(hidden_size, hidden_size)
|
| 408 |
+
|
| 409 |
+
def forward(
|
| 410 |
+
self,
|
| 411 |
+
hidden_states: torch.Tensor,
|
| 412 |
+
query_position_embeddings: torch.Tensor,
|
| 413 |
+
attention_mask: torch.Tensor | None = None,
|
| 414 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 415 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 416 |
+
"""
|
| 417 |
+
Args:
|
| 418 |
+
hidden_states (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 419 |
+
Input hidden states from the decoder layer.
|
| 420 |
+
query_position_embeddings (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 421 |
+
Position embeddings for queries and keys. Required (unlike standard attention). Processed through
|
| 422 |
+
separate position projections (`q_pos_proj`, `k_pos_proj`) and added to content projections.
|
| 423 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, 1, num_queries, num_queries)`, *optional*):
|
| 424 |
+
Attention mask to avoid attending to padding tokens.
|
| 425 |
+
"""
|
| 426 |
+
input_shape = hidden_states.shape[:-1]
|
| 427 |
+
hidden_shape = (*input_shape, -1, self.head_dim)
|
| 428 |
+
|
| 429 |
+
query_states = (
|
| 430 |
+
(self.q_content_proj(hidden_states) + self.q_pos_proj(query_position_embeddings))
|
| 431 |
+
.view(hidden_shape)
|
| 432 |
+
.transpose(1, 2)
|
| 433 |
+
)
|
| 434 |
+
key_states = (
|
| 435 |
+
(self.k_content_proj(hidden_states) + self.k_pos_proj(query_position_embeddings))
|
| 436 |
+
.view(hidden_shape)
|
| 437 |
+
.transpose(1, 2)
|
| 438 |
+
)
|
| 439 |
+
value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 440 |
+
|
| 441 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 442 |
+
self.config._attn_implementation, eager_attention_forward
|
| 443 |
+
)
|
| 444 |
+
|
| 445 |
+
attn_output, attn_weights = attention_interface(
|
| 446 |
+
self,
|
| 447 |
+
query_states,
|
| 448 |
+
key_states,
|
| 449 |
+
value_states,
|
| 450 |
+
attention_mask,
|
| 451 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 452 |
+
scaling=self.scaling,
|
| 453 |
+
**kwargs,
|
| 454 |
+
)
|
| 455 |
+
|
| 456 |
+
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
| 457 |
+
attn_output = self.o_proj(attn_output)
|
| 458 |
+
return attn_output, attn_weights
|
| 459 |
+
|
| 460 |
+
|
| 461 |
+
class ConditionalDetrDecoderCrossAttention(nn.Module):
|
| 462 |
+
"""
|
| 463 |
+
Multi-headed cross-attention for Conditional DETR decoder layers.
|
| 464 |
+
|
| 465 |
+
This attention module handles the special cross-attention logic in Conditional DETR:
|
| 466 |
+
- Separate content and position projections for queries and keys
|
| 467 |
+
- Concatenation of query sine embeddings with queries (doubling query dimension)
|
| 468 |
+
- Concatenation of key position embeddings with keys (doubling key dimension)
|
| 469 |
+
- Output dimension remains hidden_size despite doubled input dimensions
|
| 470 |
+
"""
|
| 471 |
+
|
| 472 |
+
def __init__(
|
| 473 |
+
self,
|
| 474 |
+
config: ConditionalDetrConfig,
|
| 475 |
+
hidden_size: int,
|
| 476 |
+
num_attention_heads: int,
|
| 477 |
+
dropout: float | int = 0.0,
|
| 478 |
+
):
|
| 479 |
+
super().__init__()
|
| 480 |
+
self.config = config
|
| 481 |
+
self.hidden_size = hidden_size
|
| 482 |
+
self.num_attention_heads = num_attention_heads
|
| 483 |
+
self.head_dim = hidden_size // num_attention_heads
|
| 484 |
+
self.attention_dropout = dropout
|
| 485 |
+
self.is_causal = False
|
| 486 |
+
|
| 487 |
+
# Content and position projections
|
| 488 |
+
self.q_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 489 |
+
self.q_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 490 |
+
self.k_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 491 |
+
self.k_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 492 |
+
self.v_proj = nn.Linear(hidden_size, hidden_size)
|
| 493 |
+
self.q_pos_sine_proj = nn.Linear(hidden_size, hidden_size)
|
| 494 |
+
|
| 495 |
+
# Output projection: input is hidden_size * 2 (from concatenated q/k), output is hidden_size
|
| 496 |
+
self.o_proj = nn.Linear(hidden_size, hidden_size)
|
| 497 |
+
|
| 498 |
+
# Compute scaling for expanded head_dim (q and k have doubled dimensions after concatenation)
|
| 499 |
+
# This matches the original Conditional DETR implementation where embed_dim * 2 is used
|
| 500 |
+
expanded_head_dim = (hidden_size * 2) // num_attention_heads
|
| 501 |
+
self.scaling = expanded_head_dim**-0.5
|
| 502 |
+
|
| 503 |
+
def forward(
|
| 504 |
+
self,
|
| 505 |
+
hidden_states: torch.Tensor,
|
| 506 |
+
encoder_hidden_states: torch.Tensor,
|
| 507 |
+
query_sine_embed: torch.Tensor,
|
| 508 |
+
encoder_position_embeddings: torch.Tensor,
|
| 509 |
+
query_position_embeddings: torch.Tensor | None = None,
|
| 510 |
+
attention_mask: torch.Tensor | None = None,
|
| 511 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 512 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 513 |
+
"""
|
| 514 |
+
Args:
|
| 515 |
+
hidden_states (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 516 |
+
Decoder hidden states (queries).
|
| 517 |
+
encoder_hidden_states (`torch.Tensor` of shape `(batch_size, encoder_seq_len, hidden_size)`):
|
| 518 |
+
Encoder output hidden states (keys and values).
|
| 519 |
+
query_sine_embed (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 520 |
+
Sine position embeddings for queries. **Concatenated** (not added) with query content,
|
| 521 |
+
doubling the query dimension.
|
| 522 |
+
encoder_position_embeddings (`torch.Tensor` of shape `(batch_size, encoder_seq_len, hidden_size)`):
|
| 523 |
+
Position embeddings for keys. **Concatenated** (not added) with key content, doubling the key dimension.
|
| 524 |
+
query_position_embeddings (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 525 |
+
Additional position embeddings. When provided (first layer only), **added** to query content
|
| 526 |
+
before concatenation with `query_sine_embed`. Also causes `encoder_position_embeddings` to be
|
| 527 |
+
added to key content before concatenation.
|
| 528 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, 1, num_queries, encoder_seq_len)`, *optional*):
|
| 529 |
+
Attention mask to avoid attending to padding tokens.
|
| 530 |
+
"""
|
| 531 |
+
query_input_shape = hidden_states.shape[:-1]
|
| 532 |
+
kv_input_shape = encoder_hidden_states.shape[:-1]
|
| 533 |
+
query_hidden_shape = (*query_input_shape, self.num_attention_heads, self.head_dim)
|
| 534 |
+
kv_hidden_shape = (*kv_input_shape, self.num_attention_heads, self.head_dim)
|
| 535 |
+
|
| 536 |
+
# Apply content and position projections
|
| 537 |
+
query_input = self.q_content_proj(hidden_states)
|
| 538 |
+
key_input = self.k_content_proj(encoder_hidden_states)
|
| 539 |
+
value_states = self.v_proj(encoder_hidden_states)
|
| 540 |
+
key_pos = self.k_pos_proj(encoder_position_embeddings)
|
| 541 |
+
|
| 542 |
+
# Combine content and position embeddings
|
| 543 |
+
if query_position_embeddings is not None:
|
| 544 |
+
query_input = query_input + self.q_pos_proj(query_position_embeddings)
|
| 545 |
+
key_input = key_input + key_pos
|
| 546 |
+
|
| 547 |
+
# Reshape and concatenate position embeddings (doubling head_dim)
|
| 548 |
+
query_input = query_input.view(query_hidden_shape)
|
| 549 |
+
key_input = key_input.view(kv_hidden_shape)
|
| 550 |
+
query_sine_embed = self.q_pos_sine_proj(query_sine_embed).view(query_hidden_shape)
|
| 551 |
+
key_pos = key_pos.view(kv_hidden_shape)
|
| 552 |
+
|
| 553 |
+
query_states = torch.cat([query_input, query_sine_embed], dim=-1).view(*query_input_shape, -1)
|
| 554 |
+
key_states = torch.cat([key_input, key_pos], dim=-1).view(*kv_input_shape, -1)
|
| 555 |
+
|
| 556 |
+
# Reshape for attention computation
|
| 557 |
+
expanded_head_dim = query_states.shape[-1] // self.num_attention_heads
|
| 558 |
+
query_states = query_states.view(*query_input_shape, self.num_attention_heads, expanded_head_dim).transpose(
|
| 559 |
+
1, 2
|
| 560 |
+
)
|
| 561 |
+
key_states = key_states.view(*kv_input_shape, self.num_attention_heads, expanded_head_dim).transpose(1, 2)
|
| 562 |
+
value_states = value_states.view(kv_hidden_shape).transpose(1, 2)
|
| 563 |
+
|
| 564 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 565 |
+
self.config._attn_implementation, eager_attention_forward
|
| 566 |
+
)
|
| 567 |
+
|
| 568 |
+
attn_output, attn_weights = attention_interface(
|
| 569 |
+
self,
|
| 570 |
+
query_states,
|
| 571 |
+
key_states,
|
| 572 |
+
value_states,
|
| 573 |
+
attention_mask,
|
| 574 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 575 |
+
scaling=self.scaling,
|
| 576 |
+
**kwargs,
|
| 577 |
+
)
|
| 578 |
+
|
| 579 |
+
attn_output = attn_output.reshape(*query_input_shape, -1).contiguous()
|
| 580 |
+
attn_output = self.o_proj(attn_output)
|
| 581 |
+
return attn_output, attn_weights
|
| 582 |
+
|
| 583 |
+
|
| 584 |
+
class ConditionalDetrMLP(DetrMLP):
|
| 585 |
+
pass
|
| 586 |
+
|
| 587 |
+
|
| 588 |
+
class ConditionalDetrEncoderLayer(DetrEncoderLayer):
|
| 589 |
+
pass
|
| 590 |
+
|
| 591 |
+
|
| 592 |
+
class ConditionalDetrDecoderLayer(DetrDecoderLayer):
|
| 593 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 594 |
+
super().__init__()
|
| 595 |
+
self.self_attn = ConditionalDetrDecoderSelfAttention(
|
| 596 |
+
config=config,
|
| 597 |
+
hidden_size=self.hidden_size,
|
| 598 |
+
num_attention_heads=config.decoder_attention_heads,
|
| 599 |
+
dropout=config.attention_dropout,
|
| 600 |
+
)
|
| 601 |
+
self.encoder_attn = ConditionalDetrDecoderCrossAttention(
|
| 602 |
+
config=config,
|
| 603 |
+
hidden_size=self.hidden_size,
|
| 604 |
+
num_attention_heads=config.decoder_attention_heads,
|
| 605 |
+
dropout=config.attention_dropout,
|
| 606 |
+
)
|
| 607 |
+
|
| 608 |
+
def forward(
|
| 609 |
+
self,
|
| 610 |
+
hidden_states: torch.Tensor,
|
| 611 |
+
attention_mask: torch.Tensor | None = None,
|
| 612 |
+
spatial_position_embeddings: torch.Tensor | None = None,
|
| 613 |
+
query_position_embeddings: torch.Tensor | None = None,
|
| 614 |
+
query_sine_embed: torch.Tensor | None = None,
|
| 615 |
+
encoder_hidden_states: torch.Tensor | None = None,
|
| 616 |
+
encoder_attention_mask: torch.Tensor | None = None,
|
| 617 |
+
is_first: bool | None = False,
|
| 618 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 619 |
+
) -> torch.Tensor:
|
| 620 |
+
"""
|
| 621 |
+
Args:
|
| 622 |
+
hidden_states (`torch.FloatTensor`): input to the layer of shape `(seq_len, batch, embed_dim)`
|
| 623 |
+
attention_mask (`torch.FloatTensor`): attention mask of size
|
| 624 |
+
`(batch, 1, target_len, source_len)` where padding elements are indicated by very large negative
|
| 625 |
+
values.
|
| 626 |
+
spatial_position_embeddings (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 627 |
+
Spatial position embeddings (2D positional encodings) that are added to the queries and keys in each self-attention layer.
|
| 628 |
+
query_position_embeddings (`torch.FloatTensor`, *optional*):
|
| 629 |
+
object_queries that are added to the queries and keys
|
| 630 |
+
in the self-attention layer.
|
| 631 |
+
encoder_hidden_states (`torch.FloatTensor`):
|
| 632 |
+
cross attention input to the layer of shape `(seq_len, batch, embed_dim)`
|
| 633 |
+
encoder_attention_mask (`torch.FloatTensor`): encoder attention mask of size
|
| 634 |
+
`(batch, 1, target_len, source_len)` where padding elements are indicated by very large negative
|
| 635 |
+
values.
|
| 636 |
+
output_attentions (`bool`, *optional*):
|
| 637 |
+
Whether or not to return the attentions tensors of all attention layers. See `attentions` under
|
| 638 |
+
returned tensors for more detail.
|
| 639 |
+
"""
|
| 640 |
+
residual = hidden_states
|
| 641 |
+
|
| 642 |
+
hidden_states, _ = self.self_attn(
|
| 643 |
+
hidden_states=hidden_states,
|
| 644 |
+
query_position_embeddings=query_position_embeddings,
|
| 645 |
+
attention_mask=attention_mask,
|
| 646 |
+
**kwargs,
|
| 647 |
+
)
|
| 648 |
+
|
| 649 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 650 |
+
hidden_states = residual + hidden_states
|
| 651 |
+
hidden_states = self.self_attn_layer_norm(hidden_states)
|
| 652 |
+
|
| 653 |
+
if encoder_hidden_states is not None:
|
| 654 |
+
residual = hidden_states
|
| 655 |
+
|
| 656 |
+
hidden_states, _ = self.encoder_attn(
|
| 657 |
+
hidden_states=hidden_states,
|
| 658 |
+
encoder_hidden_states=encoder_hidden_states,
|
| 659 |
+
attention_mask=encoder_attention_mask,
|
| 660 |
+
query_sine_embed=query_sine_embed,
|
| 661 |
+
encoder_position_embeddings=spatial_position_embeddings,
|
| 662 |
+
# Only pass query_position_embeddings for the first layer
|
| 663 |
+
query_position_embeddings=query_position_embeddings if is_first else None,
|
| 664 |
+
**kwargs,
|
| 665 |
+
)
|
| 666 |
+
|
| 667 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 668 |
+
hidden_states = residual + hidden_states
|
| 669 |
+
hidden_states = self.encoder_attn_layer_norm(hidden_states)
|
| 670 |
+
|
| 671 |
+
# Fully Connected
|
| 672 |
+
residual = hidden_states
|
| 673 |
+
hidden_states = self.mlp(hidden_states)
|
| 674 |
+
hidden_states = residual + hidden_states
|
| 675 |
+
hidden_states = self.final_layer_norm(hidden_states)
|
| 676 |
+
|
| 677 |
+
return hidden_states
|
| 678 |
+
|
| 679 |
+
|
| 680 |
+
class ConditionalDetrMLPPredictionHead(DetrMLPPredictionHead):
|
| 681 |
+
pass
|
| 682 |
+
|
| 683 |
+
|
| 684 |
+
class ConditionalDetrPreTrainedModel(DetrPreTrainedModel):
|
| 685 |
+
_keys_to_ignore_on_load_unexpected = [
|
| 686 |
+
r"detr\.model\.backbone\.model\.layer\d+\.0\.downsample\.1\.num_batches_tracked"
|
| 687 |
+
]
|
| 688 |
+
|
| 689 |
+
|
| 690 |
+
class ConditionalDetrEncoder(DetrEncoder):
|
| 691 |
+
pass
|
| 692 |
+
|
| 693 |
+
|
| 694 |
+
class ConditionalDetrDecoder(ConditionalDetrPreTrainedModel):
|
| 695 |
+
"""
|
| 696 |
+
Transformer decoder consisting of *config.decoder_layers* layers. Each layer is a [`ConditionalDetrDecoderLayer`].
|
| 697 |
+
|
| 698 |
+
The decoder updates the query embeddings through multiple self-attention and cross-attention layers.
|
| 699 |
+
|
| 700 |
+
Some small tweaks for Conditional DETR:
|
| 701 |
+
|
| 702 |
+
- object_queries and query_position_embeddings are added to the forward pass.
|
| 703 |
+
- if self.config.auxiliary_loss is set to True, also returns a stack of activations from all decoding layers.
|
| 704 |
+
|
| 705 |
+
Args:
|
| 706 |
+
config: ConditionalDetrConfig
|
| 707 |
+
"""
|
| 708 |
+
|
| 709 |
+
_can_record_outputs = {
|
| 710 |
+
"hidden_states": ConditionalDetrDecoderLayer,
|
| 711 |
+
"attentions": OutputRecorder(ConditionalDetrDecoderSelfAttention, layer_name="self_attn", index=1),
|
| 712 |
+
"cross_attentions": OutputRecorder(ConditionalDetrDecoderCrossAttention, layer_name="encoder_attn", index=1),
|
| 713 |
+
}
|
| 714 |
+
|
| 715 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 716 |
+
super().__init__(config)
|
| 717 |
+
self.hidden_size = config.d_model
|
| 718 |
+
|
| 719 |
+
self.dropout = config.dropout
|
| 720 |
+
self.layerdrop = config.decoder_layerdrop
|
| 721 |
+
|
| 722 |
+
self.layers = nn.ModuleList([ConditionalDetrDecoderLayer(config) for _ in range(config.decoder_layers)])
|
| 723 |
+
# in Conditional DETR, the decoder uses layernorm after the last decoder layer output
|
| 724 |
+
self.layernorm = nn.LayerNorm(config.d_model)
|
| 725 |
+
|
| 726 |
+
# query_scale is the FFN applied on f to generate transformation T
|
| 727 |
+
self.query_scale = ConditionalDetrMLPPredictionHead(self.hidden_size, self.hidden_size, self.hidden_size, 2)
|
| 728 |
+
self.ref_point_head = ConditionalDetrMLPPredictionHead(self.hidden_size, self.hidden_size, 2, 2)
|
| 729 |
+
for layer_id in range(config.decoder_layers - 1):
|
| 730 |
+
# Set q_pos_proj to None for layers after the first (only first layer uses query position embeddings)
|
| 731 |
+
self.layers[layer_id + 1].encoder_attn.q_pos_proj = None
|
| 732 |
+
|
| 733 |
+
# Initialize weights and apply final processing
|
| 734 |
+
self.post_init()
|
| 735 |
+
|
| 736 |
+
@merge_with_config_defaults
|
| 737 |
+
@capture_outputs
|
| 738 |
+
def forward(
|
| 739 |
+
self,
|
| 740 |
+
inputs_embeds=None,
|
| 741 |
+
attention_mask=None,
|
| 742 |
+
encoder_hidden_states=None,
|
| 743 |
+
encoder_attention_mask=None,
|
| 744 |
+
spatial_position_embeddings=None,
|
| 745 |
+
object_queries_position_embeddings=None,
|
| 746 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 747 |
+
) -> ConditionalDetrDecoderOutput:
|
| 748 |
+
r"""
|
| 749 |
+
Args:
|
| 750 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 751 |
+
The query embeddings that are passed into the decoder.
|
| 752 |
+
|
| 753 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 754 |
+
Mask to avoid performing attention on certain queries. Mask values selected in `[0, 1]`:
|
| 755 |
+
|
| 756 |
+
- 1 for queries that are **not masked**,
|
| 757 |
+
- 0 for queries that are **masked**.
|
| 758 |
+
|
| 759 |
+
[What are attention masks?](../glossary#attention-mask)
|
| 760 |
+
encoder_hidden_states (`torch.FloatTensor` of shape `(batch_size, encoder_sequence_length, hidden_size)`, *optional*):
|
| 761 |
+
Sequence of hidden-states at the output of the last layer of the encoder. Used in the cross-attention
|
| 762 |
+
of the decoder.
|
| 763 |
+
encoder_attention_mask (`torch.LongTensor` of shape `(batch_size, encoder_sequence_length)`, *optional*):
|
| 764 |
+
Mask to avoid performing cross-attention on padding pixel_values of the encoder. Mask values selected
|
| 765 |
+
in `[0, 1]`:
|
| 766 |
+
|
| 767 |
+
- 1 for pixels that are real (i.e. **not masked**),
|
| 768 |
+
- 0 for pixels that are padding (i.e. **masked**).
|
| 769 |
+
|
| 770 |
+
spatial_position_embeddings (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 771 |
+
Spatial position embeddings that are added to the queries and keys in each cross-attention layer.
|
| 772 |
+
object_queries_position_embeddings (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 773 |
+
, *optional*): Position embeddings that are added to the queries and keys in each self-attention layer.
|
| 774 |
+
"""
|
| 775 |
+
if inputs_embeds is not None:
|
| 776 |
+
hidden_states = inputs_embeds
|
| 777 |
+
|
| 778 |
+
# expand encoder attention mask
|
| 779 |
+
if encoder_hidden_states is not None and encoder_attention_mask is not None:
|
| 780 |
+
# [batch_size, seq_len] -> [batch_size, 1, target_seq_len, source_seq_len]
|
| 781 |
+
encoder_attention_mask = create_bidirectional_mask(
|
| 782 |
+
self.config,
|
| 783 |
+
inputs_embeds,
|
| 784 |
+
encoder_attention_mask,
|
| 785 |
+
)
|
| 786 |
+
|
| 787 |
+
# optional intermediate hidden states
|
| 788 |
+
intermediate = () if self.config.auxiliary_loss else None
|
| 789 |
+
|
| 790 |
+
reference_points_before_sigmoid = self.ref_point_head(
|
| 791 |
+
object_queries_position_embeddings
|
| 792 |
+
) # [num_queries, batch_size, 2]
|
| 793 |
+
reference_points = reference_points_before_sigmoid.sigmoid().transpose(0, 1)
|
| 794 |
+
obj_center = reference_points[..., :2].transpose(0, 1)
|
| 795 |
+
# get sine embedding for the query vector
|
| 796 |
+
query_sine_embed_before_transformation = encode_sinusoidal_position_embedding(
|
| 797 |
+
obj_center, num_pos_feats=self.config.d_model // 2
|
| 798 |
+
)
|
| 799 |
+
|
| 800 |
+
for idx, decoder_layer in enumerate(self.layers):
|
| 801 |
+
if self.training:
|
| 802 |
+
dropout_probability = torch.rand([])
|
| 803 |
+
if dropout_probability < self.layerdrop:
|
| 804 |
+
continue
|
| 805 |
+
if idx == 0:
|
| 806 |
+
pos_transformation = 1
|
| 807 |
+
else:
|
| 808 |
+
pos_transformation = self.query_scale(hidden_states)
|
| 809 |
+
# apply transformation
|
| 810 |
+
query_sine_embed = query_sine_embed_before_transformation * pos_transformation
|
| 811 |
+
|
| 812 |
+
hidden_states = decoder_layer(
|
| 813 |
+
hidden_states,
|
| 814 |
+
None,
|
| 815 |
+
spatial_position_embeddings,
|
| 816 |
+
object_queries_position_embeddings,
|
| 817 |
+
query_sine_embed,
|
| 818 |
+
encoder_hidden_states, # as a positional argument for gradient checkpointing
|
| 819 |
+
encoder_attention_mask=encoder_attention_mask,
|
| 820 |
+
is_first=(idx == 0),
|
| 821 |
+
**kwargs,
|
| 822 |
+
)
|
| 823 |
+
|
| 824 |
+
if self.config.auxiliary_loss:
|
| 825 |
+
hidden_states = self.layernorm(hidden_states)
|
| 826 |
+
intermediate += (hidden_states,)
|
| 827 |
+
|
| 828 |
+
# finally, apply layernorm
|
| 829 |
+
hidden_states = self.layernorm(hidden_states)
|
| 830 |
+
|
| 831 |
+
# stack intermediate decoder activations
|
| 832 |
+
if self.config.auxiliary_loss:
|
| 833 |
+
intermediate = torch.stack(intermediate)
|
| 834 |
+
|
| 835 |
+
return ConditionalDetrDecoderOutput(
|
| 836 |
+
last_hidden_state=hidden_states,
|
| 837 |
+
intermediate_hidden_states=intermediate,
|
| 838 |
+
reference_points=reference_points,
|
| 839 |
+
)
|
| 840 |
+
|
| 841 |
+
|
| 842 |
+
class ConditionalDetrModel(DetrModel):
|
| 843 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 844 |
+
super().__init__(config)
|
| 845 |
+
self.query_position_embeddings = nn.Embedding(config.num_queries, config.d_model)
|
| 846 |
+
|
| 847 |
+
# Initialize weights and apply final processing
|
| 848 |
+
self.post_init()
|
| 849 |
+
|
| 850 |
+
@auto_docstring
|
| 851 |
+
@can_return_tuple
|
| 852 |
+
def forward(
|
| 853 |
+
self,
|
| 854 |
+
pixel_values: torch.FloatTensor,
|
| 855 |
+
pixel_mask: torch.LongTensor | None = None,
|
| 856 |
+
decoder_attention_mask: torch.LongTensor | None = None,
|
| 857 |
+
encoder_outputs: torch.FloatTensor | None = None,
|
| 858 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 859 |
+
decoder_inputs_embeds: torch.FloatTensor | None = None,
|
| 860 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 861 |
+
) -> ConditionalDetrModelOutput:
|
| 862 |
+
r"""
|
| 863 |
+
decoder_attention_mask (`torch.FloatTensor` of shape `(batch_size, num_queries)`, *optional*):
|
| 864 |
+
Not used by default. Can be used to mask object queries.
|
| 865 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 866 |
+
Optionally, instead of passing the flattened feature map (output of the backbone + projection layer), you
|
| 867 |
+
can choose to directly pass a flattened representation of an image.
|
| 868 |
+
decoder_inputs_embeds (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 869 |
+
Optionally, instead of initializing the queries with a tensor of zeros, you can choose to directly pass an
|
| 870 |
+
embedded representation.
|
| 871 |
+
|
| 872 |
+
Examples:
|
| 873 |
+
|
| 874 |
+
```python
|
| 875 |
+
>>> from transformers import AutoImageProcessor, AutoModel
|
| 876 |
+
>>> from PIL import Image
|
| 877 |
+
>>> import httpx
|
| 878 |
+
>>> from io import BytesIO
|
| 879 |
+
|
| 880 |
+
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
| 881 |
+
>>> with httpx.stream("GET", url) as response:
|
| 882 |
+
... image = Image.open(BytesIO(response.read()))
|
| 883 |
+
|
| 884 |
+
>>> image_processor = AutoImageProcessor.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 885 |
+
>>> model = AutoModel.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 886 |
+
|
| 887 |
+
>>> # prepare image for the model
|
| 888 |
+
>>> inputs = image_processor(images=image, return_tensors="pt")
|
| 889 |
+
|
| 890 |
+
>>> # forward pass
|
| 891 |
+
>>> outputs = model(**inputs)
|
| 892 |
+
|
| 893 |
+
>>> # the last hidden states are the final query embeddings of the Transformer decoder
|
| 894 |
+
>>> # these are of shape (batch_size, num_queries, hidden_size)
|
| 895 |
+
>>> last_hidden_states = outputs.last_hidden_state
|
| 896 |
+
>>> list(last_hidden_states.shape)
|
| 897 |
+
[1, 300, 256]
|
| 898 |
+
```"""
|
| 899 |
+
batch_size, num_channels, height, width = pixel_values.shape
|
| 900 |
+
device = pixel_values.device
|
| 901 |
+
|
| 902 |
+
if pixel_mask is None:
|
| 903 |
+
pixel_mask = torch.ones(((batch_size, height, width)), device=device)
|
| 904 |
+
|
| 905 |
+
# First, sent pixel_values + pixel_mask through Backbone to obtain the features
|
| 906 |
+
# pixel_values should be of shape (batch_size, num_channels, height, width)
|
| 907 |
+
# pixel_mask should be of shape (batch_size, height, width)
|
| 908 |
+
features = self.backbone(pixel_values, pixel_mask)
|
| 909 |
+
|
| 910 |
+
# get final feature map and downsampled mask
|
| 911 |
+
feature_map, mask = features[-1]
|
| 912 |
+
|
| 913 |
+
if mask is None:
|
| 914 |
+
raise ValueError("Backbone does not return downsampled pixel mask")
|
| 915 |
+
|
| 916 |
+
# Second, apply 1x1 convolution to reduce the channel dimension to d_model (256 by default)
|
| 917 |
+
projected_feature_map = self.input_projection(feature_map)
|
| 918 |
+
|
| 919 |
+
# Generate position embeddings
|
| 920 |
+
spatial_position_embeddings = (
|
| 921 |
+
self.position_embedding(shape=feature_map.shape, device=device, dtype=pixel_values.dtype, mask=mask)
|
| 922 |
+
.flatten(2)
|
| 923 |
+
.transpose(1, 2)
|
| 924 |
+
)
|
| 925 |
+
|
| 926 |
+
# Third, flatten the feature map of shape NxCxHxW to NxCxHW, and permute it to NxHWxC
|
| 927 |
+
# In other words, turn their shape into (batch_size, sequence_length, hidden_size)
|
| 928 |
+
flattened_features = projected_feature_map.flatten(2).transpose(1, 2)
|
| 929 |
+
|
| 930 |
+
flattened_mask = mask.flatten(1)
|
| 931 |
+
|
| 932 |
+
# Fourth, sent flattened_features + flattened_mask + spatial_position_embeddings through encoder
|
| 933 |
+
# flattened_features is a Tensor of shape (batch_size, height*width, hidden_size)
|
| 934 |
+
# flattened_mask is a Tensor of shape (batch_size, height*width)
|
| 935 |
+
if encoder_outputs is None:
|
| 936 |
+
encoder_outputs = self.encoder(
|
| 937 |
+
inputs_embeds=flattened_features,
|
| 938 |
+
attention_mask=flattened_mask,
|
| 939 |
+
spatial_position_embeddings=spatial_position_embeddings,
|
| 940 |
+
**kwargs,
|
| 941 |
+
)
|
| 942 |
+
# If the user passed a tuple for encoder_outputs, we wrap it in a BaseModelOutput
|
| 943 |
+
elif not isinstance(encoder_outputs, BaseModelOutput):
|
| 944 |
+
encoder_outputs = BaseModelOutput(
|
| 945 |
+
last_hidden_state=encoder_outputs[0],
|
| 946 |
+
hidden_states=encoder_outputs[1] if len(encoder_outputs) > 1 else None,
|
| 947 |
+
attentions=encoder_outputs[2] if len(encoder_outputs) > 2 else None,
|
| 948 |
+
)
|
| 949 |
+
|
| 950 |
+
# Fifth, sent query embeddings through the decoder (which is conditioned on the encoder output)
|
| 951 |
+
object_queries_position_embeddings = self.query_position_embeddings.weight.unsqueeze(0).repeat(
|
| 952 |
+
batch_size, 1, 1
|
| 953 |
+
)
|
| 954 |
+
queries = torch.zeros_like(object_queries_position_embeddings)
|
| 955 |
+
|
| 956 |
+
# decoder outputs consists of (dec_features, dec_hidden, dec_attn)
|
| 957 |
+
decoder_outputs = self.decoder(
|
| 958 |
+
inputs_embeds=queries,
|
| 959 |
+
attention_mask=None,
|
| 960 |
+
spatial_position_embeddings=spatial_position_embeddings,
|
| 961 |
+
object_queries_position_embeddings=object_queries_position_embeddings,
|
| 962 |
+
encoder_hidden_states=encoder_outputs.last_hidden_state,
|
| 963 |
+
encoder_attention_mask=flattened_mask,
|
| 964 |
+
**kwargs,
|
| 965 |
+
)
|
| 966 |
+
|
| 967 |
+
return ConditionalDetrModelOutput(
|
| 968 |
+
last_hidden_state=decoder_outputs.last_hidden_state,
|
| 969 |
+
decoder_hidden_states=decoder_outputs.hidden_states,
|
| 970 |
+
decoder_attentions=decoder_outputs.attentions,
|
| 971 |
+
cross_attentions=decoder_outputs.cross_attentions,
|
| 972 |
+
encoder_last_hidden_state=encoder_outputs.last_hidden_state,
|
| 973 |
+
encoder_hidden_states=encoder_outputs.hidden_states,
|
| 974 |
+
encoder_attentions=encoder_outputs.attentions,
|
| 975 |
+
intermediate_hidden_states=decoder_outputs.intermediate_hidden_states,
|
| 976 |
+
reference_points=decoder_outputs.reference_points,
|
| 977 |
+
)
|
| 978 |
+
|
| 979 |
+
|
| 980 |
+
class ConditionalDetrForObjectDetection(DetrForObjectDetection):
|
| 981 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 982 |
+
super().__init__(config)
|
| 983 |
+
self.class_labels_classifier = nn.Linear(config.d_model, config.num_labels)
|
| 984 |
+
|
| 985 |
+
# taken from https://github.com/Atten4Vis/conditionalDETR/blob/master/models/conditional_detr.py
|
| 986 |
+
def _set_aux_loss(self, outputs_class, outputs_coord):
|
| 987 |
+
return [{"logits": a, "pred_boxes": b} for a, b in zip(outputs_class[:-1], outputs_coord[:-1])]
|
| 988 |
+
|
| 989 |
+
@auto_docstring
|
| 990 |
+
@can_return_tuple
|
| 991 |
+
def forward(
|
| 992 |
+
self,
|
| 993 |
+
pixel_values: torch.FloatTensor,
|
| 994 |
+
pixel_mask: torch.LongTensor | None = None,
|
| 995 |
+
decoder_attention_mask: torch.LongTensor | None = None,
|
| 996 |
+
encoder_outputs: torch.FloatTensor | None = None,
|
| 997 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 998 |
+
decoder_inputs_embeds: torch.FloatTensor | None = None,
|
| 999 |
+
labels: list[dict] | None = None,
|
| 1000 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 1001 |
+
) -> ConditionalDetrObjectDetectionOutput:
|
| 1002 |
+
r"""
|
| 1003 |
+
decoder_attention_mask (`torch.FloatTensor` of shape `(batch_size, num_queries)`, *optional*):
|
| 1004 |
+
Not used by default. Can be used to mask object queries.
|
| 1005 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 1006 |
+
Optionally, instead of passing the flattened feature map (output of the backbone + projection layer), you
|
| 1007 |
+
can choose to directly pass a flattened representation of an image.
|
| 1008 |
+
decoder_inputs_embeds (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 1009 |
+
Optionally, instead of initializing the queries with a tensor of zeros, you can choose to directly pass an
|
| 1010 |
+
embedded representation.
|
| 1011 |
+
labels (`list[Dict]` of len `(batch_size,)`, *optional*):
|
| 1012 |
+
Labels for computing the bipartite matching loss. List of dicts, each dictionary containing at least the
|
| 1013 |
+
following 2 keys: 'class_labels' and 'boxes' (the class labels and bounding boxes of an image in the batch
|
| 1014 |
+
respectively). The class labels themselves should be a `torch.LongTensor` of len `(number of bounding boxes
|
| 1015 |
+
in the image,)` and the boxes a `torch.FloatTensor` of shape `(number of bounding boxes in the image, 4)`.
|
| 1016 |
+
|
| 1017 |
+
Examples:
|
| 1018 |
+
|
| 1019 |
+
```python
|
| 1020 |
+
>>> from transformers import AutoImageProcessor, AutoModelForObjectDetection
|
| 1021 |
+
>>> from PIL import Image
|
| 1022 |
+
>>> import httpx
|
| 1023 |
+
>>> from io import BytesIO
|
| 1024 |
+
|
| 1025 |
+
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
| 1026 |
+
>>> with httpx.stream("GET", url) as response:
|
| 1027 |
+
... image = Image.open(BytesIO(response.read()))
|
| 1028 |
+
|
| 1029 |
+
>>> image_processor = AutoImageProcessor.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 1030 |
+
>>> model = AutoModelForObjectDetection.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 1031 |
+
|
| 1032 |
+
>>> inputs = image_processor(images=image, return_tensors="pt")
|
| 1033 |
+
|
| 1034 |
+
>>> outputs = model(**inputs)
|
| 1035 |
+
|
| 1036 |
+
>>> # convert outputs (bounding boxes and class logits) to Pascal VOC format (xmin, ymin, xmax, ymax)
|
| 1037 |
+
>>> target_sizes = torch.tensor([image.size[::-1]])
|
| 1038 |
+
>>> results = image_processor.post_process_object_detection(outputs, threshold=0.5, target_sizes=target_sizes)[
|
| 1039 |
+
... 0
|
| 1040 |
+
... ]
|
| 1041 |
+
>>> for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
|
| 1042 |
+
... box = [round(i, 2) for i in box.tolist()]
|
| 1043 |
+
... print(
|
| 1044 |
+
... f"Detected {model.config.id2label[label.item()]} with confidence "
|
| 1045 |
+
... f"{round(score.item(), 3)} at location {box}"
|
| 1046 |
+
... )
|
| 1047 |
+
Detected remote with confidence 0.833 at location [38.31, 72.1, 177.63, 118.45]
|
| 1048 |
+
Detected cat with confidence 0.831 at location [9.2, 51.38, 321.13, 469.0]
|
| 1049 |
+
Detected cat with confidence 0.804 at location [340.3, 16.85, 642.93, 370.95]
|
| 1050 |
+
Detected remote with confidence 0.683 at location [334.48, 73.49, 366.37, 190.01]
|
| 1051 |
+
Detected couch with confidence 0.535 at location [0.52, 1.19, 640.35, 475.1]
|
| 1052 |
+
```"""
|
| 1053 |
+
# First, sent images through CONDITIONAL_DETR base model to obtain encoder + decoder outputs
|
| 1054 |
+
outputs = self.model(
|
| 1055 |
+
pixel_values,
|
| 1056 |
+
pixel_mask=pixel_mask,
|
| 1057 |
+
decoder_attention_mask=decoder_attention_mask,
|
| 1058 |
+
encoder_outputs=encoder_outputs,
|
| 1059 |
+
inputs_embeds=inputs_embeds,
|
| 1060 |
+
decoder_inputs_embeds=decoder_inputs_embeds,
|
| 1061 |
+
**kwargs,
|
| 1062 |
+
)
|
| 1063 |
+
|
| 1064 |
+
sequence_output = outputs[0]
|
| 1065 |
+
|
| 1066 |
+
# class logits + predicted bounding boxes
|
| 1067 |
+
logits = self.class_labels_classifier(sequence_output)
|
| 1068 |
+
|
| 1069 |
+
reference = outputs.reference_points
|
| 1070 |
+
reference_before_sigmoid = inverse_sigmoid(reference).transpose(0, 1)
|
| 1071 |
+
|
| 1072 |
+
hs = sequence_output
|
| 1073 |
+
tmp = self.bbox_predictor(hs)
|
| 1074 |
+
tmp[..., :2] += reference_before_sigmoid
|
| 1075 |
+
pred_boxes = tmp.sigmoid()
|
| 1076 |
+
# pred_boxes = self.bbox_predictor(sequence_output).sigmoid()
|
| 1077 |
+
|
| 1078 |
+
loss, loss_dict, auxiliary_outputs = None, None, None
|
| 1079 |
+
if labels is not None:
|
| 1080 |
+
outputs_class, outputs_coord = None, None
|
| 1081 |
+
if self.config.auxiliary_loss:
|
| 1082 |
+
outputs_coords = []
|
| 1083 |
+
intermediate = outputs.intermediate_hidden_states
|
| 1084 |
+
outputs_class = self.class_labels_classifier(intermediate)
|
| 1085 |
+
for lvl in range(intermediate.shape[0]):
|
| 1086 |
+
tmp = self.bbox_predictor(intermediate[lvl])
|
| 1087 |
+
tmp[..., :2] += reference_before_sigmoid
|
| 1088 |
+
outputs_coord = tmp.sigmoid()
|
| 1089 |
+
outputs_coords.append(outputs_coord)
|
| 1090 |
+
outputs_coord = torch.stack(outputs_coords)
|
| 1091 |
+
loss, loss_dict, auxiliary_outputs = self.loss_function(
|
| 1092 |
+
logits, labels, self.device, pred_boxes, self.config, outputs_class, outputs_coord
|
| 1093 |
+
)
|
| 1094 |
+
|
| 1095 |
+
return ConditionalDetrObjectDetectionOutput(
|
| 1096 |
+
loss=loss,
|
| 1097 |
+
loss_dict=loss_dict,
|
| 1098 |
+
logits=logits,
|
| 1099 |
+
pred_boxes=pred_boxes,
|
| 1100 |
+
auxiliary_outputs=auxiliary_outputs,
|
| 1101 |
+
last_hidden_state=outputs.last_hidden_state,
|
| 1102 |
+
decoder_hidden_states=outputs.decoder_hidden_states,
|
| 1103 |
+
decoder_attentions=outputs.decoder_attentions,
|
| 1104 |
+
cross_attentions=outputs.cross_attentions,
|
| 1105 |
+
encoder_last_hidden_state=outputs.encoder_last_hidden_state,
|
| 1106 |
+
encoder_hidden_states=outputs.encoder_hidden_states,
|
| 1107 |
+
encoder_attentions=outputs.encoder_attentions,
|
| 1108 |
+
)
|
| 1109 |
+
|
| 1110 |
+
|
| 1111 |
+
class ConditionalDetrForSegmentation(DetrForSegmentation):
|
| 1112 |
+
pass
|
| 1113 |
+
|
| 1114 |
+
|
| 1115 |
+
__all__ = [
|
| 1116 |
+
"ConditionalDetrImageProcessor",
|
| 1117 |
+
"ConditionalDetrImageProcessorPil",
|
| 1118 |
+
"ConditionalDetrForObjectDetection",
|
| 1119 |
+
"ConditionalDetrForSegmentation",
|
| 1120 |
+
"ConditionalDetrModel",
|
| 1121 |
+
"ConditionalDetrPreTrainedModel",
|
| 1122 |
+
]
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/mra/configuration_mra.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 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 |
+
"""MRA model configuration"""
|
| 15 |
+
|
| 16 |
+
from huggingface_hub.dataclasses import strict
|
| 17 |
+
|
| 18 |
+
from ...configuration_utils import PreTrainedConfig
|
| 19 |
+
from ...utils import auto_docstring
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@auto_docstring(checkpoint="uw-madison/mra-base-512-4")
|
| 23 |
+
@strict
|
| 24 |
+
class MraConfig(PreTrainedConfig):
|
| 25 |
+
r"""
|
| 26 |
+
block_per_row (`int`, *optional*, defaults to 4):
|
| 27 |
+
Used to set the budget for the high resolution scale.
|
| 28 |
+
approx_mode (`str`, *optional*, defaults to `"full"`):
|
| 29 |
+
Controls whether both low and high resolution approximations are used. Set to `"full"` for both low and
|
| 30 |
+
high resolution and `"sparse"` for only low resolution.
|
| 31 |
+
initial_prior_first_n_blocks (`int`, *optional*, defaults to 0):
|
| 32 |
+
The initial number of blocks for which high resolution is used.
|
| 33 |
+
initial_prior_diagonal_n_blocks (`int`, *optional*, defaults to 0):
|
| 34 |
+
The number of diagonal blocks for which high resolution is used.
|
| 35 |
+
|
| 36 |
+
Example:
|
| 37 |
+
|
| 38 |
+
```python
|
| 39 |
+
>>> from transformers import MraConfig, MraModel
|
| 40 |
+
|
| 41 |
+
>>> # Initializing a Mra uw-madison/mra-base-512-4 style configuration
|
| 42 |
+
>>> configuration = MraConfig()
|
| 43 |
+
|
| 44 |
+
>>> # Initializing a model (with random weights) from the uw-madison/mra-base-512-4 style configuration
|
| 45 |
+
>>> model = MraModel(configuration)
|
| 46 |
+
|
| 47 |
+
>>> # Accessing the model configuration
|
| 48 |
+
>>> configuration = model.config
|
| 49 |
+
```"""
|
| 50 |
+
|
| 51 |
+
model_type = "mra"
|
| 52 |
+
|
| 53 |
+
vocab_size: int = 50265
|
| 54 |
+
hidden_size: int = 768
|
| 55 |
+
num_hidden_layers: int = 12
|
| 56 |
+
num_attention_heads: int = 12
|
| 57 |
+
intermediate_size: int = 3072
|
| 58 |
+
hidden_act: str = "gelu"
|
| 59 |
+
hidden_dropout_prob: float | int = 0.1
|
| 60 |
+
attention_probs_dropout_prob: float | int = 0.1
|
| 61 |
+
max_position_embeddings: int = 512
|
| 62 |
+
type_vocab_size: int = 1
|
| 63 |
+
initializer_range: float = 0.02
|
| 64 |
+
layer_norm_eps: float = 1e-5
|
| 65 |
+
block_per_row: int = 4
|
| 66 |
+
approx_mode: str = "full"
|
| 67 |
+
initial_prior_first_n_blocks: int = 0
|
| 68 |
+
initial_prior_diagonal_n_blocks: int = 0
|
| 69 |
+
pad_token_id: int | None = 1
|
| 70 |
+
bos_token_id: int | None = 0
|
| 71 |
+
eos_token_id: int | list[int] | None = 2
|
| 72 |
+
add_cross_attention: bool = False
|
| 73 |
+
tie_word_embeddings: bool = True
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
__all__ = ["MraConfig"]
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/sam_hq/configuration_sam_hq.py
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/sam_hq/modular_sam_hq.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_sam_hq.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2025 Google Inc. HuggingFace Inc. team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
#
|
| 10 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 11 |
+
# you may not use this file except in compliance with the License.
|
| 12 |
+
# You may obtain a copy of the License at
|
| 13 |
+
#
|
| 14 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 15 |
+
#
|
| 16 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 17 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 18 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 19 |
+
# See the License for the specific language governing permissions and
|
| 20 |
+
# limitations under the License.
|
| 21 |
+
from huggingface_hub.dataclasses import strict
|
| 22 |
+
|
| 23 |
+
from ...configuration_utils import PreTrainedConfig
|
| 24 |
+
from ...utils import auto_docstring
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
@auto_docstring(checkpoint="syscv-community/sam-hq-vit-base")
|
| 28 |
+
@strict
|
| 29 |
+
class SamHQPromptEncoderConfig(PreTrainedConfig):
|
| 30 |
+
r"""
|
| 31 |
+
mask_input_channels (`int`, *optional*, defaults to 16):
|
| 32 |
+
The number of channels to be fed to the `MaskDecoder` module.
|
| 33 |
+
num_point_embeddings (`int`, *optional*, defaults to 4):
|
| 34 |
+
The number of point embeddings to be used.
|
| 35 |
+
"""
|
| 36 |
+
|
| 37 |
+
base_config_key = "prompt_encoder_config"
|
| 38 |
+
|
| 39 |
+
hidden_size: int = 256
|
| 40 |
+
image_size: int | list[int] | tuple[int, int] = 1024
|
| 41 |
+
patch_size: int | list[int] | tuple[int, int] = 16
|
| 42 |
+
mask_input_channels: int = 16
|
| 43 |
+
num_point_embeddings: int = 4
|
| 44 |
+
hidden_act: str = "gelu"
|
| 45 |
+
layer_norm_eps: float = 1e-6
|
| 46 |
+
|
| 47 |
+
def __post_init__(self, **kwargs):
|
| 48 |
+
self.image_embedding_size = self.image_size // self.patch_size
|
| 49 |
+
super().__post_init__(**kwargs)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
@auto_docstring(checkpoint="syscv-community/sam-hq-vit-base")
|
| 53 |
+
@strict
|
| 54 |
+
class SamHQVisionConfig(PreTrainedConfig):
|
| 55 |
+
r"""
|
| 56 |
+
output_channels (`int`, *optional*, defaults to 256):
|
| 57 |
+
Dimensionality of the output channels in the Patch Encoder.
|
| 58 |
+
use_rel_pos (`bool`, *optional*, defaults to `True`):
|
| 59 |
+
Whether to use relative position embedding.
|
| 60 |
+
window_size (`int`, *optional*, defaults to 14):
|
| 61 |
+
Window size for relative position.
|
| 62 |
+
global_attn_indexes (`list[int]`, *optional*, defaults to `[2, 5, 8, 11]`):
|
| 63 |
+
The indexes of the global attention layers.
|
| 64 |
+
num_pos_feats (`int`, *optional*, defaults to 128):
|
| 65 |
+
The dimensionality of the position embedding.
|
| 66 |
+
mlp_dim (`int`, *optional*):
|
| 67 |
+
The dimensionality of the MLP layer in the Transformer encoder. If `None`, defaults to `mlp_ratio *
|
| 68 |
+
hidden_size`.
|
| 69 |
+
|
| 70 |
+
Example:
|
| 71 |
+
|
| 72 |
+
```python
|
| 73 |
+
>>> from transformers import (
|
| 74 |
+
... SamHQVisionConfig,
|
| 75 |
+
... SamHQVisionModel,
|
| 76 |
+
... )
|
| 77 |
+
|
| 78 |
+
>>> # Initializing a SamHQVisionConfig with `"facebook/sam_hq-vit-huge"` style configuration
|
| 79 |
+
>>> configuration = SamHQVisionConfig()
|
| 80 |
+
|
| 81 |
+
>>> # Initializing a SamHQVisionModel (with random weights) from the `"facebook/sam_hq-vit-huge"` style configuration
|
| 82 |
+
>>> model = SamHQVisionModel(configuration)
|
| 83 |
+
|
| 84 |
+
>>> # Accessing the model configuration
|
| 85 |
+
>>> configuration = model.config
|
| 86 |
+
```"""
|
| 87 |
+
|
| 88 |
+
base_config_key = "vision_config"
|
| 89 |
+
model_type = "sam_hq_vision_model"
|
| 90 |
+
|
| 91 |
+
hidden_size: int = 768
|
| 92 |
+
output_channels: int = 256
|
| 93 |
+
num_hidden_layers: int = 12
|
| 94 |
+
num_attention_heads: int = 12
|
| 95 |
+
num_channels: int = 3
|
| 96 |
+
image_size: int | list[int] | tuple[int, int] = 1024
|
| 97 |
+
patch_size: int | list[int] | tuple[int, int] = 16
|
| 98 |
+
hidden_act: str = "gelu"
|
| 99 |
+
layer_norm_eps: float = 1e-06
|
| 100 |
+
attention_dropout: float | int = 0.0
|
| 101 |
+
initializer_range: float = 1e-10
|
| 102 |
+
qkv_bias: bool = True
|
| 103 |
+
mlp_ratio: float = 4.0
|
| 104 |
+
use_abs_pos: bool = True
|
| 105 |
+
use_rel_pos: bool = True
|
| 106 |
+
window_size: int = 14
|
| 107 |
+
global_attn_indexes: list[int] | tuple[int, ...] = (2, 5, 8, 11)
|
| 108 |
+
num_pos_feats: int = 128
|
| 109 |
+
mlp_dim: int | None = None
|
| 110 |
+
|
| 111 |
+
def __post_init__(self, **kwargs):
|
| 112 |
+
self.mlp_dim = int(self.hidden_size * self.mlp_ratio) if self.mlp_dim is None else self.mlp_dim
|
| 113 |
+
self.scale = self.hidden_size // 2
|
| 114 |
+
super().__post_init__(**kwargs)
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
@auto_docstring(checkpoint="syscv-community/sam-hq-vit-base")
|
| 118 |
+
@strict
|
| 119 |
+
class SamHQMaskDecoderConfig(PreTrainedConfig):
|
| 120 |
+
r"""
|
| 121 |
+
mlp_dim (`int`, *optional*, defaults to 2048):
|
| 122 |
+
Dimensionality of the "intermediate" (i.e., feed-forward) layer in the Transformer encoder.
|
| 123 |
+
attention_downsample_rate (`int`, *optional*, defaults to 2):
|
| 124 |
+
The downsampling rate of the attention layer.
|
| 125 |
+
num_multimask_outputs (`int`, *optional*, defaults to 3):
|
| 126 |
+
The number of outputs from the `SamMaskDecoder` module. In the Segment Anything paper, this is set to 3.
|
| 127 |
+
iou_head_depth (`int`, *optional*, defaults to 3):
|
| 128 |
+
The number of layers in the IoU head module.
|
| 129 |
+
iou_head_hidden_dim (`int`, *optional*, defaults to 256):
|
| 130 |
+
The dimensionality of the hidden states in the IoU head module.
|
| 131 |
+
vit_dim (`int`, *optional*, defaults to 768):
|
| 132 |
+
Dimensionality of the Vision Transformer (ViT) used in the `SamHQMaskDecoder` module.
|
| 133 |
+
"""
|
| 134 |
+
|
| 135 |
+
base_config_key = "mask_decoder_config"
|
| 136 |
+
|
| 137 |
+
hidden_size: int = 256
|
| 138 |
+
hidden_act: str = "relu"
|
| 139 |
+
mlp_dim: int = 2048
|
| 140 |
+
num_hidden_layers: int = 2
|
| 141 |
+
num_attention_heads: int = 8
|
| 142 |
+
attention_downsample_rate: int = 2
|
| 143 |
+
num_multimask_outputs: int = 3
|
| 144 |
+
iou_head_depth: int = 3
|
| 145 |
+
iou_head_hidden_dim: int = 256
|
| 146 |
+
layer_norm_eps: float = 1e-6
|
| 147 |
+
|
| 148 |
+
vit_dim: int = 768
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
@auto_docstring(checkpoint="syscv-community/sam-hq-vit-base")
|
| 152 |
+
@strict
|
| 153 |
+
class SamHQConfig(PreTrainedConfig):
|
| 154 |
+
r"""
|
| 155 |
+
prompt_encoder_config (Union[`dict`, `SamHQPromptEncoderConfig`], *optional*):
|
| 156 |
+
Dictionary of configuration options used to initialize [`SamHQPromptEncoderConfig`].
|
| 157 |
+
mask_decoder_config (Union[`dict`, `SamHQMaskDecoderConfig`], *optional*):
|
| 158 |
+
Dictionary of configuration options used to initialize [`SamHQMaskDecoderConfig`].
|
| 159 |
+
"""
|
| 160 |
+
|
| 161 |
+
model_type = "sam_hq"
|
| 162 |
+
sub_configs = {
|
| 163 |
+
"prompt_encoder_config": SamHQPromptEncoderConfig,
|
| 164 |
+
"mask_decoder_config": SamHQMaskDecoderConfig,
|
| 165 |
+
"vision_config": SamHQVisionConfig,
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
vision_config: dict | PreTrainedConfig | None = None
|
| 169 |
+
prompt_encoder_config: dict | PreTrainedConfig | None = None
|
| 170 |
+
mask_decoder_config: dict | PreTrainedConfig | None = None
|
| 171 |
+
initializer_range: float = 0.02
|
| 172 |
+
tie_word_embeddings: bool = True
|
| 173 |
+
|
| 174 |
+
def __post_init__(self, **kwargs):
|
| 175 |
+
if isinstance(self.vision_config, dict):
|
| 176 |
+
self.vision_config = SamHQVisionConfig(**self.vision_config)
|
| 177 |
+
elif self.vision_config is None:
|
| 178 |
+
self.vision_config = SamHQVisionConfig()
|
| 179 |
+
|
| 180 |
+
if isinstance(self.prompt_encoder_config, dict):
|
| 181 |
+
self.prompt_encoder_config = SamHQPromptEncoderConfig(**self.prompt_encoder_config)
|
| 182 |
+
elif self.prompt_encoder_config is None:
|
| 183 |
+
self.prompt_encoder_config = SamHQPromptEncoderConfig()
|
| 184 |
+
|
| 185 |
+
if isinstance(self.mask_decoder_config, dict):
|
| 186 |
+
self.mask_decoder_config = SamHQMaskDecoderConfig(**self.mask_decoder_config)
|
| 187 |
+
elif self.mask_decoder_config is None:
|
| 188 |
+
self.mask_decoder_config = SamHQMaskDecoderConfig()
|
| 189 |
+
|
| 190 |
+
super().__post_init__(**kwargs)
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
__all__ = ["SamHQVisionConfig", "SamHQMaskDecoderConfig", "SamHQPromptEncoderConfig", "SamHQConfig"]
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/runs/owt_t5_elftokenized_full_len1024_C1_to_1024_pow1_d768_l12_h12_gbs512_2x8gpu_50ep_lr4e3_ema0p9999_elfopt_not5_bottleneck128_unfixed_norm_stateprobadd_selfcond_ce_fast_20260610_020108/step_108000.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1bf79262204c502cd6fdbf64ca81e4fdaa3b1c754b6bcac1329bdad2880d298e
|
| 3 |
+
size 927700322
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/runs/owt_t5_elftokenized_full_len1024_C1_to_1024_pow1_d768_l12_h12_gbs512_2x8gpu_50ep_lr4e3_ema0p9999_elfopt_not5_bottleneck128_unfixed_norm_stateprobadd_selfcond_ce_fast_20260610_020108/step_127000.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7a2ffe508d16afb6833bea352ebd3443a6c5f6400aea033956b03705e4bb32ac
|
| 3 |
+
size 927700322
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/runs/owt_t5_elftokenized_full_len1024_C1_to_1024_pow1_d768_l12_h12_gbs512_2x8gpu_50ep_lr4e3_ema0p9999_elfopt_not5_bottleneck128_unfixed_norm_stateprobadd_selfcond_ce_fast_20260610_020108/step_180000.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:397b1b8db3af35c9aff0a7bb1291d384eb0dbe18a6f968d3c674e723751dc53e
|
| 3 |
+
size 927700322
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/runs/owt_t5_elftokenized_full_len1024_C1_to_1024_pow1_d768_l12_h12_gbs512_2x8gpu_50ep_lr4e3_ema0p9999_elfopt_not5_bottleneck128_unfixed_norm_stateprobadd_selfcond_ce_fast_20260610_020108/step_190000.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4c2449ca6ea70ef4f4d7ebb222eed6bed883aa415505423b0e035b44cb8784fc
|
| 3 |
+
size 927700322
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/runs/owt_t5_elftokenized_full_len1024_C1_to_1024_pow1_d768_l12_h12_gbs512_2x8gpu_50ep_lr4e3_ema0p9999_elfopt_not5_bottleneck128_unfixed_norm_stateprobadd_selfcond_ce_fast_20260610_020108/step_248000.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:701a956f3bb065d6d704173f18cb076fb94d08fa1458cee4e0e68042359ae7d8
|
| 3 |
+
size 927700322
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/runs/owt_t5_elftokenized_full_len1024_C1_to_1024_pow1_d768_l12_h12_gbs512_2x8gpu_50ep_lr4e3_ema0p9999_elfopt_not5_bottleneck128_unfixed_norm_stateprobadd_selfcond_ce_fast_20260610_020108/step_274000.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c31b531b29ff0db0b3591ab0c59df39f169852d207707225ca6372df139f4be6
|
| 3 |
+
size 927700322
|