SunXiang2025 commited on
Commit
25986db
·
verified ·
1 Parent(s): a2ec230

Upload ATCTrack-VLM code and selected checkpoints

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +5 -0
  2. QWEN_STATE_CURRENT_LOGIC.md +264 -0
  3. README.md +167 -0
  4. TRAIN_QWEN_STATE_GUIDE.md +405 -0
  5. VLT_environment_summary.md +223 -0
  6. asset/experiment.png +3 -0
  7. asset/framework.png +3 -0
  8. asset/motivation.png +3 -0
  9. checkpoint/ATCTrack_b.pth.tar +3 -0
  10. experiments/atctrack/atctrack_base.yaml +103 -0
  11. experiments/atctrack/atctrack_large.yaml +79 -0
  12. experiments/atctrack/atctrack_qwen_state.yaml +109 -0
  13. install.sh +108 -0
  14. lib/__init__.py +0 -0
  15. lib/config/__init__.py +0 -0
  16. lib/config/atctrack/config.py +184 -0
  17. lib/models/__init__.py +0 -0
  18. lib/models/aqatrack/__init__.py +1 -0
  19. lib/models/aqatrack/aqatrack.py +196 -0
  20. lib/models/aqatrack/base_backbone.py +142 -0
  21. lib/models/aqatrack/fast_itpn.py +1173 -0
  22. lib/models/aqatrack/hivit.py +270 -0
  23. lib/models/aqatrack/itpn.py +430 -0
  24. lib/models/aqatrack/utils.py +99 -0
  25. lib/models/atctrack/__init__.py +1 -0
  26. lib/models/atctrack/atctrack.py +1051 -0
  27. lib/models/atctrack/decoder.py +331 -0
  28. lib/models/atctrack/encoder.py +100 -0
  29. lib/models/atctrack/language_model.py +320 -0
  30. lib/models/atctrack/utils.py +64 -0
  31. lib/models/atctrack/vit.py +466 -0
  32. lib/models/atctrack/vit_mm.py +575 -0
  33. lib/models/layers/__init__.py +0 -0
  34. lib/models/layers/adapter.py +104 -0
  35. lib/models/layers/attn.py +128 -0
  36. lib/models/layers/attn_adapt_blocks.py +155 -0
  37. lib/models/layers/attn_blocks.py +122 -0
  38. lib/models/layers/dualstream_attn_blocks.py +152 -0
  39. lib/models/layers/frozen_bn.py +40 -0
  40. lib/models/layers/head.py +248 -0
  41. lib/models/layers/max_head.py +280 -0
  42. lib/models/layers/patch_embed.py +32 -0
  43. lib/models/layers/position_encoding.py +154 -0
  44. lib/models/layers/rpe.py +104 -0
  45. lib/models/layers/transformer_dec.py +415 -0
  46. lib/models/transformers/__init__.py +2 -0
  47. lib/models/transformers/position_encoding.py +154 -0
  48. lib/models/transformers/transformer.py +498 -0
  49. lib/models/transformers/transformer_visual.py +385 -0
  50. lib/test/__init__.py +0 -0
.gitattributes CHANGED
@@ -33,3 +33,8 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ asset/experiment.png filter=lfs diff=lfs merge=lfs -text
37
+ asset/framework.png filter=lfs diff=lfs merge=lfs -text
38
+ asset/motivation.png filter=lfs diff=lfs merge=lfs -text
39
+ resource/text_infor/refcoco_4o_v3_extract_mask.json filter=lfs diff=lfs merge=lfs -text
40
+ resource/text_infor/vasttrack_4o_v3_extract_mask.json filter=lfs diff=lfs merge=lfs -text
QWEN_STATE_CURRENT_LOGIC.md ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ATCTrack-VLM Qwen 更新器当前逻辑
2
+
3
+ 本文档按当前代码真实逻辑梳理,重点包括 Qwen 更新器、训练参数、loss、保存方式和具体代码位置。
4
+
5
+ ## 1. Qwen 更新器结构
6
+
7
+ Qwen 更新器类位置:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:70`
8
+
9
+ ```python
10
+ QwenTargetStateEncoder
11
+ ```
12
+
13
+ 初始化逻辑:
14
+
15
+ - 加载 Qwen processor/tokenizer/model:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:98`
16
+ - `padding_side` 设置为 `left`:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:104`
17
+ - 新增 5 个 token:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:107`
18
+
19
+ ```text
20
+ <answer>
21
+ </answer>
22
+ <state_token>
23
+ </state_token>
24
+ <TARGET_STATE>
25
+ ```
26
+
27
+ - Qwen 主体先冻结:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:125`
28
+ - 如果 `USE_LORA: true`,加 LoRA:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:132`
29
+ - `<TARGET_STATE>` embedding 训练方式:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:151`
30
+
31
+ 现在不是外挂一个独立参数,而是训练 Qwen 原始 embedding 表里的 `<TARGET_STATE>` 那一行。通过 grad hook 只保留这一行梯度,其它 token embedding 梯度置 0:
32
+
33
+ ```python
34
+ mask.index_fill_(0, token_ids, 1)
35
+ return grad * mask.view(-1, 1)
36
+ ```
37
+
38
+ ## 2. Qwen 输入和生成流程
39
+
40
+ prompt 位置:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:210`
41
+
42
+ 当前 prompt 里不会直接出现 `<TARGET_STATE>` 字符串,只说生成 special target-state token。
43
+
44
+ forward 流程位置:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:439`
45
+
46
+ ```text
47
+ template[-2] 图片 + bbox
48
+ template[-1] 图片 + bbox
49
+ prompt
50
+ -> processor
51
+ -> Qwen generate 一次
52
+ -> 输出 <answer>yes/no</answer><state_token><TARGET_STATE></state_token>
53
+ ```
54
+
55
+ 具体流程:
56
+
57
+ - 两张图片画 bbox:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:445`
58
+ - 构造 image + text message:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:448`
59
+ - processor 编码图文输入:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:462`
60
+ - Qwen generate:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:464`
61
+
62
+ 生成被限制成两种合法格式之一:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:324`
63
+
64
+ ```text
65
+ <answer>yes</answer><state_token><TARGET_STATE></state_token>
66
+ <answer>no</answer><state_token><TARGET_STATE></state_token>
67
+ ```
68
+
69
+ 限制函数位置:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:348`
70
+
71
+ 核心是 `prefix_allowed_tokens_fn`。
72
+
73
+ ## 3. Token Hidden State 使用方式
74
+
75
+ `<TARGET_STATE>` hidden state 提取位置:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:418`
76
+
77
+ 逻辑:
78
+
79
+ ```text
80
+ 如果生成了 <TARGET_STATE>:
81
+ 取 <TARGET_STATE> 对应 hidden state
82
+ 否则:
83
+ fallback 到最后一个非 pad 生成 token 的 hidden state
84
+ ```
85
+
86
+ 然后:
87
+
88
+ ```text
89
+ h_target -> projector -> z_target
90
+ ```
91
+
92
+ 代码位置:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:479`
93
+
94
+ ```python
95
+ h_target = self._target_hidden_from_generation(...)
96
+ z_target = self.projector(h_target)
97
+ ```
98
+
99
+ `z_target` 注入 tracker 的方式是 FiLM 调制:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:485`
100
+
101
+ ```python
102
+ opt_feat * (1 + gate * gamma) + gate * beta
103
+ ```
104
+
105
+ 实际注入位置在 tracker temporal loop:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:823`
106
+
107
+ ## 4. Template 更新逻辑
108
+
109
+ 训练时用 3 张 template、4 张 search:
110
+
111
+ - template 配置:`ATCTrack-VLM/experiments/atctrack/atctrack_qwen_state.yaml:17`
112
+ - search 配置:`ATCTrack-VLM/experiments/atctrack/atctrack_qwen_state.yaml:7`
113
+
114
+ 采样逻辑位置:`ATCTrack-VLM/lib/train/data/sampler.py:131`
115
+
116
+ ```text
117
+ base_frame_id 作为第一个 template
118
+ prev_frame_ids 随机取前面的 num_template_frames - 1 帧
119
+ template_frame_ids = base_frame_id + prev_frame_ids
120
+ search_frame_ids 从 base_frame_id 之后随机取 4 帧
121
+ ```
122
+
123
+ tracker 使用逻辑位置:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:676`
124
+
125
+ ```text
126
+ template[0]:tracker 固定使用的初始模板
127
+ template[-2]:旧动态模板,给 Qwen 的 Frame 1
128
+ template[-1]:新候选模板,给 Qwen 的 Frame 2
129
+
130
+ Qwen 输出 yes:
131
+ dynamic_template = template[-1]
132
+ Qwen 输出 no:
133
+ dynamic_template = template[-2]
134
+ ```
135
+
136
+ 具体选择位置:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:681`
137
+
138
+ ## 5. Loss 设计
139
+
140
+ loss 位置:`ATCTrack-VLM/lib/train/actors/atctrack.py:101`
141
+
142
+ 主 loss:
143
+
144
+ ```text
145
+ 2.0 * giou_loss
146
+ + 5.0 * l1_loss
147
+ + focal_loss
148
+ + confidence_loss
149
+ + 0.01 * qwen_format_loss
150
+ + 0.1 * qwen_teacher_loss
151
+ ```
152
+
153
+ 代码位置:`ATCTrack-VLM/lib/train/actors/atctrack.py:151`
154
+
155
+ 当前 `TRAIN.TYPE == target_state` 时,原来的 subject index loss 权重被置 0:`ATCTrack-VLM/lib/train/actors/atctrack.py:139`
156
+
157
+ `qwen_format_loss` 是对 Qwen 生成 token 的 CE:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:383`
158
+
159
+ `qwen_teacher_loss` 是 teacher yes/no 监督 loss,teacher 查询逻辑在:`ATCTrack-VLM/lib/models/atctrack/atctrack.py:247`
160
+
161
+ 注意:yaml 里 teacher 默认 false,但脚本里默认 true。
162
+
163
+ ## 6. 可训练参数
164
+
165
+ optimizer 冻结/解冻位置:`ATCTrack-VLM/lib/train/base_functions.py:233`
166
+
167
+ 当前 `target_state` 模式默认可训练:
168
+
169
+ ```text
170
+ target_state_encoder.projector
171
+ target_state_encoder.film
172
+ target_state_encoder.film_gate
173
+ Qwen LoRA 权重,名字包含 lora_
174
+ box_head
175
+ confidence_pred
176
+ Qwen input embedding 表,但 hook 只训练 <TARGET_STATE> 一行
177
+ ```
178
+
179
+ embedding 单独 optimizer group,`weight_decay=0`:`ATCTrack-VLM/lib/train/base_functions.py:271`
180
+
181
+ ## 7. 训练配置
182
+
183
+ 配置文件:`ATCTrack-VLM/experiments/atctrack/atctrack_qwen_state.yaml:1`
184
+
185
+ 关键参数:
186
+
187
+ ```yaml
188
+ MODEL.TARGET_STATE.ENABLE: true
189
+ MODEL.TARGET_STATE.MODEL_PATH: "../Qwen/Qwen3.5-2B"
190
+ MODEL.TARGET_STATE.FREEZE_QWEN: true
191
+ MODEL.TARGET_STATE.TRAIN_TOKEN_EMBEDDING: true
192
+ MODEL.TARGET_STATE.USE_LORA: true
193
+ LORA_R: 8
194
+ LORA_ALPHA: 16
195
+ LORA_DROPOUT: 0.05
196
+
197
+ TRAIN.BATCH_SIZE: 2
198
+ TRAIN.EPOCH: 180
199
+ TRAIN.LR: 0.0001
200
+ TRAIN.WEIGHT_DECAY: 0.0001
201
+ TRAIN.AMP: False
202
+ TRAIN.TYPE: target_state
203
+ ```
204
+
205
+ 训练脚本:`ATCTrack-VLM/scripts/train_qwen_state.sh:1`
206
+
207
+ 路径参数位置:`ATCTrack-VLM/scripts/train_qwen_state.sh:8`
208
+
209
+ ```bash
210
+ GPUS=0,1,2,3
211
+ NPROC_PER_NODE=4
212
+ QWEN_MODEL_PATH=../Qwen/Qwen3.5-2B
213
+ ROBERTA_MODEL_PATH=resource/pretrained_models/roberta-base
214
+ LASOT_DIR=../Dataset/LaSOT/LaSOTBenchmark
215
+ ```
216
+
217
+ 启动命令位置:`ATCTrack-VLM/scripts/train_qwen_state.sh:32`
218
+
219
+ ## 8. 保存方式
220
+
221
+ 轻量保存逻辑位置:`ATCTrack-VLM/lib/train/trainers/base_trainer.py:115`
222
+
223
+ `target_state` 模式保存:
224
+
225
+ ```text
226
+ box_head.*
227
+ confidence_pred.*
228
+ target_state_encoder.projector.*
229
+ target_state_encoder.film.*
230
+ target_state_encoder.film_gate
231
+ 所有 lora_ 权重
232
+ <TARGET_STATE> embedding 那一行
233
+ epoch / stats / settings
234
+ ```
235
+
236
+ 不保存:
237
+
238
+ ```text
239
+ 完整 Qwen base
240
+ 完整 Qwen embedding 表
241
+ 完整 backbone
242
+ 完整 RoBERTa
243
+ optimizer state
244
+ ```
245
+
246
+ 具体保存 state 位置:`ATCTrack-VLM/lib/train/trainers/base_trainer.py:171`
247
+
248
+ 加载轻量 checkpoint 位置:`ATCTrack-VLM/lib/train/trainers/base_trainer.py:268`
249
+
250
+ 加载时会 `strict=False` 加载增量权重,然后单独恢复 `<TARGET_STATE>` embedding 行。
251
+
252
+ 默认保存路径:
253
+
254
+ ```text
255
+ /media/data/WWZ/SX/ATCTrack-VLM/output/checkpoints/train/atctrack/atctrack_qwen_state/ATCTrack_epXXXX.pth.tar
256
+ ```
257
+
258
+ 保存频率:
259
+
260
+ ```text
261
+ 每 5 个 epoch 保存一次
262
+ 最后 10 个 epoch 每个 epoch 保存
263
+ rank 0 保存
264
+ ```
README.md ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ATCTrack: Aligning Target-Context Cues with Dynamic Target States for Robust Vision-Language Tracking
2
+
3
+ > [Xiaokun Feng](https://scholar.google.com.hk/citations?user=NqXtIPIAAAAJ), [Shiyu Hu](https://huuuuusy.github.io/), [Xuchen Li](https://github.com/Xuchen-Li), [Dailing Zhang](https://scholar.google.com.hk/citations?user=ApH4wOcAAAAJ), [Meiqi Wu](https://scholar.google.com.hk/citations?user=fGc7NVAAAAAJ), [Jing Zhang](https://github.com/XiaokunFeng/CSTrack), [Xiaotang Chen](http://www.ia.cas.cn/rcdw/fyjy/202404/t20240422_7129814.html), [Kaiqi Huang](https://people.ucas.ac.cn/~0004554)
4
+
5
+
6
+ [![](https://img.shields.io/badge/ATCTrack-arXiv%20-b31b1b?logo=arxiv&logoColor=red)](https://arxiv.org/abs/2507.19875)
7
+ [![HuggingFace](https://img.shields.io/badge/%F0%9F%A4%97%20ATCTrack-Results&ckpts-red)](https://huggingface.co/Xiaokunfeng2022/ATCTrack)
8
+
9
+ This is an official pytorch implementation of the paper **ATCTrack: Aligning Target-Context Cues with Dynamic Target States for Robust Vision-Language Tracking**.
10
+
11
+
12
+ ### 🔥 Updates
13
+
14
+ * \[8/2025\] **ATCTrack's** code is available!
15
+ * \[6/2025\] **ATCTrack** is accepted by ICCV25 Highlight!
16
+
17
+ ### 📣 Overview
18
+ #### Our motivation & Core modeling approach
19
+
20
+ Vision-language tracking aims to locate the target object in the video sequence using a template patch and a language description provided in the initial frame. To achieve
21
+ robust tracking, especially in complex long-term scenarios that reflect real-world conditions as recently highlighted by
22
+ MGIT, it is essential not only to characterize the target features but also to utilize the context features related to the
23
+ target. However, the visual and textual target-context cues
24
+ derived from the initial prompts generally align only with
25
+ the initial target state. Due to their dynamic nature, target states are constantly changing, particularly in complex
26
+ long-term sequences. It is intractable for these cues to continuously guide Vision-Language Trackers (VLTs). Furthermore, for the text prompts with diverse expressions, our
27
+ experiments reveal that existing VLTs struggle to discern
28
+ which words pertain to the target or the context, complicating the utilization of textual cues.
29
+ ![ATCTrack_motivation](asset/motivation.png)
30
+
31
+ In this work, we present a novel tracker named ATCTrack, which can obtain multimodal cues Aligned with the dynamic target states
32
+ through comprehensive Target-Context feature modeling,
33
+ thereby achieving robust tracking. Specifically, (1) for the
34
+ visual modality, we propose an effective temporal visual
35
+ target-context modeling approach that provides the tracker
36
+ with timely visual cues. (2) For the textual modality, we
37
+ achieve precise target words identification solely based on
38
+ textual content, and design an innovative context words
39
+ calibration method to adaptively utilize auxiliary context
40
+ words. (3) We conduct extensive experiments on mainstream benchmarks and ATCTrack achieves a new SOTA
41
+ performance
42
+ ![ATCTrack_pipeline](asset/framework.png)
43
+
44
+ #### Strong performance
45
+
46
+ ![ATCTrack_experiment](asset/experiment.png)
47
+
48
+
49
+
50
+ ### 🔨 Installation
51
+ ```
52
+ conda create -n atctrack python=3.8
53
+ conda activate atctrack
54
+ bash install.sh
55
+ ```
56
+
57
+ ### 🔧 Usage
58
+
59
+ #### Data Preparation
60
+ Our ATCTrack is trained on LaSOT, TNL2K, RefCOCOg, OTB99-Lang, VastTrack, GOT-10k, and TrackingNet datasets.
61
+ Put these tracking datasets in [./data](data). It should look like:
62
+
63
+ ```
64
+ ${ATCTrack_ROOT}
65
+ -- data
66
+ -- lasot
67
+ |-- airplane
68
+ |-- basketball
69
+ |-- bear
70
+ ...
71
+ -- got10k
72
+ |-- test
73
+ |-- train
74
+ |-- val
75
+ -- coco
76
+ |-- annotations
77
+ |-- images
78
+ -- trackingnet
79
+ |-- TRAIN_0
80
+ |-- TRAIN_1
81
+ ...
82
+ |-- TRAIN_11
83
+ |-- TEST
84
+ -- VastTrack
85
+ |-- unisot_train_final_backup
86
+ |-- Aardwolf
87
+ ...
88
+ |-- Zither
89
+ |-- unisot_final_test
90
+ |-- Aardwolf
91
+ ...
92
+ |-- Zither
93
+ -- tnl2k
94
+ -- train
95
+ |-- Arrow_Video_ZZ04_done
96
+ |-- Assassin_video_1-Done
97
+ |-- Assassin_video_2-Done
98
+ ...
99
+ -- test
100
+ |-- advSamp_Baseball_game_002-Done
101
+ |-- advSamp_Baseball_video_01-Done
102
+ |-- advSamp_Baseball_video_02-Done
103
+ ...
104
+
105
+ ```
106
+
107
+ #### Set project paths
108
+ Run the following command to set paths for this project
109
+ ```
110
+ python tracking/create_default_local_file.py --workspace_dir . --data_dir ./data --save_dir .
111
+ ```
112
+ After running this command, you can also modify paths by editing these two files
113
+ ```
114
+ lib/train/admin/local.py # paths about training
115
+ lib/test/evaluation/local.py # paths about testing
116
+ ```
117
+
118
+ #### Train
119
+ ##### Prepare pretrained backbone
120
+ The backbone and patch embedding of ATCTrack are initialized with pre-trained weights from [**Fast-iTPN**](https://github.com/sunsmarterjie/iTPN), and we adopt RoBERTa-Base as our text encoder.
121
+ Please download the **fast_itpn_base_clipl_e1600.pt**, **fast_itpn_large_1600e_1k.pt** and **roberta-base** checkpoints and place them in [./resource/pretrained_models](./resource/pretrained_models).
122
+
123
+ ##### Train ATCTrack
124
+ You can run the following command to train the ATCTrack-B:
125
+ ```
126
+ python -m torch.distributed.launch --nproc_per_node 3 lib/train/run_training.py --script atctrack --config atctrack_base --save_dir .
127
+ ```
128
+
129
+ Besides, you can run the following command to train the ATCTrack-L:
130
+ ```
131
+ python -m torch.distributed.launch --nproc_per_node 3 lib/train/run_training.py --script atctrack --config atctrack_large --save_dir .
132
+ ```
133
+
134
+ #### Test and evaluate on benchmarks
135
+ First, you need to set the paths for the various evaluation benchmarks in [./lib/test/evaluation/local.py](./lib/test/evaluation/local.py), and prepare the model weights for evaluation.
136
+ Then, run the following command to perform evaluation on different benchmarks (taking atctrack_base as an example).
137
+ - LaSOT
138
+ ```
139
+ python tracking/test.py --tracker_name atctrack --tracker_param atctrack_base --dataset lasot_lang --threads 4 --num_gpus 2 --ckpt_path '{your_dir_saved_model_ckpt}/ATCTrack_b.pth.tar'
140
+ python tracking/analysis_results.py --dataset_name lasot_lang --tracker_param atctrack_base
141
+ ```
142
+ - LaSOT_ext
143
+ ```
144
+ python tracking/test.py --tracker_name atctrack --tracker_param atctrack_base --dataset lasot_extension_subset_lang --threads 4 --num_gpus 2 --ckpt_path '{your_dir_saved_model_ckpt}/ATCTrack_b.pth.tar'
145
+ python tracking/analysis_results.py --dataset_name lasot_extension_subset_lang --tracker_param atctrack_base
146
+ ```
147
+
148
+ - TNL2K
149
+ ```
150
+ python tracking/test.py --tracker_name atctrack --tracker_param atctrack_base --dataset tnl2k --threads 4 --num_gpus 2 --ckpt_path '{your_dir_saved_model_ckpt}/ATCTrack_b.pth.tar'
151
+ python tracking/analysis_results.py --dataset_name lasot_extension_subset_lang --tracker_param atctrack_base
152
+ ```
153
+
154
+ - MGIT
155
+
156
+ Please refer to the [official MGIT testing platform](http://videocube.aitestunion.com/) and [tools](https://github.com/huuuuusy/videocube-toolkit) to complete the corresponding evaluation.
157
+
158
+ ### 📊 Model Zoo
159
+ The trained models, and the raw tracking results are provided in the [![HuggingFace](https://img.shields.io/badge/%F0%9F%A4%97%20ATCTrack-Results&ckpts-red)](https://huggingface.co/Xiaokunfeng2022/ATCTrack).
160
+
161
+
162
+ ### ❤️Acknowledgement
163
+ We would like to express our gratitude to the following open-source repositories that our work is based on: [SeqtrackV2](https://github.com/chenxin-dlut/SeqTrackv2), [AQATrack](https://github.com/GXNU-ZhongLab/AQATrack), [Fast-iTPN](https://github.com/sunsmarterjie/iTPN).
164
+ Their contributions have been invaluable to this project.
165
+
166
+
167
+
TRAIN_QWEN_STATE_GUIDE.md ADDED
@@ -0,0 +1,405 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ATCTrack-VLM Qwen Target-State 训练指南
2
+
3
+ 本文档说明如何在当前 ATCTrack-VLM 代码中运行 Qwen target-state 更新器训练,以及迁移到其他服务器时需要检查的路径、参数和保存方式。内容已按当前代码实现同步。
4
+
5
+ ## 1. 当前训练做什么
6
+
7
+ 当前方法以 ATCTrack 为 baseline,新增一个基于 Qwen 的 target-state 更新器。
8
+
9
+ 和原始 ATCTrack 的主要区别:
10
+
11
+ - 每个训练样本使用 3 张 template 和 4 张 search。
12
+ - tracker 始终使用 `template[0]` 作为静态模板。
13
+ - Qwen 比较 `template[-2]` 和 `template[-1]`,两张图都会裁剪到 template size,并画上 bbox。
14
+ - Qwen 输入原始 prompt 和两张图,训练/推理时都只 `generate` 一次。
15
+ - Qwen 输出被约束为两种合法格式之一:
16
+
17
+ ```text
18
+ <answer>yes</answer><state_token><TARGET_STATE></state_token>
19
+ <answer>no</answer><state_token><TARGET_STATE></state_token>
20
+ ```
21
+
22
+ - 如果 Qwen 输出 `yes`,tracker 使用 `template[-1]` 作为动态模板。
23
+ - 如果 Qwen 输出 `no`,tracker 使用 `template[-2]` 作为动态模板。
24
+ - 提取 `<TARGET_STATE>` 对应 hidden state,经过 projector 映射到 tracker 维度,再通过 FiLM 调制 tracker feature。
25
+ - 可选 teacher 模型输出 `<answer>yes/no</answer>`,用于监督当前 Qwen 更新器的 yes/no 判断。
26
+
27
+ ## 2. 推荐目录结构
28
+
29
+ 默认脚本假设目录结构如下:
30
+
31
+ ```text
32
+ parent_dir/
33
+ ATCTrack-VLM/
34
+ Qwen/
35
+ Qwen3.5-2B/
36
+ Dataset/
37
+ LaSOT/
38
+ LaSOTBenchmark/
39
+ ```
40
+
41
+ 如果目录不同,可以用环境变量覆盖路径。
42
+
43
+ 必需文件:
44
+
45
+ - ATCTrack checkpoint:`ATCTrack-VLM/checkpoint/ATCTrack_b.pth.tar`
46
+ - backbone 预训练文件:`ATCTrack-VLM/resource/pretrained_models/fast_itpn_base_clipl_e1600.pt`
47
+ - RoBERTa:`ATCTrack-VLM/resource/pretrained_models/roberta-base`
48
+ - Qwen 更新器:默认 `ATCTrack-VLM/../Qwen/Qwen3.5-2B`
49
+ - LaSOT:默认 `ATCTrack-VLM/../Dataset/LaSOT/LaSOTBenchmark`
50
+
51
+ ## 3. 训练脚本和环境变量
52
+
53
+ 主训练脚本:
54
+
55
+ ```bash
56
+ scripts/train_qwen_state.sh
57
+ ```
58
+
59
+ 脚本会自动根据自身位置推导 `PROJECT_DIR`,所以项目移动到其他服务器后通常不需要改脚本,只需要保证相对目录或环境变量正确。
60
+
61
+ 当前脚本里的关键变量:
62
+
63
+ ```bash
64
+ PROJECT_DIR=/path/to/ATCTrack-VLM
65
+ PYTHON_BIN=python
66
+ GPUS=0,1,2,3
67
+ NPROC_PER_NODE=4
68
+ MASTER_PORT=29501
69
+ SAVE_DIR=/path/to/output
70
+ SEED=0
71
+ CONFIG=atctrack_qwen_state
72
+
73
+ QWEN_MODEL_PATH=/path/to/Qwen/Qwen3.5-2B
74
+ ROBERTA_MODEL_PATH=/path/to/ATCTrack-VLM/resource/pretrained_models/roberta-base
75
+ LASOT_DIR=/path/to/LaSOT/LaSOTBenchmark
76
+
77
+ QWEN_TEACHER_ENABLE=true
78
+ QWEN_TEACHER_MODEL=qwen3.5
79
+ QWEN_TEACHER_BASE_URL=http://127.0.0.1:8001/v1
80
+ QWEN_TEACHER_API_KEY=sk-no-key-required
81
+ ```
82
+
83
+ 注意:虽然 yaml 里 `MODEL.TARGET_STATE.TEACHER_ENABLE: false`,但脚本默认:
84
+
85
+ ```bash
86
+ QWEN_TEACHER_ENABLE=true
87
+ ```
88
+
89
+ 代码优先读取环境变量,所以直接运行脚本会调用 teacher。如果不想调用 teacher,使用:
90
+
91
+ ```bash
92
+ QWEN_TEACHER_ENABLE=false bash scripts/train_qwen_state.sh
93
+ ```
94
+
95
+ 数据集路径也可以用环境变量覆盖:
96
+
97
+ ```bash
98
+ DATASET_ROOT=/path/to/Dataset
99
+ LASOT_DIR=/path/to/LaSOT/LaSOTBenchmark
100
+ ```
101
+
102
+ ## 4. Teacher 服务
103
+
104
+ 如果 `QWEN_TEACHER_ENABLE=true`,训练会调用 OpenAI-compatible API 作为 teacher,生成 yes/no 标签。
105
+
106
+ teacher prompt:
107
+
108
+ ```text
109
+ Role: [OBJECT] tracking update judge.
110
+ Task: Compare the targets inside the provided bboxes in Frame 1 (Original) and Frame 2 (New), and decide whether Frame 2 should update the tracking template.
111
+
112
+ Reject update for full occlusion, out of view, too small target, severe blur/clipping, wrong bbox, distractor, uncertain identity, or no meaningful target appearance change.
113
+ Accept only if Frame 2 is the same target, bbox is reliable, target is clear, and appearance change is useful.
114
+
115
+ Output exactly: <answer>yes/no</answer>
116
+ ```
117
+
118
+ vLLM 服务示例:
119
+
120
+ ```bash
121
+ python -m vllm.entrypoints.openai.api_server \
122
+ --model /path/to/Qwen/Qwen3.5-2B \
123
+ --served-model-name qwen3.5 \
124
+ --port 8001 \
125
+ --tensor-parallel-size 4 \
126
+ --trust-remote-code \
127
+ --dtype bfloat16 \
128
+ --gpu-memory-utilization 0.4 \
129
+ --max-model-len 40000 \
130
+ --enforce-eager
131
+ ```
132
+
133
+ 建议不要把 teacher 服务和 4-rank DDP 训练放在同一组 24GB GPU 上。之前测试中 teacher 服务和训练共享 GPU 时显存非常接近 3090 上限。
134
+
135
+ 如果没有 teacher 服务,先关闭 teacher:
136
+
137
+ ```bash
138
+ QWEN_TEACHER_ENABLE=false bash scripts/train_qwen_state.sh
139
+ ```
140
+
141
+ ## 5. 启动训练
142
+
143
+ 先激活环境:
144
+
145
+ ```bash
146
+ conda activate VLT
147
+ cd /path/to/ATCTrack-VLM
148
+ bash scripts/train_qwen_state.sh
149
+ ```
150
+
151
+ 迁移到其他服务器时,推荐显式覆盖路径:
152
+
153
+ ```bash
154
+ PROJECT_DIR=/path/to/ATCTrack-VLM \
155
+ QWEN_MODEL_PATH=/path/to/Qwen/Qwen3.5-2B \
156
+ ROBERTA_MODEL_PATH=/path/to/ATCTrack-VLM/resource/pretrained_models/roberta-base \
157
+ LASOT_DIR=/path/to/LaSOT/LaSOTBenchmark \
158
+ SAVE_DIR=/path/to/output \
159
+ GPUS=0,1,2,3 \
160
+ NPROC_PER_NODE=4 \
161
+ QWEN_TEACHER_ENABLE=false \
162
+ bash scripts/train_qwen_state.sh
163
+ ```
164
+
165
+ 单卡 smoke test:
166
+
167
+ ```bash
168
+ GPUS=0 NPROC_PER_NODE=1 QWEN_TEACHER_ENABLE=false bash scripts/train_qwen_state.sh
169
+ ```
170
+
171
+ ## 6. 当前可训练和冻结模块
172
+
173
+ 当前 `TRAIN.TYPE: target_state` 时,可训练部分为:
174
+
175
+ - ATCTrack `box_head`
176
+ - ATCTrack `confidence_pred`
177
+ - Qwen LoRA 权重,参数名中包含 `lora_`
178
+ - `target_state_encoder.projector`
179
+ - `target_state_encoder.film`
180
+ - `target_state_encoder.film_gate`
181
+ - Qwen 原始 input embedding 表里的 `<TARGET_STATE>` 那一行
182
+
183
+ `<TARGET_STATE>` embedding 不是独立外挂参数。当前做法是打开 Qwen 原始 embedding 表的梯度,然后通过 grad hook 只保留 `<TARGET_STATE>` 对应 token id 那一行梯度,其它 token embedding 梯度置 0。
184
+
185
+ embedding 参数被单独放到 optimizer group,并设置:
186
+
187
+ ```text
188
+ weight_decay = 0.0
189
+ ```
190
+
191
+ 这样可以避免 AdamW 的 decoupled weight decay 改动整张 embedding 表。
192
+
193
+ 冻结部分:
194
+
195
+ - Qwen base 参数,除了 LoRA 和 `<TARGET_STATE>` embedding 行。
196
+ - ATCTrack backbone/encoder。
197
+ - RoBERTa text encoder。
198
+ - 其它不在 target_state 可训练关键词里的模块。
199
+
200
+ ## 7. Loss 设计
201
+
202
+ 主 loss:
203
+
204
+ ```text
205
+ L = 2.0 * GIoU
206
+ + 5.0 * L1
207
+ + focal/location
208
+ + confidence
209
+ + QWEN_FORMAT_WEIGHT * qwen_format_loss
210
+ + QWEN_TEACHER_WEIGHT * qwen_teacher_loss
211
+ ```
212
+
213
+ 当前配置:
214
+
215
+ ```yaml
216
+ QWEN_FORMAT_WEIGHT: 0.01
217
+ QWEN_TEACHER_WEIGHT: 0.1
218
+ ```
219
+
220
+ 说明:
221
+
222
+ - `qwen_format_loss` 是基于 Qwen `generate` 返回的 scores,对实际生成的固定格式 token 计算 CE。由于输出受到 `prefix_allowed_tokens_fn` 约束,它主要是格式生成置信度约束,不代表格式一定错。
223
+ - `qwen_teacher_loss` 使用 teacher yes/no 标签监督当前 Qwen 在 yes/no token 位置的判断。
224
+ - 当 teacher 关闭或 teacher 返回无效时,`qwen_teacher_loss = 0`。
225
+ - `TRAIN.TYPE == target_state` 时,原 subject index loss 权重为 0。
226
+
227
+ ## 8. 当前训练配置
228
+
229
+ 配置文件:
230
+
231
+ ```text
232
+ experiments/atctrack/atctrack_qwen_state.yaml
233
+ ```
234
+
235
+ 关键配置:
236
+
237
+ ```yaml
238
+ DATA:
239
+ TEMPLATE:
240
+ NUMBER: 3
241
+ SIZE: 128
242
+ SEARCH:
243
+ NUMBER: 4
244
+ SIZE: 256
245
+ TRAIN:
246
+ DATASETS_NAME:
247
+ - LASOT
248
+ DATASETS_RATIO:
249
+ - 1
250
+ SAMPLE_PER_EPOCH: 25000
251
+
252
+ MODEL:
253
+ PRETRAIN_FILE: "fast_itpn_base_clipl_e1600.pt"
254
+ PRETRAINED_PATH: "checkpoint/ATCTrack_b.pth.tar"
255
+ TARGET_STATE:
256
+ ENABLE: true
257
+ MODEL_PATH: "../Qwen/Qwen3.5-2B"
258
+ TOKEN: "<TARGET_STATE>"
259
+ FREEZE_QWEN: true
260
+ TRAIN_TOKEN_EMBEDDING: true
261
+ USE_LORA: true
262
+ LORA_R: 8
263
+ LORA_ALPHA: 16
264
+ LORA_DROPOUT: 0.05
265
+ TEACHER_ENABLE: false
266
+
267
+ TRAIN:
268
+ BATCH_SIZE: 2
269
+ EPOCH: 180
270
+ LR: 0.0001
271
+ LR_DROP_EPOCH: 144
272
+ WEIGHT_DECAY: 0.0001
273
+ GRAD_CLIP_NORM: 0.1
274
+ AMP: False
275
+ TYPE: target_state
276
+ ```
277
+
278
+ 注意:teacher 是否开启以环境变量 `QWEN_TEACHER_ENABLE` 为准。脚本默认是 true。
279
+
280
+ ## 9. 显存记录
281
+
282
+ 最近一次 2B、单进程、batch size 2、关闭 teacher 的完整 forward/backward/optimizer step 测试结果:
283
+
284
+ ```text
285
+ 结果目录:temp-result/qwen35_2b_train_memory_after_target_embedding_20260608_121711
286
+
287
+ after_model_to_cuda: 5549 MiB
288
+ after_forward_loss: 13405 MiB
289
+ after_backward: 16357 MiB
290
+ after_optimizer_step: 17329 MiB
291
+
292
+ torch max allocated: 15572.61 MiB
293
+ ```
294
+
295
+ 因此在 3090 24GB 上,2B + batch size 2 + 无 teacher 的单进程训练大约需要 16 到 17GB 常驻显存。
296
+
297
+ 如果启用 teacher,尤其 teacher 服务也占用同一张 GPU,显存会明显增加。DDP 训练时每个 rank 都会有一份训练模型,并且每个 rank 都可能调用 teacher API。
298
+
299
+ 建议:
300
+
301
+ - 先用 `QWEN_TEACHER_ENABLE=false` 做 smoke test。
302
+ - teacher 服务尽量放到单独 GPU 或单独机器。
303
+ - 9B 不适合普通 DDP 复制到 24GB GPU 上训练,除非使用模型并行、FSDP、DeepSpeed 或外部推理服务。
304
+
305
+ ## 10. 轻量保存和恢复
306
+
307
+ 当前 target_state 模式使用轻量 checkpoint 保存。
308
+
309
+ 保存位置:
310
+
311
+ ```text
312
+ output/checkpoints/train/atctrack/atctrack_qwen_state/ATCTrack_epXXXX.pth.tar
313
+ ```
314
+
315
+ 保存频率:
316
+
317
+ ```text
318
+ 每 5 个 epoch 保存一次
319
+ 最后 10 个 epoch 每个 epoch 保存
320
+ rank 0 保存
321
+ ```
322
+
323
+ 轻量 checkpoint 保存内容:
324
+
325
+ ```text
326
+ box_head.*
327
+ confidence_pred.*
328
+ target_state_encoder.projector.*
329
+ target_state_encoder.film.*
330
+ target_state_encoder.film_gate
331
+ 所有 lora_ 权重
332
+ <TARGET_STATE> embedding 那一行
333
+ epoch / stats / settings
334
+ ```
335
+
336
+ 不保存:
337
+
338
+ ```text
339
+ 完整 Qwen base
340
+ 完整 Qwen embedding 表
341
+ 完整 backbone
342
+ 完整 RoBERTa
343
+ optimizer state
344
+ ```
345
+
346
+ 可以加载轻量 checkpoint 继续训练。加载时会:
347
+
348
+ ```text
349
+ 1. strict=False 加载轻量 net 权重
350
+ 2. 单独恢复 <TARGET_STATE> embedding 那一行
351
+ 3. 恢复 epoch 和 stats
352
+ ```
353
+
354
+ 注意:轻量 checkpoint 不保存 optimizer state,所以继续训练时 AdamW 动量不会恢复。这是为了减小 checkpoint 体积的取舍。
355
+
356
+ ## 11. 迁移路径检查
357
+
358
+ 生产训练路径���经做了相对路径和环境变量兼容:
359
+
360
+ - `scripts/train_qwen_state.sh` 会根据脚本位置推导 `PROJECT_DIR`。
361
+ - `QWEN_MODEL_PATH`、`ROBERTA_MODEL_PATH`、`LASOT_DIR`、teacher URL/model/key 都可以用环境变量覆盖。
362
+ - `lib/train/admin/local.py` 使用 `DATASET_ROOT` 和各数据集环境变量。
363
+ - `lib/test/evaluation/local.py` 也使用环境变量。
364
+
365
+ 之前扫描到的绝对路径主要在非当前训练入口文件里:
366
+
367
+ - `lib/train/run_training_debug_version.py`
368
+ - `lib/utils/gen_fname_list.py`
369
+ - `lib/utils/write_to_lmdb.py`
370
+ - VideoCube 相关 test 代码
371
+ - `temp-result` 下的调试脚本
372
+
373
+ 这些不会被 `scripts/train_qwen_state.sh` 调用。只有使用这些工具或 VideoCube 评测时才需要另外修改。
374
+
375
+ ## 12. 新服务器训练前检查清单
376
+
377
+ 1. 检查 Python 环境:
378
+
379
+ ```bash
380
+ python -c "import torch, transformers, peft, openai; print(torch.__version__)"
381
+ ```
382
+
383
+ 2. 检查关键文件:
384
+
385
+ ```bash
386
+ ls checkpoint/ATCTrack_b.pth.tar
387
+ ls resource/pretrained_models/fast_itpn_base_clipl_e1600.pt
388
+ ls resource/pretrained_models/roberta-base
389
+ ls "$QWEN_MODEL_PATH"
390
+ ls "$LASOT_DIR"
391
+ ```
392
+
393
+ 3. 如果开启 teacher,检查 API:
394
+
395
+ ```bash
396
+ curl http://127.0.0.1:8001/v1/models
397
+ ```
398
+
399
+ 4. 先跑单卡 smoke test:
400
+
401
+ ```bash
402
+ GPUS=0 NPROC_PER_NODE=1 QWEN_TEACHER_ENABLE=false bash scripts/train_qwen_state.sh
403
+ ```
404
+
405
+ 5. smoke test 正常后,再按目标 GPU 数量和 teacher 设置启动完整训练。
VLT_environment_summary.md ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # VLT 虚拟环境迁移说明
2
+
3
+ 本文档总结当前机器上的 `VLT` conda 环境,用于在另一台电脑上重新配置相近环境。
4
+
5
+ ## 1. 当前环境概况
6
+
7
+ - 环境名:`VLT`
8
+ - Python:`3.11.14`
9
+ - PyTorch:`2.10.0+cu128`
10
+ - torchvision:`0.25.0+cu128`
11
+ - torchaudio:`2.10.0`
12
+ - torchdata:`0.11.0`
13
+ - PyTorch CUDA runtime:`12.8`
14
+ - cuDNN:`9.10.2`
15
+ - NCCL:`2.27.5`
16
+ - 当前机器 NVIDIA Driver:`560.35.05`
17
+ - 当前机器 CUDA Driver API:`12.6`
18
+
19
+ 注意:这个环境里的 PyTorch 是 CUDA 12.8 wheel。新机器的 NVIDIA 驱动需要足够新,建议使用 `560+` 或更新版本。
20
+
21
+ ## 2. 推荐创建方式
22
+
23
+ 建议先创建干净 conda 环境,再用 pip 安装核心依赖:
24
+
25
+ ```bash
26
+ conda create -n VLT python=3.11.14 pip -y
27
+ conda activate VLT
28
+ ```
29
+
30
+ 安装 PyTorch CUDA 12.8 版本:
31
+
32
+ ```bash
33
+ pip install torch==2.10.0 torchvision==0.25.0 torchaudio==2.10.0 --index-url https://download.pytorch.org/whl/cu128
34
+ ```
35
+
36
+ 然后安装视觉跟踪、VLM、训练相关依赖:
37
+
38
+ ```bash
39
+ pip install \
40
+ timm==1.0.25 \
41
+ numpy==2.3.5 \
42
+ opencv-python==4.13.0.92 \
43
+ opencv-python-headless==4.13.0.92 \
44
+ pillow==11.3.0 \
45
+ scipy==1.17.0 \
46
+ scikit-image==0.26.0 \
47
+ pandas==2.3.3 \
48
+ matplotlib==3.10.8 \
49
+ pycocotools==2.0.11 \
50
+ lmdb==1.8.1 \
51
+ easydict==1.13 \
52
+ omegaconf==2.3.0 \
53
+ einops==0.8.2 \
54
+ tqdm==4.67.1 \
55
+ visdom==0.2.4 \
56
+ tensorboard==2.20.0 \
57
+ tensorboardX==2.6.4 \
58
+ nltk==3.9.4 \
59
+ openai==2.29.0 \
60
+ transformers==5.10.2 \
61
+ accelerate==1.11.0 \
62
+ datasets==4.0.0 \
63
+ peft==0.18.0 \
64
+ trl==0.24.0 \
65
+ deepspeed==0.18.4 \
66
+ gradio==5.50.0 \
67
+ fastapi==0.128.0 \
68
+ uvicorn==0.40.0 \
69
+ modelscope==1.34.0
70
+ ```
71
+
72
+ 安装 OpenMMLab 相关包:
73
+
74
+ ```bash
75
+ pip install mmengine==0.10.7 mmdet==3.3.0 mmcv==2.1.0
76
+ ```
77
+
78
+ 如果 `mmcv` 安装失败,优先根据新机器的 PyTorch/CUDA 版本选择 OpenMMLab 官方预编译 wheel;不要盲目源码编译。
79
+
80
+ ## 3. 当前环境中的关键包版本
81
+
82
+ ### 跟踪/视觉相关
83
+
84
+ ```text
85
+ timm 1.0.25
86
+ opencv-python 4.13.0.92
87
+ opencv-python-headless 4.13.0.92
88
+ Pillow 11.3.0
89
+ numpy 2.3.5
90
+ scipy 1.17.0
91
+ scikit-image 0.26.0
92
+ pycocotools 2.0.11
93
+ lmdb 1.8.1
94
+ easydict 1.13
95
+ omegaconf 2.3.0
96
+ einops 0.8.2
97
+ visdom 0.2.4
98
+ ```
99
+
100
+ ### PyTorch/CUDA 相关
101
+
102
+ ```text
103
+ torch 2.10.0+cu128
104
+ torchvision 0.25.0+cu128
105
+ torchaudio 2.10.0
106
+ torchdata 0.11.0
107
+ triton 3.6.0
108
+ nvidia-cublas-cu12 12.8.4.1
109
+ nvidia-cudnn-cu12 9.10.2.21
110
+ nvidia-nccl-cu12 2.27.5
111
+ ```
112
+
113
+ ### MLLM/VLM/API 相关
114
+
115
+ ```text
116
+ openai 2.29.0
117
+ transformers 5.10.2
118
+ tokenizers 0.22.2
119
+ accelerate 1.11.0
120
+ datasets 4.0.0
121
+ peft 0.18.0
122
+ trl 0.24.0
123
+ deepspeed 0.18.4
124
+ sentencepiece 0.2.1
125
+ tiktoken 0.12.0
126
+ modelscope 1.34.0
127
+ gradio 5.50.0
128
+ fastapi 0.128.0
129
+ uvicorn 0.40.0
130
+ ```
131
+
132
+ ### OpenMMLab 相关
133
+
134
+ ```text
135
+ mmcv 2.1.0
136
+ mmdet 3.3.0
137
+ mmengine 0.10.7
138
+ ```
139
+
140
+ ## 4. 本地 editable 包
141
+
142
+ 当前环境里有一个本地 editable 安装:
143
+
144
+ ```text
145
+ llamafactory 0.9.5.dev0 -> /media/data/WWZ/SX/LlamaFactory
146
+ ```
147
+
148
+ 如果新机器也需要跑 LLaMA-Factory 相关训练或推理,需要把该仓库同步过去后执行:
149
+
150
+ ```bash
151
+ cd /path/to/LlamaFactory
152
+ pip install -e .
153
+ ```
154
+
155
+ 如果只跑 ATCTrack/SUTrack/CTVLT 等跟踪测试,不一定需要这个 editable 包。
156
+
157
+ ## 5. NLTK 数据
158
+
159
+ 部分代码会下载:
160
+
161
+ ```text
162
+ punkt
163
+ averaged_perceptron_tagger
164
+ ```
165
+
166
+ 如果新机器无法联网,可以从旧机器的 `~/nltk_data` 拷贝到新机器同路径,或手动设置:
167
+
168
+ ```bash
169
+ export NLTK_DATA=/path/to/nltk_data
170
+ ```
171
+
172
+ ## 6. 代理设置
173
+
174
+ 如果新机器访问 HuggingFace、PyPI 或 OpenAI-compatible API 需要代理,可以写入 shell 配置:
175
+
176
+ ```bash
177
+ export HTTP_PROXY=http://127.0.0.1:7890
178
+ export HTTPS_PROXY=http://127.0.0.1:7890
179
+ export ALL_PROXY=http://127.0.0.1:7890
180
+ ```
181
+
182
+ ## 7. 验证命令
183
+
184
+ 环境配置完成后,先验证 PyTorch/CUDA:
185
+
186
+ ```bash
187
+ python - <<'PY'
188
+ import torch, torchvision
189
+ print("torch:", torch.__version__)
190
+ print("torchvision:", torchvision.__version__)
191
+ print("cuda available:", torch.cuda.is_available())
192
+ print("torch cuda:", torch.version.cuda)
193
+ print("cudnn:", torch.backends.cudnn.version())
194
+ if torch.cuda.is_available():
195
+ print("gpu:", torch.cuda.get_device_name(0))
196
+ PY
197
+ ```
198
+
199
+ 验证跟踪常用依赖:
200
+
201
+ ```bash
202
+ python - <<'PY'
203
+ import cv2, timm, numpy, pandas, mmcv, mmdet, mmengine
204
+ import transformers, openai
205
+ print("basic imports ok")
206
+ PY
207
+ ```
208
+
209
+ ## 8. 复现���整环境的备选方式
210
+
211
+ 如果希望尽量完整复刻当前环境,可以在旧机器导出:
212
+
213
+ ```bash
214
+ conda env export -n VLT --no-builds > vlt_environment.yml
215
+ ```
216
+
217
+ 在新机器创建:
218
+
219
+ ```bash
220
+ conda env create -f vlt_environment.yml
221
+ ```
222
+
223
+ 但这种方式可能因为 CUDA wheel、OpenMMLab wheel、镜像源或本地 editable 包路径不同而失败。实际迁移时更推荐按本文第 2 节分组安装。
asset/experiment.png ADDED

Git LFS Details

  • SHA256: d9d8ff1434bb0880e3ea81b10c01b07fc97f7ea9769cd83541357360cbc7ccb3
  • Pointer size: 131 Bytes
  • Size of remote file: 238 kB
asset/framework.png ADDED

Git LFS Details

  • SHA256: a310851d54897c52d510829bf3d52b4cf12a69132817c7ccfb36a30c7ccaef09
  • Pointer size: 131 Bytes
  • Size of remote file: 669 kB
asset/motivation.png ADDED

Git LFS Details

  • SHA256: eac09aa20d3d77dbe53c5e9f1ca8d9151579fb1fa223b563f45737aed2bfff0a
  • Pointer size: 132 Bytes
  • Size of remote file: 1.28 MB
checkpoint/ATCTrack_b.pth.tar ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c01b720243b03216554dd8c41bcd9f14136cee14847929bcfe94a32b6aa7f00e
3
+ size 1703949574
experiments/atctrack/atctrack_base.yaml ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ DATA:
2
+ MAX_SAMPLE_INTERVAL: 400
3
+ MEAN:
4
+ - 0.485
5
+ - 0.456
6
+ - 0.406
7
+ SEARCH:
8
+ CENTER_JITTER: 3.5
9
+ FACTOR: 4.0
10
+ SCALE_JITTER: 0.5
11
+ SIZE: 256
12
+ NUMBER: 4 # 6
13
+ STD:
14
+ - 0.229
15
+ - 0.224
16
+ - 0.225
17
+ TEMPLATE:
18
+ CENTER_JITTER: 0
19
+ FACTOR: 2.0
20
+ SCALE_JITTER: 0
21
+ SIZE: 128
22
+ NUMBER: 2
23
+ TRAIN:
24
+ DATASETS_NAME:
25
+ - LASOT
26
+ # - GOT10K_vottrain
27
+ # - TRACKINGNET
28
+ # - VastTrack
29
+ # - TNL2K_train
30
+ # - RefCOCO14 # RefCOCO14,COCO17
31
+ # - OTB99_train
32
+ DATASETS_RATIO:
33
+ # - 6
34
+ # - 6
35
+ # - 6
36
+ # - 6
37
+ # - 6
38
+ # - 6
39
+ - 1
40
+ SAMPLE_PER_EPOCH: 25000
41
+ MODEL:
42
+ PRETRAIN_FILE: "fast_itpn_base_clipl_e1600.pt" # for backbone
43
+ PRETRAINED_PATH: "checkpoint/ATCTrack_b.pth.tar"
44
+ TARGET_STATE:
45
+ ENABLE: true
46
+ MODEL_PATH: "../Qwen/Qwen3.5-4B"
47
+ TOKEN: "<TARGET_STATE>"
48
+ FREEZE_QWEN: true
49
+ TRAIN_TOKEN_EMBEDDING: true
50
+ USE_LORA: true
51
+ LORA_R: 8
52
+ LORA_ALPHA: 16
53
+ LORA_DROPOUT: 0.05
54
+ LORA_TARGET_MODULES:
55
+ - in_proj_qkv
56
+ - out_proj
57
+ - in_proj_z
58
+ - in_proj_b
59
+ - in_proj_a
60
+ - q_proj
61
+ - k_proj
62
+ - v_proj
63
+ - o_proj
64
+ - gate_proj
65
+ - up_proj
66
+ - down_proj
67
+ BACKBONE:
68
+ TYPE: itpn_base
69
+ STRIDE: 16
70
+ HEAD:
71
+ TYPE: CENTER
72
+ NUM_CHANNELS: 256
73
+ HIDDEN_DIM: 512
74
+ TRAIN:
75
+ BACKBONE_MULTIPLIER: 0.1
76
+ DROP_PATH_RATE: 0.1
77
+ BATCH_SIZE: 1
78
+ EPOCH: 180
79
+ GIOU_WEIGHT: 2.0
80
+ L1_WEIGHT: 5.0
81
+ GRAD_CLIP_NORM: 0.1
82
+ LR: 0.0001
83
+ LR_DROP_EPOCH: 144 # 4/5(0.8)
84
+ NUM_WORKER: 8
85
+ OPTIMIZER: ADAMW
86
+ PRINT_INTERVAL: 50
87
+ SCHEDULER:
88
+ TYPE: step
89
+ DECAY_RATE: 0.1
90
+ WEIGHT_DECAY: 0.0001
91
+ AMP: False
92
+ FIX_BN: true
93
+ TYPE: target_state # train target-state projector/gate and tracker head
94
+
95
+ TEST:
96
+ EPOCH: 240
97
+ SEARCH_FACTOR: 4.0
98
+ SEARCH_SIZE: 256
99
+ TEMPLATE_FACTOR: 2.0
100
+ TEMPLATE_SIZE: 128
101
+ WINDOW: true
102
+ NUM_TEMPLATES: 2
103
+
experiments/atctrack/atctrack_large.yaml ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ DATA:
2
+ MAX_SAMPLE_INTERVAL: 400
3
+ MEAN:
4
+ - 0.485
5
+ - 0.456
6
+ - 0.406
7
+ SEARCH:
8
+ CENTER_JITTER: 3.5
9
+ FACTOR: 4.0
10
+ SCALE_JITTER: 0.5
11
+ SIZE: 256
12
+ NUMBER: 4 # 6
13
+ STD:
14
+ - 0.229
15
+ - 0.224
16
+ - 0.225
17
+ TEMPLATE:
18
+ CENTER_JITTER: 0
19
+ FACTOR: 2.0
20
+ SCALE_JITTER: 0
21
+ SIZE: 128
22
+ NUMBER: 2
23
+ TRAIN:
24
+ DATASETS_NAME:
25
+ - LASOT
26
+ - GOT10K_vottrain
27
+ - TRACKINGNET
28
+ - VastTrack
29
+ - TNL2K_train
30
+ - RefCOCO14 # RefCOCO14,COCO17
31
+ - OTB99_train
32
+ DATASETS_RATIO:
33
+ - 6
34
+ - 6
35
+ - 6
36
+ - 6
37
+ - 6
38
+ - 6
39
+ - 1
40
+ SAMPLE_PER_EPOCH: 25000
41
+ MODEL:
42
+ PRETRAIN_FILE: "fast_itpn_large_1600e_1k.pt" # "fast_itpn_base_clipl_e1600.pt" # for backbone
43
+ PRETRAINED_PATH: ""
44
+ BACKBONE:
45
+ TYPE: itpn_large
46
+ STRIDE: 16
47
+ HEAD:
48
+ TYPE: CENTER
49
+ NUM_CHANNELS: 256
50
+ HIDDEN_DIM: 512
51
+ TRAIN:
52
+ BACKBONE_MULTIPLIER: 0.1
53
+ DROP_PATH_RATE: 0.1
54
+ BATCH_SIZE: 5
55
+ EPOCH: 150
56
+ GIOU_WEIGHT: 2.0
57
+ L1_WEIGHT: 5.0
58
+ GRAD_CLIP_NORM: 0.1
59
+ LR: 0.0001
60
+ LR_DROP_EPOCH: 120 # 4/5(0.8)
61
+ NUM_WORKER: 8
62
+ OPTIMIZER: ADAMW
63
+ PRINT_INTERVAL: 50
64
+ SCHEDULER:
65
+ TYPE: step
66
+ DECAY_RATE: 0.1
67
+ WEIGHT_DECAY: 0.0001
68
+ AMP: False
69
+ FIX_BN: true
70
+
71
+ TEST:
72
+ EPOCH: 240
73
+ SEARCH_FACTOR: 4.0
74
+ SEARCH_SIZE: 256
75
+ TEMPLATE_FACTOR: 2.0
76
+ TEMPLATE_SIZE: 128
77
+ WINDOW: true
78
+ NUM_TEMPLATES: 2
79
+
experiments/atctrack/atctrack_qwen_state.yaml ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ DATA:
2
+ MAX_SAMPLE_INTERVAL: 400
3
+ MEAN:
4
+ - 0.485
5
+ - 0.456
6
+ - 0.406
7
+ SEARCH:
8
+ CENTER_JITTER: 3.5
9
+ FACTOR: 4.0
10
+ SCALE_JITTER: 0.5
11
+ SIZE: 256
12
+ NUMBER: 4 # 6
13
+ STD:
14
+ - 0.229
15
+ - 0.224
16
+ - 0.225
17
+ TEMPLATE:
18
+ CENTER_JITTER: 0
19
+ FACTOR: 2.0
20
+ SCALE_JITTER: 0
21
+ SIZE: 128
22
+ NUMBER: 3
23
+ TRAIN:
24
+ DATASETS_NAME:
25
+ - LASOT
26
+ # - GOT10K_vottrain
27
+ # - TRACKINGNET
28
+ # - VastTrack
29
+ # - TNL2K_train
30
+ # - RefCOCO14 # RefCOCO14,COCO17
31
+ # - OTB99_train
32
+ DATASETS_RATIO:
33
+ # - 6
34
+ # - 6
35
+ # - 6
36
+ # - 6
37
+ # - 6
38
+ # - 6
39
+ - 1
40
+ SAMPLE_PER_EPOCH: 25000
41
+ MODEL:
42
+ PRETRAIN_FILE: "fast_itpn_base_clipl_e1600.pt" # for backbone
43
+ PRETRAINED_PATH: "checkpoint/ATCTrack_b.pth.tar"
44
+ TARGET_STATE:
45
+ ENABLE: true
46
+ MODEL_PATH: "../Qwen/Qwen3.5-2B"
47
+ TOKEN: "<TARGET_STATE>"
48
+ FREEZE_QWEN: true
49
+ TRAIN_TOKEN_EMBEDDING: true
50
+ USE_LORA: true
51
+ LORA_R: 8
52
+ LORA_ALPHA: 16
53
+ LORA_DROPOUT: 0.05
54
+ LORA_TARGET_MODULES:
55
+ - in_proj_qkv
56
+ - out_proj
57
+ - in_proj_z
58
+ - in_proj_b
59
+ - in_proj_a
60
+ - q_proj
61
+ - k_proj
62
+ - v_proj
63
+ - o_proj
64
+ - gate_proj
65
+ - up_proj
66
+ - down_proj
67
+ TEACHER_ENABLE: false
68
+ TEACHER_MODEL: qwen3.5
69
+ TEACHER_BASE_URL: http://127.0.0.1:8001/v1
70
+ TEACHER_API_KEY: sk-no-key-required
71
+ BACKBONE:
72
+ TYPE: itpn_base
73
+ STRIDE: 16
74
+ HEAD:
75
+ TYPE: CENTER
76
+ NUM_CHANNELS: 256
77
+ HIDDEN_DIM: 512
78
+ TRAIN:
79
+ BACKBONE_MULTIPLIER: 0.1
80
+ DROP_PATH_RATE: 0.1
81
+ BATCH_SIZE: 2
82
+ EPOCH: 180
83
+ GIOU_WEIGHT: 2.0
84
+ L1_WEIGHT: 5.0
85
+ QWEN_FORMAT_WEIGHT: 0.01
86
+ QWEN_TEACHER_WEIGHT: 0.1
87
+ GRAD_CLIP_NORM: 0.1
88
+ LR: 0.0001
89
+ LR_DROP_EPOCH: 144 # 4/5(0.8)
90
+ NUM_WORKER: 8
91
+ OPTIMIZER: ADAMW
92
+ PRINT_INTERVAL: 50
93
+ SCHEDULER:
94
+ TYPE: step
95
+ DECAY_RATE: 0.1
96
+ WEIGHT_DECAY: 0.0001
97
+ AMP: False
98
+ FIX_BN: true
99
+ TYPE: target_state # train target-state projector/gate and tracker head
100
+
101
+ TEST:
102
+ EPOCH: 240
103
+ SEARCH_FACTOR: 4.0
104
+ SEARCH_SIZE: 256
105
+ TEMPLATE_FACTOR: 2.0
106
+ TEMPLATE_SIZE: 128
107
+ WINDOW: true
108
+ NUM_TEMPLATES: 2
109
+
install.sh ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ echo "****************** Installing pytorch ******************"
2
+ pip install torch==1.11.0+cu113 torchvision==0.12.0+cu113 torchaudio==0.11.0 --extra-index-url https://download.pytorch.org/whl/cu113
3
+ #conda install -y pytorch=1.11 torchvision torchaudio cudatoolkit=11.3 -c pytorch
4
+
5
+ echo ""
6
+ echo ""
7
+ echo "****************** Installing yaml ******************"
8
+ pip install PyYAML
9
+
10
+ echo ""
11
+ echo ""
12
+ echo "****************** Installing easydict ******************"
13
+ pip install easydict
14
+
15
+ echo ""
16
+ echo ""
17
+ echo "****************** Installing cython ******************"
18
+ pip install cython
19
+
20
+ echo ""
21
+ echo ""
22
+ echo "****************** Installing opencv-python ******************"
23
+ pip install opencv-python
24
+
25
+ echo ""
26
+ echo ""
27
+ echo "****************** Installing pandas ******************"
28
+ pip install pandas
29
+
30
+ echo ""
31
+ echo ""
32
+ echo "****************** Installing tqdm ******************"
33
+ conda install -y tqdm
34
+
35
+ echo ""
36
+ echo ""
37
+ echo "****************** Installing coco toolkit ******************"
38
+ pip install pycocotools
39
+
40
+ echo ""
41
+ echo ""
42
+ echo "****************** Installing jpeg4py python wrapper ******************"
43
+ pip install jpeg4py
44
+
45
+ echo ""
46
+ echo ""
47
+ echo "****************** Installing tensorboard ******************"
48
+ pip install tb-nightly
49
+
50
+ echo ""
51
+ echo ""
52
+ echo "****************** Installing tikzplotlib ******************"
53
+ pip install tikzplotlib
54
+
55
+ echo ""
56
+ echo ""
57
+ echo "****************** Installing thop tool for FLOPs and Params computing ******************"
58
+ pip install --upgrade git+https://github.com/Lyken17/pytorch-OpCounter.git
59
+
60
+ echo ""
61
+ echo ""
62
+ echo "****************** Installing colorama ******************"
63
+ pip install colorama
64
+
65
+ echo ""
66
+ echo ""
67
+ echo "****************** Installing lmdb ******************"
68
+ pip install lmdb
69
+
70
+ echo ""
71
+ echo ""
72
+ echo "****************** Installing scipy ******************"
73
+ pip install scipy
74
+
75
+ echo ""
76
+ echo ""
77
+ echo "****************** Installing visdom ******************"
78
+ pip install visdom
79
+
80
+ echo ""
81
+ echo ""
82
+ echo "****************** Installing vot-toolkit python ******************"
83
+ pip install git+https://github.com/votchallenge/vot-toolkit-python
84
+
85
+ echo ""
86
+ echo ""
87
+ echo "****************** Installing timm ******************"
88
+ pip install timm==0.5.4
89
+
90
+ echo ""
91
+ echo ""
92
+ echo "****************** Installing yacs ******************"
93
+ pip install yacs
94
+
95
+ echo ""
96
+ echo ""
97
+ echo "****************** Installing pytorch-pretrained-bert ******************"
98
+ pip install pytorch-pretrained-bert==0.6.2
99
+
100
+ echo ""
101
+ echo ""
102
+ echo "****************** Installing scikit-image ******************"
103
+ pip install scikit-image
104
+
105
+ echo ""
106
+ echo ""
107
+
108
+ echo "****************** Installation complete! ******************"
lib/__init__.py ADDED
File without changes
lib/config/__init__.py ADDED
File without changes
lib/config/atctrack/config.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from easydict import EasyDict as edict
2
+ import yaml
3
+
4
+ cfg = edict()
5
+
6
+ # MODEL
7
+ cfg.MODEL = edict()
8
+ cfg.MODEL.HIDDEN_DIM = 256 # hidden dimension for the decoder and vocabulary
9
+ cfg.MODEL.BINS = 4000 # number of discrete bins
10
+ cfg.MODEL.FEATURE_TYPE = "x" # the input feature to decoder. x, xz, or token
11
+ cfg.MODEL.INTERFACE_TYPE = 'low-rank_add'
12
+ cfg.MODEL.INTERFACE_DIM = 8
13
+
14
+ # MODEL.LANGUAGE
15
+ cfg.MODEL.PRETRAIN_FILE = ""
16
+ cfg.MODEL.PRETRAINED_PATH = ""
17
+
18
+ # MODEL.TARGET_STATE
19
+ cfg.MODEL.TARGET_STATE = edict()
20
+ cfg.MODEL.TARGET_STATE.ENABLE = False
21
+ cfg.MODEL.TARGET_STATE.MODEL_PATH = "../Qwen/Qwen3.5-4B"
22
+ cfg.MODEL.TARGET_STATE.TOKEN = "<TARGET_STATE>"
23
+ cfg.MODEL.TARGET_STATE.FREEZE_QWEN = True
24
+ cfg.MODEL.TARGET_STATE.TRAIN_TOKEN_EMBEDDING = True
25
+ cfg.MODEL.TARGET_STATE.USE_LORA = True
26
+ cfg.MODEL.TARGET_STATE.LORA_R = 8
27
+ cfg.MODEL.TARGET_STATE.LORA_ALPHA = 16
28
+ cfg.MODEL.TARGET_STATE.LORA_DROPOUT = 0.05
29
+ cfg.MODEL.TARGET_STATE.LORA_TARGET_MODULES = [
30
+ "in_proj_qkv", "out_proj", "in_proj_z", "in_proj_b", "in_proj_a",
31
+ "q_proj", "k_proj", "v_proj", "o_proj",
32
+ "gate_proj", "up_proj", "down_proj",
33
+ ]
34
+ cfg.MODEL.TARGET_STATE.TEACHER_ENABLE = False
35
+ cfg.MODEL.TARGET_STATE.TEACHER_MODEL = "qwen3.5"
36
+ cfg.MODEL.TARGET_STATE.TEACHER_BASE_URL = "http://127.0.0.1:8001/v1"
37
+ cfg.MODEL.TARGET_STATE.TEACHER_API_KEY = "sk-no-key-required"
38
+
39
+
40
+ # MODEL.BACKBONE
41
+ cfg.MODEL.BACKBONE = edict()
42
+ cfg.MODEL.BACKBONE.TYPE = "vit_base_patch16_224"
43
+ cfg.MODEL.BACKBONE.STRIDE = 16
44
+ cfg.MODEL.BACKBONE.MID_PE = False
45
+ cfg.MODEL.BACKBONE.SEP_SEG = False
46
+ cfg.MODEL.BACKBONE.CAT_MODE = 'direct'
47
+ cfg.MODEL.BACKBONE.MERGE_LAYER = 0
48
+ cfg.MODEL.BACKBONE.ADD_CLS_TOKEN = False
49
+ cfg.MODEL.BACKBONE.CLS_TOKEN_USE_MODE = 'ignore'
50
+
51
+ # MODEL.HEAD
52
+ cfg.MODEL.HEAD = edict()
53
+ cfg.MODEL.HEAD.TYPE = "CENTER"
54
+ cfg.MODEL.HEAD.NUM_CHANNELS = 512
55
+
56
+
57
+ # TRAIN
58
+ cfg.TRAIN = edict()
59
+ cfg.TRAIN.LR = 0.0001
60
+ cfg.TRAIN.WEIGHT_DECAY = 0.0001
61
+ cfg.TRAIN.AMP = False
62
+ cfg.TRAIN.EPOCH = 500
63
+ cfg.TRAIN.LR_DROP_EPOCH = 400
64
+ cfg.TRAIN.BATCH_SIZE = 8
65
+ cfg.TRAIN.NUM_WORKER = 8
66
+ cfg.TRAIN.OPTIMIZER = "ADAMW"
67
+ cfg.TRAIN.ENCODER_MULTIPLIER = 0.1 # encoder's LR = this factor * LR
68
+ cfg.TRAIN.FREEZE_ENCODER = False # for freezing the parameters of encoder
69
+ cfg.TRAIN.ENCODER_OPEN = [] # only for debug, open some layers of encoder when FREEZE_ENCODER is True
70
+ cfg.TRAIN.CE_WEIGHT = 1.0 # weight for cross-entropy loss
71
+ cfg.TRAIN.GIOU_WEIGHT = 2.0
72
+ cfg.TRAIN.L1_WEIGHT = 5.0
73
+ cfg.TRAIN.QWEN_FORMAT_WEIGHT = 0.01
74
+ cfg.TRAIN.QWEN_TEACHER_WEIGHT = 0.1
75
+
76
+ cfg.TRAIN.PRINT_INTERVAL = 50 # interval to print the training log
77
+ cfg.TRAIN.GRAD_CLIP_NORM = 0.1
78
+ cfg.TRAIN.FIX_BN = False
79
+ cfg.TRAIN.BACKBONE_MULTIPLIER = 0.1
80
+ cfg.TRAIN.DROP_PATH_RATE = 0.1
81
+
82
+ # TRAIN.SCHEDULER
83
+ cfg.TRAIN.SCHEDULER = edict()
84
+ cfg.TRAIN.SCHEDULER.TYPE = "step"
85
+ cfg.TRAIN.SCHEDULER.DECAY_RATE = 0.1
86
+ cfg.TRAIN.TYPE = "peft" # peft or fft
87
+ cfg.TRAIN.PRETRAINED_PATH = None
88
+
89
+ # DATA
90
+ cfg.DATA = edict()
91
+ cfg.DATA.MEAN = [0.485, 0.456, 0.406]
92
+ cfg.DATA.STD = [0.229, 0.224, 0.225]
93
+ cfg.DATA.MAX_SAMPLE_INTERVAL = 200
94
+ cfg.DATA.SAMPLER_MODE = "order"
95
+ cfg.DATA.LOADER = "tracking"
96
+ cfg.DATA.SEQ_FORMAT = "xywh"
97
+ cfg.DATA.MULTI_MODAL_VISION = False # vision multi-modal
98
+ cfg.DATA.MULTI_MODAL_LANGUAGE = True # language multi-modal
99
+ # DATA.TRAIN
100
+ cfg.DATA.TRAIN = edict()
101
+ cfg.DATA.TRAIN.DATASETS_NAME = ["LASOT", "GOT10K_vottrain"]
102
+ cfg.DATA.TRAIN.DATASETS_RATIO = [1, 1]
103
+ cfg.DATA.TRAIN.SAMPLE_PER_EPOCH = 60000
104
+ # DATA.SEARCH
105
+ cfg.DATA.SEARCH = edict()
106
+ cfg.DATA.SEARCH.NUMBER = 1 #number of search region, only support 1 for now.
107
+ cfg.DATA.SEARCH.SIZE = 256
108
+ cfg.DATA.SEARCH.FACTOR = 4.0
109
+ cfg.DATA.SEARCH.CENTER_JITTER = 3.5
110
+ cfg.DATA.SEARCH.SCALE_JITTER = 0.5
111
+ # DATA.TEMPLATE
112
+ cfg.DATA.TEMPLATE = edict()
113
+ cfg.DATA.TEMPLATE.NUMBER = 1
114
+ cfg.DATA.TEMPLATE.SIZE = 256
115
+ cfg.DATA.TEMPLATE.FACTOR = 4.0
116
+ cfg.DATA.TEMPLATE.CENTER_JITTER = 0
117
+ cfg.DATA.TEMPLATE.SCALE_JITTER = 0
118
+
119
+ # TEST
120
+ cfg.TEST = edict()
121
+ cfg.TEST.TEMPLATE_FACTOR = 4.0
122
+ cfg.TEST.TEMPLATE_SIZE = 128
123
+ cfg.TEST.SEARCH_FACTOR = 4.0
124
+ cfg.TEST.SEARCH_SIZE = 256
125
+ cfg.TEST.EPOCH = 500
126
+ cfg.TEST.WINDOW = False # window penalty
127
+ cfg.TEST.NUM_TEMPLATES = 1
128
+
129
+ cfg.TEST.UPDATE_INTERVALS = edict()
130
+ cfg.TEST.UPDATE_INTERVALS.DEFAULT = 25
131
+
132
+ cfg.TEST.UPDATE_THRESHOLD = edict()
133
+ cfg.TEST.UPDATE_THRESHOLD.DEFAULT = 0.475
134
+
135
+ cfg.TEST.MULTI_MODAL_VISION = edict()
136
+ cfg.TEST.MULTI_MODAL_VISION.DEFAULT = False
137
+ cfg.TEST.MULTI_MODAL_VISION.OTB99_LANG = False
138
+ cfg.TEST.MULTI_MODAL_VISION.TNL2K = False
139
+ cfg.TEST.MULTI_MODAL_VISION.LASOT_LANG = False
140
+
141
+
142
+
143
+
144
+
145
+ def _edict2dict(dest_dict, src_edict):
146
+ if isinstance(dest_dict, dict) and isinstance(src_edict, dict):
147
+ for k, v in src_edict.items():
148
+ if not isinstance(v, edict):
149
+ dest_dict[k] = v
150
+ else:
151
+ dest_dict[k] = {}
152
+ _edict2dict(dest_dict[k], v)
153
+ else:
154
+ return
155
+
156
+
157
+ def gen_config(config_file):
158
+ cfg_dict = {}
159
+ _edict2dict(cfg_dict, cfg)
160
+ with open(config_file, 'w') as f:
161
+ yaml.dump(cfg_dict, f, default_flow_style=False)
162
+
163
+
164
+ def _update_config(base_cfg, exp_cfg):
165
+ if isinstance(base_cfg, dict) and isinstance(exp_cfg, edict):
166
+ for k, v in exp_cfg.items():
167
+ if k in base_cfg:
168
+ if not isinstance(v, dict):
169
+ base_cfg[k] = v
170
+ else:
171
+ _update_config(base_cfg[k], v)
172
+ else:
173
+ raise ValueError("{} not exist in config.py".format(k))
174
+ else:
175
+ return
176
+
177
+
178
+ def update_config_from_file(filename):
179
+ exp_config = None
180
+ with open(filename) as f:
181
+ exp_config = edict(yaml.safe_load(f))
182
+ _update_config(cfg, exp_config)
183
+
184
+
lib/models/__init__.py ADDED
File without changes
lib/models/aqatrack/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .aqatrack import build_aqatrack
lib/models/aqatrack/aqatrack.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Basic AQATrack model.
3
+ """
4
+ import math
5
+ import os
6
+ from typing import List
7
+
8
+ import torch
9
+ from torch import nn
10
+ from torch.nn.modules.transformer import _get_clones
11
+
12
+ from lib.models.layers.head import build_box_head
13
+ from lib.models.aqatrack.hivit import hivit_small, hivit_base
14
+ from lib.utils.box_ops import box_xyxy_to_cxcywh
15
+
16
+ from lib.models.layers.transformer_dec import build_transformer_dec
17
+ from lib.models.layers.position_encoding import build_position_encoding
18
+ from lib.utils.misc import NestedTensor
19
+
20
+
21
+ import queue
22
+
23
+ class AQATrack(nn.Module):
24
+ """ This is the base class for AQATrack """
25
+
26
+ def __init__(self, transformer, box_head, transformer_dec, position_encoding, aux_loss=False, head_type="CORNER"):
27
+ """ Initializes the model.
28
+ Parameters:
29
+ transformer: torch module of the transformer architecture.
30
+ aux_loss: True if auxiliary decoding losses (loss at each decoder layer) are to be used.
31
+ """
32
+ super().__init__()
33
+ self.backbone = transformer
34
+ self.box_head = box_head
35
+
36
+ self.aux_loss = aux_loss
37
+ self.head_type = head_type
38
+ if head_type == "CORNER" or head_type == "CENTER":
39
+ self.feat_sz_s = int(box_head.feat_sz)
40
+ self.feat_len_s = int(box_head.feat_sz ** 2)
41
+
42
+ if self.aux_loss:
43
+ self.box_head = _get_clones(self.box_head, 6)
44
+
45
+ self.transformer_dec = transformer_dec
46
+ self.position_encoding = position_encoding
47
+ self.query_embed=nn.Embedding(num_embeddings=1, embedding_dim=512)
48
+
49
+
50
+ def forward(self, template: torch.Tensor,
51
+ search: torch.Tensor,
52
+ return_last_attn=False,
53
+ training=True, #True
54
+ tgt_pre = None,
55
+ ):
56
+ b0, num_search = template[0].shape[0], len(search)
57
+ if training:
58
+ search = torch.cat(search, dim=0)
59
+ template = template[0].repeat(num_search,1,1,1)
60
+
61
+ x, aux_dict = self.backbone(z=template, x=search,
62
+ return_last_attn=return_last_attn, ) #x=[B,N,C]
63
+
64
+ b,n,c = x.shape
65
+ input_dec = x
66
+ batches = [[] for _ in range(b0)]
67
+ for i, input in enumerate(input_dec):
68
+ batches[i % b0].append(input.unsqueeze(0))
69
+ x_decs = []
70
+ query_embed = self.query_embed.weight
71
+ assert len(query_embed.size()) in [2, 3]
72
+ if len(query_embed.size()) == 2:
73
+ query_embeding = query_embed.unsqueeze(1)
74
+ for i,batch in enumerate(batches):
75
+ if len(batch) ==0:
76
+ continue
77
+ tgt_all = [torch.zeros_like(query_embeding) for _ in range(num_search)]
78
+
79
+ for j, input in enumerate(batch):
80
+ pos_embed = self.position_encoding(1)
81
+ tgt_q = tgt_all[j]
82
+ tgt_kv = torch.cat(tgt_all[:j+1], dim=0)
83
+ if not training and len(tgt_pre) != 0:
84
+ tgt_kv = torch.cat(tgt_pre, dim=0)
85
+ tgt = [tgt_q, tgt_kv]
86
+ tgt_out = self.transformer_dec(input.transpose(0, 1), tgt, self.feat_len_s, pos_embed, query_embeding)
87
+ x_decs.append(tgt_out[0])
88
+ tgt_all[j] = tgt_out[0]#
89
+ if not training:
90
+ if len(tgt_pre) < 3: #num_search-1
91
+ tgt_pre.append(tgt_out[0])
92
+ else:
93
+ tgt_pre.pop(0)
94
+ tgt_pre.append(tgt_out[0])
95
+
96
+ batch0 =[]
97
+ if not training:
98
+ batch0.append(x_decs[0])
99
+ else:
100
+ batch0 = [x_decs[i + j*num_search] for j in range(b0) for i in range(num_search)]
101
+
102
+ x_dec = torch.cat(batch0, dim = 1)
103
+
104
+ # Forward head
105
+ feat_last = x
106
+ if isinstance(x, list):
107
+ feat_last = x[-1]
108
+
109
+ out = self.forward_head(feat_last, x_dec, None) # STM and head
110
+
111
+ out.update(aux_dict)
112
+ out['tgt'] = tgt_pre
113
+ #print(len(out['tgt']), 'out[tgt]')
114
+ return out
115
+
116
+ def forward_head(self, cat_feature, out_dec=None, gt_score_map=None):
117
+ """
118
+ cat_feature: output embeddings of the backbone, it can be (HW1+HW2, B, C) or (HW2, B, C)
119
+ """
120
+ # STM
121
+ enc_opt = cat_feature[:, -self.feat_len_s:]
122
+ dec_opt = out_dec.transpose(0,1).transpose(1,2)
123
+ att = torch.matmul(enc_opt, dec_opt)
124
+ opt = (enc_opt.unsqueeze(-1) * att.unsqueeze(-2)).permute((0, 3, 2, 1)).contiguous()
125
+ bs, Nq, C, HW = opt.size()
126
+ opt_feat = opt.view(-1, C, self.feat_sz_s, self.feat_sz_s)
127
+
128
+ #Head
129
+ if self.head_type == "CORNER":
130
+ # run the corner head
131
+ pred_box, score_map = self.box_head(opt_feat, True)
132
+ outputs_coord = box_xyxy_to_cxcywh(pred_box)
133
+ outputs_coord_new = outputs_coord.view(bs, Nq, 4)
134
+ out = {'pred_boxes': outputs_coord_new,
135
+ 'score_map': score_map,
136
+ }
137
+ return out
138
+
139
+ elif self.head_type == "CENTER":
140
+ # run the center head
141
+ score_map_ctr, bbox, size_map, offset_map = self.box_head(opt_feat, gt_score_map)
142
+ # outputs_coord = box_xyxy_to_cxcywh(bbox)
143
+ outputs_coord = bbox
144
+ outputs_coord_new = outputs_coord.view(bs, Nq, 4)
145
+ out = {'pred_boxes': outputs_coord_new,
146
+ 'score_map': score_map_ctr,
147
+ 'size_map': size_map,
148
+ 'offset_map': offset_map}
149
+ return out
150
+ else:
151
+ raise NotImplementedError
152
+
153
+
154
+ def build_aqatrack(cfg, training=True):
155
+ current_dir = os.path.dirname(os.path.abspath(__file__)) # This is your Project Root
156
+ pretrained_path = os.path.join(current_dir, '../../../pretrained_models')
157
+ if cfg.MODEL.PRETRAIN_FILE and ('AQATrack' not in cfg.MODEL.PRETRAIN_FILE) and training:
158
+ pretrained = os.path.join(pretrained_path, cfg.MODEL.PRETRAIN_FILE)
159
+ else:
160
+ pretrained = ''
161
+
162
+ if cfg.MODEL.BACKBONE.TYPE == 'hivit_small':
163
+ backbone = hivit_small(pretrained, drop_path_rate=cfg.TRAIN.DROP_PATH_RATE)
164
+ hidden_dim = backbone.embed_dim
165
+ patch_start_index = 1
166
+
167
+ elif cfg.MODEL.BACKBONE.TYPE == 'hivit_base':
168
+ backbone = hivit_base(pretrained, drop_path_rate=cfg.TRAIN.DROP_PATH_RATE)
169
+ hidden_dim = backbone.embed_dim
170
+ patch_start_index = 1
171
+
172
+ else:
173
+ raise NotImplementedError
174
+
175
+ backbone.finetune_track(cfg=cfg, patch_start_index=patch_start_index)
176
+
177
+
178
+ transformer_dec = build_transformer_dec(cfg, hidden_dim)
179
+ position_encoding = build_position_encoding(cfg, sz = 1)
180
+
181
+ box_head = build_box_head(cfg, hidden_dim)
182
+ model = AQATrack(
183
+ backbone,
184
+ box_head,
185
+ transformer_dec,
186
+ position_encoding,
187
+ aux_loss=False,
188
+ head_type=cfg.MODEL.HEAD.TYPE,
189
+ )
190
+
191
+ if 'AQATrack' in cfg.MODEL.PRETRAIN_FILE and training:
192
+ checkpoint = torch.load(cfg.MODEL.PRETRAIN_FILE, map_location="cpu")
193
+ missing_keys, unexpected_keys = model.load_state_dict(checkpoint["net"], strict=False)
194
+ print('Load pretrained model from: ' + cfg.MODEL.PRETRAIN_FILE)
195
+
196
+ return model
lib/models/aqatrack/base_backbone.py ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from functools import partial
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.nn.functional as F
6
+ from timm.models.vision_transformer import resize_pos_embed
7
+ from timm.models.layers import DropPath, to_2tuple, trunc_normal_
8
+
9
+ from lib.models.layers.patch_embed import PatchEmbed
10
+ from lib.models.aqatrack.utils import combine_tokens, recover_tokens
11
+
12
+
13
+ class BaseBackbone(nn.Module):
14
+ def __init__(self):
15
+ super().__init__()
16
+
17
+ self.pos_embed = None
18
+ self.img_size = [224, 224]
19
+ self.patch_size = 16
20
+ self.embed_dim = 384
21
+
22
+ self.cat_mode = 'direct'
23
+
24
+ self.pos_embed_z = None
25
+ self.pos_embed_x = None
26
+
27
+ self.template_segment_pos_embed = None
28
+ self.search_segment_pos_embed = None
29
+
30
+ self.return_inter = False
31
+ self.return_stage = [2, 5, 8, 11]
32
+
33
+ self.add_cls_token = True
34
+ self.add_sep_seg = False
35
+
36
+ self.cls_token = nn.Parameter(torch.zeros(1, 1, 512))
37
+
38
+ def finetune_track(self, cfg,dim, patch_start_index=1):
39
+
40
+ search_size = to_2tuple(cfg.DATA.SEARCH.SIZE)
41
+ template_size = to_2tuple(cfg.DATA.TEMPLATE.SIZE)
42
+ new_patch_size = cfg.MODEL.BACKBONE.STRIDE
43
+
44
+ self.cat_mode = cfg.MODEL.BACKBONE.CAT_MODE
45
+ self.return_inter = False
46
+
47
+ patch_pos_embed_all = self.pos_embed
48
+ patch_pos_embed = patch_pos_embed_all[:,1:,:]
49
+ patch_pos_embed = patch_pos_embed.transpose(1, 2)
50
+ B, E, Q = patch_pos_embed.shape
51
+ P_H, P_W = self.img_size // self.patch_size, self.img_size // self.patch_size
52
+ patch_pos_embed = patch_pos_embed.view(B, E, P_H, P_W)
53
+
54
+ # for search region
55
+ H, W = search_size
56
+ new_P_H, new_P_W = H // new_patch_size, W // new_patch_size
57
+ search_patch_pos_embed = nn.functional.interpolate(patch_pos_embed, size=(new_P_H, new_P_W), mode='bicubic',
58
+ align_corners=False)
59
+ search_patch_pos_embed = search_patch_pos_embed.flatten(2).transpose(1, 2)
60
+
61
+ # for template region
62
+ H, W = template_size
63
+ new_P_H, new_P_W = H // new_patch_size, W // new_patch_size
64
+ template_patch_pos_embed = nn.functional.interpolate(patch_pos_embed, size=(new_P_H, new_P_W), mode='bicubic',
65
+ align_corners=False)
66
+ template_patch_pos_embed = template_patch_pos_embed.flatten(2).transpose(1, 2)
67
+
68
+ self.pos_embed_z = nn.Parameter(torch.cat([template_patch_pos_embed,template_patch_pos_embed],dim=1))
69
+ self.pos_embed_x = nn.Parameter(search_patch_pos_embed)
70
+
71
+ cls_token = patch_pos_embed_all[:,0,:].unsqueeze(1)
72
+ self.cls_token = nn.Parameter(cls_token)
73
+
74
+ # token_type
75
+ self.token_type_search = nn.Parameter(torch.zeros(1, 1, dim))
76
+ self.token_type_template_fg = nn.Parameter(torch.zeros(1, 1, dim))
77
+ self.token_type_template_bg = nn.Parameter(torch.zeros(1, 1, dim))
78
+
79
+
80
+ if self.return_inter:
81
+ for i_layer in self.fpn_stage:
82
+ if i_layer != 11:
83
+ norm_layer = partial(nn.LayerNorm, eps=1e-6)
84
+ layer = norm_layer(self.embed_dim)
85
+ layer_name = f'norm{i_layer}'
86
+ self.add_module(layer_name, layer)
87
+
88
+ def forward_features(self, z, x, mask=None):
89
+ B = x.shape[0]
90
+
91
+ z = self.patch_embed(z)
92
+ x = self.patch_embed(x)
93
+
94
+ for blk in self.blocks[:-self.num_main_blocks]:
95
+ x = blk(x)
96
+ z = blk(z)
97
+
98
+ x = x[..., 0, 0, :]
99
+ z = z[..., 0, 0, :]
100
+
101
+
102
+ z += self.pos_embed_z
103
+ x += self.pos_embed_x
104
+
105
+ lens_z = self.pos_embed_z.shape[1]
106
+ lens_x = self.pos_embed_x.shape[1]
107
+
108
+ x = combine_tokens(z, x, mode=self.cat_mode)
109
+ #x = combine_tokens(x, z, mode=self.cat_mode)
110
+
111
+
112
+ if self.add_cls_token:
113
+ cls_tokens = self.cls_token.expand(B, -1, -1)
114
+ # cls_tokens = cls_tokens + self.cls_pos_embed
115
+ x = torch.cat([cls_tokens, x], dim=1)
116
+
117
+ x = self.pos_drop(x)
118
+
119
+ for blk in self.blocks[-self.num_main_blocks:]:
120
+ x = blk(x)
121
+
122
+ x = recover_tokens(x, lens_z, lens_x, mode=self.cat_mode)
123
+
124
+ aux_dict = {"attn": None}
125
+ x = self.norm_(x)
126
+
127
+ return x, aux_dict
128
+
129
+ def forward(self, z, x, **kwargs):
130
+ """
131
+ Joint feature extraction and relation modeling for the basic HiViT backbone.
132
+ Args:
133
+ z (torch.Tensor): template feature, [B, C, H_z, W_z]
134
+ x (torch.Tensor): search region feature, [B, C, H_x, W_x]
135
+
136
+ Returns:
137
+ x (torch.Tensor): merged template and search region feature, [B, L_z+L_x, C]
138
+ attn : None
139
+ """
140
+ x, aux_dict = self.forward_features(z, x,)
141
+
142
+ return x, aux_dict
lib/models/aqatrack/fast_itpn.py ADDED
@@ -0,0 +1,1173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # --------------------------------------------------------
2
+ # Fast-iTPN: Integrally Pre-Trained Transformer Pyramid Network with Token Migration
3
+ # Github source: https://github.com/sunsmarterjie/iTPN/tree/main/fast_itpn
4
+ # Copyright (c) 2023 University of Chinese Academy of Sciences
5
+ # Licensed under The MIT License [see LICENSE for details]
6
+ # By Yunjie Tian
7
+ # Based on EVA02, timm and deit code bases
8
+ # https://github.com/baaivision/EVA/tree/master/EVA-02
9
+ # https://github.com/rwightman/pytorch-image-models/tree/master/timm
10
+ # https://github.com/facebookresearch/deit/
11
+ # --------------------------------------------------------'
12
+ from functools import partial
13
+
14
+ import math
15
+ import torch
16
+ import torch.nn as nn
17
+ from timm.models.registry import register_model
18
+ import torch.nn.functional as F
19
+ import torch.utils.checkpoint as checkpoint
20
+ from timm.models.layers import to_2tuple, drop_path, trunc_normal_
21
+
22
+ from torch import Tensor, Size
23
+ from typing import Union, List
24
+ from lib.models.aqatrack.base_backbone import BaseBackbone
25
+
26
+
27
+ def _cfg(url='', **kwargs):
28
+ return {
29
+ 'url': url,
30
+ 'num_classes': 1000, 'input_size': (3, 224, 224), 'pool_size': None,
31
+ 'crop_pct': .9, 'interpolation': 'bicubic',
32
+ 'mean': (0.5, 0.5, 0.5), 'std': (0.5, 0.5, 0.5),
33
+ **kwargs
34
+ }
35
+
36
+
37
+ _shape_t = Union[int, List[int], Size]
38
+
39
+
40
+ class DropPath(nn.Module):
41
+ """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
42
+ """
43
+
44
+ def __init__(self, drop_prob=None):
45
+ super(DropPath, self).__init__()
46
+ self.drop_prob = drop_prob
47
+
48
+ def forward(self, x):
49
+ return drop_path(x, self.drop_prob, self.training)
50
+
51
+ def extra_repr(self) -> str:
52
+ return 'p={}'.format(self.drop_prob)
53
+
54
+
55
+ class Mlp(nn.Module):
56
+ def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.,
57
+ norm_layer=nn.LayerNorm, subln=False
58
+ ):
59
+ super().__init__()
60
+ out_features = out_features or in_features
61
+ hidden_features = hidden_features or in_features
62
+
63
+ self.fc1 = nn.Linear(in_features, hidden_features)
64
+ self.act = act_layer()
65
+
66
+ self.ffn_ln = norm_layer(hidden_features) if subln else nn.Identity()
67
+
68
+ self.fc2 = nn.Linear(hidden_features, out_features)
69
+ self.drop = nn.Dropout(drop)
70
+
71
+ def forward(self, x):
72
+ x = self.fc1(x)
73
+ x = self.act(x)
74
+ x = self.ffn_ln(x)
75
+ x = self.fc2(x)
76
+ x = self.drop(x)
77
+ return x
78
+
79
+
80
+ class ConvMlp(nn.Module):
81
+ def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.,
82
+ norm_layer=nn.LayerNorm, subln=False
83
+ ):
84
+ super().__init__()
85
+ out_features = out_features or in_features
86
+ hidden_features = hidden_features or in_features
87
+
88
+ self.fc1 = nn.Conv2d(in_features, hidden_features, 1)
89
+ self.act = act_layer()
90
+
91
+ self.ffn_ln = norm_layer(hidden_features) if subln else None
92
+
93
+ self.fc2 = nn.Conv2d(hidden_features, out_features, 1)
94
+ self.drop = nn.Dropout(drop)
95
+
96
+ def forward(self, x):
97
+ x = self.fc1(x)
98
+ x = self.act(x)
99
+ if self.ffn_ln is not None:
100
+ x = x.permute(0, 2, 3, 1)
101
+ x = self.ffn_ln(x)
102
+ x = x.permute(0, 3, 1, 2)
103
+ x = self.fc2(x)
104
+ x = self.drop(x)
105
+ return x
106
+
107
+
108
+ class SwiGLU(nn.Module):
109
+ def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.SiLU, drop=0.,
110
+ norm_layer=nn.LayerNorm, subln=False
111
+ ):
112
+ super().__init__()
113
+ out_features = out_features or in_features
114
+ hidden_features = hidden_features or in_features
115
+
116
+ self.w1 = nn.Linear(in_features, hidden_features)
117
+ self.w2 = nn.Linear(in_features, hidden_features)
118
+
119
+ self.act = act_layer()
120
+ self.ffn_ln = norm_layer(hidden_features) if subln else nn.Identity()
121
+ self.w3 = nn.Linear(hidden_features, out_features)
122
+
123
+ self.drop = nn.Dropout(drop)
124
+
125
+ def forward(self, x):
126
+ x1 = self.w1(x)
127
+ x2 = self.w2(x)
128
+ hidden = self.act(x1) * x2
129
+ x = self.ffn_ln(hidden)
130
+ x = self.w3(x)
131
+ x = self.drop(x)
132
+ return x
133
+
134
+
135
+ class ConvSwiGLU(nn.Module):
136
+ def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.SiLU, drop=0.,
137
+ norm_layer=nn.LayerNorm, subln=False
138
+ ):
139
+ super().__init__()
140
+ out_features = out_features or in_features
141
+ hidden_features = hidden_features or in_features
142
+
143
+ self.w1 = nn.Conv2d(in_features, hidden_features, 1)
144
+ self.w2 = nn.Conv2d(in_features, hidden_features, 1)
145
+
146
+ self.act = act_layer()
147
+ self.ffn_ln = norm_layer(hidden_features) if subln else nn.Identity()
148
+ self.w3 = nn.Conv2d(hidden_features, out_features, 1)
149
+
150
+ self.drop = nn.Dropout(drop)
151
+
152
+ def forward(self, x):
153
+ B, C, H, W = x.shape
154
+ x1 = self.w1(x).flatten(2).transpose(1, 2)
155
+ x2 = self.w2(x).flatten(2).transpose(1, 2)
156
+ hidden = self.act(x1) * x2
157
+ x = self.ffn_ln(hidden).transpose(1, 2).view(B, C, H, W)
158
+ x = self.w3(x)
159
+ x = self.drop(x)
160
+ return x
161
+
162
+
163
+ class Attention(nn.Module):
164
+ def __init__(
165
+ self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0., window_size=None,
166
+ attn_head_dim=None, use_decoupled_rel_pos_bias=False, deepnorm=False, subln=False
167
+ ):
168
+ super().__init__()
169
+ self.num_heads = num_heads
170
+ head_dim = dim // num_heads
171
+ if attn_head_dim is not None:
172
+ head_dim = attn_head_dim
173
+ all_head_dim = head_dim * self.num_heads
174
+ self.scale = qk_scale or head_dim ** -0.5
175
+
176
+ self.deepnorm = deepnorm
177
+ self.subln = subln
178
+ if self.deepnorm or self.subln:
179
+ self.q_proj = nn.Linear(dim, all_head_dim, bias=False)
180
+ self.k_proj = nn.Linear(dim, all_head_dim, bias=False)
181
+ self.v_proj = nn.Linear(dim, all_head_dim, bias=False)
182
+ else:
183
+ self.qkv = nn.Linear(dim, all_head_dim * 3, bias=False)
184
+
185
+ if qkv_bias:
186
+ self.q_bias = nn.Parameter(torch.zeros(all_head_dim))
187
+ self.v_bias = nn.Parameter(torch.zeros(all_head_dim))
188
+ else:
189
+ self.q_bias = None
190
+ self.v_bias = None
191
+
192
+ self.rel_pos_bias = None
193
+ self.qk_float = True
194
+
195
+ self.window_size = None
196
+ self.relative_position_bias_table = None
197
+
198
+ if window_size:
199
+ if use_decoupled_rel_pos_bias:
200
+ self.rel_pos_bias = DecoupledRelativePositionBias(window_size=window_size, num_heads=num_heads)
201
+ else:
202
+ self.window_size = window_size
203
+ self.num_relative_distance = (2 * window_size[0] - 1) * (
204
+ 2 * window_size[1] - 1) + 3 # (2*14-1) * (2*14-1) + 3
205
+ self.relative_position_bias_table = nn.Parameter(
206
+ torch.zeros(self.num_relative_distance, num_heads)) # 2*Wh-1 * 2*Ww-1, nH
207
+ # cls to token & token 2 cls & cls to cls
208
+
209
+ # get pair-wise relative position index for each token inside the window
210
+ coords_h = torch.arange(window_size[0])
211
+ coords_w = torch.arange(window_size[1])
212
+ coords = torch.stack(torch.meshgrid([coords_h, coords_w])) # 2, Wh, Ww
213
+ coords_flatten = torch.flatten(coords, 1) # 2, Wh*Ww
214
+ relative_coords = coords_flatten[:, :, None] - coords_flatten[:, None, :] # 2, Wh*Ww, Wh*Ww
215
+ relative_coords = relative_coords.permute(1, 2, 0).contiguous() # Wh*Ww, Wh*Ww, 2
216
+ relative_coords[:, :, 0] += window_size[0] - 1 # shift to start from 0
217
+ relative_coords[:, :, 1] += window_size[1] - 1
218
+ relative_coords[:, :, 0] *= 2 * window_size[1] - 1
219
+ relative_position_index = \
220
+ torch.zeros(size=(window_size[0] * window_size[1] + 1,) * 2, dtype=relative_coords.dtype)
221
+ relative_position_index[1:, 1:] = relative_coords.sum(-1) # Wh*Ww, Wh*Ww
222
+ relative_position_index[0, 0:] = self.num_relative_distance - 3
223
+ relative_position_index[0:, 0] = self.num_relative_distance - 2
224
+ relative_position_index[0, 0] = self.num_relative_distance - 1
225
+
226
+ self.register_buffer("relative_position_index", relative_position_index)
227
+
228
+ self.attn_drop = nn.Dropout(attn_drop)
229
+ self.proj = nn.Linear(all_head_dim, dim)
230
+ self.proj_drop = nn.Dropout(proj_drop)
231
+
232
+ def forward(self, x, rel_pos_bias=None, attn_mask=None,require_attn = False):
233
+ B, N, C = x.shape
234
+
235
+ if self.deepnorm or self.subln:
236
+ q = F.linear(input=x, weight=self.q_proj.weight, bias=self.q_bias)
237
+ k = F.linear(input=x, weight=self.k_proj.weight, bias=None)
238
+ v = F.linear(input=x, weight=self.v_proj.weight, bias=self.v_bias)
239
+
240
+ q = q.reshape(B, N, self.num_heads, -1).permute(0, 2, 1, 3) # B, num_heads, N, C
241
+ k = k.reshape(B, N, self.num_heads, -1).permute(0, 2, 1, 3)
242
+ v = v.reshape(B, N, self.num_heads, -1).permute(0, 2, 1, 3)
243
+ else:
244
+ qkv_bias = None
245
+ if self.q_bias is not None:
246
+ qkv_bias = torch.cat((self.q_bias, torch.zeros_like(self.v_bias, requires_grad=False), self.v_bias))
247
+ qkv = F.linear(input=x, weight=self.qkv.weight, bias=qkv_bias)
248
+ qkv = qkv.reshape(B, N, 3, self.num_heads, -1).permute(2, 0, 3, 1, 4) # 3, B, num_heads, N, C
249
+ q, k, v = qkv[0], qkv[1], qkv[2]
250
+
251
+ q = q * self.scale
252
+ if self.qk_float:
253
+ attn = (q.float() @ k.float().transpose(-2, -1))
254
+ else:
255
+ attn = (q @ k.transpose(-2, -1))
256
+
257
+ if self.relative_position_bias_table is not None:
258
+ relative_position_bias = \
259
+ self.relative_position_bias_table[self.relative_position_index.view(-1)].view(
260
+ self.window_size[0] * self.window_size[1] + 1,
261
+ self.window_size[0] * self.window_size[1] + 1, -1) # Wh*Ww,Wh*Ww,nH
262
+ relative_position_bias = relative_position_bias.permute(2, 0, 1).contiguous() # nH, Wh*Ww, Wh*Ww
263
+ attn = attn + relative_position_bias.unsqueeze(0).type_as(attn)
264
+
265
+ if self.rel_pos_bias is not None:
266
+ attn = attn + self.rel_pos_bias().type_as(attn)
267
+
268
+ if rel_pos_bias is not None:
269
+ attn = attn + rel_pos_bias.type_as(attn)
270
+ if attn_mask is not None:
271
+ attn_mask = attn_mask.bool()
272
+ attn = attn.masked_fill(~attn_mask[:, None, None, :], float("-inf"))
273
+ attn = attn.softmax(dim=-1).type_as(x)
274
+ attn = self.attn_drop(attn)
275
+
276
+ x = (attn @ v).transpose(1, 2).reshape(B, N, -1)
277
+ x = self.proj(x)
278
+ x = self.proj_drop(x)
279
+
280
+ if require_attn:
281
+ return x,attn
282
+ else:
283
+ return x
284
+
285
+
286
+ class Block(nn.Module):
287
+
288
+ def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop=0., attn_drop=0.,
289
+ drop_path=0., init_values=None, norm_layer=nn.LayerNorm, window_size=None, attn_head_dim=None,
290
+ use_decoupled_rel_pos_bias=False,
291
+ depth=None,
292
+ postnorm=False,
293
+ deepnorm=False,
294
+ subln=False,
295
+ swiglu=False,
296
+ naiveswiglu=False,
297
+ ):
298
+ super().__init__()
299
+
300
+ with_attn = num_heads > 0
301
+
302
+ self.norm1 = norm_layer(dim) if with_attn else None
303
+ self.attn = Attention(
304
+ dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale,
305
+ attn_drop=attn_drop, proj_drop=drop, window_size=window_size,
306
+ use_decoupled_rel_pos_bias=use_decoupled_rel_pos_bias, attn_head_dim=attn_head_dim,
307
+ deepnorm=deepnorm,
308
+ subln=subln
309
+ ) if with_attn else None
310
+
311
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
312
+ self.norm2 = norm_layer(dim)
313
+
314
+ mlp_hidden_dim = int(dim * mlp_ratio)
315
+ if swiglu:
316
+ self.mlp = xops.SwiGLU(
317
+ in_features=dim,
318
+ hidden_features=mlp_hidden_dim
319
+ ) # hidden_features: 2/3
320
+ elif naiveswiglu:
321
+ self.mlp = SwiGLU(
322
+ in_features=dim,
323
+ hidden_features=mlp_hidden_dim,
324
+ subln=subln,
325
+ norm_layer=norm_layer,
326
+ )
327
+ else:
328
+ self.mlp = Mlp(
329
+ in_features=dim,
330
+ hidden_features=mlp_hidden_dim,
331
+ subln=subln,
332
+ norm_layer=norm_layer
333
+ )
334
+
335
+ if init_values is not None and init_values > 0:
336
+ self.gamma_1 = nn.Parameter(init_values * torch.ones((dim)),
337
+ requires_grad=True) if self.attn is not None else None
338
+ self.gamma_2 = nn.Parameter(init_values * torch.ones((dim)), requires_grad=True)
339
+ else:
340
+ self.gamma_1, self.gamma_2 = None, None
341
+
342
+ self.deepnorm = deepnorm
343
+ if self.deepnorm:
344
+ self.alpha = math.pow(2.0 * depth, 0.25)
345
+
346
+ self.postnorm = postnorm
347
+
348
+ def forward(self, x, rel_pos_bias=None, attn_mask=None,require_attn= False):
349
+ if self.gamma_2 is None:
350
+ if self.postnorm:
351
+ if self.attn is not None:
352
+ x = x + self.drop_path(
353
+ self.norm1(self.attn(x, rel_pos_bias=rel_pos_bias, attn_mask=attn_mask)))
354
+ x = x + self.drop_path(self.norm2(self.mlp(x)))
355
+ elif self.deepnorm:
356
+ if self.attn is not None:
357
+ residual = x
358
+ x = self.attn(x, rel_pos_bias=rel_pos_bias, attn_mask=attn_mask)
359
+ x = self.drop_path(x)
360
+ x = residual * self.alpha + x
361
+ x = self.norm1(x)
362
+
363
+ residual = x
364
+ x = self.mlp(x)
365
+ x = self.drop_path(x)
366
+ x = residual * self.alpha + x
367
+ x = self.norm2(x)
368
+ else:
369
+ if self.attn is not None:
370
+ x = x + self.drop_path(
371
+ self.attn(self.norm1(x), rel_pos_bias=rel_pos_bias, attn_mask=attn_mask))
372
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
373
+ else:
374
+ if self.postnorm:
375
+ if self.attn is not None:
376
+ x = x + self.drop_path(
377
+ self.gamma_1 * self.norm1(self.attn(x, rel_pos_bias=rel_pos_bias, attn_mask=attn_mask)))
378
+ x = x + self.drop_path(self.gamma_2 * self.norm2(self.mlp(x)))
379
+ else:
380
+ if self.attn is not None:
381
+ if require_attn:
382
+ x_m,attn = self.attn(self.norm1(x), rel_pos_bias=rel_pos_bias, attn_mask=attn_mask, require_attn=True)
383
+ x = x + self.drop_path(
384
+ self.gamma_1 *x_m )
385
+ else:
386
+ x = x + self.drop_path(
387
+ self.gamma_1 * self.attn(self.norm1(x), rel_pos_bias=rel_pos_bias, attn_mask=attn_mask))
388
+ x = x + self.drop_path(self.gamma_2 * self.mlp(self.norm2(x)))
389
+ if require_attn:
390
+ return x,attn
391
+ else:
392
+ return x
393
+
394
+
395
+ class ConvMlpBlock(nn.Module):
396
+
397
+ def __init__(self, dim, mlp_ratio=4., drop_path=0., init_values=None, norm_layer=nn.LayerNorm,
398
+ depth=None,
399
+ postnorm=False,
400
+ deepnorm=False,
401
+ subln=False,
402
+ swiglu=False,
403
+ naiveswiglu=False,
404
+ ):
405
+ super().__init__()
406
+
407
+ self.attn = None
408
+
409
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
410
+ self.norm2 = norm_layer(dim)
411
+
412
+ mlp_hidden_dim = int(dim * mlp_ratio)
413
+
414
+ if swiglu:
415
+ self.mlp = xops.SwiGLU(
416
+ in_features=dim,
417
+ hidden_features=mlp_hidden_dim
418
+ ) # hidden_features: 2/3
419
+ elif naiveswiglu:
420
+ self.mlp = ConvSwiGLU(
421
+ in_features=dim,
422
+ hidden_features=mlp_hidden_dim,
423
+ subln=subln,
424
+ norm_layer=norm_layer,
425
+ )
426
+ else:
427
+ self.mlp = ConvMlp(
428
+ in_features=dim,
429
+ hidden_features=mlp_hidden_dim,
430
+ subln=subln,
431
+ norm_layer=norm_layer
432
+ )
433
+
434
+ if init_values is not None and init_values > 0:
435
+ self.gamma_1 = nn.Parameter(init_values * torch.ones((dim)),
436
+ requires_grad=True) if self.attn is not None else None
437
+ self.gamma_2 = nn.Parameter(init_values * torch.ones((dim)), requires_grad=True)
438
+ else:
439
+ self.gamma_1, self.gamma_2 = None, None
440
+
441
+ self.deepnorm = deepnorm
442
+ if self.deepnorm:
443
+ self.alpha = math.pow(2.0 * depth, 0.25)
444
+
445
+ self.postnorm = postnorm
446
+
447
+ def forward(self, x):
448
+ if self.gamma_2 is None:
449
+ if self.postnorm:
450
+ x = x + self.drop_path(self.norm2(self.mlp(x)))
451
+ elif self.deepnorm:
452
+ residual = x
453
+ x = self.mlp(x)
454
+ x = self.drop_path(x)
455
+ x = residual * self.alpha + x
456
+ x = self.norm2(x)
457
+ else:
458
+ x = x + self.drop_path(self.mlp(self.norm2(x.permute(0, 2, 3, 1)).permute(0, 3, 1, 2)))
459
+ else:
460
+ if self.postnorm:
461
+ x = x + self.drop_path(self.gamma_2 * self.norm2(self.mlp(x)))
462
+ else:
463
+ m = self.mlp(self.norm2(x.permute(0, 2, 3, 1)).permute(0, 3, 1, 2))
464
+ x = x + self.drop_path(self.gamma_2 * m)
465
+ return x
466
+
467
+
468
+ class PatchEmbed(nn.Module):
469
+ def __init__(self, img_size=224, patch_size=16, inner_patches=4, in_chans=3, embed_dim=128, norm_layer=None):
470
+ super().__init__()
471
+ img_size = to_2tuple(img_size)
472
+ patch_size = to_2tuple(patch_size)
473
+ patches_resolution = [img_size[0] // patch_size[0], img_size[1] // patch_size[1]]
474
+ self.img_size = img_size
475
+ self.patch_size = patch_size
476
+ self.inner_patches = inner_patches
477
+ self.patches_resolution = self.patch_shape = patches_resolution
478
+ self.num_patches = patches_resolution[0] * patches_resolution[1]
479
+
480
+ # self.in_chans = 6
481
+ self.in_chans = in_chans
482
+ self.embed_dim = embed_dim
483
+
484
+ conv_size = [size // inner_patches for size in patch_size]
485
+ self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=conv_size, stride=conv_size)
486
+ if norm_layer is not None:
487
+ self.norm = norm_layer(embed_dim)
488
+ else:
489
+ self.norm = None
490
+
491
+ def forward(self, x):
492
+ B, C, H, W = x.shape
493
+ patches_resolution = (H // self.patch_size[0], W // self.patch_size[1])
494
+ num_patches = patches_resolution[0] * patches_resolution[1]
495
+ x = self.proj(x).view(
496
+ B, -1,
497
+ patches_resolution[0], self.inner_patches,
498
+ patches_resolution[1], self.inner_patches,
499
+ ).permute(0, 2, 4, 3, 5, 1).reshape(B, num_patches, self.inner_patches, self.inner_patches, -1)
500
+ if self.norm is not None:
501
+ x = self.norm(x)
502
+ return x
503
+
504
+
505
+ class ConvPatchEmbed(nn.Module):
506
+ def __init__(self, img_size=224, patch_size=16, inner_patches=4, in_chans=3, embed_dim=128, norm_layer=None,
507
+ stop_grad_conv1=False):
508
+ super().__init__()
509
+ img_size = to_2tuple(img_size)
510
+ patch_size = to_2tuple(patch_size)
511
+ patches_resolution = [img_size[0] // patch_size[0], img_size[1] // patch_size[1]]
512
+ self.img_size = img_size
513
+ self.patch_size = patch_size
514
+ self.stop_grad_conv1 = stop_grad_conv1
515
+ self.inner_patches = inner_patches
516
+ self.patches_resolution = self.patch_shape = patches_resolution
517
+ self.num_patches = patches_resolution[0] * patches_resolution[1]
518
+
519
+ # self.in_chans = 6
520
+ self.in_chans = in_chans
521
+ self.embed_dim = embed_dim
522
+
523
+ conv_size = [size // inner_patches for size in patch_size]
524
+ self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=conv_size, stride=conv_size)
525
+ if norm_layer is not None:
526
+ self.norm = norm_layer(embed_dim)
527
+ else:
528
+ self.norm = None
529
+
530
+ def forward(self, x, bool_masked_pos=None, mask_token=None):
531
+ B, C, H, W = x.shape
532
+ x = self.proj(x)
533
+ if self.stop_grad_conv1:
534
+ x = x.detach() * 0.9 + x * 0.1
535
+
536
+ if bool_masked_pos is not None:
537
+ x = torch.nn.functional.unfold(x, kernel_size=4, stride=4, padding=0).transpose(1, 2)
538
+
539
+ seq_len = x.shape[1]
540
+ mask_token = mask_token.expand(B, seq_len, -1)
541
+ w = bool_masked_pos.unsqueeze(-1).type_as(mask_token)
542
+ x = x * (1 - w) + mask_token * w
543
+
544
+ x = torch.nn.functional.fold(x.transpose(1, 2), output_size=(H // 4, W // 4), kernel_size=4, padding=0,
545
+ stride=4)
546
+ if self.norm is not None:
547
+ x = self.norm(x)
548
+ return x
549
+
550
+
551
+ class PatchMerge(nn.Module):
552
+ def __init__(self, dim, norm_layer):
553
+ super().__init__()
554
+ self.norm = norm_layer(dim * 4)
555
+ self.reduction = nn.Linear(dim * 4, dim * 2, bias=False)
556
+ self.mlp = None
557
+
558
+ def forward(self, x):
559
+ x0 = x[..., 0::2, 0::2, :]
560
+ x1 = x[..., 1::2, 0::2, :]
561
+ x2 = x[..., 0::2, 1::2, :]
562
+ x3 = x[..., 1::2, 1::2, :]
563
+
564
+ x = torch.cat([x0, x1, x2, x3], dim=-1)
565
+ x = self.norm(x)
566
+ x = self.reduction(x)
567
+ return x
568
+
569
+
570
+ class ConvPatchMerge(nn.Module):
571
+ def __init__(self, dim, norm_layer):
572
+ super().__init__()
573
+ self.norm = norm_layer(dim)
574
+ self.reduction = nn.Conv2d(dim, dim * 2, kernel_size=2, stride=2, padding=0)
575
+ self.mlp = None
576
+
577
+ def forward(self, x):
578
+ x = self.norm(x.permute(0, 2, 3, 1)).permute(0, 3, 1, 2)
579
+ x = self.reduction(x)
580
+ return x
581
+
582
+
583
+ class RelativePositionBias(nn.Module):
584
+
585
+ def __init__(self, window_size, num_heads):
586
+ super().__init__()
587
+ self.window_size = window_size
588
+ self.num_relative_distance = (2 * window_size[0] - 1) * (2 * window_size[1] - 1) + 3
589
+ self.relative_position_bias_table = nn.Parameter(
590
+ torch.zeros(self.num_relative_distance, num_heads)) # 2*Wh-1 * 2*Ww-1, nH
591
+ # cls to token & token 2 cls & cls to cls
592
+
593
+ # get pair-wise relative position index for each token inside the window
594
+ coords_h = torch.arange(window_size[0])
595
+ coords_w = torch.arange(window_size[1])
596
+ coords = torch.stack(torch.meshgrid([coords_h, coords_w])) # 2, Wh, Ww
597
+ coords_flatten = torch.flatten(coords, 1) # 2, Wh*Ww
598
+ relative_coords = coords_flatten[:, :, None] - coords_flatten[:, None, :] # 2, Wh*Ww, Wh*Ww
599
+ relative_coords = relative_coords.permute(1, 2, 0).contiguous() # Wh*Ww, Wh*Ww, 2
600
+ relative_coords[:, :, 0] += window_size[0] - 1 # shift to start from 0
601
+ relative_coords[:, :, 1] += window_size[1] - 1
602
+ relative_coords[:, :, 0] *= 2 * window_size[1] - 1
603
+ relative_position_index = \
604
+ torch.zeros(size=(window_size[0] * window_size[1] + 1,) * 2, dtype=relative_coords.dtype)
605
+ relative_position_index[1:, 1:] = relative_coords.sum(-1) # Wh*Ww, Wh*Ww
606
+ relative_position_index[0, 0:] = self.num_relative_distance - 3
607
+ relative_position_index[0:, 0] = self.num_relative_distance - 2
608
+ relative_position_index[0, 0] = self.num_relative_distance - 1
609
+
610
+ self.register_buffer("relative_position_index", relative_position_index)
611
+
612
+ def forward(self):
613
+ relative_position_bias = \
614
+ self.relative_position_bias_table[self.relative_position_index.view(-1)].view(
615
+ self.window_size[0] * self.window_size[1] + 1,
616
+ self.window_size[0] * self.window_size[1] + 1, -1) # Wh*Ww,Wh*Ww,nH
617
+ return relative_position_bias.permute(2, 0, 1).contiguous() # nH, Wh*Ww, Wh*Ww
618
+
619
+
620
+ def _mask_1d_rel_pos_index(seq_len):
621
+ index = torch.arange(seq_len)
622
+ return index.view(1, seq_len) - index.view(seq_len, 1) + seq_len - 1
623
+
624
+
625
+ def _add_cls_to_index_matrix(index, num_tokens, offset):
626
+ index = index.contiguous().view(num_tokens, num_tokens)
627
+ new_index = torch.zeros(size=(num_tokens + 1, num_tokens + 1), dtype=index.dtype)
628
+ new_index[1:, 1:] = index
629
+ new_index[0, 0:] = offset
630
+ new_index[0:, 0] = offset + 1
631
+ new_index[0, 0] = offset + 2
632
+ return new_index
633
+
634
+
635
+ class DecoupledRelativePositionBias(nn.Module):
636
+
637
+ def __init__(self, window_size, num_heads):
638
+ super().__init__()
639
+ self.window_size = window_size
640
+ self.num_relative_distance = (2 * window_size[0] + 2, 2 * window_size[1] + 2)
641
+
642
+ num_tokens = window_size[0] * window_size[1]
643
+
644
+ self.relative_position_bias_for_high = nn.Parameter(torch.zeros(self.num_relative_distance[0], num_heads))
645
+ self.relative_position_bias_for_width = nn.Parameter(torch.zeros(self.num_relative_distance[1], num_heads))
646
+ # cls to token & token 2 cls & cls to cls
647
+
648
+ h_index = _mask_1d_rel_pos_index(window_size[0]).view(
649
+ window_size[0], 1, window_size[0], 1).expand(-1, window_size[1], -1, window_size[1])
650
+ h_index = _add_cls_to_index_matrix(h_index, num_tokens, 2 * window_size[0] - 1)
651
+ self.register_buffer("relative_position_high_index", h_index)
652
+
653
+ w_index = _mask_1d_rel_pos_index(window_size[1]).view(
654
+ 1, window_size[1], 1, window_size[1]).expand(window_size[0], -1, window_size[0], -1)
655
+ w_index = _add_cls_to_index_matrix(w_index, num_tokens, 2 * window_size[1] - 1)
656
+
657
+ self.register_buffer("relative_position_width_index", w_index)
658
+
659
+ def forward(self):
660
+ relative_position_bias = \
661
+ F.embedding(input=self.relative_position_high_index, weight=self.relative_position_bias_for_high) + \
662
+ F.embedding(input=self.relative_position_width_index, weight=self.relative_position_bias_for_width)
663
+ return relative_position_bias.permute(2, 0, 1).contiguous()
664
+
665
+
666
+ class Fast_iTPN(BaseBackbone):
667
+ def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=512, depth_stage1=3, depth_stage2=3, depth=24,
668
+ num_heads=8, bridge_mlp_ratio=3., mlp_ratio=4., qkv_bias=True, qk_scale=None, drop_rate=0.,
669
+ attn_drop_rate=0., drop_path_rate=0.0, init_values=0.1, attn_head_dim=None, norm_layer=nn.LayerNorm,
670
+ patch_norm=False, num_classes=1000, use_mean_pooling=False,
671
+ init_scale=0.01,
672
+ cls_token=False,
673
+ grad_ckpt=False,
674
+ stop_grad_conv1=False,
675
+ use_abs_pos_emb=True,
676
+ use_rel_pos_bias=False,
677
+ use_shared_rel_pos_bias=False,
678
+ use_shared_decoupled_rel_pos_bias=False,
679
+ convmlp=False,
680
+
681
+ postnorm=False,
682
+ deepnorm=False,
683
+ subln=False,
684
+ swiglu=False,
685
+ naiveswiglu=False,
686
+ **kwargs):
687
+ super().__init__()
688
+ self.img_size = img_size
689
+ self.mlp_ratio = mlp_ratio
690
+ self.grad_ckpt = grad_ckpt
691
+ self.num_main_blocks = depth
692
+ self.depth_stage1 = depth_stage1
693
+ self.depth_stage2 = depth_stage2
694
+ self.depth = depth
695
+ self.patch_size = patch_size
696
+ self.num_features = self.embed_dim = embed_dim
697
+ self.convmlp = convmlp
698
+ self.stop_grad_conv1 = stop_grad_conv1
699
+ self.use_rel_pos_bias = use_rel_pos_bias
700
+ self.use_shared_rel_pos_bias = use_shared_rel_pos_bias
701
+ self.use_shared_decoupled_rel_pos_bias = use_shared_decoupled_rel_pos_bias
702
+ self.use_decoupled_rel_pos_bias = False
703
+
704
+ mlvl_dims = {'4': embed_dim // 4, '8': embed_dim // 2, '16': embed_dim}
705
+ # split image into non-overlapping patches
706
+ # in_chans = 6
707
+ if convmlp:
708
+ self.patch_embed = ConvPatchEmbed(
709
+ img_size=img_size, patch_size=patch_size, in_chans=in_chans, embed_dim=mlvl_dims['4'],
710
+ stop_grad_conv1=stop_grad_conv1,
711
+ norm_layer=norm_layer if patch_norm else None)
712
+ else:
713
+ self.patch_embed = PatchEmbed(
714
+ img_size=img_size, patch_size=patch_size, in_chans=in_chans, embed_dim=mlvl_dims['4'],
715
+ norm_layer=norm_layer if patch_norm else None)
716
+ num_patches = self.patch_embed.num_patches
717
+
718
+ if cls_token:
719
+ self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))
720
+ else:
721
+ self.cls_token = None
722
+ if use_abs_pos_emb:
723
+ if cls_token:
724
+ self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, embed_dim))
725
+ else:
726
+ self.pos_embed = nn.Parameter(torch.zeros(1, num_patches, embed_dim))
727
+ else:
728
+ self.pos_embed = None
729
+ self.pos_drop = nn.Dropout(p=drop_rate)
730
+
731
+ if use_shared_rel_pos_bias:
732
+ self.rel_pos_bias = RelativePositionBias(window_size=self.patch_embed.patch_shape, num_heads=num_heads)
733
+ else:
734
+ self.rel_pos_bias = None
735
+
736
+ if use_shared_decoupled_rel_pos_bias:
737
+ assert self.rel_pos_bias is None
738
+ self.rel_pos_bias = DecoupledRelativePositionBias(window_size=self.patch_embed.patch_shape,
739
+ num_heads=num_heads)
740
+
741
+ self.subln = subln
742
+ self.swiglu = swiglu
743
+ self.naiveswiglu = naiveswiglu
744
+
745
+ self.build_blocks(
746
+ depths=[depth_stage1, depth_stage2, depth],
747
+ dims=mlvl_dims,
748
+ num_heads=num_heads,
749
+ bridge_mlp_ratio=bridge_mlp_ratio,
750
+ mlp_ratio=mlp_ratio,
751
+ qkv_bias=qkv_bias,
752
+ qk_scale=qk_scale,
753
+ window_size=self.patch_embed.patch_shape if use_rel_pos_bias else None,
754
+ drop=drop_rate,
755
+ attn_drop=attn_drop_rate,
756
+ drop_path_rate=drop_path_rate,
757
+ norm_layer=norm_layer,
758
+ init_values=init_values,
759
+ attn_head_dim=attn_head_dim,
760
+ postnorm=postnorm,
761
+ deepnorm=deepnorm,
762
+ subln=subln,
763
+ swiglu=swiglu,
764
+ naiveswiglu=naiveswiglu,
765
+ convmlp=convmlp,
766
+ )
767
+
768
+ self.norm = nn.Identity() if use_mean_pooling else norm_layer(embed_dim)
769
+
770
+ if self.pos_embed is not None:
771
+ trunc_normal_(self.pos_embed, std=.02)
772
+ if self.cls_token is not None:
773
+ trunc_normal_(self.cls_token, std=.02)
774
+
775
+ self.apply(self._init_weights)
776
+
777
+
778
+ def build_blocks(self,
779
+ depths=[3, 3, 24],
780
+ dims={'4': 128 // 4, '8': 256, '16': 512},
781
+ num_heads=8,
782
+ bridge_mlp_ratio=3.,
783
+ mlp_ratio=4.0,
784
+ qkv_bias=True,
785
+ qk_scale=None,
786
+ window_size=None,
787
+ drop=0.,
788
+ attn_drop=0.,
789
+ drop_path_rate=0.,
790
+ norm_layer=nn.LayerNorm,
791
+ init_values=0.,
792
+ attn_head_dim=None,
793
+ postnorm=False,
794
+ deepnorm=False,
795
+ subln=False,
796
+ swiglu=False,
797
+ naiveswiglu=False,
798
+ convmlp=False,
799
+ ):
800
+ dpr = iter(x.item() for x in torch.linspace(0, drop_path_rate, depths[0] + depths[1] + depths[2]))
801
+
802
+ self.blocks = nn.ModuleList()
803
+
804
+ if convmlp:
805
+ self.blocks.extend([
806
+ ConvMlpBlock(
807
+ dim=dims['4'],
808
+ mlp_ratio=bridge_mlp_ratio,
809
+ drop_path=next(dpr),
810
+ norm_layer=norm_layer,
811
+ init_values=0.,
812
+ depth=depths[-1],
813
+ postnorm=postnorm,
814
+ deepnorm=deepnorm,
815
+ subln=subln,
816
+ swiglu=False,
817
+ naiveswiglu=False,
818
+ ) for _ in range(depths[0])
819
+ ])
820
+ self.blocks.append(ConvPatchMerge(dims['4'], norm_layer))
821
+ self.blocks.extend([
822
+ ConvMlpBlock(
823
+ dim=dims['8'],
824
+ mlp_ratio=bridge_mlp_ratio,
825
+ drop_path=next(dpr),
826
+ norm_layer=norm_layer,
827
+ init_values=0.,
828
+ depth=depths[-1],
829
+ postnorm=postnorm,
830
+ deepnorm=deepnorm,
831
+ subln=subln,
832
+ swiglu=False,
833
+ naiveswiglu=False,
834
+ ) for _ in range(depths[1])
835
+ ])
836
+ self.blocks.append(ConvPatchMerge(dims['8'], norm_layer))
837
+ else:
838
+ self.blocks.extend([
839
+ Block(
840
+ dim=dims['4'],
841
+ num_heads=0,
842
+ mlp_ratio=bridge_mlp_ratio,
843
+ qkv_bias=qkv_bias,
844
+ qk_scale=qk_scale,
845
+ drop=drop,
846
+ attn_drop=attn_drop,
847
+ drop_path=next(dpr),
848
+ norm_layer=norm_layer,
849
+ init_values=init_values,
850
+ window_size=window_size,
851
+ depth=depths[-1],
852
+ postnorm=postnorm,
853
+ deepnorm=deepnorm,
854
+ subln=subln,
855
+ swiglu=swiglu,
856
+ naiveswiglu=naiveswiglu,
857
+ ) for _ in range(depths[0])
858
+ ])
859
+ self.blocks.append(PatchMerge(dims['4'], norm_layer))
860
+ self.blocks.extend([
861
+ Block(
862
+ dim=dims['8'],
863
+ num_heads=0,
864
+ mlp_ratio=bridge_mlp_ratio,
865
+ qkv_bias=qkv_bias,
866
+ qk_scale=qk_scale,
867
+ drop=drop,
868
+ attn_drop=attn_drop,
869
+ drop_path=next(dpr),
870
+ norm_layer=norm_layer,
871
+ init_values=init_values,
872
+ window_size=window_size,
873
+ depth=depths[-1],
874
+ postnorm=postnorm,
875
+ deepnorm=deepnorm,
876
+ subln=subln,
877
+ swiglu=swiglu,
878
+ naiveswiglu=naiveswiglu,
879
+ ) for _ in range(depths[1])
880
+ ])
881
+ self.blocks.append(PatchMerge(dims['8'], norm_layer))
882
+
883
+ ######### stage 3 ########
884
+ self.blocks.extend([
885
+ Block(
886
+ dim=dims['16'],
887
+ num_heads=num_heads,
888
+ mlp_ratio=mlp_ratio,
889
+ qkv_bias=qkv_bias,
890
+ qk_scale=qk_scale,
891
+ drop=drop,
892
+ attn_drop=attn_drop,
893
+ drop_path=next(dpr),
894
+ norm_layer=norm_layer,
895
+ init_values=init_values,
896
+ window_size=window_size,
897
+ attn_head_dim=attn_head_dim,
898
+ depth=depths[-1],
899
+ postnorm=postnorm,
900
+ deepnorm=deepnorm,
901
+ subln=subln,
902
+ swiglu=swiglu,
903
+ naiveswiglu=naiveswiglu,
904
+ ) for _ in range(depths[2])
905
+ ])
906
+
907
+ def _init_weights(self, m):
908
+ if isinstance(m, nn.Linear):
909
+ trunc_normal_(m.weight, std=.02)
910
+ if isinstance(m, nn.Linear) and m.bias is not None:
911
+ nn.init.constant_(m.bias, 0)
912
+ elif isinstance(m, nn.LayerNorm):
913
+ nn.init.constant_(m.bias, 0)
914
+ nn.init.constant_(m.weight, 1.0)
915
+
916
+ def get_num_layers(self):
917
+ return len(self.blocks)
918
+
919
+ @torch.jit.ignore
920
+ def no_weight_decay(self):
921
+ if self.cls_token is not None:
922
+ return {'pos_embed', 'cls_token'}
923
+ return {'pos_embed'}
924
+
925
+ def get_classifer(self):
926
+ return self.head
927
+
928
+ def reset_classifier(self, num_classes, global_pool=''):
929
+ self.num_classes = num_classes
930
+ self.head = nn.Linear(self.embed_dim, num_classes) if num_classes > 0 else nn.Identity()
931
+
932
+ @torch.jit.ignore
933
+ def no_weight_decay_keywords(self):
934
+ return {'relative_position_bias_table'}
935
+ def forward_features_pe(self, z,x,soft_token_template_mask):
936
+ B, C, H, W = x.shape
937
+ z, z1 = z[0], z[1]
938
+ z = self.patch_embed(z)
939
+ z1 = self.patch_embed(z1)
940
+ x = self.patch_embed(x)
941
+
942
+ for blk in self.blocks[:-self.num_main_blocks]:
943
+ x = blk(x)
944
+ z = blk(z)
945
+ z1 = blk(z1)
946
+
947
+ x = x.flatten(2).transpose(1, 2)
948
+ z = z.flatten(2).transpose(1, 2)
949
+ z1 = z1.flatten(2).transpose(1, 2)
950
+
951
+ token_type_search = self.token_type_search.expand(B, x.shape[1], -1)
952
+ token_type_template_bg = self.token_type_template_bg.expand(B, z.shape[1], -1)
953
+ token_type_template_fg = self.token_type_template_fg.expand(B, z.shape[1], -1)
954
+
955
+ x += token_type_search
956
+
957
+ token_type_template_fg = soft_token_template_mask[0] * token_type_template_fg
958
+ token_type_template_bg = (1 - soft_token_template_mask[0]) * token_type_template_bg
959
+ token_type_template_0 = token_type_template_fg + token_type_template_bg
960
+ z += token_type_template_0
961
+
962
+ token_type_template_fg = soft_token_template_mask[1] * token_type_template_fg
963
+ token_type_template_bg = (1 - soft_token_template_mask[1]) * token_type_template_bg
964
+ token_type_template_1 = token_type_template_fg + token_type_template_bg
965
+ z1 += token_type_template_1
966
+
967
+ x = torch.cat([z, z1, x], dim=1)
968
+
969
+ return x,[token_type_search,token_type_template_0,token_type_template_1 ]
970
+
971
+ def forward_features_stage3(self, x, update_cls_token,pos_embed=None):
972
+ B, L, D = x.shape
973
+ if self.cls_token is not None:
974
+ if update_cls_token is None:
975
+ cls_tokens = self.cls_token.expand(B, -1, -1)
976
+ else:
977
+ cls_tokens = update_cls_token
978
+ x = torch.cat([cls_tokens, x], dim=1)
979
+
980
+ if pos_embed is None:
981
+ pos_embed_z = self.pos_embed_z.expand(B, -1, -1)
982
+ pos_embed_x = self.pos_embed_x.expand(B, -1, -1)
983
+ cls_token = self.cls_token.expand(B, -1, -1)
984
+ pos_embed = torch.cat([cls_token, pos_embed_z, pos_embed_x], dim=1)
985
+
986
+ x = x + pos_embed
987
+ x = self.pos_drop(x)
988
+
989
+ rel_pos_bias = self.rel_pos_bias() if self.rel_pos_bias is not None else None
990
+ for blk in self.blocks[-self.num_main_blocks:]:
991
+ x = blk(x, rel_pos_bias)
992
+
993
+ x = self.norm(x)
994
+ aux_dict = {"attn": None}
995
+ return x, aux_dict
996
+
997
+ def forward_features(self, z,x,update_cls_token,soft_token_template_mask):
998
+ B, C, H, W = x.shape
999
+ z,z1 = z[0],z[1]
1000
+ z = self.patch_embed(z)
1001
+ z1 = self.patch_embed(z1)
1002
+ x = self.patch_embed(x)
1003
+
1004
+
1005
+ for blk in self.blocks[:-self.num_main_blocks]:
1006
+ x = blk(x)
1007
+ z = blk(z)
1008
+ z1 = blk(z1)
1009
+
1010
+ x = x.flatten(2).transpose(1, 2)
1011
+ z = z.flatten(2).transpose(1, 2)
1012
+ z1 = z1.flatten(2).transpose(1, 2)
1013
+
1014
+ token_type_search = self.token_type_search.expand(B, x.shape[1], -1)
1015
+ token_type_template_bg = self.token_type_template_bg.expand(B, z.shape[1], -1)
1016
+ token_type_template_fg = self.token_type_template_fg.expand(B, z.shape[1], -1)
1017
+
1018
+ x += token_type_search
1019
+
1020
+ token_type_template_fg = soft_token_template_mask[0] * token_type_template_fg
1021
+ token_type_template_bg = (1 - soft_token_template_mask[0]) * token_type_template_bg
1022
+ z += token_type_template_fg + token_type_template_bg
1023
+
1024
+ token_type_template_fg = soft_token_template_mask[1] * token_type_template_fg
1025
+ token_type_template_bg = (1 - soft_token_template_mask[1]) * token_type_template_bg
1026
+ z1 += token_type_template_fg + token_type_template_bg
1027
+
1028
+ # soft_token_debug_1, soft_token_debug_2 = soft_token_template_mask[0][0,:,0].view(7,7),soft_token_template_mask[1][0,:,0].view(7,7)
1029
+
1030
+ if self.cls_token is not None:
1031
+ if update_cls_token is None:
1032
+ cls_tokens = self.cls_token.expand(B, -1, -1)
1033
+ else:
1034
+ cls_tokens = update_cls_token
1035
+ x = torch.cat([cls_tokens, z,z1,x], dim=1)
1036
+
1037
+ pos_embed_z = self.pos_embed_z.expand(B, -1, -1)
1038
+ pos_embed_x = self.pos_embed_x.expand(B, -1, -1)
1039
+ cls_token = self.cls_token.expand(B, -1, -1)
1040
+ pos_embed = torch.cat([cls_token,pos_embed_z,pos_embed_x],dim=1)
1041
+
1042
+
1043
+ x = x + pos_embed
1044
+ x = self.pos_drop(x)
1045
+
1046
+ rel_pos_bias = self.rel_pos_bias() if self.rel_pos_bias is not None else None
1047
+ for blk in self.blocks[-self.num_main_blocks:]:
1048
+ x,attn = blk(x, rel_pos_bias,require_attn= True)
1049
+
1050
+ x = self.norm(x)
1051
+ aux_dict = {"attn": attn}
1052
+ return x, aux_dict
1053
+
1054
+ def forward(self, z,x,update_cls_token,soft_token_template_mask):
1055
+ x, aux_dict = self.forward_features(z, x, update_cls_token,soft_token_template_mask)
1056
+ return x, aux_dict
1057
+
1058
+
1059
+ @register_model
1060
+ def fast_itpn_tiny_1112_patch16_224(pretrained=False, **kwargs):
1061
+ model = Fast_iTPN(
1062
+ patch_size=16, embed_dim=384, depth_stage1=1, depth_stage2=1, depth=12, num_heads=6, bridge_mlp_ratio=3.,
1063
+ mlp_ratio=3., qkv_bias=True, norm_layer=partial(nn.LayerNorm, eps=1e-6),
1064
+ convmlp=True,
1065
+ naiveswiglu=True,
1066
+ subln=True,
1067
+ **kwargs)
1068
+ model.default_cfg = _cfg()
1069
+ if pretrained:
1070
+ checkpoint = torch.load(
1071
+ kwargs["init_ckpt"], map_location="cpu"
1072
+ )
1073
+ model.load_state_dict(checkpoint["model"])
1074
+ return model
1075
+
1076
+
1077
+ @register_model
1078
+ def fast_itpn_small_2220_patch16_224(pretrained=False, **kwargs):
1079
+ model = Fast_iTPN(
1080
+ patch_size=16, embed_dim=384, depth_stage1=2, depth_stage2=2, depth=20, num_heads=6, bridge_mlp_ratio=3.,
1081
+ mlp_ratio=3., qkv_bias=True, norm_layer=partial(nn.LayerNorm, eps=1e-6),
1082
+ convmlp=True,
1083
+ naiveswiglu=True,
1084
+ subln=True,
1085
+ **kwargs)
1086
+ model.default_cfg = _cfg()
1087
+ if pretrained:
1088
+ checkpoint = torch.load(
1089
+ kwargs["init_ckpt"], map_location="cpu"
1090
+ )
1091
+ model.load_state_dict(checkpoint["model"])
1092
+ return model
1093
+
1094
+
1095
+ @register_model
1096
+ def fast_itpn_base_3324_patch16_224(pretrained="", **kwargs):
1097
+ model = Fast_iTPN(
1098
+ patch_size=16, embed_dim=512, depth_stage1=3, depth_stage2=3, depth=24, num_heads=8, bridge_mlp_ratio=3.,
1099
+ mlp_ratio=3., qkv_bias=True, norm_layer=partial(nn.LayerNorm, eps=1e-6),
1100
+ convmlp=True,
1101
+ naiveswiglu=True,
1102
+ subln=True,
1103
+ cls_token = True, # for task cls
1104
+ **kwargs)
1105
+ model.default_cfg = _cfg()
1106
+
1107
+ if pretrained:
1108
+ checkpoint = torch.load(
1109
+ pretrained, map_location="cpu"
1110
+ )
1111
+ checkpoint = checkpoint["module"]
1112
+ ###### naive method
1113
+ # missing_keys, unexpected_keys = model.load_state_dict(checkpoint, strict=False)
1114
+
1115
+ #### process patch_embed.proj
1116
+ normal_weights = {}
1117
+ # special_weights = {}
1118
+ for k, v in checkpoint.items():
1119
+ # if "patch_embed.proj.weight" in k:
1120
+ # v1 = torch.cat([v, v], dim=1)*0.5
1121
+ # normal_weights[k] = v1
1122
+ if "pos_embed" in k:
1123
+ # add cls token
1124
+ cls_pos = torch.mean(v,dim=1).unsqueeze(dim=1)
1125
+ v1 = torch.cat([cls_pos,v],dim=1)
1126
+ normal_weights[k] = v1
1127
+
1128
+ else:
1129
+ normal_weights[k] = v
1130
+
1131
+ missing_keys, unexpected_keys = model.load_state_dict(normal_weights, strict=False)
1132
+
1133
+
1134
+ return model
1135
+
1136
+ @register_model
1137
+ def fast_itpn_large_2240_patch16_256(pretrained=False, **kwargs):
1138
+ model = Fast_iTPN(
1139
+ patch_size=16, embed_dim=768, depth_stage1=2, depth_stage2=2, depth=40, num_heads=12, bridge_mlp_ratio=3.,
1140
+ mlp_ratio=3., qkv_bias=True, norm_layer=partial(nn.LayerNorm, eps=1e-6),
1141
+ convmlp=True,
1142
+ naiveswiglu=True,
1143
+ subln=True,
1144
+ cls_token=True, # for task cls
1145
+ **kwargs)
1146
+ model.default_cfg = _cfg()
1147
+ if pretrained:
1148
+ checkpoint = torch.load(
1149
+ pretrained, map_location="cpu"
1150
+ )
1151
+ checkpoint = checkpoint["module"]
1152
+ ###### naive method
1153
+ # missing_keys, unexpected_keys = model.load_state_dict(checkpoint, strict=False)
1154
+
1155
+ #### process patch_embed.proj
1156
+ normal_weights = {}
1157
+ # special_weights = {}
1158
+ for k, v in checkpoint.items():
1159
+ # if "patch_embed.proj.weight" in k:
1160
+ # v1 = torch.cat([v, v], dim=1)*0.5
1161
+ # normal_weights[k] = v1
1162
+ if "pos_embed" in k:
1163
+ # add cls token
1164
+ cls_pos = torch.mean(v, dim=1).unsqueeze(dim=1)
1165
+ v1 = torch.cat([cls_pos, v], dim=1)
1166
+ normal_weights[k] = v1
1167
+
1168
+ else:
1169
+ normal_weights[k] = v
1170
+
1171
+ missing_keys, unexpected_keys = model.load_state_dict(normal_weights, strict=False)
1172
+
1173
+ return model
lib/models/aqatrack/hivit.py ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Vision Transformer (ViT) in PyTorch
2
+ A PyTorch implement of Vision Transformers as described in:
3
+ 'An Image Is Worth 16 x 16 Words: Transformers for Image Recognition at Scale'
4
+ - https://arxiv.org/abs/2010.11929
5
+ `How to train your ViT? Data, Augmentation, and Regularization in Vision Transformers`
6
+ - https://arxiv.org/abs/2106.10270
7
+ The official jax code is released and available at https://github.com/google-research/vision_transformer
8
+ DeiT model defs and weights from https://github.com/facebookresearch/deit,
9
+ paper `DeiT: Data-efficient Image Transformers` - https://arxiv.org/abs/2012.12877
10
+ Acknowledgments:
11
+ * The paper authors for releasing code and weights, thanks!
12
+ * I fixed my class token impl based on Phil Wang's https://github.com/lucidrains/vit-pytorch ... check it out
13
+ for some einops/einsum fun
14
+ * Simple transformer style inspired by Andrej Karpathy's https://github.com/karpathy/minGPT
15
+ * Bert reference code checks against Huggingface Transformers and Tensorflow Bert
16
+ Hacked together by / Copyright 2021 Ross Wightman
17
+
18
+ Modified by Botao Ye
19
+ """
20
+ import math
21
+ import torch
22
+ import torch.nn as nn
23
+ import torch.nn.functional as F
24
+ from functools import partial
25
+ import torch.utils.checkpoint as checkpoint
26
+ from timm.models.vision_transformer import DropPath, Mlp, trunc_normal_
27
+ from timm.models.layers import to_2tuple
28
+ from lib.models.aqatrack.base_backbone import BaseBackbone
29
+
30
+ class Attention(nn.Module):
31
+ def __init__(self, input_size, dim, num_heads, qkv_bias=True, qk_scale=None,
32
+ attn_drop=0., proj_drop=0., rpe=True):
33
+ super().__init__()
34
+ self.input_size = input_size
35
+ self.dim = dim
36
+ self.num_heads = num_heads
37
+ head_dim = dim // num_heads
38
+ self.scale = qk_scale or head_dim ** -0.5
39
+
40
+
41
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
42
+ self.attn_drop = nn.Dropout(attn_drop)
43
+ self.proj = nn.Linear(dim, dim)
44
+ self.proj_drop = nn.Dropout(proj_drop)
45
+ self.softmax = nn.Softmax(dim=-1)
46
+
47
+ def forward(self, x, rpe_index=None, mask=None):
48
+ B, N, C = x.shape
49
+ qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
50
+ q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple)
51
+
52
+ q = q * self.scale
53
+ attn = (q @ k.transpose(-2, -1))
54
+
55
+ attn = attn.float().clamp(min=torch.finfo(torch.float32).min, max=torch.finfo(torch.float32).max)
56
+ attn = self.softmax(attn)
57
+ attn = self.attn_drop(attn)
58
+
59
+ x = (attn @ v).transpose(1, 2).reshape(B, N, C)
60
+ x = self.proj(x)
61
+ x = self.proj_drop(x)
62
+ return x
63
+
64
+
65
+ class BlockWithRPE(nn.Module):
66
+ def __init__(self, input_size, dim, num_heads=0., mlp_ratio=4., qkv_bias=True, qk_scale=None,
67
+ drop=0., attn_drop=0., drop_path=0., rpe=True,
68
+ act_layer=nn.GELU, norm_layer=nn.LayerNorm):
69
+ super().__init__()
70
+ self.dim = dim
71
+ self.num_heads = num_heads
72
+ self.mlp_ratio = mlp_ratio
73
+
74
+ with_attn = num_heads > 0.
75
+
76
+ self.norm1 = norm_layer(dim) if with_attn else None
77
+ self.attn = Attention(
78
+ input_size, dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale,
79
+ attn_drop=attn_drop, proj_drop=drop, rpe=rpe,
80
+ ) if with_attn else None
81
+
82
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
83
+ self.norm2 = norm_layer(dim)
84
+ mlp_hidden_dim = int(dim * mlp_ratio)
85
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
86
+
87
+ def forward(self, x, rpe_index=None, mask=None):
88
+ if self.attn is not None:
89
+ x = x + self.drop_path(self.attn(self.norm1(x), rpe_index, mask))
90
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
91
+ return x
92
+
93
+
94
+ class PatchEmbed(nn.Module):
95
+ def __init__(self, img_size=224, patch_size=16, inner_patches=4, in_chans=3, embed_dim=96, norm_layer=None):
96
+ super().__init__()
97
+ img_size = to_2tuple(img_size)
98
+ patch_size = to_2tuple(patch_size)
99
+ patches_resolution = [img_size[0] // patch_size[0], img_size[1] // patch_size[1]]
100
+ self.img_size = img_size
101
+ self.patch_size = patch_size
102
+ self.inner_patches = inner_patches
103
+ self.patches_resolution = patches_resolution
104
+ self.num_patches = patches_resolution[0] * patches_resolution[1]
105
+
106
+ in_chans = 6
107
+ self.in_chans = in_chans
108
+ self.embed_dim = embed_dim
109
+
110
+ conv_size = [size // inner_patches for size in patch_size]
111
+ self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=conv_size, stride=conv_size)
112
+ if norm_layer is not None:
113
+ self.norm = norm_layer(embed_dim)
114
+ else:
115
+ self.norm = None
116
+
117
+ def forward(self, x):
118
+ B, C, H, W = x.shape
119
+ patches_resolution = (H // self.patch_size[0], W // self.patch_size[1])
120
+ num_patches = patches_resolution[0] * patches_resolution[1]
121
+ x = self.proj(x).view(
122
+ B, -1,
123
+ patches_resolution[0], self.inner_patches,
124
+ patches_resolution[1], self.inner_patches,
125
+ ).permute(0, 2, 4, 3, 5, 1).reshape(B, num_patches, self.inner_patches, self.inner_patches, -1)
126
+ if self.norm is not None:
127
+ x = self.norm(x)
128
+ return x
129
+
130
+
131
+ class PatchMerge(nn.Module):
132
+ def __init__(self, dim, norm_layer):
133
+ super().__init__()
134
+ self.norm = norm_layer(dim * 4)
135
+ self.reduction = nn.Linear(dim * 4, dim * 2, bias=False)
136
+
137
+ def forward(self, x):
138
+ x0 = x[..., 0::2, 0::2, :]
139
+ x1 = x[..., 1::2, 0::2, :]
140
+ x2 = x[..., 0::2, 1::2, :]
141
+ x3 = x[..., 1::2, 1::2, :]
142
+
143
+ x = torch.cat([x0, x1, x2, x3], dim=-1)
144
+ x = self.norm(x)
145
+ x = self.reduction(x)
146
+ return x
147
+
148
+
149
+ class HiViT(BaseBackbone):
150
+ def __init__(self, img_size=224, patch_size=16, in_chans=3, num_classes=1000,
151
+ embed_dim=512, depths=[4, 4, 20], num_heads=8, stem_mlp_ratio=3., mlp_ratio=4.,
152
+ qkv_bias=True, qk_scale=None, drop_rate=0., attn_drop_rate=0., drop_path_rate=0.0,
153
+ norm_layer=nn.LayerNorm, ape=True, rpe=True, patch_norm=True, use_checkpoint=False,
154
+ **kwargs):
155
+ super().__init__()
156
+ self.num_layers = len(depths)
157
+ self.ape = ape
158
+ self.rpe = rpe
159
+ self.patch_norm = patch_norm
160
+ self.num_features = self.embed_dim = embed_dim
161
+ self.mlp_ratio = mlp_ratio
162
+ self.use_checkpoint = use_checkpoint
163
+ self.num_main_blocks = depths[-1]
164
+
165
+ embed_dim = embed_dim // 2 ** (self.num_layers - 1)
166
+ # split image into non-overlapping patches
167
+ self.patch_embed = PatchEmbed(
168
+ img_size=img_size, patch_size=patch_size, in_chans=in_chans, embed_dim=embed_dim,
169
+ norm_layer=norm_layer if self.patch_norm else None)
170
+ num_patches = self.patch_embed.num_patches
171
+ Hp, Wp = self.patch_embed.patches_resolution
172
+ assert Hp == Wp
173
+
174
+ # absolute position embedding
175
+ if ape:
176
+ self.absolute_pos_embed = nn.Parameter(
177
+ torch.zeros(1, num_patches, self.num_features)
178
+ )
179
+ trunc_normal_(self.absolute_pos_embed, std=.02)
180
+ if rpe:
181
+ coords_h = torch.arange(Hp)
182
+ coords_w = torch.arange(Wp)
183
+ coords = torch.stack(torch.meshgrid([coords_h, coords_w]))
184
+ coords_flatten = torch.flatten(coords, 1)
185
+ relative_coords = coords_flatten[:, :, None] - coords_flatten[:, None, :]
186
+ relative_coords = relative_coords.permute(1, 2, 0).contiguous()
187
+ relative_coords[:, :, 0] += Hp - 1
188
+ relative_coords[:, :, 1] += Wp - 1
189
+ relative_coords[:, :, 0] *= 2 * Wp - 1
190
+ relative_position_index = relative_coords.sum(-1)
191
+ self.register_buffer("relative_position_index", relative_position_index)
192
+
193
+ self.pos_drop = nn.Dropout(p=drop_rate)
194
+
195
+ # stochastic depth
196
+ dpr = iter(x.item() for x in torch.linspace(0, drop_path_rate, sum(depths) + sum(depths[:-1]))) # stochastic depth decay rule
197
+
198
+ # build blocks
199
+ self.blocks = nn.ModuleList()
200
+ for stage_depth in depths:
201
+ is_main_stage = embed_dim == self.num_features
202
+ nhead = num_heads if is_main_stage else 0
203
+ ratio = mlp_ratio if is_main_stage else stem_mlp_ratio
204
+ # every block not in main stage include two mlp blocks
205
+ stage_depth = stage_depth if is_main_stage else stage_depth * 2
206
+ for i in range(stage_depth):
207
+ self.blocks.append(
208
+ BlockWithRPE(
209
+ Hp, embed_dim, nhead, ratio, qkv_bias, qk_scale,
210
+ drop=drop_rate, attn_drop=attn_drop_rate, drop_path=next(dpr),
211
+ rpe=rpe, norm_layer=norm_layer,
212
+ )
213
+ )
214
+ if not is_main_stage:
215
+ self.blocks.append(
216
+ PatchMerge(embed_dim, norm_layer)
217
+ )
218
+ embed_dim *= 2
219
+ self.norm_ = norm_layer(embed_dim)
220
+ # self.head = nn.Linear(self.num_features, num_classes) if num_classes > 0 else nn.Identity()
221
+
222
+ self.apply(self._init_weights)
223
+
224
+ def _init_weights(self, m):
225
+ if isinstance(m, nn.Linear):
226
+ trunc_normal_(m.weight, std=.02)
227
+ if isinstance(m, nn.Linear) and m.bias is not None:
228
+ nn.init.constant_(m.bias, 0)
229
+ elif isinstance(m, nn.LayerNorm):
230
+ nn.init.constant_(m.bias, 0)
231
+ nn.init.constant_(m.weight, 1.0)
232
+
233
+ @torch.jit.ignore
234
+ def no_weight_decay(self):
235
+ return {'absolute_pos_embed'}
236
+
237
+ @torch.jit.ignore
238
+ def no_weight_decay_keywords(self):
239
+ return {'relative_position_bias_table'}
240
+
241
+ def _create_vision_transformer(pretrained=False, default_cfg=None, **kwargs):
242
+
243
+ model = HiViT(**kwargs)
244
+
245
+ if pretrained:
246
+ checkpoint = torch.load(pretrained, map_location="cpu")
247
+ missing_keys, unexpected_keys = model.load_state_dict(checkpoint, strict=False)
248
+ print(missing_keys, unexpected_keys)
249
+ print('Load pretrained model from: ' + pretrained)
250
+
251
+ return model
252
+
253
+
254
+ def hivit_base(pretrained=False, **kwargs):
255
+ model_kwargs = dict(
256
+ embed_dim=512, depths=[2, 2, 20], num_heads=8, stem_mlp_ratio=3., mlp_ratio=4.,
257
+ rpe=False, norm_layer=partial(nn.LayerNorm, eps=1e-6),**kwargs
258
+ )
259
+ model = _create_vision_transformer(pretrained=pretrained, **model_kwargs)
260
+
261
+ return model
262
+
263
+ def hivit_small(pretrained=False, **kwargs):
264
+ model_kwargs = dict(
265
+ embed_dim=384, depths=[2, 2, 20], num_heads=6, stem_mlp_ratio=3., mlp_ratio=4.,
266
+ rpe=False, norm_layer=partial(nn.LayerNorm, eps=1e-6),**kwargs
267
+ )
268
+ model = _create_vision_transformer(pretrained=pretrained, **model_kwargs)
269
+
270
+ return model
lib/models/aqatrack/itpn.py ADDED
@@ -0,0 +1,430 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # --------------------------------------------------------
2
+ # BEIT: BERT Pre-Training of Image Transformers (https://arxiv.org/abs/2106.08254)
3
+ # Github source: https://github.com/microsoft/unilm/tree/master/beit
4
+ # Copyright (c) 2021 Microsoft
5
+ # Licensed under The MIT License [see LICENSE for details]
6
+ # By Yunjie Tian
7
+ # Based on timm and DeiT code bases
8
+ # https://github.com/rwightman/pytorch-image-models/tree/master/timm
9
+ # https://github.com/facebookresearch/deit/
10
+ # https://github.com/facebookresearch/dino
11
+ # --------------------------------------------------------'
12
+ from functools import partial
13
+
14
+ import math
15
+ import torch
16
+ import torch.nn as nn
17
+ from timm.models.registry import register_model
18
+ import torch.nn.functional as F
19
+ import torch.utils.checkpoint as checkpoint
20
+ from timm.models.vision_transformer import DropPath, Mlp, trunc_normal_
21
+ from timm.models.layers import to_2tuple
22
+ from lib.models.aqatrack.base_backbone import BaseBackbone
23
+ from lib.utils.utils import combine_tokens, recover_tokens
24
+
25
+ def _cfg(url='', **kwargs):
26
+ return {
27
+ 'url': url,
28
+ 'num_classes': 1000, 'input_size': (3, 224, 224), 'pool_size': None,
29
+ 'crop_pct': .9, 'interpolation': 'bicubic',
30
+ 'mean': (0.5, 0.5, 0.5), 'std': (0.5, 0.5, 0.5),
31
+ **kwargs
32
+ }
33
+
34
+
35
+ class Attention(nn.Module):
36
+ def __init__(self, input_size, dim, num_heads, qkv_bias=True, qk_scale=None, attn_drop=0., proj_drop=0., rpe=True):
37
+ super().__init__()
38
+ self.input_size = input_size
39
+ self.dim = dim
40
+ self.num_heads = num_heads
41
+ head_dim = dim // num_heads
42
+ self.scale = qk_scale or head_dim ** -0.5
43
+
44
+ # define a parameter table of relative position bias
45
+ self.relative_position_bias_table = nn.Parameter(
46
+ torch.zeros((2 * input_size - 1) * (2 * input_size - 1), num_heads)
47
+ ) if rpe else None
48
+
49
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
50
+ self.attn_drop = nn.Dropout(attn_drop)
51
+ self.proj = nn.Linear(dim, dim)
52
+ self.proj_drop = nn.Dropout(proj_drop)
53
+ self.softmax = nn.Softmax(dim=-1)
54
+
55
+ def forward(self, x, rpe_index=None, mask=None):
56
+ B, N, C = x.shape
57
+ qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
58
+ q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple)
59
+
60
+ q = q * self.scale
61
+ attn = (q @ k.transpose(-2, -1))
62
+
63
+ if rpe_index is not None:
64
+ S = int(math.sqrt(rpe_index.size(-1)))
65
+ relative_position_bias = self.relative_position_bias_table[rpe_index].view(-1, S, S, self.num_heads)
66
+ relative_position_bias = relative_position_bias.permute(0, 3, 1, 2).contiguous()
67
+ attn = attn + relative_position_bias
68
+ if mask is not None:
69
+ mask = mask.bool()
70
+ attn = attn.masked_fill(~mask[:, None, None, :], float("-inf"))
71
+ attn = attn.float().clamp(min=torch.finfo(torch.float32).min, max=torch.finfo(torch.float32).max)
72
+ attn = self.softmax(attn)
73
+ attn = self.attn_drop(attn)
74
+
75
+ x = (attn @ v).transpose(1, 2).reshape(B, N, C)
76
+ x = self.proj(x)
77
+ x = self.proj_drop(x)
78
+ return x
79
+
80
+
81
+ class BlockWithRPE(nn.Module):
82
+ def __init__(self, input_size, dim, num_heads=0., mlp_ratio=4., qkv_bias=True, qk_scale=None, init_values=None,
83
+ drop=0., attn_drop=0., drop_path=0., rpe=True, act_layer=nn.GELU, norm_layer=nn.LayerNorm):
84
+ super().__init__()
85
+ self.dim = dim
86
+ self.num_heads = num_heads
87
+ self.mlp_ratio = mlp_ratio
88
+
89
+ with_attn = num_heads > 0.
90
+
91
+ self.norm1 = norm_layer(dim) if with_attn else None
92
+ self.attn = Attention(
93
+ input_size, dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale,
94
+ attn_drop=attn_drop, proj_drop=drop, rpe=rpe,
95
+ ) if with_attn else None
96
+
97
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
98
+ self.norm2 = norm_layer(dim)
99
+ mlp_hidden_dim = int(dim * mlp_ratio)
100
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
101
+
102
+ if init_values is not None and init_values > 0:
103
+ if self.attn is not None:
104
+ self.gamma_1 = nn.Parameter(init_values * torch.ones((dim)), requires_grad=True)
105
+ else:
106
+ self.gamma_1 = None
107
+ self.gamma_2 = nn.Parameter(init_values * torch.ones((dim)), requires_grad=True)
108
+ else:
109
+ self.gamma_1, self.gamma_2 = None, None
110
+
111
+ def forward(self, x, rpe_index=None, mask=None):
112
+ if self.gamma_2 is None:
113
+ if self.attn is not None:
114
+ x = x + self.drop_path(self.attn(self.norm1(x), rpe_index, mask))
115
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
116
+ else:
117
+ if self.attn is not None:
118
+ x = x + self.drop_path(self.gamma_1 * self.attn(self.norm1(x), rpe_index, mask))
119
+ x = x + self.drop_path(self.gamma_2 * self.mlp(self.norm2(x)))
120
+ return x
121
+
122
+
123
+ class PatchEmbed(nn.Module):
124
+ def __init__(self, img_size=224, patch_size=16, inner_patches=4, in_chans=3, embed_dim=96, norm_layer=None):
125
+ super().__init__()
126
+ img_size = to_2tuple(img_size)
127
+ patch_size = to_2tuple(patch_size)
128
+ patches_resolution = [img_size[0] // patch_size[0], img_size[1] // patch_size[1]]
129
+ self.img_size = img_size
130
+ self.patch_size = patch_size
131
+ self.inner_patches = inner_patches
132
+ self.patches_resolution = self.patch_shape = patches_resolution
133
+ self.num_patches = patches_resolution[0] * patches_resolution[1]
134
+
135
+ in_chans = 6
136
+ self.in_chans = in_chans
137
+ self.embed_dim = embed_dim
138
+
139
+ conv_size = [size // inner_patches for size in patch_size]
140
+ self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=conv_size, stride=conv_size)
141
+ if norm_layer is not None:
142
+ self.norm = norm_layer(embed_dim)
143
+ else:
144
+ self.norm = None
145
+
146
+ def forward(self, x):
147
+ B, C, H, W = x.shape
148
+ patches_resolution = (H // self.patch_size[0], W // self.patch_size[1])
149
+ num_patches = patches_resolution[0] * patches_resolution[1]
150
+ x = self.proj(x).view(
151
+ B, -1,
152
+ patches_resolution[0], self.inner_patches,
153
+ patches_resolution[1], self.inner_patches,
154
+ ).permute(0, 2, 4, 3, 5, 1).reshape(B, num_patches, self.inner_patches, self.inner_patches, -1)
155
+ if self.norm is not None:
156
+ x = self.norm(x)
157
+ return x
158
+
159
+
160
+ # the spatial size are split into 4 patches (then downsample 2x)
161
+ # concat them and then reduce them to be of 2x channels.
162
+ #
163
+ class PatchMerge(nn.Module):
164
+ def __init__(self, dim, norm_layer):
165
+ super().__init__()
166
+ self.norm = norm_layer(dim * 4)
167
+ self.reduction = nn.Linear(dim * 4, dim * 2, bias=False)
168
+
169
+ def forward(self, x):
170
+ x0 = x[..., 0::2, 0::2, :]
171
+ x1 = x[..., 1::2, 0::2, :]
172
+ x2 = x[..., 0::2, 1::2, :]
173
+ x3 = x[..., 1::2, 1::2, :]
174
+
175
+ x = torch.cat([x0, x1, x2, x3], dim=-1)
176
+ x = self.norm(x)
177
+ x = self.reduction(x)
178
+ return x
179
+
180
+
181
+ # PatchSplit is for upsample
182
+ # used in FPN for downstream tasks such as detection/segmentation
183
+ class PatchSplit(nn.Module):
184
+ def __init__(self, dim, fpn_dim, norm_layer):
185
+ super().__init__()
186
+ self.norm = norm_layer(dim)
187
+ self.reduction = nn.Linear(dim, fpn_dim * 4, bias=False)
188
+ self.fpn_dim = fpn_dim
189
+
190
+ def forward(self, x):
191
+ B, N, H, W, C = x.shape
192
+ x = self.norm(x)
193
+ x = self.reduction(x)
194
+ x = x.reshape(
195
+ B, N, H, W, 2, 2, self.fpn_dim
196
+ ).permute(0, 1, 2, 4, 3, 5, 6).reshape(
197
+ B, N, 2 * H, 2 * W, self.fpn_dim
198
+ )
199
+ return x
200
+
201
+
202
+ class iTPN(BaseBackbone):
203
+ def __init__(self, img_size=224, patch_size=16, in_chans=3, num_classes=1000, fpn_dim=256, fpn_depth=2,
204
+ embed_dim=256, mlp_depth1=3, mlp_depth2=3, depth=24, num_heads=8, bridge_mlp_ratio=3., mlp_ratio=4.,
205
+ qkv_bias=True, qk_scale=None, drop_rate=0., attn_drop_rate=0., drop_path_rate=0.0, init_values=None,
206
+ norm_layer=nn.LayerNorm, ape=True, rpe=False, patch_norm=True, use_checkpoint=False,
207
+ num_outs=3, **kwargs):
208
+ super().__init__()
209
+ assert num_outs in [1, 2, 3, 4, 5]
210
+ self.num_classes = num_classes
211
+ self.ape = ape
212
+ self.rpe = rpe
213
+ self.patch_norm = patch_norm
214
+ self.num_features = self.embed_dim = embed_dim
215
+ self.mlp_ratio = mlp_ratio
216
+ self.use_checkpoint = use_checkpoint
217
+ self.num_outs = num_outs
218
+ self.num_main_blocks = depth
219
+ self.fpn_dim = fpn_dim
220
+ self.mlp_depth1 = mlp_depth1
221
+ self.mlp_depth2 = mlp_depth2
222
+ self.depth = depth
223
+
224
+ mlvl_dims = {'4': embed_dim // 4, '8': embed_dim // 2, '16': embed_dim}
225
+ # split image into non-overlapping patches
226
+ self.patch_embed = PatchEmbed(
227
+ img_size=img_size, patch_size=patch_size, in_chans=in_chans, embed_dim=mlvl_dims['4'],
228
+ norm_layer=norm_layer if self.patch_norm else None)
229
+ num_patches = self.patch_embed.num_patches
230
+ Hp, Wp = self.patch_embed.patches_resolution
231
+ assert Hp == Wp
232
+
233
+ # absolute position embedding
234
+ if ape:
235
+ self.absolute_pos_embed = nn.Parameter(
236
+ torch.zeros(1, num_patches, self.num_features)
237
+ )
238
+ trunc_normal_(self.absolute_pos_embed, std=.02)
239
+ if rpe:
240
+ coords_h = torch.arange(Hp)
241
+ coords_w = torch.arange(Wp)
242
+ coords = torch.stack(torch.meshgrid([coords_h, coords_w]))
243
+ coords_flatten = torch.flatten(coords, 1)
244
+ relative_coords = coords_flatten[:, :, None] - coords_flatten[:, None, :]
245
+ relative_coords = relative_coords.permute(1, 2, 0).contiguous()
246
+ relative_coords[:, :, 0] += Hp - 1
247
+ relative_coords[:, :, 1] += Wp - 1
248
+ relative_coords[:, :, 0] *= 2 * Wp - 1
249
+ relative_position_index = relative_coords.sum(-1)
250
+ self.register_buffer("relative_position_index", relative_position_index)
251
+
252
+ # Hp_z, Hp_z
253
+ coords_h = torch.arange(Hp)
254
+ coords_w = torch.arange(Wp)
255
+ coords = torch.stack(torch.meshgrid([coords_h, coords_w]))
256
+ coords_flatten = torch.flatten(coords, 1)
257
+ relative_coords = coords_flatten[:, :, None] - coords_flatten[:, None, :]
258
+ relative_coords = relative_coords.permute(1, 2, 0).contiguous()
259
+ relative_coords[:, :, 0] += Hp - 1
260
+ relative_coords[:, :, 1] += Wp - 1
261
+ relative_coords[:, :, 0] *= 2 * Wp - 1
262
+ relative_position_index = relative_coords.sum(-1)
263
+ self.register_buffer("relative_position_index", relative_position_index)
264
+
265
+ self.pos_drop = nn.Dropout(p=drop_rate)
266
+
267
+ dpr = iter(x.item() for x in torch.linspace(0, drop_path_rate, mlp_depth1 + mlp_depth2 + depth))
268
+ self.blocks = nn.ModuleList()
269
+
270
+ self.blocks.extend([
271
+ BlockWithRPE(
272
+ Hp, mlvl_dims['4'], 0, bridge_mlp_ratio, qkv_bias, qk_scale,
273
+ drop=drop_rate, attn_drop=attn_drop_rate, drop_path=next(dpr),
274
+ rpe=rpe, norm_layer=norm_layer, init_values=init_values
275
+ ) for _ in range(mlp_depth1)]
276
+ )
277
+ self.blocks.append(PatchMerge(mlvl_dims['4'], norm_layer))
278
+ self.blocks.extend([
279
+ BlockWithRPE(
280
+ Hp, mlvl_dims['8'], 0, bridge_mlp_ratio, qkv_bias, qk_scale,
281
+ drop=drop_rate, attn_drop=attn_drop_rate, drop_path=next(dpr),
282
+ rpe=rpe, norm_layer=norm_layer, init_values=init_values
283
+ ) for _ in range(mlp_depth2)]
284
+ )
285
+ self.blocks.append(PatchMerge(mlvl_dims['8'], norm_layer))
286
+ self.blocks.extend([
287
+ BlockWithRPE(
288
+ Hp, mlvl_dims['16'], num_heads, mlp_ratio, qkv_bias, qk_scale,
289
+ drop=drop_rate, attn_drop=attn_drop_rate, drop_path=next(dpr),
290
+ rpe=rpe, norm_layer=norm_layer, init_values=init_values
291
+ ) for _ in range(depth)]
292
+ )
293
+
294
+ self.norm_ = norm_layer(embed_dim)
295
+ self.apply(self._init_weights)
296
+
297
+ def _init_weights(self, m):
298
+ if isinstance(m, nn.Linear):
299
+ trunc_normal_(m.weight, std=.02)
300
+ if isinstance(m, nn.Linear) and m.bias is not None:
301
+ nn.init.constant_(m.bias, 0)
302
+ elif isinstance(m, nn.LayerNorm):
303
+ nn.init.constant_(m.bias, 0)
304
+ nn.init.constant_(m.weight, 1.0)
305
+
306
+ @torch.jit.ignore
307
+ def no_weight_decay(self):
308
+ return {'absolute_pos_embed'}
309
+
310
+ @torch.jit.ignore
311
+ def no_weight_decay_keywords(self):
312
+ return {'relative_position_bias_table'}
313
+
314
+ def interpolate_pos_encoding(self, x, h, w):
315
+ npatch = x.shape[1]
316
+ N = self.absolute_pos_embed.shape[1]
317
+ if npatch == N and w == h:
318
+ return self.absolute_pos_embed
319
+ patch_pos_embed = self.absolute_pos_embed
320
+ dim = x.shape[-1]
321
+ # we add a small number to avoid floating point error in the interpolation
322
+ # see discussion at https://github.com/facebookresearch/dino/issues/8
323
+ w0, h0 = w + 0.1, h + 0.1
324
+ patch_pos_embed = nn.functional.interpolate(
325
+ patch_pos_embed.reshape(1, int(math.sqrt(N)), int(math.sqrt(N)), dim).permute(0, 3, 1, 2),
326
+ scale_factor=(h0 / math.sqrt(N), w0 / math.sqrt(N)),
327
+ mode='bicubic',
328
+ )
329
+ assert int(h0) == patch_pos_embed.shape[-2] and int(w0) == patch_pos_embed.shape[-1]
330
+ patch_pos_embed = patch_pos_embed.permute(0, 2, 3, 1).view(1, -1, dim)
331
+ return patch_pos_embed
332
+
333
+ def get_num_layers(self):
334
+ return self.mlp_depth1 + self.mlp_depth2 + self.depth
335
+
336
+ def forward_features(self, z,x,soft_token_template_mask):
337
+ B, C, H, W = x.shape
338
+ Hp, Wp = H // self.patch_embed.patch_size[0], W // self.patch_embed.patch_size[1]
339
+
340
+ _, _, H_z, W_z = z.shape
341
+ Hp_z, Wp_z = H_z // self.patch_embed.patch_size[0], W_z // self.patch_embed.patch_size[1]
342
+
343
+ z = self.patch_embed(z)
344
+ x = self.patch_embed(x)
345
+
346
+ for blk in self.blocks[:-self.num_main_blocks]:
347
+ x = blk(x)
348
+ z = blk(z)
349
+
350
+ x = x[..., 0, 0, :]
351
+ z = z[..., 0, 0, :]
352
+
353
+ x += self.pos_embed_x
354
+ z += self.pos_embed_z
355
+
356
+ token_type_search = self.token_type_search.expand(B, x.shape[1], -1)
357
+ token_type_template_bg = self.token_type_template_bg.expand(B, z.shape[1], -1)
358
+ token_type_template_fg = self.token_type_template_fg.expand(B, z.shape[1], -1)
359
+
360
+ x += token_type_search
361
+
362
+ token_type_template_fg = soft_token_template_mask*token_type_template_fg
363
+ token_type_template_bg = (1- soft_token_template_mask) * token_type_template_bg
364
+ z += token_type_template_fg + token_type_template_bg
365
+
366
+ x = combine_tokens(z, x, mode=self.cat_mode)
367
+ if self.add_cls_token:
368
+ cls_tokens = self.cls_token.expand(B, -1, -1)
369
+ # cls_tokens = cls_tokens + self.cls_pos_embed
370
+ x = torch.cat([cls_tokens, x], dim=1)
371
+
372
+ x = self.pos_drop(x)
373
+
374
+ for blk in self.blocks[-self.num_main_blocks:]:
375
+ x = blk(x)
376
+
377
+ lens_z = self.pos_embed_z.shape[1]
378
+ lens_x = self.pos_embed_x.shape[1]
379
+ x = recover_tokens(x, lens_z, lens_x, mode=self.cat_mode)
380
+
381
+ aux_dict = {"attn": None}
382
+ x = self.norm_(x)
383
+
384
+ return x,aux_dict
385
+
386
+
387
+ def forward(self, z,x,soft_token_template_mask, **kwargs):
388
+ x,aux_dict = self.forward_features(z,x,soft_token_template_mask)
389
+ return x,aux_dict
390
+
391
+
392
+ @register_model
393
+ def itpn_base_3324_patch16_224(pretrained="", **kwargs):
394
+ model = iTPN(
395
+ patch_size=16, embed_dim=512, mlp_depth1=3, mlp_depth2=3, depth=24, num_heads=8, bridge_mlp_ratio=3.,
396
+ mlp_ratio=4, num_outs=1, norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)
397
+ model.default_cfg = _cfg()
398
+ if pretrained:
399
+ checkpoint = torch.load(
400
+ pretrained, map_location="cpu"
401
+ )
402
+ ###### naive method
403
+ # missing_keys, unexpected_keys = model.load_state_dict(checkpoint, strict=False)
404
+
405
+ #### process patch_embed.proj
406
+ normal_weights = {}
407
+ # special_weights = {}
408
+ for k, v in checkpoint.items():
409
+ if "patch_embed.proj.weight" in k:
410
+ normal_weights[k] = torch.cat([v, v], dim=1)
411
+ else:
412
+ normal_weights[k] = v
413
+
414
+ missing_keys, unexpected_keys = model.load_state_dict(normal_weights, strict=False)
415
+
416
+ return model
417
+
418
+
419
+ @register_model
420
+ def itpn_large_2240_patch16_224(pretrained=False, **kwargs):
421
+ model = iTPN(
422
+ patch_size=16, embed_dim=768, mlp_depth1=2, mlp_depth2=2, depth=40, num_heads=12, bridge_mlp_ratio=3.,
423
+ mlp_ratio=4, num_outs=1, norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)
424
+ model.default_cfg = _cfg()
425
+ if pretrained:
426
+ checkpoint = torch.load(
427
+ kwargs["init_ckpt"], map_location="cpu"
428
+ )
429
+ model.load_state_dict(checkpoint["model"])
430
+ return model
lib/models/aqatrack/utils.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+
3
+ import torch
4
+ import torch.nn.functional as F
5
+
6
+
7
+ def combine_tokens(template_tokens, search_tokens, mode='direct', return_res=False):
8
+ # [B, HW, C]
9
+ len_t = template_tokens.shape[1]
10
+ len_s = search_tokens.shape[1]
11
+
12
+ if mode == 'direct':
13
+ merged_feature = torch.cat((template_tokens, search_tokens), dim=1)
14
+ elif mode == 'template_central':
15
+ central_pivot = len_s // 2
16
+ first_half = search_tokens[:, :central_pivot, :]
17
+ second_half = search_tokens[:, central_pivot:, :]
18
+ merged_feature = torch.cat((first_half, template_tokens, second_half), dim=1)
19
+ elif mode == 'partition':
20
+ feat_size_s = int(math.sqrt(len_s))
21
+ feat_size_t = int(math.sqrt(len_t))
22
+ window_size = math.ceil(feat_size_t / 2.)
23
+ # pad feature maps to multiples of window size
24
+ B, _, C = template_tokens.shape
25
+ H = W = feat_size_t
26
+ template_tokens = template_tokens.view(B, H, W, C)
27
+ pad_l = pad_b = pad_r = 0
28
+ # pad_r = (window_size - W % window_size) % window_size
29
+ pad_t = (window_size - H % window_size) % window_size
30
+ template_tokens = F.pad(template_tokens, (0, 0, pad_l, pad_r, pad_t, pad_b))
31
+ _, Hp, Wp, _ = template_tokens.shape
32
+ template_tokens = template_tokens.view(B, Hp // window_size, window_size, W, C)
33
+ template_tokens = torch.cat([template_tokens[:, 0, ...], template_tokens[:, 1, ...]], dim=2)
34
+ _, Hc, Wc, _ = template_tokens.shape
35
+ template_tokens = template_tokens.view(B, -1, C)
36
+ merged_feature = torch.cat([template_tokens, search_tokens], dim=1)
37
+
38
+ # calculate new h and w, which may be useful for SwinT or others
39
+ merged_h, merged_w = feat_size_s + Hc, feat_size_s
40
+ if return_res:
41
+ return merged_feature, merged_h, merged_w
42
+
43
+ else:
44
+ raise NotImplementedError
45
+
46
+ return merged_feature
47
+
48
+
49
+ def recover_tokens(merged_tokens, len_template_token, len_search_token, mode='direct'):
50
+ if mode == 'direct':
51
+ recovered_tokens = merged_tokens
52
+ elif mode == 'template_central':
53
+ central_pivot = len_search_token // 2
54
+ len_remain = len_search_token - central_pivot
55
+ len_half_and_t = central_pivot + len_template_token
56
+
57
+ first_half = merged_tokens[:, :central_pivot, :]
58
+ second_half = merged_tokens[:, -len_remain:, :]
59
+ template_tokens = merged_tokens[:, central_pivot:len_half_and_t, :]
60
+
61
+ recovered_tokens = torch.cat((template_tokens, first_half, second_half), dim=1)
62
+ elif mode == 'partition':
63
+ recovered_tokens = merged_tokens
64
+ else:
65
+ raise NotImplementedError
66
+
67
+ return recovered_tokens
68
+
69
+
70
+ def window_partition(x, window_size: int):
71
+ """
72
+ Args:
73
+ x: (B, H, W, C)
74
+ window_size (int): window size
75
+
76
+ Returns:
77
+ windows: (num_windows*B, window_size, window_size, C)
78
+ """
79
+ B, H, W, C = x.shape
80
+ x = x.view(B, H // window_size, window_size, W // window_size, window_size, C)
81
+ windows = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(-1, window_size, window_size, C)
82
+ return windows
83
+
84
+
85
+ def window_reverse(windows, window_size: int, H: int, W: int):
86
+ """
87
+ Args:
88
+ windows: (num_windows*B, window_size, window_size, C)
89
+ window_size (int): Window size
90
+ H (int): Height of image
91
+ W (int): Width of image
92
+
93
+ Returns:
94
+ x: (B, H, W, C)
95
+ """
96
+ B = int(windows.shape[0] / (H * W / window_size / window_size))
97
+ x = windows.view(B, H // window_size, W // window_size, window_size, window_size, -1)
98
+ x = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(B, H, W, -1)
99
+ return x
lib/models/atctrack/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .atctrack import build_atctrack
lib/models/atctrack/atctrack.py ADDED
@@ -0,0 +1,1051 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ATCTrack Model
3
+ """
4
+ import os
5
+ import re
6
+ import base64
7
+ from io import BytesIO
8
+
9
+ import torch
10
+ import math
11
+ from torch import nn
12
+ import torch.nn.functional as F
13
+
14
+ from lib.utils.misc import NestedTensor
15
+
16
+ # from .language_model import build_bert
17
+ from lib.utils.box_ops import box_cxcywh_to_xyxy, box_xywh_to_xyxy, box_xyxy_to_cxcywh, box_iou
18
+ ### aqatrack
19
+ from lib.models.aqatrack.hivit import hivit_small, hivit_base
20
+ from lib.models.aqatrack.itpn import itpn_base_3324_patch16_224
21
+ from lib.models.aqatrack.fast_itpn import fast_itpn_base_3324_patch16_224,fast_itpn_large_2240_patch16_256
22
+
23
+ from lib.models.transformers.transformer import build_rgb_det_decoder
24
+ from lib.models.layers.transformer_dec import build_transformer_dec,build_transformer_dec_with_mask
25
+
26
+ from torch.nn.modules.transformer import _get_clones
27
+ from lib.models.layers.head import build_box_head
28
+
29
+ import torch.nn.functional as F
30
+ from lib.models.layers.frozen_bn import FrozenBatchNorm2d
31
+ from transformers import BertTokenizer, BertModel, RobertaModel, RobertaTokenizerFast, AutoTokenizer, AutoProcessor
32
+ from PIL import Image, ImageDraw
33
+ from lib.models.transformers import build_decoder, VisionLanguageFusionModule, PositionEmbeddingSine1D,build_text_prompt_decoder
34
+
35
+
36
+ TARGET_STATE_TOKEN = "<TARGET_STATE>"
37
+
38
+
39
+ def _project_root():
40
+ return os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../.."))
41
+
42
+
43
+ def _resolve_project_path(path):
44
+ if not path or os.path.isabs(path):
45
+ return path
46
+ candidate = os.path.abspath(os.path.join(_project_root(), path))
47
+ if os.path.exists(candidate) or path.startswith((".", "..", "checkpoint", "resource")):
48
+ return candidate
49
+ return path
50
+
51
+
52
+ def _load_qwen_target_state_model(model_path):
53
+ try:
54
+ from transformers import AutoModelForImageTextToText
55
+ model_cls = AutoModelForImageTextToText
56
+ except ImportError:
57
+ from transformers import AutoModelForCausalLM
58
+ model_cls = AutoModelForCausalLM
59
+
60
+ try:
61
+ return model_cls.from_pretrained(model_path, trust_remote_code=True)
62
+ except ValueError as exc:
63
+ raise RuntimeError(
64
+ "Cannot load Qwen target-state model. The current transformers package "
65
+ "does not recognize this Qwen architecture. Upgrade transformers in the "
66
+ "training environment before enabling MODEL.TARGET_STATE."
67
+ ) from exc
68
+
69
+
70
+ class QwenTargetStateEncoder(nn.Module):
71
+ def __init__(self, cfg, tracker_dim):
72
+ super().__init__()
73
+ ts_cfg = cfg.MODEL.TARGET_STATE
74
+ self.model_path = _resolve_project_path(os.environ.get("QWEN_MODEL_PATH", ts_cfg.MODEL_PATH))
75
+ self.token = getattr(ts_cfg, "TOKEN", TARGET_STATE_TOKEN)
76
+ self.prompt_template = getattr(ts_cfg, "PROMPT_TEMPLATE", "default")
77
+ self.train_token_embedding = getattr(ts_cfg, "TRAIN_TOKEN_EMBEDDING", False)
78
+ self.freeze_qwen = getattr(ts_cfg, "FREEZE_QWEN", True)
79
+ self.use_lora = getattr(ts_cfg, "USE_LORA", False)
80
+ self.lora_r = getattr(ts_cfg, "LORA_R", 8)
81
+ self.lora_alpha = getattr(ts_cfg, "LORA_ALPHA", 16)
82
+ self.lora_dropout = getattr(ts_cfg, "LORA_DROPOUT", 0.05)
83
+ self.lora_target_modules = getattr(ts_cfg, "LORA_TARGET_MODULES", [
84
+ "in_proj_qkv", "out_proj", "in_proj_z", "in_proj_b", "in_proj_a",
85
+ "q_proj", "k_proj", "v_proj", "o_proj",
86
+ "gate_proj", "up_proj", "down_proj",
87
+ ])
88
+ teacher_enable_env = os.environ.get("QWEN_TEACHER_ENABLE")
89
+ if teacher_enable_env is None:
90
+ self.teacher_enable = bool(getattr(ts_cfg, "TEACHER_ENABLE", False))
91
+ else:
92
+ self.teacher_enable = teacher_enable_env.strip().lower() in ("1", "true", "yes", "on")
93
+ self.teacher_model = os.environ.get("QWEN_TEACHER_MODEL", getattr(ts_cfg, "TEACHER_MODEL", "qwen3.5"))
94
+ self.teacher_base_url = os.environ.get("QWEN_TEACHER_BASE_URL", getattr(ts_cfg, "TEACHER_BASE_URL", "http://127.0.0.1:8001/v1"))
95
+ self.teacher_api_key = os.environ.get("QWEN_TEACHER_API_KEY", getattr(ts_cfg, "TEACHER_API_KEY", "sk-no-key-required"))
96
+ self.teacher_client = None
97
+
98
+ self.processor = AutoProcessor.from_pretrained(self.model_path, trust_remote_code=True)
99
+ self.tokenizer = getattr(self.processor, "tokenizer", None)
100
+ if self.tokenizer is None:
101
+ self.tokenizer = AutoTokenizer.from_pretrained(self.model_path, trust_remote_code=True)
102
+ if self.tokenizer.pad_token is None:
103
+ self.tokenizer.pad_token = self.tokenizer.eos_token
104
+ self.tokenizer.padding_side = "left"
105
+ self.qwen = _load_qwen_target_state_model(self.model_path)
106
+
107
+ self.target_state_special_tokens = ["<answer>", "</answer>", "<state_token>", "</state_token>", self.token]
108
+ special_tokens = {"additional_special_tokens": self.target_state_special_tokens}
109
+ num_added = self.tokenizer.add_special_tokens(special_tokens)
110
+ if num_added > 0:
111
+ self.qwen.resize_token_embeddings(len(self.tokenizer))
112
+ self.target_token_id = self.tokenizer.convert_tokens_to_ids(self.token)
113
+ self._embedding_grad_hook = None
114
+
115
+ qwen_hidden_dim = self.qwen.config.text_config.hidden_size if hasattr(self.qwen.config, "text_config") else self.qwen.config.hidden_size
116
+ self.projector = nn.Sequential(
117
+ nn.Linear(qwen_hidden_dim, tracker_dim),
118
+ nn.LayerNorm(tracker_dim),
119
+ nn.GELU(),
120
+ nn.Linear(tracker_dim, tracker_dim),
121
+ )
122
+ self.film = nn.Linear(tracker_dim, tracker_dim * 2)
123
+ self.film_gate = nn.Parameter(torch.zeros(1))
124
+
125
+ if self.freeze_qwen:
126
+ for p in self.qwen.parameters():
127
+ p.requires_grad = False
128
+ if self.use_lora:
129
+ self._enable_qwen_lora()
130
+ self.configure_token_embedding_training(self.train_token_embedding)
131
+
132
+ def _enable_qwen_lora(self):
133
+ try:
134
+ from peft import LoraConfig, get_peft_model
135
+ except ImportError as exc:
136
+ raise RuntimeError("MODEL.TARGET_STATE.USE_LORA=True requires the peft package.") from exc
137
+
138
+ target_modules = self.lora_target_modules
139
+ if isinstance(target_modules, str):
140
+ target_modules = [item.strip() for item in target_modules.split(",") if item.strip()]
141
+ config = LoraConfig(
142
+ r=self.lora_r,
143
+ lora_alpha=self.lora_alpha,
144
+ target_modules=list(target_modules),
145
+ lora_dropout=self.lora_dropout,
146
+ bias="none",
147
+ task_type="CAUSAL_LM",
148
+ )
149
+ self.qwen = get_peft_model(self.qwen, config)
150
+
151
+ def configure_token_embedding_training(self, enabled):
152
+ embedding = self.qwen.get_input_embeddings()
153
+ embedding.weight.requires_grad = bool(enabled)
154
+ if self._embedding_grad_hook is not None:
155
+ self._embedding_grad_hook.remove()
156
+ self._embedding_grad_hook = None
157
+ if enabled:
158
+ train_token_ids = torch.tensor([self.target_token_id], dtype=torch.long)
159
+
160
+ def mask_embedding_grad(grad):
161
+ token_ids = train_token_ids.to(grad.device)
162
+ mask = torch.zeros((grad.shape[0],), device=grad.device, dtype=grad.dtype)
163
+ mask.index_fill_(0, token_ids, 1)
164
+ return grad * mask.view(-1, 1)
165
+
166
+ self._embedding_grad_hook = embedding.weight.register_hook(mask_embedding_grad)
167
+
168
+ def _qwen_forward_with_target_embedding(self, tokenized, labels=None):
169
+ return self.qwen(**tokenized, labels=labels, output_hidden_states=True, use_cache=False)
170
+
171
+ @staticmethod
172
+ def _tensor_batch_to_pil(images, boxes=None):
173
+ mean = images.new_tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1)
174
+ std = images.new_tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1)
175
+ images = (images.detach().float() * std + mean).clamp(0, 1)
176
+ images = (images * 255).byte().permute(0, 2, 3, 1).cpu().numpy()
177
+ pil_images = [Image.fromarray(image) for image in images]
178
+
179
+ if boxes is None:
180
+ return pil_images
181
+
182
+ boxes = boxes.detach().float().cpu()
183
+ for image, box in zip(pil_images, boxes):
184
+ draw = ImageDraw.Draw(image)
185
+ x, y, w, h = box.tolist()
186
+ if max(abs(x), abs(y), abs(w), abs(h)) <= 2.0:
187
+ img_w, img_h = image.size
188
+ x, w = x * img_w, w * img_w
189
+ y, h = y * img_h, h * img_h
190
+ x1 = max(0.0, min(float(image.size[0] - 1), x))
191
+ y1 = max(0.0, min(float(image.size[1] - 1), y))
192
+ x2 = max(0.0, min(float(image.size[0] - 1), x + w))
193
+ y2 = max(0.0, min(float(image.size[1] - 1), y + h))
194
+ if x2 > x1 and y2 > y1:
195
+ line_width = max(2, round(min(image.size) / 80))
196
+ draw.rectangle([x1, y1, x2, y2], outline=(255, 0, 0), width=line_width)
197
+ return pil_images
198
+
199
+ def _build_prompt(self, caption, object_name=None):
200
+ caption = caption if caption else "the target object"
201
+ object_name = object_name if object_name else caption
202
+ return (
203
+ f"Role: {object_name} tracking update judge and target-state token generator.\n\n"
204
+ "Task: Compare the targets inside the provided bboxes in Frame 1 (Original) "
205
+ "and Frame 2 (New). Decide whether Frame 2 should update the tracking template, "
206
+ "and generate a target-state token for the tracking model.\n\n"
207
+ "Reject update for full occlusion, out of view, too small target, severe blur/clipping, "
208
+ "wrong bbox, distractor, uncertain identity, or no meaningful target appearance change.\n\n"
209
+ "Accept update only if Frame 2 contains the same target as Frame 1, the bbox is reliable, "
210
+ "the target is clear, and the appearance change is useful for future tracking.\n\n"
211
+ "The target-state token should summarize the current target condition for the tracking model. "
212
+ "It should encode whether the candidate is reliable, whether the target identity is consistent, "
213
+ "and whether the current appearance is useful or risky for tracking.\n\n"
214
+ "Frame 1 (Original) is the first image. Frame 2 (New candidate/search crop) is the second image.\n\n"
215
+ "Output exactly one answer XML tag containing yes or no, immediately followed by one "
216
+ "state_token XML tag containing the special target-state token. Do not output any extra text."
217
+ )
218
+
219
+ def _build_teacher_prompt(self, caption, object_name=None):
220
+ caption = caption if caption else "the target object"
221
+ object_name = object_name if object_name else caption
222
+ return (
223
+ f"Role: {object_name} tracking update judge.\n"
224
+ "Task: Compare the targets inside the provided bboxes in Frame 1 (Original) and Frame 2 (New), "
225
+ "and decide whether Frame 2 should update the tracking template.\n\n"
226
+ "Reject update for full occlusion, out of view, too small target, severe blur/clipping, wrong bbox, "
227
+ "distractor, uncertain identity, or no meaningful target appearance change.\n"
228
+ "Accept only if Frame 2 is the same target, bbox is reliable, target is clear, and appearance change is useful.\n\n"
229
+ "Output exactly: <answer>yes/no</answer>"
230
+ )
231
+
232
+ @staticmethod
233
+ def _pil_to_base64_jpeg(image):
234
+ buffer = BytesIO()
235
+ image.save(buffer, format="JPEG")
236
+ return base64.b64encode(buffer.getvalue()).decode("utf-8")
237
+
238
+ def _get_teacher_client(self):
239
+ if self.teacher_client is None:
240
+ try:
241
+ from openai import OpenAI
242
+ except ImportError as exc:
243
+ raise RuntimeError("Teacher update judge requires the openai package.") from exc
244
+ self.teacher_client = OpenAI(base_url=self.teacher_base_url, api_key=self.teacher_api_key, timeout=5.0)
245
+ return self.teacher_client
246
+
247
+ def _query_teacher_decisions(self, prompts, template_pils, search_pils):
248
+ if not self.teacher_enable:
249
+ return None, None
250
+ client = self._get_teacher_client()
251
+ decisions = []
252
+ responses = []
253
+ for prompt, template_pil, search_pil in zip(prompts, template_pils, search_pils):
254
+ base64_image1 = self._pil_to_base64_jpeg(template_pil)
255
+ base64_image2 = self._pil_to_base64_jpeg(search_pil)
256
+ messages = [{
257
+ "role": "user",
258
+ "content": [
259
+ {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image1}"}},
260
+ {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image2}"}},
261
+ {"type": "text", "text": prompt},
262
+ ],
263
+ }]
264
+ try:
265
+ chat_response = client.chat.completions.create(
266
+ model=self.teacher_model,
267
+ messages=messages,
268
+ max_tokens=32,
269
+ temperature=0.1,
270
+ top_p=1.0,
271
+ presence_penalty=0.0,
272
+ extra_body={
273
+ "top_k": 1,
274
+ "chat_template_kwargs": {"enable_thinking": False},
275
+ "guided_regex": r"<answer>(yes|no)</answer>",
276
+ },
277
+ )
278
+ content = chat_response.choices[0].message.content
279
+ match = re.findall(r"<answer>\s*(yes|no)\s*</answer>", content, flags=re.IGNORECASE)
280
+ if not match:
281
+ decisions.append(None)
282
+ else:
283
+ decisions.append(match[-1].lower() == "yes")
284
+ responses.append(content)
285
+ except Exception as exc:
286
+ print(f"Qwen teacher update judge failed: {exc}")
287
+ decisions.append(None)
288
+ responses.append(None)
289
+ return decisions, responses
290
+
291
+ @staticmethod
292
+ def _parse_update_decisions(decoded_outputs):
293
+ decisions = []
294
+ for text in decoded_outputs:
295
+ text_l = text.lower()
296
+ answer_start = text_l.rfind("<answer>")
297
+ answer_end = text_l.find("</answer>", answer_start + len("<answer>")) if answer_start >= 0 else -1
298
+ answer = text_l[answer_start + len("<answer>"):answer_end].strip() if answer_start >= 0 and answer_end >= 0 else text_l
299
+ answer = answer.replace("<|im_end|>", " ").replace("<|endoftext|>", " ")
300
+ tokens = answer.replace("<", " ").replace(">", " ").replace("/", " ").split()
301
+ if "yes" in tokens and "no" not in tokens:
302
+ decisions.append(True)
303
+ elif "no" in tokens:
304
+ decisions.append(False)
305
+ else:
306
+ decisions.append(False)
307
+ return decisions
308
+
309
+ def _apply_qwen_chat_template(self, message):
310
+ try:
311
+ return self.processor.apply_chat_template(
312
+ message,
313
+ tokenize=False,
314
+ add_generation_prompt=True,
315
+ enable_thinking=False,
316
+ )
317
+ except TypeError:
318
+ return self.processor.apply_chat_template(
319
+ message,
320
+ tokenize=False,
321
+ add_generation_prompt=True,
322
+ )
323
+
324
+ def _target_state_answer_sequences(self):
325
+ outputs = [
326
+ f"<answer>yes</answer><state_token>{self.token}</state_token>",
327
+ f"<answer>no</answer><state_token>{self.token}</state_token>",
328
+ ]
329
+ return [self.tokenizer(text, add_special_tokens=False).input_ids for text in outputs]
330
+
331
+ def _qwen_generate(self, **kwargs):
332
+ if self.training and hasattr(self.qwen, "get_base_model"):
333
+ base_model = self.qwen.get_base_model()
334
+ unwrapped = getattr(base_model.generate, "__wrapped__", None)
335
+ if unwrapped is not None:
336
+ with self.qwen._enable_peft_forward_hooks(**kwargs):
337
+ peft_args = getattr(self.qwen, "special_peft_forward_args", set())
338
+ clean_kwargs = {k: v for k, v in kwargs.items() if k not in peft_args}
339
+ return unwrapped(base_model, **clean_kwargs)
340
+
341
+ generate_fn = self.qwen.generate
342
+ if self.training:
343
+ unwrapped = getattr(generate_fn, "__wrapped__", None)
344
+ if unwrapped is not None:
345
+ return unwrapped(self.qwen, **kwargs)
346
+ return generate_fn(**kwargs)
347
+
348
+ def _qwen_generation_kwargs(self, prompt_len=None):
349
+ eos_token_ids = []
350
+ for token in ("<|im_end|>", "<|endoftext|>"):
351
+ token_id = self.tokenizer.convert_tokens_to_ids(token)
352
+ if isinstance(token_id, int) and token_id >= 0 and token_id != self.tokenizer.unk_token_id:
353
+ eos_token_ids.append(token_id)
354
+ if self.tokenizer.eos_token_id is not None:
355
+ eos_token_ids.append(self.tokenizer.eos_token_id)
356
+ eos_token_ids = list(dict.fromkeys(eos_token_ids))
357
+ kwargs = {
358
+ "max_new_tokens": 16,
359
+ "do_sample": False,
360
+ "num_beams": 1,
361
+ "repetition_penalty": 1.0,
362
+ "eos_token_id": eos_token_ids or self.tokenizer.eos_token_id,
363
+ "pad_token_id": self.tokenizer.pad_token_id,
364
+ }
365
+ if prompt_len is not None:
366
+ answer_sequences = self._target_state_answer_sequences()
367
+ stop_ids = eos_token_ids or [self.tokenizer.eos_token_id]
368
+
369
+ def prefix_allowed_tokens_fn(batch_id, input_ids):
370
+ suffix = input_ids[prompt_len:].tolist()
371
+ allowed = []
372
+ for sequence in answer_sequences:
373
+ if len(suffix) <= len(sequence) and suffix == sequence[:len(suffix)]:
374
+ if len(suffix) == len(sequence):
375
+ allowed.extend(stop_ids)
376
+ else:
377
+ allowed.append(sequence[len(suffix)])
378
+ return list(dict.fromkeys(allowed)) or stop_ids
379
+
380
+ kwargs["prefix_allowed_tokens_fn"] = prefix_allowed_tokens_fn
381
+ return kwargs
382
+
383
+ def _format_loss_from_generation_scores(self, scores, generated_suffix):
384
+ if scores is None or len(scores) == 0:
385
+ return generated_suffix.new_tensor(0.0, dtype=torch.float32)
386
+ num_steps = min(len(scores), generated_suffix.shape[1])
387
+ logits = torch.stack(scores[:num_steps], dim=1).float()
388
+ targets = generated_suffix[:, :num_steps]
389
+ return F.cross_entropy(
390
+ logits.reshape(-1, logits.shape[-1]),
391
+ targets.reshape(-1),
392
+ ignore_index=self.tokenizer.pad_token_id,
393
+ )
394
+
395
+ def _teacher_decision_loss(self, scores, teacher_decisions):
396
+ valid_items = [(idx, decision) for idx, decision in enumerate(teacher_decisions or []) if decision is not None]
397
+ if not valid_items or scores is None or len(scores) == 0:
398
+ device = scores[0].device if scores else self.qwen.get_input_embeddings().weight.device
399
+ return torch.tensor(0.0, device=device), None
400
+
401
+ yes_seq, no_seq = self._target_state_answer_sequences()
402
+ decision_step = next((i for i, (yes_id, no_id) in enumerate(zip(yes_seq, no_seq)) if yes_id != no_id), None)
403
+ if decision_step is None or decision_step >= len(scores):
404
+ return scores[0].new_tensor(0.0), None
405
+
406
+ batch_indices = torch.tensor([idx for idx, _ in valid_items], device=scores[decision_step].device, dtype=torch.long)
407
+ target_ids = torch.tensor(
408
+ [yes_seq[decision_step] if decision else no_seq[decision_step] for _, decision in valid_items],
409
+ device=scores[decision_step].device,
410
+ dtype=torch.long,
411
+ )
412
+ logits = scores[decision_step].float().index_select(0, batch_indices)
413
+ loss = F.cross_entropy(logits, target_ids)
414
+ labels = torch.full((len(teacher_decisions),), -1, device=scores[decision_step].device, dtype=torch.long)
415
+ labels[batch_indices] = torch.tensor([1 if decision else 0 for _, decision in valid_items], device=labels.device)
416
+ return loss, labels
417
+
418
+ def _target_hidden_from_generation(self, generation_hidden_states, generated_suffix):
419
+ target_mask = generated_suffix.eq(self.target_token_id)
420
+ if target_mask.any(dim=1).all():
421
+ target_pos = target_mask.float().argmax(dim=1)
422
+ else:
423
+ non_pad = generated_suffix.ne(self.tokenizer.pad_token_id)
424
+ target_pos = non_pad.sum(dim=1).clamp_min(1) - 1
425
+
426
+ hidden_steps = generation_hidden_states or []
427
+ if len(hidden_steps) == 0:
428
+ raise RuntimeError("Qwen generation did not return hidden states.")
429
+ h_targets = []
430
+ for batch_idx, pos in enumerate(target_pos.detach().cpu().tolist()):
431
+ # In cached generation, step t predicts generated token t. The hidden
432
+ # state for generated token k is available at step k + 1, when that
433
+ # token is fed back to predict the next token.
434
+ step = min(pos + 1, len(hidden_steps) - 1)
435
+ last_hidden = hidden_steps[step][-1]
436
+ h_targets.append(last_hidden[batch_idx, -1])
437
+ return torch.stack(h_targets, dim=0).float()
438
+
439
+ def forward(self, captions, template_images, search_images, template_boxes, search_boxes, device,
440
+ object_names=None, return_update_decision=False):
441
+ if object_names is None:
442
+ object_names = [None] * len(captions)
443
+ prompts = [self._build_prompt(caption, object_name) for caption, object_name in zip(captions, object_names)]
444
+ teacher_prompts = [self._build_teacher_prompt(caption, object_name) for caption, object_name in zip(captions, object_names)]
445
+ template_pils = self._tensor_batch_to_pil(template_images, template_boxes)
446
+ search_pils = self._tensor_batch_to_pil(search_images, search_boxes)
447
+ teacher_decisions, teacher_outputs = self._query_teacher_decisions(teacher_prompts, template_pils, search_pils)
448
+ messages = []
449
+ for prompt, template_pil, search_pil in zip(prompts, template_pils, search_pils):
450
+ messages.append([
451
+ {
452
+ "role": "user",
453
+ "content": [
454
+ {"type": "image", "image": template_pil},
455
+ {"type": "image", "image": search_pil},
456
+ {"type": "text", "text": prompt},
457
+ ],
458
+ }
459
+ ])
460
+ texts = [self._apply_qwen_chat_template(message) for message in messages]
461
+ images = [[template_pil, search_pil] for template_pil, search_pil in zip(template_pils, search_pils)]
462
+ tokenized = self.processor(text=texts, images=images, padding=True, return_tensors="pt").to(device)
463
+
464
+ generation = self._qwen_generate(
465
+ **tokenized,
466
+ **self._qwen_generation_kwargs(prompt_len=tokenized.input_ids.shape[1]),
467
+ return_dict_in_generate=True,
468
+ output_scores=True,
469
+ output_hidden_states=True,
470
+ )
471
+ generated_ids = generation.sequences
472
+ generated_suffix = generated_ids[:, tokenized.input_ids.shape[1]:]
473
+ decoded_outputs = self.tokenizer.batch_decode(generated_suffix, skip_special_tokens=False)
474
+ update_decisions = torch.tensor(
475
+ self._parse_update_decisions(decoded_outputs), device=device, dtype=torch.bool
476
+ )
477
+ qwen_format_loss = self._format_loss_from_generation_scores(generation.scores, generated_suffix)
478
+ qwen_teacher_loss, teacher_labels = self._teacher_decision_loss(generation.scores, teacher_decisions)
479
+ h_target = self._target_hidden_from_generation(generation.hidden_states, generated_suffix)
480
+ z_target = self.projector(h_target)
481
+ if return_update_decision:
482
+ return z_target, update_decisions, qwen_format_loss, qwen_teacher_loss, teacher_labels, teacher_outputs
483
+ return z_target
484
+
485
+ def modulate_feature(self, opt_feat, z_target):
486
+ gamma, beta = self.film(z_target).chunk(2, dim=-1)
487
+ gate = torch.tanh(self.film_gate)
488
+ gamma = gamma[:, :, None, None]
489
+ beta = beta[:, :, None, None]
490
+ return opt_feat * (1 + gate * gamma) + gate * beta
491
+ def conv(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1,
492
+ freeze_bn=False):
493
+ if freeze_bn:
494
+ return nn.Sequential(
495
+ nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride,
496
+ padding=padding, dilation=dilation, bias=True),
497
+ FrozenBatchNorm2d(out_planes),
498
+ nn.ReLU(inplace=True))
499
+ else:
500
+ return nn.Sequential(
501
+ nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride,
502
+ padding=padding, dilation=dilation, bias=True),
503
+ nn.BatchNorm2d(out_planes),
504
+ nn.ReLU(inplace=True))
505
+ class ConfidencePred(nn.Module):
506
+ def __init__(self):
507
+ super(ConfidencePred, self).__init__()
508
+ self.feat_sz = 24
509
+ self.stride = 1
510
+ self.img_sz = self.feat_sz * self.stride
511
+ freeze_bn = False
512
+
513
+ # CNN
514
+ self.conv1_ctr = conv(5, 16, freeze_bn=freeze_bn)
515
+ self.conv2_ctr = conv(16, 16 // 2, freeze_bn=freeze_bn)
516
+ self.conv3_ctr = conv(16 // 2, 16 // 4, freeze_bn=freeze_bn)
517
+ self.conv4_ctr = conv(16 // 4, 16 // 8, freeze_bn=freeze_bn)
518
+ self.conv5_ctr = nn.Conv2d(16 // 8, 1, kernel_size=1)
519
+
520
+ # 定义全连接层
521
+ self.fc1 = nn.Linear(256, 512)
522
+
523
+ ## cross attn 交互层
524
+ # self.multihead_attn = nn.MultiheadAttention(512, 4, dropout=0.1)
525
+ # # Implementation of Feedforward model
526
+ # self.dropout = nn.Dropout(0.1)
527
+ # self.norm1 = nn.LayerNorm(512)
528
+
529
+
530
+ self.fc2 = nn.Linear(512, 1)
531
+
532
+ # 定义激活函数
533
+ self.relu = nn.ReLU()
534
+ self.sigmoid = nn.Sigmoid()
535
+
536
+ for p in self.parameters():
537
+ if p.dim() > 1:
538
+ nn.init.xavier_uniform_(p)
539
+
540
+ def forward(self, x,xz_feature=None, gt_score_map=None):
541
+ """ Forward pass with input x. """
542
+
543
+ # ctr branch
544
+ x_ctr1 = self.conv1_ctr(x)
545
+ x_ctr2 = self.conv2_ctr(x_ctr1)
546
+ x_ctr3 = self.conv3_ctr(x_ctr2)
547
+ x_ctr4 = self.conv4_ctr(x_ctr3)
548
+ score_map_ctr = self.conv5_ctr(x_ctr4)
549
+
550
+ # 展平输入
551
+ x = score_map_ctr.flatten(1)
552
+ x = self.relu(self.fc1(x))
553
+
554
+ x = self.sigmoid(self.fc2(x))
555
+
556
+ return x
557
+
558
+ class SubjectIndexPred(nn.Module):
559
+ def __init__(self,dim):
560
+ super(SubjectIndexPred, self).__init__()
561
+
562
+ # 定义全连接层
563
+ self.fc1 = nn.Linear(dim, 256)
564
+ self.fc2 = nn.Linear(256, 128)
565
+ self.fc3 = nn.Linear(128, 1)
566
+ self.sigmoid = nn.Sigmoid()
567
+
568
+ for p in self.parameters():
569
+ if p.dim() > 1:
570
+ nn.init.xavier_uniform_(p)
571
+
572
+ def forward(self, x):
573
+ """ Forward pass with input x. """
574
+
575
+ # 全连接层前向传播
576
+ x = torch.relu(self.fc1(x))
577
+ x = torch.relu(self.fc2(x))
578
+ x = self.sigmoid(self.fc3(x))
579
+
580
+ return x
581
+
582
+
583
+ class ATCTrack(nn.Module):
584
+ """ This is the base class for ATCTrack"""
585
+ def __init__(self, transformer, box_head, tokenizer, text_encoder, aux_loss=False, head_type="CORNER",dim=512,cfg=None):
586
+ """ Initializes the model.
587
+ Parameters:
588
+ encoder: torch module of the encoder to be used. See encoder.py
589
+ decoder: torch module of the decoder architecture. See decoder.py
590
+ """
591
+ super().__init__()
592
+ self.backbone = transformer
593
+ self.box_head = box_head
594
+
595
+ self.aux_loss = aux_loss
596
+ self.head_type = head_type
597
+ if head_type == "CORNER" or head_type == "CENTER":
598
+ self.feat_sz_s = int(box_head.feat_sz)
599
+ self.feat_len_s = int(box_head.feat_sz ** 2)
600
+
601
+ if self.aux_loss:
602
+ self.box_head = _get_clones(self.box_head, 6)
603
+
604
+ self.dim = dim
605
+
606
+ self.query_len = 1
607
+ self.cls_prompts_pos = nn.Embedding(num_embeddings=self.query_len, embedding_dim=self.dim ) # pos for cur query
608
+ # self.cls_initial= nn.Embedding(num_embeddings=self.query_len, embedding_dim=self.dim ) # pos for cur query
609
+ self.confidence_pred = ConfidencePred()
610
+
611
+ ### visual temporal
612
+ self.visual_temporal_fusion = build_transformer_dec_with_mask(cfg, self.dim )
613
+ self.temporal_len = 4
614
+ self.dy_template_pos_embed = nn.Embedding(num_embeddings=self.temporal_len,
615
+ embedding_dim=self.dim ) # pos for cur query
616
+
617
+ ## invlove_text
618
+ self.tokenizer = tokenizer
619
+ self.text_encoder = text_encoder
620
+ self.text_adj = nn.Sequential(
621
+ nn.Linear(768, self.dim , bias=True),
622
+ nn.LayerNorm(self.dim , eps=1e-12),
623
+ nn.Dropout(0.1),
624
+ )
625
+
626
+ self.language_adjust = build_transformer_dec(cfg, self.dim )
627
+ self.vl_fusion = VisionLanguageFusionModule(dim=self.dim , num_heads=8, attn_drop=0.1, proj_drop=0.1,
628
+ num_vlfusion_layers=2,
629
+ vl_input_type='separate')
630
+
631
+ self.text_pos = PositionEmbeddingSine1D(self.dim , normalize=True)
632
+
633
+ self.text_sub_idnex_classifier = SubjectIndexPred(self.dim)
634
+
635
+ self.use_target_state = getattr(cfg.MODEL.TARGET_STATE, "ENABLE", False) if hasattr(cfg.MODEL, "TARGET_STATE") else False
636
+ if self.use_target_state:
637
+ self.target_state_encoder = QwenTargetStateEncoder(cfg, self.dim)
638
+ else:
639
+ self.target_state_encoder = None
640
+
641
+ def forward_backbone(self, template, search, cls_token,soft_token_template_mask,x_pos):
642
+ # template b, 12, h,w
643
+ # search b,6,h,w
644
+ template = [template[:,:3],template[:,3:]]
645
+ soft_token_template_mask = [soft_token_template_mask[:, :64], soft_token_template_mask[:, 64:]]
646
+
647
+ x, token_type_infor = self.backbone.forward_features_pe(z=template, x=search, soft_token_template_mask =soft_token_template_mask)
648
+ x, aux_dict = self.backbone.forward_features_stage3(x, cls_token,x_pos)
649
+ return x, aux_dict
650
+
651
+ def forward(self, template: torch.Tensor,
652
+ search: torch.Tensor,
653
+ soft_token_template_mask=None,
654
+ exp_str=None,
655
+ exp_subject_mask=None,
656
+ target_state_exp_str=None,
657
+ target_state_template_bbox=None,
658
+ target_state_new_template_bbox=None,
659
+ target_state_object_name=None,
660
+ temporal_infor=[],
661
+ first_frame_flag=False,
662
+ training=True):
663
+
664
+ b0, num_search = template[0].shape[0], len(search)
665
+ z_target = None
666
+ target_state_update_decision = None
667
+ qwen_format_loss = None
668
+ qwen_teacher_loss = None
669
+ qwen_teacher_labels = None
670
+ qwen_teacher_outputs = None
671
+ target_state_captions = target_state_exp_str if target_state_exp_str is not None else exp_str
672
+
673
+ if training:
674
+ search = torch.cat(search, dim=0)
675
+ if self.use_target_state and target_state_captions and len(template) >= 3:
676
+ z_target, target_state_update_decision, qwen_format_loss, qwen_teacher_loss, qwen_teacher_labels, qwen_teacher_outputs = self.target_state_encoder(
677
+ target_state_captions, template[-2], template[-1], target_state_template_bbox,
678
+ target_state_new_template_bbox, search.device, object_names=target_state_object_name,
679
+ return_update_decision=True
680
+ )
681
+ selector = target_state_update_decision.view(b0, 1, 1, 1)
682
+ dynamic_template = torch.where(selector, template[-1], template[-2])
683
+ dynamic_mask = torch.where(
684
+ target_state_update_decision.view(b0, 1, 1),
685
+ soft_token_template_mask[-1],
686
+ soft_token_template_mask[-2],
687
+ )
688
+ else:
689
+ dynamic_template = template[1]
690
+ dynamic_mask = soft_token_template_mask[1]
691
+ template = torch.cat([template[0], dynamic_template], dim=1)
692
+ soft_token_template_mask = torch.cat([soft_token_template_mask[0], dynamic_mask], dim=1)
693
+ template_temporal = []
694
+ soft_token_template_mask_temporal = []
695
+ for _ in range(num_search):
696
+ template_temporal.append(template)
697
+ soft_token_template_mask_temporal.append(soft_token_template_mask)
698
+ template_temporal = torch.cat(template_temporal, dim=0)
699
+ soft_token_template_mask_temporal = torch.cat(soft_token_template_mask_temporal,dim=0)
700
+
701
+ else:
702
+ b0 = 1
703
+ if self.use_target_state and target_state_captions and len(template) >= 3:
704
+ z_target, target_state_update_decision, qwen_format_loss, qwen_teacher_loss, qwen_teacher_labels, qwen_teacher_outputs = self.target_state_encoder(
705
+ target_state_captions, template[-2], template[-1], target_state_template_bbox,
706
+ target_state_new_template_bbox, search.device, object_names=target_state_object_name,
707
+ return_update_decision=True
708
+ )
709
+ dynamic_template = template[-1] if bool(target_state_update_decision[0].item()) else template[-2]
710
+ dynamic_mask = soft_token_template_mask[-1] if bool(target_state_update_decision[0].item()) else soft_token_template_mask[-2]
711
+ template_temporal = torch.cat([template[0], dynamic_template], dim=1)
712
+ soft_token_template_mask_temporal = torch.cat([soft_token_template_mask[0], dynamic_mask], dim=1)
713
+ else:
714
+ template_temporal = torch.cat(template[:2], dim=1)
715
+ soft_token_template_mask_temporal = torch.cat(soft_token_template_mask[:2], dim=1)
716
+
717
+ # x, aux_dict = self.backbone(z=template, x=search,
718
+ # soft_token_template_mask = soft_token_template_mask )
719
+ cls_prompts_pos = self.cls_prompts_pos.weight.unsqueeze(0)
720
+ x_pos_0 = torch.cat([cls_prompts_pos, self.backbone.pos_embed_z, self.backbone.pos_embed_x], dim=1)
721
+ # pos_embed = x_pos.transpose(0, 1).repeat(1, b0, 1)
722
+ x_pos = x_pos_0.repeat(b0*num_search, 1, 1)
723
+ x, aux_dict = self.forward_backbone(template_temporal, search, None, soft_token_template_mask_temporal,
724
+ x_pos)
725
+ # forward Language branch
726
+ if training:
727
+ if exp_str:
728
+ text_features, text_subject_features, subject_infor_mask_pred, subject_infor_mask_gt = self.forward_text(
729
+ exp_str, num_search, exp_subject_mask, device=search.device) # text_subject_features, subject_infor_mask_pred, subject_infor_mask_gt
730
+ else:
731
+ text_features = exp_str
732
+ text_subject_features = exp_subject_mask
733
+ subject_infor_mask_pred = None
734
+ subject_infor_mask_gt = None
735
+ if z_target is not None and z_target.shape[0] == b0 and num_search > 1:
736
+ z_target = torch.cat([z_target for _ in range(num_search)], dim=0)
737
+
738
+ batch_size = text_features.tensors.shape[0]
739
+ text_pos = self.text_pos(text_features) # [batch_size, length, c]
740
+ text_pos_0 = text_pos[:b0]
741
+ x_s_pos_item = x_pos_0.repeat(b0, 1, 1)[:, -self.feat_len_s:]
742
+ pre_temporal_pos = self.dy_template_pos_embed.weight.unsqueeze(1)
743
+ pre_temporal_pos = pre_temporal_pos.repeat(b0, 1, self.query_len)
744
+ pre_temporal_pos = pre_temporal_pos.view(b0, self.temporal_len * self.query_len, self.dim).contiguous()
745
+
746
+ # Forward temporal
747
+ xt_data = []
748
+ for temporal_index in range(num_search):
749
+ x_item = x[temporal_index * b0:(temporal_index + 1) * b0]
750
+
751
+ visual_prompts_token = x_item[:, :self.query_len, :]
752
+
753
+ ## heatmap by backbone feat
754
+ ## by attn
755
+ # attn_xz = attn[:, :, :-self.feat_len_s, -self.feat_len_s:] # b,h,l,l
756
+ # attn_xz_1 = attn_xz.mean(1).mean(1)
757
+ # # attn_xz = attn_xz.view(16, 16)
758
+ # # attn_weights_debug = attn_xz.detach().cpu().numpy()
759
+ x_f = x_item[:, -256:]
760
+ x_f1 = torch.matmul(x_f, x_f.permute(0, 2, 1).contiguous())
761
+ x_f = torch.matmul(x_f1, x_f)
762
+
763
+ z_f = x_item[:, :-256]
764
+
765
+ x_z = torch.matmul(x_f, z_f.permute(0, 2, 1).contiguous())
766
+ att_map = x_z.mean(-1)
767
+
768
+ tensor_min = torch.min(att_map)
769
+ tensor_max = torch.max(att_map)
770
+ # normalized_tensor = (s_vl_1 - tensor_min) / (tensor_max - tensor_min)
771
+ normalized_tensor = (tensor_max - att_map) / (tensor_max - tensor_min)
772
+
773
+ attn_xz = normalized_tensor.view(-1, 256,1).contiguous()
774
+
775
+ ### initialize & update memory
776
+ if training:
777
+ if temporal_index == 0:
778
+ temporal_infor = []
779
+ for _ in range(self.temporal_len):
780
+ temporal_infor.append(visual_prompts_token)
781
+ else:
782
+ if first_frame_flag:
783
+ temporal_infor = []
784
+ for _ in range(self.temporal_len):
785
+ temporal_infor.append(visual_prompts_token)
786
+
787
+ temporal_infor_data = torch.cat(temporal_infor, dim=1)
788
+
789
+ #### vl fusion ############
790
+ ## L adjust
791
+ l_item_initial = text_features.tensors[temporal_index * b0:(temporal_index + 1) * b0]
792
+ l_item_subject = text_subject_features.tensors[temporal_index * b0:(temporal_index + 1) * b0]
793
+ l_mask_item_0 = text_features.mask[temporal_index * b0:(temporal_index + 1) * b0]
794
+ temporal_mask = torch.ones((l_mask_item_0.shape[0],self.temporal_len)).bool().to(l_mask_item_0.device)
795
+ l_mask_item = torch.cat([l_mask_item_0, temporal_mask],dim=1)
796
+
797
+ l_subject_temporal = torch.cat([l_item_subject,temporal_infor_data],dim=1)
798
+ l_subject_temporal_pos = torch.cat([text_pos_0,pre_temporal_pos ],dim=1)
799
+
800
+ l_item_update,_ = self.language_adjust([l_item_initial,l_subject_temporal],None,
801
+ text_pos_0,l_subject_temporal_pos,l_mask_item)
802
+ l_all = torch.cat([ l_item_initial,l_item_update ],dim=1)
803
+ x_s_item = x_item[:, -self.feat_len_s:]
804
+ x_s_item = self.vl_fusion(x_s_item,
805
+ l_all,
806
+ query_pos=x_pos_0[:, -self.feat_len_s:],
807
+ memory_pos=torch.cat([text_pos_0,text_pos_0],dim=1),
808
+ memory_key_padding_mask=torch.cat([l_mask_item_0,l_mask_item_0],dim=1),
809
+ need_weights=False)
810
+
811
+
812
+ #### cross_attention with temporal_infor
813
+ temporal_infor_update = self.visual_temporal_fusion(temporal_infor_data, x_s_item, attn_xz,pre_temporal_pos ,kv_pos= x_s_pos_item )
814
+ temporal_item = temporal_infor_update[:,-1,:].unsqueeze(1)
815
+
816
+ # STM
817
+ enc_opt = x_s_item
818
+ dec_opt = temporal_item.transpose(1, 2)
819
+ att = torch.matmul(enc_opt, dec_opt)
820
+ opt = (enc_opt.unsqueeze(-1) * att.unsqueeze(-2)).permute((0, 3, 2, 1)).contiguous()
821
+ bs, Nq, C, HW = opt.size()
822
+ opt_feat = opt.view(-1, C, self.feat_sz_s, self.feat_sz_s)
823
+ if z_target is not None:
824
+ z_item = z_target[temporal_index * b0:(temporal_index + 1) * b0]
825
+ opt_feat = self.target_state_encoder.modulate_feature(opt_feat, z_item)
826
+
827
+ xt_data.append(opt_feat)
828
+
829
+ ### update temporal infor
830
+ if training:
831
+ if temporal_index == 0:
832
+ temporal_infor = []
833
+ for _ in range(self.temporal_len):
834
+ temporal_infor.append(temporal_item)
835
+ else:
836
+ temporal_infor[:-1] = temporal_infor[1:]
837
+ temporal_infor[-1] = temporal_item
838
+ else:
839
+ if first_frame_flag:
840
+ temporal_infor = []
841
+ for _ in range(self.temporal_len):
842
+ temporal_infor.append(temporal_item)
843
+
844
+ else:
845
+ temporal_infor[:-1] = temporal_infor[1:]
846
+ temporal_infor[-1] = temporal_item
847
+
848
+
849
+ # Forward head
850
+ xt_data = torch.cat(xt_data,dim=0)
851
+ out = self.forward_head(xt_data, None)
852
+
853
+ out.update(aux_dict)
854
+ out['backbone_feat'] = x
855
+ out['subject_infor_mask_pred'] = subject_infor_mask_pred
856
+ out['subject_infor_mask_gt'] = subject_infor_mask_gt
857
+ out['target_state_update_decision'] = target_state_update_decision
858
+ out['qwen_format_loss'] = qwen_format_loss
859
+ out['qwen_teacher_loss'] = qwen_teacher_loss
860
+ out['qwen_teacher_labels'] = qwen_teacher_labels
861
+ out['qwen_teacher_outputs'] = qwen_teacher_outputs
862
+
863
+ if training == False:
864
+ out["temporal_infor"] = temporal_infor
865
+
866
+ return out
867
+
868
+ def forward_head(self, opt_feat, gt_score_map=None):
869
+ """
870
+ cat_feature: output embeddings of the backbone, it can be (HW1+HW2, B, C) or (HW2, B, C)
871
+ """
872
+
873
+ # enc_opt = cat_feature #[:, -self.feat_len_s:] # encoder output for the search region (B, HW, C)
874
+ # opt = (enc_opt.unsqueeze(-1)).permute((0, 3, 2, 1)).contiguous()
875
+ # bs, Nq, C, HW = opt.size()
876
+ # opt_feat = opt.view(-1, C, self.feat_sz_s, self.feat_sz_s).contiguous()
877
+
878
+ bs = opt_feat.shape[0]
879
+ Nq = 1
880
+ # Head
881
+ if self.head_type == "CORNER":
882
+ # run the corner head
883
+ pred_box, score_map = self.box_head(opt_feat, True)
884
+ outputs_coord = box_xyxy_to_cxcywh(pred_box)
885
+ outputs_coord_new = outputs_coord.view(bs, Nq, 4).contiguous()
886
+ out = {'pred_boxes': outputs_coord_new,
887
+ 'score_map': score_map,
888
+ }
889
+ return out
890
+
891
+ elif self.head_type == "CENTER":
892
+ # run the center head
893
+ score_map_ctr, bbox, size_map, offset_map = self.box_head(opt_feat, gt_score_map)
894
+ # outputs_coord = box_xyxy_to_cxcywh(bbox)
895
+
896
+ score_map = torch.cat([score_map_ctr, size_map, offset_map], dim=1)
897
+ confidence_pred = self.confidence_pred(score_map)
898
+
899
+ outputs_coord = bbox
900
+ outputs_coord_new = outputs_coord.view(bs, Nq, 4).contiguous()
901
+ out = {'pred_boxes': outputs_coord_new,
902
+ 'score_map': score_map_ctr,
903
+ 'size_map': size_map,
904
+ 'offset_map': offset_map,
905
+ "confidence_pred": confidence_pred}
906
+ return out
907
+ else:
908
+ raise NotImplementedError
909
+
910
+ def forward_text(self, captions, num_search, exp_subject_mask, device):
911
+ tokenized = self.tokenizer(captions, padding=True, return_tensors="pt").to(device)
912
+ encoded_text = self.text_encoder(**tokenized)
913
+
914
+ text_attention_mask = tokenized.attention_mask.ne(1).bool()
915
+ # text_attention_mask: [batch_size, length]
916
+
917
+ text_features = encoded_text.last_hidden_state
918
+ text_features = self.text_adj(text_features)
919
+
920
+ encodings_infor = tokenized.encodings
921
+
922
+ subject_infor_mask_gt = None
923
+ if exp_subject_mask is not None:
924
+ # train: given the exp_subject_mask, used for generating sub_index_gt
925
+ subject_infor_mask_gt = torch.zeros(text_attention_mask.shape[0], text_attention_mask.shape[1]).to(
926
+ text_features.device)
927
+
928
+ for item_index, item in enumerate(encodings_infor):
929
+ word_ids_item = item.word_ids
930
+ exp_subject_mask_item = exp_subject_mask[item_index]
931
+ text_index_list = []
932
+ for word_index, word_item in enumerate(word_ids_item):
933
+ if word_item in exp_subject_mask_item:
934
+ text_index_list.append(word_index)
935
+
936
+ subject_infor_mask_gt[item_index, text_index_list] = 1
937
+
938
+ subject_infor_mask_pred = self.text_sub_idnex_classifier(text_features)
939
+ subject_infor_mask_pred_1 = subject_infor_mask_pred.expand_as(text_features)
940
+
941
+ subject_infor = text_features * subject_infor_mask_pred_1
942
+
943
+ # (B,L,D) to (T,B,L,D)
944
+ text_features_t = []
945
+ text_attention_mask_t = []
946
+ text_subject_infor_t = []
947
+ for i in range(num_search):
948
+ text_features_t.append(text_features)
949
+ text_attention_mask_t.append(text_attention_mask)
950
+ text_subject_infor_t.append(subject_infor)
951
+
952
+ text_features = torch.cat(text_features_t, dim=0)
953
+ text_attention_mask = torch.cat(text_attention_mask_t, dim=0)
954
+ text_features = NestedTensor(text_features, text_attention_mask)
955
+ subject_infor = torch.cat(text_subject_infor_t, dim=0)
956
+ subject_infor = NestedTensor(subject_infor, text_attention_mask)
957
+
958
+ return text_features, subject_infor, subject_infor_mask_pred, subject_infor_mask_gt
959
+
960
+
961
+ class MLP(nn.Module):
962
+ """ Very simple multi-layer perceptron (also called FFN)"""
963
+
964
+ def __init__(self, input_dim, hidden_dim, output_dim, num_layers):
965
+ super().__init__()
966
+ self.num_layers = num_layers
967
+ h = [hidden_dim] * (num_layers - 1)
968
+ self.layers = nn.ModuleList(nn.Linear(n, k) for n, k in zip([input_dim] + h, h + [output_dim]))
969
+
970
+ def forward(self, x):
971
+ for i, layer in enumerate(self.layers):
972
+ x = F.relu(layer(x)) if i < self.num_layers - 1 else layer(x)
973
+ return x
974
+
975
+ def build_atctrack(cfg, training=True):
976
+ current_dir = os.path.dirname(os.path.abspath(__file__)) # This is your Project Root
977
+ pretrained_path = os.path.join(current_dir, '../../../resource/pretrained_models')
978
+
979
+ if cfg.MODEL.PRETRAIN_FILE and training and ("ATCTrack" not in cfg.MODEL.PRETRAIN_FILE) :
980
+ pretrained = os.path.join(pretrained_path, cfg.MODEL.PRETRAIN_FILE)
981
+ else:
982
+ pretrained = ''
983
+
984
+
985
+ if cfg.MODEL.BACKBONE.TYPE == 'hivit_base_adaptor':
986
+ backbone = hivit_base(pretrained, drop_path_rate=cfg.TRAIN.DROP_PATH_RATE)
987
+ hidden_dim = backbone.embed_dim
988
+ patch_start_index = 1
989
+
990
+ elif cfg.MODEL.BACKBONE.TYPE == 'itpn_base': # by this
991
+ backbone = fast_itpn_base_3324_patch16_224(pretrained, drop_path_rate=cfg.TRAIN.DROP_PATH_RATE)
992
+ hidden_dim = backbone.embed_dim
993
+ patch_start_index = 1
994
+ elif cfg.MODEL.BACKBONE.TYPE == 'itpn_large': # by this
995
+ backbone = fast_itpn_large_2240_patch16_256(pretrained, drop_path_rate=cfg.TRAIN.DROP_PATH_RATE)
996
+ hidden_dim = backbone.embed_dim
997
+ patch_start_index = 1
998
+
999
+ else:
1000
+ raise NotImplementedError
1001
+
1002
+ backbone.finetune_track(cfg=cfg,dim=hidden_dim, patch_start_index=patch_start_index)
1003
+
1004
+ box_head = build_box_head(cfg, hidden_dim)
1005
+
1006
+ # Build Text Encoder
1007
+ roberta_path = _resolve_project_path(os.environ.get("ROBERTA_MODEL_PATH", os.path.join(pretrained_path, 'roberta-base')))
1008
+ tokenizer = RobertaTokenizerFast.from_pretrained(roberta_path) # load pretrained RoBERTa Tokenizer
1009
+ text_encoder = RobertaModel.from_pretrained(roberta_path) # load pretrained RoBERTa model
1010
+
1011
+
1012
+ model = ATCTrack(
1013
+ backbone,
1014
+ box_head,
1015
+ tokenizer,
1016
+ text_encoder,
1017
+ aux_loss=False,
1018
+ head_type=cfg.MODEL.HEAD.TYPE,
1019
+ dim = hidden_dim,
1020
+ cfg=cfg
1021
+ )
1022
+
1023
+ pretrained_checkpoint = _resolve_project_path(cfg.MODEL.PRETRAINED_PATH)
1024
+ if ("ATCTrack" in pretrained_checkpoint) and training:
1025
+ checkpoint = torch.load(pretrained_checkpoint, map_location="cpu", weights_only=False)
1026
+ ckpt = checkpoint["net"]
1027
+ model_weight = {}
1028
+ for k, v in ckpt.items():
1029
+ model_weight[k] = v
1030
+
1031
+ missing_keys, unexpected_keys = model.load_state_dict(model_weight, strict=False)
1032
+ print('Load pretrained model from: ' + cfg.MODEL.PRETRAIN_FILE)
1033
+
1034
+
1035
+ return model
1036
+
1037
+ def load_pretrained(model, pretrained_path, strict=False):
1038
+
1039
+ model_ckpt = torch.load(pretrained_path, map_location="cpu")
1040
+ state_dict = model_ckpt['net']
1041
+ pos_st = state_dict['encoder.body.pos_embed']
1042
+ pos_s = pos_st[:,:(pos_st.size(1) // 2)]
1043
+ pos_t = pos_st[:,(pos_st.size(1) // 2):]
1044
+ state_dict['encoder.body.pos_embed_search'] = pos_s
1045
+ state_dict['encoder.body.pos_embed_template'] = pos_t
1046
+ state_dict['encoder.body.patch_embed_interface.proj.weight'] = state_dict['encoder.body.patch_embed.proj.weight']
1047
+ state_dict['encoder.body.patch_embed_interface.proj.bias'] = state_dict['encoder.body.patch_embed.proj.bias']
1048
+ state_dict['decoder.embedding.prompt_embeddings.weight'] = model.state_dict()['decoder.embedding.prompt_embeddings.weight']
1049
+ state_dict['decoder.embedding.prompt_embeddings.weight'][:] = state_dict['decoder.embedding.word_embeddings.weight'][-1]
1050
+ del state_dict['encoder.body.pos_embed']
1051
+ model.load_state_dict(state_dict, strict=strict)
lib/models/atctrack/decoder.py ADDED
@@ -0,0 +1,331 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
2
+ """
3
+ """
4
+
5
+ import copy
6
+ from typing import Optional
7
+
8
+ import torch
9
+ import torch.nn.functional as F
10
+ from torch import Tensor
11
+ import torch.nn as nn
12
+
13
+
14
+ class DecoderEmbeddings(nn.Module):
15
+ def __init__(self, vocab_size, instruct_vocab_size, hidden_dim, max_position_embeddings, dropout):
16
+ super().__init__()
17
+ self.vocab_size = vocab_size
18
+ self.instruct_vocab_size = instruct_vocab_size
19
+ self.hidden_dim = hidden_dim
20
+ self.word_embeddings = nn.Embedding(
21
+ vocab_size, hidden_dim)
22
+ self.prompt_embeddings = nn.Embedding(
23
+ instruct_vocab_size, hidden_dim)
24
+ self.position_embeddings = nn.Embedding(
25
+ max_position_embeddings, hidden_dim
26
+ )
27
+
28
+ self.LayerNorm = torch.nn.LayerNorm(
29
+ hidden_dim)
30
+ self.dropout = nn.Dropout(dropout)
31
+
32
+ def forward(self, x):
33
+ # input_embeds = self.word_embeddings(x)
34
+ # embeddings = input_embeds
35
+
36
+ use_word_embeddings = (x < self.vocab_size)
37
+ use_prompt_embeddings = ~use_word_embeddings
38
+
39
+ embeddings = torch.zeros([x.size(0),x.size(1),self.hidden_dim], dtype=torch.float32).to(x.device)
40
+ embeddings[use_word_embeddings] = self.word_embeddings(x[use_word_embeddings])
41
+ embeddings[use_prompt_embeddings] = self.prompt_embeddings(x[use_prompt_embeddings]-self.vocab_size)
42
+
43
+
44
+ embeddings = self.LayerNorm(embeddings)
45
+ embeddings = self.dropout(embeddings)
46
+
47
+ return embeddings
48
+
49
+
50
+ class SeqTrackDecoder(nn.Module):
51
+
52
+ def __init__(self, d_model=512, nhead=8,
53
+ num_decoder_layers=6, dim_feedforward=2048, dropout=0.1,
54
+ activation="relu", normalize_before=False,
55
+ return_intermediate_dec=False, bins=1000, num_frames=9,
56
+ instruct=True):
57
+ super().__init__()
58
+ self.bins = bins
59
+
60
+ self.instruct = instruct
61
+
62
+ self.instruct_tokens = {
63
+ 'end': bins,
64
+ 'lasot': bins+1,
65
+ 'trackingnet': bins+1,
66
+ 'got10k': bins+1,
67
+ 'coco': bins+1,
68
+ 'depthtrack': bins+2,
69
+ 'lasher': bins+3,
70
+ 'visevent': bins+4,
71
+ 'otb99_lang': bins+5,
72
+ 'refcocog': bins+5,
73
+ 'tnl2k': bins+5,
74
+ 'lasot_lang': bins+5
75
+ }
76
+ instruct_vocab_size = 4 # should be consistent with new tokens in self.instruct_tokens
77
+
78
+ self.num_frames = num_frames
79
+ self.num_coordinates = 4 # [x,y,w,h]
80
+ max_position_embeddings = (self.num_coordinates+1) * num_frames
81
+ self.embedding = DecoderEmbeddings(bins+2, instruct_vocab_size, d_model, max_position_embeddings, dropout)
82
+
83
+ decoder_layer = TransformerDecoderLayer(d_model, nhead, dim_feedforward,
84
+ dropout, activation, normalize_before)
85
+ decoder_norm = nn.LayerNorm(d_model)
86
+ self.body = TransformerDecoder(decoder_layer, num_decoder_layers, decoder_norm,
87
+ return_intermediate=return_intermediate_dec)
88
+
89
+ self._reset_parameters()
90
+
91
+ self.d_model = d_model
92
+ self.nhead = nhead
93
+
94
+ def _reset_parameters(self):
95
+ for p in self.parameters():
96
+ if p.dim() > 1:
97
+ nn.init.xavier_uniform_(p)
98
+
99
+ def forward(self, src, pos_embed, seq):
100
+ # flatten NxCxHxW to HWxNxC
101
+ n, bs, c = src.shape
102
+ if not self.instruct:
103
+ seq[:, 0] = self.bins+1
104
+ tgt = self.embedding(seq).permute(1, 0, 2)
105
+
106
+ query_embed = self.embedding.position_embeddings.weight.unsqueeze(1)
107
+ query_embed = query_embed.repeat(1, bs, 1)
108
+
109
+ memory = src
110
+
111
+ tgt_mask = generate_square_subsequent_mask(len(tgt)).to(tgt.device) #generate the causal mask
112
+
113
+ hs = self.body(tgt, memory, pos=pos_embed, query_pos=query_embed[:len(tgt)],
114
+ tgt_mask=tgt_mask, memory_mask=None)
115
+
116
+ return hs.transpose(1, 2)
117
+
118
+
119
+ def inference(self, src, pos_embed, seq, vocab_embed,
120
+ window, seq_format):
121
+ if not self.instruct:
122
+ seq[:, 0] = self.bins+1
123
+ # flatten NxCxHxW to HWxNxC
124
+ n, bs, c = src.shape
125
+ memory = src
126
+ confidence_list = []
127
+ box_pos = [0, 1, 2, 3] # the position of bounding box
128
+ center_pos = [0, 1] # the position of x_center and y_center
129
+ if seq_format == 'whxy':
130
+ center_pos = [2, 3]
131
+
132
+ for i in range(self.num_coordinates): # only cycle 4 times, because we do not need to predict the end token during inference
133
+ tgt = self.embedding(seq).permute(1, 0, 2)
134
+ query_embed = self.embedding.position_embeddings.weight.unsqueeze(1)
135
+ query_embed = query_embed.repeat(1, bs, 1)
136
+ tgt_mask = generate_square_subsequent_mask(len(tgt)).to(tgt.device)
137
+
138
+ hs = self.body(tgt, memory, pos=pos_embed[:len(memory)], query_pos=query_embed[:len(tgt)],
139
+ tgt_mask=tgt_mask, memory_mask=None)
140
+
141
+ # embedding --> likelihood
142
+ out = vocab_embed(hs.transpose(1, 2)[-1, :, -1, :])
143
+ out = out.softmax(-1)
144
+
145
+ if i in box_pos:
146
+ out = out[:, :self.bins] # only include the coordinate values' confidence
147
+
148
+ if ((i in center_pos) and (window!=None)):
149
+ out = out * window # window penalty
150
+
151
+ confidence, token_generated = out.topk(dim=-1, k=1)
152
+ seq = torch.cat([seq, token_generated], dim=-1)
153
+ confidence_list.append(confidence)
154
+
155
+ out_dict = {}
156
+ out_dict['pred_boxes'] = seq[:, -self.num_coordinates:] # Discard the START token, only get the bounding box
157
+ out_dict['confidence'] = torch.cat(confidence_list, dim=-1)[:, :]
158
+
159
+ return out_dict
160
+
161
+
162
+
163
+
164
+ def generate_square_subsequent_mask(sz):
165
+ r"""Generate a square mask for the sequence. The masked positions are filled with float('-inf').
166
+ Unmasked positions are filled with float(0.0).
167
+ """
168
+
169
+ #each token only can see tokens before them
170
+ mask = (torch.triu(torch.ones(sz, sz)) == 1).transpose(0, 1)
171
+ mask = mask.float().masked_fill(mask == 0, float(
172
+ '-inf')).masked_fill(mask == 1, float(0.0))
173
+ return mask
174
+
175
+ class TransformerDecoder(nn.Module):
176
+
177
+ def __init__(self, decoder_layer, num_layers, norm=None, return_intermediate=False):
178
+ super().__init__()
179
+ self.layers = _get_clones(decoder_layer, num_layers)
180
+ self.num_layers = num_layers
181
+ self.norm = norm
182
+ self.return_intermediate = return_intermediate
183
+
184
+ def forward(self, tgt, memory,
185
+ tgt_mask: Optional[Tensor] = None,
186
+ memory_mask: Optional[Tensor] = None,
187
+ tgt_key_padding_mask: Optional[Tensor] = None,
188
+ memory_key_padding_mask: Optional[Tensor] = None,
189
+ pos: Optional[Tensor] = None,
190
+ query_pos: Optional[Tensor] = None):
191
+ output = tgt
192
+
193
+ intermediate = []
194
+
195
+ for layer in self.layers:
196
+ output = layer(output, memory, tgt_mask=tgt_mask,
197
+ memory_mask=memory_mask,
198
+ tgt_key_padding_mask=tgt_key_padding_mask,
199
+ memory_key_padding_mask=memory_key_padding_mask,
200
+ pos=pos, query_pos=query_pos)
201
+
202
+ if self.return_intermediate:
203
+ intermediate.append(self.norm(output))
204
+
205
+ if self.norm is not None:
206
+ output = self.norm(output)
207
+ if self.return_intermediate:
208
+ intermediate.pop()
209
+ intermediate.append(output)
210
+
211
+ if self.return_intermediate:
212
+ return torch.stack(intermediate)
213
+
214
+ return output.unsqueeze(0)
215
+
216
+
217
+ class TransformerDecoderLayer(nn.Module):
218
+
219
+ def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1,
220
+ activation="relu", normalize_before=False):
221
+ super().__init__()
222
+ self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
223
+ self.multihead_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
224
+ # Implementation of Feedforward model
225
+ self.linear1 = nn.Linear(d_model, dim_feedforward)
226
+ self.dropout = nn.Dropout(dropout)
227
+ self.linear2 = nn.Linear(dim_feedforward, d_model)
228
+
229
+ self.norm1 = nn.LayerNorm(d_model)
230
+ self.norm2 = nn.LayerNorm(d_model)
231
+ self.norm3 = nn.LayerNorm(d_model)
232
+ self.dropout1 = nn.Dropout(dropout)
233
+ self.dropout2 = nn.Dropout(dropout)
234
+ self.dropout3 = nn.Dropout(dropout)
235
+
236
+ self.activation = _get_activation_fn(activation)
237
+ self.normalize_before = normalize_before
238
+
239
+ def with_pos_embed(self, tensor, pos: Optional[Tensor]):
240
+ return tensor if pos is None else tensor + pos
241
+
242
+ def forward_post(self, tgt, memory,
243
+ tgt_mask: Optional[Tensor] = None,
244
+ memory_mask: Optional[Tensor] = None,
245
+ tgt_key_padding_mask: Optional[Tensor] = None,
246
+ memory_key_padding_mask: Optional[Tensor] = None,
247
+ pos: Optional[Tensor] = None,
248
+ query_pos: Optional[Tensor] = None):
249
+ q = k = self.with_pos_embed(tgt, query_pos)
250
+ tgt2 = self.self_attn(q, k, tgt, attn_mask=tgt_mask,
251
+ key_padding_mask=tgt_key_padding_mask)[0]
252
+ tgt = tgt + self.dropout1(tgt2)
253
+ tgt = self.norm1(tgt)
254
+ tgt2 = self.multihead_attn(self.with_pos_embed(tgt, query_pos),
255
+ self.with_pos_embed(memory, pos),
256
+ memory, attn_mask=memory_mask,
257
+ key_padding_mask=memory_key_padding_mask)[0]
258
+
259
+ tgt = tgt + self.dropout2(tgt2)
260
+ tgt = self.norm2(tgt)
261
+ tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt))))
262
+ tgt = tgt + self.dropout3(tgt2)
263
+ tgt = self.norm3(tgt)
264
+
265
+ return tgt
266
+
267
+ def forward_pre(self, tgt, memory,
268
+ tgt_mask: Optional[Tensor] = None,
269
+ memory_mask: Optional[Tensor] = None,
270
+ tgt_key_padding_mask: Optional[Tensor] = None,
271
+ memory_key_padding_mask: Optional[Tensor] = None,
272
+ pos: Optional[Tensor] = None,
273
+ query_pos: Optional[Tensor] = None):
274
+ tgt2 = self.norm1(tgt)
275
+ q = k = self.with_pos_embed(tgt2, query_pos)
276
+ tgt2 = self.self_attn(q, k, tgt2, attn_mask=tgt_mask,
277
+ key_padding_mask=tgt_key_padding_mask)[0]
278
+ tgt = tgt + self.dropout1(tgt2)
279
+ tgt2 = self.norm2(tgt)
280
+ tgt2 = self.multihead_attn(self.with_pos_embed(tgt2, query_pos),
281
+ self.with_pos_embed(memory, pos),
282
+ memory, attn_mask=memory_mask,
283
+ key_padding_mask=memory_key_padding_mask)[0]
284
+ tgt = tgt + self.dropout2(tgt2)
285
+ tgt2 = self.norm3(tgt)
286
+ tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt2))))
287
+ tgt = tgt + self.dropout3(tgt2)
288
+ return tgt
289
+
290
+ def forward(self, tgt, memory,
291
+ tgt_mask: Optional[Tensor] = None,
292
+ memory_mask: Optional[Tensor] = None,
293
+ tgt_key_padding_mask: Optional[Tensor] = None,
294
+ memory_key_padding_mask: Optional[Tensor] = None,
295
+ pos: Optional[Tensor] = None,
296
+ query_pos: Optional[Tensor] = None):
297
+ if self.normalize_before:
298
+ return self.forward_pre(tgt, memory, tgt_mask, memory_mask,
299
+ tgt_key_padding_mask, memory_key_padding_mask, pos, query_pos)
300
+ return self.forward_post(tgt, memory, tgt_mask, memory_mask,
301
+ tgt_key_padding_mask, memory_key_padding_mask, pos, query_pos)
302
+
303
+
304
+ def _get_clones(module, N):
305
+ return nn.ModuleList([copy.deepcopy(module) for i in range(N)])
306
+
307
+
308
+ def build_decoder(cfg):
309
+ return SeqTrackDecoder(
310
+ d_model=cfg.MODEL.HIDDEN_DIM,
311
+ dropout=cfg.MODEL.DECODER.DROPOUT,
312
+ nhead=cfg.MODEL.DECODER.NHEADS,
313
+ dim_feedforward=cfg.MODEL.DECODER.DIM_FEEDFORWARD,
314
+ num_decoder_layers=cfg.MODEL.DECODER.DEC_LAYERS,
315
+ normalize_before=cfg.MODEL.DECODER.PRE_NORM,
316
+ return_intermediate_dec=False,
317
+ bins=cfg.MODEL.BINS,
318
+ num_frames=cfg.DATA.SEARCH.NUMBER,
319
+ instruct=cfg.MODEL.DECODER.INSTRUCT
320
+ )
321
+
322
+
323
+ def _get_activation_fn(activation):
324
+ """Return an activation function given a string"""
325
+ if activation == "relu":
326
+ return F.relu
327
+ if activation == "gelu":
328
+ return F.gelu
329
+ if activation == "glu":
330
+ return F.glu
331
+ raise RuntimeError(F"activation should be relu/gelu, not {activation}.")
lib/models/atctrack/encoder.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Encoder modules: we use ViT for the encoder.
3
+ """
4
+
5
+ from torch import nn
6
+ from lib.utils.misc import is_main_process
7
+ from lib.models.atctrack import vit as vit_module
8
+ from lib.models.atctrack import vit_mm as vitmm_module
9
+
10
+
11
+
12
+
13
+ class EncoderBase(nn.Module):
14
+
15
+ def __init__(self, encoder: nn.Module, train_encoder: bool, open_layers: list, num_channels: int):
16
+ super().__init__()
17
+ open_blocks = open_layers[2:]
18
+ open_items = open_layers[0:2]
19
+ for name, parameter in encoder.named_parameters():
20
+
21
+ if not train_encoder:
22
+ freeze = True
23
+ for open_block in open_blocks:
24
+ if open_block in name:
25
+ freeze = False
26
+ if name in open_items:
27
+ freeze = False
28
+ if freeze == True:
29
+ parameter.requires_grad_(False) # here should allow users to specify which layers to freeze !
30
+
31
+ self.body = encoder
32
+ self.num_channels = num_channels
33
+
34
+ def forward(self, template_list, search_list, text_src, seq):
35
+ xs = self.body(template_list, search_list, text_src, seq)
36
+ return xs
37
+
38
+ def forward_rgb(self, template_list, search_list):
39
+ xs = self.body.forward_rgb(template_list, search_list)
40
+ return xs
41
+
42
+
43
+ class Encoder(EncoderBase):
44
+ """ViT encoder."""
45
+ def __init__(self, name: str,
46
+ train_encoder: bool,
47
+ pretrain_type: str,
48
+ search_size: int,
49
+ search_number: int,
50
+ template_size: int,
51
+ template_number: int,
52
+ open_layers: list,
53
+ cfg=None):
54
+ if "vitmm" in name.lower():
55
+ encoder = getattr(vitmm_module, name)(pretrained=is_main_process(), pretrain_type=pretrain_type,
56
+ search_size=search_size, template_size=template_size,
57
+ search_number=search_number, template_number=template_number,
58
+ drop_path_rate=cfg.MODEL.ENCODER.DROP_PATH,
59
+ use_checkpoint=cfg.MODEL.ENCODER.USE_CHECKPOINT,
60
+ interface_type=cfg.MODEL.INTERFACE_TYPE,
61
+ interface_dim=cfg.MODEL.INTERFACE_DIM,
62
+ instruct=cfg.MODEL.ENCODER.INSTRUCT)
63
+ if "_base_" in name:
64
+ num_channels = 768
65
+ elif "_large_" in name:
66
+ num_channels = 1024
67
+ elif "_huge_" in name:
68
+ num_channels = 1280
69
+ else:
70
+ num_channels = 768
71
+ elif "vit" in name.lower():
72
+ encoder = getattr(vit_module, name)(pretrained=is_main_process(), pretrain_type=pretrain_type,
73
+ search_size=search_size, template_size=template_size,
74
+ search_number=search_number, template_number=template_number,
75
+ drop_path_rate=cfg.MODEL.ENCODER.DROP_PATH,
76
+ use_checkpoint=cfg.MODEL.ENCODER.USE_CHECKPOINT
77
+ )
78
+ if "_base_" in name:
79
+ num_channels = 768
80
+ elif "_large_" in name:
81
+ num_channels = 1024
82
+ elif "_huge_" in name:
83
+ num_channels = 1280
84
+ else:
85
+ num_channels = 768
86
+
87
+ else:
88
+ raise ValueError()
89
+ super().__init__(encoder, train_encoder, open_layers, num_channels)
90
+
91
+
92
+
93
+ def build_encoder(cfg):
94
+ train_encoder = (cfg.TRAIN.ENCODER_MULTIPLIER > 0) and (cfg.TRAIN.FREEZE_ENCODER == False)
95
+ encoder = Encoder(cfg.MODEL.ENCODER.TYPE, train_encoder,
96
+ cfg.MODEL.ENCODER.PRETRAIN_TYPE,
97
+ cfg.DATA.SEARCH.SIZE, cfg.DATA.SEARCH.NUMBER,
98
+ cfg.DATA.TEMPLATE.SIZE, cfg.DATA.TEMPLATE.NUMBER,
99
+ cfg.TRAIN.ENCODER_OPEN, cfg)
100
+ return encoder
lib/models/atctrack/language_model.py ADDED
@@ -0,0 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
2
+ """
3
+ Backbone modules.
4
+ """
5
+ import os.path
6
+ import shutil
7
+ import tarfile
8
+ import tempfile
9
+
10
+ import torch
11
+ from pytorch_pretrained_bert import BertConfig, cached_path, CONFIG_NAME, WEIGHTS_NAME, load_tf_weights_in_bert
12
+ from pytorch_pretrained_bert.modeling import BertLayerNorm, PRETRAINED_MODEL_ARCHIVE_MAP, logger, BERT_CONFIG_NAME, \
13
+ BertEmbeddings, BertEncoder
14
+ from pytorch_pretrained_bert.modeling_transfo_xl import TF_WEIGHTS_NAME
15
+ from torch import nn
16
+
17
+ from lib.utils.misc import NestedTensor
18
+
19
+
20
+ class BertPreTrainedModel(nn.Module):
21
+ """ An abstract class to handle weights initialization and
22
+ a simple interface for dowloading and loading pretrained checkpoints.
23
+ """
24
+ def __init__(self, config, *inputs, **kwargs):
25
+ super(BertPreTrainedModel, self).__init__()
26
+ if not isinstance(config, BertConfig):
27
+ raise ValueError(
28
+ "Parameter config in `{}(config)` should be an instance of class `BertConfig`. "
29
+ "To create a model from a Google pretrained model use "
30
+ "`model = {}.from_pretrained(PRETRAINED_MODEL_NAME)`".format(
31
+ self.__class__.__name__, self.__class__.__name__
32
+ ))
33
+ self.config = config
34
+
35
+ def init_bert_weights(self, module):
36
+ """ Initialize the weights.
37
+ """
38
+ if isinstance(module, (nn.Linear, nn.Embedding)):
39
+ # Slightly different from the TF version which uses truncated_normal for initialization
40
+ # cf https://github.com/pytorch/pytorch/pull/5617
41
+ module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
42
+ elif isinstance(module, BertLayerNorm):
43
+ module.bias.data.zero_()
44
+ module.weight.data.fill_(1.0)
45
+ if isinstance(module, nn.Linear) and module.bias is not None:
46
+ module.bias.data.zero_()
47
+
48
+ @classmethod
49
+ def from_pretrained(cls, pretrained_model_name_or_path, *inputs, **kwargs):
50
+ """
51
+ Instantiate a BertPreTrainedModel from a pre-trained model file or a pytorch state dict.
52
+ Download and cache the pre-trained model file if needed.
53
+
54
+ Params:
55
+ pretrained_model_name_or_path: either:
56
+ - a str with the name of a pre-trained model to load selected in the list of:
57
+ . `bert-base-uncased`
58
+ . `bert-large-uncased`
59
+ . `bert-base-cased`
60
+ . `bert-large-cased`
61
+ . `bert-base-multilingual-uncased`
62
+ . `bert-base-multilingual-cased`
63
+ . `bert-base-chinese`
64
+ - a path or url to a pretrained model archive containing:
65
+ . `bert_config.json` a configuration file for the model
66
+ . `pytorch_model.bin` a PyTorch dump of a BertForPreTraining instance
67
+ - a path or url to a pretrained model archive containing:
68
+ . `bert_config.json` a configuration file for the model
69
+ . `model.chkpt` a TensorFlow checkpoint
70
+ from_tf: should we load the weights from a locally saved TensorFlow checkpoint
71
+ cache_dir: an optional path to a folder in which the pre-trained checkpoints will be cached.
72
+ state_dict: an optional state dictionnary (collections.OrderedDict object) to use instead of Google pre-trained checkpoints
73
+ *inputs, **kwargs: additional input for the specific Bert class
74
+ (ex: num_labels for BertForSequenceClassification)
75
+ """
76
+ state_dict = kwargs.get('state_dict', None)
77
+ kwargs.pop('state_dict', None)
78
+ cache_dir = kwargs.get('cache_dir', None)
79
+ kwargs.pop('cache_dir', None)
80
+ from_tf = kwargs.get('from_tf', False)
81
+ kwargs.pop('from_tf', None)
82
+
83
+ if pretrained_model_name_or_path in PRETRAINED_MODEL_ARCHIVE_MAP:
84
+ archive_file = PRETRAINED_MODEL_ARCHIVE_MAP[pretrained_model_name_or_path]
85
+ else:
86
+ archive_file = pretrained_model_name_or_path
87
+ # redirect to the cache, if necessary
88
+ try:
89
+ resolved_archive_file = cached_path(archive_file, cache_dir=cache_dir)
90
+ except EnvironmentError:
91
+ logger.error(
92
+ "Model name '{}' was not found in model name list ({}). "
93
+ "We assumed '{}' was a path or url but couldn't find any file "
94
+ "associated to this path or url.".format(
95
+ pretrained_model_name_or_path,
96
+ ', '.join(PRETRAINED_MODEL_ARCHIVE_MAP.keys()),
97
+ archive_file))
98
+ return None
99
+ if resolved_archive_file == archive_file:
100
+ logger.info("loading archive file {}".format(archive_file))
101
+ else:
102
+ logger.info("loading archive file {} from cache at {}".format(
103
+ archive_file, resolved_archive_file))
104
+ tempdir = None
105
+ if os.path.isdir(resolved_archive_file) or from_tf:
106
+ serialization_dir = resolved_archive_file
107
+ else:
108
+ # Extract archive to temp dir
109
+ tempdir = tempfile.mkdtemp()
110
+ logger.info("extracting archive file {} to temp dir {}".format(
111
+ resolved_archive_file, tempdir))
112
+ with tarfile.open(resolved_archive_file, 'r:gz') as archive:
113
+ archive.extractall(tempdir)
114
+ serialization_dir = tempdir
115
+ # Load config
116
+ config_file = os.path.join(serialization_dir, CONFIG_NAME)
117
+ if not os.path.exists(config_file):
118
+ # Backward compatibility with old naming format
119
+ config_file = os.path.join(serialization_dir, BERT_CONFIG_NAME)
120
+ config = BertConfig.from_json_file(config_file)
121
+ logger.info("Model config {}".format(config))
122
+ # Instantiate model.
123
+ model = cls(config, *inputs, **kwargs)
124
+ if state_dict is None and not from_tf:
125
+ weights_path = os.path.join(serialization_dir, WEIGHTS_NAME)
126
+ state_dict = torch.load(weights_path, map_location='cpu')
127
+ if tempdir:
128
+ # Clean up temp dir
129
+ shutil.rmtree(tempdir)
130
+ if from_tf:
131
+ # Directly load from a TensorFlow checkpoint
132
+ weights_path = os.path.join(serialization_dir, TF_WEIGHTS_NAME)
133
+ return load_tf_weights_in_bert(model, weights_path)
134
+ # Load from a PyTorch state_dict
135
+ old_keys = []
136
+ new_keys = []
137
+ for key in state_dict.keys():
138
+ new_key = None
139
+ if 'gamma' in key:
140
+ new_key = key.replace('gamma', 'weight')
141
+ if 'beta' in key:
142
+ new_key = key.replace('beta', 'bias')
143
+ if new_key:
144
+ old_keys.append(key)
145
+ new_keys.append(new_key)
146
+ for old_key, new_key in zip(old_keys, new_keys):
147
+ state_dict[new_key] = state_dict.pop(old_key)
148
+
149
+ missing_keys = []
150
+ unexpected_keys = []
151
+ error_msgs = []
152
+ # copy state_dict so _load_from_state_dict can modify it
153
+ metadata = getattr(state_dict, '_metadata', None)
154
+ state_dict = state_dict.copy()
155
+ if metadata is not None:
156
+ state_dict._metadata = metadata
157
+
158
+ def load(module, prefix=''):
159
+ local_metadata = {} if metadata is None else metadata.get(prefix[:-1], {})
160
+ module._load_from_state_dict(
161
+ state_dict, prefix, local_metadata, True, missing_keys, unexpected_keys, error_msgs)
162
+ for name, child in module._modules.items():
163
+ if child is not None:
164
+ load(child, prefix + name + '.')
165
+ start_prefix = ''
166
+ if not hasattr(model, 'bert') and any(s.startswith('bert.') for s in state_dict.keys()):
167
+ start_prefix = 'bert.'
168
+ load(model, prefix=start_prefix)
169
+ if len(missing_keys) > 0:
170
+ logger.info("Weights of {} not initialized from pretrained model: {}".format(
171
+ model.__class__.__name__, missing_keys))
172
+ if len(unexpected_keys) > 0:
173
+ logger.info("Weights from pretrained model not used in {}: {}".format(
174
+ model.__class__.__name__, unexpected_keys))
175
+ if len(error_msgs) > 0:
176
+ raise RuntimeError('Error(s) in loading state_dict for {}:\n\t{}'.format(
177
+ model.__class__.__name__, "\n\t".join(error_msgs)))
178
+ return model
179
+
180
+
181
+ class BertModel(BertPreTrainedModel):
182
+ """BERT model ("Bidirectional Embedding Representations from a Transformer").
183
+
184
+ Params:
185
+ config: a BertConfig class instance with the configuration to build a new model
186
+
187
+ Inputs:
188
+ `input_ids`: a torch.LongTensor of shape [batch_size, sequence_length]
189
+ with the word token indices in the vocabulary(see the tokens preprocessing logic in the scripts
190
+ `extract_features.py`, `run_classifier.py` and `run_squad.py`)
191
+ `token_type_ids`: an optional torch.LongTensor of shape [batch_size, sequence_length] with the token
192
+ types indices selected in [0, 1]. Type 0 corresponds to a `sentence A` and type 1 corresponds to
193
+ a `sentence B` token (see BERT paper for more details).
194
+ `attention_mask`: an optional torch.LongTensor of shape [batch_size, sequence_length] with indices
195
+ selected in [0, 1]. It's a mask to be used if the input sequence length is smaller than the max
196
+ input sequence length in the current batch. It's the mask that we typically use for attention when
197
+ a batch has varying length sentences.
198
+ `output_all_encoded_layers`: boolean which controls the content of the `encoded_layers` output as described below. Default: `True`.
199
+
200
+ Outputs: Tuple of (encoded_layers, pooled_output)
201
+ `encoded_layers`: controled by `output_all_encoded_layers` argument:
202
+ - `output_all_encoded_layers=True`: outputs a list of the full sequences of encoded-hidden-states at the end
203
+ of each attention block (i.e. 12 full sequences for BERT-base, 24 for BERT-large), each
204
+ encoded-hidden-state is a torch.FloatTensor of size [batch_size, sequence_length, hidden_size],
205
+ - `output_all_encoded_layers=False`: outputs only the full sequence of hidden-states corresponding
206
+ to the last attention block of shape [batch_size, sequence_length, hidden_size],
207
+ `pooled_output`: a torch.FloatTensor of size [batch_size, hidden_size] which is the output of a
208
+ classifier pretrained on top of the hidden state associated to the first character of the
209
+ input (`CLS`) to train on the Next-Sentence task (see BERT's paper).
210
+
211
+ Example usage:
212
+ ```python
213
+ # Already been converted into WordPiece token ids
214
+ input_ids = torch.LongTensor([[31, 51, 99], [15, 5, 0]])
215
+ input_mask = torch.LongTensor([[1, 1, 1], [1, 1, 0]])
216
+ token_type_ids = torch.LongTensor([[0, 0, 1], [0, 1, 0]])
217
+
218
+ config = modeling.BertConfig(vocab_size_or_config_json_file=32000, hidden_size=768,
219
+ num_hidden_layers=12, num_attention_heads=12, intermediate_size=3072)
220
+
221
+ model = modeling.BertModel(config=config)
222
+ all_encoder_layers, pooled_output = model(input_ids, token_type_ids, input_mask)
223
+ ```
224
+ """
225
+ def __init__(self, config):
226
+ super(BertModel, self).__init__(config)
227
+ self.embeddings = BertEmbeddings(config)
228
+ self.encoder = BertEncoder(config)
229
+ # self.pooler = BertPooler(config)
230
+ self.apply(self.init_bert_weights)
231
+
232
+ def forward(self, input_ids, token_type_ids=None, attention_mask=None, output_all_encoded_layers=True):
233
+ if attention_mask is None:
234
+ attention_mask = torch.ones_like(input_ids)
235
+ if token_type_ids is None:
236
+ token_type_ids = torch.zeros_like(input_ids)
237
+
238
+ # We create a 3D attention mask from a 2D tensor mask.
239
+ # Sizes are [batch_size, 1, 1, to_seq_length]
240
+ # So we can broadcast to [batch_size, num_heads, from_seq_length, to_seq_length]
241
+ # this attention mask is more simple than the triangular masking of causal attention
242
+ # used in OpenAI GPT, we just need to prepare the broadcast dimension here.
243
+ extended_attention_mask = attention_mask.unsqueeze(1).unsqueeze(2)
244
+
245
+ # Since attention_mask is 1.0 for positions we want to attend and 0.0 for
246
+ # masked positions, this operation will create a tensor which is 0.0 for
247
+ # positions we want to attend and -10000.0 for masked positions.
248
+ # Since we are adding it to the raw scores before the softmax, this is
249
+ # effectively the same as removing these entirely.
250
+ extended_attention_mask = extended_attention_mask.to(dtype=next(self.parameters()).dtype) # fp16 compatibility
251
+ extended_attention_mask = (1.0 - extended_attention_mask) * -10000.0
252
+
253
+ embedding_output = self.embeddings(input_ids, token_type_ids)
254
+ encoded_layers = self.encoder(embedding_output,
255
+ extended_attention_mask,
256
+ output_all_encoded_layers=output_all_encoded_layers)
257
+ # sequence_output = encoded_layers[-1]
258
+ # pooled_output = self.pooler(sequence_output)
259
+ if not output_all_encoded_layers:
260
+ encoded_layers = encoded_layers[-1]
261
+ return encoded_layers
262
+
263
+
264
+ class BERT(nn.Module):
265
+ def __init__(self, name: str, path: str, train_bert: bool, hidden_dim: int, max_len: int, enc_num):
266
+ super().__init__()
267
+ if name == 'bert-base-uncased':
268
+ self.num_channels = 768
269
+ else:
270
+ self.num_channels = 1024
271
+ self.enc_num = enc_num
272
+ if path is not None and os.path.exists(path):
273
+ self.bert = BertModel.from_pretrained(path)
274
+ else:
275
+ self.bert = BertModel.from_pretrained(name)
276
+
277
+ if not train_bert:
278
+ print('Language Model Bert has been frozen!')
279
+ for parameter in self.bert.parameters():
280
+ parameter.requires_grad_(False)
281
+ # print(self.bert)
282
+
283
+ def forward(self, tensor_list: NestedTensor):
284
+
285
+ if self.enc_num > 0:
286
+ all_encoder_layers = self.bert(tensor_list.tensors, token_type_ids=None, attention_mask=tensor_list.mask)
287
+ # use the output of the X-th transformer encoder layers
288
+ xs = all_encoder_layers[self.enc_num - 1]
289
+ else:
290
+ xs = self.bert.embeddings.word_embeddings(tensor_list.tensors)
291
+
292
+ mask = tensor_list.mask.to(torch.bool)
293
+ mask = ~mask
294
+ out = NestedTensor(xs, mask)
295
+
296
+ return out
297
+
298
+
299
+ # def build_bert(cfg):
300
+ # # position_embedding = build_position_encoding(cfg)
301
+ # train_bert = cfg.MODEL.LANGUAGE.BERT.LR > 0
302
+ # bert = BERT(cfg.MODEL.LANGUAGE.TYPE, cfg.MODEL.LANGUAGE.PATH, train_bert, cfg.MODEL.LANGUAGE.BERT.HIDDEN_DIM,
303
+ # cfg.MODEL.LANGUAGE.BERT.MAX_QUERY_LEN, cfg.MODEL.LANGUAGE.BERT.ENC_NUM)
304
+ # # model = Joiner(bert, position_embedding)
305
+ # # model.num_channels = bert.num_channels
306
+ # return bert
307
+
308
+ def build_bert(cfg):
309
+ # position_embedding = build_position_encoding(cfg)
310
+ # train_bert = cfg.MODEL.LANGUAGE.BERT.LR > 0
311
+ train_bert = cfg.TRAIN.LR > 0
312
+ bert_type = cfg.MODEL.LANGUAGE.IMPLEMENT
313
+ if bert_type == "pytorch":
314
+ bert_model = BERT(cfg.MODEL.LANGUAGE.TYPE, cfg.MODEL.LANGUAGE.PATH, train_bert,
315
+ cfg.MODEL.LANGUAGE.BERT.HIDDEN_DIM,
316
+ cfg.MODEL.LANGUAGE.BERT.MAX_QUERY_LEN, cfg.MODEL.LANGUAGE.BERT.ENC_NUM)
317
+ else:
318
+ raise ValueError("Undefined BERT TYPE '%s'" % bert_type)
319
+ return bert_model
320
+
lib/models/atctrack/utils.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+
3
+ import torch
4
+ import torch.nn.functional as F
5
+
6
+ def combine_tokens(template_tokens, search_tokens, mode='direct', return_res=False):
7
+ # [B, HW, C]
8
+ len_t = template_tokens.shape[1]
9
+ len_s = search_tokens.shape[1]
10
+
11
+ if mode == 'direct':
12
+ merged_feature = torch.cat((template_tokens, search_tokens), dim=1)
13
+ elif mode == 'template_central':
14
+ central_pivot = len_s // 2
15
+ first_half = search_tokens[:, :central_pivot, :]
16
+ second_half = search_tokens[:, central_pivot:, :]
17
+ merged_feature = torch.cat((first_half, template_tokens, second_half), dim=1)
18
+ elif mode == 'partition':
19
+ feat_size_s = int(math.sqrt(len_s))
20
+ feat_size_t = int(math.sqrt(len_t))
21
+ window_size = math.ceil(feat_size_t / 2.)
22
+ # pad feature maps to multiples of window size
23
+ B, _, C = template_tokens.shape
24
+ H = W = feat_size_t
25
+ template_tokens = template_tokens.view(B, H, W, C)
26
+ pad_l = pad_b = pad_r = 0
27
+ # pad_r = (window_size - W % window_size) % window_size
28
+ pad_t = (window_size - H % window_size) % window_size
29
+ template_tokens = F.pad(template_tokens, (0, 0, pad_l, pad_r, pad_t, pad_b))
30
+ _, Hp, Wp, _ = template_tokens.shape
31
+ template_tokens = template_tokens.view(B, Hp // window_size, window_size, W, C)
32
+ template_tokens = torch.cat([template_tokens[:, 0, ...], template_tokens[:, 1, ...]], dim=2)
33
+ _, Hc, Wc, _ = template_tokens.shape
34
+ template_tokens = template_tokens.view(B, -1, C)
35
+ merged_feature = torch.cat([template_tokens, search_tokens], dim=1)
36
+
37
+ # calculate new h and w, which may be useful for SwinT or others
38
+ merged_h, merged_w = feat_size_s + Hc, feat_size_s
39
+ if return_res:
40
+ return merged_feature, merged_h, merged_w
41
+
42
+ else:
43
+ raise NotImplementedError
44
+
45
+ return merged_feature
46
+
47
+ '''
48
+ add token transfer to feature
49
+ '''
50
+ def token2feature(tokens):
51
+ B,L,D=tokens.shape
52
+ H=W=int(L**0.5)
53
+ x = tokens.permute(0, 2, 1).view(B, D, W, H).contiguous()
54
+ return x
55
+
56
+
57
+ '''
58
+ feature2token
59
+ '''
60
+ def feature2token(x):
61
+ B,C,W,H = x.shape
62
+ L = W*H
63
+ tokens = x.view(B, C, L).permute(0, 2, 1).contiguous()
64
+ return tokens
lib/models/atctrack/vit.py ADDED
@@ -0,0 +1,466 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Vision Transformer (ViT) in PyTorch
2
+
3
+ A PyTorch implement of Vision Transformers as described in
4
+ 'An Image Is Worth 16 x 16 Words: Transformers for Image Recognition at Scale' - https://arxiv.org/abs/2010.11929
5
+
6
+ The official jax code is released and available at https://github.com/google-research/vision_transformer
7
+
8
+ Status/TODO:
9
+ * Models updated to be compatible with official impl. Args added to support backward compat for old PyTorch weights.
10
+ * Weights ported from official jax impl for 384x384 base and small models, 16x16 and 32x32 patches.
11
+ * Trained (supervised on ImageNet-1k) my custom 'small' patch model to 77.9, 'base' to 79.4 top-1 with this code.
12
+ * Hopefully find time and GPUs for SSL or unsupervised pretraining on OpenImages w/ ImageNet fine-tune in future.
13
+
14
+ Acknowledgments:
15
+ * The paper authors for releasing code and weights, thanks!
16
+ * I fixed my class token impl based on Phil Wang's https://github.com/lucidrains/vit-pytorch ... check it out
17
+ for some einops/einsum fun
18
+ * Simple transformer style inspired by Andrej Karpathy's https://github.com/karpathy/minGPT
19
+ * Bert reference code checks against Huggingface Transformers and Tensorflow Bert
20
+
21
+ Hacked together by / Copyright 2020 Ross Wightman
22
+ """
23
+ import torch
24
+ import torch.nn as nn
25
+ import torch.utils.model_zoo as model_zoo
26
+ import torch.utils.checkpoint as checkpoint
27
+ import torch.nn.functional as F
28
+ import math
29
+ from functools import partial
30
+
31
+ from timm.data import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD
32
+ from timm.models.layers import DropPath, to_2tuple, trunc_normal_
33
+ from timm.models.registry import register_model
34
+
35
+
36
+
37
+ def _cfg(url='', **kwargs):
38
+ return {
39
+ 'url': url,
40
+ 'num_classes': 1000, 'input_size': (3, 224, 224), 'pool_size': None,
41
+ 'crop_pct': .9, 'interpolation': 'bicubic',
42
+ 'mean': IMAGENET_DEFAULT_MEAN, 'std': IMAGENET_DEFAULT_STD,
43
+ 'first_conv': 'patch_embed.proj', 'classifier': 'head',
44
+ **kwargs
45
+ }
46
+
47
+
48
+ default_cfgs = {
49
+ # patch models
50
+ # mae ViT-B/16-224 pre-trained model
51
+ 'vit_base_patch16_224_mae': _cfg(
52
+ url='https://dl.fbaipublicfiles.com/mae/pretrain/mae_pretrain_vit_base.pth',
53
+ input_size=(3, 224, 224), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
54
+ 'vit_base_patch16_224_default': _cfg(
55
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_p16_384-83fb41ba.pth',
56
+ input_size=(3, 224, 224), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
57
+ # mae ViT-L/16-224 pre-trained model
58
+ 'vit_large_patch16_224_mae': _cfg(
59
+ url='https://dl.fbaipublicfiles.com/mae/pretrain/mae_pretrain_vit_large.pth',
60
+ input_size=(3, 224, 224), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
61
+ # mae ViT-H/14-224 pre-trained model
62
+ 'vit_huge_patch14_224_mae': _cfg(
63
+ url='https://dl.fbaipublicfiles.com/mae/pretrain/mae_pretrain_vit_huge.pth',
64
+ input_size=(3, 224, 224), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
65
+ 'vit_small_patch16_224': _cfg(
66
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-weights/vit_small_p16_224-15ec54c9.pth',
67
+ ),
68
+ 'vit_base_patch16_224': _cfg(
69
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_p16_224-80ecf9dd.pth',
70
+ mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5),
71
+ ),
72
+ 'vit_base_patch16_384': _cfg(
73
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_p16_384-83fb41ba.pth',
74
+ input_size=(3, 384, 384), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
75
+ 'vit_base_patch32_384': _cfg(
76
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_p32_384-830016f5.pth',
77
+ input_size=(3, 384, 384), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
78
+ 'vit_large_patch16_224': _cfg(
79
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_large_p16_224-4ee7a4dc.pth',
80
+ mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)),
81
+ 'vit_large_patch16_384': _cfg(
82
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_large_p16_384-b3be5167.pth',
83
+ input_size=(3, 384, 384), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
84
+ 'vit_large_patch32_384': _cfg(
85
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_large_p32_384-9b920ba8.pth',
86
+ input_size=(3, 384, 384), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
87
+ 'vit_huge_patch16_224': _cfg(),
88
+ 'vit_huge_patch32_384': _cfg(input_size=(3, 384, 384)),
89
+ # hybrid models
90
+ 'vit_small_resnet26d_224': _cfg(),
91
+ 'vit_small_resnet50d_s3_224': _cfg(),
92
+ 'vit_base_resnet26d_224': _cfg(),
93
+ 'vit_base_resnet50d_224': _cfg(),
94
+ }
95
+
96
+
97
+ class Mlp(nn.Module):
98
+ def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):
99
+ super().__init__()
100
+ out_features = out_features or in_features
101
+ hidden_features = hidden_features or in_features
102
+ self.fc1 = nn.Linear(in_features, hidden_features)
103
+ self.act = act_layer()
104
+ self.fc2 = nn.Linear(hidden_features, out_features)
105
+ self.drop = nn.Dropout(drop)
106
+
107
+ def forward(self, x):
108
+ x = self.fc1(x)
109
+ x = self.act(x)
110
+ x = self.drop(x)
111
+ x = self.fc2(x)
112
+ x = self.drop(x)
113
+ return x
114
+
115
+
116
+ class Attention(nn.Module):
117
+ def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):
118
+ super().__init__()
119
+ self.num_heads = num_heads
120
+ head_dim = dim // num_heads
121
+ # NOTE scale factor was wrong in my original version, can set manually to be compat with prev weights
122
+ self.scale = qk_scale or head_dim ** -0.5
123
+
124
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
125
+ self.attn_drop = nn.Dropout(attn_drop)
126
+ self.proj = nn.Linear(dim, dim)
127
+ self.proj_drop = nn.Dropout(proj_drop)
128
+
129
+ def forward(self, x):
130
+ B, N, C = x.shape
131
+ qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
132
+ q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple)
133
+
134
+ attn = (q @ k.transpose(-2, -1)) * self.scale
135
+ attn = attn.softmax(dim=-1)
136
+ attn = self.attn_drop(attn)
137
+
138
+ x = (attn @ v).transpose(1, 2).reshape(B, N, C)
139
+ x = self.proj(x)
140
+ x = self.proj_drop(x)
141
+ return x
142
+
143
+
144
+ class Block(nn.Module):
145
+
146
+ def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop=0., attn_drop=0.,
147
+ drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm):
148
+ super().__init__()
149
+ self.norm1 = norm_layer(dim)
150
+ self.attn = Attention(
151
+ dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop)
152
+ # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here
153
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
154
+ self.norm2 = norm_layer(dim)
155
+ mlp_hidden_dim = int(dim * mlp_ratio)
156
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
157
+
158
+ def forward(self, x):
159
+ x = x + self.drop_path(self.attn(self.norm1(x)))
160
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
161
+ return x
162
+
163
+
164
+ class PatchEmbed(nn.Module):
165
+ """ Image to Patch Embedding
166
+ """
167
+ def __init__(self, patch_size=16, in_chans=3, embed_dim=768):
168
+ super().__init__()
169
+ self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size)
170
+
171
+ def forward(self, x):
172
+ # B, C, H, W = x.shape
173
+ x = self.proj(x).flatten(2).transpose(1, 2)
174
+ return x
175
+
176
+
177
+ class HybridEmbed(nn.Module):
178
+ """ CNN Feature Map Embedding
179
+ Extract feature map from CNN, flatten, project to embedding dim.
180
+ """
181
+ def __init__(self, backbone, img_size=224, feature_size=None, in_chans=3, embed_dim=768):
182
+ super().__init__()
183
+ assert isinstance(backbone, nn.Module)
184
+ img_size = to_2tuple(img_size)
185
+ self.img_size = img_size
186
+ self.backbone = backbone
187
+ if feature_size is None:
188
+ with torch.no_grad():
189
+ # FIXME this is hacky, but most reliable way of determining the exact dim of the output feature
190
+ # map for all networks, the feature metadata has reliable channel and stride info, but using
191
+ # stride to calc feature dim requires info about padding of each stage that isn't captured.
192
+ training = backbone.training
193
+ if training:
194
+ backbone.eval()
195
+ o = self.backbone(torch.zeros(1, in_chans, img_size[0], img_size[1]))[-1]
196
+ feature_size = o.shape[-2:]
197
+ feature_dim = o.shape[1]
198
+ backbone.train(training)
199
+ else:
200
+ feature_size = to_2tuple(feature_size)
201
+ feature_dim = self.backbone.feature_info.channels()[-1]
202
+ self.num_patches = feature_size[0] * feature_size[1]
203
+ self.proj = nn.Linear(feature_dim, embed_dim)
204
+
205
+ def forward(self, x):
206
+ x = self.backbone(x)[-1]
207
+ x = x.flatten(2).transpose(1, 2)
208
+ x = self.proj(x)
209
+ return x
210
+
211
+
212
+ class VisionTransformer(nn.Module):
213
+ """ Vision Transformer with support for patch or hybrid CNN input stage
214
+ """
215
+ def __init__(self, search_size=384, template_size=192,
216
+ patch_size=16, in_chans=3, num_classes=1000, embed_dim=768, depth=12,
217
+ num_heads=12, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop_rate=0., attn_drop_rate=0.,
218
+ drop_path_rate=0., hybrid_backbone=None, norm_layer=nn.LayerNorm,
219
+ search_number=1, template_number=1, use_checkpoint=False):
220
+ super().__init__()
221
+ self.use_checkpoint = use_checkpoint
222
+ self.num_classes = num_classes
223
+ self.num_features = self.embed_dim = embed_dim # num_features for consistency with other models
224
+ self.embed_dim_list = [embed_dim]
225
+ self.num_search = search_number
226
+ self.num_template = template_number
227
+
228
+ self.patch_embed = PatchEmbed(
229
+ patch_size=patch_size, in_chans=in_chans, embed_dim=embed_dim)
230
+
231
+ self.num_patches_search = (search_size // patch_size) * (search_size // patch_size)
232
+ self.num_patches_template = (template_size // patch_size) * (template_size // patch_size)
233
+
234
+ self.pos_embed = nn.Parameter(torch.zeros(1, self.num_patches_search + self.num_patches_template, embed_dim))
235
+ # self.pos_embed_search = nn.Parameter(torch.zeros(1, self.num_patches_search, embed_dim))
236
+ # self.pos_embed_template = nn.Parameter(torch.zeros(1, self.num_patches_template, embed_dim))
237
+
238
+ self.pos_drop = nn.Dropout(p=drop_rate)
239
+
240
+ dpr = [x.item() for x in torch.linspace(0, drop_path_rate, depth)] # stochastic depth decay rule
241
+ self.blocks = nn.ModuleList([
242
+ Block(
243
+ dim=embed_dim, num_heads=num_heads, mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, qk_scale=qk_scale,
244
+ drop=drop_rate, attn_drop=attn_drop_rate, drop_path=dpr[i], norm_layer=norm_layer)
245
+ for i in range(depth)])
246
+
247
+ self.norm = norm_layer(embed_dim)
248
+ trunc_normal_(self.pos_embed, std=.02)
249
+ # trunc_normal_(self.pos_embed_search, std=.02)
250
+ # trunc_normal_(self.pos_embed_template, std=.02)
251
+ self.apply(self._init_weights)
252
+
253
+ def _init_weights(self, m):
254
+ if isinstance(m, nn.Linear):
255
+ trunc_normal_(m.weight, std=.02)
256
+ if isinstance(m, nn.Linear) and m.bias is not None:
257
+ nn.init.constant_(m.bias, 0)
258
+ elif isinstance(m, nn.LayerNorm):
259
+ nn.init.constant_(m.bias, 0)
260
+ nn.init.constant_(m.weight, 1.0)
261
+
262
+ @torch.jit.ignore
263
+ def no_weight_decay(self):
264
+ return {'pos_embed', 'cls_token'}
265
+
266
+ def get_classifier(self):
267
+ return self.head
268
+
269
+ def reset_classifier(self, num_classes, global_pool=''):
270
+ self.num_classes = num_classes
271
+ self.head = nn.Linear(self.embed_dim, num_classes) if num_classes > 0 else nn.Identity()
272
+
273
+ def forward_features(self, template_list, search_list):
274
+ num_template = len(template_list)
275
+ num_search = len(search_list)
276
+
277
+ z = torch.stack(template_list, dim=1)#(b,n,c,h,w)
278
+ z = z.view(-1, *z.size()[2:])#(bn,c,h,w)
279
+ z = self.patch_embed(z)
280
+ z = z + self.pos_embed[:, self.num_patches_search:, :]
281
+ z = z.view(-1,num_template,z.size(-2),z.size(-1))
282
+ z = z.reshape(z.size(0),-1,z.size(-1))
283
+
284
+ x = torch.stack(search_list, dim=1)#(b,n,c,h,w)
285
+ x = x.view(-1, *x.size()[2:])#(bn,c,h,w)
286
+ x = self.patch_embed(x)
287
+ x = x + self.pos_embed[:, :self.num_patches_search, :]
288
+ x = x.view(-1,num_search,x.size(-2),x.size(-1))
289
+ x = x.reshape(x.size(0),-1,x.size(-1))
290
+
291
+ xz = torch.cat([x, z], dim=1)
292
+
293
+ xz = self.pos_drop(xz)
294
+
295
+ for blk in self.blocks: #batch is the first dimension.
296
+ if self.use_checkpoint:
297
+ xz = checkpoint.checkpoint(blk, xz)
298
+ else:
299
+ xz = blk(xz)
300
+
301
+ xz = self.norm(xz) # B,N,C
302
+ return xz
303
+
304
+ def forward(self, template_list, search_list):
305
+ xz = self.forward_features(template_list, search_list)
306
+ out=[xz]
307
+ return out
308
+
309
+
310
+ def _conv_filter(state_dict, patch_size=16):
311
+ """ convert patch embedding weight from manual patchify + linear proj to conv"""
312
+ out_dict = {}
313
+ for k, v in state_dict.items():
314
+ if 'patch_embed.proj.weight' in k:
315
+ v = v.reshape((v.shape[0], 3, patch_size, patch_size))
316
+ out_dict[k] = v
317
+ return out_dict
318
+
319
+
320
+ @register_model
321
+ def vit_base_patch16(pretrained=False, pretrain_type='default',
322
+ search_size=384, template_size=192, **kwargs):
323
+ patch_size = 16
324
+ model = VisionTransformer(
325
+ search_size=search_size, template_size=template_size,
326
+ patch_size=patch_size, num_classes=0,
327
+ embed_dim=768, depth=12, num_heads=12, mlp_ratio=4, qkv_bias=True,
328
+ norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)
329
+ cfg_type = 'vit_base_patch16_224_' + pretrain_type
330
+ if pretrain_type == 'scratch':
331
+ pretrained = False
332
+ return model
333
+ model.default_cfg = default_cfgs[cfg_type]
334
+ if pretrained:
335
+ load_pretrained(model, pretrain_type,
336
+ num_classes=model.num_classes, in_chans=kwargs.get('in_chans', 3))
337
+ return model
338
+
339
+ @register_model
340
+ def vit_large_patch16(pretrained=False, pretrain_type='default',
341
+ search_size=384, template_size=192, **kwargs):
342
+ patch_size = 16
343
+ model = VisionTransformer(
344
+ search_size=search_size, template_size=template_size,
345
+ patch_size=patch_size, num_classes=0,
346
+ embed_dim=1024, depth=24, num_heads=16, mlp_ratio=4, qkv_bias=True,
347
+ norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)
348
+ cfg_type = 'vit_large_patch16_224_' + pretrain_type
349
+ if pretrain_type == 'scratch':
350
+ pretrained = False
351
+ return model
352
+ model.default_cfg = default_cfgs[cfg_type]
353
+ if pretrained:
354
+ load_pretrained(model, pretrain_type, num_classes=model.num_classes, in_chans=kwargs.get('in_chans', 3))
355
+ return model
356
+
357
+ @register_model
358
+ def vit_huge_patch14(pretrained=False, pretrain_type='default',
359
+ search_size=364, template_size=182, **kwargs):
360
+ patch_size = 14
361
+ model = VisionTransformer(
362
+ search_size=search_size, template_size=template_size,
363
+ patch_size=patch_size, num_classes=0,
364
+ embed_dim=1280, depth=32, num_heads=16, mlp_ratio=4, qkv_bias=True,
365
+ norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)
366
+ cfg_type = 'vit_huge_patch14_224_' + pretrain_type
367
+ if pretrain_type == 'scratch':
368
+ pretrained = False
369
+ return model
370
+ model.default_cfg = default_cfgs[cfg_type]
371
+ if pretrained:
372
+ load_pretrained(model,
373
+ pretrain_type, num_classes=model.num_classes, in_chans=kwargs.get('in_chans', 3))
374
+ return model
375
+
376
+ def load_pretrained(model, pretrain_type='default', cfg=None, num_classes=1000, in_chans=3, filter_fn=None, strict=True):
377
+ if cfg is None:
378
+ cfg = getattr(model, 'default_cfg')
379
+ if cfg is None or 'url' not in cfg or not cfg['url']:
380
+ print("Pretrained model URL is invalid, using random initialization.")
381
+ return
382
+
383
+ state_dict = model_zoo.load_url(cfg['url'], progress=False, map_location='cpu')
384
+ if pretrain_type == 'mae':
385
+ state_dict = state_dict['model']
386
+
387
+ if filter_fn is not None:
388
+ state_dict = filter_fn(state_dict)
389
+
390
+ if in_chans == 1:
391
+ conv1_name = cfg['first_conv']
392
+ print('Converting first conv (%s) pretrained weights from 3 to 1 channel' % conv1_name)
393
+ conv1_weight = state_dict[conv1_name + '.weight']
394
+ # Some weights are in torch.half, ensure it's float for sum on CPU
395
+ conv1_type = conv1_weight.dtype
396
+ conv1_weight = conv1_weight.float()
397
+ O, I, J, K = conv1_weight.shape
398
+ if I > 3:
399
+ assert conv1_weight.shape[1] % 3 == 0
400
+ # For models with space2depth stems
401
+ conv1_weight = conv1_weight.reshape(O, I // 3, 3, J, K)
402
+ conv1_weight = conv1_weight.sum(dim=2, keepdim=False)
403
+ else:
404
+ conv1_weight = conv1_weight.sum(dim=1, keepdim=True)
405
+ conv1_weight = conv1_weight.to(conv1_type)
406
+ state_dict[conv1_name + '.weight'] = conv1_weight
407
+ elif in_chans != 3:
408
+ conv1_name = cfg['first_conv']
409
+ conv1_weight = state_dict[conv1_name + '.weight']
410
+ conv1_type = conv1_weight.dtype
411
+ conv1_weight = conv1_weight.float()
412
+ O, I, J, K = conv1_weight.shape
413
+ if I != 3:
414
+ print('Deleting first conv (%s) from pretrained weights.' % conv1_name)
415
+ del state_dict[conv1_name + '.weight']
416
+ strict = False
417
+ else:
418
+ # NOTE this strategy should be better than random init, but there could be other combinations of
419
+ # the original RGB input layer weights that'd work better for specific cases.
420
+ print('Repeating first conv (%s) weights in channel dim.' % conv1_name)
421
+ repeat = int(math.ceil(in_chans / 3))
422
+ conv1_weight = conv1_weight.repeat(1, repeat, 1, 1)[:, :in_chans, :, :]
423
+ conv1_weight *= (3 / float(in_chans))
424
+ conv1_weight = conv1_weight.to(conv1_type)
425
+ state_dict[conv1_name + '.weight'] = conv1_weight
426
+
427
+ classifier_name = cfg['classifier']
428
+ if pretrain_type == "mae":
429
+ pass
430
+ elif num_classes == 1000 and cfg['num_classes'] == 1001:
431
+ # special case for imagenet trained models with extra background class in pretrained weights
432
+ classifier_weight = state_dict[classifier_name + '.weight']
433
+ state_dict[classifier_name + '.weight'] = classifier_weight[1:]
434
+ classifier_bias = state_dict[classifier_name + '.bias']
435
+ state_dict[classifier_name + '.bias'] = classifier_bias[1:]
436
+ elif num_classes != cfg['num_classes']:
437
+ # completely discard fully connected for all other differences between pretrained and created model
438
+ del state_dict[classifier_name + '.weight']
439
+ del state_dict[classifier_name + '.bias']
440
+
441
+ # adjust position encoding
442
+ pe = state_dict['pos_embed'][:,1:,:]
443
+ b_pe, hw_pe, c_pe = pe.shape
444
+ side_pe = int(math.sqrt(hw_pe))
445
+ side_num_patches_search = int(math.sqrt(model.num_patches_search))
446
+ side_num_patches_template = int(math.sqrt(model.num_patches_template))
447
+ pe_2D = pe.reshape([b_pe, side_pe, side_pe, c_pe]).permute([0,3,1,2]) #b,c,h,w
448
+ if side_pe != side_num_patches_search:
449
+ pe_s_2D = nn.functional.interpolate(pe_2D, [side_num_patches_search, side_num_patches_search], align_corners=True, mode='bicubic')
450
+ pe_s = torch.flatten(pe_s_2D.permute([0,2,3,1]),1,2)
451
+ else:
452
+ pe_s = pe
453
+ if side_pe != side_num_patches_template:
454
+ pe_t_2D = nn.functional.interpolate(pe_2D, [side_num_patches_template, side_num_patches_template], align_corners=True, mode='bicubic')
455
+ pe_t = torch.flatten(pe_t_2D.permute([0, 2, 3, 1]), 1, 2)
456
+ else:
457
+ pe_t = pe
458
+ pe_xz = torch.cat((pe_s, pe_t), dim=1)
459
+ state_dict['pos_embed'] = pe_xz
460
+ # state_dict['pos_embed_template'] = pe_t
461
+ # state_dict['pos_embed_search'] = pe_s
462
+ # del state_dict['pos_embed']
463
+ del state_dict['cls_token']
464
+
465
+ model.load_state_dict(state_dict, strict=strict)
466
+
lib/models/atctrack/vit_mm.py ADDED
@@ -0,0 +1,575 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Vision Transformer (ViT) in PyTorch
2
+
3
+ A PyTorch implement of Vision Transformers as described in
4
+ 'An Image Is Worth 16 x 16 Words: Transformers for Image Recognition at Scale' - https://arxiv.org/abs/2010.11929
5
+
6
+ The official jax code is released and available at https://github.com/google-research/vision_transformer
7
+
8
+ Status/TODO:
9
+ * Models updated to be compatible with official impl. Args added to support backward compat for old PyTorch weights.
10
+ * Weights ported from official jax impl for 384x384 base and small models, 16x16 and 32x32 patches.
11
+ * Trained (supervised on ImageNet-1k) my custom 'small' patch model to 77.9, 'base' to 79.4 top-1 with this code.
12
+ * Hopefully find time and GPUs for SSL or unsupervised pretraining on OpenImages w/ ImageNet fine-tune in future.
13
+
14
+ Acknowledgments:
15
+ * The paper authors for releasing code and weights, thanks!
16
+ * I fixed my class token impl based on Phil Wang's https://github.com/lucidrains/vit-pytorch ... check it out
17
+ for some einops/einsum fun
18
+ * Simple transformer style inspired by Andrej Karpathy's https://github.com/karpathy/minGPT
19
+ * Bert reference code checks against Huggingface Transformers and Tensorflow Bert
20
+
21
+ Hacked together by / Copyright 2020 Ross Wightman
22
+ """
23
+ import torch
24
+ import torch.nn as nn
25
+ import torch.utils.model_zoo as model_zoo
26
+ import torch.utils.checkpoint as checkpoint
27
+ import torch.nn.functional as F
28
+ import math
29
+ from functools import partial
30
+
31
+ from timm.data import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD
32
+ from timm.models.layers import DropPath, to_2tuple, trunc_normal_
33
+ from timm.models.registry import register_model
34
+ from .utils import combine_tokens, token2feature, feature2token
35
+
36
+
37
+ def _cfg(url='', **kwargs):
38
+ return {
39
+ 'url': url,
40
+ 'num_classes': 1000, 'input_size': (3, 224, 224), 'pool_size': None,
41
+ 'crop_pct': .9, 'interpolation': 'bicubic',
42
+ 'mean': IMAGENET_DEFAULT_MEAN, 'std': IMAGENET_DEFAULT_STD,
43
+ 'first_conv': 'patch_embed.proj', 'classifier': 'head',
44
+ **kwargs
45
+ }
46
+
47
+
48
+ default_cfgs = {
49
+ # patch models
50
+ # mae ViT-B/16-224 pre-trained model
51
+ 'vit_base_patch16_224_mae': _cfg(
52
+ url='https://dl.fbaipublicfiles.com/mae/pretrain/mae_pretrain_vit_base.pth',
53
+ input_size=(3, 224, 224), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
54
+ 'vit_base_patch16_224_default': _cfg(
55
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_p16_384-83fb41ba.pth',
56
+ input_size=(3, 224, 224), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
57
+ # mae ViT-L/16-224 pre-trained model
58
+ 'vit_large_patch16_224_mae': _cfg(
59
+ url='https://dl.fbaipublicfiles.com/mae/pretrain/mae_pretrain_vit_large.pth',
60
+ input_size=(3, 224, 224), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
61
+ # mae ViT-H/14-224 pre-trained model
62
+ 'vit_huge_patch14_224_mae': _cfg(
63
+ url='https://dl.fbaipublicfiles.com/mae/pretrain/mae_pretrain_vit_huge.pth',
64
+ input_size=(3, 224, 224), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
65
+ 'vit_small_patch16_224': _cfg(
66
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-weights/vit_small_p16_224-15ec54c9.pth',
67
+ ),
68
+ 'vit_base_patch16_224': _cfg(
69
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_p16_224-80ecf9dd.pth',
70
+ mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5),
71
+ ),
72
+ 'vit_base_patch16_384': _cfg(
73
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_p16_384-83fb41ba.pth',
74
+ input_size=(3, 384, 384), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
75
+ 'vit_base_patch32_384': _cfg(
76
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_p32_384-830016f5.pth',
77
+ input_size=(3, 384, 384), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
78
+ 'vit_large_patch16_224': _cfg(
79
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_large_p16_224-4ee7a4dc.pth',
80
+ mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)),
81
+ 'vit_large_patch16_384': _cfg(
82
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_large_p16_384-b3be5167.pth',
83
+ input_size=(3, 384, 384), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
84
+ 'vit_large_patch32_384': _cfg(
85
+ url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_large_p32_384-9b920ba8.pth',
86
+ input_size=(3, 384, 384), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
87
+ 'vit_huge_patch16_224': _cfg(),
88
+ 'vit_huge_patch32_384': _cfg(input_size=(3, 384, 384)),
89
+ # hybrid models
90
+ 'vit_small_resnet26d_224': _cfg(),
91
+ 'vit_small_resnet50d_s3_224': _cfg(),
92
+ 'vit_base_resnet26d_224': _cfg(),
93
+ 'vit_base_resnet50d_224': _cfg(),
94
+ }
95
+
96
+
97
+ class Mlp(nn.Module):
98
+ def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):
99
+ super().__init__()
100
+ out_features = out_features or in_features
101
+ hidden_features = hidden_features or in_features
102
+ self.fc1 = nn.Linear(in_features, hidden_features)
103
+ self.act = act_layer()
104
+ self.fc2 = nn.Linear(hidden_features, out_features)
105
+ self.drop = nn.Dropout(drop)
106
+
107
+ def forward(self, x):
108
+ x = self.fc1(x)
109
+ x = self.act(x)
110
+ x = self.drop(x)
111
+ x = self.fc2(x)
112
+ x = self.drop(x)
113
+ return x
114
+
115
+
116
+ class Attention(nn.Module):
117
+ def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):
118
+ super().__init__()
119
+ self.num_heads = num_heads
120
+ head_dim = dim // num_heads
121
+ # NOTE scale factor was wrong in my original version, can set manually to be compat with prev weights
122
+ self.scale = qk_scale or head_dim ** -0.5
123
+
124
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
125
+ self.attn_drop = nn.Dropout(attn_drop)
126
+ self.proj = nn.Linear(dim, dim)
127
+ self.proj_drop = nn.Dropout(proj_drop)
128
+
129
+ def forward(self, x):
130
+ B, N, C = x.shape
131
+ qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
132
+ q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple)
133
+
134
+ attn = (q @ k.transpose(-2, -1)) * self.scale
135
+ attn = attn.softmax(dim=-1)
136
+ attn = self.attn_drop(attn)
137
+
138
+ x = (attn @ v).transpose(1, 2).reshape(B, N, C)
139
+ x = self.proj(x)
140
+ x = self.proj_drop(x)
141
+ return x
142
+
143
+
144
+ class Block(nn.Module):
145
+
146
+ def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop=0., attn_drop=0.,
147
+ drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm):
148
+ super().__init__()
149
+ self.norm1 = norm_layer(dim)
150
+ self.attn = Attention(
151
+ dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop)
152
+ # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here
153
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
154
+ self.norm2 = norm_layer(dim)
155
+ mlp_hidden_dim = int(dim * mlp_ratio)
156
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
157
+
158
+ def forward(self, x):
159
+ x = x + self.drop_path(self.attn(self.norm1(x)))
160
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
161
+ return x
162
+
163
+
164
+ class PatchEmbed(nn.Module):
165
+ """ Image to Patch Embedding
166
+ """
167
+ def __init__(self, patch_size=16, in_chans=3, embed_dim=768):
168
+ super().__init__()
169
+ self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size)
170
+
171
+ def forward(self, x):
172
+ # B, C, H, W = x.shape
173
+ x = self.proj(x).flatten(2).transpose(1, 2)
174
+ return x
175
+
176
+ class Interface_block(nn.Module, ):
177
+ def __init__(self, inplanes=None, hide_channel=None):
178
+ super(Interface_block, self).__init__()
179
+ self.conv0_0 = nn.Conv2d(in_channels=inplanes, out_channels=hide_channel, kernel_size=1, stride=1, padding=0)
180
+ self.conv0_1 = nn.Conv2d(in_channels=inplanes, out_channels=hide_channel, kernel_size=1, stride=1, padding=0)
181
+ self.conv1x1 = nn.Conv2d(in_channels=hide_channel, out_channels=inplanes, kernel_size=1, stride=1, padding=0)
182
+
183
+ for p in self.parameters():
184
+ if p.dim() > 1:
185
+ nn.init.xavier_uniform_(p)
186
+
187
+ def forward(self, x):
188
+ """ Forward pass with input x. """
189
+ B, C, W, H = x.shape
190
+ x0 = x[:, 0:int(C/2), :, :].contiguous()
191
+ x0 = self.conv0_0(x0)
192
+ x1 = x[:, int(C/2):, :, :].contiguous()
193
+ x1 = self.conv0_1(x1)
194
+ x0 = x0 + x1
195
+ return self.conv1x1(x0)
196
+
197
+ class VisionTransformerMM(nn.Module):
198
+ """ Vision Transformer with support for patch or hybrid CNN input stage
199
+ """
200
+ def __init__(self, search_size=384, template_size=192,
201
+ patch_size=16, in_chans=3, num_classes=1000, embed_dim=768, depth=12,
202
+ num_heads=12, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop_rate=0., attn_drop_rate=0.,
203
+ drop_path_rate=0., hybrid_backbone=None, norm_layer=nn.LayerNorm,
204
+ search_number=1, template_number=1, use_checkpoint=False,
205
+ interface_type=None, interface_dim=8, instruct=True):
206
+ super().__init__()
207
+ self.use_checkpoint = use_checkpoint
208
+ self.num_classes = num_classes
209
+ self.num_features = self.embed_dim = embed_dim # num_features for consistency with other models
210
+ self.embed_dim_list = [embed_dim]
211
+ self.num_search = search_number
212
+ self.num_template = template_number
213
+
214
+ self.patch_embed = PatchEmbed(
215
+ patch_size=patch_size, in_chans=in_chans, embed_dim=embed_dim)
216
+
217
+ self.patch_embed_interface = PatchEmbed(
218
+ patch_size=patch_size, in_chans=in_chans, embed_dim=embed_dim)
219
+
220
+ self.num_patches_search = (search_size // patch_size) * (search_size // patch_size)
221
+ self.num_patches_template = (template_size // patch_size) * (template_size // patch_size)
222
+
223
+ # self.pos_embed = nn.Parameter(torch.zeros(1, self.num_patches_search + self.num_patches_template, embed_dim))
224
+ self.pos_embed_search = nn.Parameter(torch.zeros(1, self.num_patches_search, embed_dim))
225
+ self.pos_embed_template = nn.Parameter(torch.zeros(1, self.num_patches_template, embed_dim))
226
+
227
+ self.pos_drop = nn.Dropout(p=drop_rate)
228
+
229
+ # for multi-modal
230
+ self.interface_type = interface_type
231
+ '''interface parameters'''
232
+ if self.interface_type in ['low-rank_add']:
233
+ interface_blocks = []
234
+ block_nums = depth
235
+ for i in range(block_nums):
236
+ if self.interface_type == 'low-rank_add':
237
+ interface_blocks.append(Interface_block(inplanes=embed_dim, hide_channel=interface_dim))
238
+ else:
239
+ raise NotImplementedError
240
+ self.interface_blocks = nn.Sequential(*interface_blocks)
241
+
242
+ interface_norms = []
243
+ for i in range(block_nums):
244
+ interface_norms.append(norm_layer(embed_dim))
245
+ self.interface_norms = nn.Sequential(*interface_norms)
246
+
247
+
248
+ dpr = [x.item() for x in torch.linspace(0, drop_path_rate, depth)] # stochastic depth decay rule
249
+ self.blocks = nn.ModuleList([
250
+ Block(
251
+ dim=embed_dim, num_heads=num_heads, mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, qk_scale=qk_scale,
252
+ drop=drop_rate, attn_drop=attn_drop_rate, drop_path=dpr[i], norm_layer=norm_layer)
253
+ for i in range(depth)])
254
+
255
+ self.instruct = instruct
256
+ if instruct:
257
+ num_embeddings = 4
258
+ self.prompt_embeddings = nn.Embedding(num_embeddings, embed_dim) # should be consistent with new tokens in decoder.instruct_tokens
259
+
260
+ self.norm = norm_layer(embed_dim)
261
+ trunc_normal_(self.pos_embed_search, std=.02)
262
+ trunc_normal_(self.pos_embed_template, std=.02)
263
+ self.apply(self._init_weights)
264
+
265
+ def _init_weights(self, m):
266
+ if isinstance(m, nn.Linear):
267
+ trunc_normal_(m.weight, std=.02)
268
+ if isinstance(m, nn.Linear) and m.bias is not None:
269
+ nn.init.constant_(m.bias, 0)
270
+ elif isinstance(m, nn.LayerNorm):
271
+ nn.init.constant_(m.bias, 0)
272
+ nn.init.constant_(m.weight, 1.0)
273
+
274
+ @torch.jit.ignore
275
+ def no_weight_decay(self):
276
+ return {'pos_embed', 'cls_token'}
277
+
278
+ def get_classifier(self):
279
+ return self.head
280
+
281
+ def reset_classifier(self, num_classes, global_pool=''):
282
+ self.num_classes = num_classes
283
+ self.head = nn.Linear(self.embed_dim, num_classes) if num_classes > 0 else nn.Identity()
284
+
285
+ def forward_features(self, template_list, search_list, text_src, seq):
286
+ num_template = len(template_list)
287
+ num_search = len(search_list)
288
+ if self.instruct:
289
+ instruct_embedding = self.prompt_embeddings(seq).unsqueeze(1)
290
+
291
+ z = torch.stack(template_list, dim=1)#(b,n,c,h,w)
292
+ z = z.view(-1, *z.size()[2:])#(bn,c,h,w)
293
+ x = torch.stack(search_list, dim=1)#(b,n,c,h,w)
294
+ x = x.view(-1, *x.size()[2:])#(bn,c,h,w)
295
+
296
+ # rgb image
297
+ x_rgb = x[:, :3, :, :]
298
+ z_rgb = z[:, :3, :, :]
299
+ # multi-modal image
300
+ x_dte = x[:, 3:, :, :]
301
+ z_dte = z[:, 3:, :, :]
302
+
303
+ x_rgb = self.patch_embed(x_rgb)
304
+ z_rgb = self.patch_embed(z_rgb)
305
+
306
+ if self.interface_type in ['low-rank_add']:
307
+ z_dte = self.patch_embed_interface(z_dte)
308
+ x_dte = self.patch_embed_interface(x_dte)
309
+ z_dte, x_dte = self.language_interface(z_dte, x_dte, text_src) # add language information
310
+ z_rgb_feat = token2feature(self.interface_norms[0](z_rgb))
311
+ x_rgb_feat = token2feature(self.interface_norms[0](x_rgb))
312
+ z_dte_feat = token2feature(self.interface_norms[0](z_dte))
313
+ x_dte_feat = token2feature(self.interface_norms[0](x_dte))
314
+ z_feat = torch.cat([z_rgb_feat, z_dte_feat], dim=1)
315
+ x_feat = torch.cat([x_rgb_feat, x_dte_feat], dim=1)
316
+ z_feat = self.interface_blocks[0](z_feat)
317
+ x_feat = self.interface_blocks[0](x_feat)
318
+ z_dte = feature2token(z_feat)
319
+ x_dte = feature2token(x_feat)
320
+ x = x_rgb + x_dte
321
+ z = z_rgb + z_dte
322
+ z = z + self.pos_embed_template
323
+ x = x + self.pos_embed_search
324
+ x_dte = x_dte.reshape(-1, num_search * x_dte.size(1), x_dte.size(-1))
325
+ z_dte = z_dte.reshape(-1, num_template * z_dte.size(1), z_dte.size(-1))
326
+ z = z.reshape(-1, num_template * z.size(1), z.size(-1))
327
+ x = x.reshape(-1, num_search * x.size(1), x.size(-1))
328
+ len_x = x.size(1)
329
+ len_z = z.size(1)
330
+ xz = torch.cat([x, z], dim=1)
331
+ else:
332
+ raise ValueError('illegal interface_type')
333
+
334
+ if self.instruct:
335
+ xz = torch.cat([instruct_embedding, xz], dim=1)
336
+
337
+ xz = self.pos_drop(xz)
338
+
339
+ for i, blk in enumerate(self.blocks): #batch is the first dimension.
340
+ if i >= 1:
341
+ if self.interface_type in ['low-rank_add']:
342
+ if self.instruct:
343
+ instruct_embedding = xz[:, 0, :].unsqueeze(1)
344
+ xz = xz[:, 1:, :]
345
+ xz_ori = xz
346
+ x = xz[:, :len_x, :]
347
+ z = xz[:, len_x:, :]
348
+ x = x.reshape(x.size(0)*num_search,-1,x.size(-1))
349
+ z = z.reshape(z.size(0)*num_template,-1,z.size(-1))
350
+ x_dte = x_dte.reshape(x_dte.size(0)*num_search,-1,x.size(-1))
351
+ z_dte = z_dte.reshape(z_dte.size(0)*num_template,-1,z.size(-1))
352
+ x_rgb_feat = token2feature(self.interface_norms[i](x))
353
+ z_rgb_feat = token2feature(self.interface_norms[i](z))
354
+ x_dte_feat = token2feature(self.interface_norms[i](x_dte))
355
+ z_dte_feat = token2feature(self.interface_norms[i](z_dte))
356
+ z_feat = torch.cat([z_rgb_feat, z_dte_feat], dim=1)
357
+ x_feat = torch.cat([x_rgb_feat, x_dte_feat], dim=1)
358
+ z_feat = self.interface_blocks[i](z_feat)
359
+ x_feat = self.interface_blocks[i](x_feat)
360
+ z_dte = feature2token(z_feat)
361
+ x_dte = feature2token(x_feat)
362
+ x_dte = x_dte.reshape(-1,num_search*x_dte.size(1),x_dte.size(-1))
363
+ z_dte = z_dte.reshape(-1,num_template*z_dte.size(1),z_dte.size(-1))
364
+ xz_dte = torch.cat([x_dte, z_dte], dim=1)
365
+ xz = xz_ori + xz_dte
366
+ if self.instruct:
367
+ xz = torch.cat([instruct_embedding, xz], dim=1)
368
+
369
+ if self.use_checkpoint:
370
+ xz = checkpoint.checkpoint(blk, xz)
371
+ else:
372
+ xz = blk(xz)
373
+
374
+ xz = self.norm(xz) # B,N,C
375
+ return xz
376
+
377
+ def forward_features_rgb(self, template_list, search_list):
378
+ num_template = len(template_list)
379
+ num_search = len(search_list)
380
+
381
+ z = torch.stack(template_list, dim=1)#(b,n,c,h,w)
382
+ z = z.view(-1, *z.size()[2:])#(bn,c,h,w)
383
+ x = torch.stack(search_list, dim=1)#(b,n,c,h,w)
384
+ x = x.view(-1, *x.size()[2:])#(bn,c,h,w)
385
+
386
+ x = self.patch_embed(x)
387
+ z = self.patch_embed(z)
388
+
389
+
390
+ z = z + self.pos_embed_template
391
+ x = x + self.pos_embed_search
392
+
393
+ # for multiple search region and template, go back
394
+ z = z.reshape(-1,num_template * z.size(1),z.size(-1))
395
+ x = x.reshape(-1,num_search * x.size(1),x.size(-1))
396
+
397
+ len_x = x.size(1)
398
+ len_z = z.size(1)
399
+
400
+ xz = torch.cat([x, z], dim=1)
401
+
402
+ xz = self.pos_drop(xz)
403
+
404
+ for i, blk in enumerate(self.blocks): #batch is the first dimension.
405
+ if self.use_checkpoint:
406
+ xz = checkpoint.checkpoint(blk, xz)
407
+ else:
408
+ print(i)
409
+ xz = blk(xz)
410
+
411
+ xz = self.norm(xz) # B,N,C
412
+ return xz
413
+
414
+ def forward(self, template_list, search_list, text_src, seq):
415
+ xz = self.forward_features(template_list, search_list, text_src, seq)
416
+ out=[xz]
417
+ return out
418
+
419
+ def forward_rgb(self, template_list, search_list):
420
+ xz = self.forward_features_rgb(template_list, search_list)
421
+ out=[xz]
422
+ return out
423
+
424
+ def language_interface(self, z_dte, x_dte, text_src):
425
+ text_src = text_src.unsqueeze(1)
426
+ x_dte = x_dte * text_src
427
+ text_src_z = text_src.expand(-1,self.num_template,-1).reshape(text_src.size(0)*self.num_template,1,-1)
428
+ z_dte = z_dte * text_src_z
429
+ return z_dte, x_dte
430
+
431
+ @register_model
432
+ def vitmm_base_patch16(pretrained=False, pretrain_type='default',
433
+ search_size=384, template_size=192, **kwargs):
434
+ patch_size = 16
435
+ model = VisionTransformerMM(
436
+ search_size=search_size, template_size=template_size,
437
+ patch_size=patch_size, num_classes=0,
438
+ embed_dim=768, depth=12, num_heads=12, mlp_ratio=4, qkv_bias=True,
439
+ norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)
440
+ cfg_type = 'vit_base_patch16_224_' + pretrain_type
441
+ if pretrain_type == 'scratch':
442
+ pretrained = False
443
+ return model
444
+ model.default_cfg = default_cfgs[cfg_type]
445
+ if pretrained:
446
+ load_pretrained(model, pretrain_type,
447
+ num_classes=model.num_classes, in_chans=kwargs.get('in_chans', 3))
448
+ return model
449
+
450
+ @register_model
451
+ def vitmm_large_patch16(pretrained=False, pretrain_type='default',
452
+ search_size=384, template_size=192, **kwargs):
453
+ patch_size = 16
454
+ model = VisionTransformerMM(
455
+ search_size=search_size, template_size=template_size,
456
+ patch_size=patch_size, num_classes=0,
457
+ embed_dim=1024, depth=24, num_heads=16, mlp_ratio=4, qkv_bias=True,
458
+ norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)
459
+ cfg_type = 'vit_large_patch16_224_' + pretrain_type
460
+ if pretrain_type == 'scratch':
461
+ pretrained = False
462
+ return model
463
+ model.default_cfg = default_cfgs[cfg_type]
464
+ if pretrained:
465
+ load_pretrained(model, pretrain_type, num_classes=model.num_classes, in_chans=kwargs.get('in_chans', 3))
466
+ return model
467
+
468
+ @register_model
469
+ def vitmm_huge_patch14(pretrained=False, pretrain_type='default',
470
+ search_size=364, template_size=182, **kwargs):
471
+ patch_size = 14
472
+ model = VisionTransformerMM(
473
+ search_size=search_size, template_size=template_size,
474
+ patch_size=patch_size, num_classes=0,
475
+ embed_dim=1280, depth=32, num_heads=16, mlp_ratio=4, qkv_bias=True,
476
+ norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)
477
+ cfg_type = 'vit_huge_patch14_224_' + pretrain_type
478
+ if pretrain_type == 'scratch':
479
+ pretrained = False
480
+ return model
481
+ model.default_cfg = default_cfgs[cfg_type]
482
+ if pretrained:
483
+ load_pretrained(model,
484
+ pretrain_type, num_classes=model.num_classes, in_chans=kwargs.get('in_chans', 3))
485
+ return model
486
+
487
+ def load_pretrained(model, pretrain_type='default', cfg=None, num_classes=1000, in_chans=3, filter_fn=None, strict=False):
488
+ if cfg is None:
489
+ cfg = getattr(model, 'default_cfg')
490
+ if cfg is None or 'url' not in cfg or not cfg['url']:
491
+ print("Pretrained model URL is invalid, using random initialization.")
492
+ return
493
+
494
+ state_dict = model_zoo.load_url(cfg['url'], progress=False, map_location='cpu')
495
+ if pretrain_type == 'mae':
496
+ state_dict = state_dict['model']
497
+
498
+ if filter_fn is not None:
499
+ state_dict = filter_fn(state_dict)
500
+
501
+ if in_chans == 1:
502
+ conv1_name = cfg['first_conv']
503
+ print('Converting first conv (%s) pretrained weights from 3 to 1 channel' % conv1_name)
504
+ conv1_weight = state_dict[conv1_name + '.weight']
505
+ # Some weights are in torch.half, ensure it's float for sum on CPU
506
+ conv1_type = conv1_weight.dtype
507
+ conv1_weight = conv1_weight.float()
508
+ O, I, J, K = conv1_weight.shape
509
+ if I > 3:
510
+ assert conv1_weight.shape[1] % 3 == 0
511
+ # For models with space2depth stems
512
+ conv1_weight = conv1_weight.reshape(O, I // 3, 3, J, K)
513
+ conv1_weight = conv1_weight.sum(dim=2, keepdim=False)
514
+ else:
515
+ conv1_weight = conv1_weight.sum(dim=1, keepdim=True)
516
+ conv1_weight = conv1_weight.to(conv1_type)
517
+ state_dict[conv1_name + '.weight'] = conv1_weight
518
+ elif in_chans != 3:
519
+ conv1_name = cfg['first_conv']
520
+ conv1_weight = state_dict[conv1_name + '.weight']
521
+ conv1_type = conv1_weight.dtype
522
+ conv1_weight = conv1_weight.float()
523
+ O, I, J, K = conv1_weight.shape
524
+ if I != 3:
525
+ print('Deleting first conv (%s) from pretrained weights.' % conv1_name)
526
+ del state_dict[conv1_name + '.weight']
527
+ strict = False
528
+ else:
529
+ # NOTE this strategy should be better than random init, but there could be other combinations of
530
+ # the original RGB input layer weights that'd work better for specific cases.
531
+ print('Repeating first conv (%s) weights in channel dim.' % conv1_name)
532
+ repeat = int(math.ceil(in_chans / 3))
533
+ conv1_weight = conv1_weight.repeat(1, repeat, 1, 1)[:, :in_chans, :, :]
534
+ conv1_weight *= (3 / float(in_chans))
535
+ conv1_weight = conv1_weight.to(conv1_type)
536
+ state_dict[conv1_name + '.weight'] = conv1_weight
537
+
538
+ classifier_name = cfg['classifier']
539
+ if pretrain_type == "mae":
540
+ pass
541
+ elif num_classes == 1000 and cfg['num_classes'] == 1001:
542
+ # special case for imagenet trained models with extra background class in pretrained weights
543
+ classifier_weight = state_dict[classifier_name + '.weight']
544
+ state_dict[classifier_name + '.weight'] = classifier_weight[1:]
545
+ classifier_bias = state_dict[classifier_name + '.bias']
546
+ state_dict[classifier_name + '.bias'] = classifier_bias[1:]
547
+ elif num_classes != cfg['num_classes']:
548
+ # completely discard fully connected for all other differences between pretrained and created model
549
+ del state_dict[classifier_name + '.weight']
550
+ del state_dict[classifier_name + '.bias']
551
+
552
+ # adjust position encoding
553
+ pe = state_dict['pos_embed'][:,1:,:]
554
+ b_pe, hw_pe, c_pe = pe.shape
555
+ side_pe = int(math.sqrt(hw_pe))
556
+ side_num_patches_search = int(math.sqrt(model.num_patches_search))
557
+ side_num_patches_template = int(math.sqrt(model.num_patches_template))
558
+ pe_2D = pe.reshape([b_pe, side_pe, side_pe, c_pe]).permute([0,3,1,2]) #b,c,h,w
559
+ if side_pe != side_num_patches_search:
560
+ pe_s_2D = nn.functional.interpolate(pe_2D, [side_num_patches_search, side_num_patches_search], align_corners=True, mode='bicubic')
561
+ pe_s = torch.flatten(pe_s_2D.permute([0,2,3,1]),1,2)
562
+ else:
563
+ pe_s = pe
564
+ if side_pe != side_num_patches_template:
565
+ pe_t_2D = nn.functional.interpolate(pe_2D, [side_num_patches_template, side_num_patches_template], align_corners=True, mode='bicubic')
566
+ pe_t = torch.flatten(pe_t_2D.permute([0, 2, 3, 1]), 1, 2)
567
+ else:
568
+ pe_t = pe
569
+ state_dict['pos_embed_template'] = pe_t
570
+ state_dict['pos_embed_search'] = pe_s
571
+ del state_dict['cls_token']
572
+ del state_dict['pos_embed']
573
+
574
+ model.load_state_dict(state_dict, strict=strict)
575
+
lib/models/layers/__init__.py ADDED
File without changes
lib/models/layers/adapter.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+ import timm
4
+ import math
5
+
6
+
7
+ '''
8
+ def forward_block(self, x):
9
+ x = x + self.drop_path(self.attn(self.norm1(x))) + self.drop_path(self.adapter_attn(self.norm1(x))) * self.s
10
+ x = x + self.drop_path(self.mlp(self.norm2(x))) + self.drop_path(self.adapter_mlp(self.norm2(x))) * self.s
11
+ return x
12
+
13
+
14
+ def forward_block_attn(self, x):
15
+ x = x + self.drop_path(self.attn(self.norm1(x))) + self.drop_path(self.adapter_attn(self.norm1(x))) * self.s
16
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
17
+ return x
18
+ '''
19
+
20
+
21
+ class QuickGELU(nn.Module):
22
+ def forward(self, x: torch.Tensor):
23
+ return x * torch.sigmoid(1.702 * x)
24
+
25
+
26
+
27
+ class Bi_direct_adapter(nn.Module):
28
+ def __init__(self, dim=8,input_dim=768, xavier_init=False):
29
+ super().__init__()
30
+
31
+ self.adapter_down = nn.Linear(input_dim, dim)
32
+ self.adapter_up = nn.Linear(dim, input_dim)
33
+ self.adapter_mid = nn.Linear(dim, dim)
34
+
35
+ #nn.init.xavier_uniform_(self.adapter_down.weight)
36
+ nn.init.zeros_(self.adapter_mid.bias)
37
+ nn.init.zeros_(self.adapter_mid.weight)
38
+ nn.init.zeros_(self.adapter_down.weight)
39
+ nn.init.zeros_(self.adapter_down.bias)
40
+ nn.init.zeros_(self.adapter_up.weight)
41
+ nn.init.zeros_(self.adapter_up.bias)
42
+
43
+ #self.act = QuickGELU()
44
+ self.dropout = nn.Dropout(0.1)
45
+ self.dim = dim
46
+
47
+ def forward(self, x):
48
+ # B, N, C = x.shape
49
+ x_down = self.adapter_down(x)
50
+ #x_down = self.act(x_down)
51
+ x_down = self.adapter_mid(x_down)
52
+ #x_down = self.act(x_down)
53
+ x_down = self.dropout(x_down)
54
+ x_up = self.adapter_up(x_down)
55
+ #print("return adap x", x_up.size())
56
+ return x_up
57
+
58
+ """
59
+
60
+
61
+ class Convpass(nn.Module):
62
+ def __init__(self, dim=8, xavier_init=False):
63
+ super().__init__()
64
+
65
+ self.adapter_conv = nn.Conv2d(dim, dim, 3, 1, 1)
66
+ if xavier_init:
67
+ nn.init.xavier_uniform_(self.adapter_conv.weight)
68
+ else:
69
+ nn.init.zeros_(self.adapter_conv.weight)
70
+ self.adapter_conv.weight.data[:, :, 1, 1] += torch.eye(8, dtype=torch.float)
71
+ nn.init.zeros_(self.adapter_conv.bias)
72
+
73
+ self.adapter_down = nn.Linear(768, dim) # equivalent to 1 * 1 Conv
74
+ self.adapter_up = nn.Linear(dim, 768) # equivalent to 1 * 1 Conv
75
+ nn.init.xavier_uniform_(self.adapter_down.weight)
76
+ nn.init.zeros_(self.adapter_down.bias)
77
+ nn.init.zeros_(self.adapter_up.weight)
78
+ nn.init.zeros_(self.adapter_up.bias)
79
+
80
+ self.act = QuickGELU()
81
+ self.dropout = nn.Dropout(0.1)
82
+ self.dim = dim
83
+
84
+ def forward(self, x):
85
+ B, N, C = x.shape
86
+ #print(x.shape)
87
+ x_down = self.adapter_down(x) # equivalent to 1 * 1 Conv
88
+ x_down = self.act(x_down)
89
+
90
+ #print(x_down.shape)
91
+
92
+ x_patch = x_down[:, 64:].reshape(B, 16, 16, self.dim).permute(0, 3, 1, 2) ############
93
+ x_patch = self.adapter_conv(x_patch)
94
+ x_patch = x_patch.permute(0, 2, 3, 1).reshape(B, 16 * 16, self.dim)
95
+
96
+
97
+ #x_down = torch.cat([x_cls, x_patch], dim=1)
98
+
99
+ x_down = self.act(x_down)
100
+ x_down = self.dropout(x_down)
101
+ x_up = self.adapter_up(x_down) # equivalent to 1 * 1 Conv
102
+
103
+ return x_up
104
+ """
lib/models/layers/attn.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+ from timm.models.layers import trunc_normal_
5
+
6
+ from lib.models.layers.rpe import generate_2d_concatenated_self_attention_relative_positional_encoding_index
7
+
8
+
9
+ class Attention(nn.Module):
10
+ def __init__(self, dim, num_heads=8, qkv_bias=False, attn_drop=0., proj_drop=0.,
11
+ rpe=False, z_size=7, x_size=14):
12
+ super().__init__()
13
+ self.num_heads = num_heads
14
+ head_dim = dim // num_heads
15
+ self.scale = head_dim ** -0.5
16
+
17
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
18
+ self.attn_drop = nn.Dropout(attn_drop)
19
+ self.proj = nn.Linear(dim, dim)
20
+ self.proj_drop = nn.Dropout(proj_drop)
21
+
22
+ self.rpe =rpe
23
+ if self.rpe:
24
+ relative_position_index = \
25
+ generate_2d_concatenated_self_attention_relative_positional_encoding_index([z_size, z_size],
26
+ [x_size, x_size])
27
+ self.register_buffer("relative_position_index", relative_position_index)
28
+ # define a parameter table of relative position bias
29
+ self.relative_position_bias_table = nn.Parameter(torch.empty((num_heads,
30
+ relative_position_index.max() + 1)))
31
+ trunc_normal_(self.relative_position_bias_table, std=0.02)
32
+
33
+ def forward(self, x, mask=None, return_attention=False):
34
+ # x: B, N, C
35
+ # mask: [B, N, ] torch.bool
36
+ B, N, C = x.shape
37
+ qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
38
+ q, k, v = qkv.unbind(0) # make torchscript happy (cannot use tensor as tuple)
39
+
40
+ attn = (q @ k.transpose(-2, -1)) * self.scale
41
+
42
+ if self.rpe:
43
+ relative_position_bias = self.relative_position_bias_table[:, self.relative_position_index].unsqueeze(0)
44
+ attn += relative_position_bias
45
+
46
+ if mask is not None:
47
+ attn = attn.masked_fill(mask.unsqueeze(1).unsqueeze(2), float('-inf'),)
48
+
49
+ split_attn = False
50
+ len_t = 49
51
+ if split_attn:
52
+ attn_t = attn[..., :len_t].softmax(dim=-1)
53
+ attn_s = attn[..., len_t:].softmax(dim=-1)
54
+ attn = torch.cat([attn_t, attn_s], dim=-1)
55
+ else:
56
+ attn = attn.softmax(dim=-1)
57
+ attn = self.attn_drop(attn)
58
+
59
+ x = (attn @ v).transpose(1, 2).reshape(B, N, C)
60
+ x = self.proj(x)
61
+ x = self.proj_drop(x)
62
+
63
+ if return_attention:
64
+ return x, attn
65
+ else:
66
+ return x
67
+
68
+
69
+ class Attention_talking_head(nn.Module):
70
+ # taken from https://github.com/rwightman/pytorch-image-models/blob/master/timm/models/vision_transformer.py
71
+ # with slight modifications to add Talking Heads Attention (https://arxiv.org/pdf/2003.02436v1.pdf)
72
+ def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.,
73
+ rpe=True, z_size=7, x_size=14):
74
+ super().__init__()
75
+
76
+ self.num_heads = num_heads
77
+
78
+ head_dim = dim // num_heads
79
+
80
+ self.scale = qk_scale or head_dim ** -0.5
81
+
82
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
83
+ self.attn_drop = nn.Dropout(attn_drop)
84
+
85
+ self.proj = nn.Linear(dim, dim)
86
+
87
+ self.proj_l = nn.Linear(num_heads, num_heads)
88
+ self.proj_w = nn.Linear(num_heads, num_heads)
89
+
90
+ self.proj_drop = nn.Dropout(proj_drop)
91
+
92
+ self.rpe = rpe
93
+ if self.rpe:
94
+ relative_position_index = \
95
+ generate_2d_concatenated_self_attention_relative_positional_encoding_index([z_size, z_size],
96
+ [x_size, x_size])
97
+ self.register_buffer("relative_position_index", relative_position_index)
98
+ # define a parameter table of relative position bias
99
+ self.relative_position_bias_table = nn.Parameter(torch.empty((num_heads,
100
+ relative_position_index.max() + 1)))
101
+ trunc_normal_(self.relative_position_bias_table, std=0.02)
102
+
103
+ def forward(self, x, mask=None):
104
+ B, N, C = x.shape
105
+ qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
106
+ q, k, v = qkv[0] * self.scale, qkv[1], qkv[2]
107
+
108
+ attn = (q @ k.transpose(-2, -1))
109
+
110
+ if self.rpe:
111
+ relative_position_bias = self.relative_position_bias_table[:, self.relative_position_index].unsqueeze(0)
112
+ attn += relative_position_bias
113
+
114
+ if mask is not None:
115
+ attn = attn.masked_fill(mask.unsqueeze(1).unsqueeze(2),
116
+ float('-inf'),)
117
+
118
+ attn = self.proj_l(attn.permute(0, 2, 3, 1)).permute(0, 3, 1, 2)
119
+
120
+ attn = attn.softmax(dim=-1)
121
+
122
+ attn = self.proj_w(attn.permute(0, 2, 3, 1)).permute(0, 3, 1, 2)
123
+ attn = self.attn_drop(attn)
124
+
125
+ x = (attn @ v).transpose(1, 2).reshape(B, N, C)
126
+ x = self.proj(x)
127
+ x = self.proj_drop(x)
128
+ return x
lib/models/layers/attn_adapt_blocks.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ import torch.nn as nn
4
+ from timm.models.layers import Mlp, DropPath, trunc_normal_, lecun_normal_
5
+
6
+ from lib.models.layers.attn import Attention
7
+ from lib.models.layers.adapter import Bi_direct_adapter
8
+
9
+
10
+
11
+ def candidate_elimination(attn: torch.Tensor, tokens: torch.Tensor, lens_t: int, keep_ratio: float, global_index: torch.Tensor, box_mask_z: torch.Tensor):
12
+ """
13
+ Eliminate potential background candidates for computation reduction and noise cancellation.
14
+ Args:
15
+ attn (torch.Tensor): [B, num_heads, L_t + L_s, L_t + L_s], attention weights
16
+ tokens (torch.Tensor): [B, L_t + L_s, C], template and search region tokens
17
+ lens_t (int): length of template
18
+ keep_ratio (float): keep ratio of search region tokens (candidates)
19
+ global_index (torch.Tensor): global index of search region tokens
20
+ box_mask_z (torch.Tensor): template mask used to accumulate attention weights
21
+
22
+ Returns:
23
+ tokens_new (torch.Tensor): tokens after candidate elimination
24
+ keep_index (torch.Tensor): indices of kept search region tokens
25
+ removed_index (torch.Tensor): indices of removed search region tokens
26
+ """
27
+ lens_s = attn.shape[-1] - lens_t
28
+ bs, hn, _, _ = attn.shape
29
+
30
+ lens_keep = math.ceil(keep_ratio * lens_s)
31
+ if lens_keep == lens_s:
32
+ return tokens, global_index, None
33
+
34
+ attn_t = attn[:, :, :lens_t, lens_t:]
35
+
36
+
37
+
38
+
39
+ if box_mask_z is not None:
40
+ #print("\n1\n1\n1")
41
+ box_mask_z = box_mask_z.unsqueeze(1).unsqueeze(-1).expand(-1, attn_t.shape[1], -1, attn_t.shape[-1])
42
+ # attn_t = attn_t[:, :, box_mask_z, :]
43
+ attn_t = attn_t[box_mask_z]
44
+ attn_t = attn_t.view(bs, hn, -1, lens_s)
45
+ attn_t = attn_t.mean(dim=2).mean(dim=1) # B, H, L-T, L_s --> B, L_s
46
+
47
+ # attn_t = [attn_t[i, :, box_mask_z[i, :], :] for i in range(attn_t.size(0))]
48
+ # attn_t = [attn_t[i].mean(dim=1).mean(dim=0) for i in range(len(attn_t))]
49
+ # attn_t = torch.stack(attn_t, dim=0)
50
+ else:
51
+ attn_t = attn_t.mean(dim=2).mean(dim=1) # B, H, L-T, L_s --> B, L_s
52
+
53
+ # use sort instead of topk, due to the speed issue
54
+ # https://github.com/pytorch/pytorch/issues/22812
55
+ sorted_attn, indices = torch.sort(attn_t, dim=1, descending=True)
56
+
57
+
58
+
59
+ topk_attn, topk_idx = sorted_attn[:, :lens_keep], indices[:, :lens_keep]
60
+ non_topk_attn, non_topk_idx = sorted_attn[:, lens_keep:], indices[:, lens_keep:]
61
+
62
+ keep_index = global_index.gather(dim=1, index=topk_idx)
63
+
64
+ removed_index = global_index.gather(dim=1, index=non_topk_idx)
65
+
66
+
67
+ # separate template and search tokens
68
+ tokens_t = tokens[:, :lens_t]
69
+ tokens_s = tokens[:, lens_t:]
70
+
71
+ # obtain the attentive and inattentive tokens
72
+ B, L, C = tokens_s.shape
73
+ # topk_idx_ = topk_idx.unsqueeze(-1).expand(B, lens_keep, C)
74
+
75
+ attentive_tokens = tokens_s.gather(dim=1, index=topk_idx.unsqueeze(-1).expand(B, -1, C))
76
+ # inattentive_tokens = tokens_s.gather(dim=1, index=non_topk_idx.unsqueeze(-1).expand(B, -1, C))
77
+
78
+ # compute the weighted combination of inattentive tokens
79
+ # fused_token = non_topk_attn @ inattentive_tokens
80
+
81
+ # concatenate these tokens
82
+ # tokens_new = torch.cat([tokens_t, attentive_tokens, fused_token], dim=0)
83
+ tokens_new = torch.cat([tokens_t, attentive_tokens], dim=1)
84
+
85
+ #print("finish ce func")
86
+
87
+ return tokens_new, keep_index, removed_index # x, global_index_search, removed_index_search
88
+
89
+
90
+ class CEABlock(nn.Module):
91
+
92
+ def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, drop=0., attn_drop=0.,
93
+ drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm, keep_ratio_search=1.0,):
94
+ super().__init__()
95
+ self.norm1 = norm_layer(dim)
96
+ self.attn = Attention(dim, num_heads=num_heads, qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=drop)
97
+ # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here
98
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
99
+ self.norm2 = norm_layer(dim)
100
+ mlp_hidden_dim = int(dim * mlp_ratio)
101
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop) #from timm.models.layers import Mlp, DropPath, trunc_normal_, lecun_normal_
102
+
103
+ self.keep_ratio_search = keep_ratio_search
104
+
105
+
106
+ self.adap_t = Bi_direct_adapter()
107
+ self.adap2_t = Bi_direct_adapter()
108
+
109
+ def forward(self, x, xi, global_index_template, global_index_templatei, global_index_search, global_index_searchi, mask=None, ce_template_mask=None, keep_ratio_search=None):
110
+
111
+ xori = x
112
+
113
+ x_attn, attn = self.attn(self.norm1(x), mask, True)
114
+ x = x + self.drop_path(x_attn) + self.drop_path(self.adap_t(self.norm1(xi))) #########-------------------------adapter
115
+
116
+ xi_attn, i_attn = self.attn(self.norm1(xi), mask,True)
117
+ xi = xi + self.drop_path(xi_attn) + self.drop_path(self.adap_t(self.norm1(xori))) #########-------------------------adapter
118
+
119
+ lens_t = global_index_template.shape[1]
120
+
121
+ removed_index_search = None
122
+ removed_index_searchi = None
123
+ if self.keep_ratio_search < 1 and (keep_ratio_search is None or keep_ratio_search < 1):
124
+ keep_ratio_search = self.keep_ratio_search if keep_ratio_search is None else keep_ratio_search
125
+ x, global_index_search, removed_index_search = candidate_elimination(attn, x, lens_t, keep_ratio_search, global_index_search, ce_template_mask)
126
+ xi, global_index_searchi, removed_index_searchi = candidate_elimination(i_attn, xi, lens_t, keep_ratio_search, global_index_searchi, ce_template_mask)
127
+
128
+ xori = x
129
+
130
+ x = x + self.drop_path(self.mlp(self.norm2(x))) + self.drop_path(self.adap2_t(self.norm2(xi))) ###-------adapter
131
+
132
+ xi = xi + self.drop_path(self.mlp(self.norm2(xi))) + self.drop_path(self.adap2_t(self.norm2(xori))) ###-------adapter
133
+
134
+ return x, global_index_template, global_index_search, removed_index_search, attn, xi, global_index_templatei, global_index_searchi, removed_index_searchi, i_attn
135
+
136
+
137
+ class Block(nn.Module):
138
+
139
+ def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, drop=0., attn_drop=0.,
140
+ drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm):
141
+ super().__init__()
142
+ self.norm1 = norm_layer(dim)
143
+ #print("class Block ")
144
+ self.attn = Attention(dim, num_heads=num_heads, qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=drop)
145
+ # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here
146
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
147
+ self.norm2 = norm_layer(dim)
148
+ mlp_hidden_dim = int(dim * mlp_ratio)
149
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
150
+
151
+ def forward(self, x, mask=None):
152
+ #print("class Block forward")
153
+ x = x + self.drop_path(self.attn(self.norm1(x), mask))
154
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
155
+ return x
lib/models/layers/attn_blocks.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ import torch.nn as nn
4
+ from timm.models.layers import Mlp, DropPath, trunc_normal_, lecun_normal_
5
+
6
+ from lib.models.layers.attn import Attention
7
+
8
+
9
+ def candidate_elimination(attn: torch.Tensor, tokens: torch.Tensor, lens_t: int, keep_ratio: float, global_index: torch.Tensor, box_mask_z: torch.Tensor):
10
+ """
11
+ Eliminate potential background candidates for computation reduction and noise cancellation.
12
+ Args:
13
+ attn (torch.Tensor): [B, num_heads, L_t + L_s, L_t + L_s], attention weights
14
+ tokens (torch.Tensor): [B, L_t + L_s, C], template and search region tokens
15
+ lens_t (int): length of template
16
+ keep_ratio (float): keep ratio of search region tokens (candidates)
17
+ global_index (torch.Tensor): global index of search region tokens
18
+ box_mask_z (torch.Tensor): template mask used to accumulate attention weights
19
+
20
+ Returns:
21
+ tokens_new (torch.Tensor): tokens after candidate elimination
22
+ keep_index (torch.Tensor): indices of kept search region tokens
23
+ removed_index (torch.Tensor): indices of removed search region tokens
24
+ """
25
+ lens_s = attn.shape[-1] - lens_t
26
+ bs, hn, _, _ = attn.shape
27
+
28
+ lens_keep = math.ceil(keep_ratio * lens_s)
29
+ if lens_keep == lens_s:
30
+ return tokens, global_index, None
31
+
32
+ attn_t = attn[:, :, :lens_t, lens_t:]
33
+
34
+ if box_mask_z is not None:
35
+ box_mask_z = box_mask_z.unsqueeze(1).unsqueeze(-1).expand(-1, attn_t.shape[1], -1, attn_t.shape[-1])
36
+ # attn_t = attn_t[:, :, box_mask_z, :]
37
+ attn_t = attn_t[box_mask_z]
38
+ attn_t = attn_t.view(bs, hn, -1, lens_s)
39
+ attn_t = attn_t.mean(dim=2).mean(dim=1) # B, H, L-T, L_s --> B, L_s
40
+
41
+ # attn_t = [attn_t[i, :, box_mask_z[i, :], :] for i in range(attn_t.size(0))]
42
+ # attn_t = [attn_t[i].mean(dim=1).mean(dim=0) for i in range(len(attn_t))]
43
+ # attn_t = torch.stack(attn_t, dim=0)
44
+ else:
45
+ attn_t = attn_t.mean(dim=2).mean(dim=1) # B, H, L-T, L_s --> B, L_s
46
+
47
+ # use sort instead of topk, due to the speed issue
48
+ # https://github.com/pytorch/pytorch/issues/22812
49
+ sorted_attn, indices = torch.sort(attn_t, dim=1, descending=True)
50
+
51
+ topk_attn, topk_idx = sorted_attn[:, :lens_keep], indices[:, :lens_keep]
52
+ non_topk_attn, non_topk_idx = sorted_attn[:, lens_keep:], indices[:, lens_keep:]
53
+
54
+ keep_index = global_index.gather(dim=1, index=topk_idx)
55
+ removed_index = global_index.gather(dim=1, index=non_topk_idx)
56
+
57
+ # separate template and search tokens
58
+ tokens_t = tokens[:, :lens_t]
59
+ tokens_s = tokens[:, lens_t:]
60
+
61
+ # obtain the attentive and inattentive tokens
62
+ B, L, C = tokens_s.shape
63
+ # topk_idx_ = topk_idx.unsqueeze(-1).expand(B, lens_keep, C)
64
+ attentive_tokens = tokens_s.gather(dim=1, index=topk_idx.unsqueeze(-1).expand(B, -1, C))
65
+ # inattentive_tokens = tokens_s.gather(dim=1, index=non_topk_idx.unsqueeze(-1).expand(B, -1, C))
66
+
67
+ # compute the weighted combination of inattentive tokens
68
+ # fused_token = non_topk_attn @ inattentive_tokens
69
+
70
+ # concatenate these tokens
71
+ # tokens_new = torch.cat([tokens_t, attentive_tokens, fused_token], dim=0)
72
+ tokens_new = torch.cat([tokens_t, attentive_tokens], dim=1)
73
+
74
+ return tokens_new, keep_index, removed_index
75
+
76
+
77
+ class CEBlock(nn.Module):
78
+
79
+ def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, drop=0., attn_drop=0.,
80
+ drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm, keep_ratio_search=1.0,):
81
+ super().__init__()
82
+ self.norm1 = norm_layer(dim)
83
+ self.attn = Attention(dim, num_heads=num_heads, qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=drop)
84
+ # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here
85
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
86
+ self.norm2 = norm_layer(dim)
87
+ mlp_hidden_dim = int(dim * mlp_ratio)
88
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
89
+
90
+ self.keep_ratio_search = keep_ratio_search
91
+
92
+ def forward(self, x, global_index_template, global_index_search, mask=None, ce_template_mask=None, keep_ratio_search=None):
93
+ x_attn, attn = self.attn(self.norm1(x), mask, True)
94
+ x = x + self.drop_path(x_attn)
95
+ lens_t = global_index_template.shape[1]
96
+
97
+ removed_index_search = None
98
+ if self.keep_ratio_search < 1 and (keep_ratio_search is None or keep_ratio_search < 1):
99
+ keep_ratio_search = self.keep_ratio_search if keep_ratio_search is None else keep_ratio_search
100
+ x, global_index_search, removed_index_search = candidate_elimination(attn, x, lens_t, keep_ratio_search, global_index_search, ce_template_mask)
101
+
102
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
103
+ return x, global_index_template, global_index_search, removed_index_search, attn
104
+
105
+
106
+ class Block(nn.Module):
107
+
108
+ def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, drop=0., attn_drop=0.,
109
+ drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm):
110
+ super().__init__()
111
+ self.norm1 = norm_layer(dim)
112
+ self.attn = Attention(dim, num_heads=num_heads, qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=drop)
113
+ # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here
114
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
115
+ self.norm2 = norm_layer(dim)
116
+ mlp_hidden_dim = int(dim * mlp_ratio)
117
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
118
+
119
+ def forward(self, x, mask=None):
120
+ x = x + self.drop_path(self.attn(self.norm1(x), mask))
121
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
122
+ return x
lib/models/layers/dualstream_attn_blocks.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ import torch.nn as nn
4
+ from timm.models.layers import Mlp, DropPath, trunc_normal_, lecun_normal_
5
+
6
+ from lib.models.layers.attn import Attention
7
+ from lib.models.layers.adapter import Bi_direct_adapter
8
+
9
+
10
+
11
+
12
+
13
+ def candidate_elimination(attn: torch.Tensor, tokens: torch.Tensor, lens_t: int, keep_ratio: float, global_index: torch.Tensor, box_mask_z: torch.Tensor):
14
+ """
15
+ Eliminate potential background candidates for computation reduction and noise cancellation.
16
+ Args:
17
+ attn (torch.Tensor): [B, num_heads, L_t + L_s, L_t + L_s], attention weights
18
+ tokens (torch.Tensor): [B, L_t + L_s, C], template and search region tokens
19
+ lens_t (int): length of template
20
+ keep_ratio (float): keep ratio of search region tokens (candidates)
21
+ global_index (torch.Tensor): global index of search region tokens
22
+ box_mask_z (torch.Tensor): template mask used to accumulate attention weights
23
+
24
+ Returns:
25
+ tokens_new (torch.Tensor): tokens after candidate elimination
26
+ keep_index (torch.Tensor): indices of kept search region tokens
27
+ removed_index (torch.Tensor): indices of removed search region tokens
28
+ """
29
+ lens_s = attn.shape[-1] - lens_t
30
+ bs, hn, _, _ = attn.shape
31
+
32
+ lens_keep = math.ceil(keep_ratio * lens_s)
33
+ if lens_keep == lens_s:
34
+ return tokens, global_index, None
35
+
36
+ attn_t = attn[:, :, :lens_t, lens_t:]
37
+
38
+ #print("box_mask_z")
39
+
40
+
41
+ if box_mask_z is not None:
42
+ #print("\n1\n1\n1")
43
+ box_mask_z = box_mask_z.unsqueeze(1).unsqueeze(-1).expand(-1, attn_t.shape[1], -1, attn_t.shape[-1])
44
+ # attn_t = attn_t[:, :, box_mask_z, :]
45
+ attn_t = attn_t[box_mask_z]
46
+ attn_t = attn_t.view(bs, hn, -1, lens_s)
47
+ attn_t = attn_t.mean(dim=2).mean(dim=1) # B, H, L-T, L_s --> B, L_s
48
+
49
+ # attn_t = [attn_t[i, :, box_mask_z[i, :], :] for i in range(attn_t.size(0))]
50
+ # attn_t = [attn_t[i].mean(dim=1).mean(dim=0) for i in range(len(attn_t))]
51
+ # attn_t = torch.stack(attn_t, dim=0)
52
+ else:
53
+ attn_t = attn_t.mean(dim=2).mean(dim=1) # B, H, L-T, L_s --> B, L_s
54
+
55
+ # use sort instead of topk, due to the speed issue
56
+ # https://github.com/pytorch/pytorch/issues/22812
57
+ sorted_attn, indices = torch.sort(attn_t, dim=1, descending=True)
58
+
59
+
60
+
61
+ topk_attn, topk_idx = sorted_attn[:, :lens_keep], indices[:, :lens_keep]
62
+ non_topk_attn, non_topk_idx = sorted_attn[:, lens_keep:], indices[:, lens_keep:]
63
+
64
+ keep_index = global_index.gather(dim=1, index=topk_idx)
65
+
66
+ removed_index = global_index.gather(dim=1, index=non_topk_idx)
67
+
68
+
69
+ # separate template and search tokens
70
+ tokens_t = tokens[:, :lens_t]
71
+ tokens_s = tokens[:, lens_t:]
72
+
73
+ # obtain the attentive and inattentive tokens
74
+ B, L, C = tokens_s.shape
75
+ # topk_idx_ = topk_idx.unsqueeze(-1).expand(B, lens_keep, C)
76
+
77
+ attentive_tokens = tokens_s.gather(dim=1, index=topk_idx.unsqueeze(-1).expand(B, -1, C))
78
+ # inattentive_tokens = tokens_s.gather(dim=1, index=non_topk_idx.unsqueeze(-1).expand(B, -1, C))
79
+
80
+ # compute the weighted combination of inattentive tokens
81
+ # fused_token = non_topk_attn @ inattentive_tokens
82
+
83
+ # concatenate these tokens
84
+ # tokens_new = torch.cat([tokens_t, attentive_tokens, fused_token], dim=0)
85
+ tokens_new = torch.cat([tokens_t, attentive_tokens], dim=1)
86
+
87
+ #print("finish ce func")
88
+
89
+ return tokens_new, keep_index, removed_index # x, global_index_search, removed_index_search
90
+
91
+
92
+ class DSBlock(nn.Module):
93
+
94
+ def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, drop=0., attn_drop=0.,
95
+ drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm, keep_ratio_search=1.0,):
96
+ super().__init__()
97
+ self.norm1 = norm_layer(dim)
98
+ self.attn = Attention(dim, num_heads=num_heads, qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=drop)
99
+ # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here
100
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
101
+ self.norm2 = norm_layer(dim)
102
+ mlp_hidden_dim = int(dim * mlp_ratio)
103
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop) #from timm.models.layers import Mlp, DropPath, trunc_normal_, lecun_normal_
104
+
105
+ self.keep_ratio_search = keep_ratio_search
106
+
107
+
108
+ def forward(self, x, xi, global_index_template, global_index_templatei, global_index_search, global_index_searchi, mask=None, ce_template_mask=None, keep_ratio_search=None):
109
+
110
+
111
+ x_attn, attn = self.attn(self.norm1(x), mask, True)
112
+ x = x + self.drop_path(x_attn)
113
+ xi_attn, i_attn = self.attn(self.norm1(xi), mask,True)
114
+ xi = xi + self.drop_path(xi_attn)
115
+
116
+ lens_t = global_index_template.shape[1]
117
+
118
+ removed_index_search = None
119
+ removed_index_searchi = None
120
+ if self.keep_ratio_search < 1 and (keep_ratio_search is None or keep_ratio_search < 1):
121
+ keep_ratio_search = self.keep_ratio_search if keep_ratio_search is None else keep_ratio_search
122
+ x, global_index_search, removed_index_search = candidate_elimination(attn, x, lens_t, keep_ratio_search, global_index_search, ce_template_mask)
123
+ xi, global_index_searchi, removed_index_searchi = candidate_elimination(i_attn, xi, lens_t, keep_ratio_search, global_index_searchi, ce_template_mask)
124
+
125
+
126
+
127
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
128
+
129
+ xi = xi + self.drop_path(self.mlp(self.norm2(xi)))
130
+
131
+ return x, global_index_template, global_index_search, removed_index_search, attn, xi, global_index_templatei, global_index_searchi, removed_index_searchi, i_attn
132
+
133
+
134
+ class Block(nn.Module):
135
+
136
+ def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, drop=0., attn_drop=0.,
137
+ drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm):
138
+ super().__init__()
139
+ self.norm1 = norm_layer(dim)
140
+ #print("class Block ")
141
+ self.attn = Attention(dim, num_heads=num_heads, qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=drop)
142
+ # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here
143
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
144
+ self.norm2 = norm_layer(dim)
145
+ mlp_hidden_dim = int(dim * mlp_ratio)
146
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
147
+
148
+ def forward(self, x, mask=None):
149
+ #print("class Block forward")
150
+ x = x + self.drop_path(self.attn(self.norm1(x), mask))
151
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
152
+ return x
lib/models/layers/frozen_bn.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+
3
+
4
+ class FrozenBatchNorm2d(torch.nn.Module):
5
+ """
6
+ BatchNorm2d where the batch statistics and the affine parameters are fixed.
7
+
8
+ Copy-paste from torchvision.misc.ops with added eps before rqsrt,
9
+ without which any other models than torchvision.models.resnet[18,34,50,101]
10
+ produce nans.
11
+ """
12
+
13
+ def __init__(self, n):
14
+ super(FrozenBatchNorm2d, self).__init__()
15
+ self.register_buffer("weight", torch.ones(n))
16
+ self.register_buffer("bias", torch.zeros(n))
17
+ self.register_buffer("running_mean", torch.zeros(n))
18
+ self.register_buffer("running_var", torch.ones(n))
19
+
20
+ def _load_from_state_dict(self, state_dict, prefix, local_metadata, strict,
21
+ missing_keys, unexpected_keys, error_msgs):
22
+ num_batches_tracked_key = prefix + 'num_batches_tracked'
23
+ if num_batches_tracked_key in state_dict:
24
+ del state_dict[num_batches_tracked_key]
25
+
26
+ super(FrozenBatchNorm2d, self)._load_from_state_dict(
27
+ state_dict, prefix, local_metadata, strict,
28
+ missing_keys, unexpected_keys, error_msgs)
29
+
30
+ def forward(self, x):
31
+ # move reshapes to the beginning
32
+ # to make it fuser-friendly
33
+ w = self.weight.reshape(1, -1, 1, 1)
34
+ b = self.bias.reshape(1, -1, 1, 1)
35
+ rv = self.running_var.reshape(1, -1, 1, 1)
36
+ rm = self.running_mean.reshape(1, -1, 1, 1)
37
+ eps = 1e-5
38
+ scale = w * (rv + eps).rsqrt() # rsqrt(x): 1/sqrt(x), r: reciprocal
39
+ bias = b - rm * scale
40
+ return x * scale + bias
lib/models/layers/head.py ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.nn as nn
2
+ import torch
3
+ import torch.nn.functional as F
4
+
5
+ from lib.models.layers.frozen_bn import FrozenBatchNorm2d
6
+
7
+
8
+ def conv(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1,
9
+ freeze_bn=False):
10
+ if freeze_bn:
11
+ return nn.Sequential(
12
+ nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride,
13
+ padding=padding, dilation=dilation, bias=True),
14
+ FrozenBatchNorm2d(out_planes),
15
+ nn.ReLU(inplace=True))
16
+ else:
17
+ return nn.Sequential(
18
+ nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride,
19
+ padding=padding, dilation=dilation, bias=True),
20
+ nn.BatchNorm2d(out_planes),
21
+ nn.ReLU(inplace=True))
22
+
23
+
24
+ class Corner_Predictor(nn.Module):
25
+ """ Corner Predictor module"""
26
+
27
+ def __init__(self, inplanes=64, channel=256, feat_sz=20, stride=16, freeze_bn=False):
28
+ super(Corner_Predictor, self).__init__()
29
+ self.feat_sz = feat_sz
30
+ self.stride = stride
31
+ self.img_sz = self.feat_sz * self.stride
32
+ '''top-left corner'''
33
+ self.conv1_tl = conv(inplanes, channel, freeze_bn=freeze_bn)
34
+ self.conv2_tl = conv(channel, channel // 2, freeze_bn=freeze_bn)
35
+ self.conv3_tl = conv(channel // 2, channel // 4, freeze_bn=freeze_bn)
36
+ self.conv4_tl = conv(channel // 4, channel // 8, freeze_bn=freeze_bn)
37
+ self.conv5_tl = nn.Conv2d(channel // 8, 1, kernel_size=1)
38
+
39
+ '''bottom-right corner'''
40
+ self.conv1_br = conv(inplanes, channel, freeze_bn=freeze_bn)
41
+ self.conv2_br = conv(channel, channel // 2, freeze_bn=freeze_bn)
42
+ self.conv3_br = conv(channel // 2, channel // 4, freeze_bn=freeze_bn)
43
+ self.conv4_br = conv(channel // 4, channel // 8, freeze_bn=freeze_bn)
44
+ self.conv5_br = nn.Conv2d(channel // 8, 1, kernel_size=1)
45
+
46
+ '''about coordinates and indexs'''
47
+ with torch.no_grad():
48
+ self.indice = torch.arange(0, self.feat_sz).view(-1, 1) * self.stride
49
+ # generate mesh-grid
50
+ self.coord_x = self.indice.repeat((self.feat_sz, 1)) \
51
+ .view((self.feat_sz * self.feat_sz,)).float().cuda()
52
+ self.coord_y = self.indice.repeat((1, self.feat_sz)) \
53
+ .view((self.feat_sz * self.feat_sz,)).float().cuda()
54
+
55
+ def forward(self, x, return_dist=False, softmax=True):
56
+ """ Forward pass with input x. """
57
+ score_map_tl, score_map_br = self.get_score_map(x)
58
+ if return_dist:
59
+ coorx_tl, coory_tl, prob_vec_tl = self.soft_argmax(score_map_tl, return_dist=True, softmax=softmax)
60
+ coorx_br, coory_br, prob_vec_br = self.soft_argmax(score_map_br, return_dist=True, softmax=softmax)
61
+ return torch.stack((coorx_tl, coory_tl, coorx_br, coory_br), dim=1) / self.img_sz, prob_vec_tl, prob_vec_br
62
+ else:
63
+ coorx_tl, coory_tl = self.soft_argmax(score_map_tl)
64
+ coorx_br, coory_br = self.soft_argmax(score_map_br)
65
+ return torch.stack((coorx_tl, coory_tl, coorx_br, coory_br), dim=1) / self.img_sz
66
+
67
+ def get_score_map(self, x):
68
+ # top-left branch
69
+ x_tl1 = self.conv1_tl(x)
70
+ x_tl2 = self.conv2_tl(x_tl1)
71
+ x_tl3 = self.conv3_tl(x_tl2)
72
+ x_tl4 = self.conv4_tl(x_tl3)
73
+ score_map_tl = self.conv5_tl(x_tl4)
74
+
75
+ # bottom-right branch
76
+ x_br1 = self.conv1_br(x)
77
+ x_br2 = self.conv2_br(x_br1)
78
+ x_br3 = self.conv3_br(x_br2)
79
+ x_br4 = self.conv4_br(x_br3)
80
+ score_map_br = self.conv5_br(x_br4)
81
+ return score_map_tl, score_map_br
82
+
83
+ def soft_argmax(self, score_map, return_dist=False, softmax=True):
84
+ """ get soft-argmax coordinate for a given heatmap """
85
+ score_vec = score_map.view((-1, self.feat_sz * self.feat_sz)) # (batch, feat_sz * feat_sz)
86
+ prob_vec = nn.functional.softmax(score_vec, dim=1)
87
+ exp_x = torch.sum((self.coord_x * prob_vec), dim=1)
88
+ exp_y = torch.sum((self.coord_y * prob_vec), dim=1)
89
+ if return_dist:
90
+ if softmax:
91
+ return exp_x, exp_y, prob_vec
92
+ else:
93
+ return exp_x, exp_y, score_vec
94
+ else:
95
+ return exp_x, exp_y
96
+
97
+
98
+ class CenterPredictor(nn.Module, ):
99
+ def __init__(self, inplanes=64, channel=256, feat_sz=20, stride=16, freeze_bn=False):
100
+ super(CenterPredictor, self).__init__()
101
+ self.feat_sz = feat_sz
102
+ self.stride = stride
103
+ self.img_sz = self.feat_sz * self.stride
104
+
105
+ # corner predict
106
+ self.conv1_ctr = conv(inplanes, channel, freeze_bn=freeze_bn)
107
+ self.conv2_ctr = conv(channel, channel // 2, freeze_bn=freeze_bn)
108
+ self.conv3_ctr = conv(channel // 2, channel // 4, freeze_bn=freeze_bn)
109
+ self.conv4_ctr = conv(channel // 4, channel // 8, freeze_bn=freeze_bn)
110
+ self.conv5_ctr = nn.Conv2d(channel // 8, 1, kernel_size=1)
111
+
112
+ # size regress
113
+ self.conv1_offset = conv(inplanes, channel, freeze_bn=freeze_bn)
114
+ self.conv2_offset = conv(channel, channel // 2, freeze_bn=freeze_bn)
115
+ self.conv3_offset = conv(channel // 2, channel // 4, freeze_bn=freeze_bn)
116
+ self.conv4_offset = conv(channel // 4, channel // 8, freeze_bn=freeze_bn)
117
+ self.conv5_offset = nn.Conv2d(channel // 8, 2, kernel_size=1)
118
+
119
+ # size regress
120
+ self.conv1_size = conv(inplanes, channel, freeze_bn=freeze_bn)
121
+ self.conv2_size = conv(channel, channel // 2, freeze_bn=freeze_bn)
122
+ self.conv3_size = conv(channel // 2, channel // 4, freeze_bn=freeze_bn)
123
+ self.conv4_size = conv(channel // 4, channel // 8, freeze_bn=freeze_bn)
124
+ self.conv5_size = nn.Conv2d(channel // 8, 2, kernel_size=1)
125
+
126
+ for p in self.parameters():
127
+ if p.dim() > 1:
128
+ nn.init.xavier_uniform_(p)
129
+
130
+ def forward(self, x, gt_score_map=None):
131
+ """ Forward pass with input x. """
132
+ score_map_ctr, size_map, offset_map = self.get_score_map(x)
133
+
134
+ # assert gt_score_map is None
135
+ if gt_score_map is None:
136
+ bbox = self.cal_bbox(score_map_ctr, size_map, offset_map)
137
+ else:
138
+ bbox = self.cal_bbox(gt_score_map.unsqueeze(1), size_map, offset_map)
139
+
140
+ return score_map_ctr, bbox, size_map, offset_map
141
+
142
+ def cal_bbox(self, score_map_ctr, size_map, offset_map, return_score=False):
143
+ max_score, idx = torch.max(score_map_ctr.flatten(1), dim=1, keepdim=True)
144
+ idx_y = idx // self.feat_sz
145
+ idx_x = idx % self.feat_sz
146
+
147
+ idx = idx.unsqueeze(1).expand(idx.shape[0], 2, 1)
148
+ size = size_map.flatten(2).gather(dim=2, index=idx)
149
+ offset = offset_map.flatten(2).gather(dim=2, index=idx).squeeze(-1)
150
+
151
+ # bbox = torch.cat([idx_x - size[:, 0] / 2, idx_y - size[:, 1] / 2,
152
+ # idx_x + size[:, 0] / 2, idx_y + size[:, 1] / 2], dim=1) / self.feat_sz
153
+ # cx, cy, w, h
154
+ bbox = torch.cat([(idx_x.to(torch.float) + offset[:, :1]) / self.feat_sz,
155
+ (idx_y.to(torch.float) + offset[:, 1:]) / self.feat_sz,
156
+ size.squeeze(-1)], dim=1)
157
+
158
+ if return_score:
159
+ return bbox, max_score
160
+ return bbox
161
+
162
+ def get_pred(self, score_map_ctr, size_map, offset_map):
163
+ max_score, idx = torch.max(score_map_ctr.flatten(1), dim=1, keepdim=True)
164
+ idx_y = idx // self.feat_sz
165
+ idx_x = idx % self.feat_sz
166
+
167
+ idx = idx.unsqueeze(1).expand(idx.shape[0], 2, 1)
168
+ size = size_map.flatten(2).gather(dim=2, index=idx)
169
+ offset = offset_map.flatten(2).gather(dim=2, index=idx).squeeze(-1)
170
+
171
+ # bbox = torch.cat([idx_x - size[:, 0] / 2, idx_y - size[:, 1] / 2,
172
+ # idx_x + size[:, 0] / 2, idx_y + size[:, 1] / 2], dim=1) / self.feat_sz
173
+ return size * self.feat_sz, offset
174
+
175
+ def get_score_map(self, x):
176
+
177
+ def _sigmoid(x):
178
+ y = torch.clamp(x.sigmoid_(), min=1e-4, max=1 - 1e-4)
179
+ return y
180
+
181
+ # ctr branch
182
+ x_ctr1 = self.conv1_ctr(x)
183
+ x_ctr2 = self.conv2_ctr(x_ctr1)
184
+ x_ctr3 = self.conv3_ctr(x_ctr2)
185
+ x_ctr4 = self.conv4_ctr(x_ctr3)
186
+ score_map_ctr = self.conv5_ctr(x_ctr4)
187
+
188
+ # offset branch
189
+ x_offset1 = self.conv1_offset(x)
190
+ x_offset2 = self.conv2_offset(x_offset1)
191
+ x_offset3 = self.conv3_offset(x_offset2)
192
+ x_offset4 = self.conv4_offset(x_offset3)
193
+ score_map_offset = self.conv5_offset(x_offset4)
194
+
195
+ # size branch
196
+ x_size1 = self.conv1_size(x)
197
+ x_size2 = self.conv2_size(x_size1)
198
+ x_size3 = self.conv3_size(x_size2)
199
+ x_size4 = self.conv4_size(x_size3)
200
+ score_map_size = self.conv5_size(x_size4)
201
+ return _sigmoid(score_map_ctr), _sigmoid(score_map_size), score_map_offset
202
+
203
+
204
+ class MLP(nn.Module):
205
+ """ Very simple multi-layer perceptron (also called FFN)"""
206
+
207
+ def __init__(self, input_dim, hidden_dim, output_dim, num_layers, BN=False):
208
+ super().__init__()
209
+ self.num_layers = num_layers
210
+ h = [hidden_dim] * (num_layers - 1)
211
+ if BN:
212
+ self.layers = nn.ModuleList(nn.Sequential(nn.Linear(n, k), nn.BatchNorm1d(k))
213
+ for n, k in zip([input_dim] + h, h + [output_dim]))
214
+ else:
215
+ self.layers = nn.ModuleList(nn.Linear(n, k)
216
+ for n, k in zip([input_dim] + h, h + [output_dim]))
217
+
218
+ def forward(self, x):
219
+ for i, layer in enumerate(self.layers):
220
+ x = F.relu(layer(x)) if i < self.num_layers - 1 else layer(x)
221
+ return x
222
+
223
+
224
+ def build_box_head(cfg, hidden_dim):
225
+ stride = cfg.MODEL.BACKBONE.STRIDE
226
+
227
+ if cfg.MODEL.HEAD.TYPE == "MLP":
228
+ mlp_head = MLP(hidden_dim, hidden_dim, 4, 3) # dim_in, dim_hidden, dim_out, 3 layers
229
+ return mlp_head
230
+ elif "CORNER" in cfg.MODEL.HEAD.TYPE:
231
+ feat_sz = int(cfg.DATA.SEARCH.SIZE / stride)
232
+ channel = getattr(cfg.MODEL, "NUM_CHANNELS", 256)
233
+ print("head channel: %d" % channel)
234
+ if cfg.MODEL.HEAD.TYPE == "CORNER":
235
+ corner_head = Corner_Predictor(inplanes=cfg.MODEL.HIDDEN_DIM, channel=channel,
236
+ feat_sz=feat_sz, stride=stride)
237
+ else:
238
+ raise ValueError()
239
+ return corner_head
240
+ elif cfg.MODEL.HEAD.TYPE == "CENTER":
241
+ in_channel = hidden_dim
242
+ out_channel = cfg.MODEL.HEAD.NUM_CHANNELS
243
+ feat_sz = int(cfg.DATA.SEARCH.SIZE / stride)
244
+ center_head = CenterPredictor(inplanes=in_channel, channel=out_channel,
245
+ feat_sz=feat_sz, stride=stride)
246
+ return center_head
247
+ else:
248
+ raise ValueError("HEAD TYPE %s is not supported." % cfg.MODEL.HEAD_TYPE)
lib/models/layers/max_head.py ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.nn as nn
2
+ import torch
3
+ import torch.nn.functional as F
4
+
5
+ from lib.models.layers.frozen_bn import FrozenBatchNorm2d
6
+
7
+
8
+ def conv(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1,
9
+ freeze_bn=False):
10
+ if freeze_bn:
11
+ return nn.Sequential(
12
+ nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride,
13
+ padding=padding, dilation=dilation, bias=True),
14
+ FrozenBatchNorm2d(out_planes),
15
+ nn.ReLU(inplace=True))
16
+ else:
17
+ return nn.Sequential(
18
+ nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride,
19
+ padding=padding, dilation=dilation, bias=True),
20
+ nn.BatchNorm2d(out_planes),
21
+ nn.ReLU(inplace=True))
22
+
23
+
24
+ class Corner_Predictor(nn.Module):
25
+ """ Corner Predictor module"""
26
+
27
+ def __init__(self, inplanes=64, channel=256, feat_sz=20, stride=16, freeze_bn=False):
28
+ super(Corner_Predictor, self).__init__()
29
+ self.feat_sz = feat_sz
30
+ self.stride = stride
31
+ self.img_sz = self.feat_sz * self.stride
32
+ '''top-left corner'''
33
+ self.conv1_tl = conv(inplanes, channel, freeze_bn=freeze_bn)
34
+ self.conv2_tl = conv(channel, channel // 2, freeze_bn=freeze_bn)
35
+ self.conv3_tl = conv(channel // 2, channel // 4, freeze_bn=freeze_bn)
36
+ self.conv4_tl = conv(channel // 4, channel // 8, freeze_bn=freeze_bn)
37
+ self.conv5_tl = nn.Conv2d(channel // 8, 1, kernel_size=1)
38
+
39
+ '''bottom-right corner'''
40
+ self.conv1_br = conv(inplanes, channel, freeze_bn=freeze_bn)
41
+ self.conv2_br = conv(channel, channel // 2, freeze_bn=freeze_bn)
42
+ self.conv3_br = conv(channel // 2, channel // 4, freeze_bn=freeze_bn)
43
+ self.conv4_br = conv(channel // 4, channel // 8, freeze_bn=freeze_bn)
44
+ self.conv5_br = nn.Conv2d(channel // 8, 1, kernel_size=1)
45
+
46
+ '''about coordinates and indexs'''
47
+ with torch.no_grad():
48
+ self.indice = torch.arange(0, self.feat_sz).view(-1, 1) * self.stride
49
+ # generate mesh-grid
50
+ self.coord_x = self.indice.repeat((self.feat_sz, 1)) \
51
+ .view((self.feat_sz * self.feat_sz,)).float().cuda()
52
+ self.coord_y = self.indice.repeat((1, self.feat_sz)) \
53
+ .view((self.feat_sz * self.feat_sz,)).float().cuda()
54
+
55
+ def forward(self, x, return_dist=False, softmax=True):
56
+ """ Forward pass with input x. """
57
+ score_map_tl, score_map_br = self.get_score_map(x)
58
+ if return_dist:
59
+ coorx_tl, coory_tl, prob_vec_tl = self.soft_argmax(score_map_tl, return_dist=True, softmax=softmax)
60
+ coorx_br, coory_br, prob_vec_br = self.soft_argmax(score_map_br, return_dist=True, softmax=softmax)
61
+ return torch.stack((coorx_tl, coory_tl, coorx_br, coory_br), dim=1) / self.img_sz, prob_vec_tl, prob_vec_br
62
+ else:
63
+ coorx_tl, coory_tl = self.soft_argmax(score_map_tl)
64
+ coorx_br, coory_br = self.soft_argmax(score_map_br)
65
+ return torch.stack((coorx_tl, coory_tl, coorx_br, coory_br), dim=1) / self.img_sz
66
+
67
+ def get_score_map(self, x):
68
+ # top-left branch
69
+ x_tl1 = self.conv1_tl(x)
70
+ x_tl2 = self.conv2_tl(x_tl1)
71
+ x_tl3 = self.conv3_tl(x_tl2)
72
+ x_tl4 = self.conv4_tl(x_tl3)
73
+ score_map_tl = self.conv5_tl(x_tl4)
74
+
75
+ # bottom-right branch
76
+ x_br1 = self.conv1_br(x)
77
+ x_br2 = self.conv2_br(x_br1)
78
+ x_br3 = self.conv3_br(x_br2)
79
+ x_br4 = self.conv4_br(x_br3)
80
+ score_map_br = self.conv5_br(x_br4)
81
+ return score_map_tl, score_map_br
82
+
83
+ def soft_argmax(self, score_map, return_dist=False, softmax=True):
84
+ """ get soft-argmax coordinate for a given heatmap """
85
+ score_vec = score_map.view((-1, self.feat_sz * self.feat_sz)) # (batch, feat_sz * feat_sz)
86
+ prob_vec = nn.functional.softmax(score_vec, dim=1)
87
+ exp_x = torch.sum((self.coord_x * prob_vec), dim=1)
88
+ exp_y = torch.sum((self.coord_y * prob_vec), dim=1)
89
+ if return_dist:
90
+ if softmax:
91
+ return exp_x, exp_y, prob_vec
92
+ else:
93
+ return exp_x, exp_y, score_vec
94
+ else:
95
+ return exp_x, exp_y
96
+
97
+
98
+ class CenterPredictor(nn.Module, ):
99
+ def __init__(self, inplanes=64, channel=256, feat_sz=20, stride=16, freeze_bn=False):
100
+ super(CenterPredictor, self).__init__()
101
+ self.feat_sz = feat_sz
102
+ self.stride = stride
103
+ self.img_sz = self.feat_sz * self.stride
104
+
105
+ # corner predict
106
+ self.conv1_ctr = conv(inplanes, channel, freeze_bn=freeze_bn)
107
+ self.conv2_ctr = conv(channel, channel // 2, freeze_bn=freeze_bn)
108
+ self.conv3_ctr = conv(channel // 2, channel // 4, freeze_bn=freeze_bn)
109
+ self.conv4_ctr = conv(channel // 4, channel // 8, freeze_bn=freeze_bn)
110
+ self.conv5_ctr = nn.Conv2d(channel // 8, 1, kernel_size=1)
111
+
112
+ # size regress
113
+ self.conv1_offset = conv(inplanes, channel, freeze_bn=freeze_bn)
114
+ self.conv2_offset = conv(channel, channel // 2, freeze_bn=freeze_bn)
115
+ self.conv3_offset = conv(channel // 2, channel // 4, freeze_bn=freeze_bn)
116
+ self.conv4_offset = conv(channel // 4, channel // 8, freeze_bn=freeze_bn)
117
+ self.conv5_offset = nn.Conv2d(channel // 8, 2, kernel_size=1)
118
+
119
+ # size regress
120
+ self.conv1_size = conv(inplanes, channel, freeze_bn=freeze_bn)
121
+ self.conv2_size = conv(channel, channel // 2, freeze_bn=freeze_bn)
122
+ self.conv3_size = conv(channel // 2, channel // 4, freeze_bn=freeze_bn)
123
+ self.conv4_size = conv(channel // 4, channel // 8, freeze_bn=freeze_bn)
124
+ self.conv5_size = nn.Conv2d(channel // 8, 2, kernel_size=1)
125
+
126
+ for p in self.parameters():
127
+ if p.dim() > 1:
128
+ nn.init.xavier_uniform_(p)
129
+
130
+ def forward(self, x, gt_score_map=None):
131
+ """ Forward pass with input x. """
132
+ #print("input x shape ", x.shape)
133
+ score_map_ctr, size_map, offset_map = self.get_score_map(x)
134
+ #print("score_map_ctr shape ",score_map_ctr.shape)
135
+ #print("size_map shape ", size_map.shape)
136
+ #print("offset_map shape ", offset_map.shape)
137
+ score_map_ctr_rgbt = torch.split(score_map_ctr, 1, dim=0)
138
+ #print("score_map_ctr_rgbt shape ", score_map_ctr_rgbt[0].shape)
139
+ # assert gt_score_map is None
140
+ if gt_score_map is None:
141
+ bbox = self.cal_bbox(score_map_ctr, size_map, offset_map)
142
+ else:
143
+ bbox = self.cal_bbox(gt_score_map.unsqueeze(1), size_map, offset_map)
144
+
145
+
146
+
147
+ return score_map_ctr, bbox, size_map, offset_map
148
+
149
+ def cal_bbox(self, score_map_ctr_rgbt, size_map_rgbt, offset_map_rgbt, return_score=False):
150
+ max_score1, idx1 = (torch.max(score_map_ctr_rgbt[0].flatten(1), dim=1, keepdim=True))
151
+ max_score2, idx2 = (torch.max(score_map_ctr_rgbt[1].flatten(1), dim=1, keepdim=True))
152
+
153
+
154
+ sm = torch.split(size_map_rgbt, 1, dim=0)
155
+ om = torch.split(offset_map_rgbt, 1, dim=0)
156
+
157
+ if max_score1 >= max_score2:
158
+ max_score = max_score1
159
+ idx = idx1
160
+ size_map = sm[0]
161
+ offset_map = om[0]
162
+ else:
163
+ max_score = max_score2
164
+ idx = idx2
165
+ size_map = sm[1]
166
+ offset_map = om[1]
167
+ #size_map = size_map_rgbt[1]
168
+ #offset_map = offset_map_rgbt[1]
169
+
170
+
171
+
172
+ idx_y = idx // self.feat_sz
173
+ idx_x = idx % self.feat_sz
174
+
175
+ idx = idx.unsqueeze(1).expand(idx.shape[0], 2, 1)
176
+
177
+ size = size_map.flatten(2).gather(dim=2, index=idx)
178
+
179
+ offset = offset_map.flatten(2).gather(dim=2, index=idx).squeeze(-1)
180
+
181
+
182
+ # bbox = torch.cat([idx_x - size[:, 0] / 2, idx_y - size[:, 1] / 2,
183
+ # idx_x + size[:, 0] / 2, idx_y + size[:, 1] / 2], dim=1) / self.feat_sz
184
+ # cx, cy, w, h
185
+ bbox = torch.cat([(idx_x.to(torch.float) + offset[:, :1]) / self.feat_sz,
186
+ (idx_y.to(torch.float) + offset[:, 1:]) / self.feat_sz,
187
+ size.squeeze(-1)], dim=1)
188
+
189
+ if return_score:
190
+ return bbox, max_score
191
+ return bbox
192
+
193
+ def get_pred(self, score_map_ctr, size_map, offset_map):
194
+ max_score, idx = torch.max(score_map_ctr.flatten(1), dim=1, keepdim=True)
195
+ idx_y = idx // self.feat_sz
196
+ idx_x = idx % self.feat_sz
197
+
198
+ idx = idx.unsqueeze(1).expand(idx.shape[0], 2, 1)
199
+ size = size_map.flatten(2).gather(dim=2, index=idx)
200
+ offset = offset_map.flatten(2).gather(dim=2, index=idx).squeeze(-1)
201
+
202
+ # bbox = torch.cat([idx_x - size[:, 0] / 2, idx_y - size[:, 1] / 2,
203
+ # idx_x + size[:, 0] / 2, idx_y + size[:, 1] / 2], dim=1) / self.feat_sz
204
+ return size * self.feat_sz, offset
205
+
206
+ def get_score_map(self, x):
207
+
208
+
209
+ def _sigmoid(x):
210
+ y = torch.clamp(x.sigmoid_(), min=1e-4, max=1 - 1e-4)
211
+ return y
212
+
213
+ # ctr branch
214
+ x_ctr1 = self.conv1_ctr(x)
215
+ x_ctr2 = self.conv2_ctr(x_ctr1)
216
+ x_ctr3 = self.conv3_ctr(x_ctr2)
217
+ x_ctr4 = self.conv4_ctr(x_ctr3)
218
+ score_map_ctr = self.conv5_ctr(x_ctr4)
219
+
220
+ # offset branch
221
+ x_offset1 = self.conv1_offset(x)
222
+ x_offset2 = self.conv2_offset(x_offset1)
223
+ x_offset3 = self.conv3_offset(x_offset2)
224
+ x_offset4 = self.conv4_offset(x_offset3)
225
+ score_map_offset = self.conv5_offset(x_offset4)
226
+
227
+ # size branch
228
+ x_size1 = self.conv1_size(x)
229
+ x_size2 = self.conv2_size(x_size1)
230
+ x_size3 = self.conv3_size(x_size2)
231
+ x_size4 = self.conv4_size(x_size3)
232
+ score_map_size = self.conv5_size(x_size4)
233
+ return _sigmoid(score_map_ctr), _sigmoid(score_map_size), score_map_offset
234
+
235
+
236
+ class MLP(nn.Module):
237
+ """ Very simple multi-layer perceptron (also called FFN)"""
238
+
239
+ def __init__(self, input_dim, hidden_dim, output_dim, num_layers, BN=False):
240
+ super().__init__()
241
+ self.num_layers = num_layers
242
+ h = [hidden_dim] * (num_layers - 1)
243
+ if BN:
244
+ self.layers = nn.ModuleList(nn.Sequential(nn.Linear(n, k), nn.BatchNorm1d(k))
245
+ for n, k in zip([input_dim] + h, h + [output_dim]))
246
+ else:
247
+ self.layers = nn.ModuleList(nn.Linear(n, k)
248
+ for n, k in zip([input_dim] + h, h + [output_dim]))
249
+
250
+ def forward(self, x):
251
+ for i, layer in enumerate(self.layers):
252
+ x = F.relu(layer(x)) if i < self.num_layers - 1 else layer(x)
253
+ return x
254
+
255
+
256
+ def build_box_head(cfg, hidden_dim):
257
+ stride = cfg.MODEL.BACKBONE.STRIDE
258
+
259
+ if cfg.MODEL.HEAD.TYPE == "MLP":
260
+ mlp_head = MLP(hidden_dim, hidden_dim, 4, 3) # dim_in, dim_hidden, dim_out, 3 layers
261
+ return mlp_head
262
+ elif "CORNER" in cfg.MODEL.HEAD.TYPE:
263
+ feat_sz = int(cfg.DATA.SEARCH.SIZE / stride)
264
+ channel = getattr(cfg.MODEL, "NUM_CHANNELS", 256)
265
+ print("head channel: %d" % channel)
266
+ if cfg.MODEL.HEAD.TYPE == "CORNER":
267
+ corner_head = Corner_Predictor(inplanes=cfg.MODEL.HIDDEN_DIM, channel=channel,
268
+ feat_sz=feat_sz, stride=stride)
269
+ else:
270
+ raise ValueError()
271
+ return corner_head
272
+ elif cfg.MODEL.HEAD.TYPE == "CENTER":
273
+ in_channel = hidden_dim
274
+ out_channel = cfg.MODEL.HEAD.NUM_CHANNELS
275
+ feat_sz = int(cfg.DATA.SEARCH.SIZE / stride)
276
+ center_head = CenterPredictor(inplanes=in_channel, channel=out_channel,
277
+ feat_sz=feat_sz, stride=stride)
278
+ return center_head
279
+ else:
280
+ raise ValueError("HEAD TYPE %s is not supported." % cfg.MODEL.HEAD_TYPE)
lib/models/layers/patch_embed.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.nn as nn
2
+
3
+ from timm.models.layers import to_2tuple
4
+
5
+
6
+ class PatchEmbed(nn.Module):
7
+ """ 2D Image to Patch Embedding
8
+ """
9
+
10
+ def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=768, norm_layer=None, flatten=True):
11
+ super().__init__()
12
+ img_size = to_2tuple(img_size)
13
+ patch_size = to_2tuple(patch_size)
14
+ self.img_size = img_size
15
+ self.patch_size = patch_size
16
+ self.grid_size = (img_size[0] // patch_size[0], img_size[1] // patch_size[1])
17
+ self.num_patches = self.grid_size[0] * self.grid_size[1]
18
+ self.flatten = flatten
19
+
20
+ self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size)
21
+ self.norm = norm_layer(embed_dim) if norm_layer else nn.Identity()
22
+
23
+ def forward(self, x):
24
+ # allow different input size
25
+ # B, C, H, W = x.shape
26
+ # _assert(H == self.img_size[0], f"Input image height ({H}) doesn't match model ({self.img_size[0]}).")
27
+ # _assert(W == self.img_size[1], f"Input image width ({W}) doesn't match model ({self.img_size[1]}).")
28
+ x = self.proj(x)
29
+ if self.flatten:
30
+ x = x.flatten(2).transpose(1, 2) # BCHW -> BNC
31
+ x = self.norm(x)
32
+ return x
lib/models/layers/position_encoding.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Various positional encodings for the transformer.
3
+ """
4
+ import math
5
+ import torch
6
+ from torch import nn
7
+
8
+ from lib.utils.misc import NestedTensor
9
+
10
+
11
+ class PositionEmbeddingSine(nn.Module):
12
+ """
13
+ This is a more standard version of the position embedding, very similar to the one
14
+ used by the Attention is all you need paper, generalized to work on images.
15
+ """
16
+ def __init__(self, num_pos_feats=64, temperature=10000, normalize=False, scale=None):
17
+ super().__init__()
18
+ self.num_pos_feats = num_pos_feats
19
+ self.temperature = temperature
20
+ self.normalize = normalize
21
+ if scale is not None and normalize is False:
22
+ raise ValueError("normalize should be True if scale is passed")
23
+ if scale is None:
24
+ scale = 2 * math.pi
25
+ self.scale = scale
26
+
27
+ def forward(self, tensor_list: NestedTensor):
28
+ x = tensor_list.tensors
29
+ mask = tensor_list.mask
30
+ assert mask is not None
31
+ not_mask = ~mask # (b,h,w)
32
+ y_embed = not_mask.cumsum(1, dtype=torch.float32) # cumulative sum along axis 1 (h axis) --> (b, h, w)
33
+ x_embed = not_mask.cumsum(2, dtype=torch.float32) # cumulative sum along axis 2 (w axis) --> (b, h, w)
34
+ if self.normalize:
35
+ eps = 1e-6
36
+ y_embed = y_embed / (y_embed[:, -1:, :] + eps) * self.scale # 2pi * (y / sigma(y))
37
+ x_embed = x_embed / (x_embed[:, :, -1:] + eps) * self.scale # 2pi * (x / sigma(x))
38
+
39
+ dim_t = torch.arange(self.num_pos_feats, dtype=torch.float32, device=x.device) # (0,1,2,...,d/2)
40
+ dim_t = self.temperature ** (2 * (dim_t // 2) / self.num_pos_feats)
41
+
42
+ pos_x = x_embed[:, :, :, None] / dim_t # (b,h,w,d/2)
43
+ pos_y = y_embed[:, :, :, None] / dim_t # (b,h,w,d/2)
44
+ pos_x = torch.stack((pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4).flatten(3) # (b,h,w,d/2)
45
+ pos_y = torch.stack((pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4).flatten(3) # (b,h,w,d/2)
46
+ pos = torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2) # (b,h,w,d)
47
+ return pos
48
+
49
+
50
+ class PositionEmbeddingLearned(nn.Module):
51
+ """
52
+ Absolute pos embedding, learned.
53
+ """
54
+ def __init__(self, num_pos_feats=256):
55
+ super().__init__()
56
+ self.row_embed = nn.Embedding(50, num_pos_feats)
57
+ self.col_embed = nn.Embedding(50, num_pos_feats)
58
+ self.reset_parameters()
59
+
60
+ def reset_parameters(self):
61
+ nn.init.uniform_(self.row_embed.weight)
62
+ nn.init.uniform_(self.col_embed.weight)
63
+
64
+ def forward(self, tensor_list: NestedTensor):
65
+ x = tensor_list.tensors
66
+ h, w = x.shape[-2:]
67
+ i = torch.arange(w, device=x.device)
68
+ j = torch.arange(h, device=x.device)
69
+ x_emb = self.col_embed(i)
70
+ y_emb = self.row_embed(j)
71
+ pos = torch.cat([
72
+ x_emb.unsqueeze(0).repeat(h, 1, 1),
73
+ y_emb.unsqueeze(1).repeat(1, w, 1),
74
+ ], dim=-1).permute(2, 0, 1).unsqueeze(0).repeat(x.shape[0], 1, 1, 1)
75
+ return pos # (H,W,C) --> (C,H,W) --> (1,C,H,W) --> (B,C,H,W)
76
+
77
+
78
+ class PositionEmbeddingNone(nn.Module):
79
+ """
80
+ No positional encoding.
81
+ """
82
+ def __init__(self, num_pos_feats=256):
83
+ super().__init__()
84
+ self.n_dim = num_pos_feats * 2
85
+
86
+ def forward(self, tensor_list: NestedTensor):
87
+ x = tensor_list.tensors
88
+ b, _, h, w = x.size()
89
+ return torch.zeros((b, self.n_dim, h, w), device=x.device) # (B, C, H, W)
90
+
91
+
92
+ def build_position_encoding(cfg):
93
+ N_steps = cfg.MODEL.HIDDEN_DIM // 2
94
+ if cfg.MODEL.POSITION_EMBEDDING in ('v2', 'sine'):
95
+ # TODO find a better way of exposing other arguments
96
+ position_embedding = PositionEmbeddingSine(N_steps, normalize=True)
97
+ elif cfg.MODEL.POSITION_EMBEDDING in ('v3', 'learned'):
98
+ position_embedding = PositionEmbeddingLearned(N_steps)
99
+ elif cfg.MODEL.POSITION_EMBEDDING in ('None', ):
100
+ print("Not using positional encoding.")
101
+ position_embedding = PositionEmbeddingNone(N_steps)
102
+ else:
103
+ raise ValueError(f"not supported {cfg.MODEL.POSITION_EMBEDDING}")
104
+
105
+ return position_embedding
106
+
107
+
108
+ class PositionEmbeddingLearned_new(nn.Module):
109
+ """
110
+ Absolute pos embedding, learned. (allow users to specify the size)
111
+ """
112
+ def __init__(self, num_pos_feats=256, sz=20):
113
+ super().__init__()
114
+ self.sz = sz
115
+ self.row_embed = nn.Embedding(sz, num_pos_feats)
116
+ self.col_embed = nn.Embedding(sz, num_pos_feats)
117
+ self.reset_parameters()
118
+
119
+ def reset_parameters(self):
120
+ nn.init.uniform_(self.row_embed.weight)
121
+ nn.init.uniform_(self.col_embed.weight)
122
+
123
+ def forward(self, bs):
124
+ """bs: batch size"""
125
+ h, w = self.sz, self.sz
126
+ i = torch.arange(w, device=self.col_embed.weight.device)
127
+ j = torch.arange(h, device=self.row_embed.weight.device)
128
+ x_emb = self.col_embed(i)
129
+ y_emb = self.row_embed(j)
130
+ # pos = torch.cat([
131
+ # x_emb.unsqueeze(0).repeat(h, 1, 1),
132
+ # y_emb.unsqueeze(1).repeat(1, w, 1),
133
+ # ], dim=-1).permute(2, 0, 1).unsqueeze(0).repeat(bs, 1, 1, 1)
134
+
135
+ pos = torch.cat([
136
+ x_emb.unsqueeze(0).repeat(h, 1, 1),
137
+ y_emb.unsqueeze(1).repeat(1, w, 1),
138
+ ], dim=-1).repeat(1, bs, 1)
139
+ # print(bs, pos)
140
+ return pos # (H,W,C) --> (C,H,W) --> (1,C,H,W) --> (B,C,H,W)
141
+
142
+
143
+ # def build_position_encoding_new(cfg, sz):
144
+ # N_steps = cfg.MODEL.HIDDEN_DIM // 2
145
+ # position_embedding = PositionEmbeddingLearned_new(N_steps, sz)
146
+ # return position_embedding
147
+
148
+
149
+
150
+ def build_position_encoding(embed_dim, sz=256):
151
+ N_steps = embed_dim // 2
152
+ position_embedding = PositionEmbeddingLearned_new(N_steps, sz)
153
+ return position_embedding
154
+
lib/models/layers/rpe.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ from timm.models.layers import trunc_normal_
4
+
5
+
6
+ def generate_2d_relative_positional_encoding_index(z_shape, x_shape):
7
+ '''
8
+ z_shape: (z_h, z_w)
9
+ x_shape: (x_h, x_w)
10
+ '''
11
+ z_2d_index_h, z_2d_index_w = torch.meshgrid(torch.arange(z_shape[0]), torch.arange(z_shape[1]))
12
+ x_2d_index_h, x_2d_index_w = torch.meshgrid(torch.arange(x_shape[0]), torch.arange(x_shape[1]))
13
+
14
+ z_2d_index_h = z_2d_index_h.flatten(0)
15
+ z_2d_index_w = z_2d_index_w.flatten(0)
16
+ x_2d_index_h = x_2d_index_h.flatten(0)
17
+ x_2d_index_w = x_2d_index_w.flatten(0)
18
+
19
+ diff_h = z_2d_index_h[:, None] - x_2d_index_h[None, :]
20
+ diff_w = z_2d_index_w[:, None] - x_2d_index_w[None, :]
21
+
22
+ diff = torch.stack((diff_h, diff_w), dim=-1)
23
+ _, indices = torch.unique(diff.view(-1, 2), return_inverse=True, dim=0)
24
+ return indices.view(z_shape[0] * z_shape[1], x_shape[0] * x_shape[1])
25
+
26
+
27
+ def generate_2d_concatenated_self_attention_relative_positional_encoding_index(z_shape, x_shape):
28
+ '''
29
+ z_shape: (z_h, z_w)
30
+ x_shape: (x_h, x_w)
31
+ '''
32
+ z_2d_index_h, z_2d_index_w = torch.meshgrid(torch.arange(z_shape[0]), torch.arange(z_shape[1]))
33
+ x_2d_index_h, x_2d_index_w = torch.meshgrid(torch.arange(x_shape[0]), torch.arange(x_shape[1]))
34
+
35
+ z_2d_index_h = z_2d_index_h.flatten(0)
36
+ z_2d_index_w = z_2d_index_w.flatten(0)
37
+ x_2d_index_h = x_2d_index_h.flatten(0)
38
+ x_2d_index_w = x_2d_index_w.flatten(0)
39
+
40
+ concatenated_2d_index_h = torch.cat((z_2d_index_h, x_2d_index_h))
41
+ concatenated_2d_index_w = torch.cat((z_2d_index_w, x_2d_index_w))
42
+
43
+ diff_h = concatenated_2d_index_h[:, None] - concatenated_2d_index_h[None, :]
44
+ diff_w = concatenated_2d_index_w[:, None] - concatenated_2d_index_w[None, :]
45
+
46
+ z_len = z_shape[0] * z_shape[1]
47
+ x_len = x_shape[0] * x_shape[1]
48
+ a = torch.empty((z_len + x_len), dtype=torch.int64)
49
+ a[:z_len] = 0
50
+ a[z_len:] = 1
51
+ b=a[:, None].repeat(1, z_len + x_len)
52
+ c=a[None, :].repeat(z_len + x_len, 1)
53
+
54
+ diff = torch.stack((diff_h, diff_w, b, c), dim=-1)
55
+ _, indices = torch.unique(diff.view((z_len + x_len) * (z_len + x_len), 4), return_inverse=True, dim=0)
56
+ return indices.view((z_len + x_len), (z_len + x_len))
57
+
58
+
59
+ def generate_2d_concatenated_cross_attention_relative_positional_encoding_index(z_shape, x_shape):
60
+ '''
61
+ z_shape: (z_h, z_w)
62
+ x_shape: (x_h, x_w)
63
+ '''
64
+ z_2d_index_h, z_2d_index_w = torch.meshgrid(torch.arange(z_shape[0]), torch.arange(z_shape[1]))
65
+ x_2d_index_h, x_2d_index_w = torch.meshgrid(torch.arange(x_shape[0]), torch.arange(x_shape[1]))
66
+
67
+ z_2d_index_h = z_2d_index_h.flatten(0)
68
+ z_2d_index_w = z_2d_index_w.flatten(0)
69
+ x_2d_index_h = x_2d_index_h.flatten(0)
70
+ x_2d_index_w = x_2d_index_w.flatten(0)
71
+
72
+ concatenated_2d_index_h = torch.cat((z_2d_index_h, x_2d_index_h))
73
+ concatenated_2d_index_w = torch.cat((z_2d_index_w, x_2d_index_w))
74
+
75
+ diff_h = x_2d_index_h[:, None] - concatenated_2d_index_h[None, :]
76
+ diff_w = x_2d_index_w[:, None] - concatenated_2d_index_w[None, :]
77
+
78
+ z_len = z_shape[0] * z_shape[1]
79
+ x_len = x_shape[0] * x_shape[1]
80
+
81
+ a = torch.empty(z_len + x_len, dtype=torch.int64)
82
+ a[: z_len] = 0
83
+ a[z_len:] = 1
84
+ c = a[None, :].repeat(x_len, 1)
85
+
86
+ diff = torch.stack((diff_h, diff_w, c), dim=-1)
87
+ _, indices = torch.unique(diff.view(x_len * (z_len + x_len), 3), return_inverse=True, dim=0)
88
+ return indices.view(x_len, (z_len + x_len))
89
+
90
+
91
+ class RelativePosition2DEncoder(nn.Module):
92
+ def __init__(self, num_heads, embed_size):
93
+ super(RelativePosition2DEncoder, self).__init__()
94
+ self.relative_position_bias_table = nn.Parameter(torch.empty((num_heads, embed_size)))
95
+ trunc_normal_(self.relative_position_bias_table, std=0.02)
96
+
97
+ def forward(self, attn_rpe_index):
98
+ '''
99
+ Args:
100
+ attn_rpe_index (torch.Tensor): (*), any shape containing indices, max(attn_rpe_index) < embed_size
101
+ Returns:
102
+ torch.Tensor: (1, num_heads, *)
103
+ '''
104
+ return self.relative_position_bias_table[:, attn_rpe_index].unsqueeze(0)
lib/models/layers/transformer_dec.py ADDED
@@ -0,0 +1,415 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ from typing import Optional, List
3
+
4
+ import torch
5
+ import torch.nn.functional as F
6
+ from torch import nn, Tensor
7
+ import time
8
+
9
+
10
+ def check_inf(tensor):
11
+ return torch.isinf(tensor.detach()).any()
12
+
13
+
14
+ def check_nan(tensor):
15
+ return torch.isnan(tensor.detach()).any()
16
+
17
+
18
+ def check_valid(tensor, type_name):
19
+ if check_inf(tensor):
20
+ print("%s is inf." % type_name)
21
+ if check_nan(tensor):
22
+ print("%s is nan" % type_name)
23
+
24
+
25
+ def generate_square_subsequent_mask(sz):
26
+ r"""Generate a square mask for the sequence. The masked positions are filled with float('-inf').
27
+ Unmasked positions are filled with float(0.0).
28
+ """
29
+
30
+ # each token only can see tokens before them
31
+ mask = (torch.triu(torch.ones(sz, sz)) == 1).transpose(0, 1)
32
+ mask = mask.float().masked_fill(mask == 0, float(
33
+ '-inf')).masked_fill(mask == 1, float(0.0))
34
+ return mask
35
+
36
+
37
+ class Transformer_dec(nn.Module):
38
+
39
+ def __init__(self, d_model=512, nhead=8, num_encoder_layers=6,
40
+ num_decoder_layers=6, dim_feedforward=768, dropout=0.1,
41
+ activation="relu", normalize_before=False,
42
+ return_intermediate_dec=False, divide_norm=False):
43
+ super().__init__()
44
+ decoder_layer = TransformerDecoderLayer(d_model, nhead, dim_feedforward,
45
+ dropout, activation, normalize_before, divide_norm=divide_norm)
46
+ decoder_norm = nn.LayerNorm(d_model)
47
+
48
+ self.decoder = TransformerDecoder(decoder_layer, num_decoder_layers, decoder_norm,
49
+ return_intermediate=return_intermediate_dec)
50
+
51
+ self._reset_parameters()
52
+
53
+ self.d_model = d_model
54
+ self.nhead = nhead
55
+ self.d_feed = dim_feedforward
56
+
57
+ def _reset_parameters(self):
58
+ for p in self.parameters():
59
+ if p.dim() > 1:
60
+ nn.init.xavier_uniform_(p)
61
+
62
+ def forward(self,tgt, feat, pos, query_embed,mask):
63
+ memory = feat # output of hivit
64
+ hs = self.decoder(tgt, memory, pos=pos, query_pos=query_embed,memory_key_padding_mask=mask)
65
+ return hs
66
+
67
+
68
+ class TransformerDecoder(nn.Module):
69
+
70
+ def __init__(self, decoder_layer, num_layers, norm=None, return_intermediate=False):
71
+ super().__init__()
72
+ self.layers = _get_clones(decoder_layer, num_layers)
73
+ self.num_layers = num_layers
74
+ self.norm = norm
75
+ self.return_intermediate = return_intermediate
76
+
77
+ def forward(self, tgt, memory,
78
+ tgt_mask: Optional[Tensor] = None,
79
+ memory_mask: Optional[Tensor] = None,
80
+ tgt_key_padding_mask: Optional[Tensor] = None,
81
+ memory_key_padding_mask: Optional[Tensor] = None,
82
+ pos: Optional[Tensor] = None,
83
+ query_pos: Optional[Tensor] = None):
84
+ output = tgt
85
+
86
+ intermediate = []
87
+ for layer_id, layer in enumerate(self.layers):
88
+ output = layer(output, memory, tgt_mask=tgt_mask,
89
+ memory_mask=memory_mask,
90
+ tgt_key_padding_mask=tgt_key_padding_mask,
91
+ memory_key_padding_mask=memory_key_padding_mask,
92
+ pos=pos, query_pos=query_pos)
93
+ if self.return_intermediate:
94
+ intermediate.append(self.norm(output))
95
+
96
+ if self.norm is not None:
97
+ output[0] = self.norm(output[0])
98
+ if self.return_intermediate:
99
+ intermediate.pop()
100
+ intermediate.append(output)
101
+
102
+ if self.return_intermediate:
103
+ return torch.stack(intermediate)
104
+ return output
105
+
106
+
107
+ class TransformerDecoderLayer(nn.Module):
108
+
109
+ def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1,
110
+ activation="relu", normalize_before=False, divide_norm=False):
111
+ super().__init__()
112
+ self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout,batch_first=True)
113
+ self.multihead_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout,batch_first=True)
114
+ # Implementation of Feedforward model
115
+ self.linear1 = nn.Linear(d_model, dim_feedforward)
116
+ self.dropout = nn.Dropout(dropout)
117
+ self.linear2 = nn.Linear(dim_feedforward, d_model)
118
+
119
+ self.norm1 = nn.LayerNorm(d_model)
120
+ self.norm2 = nn.LayerNorm(d_model)
121
+ self.norm3 = nn.LayerNorm(d_model)
122
+ self.dropout1 = nn.Dropout(dropout)
123
+ self.dropout2 = nn.Dropout(dropout)
124
+ self.dropout3 = nn.Dropout(dropout)
125
+
126
+ self.activation = _get_activation_fn(activation)
127
+ self.normalize_before = normalize_before
128
+
129
+ self.divide_norm = divide_norm
130
+ self.scale_factor = float(d_model // nhead) ** 0.5
131
+
132
+ def with_pos_embed(self, tensor, pos: Optional[Tensor]):
133
+ return tensor if pos is None else tensor + pos
134
+
135
+ def forward_post(self, tgt_all, memory,
136
+ tgt_mask: Optional[Tensor] = None,
137
+ memory_mask: Optional[Tensor] = None,
138
+ tgt_key_padding_mask: Optional[Tensor] = None,
139
+ memory_key_padding_mask: Optional[Tensor] = None,
140
+ pos: Optional[Tensor] = None,
141
+ query_pos: Optional[Tensor] = None):
142
+ # print(tgt.shape, memory.shape)
143
+ # print(len(tgt_all))
144
+ q_initial = tgt_all[0]
145
+ kv_initial = tgt_all[1]
146
+ q = kv_initial
147
+ k = tgt = kv_initial # self.with_pos_embed(tgt, query_pos)
148
+ # print(q.shape, k.shape, tgt.shape, 'tgt kv')
149
+ tgt2 = self.self_attn(self.with_pos_embed(q,query_pos), self.with_pos_embed(k,query_pos), value=tgt, attn_mask=tgt_mask,
150
+ key_padding_mask=memory_key_padding_mask)[0]
151
+ # print(tgt.shape, tgt2.shape, 'tgt 1')
152
+ tgt = q + self.dropout1(tgt2)
153
+ # print(tgt.shape, tgt2.shape, 'tgt 2')
154
+ kv_update = self.norm1(tgt)
155
+
156
+ tgt2 = self.multihead_attn(query=self.with_pos_embed(q_initial, pos),
157
+ key=self.with_pos_embed(kv_update, query_pos),
158
+ value=kv_update, attn_mask=memory_mask,
159
+ key_padding_mask=memory_key_padding_mask)[0]
160
+ tgt = q_initial + self.dropout2(tgt2)
161
+ tgt = self.norm2(tgt)
162
+
163
+ # tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt))))
164
+ # tgt = tgt + self.dropout3(tgt2)
165
+ # tgt = self.norm3(tgt)
166
+ # print(tgt.shape, 'tgt 2')
167
+ return [tgt, kv_update]
168
+
169
+ def forward_pre(self, tgt, memory,
170
+ tgt_mask: Optional[Tensor] = None,
171
+ memory_mask: Optional[Tensor] = None,
172
+ tgt_key_padding_mask: Optional[Tensor] = None,
173
+ memory_key_padding_mask: Optional[Tensor] = None,
174
+ pos: Optional[Tensor] = None,
175
+ query_pos: Optional[Tensor] = None):
176
+ tgt2 = self.norm1(tgt)
177
+ q = k = self.with_pos_embed(tgt2, query_pos)
178
+ tgt2 = self.self_attn(q, k, value=tgt2, attn_mask=tgt_mask,
179
+ key_padding_mask=tgt_key_padding_mask)[0]
180
+ tgt = tgt + self.dropout1(tgt2)
181
+ tgt2 = self.norm2(tgt)
182
+ tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt2, query_pos),
183
+ key=self.with_pos_embed(memory, pos),
184
+ value=memory, attn_mask=memory_mask,
185
+ key_padding_mask=memory_key_padding_mask)[0]
186
+ tgt = tgt + self.dropout2(tgt2)
187
+ tgt2 = self.norm3(tgt)
188
+ tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt2))))
189
+ tgt = tgt + self.dropout3(tgt2)
190
+ return tgt
191
+
192
+ def forward(self, tgt, memory,
193
+ tgt_mask: Optional[Tensor] = None,
194
+ memory_mask: Optional[Tensor] = None,
195
+ tgt_key_padding_mask: Optional[Tensor] = None,
196
+ memory_key_padding_mask: Optional[Tensor] = None,
197
+ pos: Optional[Tensor] = None,
198
+ query_pos: Optional[Tensor] = None):
199
+ if self.normalize_before:
200
+ return self.forward_pre(tgt, memory, tgt_mask, memory_mask,
201
+ tgt_key_padding_mask, memory_key_padding_mask, pos,query_pos)
202
+ return self.forward_post(tgt, memory, tgt_mask, memory_mask,
203
+ tgt_key_padding_mask, memory_key_padding_mask, pos,query_pos)
204
+
205
+
206
+ class Transformer_dec_with_mask(nn.Module):
207
+
208
+ def __init__(self, d_model=512, nhead=8, num_encoder_layers=6,
209
+ num_decoder_layers=6, dim_feedforward=768, dropout=0.1,
210
+ activation="relu", normalize_before=False,
211
+ return_intermediate_dec=False, divide_norm=False):
212
+ super().__init__()
213
+ decoder_layer = TransformerDecoderWithMaskLayer(d_model, nhead, dim_feedforward,
214
+ dropout, activation, normalize_before, divide_norm=divide_norm)
215
+ decoder_norm = nn.LayerNorm(d_model)
216
+
217
+ self.decoder = TransformerDecoderWithMask(decoder_layer, num_decoder_layers, decoder_norm,
218
+ return_intermediate=return_intermediate_dec)
219
+
220
+ self._reset_parameters()
221
+
222
+ self.d_model = d_model
223
+ self.nhead = nhead
224
+ self.d_feed = dim_feedforward
225
+
226
+ def _reset_parameters(self):
227
+ for p in self.parameters():
228
+ if p.dim() > 1:
229
+ nn.init.xavier_uniform_(p)
230
+
231
+ def forward(self, q, kv, feat_mask, q_pos, kv_pos=None):
232
+ memory = kv # output of hivit
233
+ hs = self.decoder(q, memory, feat_mask, pos=kv_pos, query_pos=q_pos)
234
+ return hs
235
+
236
+
237
+ class TransformerDecoderWithMask(nn.Module):
238
+
239
+ def __init__(self, decoder_layer, num_layers, norm=None, return_intermediate=False):
240
+ super().__init__()
241
+ self.layers = _get_clones(decoder_layer, num_layers)
242
+ self.num_layers = num_layers
243
+ self.norm = norm
244
+ self.return_intermediate = return_intermediate
245
+
246
+ def forward(self, tgt, memory, feat_mask,
247
+ tgt_mask: Optional[Tensor] = None,
248
+ memory_mask: Optional[Tensor] = None,
249
+ tgt_key_padding_mask: Optional[Tensor] = None,
250
+ memory_key_padding_mask: Optional[Tensor] = None,
251
+ pos: Optional[Tensor] = None,
252
+ query_pos: Optional[Tensor] = None,
253
+ pre_query_pos: Optional[Tensor] = None):
254
+ output = tgt
255
+
256
+ intermediate = []
257
+ for layer_id, layer in enumerate(self.layers):
258
+ output = layer(output, memory, feat_mask,
259
+ tgt_mask=tgt_mask,
260
+ memory_mask=memory_mask,
261
+ tgt_key_padding_mask=tgt_key_padding_mask,
262
+ memory_key_padding_mask=memory_key_padding_mask,
263
+ pos=pos, query_pos=query_pos, pre_query_pos=pre_query_pos)
264
+ if self.return_intermediate:
265
+ intermediate.append(self.norm(output))
266
+
267
+ if self.norm is not None:
268
+ output = self.norm(output)
269
+ if self.return_intermediate:
270
+ intermediate.pop()
271
+ intermediate.append(output)
272
+
273
+ if self.return_intermediate:
274
+ return torch.stack(intermediate)
275
+ return output
276
+
277
+
278
+ class TransformerDecoderWithMaskLayer(nn.Module):
279
+
280
+ def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1,
281
+ activation="relu", normalize_before=False, divide_norm=False):
282
+ super().__init__()
283
+ self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout, batch_first=True)
284
+ self.multihead_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout, batch_first=True)
285
+ # Implementation of Feedforward model
286
+ self.linear1 = nn.Linear(d_model, dim_feedforward)
287
+ self.dropout = nn.Dropout(dropout)
288
+ self.linear2 = nn.Linear(dim_feedforward, d_model)
289
+
290
+ self.norm1 = nn.LayerNorm(d_model)
291
+ self.norm2 = nn.LayerNorm(d_model)
292
+ self.norm3 = nn.LayerNorm(d_model)
293
+ self.dropout1 = nn.Dropout(dropout)
294
+ self.dropout2 = nn.Dropout(dropout)
295
+ self.dropout3 = nn.Dropout(dropout)
296
+
297
+ self.activation = _get_activation_fn(activation)
298
+ self.normalize_before = normalize_before
299
+
300
+ self.divide_norm = divide_norm
301
+ self.scale_factor = float(d_model // nhead) ** 0.5
302
+
303
+ def with_pos_embed(self, tensor, pos: Optional[Tensor]):
304
+ return tensor if pos is None else tensor + pos
305
+
306
+ def forward_post(self, tgt_all, memory, feat_mask,
307
+ tgt_mask: Optional[Tensor] = None,
308
+ memory_mask: Optional[Tensor] = None,
309
+ tgt_key_padding_mask: Optional[Tensor] = None,
310
+ memory_key_padding_mask: Optional[Tensor] = None,
311
+ pos: Optional[Tensor] = None,
312
+ query_pos: Optional[Tensor] = None,
313
+ pre_query_pos: Optional[Tensor] = None):
314
+ q = tgt_all
315
+ k = memory * feat_mask
316
+ tgt2 = self.self_attn(self.with_pos_embed(q, query_pos ), self.with_pos_embed(k, pos), value=k,
317
+ attn_mask=tgt_mask,
318
+ key_padding_mask=tgt_key_padding_mask)[0]
319
+ tgt = q + self.dropout1(tgt2)
320
+ tgt = self.norm2(tgt)
321
+
322
+ # memory_1 = self.norm1(tgt)
323
+ #
324
+ # tgt = tgt_all
325
+ # tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt, query_pos),
326
+ # key=self.with_pos_embed(memory_1, pos),
327
+ # value=memory_1, attn_mask=memory_mask,
328
+ # key_padding_mask=memory_key_padding_mask)[0]
329
+ # tgt = tgt + self.dropout2(tgt2)
330
+ # tgt = self.norm2(tgt)
331
+ tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt))))
332
+ tgt = tgt + self.dropout3(tgt2)
333
+ tgt = self.norm3(tgt)
334
+
335
+ return tgt
336
+
337
+ def forward_pre(self, tgt, memory,
338
+ tgt_mask: Optional[Tensor] = None,
339
+ memory_mask: Optional[Tensor] = None,
340
+ tgt_key_padding_mask: Optional[Tensor] = None,
341
+ memory_key_padding_mask: Optional[Tensor] = None,
342
+ pos: Optional[Tensor] = None,
343
+ query_pos: Optional[Tensor] = None):
344
+ tgt2 = self.norm1(tgt)
345
+ q = k = self.with_pos_embed(tgt2, query_pos)
346
+ tgt2 = self.self_attn(q, k, value=tgt2, attn_mask=tgt_mask,
347
+ key_padding_mask=tgt_key_padding_mask)[0]
348
+ tgt = tgt + self.dropout1(tgt2)
349
+ tgt2 = self.norm2(tgt)
350
+ tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt2, query_pos),
351
+ key=self.with_pos_embed(memory, pos),
352
+ value=memory, attn_mask=memory_mask,
353
+ key_padding_mask=memory_key_padding_mask)[0]
354
+ tgt = tgt + self.dropout2(tgt2)
355
+ tgt2 = self.norm3(tgt)
356
+ tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt2))))
357
+ tgt = tgt + self.dropout3(tgt2)
358
+ return tgt
359
+
360
+ def forward(self, tgt, memory, feat_mask,
361
+ tgt_mask: Optional[Tensor] = None,
362
+ memory_mask: Optional[Tensor] = None,
363
+ tgt_key_padding_mask: Optional[Tensor] = None,
364
+ memory_key_padding_mask: Optional[Tensor] = None,
365
+ pos: Optional[Tensor] = None,
366
+ query_pos: Optional[Tensor] = None,
367
+ pre_query_pos: Optional[Tensor] = None):
368
+ if self.normalize_before:
369
+ return self.forward_pre(tgt, memory, tgt_mask, memory_mask,
370
+ tgt_key_padding_mask, memory_key_padding_mask, pos)
371
+ return self.forward_post(tgt, memory, feat_mask, tgt_mask, memory_mask,
372
+ tgt_key_padding_mask, memory_key_padding_mask, pos, query_pos, pre_query_pos)
373
+
374
+
375
+ def _get_clones(module, N):
376
+ return nn.ModuleList([copy.deepcopy(module) for i in range(N)])
377
+
378
+
379
+ def build_transformer_dec(cfg, hidden_dim):
380
+ return Transformer_dec(
381
+ d_model=hidden_dim,
382
+ dropout=0.1,
383
+ nhead=8,
384
+ dim_feedforward=hidden_dim,
385
+ num_encoder_layers=0,
386
+ num_decoder_layers=2,
387
+ normalize_before=False,
388
+ return_intermediate_dec=False,
389
+ divide_norm=False
390
+ )
391
+
392
+
393
+ def build_transformer_dec_with_mask(cfg, hidden_dim):
394
+ return Transformer_dec_with_mask(
395
+ d_model=hidden_dim,
396
+ dropout=0.1,
397
+ nhead=8,
398
+ dim_feedforward=hidden_dim,
399
+ num_encoder_layers=0,
400
+ num_decoder_layers=2,
401
+ normalize_before=False,
402
+ return_intermediate_dec=False,
403
+ divide_norm=False
404
+ )
405
+
406
+
407
+ def _get_activation_fn(activation):
408
+ """Return an activation function given a string"""
409
+ if activation == "relu":
410
+ return F.relu
411
+ if activation == "gelu":
412
+ return F.gelu
413
+ if activation == "glu":
414
+ return F.glu
415
+ raise RuntimeError(F"activation should be relu/gelu, not {activation}.")
lib/models/transformers/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from .transformer import build_decoder, VisionLanguageFusionModule,build_temporal_decoder,build_text_prompt_decoder
2
+ from .position_encoding import PositionEmbeddingSine1D
lib/models/transformers/position_encoding.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Various positional encodings for the transformer.
3
+ """
4
+ import math
5
+ import torch
6
+ from torch import nn
7
+
8
+ from lib.utils.misc import NestedTensor
9
+
10
+
11
+ class PositionEmbeddingSine1D(nn.Module):
12
+ """
13
+ This is a more standard version of the position embedding, very similar to the one
14
+ used by the Attention is all you need paper, generalized to work on images.
15
+ """
16
+ def __init__(self, num_pos_feats=256, temperature=10000, normalize=False, scale=None):
17
+ super().__init__()
18
+ self.num_pos_feats = num_pos_feats
19
+ self.temperature = temperature
20
+ self.normalize = normalize
21
+ if scale is not None and normalize is False:
22
+ raise ValueError("normalize should be True if scale is passed")
23
+ if scale is None:
24
+ scale = 2 * math.pi
25
+ self.scale = scale
26
+
27
+ def forward(self, tensor_list: NestedTensor):
28
+ x = tensor_list.tensors # [B, L, C]
29
+ mask = tensor_list.mask # [B, L]
30
+ assert mask is not None
31
+ not_mask = ~mask
32
+ x_embed = not_mask.cumsum(1, dtype=torch.float32) # [B, L]
33
+ if self.normalize:
34
+ eps = 1e-6
35
+ x_embed = x_embed / (x_embed[:, -1:] + eps) * self.scale
36
+
37
+ dim_t = torch.arange(self.num_pos_feats, dtype=torch.float32, device=x.device)
38
+ dim_t = self.temperature ** (2 * (dim_t // 2) / self.num_pos_feats)
39
+
40
+ pos_x = x_embed[:, :, None] / dim_t # [B, L, C]
41
+ pos_x = torch.stack((pos_x[:, :, 0::2].sin(), pos_x[:, :, 1::2].cos()), dim=3).flatten(2) # [B, L, C]
42
+ # pos = pos_x.permute(0, 2, 1) # [B, C, L]
43
+ return pos_x
44
+
45
+
46
+ class PositionEmbeddingSine2D(nn.Module):
47
+ """
48
+ This is a more standard version of the position embedding, very similar to the one
49
+ used by the Attention is all you need paper, generalized to work on images.
50
+ """
51
+ def __init__(self, num_pos_feats=64, temperature=10000, normalize=False, scale=None):
52
+ super().__init__()
53
+ self.num_pos_feats = num_pos_feats
54
+ self.temperature = temperature
55
+ self.normalize = normalize
56
+ if scale is not None and normalize is False:
57
+ raise ValueError("normalize should be True if scale is passed")
58
+ if scale is None:
59
+ scale = 2 * math.pi
60
+ self.scale = scale
61
+
62
+ def forward(self, mask):
63
+ # mask: (B, H, W)
64
+ not_mask = ~mask # (batch,h,w) ~mask:按位取反
65
+ y_embed = not_mask.cumsum(1, dtype=torch.float32) # cumulative sum along axis 1 (h axis) --> (b, h, w)
66
+ x_embed = not_mask.cumsum(2, dtype=torch.float32) # cumulative sum along axis 2 (w axis) --> (b, h, w)
67
+ if self.normalize:
68
+ eps = 1e-6
69
+ y_embed = y_embed / (y_embed[:, -1:, :] + eps) * self.scale # 2π * (y / sigma(y)) (16,8,8)
70
+ x_embed = x_embed / (x_embed[:, :, -1:] + eps) * self.scale # 2π * (x / sigma(x)) (16,8,8)
71
+
72
+ dim_t = torch.arange(self.num_pos_feats, dtype=torch.float32, device=mask.device) # (0,1,2,...,d/2)
73
+ dim_t = self.temperature ** (2 * (dim_t // 2) / self.num_pos_feats)
74
+
75
+ pos_x = x_embed[:, :, :, None] / dim_t # (b,h,w,d/2)
76
+ pos_y = y_embed[:, :, :, None] / dim_t # (b,h,w,d/2)
77
+ pos_x = torch.stack((pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4).flatten(3) # (b,h,w,d/2) (16,8,8,128)
78
+ pos_y = torch.stack((pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4).flatten(3) # (b,h,w,d/2) (16,8,8,128)
79
+ pos = torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2) # (b,h,w,d) (16,8,8,256) to (16,256,8,8)
80
+ return pos
81
+
82
+
83
+ class PositionEmbeddingLearned(nn.Module):
84
+ """
85
+ Absolute pos embedding, learned.
86
+ """
87
+ def __init__(self, in_dim, out_dim):
88
+ super().__init__()
89
+ self.embed = nn.Embedding(in_dim, out_dim)
90
+ self.reset_parameters()
91
+
92
+ def reset_parameters(self):
93
+ nn.init.uniform_(self.embed.weight)
94
+
95
+ def forward(self, x):
96
+ # x: (B, 5, C) or (B, mask, C) or (B, bbox+mask, C)
97
+ n = x.size(1)
98
+ i = torch.arange(n, device=x.device)
99
+ pos = self.embed(i).unsqueeze(0).repeat(x.size(0), 1, 1) # (N,C) --> (1,N,C) --> (B,N,C)
100
+ return pos
101
+
102
+
103
+ class PositionEmbeddingNone(nn.Module):
104
+ """
105
+ No positional encoding.
106
+ """
107
+ def __init__(self, num_pos_feats=256):
108
+ super().__init__()
109
+ self.n_dim = num_pos_feats * 2
110
+
111
+ def forward(self, tensor_list: NestedTensor):
112
+ x = tensor_list.tensors
113
+ b, _, h, w = x.size()
114
+ return torch.zeros((b, self.n_dim, h, w), device=x.device) # (B, C, H, W)
115
+
116
+
117
+ def build_memory_position_encoding(cfg):
118
+ N_steps = cfg.MODEL.DECODER.HIDDEN_DIM // 2 # N_steps = 128
119
+ if cfg.MODEL.DECODER.MEMORY_POSITION_EMBEDDING in ('v2', 'sine'):
120
+ # TODO find a better way of exposing other arguments
121
+ position_embedding = PositionEmbeddingSine2D(N_steps, normalize=True)
122
+ elif cfg.MODEL.DECODER.MEMORY_POSITION_EMBEDDING in ('v3', 'learned'):
123
+ position_embedding = PositionEmbeddingLearned(N_steps)
124
+ elif cfg.MODEL.DECODER.MEMORY_POSITION_EMBEDDING in ('None', ):
125
+ print("Not using positional encoding.")
126
+ position_embedding = PositionEmbeddingNone(N_steps)
127
+ else:
128
+ raise ValueError(f"not supported {cfg.MODEL.DECODER.MEMORY_POSITION_EMBEDDING}")
129
+
130
+ return position_embedding
131
+
132
+
133
+ def build_query_position_encoding(cfg):
134
+ bbox_task = cfg.TRAIN.BBOX_TASK
135
+ language_task = getattr(cfg.TRAIN, "LANGUAGE_TASK", False)
136
+
137
+ if bbox_task and language_task: # bbox and language tasks
138
+ seq_in_dim = (4+1) + (1+1)
139
+ elif bbox_task and not language_task: # bbox level
140
+ seq_in_dim = 4+1
141
+
142
+ N_steps = cfg.MODEL.DECODER.HIDDEN_DIM
143
+ if cfg.MODEL.DECODER.QUERY_POSITION_EMBEDDING in ('v2', 'sine'):
144
+ # TODO find a better way of exposing other arguments
145
+ position_embedding = PositionEmbeddingSine2D(N_steps, normalize=True)
146
+ elif cfg.MODEL.DECODER.QUERY_POSITION_EMBEDDING in ('v3', 'learned'):
147
+ position_embedding = PositionEmbeddingLearned(in_dim=seq_in_dim, out_dim=N_steps)
148
+ elif cfg.MODEL.DECODER.QUERY_POSITION_EMBEDDING in ('None', ):
149
+ print("Not using positional encoding.")
150
+ position_embedding = PositionEmbeddingNone(N_steps)
151
+ else:
152
+ raise ValueError(f"not supported {cfg.MODEL.DECODER.QUERY_POSITION_EMBEDDING}")
153
+
154
+ return position_embedding
lib/models/transformers/transformer.py ADDED
@@ -0,0 +1,498 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ from tkinter import N
3
+ from typing import Optional, List
4
+ import warnings
5
+ import torch
6
+ import torch.nn.functional as F
7
+ from torch import nn, Tensor
8
+ import math
9
+ from functools import partial
10
+ from timm.models.helpers import build_model_with_cfg, named_apply, adapt_input_conv
11
+ from timm.models.layers import Mlp, DropPath, trunc_normal_, lecun_normal_
12
+ from .position_encoding import build_memory_position_encoding, build_query_position_encoding
13
+
14
+ from lib.models.transformers.position_encoding import PositionEmbeddingNone,PositionEmbeddingLearned
15
+
16
+
17
+ def with_pos_embed(tensor, pos: Optional[Tensor]):
18
+ return tensor if pos is None else tensor + pos
19
+
20
+ class MultiheadAttention(nn.Module):
21
+ def __init__(self, dim, num_heads=8, qkv_bias=False, attn_drop=0., proj_drop=0.):
22
+ super().__init__()
23
+ self.num_heads = num_heads
24
+ head_dim = dim // num_heads
25
+ self.scale = head_dim ** -0.5
26
+
27
+ self.q = nn.Linear(dim, dim, bias=qkv_bias)
28
+ self.k = nn.Linear(dim, dim, bias=qkv_bias)
29
+ self.v = nn.Linear(dim, dim, bias=qkv_bias)
30
+
31
+ self.attn_drop = nn.Dropout(attn_drop)
32
+ self.proj = nn.Linear(dim, dim)
33
+
34
+
35
+ def forward(self, query, key, value=None,
36
+ attn_mask=None, key_padding_mask=None,
37
+ need_weights=False):
38
+ """
39
+ query: [B, N, C]
40
+ attn_mask: [N, N] torch.float32
41
+ key_padding_mask: [B, N] torch.bool
42
+ """
43
+ B, q_N, C = query.shape
44
+
45
+ if attn_mask is not None:
46
+ assert attn_mask.dtype == torch.float32 or attn_mask.dtype == torch.float64 or \
47
+ attn_mask.dtype == torch.float16 or attn_mask.dtype == torch.uint8 or attn_mask.dtype == torch.bool, \
48
+ 'Only float, byte, and bool types are supported for attn_mask, not {}'.format(attn_mask.dtype)
49
+ if attn_mask.dtype == torch.uint8:
50
+ warnings.warn("Byte tensor for attn_mask in nn.MultiheadAttention is deprecated. Use bool tensor instead.")
51
+ attn_mask = attn_mask.to(torch.bool)
52
+
53
+ if attn_mask.dim() == 2:
54
+ attn_mask = attn_mask.unsqueeze(0)
55
+ if list(attn_mask.size()) != [1, query.size(1), key.size(1)]:
56
+ raise RuntimeError('The size of the 2D attn_mask is not correct.')
57
+ elif attn_mask.dim() == 3:
58
+ if list(attn_mask.size()) != [B * self.num_heads, query.size(1), key.size(1)]:
59
+ raise RuntimeError('The size of the 3D attn_mask is not correct.')
60
+ else:
61
+ raise RuntimeError("attn_mask's dimension {} is not supported".format(attn_mask.dim()))
62
+ # attn_mask's dim is 3 now.
63
+
64
+ # convert key_padding_mask to bool
65
+ if key_padding_mask is not None and key_padding_mask.dtype == torch.uint8:
66
+ warnings.warn("Byte tensor for key_padding_mask in nn.MultiheadAttention is deprecated. Use bool tensor instead.")
67
+ key_padding_mask = key_padding_mask.to(torch.bool)
68
+
69
+ q = self.q(query).reshape(B, q_N, self.num_heads, C // self.num_heads).permute(0, 2, 1, 3) # B,head,HW,C/head
70
+ k = self.k(key).reshape(B, -1, self.num_heads, C // self.num_heads).permute(0, 2, 1, 3)
71
+ v = self.v(value).reshape(B, -1, self.num_heads, C // self.num_heads).permute(0, 2, 1, 3)
72
+
73
+ attn = (q @ k.transpose(-2, -1)) * self.scale # (B, head, N, N)
74
+
75
+ if attn_mask is not None:
76
+ if attn_mask.dtype == torch.bool:
77
+ attn.masked_fill_(attn_mask, float('-inf'))
78
+ else:
79
+ attn += attn_mask
80
+
81
+ if key_padding_mask is not None:
82
+ attn = attn.masked_fill(
83
+ key_padding_mask.unsqueeze(1).unsqueeze(2),
84
+ float('-inf'),
85
+ )
86
+
87
+ attn = attn.softmax(dim=-1)
88
+ attn = self.attn_drop(attn)
89
+
90
+ x = (attn @ v).transpose(1, 2).reshape(B, q_N, C)
91
+ x = self.proj(x)
92
+
93
+ if need_weights:
94
+ # average attention weights over heads
95
+ return x, attn.sum(dim=1) / self.num_heads # attn: (B, q_len, k_len)
96
+ else:
97
+ return x, None
98
+
99
+
100
+ class MLP(nn.Module):
101
+ """ MLP as used in Vision Transformer, MLP-Mixer and related networks
102
+ """
103
+ def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.): # nn.ReLU
104
+ super().__init__()
105
+ out_features = out_features or in_features
106
+ hidden_features = hidden_features or in_features
107
+ self.fc1 = nn.Linear(in_features, hidden_features)
108
+ self.act = act_layer()
109
+ self.drop = nn.Dropout(drop)
110
+ self.fc2 = nn.Linear(hidden_features, out_features)
111
+
112
+ def forward(self, x):
113
+ x = self.fc1(x)
114
+ x = self.act(x)
115
+ x = self.drop(x)
116
+ x = self.fc2(x)
117
+ return x
118
+
119
+
120
+ class TransformerDecoder(nn.Module):
121
+ def __init__(self, d_model=256, nhead=8, num_decoder_layers=0, mlp_ratio=1,
122
+ dropout=0., vocab_size=1001, memory_pos_embedding=None, query_pos_embedding=None):
123
+ super().__init__()
124
+ self.d_model = d_model
125
+ self.nhead = nhead
126
+ self.query_embedding = nn.Embedding(vocab_size, self.d_model) # (1001, 256)
127
+ self.memory_pos_embedding = memory_pos_embedding
128
+ self.query_pos_embedding = query_pos_embedding
129
+
130
+ decoder_layer = TransformerDecoderLayer(d_model=d_model, num_heads=nhead, mlp_ratio=mlp_ratio,
131
+ attn_drop=dropout, proj_drop=dropout)
132
+ if num_decoder_layers == 0:
133
+ self.layers = None
134
+ else:
135
+ self.layers = _get_clones(decoder_layer, num_decoder_layers)
136
+
137
+ self.num_decoder_layers = num_decoder_layers
138
+ self.scale_factor = float(d_model // nhead) ** 0.5
139
+
140
+ self.apply(self._init_weights)
141
+
142
+ def _init_weights(self, m):
143
+ if isinstance(m, nn.Linear):
144
+ trunc_normal_(m.weight, std=.02)
145
+ if isinstance(m, nn.Linear) and m.bias is not None:
146
+ nn.init.constant_(m.bias, 0)
147
+ elif isinstance(m, nn.LayerNorm):
148
+ nn.init.constant_(m.bias, 0)
149
+ nn.init.constant_(m.weight, 1.0)
150
+ elif isinstance(m, nn.Conv2d):
151
+ fan_out = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
152
+ fan_out = fan_out // m.groups
153
+ m.weight.data.normal_(0, math.sqrt(2.0 / fan_out))
154
+ if m.bias is not None:
155
+ m.bias.data.zero_()
156
+
157
+
158
+ def memory_mask_pos_enc(self, attn_mask, feat_sz):
159
+ """
160
+ attn_mask: (B, img_H, img_W)
161
+ feat_sz: feature size
162
+ """
163
+ batch_size = attn_mask.size(0)
164
+ attn_mask = attn_mask.to(torch.float32)
165
+ attn_mask = F.interpolate(attn_mask.unsqueeze(1), size=(feat_sz, feat_sz)).to(torch.bool).squeeze(1)
166
+
167
+ pos_embeds = self.memory_pos_embedding(attn_mask) # sine position encoding (B, C, feat_sz, feat_sz)
168
+
169
+ attn_mask = attn_mask.view(batch_size, -1)
170
+ pos_embeds = pos_embeds.view(batch_size, self.d_model, -1).transpose(1, 2)
171
+
172
+ return attn_mask, pos_embeds
173
+
174
+
175
+ def tri_mask(self, length):
176
+ mask = (torch.triu(torch.ones(length, length)) == 1).float().transpose(0, 1)
177
+ mask.masked_fill_(mask == 0, float('-inf'))
178
+ mask.masked_fill_(mask == 1, float(0.))
179
+ return mask
180
+
181
+
182
+ def forward(self, query, memory, memory_key_padding_mask, memory_pos,
183
+ return_intermediate_output=False, is_inference=False):
184
+ """
185
+ query: (B, 5, C) or (B, 18, C) or (B, bbox+mask, C)
186
+ memory: (B, HW, C)
187
+ memory_key_padding_mask: (B, HW)
188
+ memory_pos: (B, HW, C)
189
+ """
190
+ # learnable pos encoding
191
+ query_pos = self.query_pos_embedding(query)
192
+
193
+ query_mask = self.tri_mask(query.size(1)).to(query.device)
194
+
195
+ aux_logits = []
196
+ output = query
197
+ for i in range(len(self.layers)):
198
+ output, attn_weights = self.layers[i](output, memory,
199
+ query_pos=query_pos, memory_pos=memory_pos,
200
+ query_mask=query_mask,
201
+ memory_key_padding_mask=memory_key_padding_mask,
202
+ need_weights=False)
203
+ if return_intermediate_output and i < len(self.layers)-1:
204
+ aux_logits.append(output)
205
+
206
+ if is_inference:
207
+ return output
208
+ else:
209
+ return output, aux_logits
210
+
211
+
212
+ class TransformerDecoderLayer(nn.Module):
213
+ def __init__(self, d_model=256, num_heads=8, mlp_ratio=8,
214
+ attn_drop=0.1, proj_drop=0.1):
215
+ super().__init__()
216
+ # self_attn
217
+ # self.self_attn = MultiheadAttention(dim=d_model, num_heads=num_heads, attn_drop=attn_drop, proj_drop=proj_drop)
218
+ # self.dropout1 = nn.Dropout(proj_drop)
219
+ # self.norm1 = nn.LayerNorm(d_model)
220
+ #
221
+ # self.self_attn_det = MultiheadAttention(dim=d_model, num_heads=num_heads, attn_drop=attn_drop, proj_drop=proj_drop)
222
+ # self.dropout1_det = nn.Dropout(proj_drop)
223
+ # self.norm1_det = nn.LayerNorm(d_model)
224
+
225
+ # cross_attn
226
+ self.cross_attn = MultiheadAttention(dim=d_model, num_heads=num_heads, attn_drop=attn_drop, proj_drop=proj_drop)
227
+ self.dropout2 = nn.Dropout(proj_drop)
228
+ self.norm2 = nn.LayerNorm(d_model)
229
+
230
+ self.cross_attn_det = MultiheadAttention(dim=d_model, num_heads=num_heads, attn_drop=attn_drop, proj_drop=proj_drop)
231
+ self.dropout2_det = nn.Dropout(proj_drop)
232
+ self.norm2_det = nn.LayerNorm(d_model)
233
+
234
+ # mlp
235
+ dim_feedforward = d_model * mlp_ratio
236
+ self.MLP = MLP(in_features=d_model, hidden_features=dim_feedforward, out_features=d_model, drop=proj_drop)
237
+ self.dropout3 = nn.Dropout(proj_drop)
238
+ self.norm3 = nn.LayerNorm(d_model)
239
+
240
+ self.MLP_det = MLP(in_features=d_model, hidden_features=dim_feedforward, out_features=d_model, drop=proj_drop)
241
+ self.dropout3_det = nn.Dropout(proj_drop)
242
+ self.norm3_det = nn.LayerNorm(d_model)
243
+
244
+ # final
245
+ self.norm_final = nn.LayerNorm(d_model)
246
+
247
+
248
+ def forward(self, query, memory,
249
+ query_pos: Optional[Tensor] = None,
250
+ memory_pos: Optional[Tensor] = None,
251
+ query_mask: Optional[Tensor] = None,
252
+ memory_key_padding_mask: Optional[Tensor] = None,
253
+ need_weights: bool = False):
254
+ """
255
+ query: (B, 5, C)
256
+ memory: (B, HW, C)
257
+ query_pos: (B, 5, C)
258
+ memory_pos: (B, HW, C)
259
+ query_mask: (5,5)
260
+ memory_key_padding_mask: (B, HW)
261
+ """
262
+ # query self attn
263
+ # q = k = with_pos_embed(query, query_pos)
264
+ # query2, selfattn_weights = self.self_attn(q, k, value=query, attn_mask=query_mask, need_weights=need_weights)
265
+ # query = query + self.dropout1(query2)
266
+ # query = self.norm1(query)
267
+ #
268
+ # # memory self attn
269
+ # q = k = with_pos_embed(memory, memory_pos)
270
+ # query2, selfattn_weights = self.self_attn_det(q, k, value=memory, attn_mask=memory_key_padding_mask, need_weights=need_weights)
271
+ # memory = memory + self.dropout1_det(query2)
272
+ # memory = self.norm1_det(memory)
273
+
274
+ # query to memory
275
+ query2, crossattn_weights = self.cross_attn(query=with_pos_embed(query, query_pos),
276
+ key=with_pos_embed(memory, memory_pos),
277
+ value=memory,
278
+ key_padding_mask=memory_key_padding_mask,
279
+ need_weights=need_weights)
280
+ query = query + self.dropout2(query2)
281
+ query = self.norm2(query)
282
+
283
+ # memory to query
284
+ query2, crossattn_weights = self.cross_attn_det(query=with_pos_embed(memory, memory_pos),
285
+ key=with_pos_embed(query, query_pos),
286
+ value=query,
287
+ key_padding_mask=memory_key_padding_mask,
288
+ need_weights=need_weights)
289
+ memory = memory + self.dropout2_det(query2)
290
+ memory = self.norm2_det(memory)
291
+
292
+
293
+ # mlp
294
+ query2 = self.MLP(query)
295
+ query = query + self.dropout3(query2)
296
+ query = self.norm3(query)
297
+
298
+ memory = self.MLP_det(memory)
299
+ memory = memory + self.dropout3_det(memory)
300
+ memory = self.norm3_det(memory)
301
+
302
+ ### final fusion
303
+ final_x = query[:,4:] + memory[:,4:]
304
+ final = torch.cat([query[:,:4], memory[:,:4] , final_x ],dim=1)
305
+ query = self.norm_final(final)
306
+
307
+ if need_weights:
308
+ return query, crossattn_weights
309
+ else:
310
+ return query, None
311
+ class TransformerDecoder_v0(nn.Module):
312
+ def __init__(self, d_model=256, nhead=8, num_decoder_layers=0, mlp_ratio=1,
313
+ dropout=0.):
314
+ super().__init__()
315
+ self.d_model = d_model
316
+ self.nhead = nhead
317
+
318
+ decoder_layer = TransformerDecoderLayer(d_model=d_model, num_heads=nhead, mlp_ratio=mlp_ratio,
319
+ attn_drop=dropout, proj_drop=dropout)
320
+ if num_decoder_layers == 0:
321
+ self.layers = None
322
+ else:
323
+ self.layers = _get_clones(decoder_layer, num_decoder_layers)
324
+
325
+ self.num_decoder_layers = num_decoder_layers
326
+ self.scale_factor = float(d_model // nhead) ** 0.5
327
+
328
+ self.apply(self._init_weights)
329
+
330
+ def _init_weights(self, m):
331
+ if isinstance(m, nn.Linear):
332
+ trunc_normal_(m.weight, std=.02)
333
+ if isinstance(m, nn.Linear) and m.bias is not None:
334
+ nn.init.constant_(m.bias, 0)
335
+ elif isinstance(m, nn.LayerNorm):
336
+ nn.init.constant_(m.bias, 0)
337
+ nn.init.constant_(m.weight, 1.0)
338
+ elif isinstance(m, nn.Conv2d):
339
+ fan_out = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
340
+ fan_out = fan_out // m.groups
341
+ m.weight.data.normal_(0, math.sqrt(2.0 / fan_out))
342
+ if m.bias is not None:
343
+ m.bias.data.zero_()
344
+
345
+ def memory_mask_pos_enc(self, attn_mask, feat_sz):
346
+ """
347
+ attn_mask: (B, img_H, img_W)
348
+ feat_sz: feature size
349
+ """
350
+ batch_size = attn_mask.size(0)
351
+ attn_mask = attn_mask.to(torch.float32)
352
+ attn_mask = F.interpolate(attn_mask.unsqueeze(1), size=(feat_sz, feat_sz)).to(torch.bool).squeeze(1)
353
+
354
+ pos_embeds = self.memory_pos_embedding(attn_mask) # sine position encoding (B, C, feat_sz, feat_sz)
355
+
356
+ attn_mask = attn_mask.view(batch_size, -1)
357
+ pos_embeds = pos_embeds.view(batch_size, self.d_model, -1).transpose(1, 2)
358
+
359
+ return attn_mask, pos_embeds
360
+
361
+
362
+ def forward(self, query, memory, query_pos, memory_pos):
363
+ """
364
+ query: (B, 5, C) or (B, 18, C) or (B, bbox+mask, C)
365
+ memory: (B, HW, C)
366
+ memory_key_padding_mask: (B, HW)
367
+ memory_pos: (B, HW, C)
368
+ """
369
+ # learnable pos encoding
370
+ # query_pos = self.query_pos_embedding(query)
371
+
372
+ output = query
373
+ for i in range(len(self.layers)):
374
+ output, attn_weights = self.layers[i](output, memory,
375
+ query_pos=query_pos, memory_pos=memory_pos,
376
+ memory_key_padding_mask=None,
377
+ need_weights=False)
378
+
379
+
380
+ return output
381
+
382
+ class VisionLanguageFusionModule(nn.Module):
383
+ def __init__(self, dim, num_heads=8, qkv_bias=False, attn_drop=0., proj_drop=0., num_vlfusion_layers=0,
384
+ vl_input_type='separate'):
385
+ super().__init__()
386
+ # self.multihead_attn = MultiheadAttention(dim, num_heads=num_heads,
387
+ # qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=proj_drop)
388
+
389
+ self.vl_input_type = vl_input_type
390
+ VLFusion_layer = MultiheadAttention(dim, num_heads=num_heads,
391
+ qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=proj_drop)
392
+ if num_vlfusion_layers == 0:
393
+ self.VLFusion_layers = None
394
+ else:
395
+ self.VLFusion_layers = _get_clones(VLFusion_layer, num_vlfusion_layers)
396
+
397
+ def forward(self, query, memory,
398
+ query_pos: Optional[Tensor] = None,
399
+ memory_pos: Optional[Tensor] = None,
400
+ query_mask: Optional[Tensor] = None,
401
+ query_key_padding_mask: Optional[Tensor] = None,
402
+ memory_key_padding_mask: Optional[Tensor] = None,
403
+ need_weights: bool = False):
404
+
405
+ if self.vl_input_type == 'separate':
406
+ output = query
407
+ elif self.vl_input_type == 'concat':
408
+ output, query_pos = torch.cat([memory, query], dim=1), torch.cat([memory_pos, query_pos], dim=1)
409
+ memory, memory_pos = output.clone(), query_pos.clone()
410
+ memory_key_padding_mask = torch.cat([memory_key_padding_mask, query_key_padding_mask], dim=1)
411
+
412
+ for layer in self.VLFusion_layers:
413
+ output, attn_weights = layer(query=with_pos_embed(output, query_pos),
414
+ key=with_pos_embed(memory, memory_pos),
415
+ value=memory,
416
+ key_padding_mask=memory_key_padding_mask,
417
+ need_weights=need_weights) # attn_weights: (B, q_len, k_len)
418
+
419
+ output = query * output # todo: 残乘,应该是和前一个block的输出相乘吧,而不是始终和初始的输入相乘? 或者把这个放在 for循环外边
420
+
421
+
422
+ return output
423
+
424
+
425
+ def _get_clones(module, N):
426
+ return nn.ModuleList([copy.deepcopy(module) for i in range(N)])
427
+
428
+
429
+ def build_decoder(cfg):
430
+ memory_pos_embedding = build_memory_position_encoding(cfg)
431
+ query_pos_embedding = build_query_position_encoding(cfg)
432
+ return TransformerDecoder(
433
+ d_model=cfg.MODEL.DECODER.HIDDEN_DIM,
434
+ dropout=cfg.MODEL.DECODER.DROPOUT,
435
+ nhead=cfg.MODEL.DECODER.NUM_HEADS,
436
+ mlp_ratio=cfg.MODEL.DECODER.MLP_RATIO,
437
+ num_decoder_layers=cfg.MODEL.DECODER.DEC_LAYERS,
438
+ vocab_size=cfg.MODEL.DECODER.VOCAB_SIZE,
439
+ memory_pos_embedding=memory_pos_embedding,
440
+ query_pos_embedding=query_pos_embedding,
441
+ )
442
+
443
+ from lib.models.transformers.position_encoding import PositionEmbeddingNone,PositionEmbeddingLearned
444
+ def build_temporal_decoder(cfg):
445
+ memory_pos_embedding = PositionEmbeddingLearned(15,256)
446
+ query_pos_embedding = PositionEmbeddingLearned(15,256)
447
+ return TransformerDecoder_v0(
448
+ d_model=cfg.MODEL.DECODER.HIDDEN_DIM,
449
+ dropout=cfg.MODEL.DECODER.DROPOUT,
450
+ nhead=cfg.MODEL.DECODER.NUM_HEADS,
451
+ mlp_ratio=cfg.MODEL.DECODER.MLP_RATIO,
452
+ num_decoder_layers=2,
453
+ vocab_size=cfg.MODEL.DECODER.VOCAB_SIZE,
454
+ memory_pos_embedding=memory_pos_embedding,
455
+ query_pos_embedding=query_pos_embedding,
456
+ )
457
+
458
+ def build_text_prompt_decoder(cfg):
459
+ memory_pos_embedding = PositionEmbeddingLearned(15,512)
460
+ query_pos_embedding = PositionEmbeddingLearned(15,512)
461
+ return TransformerDecoder_v0(
462
+ d_model=512,
463
+ dropout=cfg.MODEL.DECODER.DROPOUT,
464
+ nhead=cfg.MODEL.DECODER.NUM_HEADS,
465
+ mlp_ratio=cfg.MODEL.DECODER.MLP_RATIO,
466
+ num_decoder_layers=2,
467
+ vocab_size=cfg.MODEL.DECODER.VOCAB_SIZE,
468
+ memory_pos_embedding=memory_pos_embedding,
469
+ query_pos_embedding=query_pos_embedding,
470
+ )
471
+
472
+ def build_img_prompt_decoder(cfg):
473
+ memory_pos_embedding = PositionEmbeddingLearned(15,256)
474
+ query_pos_embedding = PositionEmbeddingLearned(15,256)
475
+ return TransformerDecoder_v0(
476
+ d_model=cfg.MODEL.DECODER.HIDDEN_DIM,
477
+ dropout=cfg.MODEL.DECODER.DROPOUT,
478
+ nhead=8,
479
+ mlp_ratio=cfg.MODEL.DECODER.MLP_RATIO,
480
+ num_decoder_layers=2,
481
+ vocab_size=cfg.MODEL.DECODER.VOCAB_SIZE,
482
+ memory_pos_embedding=memory_pos_embedding,
483
+ query_pos_embedding=query_pos_embedding,
484
+ )
485
+
486
+
487
+ def build_rgb_det_decoder(cfg):
488
+ return TransformerDecoder_v0(
489
+ d_model=512,
490
+ dropout=0.1,
491
+ nhead=8,
492
+ mlp_ratio=1,
493
+ num_decoder_layers=1
494
+ )
495
+
496
+
497
+
498
+
lib/models/transformers/transformer_visual.py ADDED
@@ -0,0 +1,385 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
2
+ """
3
+ DETR Transformer class.
4
+
5
+ Copy-paste from torch.nn.Transformer with modifications:
6
+ * positional encodings are passed in MHattention
7
+ * extra LN at the end of encoder is removed
8
+ * decoder returns a stack of activations from all decoding layers
9
+ """
10
+ import copy
11
+ from typing import Optional
12
+ import torch
13
+ import torch.nn.functional as F
14
+ from torch import nn, Tensor
15
+
16
+ from lib.models.utils import QuickGELU
17
+
18
+
19
+ class Transformer(nn.Module):
20
+
21
+ def __init__(self, d_model=512, nhead=8, num_encoder_layers=6,
22
+ num_decoder_layers=6, dim_feedforward=2048, dropout=0.1,
23
+ activation="relu", normalize_before=False,
24
+ return_intermediate_dec=False):
25
+ super().__init__()
26
+
27
+ encoder_layer = TransformerEncoderLayer(d_model, nhead, dim_feedforward,
28
+ dropout, activation, normalize_before)
29
+ encoder_norm = nn.LayerNorm(d_model) if normalize_before else None
30
+ self.encoder = TransformerEncoder(encoder_layer, num_encoder_layers, encoder_norm)
31
+
32
+ if num_decoder_layers > 0:
33
+ decoder_layer = TransformerDecoderLayer(d_model, nhead, dim_feedforward,
34
+ dropout, activation, normalize_before)
35
+ decoder_norm = nn.LayerNorm(d_model)
36
+ self.decoder = TransformerDecoder(decoder_layer, num_decoder_layers, decoder_norm,
37
+ return_intermediate=return_intermediate_dec)
38
+ else:
39
+ self.decoder = None
40
+
41
+ self._reset_parameters()
42
+
43
+ self.d_model = d_model
44
+ self.nhead = nhead
45
+
46
+ def _reset_parameters(self):
47
+ for p in self.parameters():
48
+ if p.dim() > 1:
49
+ nn.init.xavier_uniform_(p)
50
+
51
+ def forward(self, src, mask, pos_embed, query_embed=None):
52
+ # flatten NxCxHxW to HWxNxC
53
+ # src = src.flatten(2).permute(2, 0, 1)
54
+ # pos_embed = pos_embed.flatten(2).permute(2, 0, 1)
55
+ # mask = mask.flatten(1)
56
+ memory = self.encoder(src, src_key_padding_mask=mask, pos=pos_embed)
57
+
58
+ if self.decoder is not None:
59
+ # query_embed = query_embed.unsqueeze(1).repeat(1, bs, 1)
60
+ tgt = torch.zeros_like(query_embed)
61
+ hs = self.decoder(tgt, memory, memory_key_padding_mask=mask,
62
+ pos=pos_embed, query_pos=query_embed)
63
+
64
+ return hs, memory
65
+ else:
66
+ return mask, memory
67
+
68
+
69
+ class TransformerEncOnly(nn.Module):
70
+
71
+ def __init__(self, d_model=512, nhead=8, num_encoder_layers=6,
72
+ dim_feedforward=2048, dropout=0.1, activation="relu", normalize_before=False):
73
+ super().__init__()
74
+
75
+ encoder_layer = TransformerEncoderLayer(d_model, nhead, dim_feedforward,
76
+ dropout, activation, normalize_before)
77
+ encoder_norm = nn.LayerNorm(d_model) if normalize_before else None
78
+ self.encoder = TransformerEncoder(encoder_layer, num_encoder_layers, encoder_norm)
79
+
80
+ self._reset_parameters()
81
+
82
+ self.d_model = d_model
83
+ self.nhead = nhead
84
+
85
+ def _reset_parameters(self):
86
+ for p in self.parameters():
87
+ if p.dim() > 1:
88
+ nn.init.xavier_uniform_(p)
89
+
90
+ def forward(self, src, mask, pos_embed):
91
+ # flatten NxCxHxW to HWxNxC
92
+ src = src.permute(1, 0, 2)
93
+ pos_embed = pos_embed.permute(1, 0, 2)
94
+
95
+ memory = self.encoder(src, src_key_padding_mask=mask, pos=pos_embed)
96
+
97
+ return memory.permute(1, 0,2)
98
+
99
+
100
+ class TransformerEncoder(nn.Module):
101
+
102
+ def __init__(self, encoder_layer, num_layers, norm=None):
103
+ super().__init__()
104
+ self.layers = _get_clones(encoder_layer, num_layers)
105
+ self.num_layers = num_layers
106
+ self.norm = norm
107
+
108
+ def forward(self, src,
109
+ mask: Optional[Tensor] = None,
110
+ src_key_padding_mask: Optional[Tensor] = None,
111
+ pos: Optional[Tensor] = None):
112
+ output = src
113
+
114
+ for layer in self.layers:
115
+ output = layer(output, src_mask=mask,
116
+ src_key_padding_mask=src_key_padding_mask, pos=pos)
117
+
118
+ if self.norm is not None:
119
+ output = self.norm(output)
120
+
121
+ return output
122
+
123
+
124
+ class TransformerDecoder(nn.Module):
125
+
126
+ def __init__(self, decoder_layer, num_layers, norm=None, return_intermediate=False):
127
+ super().__init__()
128
+ self.layers = _get_clones(decoder_layer, num_layers)
129
+ self.num_layers = num_layers
130
+ self.norm = norm
131
+ self.return_intermediate = return_intermediate
132
+
133
+ def forward(self, tgt, memory,
134
+ tgt_mask: Optional[Tensor] = None,
135
+ memory_mask: Optional[Tensor] = None,
136
+ tgt_key_padding_mask: Optional[Tensor] = None,
137
+ memory_key_padding_mask: Optional[Tensor] = None,
138
+ pos: Optional[Tensor] = None,
139
+ query_pos: Optional[Tensor] = None):
140
+ output = tgt
141
+
142
+ intermediate = []
143
+
144
+ for layer in self.layers:
145
+ output = layer(output, memory, tgt_mask=tgt_mask,
146
+ memory_mask=memory_mask,
147
+ tgt_key_padding_mask=tgt_key_padding_mask,
148
+ memory_key_padding_mask=memory_key_padding_mask,
149
+ pos=pos, query_pos=query_pos)
150
+ if self.return_intermediate:
151
+ intermediate.append(self.norm(output))
152
+
153
+ if self.norm is not None:
154
+ output = self.norm(output)
155
+ if self.return_intermediate:
156
+ intermediate.pop()
157
+ intermediate.append(output)
158
+
159
+ if self.return_intermediate:
160
+ return torch.stack(intermediate)
161
+
162
+ return output
163
+
164
+
165
+ class TransformerEncoderLayer(nn.Module):
166
+
167
+ def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1,
168
+ activation="relu", normalize_before=False):
169
+ """
170
+ args
171
+ """
172
+ super().__init__()
173
+ self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
174
+ # Implementation of Feedforward model
175
+ self.linear1 = nn.Linear(d_model, dim_feedforward)
176
+ self.dropout = nn.Dropout(dropout)
177
+ self.linear2 = nn.Linear(dim_feedforward, d_model)
178
+
179
+ self.norm1 = nn.LayerNorm(d_model)
180
+ self.norm2 = nn.LayerNorm(d_model)
181
+ self.dropout1 = nn.Dropout(dropout)
182
+ self.dropout2 = nn.Dropout(dropout)
183
+
184
+ self.activation = _get_activation_fn(activation)
185
+ self.normalize_before = normalize_before
186
+
187
+ def with_pos_embed(self, tensor, pos: Optional[Tensor]):
188
+ return tensor if pos is None else tensor + pos
189
+
190
+ def forward_post(self, src,
191
+ src_mask: Optional[Tensor] = None,
192
+ src_key_padding_mask: Optional[Tensor] = None,
193
+ pos: Optional[Tensor] = None):
194
+ q = k = self.with_pos_embed(src, pos)
195
+ src2 = self.self_attn(q, k, value=src, attn_mask=src_mask,
196
+ key_padding_mask=src_key_padding_mask)[0]
197
+ src = src + self.dropout1(src2)
198
+ src = self.norm1(src)
199
+ src2 = self.linear2(self.dropout(self.activation(self.linear1(src))))
200
+ src = src + self.dropout2(src2)
201
+ src = self.norm2(src)
202
+ return src
203
+
204
+ def forward_pre(self, src,
205
+ src_mask: Optional[Tensor] = None,
206
+ src_key_padding_mask: Optional[Tensor] = None,
207
+ pos: Optional[Tensor] = None):
208
+ src2 = self.norm1(src)
209
+ q = k = self.with_pos_embed(src2, pos)
210
+ src2 = self.self_attn(q, k, value=src2, attn_mask=src_mask,
211
+ key_padding_mask=src_key_padding_mask)[0]
212
+ src = src + self.dropout1(src2)
213
+ src2 = self.norm2(src)
214
+ src2 = self.linear2(self.dropout(self.activation(self.linear1(src2))))
215
+ src = src + self.dropout2(src2)
216
+ return src
217
+
218
+ def forward(self, src,
219
+ src_mask: Optional[Tensor] = None,
220
+ src_key_padding_mask: Optional[Tensor] = None,
221
+ pos: Optional[Tensor] = None):
222
+ if self.normalize_before:
223
+ return self.forward_pre(src, src_mask, src_key_padding_mask, pos)
224
+ return self.forward_post(src, src_mask, src_key_padding_mask, pos)
225
+
226
+
227
+ class TransformerDecoderLayer(nn.Module):
228
+
229
+ def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1,
230
+ activation="relu", normalize_before=False):
231
+ super().__init__()
232
+ self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
233
+ self.multihead_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
234
+ # Implementation of Feedforward model
235
+ self.linear1 = nn.Linear(d_model, dim_feedforward)
236
+ self.dropout = nn.Dropout(dropout)
237
+ self.linear2 = nn.Linear(dim_feedforward, d_model)
238
+
239
+ self.norm1 = nn.LayerNorm(d_model)
240
+ self.norm2 = nn.LayerNorm(d_model)
241
+ self.norm3 = nn.LayerNorm(d_model)
242
+ self.dropout1 = nn.Dropout(dropout)
243
+ self.dropout2 = nn.Dropout(dropout)
244
+ self.dropout3 = nn.Dropout(dropout)
245
+
246
+ self.activation = _get_activation_fn(activation)
247
+ self.normalize_before = normalize_before
248
+
249
+ def with_pos_embed(self, tensor, pos: Optional[Tensor]):
250
+ return tensor if pos is None else tensor + pos
251
+
252
+ def forward_post(self, tgt, memory,
253
+ tgt_mask: Optional[Tensor] = None,
254
+ memory_mask: Optional[Tensor] = None,
255
+ tgt_key_padding_mask: Optional[Tensor] = None,
256
+ memory_key_padding_mask: Optional[Tensor] = None,
257
+ pos: Optional[Tensor] = None,
258
+ query_pos: Optional[Tensor] = None):
259
+ q = k = self.with_pos_embed(tgt, query_pos)
260
+ tgt2 = self.self_attn(q, k, value=tgt, attn_mask=tgt_mask,
261
+ key_padding_mask=tgt_key_padding_mask)[0]
262
+ tgt = tgt + self.dropout1(tgt2)
263
+ tgt = self.norm1(tgt)
264
+ tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt, query_pos),
265
+ key=self.with_pos_embed(memory, pos),
266
+ value=memory, attn_mask=memory_mask,
267
+ key_padding_mask=memory_key_padding_mask)[0]
268
+ tgt = tgt + self.dropout2(tgt2)
269
+ tgt = self.norm2(tgt)
270
+ tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt))))
271
+ tgt = tgt + self.dropout3(tgt2)
272
+ tgt = self.norm3(tgt)
273
+ return tgt
274
+
275
+ def forward_pre(self, tgt, memory,
276
+ tgt_mask: Optional[Tensor] = None,
277
+ memory_mask: Optional[Tensor] = None,
278
+ tgt_key_padding_mask: Optional[Tensor] = None,
279
+ memory_key_padding_mask: Optional[Tensor] = None,
280
+ pos: Optional[Tensor] = None,
281
+ query_pos: Optional[Tensor] = None):
282
+ tgt2 = self.norm1(tgt)
283
+ q = k = self.with_pos_embed(tgt2, query_pos)
284
+ tgt2 = self.self_attn(q, k, value=tgt2, attn_mask=tgt_mask,
285
+ key_padding_mask=tgt_key_padding_mask)[0]
286
+ tgt = tgt + self.dropout1(tgt2)
287
+ tgt2 = self.norm2(tgt)
288
+ tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt2, query_pos),
289
+ key=self.with_pos_embed(memory, pos),
290
+ value=memory, attn_mask=memory_mask,
291
+ key_padding_mask=memory_key_padding_mask)[0]
292
+ tgt = tgt + self.dropout2(tgt2)
293
+ tgt2 = self.norm3(tgt)
294
+ tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt2))))
295
+ tgt = tgt + self.dropout3(tgt2)
296
+ return tgt
297
+
298
+ def forward(self, tgt, memory,
299
+ tgt_mask: Optional[Tensor] = None,
300
+ memory_mask: Optional[Tensor] = None,
301
+ tgt_key_padding_mask: Optional[Tensor] = None,
302
+ memory_key_padding_mask: Optional[Tensor] = None,
303
+ pos: Optional[Tensor] = None,
304
+ query_pos: Optional[Tensor] = None):
305
+ if self.normalize_before:
306
+ return self.forward_pre(tgt, memory, tgt_mask, memory_mask,
307
+ tgt_key_padding_mask, memory_key_padding_mask, pos, query_pos)
308
+ return self.forward_post(tgt, memory, tgt_mask, memory_mask,
309
+ tgt_key_padding_mask, memory_key_padding_mask, pos, query_pos)
310
+
311
+
312
+ def _get_clones(module, N):
313
+ return nn.ModuleList([copy.deepcopy(module) for i in range(N)])
314
+
315
+
316
+ def build_transformer(cfg):
317
+ return Transformer(
318
+ d_model=cfg.MODEL.VL.HIDDEN_DIM,
319
+ dropout=cfg.MODEL.VL.DROPOUT,
320
+ nhead=cfg.MODEL.VL.NHEAD,
321
+ dim_feedforward=cfg.MODEL.VL.DIM_FEEDFORWARD,
322
+ num_encoder_layers=cfg.MODEL.VL.ENC_LAYERS,
323
+ num_decoder_layers=cfg.MODEL.VL.DEC_LAYERS,
324
+ normalize_before=cfg.MODEL.VL.NORM_BEFORE,
325
+ return_intermediate_dec=cfg.MODEL.VL.RETURN_INTERMEDIATE,
326
+ activation=cfg.MODEL.VL.ACTIVATION
327
+ )
328
+
329
+ def build_temporal_encoder(cfg):
330
+ return TransformerEncOnly(d_model=cfg.MODEL.DECODER.HIDDEN_DIM,
331
+ nhead=8,
332
+ num_encoder_layers=2,
333
+ dim_feedforward=512, dropout=cfg.MODEL.DECODER.DROPOUT,
334
+ activation="GELU", normalize_before=False)
335
+
336
+ def build_decoder_by_transformer_encoder(cfg):
337
+ return TransformerEncOnly(d_model=cfg.MODEL.DECODER.HIDDEN_DIM,
338
+ nhead=8,
339
+ num_encoder_layers=6,
340
+ dim_feedforward=512, dropout=cfg.MODEL.DECODER.DROPOUT,
341
+ activation="GELU", normalize_before=False)
342
+
343
+ def build_visual_prompt_forward(cfg):
344
+ return TransformerEncOnly(d_model=cfg.MODEL.DECODER.HIDDEN_DIM,
345
+ nhead=cfg.MODEL.DECODER.NUM_HEADS,
346
+ num_encoder_layers=2,
347
+ dim_feedforward=512, dropout=cfg.MODEL.DECODER.DROPOUT,
348
+ activation="GELU", normalize_before=False)
349
+
350
+ def build_text_prompt_forward(cfg):
351
+ return TransformerEncOnly(d_model=cfg.MODEL.DECODER.HIDDEN_DIM,
352
+ nhead=cfg.MODEL.DECODER.NUM_HEADS,
353
+ num_encoder_layers=2,
354
+ dim_feedforward=512, dropout=cfg.MODEL.DECODER.DROPOUT,
355
+ activation="GELU", normalize_before=False)
356
+
357
+ def build_search_delate_template_forward(cfg):
358
+ return TransformerEncOnly(d_model=cfg.MODEL.DECODER.HIDDEN_DIM,
359
+ nhead=cfg.MODEL.DECODER.NUM_HEADS,
360
+ num_encoder_layers=2,
361
+ dim_feedforward=512, dropout=cfg.MODEL.DECODER.DROPOUT,
362
+ activation="GELU", normalize_before=False)
363
+
364
+ def build_decoder(cfg):
365
+ decoder_layer = TransformerDecoderLayer(d_model=cfg.MODEL.VL.HIDDEN_DIM, nhead=cfg.MODEL.VL.NHEAD,
366
+ dim_feedforward=cfg.MODEL.VL.DIM_FEEDFORWARD,
367
+ dropout=cfg.MODEL.VL.DROPOUT, activation=cfg.MODEL.VL.ACTIVATION,
368
+ normalize_before=cfg.MODEL.VL.NORM_BEFORE)
369
+ decoder_norm = nn.LayerNorm(cfg.MODEL.VL.HIDDEN_DIM)
370
+
371
+ return TransformerDecoder(decoder_layer, cfg.MODEL.VL.DEC_LAYERS, decoder_norm,
372
+ return_intermediate=cfg.MODEL.VL.RETURN_INTERMEDIATE)
373
+
374
+
375
+ def _get_activation_fn(activation):
376
+ """Return an activation function given a string"""
377
+ if activation == "RELU":
378
+ return F.relu
379
+ if activation == "GELU":
380
+ return F.gelu
381
+ if activation == "GLU":
382
+ return F.glu
383
+ elif activation == "QUICK_GELU":
384
+ return QuickGELU()
385
+ raise RuntimeError(F"activation should be RELU/GELU/GLU/QUICK_GELU, not {activation}.")
lib/test/__init__.py ADDED
File without changes