├── README.md ├── config └── cod_resnet50.yaml ├── data └── voc2012 │ ├── voc2012_colors.txt │ └── voc2012_names.txt ├── images ├── framework.png ├── images.txt ├── res.png └── table.png ├── lib └── sync_bn │ ├── functions │ ├── __init__.py │ └── sync_bn.py │ ├── modules │ ├── __init__.py │ └── sync_bn.py │ └── src │ ├── __init__.py │ ├── cpu │ ├── operator.cpp │ ├── operator.h │ └── sync_bn.cpp │ └── gpu │ ├── common.h │ ├── device_tensor.h │ ├── operator.cpp │ ├── operator.h │ └── sync_bn_cuda.cu ├── model ├── __pycache__ │ ├── loss.cpython-36.pyc │ ├── pmm.cpython-36.pyc │ ├── position_encoding.cpython-36.pyc │ ├── pspnet.cpython-36.pyc │ ├── resnet.cpython-36.pyc │ ├── resnet.cpython-37.pyc │ ├── transformer.cpython-36.pyc │ ├── ugtr.cpython-36.pyc │ └── ugtr.cpython-37.pyc ├── loss.py ├── pmm.py ├── position_encoding.py ├── resnet.py ├── transformer.py └── ugtr.py ├── model_file └── model.txt ├── pre_trained └── model.txt ├── test.py ├── train.py ├── train_test_file ├── CAMO_test.lst ├── CHAMELEON_test.lst ├── COD10K_test.lst ├── NC4K_test.lst └── train.lst └── util ├── __pycache__ ├── config.cpython-36.pyc ├── config.cpython-37.pyc ├── dataset.cpython-36.pyc ├── dataset.cpython-37.pyc ├── transform.cpython-36.pyc ├── transform.cpython-37.pyc ├── util.cpython-36.pyc └── util.cpython-37.pyc ├── config.py ├── dataset.py ├── transform.py └── util.py /README.md: -------------------------------------------------------------------------------- 1 | # Uncertainty-Guided Transformer Reasoning for Camouflaged Object Detection (ICCV2021) 2 | 3 | > Authors: 4 | > [Fan Yang](https://scholar.google.com/citations?user=FSfSgwQAAAAJ&hl=en), 5 | > [Qiang Zhai](https://github.com/cvqiang/mgl), 6 | > [Xin Li](https://scholar.google.com/citations?user=TK-hRO8AAAAJ&hl=en), 7 | > Rui Huang, 8 | > [Hong Cheng](https://scholar.google.com/citations?user=-845MAcAAAAJ&hl=zh-CN), 9 | > [Deng-Ping Fan](https://dpfan.net/). 10 | 11 | ![](images/framework.png) 12 | 13 | 1. Configuring your environment (Prerequisites): 14 | 15 | Pytorch>=1.0.0 16 | 17 | OpenCV 18 | 19 | 20 | 2. Downloading Testing Sets: 21 | + downloading _**NEW testing dataset**_ (COD10K-test + CAMO-test + CHAMELEON), which can be found in this [Google Drive link](https://drive.google.com/file/d/1QEGnP9O7HbN_2tH999O3HRIsErIVYalx/view?usp=sharing) or [Baidu Pan link](https://pan.baidu.com/s/143yHFLAabMBT7wgXA0LrMg) with the fetch code: z83z. 22 | 23 | 3. Testing Configuration: 24 | 25 | + After you download the trained models [Google Drive link](https://drive.google.com/file/d/1RFdqvzMZMzi6VdVl_8-sMgWT0Os-E9tE/view?usp=sharing) or [Baidu Pan link](https://pan.baidu.com/s/16WRL_J6C7_Wq4d1spgfj5g?pwd=9f0u), move it into './model_file/'. 26 | + Assigning your comstomed path in 'config/cod_resnet50.yaml', like 'data_root', 'test_list'. 27 | + Playing 'test.py' to generate the final prediction map, the predicted camouflaged object region and cmouflaged object edge is saved into 'result' as default. 28 | 29 | 5. Evaluation your trained model: 30 | 31 | + One-key evaluation is written in MATLAB code (revised from [link](https://github.com/DengPingFan/CODToolbox)), 32 | please follow this the instructions in `main.m` and just run it to generate the evaluation results in 33 | `./EvaluationTool/EvaluationResults/Result-CamObjDet/`. 34 | + The results can be downloaded in [Baidu Pan link](https://pan.baidu.com/s/1gA-Rf9oqQK8vfXamemSxlw?pwd=2kj3)(password: 2kj3). 35 | 36 | ![](images/table.png) 37 | 38 | ![](images/res.png) 39 | 40 | 6. Training Configuration: 41 | + After you download the initial model [Google Drive link](https://drive.google.com/file/d/17WYyKg40DkAgFWOusiAKgqZOlfUFzjn5/view?usp=sharing) or [Baidu Pan link](https://pan.baidu.com/s/1BqNRkCWxgvVd7-uGh8IN1Q?pwd=heb7), move it to './pre_trained/'. 42 | + Put the 'train_test_file/train.lst' to the path which is included in cod_resnet50.yaml. 43 | + Run train.py 44 | 45 | 6. If you think this work is helpful, please cite 46 | 47 | ``` 48 | @inproceedings{fan2021ugtr, 49 | title={Uncertainty-Guided Transformer Reasoning for Camouflaged Object Detection}, 50 | author={Yang, Fan and Zhai, Qiang and Li, Xin and Huang, Rui and Cheng, Hong and Fan, Deng-Ping}, 51 | booktitle={IEEE International Conference on Computer Vision(ICCV)}, 52 | pages={}, 53 | year={2021} 54 | } 55 | ``` 56 | -------------------------------------------------------------------------------- /config/cod_resnet50.yaml: -------------------------------------------------------------------------------- 1 | DATA: 2 | data_root: /raid/workspace/loc_toy/dataset/cod/ 3 | train_list: /raid/workspace/loc_toy/dataset/cod/COD_train/train.lst 4 | val_list: /raid/workspace/loc_toy/dataset/cod/COD10K_test/test.lst 5 | classes: 1 6 | 7 | TRAIN: 8 | num_clusters: 32 9 | mode: #cluster # clustering before training 10 | threads: 4 11 | cacheBatchSize: 16 12 | arch: ugtr 13 | layers: 50 14 | sync_bn: True # adopt sync_bn or not 15 | train_h: 473 16 | train_w: 473 17 | scale_min: 0.5 # minimum random scale 18 | scale_max: 2.0 # maximum random scale 19 | rotate_min: -90 #-10 # minimum random rotate 20 | rotate_max: 90 #10 # maximum random rotate 21 | zoom_factor: 8 # zoom factor for final prediction during training, be in [1, 2, 4, 8] 22 | ignore_label: 0 # 255 23 | aux_weight: 0.4 24 | train_gpu: [1, 2, 3, 4, 5] 25 | workers: 16 # data loader workers 26 | batch_size: 20 #12 # batch size for training 27 | batch_size_val: 36 # batch size for validation during training, memory and speed tradeoff 28 | base_lr: 0.000000001 29 | epochs: 1000 #500 #200 #50 30 | start_epoch: 0 31 | power: 0.9 32 | momentum: 0.9 33 | weight_decay: 0.0001 34 | manual_seed: 35 | print_freq: 20 36 | save_freq: 5 37 | save_path: model_file 38 | weight: pre_trained/resnet50_v1.pth 39 | resume: 40 | evaluate: True #False # evaluate on validation set, extra gpu memory needed and small batch_size_val is recommend 41 | 42 | Distributed: 43 | dist_url: tcp://127.0.0.1:6789 44 | dist_backend: 'nccl' 45 | multiprocessing_distributed: True 46 | world_size: 1 47 | rank: 0 48 | use_apex: True 49 | opt_level: 'O0' 50 | keep_batchnorm_fp32: 51 | loss_scale: 52 | 53 | TEST: 54 | test_list: /raid/workspace/loc_toy/dataset/cod/COD10K_test/test.lst 55 | #test_list: /raid/workspace/loc_toy/dataset/cod/CAMO_test/test.lst 56 | #test_list: /raid/workspace/loc_toy/dataset/cod/CHAMELEON/test.lst 57 | #test_list: /raid/workspace/loc_toy/dataset/cod/NC4K/test.lst 58 | split: val # split in [train, val and test] 59 | base_size: 473 # based size for scaling 60 | test_h: 473 61 | test_w: 473 62 | scales: [1.0] # evaluation scales, ms as [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] 63 | test_batch_size: 1 64 | has_prediction: False # has prediction already or not 65 | index_start: 0 # evaluation start index in list 66 | index_step: 0 # evaluation step index in list, 0 means to end 67 | test_gpu: [10] 68 | model_path: model_file/ugtr.pth 69 | save_folder: result/ # results save folder 70 | colors_path: data/voc2012/voc2012_colors.txt # path of dataset colors 71 | names_path: data/voc2012/voc2012_names.txt # path of dataset category names 72 | -------------------------------------------------------------------------------- /data/voc2012/voc2012_colors.txt: -------------------------------------------------------------------------------- 1 | 0 0 0 2 | 128 0 0 3 | 0 128 0 4 | 128 128 0 5 | 0 0 128 6 | 128 0 128 7 | 0 128 128 8 | 128 128 128 9 | 64 0 0 10 | 192 0 0 11 | 64 128 0 12 | 192 128 0 13 | 64 0 128 14 | 192 0 128 15 | 64 128 128 16 | 192 128 128 17 | 0 64 0 18 | 128 64 0 19 | 0 192 0 20 | 128 192 0 21 | 0 64 128 22 | -------------------------------------------------------------------------------- /data/voc2012/voc2012_names.txt: -------------------------------------------------------------------------------- 1 | background 2 | aeroplane 3 | bicycle 4 | bird 5 | boat 6 | bottle 7 | bus 8 | car 9 | cat 10 | chair 11 | cow 12 | diningtable 13 | dog 14 | horse 15 | motorbike 16 | person 17 | pottedplant 18 | sheep 19 | sofa 20 | train 21 | tvmonitor 22 | -------------------------------------------------------------------------------- /images/framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/images/framework.png -------------------------------------------------------------------------------- /images/images.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/images/images.txt -------------------------------------------------------------------------------- /images/res.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/images/res.png -------------------------------------------------------------------------------- /images/table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/images/table.png -------------------------------------------------------------------------------- /lib/sync_bn/functions/__init__.py: -------------------------------------------------------------------------------- 1 | from .sync_bn import * 2 | -------------------------------------------------------------------------------- /lib/sync_bn/functions/sync_bn.py: -------------------------------------------------------------------------------- 1 | ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 | ## Created by: Hang Zhang 3 | ## Email: zhanghang0704@gmail.com 4 | ## Copyright (c) 2018 5 | ## 6 | ## This source code is licensed under the MIT-style license found in the 7 | ## LICENSE file in the root directory of this source tree 8 | ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 9 | 10 | """Synchronized Cross-GPU Batch Normalization functions""" 11 | import torch 12 | import torch.cuda.comm as comm 13 | from torch.autograd import Function 14 | from torch.autograd.function import once_differentiable 15 | from .. import src 16 | 17 | __all__ = ['moments', 'syncbatchnorm', 'inp_syncbatchnorm'] 18 | 19 | class moments(Function): 20 | @staticmethod 21 | def forward(ctx, x): 22 | if x.is_cuda: 23 | ex, ex2 = src.gpu.expectation_forward(x) 24 | else: 25 | raise NotImplemented 26 | return ex, ex2 27 | 28 | @staticmethod 29 | def backward(ctx, x, dex, dex2): 30 | if x.is_cuda: 31 | dx = src.gpu.expectation_backward(x, dex, dex2) 32 | else: 33 | raise NotImplemented 34 | return dx 35 | 36 | class syncbatchnorm_(Function): 37 | @classmethod 38 | def forward(cls, ctx, x, gamma, beta, running_mean, running_var, 39 | extra, sync=True, training=True, momentum=0.1, eps=1e-05, 40 | activation="none", slope=0.01): 41 | # save context 42 | cls._parse_extra(ctx, extra) 43 | ctx.sync = sync 44 | ctx.training = training 45 | ctx.momentum = momentum 46 | ctx.eps = eps 47 | ctx.activation = activation 48 | ctx.slope = slope 49 | assert activation == 'none' 50 | 51 | # continous inputs 52 | x = x.contiguous() 53 | gamma = gamma.contiguous() 54 | beta = beta.contiguous() 55 | 56 | if ctx.training: 57 | if x.is_cuda: 58 | _ex, _exs = src.gpu.expectation_forward(x) 59 | else: 60 | raise NotImplemented 61 | 62 | if ctx.sync: 63 | if ctx.is_master: 64 | _ex, _exs = [_ex.unsqueeze(0)], [_exs.unsqueeze(0)] 65 | for _ in range(ctx.master_queue.maxsize): 66 | _ex_w, _exs_w = ctx.master_queue.get() 67 | ctx.master_queue.task_done() 68 | _ex.append(_ex_w.unsqueeze(0)) 69 | _exs.append(_exs_w.unsqueeze(0)) 70 | 71 | _ex = comm.gather(_ex).mean(0) 72 | _exs = comm.gather(_exs).mean(0) 73 | 74 | tensors = comm.broadcast_coalesced((_ex, _exs), [_ex.get_device()] + ctx.worker_ids) 75 | for ts, queue in zip(tensors[1:], ctx.worker_queues): 76 | queue.put(ts) 77 | else: 78 | ctx.master_queue.put((_ex, _exs)) 79 | _ex, _exs = ctx.worker_queue.get() 80 | ctx.worker_queue.task_done() 81 | 82 | # Update running stats 83 | _var = _exs - _ex ** 2 84 | running_mean.mul_((1 - ctx.momentum)).add_(ctx.momentum * _ex) 85 | running_var.mul_((1 - ctx.momentum)).add_(ctx.momentum * _var) 86 | 87 | # Mark in-place modified tensors 88 | ctx.mark_dirty(running_mean, running_var) 89 | else: 90 | _ex, _var = running_mean.contiguous(), running_var.contiguous() 91 | _exs = _var + _ex ** 2 92 | 93 | # BN forward + activation 94 | if x.is_cuda: 95 | y = src.gpu.batchnorm_forward(x, _ex, _exs, gamma, beta, ctx.eps) 96 | else: 97 | y = src.cpu.batchnorm_forward(x, _ex, _exs, gamma, beta, ctx.eps) 98 | 99 | # Output 100 | ctx.save_for_backward(x, _ex, _exs, gamma, beta) 101 | return y 102 | 103 | @staticmethod 104 | @once_differentiable 105 | def backward(ctx, dz): 106 | x, _ex, _exs, gamma, beta = ctx.saved_tensors 107 | dz = dz.contiguous() 108 | 109 | # BN backward 110 | if dz.is_cuda: 111 | dx, _dex, _dexs, dgamma, dbeta = \ 112 | src.gpu.batchnorm_backward(dz, x, _ex, _exs, gamma, beta, ctx.eps) 113 | else: 114 | raise NotImplemented 115 | 116 | if ctx.training: 117 | if ctx.sync: 118 | if ctx.is_master: 119 | _dex, _dexs = [_dex.unsqueeze(0)], [_dexs.unsqueeze(0)] 120 | for _ in range(ctx.master_queue.maxsize): 121 | _dex_w, _dexs_w = ctx.master_queue.get() 122 | ctx.master_queue.task_done() 123 | _dex.append(_dex_w.unsqueeze(0)) 124 | _dexs.append(_dexs_w.unsqueeze(0)) 125 | 126 | _dex = comm.gather(_dex).mean(0) 127 | _dexs = comm.gather(_dexs).mean(0) 128 | 129 | tensors = comm.broadcast_coalesced((_dex, _dexs), [_dex.get_device()] + ctx.worker_ids) 130 | for ts, queue in zip(tensors[1:], ctx.worker_queues): 131 | queue.put(ts) 132 | else: 133 | ctx.master_queue.put((_dex, _dexs)) 134 | _dex, _dexs = ctx.worker_queue.get() 135 | ctx.worker_queue.task_done() 136 | 137 | if x.is_cuda: 138 | dx_ = src.gpu.expectation_backward(x, _dex, _dexs) 139 | else: 140 | raise NotImplemented 141 | dx = dx + dx_ 142 | 143 | return dx, dgamma, dbeta, None, None, None, None, None, None, None, None, None 144 | 145 | @staticmethod 146 | def _parse_extra(ctx, extra): 147 | ctx.is_master = extra["is_master"] 148 | if ctx.is_master: 149 | ctx.master_queue = extra["master_queue"] 150 | ctx.worker_queues = extra["worker_queues"] 151 | ctx.worker_ids = extra["worker_ids"] 152 | else: 153 | ctx.master_queue = extra["master_queue"] 154 | ctx.worker_queue = extra["worker_queue"] 155 | 156 | def _act_forward(ctx, x): 157 | if ctx.activation.lower() == "leaky_relu": 158 | if x.is_cuda: 159 | src.gpu.leaky_relu_forward(x, ctx.slope) 160 | else: 161 | raise NotImplemented 162 | else: 163 | assert ctx.activation == 'none' 164 | 165 | def _act_backward(ctx, x, dx): 166 | if ctx.activation.lower() == "leaky_relu": 167 | if x.is_cuda: 168 | src.gpu.leaky_relu_backward(x, dx, ctx.slope) 169 | else: 170 | raise NotImplemented 171 | else: 172 | assert ctx.activation == 'none' 173 | 174 | class inp_syncbatchnorm_(Function): 175 | @classmethod 176 | def forward(cls, ctx, x, gamma, beta, running_mean, running_var, 177 | extra, sync=True, training=True, momentum=0.1, eps=1e-05, 178 | activation="none", slope=0.01): 179 | # save context 180 | cls._parse_extra(ctx, extra) 181 | ctx.sync = sync 182 | ctx.training = training 183 | ctx.momentum = momentum 184 | ctx.eps = eps 185 | ctx.activation = activation 186 | ctx.slope = slope 187 | 188 | # continous inputs 189 | x = x.contiguous() 190 | gamma = gamma.contiguous() 191 | beta = beta.contiguous() 192 | 193 | if ctx.training: 194 | if x.is_cuda: 195 | _ex, _exs = src.gpu.expectation_forward(x) 196 | else: 197 | raise NotImplemented 198 | 199 | if ctx.sync: 200 | if ctx.is_master: 201 | _ex, _exs = [_ex.unsqueeze(0)], [_exs.unsqueeze(0)] 202 | for _ in range(ctx.master_queue.maxsize): 203 | _ex_w, _exs_w = ctx.master_queue.get() 204 | ctx.master_queue.task_done() 205 | _ex.append(_ex_w.unsqueeze(0)) 206 | _exs.append(_exs_w.unsqueeze(0)) 207 | 208 | _ex = comm.gather(_ex).mean(0) 209 | _exs = comm.gather(_exs).mean(0) 210 | 211 | tensors = comm.broadcast_coalesced((_ex, _exs), [_ex.get_device()] + ctx.worker_ids) 212 | for ts, queue in zip(tensors[1:], ctx.worker_queues): 213 | queue.put(ts) 214 | else: 215 | ctx.master_queue.put((_ex, _exs)) 216 | _ex, _exs = ctx.worker_queue.get() 217 | ctx.worker_queue.task_done() 218 | 219 | # Update running stats 220 | _var = _exs - _ex ** 2 221 | running_mean.mul_((1 - ctx.momentum)).add_(ctx.momentum * _ex) 222 | running_var.mul_((1 - ctx.momentum)).add_(ctx.momentum * _var) 223 | 224 | # Mark in-place modified tensors 225 | ctx.mark_dirty(x, running_mean, running_var) 226 | else: 227 | _ex, _var = running_mean.contiguous(), running_var.contiguous() 228 | _exs = _var + _ex ** 2 229 | ctx.mark_dirty(x) 230 | 231 | # BN forward + activation 232 | if x.is_cuda: 233 | src.gpu.batchnorm_inp_forward(x, _ex, _exs, gamma, beta, ctx.eps) 234 | else: 235 | raise NotImplemented 236 | 237 | _act_forward(ctx, x) 238 | 239 | # Output 240 | ctx.save_for_backward(x, _ex, _exs, gamma, beta) 241 | return x 242 | 243 | @staticmethod 244 | @once_differentiable 245 | def backward(ctx, dz): 246 | z, _ex, _exs, gamma, beta = ctx.saved_tensors 247 | dz = dz.contiguous() 248 | 249 | # Undo activation 250 | _act_backward(ctx, z, dz) 251 | 252 | # BN backward 253 | if dz.is_cuda: 254 | dx, _dex, _dexs, dgamma, dbeta = \ 255 | src.gpu.batchnorm_inp_backward(dz, z, _ex, _exs, gamma, beta, ctx.eps) 256 | else: 257 | raise NotImplemented 258 | 259 | if ctx.training: 260 | if ctx.sync: 261 | if ctx.is_master: 262 | _dex, _dexs = [_dex.unsqueeze(0)], [_dexs.unsqueeze(0)] 263 | for _ in range(ctx.master_queue.maxsize): 264 | _dex_w, _dexs_w = ctx.master_queue.get() 265 | ctx.master_queue.task_done() 266 | _dex.append(_dex_w.unsqueeze(0)) 267 | _dexs.append(_dexs_w.unsqueeze(0)) 268 | 269 | _dex = comm.gather(_dex).mean(0) 270 | _dexs = comm.gather(_dexs).mean(0) 271 | 272 | tensors = comm.broadcast_coalesced((_dex, _dexs), [_dex.get_device()] + ctx.worker_ids) 273 | for ts, queue in zip(tensors[1:], ctx.worker_queues): 274 | queue.put(ts) 275 | else: 276 | ctx.master_queue.put((_dex, _dexs)) 277 | _dex, _dexs = ctx.worker_queue.get() 278 | ctx.worker_queue.task_done() 279 | 280 | if z.is_cuda: 281 | src.gpu.expectation_inp_backward(dx, z, _dex, _dexs, _ex, _exs, gamma, beta, ctx.eps) 282 | else: 283 | raise NotImplemented 284 | 285 | return dx, dgamma, dbeta, None, None, None, None, None, None, None, None, None 286 | 287 | @staticmethod 288 | def _parse_extra(ctx, extra): 289 | ctx.is_master = extra["is_master"] 290 | if ctx.is_master: 291 | ctx.master_queue = extra["master_queue"] 292 | ctx.worker_queues = extra["worker_queues"] 293 | ctx.worker_ids = extra["worker_ids"] 294 | else: 295 | ctx.master_queue = extra["master_queue"] 296 | ctx.worker_queue = extra["worker_queue"] 297 | 298 | syncbatchnorm = syncbatchnorm_.apply 299 | inp_syncbatchnorm = inp_syncbatchnorm_.apply 300 | -------------------------------------------------------------------------------- /lib/sync_bn/modules/__init__.py: -------------------------------------------------------------------------------- 1 | from .sync_bn import * 2 | -------------------------------------------------------------------------------- /lib/sync_bn/modules/sync_bn.py: -------------------------------------------------------------------------------- 1 | ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 | ## Created by: Hang Zhang 3 | ## ECE Department, Rutgers University 4 | ## Email: zhang.hang@rutgers.edu 5 | ## Copyright (c) 2017 6 | ## 7 | ## This source code is licensed under the MIT-style license found in the 8 | ## LICENSE file in the root directory of this source tree 9 | ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 10 | 11 | """Synchronized Cross-GPU Batch Normalization Module""" 12 | import warnings 13 | try: 14 | from queue import Queue 15 | except ImportError: 16 | from Queue import Queue 17 | 18 | import torch 19 | from torch.nn.modules.batchnorm import _BatchNorm 20 | 21 | from ..functions import * 22 | 23 | 24 | __all__ = ['SyncBatchNorm', 'BatchNorm1d', 'BatchNorm2d', 'BatchNorm3d'] 25 | 26 | 27 | class SyncBatchNorm(_BatchNorm): 28 | r"""Cross-GPU Synchronized Batch normalization (SyncBN) 29 | 30 | Standard BN [1]_ implementation only normalize the data within each device (GPU). 31 | SyncBN normalizes the input within the whole mini-batch. 32 | We follow the sync-onece implmentation described in the paper [2]_ . 33 | Please see the design idea in the `notes <./notes/syncbn.html>`_. 34 | 35 | .. math:: 36 | 37 | y = \frac{x - mean[x]}{ \sqrt{Var[x] + \epsilon}} * gamma + beta 38 | 39 | The mean and standard-deviation are calculated per-channel over 40 | the mini-batches and gamma and beta are learnable parameter vectors 41 | of size C (where C is the input size). 42 | 43 | During training, this layer keeps a running estimate of its computed mean 44 | and variance. The running sum is kept with a default momentum of 0.1. 45 | 46 | During evaluation, this running mean/variance is used for normalization. 47 | 48 | Because the BatchNorm is done over the `C` dimension, computing statistics 49 | on `(N, H, W)` slices, it's common terminology to call this Spatial BatchNorm 50 | 51 | Args: 52 | num_features: num_features from an expected input of 53 | size batch_size x num_features x height x width 54 | eps: a value added to the denominator for numerical stability. 55 | Default: 1e-5 56 | momentum: the value used for the running_mean and running_var 57 | computation. Default: 0.1 58 | sync: a boolean value that when set to ``True``, synchronize across 59 | different gpus. Default: ``True`` 60 | activation : str 61 | Name of the activation functions, one of: `leaky_relu` or `none`. 62 | slope : float 63 | Negative slope for the `leaky_relu` activation. 64 | 65 | Shape: 66 | - Input: :math:`(N, C, H, W)` 67 | - Output: :math:`(N, C, H, W)` (same shape as input) 68 | 69 | Reference: 70 | .. [1] Ioffe, Sergey, and Christian Szegedy. "Batch normalization: Accelerating deep network training by reducing internal covariate shift." *ICML 2015* 71 | .. [2] Hang Zhang, Kristin Dana, Jianping Shi, Zhongyue Zhang, Xiaogang Wang, Ambrish Tyagi, and Amit Agrawal. "Context Encoding for Semantic Segmentation." *CVPR 2018* 72 | 73 | Examples: 74 | >>> m = SyncBatchNorm(100) 75 | >>> net = torch.nn.DataParallel(m) 76 | >>> output = net(input) 77 | """ 78 | 79 | def __init__(self, num_features, eps=1e-5, momentum=0.1, sync=True, activation="none", slope=0.01, 80 | inplace=True): 81 | super(SyncBatchNorm, self).__init__(num_features, eps=eps, momentum=momentum, affine=True) 82 | self.activation = activation 83 | self.inplace = False if activation == 'none' else inplace 84 | #self.inplace = inplace 85 | self.slope = slope 86 | self.devices = list(range(torch.cuda.device_count())) 87 | self.sync = sync if len(self.devices) > 1 else False 88 | # Initialize queues 89 | self.worker_ids = self.devices[1:] 90 | self.master_queue = Queue(len(self.worker_ids)) 91 | self.worker_queues = [Queue(1) for _ in self.worker_ids] 92 | # running_exs 93 | #self.register_buffer('running_exs', torch.ones(num_features)) 94 | 95 | def forward(self, x): 96 | # Resize the input to (B, C, -1). 97 | input_shape = x.size() 98 | x = x.view(input_shape[0], self.num_features, -1) 99 | if x.get_device() == self.devices[0]: 100 | # Master mode 101 | extra = { 102 | "is_master": True, 103 | "master_queue": self.master_queue, 104 | "worker_queues": self.worker_queues, 105 | "worker_ids": self.worker_ids 106 | } 107 | else: 108 | # Worker mode 109 | extra = { 110 | "is_master": False, 111 | "master_queue": self.master_queue, 112 | "worker_queue": self.worker_queues[self.worker_ids.index(x.get_device())] 113 | } 114 | if self.inplace: 115 | return inp_syncbatchnorm(x, self.weight, self.bias, self.running_mean, self.running_var, 116 | extra, self.sync, self.training, self.momentum, self.eps, 117 | self.activation, self.slope).view(input_shape) 118 | else: 119 | return syncbatchnorm(x, self.weight, self.bias, self.running_mean, self.running_var, 120 | extra, self.sync, self.training, self.momentum, self.eps, 121 | self.activation, self.slope).view(input_shape) 122 | 123 | def extra_repr(self): 124 | if self.activation == 'none': 125 | return 'sync={}'.format(self.sync) 126 | else: 127 | return 'sync={}, act={}, slope={}, inplace={}'.format( 128 | self.sync, self.activation, self.slope, self.inplace 129 | ) 130 | 131 | class BatchNorm1d(SyncBatchNorm): 132 | r""" 133 | .. warning:: 134 | BatchNorm1d is deprecated in favor of :class:`encoding.nn.SyncBatchNorm`. 135 | """ 136 | def __init__(self, *args, **kwargs): 137 | super(BatchNorm1d, self).__init__(*args, **kwargs) 138 | 139 | class BatchNorm2d(SyncBatchNorm): 140 | r""" 141 | .. warning:: 142 | BatchNorm2d is deprecated in favor of :class:`encoding.nn.SyncBatchNorm`. 143 | """ 144 | def __init__(self, *args, **kwargs): 145 | super(BatchNorm2d, self).__init__(*args, **kwargs) 146 | 147 | class BatchNorm3d(SyncBatchNorm): 148 | r""" 149 | .. warning:: 150 | BatchNorm3d is deprecated in favor of :class:`encoding.nn.SyncBatchNorm`. 151 | """ 152 | def __init__(self, *args, **kwargs): 153 | super(BatchNorm3d, self).__init__(*args, **kwargs) 154 | -------------------------------------------------------------------------------- /lib/sync_bn/src/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import torch 3 | from torch.utils.cpp_extension import load 4 | 5 | cwd = os.path.dirname(os.path.realpath(__file__)) 6 | cpu_path = os.path.join(cwd, 'cpu') 7 | gpu_path = os.path.join(cwd, 'gpu') 8 | 9 | cpu = load('sync_bn_cpu', [ 10 | os.path.join(cpu_path, 'operator.cpp'), 11 | os.path.join(cpu_path, 'sync_bn.cpp'), 12 | ], build_directory=cpu_path, verbose=False) 13 | 14 | if torch.cuda.is_available(): 15 | gpu = load('sync_bn_gpu', [ 16 | os.path.join(gpu_path, 'operator.cpp'), 17 | os.path.join(gpu_path, 'sync_bn_cuda.cu'), 18 | ], build_directory=gpu_path, verbose=False) 19 | -------------------------------------------------------------------------------- /lib/sync_bn/src/cpu/operator.cpp: -------------------------------------------------------------------------------- 1 | #include "operator.h" 2 | 3 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 4 | m.def("batchnorm_forward", &BatchNorm_Forward_CPU, "BatchNorm forward (CPU)"); 5 | m.def("batchnorm_backward", &BatchNorm_Backward_CPU, "BatchNorm backward (CPU)"); 6 | m.def("sumsquare_forward", &Sum_Square_Forward_CPU, "SumSqu forward (CPU)"); 7 | m.def("sumsquare_backward", &Sum_Square_Backward_CPU, "SumSqu backward (CPU)"); 8 | } 9 | -------------------------------------------------------------------------------- /lib/sync_bn/src/cpu/operator.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | at::Tensor BatchNorm_Forward_CPU( 5 | const at::Tensor input_, 6 | const at::Tensor mean_, 7 | const at::Tensor std_, 8 | const at::Tensor gamma_, 9 | const at::Tensor beta_); 10 | 11 | std::vector BatchNorm_Backward_CPU( 12 | const at::Tensor gradoutput_, 13 | const at::Tensor input_, 14 | const at::Tensor mean_, 15 | const at::Tensor std_, 16 | const at::Tensor gamma_, 17 | const at::Tensor beta_, 18 | bool train); 19 | 20 | std::vector Sum_Square_Forward_CPU( 21 | const at::Tensor input_); 22 | 23 | at::Tensor Sum_Square_Backward_CPU( 24 | const at::Tensor input_, 25 | const at::Tensor gradSum_, 26 | const at::Tensor gradSquare_); 27 | -------------------------------------------------------------------------------- /lib/sync_bn/src/cpu/sync_bn.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | at::Tensor broadcast_to(at::Tensor v, at::Tensor x) { 6 | if (x.ndimension() == 2) { 7 | return v; 8 | } else { 9 | std::vector broadcast_size = {1, -1}; 10 | for (int64_t i = 2; i < x.ndimension(); ++i) 11 | broadcast_size.push_back(1); 12 | 13 | return v.view(broadcast_size); 14 | } 15 | } 16 | 17 | at::Tensor BatchNorm_Forward_CPU( 18 | const at::Tensor input, 19 | const at::Tensor mean, 20 | const at::Tensor std, 21 | const at::Tensor gamma, 22 | const at::Tensor beta) { 23 | auto output = (input - broadcast_to(mean, input)) / broadcast_to(std, input); 24 | output = output * broadcast_to(gamma, input) + broadcast_to(beta, input); 25 | return output; 26 | } 27 | 28 | // Not implementing CPU backward for now 29 | std::vector BatchNorm_Backward_CPU( 30 | const at::Tensor gradoutput, 31 | const at::Tensor input, 32 | const at::Tensor mean, 33 | const at::Tensor std, 34 | const at::Tensor gamma, 35 | const at::Tensor beta, 36 | bool train) { 37 | /* outputs*/ 38 | at::Tensor gradinput = at::zeros_like(input); 39 | at::Tensor gradgamma = at::zeros_like(gamma); 40 | at::Tensor gradbeta = at::zeros_like(beta); 41 | at::Tensor gradMean = at::zeros_like(mean); 42 | at::Tensor gradStd = at::zeros_like(std); 43 | return {gradinput, gradMean, gradStd, gradgamma, gradbeta}; 44 | } 45 | 46 | std::vector Sum_Square_Forward_CPU( 47 | const at::Tensor input) { 48 | /* outputs */ 49 | at::Tensor sum = torch::zeros({input.size(1)}, input.options()); 50 | at::Tensor square = torch::zeros({input.size(1)}, input.options()); 51 | return {sum, square}; 52 | } 53 | 54 | at::Tensor Sum_Square_Backward_CPU( 55 | const at::Tensor input, 56 | const at::Tensor gradSum, 57 | const at::Tensor gradSquare) { 58 | /* outputs */ 59 | at::Tensor gradInput = at::zeros_like(input); 60 | return gradInput; 61 | } 62 | -------------------------------------------------------------------------------- /lib/sync_bn/src/gpu/common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static const unsigned WARP_SIZE = 32; 5 | 6 | // The maximum number of threads in a block 7 | static const unsigned MAX_BLOCK_SIZE = 512U; 8 | 9 | template 10 | struct ScalarConvert { 11 | static __host__ __device__ __forceinline__ Out to(const In v) { return (Out) v; } 12 | }; 13 | 14 | // Number of threads in a block given an input size up to MAX_BLOCK_SIZE 15 | static int getNumThreads(int nElem) { 16 | int threadSizes[5] = { 32, 64, 128, 256, MAX_BLOCK_SIZE }; 17 | for (int i = 0; i != 5; ++i) { 18 | if (nElem <= threadSizes[i]) { 19 | return threadSizes[i]; 20 | } 21 | } 22 | return MAX_BLOCK_SIZE; 23 | } 24 | 25 | // Returns the index of the most significant 1 bit in `val`. 26 | __device__ __forceinline__ int getMSB(int val) { 27 | return 31 - __clz(val); 28 | } 29 | 30 | template 31 | __device__ __forceinline__ T WARP_SHFL_XOR(T value, int laneMask, int width = warpSize, unsigned int mask = 0xffffffff) 32 | { 33 | #if CUDA_VERSION >= 9000 34 | return __shfl_xor_sync(mask, value, laneMask, width); 35 | #else 36 | return __shfl_xor(value, laneMask, width); 37 | #endif 38 | } 39 | 40 | // Sum across all threads within a warp 41 | template 42 | static __device__ __forceinline__ T warpSum(T val) { 43 | #if __CUDA_ARCH__ >= 300 44 | for (int i = 0; i < getMSB(WARP_SIZE); ++i) { 45 | val += WARP_SHFL_XOR(val, 1 << i, WARP_SIZE); 46 | } 47 | #else 48 | __shared__ T values[MAX_BLOCK_SIZE]; 49 | values[threadIdx.x] = val; 50 | __threadfence_block(); 51 | const int base = (threadIdx.x / WARP_SIZE) * WARP_SIZE; 52 | for (int i = 1; i < WARP_SIZE; i++) { 53 | val += values[base + ((i + threadIdx.x) % WARP_SIZE)]; 54 | } 55 | #endif 56 | return val; 57 | } 58 | 59 | template 60 | struct Float2 { 61 | Acctype v1, v2; 62 | __device__ Float2() {} 63 | __device__ Float2(DType v1, DType v2) : v1(ScalarConvert::to(v1)), v2(ScalarConvert::to(v2)) {} 64 | __device__ Float2(DType v) : v1(ScalarConvert::to(v)), v2(ScalarConvert::to(v)) {} 65 | __device__ Float2(int v) : v1(ScalarConvert::to(v)), v2(ScalarConvert::to(v)) {} 66 | __device__ Float2& operator+=(const Float2& a) { 67 | v1 += a.v1; 68 | v2 += a.v2; 69 | return *this; 70 | } 71 | }; 72 | 73 | template 74 | static __device__ __forceinline__ Float2 warpSum(Float2 value) { 75 | value.v1 = warpSum(value.v1); 76 | value.v2 = warpSum(value.v2); 77 | return value; 78 | } 79 | 80 | template 81 | __device__ T reduceD( 82 | Op op, int b, int i, int k, int D) { 83 | T sum = 0; 84 | for (int x = threadIdx.x; x < D; x += blockDim.x) { 85 | sum += op(b,i,k,x); 86 | } 87 | // sum over NumThreads within a warp 88 | sum = warpSum(sum); 89 | 90 | // 'transpose', and reduce within warp again 91 | __shared__ T shared[32]; 92 | 93 | __syncthreads(); 94 | if (threadIdx.x % WARP_SIZE == 0) { 95 | if (threadIdx.x / WARP_SIZE < 32) { 96 | shared[threadIdx.x / WARP_SIZE] = sum; 97 | } 98 | } 99 | if (threadIdx.x >= blockDim.x / WARP_SIZE && threadIdx.x < WARP_SIZE) { 100 | // zero out the other entries in shared 101 | shared[threadIdx.x] = (T) 0; 102 | } 103 | __syncthreads(); 104 | if (threadIdx.x / WARP_SIZE == 0) { 105 | sum = warpSum(shared[threadIdx.x]); 106 | if (threadIdx.x == 0) { 107 | shared[0] = sum; 108 | } 109 | } 110 | __syncthreads(); 111 | 112 | // Everyone picks it up, should be broadcast into the whole gradInput 113 | return shared[0]; 114 | } 115 | 116 | template 117 | __device__ T reduceN( 118 | Op op, int b, int k, int d, int N) { 119 | T sum = 0; 120 | for (int x = threadIdx.x; x < N; x += blockDim.x) { 121 | sum += op(b,x,k,d); 122 | } 123 | // sum over NumThreads within a warp 124 | sum = warpSum(sum); 125 | 126 | // 'transpose', and reduce within warp again 127 | __shared__ T shared[32]; 128 | 129 | __syncthreads(); 130 | if (threadIdx.x % WARP_SIZE == 0) { 131 | if (threadIdx.x / WARP_SIZE < 32) { 132 | shared[threadIdx.x / WARP_SIZE] = sum; 133 | } 134 | } 135 | if (threadIdx.x >= blockDim.x / WARP_SIZE && threadIdx.x < WARP_SIZE) { 136 | // zero out the other entries in shared 137 | shared[threadIdx.x] = (T) 0; 138 | } 139 | __syncthreads(); 140 | if (threadIdx.x / WARP_SIZE == 0) { 141 | sum = warpSum(shared[threadIdx.x]); 142 | if (threadIdx.x == 0) { 143 | shared[0] = sum; 144 | } 145 | } 146 | __syncthreads(); 147 | 148 | // Everyone picks it up, should be broadcast into the whole gradInput 149 | return shared[0]; 150 | } 151 | 152 | template 153 | __device__ T reduceK( 154 | Op op, int b, int i, int d, int K) { 155 | T sum = 0; 156 | for (int x = threadIdx.x; x < K; x += blockDim.x) { 157 | sum += op(b,i,x,d); 158 | } 159 | // sum over NumThreads within a warp 160 | sum = warpSum(sum); 161 | 162 | // 'transpose', and reduce within warp again 163 | __shared__ T shared[32]; 164 | 165 | __syncthreads(); 166 | if (threadIdx.x % WARP_SIZE == 0) { 167 | if (threadIdx.x / WARP_SIZE < 32) { 168 | shared[threadIdx.x / WARP_SIZE] = sum; 169 | } 170 | } 171 | if (threadIdx.x >= blockDim.x / WARP_SIZE && threadIdx.x < WARP_SIZE) { 172 | // zero out the other entries in shared 173 | shared[threadIdx.x] = (T) 0; 174 | } 175 | __syncthreads(); 176 | if (threadIdx.x / WARP_SIZE == 0) { 177 | sum = warpSum(shared[threadIdx.x]); 178 | if (threadIdx.x == 0) { 179 | shared[0] = sum; 180 | } 181 | } 182 | __syncthreads(); 183 | 184 | // Everyone picks it up, should be broadcast into the whole gradInput 185 | return shared[0]; 186 | } 187 | 188 | template 189 | __device__ T reduceBN( 190 | Op op, 191 | int k, int d, int B, int N) { 192 | T sum = 0; 193 | for (int batch = 0; batch < B; ++batch) { 194 | for (int x = threadIdx.x; x < N; x += blockDim.x) { 195 | sum += op(batch,x,k,d); 196 | } 197 | } 198 | // sum over NumThreads within a warp 199 | sum = warpSum(sum); 200 | // 'transpose', and reduce within warp again 201 | __shared__ T shared[32]; 202 | 203 | __syncthreads(); 204 | if (threadIdx.x % WARP_SIZE == 0) { 205 | if (threadIdx.x / WARP_SIZE < 32) { 206 | shared[threadIdx.x / WARP_SIZE] = sum; 207 | } 208 | } 209 | if (threadIdx.x >= blockDim.x / WARP_SIZE && threadIdx.x < WARP_SIZE) { 210 | // zero out the other entries in shared 211 | shared[threadIdx.x] = (T) 0; 212 | } 213 | __syncthreads(); 214 | if (threadIdx.x / WARP_SIZE == 0) { 215 | sum = warpSum(shared[threadIdx.x]); 216 | if (threadIdx.x == 0) { 217 | shared[0] = sum; 218 | } 219 | } 220 | __syncthreads(); 221 | 222 | // Everyone picks it up, should be broadcast into the whole gradInput 223 | return shared[0]; 224 | } 225 | -------------------------------------------------------------------------------- /lib/sync_bn/src/gpu/device_tensor.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | struct DeviceTensor { 5 | public: 6 | inline __device__ __host__ DeviceTensor(DType *p, const int *size) 7 | : dptr_(p) { 8 | for (int i = 0; i < Dim; ++i) { 9 | size_[i] = size ? size[i] : 0; 10 | } 11 | } 12 | 13 | inline __device__ __host__ unsigned getSize(const int i) const { 14 | assert(i < Dim); 15 | return size_[i]; 16 | } 17 | 18 | inline __device__ __host__ int numElements() const { 19 | int n = 1; 20 | for (int i = 0; i < Dim; ++i) { 21 | n *= size_[i]; 22 | } 23 | return n; 24 | } 25 | 26 | inline __device__ __host__ DeviceTensor select(const size_t x) const { 27 | assert(Dim > 1); 28 | int offset = x; 29 | for (int i = 1; i < Dim; ++i) { 30 | offset *= size_[i]; 31 | } 32 | DeviceTensor tensor(dptr_ + offset, nullptr); 33 | for (int i = 0; i < Dim - 1; ++i) { 34 | tensor.size_[i] = this->size_[i+1]; 35 | } 36 | return tensor; 37 | } 38 | 39 | inline __device__ __host__ DeviceTensor operator[](const size_t x) const { 40 | assert(Dim > 1); 41 | int offset = x; 42 | for (int i = 1; i < Dim; ++i) { 43 | offset *= size_[i]; 44 | } 45 | DeviceTensor tensor(dptr_ + offset, nullptr); 46 | for (int i = 0; i < Dim - 1; ++i) { 47 | tensor.size_[i] = this->size_[i+1]; 48 | } 49 | return tensor; 50 | } 51 | 52 | inline __device__ __host__ size_t InnerSize() const { 53 | assert(Dim >= 3); 54 | size_t sz = 1; 55 | for (size_t i = 2; i < Dim; ++i) { 56 | sz *= size_[i]; 57 | } 58 | return sz; 59 | } 60 | 61 | inline __device__ __host__ size_t ChannelCount() const { 62 | assert(Dim >= 3); 63 | return size_[1]; 64 | } 65 | 66 | inline __device__ __host__ DType* data_ptr() const { 67 | return dptr_; 68 | } 69 | 70 | DType *dptr_; 71 | int size_[Dim]; 72 | }; 73 | 74 | template 75 | struct DeviceTensor { 76 | inline __device__ __host__ DeviceTensor(DType *p, const int *size) 77 | : dptr_(p) { 78 | size_[0] = size ? size[0] : 0; 79 | } 80 | 81 | inline __device__ __host__ unsigned getSize(const int i) const { 82 | assert(i == 0); 83 | return size_[0]; 84 | } 85 | 86 | inline __device__ __host__ int numElements() const { 87 | return size_[0]; 88 | } 89 | 90 | inline __device__ __host__ DType &operator[](const size_t x) const { 91 | return *(dptr_ + x); 92 | } 93 | 94 | inline __device__ __host__ DType* data_ptr() const { 95 | return dptr_; 96 | } 97 | 98 | DType *dptr_; 99 | int size_[1]; 100 | }; 101 | 102 | template 103 | static DeviceTensor devicetensor(const at::Tensor &blob) { 104 | DType *data = blob.data(); 105 | DeviceTensor tensor(data, nullptr); 106 | for (int i = 0; i < Dim; ++i) { 107 | tensor.size_[i] = blob.size(i); 108 | } 109 | return tensor; 110 | } 111 | -------------------------------------------------------------------------------- /lib/sync_bn/src/gpu/operator.cpp: -------------------------------------------------------------------------------- 1 | #include "operator.h" 2 | 3 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 4 | m.def("batchnorm_forward", &BatchNorm_Forward_CUDA, "BatchNorm forward (CUDA)"); 5 | m.def("batchnorm_inp_forward", &BatchNorm_Forward_Inp_CUDA, "BatchNorm forward (CUDA)"); 6 | m.def("batchnorm_backward", &BatchNorm_Backward_CUDA, "BatchNorm backward (CUDA)"); 7 | m.def("batchnorm_inp_backward", &BatchNorm_Inp_Backward_CUDA, "BatchNorm backward (CUDA)"); 8 | m.def("expectation_forward", &Expectation_Forward_CUDA, "Expectation forward (CUDA)"); 9 | m.def("expectation_backward", &Expectation_Backward_CUDA, "Expectation backward (CUDA)"); 10 | m.def("expectation_inp_backward", &Expectation_Inp_Backward_CUDA, 11 | "Inplace Expectation backward (CUDA)"); 12 | } 13 | -------------------------------------------------------------------------------- /lib/sync_bn/src/gpu/operator.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | at::Tensor BatchNorm_Forward_CUDA( 5 | const at::Tensor input_, 6 | const at::Tensor mean_, 7 | const at::Tensor std_, 8 | const at::Tensor gamma_, 9 | const at::Tensor beta_, 10 | float eps); 11 | 12 | at::Tensor BatchNorm_Forward_Inp_CUDA( 13 | const at::Tensor input_, 14 | const at::Tensor ex_, 15 | const at::Tensor exs_, 16 | const at::Tensor gamma_, 17 | const at::Tensor beta_, 18 | float eps); 19 | 20 | std::vector BatchNorm_Backward_CUDA( 21 | const at::Tensor gradoutput_, 22 | const at::Tensor input_, 23 | const at::Tensor ex_, 24 | const at::Tensor exs_, 25 | const at::Tensor gamma_, 26 | const at::Tensor beta_, 27 | float eps); 28 | 29 | std::vector BatchNorm_Inp_Backward_CUDA( 30 | const at::Tensor gradoutput_, 31 | const at::Tensor output_, 32 | const at::Tensor ex_, 33 | const at::Tensor exs_, 34 | const at::Tensor gamma_, 35 | const at::Tensor beta_, 36 | float eps); 37 | 38 | std::vector Expectation_Forward_CUDA( 39 | const at::Tensor input_); 40 | 41 | at::Tensor Expectation_Backward_CUDA( 42 | const at::Tensor input_, 43 | const at::Tensor gradEx_, 44 | const at::Tensor gradExs_); 45 | 46 | at::Tensor Expectation_Inp_Backward_CUDA( 47 | const at::Tensor gradInput_, 48 | const at::Tensor output_, 49 | const at::Tensor gradEx_, 50 | const at::Tensor gradExs_, 51 | const at::Tensor ex_, 52 | const at::Tensor exs_, 53 | const at::Tensor gamma_, 54 | const at::Tensor beta_, 55 | float eps); 56 | -------------------------------------------------------------------------------- /lib/sync_bn/src/gpu/sync_bn_cuda.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "common.h" 7 | #include "device_tensor.h" 8 | 9 | namespace { 10 | 11 | template 12 | struct GradOp { 13 | __device__ GradOp(Acctype m, const DeviceTensor3 i, const DeviceTensor3 g) 14 | : beta(m), output(i), gradOutput(g) {} 15 | __device__ __forceinline__ Float2 operator()(int batch, int plane, int n) { 16 | DType g = gradOutput[batch][plane][n]; 17 | DType c = ScalarConvert::to(output[batch][plane][n] - beta); 18 | return Float2(g, g * c); 19 | } 20 | const Acctype beta; 21 | const DeviceTensor3 output; 22 | const DeviceTensor3 gradOutput; 23 | }; 24 | 25 | template 26 | struct SumOp { 27 | __device__ SumOp(DeviceTensor i) : input(i){} 28 | __device__ __forceinline__ Float2 operator()(int batch, int plane, int n) { 29 | DType g = input[batch][plane][n]; 30 | return Float2(g, g * g); 31 | } 32 | DType mean; 33 | DeviceTensor input; 34 | }; 35 | 36 | // Sum across (batch, x/y/z) applying Op() pointwise 37 | template 38 | __device__ T reduce(Op op, DeviceTensor3 tensor, int plane) { 39 | T sum = (T)0; 40 | for (int batch = 0; batch < tensor.getSize(0); ++batch) { 41 | for (int x = threadIdx.x; x < tensor.getSize(2); x += blockDim.x) { 42 | sum += op(batch, plane, x); 43 | } 44 | } 45 | 46 | // sum over NumThreads within a warp 47 | sum = warpSum(sum); 48 | 49 | // 'transpose', and reduce within warp again 50 | __shared__ T shared[32]; 51 | __syncthreads(); 52 | if (threadIdx.x % WARP_SIZE == 0) { 53 | shared[threadIdx.x / WARP_SIZE] = sum; 54 | } 55 | if (threadIdx.x >= blockDim.x / WARP_SIZE && threadIdx.x < WARP_SIZE) { 56 | // zero out the other entries in shared 57 | shared[threadIdx.x] = (T)0; 58 | } 59 | __syncthreads(); 60 | if (threadIdx.x / WARP_SIZE == 0) { 61 | sum = warpSum(shared[threadIdx.x]); 62 | if (threadIdx.x == 0) { 63 | shared[0] = sum; 64 | } 65 | } 66 | __syncthreads(); 67 | 68 | // Everyone picks it up, should be broadcast into the whole gradInput 69 | return shared[0]; 70 | } 71 | 72 | template 73 | __global__ void BatchNorm_Forward_kernel ( 74 | DeviceTensor output, 75 | DeviceTensor input, 76 | DeviceTensor mean, 77 | DeviceTensor std, 78 | DeviceTensor gamma, 79 | DeviceTensor beta) { 80 | int c = blockIdx.x; 81 | /* main operation */ 82 | for (int b = 0; b < input.getSize(0); ++b) { 83 | for (int x = threadIdx.x; x < input.getSize(2); x += blockDim.x) { 84 | DType inp = input[b][c][x]; 85 | output[b][c][x] = gamma[c] * (inp - mean[c]) / 86 | std[c] + beta[c]; 87 | } 88 | } 89 | } 90 | 91 | template 92 | __global__ void BatchNorm_Forward_Inp_kernel ( 93 | DeviceTensor input, 94 | DeviceTensor mean, 95 | DeviceTensor std, 96 | DeviceTensor gamma, 97 | DeviceTensor beta) { 98 | int c = blockIdx.x; 99 | /* main operation */ 100 | for (int b = 0; b < input.getSize(0); ++b) { 101 | for (int x = threadIdx.x; x < input.getSize(2); x += blockDim.x) { 102 | DType inp = input[b][c][x]; 103 | input[b][c][x] = gamma[c] * (inp - mean[c]) / 104 | std[c] + beta[c]; 105 | } 106 | } 107 | } 108 | 109 | template 110 | __global__ void BatchNorm_Backward_Inp_kernel ( 111 | DeviceTensor gradoutput, 112 | DeviceTensor output, 113 | DeviceTensor gradinput, 114 | DeviceTensor gradgamma, 115 | DeviceTensor gradbeta, 116 | DeviceTensor mean, 117 | DeviceTensor std, 118 | DeviceTensor gamma, 119 | DeviceTensor beta, 120 | DeviceTensor gradEx, 121 | DeviceTensor gradExs) { 122 | /* declarations of the variables */ 123 | /* Get the index and channels */ 124 | int c = blockIdx.x; 125 | /* main operation */ 126 | GradOp> g(beta[c], output, gradoutput); 127 | Float2 res = reduce, 128 | GradOp>, 129 | DeviceTensor>(g, gradoutput, c); 130 | DType gradOutputSum = res.v1; 131 | DType dotP = res.v2; 132 | DType invstd = DType(1.0) / std[c]; 133 | DType gradScale = invstd * gamma[c]; 134 | if (threadIdx.x == 0) { 135 | gradEx[c] = - gradOutputSum * gradScale + mean[c] * invstd * invstd * dotP; 136 | gradExs[c] = - 0.5 * invstd * invstd * dotP; 137 | } 138 | if (gradinput.numElements() > 0) { 139 | for (int batch = 0; batch < gradoutput.getSize(0); ++batch) { 140 | for (int x = threadIdx.x; x < gradoutput.getSize(2); x += blockDim.x) { 141 | gradinput[batch][c][x] = gradoutput[batch][c][x] * gradScale; 142 | } 143 | } 144 | } 145 | if (gradgamma.numElements() > 0) { 146 | if (threadIdx.x == 0) { 147 | gradgamma[c] += dotP / gamma[c]; 148 | } 149 | } 150 | if (gradbeta.numElements() > 0) { 151 | if (threadIdx.x == 0) { 152 | gradbeta[c] += gradOutputSum; 153 | } 154 | } 155 | } 156 | 157 | template 158 | __global__ void BatchNorm_Backward_kernel ( 159 | DeviceTensor gradoutput, 160 | DeviceTensor input, 161 | DeviceTensor gradinput, 162 | DeviceTensor gradgamma, 163 | DeviceTensor gradbeta, 164 | DeviceTensor mean, 165 | DeviceTensor std, 166 | DeviceTensor gamma, 167 | DeviceTensor beta, 168 | DeviceTensor gradEx, 169 | DeviceTensor gradExs) { 170 | /* declarations of the variables */ 171 | /* Get the index and channels */ 172 | int c = blockIdx.x; 173 | /* main operation */ 174 | GradOp> g(mean[c], input, gradoutput); 175 | Float2 res = reduce, 176 | GradOp>, 177 | DeviceTensor>(g, gradoutput, c); 178 | DType gradOutputSum = res.v1; 179 | DType dotP = res.v2; 180 | DType invstd = DType(1.0) / std[c]; 181 | DType gradScale = invstd * gamma[c]; 182 | if (threadIdx.x == 0) { 183 | gradEx[c] = - gradOutputSum * gradScale + mean[c] * invstd * invstd * dotP * gradScale; 184 | gradExs[c] = - 0.5 * invstd * invstd * dotP * gradScale; 185 | } 186 | if (gradinput.numElements() > 0) { 187 | for (int batch = 0; batch < gradoutput.getSize(0); ++batch) { 188 | for (int x = threadIdx.x; x < gradoutput.getSize(2); x += blockDim.x) { 189 | gradinput[batch][c][x] = gradoutput[batch][c][x] * gradScale; 190 | } 191 | } 192 | } 193 | if (gradgamma.numElements() > 0) { 194 | if (threadIdx.x == 0) { 195 | gradgamma[c] += dotP * invstd; 196 | } 197 | } 198 | if (gradbeta.numElements() > 0) { 199 | if (threadIdx.x == 0) { 200 | gradbeta[c] += gradOutputSum; 201 | } 202 | } 203 | } 204 | 205 | 206 | template 207 | __global__ void Expectation_Forward_kernel ( 208 | DeviceTensor input, 209 | DeviceTensor ex, 210 | DeviceTensor exs, 211 | DType norm) { 212 | int c = blockIdx.x; 213 | /* main operation */ 214 | SumOp g(input); 215 | Float2 res = reduce, 216 | SumOp, DeviceTensor>(g, input, c); 217 | DType xsum = res.v1; 218 | DType xsquare = res.v2; 219 | if (threadIdx.x == 0) { 220 | ex[c] = xsum * norm; 221 | exs[c] = xsquare * norm; 222 | } 223 | } 224 | 225 | template 226 | __global__ void Expectation_Backward_kernel ( 227 | DeviceTensor gradInput, 228 | DeviceTensor input, 229 | DeviceTensor gradEx, 230 | DeviceTensor gradExs, 231 | DType norm) { 232 | int c = blockIdx.x; 233 | /* main operation */ 234 | for (int batch = 0; batch < gradInput.getSize(0); ++batch) { 235 | for (int x = threadIdx.x; x < gradInput.getSize(2); x += blockDim.x) { 236 | gradInput[batch][c][x] = gradEx[c] * norm + 2 * gradExs[c] * 237 | input[batch][c][x] * norm; 238 | } 239 | } 240 | } 241 | 242 | template 243 | __global__ void Expectation_Backward_Inp_kernel ( 244 | DeviceTensor gradInput, 245 | DeviceTensor output, 246 | DeviceTensor gradEx, 247 | DeviceTensor gradExs, 248 | DeviceTensor mean, 249 | DeviceTensor std, 250 | DeviceTensor gamma, 251 | DeviceTensor beta, 252 | DType norm) { 253 | int c = blockIdx.x; 254 | /* main operation */ 255 | for (int batch = 0; batch < gradInput.getSize(0); ++batch) { 256 | for (int x = threadIdx.x; x < gradInput.getSize(2); x += blockDim.x) { 257 | gradInput[batch][c][x] += gradEx[c] * norm + 2 * gradExs[c] * 258 | ((output[batch][c][x] - beta[c]) / gamma[c] * std[c] + mean[c]) * norm; 259 | } 260 | } 261 | } 262 | 263 | } // namespace 264 | 265 | at::Tensor BatchNorm_Forward_CUDA( 266 | const at::Tensor input_, 267 | const at::Tensor ex_, 268 | const at::Tensor exs_, 269 | const at::Tensor gamma_, 270 | const at::Tensor beta_, 271 | float eps) { 272 | auto output_ = at::zeros_like(input_); 273 | auto std_ = (exs_ - ex_ * ex_ + eps).sqrt(); 274 | cudaStream_t stream = at::cuda::getCurrentCUDAStream(); 275 | dim3 blocks(input_.size(1)); 276 | dim3 threads(getNumThreads(input_.size(2))); 277 | AT_DISPATCH_FLOATING_TYPES(input_.type(), "BatchNorm_Forward_CUDA", ([&] { 278 | /* Device tensors */ 279 | DeviceTensor output = devicetensor(output_); 280 | DeviceTensor input = devicetensor(input_); 281 | DeviceTensor ex = devicetensor(ex_); 282 | DeviceTensor std = devicetensor(std_); 283 | DeviceTensor gamma = devicetensor(gamma_); 284 | DeviceTensor beta = devicetensor(beta_); 285 | /* kernel function */ 286 | BatchNorm_Forward_kernel<<>>( 287 | output, input, ex, std, gamma, beta); 288 | })); 289 | AT_ASSERT(cudaGetLastError() == cudaSuccess); 290 | return output_; 291 | } 292 | 293 | at::Tensor BatchNorm_Forward_Inp_CUDA( 294 | const at::Tensor input_, 295 | const at::Tensor ex_, 296 | const at::Tensor exs_, 297 | const at::Tensor gamma_, 298 | const at::Tensor beta_, 299 | float eps) { 300 | auto std_ = (exs_ - ex_ * ex_ + eps).sqrt(); 301 | cudaStream_t stream = at::cuda::getCurrentCUDAStream(); 302 | dim3 blocks(input_.size(1)); 303 | dim3 threads(getNumThreads(input_.size(2))); 304 | AT_DISPATCH_FLOATING_TYPES(input_.type(), "BatchNorm_Forward_CUDA", ([&] { 305 | /* Device tensors */ 306 | DeviceTensor input = devicetensor(input_); 307 | DeviceTensor ex = devicetensor(ex_); 308 | DeviceTensor std = devicetensor(std_); 309 | DeviceTensor gamma = devicetensor(gamma_); 310 | DeviceTensor beta = devicetensor(beta_); 311 | /* kernel function */ 312 | BatchNorm_Forward_Inp_kernel<<>>( 313 | input, ex, std, gamma, beta); 314 | })); 315 | AT_ASSERT(cudaGetLastError() == cudaSuccess); 316 | return input_; 317 | } 318 | 319 | 320 | std::vector BatchNorm_Inp_Backward_CUDA( 321 | const at::Tensor gradoutput_, 322 | const at::Tensor output_, 323 | const at::Tensor ex_, 324 | const at::Tensor exs_, 325 | const at::Tensor gamma_, 326 | const at::Tensor beta_, 327 | float eps) { 328 | /* outputs*/ 329 | auto std_ = (exs_ - ex_ * ex_ + eps).sqrt(); 330 | auto gradinput_ = at::zeros_like(output_); 331 | auto gradgamma_ = at::zeros_like(gamma_); 332 | auto gradbeta_ = at::zeros_like(beta_); 333 | auto gradEx_ = at::zeros_like(ex_); 334 | auto gradExs_ = at::zeros_like(std_); 335 | /* cuda utils*/ 336 | cudaStream_t stream = at::cuda::getCurrentCUDAStream(); 337 | dim3 blocks(output_.size(1)); 338 | dim3 threads(getNumThreads(output_.size(2))); 339 | AT_DISPATCH_FLOATING_TYPES(output_.type(), "BatchNorm_Inp_Backward_CUDA", ([&] { 340 | /* Device tensors */ 341 | DeviceTensor gradoutput = devicetensor(gradoutput_); 342 | DeviceTensor output = devicetensor(output_); 343 | DeviceTensor gradinput = devicetensor(gradinput_); 344 | DeviceTensor gradgamma = devicetensor(gradgamma_); 345 | DeviceTensor gradbeta = devicetensor(gradbeta_); 346 | DeviceTensor ex = devicetensor(ex_); 347 | DeviceTensor std = devicetensor(std_); 348 | DeviceTensor gamma = devicetensor(gamma_); 349 | DeviceTensor beta = devicetensor(beta_); 350 | DeviceTensor gradEx = devicetensor(gradEx_); 351 | DeviceTensor gradExs = devicetensor(gradExs_); 352 | /* kernel function */ 353 | BatchNorm_Backward_Inp_kernel 354 | <<>>( 355 | gradoutput, output, gradinput, gradgamma, gradbeta, ex, std, 356 | gamma, beta, gradEx, gradExs); 357 | })); 358 | AT_ASSERT(cudaGetLastError() == cudaSuccess); 359 | return {gradinput_, gradEx_, gradExs_, gradgamma_, gradbeta_}; 360 | } 361 | 362 | 363 | std::vector BatchNorm_Backward_CUDA( 364 | const at::Tensor gradoutput_, 365 | const at::Tensor input_, 366 | const at::Tensor ex_, 367 | const at::Tensor exs_, 368 | const at::Tensor gamma_, 369 | const at::Tensor beta_, 370 | float eps) { 371 | /* outputs*/ 372 | auto std_ = (exs_ - ex_ * ex_ + eps).sqrt(); 373 | auto gradinput_ = at::zeros_like(input_); 374 | auto gradgamma_ = at::zeros_like(gamma_); 375 | auto gradbeta_ = at::zeros_like(beta_); 376 | auto gradEx_ = at::zeros_like(ex_); 377 | auto gradExs_ = at::zeros_like(std_); 378 | /* cuda utils*/ 379 | cudaStream_t stream = at::cuda::getCurrentCUDAStream(); 380 | dim3 blocks(input_.size(1)); 381 | dim3 threads(getNumThreads(input_.size(2))); 382 | AT_DISPATCH_FLOATING_TYPES(input_.type(), "BatchNorm_Inp_Backward_CUDA", ([&] { 383 | /* Device tensors */ 384 | DeviceTensor gradoutput = devicetensor(gradoutput_); 385 | DeviceTensor input = devicetensor(input_); 386 | DeviceTensor gradinput = devicetensor(gradinput_); 387 | DeviceTensor gradgamma = devicetensor(gradgamma_); 388 | DeviceTensor gradbeta = devicetensor(gradbeta_); 389 | DeviceTensor ex = devicetensor(ex_); 390 | DeviceTensor std = devicetensor(std_); 391 | DeviceTensor gamma = devicetensor(gamma_); 392 | DeviceTensor beta = devicetensor(beta_); 393 | DeviceTensor gradEx = devicetensor(gradEx_); 394 | DeviceTensor gradExs = devicetensor(gradExs_); 395 | /* kernel function */ 396 | BatchNorm_Backward_kernel 397 | <<>>( 398 | gradoutput, input, gradinput, gradgamma, gradbeta, ex, std, 399 | gamma, beta, gradEx, gradExs); 400 | })); 401 | AT_ASSERT(cudaGetLastError() == cudaSuccess); 402 | return {gradinput_, gradEx_, gradExs_, gradgamma_, gradbeta_}; 403 | } 404 | 405 | std::vector Expectation_Forward_CUDA( 406 | const at::Tensor input_) { 407 | /* outputs */ 408 | auto ex_ = torch::zeros({input_.size(1)}, input_.options()); 409 | auto exs_ = torch::zeros({input_.size(1)}, input_.options()); 410 | /* cuda utils*/ 411 | cudaStream_t stream = at::cuda::getCurrentCUDAStream(); 412 | dim3 blocks(input_.size(1)); 413 | dim3 threads(getNumThreads(input_.size(2))); 414 | AT_DISPATCH_FLOATING_TYPES(input_.type(), "SumSquare_forward_CUDA", ([&] { 415 | scalar_t norm = scalar_t(1) / (input_.size(0) * input_.size(2)); 416 | /* Device tensors */ 417 | DeviceTensor input = devicetensor(input_); 418 | DeviceTensor ex = devicetensor(ex_); 419 | DeviceTensor exs = devicetensor(exs_); 420 | /* kernel function */ 421 | Expectation_Forward_kernel 422 | <<>>(input, ex, exs, norm); 423 | })); 424 | AT_ASSERT(cudaGetLastError() == cudaSuccess); 425 | return {ex_, exs_}; 426 | } 427 | 428 | at::Tensor Expectation_Backward_CUDA( 429 | const at::Tensor input_, 430 | const at::Tensor gradEx_, 431 | const at::Tensor gradExs_) { 432 | /* outputs */ 433 | at::Tensor gradInput_ = at::zeros_like(input_); 434 | /* cuda utils*/ 435 | cudaStream_t stream = at::cuda::getCurrentCUDAStream(); 436 | dim3 blocks(input_.size(1)); 437 | dim3 threads(getNumThreads(input_.size(2))); 438 | AT_DISPATCH_FLOATING_TYPES(input_.type(), "SumSquare_Backward_CUDA", ([&] { 439 | scalar_t norm = scalar_t(1) / (input_.size(0) * input_.size(2)); 440 | /* Device tensors */ 441 | DeviceTensor gradInput = devicetensor(gradInput_); 442 | DeviceTensor input = devicetensor(input_); 443 | DeviceTensor gradEx = devicetensor(gradEx_); 444 | DeviceTensor gradExs =devicetensor(gradExs_); 445 | /* kernel function */ 446 | Expectation_Backward_kernel 447 | <<>>(gradInput, input, gradEx, gradExs, norm); 448 | })); 449 | AT_ASSERT(cudaGetLastError() == cudaSuccess); 450 | return gradInput_; 451 | } 452 | 453 | at::Tensor Expectation_Inp_Backward_CUDA( 454 | const at::Tensor gradInput_, 455 | const at::Tensor output_, 456 | const at::Tensor gradEx_, 457 | const at::Tensor gradExs_, 458 | const at::Tensor ex_, 459 | const at::Tensor exs_, 460 | const at::Tensor gamma_, 461 | const at::Tensor beta_, 462 | float eps) { 463 | /* outputs */ 464 | //auto gradInput_ = at::zeros_like(output_); 465 | auto std_ = (exs_ - ex_ * ex_ + eps).sqrt(); 466 | /* cuda utils*/ 467 | cudaStream_t stream = at::cuda::getCurrentCUDAStream(); 468 | dim3 blocks(output_.size(1)); 469 | dim3 threads(getNumThreads(output_.size(2))); 470 | AT_DISPATCH_FLOATING_TYPES(output_.type(), "SumSquare_Backward_CUDA", ([&] { 471 | scalar_t norm = scalar_t(1) / (output_.size(0) * output_.size(2)); 472 | /* Device tensors */ 473 | DeviceTensor gradInput = devicetensor(gradInput_); 474 | DeviceTensor input = devicetensor(output_); 475 | DeviceTensor gradEx = devicetensor(gradEx_); 476 | DeviceTensor gradExs =devicetensor(gradExs_); 477 | DeviceTensor ex = devicetensor(ex_); 478 | DeviceTensor std = devicetensor(std_); 479 | DeviceTensor gamma = devicetensor(gamma_); 480 | DeviceTensor beta = devicetensor(beta_); 481 | /* kernel function */ 482 | Expectation_Backward_Inp_kernel 483 | <<>>(gradInput, input, gradEx, gradExs, 484 | ex, std, gamma, beta, norm); 485 | })); 486 | AT_ASSERT(cudaGetLastError() == cudaSuccess); 487 | return gradInput_; 488 | } 489 | -------------------------------------------------------------------------------- /model/__pycache__/loss.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/model/__pycache__/loss.cpython-36.pyc -------------------------------------------------------------------------------- /model/__pycache__/pmm.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/model/__pycache__/pmm.cpython-36.pyc -------------------------------------------------------------------------------- /model/__pycache__/position_encoding.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/model/__pycache__/position_encoding.cpython-36.pyc -------------------------------------------------------------------------------- /model/__pycache__/pspnet.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/model/__pycache__/pspnet.cpython-36.pyc -------------------------------------------------------------------------------- /model/__pycache__/resnet.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/model/__pycache__/resnet.cpython-36.pyc -------------------------------------------------------------------------------- /model/__pycache__/resnet.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/model/__pycache__/resnet.cpython-37.pyc -------------------------------------------------------------------------------- /model/__pycache__/transformer.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/model/__pycache__/transformer.cpython-36.pyc -------------------------------------------------------------------------------- /model/__pycache__/ugtr.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/model/__pycache__/ugtr.cpython-36.pyc -------------------------------------------------------------------------------- /model/__pycache__/ugtr.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/model/__pycache__/ugtr.cpython-37.pyc -------------------------------------------------------------------------------- /model/loss.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is the implementation of following paper: 3 | https://arxiv.org/pdf/1802.05591.pdf 4 | This implementation is based on following code: 5 | https://github.com/Wizaron/instance-segmentation-pytorch 6 | """ 7 | from torch.nn.modules.loss import _Loss 8 | from torch.autograd import Variable 9 | import torch 10 | 11 | 12 | class DiscriminativeLoss(_Loss): 13 | 14 | def __init__(self, delta_var=0.5, delta_dist=1.5, 15 | norm=2, alpha=1.0, beta=1.0, gamma=0.001, 16 | usegpu=True, size_average=True): 17 | super(DiscriminativeLoss, self).__init__(size_average) 18 | self.delta_var = delta_var 19 | self.delta_dist = delta_dist 20 | self.norm = norm 21 | self.alpha = alpha 22 | self.beta = beta 23 | self.gamma = gamma 24 | self.usegpu = usegpu 25 | assert self.norm in [1, 2] 26 | 27 | def forward(self, input): 28 | #_assert_no_grad(target) 29 | return self._discriminative_loss(input) 30 | 31 | def _discriminative_loss(self, input): 32 | n_clusters, bs, n_features = input.size() 33 | #max_n_clusters = target.size(1) 34 | 35 | input = input.contiguous().permute(1, 2, 0) #.view(bs, n_features, height * width) 36 | #target = target.contiguous().view(bs, max_n_clusters, height * width) 37 | 38 | c_means = input# self._cluster_means(input, target, n_clusters) 39 | #l_var = self._variance_term(input, target, c_means, n_clusters) 40 | l_dist = self._distance_term(c_means) 41 | l_reg = self._regularization_term(c_means) 42 | 43 | loss = self.beta * l_dist + self.gamma * l_reg 44 | 45 | return loss 46 | 47 | 48 | def _distance_term(self, c_means): 49 | bs, n_features, max_n_clusters = c_means.size() 50 | 51 | n_clusters = [max_n_clusters]*bs 52 | 53 | dist_term = 0 54 | for i in range(bs): 55 | #if n_clusters[i] <= 1: 56 | # continue 57 | 58 | # n_features, n_clusters 59 | mean_sample = c_means[i, :, :n_clusters[i]] 60 | 61 | # n_features, n_clusters, n_clusters 62 | means_a = mean_sample.unsqueeze(2).expand(n_features, n_clusters[i], n_clusters[i]) 63 | means_b = means_a.permute(0, 2, 1) 64 | diff = means_a - means_b 65 | 66 | margin = 2 * self.delta_dist * (1.0 - torch.eye(n_clusters[i])) 67 | margin = Variable(margin) 68 | if self.usegpu: 69 | margin = margin.cuda() 70 | c_dist = torch.sum(torch.clamp(margin - torch.norm(diff, self.norm, 0), min=0) ** 2) 71 | dist_term += c_dist / (2 * n_clusters[i] * (n_clusters[i] - 1)) 72 | dist_term /= bs 73 | 74 | return dist_term 75 | 76 | def _regularization_term(self, c_means): 77 | bs, n_features, max_n_clusters = c_means.size() 78 | 79 | reg_term = 0 80 | for i in range(bs): 81 | # n_features, n_clusters 82 | mean_sample = c_means[i, :, :] 83 | reg_term += torch.mean(torch.norm(mean_sample, self.norm, 0)) 84 | reg_term /= bs 85 | 86 | return reg_term 87 | -------------------------------------------------------------------------------- /model/pmm.py: -------------------------------------------------------------------------------- 1 | import math 2 | import torch 3 | import torch.nn as nn 4 | import torch.nn.functional as F 5 | import pdb 6 | 7 | class PMMs(nn.Module): 8 | '''Prototype Mixture Models 9 | Arguments: 10 | c (int): The input and output channel number. 11 | k (int): The number of the bases. 12 | stage_num (int): The iteration number for EM. 13 | ''' 14 | 15 | def __init__(self, c, k=3, stage_num=10): 16 | super(PMMs, self).__init__() 17 | self.stage_num = stage_num 18 | self.num_pro = k 19 | mu = torch.Tensor(1, c, k)#.cuda() 20 | mu.normal_(0, math.sqrt(2. / k)) # Init mu 21 | self.mu = self._l2norm(mu, dim=1) 22 | self.kappa = 20 23 | #self.register_buffer('mu', mu) 24 | 25 | 26 | def forward(self, support_feature): 27 | prototypes, z_ = self.generate_prototype(support_feature) 28 | #Prob_map, P = self.discriminative_model(query_feature, mu_f, mu_b) 29 | 30 | return prototypes, z_#, Prob_map 31 | 32 | def _l2norm(self, inp, dim): 33 | '''Normlize the inp tensor with l2-norm. 34 | Returns a tensor where each sub-tensor of input along the given dim is 35 | normalized such that the 2-norm of the sub-tensor is equal to 1. 36 | Arguments: 37 | inp (tensor): The input tensor. 38 | dim (int): The dimension to slice over to get the ssub-tensors. 39 | Returns: 40 | (tensor) The normalized tensor. 41 | ''' 42 | return inp / (1e-6 + inp.norm(dim=dim, keepdim=True)) 43 | 44 | def EM(self,x): 45 | ''' 46 | EM method 47 | :param x: feauture b * c * n 48 | :return: mu 49 | ''' 50 | b = x.shape[0] 51 | mu = self.mu.repeat(b, 1, 1).to(x.device) # b * c * k 52 | z_ = None 53 | with torch.no_grad(): 54 | for i in range(self.stage_num): 55 | # E STEP: 56 | z = self.Kernel(x, mu) 57 | z = F.softmax(z, dim=2) # b * n * k 58 | # M STEP: 59 | z_ = z / (1e-6 + z.sum(dim=1, keepdim=True)) 60 | mu = torch.bmm(x, z_) # b * c * k 61 | 62 | mu = self._l2norm(mu, dim=1) 63 | 64 | mu = mu.permute(0, 2, 1) # b * k * c 65 | 66 | return mu, z_ 67 | 68 | def Kernel(self, x, mu): 69 | x_t = x.permute(0, 2, 1) # b * n * c 70 | z = self.kappa * torch.bmm(x_t, mu) # b * n * k 71 | 72 | return z 73 | 74 | def get_prototype(self,x): 75 | b, c, h, w = x.size() 76 | x = x.view(b, c, h * w) # b * c * n 77 | mu, z_ = self.EM(x) # b * k * c 78 | 79 | return mu, z_ 80 | 81 | def generate_prototype(self, feature): 82 | #mask = F.interpolate(mask, feature.shape[-2:], mode='bilinear', align_corners=True) 83 | mask = torch.ones_like(feature) 84 | 85 | mask_bg = 1-mask 86 | 87 | # foreground 88 | z = mask * feature 89 | mu_f, z_ = self.get_prototype(z) 90 | mu_ = [] 91 | for i in range(self.num_pro): 92 | mu_.append(mu_f[:, i, :].unsqueeze(dim=2).unsqueeze(dim=3)) 93 | 94 | # background 95 | z_bg = mask_bg * feature 96 | mu_b, _ = self.get_prototype(z_bg) 97 | 98 | return mu_, z_ 99 | 100 | def discriminative_model(self, query_feature, mu_f, mu_b): 101 | 102 | mu = torch.cat([mu_f, mu_b], dim=1) 103 | mu = mu.permute(0, 2, 1) 104 | 105 | b, c, h, w = query_feature.size() 106 | x = query_feature.view(b, c, h * w) # b * c * n 107 | with torch.no_grad(): 108 | 109 | x_t = x.permute(0, 2, 1) # b * n * c 110 | z = torch.bmm(x_t, mu) # b * n * k 111 | 112 | z = F.softmax(z, dim=2) # b * n * k 113 | 114 | P = z.permute(0, 2, 1) 115 | 116 | P = P.view(b, self.num_pro * 2, h, w) # b * k * w * h probability map 117 | P_f = torch.sum(P[:, 0:self.num_pro], dim=1).unsqueeze(dim=1) # foreground 118 | P_b = torch.sum(P[:, self.num_pro:], dim=1).unsqueeze(dim=1) # background 119 | 120 | Prob_map = torch.cat([P_b, P_f], dim=1) 121 | 122 | return Prob_map, P 123 | -------------------------------------------------------------------------------- /model/position_encoding.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 2 | """ 3 | Various positional encodings for the transformer. 4 | """ 5 | import math 6 | import torch 7 | from torch import nn 8 | 9 | 10 | class PositionEmbeddingSine(nn.Module): 11 | """ 12 | This is a more standard version of the position embedding, very similar to the one 13 | used by the Attention is all you need paper, generalized to work on images. 14 | """ 15 | def __init__(self, num_pos_feats=64, temperature=10000, normalize=False, scale=None): 16 | super().__init__() 17 | self.num_pos_feats = num_pos_feats 18 | self.temperature = temperature 19 | self.normalize = normalize 20 | if scale is not None and normalize is False: 21 | raise ValueError("normalize should be True if scale is passed") 22 | if scale is None: 23 | scale = 2 * math.pi 24 | self.scale = scale 25 | 26 | def forward(self, x: torch.Tensor, mask: torch.Tensor): 27 | assert mask is not None 28 | not_mask = (~mask.to(torch.uint8)).to(torch.bool) 29 | y_embed = not_mask.cumsum(1, dtype=torch.float32) 30 | x_embed = not_mask.cumsum(2, dtype=torch.float32) 31 | if self.normalize: 32 | eps = 1e-6 33 | y_embed = y_embed / (y_embed[:, -1:, :] + eps) * self.scale 34 | x_embed = x_embed / (x_embed[:, :, -1:] + eps) * self.scale 35 | 36 | dim_t = torch.arange(self.num_pos_feats, dtype=torch.float32, device=x.device) 37 | dim_t = self.temperature ** (2 * (dim_t // 2) / self.num_pos_feats) 38 | 39 | pos_x = x_embed[:, :, :, None] / dim_t 40 | pos_y = y_embed[:, :, :, None] / dim_t 41 | pos_x = torch.stack((pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4).flatten(3) 42 | pos_y = torch.stack((pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4).flatten(3) 43 | pos = torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2) 44 | return pos 45 | 46 | 47 | class PositionEmbeddingLearned(nn.Module): 48 | """ 49 | Absolute pos embedding, learned. 50 | """ 51 | def __init__(self, num_pos_feats=256): 52 | super().__init__() 53 | self.row_embed = nn.Embedding(50, num_pos_feats) 54 | self.col_embed = nn.Embedding(50, num_pos_feats) 55 | self.reset_parameters() 56 | 57 | def reset_parameters(self): 58 | nn.init.uniform_(self.row_embed.weight) 59 | nn.init.uniform_(self.col_embed.weight) 60 | 61 | def forward(self, x: torch.Tensor, mask: torch.Tensor): 62 | h, w = x.shape[-2:] 63 | i = torch.arange(w, device=x.device) 64 | j = torch.arange(h, device=x.device) 65 | x_emb = self.col_embed(i) 66 | y_emb = self.row_embed(j) 67 | pos = torch.cat([ 68 | x_emb.unsqueeze(0).repeat(h, 1, 1), 69 | y_emb.unsqueeze(1).repeat(1, w, 1), 70 | ], dim=-1).permute(2, 0, 1).unsqueeze(0).repeat(x.shape[0], 1, 1, 1) 71 | return pos 72 | 73 | 74 | def build_position_encoding(dim, mode): 75 | N_steps = dim // 2 76 | if mode in ('v2', 'sine'): 77 | # TODO find a better way of exposing other arguments 78 | position_embedding = PositionEmbeddingSine(N_steps, normalize=True) 79 | elif mode in ('v3', 'learned'): 80 | position_embedding = PositionEmbeddingLearned(N_steps) 81 | else: 82 | raise ValueError(f"not supported {args.position_embedding}") 83 | 84 | return position_embedding 85 | 86 | -------------------------------------------------------------------------------- /model/resnet.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import math 4 | import torch.utils.model_zoo as model_zoo 5 | 6 | BatchNorm = nn.BatchNorm2d 7 | 8 | __all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 9 | 'resnet152'] 10 | 11 | 12 | model_urls = { 13 | 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth', 14 | 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth', 15 | 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth', 16 | 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth', 17 | 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth', 18 | } 19 | 20 | 21 | def conv3x3(in_planes, out_planes, stride=1): 22 | """3x3 convolution with padding""" 23 | return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, 24 | padding=1, bias=False) 25 | 26 | 27 | class BasicBlock(nn.Module): 28 | expansion = 1 29 | 30 | def __init__(self, inplanes, planes, stride=1, downsample=None): 31 | super(BasicBlock, self).__init__() 32 | self.conv1 = conv3x3(inplanes, planes, stride) 33 | self.bn1 = BatchNorm(planes) 34 | self.relu = nn.ReLU(inplace=True) 35 | self.conv2 = conv3x3(planes, planes) 36 | self.bn2 = BatchNorm(planes) 37 | self.downsample = downsample 38 | self.stride = stride 39 | 40 | def forward(self, x): 41 | residual = x 42 | 43 | out = self.conv1(x) 44 | out = self.bn1(out) 45 | out = self.relu(out) 46 | 47 | out = self.conv2(out) 48 | out = self.bn2(out) 49 | 50 | if self.downsample is not None: 51 | residual = self.downsample(x) 52 | 53 | out += residual 54 | out = self.relu(out) 55 | 56 | return out 57 | 58 | 59 | class Bottleneck(nn.Module): 60 | expansion = 4 61 | 62 | def __init__(self, inplanes, planes, stride=1, downsample=None): 63 | super(Bottleneck, self).__init__() 64 | self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) 65 | self.bn1 = BatchNorm(planes) 66 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, 67 | padding=1, bias=False) 68 | self.bn2 = BatchNorm(planes) 69 | self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False) 70 | self.bn3 = BatchNorm(planes * self.expansion) 71 | self.relu = nn.ReLU(inplace=True) 72 | self.downsample = downsample 73 | self.stride = stride 74 | 75 | def forward(self, x): 76 | residual = x 77 | 78 | out = self.conv1(x) 79 | out = self.bn1(out) 80 | out = self.relu(out) 81 | 82 | out = self.conv2(out) 83 | out = self.bn2(out) 84 | out = self.relu(out) 85 | 86 | out = self.conv3(out) 87 | out = self.bn3(out) 88 | 89 | if self.downsample is not None: 90 | residual = self.downsample(x) 91 | 92 | out += residual 93 | out = self.relu(out) 94 | 95 | return out 96 | 97 | 98 | class ResNet(nn.Module): 99 | 100 | def __init__(self, block, layers, num_classes=1000, deep_base=True): 101 | super(ResNet, self).__init__() 102 | self.deep_base = deep_base 103 | if not self.deep_base: 104 | self.inplanes = 64 105 | self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False) 106 | self.bn1 = BatchNorm(64) 107 | else: 108 | self.inplanes = 128 109 | self.conv1 = conv3x3(3, 64, stride=2) 110 | self.bn1 = BatchNorm(64) 111 | self.conv2 = conv3x3(64, 64) 112 | self.bn2 = BatchNorm(64) 113 | self.conv3 = conv3x3(64, 128) 114 | self.bn3 = BatchNorm(128) 115 | self.relu = nn.ReLU(inplace=True) 116 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) 117 | self.layer1 = self._make_layer(block, 64, layers[0]) 118 | self.layer2 = self._make_layer(block, 128, layers[1], stride=2) 119 | self.layer3 = self._make_layer(block, 256, layers[2], stride=2) 120 | self.layer4 = self._make_layer(block, 512, layers[3], stride=2) 121 | self.avgpool = nn.AvgPool2d(7, stride=1) 122 | self.fc = nn.Linear(512 * block.expansion, num_classes) 123 | 124 | for m in self.modules(): 125 | if isinstance(m, nn.Conv2d): 126 | nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') 127 | elif isinstance(m, BatchNorm): 128 | nn.init.constant_(m.weight, 1) 129 | nn.init.constant_(m.bias, 0) 130 | 131 | def _make_layer(self, block, planes, blocks, stride=1): 132 | downsample = None 133 | if stride != 1 or self.inplanes != planes * block.expansion: 134 | downsample = nn.Sequential( 135 | nn.Conv2d(self.inplanes, planes * block.expansion, 136 | kernel_size=1, stride=stride, bias=False), 137 | BatchNorm(planes * block.expansion), 138 | ) 139 | 140 | layers = [] 141 | layers.append(block(self.inplanes, planes, stride, downsample)) 142 | self.inplanes = planes * block.expansion 143 | for i in range(1, blocks): 144 | layers.append(block(self.inplanes, planes)) 145 | 146 | return nn.Sequential(*layers) 147 | 148 | def forward(self, x): 149 | x = self.relu(self.bn1(self.conv1(x))) 150 | if self.deep_base: 151 | x = self.relu(self.bn2(self.conv2(x))) 152 | x = self.relu(self.bn3(self.conv3(x))) 153 | x = self.maxpool(x) 154 | 155 | x = self.layer1(x) 156 | x = self.layer2(x) 157 | x = self.layer3(x) 158 | x = self.layer4(x) 159 | 160 | x = self.avgpool(x) 161 | x = x.view(x.size(0), -1) 162 | x = self.fc(x) 163 | 164 | return x 165 | 166 | 167 | def resnet18(pretrained=False, **kwargs): 168 | """Constructs a ResNet-18 model. 169 | 170 | Args: 171 | pretrained (bool): If True, returns a model pre-trained on ImageNet 172 | """ 173 | model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs) 174 | if pretrained: 175 | model.load_state_dict(model_zoo.load_url(model_urls['resnet18'])) 176 | return model 177 | 178 | 179 | def resnet34(pretrained=False, **kwargs): 180 | """Constructs a ResNet-34 model. 181 | 182 | Args: 183 | pretrained (bool): If True, returns a model pre-trained on ImageNet 184 | """ 185 | model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs) 186 | if pretrained: 187 | model.load_state_dict(model_zoo.load_url(model_urls['resnet34'])) 188 | return model 189 | 190 | 191 | def resnet50(pretrained=False, **kwargs): 192 | """Constructs a ResNet-50 model. 193 | 194 | Args: 195 | pretrained (bool): If True, returns a model pre-trained on ImageNet 196 | """ 197 | model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs) 198 | if pretrained: 199 | # model.load_state_dict(model_zoo.load_url(model_urls['resnet50'])) 200 | model_path = './initmodel/resnet50_v2.pth' 201 | model.load_state_dict(torch.load(model_path), strict=False) 202 | return model 203 | 204 | 205 | def resnet101(pretrained=False, **kwargs): 206 | """Constructs a ResNet-101 model. 207 | 208 | Args: 209 | pretrained (bool): If True, returns a model pre-trained on ImageNet 210 | """ 211 | model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs) 212 | if pretrained: 213 | # model.load_state_dict(model_zoo.load_url(model_urls['resnet101'])) 214 | model_path = './initmodel/resnet101_v2.pth' 215 | model.load_state_dict(torch.load(model_path), strict=False) 216 | return model 217 | 218 | 219 | def resnet152(pretrained=False, **kwargs): 220 | """Constructs a ResNet-152 model. 221 | 222 | Args: 223 | pretrained (bool): If True, returns a model pre-trained on ImageNet 224 | """ 225 | model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs) 226 | if pretrained: 227 | # model.load_state_dict(model_zoo.load_url(model_urls['resnet152'])) 228 | model_path = './initmodel/resnet152_v2.pth' 229 | model.load_state_dict(torch.load(model_path), strict=False) 230 | return model 231 | -------------------------------------------------------------------------------- /model/transformer.py: -------------------------------------------------------------------------------- 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, List 12 | 13 | import torch 14 | import torch.nn.functional as F 15 | from torch import nn, Tensor 16 | import pdb 17 | from model.loss import DiscriminativeLoss 18 | import numpy as np 19 | 20 | class Transformer(nn.Module): 21 | 22 | def __init__(self, d_model=512, nhead=8, num_encoder_layers=6, 23 | num_decoder_layers=6, dim_feedforward=2048, dropout=0.1, 24 | activation="relu", normalize_before=False, 25 | return_intermediate_dec=False): 26 | super().__init__() 27 | 28 | encoder_layer = TransformerEncoderLayer(d_model, nhead, dim_feedforward, 29 | dropout, activation, normalize_before) 30 | encoder_norm = nn.LayerNorm(d_model) if normalize_before else None 31 | self.encoder = TransformerEncoder(encoder_layer, num_encoder_layers, encoder_norm) 32 | 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 | 39 | self._reset_parameters() 40 | 41 | self.d_model = d_model 42 | self.nhead = nhead 43 | self.loss = DiscriminativeLoss() 44 | 45 | def _reset_parameters(self): 46 | for p in self.parameters(): 47 | if p.dim() > 1: 48 | nn.init.xavier_uniform_(p) 49 | 50 | #def forward(self, src, mask, query_embed, pos_embed, fea): 51 | def forward(self, src, fea, pos_embed): 52 | 53 | # flatten NxCxHxW to HWxNxC 54 | bs, c, h, w = src.shape 55 | src = src.flatten(2).permute(2, 0, 1) 56 | pos_embed = pos_embed.flatten(2).permute(2, 0, 1) 57 | #query_embed = query_embed.unsqueeze(1).repeat(1, bs, 1) 58 | #mask = mask.flatten(1).to(torch.uint8) 59 | 60 | tgt = fea.view(bs, c, -1).permute(2, 0, 1) 61 | #if self.training: 62 | # mask = np.random.randint(0, tgt.shape[0], int(0.1*tgt.shape[0])) 63 | # tgt[mask] = 0. 64 | 65 | #tgt = torch.zeros_like(query_embed) 66 | memory, pos_embed = self.encoder(src, src_key_padding_mask=None, pos=pos_embed) 67 | hs = self.decoder(tgt, memory, memory_key_padding_mask=None, 68 | pos=pos_embed, query_pos=None) 69 | loss = self.loss(memory) 70 | n, _, _, _ = hs.shape 71 | return hs.transpose(2, 3).permute(3, 0, 1, 2).transpose(2, 3).view(bs, n, c, 60, 60).squeeze(1), loss 72 | 73 | 74 | class TransformerEncoder(nn.Module): 75 | 76 | def __init__(self, encoder_layer, num_layers, norm=None): 77 | super().__init__() 78 | self.layers = _get_clones(encoder_layer, num_layers) 79 | self.num_layers = num_layers 80 | self.norm = norm 81 | num_queries = 16 82 | hidden_dim = 512 83 | self.pos_embed = nn.Embedding(num_queries, hidden_dim) 84 | 85 | def forward(self, src, 86 | mask: Optional[Tensor] = None, 87 | src_key_padding_mask: Optional[Tensor] = None, 88 | pos: Optional[Tensor] = None): 89 | output = src 90 | 91 | #pos = self.pos_embed.weight.unsqueeze(1).repeat(1, src.shape[1], 1) 92 | for layer in self.layers: 93 | output = layer(output, pos=pos) 94 | 95 | if self.norm is not None: 96 | output = self.norm(output) 97 | 98 | return output, pos 99 | 100 | 101 | class TransformerDecoder(nn.Module): 102 | 103 | def __init__(self, decoder_layer, num_layers, norm=None, return_intermediate=False): 104 | super().__init__() 105 | self.layers = _get_clones(decoder_layer, num_layers) 106 | self.num_layers = num_layers 107 | self.norm = norm 108 | self.return_intermediate = return_intermediate 109 | 110 | hidden_dim = 512 111 | self.query_embed = nn.Embedding(3600, hidden_dim) 112 | 113 | def forward(self, tgt, memory, 114 | tgt_mask: Optional[Tensor] = None, 115 | memory_mask: Optional[Tensor] = None, 116 | tgt_key_padding_mask: Optional[Tensor] = None, 117 | memory_key_padding_mask: Optional[Tensor] = None, 118 | pos: Optional[Tensor] = None, 119 | query_pos: Optional[Tensor] = None): 120 | output = tgt 121 | 122 | query_pos = self.query_embed.weight.unsqueeze(1).repeat(1, memory.shape[1], 1) 123 | intermediate = [] 124 | 125 | for layer in self.layers: 126 | output = layer(output, memory, tgt_mask=tgt_mask, 127 | memory_mask=memory_mask, 128 | tgt_key_padding_mask=tgt_key_padding_mask, 129 | memory_key_padding_mask=memory_key_padding_mask, 130 | pos=pos, query_pos=query_pos) 131 | if self.return_intermediate: 132 | intermediate.append(self.norm(output)) 133 | 134 | if self.norm is not None: 135 | output = self.norm(output) 136 | if self.return_intermediate: 137 | intermediate.pop() 138 | intermediate.append(output) 139 | 140 | if self.return_intermediate: 141 | return torch.stack(intermediate) 142 | 143 | return output.unsqueeze(0) 144 | 145 | 146 | class TransformerEncoderLayer(nn.Module): 147 | 148 | def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1, 149 | activation="relu", normalize_before=False): 150 | super().__init__() 151 | self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout) 152 | # Implementation of Feedforward model 153 | self.linear1 = nn.Linear(d_model, dim_feedforward) 154 | self.dropout = nn.Dropout(dropout) 155 | self.linear2 = nn.Linear(dim_feedforward, d_model) 156 | 157 | self.norm1 = nn.LayerNorm(d_model) 158 | self.norm2 = nn.LayerNorm(d_model) 159 | self.dropout1 = nn.Dropout(dropout) 160 | self.dropout2 = nn.Dropout(dropout) 161 | 162 | self.activation = _get_activation_fn(activation) 163 | self.normalize_before = normalize_before 164 | 165 | def with_pos_embed(self, tensor, pos: Optional[Tensor]): 166 | return tensor if pos is None else tensor + pos 167 | 168 | def forward_post(self, 169 | src, 170 | src_mask: Optional[Tensor] = None, 171 | src_key_padding_mask: Optional[Tensor] = None, 172 | pos: Optional[Tensor] = None): 173 | q = k = self.with_pos_embed(src, pos) 174 | src2 = self.self_attn(q, k, value=src, attn_mask=src_mask, 175 | key_padding_mask=src_key_padding_mask)[0] 176 | src = src + self.dropout1(src2) 177 | src = self.norm1(src) 178 | src2 = self.linear2(self.dropout(self.activation(self.linear1(src)))) 179 | src = src + self.dropout2(src2) 180 | src = self.norm2(src) 181 | return src 182 | 183 | def forward_pre(self, src, 184 | src_mask: Optional[Tensor] = None, 185 | src_key_padding_mask: Optional[Tensor] = None, 186 | pos: Optional[Tensor] = None): 187 | src2 = self.norm1(src) 188 | q = k = self.with_pos_embed(src2, pos) 189 | src2 = self.self_attn(q, k, value=src2, attn_mask=src_mask, 190 | key_padding_mask=src_key_padding_mask)[0] 191 | src = src + self.dropout1(src2) 192 | src2 = self.norm2(src) 193 | src2 = self.linear2(self.dropout(self.activation(self.linear1(src2)))) 194 | src = src + self.dropout2(src2) 195 | return src 196 | 197 | def forward(self, src, 198 | src_mask: Optional[Tensor] = None, 199 | src_key_padding_mask: Optional[Tensor] = None, 200 | pos: Optional[Tensor] = None): 201 | if self.normalize_before: 202 | return self.forward_pre(src, src_mask, src_key_padding_mask, pos) 203 | return self.forward_post(src, src_mask, src_key_padding_mask, pos) 204 | 205 | 206 | class TransformerDecoderLayer(nn.Module): 207 | 208 | def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1, 209 | activation="relu", normalize_before=False): 210 | super().__init__() 211 | self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout) 212 | self.multihead_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout) 213 | # Implementation of Feedforward model 214 | self.linear1 = nn.Linear(d_model, dim_feedforward) 215 | self.dropout = nn.Dropout(dropout) 216 | self.linear2 = nn.Linear(dim_feedforward, d_model) 217 | 218 | self.norm1 = nn.LayerNorm(d_model) 219 | self.norm2 = nn.LayerNorm(d_model) 220 | self.norm3 = nn.LayerNorm(d_model) 221 | self.dropout1 = nn.Dropout(dropout) 222 | self.dropout2 = nn.Dropout(dropout) 223 | self.dropout3 = nn.Dropout(dropout) 224 | 225 | self.activation = _get_activation_fn(activation) 226 | self.normalize_before = normalize_before 227 | 228 | def with_pos_embed(self, tensor, pos: Optional[Tensor]): 229 | return tensor if pos is None else tensor + pos 230 | 231 | def forward_post(self, tgt, memory, 232 | tgt_mask: Optional[Tensor] = None, 233 | memory_mask: Optional[Tensor] = None, 234 | tgt_key_padding_mask: Optional[Tensor] = None, 235 | memory_key_padding_mask: Optional[Tensor] = None, 236 | pos: Optional[Tensor] = None, 237 | query_pos: Optional[Tensor] = None): 238 | q = k = self.with_pos_embed(tgt, query_pos) 239 | tgt2 = self.self_attn(q, k, value=tgt, attn_mask=tgt_mask, 240 | key_padding_mask=tgt_key_padding_mask)[0] 241 | tgt = tgt + self.dropout1(tgt2) 242 | tgt = self.norm1(tgt) 243 | tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt, query_pos), 244 | key=self.with_pos_embed(memory, pos), 245 | value=memory, attn_mask=memory_mask, 246 | key_padding_mask=memory_key_padding_mask)[0] 247 | tgt = tgt + self.dropout2(tgt2) 248 | tgt = self.norm2(tgt) 249 | tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt)))) 250 | tgt = tgt + self.dropout3(tgt2) 251 | tgt = self.norm3(tgt) 252 | return tgt 253 | 254 | def forward_pre(self, tgt, memory, 255 | tgt_mask: Optional[Tensor] = None, 256 | memory_mask: Optional[Tensor] = None, 257 | tgt_key_padding_mask: Optional[Tensor] = None, 258 | memory_key_padding_mask: Optional[Tensor] = None, 259 | pos: Optional[Tensor] = None, 260 | query_pos: Optional[Tensor] = None): 261 | tgt2 = self.norm1(tgt) 262 | q = k = self.with_pos_embed(tgt2, query_pos) 263 | tgt2 = self.self_attn(q, k, value=tgt2, attn_mask=tgt_mask, 264 | key_padding_mask=tgt_key_padding_mask)[0] 265 | tgt = tgt + self.dropout1(tgt2) 266 | tgt2 = self.norm2(tgt) 267 | tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt2, query_pos), 268 | key=self.with_pos_embed(memory, pos), 269 | value=memory, attn_mask=memory_mask, 270 | key_padding_mask=memory_key_padding_mask)[0] 271 | tgt = tgt + self.dropout2(tgt2) 272 | tgt2 = self.norm3(tgt) 273 | tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt2)))) 274 | tgt = tgt + self.dropout3(tgt2) 275 | return tgt 276 | 277 | def forward(self, tgt, memory, 278 | tgt_mask: Optional[Tensor] = None, 279 | memory_mask: Optional[Tensor] = None, 280 | tgt_key_padding_mask: Optional[Tensor] = None, 281 | memory_key_padding_mask: Optional[Tensor] = None, 282 | pos: Optional[Tensor] = None, 283 | query_pos: Optional[Tensor] = None): 284 | if self.normalize_before: 285 | return self.forward_pre(tgt, memory, tgt_mask, memory_mask, 286 | tgt_key_padding_mask, memory_key_padding_mask, pos, query_pos) 287 | return self.forward_post(tgt, memory, tgt_mask, memory_mask, 288 | tgt_key_padding_mask, memory_key_padding_mask, pos, query_pos) 289 | 290 | 291 | def _get_clones(module, N): 292 | return nn.ModuleList([copy.deepcopy(module) for i in range(N)]) 293 | 294 | def build_transformer(hidden_dim, dropout, nheads, dim_feedforward, enc_layers, dec_layers, pre_norm): 295 | return Transformer( 296 | d_model=hidden_dim, 297 | dropout=dropout, 298 | nhead=nheads, 299 | dim_feedforward=dim_feedforward, 300 | num_encoder_layers=enc_layers, 301 | num_decoder_layers=dec_layers, 302 | normalize_before=pre_norm, 303 | return_intermediate_dec=False, 304 | ) 305 | 306 | 307 | def _get_activation_fn(activation): 308 | """Return an activation function given a string""" 309 | if activation == "relu": 310 | return F.relu 311 | if activation == "gelu": 312 | return F.gelu 313 | if activation == "glu": 314 | return F.glu 315 | raise RuntimeError(F"activation should be relu/gelu, not {activation}.") 316 | -------------------------------------------------------------------------------- /model/ugtr.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch import nn 3 | import torch.nn.functional as F 4 | 5 | import model.resnet as models 6 | import pdb 7 | import os 8 | import faiss 9 | import h5py 10 | import numpy as np 11 | from model.position_encoding import build_position_encoding 12 | from model.transformer import build_transformer 13 | from model.pmm import PMMs 14 | import torchvision 15 | from util.util import mask_from_tensor 16 | 17 | class UGTRNet(nn.Module): 18 | def __init__(self, layers=50, bins=(1, 2, 3, 6), dropout=0.1, classes=2, zoom_factor=8, use_ppm=True, criterion=nn.CrossEntropyLoss(ignore_index=255), BatchNorm=nn.BatchNorm2d, pretrained=True, dataset_name='', args=None): 19 | super(UGTRNet, self).__init__() 20 | assert layers in [50, 101, 152] 21 | assert 2048 % len(bins) == 0 22 | assert classes == 1 23 | assert zoom_factor in [1, 2, 4, 8] 24 | self.zoom_factor = zoom_factor 25 | self.use_ppm = use_ppm 26 | self.criterion = criterion 27 | self.args = args 28 | models.BatchNorm = BatchNorm 29 | 30 | if layers == 50: 31 | resnet = models.resnet50(pretrained=pretrained) 32 | elif layers == 101: 33 | resnet = models.resnet101(pretrained=pretrained) 34 | else: 35 | resnet = models.resnet152(pretrained=pretrained) 36 | self.layer0 = nn.Sequential(resnet.conv1, resnet.bn1, resnet.relu, resnet.conv2, resnet.bn2, resnet.relu, resnet.conv3, resnet.bn3, resnet.relu, resnet.maxpool) 37 | self.layer1, self.layer2, self.layer3, self.layer4 = resnet.layer1, resnet.layer2, resnet.layer3, resnet.layer4 38 | 39 | for n, m in self.layer3.named_modules(): 40 | if 'conv2' in n: 41 | m.dilation, m.padding, m.stride = (2, 2), (2, 2), (1, 1) 42 | elif 'downsample.0' in n: 43 | m.stride = (1, 1) 44 | for n, m in self.layer4.named_modules(): 45 | if 'conv2' in n: 46 | m.dilation, m.padding, m.stride = (4, 4), (4, 4), (1, 1) 47 | elif 'downsample.0' in n: 48 | m.stride = (1, 1) 49 | 50 | self.hidden_dim = 512 51 | self.input_proj = nn.Sequential(nn.Conv2d(2048, self.hidden_dim, kernel_size=1, bias=False),BatchNorm(self.hidden_dim),nn.ReLU(inplace=True),nn.Dropout2d(p=dropout)) 52 | self.pmm = PMMs(self.hidden_dim, 16) 53 | self.position_encoding = build_position_encoding(self.hidden_dim, 'v2') 54 | self.transformer = build_transformer(self.hidden_dim, dropout, nheads=8, dim_feedforward=2048, enc_layers=3, dec_layers=3, pre_norm=True) 55 | self.conv = nn.Conv2d(self.hidden_dim, self.hidden_dim, kernel_size=1, bias=False) 56 | 57 | self.mean_conv = nn.Conv2d(self.hidden_dim, 1, kernel_size=1, bias=False) 58 | self.std_conv = nn.Conv2d(self.hidden_dim, 1, kernel_size=1, bias=False) 59 | 60 | self.pred = nn.Conv2d(self.hidden_dim, 1, kernel_size=1) 61 | self.kl_loss = nn.KLDivLoss(size_average=False, reduce=False) 62 | 63 | kernel = torch.ones((7,7)) 64 | kernel = torch.FloatTensor(kernel).unsqueeze(0).unsqueeze(0) 65 | #kernel = np.repeat(kernel, 1, axis=0) 66 | self.weight = nn.Parameter(data=kernel, requires_grad=False) 67 | 68 | 69 | def reparameterize(self, mu, logvar, k=1): 70 | sample_z = [] 71 | for _ in range(k): 72 | std = logvar.mul(0.5).exp_() # type: Variable 73 | eps = std.data.new(std.size()).normal_() 74 | sample_z.append(eps.mul(std).add_(mu)) 75 | sample_z = torch.cat(sample_z, dim=1) 76 | return sample_z 77 | 78 | def forward(self, x, y=None): 79 | x_size = x.size() 80 | assert (x_size[2]-1) % 8 == 0 and (x_size[3]-1) % 8 == 0 81 | h = int((x_size[2] - 1) / 8 * self.zoom_factor + 1) 82 | w = int((x_size[3] - 1) / 8 * self.zoom_factor + 1) 83 | 84 | # step1. backbone feature 85 | x = self.layer0(x) 86 | x = self.layer1(x) 87 | x = self.layer2(x) 88 | x = self.layer3(x) 89 | x = self.layer4(x) 90 | 91 | # step2. 92 | x = self.input_proj(x) 93 | residual = self.conv(x) 94 | mean = self.mean_conv(x) 95 | std = self.std_conv(x) 96 | 97 | prob_x = self.reparameterize(mean, std, 1) 98 | prob_out2 = self.reparameterize(mean, std, 50) 99 | prob_out2 = torch.sigmoid(prob_out2) 100 | 101 | #uncertainty 102 | uncertainty = prob_out2.var(dim=1, keepdim=True).detach() 103 | if self.training: 104 | uncertainty = F.conv2d(uncertainty, self.weight, padding=3, groups=1) 105 | uncertainty = F.conv2d(uncertainty, self.weight, padding=3, groups=1) 106 | uncertainty = F.conv2d(uncertainty, self.weight, padding=3, groups=1) 107 | uncertainty = (uncertainty - uncertainty.min()) / (uncertainty.max() - uncertainty.min()) 108 | residual *= (1 - uncertainty) 109 | if self.training: 110 | rand_mask = uncertainty < torch.Tensor(np.random.random(uncertainty.size())).to(uncertainty.device) 111 | residual *= rand_mask.to(torch.float32) 112 | 113 | mean3 = prob_out2.mean(dim=1, keepdim=True) 114 | std3 = prob_out2.var(dim=1, keepdim=True) 115 | 116 | # step3. position encoding and gmm encoding 117 | x, mask = mask_from_tensor(x) 118 | position_encoding = self.position_encoding(x, mask).to(x.device) 119 | #x = x + position_encoding 120 | x, z_ = self.pmm(x) 121 | x = torch.stack(x, dim=3).squeeze(-1) 122 | 123 | #x, mask = mask_from_tensor(x) 124 | #position_encoding = self.position_encoding(x, mask).to(x.device) 125 | position_encoding = torch.bmm(position_encoding.flatten(2), z_).unsqueeze(2) 126 | # transformer 127 | x, t_loss = self.transformer(x, residual, position_encoding) #self.query_embed.weight, position_encoding, residual) 128 | x = self.pred(x) 129 | if self.zoom_factor != 1: 130 | prob_x = F.interpolate(prob_x, size=(h, w), mode='bilinear', align_corners=True) 131 | x = F.interpolate(x, size=(h, w), mode='bilinear', align_corners=True) 132 | mean3 = F.interpolate(mean3, size=(h, w), mode='bilinear', align_corners=True) 133 | std3 = F.interpolate(std3, size=(h, w), mode='bilinear', align_corners=True) 134 | #uncertainty = F.interpolate(uncertainty, size=(h, w), mode='bilinear', align_corners=True) 135 | 136 | if self.training: 137 | main_loss = self.criterion(x, y) + 0.5*self.criterion(prob_x, y) + 0.1*t_loss + 0.1*self.kl_loss(prob_x, y).sum() 138 | return x, main_loss 139 | else: 140 | return x, ((std3 - std3.min()) / (std3.max() - std3.min())), mean3#, uncertainty 141 | 142 | -------------------------------------------------------------------------------- /model_file/model.txt: -------------------------------------------------------------------------------- 1 | https://drive.google.com/file/d/1RFdqvzMZMzi6VdVl_8-sMgWT0Os-E9tE/view?usp=sharing -------------------------------------------------------------------------------- /pre_trained/model.txt: -------------------------------------------------------------------------------- 1 | https://drive.google.com/file/d/17WYyKg40DkAgFWOusiAKgqZOlfUFzjn5/view?usp=sharing -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import logging 4 | import argparse 5 | 6 | import cv2 7 | import numpy as np 8 | import torch 9 | import torch.backends.cudnn as cudnn 10 | import torch.nn.functional as F 11 | import torch.nn.parallel 12 | import torch.utils.data 13 | 14 | from util import dataset, transform, config 15 | from util.util import AverageMeter, intersectionAndUnion, check_makedirs, colorize, calc_mae, check_makedirs 16 | import pdb 17 | 18 | import datetime 19 | 20 | cv2.ocl.setUseOpenCL(False) 21 | 22 | 23 | def get_parser(): 24 | parser = argparse.ArgumentParser(description='PyTorch Semantic Segmentation') 25 | parser.add_argument('--config', type=str, default='config/cod_resnet50.yaml', help='config file') 26 | parser.add_argument('opts', help='see config/cod_resnet50.yaml for all options', default=None, nargs=argparse.REMAINDER) 27 | args = parser.parse_args() 28 | assert args.config is not None 29 | cfg = config.load_cfg_from_cfg_file(args.config) 30 | if args.opts is not None: 31 | cfg = config.merge_cfg_from_list(cfg, args.opts) 32 | return cfg 33 | 34 | 35 | def get_logger(): 36 | logger_name = "main-logger" 37 | logger = logging.getLogger(logger_name) 38 | logger.setLevel(logging.INFO) 39 | handler = logging.StreamHandler() 40 | fmt = "[%(asctime)s %(levelname)s %(filename)s line %(lineno)d %(process)d] %(message)s" 41 | handler.setFormatter(logging.Formatter(fmt)) 42 | logger.addHandler(handler) 43 | return logger 44 | 45 | 46 | def check(args): 47 | assert args.classes == 1 48 | assert args.zoom_factor in [1, 2, 4, 8] 49 | assert args.split in ['train', 'val', 'test'] 50 | if args.arch == 'ugtr': 51 | assert (args.train_h - 1) % 8 == 0 and (args.train_w - 1) % 8 == 0 52 | else: 53 | raise Exception('architecture not supported yet'.format(args.arch)) 54 | 55 | 56 | def main(): 57 | global args, logger 58 | args = get_parser() 59 | check(args) 60 | logger = get_logger() 61 | os.environ["CUDA_VISIBLE_DEVICES"] = ','.join(str(x) for x in args.test_gpu) 62 | logger.info(args) 63 | logger.info("=> creating model ...") 64 | logger.info("Classes: {}".format(args.classes)) 65 | 66 | value_scale = 255 67 | mean = [0.485, 0.456, 0.406] 68 | mean = [item * value_scale for item in mean] 69 | std = [0.229, 0.224, 0.225] 70 | std = [item * value_scale for item in std] 71 | 72 | date_str = str(datetime.datetime.now().date()) 73 | save_folder = args.save_folder + '/' + date_str 74 | check_makedirs(save_folder) 75 | 76 | gray_folder = os.path.join(save_folder, 'pred') 77 | 78 | test_transform = transform.Compose([ 79 | transform.Resize((args.test_h, args.test_w)), 80 | transform.ToTensor(), 81 | transform.Normalize(mean=mean, std=std)]) 82 | 83 | test_data = dataset.SemData(split=args.split, data_root=args.data_root, data_list=args.test_list, transform=test_transform) 84 | index_start = args.index_start 85 | if args.index_step == 0: 86 | index_end = len(test_data.data_list) 87 | else: 88 | index_end = min(index_start + args.index_step, len(test_data.data_list)) 89 | test_data.data_list = test_data.data_list[index_start:index_end] 90 | test_loader = torch.utils.data.DataLoader(test_data, batch_size=args.test_batch_size, shuffle=False, num_workers=args.workers, pin_memory=True) 91 | colors = np.loadtxt(args.colors_path).astype('uint8') 92 | names = [line.rstrip('\n') for line in open(args.names_path)] 93 | 94 | if not args.has_prediction: 95 | if args.arch == 'ugtr': 96 | from model.ugtr import UGTRNet 97 | model = UGTRNet(layers=args.layers, classes=args.classes, zoom_factor=args.zoom_factor, pretrained=False, dataset_name='COD10K', args=args) 98 | #logger.info(model) 99 | model = torch.nn.DataParallel(model).cuda() 100 | cudnn.benchmark = True 101 | if os.path.isfile(args.model_path): 102 | logger.info("=> loading checkpoint '{}'".format(args.model_path)) 103 | checkpoint = torch.load(args.model_path, map_location='cuda:0') 104 | model.load_state_dict(checkpoint['state_dict'], strict=False) 105 | logger.info("=> loaded checkpoint '{}', epoch {}".format(args.model_path, checkpoint['epoch'])) 106 | else: 107 | raise RuntimeError("=> no checkpoint found at '{}'".format(args.model_path)) 108 | test(test_loader, test_data.data_list, model, gray_folder) 109 | if args.split != 'test': 110 | calc_acc(test_data.data_list, gray_folder) 111 | 112 | 113 | def test(test_loader, data_list, model, gray_folder): 114 | logger.info('>>>>>>>>>>>>>>>> Start Evaluation >>>>>>>>>>>>>>>>') 115 | data_time = AverageMeter() 116 | batch_time = AverageMeter() 117 | model.eval() 118 | end = time.time() 119 | check_makedirs(gray_folder) 120 | for i, (input, _, _) in enumerate(test_loader): 121 | data_time.update(time.time() - end) 122 | with torch.no_grad(): 123 | region, uncertainty, mean = model(input) 124 | region = torch.sigmoid(region) 125 | #mean = torch.sigmoid(mean) 126 | 127 | batch_time.update(time.time() - end) 128 | end = time.time() 129 | if ((i + 1) % 10 == 0) or (i + 1 == len(test_loader)): 130 | logger.info('Test: [{}/{}] ' 131 | 'Data {data_time.val:.3f} ({data_time.avg:.3f}) ' 132 | 'Batch {batch_time.val:.3f} ({batch_time.avg:.3f}).'.format(i + 1, len(test_loader), 133 | data_time=data_time, 134 | batch_time=batch_time)) 135 | gray = np.uint8(region.squeeze().detach().cpu().numpy()*255) 136 | image_path, _, _ = data_list[i] 137 | image_name = image_path.split('/')[-1].split('.')[0] 138 | gray_path = os.path.join(gray_folder, image_name + '.png') 139 | 140 | cv2.imwrite(gray_path, gray) 141 | logger.info('<<<<<<<<<<<<<<<<< End Evaluation <<<<<<<<<<<<<<<<<') 142 | 143 | 144 | def calc_acc(data_list, pred_folder): 145 | r_mae = AverageMeter() 146 | e_mae = AverageMeter() 147 | 148 | for i, (image_path, target1_path, target2_path) in enumerate(data_list): 149 | image_name = image_path.split('/')[-1].split('.')[0] 150 | pred1 = cv2.imread(os.path.join(pred_folder, image_name+'.png'), cv2.IMREAD_GRAYSCALE) 151 | 152 | target1 = cv2.imread(target1_path, cv2.IMREAD_GRAYSCALE) 153 | 154 | if pred1.shape[0] != target1.shape[0] or pred1.shape[1] != target1.shape[1]: 155 | pred1 = cv2.resize(pred1, (target1.shape[1], target1.shape[0])) 156 | 157 | r_mae.update(calc_mae(pred1, target1)) 158 | 159 | logger.info('Evaluating {0}/{1} on image {2}, mae {3:.4f}.'.format(i + 1, len(data_list), image_name+'.png', r_mae.avg)) 160 | 161 | logger.info('Test result: r_mae / e_mae: {0:.3f}/{1:.3f}'.format(r_mae.avg, e_mae.avg)) 162 | 163 | if __name__ == '__main__': 164 | main() 165 | -------------------------------------------------------------------------------- /train.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import time 4 | import cv2 5 | import numpy as np 6 | import logging 7 | import argparse 8 | 9 | import torch 10 | import torch.backends.cudnn as cudnn 11 | import torch.nn as nn 12 | import torch.nn.functional as F 13 | import torch.nn.parallel 14 | import torch.optim 15 | import torch.utils.data 16 | import torch.multiprocessing as mp 17 | import torch.distributed as dist 18 | import apex 19 | from tensorboardX import SummaryWriter 20 | 21 | import pdb 22 | 23 | import datetime 24 | 25 | from util import dataset, transform, config 26 | from util.util import AverageMeter, poly_learning_rate, calc_mae, check_makedirs 27 | 28 | cv2.ocl.setUseOpenCL(False) 29 | cv2.setNumThreads(0) 30 | 31 | from os.path import join, exists, isfile, realpath, dirname 32 | from os import makedirs, remove, chdir, environ 33 | from torch.utils.data import DataLoader, SubsetRandomSampler 34 | import math 35 | import faiss 36 | import h5py 37 | 38 | def get_parser(): 39 | parser = argparse.ArgumentParser(description='PyTorch Semantic Segmentation') 40 | parser.add_argument('--config', type=str, default='config/cod_resnet50.yaml', help='config file') 41 | parser.add_argument('opts', help='see config/cod_resnet50.yaml for all options', default=None, nargs=argparse.REMAINDER) 42 | args = parser.parse_args() 43 | assert args.config is not None 44 | cfg = config.load_cfg_from_cfg_file(args.config) 45 | if args.opts is not None: 46 | cfg = config.merge_cfg_from_list(cfg, args.opts) 47 | return cfg 48 | 49 | 50 | def get_logger(): 51 | logger_name = "main-logger" 52 | logger = logging.getLogger(logger_name) 53 | logger.setLevel(logging.INFO) 54 | handler = logging.StreamHandler() 55 | fmt = "[%(asctime)s %(levelname)s %(filename)s line %(lineno)d %(process)d] %(message)s" 56 | handler.setFormatter(logging.Formatter(fmt)) 57 | logger.addHandler(handler) 58 | return logger 59 | 60 | 61 | def worker_init_fn(worker_id): 62 | random.seed(args.manual_seed + worker_id) 63 | 64 | 65 | def main_process(): 66 | return not args.multiprocessing_distributed or (args.multiprocessing_distributed and args.rank % args.ngpus_per_node == 0) 67 | 68 | 69 | def check(args): 70 | assert args.classes == 1 71 | assert args.zoom_factor in [1, 2, 4, 8] 72 | if args.arch == 'ugtr': 73 | assert (args.train_h - 1) % 8 == 0 and (args.train_w - 1) % 8 == 0 74 | else: 75 | raise Exception('architecture not supported yet'.format(args.arch)) 76 | 77 | 78 | def main(): 79 | args = get_parser() 80 | check(args) 81 | os.environ["CUDA_VISIBLE_DEVICES"] = ','.join(str(x) for x in args.train_gpu) 82 | 83 | save_folder = args.save_folder + '/tmp' 84 | gray_folder = os.path.join(save_folder, 'gray') 85 | check_makedirs(save_folder) 86 | check_makedirs(gray_folder) 87 | 88 | if args.manual_seed is not None: 89 | random.seed(args.manual_seed) 90 | np.random.seed(args.manual_seed) 91 | torch.manual_seed(manualSeed) 92 | torch.cuda.manual_seed(manualSeed) 93 | torch.cuda.manual_seed_all(manualSeed) 94 | cudnn.benchmark = False 95 | cudnn.deterministic = True 96 | if args.dist_url == "env://" and args.world_size == -1: 97 | args.world_size = int(os.environ["WORLD_SIZE"]) 98 | args.distributed = args.world_size > 1 or args.multiprocessing_distributed 99 | args.ngpus_per_node = len(args.train_gpu) 100 | if len(args.train_gpu) == 1: 101 | args.sync_bn = False 102 | args.distributed = False 103 | args.multiprocessing_distributed = False 104 | if args.multiprocessing_distributed: 105 | args.world_size = args.ngpus_per_node * args.world_size 106 | mp.spawn(main_worker, nprocs=args.ngpus_per_node, args=(args.ngpus_per_node, args, gray_folder)) 107 | else: 108 | main_worker(args.train_gpu, args.ngpus_per_node, args, gray_folder) 109 | 110 | 111 | def main_worker(gpu, ngpus_per_node, argss, gray_folder): 112 | global args 113 | args = argss 114 | if args.sync_bn: 115 | if args.multiprocessing_distributed: 116 | BatchNorm = apex.parallel.SyncBatchNorm 117 | else: 118 | from lib.sync_bn.modules import BatchNorm2d 119 | BatchNorm = BatchNorm2d 120 | else: 121 | BatchNorm = nn.BatchNorm2d 122 | if args.distributed: 123 | if args.dist_url == "env://" and args.rank == -1: 124 | args.rank = int(os.environ["RANK"]) 125 | if args.multiprocessing_distributed: 126 | args.rank = args.rank * ngpus_per_node + gpu 127 | dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, world_size=args.world_size, rank=args.rank) 128 | 129 | # criterion = nn.CrossEntropyLoss(ignore_index=args.ignore_label) 130 | #criterion = structure_loss 131 | criterion = nn.BCEWithLogitsLoss(reduction='sum') 132 | if args.arch == 'ugtr': 133 | from model.ugtr import UGTRNet 134 | model = UGTRNet(layers=args.layers, classes=args.classes, zoom_factor=args.zoom_factor, criterion=criterion, BatchNorm=BatchNorm, pretrained=False, dataset_name='COD10K', args=args) 135 | 136 | modules_ori = [model.layer0, model.layer1, model.layer2, model.layer3, model.layer4] 137 | modules_new = [model.input_proj, model.position_encoding, model.transformer, model.pred] 138 | 139 | frozen_layers = [] 140 | for l in frozen_layers: 141 | for p in l.parameters(): 142 | p.requires_grad = False 143 | 144 | params_list = [] 145 | for module in modules_ori: 146 | params_list.append(dict(params=module.parameters(), lr=args.base_lr )) 147 | for module in modules_new: 148 | params_list.append(dict(params=module.parameters(), lr=args.base_lr * 10)) 149 | args.index_split = 5 150 | optimizer = torch.optim.SGD(params_list, lr=args.base_lr, momentum=args.momentum, weight_decay=args.weight_decay) 151 | 152 | if main_process(): 153 | global logger, writer 154 | logger = get_logger() 155 | writer = SummaryWriter(args.save_path) 156 | logger.info(args) 157 | logger.info("=> creating model ...") 158 | logger.info("Classes: {}".format(args.classes)) 159 | logger.info(model) 160 | if args.distributed: 161 | torch.cuda.set_device(gpu) 162 | args.batch_size = int(args.batch_size / ngpus_per_node) 163 | args.batch_size_val = int(args.batch_size_val / ngpus_per_node) 164 | args.workers = int(args.workers / ngpus_per_node) 165 | if args.use_apex: 166 | model, optimizer = apex.amp.initialize(model.cuda(), optimizer, opt_level=args.opt_level, keep_batchnorm_fp32=args.keep_batchnorm_fp32, loss_scale=args.loss_scale) 167 | model = apex.parallel.DistributedDataParallel(model) 168 | else: 169 | model = torch.nn.parallel.DistributedDataParallel(model.cuda(), device_ids=[gpu]) 170 | 171 | else: 172 | model = torch.nn.DataParallel(model.cuda()) 173 | 174 | 175 | if args.weight: 176 | if os.path.isfile(args.weight): 177 | if main_process(): 178 | logger.info("=> loading weight '{}'".format(args.weight)) 179 | checkpoint = torch.load(args.weight) 180 | model.load_state_dict(checkpoint['state_dict'], strict=False) 181 | if main_process(): 182 | logger.info("=> loaded weight '{}', epoch {}".format(args.weight, checkpoint['epoch'])) 183 | else: 184 | if main_process(): 185 | logger.info("=> no weight found at '{}'".format(args.weight)) 186 | 187 | if args.resume: 188 | if os.path.isfile(args.resume): 189 | if main_process(): 190 | logger.info("=> loading checkpoint '{}'".format(args.resume)) 191 | # checkpoint = torch.load(args.resume) 192 | checkpoint = torch.load(args.resume, map_location=lambda storage, loc: storage.cuda()) 193 | args.start_epoch = checkpoint['epoch'] 194 | model.load_state_dict(checkpoint['state_dict']) 195 | optimizer.load_state_dict(checkpoint['optimizer']) 196 | if main_process(): 197 | logger.info("=> loaded checkpoint '{}' (epoch {})".format(args.resume, checkpoint['epoch'])) 198 | else: 199 | if main_process(): 200 | logger.info("=> no checkpoint found at '{}'".format(args.resume)) 201 | 202 | value_scale = 255 203 | mean = [0.485, 0.456, 0.406] 204 | mean = [item * value_scale for item in mean] 205 | std = [0.229, 0.224, 0.225] 206 | std = [item * value_scale for item in std] 207 | 208 | train_transform = transform.Compose([ 209 | transform.Resize((args.train_h, args.train_w)), 210 | #transform.RandScale([args.scale_min, args.scale_max]), 211 | #transform.RandomEqualizeHist(), 212 | transform.RandRotate([args.rotate_min, args.rotate_max], padding=mean, ignore_label=args.ignore_label), 213 | transform.RandomGaussianBlur(), 214 | transform.RandomHorizontalFlip(), 215 | transform.RandomVerticalFlip(), 216 | #transform.Crop([args.train_h, args.train_w], crop_type='rand', padding=mean, ignore_label=args.ignore_label), 217 | transform.ToTensor(), 218 | transform.Normalize(mean=mean, std=std)]) 219 | train_data = dataset.SemData(split='train', data_root=args.data_root, data_list=args.train_list, transform=train_transform) 220 | if args.distributed: 221 | train_sampler = torch.utils.data.distributed.DistributedSampler(train_data) 222 | else: 223 | train_sampler = None 224 | train_loader = torch.utils.data.DataLoader(train_data, batch_size=args.batch_size, shuffle=(train_sampler is None), num_workers=args.workers, pin_memory=True, sampler=train_sampler, drop_last=True) 225 | 226 | if args.evaluate: 227 | val_transform = transform.Compose([ 228 | transform.Resize((args.train_h, args.train_w)), 229 | transform.ToTensor(), 230 | transform.Normalize(mean=mean, std=std)]) 231 | val_data = dataset.SemData(split='val', data_root=args.data_root, data_list=args.val_list, transform=val_transform) 232 | if args.distributed: 233 | val_sampler = torch.utils.data.distributed.DistributedSampler(val_data) 234 | else: 235 | val_sampler = None 236 | val_loader = torch.utils.data.DataLoader(val_data, batch_size=args.batch_size_val, shuffle=False, num_workers=args.workers, pin_memory=True, sampler=val_sampler) 237 | 238 | 239 | date_str = str(datetime.datetime.now().date()) 240 | check_makedirs(args.save_path + '/' + date_str) 241 | best_mae = 255. 242 | for epoch in range(args.start_epoch, args.epochs): 243 | epoch_log = epoch + 1 244 | if args.distributed: 245 | train_sampler.set_epoch(epoch) 246 | loss_train = train(train_loader, model, optimizer, epoch, train_data.data_list) 247 | if main_process(): 248 | writer.add_scalar('loss_train', loss_train, epoch_log) 249 | 250 | # pdb.set_trace() 251 | if args.evaluate: 252 | r_mae, e_mae = validate(val_loader, model, gray_folder, val_data.data_list) 253 | if main_process(): 254 | writer.add_scalar('r_mae', r_mae) 255 | writer.add_scalar('e_mae', e_mae) 256 | curr_mae = r_mae # + e_mae 257 | 258 | if curr_mae < best_mae and main_process(): 259 | best_mae = curr_mae 260 | filename = args.save_path + '/' + date_str + '/train_best.pth' 261 | 262 | try: 263 | if os.path.exists(filename): 264 | os.remove(filename) 265 | if main_process(): 266 | logger.info('Saving checkpoint to: ' + filename) 267 | torch.save({'epoch': epoch_log, 'state_dict': model.state_dict(), 'optimizer': optimizer.state_dict()}, filename) 268 | 269 | filename = args.save_path + '/' + date_str + '/train_epoch_' + str(epoch_log) + '_best.pth' 270 | #torch.save({'epoch': epoch_log, 'state_dict': model.state_dict(), 'optimizer': optimizer.state_dict()}, filename) 271 | except IOError: 272 | logger.info('error') 273 | 274 | if (epoch_log % args.save_freq == 0) and main_process(): 275 | filename = args.save_path + '/' + date_str + '/train_epoch_' + str(epoch_log) + '.pth' 276 | logger.info('Saving checkpoint to: ' + filename) 277 | torch.save({'epoch': epoch_log, 'state_dict': model.state_dict(), 'optimizer': optimizer.state_dict()}, filename) 278 | 279 | if epoch_log / args.save_freq > 2: 280 | deletename = args.save_path + '/' + date_str + '/train_epoch_' + str(epoch_log - args.save_freq * 2) + '.pth' 281 | try: 282 | if os.path.exists(deletename): 283 | os.remove(deletename) 284 | except IOError: 285 | logger.info('error') 286 | 287 | def train(train_loader, model, optimizer, epoch, data_list): 288 | batch_time = AverageMeter() 289 | data_time = AverageMeter() 290 | main_loss_meter = AverageMeter() 291 | #aux_loss_meter = AverageMeter() 292 | loss_meter = AverageMeter() 293 | intersection_meter = AverageMeter() 294 | union_meter = AverageMeter() 295 | target_meter = AverageMeter() 296 | 297 | visual = False 298 | if visual: 299 | date_str = str(datetime.datetime.now().date()) 300 | save_folder = args.save_folder + '/' + date_str 301 | check_makedirs(save_folder) 302 | 303 | fg_folder = os.path.join(save_folder, 'fg') 304 | bg_folder = os.path.join(save_folder, 'bg') 305 | check_makedirs(fg_folder) 306 | check_makedirs(bg_folder) 307 | 308 | model.train() 309 | end = time.time() 310 | max_iter = args.epochs * len(train_loader) 311 | for i, (input, target, edge) in enumerate(train_loader): 312 | data_time.update(time.time() - end) 313 | if args.zoom_factor != 8: 314 | h = int((target.size()[1] - 1) / 8 * args.zoom_factor + 1) 315 | w = int((target.size()[2] - 1) / 8 * args.zoom_factor + 1) 316 | # 'nearest' mode doesn't support align_corners mode and 'bilinear' mode is fine for downsampling 317 | target = F.interpolate(target.unsqueeze(1).float(), size=(h, w), mode='bilinear', align_corners=True).squeeze(1).long() 318 | edge = F.interpolate(edge.unsqueeze(1).float(), size=(h, w), mode='bilinear', align_corners=True).squeeze(1).long() 319 | 320 | 321 | target = torch.where(target > 127, torch.full_like(target, 255), torch.full_like(target, 0)) 322 | edge = torch.where(edge > 127, torch.full_like(edge, 255), torch.full_like(edge, 0)) 323 | 324 | input = input.cuda(non_blocking=True) 325 | target = target.cuda(non_blocking=True) 326 | edge = edge.cuda(non_blocking=True) 327 | 328 | target = target.unsqueeze(1).float() / 255. 329 | edge = edge.unsqueeze(1).float() / 255. 330 | 331 | region, main_loss = model(input, target) 332 | 333 | if not args.multiprocessing_distributed: 334 | main_loss = torch.mean(main_loss) 335 | loss = main_loss 336 | 337 | optimizer.zero_grad() 338 | if args.use_apex and args.multiprocessing_distributed: 339 | with apex.amp.scale_loss(loss, optimizer) as scaled_loss: 340 | scaled_loss.backward() 341 | else: 342 | loss.backward() 343 | optimizer.step() 344 | # output = torch.sigmoid(output) 345 | n = input.size(0) 346 | if args.multiprocessing_distributed: 347 | main_loss, loss = main_loss.detach() * n, loss * n # not considering ignore pixels 348 | count = target.new_tensor([n], dtype=torch.long) 349 | dist.all_reduce(main_loss), dist.all_reduce(loss), dist.all_reduce(count) 350 | n = count.item() 351 | main_loss, loss = main_loss / n, loss / n 352 | 353 | main_loss_meter.update(main_loss.item(), n) 354 | loss_meter.update(loss.item(), n) 355 | batch_time.update(time.time() - end) 356 | end = time.time() 357 | 358 | current_iter = epoch * len(train_loader) + i + 1 359 | current_lr = poly_learning_rate(args.base_lr, current_iter, max_iter, power=args.power) 360 | for index in range(0, args.index_split): # backbone 361 | optimizer.param_groups[index]['lr'] = current_lr 362 | for index in range(args.index_split, len(optimizer.param_groups)): 363 | optimizer.param_groups[index]['lr'] = current_lr * 10 364 | remain_iter = max_iter - current_iter 365 | remain_time = remain_iter * batch_time.avg 366 | t_m, t_s = divmod(remain_time, 60) 367 | t_h, t_m = divmod(t_m, 60) 368 | remain_time = '{:02d}:{:02d}:{:02d}'.format(int(t_h), int(t_m), int(t_s)) 369 | 370 | if (i + 1) % args.print_freq == 0 and main_process(): 371 | logger.info('Epoch: [{}/{}][{}/{}] ' 372 | 'Data {data_time.val:.3f} ({data_time.avg:.3f}) ' 373 | 'Batch {batch_time.val:.3f} ({batch_time.avg:.3f}) ' 374 | 'Remain {remain_time} ' 375 | 'MainLoss {main_loss_meter.val:.4f} ' 376 | 'Loss {loss_meter.val:.4f} '.format(epoch+1, args.epochs, i + 1, len(train_loader), 377 | batch_time=batch_time, 378 | data_time=data_time, 379 | remain_time=remain_time, 380 | main_loss_meter=main_loss_meter, 381 | loss_meter=loss_meter)) 382 | if main_process(): 383 | writer.add_scalar('loss_train_batch', main_loss_meter.val, current_iter) 384 | if main_process(): 385 | logger.info('Train result at epoch [{}/{}]'.format(epoch+1, args.epochs)) 386 | 387 | torch.cuda.empty_cache() 388 | 389 | return main_loss_meter.avg 390 | 391 | 392 | def validate(val_loader, model, gray_folder, data_list): 393 | if main_process(): 394 | logger.info('>>>>>>>>>>>>>>>> Start Evaluation >>>>>>>>>>>>>>>>') 395 | r_mae, e_mae = AverageMeter(), AverageMeter() 396 | 397 | sync_idx = 0 398 | 399 | model.eval() 400 | for i, (input, target1, target2) in enumerate(val_loader): 401 | input = input.cuda(non_blocking=True) 402 | with torch.no_grad(): 403 | pred1, _, _ = model(input) 404 | pred1 = torch.sigmoid(pred1.squeeze(1)) 405 | 406 | if args.zoom_factor != 8: 407 | pred1 = F.interpolate(pred1, size=target.size()[1:], mode='bilinear', align_corners=True) 408 | 409 | pred1 = pred1.detach().cpu().numpy() 410 | target1 = target1.numpy() 411 | 412 | for j in range(len(pred1)): 413 | pred1_j = np.uint8(pred1[j]*255) 414 | if pred1_j is not None: 415 | r_mae.update(calc_mae(pred1_j, target1[j])) 416 | 417 | sync_idx += 1 418 | 419 | if main_process(): 420 | logger.info('val result: region_mae / edge_mae {:.7f}/{:.7f}'.format(r_mae.avg, e_mae.avg)) 421 | logger.info('<<<<<<<<<<<<<<<<< End Evaluation <<<<<<<<<<<<<<<<<') 422 | 423 | return r_mae.avg, e_mae.avg 424 | 425 | 426 | if __name__ == '__main__': 427 | main() 428 | 429 | -------------------------------------------------------------------------------- /train_test_file/CAMO_test.lst: -------------------------------------------------------------------------------- 1 | CAMO_test/Image/camourflage_01032.jpg CAMO_test/GT/camourflage_01032.png CAMO_test/Edge/camourflage_01032.png 2 | CAMO_test/Image/camourflage_01048.jpg CAMO_test/GT/camourflage_01048.png CAMO_test/Edge/camourflage_01048.png 3 | CAMO_test/Image/camourflage_00688.jpg CAMO_test/GT/camourflage_00688.png CAMO_test/Edge/camourflage_00688.png 4 | CAMO_test/Image/camourflage_01091.jpg CAMO_test/GT/camourflage_01091.png CAMO_test/Edge/camourflage_01091.png 5 | CAMO_test/Image/camourflage_00977.jpg CAMO_test/GT/camourflage_00977.png CAMO_test/Edge/camourflage_00977.png 6 | CAMO_test/Image/camourflage_00120.jpg CAMO_test/GT/camourflage_00120.png CAMO_test/Edge/camourflage_00120.png 7 | CAMO_test/Image/camourflage_00381.jpg CAMO_test/GT/camourflage_00381.png CAMO_test/Edge/camourflage_00381.png 8 | CAMO_test/Image/camourflage_00998.jpg CAMO_test/GT/camourflage_00998.png CAMO_test/Edge/camourflage_00998.png 9 | CAMO_test/Image/camourflage_00361.jpg CAMO_test/GT/camourflage_00361.png CAMO_test/Edge/camourflage_00361.png 10 | CAMO_test/Image/camourflage_00232.jpg CAMO_test/GT/camourflage_00232.png CAMO_test/Edge/camourflage_00232.png 11 | CAMO_test/Image/camourflage_00602.jpg CAMO_test/GT/camourflage_00602.png CAMO_test/Edge/camourflage_00602.png 12 | CAMO_test/Image/camourflage_01027.jpg CAMO_test/GT/camourflage_01027.png CAMO_test/Edge/camourflage_01027.png 13 | CAMO_test/Image/camourflage_01113.jpg CAMO_test/GT/camourflage_01113.png CAMO_test/Edge/camourflage_01113.png 14 | CAMO_test/Image/camourflage_01182.jpg CAMO_test/GT/camourflage_01182.png CAMO_test/Edge/camourflage_01182.png 15 | CAMO_test/Image/camourflage_01195.jpg CAMO_test/GT/camourflage_01195.png CAMO_test/Edge/camourflage_01195.png 16 | CAMO_test/Image/camourflage_01128.jpg CAMO_test/GT/camourflage_01128.png CAMO_test/Edge/camourflage_01128.png 17 | CAMO_test/Image/camourflage_00102.jpg CAMO_test/GT/camourflage_00102.png CAMO_test/Edge/camourflage_00102.png 18 | CAMO_test/Image/camourflage_00266.jpg CAMO_test/GT/camourflage_00266.png CAMO_test/Edge/camourflage_00266.png 19 | CAMO_test/Image/camourflage_01064.jpg CAMO_test/GT/camourflage_01064.png CAMO_test/Edge/camourflage_01064.png 20 | CAMO_test/Image/camourflage_00928.jpg CAMO_test/GT/camourflage_00928.png CAMO_test/Edge/camourflage_00928.png 21 | CAMO_test/Image/camourflage_00012.jpg CAMO_test/GT/camourflage_00012.png CAMO_test/Edge/camourflage_00012.png 22 | CAMO_test/Image/camourflage_01021.jpg CAMO_test/GT/camourflage_01021.png CAMO_test/Edge/camourflage_01021.png 23 | CAMO_test/Image/camourflage_01023.jpg CAMO_test/GT/camourflage_01023.png CAMO_test/Edge/camourflage_01023.png 24 | CAMO_test/Image/camourflage_00270.jpg CAMO_test/GT/camourflage_00270.png CAMO_test/Edge/camourflage_00270.png 25 | CAMO_test/Image/camourflage_01170.jpg CAMO_test/GT/camourflage_01170.png CAMO_test/Edge/camourflage_01170.png 26 | CAMO_test/Image/camourflage_00890.jpg CAMO_test/GT/camourflage_00890.png CAMO_test/Edge/camourflage_00890.png 27 | CAMO_test/Image/camourflage_00196.jpg CAMO_test/GT/camourflage_00196.png CAMO_test/Edge/camourflage_00196.png 28 | CAMO_test/Image/camourflage_01072.jpg CAMO_test/GT/camourflage_01072.png CAMO_test/Edge/camourflage_01072.png 29 | CAMO_test/Image/camourflage_00706.jpg CAMO_test/GT/camourflage_00706.png CAMO_test/Edge/camourflage_00706.png 30 | CAMO_test/Image/camourflage_00098.jpg CAMO_test/GT/camourflage_00098.png CAMO_test/Edge/camourflage_00098.png 31 | CAMO_test/Image/camourflage_00519.jpg CAMO_test/GT/camourflage_00519.png CAMO_test/Edge/camourflage_00519.png 32 | CAMO_test/Image/camourflage_01117.jpg CAMO_test/GT/camourflage_01117.png CAMO_test/Edge/camourflage_01117.png 33 | CAMO_test/Image/camourflage_01098.jpg CAMO_test/GT/camourflage_01098.png CAMO_test/Edge/camourflage_01098.png 34 | CAMO_test/Image/camourflage_00449.jpg CAMO_test/GT/camourflage_00449.png CAMO_test/Edge/camourflage_00449.png 35 | CAMO_test/Image/camourflage_00470.jpg CAMO_test/GT/camourflage_00470.png CAMO_test/Edge/camourflage_00470.png 36 | CAMO_test/Image/camourflage_01193.jpg CAMO_test/GT/camourflage_01193.png CAMO_test/Edge/camourflage_01193.png 37 | CAMO_test/Image/camourflage_01044.jpg CAMO_test/GT/camourflage_01044.png CAMO_test/Edge/camourflage_01044.png 38 | CAMO_test/Image/camourflage_01179.jpg CAMO_test/GT/camourflage_01179.png CAMO_test/Edge/camourflage_01179.png 39 | CAMO_test/Image/camourflage_00160.jpg CAMO_test/GT/camourflage_00160.png CAMO_test/Edge/camourflage_00160.png 40 | CAMO_test/Image/camourflage_00750.jpg CAMO_test/GT/camourflage_00750.png CAMO_test/Edge/camourflage_00750.png 41 | CAMO_test/Image/camourflage_00114.jpg CAMO_test/GT/camourflage_00114.png CAMO_test/Edge/camourflage_00114.png 42 | CAMO_test/Image/camourflage_00931.jpg CAMO_test/GT/camourflage_00931.png CAMO_test/Edge/camourflage_00931.png 43 | CAMO_test/Image/camourflage_01034.jpg CAMO_test/GT/camourflage_01034.png CAMO_test/Edge/camourflage_01034.png 44 | CAMO_test/Image/camourflage_00829.jpg CAMO_test/GT/camourflage_00829.png CAMO_test/Edge/camourflage_00829.png 45 | CAMO_test/Image/camourflage_00285.jpg CAMO_test/GT/camourflage_00285.png CAMO_test/Edge/camourflage_00285.png 46 | CAMO_test/Image/camourflage_00471.jpg CAMO_test/GT/camourflage_00471.png CAMO_test/Edge/camourflage_00471.png 47 | CAMO_test/Image/camourflage_01143.jpg CAMO_test/GT/camourflage_01143.png CAMO_test/Edge/camourflage_01143.png 48 | CAMO_test/Image/camourflage_00502.jpg CAMO_test/GT/camourflage_00502.png CAMO_test/Edge/camourflage_00502.png 49 | CAMO_test/Image/camourflage_01004.jpg CAMO_test/GT/camourflage_01004.png CAMO_test/Edge/camourflage_01004.png 50 | CAMO_test/Image/camourflage_01046.jpg CAMO_test/GT/camourflage_01046.png CAMO_test/Edge/camourflage_01046.png 51 | CAMO_test/Image/camourflage_01056.jpg CAMO_test/GT/camourflage_01056.png CAMO_test/Edge/camourflage_01056.png 52 | CAMO_test/Image/camourflage_01208.jpg CAMO_test/GT/camourflage_01208.png CAMO_test/Edge/camourflage_01208.png 53 | CAMO_test/Image/camourflage_01235.jpg CAMO_test/GT/camourflage_01235.png CAMO_test/Edge/camourflage_01235.png 54 | CAMO_test/Image/camourflage_01145.jpg CAMO_test/GT/camourflage_01145.png CAMO_test/Edge/camourflage_01145.png 55 | CAMO_test/Image/camourflage_01020.jpg CAMO_test/GT/camourflage_01020.png CAMO_test/Edge/camourflage_01020.png 56 | CAMO_test/Image/camourflage_01156.jpg CAMO_test/GT/camourflage_01156.png CAMO_test/Edge/camourflage_01156.png 57 | CAMO_test/Image/camourflage_00444.jpg CAMO_test/GT/camourflage_00444.png CAMO_test/Edge/camourflage_00444.png 58 | CAMO_test/Image/camourflage_01087.jpg CAMO_test/GT/camourflage_01087.png CAMO_test/Edge/camourflage_01087.png 59 | CAMO_test/Image/camourflage_00273.jpg CAMO_test/GT/camourflage_00273.png CAMO_test/Edge/camourflage_00273.png 60 | CAMO_test/Image/camourflage_01161.jpg CAMO_test/GT/camourflage_01161.png CAMO_test/Edge/camourflage_01161.png 61 | CAMO_test/Image/camourflage_00259.jpg CAMO_test/GT/camourflage_00259.png CAMO_test/Edge/camourflage_00259.png 62 | CAMO_test/Image/camourflage_01018.jpg CAMO_test/GT/camourflage_01018.png CAMO_test/Edge/camourflage_01018.png 63 | CAMO_test/Image/camourflage_01112.jpg CAMO_test/GT/camourflage_01112.png CAMO_test/Edge/camourflage_01112.png 64 | CAMO_test/Image/camourflage_00257.jpg CAMO_test/GT/camourflage_00257.png CAMO_test/Edge/camourflage_00257.png 65 | CAMO_test/Image/camourflage_00436.jpg CAMO_test/GT/camourflage_00436.png CAMO_test/Edge/camourflage_00436.png 66 | CAMO_test/Image/camourflage_00500.jpg CAMO_test/GT/camourflage_00500.png CAMO_test/Edge/camourflage_00500.png 67 | CAMO_test/Image/camourflage_01135.jpg CAMO_test/GT/camourflage_01135.png CAMO_test/Edge/camourflage_01135.png 68 | CAMO_test/Image/camourflage_00088.jpg CAMO_test/GT/camourflage_00088.png CAMO_test/Edge/camourflage_00088.png 69 | CAMO_test/Image/camourflage_00807.jpg CAMO_test/GT/camourflage_00807.png CAMO_test/Edge/camourflage_00807.png 70 | CAMO_test/Image/camourflage_00510.jpg CAMO_test/GT/camourflage_00510.png CAMO_test/Edge/camourflage_00510.png 71 | CAMO_test/Image/camourflage_00275.jpg CAMO_test/GT/camourflage_00275.png CAMO_test/Edge/camourflage_00275.png 72 | CAMO_test/Image/camourflage_00332.jpg CAMO_test/GT/camourflage_00332.png CAMO_test/Edge/camourflage_00332.png 73 | CAMO_test/Image/camourflage_01052.jpg CAMO_test/GT/camourflage_01052.png CAMO_test/Edge/camourflage_01052.png 74 | CAMO_test/Image/camourflage_01074.jpg CAMO_test/GT/camourflage_01074.png CAMO_test/Edge/camourflage_01074.png 75 | CAMO_test/Image/camourflage_00631.jpg CAMO_test/GT/camourflage_00631.png CAMO_test/Edge/camourflage_00631.png 76 | CAMO_test/Image/camourflage_00153.jpg CAMO_test/GT/camourflage_00153.png CAMO_test/Edge/camourflage_00153.png 77 | CAMO_test/Image/camourflage_01196.jpg CAMO_test/GT/camourflage_01196.png CAMO_test/Edge/camourflage_01196.png 78 | CAMO_test/Image/camourflage_01082.jpg CAMO_test/GT/camourflage_01082.png CAMO_test/Edge/camourflage_01082.png 79 | CAMO_test/Image/camourflage_00794.jpg CAMO_test/GT/camourflage_00794.png CAMO_test/Edge/camourflage_00794.png 80 | CAMO_test/Image/camourflage_01210.jpg CAMO_test/GT/camourflage_01210.png CAMO_test/Edge/camourflage_01210.png 81 | CAMO_test/Image/camourflage_01115.jpg CAMO_test/GT/camourflage_01115.png CAMO_test/Edge/camourflage_01115.png 82 | CAMO_test/Image/camourflage_00112.jpg CAMO_test/GT/camourflage_00112.png CAMO_test/Edge/camourflage_00112.png 83 | CAMO_test/Image/camourflage_00528.jpg CAMO_test/GT/camourflage_00528.png CAMO_test/Edge/camourflage_00528.png 84 | CAMO_test/Image/camourflage_01009.jpg CAMO_test/GT/camourflage_01009.png CAMO_test/Edge/camourflage_01009.png 85 | CAMO_test/Image/camourflage_01250.jpg CAMO_test/GT/camourflage_01250.png CAMO_test/Edge/camourflage_01250.png 86 | CAMO_test/Image/camourflage_01199.jpg CAMO_test/GT/camourflage_01199.png CAMO_test/Edge/camourflage_01199.png 87 | CAMO_test/Image/camourflage_00197.jpg CAMO_test/GT/camourflage_00197.png CAMO_test/Edge/camourflage_00197.png 88 | CAMO_test/Image/camourflage_01116.jpg CAMO_test/GT/camourflage_01116.png CAMO_test/Edge/camourflage_01116.png 89 | CAMO_test/Image/camourflage_00600.jpg CAMO_test/GT/camourflage_00600.png CAMO_test/Edge/camourflage_00600.png 90 | CAMO_test/Image/camourflage_00959.jpg CAMO_test/GT/camourflage_00959.png CAMO_test/Edge/camourflage_00959.png 91 | CAMO_test/Image/camourflage_01103.jpg CAMO_test/GT/camourflage_01103.png CAMO_test/Edge/camourflage_01103.png 92 | CAMO_test/Image/camourflage_00647.jpg CAMO_test/GT/camourflage_00647.png CAMO_test/Edge/camourflage_00647.png 93 | CAMO_test/Image/camourflage_00135.jpg CAMO_test/GT/camourflage_00135.png CAMO_test/Edge/camourflage_00135.png 94 | CAMO_test/Image/camourflage_00443.jpg CAMO_test/GT/camourflage_00443.png CAMO_test/Edge/camourflage_00443.png 95 | CAMO_test/Image/camourflage_01181.jpg CAMO_test/GT/camourflage_01181.png CAMO_test/Edge/camourflage_01181.png 96 | CAMO_test/Image/camourflage_01154.jpg CAMO_test/GT/camourflage_01154.png CAMO_test/Edge/camourflage_01154.png 97 | CAMO_test/Image/camourflage_01148.jpg CAMO_test/GT/camourflage_01148.png CAMO_test/Edge/camourflage_01148.png 98 | CAMO_test/Image/camourflage_00783.jpg CAMO_test/GT/camourflage_00783.png CAMO_test/Edge/camourflage_00783.png 99 | CAMO_test/Image/camourflage_01140.jpg CAMO_test/GT/camourflage_01140.png CAMO_test/Edge/camourflage_01140.png 100 | CAMO_test/Image/camourflage_00522.jpg CAMO_test/GT/camourflage_00522.png CAMO_test/Edge/camourflage_00522.png 101 | CAMO_test/Image/camourflage_01118.jpg CAMO_test/GT/camourflage_01118.png CAMO_test/Edge/camourflage_01118.png 102 | CAMO_test/Image/camourflage_01081.jpg CAMO_test/GT/camourflage_01081.png CAMO_test/Edge/camourflage_01081.png 103 | CAMO_test/Image/camourflage_00699.jpg CAMO_test/GT/camourflage_00699.png CAMO_test/Edge/camourflage_00699.png 104 | CAMO_test/Image/camourflage_00713.jpg CAMO_test/GT/camourflage_00713.png CAMO_test/Edge/camourflage_00713.png 105 | CAMO_test/Image/camourflage_00847.jpg CAMO_test/GT/camourflage_00847.png CAMO_test/Edge/camourflage_00847.png 106 | CAMO_test/Image/camourflage_00421.jpg CAMO_test/GT/camourflage_00421.png CAMO_test/Edge/camourflage_00421.png 107 | CAMO_test/Image/camourflage_00156.jpg CAMO_test/GT/camourflage_00156.png CAMO_test/Edge/camourflage_00156.png 108 | CAMO_test/Image/camourflage_01177.jpg CAMO_test/GT/camourflage_01177.png CAMO_test/Edge/camourflage_01177.png 109 | CAMO_test/Image/camourflage_01200.jpg CAMO_test/GT/camourflage_01200.png CAMO_test/Edge/camourflage_01200.png 110 | CAMO_test/Image/camourflage_00498.jpg CAMO_test/GT/camourflage_00498.png CAMO_test/Edge/camourflage_00498.png 111 | CAMO_test/Image/camourflage_00269.jpg CAMO_test/GT/camourflage_00269.png CAMO_test/Edge/camourflage_00269.png 112 | CAMO_test/Image/camourflage_00997.jpg CAMO_test/GT/camourflage_00997.png CAMO_test/Edge/camourflage_00997.png 113 | CAMO_test/Image/camourflage_00337.jpg CAMO_test/GT/camourflage_00337.png CAMO_test/Edge/camourflage_00337.png 114 | CAMO_test/Image/camourflage_00550.jpg CAMO_test/GT/camourflage_00550.png CAMO_test/Edge/camourflage_00550.png 115 | CAMO_test/Image/camourflage_00694.jpg CAMO_test/GT/camourflage_00694.png CAMO_test/Edge/camourflage_00694.png 116 | CAMO_test/Image/camourflage_00208.jpg CAMO_test/GT/camourflage_00208.png CAMO_test/Edge/camourflage_00208.png 117 | CAMO_test/Image/camourflage_01163.jpg CAMO_test/GT/camourflage_01163.png CAMO_test/Edge/camourflage_01163.png 118 | CAMO_test/Image/camourflage_00924.jpg CAMO_test/GT/camourflage_00924.png CAMO_test/Edge/camourflage_00924.png 119 | CAMO_test/Image/camourflage_01095.jpg CAMO_test/GT/camourflage_01095.png CAMO_test/Edge/camourflage_01095.png 120 | CAMO_test/Image/camourflage_01132.jpg CAMO_test/GT/camourflage_01132.png CAMO_test/Edge/camourflage_01132.png 121 | CAMO_test/Image/camourflage_00863.jpg CAMO_test/GT/camourflage_00863.png CAMO_test/Edge/camourflage_00863.png 122 | CAMO_test/Image/camourflage_01244.jpg CAMO_test/GT/camourflage_01244.png CAMO_test/Edge/camourflage_01244.png 123 | CAMO_test/Image/camourflage_00782.jpg CAMO_test/GT/camourflage_00782.png CAMO_test/Edge/camourflage_00782.png 124 | CAMO_test/Image/camourflage_01025.jpg CAMO_test/GT/camourflage_01025.png CAMO_test/Edge/camourflage_01025.png 125 | CAMO_test/Image/camourflage_01075.jpg CAMO_test/GT/camourflage_01075.png CAMO_test/Edge/camourflage_01075.png 126 | CAMO_test/Image/camourflage_00100.jpg CAMO_test/GT/camourflage_00100.png CAMO_test/Edge/camourflage_00100.png 127 | CAMO_test/Image/camourflage_00496.jpg CAMO_test/GT/camourflage_00496.png CAMO_test/Edge/camourflage_00496.png 128 | CAMO_test/Image/camourflage_00420.jpg CAMO_test/GT/camourflage_00420.png CAMO_test/Edge/camourflage_00420.png 129 | CAMO_test/Image/camourflage_00869.jpg CAMO_test/GT/camourflage_00869.png CAMO_test/Edge/camourflage_00869.png 130 | CAMO_test/Image/camourflage_00097.jpg CAMO_test/GT/camourflage_00097.png CAMO_test/Edge/camourflage_00097.png 131 | CAMO_test/Image/camourflage_01068.jpg CAMO_test/GT/camourflage_01068.png CAMO_test/Edge/camourflage_01068.png 132 | CAMO_test/Image/camourflage_00141.jpg CAMO_test/GT/camourflage_00141.png CAMO_test/Edge/camourflage_00141.png 133 | CAMO_test/Image/camourflage_00985.jpg CAMO_test/GT/camourflage_00985.png CAMO_test/Edge/camourflage_00985.png 134 | CAMO_test/Image/camourflage_00463.jpg CAMO_test/GT/camourflage_00463.png CAMO_test/Edge/camourflage_00463.png 135 | CAMO_test/Image/camourflage_00064.jpg CAMO_test/GT/camourflage_00064.png CAMO_test/Edge/camourflage_00064.png 136 | CAMO_test/Image/camourflage_01001.jpg CAMO_test/GT/camourflage_01001.png CAMO_test/Edge/camourflage_01001.png 137 | CAMO_test/Image/camourflage_00079.jpg CAMO_test/GT/camourflage_00079.png CAMO_test/Edge/camourflage_00079.png 138 | CAMO_test/Image/camourflage_01242.jpg CAMO_test/GT/camourflage_01242.png CAMO_test/Edge/camourflage_01242.png 139 | CAMO_test/Image/camourflage_00991.jpg CAMO_test/GT/camourflage_00991.png CAMO_test/Edge/camourflage_00991.png 140 | CAMO_test/Image/camourflage_00224.jpg CAMO_test/GT/camourflage_00224.png CAMO_test/Edge/camourflage_00224.png 141 | CAMO_test/Image/camourflage_00071.jpg CAMO_test/GT/camourflage_00071.png CAMO_test/Edge/camourflage_00071.png 142 | CAMO_test/Image/camourflage_00473.jpg CAMO_test/GT/camourflage_00473.png CAMO_test/Edge/camourflage_00473.png 143 | CAMO_test/Image/camourflage_01030.jpg CAMO_test/GT/camourflage_01030.png CAMO_test/Edge/camourflage_01030.png 144 | CAMO_test/Image/camourflage_01104.jpg CAMO_test/GT/camourflage_01104.png CAMO_test/Edge/camourflage_01104.png 145 | CAMO_test/Image/camourflage_01190.jpg CAMO_test/GT/camourflage_01190.png CAMO_test/Edge/camourflage_01190.png 146 | CAMO_test/Image/camourflage_00677.jpg CAMO_test/GT/camourflage_00677.png CAMO_test/Edge/camourflage_00677.png 147 | CAMO_test/Image/camourflage_00539.jpg CAMO_test/GT/camourflage_00539.png CAMO_test/Edge/camourflage_00539.png 148 | CAMO_test/Image/camourflage_00348.jpg CAMO_test/GT/camourflage_00348.png CAMO_test/Edge/camourflage_00348.png 149 | CAMO_test/Image/camourflage_00124.jpg CAMO_test/GT/camourflage_00124.png CAMO_test/Edge/camourflage_00124.png 150 | CAMO_test/Image/camourflage_00209.jpg CAMO_test/GT/camourflage_00209.png CAMO_test/Edge/camourflage_00209.png 151 | CAMO_test/Image/camourflage_01175.jpg CAMO_test/GT/camourflage_01175.png CAMO_test/Edge/camourflage_01175.png 152 | CAMO_test/Image/camourflage_00860.jpg CAMO_test/GT/camourflage_00860.png CAMO_test/Edge/camourflage_00860.png 153 | CAMO_test/Image/camourflage_00406.jpg CAMO_test/GT/camourflage_00406.png CAMO_test/Edge/camourflage_00406.png 154 | CAMO_test/Image/camourflage_01139.jpg CAMO_test/GT/camourflage_01139.png CAMO_test/Edge/camourflage_01139.png 155 | CAMO_test/Image/camourflage_01110.jpg CAMO_test/GT/camourflage_01110.png CAMO_test/Edge/camourflage_01110.png 156 | CAMO_test/Image/camourflage_01211.jpg CAMO_test/GT/camourflage_01211.png CAMO_test/Edge/camourflage_01211.png 157 | CAMO_test/Image/camourflage_01168.jpg CAMO_test/GT/camourflage_01168.png CAMO_test/Edge/camourflage_01168.png 158 | CAMO_test/Image/camourflage_00422.jpg CAMO_test/GT/camourflage_00422.png CAMO_test/Edge/camourflage_00422.png 159 | CAMO_test/Image/camourflage_00207.jpg CAMO_test/GT/camourflage_00207.png CAMO_test/Edge/camourflage_00207.png 160 | CAMO_test/Image/camourflage_00857.jpg CAMO_test/GT/camourflage_00857.png CAMO_test/Edge/camourflage_00857.png 161 | CAMO_test/Image/camourflage_00169.jpg CAMO_test/GT/camourflage_00169.png CAMO_test/Edge/camourflage_00169.png 162 | CAMO_test/Image/camourflage_00018.jpg CAMO_test/GT/camourflage_00018.png CAMO_test/Edge/camourflage_00018.png 163 | CAMO_test/Image/camourflage_01100.jpg CAMO_test/GT/camourflage_01100.png CAMO_test/Edge/camourflage_01100.png 164 | CAMO_test/Image/camourflage_01185.jpg CAMO_test/GT/camourflage_01185.png CAMO_test/Edge/camourflage_01185.png 165 | CAMO_test/Image/camourflage_01090.jpg CAMO_test/GT/camourflage_01090.png CAMO_test/Edge/camourflage_01090.png 166 | CAMO_test/Image/camourflage_01205.jpg CAMO_test/GT/camourflage_01205.png CAMO_test/Edge/camourflage_01205.png 167 | CAMO_test/Image/camourflage_00939.jpg CAMO_test/GT/camourflage_00939.png CAMO_test/Edge/camourflage_00939.png 168 | CAMO_test/Image/camourflage_01131.jpg CAMO_test/GT/camourflage_01131.png CAMO_test/Edge/camourflage_01131.png 169 | CAMO_test/Image/camourflage_01194.jpg CAMO_test/GT/camourflage_01194.png CAMO_test/Edge/camourflage_01194.png 170 | CAMO_test/Image/camourflage_00800.jpg CAMO_test/GT/camourflage_00800.png CAMO_test/Edge/camourflage_00800.png 171 | CAMO_test/Image/camourflage_01066.jpg CAMO_test/GT/camourflage_01066.png CAMO_test/Edge/camourflage_01066.png 172 | CAMO_test/Image/camourflage_01192.jpg CAMO_test/GT/camourflage_01192.png CAMO_test/Edge/camourflage_01192.png 173 | CAMO_test/Image/camourflage_01189.jpg CAMO_test/GT/camourflage_01189.png CAMO_test/Edge/camourflage_01189.png 174 | CAMO_test/Image/camourflage_00171.jpg CAMO_test/GT/camourflage_00171.png CAMO_test/Edge/camourflage_00171.png 175 | CAMO_test/Image/camourflage_01078.jpg CAMO_test/GT/camourflage_01078.png CAMO_test/Edge/camourflage_01078.png 176 | CAMO_test/Image/camourflage_00175.jpg CAMO_test/GT/camourflage_00175.png CAMO_test/Edge/camourflage_00175.png 177 | CAMO_test/Image/camourflage_01016.jpg CAMO_test/GT/camourflage_01016.png CAMO_test/Edge/camourflage_01016.png 178 | CAMO_test/Image/camourflage_01070.jpg CAMO_test/GT/camourflage_01070.png CAMO_test/Edge/camourflage_01070.png 179 | CAMO_test/Image/camourflage_01243.jpg CAMO_test/GT/camourflage_01243.png CAMO_test/Edge/camourflage_01243.png 180 | CAMO_test/Image/camourflage_00597.jpg CAMO_test/GT/camourflage_00597.png CAMO_test/Edge/camourflage_00597.png 181 | CAMO_test/Image/camourflage_01094.jpg CAMO_test/GT/camourflage_01094.png CAMO_test/Edge/camourflage_01094.png 182 | CAMO_test/Image/camourflage_00333.jpg CAMO_test/GT/camourflage_00333.png CAMO_test/Edge/camourflage_00333.png 183 | CAMO_test/Image/camourflage_00183.jpg CAMO_test/GT/camourflage_00183.png CAMO_test/Edge/camourflage_00183.png 184 | CAMO_test/Image/camourflage_00205.jpg CAMO_test/GT/camourflage_00205.png CAMO_test/Edge/camourflage_00205.png 185 | CAMO_test/Image/camourflage_01122.jpg CAMO_test/GT/camourflage_01122.png CAMO_test/Edge/camourflage_01122.png 186 | CAMO_test/Image/camourflage_00779.jpg CAMO_test/GT/camourflage_00779.png CAMO_test/Edge/camourflage_00779.png 187 | CAMO_test/Image/camourflage_01006.jpg CAMO_test/GT/camourflage_01006.png CAMO_test/Edge/camourflage_01006.png 188 | CAMO_test/Image/camourflage_01188.jpg CAMO_test/GT/camourflage_01188.png CAMO_test/Edge/camourflage_01188.png 189 | CAMO_test/Image/camourflage_01141.jpg CAMO_test/GT/camourflage_01141.png CAMO_test/Edge/camourflage_01141.png 190 | CAMO_test/Image/camourflage_01164.jpg CAMO_test/GT/camourflage_01164.png CAMO_test/Edge/camourflage_01164.png 191 | CAMO_test/Image/camourflage_00408.jpg CAMO_test/GT/camourflage_00408.png CAMO_test/Edge/camourflage_00408.png 192 | CAMO_test/Image/camourflage_00364.jpg CAMO_test/GT/camourflage_00364.png CAMO_test/Edge/camourflage_00364.png 193 | CAMO_test/Image/camourflage_01240.jpg CAMO_test/GT/camourflage_01240.png CAMO_test/Edge/camourflage_01240.png 194 | CAMO_test/Image/camourflage_01150.jpg CAMO_test/GT/camourflage_01150.png CAMO_test/Edge/camourflage_01150.png 195 | CAMO_test/Image/camourflage_01003.jpg CAMO_test/GT/camourflage_01003.png CAMO_test/Edge/camourflage_01003.png 196 | CAMO_test/Image/camourflage_00138.jpg CAMO_test/GT/camourflage_00138.png CAMO_test/Edge/camourflage_00138.png 197 | CAMO_test/Image/camourflage_00758.jpg CAMO_test/GT/camourflage_00758.png CAMO_test/Edge/camourflage_00758.png 198 | CAMO_test/Image/camourflage_00235.jpg CAMO_test/GT/camourflage_00235.png CAMO_test/Edge/camourflage_00235.png 199 | CAMO_test/Image/camourflage_00365.jpg CAMO_test/GT/camourflage_00365.png CAMO_test/Edge/camourflage_00365.png 200 | CAMO_test/Image/camourflage_00122.jpg CAMO_test/GT/camourflage_00122.png CAMO_test/Edge/camourflage_00122.png 201 | CAMO_test/Image/camourflage_00944.jpg CAMO_test/GT/camourflage_00944.png CAMO_test/Edge/camourflage_00944.png 202 | CAMO_test/Image/camourflage_01126.jpg CAMO_test/GT/camourflage_01126.png CAMO_test/Edge/camourflage_01126.png 203 | CAMO_test/Image/camourflage_00147.jpg CAMO_test/GT/camourflage_00147.png CAMO_test/Edge/camourflage_00147.png 204 | CAMO_test/Image/camourflage_01105.jpg CAMO_test/GT/camourflage_01105.png CAMO_test/Edge/camourflage_01105.png 205 | CAMO_test/Image/camourflage_00623.jpg CAMO_test/GT/camourflage_00623.png CAMO_test/Edge/camourflage_00623.png 206 | CAMO_test/Image/camourflage_01158.jpg CAMO_test/GT/camourflage_01158.png CAMO_test/Edge/camourflage_01158.png 207 | CAMO_test/Image/camourflage_01014.jpg CAMO_test/GT/camourflage_01014.png CAMO_test/Edge/camourflage_01014.png 208 | CAMO_test/Image/camourflage_00310.jpg CAMO_test/GT/camourflage_00310.png CAMO_test/Edge/camourflage_00310.png 209 | CAMO_test/Image/camourflage_00351.jpg CAMO_test/GT/camourflage_00351.png CAMO_test/Edge/camourflage_00351.png 210 | CAMO_test/Image/camourflage_00846.jpg CAMO_test/GT/camourflage_00846.png CAMO_test/Edge/camourflage_00846.png 211 | CAMO_test/Image/camourflage_01217.jpg CAMO_test/GT/camourflage_01217.png CAMO_test/Edge/camourflage_01217.png 212 | CAMO_test/Image/camourflage_01245.jpg CAMO_test/GT/camourflage_01245.png CAMO_test/Edge/camourflage_01245.png 213 | CAMO_test/Image/camourflage_00166.jpg CAMO_test/GT/camourflage_00166.png CAMO_test/Edge/camourflage_00166.png 214 | CAMO_test/Image/camourflage_01165.jpg CAMO_test/GT/camourflage_01165.png CAMO_test/Edge/camourflage_01165.png 215 | CAMO_test/Image/camourflage_01101.jpg CAMO_test/GT/camourflage_01101.png CAMO_test/Edge/camourflage_01101.png 216 | CAMO_test/Image/camourflage_01058.jpg CAMO_test/GT/camourflage_01058.png CAMO_test/Edge/camourflage_01058.png 217 | CAMO_test/Image/camourflage_00723.jpg CAMO_test/GT/camourflage_00723.png CAMO_test/Edge/camourflage_00723.png 218 | CAMO_test/Image/camourflage_01172.jpg CAMO_test/GT/camourflage_01172.png CAMO_test/Edge/camourflage_01172.png 219 | CAMO_test/Image/camourflage_01041.jpg CAMO_test/GT/camourflage_01041.png CAMO_test/Edge/camourflage_01041.png 220 | CAMO_test/Image/camourflage_01144.jpg CAMO_test/GT/camourflage_01144.png CAMO_test/Edge/camourflage_01144.png 221 | CAMO_test/Image/camourflage_01050.jpg CAMO_test/GT/camourflage_01050.png CAMO_test/Edge/camourflage_01050.png 222 | CAMO_test/Image/camourflage_01107.jpg CAMO_test/GT/camourflage_01107.png CAMO_test/Edge/camourflage_01107.png 223 | CAMO_test/Image/camourflage_00087.jpg CAMO_test/GT/camourflage_00087.png CAMO_test/Edge/camourflage_00087.png 224 | CAMO_test/Image/camourflage_00145.jpg CAMO_test/GT/camourflage_00145.png CAMO_test/Edge/camourflage_00145.png 225 | CAMO_test/Image/camourflage_00398.jpg CAMO_test/GT/camourflage_00398.png CAMO_test/Edge/camourflage_00398.png 226 | CAMO_test/Image/camourflage_00594.jpg CAMO_test/GT/camourflage_00594.png CAMO_test/Edge/camourflage_00594.png 227 | CAMO_test/Image/camourflage_01180.jpg CAMO_test/GT/camourflage_01180.png CAMO_test/Edge/camourflage_01180.png 228 | CAMO_test/Image/camourflage_00430.jpg CAMO_test/GT/camourflage_00430.png CAMO_test/Edge/camourflage_00430.png 229 | CAMO_test/Image/camourflage_01053.jpg CAMO_test/GT/camourflage_01053.png CAMO_test/Edge/camourflage_01053.png 230 | CAMO_test/Image/camourflage_01137.jpg CAMO_test/GT/camourflage_01137.png CAMO_test/Edge/camourflage_01137.png 231 | CAMO_test/Image/camourflage_00090.jpg CAMO_test/GT/camourflage_00090.png CAMO_test/Edge/camourflage_00090.png 232 | CAMO_test/Image/camourflage_00801.jpg CAMO_test/GT/camourflage_00801.png CAMO_test/Edge/camourflage_00801.png 233 | CAMO_test/Image/camourflage_01159.jpg CAMO_test/GT/camourflage_01159.png CAMO_test/Edge/camourflage_01159.png 234 | CAMO_test/Image/camourflage_01183.jpg CAMO_test/GT/camourflage_01183.png CAMO_test/Edge/camourflage_01183.png 235 | CAMO_test/Image/camourflage_00768.jpg CAMO_test/GT/camourflage_00768.png CAMO_test/Edge/camourflage_00768.png 236 | CAMO_test/Image/camourflage_00563.jpg CAMO_test/GT/camourflage_00563.png CAMO_test/Edge/camourflage_00563.png 237 | CAMO_test/Image/camourflage_00515.jpg CAMO_test/GT/camourflage_00515.png CAMO_test/Edge/camourflage_00515.png 238 | CAMO_test/Image/camourflage_00061.jpg CAMO_test/GT/camourflage_00061.png CAMO_test/Edge/camourflage_00061.png 239 | CAMO_test/Image/camourflage_00435.jpg CAMO_test/GT/camourflage_00435.png CAMO_test/Edge/camourflage_00435.png 240 | CAMO_test/Image/camourflage_00641.jpg CAMO_test/GT/camourflage_00641.png CAMO_test/Edge/camourflage_00641.png 241 | CAMO_test/Image/camourflage_01096.jpg CAMO_test/GT/camourflage_01096.png CAMO_test/Edge/camourflage_01096.png 242 | CAMO_test/Image/camourflage_01008.jpg CAMO_test/GT/camourflage_01008.png CAMO_test/Edge/camourflage_01008.png 243 | CAMO_test/Image/camourflage_00903.jpg CAMO_test/GT/camourflage_00903.png CAMO_test/Edge/camourflage_00903.png 244 | CAMO_test/Image/camourflage_00129.jpg CAMO_test/GT/camourflage_00129.png CAMO_test/Edge/camourflage_00129.png 245 | CAMO_test/Image/camourflage_01247.jpg CAMO_test/GT/camourflage_01247.png CAMO_test/Edge/camourflage_01247.png 246 | CAMO_test/Image/camourflage_00478.jpg CAMO_test/GT/camourflage_00478.png CAMO_test/Edge/camourflage_00478.png 247 | CAMO_test/Image/camourflage_01067.jpg CAMO_test/GT/camourflage_01067.png CAMO_test/Edge/camourflage_01067.png 248 | CAMO_test/Image/camourflage_01133.jpg CAMO_test/GT/camourflage_01133.png CAMO_test/Edge/camourflage_01133.png 249 | CAMO_test/Image/camourflage_01151.jpg CAMO_test/GT/camourflage_01151.png CAMO_test/Edge/camourflage_01151.png 250 | CAMO_test/Image/camourflage_01106.jpg CAMO_test/GT/camourflage_01106.png CAMO_test/Edge/camourflage_01106.png 251 | -------------------------------------------------------------------------------- /train_test_file/CHAMELEON_test.lst: -------------------------------------------------------------------------------- 1 | CHAMELEON/Image/animal-42.jpg CHAMELEON/GT/animal-42.png CHAMELEON/Edge/animal-42.png 2 | CHAMELEON/Image/animal-14.jpg CHAMELEON/GT/animal-14.png CHAMELEON/Edge/animal-14.png 3 | CHAMELEON/Image/animal-40.jpg CHAMELEON/GT/animal-40.png CHAMELEON/Edge/animal-40.png 4 | CHAMELEON/Image/animal-54.jpg CHAMELEON/GT/animal-54.png CHAMELEON/Edge/animal-54.png 5 | CHAMELEON/Image/animal-11.jpg CHAMELEON/GT/animal-11.png CHAMELEON/Edge/animal-11.png 6 | CHAMELEON/Image/animal-72.jpg CHAMELEON/GT/animal-72.png CHAMELEON/Edge/animal-72.png 7 | CHAMELEON/Image/animal-7.jpg CHAMELEON/GT/animal-7.png CHAMELEON/Edge/animal-7.png 8 | CHAMELEON/Image/animal-24.jpg CHAMELEON/GT/animal-24.png CHAMELEON/Edge/animal-24.png 9 | CHAMELEON/Image/animal-26.jpg CHAMELEON/GT/animal-26.png CHAMELEON/Edge/animal-26.png 10 | CHAMELEON/Image/animal-50.jpg CHAMELEON/GT/animal-50.png CHAMELEON/Edge/animal-50.png 11 | CHAMELEON/Image/animal-20.jpg CHAMELEON/GT/animal-20.png CHAMELEON/Edge/animal-20.png 12 | CHAMELEON/Image/animal-5.jpg CHAMELEON/GT/animal-5.png CHAMELEON/Edge/animal-5.png 13 | CHAMELEON/Image/animal-69.jpg CHAMELEON/GT/animal-69.png CHAMELEON/Edge/animal-69.png 14 | CHAMELEON/Image/animal-49.jpg CHAMELEON/GT/animal-49.png CHAMELEON/Edge/animal-49.png 15 | CHAMELEON/Image/animal-8.jpg CHAMELEON/GT/animal-8.png CHAMELEON/Edge/animal-8.png 16 | CHAMELEON/Image/animal-10.jpg CHAMELEON/GT/animal-10.png CHAMELEON/Edge/animal-10.png 17 | CHAMELEON/Image/animal-9.jpg CHAMELEON/GT/animal-9.png CHAMELEON/Edge/animal-9.png 18 | CHAMELEON/Image/animal-59.jpg CHAMELEON/GT/animal-59.png CHAMELEON/Edge/animal-59.png 19 | CHAMELEON/Image/animal-45.jpg CHAMELEON/GT/animal-45.png CHAMELEON/Edge/animal-45.png 20 | CHAMELEON/Image/animal-56.jpg CHAMELEON/GT/animal-56.png CHAMELEON/Edge/animal-56.png 21 | CHAMELEON/Image/animal-37.jpg CHAMELEON/GT/animal-37.png CHAMELEON/Edge/animal-37.png 22 | CHAMELEON/Image/animal-61.jpg CHAMELEON/GT/animal-61.png CHAMELEON/Edge/animal-61.png 23 | CHAMELEON/Image/animal-43.jpg CHAMELEON/GT/animal-43.png CHAMELEON/Edge/animal-43.png 24 | CHAMELEON/Image/animal-18.jpg CHAMELEON/GT/animal-18.png CHAMELEON/Edge/animal-18.png 25 | CHAMELEON/Image/animal-16.jpg CHAMELEON/GT/animal-16.png CHAMELEON/Edge/animal-16.png 26 | CHAMELEON/Image/animal-31.jpg CHAMELEON/GT/animal-31.png CHAMELEON/Edge/animal-31.png 27 | CHAMELEON/Image/animal-67.jpg CHAMELEON/GT/animal-67.png CHAMELEON/Edge/animal-67.png 28 | CHAMELEON/Image/animal-32.jpg CHAMELEON/GT/animal-32.png CHAMELEON/Edge/animal-32.png 29 | CHAMELEON/Image/animal-57.jpg CHAMELEON/GT/animal-57.png CHAMELEON/Edge/animal-57.png 30 | CHAMELEON/Image/animal-25.jpg CHAMELEON/GT/animal-25.png CHAMELEON/Edge/animal-25.png 31 | CHAMELEON/Image/animal-6.jpg CHAMELEON/GT/animal-6.png CHAMELEON/Edge/animal-6.png 32 | CHAMELEON/Image/animal-21.jpg CHAMELEON/GT/animal-21.png CHAMELEON/Edge/animal-21.png 33 | CHAMELEON/Image/animal-48.jpg CHAMELEON/GT/animal-48.png CHAMELEON/Edge/animal-48.png 34 | CHAMELEON/Image/animal-34.jpg CHAMELEON/GT/animal-34.png CHAMELEON/Edge/animal-34.png 35 | CHAMELEON/Image/animal-70.jpg CHAMELEON/GT/animal-70.png CHAMELEON/Edge/animal-70.png 36 | CHAMELEON/Image/animal-30.jpg CHAMELEON/GT/animal-30.png CHAMELEON/Edge/animal-30.png 37 | CHAMELEON/Image/animal-66.jpg CHAMELEON/GT/animal-66.png CHAMELEON/Edge/animal-66.png 38 | CHAMELEON/Image/animal-71.jpg CHAMELEON/GT/animal-71.png CHAMELEON/Edge/animal-71.png 39 | CHAMELEON/Image/animal-73.jpg CHAMELEON/GT/animal-73.png CHAMELEON/Edge/animal-73.png 40 | CHAMELEON/Image/animal-17.jpg CHAMELEON/GT/animal-17.png CHAMELEON/Edge/animal-17.png 41 | CHAMELEON/Image/animal-23.jpg CHAMELEON/GT/animal-23.png CHAMELEON/Edge/animal-23.png 42 | CHAMELEON/Image/animal-55.jpg CHAMELEON/GT/animal-55.png CHAMELEON/Edge/animal-55.png 43 | CHAMELEON/Image/animal-36.jpg CHAMELEON/GT/animal-36.png CHAMELEON/Edge/animal-36.png 44 | CHAMELEON/Image/animal-46.jpg CHAMELEON/GT/animal-46.png CHAMELEON/Edge/animal-46.png 45 | CHAMELEON/Image/animal-39.jpg CHAMELEON/GT/animal-39.png CHAMELEON/Edge/animal-39.png 46 | CHAMELEON/Image/animal-44.jpg CHAMELEON/GT/animal-44.png CHAMELEON/Edge/animal-44.png 47 | CHAMELEON/Image/animal-41.jpg CHAMELEON/GT/animal-41.png CHAMELEON/Edge/animal-41.png 48 | CHAMELEON/Image/animal-52.jpg CHAMELEON/GT/animal-52.png CHAMELEON/Edge/animal-52.png 49 | CHAMELEON/Image/animal-12.jpg CHAMELEON/GT/animal-12.png CHAMELEON/Edge/animal-12.png 50 | CHAMELEON/Image/animal-68.jpg CHAMELEON/GT/animal-68.png CHAMELEON/Edge/animal-68.png 51 | CHAMELEON/Image/animal-33.jpg CHAMELEON/GT/animal-33.png CHAMELEON/Edge/animal-33.png 52 | CHAMELEON/Image/animal-22.jpg CHAMELEON/GT/animal-22.png CHAMELEON/Edge/animal-22.png 53 | CHAMELEON/Image/animal-13.jpg CHAMELEON/GT/animal-13.png CHAMELEON/Edge/animal-13.png 54 | CHAMELEON/Image/animal-19.jpg CHAMELEON/GT/animal-19.png CHAMELEON/Edge/animal-19.png 55 | CHAMELEON/Image/animal-1.jpg CHAMELEON/GT/animal-1.png CHAMELEON/Edge/animal-1.png 56 | CHAMELEON/Image/animal-47.jpg CHAMELEON/GT/animal-47.png CHAMELEON/Edge/animal-47.png 57 | CHAMELEON/Image/animal-28.jpg CHAMELEON/GT/animal-28.png CHAMELEON/Edge/animal-28.png 58 | CHAMELEON/Image/animal-64.jpg CHAMELEON/GT/animal-64.png CHAMELEON/Edge/animal-64.png 59 | CHAMELEON/Image/animal-74.jpg CHAMELEON/GT/animal-74.png CHAMELEON/Edge/animal-74.png 60 | CHAMELEON/Image/animal-15.jpg CHAMELEON/GT/animal-15.png CHAMELEON/Edge/animal-15.png 61 | CHAMELEON/Image/animal-75.jpg CHAMELEON/GT/animal-75.png CHAMELEON/Edge/animal-75.png 62 | CHAMELEON/Image/animal-58.jpg CHAMELEON/GT/animal-58.png CHAMELEON/Edge/animal-58.png 63 | CHAMELEON/Image/animal-4.jpg CHAMELEON/GT/animal-4.png CHAMELEON/Edge/animal-4.png 64 | CHAMELEON/Image/animal-3.jpg CHAMELEON/GT/animal-3.png CHAMELEON/Edge/animal-3.png 65 | CHAMELEON/Image/animal-62.jpg CHAMELEON/GT/animal-62.png CHAMELEON/Edge/animal-62.png 66 | CHAMELEON/Image/animal-27.jpg CHAMELEON/GT/animal-27.png CHAMELEON/Edge/animal-27.png 67 | CHAMELEON/Image/animal-60.jpg CHAMELEON/GT/animal-60.png CHAMELEON/Edge/animal-60.png 68 | CHAMELEON/Image/animal-65.jpg CHAMELEON/GT/animal-65.png CHAMELEON/Edge/animal-65.png 69 | CHAMELEON/Image/animal-51.jpg CHAMELEON/GT/animal-51.png CHAMELEON/Edge/animal-51.png 70 | CHAMELEON/Image/animal-76.jpg CHAMELEON/GT/animal-76.png CHAMELEON/Edge/animal-76.png 71 | CHAMELEON/Image/animal-29.jpg CHAMELEON/GT/animal-29.png CHAMELEON/Edge/animal-29.png 72 | CHAMELEON/Image/animal-63.jpg CHAMELEON/GT/animal-63.png CHAMELEON/Edge/animal-63.png 73 | CHAMELEON/Image/animal-2.jpg CHAMELEON/GT/animal-2.png CHAMELEON/Edge/animal-2.png 74 | CHAMELEON/Image/animal-53.jpg CHAMELEON/GT/animal-53.png CHAMELEON/Edge/animal-53.png 75 | CHAMELEON/Image/animal-38.jpg CHAMELEON/GT/animal-38.png CHAMELEON/Edge/animal-38.png 76 | CHAMELEON/Image/animal-35.jpg CHAMELEON/GT/animal-35.png CHAMELEON/Edge/animal-35.png 77 | -------------------------------------------------------------------------------- /util/__pycache__/config.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/util/__pycache__/config.cpython-36.pyc -------------------------------------------------------------------------------- /util/__pycache__/config.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/util/__pycache__/config.cpython-37.pyc -------------------------------------------------------------------------------- /util/__pycache__/dataset.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/util/__pycache__/dataset.cpython-36.pyc -------------------------------------------------------------------------------- /util/__pycache__/dataset.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/util/__pycache__/dataset.cpython-37.pyc -------------------------------------------------------------------------------- /util/__pycache__/transform.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/util/__pycache__/transform.cpython-36.pyc -------------------------------------------------------------------------------- /util/__pycache__/transform.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/util/__pycache__/transform.cpython-37.pyc -------------------------------------------------------------------------------- /util/__pycache__/util.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/util/__pycache__/util.cpython-36.pyc -------------------------------------------------------------------------------- /util/__pycache__/util.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanyang587/UGTR/8f2823f655ca70c2b365f86b190d35b753992ea9/util/__pycache__/util.cpython-37.pyc -------------------------------------------------------------------------------- /util/config.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | import os 3 | from ast import literal_eval 4 | import copy 5 | 6 | 7 | class CfgNode(dict): 8 | """ 9 | CfgNode represents an internal node in the configuration tree. It's a simple 10 | dict-like container that allows for attribute-based access to keys. 11 | """ 12 | 13 | def __init__(self, init_dict=None, key_list=None, new_allowed=False): 14 | # Recursively convert nested dictionaries in init_dict into CfgNodes 15 | init_dict = {} if init_dict is None else init_dict 16 | key_list = [] if key_list is None else key_list 17 | for k, v in init_dict.items(): 18 | if type(v) is dict: 19 | # Convert dict to CfgNode 20 | init_dict[k] = CfgNode(v, key_list=key_list + [k]) 21 | super(CfgNode, self).__init__(init_dict) 22 | 23 | def __getattr__(self, name): 24 | if name in self: 25 | return self[name] 26 | else: 27 | raise AttributeError(name) 28 | 29 | def __setattr__(self, name, value): 30 | self[name] = value 31 | 32 | def __str__(self): 33 | def _indent(s_, num_spaces): 34 | s = s_.split("\n") 35 | if len(s) == 1: 36 | return s_ 37 | first = s.pop(0) 38 | s = [(num_spaces * " ") + line for line in s] 39 | s = "\n".join(s) 40 | s = first + "\n" + s 41 | return s 42 | 43 | r = "" 44 | s = [] 45 | for k, v in sorted(self.items()): 46 | seperator = "\n" if isinstance(v, CfgNode) else " " 47 | attr_str = "{}:{}{}".format(str(k), seperator, str(v)) 48 | attr_str = _indent(attr_str, 2) 49 | s.append(attr_str) 50 | r += "\n".join(s) 51 | return r 52 | 53 | def __repr__(self): 54 | return "{}({})".format(self.__class__.__name__, super(CfgNode, self).__repr__()) 55 | 56 | 57 | def load_cfg_from_cfg_file(file): 58 | cfg = {} 59 | assert os.path.isfile(file) and file.endswith('.yaml'), \ 60 | '{} is not a yaml file'.format(file) 61 | 62 | with open(file, 'r') as f: 63 | cfg_from_file = yaml.safe_load(f) 64 | 65 | for key in cfg_from_file: 66 | for k, v in cfg_from_file[key].items(): 67 | cfg[k] = v 68 | 69 | cfg = CfgNode(cfg) 70 | return cfg 71 | 72 | 73 | def merge_cfg_from_list(cfg, cfg_list): 74 | new_cfg = copy.deepcopy(cfg) 75 | assert len(cfg_list) % 2 == 0 76 | for full_key, v in zip(cfg_list[0::2], cfg_list[1::2]): 77 | subkey = full_key.split('.')[-1] 78 | assert subkey in cfg, 'Non-existent key: {}'.format(full_key) 79 | value = _decode_cfg_value(v) 80 | value = _check_and_coerce_cfg_value_type( 81 | value, cfg[subkey], subkey, full_key 82 | ) 83 | setattr(new_cfg, subkey, value) 84 | 85 | return new_cfg 86 | 87 | 88 | def _decode_cfg_value(v): 89 | """Decodes a raw config value (e.g., from a yaml config files or command 90 | line argument) into a Python object. 91 | """ 92 | # All remaining processing is only applied to strings 93 | if not isinstance(v, str): 94 | return v 95 | # Try to interpret `v` as a: 96 | # string, number, tuple, list, dict, boolean, or None 97 | try: 98 | v = literal_eval(v) 99 | # The following two excepts allow v to pass through when it represents a 100 | # string. 101 | # 102 | # Longer explanation: 103 | # The type of v is always a string (before calling literal_eval), but 104 | # sometimes it *represents* a string and other times a data structure, like 105 | # a list. In the case that v represents a string, what we got back from the 106 | # yaml parser is 'foo' *without quotes* (so, not '"foo"'). literal_eval is 107 | # ok with '"foo"', but will raise a ValueError if given 'foo'. In other 108 | # cases, like paths (v = 'foo/bar' and not v = '"foo/bar"'), literal_eval 109 | # will raise a SyntaxError. 110 | except ValueError: 111 | pass 112 | except SyntaxError: 113 | pass 114 | return v 115 | 116 | 117 | def _check_and_coerce_cfg_value_type(replacement, original, key, full_key): 118 | """Checks that `replacement`, which is intended to replace `original` is of 119 | the right type. The type is correct if it matches exactly or is one of a few 120 | cases in which the type can be easily coerced. 121 | """ 122 | original_type = type(original) 123 | replacement_type = type(replacement) 124 | 125 | # The types must match (with some exceptions) 126 | if replacement_type == original_type: 127 | return replacement 128 | 129 | # Cast replacement from from_type to to_type if the replacement and original 130 | # types match from_type and to_type 131 | def conditional_cast(from_type, to_type): 132 | if replacement_type == from_type and original_type == to_type: 133 | return True, to_type(replacement) 134 | else: 135 | return False, None 136 | 137 | # Conditionally casts 138 | # list <-> tuple 139 | casts = [(tuple, list), (list, tuple)] 140 | # For py2: allow converting from str (bytes) to a unicode string 141 | try: 142 | casts.append((str, unicode)) # noqa: F821 143 | except Exception: 144 | pass 145 | 146 | for (from_type, to_type) in casts: 147 | converted, converted_value = conditional_cast(from_type, to_type) 148 | if converted: 149 | return converted_value 150 | 151 | raise ValueError( 152 | "Type mismatch ({} vs. {}) with values ({} vs. {}) for config " 153 | "key: {}".format( 154 | original_type, replacement_type, original, replacement, full_key 155 | ) 156 | ) 157 | 158 | 159 | def _assert_with_logging(cond, msg): 160 | if not cond: 161 | logger.debug(msg) 162 | assert cond, msg -------------------------------------------------------------------------------- /util/dataset.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path 3 | import cv2 4 | import numpy as np 5 | import torch 6 | 7 | from torch.utils.data import Dataset 8 | 9 | 10 | IMG_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm'] 11 | 12 | 13 | def is_image_file(filename): 14 | filename_lower = filename.lower() 15 | return any(filename_lower.endswith(extension) for extension in IMG_EXTENSIONS) 16 | 17 | 18 | def make_dataset(split='train', data_root=None, data_list=None): 19 | assert split in ['train', 'val', 'test'] 20 | if not os.path.isfile(data_list): 21 | raise (RuntimeError("Image list file do not exist: " + data_list + "\n")) 22 | image_label_list = [] 23 | list_read = open(data_list).readlines() 24 | print("Totally {} samples in {} set.".format(len(list_read), split)) 25 | print("Starting Checking image&label pair {} list...".format(split)) 26 | for line in list_read: 27 | line = line.strip() 28 | line_split = line.split(' ') 29 | if split == 'test': 30 | if len(line_split) != 1: 31 | raise (RuntimeError("Image list file read line error : " + line + "\n")) 32 | image_name = os.path.join(data_root, line_split[0]) 33 | label_name = image_name # just set place holder for label_name, not for use 34 | edge_name = image_name 35 | else: 36 | if len(line_split) != 3: 37 | raise (RuntimeError("Image list file read line error : " + line + "\n")) 38 | image_name = os.path.join(data_root, line_split[0]) 39 | label_name = os.path.join(data_root, line_split[1]) 40 | edge_name = os.path.join(data_root, line_split[2]) 41 | ''' 42 | following check costs some time 43 | if is_image_file(image_name) and is_image_file(label_name) and os.path.isfile(image_name) and os.path.isfile(label_name): 44 | item = (image_name, label_name) 45 | image_label_list.append(item) 46 | else: 47 | raise (RuntimeError("Image list file line error : " + line + "\n")) 48 | ''' 49 | item = (image_name, label_name, edge_name) 50 | image_label_list.append(item) 51 | print("Checking image&label pair {} list done!".format(split)) 52 | return image_label_list 53 | 54 | 55 | class SemData(Dataset): 56 | def __init__(self, split='train', data_root=None, data_list=None, transform=None): 57 | print(data_root) 58 | self.split = split 59 | self.data_list = make_dataset(split, data_root, data_list) 60 | self.transform = transform 61 | self.name = 'COD10K' 62 | self.kernel = np.ones((5, 5), np.uint8) 63 | 64 | def __len__(self): 65 | return len(self.data_list) 66 | 67 | def __getitem__(self, index): 68 | image_path, label_path, edge_path = self.data_list[index] 69 | image = cv2.imread(image_path, cv2.IMREAD_COLOR) # BGR 3 channel ndarray wiht shape H * W * 3 70 | if image is None: 71 | print(image_path) 72 | image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # convert cv2 read image from BGR order to RGB order 73 | image = np.float32(image) 74 | label = cv2.imread(label_path, cv2.IMREAD_GRAYSCALE) # GRAY 1 channel ndarray with shape H * W 75 | 76 | if image.shape[0] != label.shape[0] or image.shape[1] != label.shape[1]: 77 | raise (RuntimeError("Image & label shape mismatch: " + image_path + " " + label_path + "\n")) 78 | 79 | edge = cv2.imread(edge_path, cv2.IMREAD_GRAYSCALE) 80 | if edge is None: 81 | label = cv2.resize(label, (473, 473), interpolation=cv2.INTER_NEAREST) 82 | edge = cv2.Canny(label, 50, 200) #extract edge from region mask 83 | cv2.imwrite(edge_path, edge) 84 | 85 | #if image.shape[0] != edge.shape[0] or image.shape[1] != edge.shape[1]: 86 | # raise (RuntimeError("Image & edge shape mismatch: " + image_path + " " + edge_path + "\n")) 87 | 88 | edge = cv2.dilate(edge, self.kernel, iterations=1) 89 | 90 | ''' 91 | image_name = image_path.split('/')[-1].split('.')[0] 92 | debug_edge_path = '/raid/workspace/loc_toy/code/semseg/dataset/cam/COD_train/D_Edge/' + image_name + '.png' 93 | cv2.imwrite(debug_edge_path, edge) 94 | ''' 95 | 96 | if self.transform is not None: 97 | image, label, edge = self.transform(image, label, edge) 98 | 99 | return image, label, edge #, image 100 | 101 | -------------------------------------------------------------------------------- /util/transform.py: -------------------------------------------------------------------------------- 1 | import random 2 | import math 3 | import numpy as np 4 | import numbers 5 | import collections 6 | import cv2 7 | 8 | import torch 9 | 10 | 11 | class Compose(object): 12 | # Composes segtransforms: segtransform.Compose([segtransform.RandScale([0.5, 2.0]), segtransform.ToTensor()]) 13 | def __init__(self, segtransform): 14 | self.segtransform = segtransform 15 | 16 | def __call__(self, image, label, edge): 17 | for t in self.segtransform: 18 | image, label, edge = t(image, label, edge) 19 | return image, label, edge 20 | 21 | 22 | class ToTensor(object): 23 | # Converts numpy.ndarray (H x W x C) to a torch.FloatTensor of shape (C x H x W). 24 | def __call__(self, image, label, edge): 25 | if not isinstance(image, np.ndarray) or not isinstance(label, np.ndarray) or not isinstance(edge, np.ndarray): 26 | raise (RuntimeError("segtransform.ToTensor() only handle np.ndarray" 27 | "[eg: data readed by cv2.imread()].\n")) 28 | if len(image.shape) > 3 or len(image.shape) < 2: 29 | raise (RuntimeError("segtransform.ToTensor() only handle np.ndarray with 3 dims or 2 dims.\n")) 30 | if len(image.shape) == 2: 31 | image = np.expand_dims(image, axis=2) 32 | if not len(label.shape) == 2: 33 | raise (RuntimeError("segtransform.ToTensor() only handle np.ndarray labellabel with 2 dims.\n")) 34 | if not len(edge.shape) == 2: 35 | raise (RuntimeError("segtransform.ToTensor() only handle np.ndarray labellabel with 2 dims.\n")) 36 | 37 | image = torch.from_numpy(image.transpose((2, 0, 1))) 38 | if not isinstance(image, torch.FloatTensor): 39 | image = image.float() 40 | label = torch.from_numpy(label) 41 | if not isinstance(label, torch.LongTensor): 42 | label = label.long() 43 | edge = torch.from_numpy(edge) 44 | if not isinstance(edge, torch.LongTensor): 45 | edge = edge.long() 46 | return image, label, edge 47 | 48 | 49 | class Normalize(object): 50 | # Normalize tensor with mean and standard deviation along channel: channel = (channel - mean) / std 51 | def __init__(self, mean, std=None): 52 | if std is None: 53 | assert len(mean) > 0 54 | else: 55 | assert len(mean) == len(std) 56 | self.mean = mean 57 | self.std = std 58 | 59 | def __call__(self, image, label, edge): 60 | if self.std is None: 61 | for t, m in zip(image, self.mean): 62 | t.sub_(m) 63 | else: 64 | for t, m, s in zip(image, self.mean, self.std): 65 | t.sub_(m).div_(s) 66 | return image, label, edge 67 | 68 | 69 | class Resize(object): 70 | # Resize the input to the given size, 'size' is a 2-element tuple or list in the order of (h, w). 71 | def __init__(self, size): 72 | assert (isinstance(size, collections.Iterable) and len(size) == 2) 73 | self.size = size 74 | 75 | def __call__(self, image, label, edge): 76 | image = cv2.resize(image, self.size[::-1], interpolation=cv2.INTER_LINEAR) 77 | label = cv2.resize(label, self.size[::-1], interpolation=cv2.INTER_NEAREST) 78 | edge = cv2.resize(edge, self.size[::-1], interpolation=cv2.INTER_NEAREST) 79 | return image, label, edge 80 | 81 | 82 | class RandScale(object): 83 | # Randomly resize image & label with scale factor in [scale_min, scale_max] 84 | def __init__(self, scale, aspect_ratio=None): 85 | assert (isinstance(scale, collections.Iterable) and len(scale) == 2) 86 | if isinstance(scale, collections.Iterable) and len(scale) == 2 \ 87 | and isinstance(scale[0], numbers.Number) and isinstance(scale[1], numbers.Number) \ 88 | and 0 < scale[0] < scale[1]: 89 | self.scale = scale 90 | else: 91 | raise (RuntimeError("segtransform.RandScale() scale param error.\n")) 92 | if aspect_ratio is None: 93 | self.aspect_ratio = aspect_ratio 94 | elif isinstance(aspect_ratio, collections.Iterable) and len(aspect_ratio) == 2 \ 95 | and isinstance(aspect_ratio[0], numbers.Number) and isinstance(aspect_ratio[1], numbers.Number) \ 96 | and 0 < aspect_ratio[0] < aspect_ratio[1]: 97 | self.aspect_ratio = aspect_ratio 98 | else: 99 | raise (RuntimeError("segtransform.RandScale() aspect_ratio param error.\n")) 100 | 101 | def __call__(self, image, label, edge): 102 | temp_scale = self.scale[0] + (self.scale[1] - self.scale[0]) * random.random() 103 | temp_aspect_ratio = 1.0 104 | if self.aspect_ratio is not None: 105 | temp_aspect_ratio = self.aspect_ratio[0] + (self.aspect_ratio[1] - self.aspect_ratio[0]) * random.random() 106 | temp_aspect_ratio = math.sqrt(temp_aspect_ratio) 107 | scale_factor_x = temp_scale * temp_aspect_ratio 108 | scale_factor_y = temp_scale / temp_aspect_ratio 109 | image = cv2.resize(image, None, fx=scale_factor_x, fy=scale_factor_y, interpolation=cv2.INTER_LINEAR) 110 | label = cv2.resize(label, None, fx=scale_factor_x, fy=scale_factor_y, interpolation=cv2.INTER_NEAREST) 111 | edge = cv2.resize(edge, None, fx=scale_factor_x, fy=scale_factor_y, interpolation=cv2.INTER_NEAREST) 112 | return image, label, edge 113 | 114 | 115 | class Crop(object): 116 | """Crops the given ndarray image (H*W*C or H*W). 117 | Args: 118 | size (sequence or int): Desired output size of the crop. If size is an 119 | int instead of sequence like (h, w), a square crop (size, size) is made. 120 | """ 121 | def __init__(self, size, crop_type='center', padding=None, ignore_label=255): 122 | if isinstance(size, int): 123 | self.crop_h = size 124 | self.crop_w = size 125 | elif isinstance(size, collections.Iterable) and len(size) == 2 \ 126 | and isinstance(size[0], int) and isinstance(size[1], int) \ 127 | and size[0] > 0 and size[1] > 0: 128 | self.crop_h = size[0] 129 | self.crop_w = size[1] 130 | else: 131 | raise (RuntimeError("crop size error.\n")) 132 | if crop_type == 'center' or crop_type == 'rand': 133 | self.crop_type = crop_type 134 | else: 135 | raise (RuntimeError("crop type error: rand | center\n")) 136 | if padding is None: 137 | self.padding = padding 138 | elif isinstance(padding, list): 139 | if all(isinstance(i, numbers.Number) for i in padding): 140 | self.padding = padding 141 | else: 142 | raise (RuntimeError("padding in Crop() should be a number list\n")) 143 | if len(padding) != 3: 144 | raise (RuntimeError("padding channel is not equal with 3\n")) 145 | else: 146 | raise (RuntimeError("padding in Crop() should be a number list\n")) 147 | if isinstance(ignore_label, int): 148 | self.ignore_label = ignore_label 149 | else: 150 | raise (RuntimeError("ignore_label should be an integer number\n")) 151 | 152 | def __call__(self, image, label, edge): 153 | h, w = label.shape 154 | pad_h = max(self.crop_h - h, 0) 155 | pad_w = max(self.crop_w - w, 0) 156 | pad_h_half = int(pad_h / 2) 157 | pad_w_half = int(pad_w / 2) 158 | if pad_h > 0 or pad_w > 0: 159 | if self.padding is None: 160 | raise (RuntimeError("segtransform.Crop() need padding while padding argument is None\n")) 161 | image = cv2.copyMakeBorder(image, pad_h_half, pad_h - pad_h_half, pad_w_half, pad_w - pad_w_half, cv2.BORDER_CONSTANT, value=self.padding) 162 | label = cv2.copyMakeBorder(label, pad_h_half, pad_h - pad_h_half, pad_w_half, pad_w - pad_w_half, cv2.BORDER_CONSTANT, value=self.ignore_label) 163 | edge = cv2.copyMakeBorder(edge, pad_h_half, pad_h - pad_h_half, pad_w_half, pad_w - pad_w_half, cv2.BORDER_CONSTANT, value=self.ignore_label) 164 | h, w = label.shape 165 | if self.crop_type == 'rand': 166 | h_off = random.randint(0, h - self.crop_h) 167 | w_off = random.randint(0, w - self.crop_w) 168 | else: 169 | h_off = int((h - self.crop_h) / 2) 170 | w_off = int((w - self.crop_w) / 2) 171 | image = image[h_off:h_off+self.crop_h, w_off:w_off+self.crop_w] 172 | label = label[h_off:h_off+self.crop_h, w_off:w_off+self.crop_w] 173 | edge = edge[h_off:h_off+self.crop_h, w_off:w_off+self.crop_w] 174 | return image, label, edge 175 | 176 | 177 | class RandRotate(object): 178 | # Randomly rotate image & label with rotate factor in [rotate_min, rotate_max] 179 | def __init__(self, rotate, padding, ignore_label=255, p=0.5): 180 | assert (isinstance(rotate, collections.Iterable) and len(rotate) == 2) 181 | if isinstance(rotate[0], numbers.Number) and isinstance(rotate[1], numbers.Number) and rotate[0] < rotate[1]: 182 | self.rotate = rotate 183 | else: 184 | raise (RuntimeError("segtransform.RandRotate() scale param error.\n")) 185 | assert padding is not None 186 | assert isinstance(padding, list) and len(padding) == 3 187 | if all(isinstance(i, numbers.Number) for i in padding): 188 | self.padding = padding 189 | else: 190 | raise (RuntimeError("padding in RandRotate() should be a number list\n")) 191 | assert isinstance(ignore_label, int) 192 | self.ignore_label = ignore_label 193 | self.p = p 194 | 195 | def __call__(self, image, label, edge): 196 | if random.random() < self.p: 197 | angle = self.rotate[0] + (self.rotate[1] - self.rotate[0]) * random.random() 198 | h, w = label.shape 199 | matrix = cv2.getRotationMatrix2D((w / 2, h / 2), angle, 1) 200 | image = cv2.warpAffine(image, matrix, (w, h), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=self.padding) 201 | label = cv2.warpAffine(label, matrix, (w, h), flags=cv2.INTER_NEAREST, borderMode=cv2.BORDER_CONSTANT, borderValue=self.ignore_label) 202 | edge = cv2.warpAffine(edge, matrix, (w, h), flags=cv2.INTER_NEAREST, borderMode=cv2.BORDER_CONSTANT, borderValue=self.ignore_label) 203 | return image, label, edge 204 | 205 | 206 | class RandomHorizontalFlip(object): 207 | def __init__(self, p=0.5): 208 | self.p = p 209 | 210 | def __call__(self, image, label, edge): 211 | if random.random() < self.p: 212 | image = cv2.flip(image, 1) 213 | label = cv2.flip(label, 1) 214 | edge = cv2.flip(edge, 1) 215 | return image, label, edge 216 | 217 | 218 | class RandomVerticalFlip(object): 219 | def __init__(self, p=0.5): 220 | self.p = p 221 | 222 | def __call__(self, image, label, edge): 223 | if random.random() < self.p: 224 | image = cv2.flip(image, 0) 225 | label = cv2.flip(label, 0) 226 | edge = cv2.flip(edge, 0) 227 | return image, label, edge 228 | 229 | 230 | class RandomGaussianBlur(object): 231 | def __init__(self, radius=5): 232 | self.radius = radius 233 | 234 | def __call__(self, image, label, edge): 235 | if random.random() < 0.5: 236 | image = cv2.GaussianBlur(image, (self.radius, self.radius), 0) 237 | return image, label, edge 238 | 239 | 240 | class RGB2BGR(object): 241 | # Converts image from RGB order to BGR order, for model initialized from Caffe 242 | def __call__(self, image, label, edge): 243 | image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) 244 | return image, label, edge 245 | 246 | 247 | class BGR2RGB(object): 248 | # Converts image from BGR order to RGB order, for model initialized from Pytorch 249 | def __call__(self, image, label, edge): 250 | image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) 251 | return image, label, edge 252 | 253 | class RandomEqualizeHist(object): 254 | def __init__(self, p=0.5): 255 | self.p = p 256 | def __call__(self, image, label, edge): 257 | if random.random() < self.p: 258 | image = np.uint8(image) 259 | imgYUV = cv2.cvtColor(image, cv2.COLOR_RGB2YUV) 260 | channelYUV = cv2.split(imgYUV) 261 | channelYUV[0] = cv2.equalizeHist(channelYUV[0]) # change Y channel 262 | channels = cv2.merge(channelYUV) 263 | image = cv2.cvtColor(channels, cv2.COLOR_YUV2RGB) 264 | image = np.float32(image) 265 | return image, label, edge 266 | 267 | class RandomGammaTransform(object): 268 | def __init__(self, gamma=1.0): 269 | inv_gamma = 1. / gamma 270 | table = [((i / 255.0) ** inv_gamma) * 255 for i in range(256)] 271 | self.table = np.array(table).astype('uint8') 272 | 273 | def __call__(self, image, label, edge): 274 | if random.random() < 0.5: 275 | image = cv2.LUT(image, self.table) 276 | return image, label, edge 277 | 278 | -------------------------------------------------------------------------------- /util/util.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | from PIL import Image 4 | 5 | import cv2 6 | import torch.nn.functional as F 7 | import torch 8 | from torch import nn 9 | import torch.nn.init as initer 10 | import pdb 11 | 12 | class AverageMeter(object): 13 | """Computes and stores the average and current value""" 14 | def __init__(self): 15 | self.reset() 16 | 17 | def reset(self): 18 | self.val = 0 19 | self.avg = 0 20 | self.sum = 0 21 | self.count = 0 22 | 23 | def update(self, val, n=1): 24 | self.val = val 25 | self.sum += val * n 26 | self.count += n 27 | self.avg = self.sum / self.count 28 | 29 | #pred and target is loaded by cv2.imread with GRAYSCALE 30 | def calc_mae(pred, target): 31 | pred = cv2.normalize(pred.astype('float'), None, 0.0, 1.0, cv2.NORM_MINMAX) 32 | target = np.where(target > 127, 1.0, 0.0) 33 | mae = np.mean(np.abs(pred - target)) 34 | return mae 35 | 36 | 37 | def step_learning_rate(base_lr, epoch, step_epoch, multiplier=0.1): 38 | """Sets the learning rate to the base LR decayed by 10 every step epochs""" 39 | lr = base_lr * (multiplier ** (epoch // step_epoch)) 40 | return lr 41 | 42 | 43 | def poly_learning_rate(base_lr, curr_iter, max_iter, power=0.9): 44 | """poly learning rate policy""" 45 | lr = base_lr * (1 - float(curr_iter) / max_iter) ** power 46 | return lr 47 | 48 | 49 | def intersectionAndUnion(output, target, K, ignore_index=255): 50 | # 'K' classes, output and target sizes are N or N * L or N * H * W, each value in range 0 to K - 1. 51 | assert (output.ndim in [1, 2, 3]) 52 | assert output.shape == target.shape 53 | output = output.reshape(output.size).copy() 54 | target = target.reshape(target.size) 55 | output[np.where(target == ignore_index)[0]] = ignore_index 56 | intersection = output[np.where(output == target)[0]] 57 | area_intersection, _ = np.histogram(intersection, bins=np.arange(K+1)) 58 | area_output, _ = np.histogram(output, bins=np.arange(K+1)) 59 | area_target, _ = np.histogram(target, bins=np.arange(K+1)) 60 | area_union = area_output + area_target - area_intersection 61 | return area_intersection, area_union, area_target 62 | 63 | 64 | def intersectionAndUnionGPU(output, target, K, ignore_index=255): 65 | # 'K' classes, output and target sizes are N or N * L or N * H * W, each value in range 0 to K - 1. 66 | assert (output.dim() in [1, 2, 3]) 67 | assert output.shape == target.shape 68 | output = output.view(-1) 69 | target = target.view(-1) 70 | output[target == ignore_index] = ignore_index 71 | intersection = output[output == target] 72 | # https://github.com/pytorch/pytorch/issues/1382 73 | area_intersection = torch.histc(intersection.float().cpu(), bins=K, min=0, max=K-1) 74 | area_output = torch.histc(output.float().cpu(), bins=K, min=0, max=K-1) 75 | area_target = torch.histc(target.float().cpu(), bins=K, min=0, max=K-1) 76 | area_union = area_output + area_target - area_intersection 77 | return area_intersection.cuda(), area_union.cuda(), area_target.cuda() 78 | 79 | 80 | def check_mkdir(dir_name): 81 | if not os.path.exists(dir_name): 82 | os.mkdir(dir_name) 83 | 84 | 85 | def check_makedirs(dir_name): 86 | if not os.path.exists(dir_name): 87 | os.makedirs(dir_name) 88 | 89 | 90 | def init_weights(model, conv='kaiming', batchnorm='normal', linear='kaiming', lstm='kaiming'): 91 | """ 92 | :param model: Pytorch Model which is nn.Module 93 | :param conv: 'kaiming' or 'xavier' 94 | :param batchnorm: 'normal' or 'constant' 95 | :param linear: 'kaiming' or 'xavier' 96 | :param lstm: 'kaiming' or 'xavier' 97 | """ 98 | for m in model.modules(): 99 | if isinstance(m, (nn.modules.conv._ConvNd)): 100 | if conv == 'kaiming': 101 | initer.kaiming_normal_(m.weight) 102 | elif conv == 'xavier': 103 | initer.xavier_normal_(m.weight) 104 | else: 105 | raise ValueError("init type of conv error.\n") 106 | if m.bias is not None: 107 | initer.constant_(m.bias, 0) 108 | 109 | elif isinstance(m, (nn.modules.batchnorm._BatchNorm)): 110 | if batchnorm == 'normal': 111 | initer.normal_(m.weight, 1.0, 0.02) 112 | elif batchnorm == 'constant': 113 | initer.constant_(m.weight, 1.0) 114 | else: 115 | raise ValueError("init type of batchnorm error.\n") 116 | initer.constant_(m.bias, 0.0) 117 | 118 | elif isinstance(m, nn.Linear): 119 | if linear == 'kaiming': 120 | initer.kaiming_normal_(m.weight) 121 | elif linear == 'xavier': 122 | initer.xavier_normal_(m.weight) 123 | else: 124 | raise ValueError("init type of linear error.\n") 125 | if m.bias is not None: 126 | initer.constant_(m.bias, 0) 127 | 128 | elif isinstance(m, nn.LSTM): 129 | for name, param in m.named_parameters(): 130 | if 'weight' in name: 131 | if lstm == 'kaiming': 132 | initer.kaiming_normal_(param) 133 | elif lstm == 'xavier': 134 | initer.xavier_normal_(param) 135 | else: 136 | raise ValueError("init type of lstm error.\n") 137 | elif 'bias' in name: 138 | initer.constant_(param, 0) 139 | 140 | 141 | def group_weight(weight_group, module, lr): 142 | group_decay = [] 143 | group_no_decay = [] 144 | for m in module.modules(): 145 | if isinstance(m, nn.Linear): 146 | group_decay.append(m.weight) 147 | if m.bias is not None: 148 | group_no_decay.append(m.bias) 149 | elif isinstance(m, nn.modules.conv._ConvNd): 150 | group_decay.append(m.weight) 151 | if m.bias is not None: 152 | group_no_decay.append(m.bias) 153 | elif isinstance(m, nn.modules.batchnorm._BatchNorm): 154 | if m.weight is not None: 155 | group_no_decay.append(m.weight) 156 | if m.bias is not None: 157 | group_no_decay.append(m.bias) 158 | assert len(list(module.parameters())) == len(group_decay) + len(group_no_decay) 159 | weight_group.append(dict(params=group_decay, lr=lr)) 160 | weight_group.append(dict(params=group_no_decay, weight_decay=.0, lr=lr)) 161 | return weight_group 162 | 163 | 164 | def colorize(gray, palette): 165 | # gray: numpy array of the label and 1*3N size list palette 166 | color = Image.fromarray(gray.astype(np.uint8)).convert('P') 167 | color.putpalette(palette) 168 | return color 169 | 170 | 171 | def mask_from_tensor(tensor_list): 172 | # TODO make this more general 173 | if tensor_list[0].dim() == 3: 174 | #if torchvision._is_tracing(): 175 | # nested_tensor_from_tensor_list() does not export well to ONNX 176 | # call _onnx_nested_tensor_from_tensor_list() instead 177 | # return _onnx_nested_tensor_from_tensor_list(tensor_list) 178 | 179 | # TODO make it support different-sized images 180 | max_size = _max_by_axis([list(img.shape) for img in tensor_list]) 181 | # min_size = tuple(min(s) for s in zip(*[img.shape for img in tensor_list])) 182 | batch_shape = [len(tensor_list)] + max_size 183 | b, c, h, w = batch_shape 184 | dtype = tensor_list.dtype 185 | device = tensor_list.device 186 | tensor = torch.zeros(batch_shape, dtype=dtype, device=device) 187 | mask = torch.ones((b, h, w), dtype=torch.bool, device=device) 188 | for img, pad_img, m in zip(tensor_list, tensor, mask): 189 | pad_img[: img.shape[0], : img.shape[1], : img.shape[2]] = img.data#.copy_(img) 190 | m[: img.shape[1], :img.shape[2]] = False 191 | else: 192 | raise ValueError('not supported') 193 | return tensor_list, mask 194 | 195 | def _max_by_axis(the_list): 196 | # type: (List[List[int]]) -> List[int] 197 | maxes = the_list[0] 198 | for sublist in the_list[1:]: 199 | for index, item in enumerate(sublist): 200 | maxes[index] = max(maxes[index], item) 201 | return maxes 202 | 203 | # _onnx_nested_tensor_from_tensor_list() is an implementation of 204 | # nested_tensor_from_tensor_list() that is supported by ONNX tracing. 205 | #@torch.jit.unused 206 | def _onnx_nested_tensor_from_tensor_list(tensor_list): 207 | max_size = [] 208 | for i in range(tensor_list[0].dim()): 209 | max_size_i = torch.max(torch.stack([img.shape[i] for img in tensor_list]).to(torch.float32)).to(torch.int64) 210 | max_size.append(max_size_i) 211 | max_size = tuple(max_size) 212 | 213 | # work around for 214 | # pad_img[: img.shape[0], : img.shape[1], : img.shape[2]].copy_(img) 215 | # m[: img.shape[1], :img.shape[2]] = False 216 | # which is not yet supported in onnx 217 | padded_imgs = [] 218 | padded_masks = [] 219 | for img in tensor_list: 220 | padding = [(s1 - s2) for s1, s2 in zip(max_size, tuple(img.shape))] 221 | padded_img = torch.nn.functional.pad(img, (0, padding[2], 0, padding[1], 0, padding[0])) 222 | padded_imgs.append(padded_img) 223 | 224 | m = torch.zeros_like(img[0], dtype=torch.int, device=img.device) 225 | padded_mask = torch.nn.functional.pad(m, (0, padding[2], 0, padding[1]), "constant", 1) 226 | padded_masks.append(padded_mask.to(torch.bool)) 227 | 228 | tensor = torch.stack(padded_imgs) 229 | mask = torch.stack(padded_masks) 230 | 231 | return tensor, mask 232 | 233 | --------------------------------------------------------------------------------