Upload ATCTrack-VLM code and selected checkpoints
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +5 -0
- QWEN_STATE_CURRENT_LOGIC.md +264 -0
- README.md +167 -0
- TRAIN_QWEN_STATE_GUIDE.md +405 -0
- VLT_environment_summary.md +223 -0
- asset/experiment.png +3 -0
- asset/framework.png +3 -0
- asset/motivation.png +3 -0
- checkpoint/ATCTrack_b.pth.tar +3 -0
- experiments/atctrack/atctrack_base.yaml +103 -0
- experiments/atctrack/atctrack_large.yaml +79 -0
- experiments/atctrack/atctrack_qwen_state.yaml +109 -0
- install.sh +108 -0
- lib/__init__.py +0 -0
- lib/config/__init__.py +0 -0
- lib/config/atctrack/config.py +184 -0
- lib/models/__init__.py +0 -0
- lib/models/aqatrack/__init__.py +1 -0
- lib/models/aqatrack/aqatrack.py +196 -0
- lib/models/aqatrack/base_backbone.py +142 -0
- lib/models/aqatrack/fast_itpn.py +1173 -0
- lib/models/aqatrack/hivit.py +270 -0
- lib/models/aqatrack/itpn.py +430 -0
- lib/models/aqatrack/utils.py +99 -0
- lib/models/atctrack/__init__.py +1 -0
- lib/models/atctrack/atctrack.py +1051 -0
- lib/models/atctrack/decoder.py +331 -0
- lib/models/atctrack/encoder.py +100 -0
- lib/models/atctrack/language_model.py +320 -0
- lib/models/atctrack/utils.py +64 -0
- lib/models/atctrack/vit.py +466 -0
- lib/models/atctrack/vit_mm.py +575 -0
- lib/models/layers/__init__.py +0 -0
- lib/models/layers/adapter.py +104 -0
- lib/models/layers/attn.py +128 -0
- lib/models/layers/attn_adapt_blocks.py +155 -0
- lib/models/layers/attn_blocks.py +122 -0
- lib/models/layers/dualstream_attn_blocks.py +152 -0
- lib/models/layers/frozen_bn.py +40 -0
- lib/models/layers/head.py +248 -0
- lib/models/layers/max_head.py +280 -0
- lib/models/layers/patch_embed.py +32 -0
- lib/models/layers/position_encoding.py +154 -0
- lib/models/layers/rpe.py +104 -0
- lib/models/layers/transformer_dec.py +415 -0
- lib/models/transformers/__init__.py +2 -0
- lib/models/transformers/position_encoding.py +154 -0
- lib/models/transformers/transformer.py +498 -0
- lib/models/transformers/transformer_visual.py +385 -0
- 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://arxiv.org/abs/2507.19875)
|
| 7 |
+
[](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 |
+

|
| 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 |
+

|
| 43 |
+
|
| 44 |
+
#### Strong performance
|
| 45 |
+
|
| 46 |
+

|
| 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 [](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
|
asset/framework.png
ADDED
|
Git LFS Details
|
asset/motivation.png
ADDED
|
Git LFS Details
|
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
|