├── adacrowd ├── misc │ ├── __init__.py │ ├── layer.py │ ├── transforms.py │ └── utils.py ├── models │ ├── __init__.py │ ├── baselines │ │ ├── __init__.py │ │ ├── CSRNet_BN.py │ │ ├── Res101_BN.py │ │ └── Res101_SFCN_BN.py │ ├── cc_baselines.py │ ├── adacrowd │ │ ├── CSRNet_GBN.py │ │ ├── Res101_GBN.py │ │ ├── Res101_SFCN_GBN.py │ │ └── blocks.py │ └── cc_adacrowd.py ├── datasets │ ├── __init__.py │ ├── adacrowd │ │ ├── __init__.py │ │ ├── City │ │ │ ├── __init__.py │ │ │ ├── setting.py │ │ │ ├── loading_data.py │ │ │ └── City.py │ │ ├── FDST │ │ │ ├── __init__.py │ │ │ ├── setting.py │ │ │ ├── loading_data.py │ │ │ └── FDST.py │ │ ├── Mall │ │ │ ├── __init__.py │ │ │ ├── setting.py │ │ │ ├── loading_data.py │ │ │ └── Mall.py │ │ ├── PETS │ │ │ ├── __init__.py │ │ │ ├── setting.py │ │ │ ├── loading_data.py │ │ │ └── PETS.py │ │ └── WE │ │ │ ├── __init__.py │ │ │ ├── setting.py │ │ │ ├── loading_data.py │ │ │ └── WE.py │ ├── baselines │ │ ├── WE │ │ │ ├── __init__.py │ │ │ ├── setting.py │ │ │ ├── loading_data.py │ │ │ └── WE.py │ │ ├── __init__.py │ │ ├── City │ │ │ ├── __init__.py │ │ │ ├── setting.py │ │ │ ├── loading_data.py │ │ │ └── City.py │ │ ├── FDST │ │ │ ├── __init__.py │ │ │ ├── setting.py │ │ │ ├── loading_data.py │ │ │ └── FDST.py │ │ ├── Mall │ │ │ ├── __init__.py │ │ │ ├── setting.py │ │ │ ├── loading_data.py │ │ │ └── Mall.py │ │ └── PETS │ │ │ ├── __init__.py │ │ │ ├── setting.py │ │ │ ├── loading_data.py │ │ │ └── PETS.py │ └── misc │ │ └── utils.py ├── train_adacrowd.py ├── train_baselines.py ├── config │ ├── baselines.py │ └── adacrowd.py ├── test_baselines.py ├── trainer_baselines.py ├── trainer_adacrowd.py └── test_adacrowd.py ├── setup.py ├── LICENSE.txt ├── .gitignore └── README.md /adacrowd/misc/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/models/baselines/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/City/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/FDST/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/Mall/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/PETS/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/WE/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/WE/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/City/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/FDST/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/Mall/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/PETS/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/City/setting.py: -------------------------------------------------------------------------------- 1 | from easydict import EasyDict as edict 2 | 3 | # initalization 4 | __C_City = edict() 5 | cfg_data = __C_City 6 | __C_City.DATASET = 'City' 7 | 8 | __C_City.STD_SIZE = (384, 512) 9 | __C_City.TRAIN_SIZE = (384, 512) 10 | __C_City.DATA_PATH = '' 11 | __C_City.MEAN_STD = ([0.49051812291145325, 0.48466143012046814, 0.4433270990848541], [ 12 | 0.21193557977676392, 0.2080429345369339, 0.2046535313129425]) 13 | 14 | # standard data parameters 15 | __C_City.LABEL_FACTOR = 1 16 | __C_City.LOG_PARA = 100. 17 | 18 | # training parameters 19 | __C_City.TRAIN_BATCH_SIZE = 1 20 | 21 | # validation parameters 22 | __C_City.VAL_BATCH_SIZE = 1 23 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/Mall/setting.py: -------------------------------------------------------------------------------- 1 | from easydict import EasyDict as edict 2 | 3 | # initalization 4 | __C_MALL = edict() 5 | cfg_data = __C_MALL 6 | __C_MALL.DATASET = 'MALL' 7 | 8 | # dataset parameters 9 | __C_MALL.STD_SIZE = (480, 640) 10 | __C_MALL.TRAIN_SIZE = (480, 640) 11 | __C_MALL.DATA_PATH = '' 12 | __C_MALL.MEAN_STD = ([0.537967503071, 0.460666239262, 0.41356408596], [ 13 | 0.220573320985, 0.218155637383, 0.20540446043]) 14 | 15 | # standard data parameters 16 | __C_MALL.LABEL_FACTOR = 1 17 | __C_MALL.LOG_PARA = 100. 18 | 19 | # training parameters 20 | __C_MALL.TRAIN_BATCH_SIZE = 1 21 | 22 | # validation parameters 23 | __C_MALL.VAL_BATCH_SIZE = 1 24 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/Mall/setting.py: -------------------------------------------------------------------------------- 1 | from easydict import EasyDict as edict 2 | 3 | # initalization 4 | __C_MALL = edict() 5 | cfg_data = __C_MALL 6 | __C_MALL.DATASET = 'Mall' 7 | 8 | # dataset parameters 9 | __C_MALL.STD_SIZE = (480, 640) 10 | __C_MALL.TRAIN_SIZE = (480, 640) 11 | __C_MALL.DATA_PATH = '' 12 | __C_MALL.MEAN_STD = ([0.537967503071, 0.460666239262, 0.41356408596], [ 13 | 0.220573320985, 0.218155637383, 0.20540446043]) 14 | 15 | # standard data parameters 16 | __C_MALL.LABEL_FACTOR = 1 17 | __C_MALL.LOG_PARA = 100. 18 | 19 | # training parameters 20 | __C_MALL.TRAIN_BATCH_SIZE = 1 21 | 22 | # validation parameters 23 | __C_MALL.VAL_BATCH_SIZE = 2 24 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/FDST/setting.py: -------------------------------------------------------------------------------- 1 | from easydict import EasyDict as edict 2 | 3 | # initialization 4 | __C_FDST = edict() 5 | cfg_data = __C_FDST 6 | __C_FDST.DATASET = 'FDST' 7 | 8 | # dataset parameters 9 | __C_FDST.STD_SIZE = (1080, 1920) 10 | __C_FDST.TRAIN_SIZE = (360, 640) 11 | __C_FDST.DATA_PATH = '' 12 | __C_FDST.MEAN_STD = ([0.484614104033, 0.455819487572, 0.432390660048], [ 13 | 0.23891659081, 0.229008644819, 0.226914435625]) 14 | 15 | # standard data parameters 16 | __C_FDST.LABEL_FACTOR = 1 17 | __C_FDST.LOG_PARA = 100. 18 | 19 | # training parameters 20 | __C_FDST.TRAIN_BATCH_SIZE = 1 21 | __C_FDST.TRAIN_DOWNRATE = 3 22 | 23 | # validation parameters 24 | __C_FDST.VAL_BATCH_SIZE = 1 25 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/FDST/setting.py: -------------------------------------------------------------------------------- 1 | from easydict import EasyDict as edict 2 | 3 | # initalization 4 | __C_FDST = edict() 5 | cfg_data = __C_FDST 6 | __C_FDST.DATASET = 'FDST' 7 | 8 | # dataset parameters 9 | __C_FDST.STD_SIZE = (1080, 1920) 10 | __C_FDST.TRAIN_SIZE = (360, 640) 11 | __C_FDST.DATA_PATH = '' 12 | __C_FDST.MEAN_STD = ([0.484614104033, 0.455819487572, 0.432390660048], [ 13 | 0.23891659081, 0.229008644819, 0.226914435625]) 14 | 15 | # standard data parameters 16 | __C_FDST.LABEL_FACTOR = 1 17 | __C_FDST.LOG_PARA = 100. 18 | 19 | # training parameters 20 | __C_FDST.TRAIN_BATCH_SIZE = 1 21 | __C_FDST.TRAIN_DOWNRATE = 3 22 | 23 | # validation parameters 24 | __C_FDST.VAL_BATCH_SIZE = 1 25 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/WE/setting.py: -------------------------------------------------------------------------------- 1 | from easydict import EasyDict as edict 2 | 3 | # initalization 4 | __C_WE = edict() 5 | cfg_data = __C_WE 6 | __C_WE.DATASET = 'WE' 7 | 8 | # dataset parameters 9 | __C_WE.STD_SIZE = (576, 720) 10 | __C_WE.TRAIN_SIZE = (512, 672) 11 | __C_WE.DATA_PATH = '' 12 | __C_WE.MEAN_STD = ([0.504379212856, 0.510956227779, 0.505369007587], [ 13 | 0.22513884306, 0.225588873029, 0.22579960525]) 14 | 15 | # standard data parameters 16 | __C_WE.LABEL_FACTOR = 1 17 | __C_WE.LOG_PARA = 100. 18 | 19 | # training parameters 20 | __C_WE.TRAIN_BATCH_SIZE = 1 21 | 22 | # validation parameters 23 | __C_WE.VAL_BATCH_SIZE = 1 24 | __C_WE.VAL_FOLDER = ['104207', '200608', '200702', '202201', '500717'] 25 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/WE/setting.py: -------------------------------------------------------------------------------- 1 | from easydict import EasyDict as edict 2 | 3 | # initalization 4 | __C_WE = edict() 5 | cfg_data = __C_WE 6 | __C_WE.DATASET = 'WE' 7 | 8 | # dataset parameters 9 | __C_WE.STD_SIZE = (576, 720) 10 | __C_WE.TRAIN_SIZE = (512, 672) 11 | __C_WE.DATA_PATH = '' 12 | __C_WE.MEAN_STD = ([0.504379212856, 0.510956227779, 0.505369007587], [ 13 | 0.22513884306, 0.225588873029, 0.22579960525]) 14 | 15 | # standard data parameters 16 | __C_WE.LABEL_FACTOR = 1 17 | __C_WE.LOG_PARA = 100. 18 | 19 | # training parameters 20 | __C_WE.TRAIN_BATCH_SIZE = 1 21 | 22 | # validation parameters 23 | __C_WE.VAL_BATCH_SIZE = 1 24 | __C_WE.VAL_FOLDER = ['104207', '200608', '200702', '202201', '500717'] 25 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/City/setting.py: -------------------------------------------------------------------------------- 1 | from easydict import EasyDict as edict 2 | 3 | # initalization 4 | __C_City = edict() 5 | cfg_data = __C_City 6 | __C_City.DATASET = 'City' 7 | 8 | # dataset parameters 9 | __C_City.STD_SIZE = (384, 512) 10 | __C_City.TRAIN_SIZE = (384, 512) 11 | __C_City.DATA_PATH = '' 12 | __C_City.MEAN_STD = ([0.49051812291145325, 0.48466143012046814, 0.4433270990848541], [ 13 | 0.21193557977676392, 0.2080429345369339, 0.2046535313129425]) 14 | 15 | # standard data parameters 16 | __C_City.LABEL_FACTOR = 1 17 | __C_City.LOG_PARA = 100. 18 | 19 | # training parameters 20 | __C_City.TRAIN_BATCH_SIZE = 1 # imgs 21 | 22 | # validation parameters 23 | __C_City.VAL_BATCH_SIZE = 1 24 | 25 | # TODO: list all the validation scene folders 26 | __C_City.VAL_FOLDER = [] 27 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | setuptools.setup( 4 | name='adacrowd', 5 | version='1.0.0', 6 | author='Mahesh Kumar Krishna Reddy', 7 | description='Pytorch implementation of the AdaCrowd method for unlabeled scene adaptation', 8 | packages=setuptools.find_packages(), 9 | classifiers=( 10 | 'Programming Language :: Python :: 3', 11 | 'License :: OSI Approved :: BSD License', 12 | 'Operating System :: OS Independent', 13 | ), 14 | install_requires=[ 15 | 'numpy', 16 | 'torch', 17 | 'torchvision', 18 | 'yacs', 19 | 'scipy', 20 | 'tqdm', 21 | 'scikit-image', 22 | 'tensorboardX', 23 | 'easydict', 24 | 'opencv-python', 25 | 'pandas', 26 | 'pillow' 27 | ] 28 | ) 29 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/PETS/setting.py: -------------------------------------------------------------------------------- 1 | from easydict import EasyDict as edict 2 | 3 | # initalization 4 | __C_PETS = edict() 5 | cfg_data = __C_PETS 6 | __C_PETS.DATASET = 'PETS' 7 | 8 | # dataset parameters 9 | __C_PETS.STD_SIZE = (576, 768) 10 | __C_PETS.TRAIN_SIZE = (288, 384) 11 | __C_PETS.DATA_PATH = '' 12 | __C_PETS.MEAN_STD = ([0.543214261532, 0.577665150166, 0.553619801998], [ 13 | 0.299925357103, 0.279885113239, 0.298922419548]) 14 | 15 | # standard data parameters 16 | __C_PETS.LABEL_FACTOR = 1 17 | __C_PETS.LOG_PARA = 100. 18 | 19 | # training parameters 20 | __C_PETS.TRAIN_BATCH_SIZE = 1 21 | __C_PETS.TRAIN_DOWNRATE = 2 22 | 23 | # validation parameters 24 | __C_PETS.VAL_BATCH_SIZE = 1 25 | __C_PETS.VAL_FOLDER = [ 26 | 'images/S1_L1/Time_13-57', 27 | 'images/S1_L1/Time_13-59', 28 | 'images/S1_L2/Time_14-06', 29 | 'images/S1_L2/Time_14-31'] 30 | -------------------------------------------------------------------------------- /adacrowd/train_adacrowd.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import numpy as np 4 | import torch 5 | 6 | from config.adacrowd import cfg 7 | from datasets.adacrowd.WE.loading_data import loading_data 8 | from datasets.adacrowd.WE.setting import cfg_data 9 | from trainer_adacrowd import Trainer_AdaCrowd 10 | 11 | seed = cfg.SEED 12 | if seed is not None: 13 | np.random.seed(seed) 14 | torch.manual_seed(seed) 15 | torch.cuda.manual_seed(seed) 16 | 17 | gpus = cfg.GPU_ID 18 | if len(gpus) == 1: 19 | torch.cuda.set_device(gpus[0]) 20 | 21 | torch.backends.cudnn.benchmark = True 22 | 23 | data_mode = cfg.DATASET 24 | 25 | 26 | net = cfg.NET 27 | print("Net: {}".format(net)) 28 | assert net in ['CSRNet_GBN', 'Res101_GBN', 29 | 'Res101_SFCN_GBN'], "Invalid network" 30 | 31 | pwd = os.path.split(os.path.realpath(__file__))[0] 32 | cc_trainer = Trainer_AdaCrowd(loading_data, cfg_data, pwd) 33 | cc_trainer.forward() 34 | -------------------------------------------------------------------------------- /adacrowd/train_baselines.py: -------------------------------------------------------------------------------- 1 | """ 2 | Script to train the baseline methods 3 | 4 | Usage: 5 | python train_baselines.py 6 | """ 7 | import os 8 | 9 | import numpy as np 10 | import torch 11 | 12 | from config.baselines import cfg 13 | from datasets.baselines.WE.loading_data import loading_data 14 | from datasets.baselines.WE.setting import cfg_data 15 | from trainer_baselines import Trainer 16 | 17 | seed = cfg.SEED 18 | if seed is not None: 19 | np.random.seed(seed) 20 | torch.manual_seed(seed) 21 | torch.cuda.manual_seed(seed) 22 | 23 | gpus = cfg.GPU_ID 24 | if len(gpus) == 1: 25 | torch.cuda.set_device(gpus[0]) 26 | 27 | torch.backends.cudnn.benchmark = True 28 | 29 | data_mode = cfg.DATASET 30 | 31 | net = cfg.NET 32 | print("Net: {}".format(net)) 33 | assert net in ['CSRNet_BN', 'Res101_BN', 'Res101_SFCN_BN'], "Invalid network" 34 | 35 | pwd = os.path.split(os.path.realpath(__file__))[0] 36 | cc_trainer = Trainer(loading_data, cfg_data, pwd) 37 | cc_trainer.forward() 38 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/PETS/setting.py: -------------------------------------------------------------------------------- 1 | from easydict import EasyDict as edict 2 | 3 | # initalization 4 | __C_PETS = edict() 5 | cfg_data = __C_PETS 6 | __C_PETS.DATASET = 'PETS' 7 | 8 | # dataset parameters 9 | __C_PETS.STD_SIZE = (576, 768) 10 | __C_PETS.TRAIN_SIZE = (288, 384) 11 | __C_PETS.DATA_PATH = '' 12 | __C_PETS.MEAN_STD = ([0.543214261532, 0.577665150166, 0.553619801998], [ 13 | 0.299925357103, 0.279885113239, 0.298922419548]) 14 | 15 | # standard data parameters 16 | __C_PETS.LABEL_FACTOR = 1 17 | __C_PETS.LOG_PARA = 100. 18 | 19 | 20 | # training parameters 21 | __C_PETS.TRAIN_BATCH_SIZE = 1 22 | __C_PETS.TRAIN_DOWNRATE = 2 23 | 24 | # validation parameters 25 | __C_PETS.VAL_BATCH_SIZE = 1 26 | __C_PETS.VAL_FOLDERS = [ 27 | 'images/S1_L1/Time_13-57', 28 | 'images/S1_L1/Time_13-59', 29 | 'images/S1_L2/Time_14-06', 30 | 'images/S1_L2/Time_14-31'] 31 | __C_PETS.TRAIN_FOLDERS = [ 32 | "images/S1_L3/Time_14-17", 33 | "images/S1_L3/Time_14-33", 34 | "images/S2_L2/Time_14-55", 35 | "images/S2_L3/Time_14-41"] 36 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Mahesh Kumar Krishna Reddy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/WE/loading_data.py: -------------------------------------------------------------------------------- 1 | from torch.utils.data import DataLoader 2 | 3 | from datasets.misc.utils import data_transforms 4 | 5 | from .setting import cfg_data 6 | from .WE import WE 7 | 8 | 9 | def loading_data(): 10 | 11 | train_main_transform, val_main_transform, img_transform, gt_transform, restore_transform = data_transforms( 12 | cfg_data=cfg_data) 13 | 14 | train_set = WE( 15 | cfg_data.DATA_PATH + '/train', 16 | main_transform=train_main_transform, 17 | img_transform=img_transform, 18 | gt_transform=gt_transform) 19 | train_loader = DataLoader( 20 | train_set, 21 | batch_size=cfg_data.TRAIN_BATCH_SIZE, 22 | num_workers=10, 23 | shuffle=True, 24 | drop_last=True) 25 | 26 | val_set = WE( 27 | cfg_data.DATA_PATH + '/test', 28 | main_transform=val_main_transform, 29 | img_transform=img_transform, 30 | gt_transform=gt_transform) 31 | val_loader = DataLoader( 32 | val_set, 33 | batch_size=cfg_data.VAL_BATCH_SIZE, 34 | num_workers=10, 35 | shuffle=False, 36 | drop_last=True) 37 | 38 | return train_loader, val_loader, restore_transform 39 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/City/loading_data.py: -------------------------------------------------------------------------------- 1 | from torch.utils.data import DataLoader 2 | 3 | from datasets.misc.utils import data_transforms 4 | 5 | from .City import City 6 | from .setting import cfg_data 7 | 8 | 9 | def loading_data(): 10 | train_main_transform, val_main_transform, img_transform, gt_transform, restore_transform = data_transforms( 11 | cfg_data=cfg_data) 12 | 13 | train_set = City( 14 | cfg_data.DATA_PATH + '/train', 15 | main_transform=train_main_transform, 16 | img_transform=img_transform, 17 | gt_transform=gt_transform) 18 | train_loader = DataLoader( 19 | train_set, 20 | batch_size=cfg_data.TRAIN_BATCH_SIZE, 21 | num_workers=10, 22 | shuffle=True, 23 | drop_last=False) 24 | 25 | val_set = City( 26 | cfg_data.DATA_PATH + '/test', 27 | main_transform=val_main_transform, 28 | img_transform=img_transform, 29 | gt_transform=gt_transform) 30 | val_loader = DataLoader( 31 | val_set, 32 | batch_size=cfg_data.VAL_BATCH_SIZE, 33 | num_workers=10, 34 | shuffle=False, 35 | drop_last=False) 36 | 37 | return train_loader, val_loader, restore_transform 38 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/Mall/loading_data.py: -------------------------------------------------------------------------------- 1 | from torch.utils.data import DataLoader 2 | 3 | from datasets.misc.utils import data_transforms 4 | 5 | from .Mall import Mall 6 | from .setting import cfg_data 7 | 8 | 9 | def loading_data(): 10 | _, _, img_transform, gt_transform, restore_transform = data_transforms( 11 | cfg_data=cfg_data) 12 | 13 | # train loader 14 | train_set = Mall( 15 | cfg_data.DATA_PATH + '/train', 16 | 'train', 17 | main_transform=None, 18 | img_transform=img_transform, 19 | gt_transform=gt_transform) 20 | train_loader = DataLoader( 21 | train_set, 22 | batch_size=cfg_data.TRAIN_BATCH_SIZE, 23 | num_workers=0, 24 | shuffle=True, 25 | drop_last=True) 26 | 27 | # test loader 28 | test_set = Mall( 29 | cfg_data.DATA_PATH + '/test', 30 | 'test', 31 | main_transform=None, 32 | img_transform=img_transform, 33 | gt_transform=gt_transform) 34 | test_loader = DataLoader( 35 | test_set, 36 | batch_size=cfg_data.VAL_BATCH_SIZE, 37 | num_workers=0, 38 | shuffle=False, 39 | drop_last=False) 40 | 41 | return train_loader, test_loader, restore_transform 42 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/Mall/loading_data.py: -------------------------------------------------------------------------------- 1 | from torch.utils.data import DataLoader 2 | 3 | from datasets.misc.utils import data_transforms 4 | 5 | from .Mall import Mall 6 | from .setting import cfg_data 7 | 8 | 9 | def loading_data(k_shot=1): 10 | _, _, img_transform, gt_transform, restore_transform = data_transforms( 11 | cfg_data=cfg_data) 12 | 13 | # Train loader 14 | train_set = Mall( 15 | cfg_data.DATA_PATH + '/train', 16 | 'train', 17 | main_transform=None, 18 | img_transform=img_transform, 19 | gt_transform=gt_transform, 20 | k_shot=k_shot) 21 | train_loader = DataLoader( 22 | train_set, 23 | batch_size=cfg_data.TRAIN_BATCH_SIZE, 24 | num_workers=0, 25 | shuffle=True, 26 | drop_last=True) 27 | 28 | # Test loader 29 | test_set = Mall( 30 | cfg_data.DATA_PATH + '/test', 31 | 'test', 32 | main_transform=None, 33 | img_transform=img_transform, 34 | gt_transform=gt_transform) 35 | test_loader = DataLoader( 36 | test_set, 37 | batch_size=cfg_data.VAL_BATCH_SIZE, 38 | num_workers=0, 39 | shuffle=False, 40 | drop_last=False) 41 | 42 | return train_loader, test_loader, restore_transform 43 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/WE/loading_data.py: -------------------------------------------------------------------------------- 1 | from torch.utils.data import DataLoader 2 | 3 | from datasets.misc.utils import data_transforms 4 | 5 | from .setting import cfg_data 6 | from .WE import WE 7 | 8 | 9 | def loading_data(k_shot=1, num_scenes=None): 10 | train_main_transform, val_main_transform, img_transform, gt_transform, restore_transform = data_transforms( 11 | cfg_data=cfg_data) 12 | 13 | train_set = WE( 14 | cfg_data.DATA_PATH + '/train', 15 | main_transform=train_main_transform, 16 | img_transform=img_transform, 17 | gt_transform=gt_transform, 18 | k_shot=k_shot, 19 | num_scenes=num_scenes) 20 | train_loader = DataLoader( 21 | train_set, 22 | batch_size=cfg_data.TRAIN_BATCH_SIZE, 23 | num_workers=10, 24 | shuffle=True, 25 | drop_last=True) 26 | 27 | val_set = WE( 28 | cfg_data.DATA_PATH + '/test', 29 | main_transform=val_main_transform, 30 | img_transform=img_transform, 31 | gt_transform=gt_transform, 32 | k_shot=k_shot) 33 | val_loader = DataLoader( 34 | val_set, 35 | batch_size=cfg_data.VAL_BATCH_SIZE, 36 | num_workers=10, 37 | shuffle=False, 38 | drop_last=True) 39 | 40 | return train_loader, val_loader, restore_transform 41 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/City/loading_data.py: -------------------------------------------------------------------------------- 1 | from torch.utils.data import DataLoader 2 | 3 | from datasets.misc.utils import data_transforms 4 | 5 | from .City import City 6 | from .setting import cfg_data 7 | 8 | 9 | def loading_data(k_shot=1, num_scenes=None): 10 | train_main_transform, val_main_transform, img_transform, gt_transform, restore_transform = data_transforms( 11 | cfg_data=cfg_data) 12 | 13 | train_set = City( 14 | cfg_data.DATA_PATH + '/train', 15 | main_transform=train_main_transform, 16 | img_transform=img_transform, 17 | gt_transform=gt_transform, 18 | k_shot=k_shot, 19 | num_scenes=num_scenes) 20 | train_loader = DataLoader( 21 | train_set, 22 | batch_size=cfg_data.TRAIN_BATCH_SIZE, 23 | num_workers=10, 24 | shuffle=True, 25 | drop_last=True) 26 | 27 | val_set = City( 28 | cfg_data.DATA_PATH + '/test', 29 | main_transform=val_main_transform, 30 | img_transform=img_transform, 31 | gt_transform=gt_transform, 32 | k_shot=k_shot) 33 | val_loader = DataLoader( 34 | val_set, 35 | batch_size=cfg_data.VAL_BATCH_SIZE, 36 | num_workers=10, 37 | shuffle=False, 38 | drop_last=True) 39 | 40 | return train_loader, val_loader, restore_transform 41 | -------------------------------------------------------------------------------- /adacrowd/config/baselines.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from easydict import EasyDict as edict 4 | 5 | # initalization 6 | __C = edict() 7 | cfg = __C 8 | 9 | # seed value 10 | __C.SEED = 3035 11 | 12 | # datasets: WE, Mall, PETS, FDST, City(CityUHK-X) 13 | __C.DATASET = 'WE' 14 | 15 | # networks: CSRNet_BN, Res101_BN, Res101_SFCN_BN 16 | __C.NET = 'CSRNet_BN' 17 | 18 | # resume training 19 | __C.RESUME = False 20 | __C.RESUME_PATH = None 21 | 22 | # gpu id 23 | __C.GPU_ID = [0] 24 | 25 | # learning rate settings 26 | __C.LR = 1e-5 27 | 28 | # lr scheduler settings 29 | __C.LR_DECAY = 0.995 30 | __C.LR_DECAY_START = -1 31 | __C.NUM_EPOCH_LR_DECAY = 1 32 | 33 | # training settings 34 | __C.MAX_EPOCH = 110 35 | __C.NUM_NORM = 6 36 | 37 | # print settings 38 | __C.PRINT_FREQ = 5 39 | 40 | # experiment details 41 | now = time.strftime("%m-%d_%H-%M", time.localtime()) 42 | experiment_description = 'num_norm={}'.format( 43 | __C.NUM_NORM) 44 | 45 | __C.EXP_NAME = now \ 46 | + '_' + __C.DATASET \ 47 | + '_' + __C.NET \ 48 | + '_' + str(__C.LR) \ 49 | + '_' + experiment_description 50 | 51 | # experiments & logging 52 | __C.EXP_PATH = './experiments' 53 | 54 | # validation settings 55 | __C.VAL_DENSE_START = 50 56 | __C.VAL_FREQ = 5 57 | 58 | # visualization settings 59 | __C.VISIBLE_NUM_IMGS = 1 60 | 61 | # model path for testing 62 | __C.MODEL_PATH = None 63 | -------------------------------------------------------------------------------- /adacrowd/models/cc_baselines.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | 4 | 5 | class CrowdCounter(nn.Module): 6 | def __init__(self, gpus, model_name, num_norm=6): 7 | super(CrowdCounter, self).__init__() 8 | 9 | self.num_norm = num_norm 10 | 11 | if model_name == 'CSRNet_BN': 12 | from .baselines.CSRNet_BN import CSRNet_BN as net 13 | elif model_name == 'Res101_BN': 14 | from .baselines.Res101_BN import Res101_BN as net 15 | elif model_name == 'Res101_SFCN_BN': 16 | from .baselines.Res101_SFCN_BN import Res101_SFCN_BN as net 17 | self.CCN = net(num_norm=self.num_norm) 18 | if len(gpus) > 1: 19 | self.CCN = torch.nn.DataParallel(self.CCN, device_ids=gpus).cuda() 20 | else: 21 | self.CCN = self.CCN.cuda() 22 | self.loss_mse_fn = nn.MSELoss().cuda() 23 | 24 | @property 25 | def loss(self): 26 | return self.loss_mse 27 | 28 | def forward(self, img, gt_map): 29 | density_map = self.CCN(img) 30 | self.loss_mse = self.build_loss( 31 | density_map.squeeze(), gt_map.squeeze()) 32 | return density_map 33 | 34 | def build_loss(self, density_map, gt_data): 35 | loss_mse = self.loss_mse_fn(density_map, gt_data) 36 | return loss_mse 37 | 38 | def test_forward(self, img): 39 | density_map = self.CCN(img) 40 | return density_map 41 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/FDST/loading_data.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from torch.utils.data import DataLoader 4 | 5 | from datasets.misc.utils import data_transforms 6 | 7 | from .FDST import FDST 8 | from .setting import cfg_data 9 | 10 | 11 | def loading_data(scene_folder=None): 12 | 13 | train_main_transform, val_main_transform, img_transform, gt_transform, restore_transform = data_transforms( 14 | cfg_data=cfg_data) 15 | 16 | # train loader 17 | train_set = FDST( 18 | os.path.join( 19 | cfg_data.DATA_PATH, 20 | 'train'), 21 | main_transform=train_main_transform, 22 | img_transform=img_transform, 23 | gt_transform=gt_transform, 24 | scene_folder=scene_folder) 25 | train_loader = DataLoader( 26 | train_set, 27 | batch_size=cfg_data.TRAIN_BATCH_SIZE, 28 | num_workers=10, 29 | shuffle=True, 30 | drop_last=True) 31 | 32 | # validation loader 33 | val_path = os.path.join(cfg_data.DATA_PATH, 'test') 34 | val_set = FDST( 35 | val_path, 36 | main_transform=val_main_transform, 37 | img_transform=img_transform, 38 | gt_transform=gt_transform, 39 | scene_folder=scene_folder) 40 | val_loader = DataLoader( 41 | val_set, 42 | batch_size=cfg_data.VAL_BATCH_SIZE, 43 | num_workers=10, 44 | shuffle=False, 45 | drop_last=True) 46 | 47 | return train_loader, val_loader, restore_transform 48 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/FDST/loading_data.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from torch.utils.data import DataLoader 4 | 5 | from datasets.misc.utils import data_transforms 6 | 7 | from .FDST import FDST 8 | from .setting import cfg_data 9 | 10 | 11 | def loading_data(k_shot=1, scene_folder=None): 12 | 13 | train_main_transform, val_main_transform, img_transform, gt_transform, restore_transform = data_transforms( 14 | cfg_data=cfg_data) 15 | 16 | # train loader 17 | train_set = FDST( 18 | os.path.join( 19 | cfg_data.DATA_PATH, 20 | 'train'), 21 | main_transform=train_main_transform, 22 | img_transform=img_transform, 23 | gt_transform=gt_transform, 24 | k_shot=k_shot, 25 | scene_folder=scene_folder) 26 | train_loader = DataLoader( 27 | train_set, 28 | batch_size=cfg_data.TRAIN_BATCH_SIZE, 29 | num_workers=10, 30 | shuffle=True, 31 | drop_last=True) 32 | 33 | # test 34 | test_path = os.path.join(cfg_data.DATA_PATH, 'test') 35 | test_set = FDST( 36 | test_path, 37 | main_transform=val_main_transform, 38 | img_transform=img_transform, 39 | gt_transform=gt_transform, 40 | scene_folder=scene_folder) 41 | test_loader = DataLoader( 42 | test_set, 43 | batch_size=cfg_data.VAL_BATCH_SIZE, 44 | num_workers=10, 45 | shuffle=False, 46 | drop_last=True) 47 | 48 | return train_loader, test_loader, restore_transform 49 | -------------------------------------------------------------------------------- /adacrowd/config/adacrowd.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from easydict import EasyDict as edict 4 | 5 | # initialization 6 | __C = edict() 7 | cfg = __C 8 | 9 | # seed value 10 | __C.SEED = 3035 11 | 12 | # datasets: WE, Mall, PETS, FDST, City(CityUHK-X) 13 | __C.DATASET = 'WE' 14 | 15 | # networks: CSRNet_GBN, Res101_GBN, Res101_SFCN_GBN 16 | __C.NET = 'Res101_SFCN_GBN' 17 | 18 | # resume training 19 | __C.RESUME = False 20 | __C.RESUME_PATH = None 21 | 22 | # gpu id 23 | __C.GPU_ID = [1] 24 | 25 | # learning rate settings 26 | __C.LR = 1e-5 27 | 28 | # lr scheduler settings 29 | __C.LR_DECAY = 0.995 # decay rate 30 | __C.LR_DECAY_START = -1 31 | __C.NUM_EPOCH_LR_DECAY = 1 # decay frequency 32 | __C.MAX_EPOCH = 110 33 | 34 | # training settings 35 | __C.GRAD_CLIP = 1 36 | __C.NUM_GBNNORM = 6 37 | __C.K_SHOT = 1 # number of unlabeled images: 1/5 38 | __C.NUM_SCENES = 103 # 103 for WorldExpo'10 39 | 40 | # print settings 41 | __C.PRINT_FREQ = 10 42 | 43 | # experiment settings 44 | now = time.strftime("%m-%d_%H-%M", time.localtime()) 45 | __C.EXP_DETAIL = 'num_gbnnorm_{}_k_shot_{}_scenes_{}'.format( 46 | __C.NUM_GBNNORM, __C.K_SHOT, __C.NUM_SCENES) 47 | __C.EXP_NAME = now \ 48 | + '_' + __C.DATASET \ 49 | + '_' + __C.NET \ 50 | + '_' + str(__C.LR) \ 51 | + '_' + __C.EXP_DETAIL 52 | # \ 53 | 54 | # experiments & logging 55 | __C.EXP_PATH = './experiments' 56 | 57 | # validation settings 58 | __C.VAL_DENSE_START = 50 59 | __C.VAL_FREQ = 2 60 | 61 | # visualization settings 62 | __C.VISIBLE_NUM_IMGS = 1 63 | 64 | # model path for testing 65 | __C.MODEL_PATH = None 66 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/PETS/loading_data.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from torch.utils.data import DataLoader 4 | 5 | from datasets.misc.utils import data_transforms 6 | 7 | from .PETS import PETS 8 | from .setting import cfg_data 9 | 10 | 11 | def loading_data(scene_folder=None): 12 | train_main_transform, val_main_transform, img_transform, gt_transform, restore_transform = data_transforms( 13 | cfg_data=cfg_data) 14 | 15 | # validation folders 16 | VAL_FOLDERS = [os.path.join(vf, scene_folder) 17 | for vf in cfg_data.VAL_FOLDER] 18 | 19 | # train loader 20 | train_set = PETS( 21 | os.path.join( 22 | cfg_data.DATA_PATH, 23 | 'train'), 24 | main_transform=train_main_transform, 25 | img_transform=img_transform, 26 | gt_transform=gt_transform) 27 | train_loader = DataLoader( 28 | train_set, 29 | batch_size=cfg_data.TRAIN_BATCH_SIZE, 30 | num_workers=1, 31 | shuffle=True, 32 | drop_last=True) 33 | 34 | # validation loader 35 | val_path = os.path.join(cfg_data.DATA_PATH, 'test') 36 | val_set = PETS( 37 | val_path, 38 | main_transform=val_main_transform, 39 | img_transform=img_transform, 40 | gt_transform=gt_transform, 41 | val_folders=VAL_FOLDERS) 42 | val_loader = DataLoader( 43 | val_set, 44 | batch_size=cfg_data.VAL_BATCH_SIZE, 45 | num_workers=1, 46 | shuffle=False, 47 | drop_last=True) 48 | 49 | return train_loader, val_loader, restore_transform 50 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/PETS/loading_data.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from torch.utils.data import DataLoader 4 | 5 | from datasets.misc.utils import data_transforms 6 | 7 | from .PETS import PETS 8 | from .setting import cfg_data 9 | 10 | 11 | def loading_data(k_shot=1, scene_folder=None): 12 | train_main_transform, val_main_transform, img_transform, gt_transform, restore_transform = data_transforms( 13 | cfg_data=cfg_data) 14 | 15 | VAL_FOLDERS = [os.path.join(sf, scene_folder) 16 | for sf in cfg_data.VAL_FOLDERS] 17 | TRAIN_FOLDERS = [os.path.join(sf, scene_folder) 18 | for sf in cfg_data.TRAIN_FOLDERS] 19 | 20 | # train loader 21 | train_set = PETS( 22 | os.path.join( 23 | cfg_data.DATA_PATH, 24 | 'train'), 25 | main_transform=train_main_transform, 26 | img_transform=img_transform, 27 | gt_transform=gt_transform, 28 | k_shot=k_shot, 29 | val_folders=TRAIN_FOLDERS) 30 | train_loader = DataLoader( 31 | train_set, 32 | batch_size=cfg_data.TRAIN_BATCH_SIZE, 33 | num_workers=1, 34 | shuffle=True, 35 | drop_last=True) 36 | 37 | # test 38 | test_path = os.path.join(cfg_data.DATA_PATH, 'test') 39 | test_set = PETS( 40 | test_path, 41 | main_transform=val_main_transform, 42 | img_transform=img_transform, 43 | gt_transform=gt_transform, 44 | val_folders=VAL_FOLDERS) 45 | test_loader = DataLoader( 46 | test_set, 47 | batch_size=cfg_data.VAL_BATCH_SIZE, 48 | num_workers=1, 49 | shuffle=False, 50 | drop_last=True) 51 | 52 | return train_loader, test_loader, restore_transform 53 | -------------------------------------------------------------------------------- /adacrowd/datasets/misc/utils.py: -------------------------------------------------------------------------------- 1 | import torchvision.transforms as standard_transforms 2 | 3 | import misc.transforms as own_transforms 4 | 5 | 6 | def data_transforms(cfg_data): 7 | 8 | mean_std = cfg_data.MEAN_STD 9 | log_para = cfg_data.LOG_PARA 10 | 11 | # train and val main data transformations 12 | if cfg_data.DATASET == 'City': 13 | train_main_transform = own_transforms.Compose([ 14 | own_transforms.RandomHorizontallyFlip() 15 | ]) 16 | val_main_transform = None 17 | elif cfg_data.DATASET in ['FDST', 'PETS']: 18 | train_main_transform = standard_transforms.Compose([ 19 | own_transforms.FreeScale(cfg_data.TRAIN_SIZE), 20 | ]) 21 | val_main_transform = standard_transforms.Compose([ 22 | own_transforms.FreeScale(cfg_data.TRAIN_SIZE), 23 | ]) 24 | else: 25 | train_main_transform = own_transforms.Compose([ 26 | own_transforms.RandomCrop(cfg_data.TRAIN_SIZE), 27 | own_transforms.RandomHorizontallyFlip() 28 | ]) 29 | 30 | val_main_transform = None 31 | 32 | # image and gt transformations 33 | if cfg_data.DATASET == 'FDST': 34 | gt_transform = standard_transforms.Compose([ 35 | own_transforms.GTScaleDown(cfg_data.TRAIN_DOWNRATE), 36 | own_transforms.LabelNormalize(log_para) 37 | ]) 38 | else: 39 | gt_transform = standard_transforms.Compose([ 40 | own_transforms.LabelNormalize(log_para) 41 | ]) 42 | 43 | img_transform = standard_transforms.Compose([ 44 | standard_transforms.ToTensor(), 45 | standard_transforms.Normalize(*mean_std) 46 | ]) 47 | 48 | restore_transform = standard_transforms.Compose([ 49 | own_transforms.DeNormalize(*mean_std), 50 | standard_transforms.ToPILImage() 51 | ]) 52 | 53 | return train_main_transform, val_main_transform, img_transform, gt_transform, restore_transform 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | # pycharm 107 | .idea/vcs.xml 108 | 109 | # pycharm 110 | .idea 111 | 112 | # trained model 113 | *.pth.tar 114 | 115 | # experiments 116 | /experiments 117 | 118 | # pycache 119 | /__pycache__ 120 | !**/__pycache__/ 121 | 122 | # vscode 123 | /.vscode -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/City/City.py: -------------------------------------------------------------------------------- 1 | """Script to load FDST dataset for the baseline model 2 | """ 3 | 4 | import os 5 | 6 | import numpy as np 7 | import pandas as pd 8 | from PIL import Image 9 | from torch.utils import data 10 | 11 | 12 | class City(data.Dataset): 13 | def __init__( 14 | self, 15 | data_path, 16 | main_transform=None, 17 | img_transform=None, 18 | gt_transform=None): 19 | 20 | self.data_files = [] 21 | for fol in os.listdir(data_path): 22 | img_fold = os.path.join(data_path, fol, 'images') 23 | images = [os.path.join(img_fold, img) for img in os.listdir( 24 | img_fold) if img.endswith('.jpg')] 25 | self.data_files += images 26 | 27 | self.num_samples = len(self.data_files) 28 | self.main_transform = main_transform 29 | self.img_transform = img_transform 30 | self.gt_transform = gt_transform 31 | print("Total images: {}".format(len(self.data_files))) 32 | 33 | def __getitem__(self, index): 34 | fname = self.data_files[index] 35 | 36 | img, den = self.read_image_and_gt(fname) 37 | if self.main_transform is not None: 38 | img, den = self.main_transform(img, den) 39 | if self.img_transform is not None: 40 | img = self.img_transform(img) 41 | if self.gt_transform is not None: 42 | den = self.gt_transform(den) 43 | return img, den 44 | 45 | def __len__(self): 46 | return self.num_samples 47 | 48 | def read_image_and_gt(self, fname): 49 | img = Image.open(fname) 50 | if img.mode == 'L': 51 | img = img.convert('RGB') 52 | 53 | gt_path = fname.replace('images', 'gt').replace('.jpg', '.csv') 54 | den = pd.read_csv(gt_path, sep=',', header=None).values 55 | 56 | den = den.astype(np.float32, copy=False) 57 | den = Image.fromarray(den) 58 | return img, den 59 | 60 | def get_num_samples(self): 61 | return self.num_samples 62 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/WE/WE.py: -------------------------------------------------------------------------------- 1 | """Script to load WorldExpo'10 dataset for the baseline model 2 | """ 3 | 4 | import os 5 | 6 | import numpy as np 7 | import pandas as pd 8 | from PIL import Image 9 | from torch.utils import data 10 | 11 | 12 | class WE(data.Dataset): 13 | def __init__( 14 | self, 15 | data_path, 16 | main_transform=None, 17 | img_transform=None, 18 | gt_transform=None): 19 | self.img_path = data_path + '/images' 20 | self.gt_path = data_path + '/csvs' 21 | 22 | self.data_files = [] 23 | for fol in os.listdir(self.img_path): 24 | img_fold = os.path.join(self.img_path, fol) 25 | images = [os.path.join(img_fold, img) for img in os.listdir( 26 | img_fold) if img.endswith('.jpg')] 27 | self.data_files += images 28 | 29 | self.num_samples = len(self.data_files) 30 | self.main_transform = main_transform 31 | self.img_transform = img_transform 32 | self.gt_transform = gt_transform 33 | 34 | def __getitem__(self, index): 35 | fname = self.data_files[index] 36 | 37 | img, den = self.read_image_and_gt(fname) 38 | if self.main_transform is not None: 39 | img, den = self.main_transform(img, den) 40 | if self.img_transform is not None: 41 | img = self.img_transform(img) 42 | if self.gt_transform is not None: 43 | den = self.gt_transform(den) 44 | return img, den 45 | 46 | def __len__(self): 47 | return self.num_samples 48 | 49 | def read_image_and_gt(self, fname): 50 | img = Image.open(os.path.join(self.img_path, fname)) 51 | if img.mode == 'L': 52 | img = img.convert('RGB') 53 | 54 | gt_path = fname.replace('images', 'csvs').replace('.jpg', '.csv') 55 | den = pd.read_csv(gt_path, sep=',', header=None).values 56 | 57 | den = den.astype(np.float32, copy=False) 58 | den = Image.fromarray(den) 59 | return img, den 60 | 61 | def get_num_samples(self): 62 | return self.num_samples 63 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/Mall/Mall.py: -------------------------------------------------------------------------------- 1 | """Script to load Mall dataset for the baseline model 2 | """ 3 | 4 | import os 5 | 6 | import numpy as np 7 | import pandas as pd 8 | from PIL import Image 9 | from torch.utils import data 10 | 11 | 12 | class Mall(data.Dataset): 13 | def __init__( 14 | self, 15 | data_path, 16 | mode, 17 | main_transform=None, 18 | img_transform=None, 19 | gt_transform=None): 20 | self.img_path = data_path + '/images' 21 | self.gt_path = data_path + '/csvs' 22 | self.data_files = [ 23 | filename for filename in os.listdir( 24 | self.img_path) if os.path.isfile( 25 | os.path.join( 26 | self.img_path, 27 | filename))] 28 | self.num_samples = len(self.data_files) 29 | self.main_transform = main_transform 30 | self.img_transform = img_transform 31 | self.gt_transform = gt_transform 32 | 33 | self.mode = mode 34 | 35 | if self.mode == 'train': 36 | print('[Mall DATASET]: %d training images.' % (self.num_samples)) 37 | else: 38 | print('[Mall DATASET]: %d testing images.' % (self.num_samples)) 39 | 40 | def __getitem__(self, index): 41 | fname = self.data_files[index] 42 | img, den = self.read_image_and_gt(fname) 43 | if self.main_transform is not None: 44 | img, den = self.main_transform(img, den) 45 | if self.img_transform is not None: 46 | img = self.img_transform(img) 47 | if self.gt_transform is not None: 48 | den = self.gt_transform(den) 49 | return img, den 50 | 51 | def __len__(self): 52 | return self.num_samples 53 | 54 | def read_image_and_gt(self, fname): 55 | img = Image.open(os.path.join(self.img_path, fname)) 56 | if img.mode == 'L': 57 | img = img.convert('RGB') 58 | 59 | den = pd.read_csv( 60 | os.path.join( 61 | self.gt_path, 62 | os.path.splitext(fname)[0] + 63 | '.csv'), 64 | sep=',', 65 | header=None).values 66 | 67 | den = den.astype(np.float32, copy=False) 68 | den = Image.fromarray(den) 69 | return img, den 70 | 71 | def get_num_samples(self): 72 | return self.num_samples 73 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/Mall/Mall.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import numpy as np 4 | import pandas as pd 5 | from PIL import Image 6 | from torch.utils import data 7 | 8 | 9 | class Mall(data.Dataset): 10 | def __init__( 11 | self, 12 | data_path, 13 | mode, 14 | main_transform=None, 15 | img_transform=None, 16 | gt_transform=None, 17 | k_shot=None): 18 | 19 | self.img_path = data_path + '/images' 20 | self.gt_path = data_path + '/csvs' 21 | self.data_files = [ 22 | filename for filename in os.listdir( 23 | self.img_path) if os.path.isfile( 24 | os.path.join( 25 | self.img_path, 26 | filename))] 27 | self.k_shot = k_shot 28 | 29 | if self.k_shot is not None: 30 | np.random.shuffle(self.data_files) 31 | self.data_files = self.data_files[:self.k_shot] 32 | 33 | self.num_samples = len(self.data_files) 34 | self.main_transform = main_transform 35 | self.img_transform = img_transform 36 | self.gt_transform = gt_transform 37 | 38 | self.mode = mode 39 | 40 | if self.mode == 'train': 41 | print('[Mall DATASET]: %d training images.' % (self.num_samples)) 42 | if self.mode == 'test': 43 | print('[Mall DATASET]: %d testing images.' % (self.num_samples)) 44 | 45 | def __getitem__(self, index): 46 | fname = self.data_files[index] 47 | img, den = self.read_image_and_gt(fname) 48 | 49 | if self.main_transform is not None: 50 | img, den = self.main_transform(img, den) 51 | 52 | if self.img_transform is not None: 53 | img = self.img_transform(img) 54 | 55 | if self.gt_transform is not None: 56 | den = self.gt_transform(den) 57 | return img, den 58 | 59 | def __len__(self): 60 | return self.num_samples 61 | 62 | def read_image_and_gt(self, fname): 63 | img = Image.open(os.path.join(self.img_path, fname)) 64 | 65 | if img.mode == 'L': 66 | img = img.convert('RGB') 67 | 68 | den = pd.read_csv( 69 | os.path.join( 70 | self.gt_path, 71 | os.path.splitext(fname)[0] + 72 | '.csv'), 73 | sep=',', 74 | header=None).values 75 | 76 | den = den.astype(np.float32, copy=False) 77 | den = Image.fromarray(den) 78 | return img, den 79 | 80 | def get_num_samples(self): 81 | return self.num_samples 82 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/PETS/PETS.py: -------------------------------------------------------------------------------- 1 | """Script to load PETS dataset for the baseline model 2 | """ 3 | 4 | import os 5 | 6 | import numpy as np 7 | import pandas as pd 8 | from PIL import Image 9 | from torch.utils import data 10 | 11 | 12 | class PETS(data.Dataset): 13 | def __init__( 14 | self, 15 | data_path, 16 | main_transform=None, 17 | img_transform=None, 18 | gt_transform=None, 19 | val_folders=None): 20 | 21 | self.data_files = [] 22 | if val_folders is None: 23 | # Loop through all the subfolder and create one image list 24 | scene_folders = [os.path.join(data_path, sf) 25 | for sf in os.listdir(data_path)] 26 | for sf in scene_folders: 27 | timestamp_folders = [ 28 | os.path.join( 29 | sf, tf) for tf in os.listdir(sf)] 30 | for tf in timestamp_folders: 31 | view_folders = [os.path.join(tf, vf) 32 | for vf in os.listdir(tf)] 33 | for vf in view_folders: 34 | images = [os.path.join(vf, img) 35 | for img in os.listdir(vf)] 36 | self.data_files += images 37 | else: 38 | # Loop through all the subfolders and collect th images incase of 39 | # validation 40 | for vf in val_folders: 41 | val_path = os.path.join(data_path, vf) 42 | images = [os.path.join(val_path, img) for img in os.listdir( 43 | val_path) if img.endswith('.jpg')] 44 | 45 | self.num_samples = len(self.data_files) 46 | self.main_transform = main_transform 47 | self.img_transform = img_transform 48 | self.gt_transform = gt_transform 49 | 50 | def __getitem__(self, index): 51 | fname = self.data_files[index] 52 | 53 | img, den = self.read_image_and_gt(fname) 54 | if self.main_transform is not None: 55 | img = self.main_transform(img) 56 | if self.img_transform is not None: 57 | img = self.img_transform(img) 58 | if self.gt_transform is not None: 59 | den = self.gt_transform(den) 60 | return img, den 61 | 62 | def __len__(self): 63 | return self.num_samples 64 | 65 | def read_image_and_gt(self, fname): 66 | img = Image.open(os.path.join(fname)) 67 | if img.mode == 'L': 68 | img = img.convert('RGB') 69 | 70 | gt_path = fname.replace('images', 'csvs').replace('.jpg', '.csv') 71 | den = pd.read_csv(gt_path, sep=',', header=None).values 72 | 73 | den = den.astype(np.float32, copy=False) 74 | den = Image.fromarray(den) 75 | return img, den 76 | 77 | def get_num_samples(self): 78 | return self.num_samples 79 | -------------------------------------------------------------------------------- /adacrowd/datasets/baselines/FDST/FDST.py: -------------------------------------------------------------------------------- 1 | """Script to load FDST dataset for the baseline model 2 | """ 3 | 4 | import os 5 | 6 | import numpy as np 7 | import pandas as pd 8 | from PIL import Image 9 | from torch.utils import data 10 | 11 | 12 | class FDST(data.Dataset): 13 | def __init__( 14 | self, 15 | data_path, 16 | main_transform=None, 17 | img_transform=None, 18 | gt_transform=None, 19 | scene_folder=None): 20 | 21 | self.data_files = [] 22 | data_path = os.path.join(data_path, 'images') 23 | if scene_folder is None: 24 | # Loop through all the subfolder and create a single training image 25 | # list 26 | scene_folders = [os.path.join(data_path, sf) 27 | for sf in os.listdir(data_path)] 28 | for sf in scene_folders: 29 | view_folders = [os.path.join(sf, tf) for tf in os.listdir(sf)] 30 | for tf in view_folders: 31 | images = [ 32 | os.path.join( 33 | tf, 34 | img) for img in os.listdir(tf)if img.endswith('.jpg')] 35 | self.data_files += images 36 | else: 37 | # Loop through all the subfolders and collect validation images 38 | scene_folder = os.path.join(data_path, scene_folder) 39 | view_folders = [os.path.join(scene_folder, vf) 40 | for vf in os.listdir(scene_folder)] 41 | for vf in view_folders: 42 | images = [os.path.join(vf, img) for img in os.listdir( 43 | vf) if img.endswith('.jpg')] 44 | self.data_files += images 45 | 46 | self.num_samples = len(self.data_files) 47 | self.main_transform = main_transform 48 | self.img_transform = img_transform 49 | self.gt_transform = gt_transform 50 | 51 | def __getitem__(self, index): 52 | fname = self.data_files[index] 53 | 54 | img, den = self.read_image_and_gt(fname) 55 | if self.main_transform is not None: 56 | img = self.main_transform(img) 57 | if self.img_transform is not None: 58 | img = self.img_transform(img) 59 | if self.gt_transform is not None: 60 | den = self.gt_transform(den) 61 | return img, den 62 | 63 | def __len__(self): 64 | return self.num_samples 65 | 66 | def read_image_and_gt(self, fname): 67 | img = Image.open(os.path.join(fname)) 68 | if img.mode == 'L': 69 | img = img.convert('RGB') 70 | 71 | gt_path = fname.replace('images', 'csvs').replace('.jpg', '.csv') 72 | den = pd.read_csv(gt_path, sep=',', header=None).values 73 | 74 | den = den.astype(np.float32, copy=False) 75 | den = Image.fromarray(den) 76 | return img, den 77 | 78 | def get_num_samples(self): 79 | return self.num_samples 80 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/PETS/PETS.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import numpy as np 4 | import pandas as pd 5 | from PIL import Image 6 | from torch.utils import data 7 | 8 | 9 | def read_img(path): 10 | img = Image.open(path) 11 | 12 | if img.mode == 'L': 13 | img = img.convert('RGB') 14 | return img 15 | 16 | 17 | class PETS(data.Dataset): 18 | def __init__( 19 | self, 20 | data_path, 21 | main_transform=None, 22 | img_transform=None, 23 | gt_transform=None, 24 | k_shot=1, 25 | val_folders=None): 26 | 27 | self.data_files = [] 28 | 29 | # Loop through all the subfolders and collect th images incase of 30 | # validation 31 | images = [] 32 | print(data_path, val_folders) 33 | for vf in val_folders: 34 | val_path = os.path.join(data_path, vf) 35 | images = [ 36 | os.path.join( 37 | val_path, 38 | img) for img in os.listdir(val_path) if ( 39 | img.endswith('.jpg'))] 40 | 41 | np.random.shuffle(images) 42 | gui_imgs = images[:k_shot] 43 | 44 | if 'train' in data_path: 45 | self.data_files = gui_imgs 46 | print("Number of train images: {}".format(len(self.data_files))) 47 | else: 48 | self.data_files = images 49 | print("Number of test images: {}".format(len(self.data_files))) 50 | 51 | self.num_samples = len(self.data_files) 52 | self.main_transform = main_transform 53 | self.img_transform = img_transform 54 | self.gt_transform = gt_transform 55 | 56 | def __getitem__(self, index): 57 | 58 | fname = self.data_files[index] 59 | 60 | # reading the crowd image, ground truth density map, list of unlabeled 61 | # images 62 | img, den = self.read_image_and_gt(fname) 63 | 64 | # applying main transformation (consists of image resizing) 65 | if self.main_transform is not None: 66 | img = self.main_transform(img) 67 | 68 | # applying image transformation (consists of ToTensor() and 69 | # Normalization of channels) 70 | if self.img_transform is not None: 71 | img = self.img_transform(img) 72 | 73 | # applying transformation to the crowd density maps 74 | if self.gt_transform is not None: 75 | den = self.gt_transform(den).unsqueeze(0) 76 | 77 | return img, den 78 | 79 | def __len__(self): 80 | return self.num_samples 81 | 82 | def read_image_and_gt(self, fname): 83 | """ 84 | Method to read images and ground-truths 85 | """ 86 | crowd_img = read_img(fname) 87 | den = None 88 | 89 | gt_path = fname.replace('images', 'csvs').replace('.jpg', '.csv') 90 | den = pd.read_csv(gt_path, sep=',', header=None).values 91 | den = den.astype(np.float32, copy=False) 92 | den = Image.fromarray(den) 93 | 94 | return crowd_img, den 95 | 96 | def get_num_samples(self): 97 | return self.num_samples 98 | -------------------------------------------------------------------------------- /adacrowd/models/baselines/CSRNet_BN.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | import torch.nn.functional as F 3 | from torchvision import models 4 | 5 | 6 | class CSRNet_BN(nn.Module): 7 | """ 8 | CSRNet implementation 9 | Reference: https://github.com/leeyeehoo/CSRNet-pytorch 10 | Paper: https://arxiv.org/abs/1802.10062 11 | """ 12 | 13 | def __init__(self, pretrained=True, num_norm=6): 14 | super(CSRNet_BN, self).__init__() 15 | 16 | # number of normalization layers 17 | self.num_norm = num_norm 18 | 19 | # VGG backbone 20 | self.frontend_feat = [64, 64, 'M', 128, 128, 21 | 'M', 256, 256, 256, 'M', 512, 512, 512] 22 | 23 | # Density map estimator 24 | self.backend_feat = [512, 512, 512, 256, 128, 64] 25 | 26 | self.frontend = make_layers(self.frontend_feat) 27 | self.backend = make_layers( 28 | self.backend_feat, 29 | in_channels=512, 30 | dilation=True, 31 | batch_norm=True) 32 | self.output_layer = nn.Conv2d(64, 1, kernel_size=1) 33 | 34 | # Loading weights from the pre-trained VGG16 model 35 | if pretrained: 36 | mod = models.vgg16(pretrained=True) 37 | self._initialize_weights() 38 | self.frontend.load_state_dict(mod.features[0:23].state_dict()) 39 | 40 | def forward(self, x): 41 | x = self.frontend(x) # output feature shape (B x 512 x H/8 x W/8) 42 | x = self.backend(x) # output feature shape (B x 64 x H/8 x W/8) 43 | x = self.output_layer(x) # output feature shape (B x 1 x H/8 x W/8) 44 | # upsampling the output 1/8th of the input image by 2^3 45 | x = F.upsample(x, scale_factor=8) 46 | 47 | return x 48 | 49 | # Weight initialization as per the CSRNet paper 50 | # Mean=0, Standard deviation=0.01 51 | def _initialize_weights(self): 52 | for m in self.modules(): 53 | if isinstance(m, nn.Conv2d): 54 | nn.init.normal_(m.weight, std=0.01) 55 | if m.bias is not None: 56 | nn.init.constant_(m.bias, 0) 57 | elif self.affine and isinstance(m, nn.BatchNorm2d): 58 | nn.init.constant_(m.weight, 1) 59 | nn.init.constant_(m.bias, 0) 60 | 61 | 62 | # Method to construct the layers for the backend / density map estimator 63 | def make_layers( 64 | cfg, 65 | in_channels=3, 66 | batch_norm=False, 67 | dilation=False, 68 | num_norm=6): 69 | norm_counter = 0 70 | d_rate = 2 if dilation else 1 71 | layers = [] 72 | for v in cfg: 73 | if v == 'M': 74 | layers += [nn.MaxPool2d(kernel_size=2, stride=2)] 75 | else: 76 | conv2d = nn.Conv2d( 77 | in_channels, 78 | v, 79 | kernel_size=3, 80 | padding=d_rate, 81 | dilation=d_rate) 82 | if norm_counter < num_norm: 83 | if batch_norm: 84 | layers += [conv2d, 85 | nn.BatchNorm2d(v), 86 | nn.ReLU(inplace=True)] 87 | norm_counter += 1 88 | else: 89 | layers += [conv2d, nn.ReLU(inplace=True)] 90 | else: 91 | layers += [conv2d, nn.ReLU(inplace=True)] 92 | in_channels = v 93 | return nn.Sequential(*layers) 94 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/WE/WE.py: -------------------------------------------------------------------------------- 1 | """Script to load WorldExpo'10 dataset for the adacrowd model 2 | """ 3 | 4 | import os 5 | 6 | import numpy as np 7 | import pandas as pd 8 | import torch 9 | from PIL import Image 10 | from torch.utils.data import Dataset 11 | 12 | 13 | def read_img(path): 14 | img = Image.open(path) 15 | if img.mode == 'L': 16 | img = img.convert('RGB') 17 | return img 18 | 19 | 20 | class WE(Dataset): 21 | def __init__( 22 | self, 23 | data_path, 24 | main_transform=None, 25 | img_transform=None, 26 | gt_transform=None, 27 | k_shot=1, 28 | num_scenes=None): 29 | 30 | self.img_path = data_path + '/images' 31 | self.gt_path = data_path + '/csvs' 32 | 33 | self.data_files = [] 34 | folders = os.listdir(self.img_path) 35 | folders = folders if num_scenes is None else folders[:num_scenes] 36 | print( 37 | "Num scenes: {}, loaded scenes: {}".format( 38 | num_scenes, 39 | len(folders))) 40 | for fol in folders: 41 | img_fold = os.path.join(self.img_path, fol) 42 | images = [os.path.join(img_fold, img) for img in os.listdir( 43 | img_fold) if img.endswith('.jpg')] 44 | np.random.shuffle(images) 45 | gui_imgs = images[:k_shot] 46 | crowd_imgs = images[k_shot:] 47 | 48 | combined_imgs = [[gui_imgs, crowd_img] for crowd_img in crowd_imgs] 49 | self.data_files += combined_imgs 50 | 51 | self.num_samples = len(self.data_files) 52 | self.main_transform = main_transform 53 | self.img_transform = img_transform 54 | self.gt_transform = gt_transform 55 | 56 | def __getitem__(self, index): 57 | 58 | fname = self.data_files[index] 59 | 60 | # reading the crowd image, ground truth density map, list of unlabeled 61 | # images 62 | img, den, gui_imgs = self.read_image_and_gt(fname) 63 | 64 | # applying transformation to the crowd images and it's ground-truth 65 | if self.main_transform is not None: 66 | img, den = self.main_transform(img, den) 67 | 68 | # applying image transformation to crowd images 69 | if self.img_transform is not None: 70 | img = self.img_transform(img) 71 | 72 | # applying transformation consisting of ToTensor() and Meanstd() 73 | gui_imgs = [self.img_transform(gui_img) for gui_img in gui_imgs] 74 | 75 | # applying transformation to the crowd density maps 76 | if self.gt_transform is not None: 77 | den = self.gt_transform(den).unsqueeze(0) 78 | 79 | # creating a tensor out of the list of unlabeled image tensors 80 | gui_imgs = torch.cat(gui_imgs, dim=0) 81 | 82 | # returning crowd image, density map, tensor containing unlabeled 83 | # images and the list of unlabeled image names 84 | return img, den, gui_imgs 85 | 86 | def __len__(self): 87 | return self.num_samples 88 | 89 | def read_image_and_gt(self, fname): 90 | """ 91 | Method to read images and ground-truths 92 | """ 93 | 94 | gui_imgs = fname[0] 95 | crowd_img = fname[1] 96 | 97 | crowd_im = read_img(os.path.join(self.img_path, crowd_img)) 98 | gui_imgs = [read_img(os.path.join(self.img_path, gui_img)) 99 | for gui_img in gui_imgs] 100 | gt_path = crowd_img.replace('images', 'csvs').replace('.jpg', '.csv') 101 | 102 | den = pd.read_csv(gt_path, sep=',', header=None).values 103 | 104 | den = den.astype(np.float32, copy=False) 105 | den = Image.fromarray(den) 106 | return crowd_im, den, gui_imgs 107 | 108 | def get_num_samples(self): 109 | return self.num_samples 110 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/FDST/FDST.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import numpy as np 4 | import pandas as pd 5 | from PIL import Image 6 | from torch.utils import data 7 | 8 | 9 | def read_img(path): 10 | img = Image.open(path) 11 | 12 | if img.mode == 'L': 13 | img = img.convert('RGB') 14 | return img 15 | 16 | 17 | class FDST(data.Dataset): 18 | def __init__( 19 | self, 20 | data_path, 21 | main_transform=None, 22 | img_transform=None, 23 | gt_transform=None, 24 | k_shot=1, 25 | scene_folder=None): 26 | 27 | self.data_files = [] 28 | data_path = os.path.join(data_path, 'images') 29 | 30 | # Loop through all the subfolders and collect th images incase of 31 | # validation 32 | images = [] 33 | print(data_path, scene_folder) 34 | if scene_folder is None: 35 | scene_folders = [os.path.join(data_path, sf) 36 | for sf in os.listdir(data_path)] 37 | for scene_folder in scene_folders: 38 | view_folders = [ 39 | os.path.join( 40 | scene_folder, 41 | vf) for vf in os.listdir(scene_folder)] 42 | for vf in view_folders: 43 | images += [os.path.join(vf, img) 44 | for img in os.listdir(vf) if img.endswith('.jpg')] 45 | else: 46 | scene_folder = os.path.join(data_path, scene_folder) 47 | view_folders = [os.path.join(scene_folder, vf) 48 | for vf in os.listdir(scene_folder)] 49 | for vf in view_folders: 50 | images += [os.path.join(vf, img) 51 | for img in os.listdir(vf) if img.endswith('.jpg')] 52 | 53 | np.random.shuffle(images) 54 | gui_imgs = images[:k_shot] 55 | 56 | if 'train' in data_path: 57 | self.data_files = gui_imgs 58 | print("Number of train images: {}".format(len(self.data_files))) 59 | else: 60 | self.data_files = images 61 | print("Number of test images: {}".format(len(self.data_files))) 62 | 63 | self.num_samples = len(self.data_files) 64 | self.main_transform = main_transform 65 | self.img_transform = img_transform 66 | self.gt_transform = gt_transform 67 | 68 | def __getitem__(self, index): 69 | 70 | fname = self.data_files[index] 71 | 72 | # reading the crowd image, ground truth density map, list of unlabeled 73 | # images 74 | img, den = self.read_image_and_gt(fname) 75 | 76 | # applying main transformation (consists of image resizing) 77 | if self.main_transform is not None: 78 | img = self.main_transform(img) 79 | 80 | # applying image transformation (consists of ToTensor() and 81 | # Normalization of channels) 82 | if self.img_transform is not None: 83 | img = self.img_transform(img) 84 | 85 | # applying transformation to the crowd density maps 86 | if self.gt_transform is not None: 87 | den = self.gt_transform(den).unsqueeze(0) 88 | 89 | # returning crowd image, density map, tensor containing unlabeled 90 | # images and the list of unlabeled image names 91 | return img, den 92 | 93 | def __len__(self): 94 | return self.num_samples 95 | 96 | def read_image_and_gt(self, fname): 97 | """ 98 | Method to read images and ground-truths 99 | """ 100 | crowd_img = read_img(fname) 101 | den = None 102 | 103 | gt_path = fname.replace('images', 'csvs').replace('.jpg', '.csv') 104 | den = pd.read_csv(gt_path, sep=',', header=None).values 105 | den = den.astype(np.float32, copy=False) 106 | den = Image.fromarray(den) 107 | 108 | return crowd_img, den 109 | 110 | def get_num_samples(self): 111 | return self.num_samples 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## AdaCrowd: Unlabeled Scene Adaptation for Crowd Counting 2 | 3 | This repository contains the code for [AdaCrowd: Unlabeled Scene Adaptation for Crowd 4 | Counting]()
5 | IEEE Transactions on Multimedia 2021
6 | 7 | ### Setup 8 | 9 | Create a python virtual environment using either [virtualenv](https://docs.python.org/3/tutorial/venv.html) or [conda](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html). 10 | 11 | Install all the dependencies using `setup.py` 12 | ```python 13 | python setup.py install 14 | ``` 15 | 16 | ### Datasets 17 | The details related to all the crowd counting datasets can be found in the following links. 18 | 1. [WorldExpo'10](http://www.ee.cuhk.edu.hk/~xgwang/expo.html) 19 | 2. [Mall](https://personal.ie.cuhk.edu.hk/~ccloy/downloads_mall_dataset.html) 20 | 3. [PETS](http://cs.binghamton.edu/~mrldata/pets2009) 21 | 4. [FDST](https://github.com/sweetyy83/Lstn_fdst_dataset) 22 | 5. [CityUHK-X](http://visal.cs.cityu.edu.hk/downloads/#cityuhk-x) 23 | 24 | Note: For processing datasets, please refer to [C-3-Framework](https://github.com/gjy3035/C-3-Framework). Also update `DATA_PATH` in the `setting.py` for a particular dataset before using it for either training/testing. 25 | 26 | ### Training 27 | 28 | 1. **Baseline Methods** 29 | 30 | Refer to `config/baselines.py` configuration file to train baseline methods using different backbone networks (e.g. VGG-16 / ResNet-101) and to make appropriate changes. 31 | 32 | ```python 33 | python train_baselines.py 34 | ``` 35 | 2. **AdaCrowd Methods** 36 | Refer to `config/adacrowd.py` configuration file to train adacrowd methods for different backbone networks. 37 | ```python 38 | python train_adacrowd.py 39 | ``` 40 | 41 | ### Testing 42 | 43 | Update `MODEL_PATH` in either `config/adacrowd.py` or `config/baselines.py` to test the model. 44 | 45 | Refer to the following command-line arguments to run `test_adacrowd.py`. 46 | ```python 47 | optional arguments: 48 | -h, --help show this help message and exit 49 | -mn MODEL_NAME, --model_name MODEL_NAME 50 | Name of the model to be evaluated 51 | -mp MODEL_PATH, --model_path MODEL_PATH 52 | Path of the pre-trained model 53 | -data {WE,UCSD,Mall,PETS,City}, --dataset {WE,UCSD,Mall,PETS,City} 54 | Dataset to be evaluated 55 | -k K_SHOT, --k_shot K_SHOT 56 | Number of K images used for computing the affine transformation parameters 57 | -norm NUM_NORM, --num_norm NUM_NORM 58 | Number of normalization layers 59 | -gpu GPU_ID, --gpu_id GPU_ID 60 | GPU ID 61 | -r RESULT_FOLDER, --result_folder RESULT_FOLDER 62 | Path of the results folder 63 | -t TRAILS, --trails TRAILS 64 | Number of random trails to calculate mean and std scores 65 | ``` 66 | 67 | Similarly, refer to the following command-line arguments to run `test_baselines.py`. 68 | ```python 69 | optional arguments: 70 | -h, --help show this help message and exit 71 | -mn MODEL_NAME, --model_name MODEL_NAME 72 | Name of the model to be evaluated 73 | -mp MODEL_PATH, --model_path MODEL_PATH 74 | Path of the pre-trained model 75 | -data {WE,UCSD,Mall,PETS,City}, --dataset {WE,UCSD,Mall,PETS,City} 76 | Dataset to be evaluated 77 | -norm NUM_NORM, --num_norm NUM_NORM 78 | Number of normalization layers 79 | -gpu GPU_ID, --gpu_id GPU_ID 80 | GPU ID 81 | -r RESULT_FOLDER, --result_folder RESULT_FOLDER 82 | Path of the results folder 83 | ``` 84 | 85 | ### Citation 86 | ``` 87 | @article{reddy2020adacrowd, 88 | title = {AdaCrowd: Unlabeled Scene Adaptation for Crowd Counting}, 89 | author = {Reddy, Mahesh Kumar Krishna and Rochan, Mrigank and Lu, Yiwei and Wang, Yang}, 90 | journal = {arXiv preprint arXiv:2010.12141}, 91 | year = {2020} 92 | } 93 | ``` 94 | 95 | #### Acknowledgements 96 | This project borrows code from [C-3-Framework](https://github.com/gjy3035/C-3-Framework). 97 | 98 | ### License 99 | 100 | The project is licensed under MIT license (please refer to LICENSE.txt for more details). 101 | -------------------------------------------------------------------------------- /adacrowd/datasets/adacrowd/City/City.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import numpy as np 4 | import pandas as pd 5 | import torch 6 | from PIL import Image 7 | from torch.utils.data import Dataset 8 | 9 | 10 | def read_img(path): 11 | img = Image.open(path) 12 | 13 | if img.mode == 'L': 14 | img = img.convert('RGB') 15 | return img 16 | 17 | 18 | class City(Dataset): 19 | def __init__( 20 | self, 21 | data_path, 22 | main_transform=None, 23 | img_transform=None, 24 | gt_transform=None, 25 | k_shot=1, 26 | num_scenes=None, 27 | scene_folder=None): 28 | 29 | print("Scene folder: {}".format(scene_folder)) 30 | 31 | self.data_files = [] 32 | if scene_folder is None: 33 | folders = os.listdir(data_path) 34 | folders = folders if num_scenes is None else folders[:num_scenes] 35 | print( 36 | "Num scenes: {}, loaded scenes: {}".format( 37 | num_scenes, len(folders))) 38 | for fol in folders: 39 | img_fold = os.path.join(data_path, fol, 'images') 40 | images = [os.path.join(img_fold, img) for img in os.listdir( 41 | img_fold) if img.endswith('.jpg')] 42 | np.random.shuffle(images) 43 | gui_imgs = images[:k_shot] 44 | crowd_imgs = images[k_shot:] 45 | 46 | combined_imgs = [[gui_imgs, crowd_img] 47 | for crowd_img in crowd_imgs] 48 | self.data_files += combined_imgs 49 | else: 50 | img_fold = os.path.join(data_path, scene_folder, 'images') 51 | images = [os.path.join(img_fold, img) for img in os.listdir( 52 | img_fold) if img.endswith('.jpg')] 53 | np.random.shuffle(images) 54 | gui_imgs = images[:k_shot] 55 | crowd_imgs = images[k_shot:] 56 | 57 | combined_imgs = [[gui_imgs, crowd_img] for crowd_img in crowd_imgs] 58 | self.data_files += combined_imgs 59 | 60 | self.num_samples = len(self.data_files) 61 | self.main_transform = main_transform 62 | self.img_transform = img_transform 63 | self.gt_transform = gt_transform 64 | 65 | def __getitem__(self, index): 66 | 67 | fname = self.data_files[index] 68 | 69 | # reading the crowd image, ground truth density map, list of unlabeled 70 | # images 71 | img, den, gui_imgs = self.read_image_and_gt(fname) 72 | 73 | # applying transformation to the crowd images and it's ground-truth 74 | if self.main_transform is not None: 75 | img, den = self.main_transform(img, den) 76 | 77 | # applying image transformation to crowd images 78 | if self.img_transform is not None: 79 | img = self.img_transform(img) 80 | 81 | # applying transformation consisting of ToTensor() and Meanstd() 82 | gui_imgs = [self.img_transform(gui_img) for gui_img in gui_imgs] 83 | 84 | # applying transformation to the crowd density maps 85 | if self.gt_transform is not None: 86 | den = self.gt_transform(den).unsqueeze(0) 87 | 88 | # creating a tensor out of the list of unlabeled image tensors 89 | gui_imgs = torch.cat(gui_imgs, dim=0) 90 | 91 | # returning crowd image, density map, tensor containing unlabeled 92 | # images and the list of unlabeled image names 93 | return img, den, gui_imgs 94 | 95 | def __len__(self): 96 | return self.num_samples 97 | 98 | def read_image_and_gt(self, fname): 99 | """ 100 | Method to read images and ground-truths 101 | """ 102 | 103 | gui_imgs = fname[0] 104 | crowd_img = fname[1] 105 | 106 | crowd_im = read_img(crowd_img) 107 | gui_imgs = [read_img(gui_img) for gui_img in gui_imgs] 108 | gt_path = crowd_img.replace('images', 'gt').replace('.jpg', '.csv') 109 | 110 | den = pd.read_csv(gt_path, sep=',', header=None).values 111 | 112 | den = den.astype(np.float32, copy=False) 113 | den = Image.fromarray(den) 114 | return crowd_im, den, gui_imgs 115 | 116 | def get_num_samples(self): 117 | return self.num_samples 118 | -------------------------------------------------------------------------------- /adacrowd/models/baselines/Res101_BN.py: -------------------------------------------------------------------------------- 1 | import torch.nn.functional as F 2 | from torch import nn 3 | from torchvision import models 4 | 5 | from misc.utils import initialize_weights 6 | 7 | 8 | class Res101_BN(nn.Module): 9 | def __init__(self, pretrained=True, num_norm=6): 10 | super(Res101_BN, self).__init__() 11 | 12 | self.num_norm = num_norm 13 | self.backend_feat = [512, 512, 512, 256, 128, 64] 14 | 15 | self.frontend = [] 16 | self.backend = make_layers( 17 | self.backend_feat, 18 | in_channels=1024, 19 | dilation=True, 20 | batch_norm=True, 21 | num_norm=self.num_norm) 22 | self.output_layer = nn.Sequential( 23 | nn.Conv2d(64, 1, kernel_size=1), nn.ReLU()) 24 | initialize_weights(self.modules()) 25 | 26 | res = models.resnet101(pretrained=pretrained) 27 | self.frontend = nn.Sequential( 28 | res.conv1, 29 | res.bn1, 30 | res.relu, 31 | res.maxpool, 32 | res.layer1, 33 | res.layer2) 34 | self.own_reslayer_3 = make_res_layer(Bottleneck, 256, 23, stride=1) 35 | self.own_reslayer_3.load_state_dict(res.layer3.state_dict()) 36 | 37 | def forward(self, x): 38 | x = self.frontend(x) 39 | 40 | x = self.own_reslayer_3(x) 41 | x = self.backend(x) 42 | x = self.output_layer(x) 43 | x = F.upsample(x, scale_factor=8) 44 | 45 | return x 46 | 47 | 48 | def make_layers( 49 | cfg, 50 | in_channels=3, 51 | batch_norm=False, 52 | dilation=False, 53 | num_norm=6): 54 | norm_counter = 0 55 | d_rate = 2 if dilation else 1 56 | layers = [] 57 | for v in cfg: 58 | if v == 'M': 59 | layers += [nn.MaxPool2d(kernel_size=2, stride=2)] 60 | else: 61 | conv2d = nn.Conv2d( 62 | in_channels, 63 | v, 64 | kernel_size=3, 65 | padding=d_rate, 66 | dilation=d_rate) 67 | if norm_counter < num_norm: 68 | if batch_norm: 69 | layers += [conv2d, 70 | nn.BatchNorm2d(v), 71 | nn.ReLU(inplace=True)] 72 | norm_counter += 1 73 | else: 74 | layers += [conv2d, nn.ReLU(inplace=True)] 75 | else: 76 | layers += [conv2d, nn.ReLU(inplace=True)] 77 | in_channels = v 78 | return nn.Sequential(*layers) 79 | 80 | 81 | def make_res_layer(block, planes, blocks, stride=1): 82 | downsample = None 83 | inplanes = 512 84 | if stride != 1 or inplanes != planes * block.expansion: 85 | downsample = nn.Sequential( 86 | nn.Conv2d(inplanes, planes * block.expansion, 87 | kernel_size=1, stride=stride, bias=False), 88 | nn.BatchNorm2d(planes * block.expansion), 89 | ) 90 | 91 | layers = [] 92 | layers.append(block(inplanes, planes, stride, downsample)) 93 | inplanes = planes * block.expansion 94 | for i in range(1, blocks): 95 | layers.append(block(inplanes, planes)) 96 | 97 | return nn.Sequential(*layers) 98 | 99 | 100 | class Bottleneck(nn.Module): 101 | expansion = 4 102 | 103 | def __init__(self, inplanes, planes, stride=1, downsample=None): 104 | super(Bottleneck, self).__init__() 105 | self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) 106 | self.bn1 = nn.BatchNorm2d(planes) 107 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, 108 | padding=1, bias=False) 109 | self.bn2 = nn.BatchNorm2d(planes) 110 | self.conv3 = nn.Conv2d( 111 | planes, 112 | planes * 113 | self.expansion, 114 | kernel_size=1, 115 | bias=False) 116 | self.bn3 = nn.BatchNorm2d(planes * self.expansion) 117 | self.relu = nn.ReLU(inplace=True) 118 | self.downsample = downsample 119 | self.stride = stride 120 | 121 | def forward(self, x): 122 | residual = x 123 | 124 | out = self.conv1(x) 125 | out = self.bn1(out) 126 | out = self.relu(out) 127 | 128 | out = self.conv2(out) 129 | out = self.bn2(out) 130 | out = self.relu(out) 131 | 132 | out = self.conv3(out) 133 | out = self.bn3(out) 134 | 135 | if self.downsample is not None: 136 | residual = self.downsample(x) 137 | 138 | out += residual 139 | out = self.relu(out) 140 | 141 | return out 142 | -------------------------------------------------------------------------------- /adacrowd/misc/layer.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | 4 | 5 | class Conv2d(nn.Module): 6 | def __init__( 7 | self, 8 | in_channels, 9 | out_channels, 10 | kernel_size, 11 | stride=1, 12 | NL='relu', 13 | same_padding=False, 14 | bn=False, 15 | dilation=1): 16 | super(Conv2d, self).__init__() 17 | padding = int((kernel_size - 1) // 2) if same_padding else 0 18 | self.conv = [] 19 | if dilation == 1: 20 | self.conv = nn.Conv2d( 21 | in_channels, 22 | out_channels, 23 | kernel_size, 24 | stride, 25 | padding=padding, 26 | dilation=dilation) 27 | else: 28 | self.conv = nn.Conv2d( 29 | in_channels, 30 | out_channels, 31 | kernel_size, 32 | stride, 33 | padding=dilation, 34 | dilation=dilation) 35 | self.bn = nn.BatchNorm2d( 36 | out_channels, 37 | eps=0.001, 38 | momentum=0, 39 | affine=True) if bn else None 40 | if NL == 'relu': 41 | self.relu = nn.ReLU(inplace=True) 42 | elif NL == 'prelu': 43 | self.relu = nn.PReLU() 44 | else: 45 | self.relu = None 46 | 47 | def forward(self, x): 48 | x = self.conv(x) 49 | if self.bn is not None: 50 | x = self.bn(x) 51 | if self.relu is not None: 52 | x = self.relu(x) 53 | return x 54 | 55 | 56 | class FC(nn.Module): 57 | def __init__(self, in_features, out_features, NL='relu'): 58 | super(FC, self).__init__() 59 | self.fc = nn.Linear(in_features, out_features) 60 | if NL == 'relu': 61 | self.relu = nn.ReLU(inplace=True) 62 | elif NL == 'prelu': 63 | self.relu = nn.PReLU() 64 | else: 65 | self.relu = None 66 | 67 | def forward(self, x): 68 | x = self.fc(x) 69 | if self.relu is not None: 70 | x = self.relu(x) 71 | return x 72 | 73 | 74 | class convDU(nn.Module): 75 | 76 | def __init__(self, 77 | in_out_channels=2048, 78 | kernel_size=(9, 1) 79 | ): 80 | super(convDU, self).__init__() 81 | self.conv = nn.Sequential( 82 | nn.Conv2d( 83 | in_out_channels, 84 | in_out_channels, 85 | kernel_size, 86 | stride=1, 87 | padding=( 88 | (kernel_size[0] - 1) // 2, 89 | (kernel_size[1] - 1) // 2)), 90 | nn.ReLU( 91 | inplace=True)) 92 | 93 | def forward(self, fea): 94 | n, c, h, w = fea.size() 95 | 96 | fea_stack = [] 97 | for i in range(h): 98 | i_fea = fea.select(2, i).resize(n, c, 1, w) 99 | if i == 0: 100 | fea_stack.append(i_fea) 101 | continue 102 | fea_stack.append(self.conv(fea_stack[i - 1]) + i_fea) 103 | 104 | for i in range(h): 105 | pos = h - i - 1 106 | if pos == h - 1: 107 | continue 108 | fea_stack[pos] = self.conv(fea_stack[pos + 1]) + fea_stack[pos] 109 | fea = torch.cat(fea_stack, 2) 110 | return fea 111 | 112 | 113 | class convLR(nn.Module): 114 | 115 | def __init__(self, 116 | in_out_channels=2048, 117 | kernel_size=(1, 9) 118 | ): 119 | super(convLR, self).__init__() 120 | self.conv = nn.Sequential( 121 | nn.Conv2d( 122 | in_out_channels, 123 | in_out_channels, 124 | kernel_size, 125 | stride=1, 126 | padding=( 127 | (kernel_size[0] - 1) // 2, 128 | (kernel_size[1] - 1) // 2)), 129 | nn.ReLU( 130 | inplace=True)) 131 | 132 | def forward(self, fea): 133 | n, c, h, w = fea.size() 134 | 135 | fea_stack = [] 136 | for i in range(w): 137 | i_fea = fea.select(3, i).resize(n, c, h, 1) 138 | if i == 0: 139 | fea_stack.append(i_fea) 140 | continue 141 | fea_stack.append(self.conv(fea_stack[i - 1]) + i_fea) 142 | 143 | for i in range(w): 144 | pos = w - i - 1 145 | if pos == w - 1: 146 | continue 147 | fea_stack[pos] = self.conv(fea_stack[pos + 1]) + fea_stack[pos] 148 | 149 | fea = torch.cat(fea_stack, 3) 150 | return fea 151 | -------------------------------------------------------------------------------- /adacrowd/models/baselines/Res101_SFCN_BN.py: -------------------------------------------------------------------------------- 1 | import torch.nn.functional as F 2 | from torch import nn 3 | from torchvision import models 4 | 5 | from misc.layer import convDU, convLR 6 | from misc.utils import initialize_weights 7 | 8 | 9 | class Res101_SFCN_BN(nn.Module): 10 | def __init__( 11 | self, 12 | pretrained=True, 13 | num_norm=6): 14 | super(Res101_SFCN_BN, self).__init__() 15 | 16 | self.num_norm = num_norm 17 | self.backend_feat = [512, 512, 512, 256, 128, 64] 18 | 19 | self.frontend = [] 20 | self.backend = make_layers( 21 | self.backend_feat, 22 | in_channels=1024, 23 | dilation=True, 24 | batch_norm=True, 25 | num_norm=self.num_norm) 26 | self.convDU = convDU(in_out_channels=64, kernel_size=(1, 9)) 27 | self.convLR = convLR(in_out_channels=64, kernel_size=(9, 1)) 28 | 29 | self.output_layer = nn.Sequential( 30 | nn.Conv2d(64, 1, kernel_size=1), nn.ReLU()) 31 | 32 | initialize_weights(self.modules()) 33 | 34 | res = models.resnet101(pretrained=pretrained) 35 | self.frontend = nn.Sequential( 36 | res.conv1, 37 | res.bn1, 38 | res.relu, 39 | res.maxpool, 40 | res.layer1, 41 | res.layer2) 42 | self.own_reslayer_3 = make_res_layer(Bottleneck, 256, 23, stride=1) 43 | self.own_reslayer_3.load_state_dict(res.layer3.state_dict()) 44 | 45 | def forward(self, x): 46 | x = self.frontend(x) 47 | x = self.own_reslayer_3(x) 48 | x = self.backend(x) 49 | x = self.convDU(x) 50 | x = self.convLR(x) 51 | x = self.output_layer(x) 52 | x = F.upsample(x, scale_factor=8) 53 | 54 | return x 55 | 56 | 57 | def make_layers( 58 | cfg, 59 | in_channels=3, 60 | batch_norm=False, 61 | dilation=False, 62 | num_norm=6): 63 | norm_counter = 0 64 | d_rate = 2 if dilation else 1 65 | layers = [] 66 | for v in cfg: 67 | if v == 'M': 68 | layers += [nn.MaxPool2d(kernel_size=2, stride=2)] 69 | else: 70 | conv2d = nn.Conv2d( 71 | in_channels, 72 | v, 73 | kernel_size=3, 74 | padding=d_rate, 75 | dilation=d_rate) 76 | if norm_counter < num_norm: 77 | if batch_norm: 78 | layers += [conv2d, 79 | nn.BatchNorm2d(v), 80 | nn.ReLU(inplace=True)] 81 | norm_counter += 1 82 | else: 83 | layers += [conv2d, nn.ReLU(inplace=True)] 84 | else: 85 | layers += [conv2d, nn.ReLU(inplace=True)] 86 | in_channels = v 87 | return nn.Sequential(*layers) 88 | 89 | 90 | def make_res_layer(block, planes, blocks, stride=1): 91 | downsample = None 92 | inplanes = 512 93 | if stride != 1 or inplanes != planes * block.expansion: 94 | downsample = nn.Sequential( 95 | nn.Conv2d(inplanes, planes * block.expansion, 96 | kernel_size=1, stride=stride, bias=False), 97 | nn.BatchNorm2d(planes * block.expansion), 98 | ) 99 | 100 | layers = [] 101 | layers.append(block(inplanes, planes, stride, downsample)) 102 | inplanes = planes * block.expansion 103 | for i in range(1, blocks): 104 | layers.append(block(inplanes, planes)) 105 | 106 | return nn.Sequential(*layers) 107 | 108 | 109 | class Bottleneck(nn.Module): 110 | expansion = 4 111 | 112 | def __init__(self, inplanes, planes, stride=1, downsample=None): 113 | super(Bottleneck, self).__init__() 114 | self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) 115 | self.bn1 = nn.BatchNorm2d(planes) 116 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, 117 | padding=1, bias=False) 118 | self.bn2 = nn.BatchNorm2d(planes) 119 | self.conv3 = nn.Conv2d( 120 | planes, 121 | planes * 122 | self.expansion, 123 | kernel_size=1, 124 | bias=False) 125 | self.bn3 = nn.BatchNorm2d(planes * self.expansion) 126 | self.relu = nn.ReLU(inplace=True) 127 | self.downsample = downsample 128 | self.stride = stride 129 | 130 | def forward(self, x): 131 | residual = x 132 | 133 | out = self.conv1(x) 134 | out = self.bn1(out) 135 | out = self.relu(out) 136 | 137 | out = self.conv2(out) 138 | out = self.bn2(out) 139 | out = self.relu(out) 140 | 141 | out = self.conv3(out) 142 | out = self.bn3(out) 143 | 144 | if self.downsample is not None: 145 | residual = self.downsample(x) 146 | 147 | out += residual 148 | out = self.relu(out) 149 | 150 | return out 151 | -------------------------------------------------------------------------------- /adacrowd/models/adacrowd/CSRNet_GBN.py: -------------------------------------------------------------------------------- 1 | import torch.nn.functional as F 2 | from torch import nn 3 | from torchvision import models 4 | 5 | from misc.utils import initialize_weights 6 | 7 | from .blocks import (GuidedBatchNorm2d, GuidingEncoder, GuidingMLP, 8 | get_num_adaptive_params) 9 | 10 | 11 | class CSRNet_GBN(nn.Module): 12 | def __init__(self, num_gbnnorm=6): 13 | super(CSRNet_GBN, self).__init__() 14 | 15 | self.num_gbnnorm = num_gbnnorm 16 | 17 | # crowd encoder consists of normalization layers 18 | # Params: pretrained, default_value=True 19 | self.crowd_encoder = CrowdEncoder() 20 | 21 | # guiding encoder does not consist of normalization layers 22 | self.guiding_encoder = GuidingEncoder( 23 | downs=4, 24 | ind_im=3, 25 | dim=64, 26 | latent_dim=64, 27 | norm='none', 28 | activ='relu', 29 | pad_type='reflect', 30 | pool_type='adapt_avg_pool') 31 | 32 | # decoder to generate the output density map 33 | self.crowd_decoder = CrowdDecoder(norm='GBN', num_gbnnorm=self.num_gbnnorm) 34 | 35 | # MLP to generate the adaptive normalization parameters from the output 36 | # of guiding decoder 37 | num_ada_params = get_num_adaptive_params(self.crowd_decoder) 38 | self.guiding_mlp = GuidingMLP( 39 | in_dim=64, 40 | out_dim=num_ada_params, 41 | dim=256, 42 | n_blk=3, 43 | norm='none', 44 | activ='relu') 45 | 46 | def forward(self, x): 47 | pass 48 | 49 | 50 | class CrowdDecoder(nn.Module): 51 | """ 52 | Class to decode the output density map from encoded (crowd + guiding) features 53 | """ 54 | 55 | def __init__(self, norm=None, num_gbnnorm=6): 56 | super(CrowdDecoder, self).__init__() 57 | 58 | self.norm = norm 59 | self.num_gbnnorm = num_gbnnorm 60 | 61 | self.backend_feat = [512, 512, 512, 256, 128, 64] 62 | self.backend = make_layers( 63 | self.backend_feat, 64 | in_channels=512, 65 | dilation=True, 66 | norm=self.norm, 67 | num_gbnnorm=self.num_gbnnorm) 68 | self.output_layer = nn.Conv2d(64, 1, kernel_size=1) 69 | 70 | initialize_weights(self.modules()) 71 | 72 | def forward(self, x): 73 | x = self.backend(x) 74 | x = self.output_layer(x) 75 | x = F.upsample(x, scale_factor=8) 76 | 77 | return x 78 | 79 | 80 | class CrowdEncoder(nn.Module): 81 | """ 82 | CSRNet implementation 83 | Reference: https://github.com/leeyeehoo/CSRNet-pytorch 84 | Paper: https://arxiv.org/abs/1802.10062 85 | """ 86 | 87 | def __init__(self, pretrained=True): 88 | super(CrowdEncoder, self).__init__() 89 | 90 | # VGG feature extractor 91 | self.frontend_feat = [64, 64, 'M', 128, 128, 92 | 'M', 256, 256, 256, 'M', 512, 512, 512] 93 | self.frontend = make_layers(self.frontend_feat) 94 | 95 | # Loading weights from the pre-trained VGG16 model 96 | if pretrained: 97 | mod = models.vgg16(pretrained=True) 98 | self._initialize_weights() 99 | self.frontend.load_state_dict(mod.features[0:23].state_dict()) 100 | 101 | def forward(self, x): 102 | x = self.frontend(x) # output feature shape (B x 512 x H/8 x W/8) 103 | return x 104 | 105 | # Weight initialization as per the CSRNet paper 106 | # Mean=0, Standard deviation=0.01 107 | def _initialize_weights(self): 108 | for m in self.modules(): 109 | if isinstance(m, nn.Conv2d): 110 | nn.init.normal_(m.weight, std=0.01) 111 | if m.bias is not None: 112 | nn.init.constant_(m.bias, 0) 113 | elif isinstance(m, nn.BatchNorm2d): 114 | nn.init.constant_(m.weight, 1) 115 | nn.init.constant_(m.bias, 0) 116 | 117 | 118 | def make_layers(cfg, in_channels=3, dilation=False, norm=None, num_gbnnorm=6): 119 | """ 120 | Method to make decoder layers 121 | """ 122 | gbn_counter = 0 123 | d_rate = 2 if dilation else 1 124 | layers = [] 125 | for v in cfg: 126 | if v == 'M': 127 | layers += [nn.MaxPool2d(kernel_size=2, stride=2)] 128 | else: 129 | conv2d = nn.Conv2d( 130 | in_channels, 131 | v, 132 | kernel_size=3, 133 | padding=d_rate, 134 | dilation=d_rate) 135 | if norm == 'GBN': 136 | if gbn_counter < num_gbnnorm: 137 | layers += [conv2d, 138 | GuidedBatchNorm2d(v), 139 | nn.ReLU(inplace=True)] 140 | gbn_counter += 1 141 | else: 142 | layers += [conv2d, nn.ReLU(inplace=True)] 143 | else: 144 | layers += [conv2d, nn.ReLU(inplace=True)] 145 | in_channels = v 146 | return nn.Sequential(*layers) 147 | -------------------------------------------------------------------------------- /adacrowd/test_baselines.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import json 3 | import os 4 | 5 | import numpy as np 6 | import torch 7 | from torch.autograd import Variable 8 | from tqdm import tqdm 9 | 10 | from misc.utils import AverageMeter 11 | from models.cc_baselines import CrowdCounter 12 | 13 | device = 'cuda' if torch.cuda.is_available() else 'cpu' 14 | 15 | seed = 3035 16 | torch.backends.cudnn.benchmark = True 17 | 18 | # seeding the random function 19 | if seed is not None: 20 | np.random.seed(seed) 21 | torch.manual_seed(seed) 22 | torch.cuda.manual_seed(seed) 23 | 24 | SINGLE_FOLDER_DATASETS = ["WE", "City"] 25 | 26 | 27 | def load_dataloader(data_mode): 28 | if data_mode == 'WE': 29 | from datasets.baselines.WE.loading_data import loading_data 30 | from datasets.baselines.WE.setting import cfg_data 31 | elif data_mode == 'Mall': 32 | from datasets.baselines.Mall.loading_data import loading_data 33 | from datasets.baselines.Mall.setting import cfg_data 34 | elif data_mode == 'PETS': 35 | from datasets.baselines.PETS.loading_data import loading_data 36 | from datasets.baselines.PETS.setting import cfg_data 37 | elif data_mode == 'FDST': 38 | from datasets.baselines.FDST.loading_data import loading_data 39 | from datasets.baselines.FDST.setting import cfg_data 40 | elif data_mode == 'City': 41 | from datasets.baselines.City.loading_data import loading_data 42 | from datasets.baselines.City.setting import cfg_data 43 | return loading_data, cfg_data 44 | 45 | 46 | def test(dataset, args, scene_folder=None): 47 | 48 | maes = AverageMeter() 49 | mses = AverageMeter() 50 | 51 | model_path = args.model_path 52 | model = CrowdCounter([args.gpu_id], args.model_name, 53 | num_norm=args.num_norm).to(device) 54 | checkpoint = torch.load(model_path, map_location='cuda:0') 55 | model.load_state_dict(checkpoint) 56 | model.to(device) 57 | model.eval() 58 | 59 | if dataset in ['PETS', 'FDST']: 60 | file_name = "scene_{}_stats.json".format(scene_folder) 61 | else: 62 | file_name = "stats.json" 63 | 64 | model_name = args.model_path.split(os.sep)[-1].split('.pth')[0] 65 | output_folder = os.path.join( 66 | args.result_folder, 67 | args.model_name, 68 | dataset, 69 | model_name) 70 | 71 | if not os.path.exists(output_folder): 72 | os.makedirs(output_folder) 73 | 74 | load_data, _ = load_dataloader(dataset) 75 | if dataset in ['PETS', 'FDST']: 76 | _, val_loader, _ = load_data(scene_folder=scene_folder) 77 | else: 78 | _, val_loader, _ = load_data() 79 | 80 | for _, data in enumerate(tqdm(val_loader, total=len(val_loader))): 81 | img, gt, _ = data 82 | img = Variable(img).to(device) 83 | gt = Variable(gt).to(device) 84 | pred_map = model.test_forward(img) 85 | 86 | pred_img = pred_map.data.cpu().numpy().squeeze() 87 | gt_img = gt.data.cpu().numpy().squeeze() 88 | 89 | pred_count = np.sum(pred_img) / 100. 90 | gt_count = np.sum(gt_img) / 100. 91 | 92 | difference = gt_count - pred_count 93 | maes.update(abs(difference)) 94 | mses.update(difference ** 2) 95 | 96 | mae = maes.avg 97 | mse = np.sqrt(mses.avg) 98 | print( 99 | "Model: {}, Dataset: {}, MAE: {}, MSE: {}".format( 100 | args.model_name, 101 | dataset, 102 | mae, 103 | mse)) 104 | RESULT = {'mae': mae, 'mse': mse} 105 | 106 | output_path = os.path.join(output_folder, file_name) 107 | with open(output_path, 'w') as fp: 108 | json.dump(RESULT, fp) 109 | 110 | 111 | if __name__ == '__main__': 112 | FLAGS = argparse.ArgumentParser() 113 | FLAGS.add_argument( 114 | '-mn', 115 | '--model_name', 116 | help="Name of the model to be evaluated", 117 | required=True, 118 | type=str) 119 | FLAGS.add_argument( 120 | '-mp', 121 | '--model_path', 122 | help="Path of the pre-trained model", 123 | required=True, 124 | type=str) 125 | FLAGS.add_argument( 126 | '-data', 127 | '--dataset', 128 | help="Dataset to be evaluated", 129 | default='WE', 130 | type=str, 131 | choices=[ 132 | 'WE', 133 | 'UCSD', 134 | 'Mall', 135 | 'PETS', 136 | 'City']) 137 | FLAGS.add_argument( 138 | '-norm', 139 | '--num_norm', 140 | help="Number of normalization layers", 141 | required=True, 142 | type=int) 143 | FLAGS.add_argument('-gpu', '--gpu_id', help="GPU ID", default=0, type=int) 144 | FLAGS.add_argument( 145 | '-r', 146 | '--result_folder', 147 | help="Path of the results folder", 148 | type=str, 149 | required=True) 150 | 151 | args = FLAGS.parse_args() 152 | dataset = args.dataset 153 | if dataset in ['PETS', 'FDST']: 154 | # TODO: Add the list of scenes/sub-folders in PETS or FDST folder to 155 | # evalute every scene/sub-folder 156 | scene_folders = [] 157 | for sf in scene_folders: 158 | test(dataset=dataset, args=args, scene_folder=sf) 159 | else: 160 | test(dataset=dataset, args=args) 161 | -------------------------------------------------------------------------------- /adacrowd/models/adacrowd/Res101_GBN.py: -------------------------------------------------------------------------------- 1 | import torch.nn.functional as F 2 | from torch import nn 3 | from torchvision import models 4 | 5 | from misc.utils import initialize_weights 6 | 7 | from .blocks import (GuidedBatchNorm2d, GuidingEncoder, GuidingMLP, 8 | get_num_adaptive_params) 9 | 10 | 11 | class Res101_GBN(nn.Module): 12 | def __init__(self, num_gbnnorm=6): 13 | super(Res101_GBN, self).__init__() 14 | 15 | # boolean condition to check if SSIM vec is required 16 | self.num_gbnnorm = num_gbnnorm 17 | 18 | # crowd encoder consists of normalization layers 19 | # Params: pretrained, default_value=True 20 | self.crowd_encoder = CrowdEncoder() 21 | 22 | # guiding encoder does not consist of normalization layers 23 | self.guiding_encoder = GuidingEncoder(downs=4, ind_im=3, dim=64, latent_dim=64, norm='none', activ='relu', 24 | pad_type='reflect', pool_type='adapt_avg_pool') 25 | 26 | # decoder to generate the output density map 27 | self.crowd_decoder = CrowdDecoder(norm='GBN', num_gbnnorm=self.num_gbnnorm) 28 | 29 | # MLP to generate the adaptive normalization parameters from the output of guiding decoder 30 | num_ada_params = get_num_adaptive_params(self.crowd_decoder) 31 | self.guiding_mlp = GuidingMLP(in_dim=64, out_dim=num_ada_params, dim=256, n_blk=3, norm='none', 32 | activ='relu') 33 | 34 | def forward(self, x): 35 | pass 36 | 37 | 38 | class CrowdEncoder(nn.Module): 39 | """ 40 | Class to extract features from the crowd image 41 | Input dim: B x 3 x H x W 42 | Output dim: B x 512 x H/8 x W/8 43 | 44 | Params: pretrained=True, makes use of pretrained weights from ImageNet for the encoder part of the encoder 45 | """ 46 | 47 | def __init__(self, pretrained=True): 48 | super(CrowdEncoder, self).__init__() 49 | res = models.resnet101(pretrained=pretrained) 50 | self.frontend = nn.Sequential(res.conv1, res.bn1, res.relu, res.maxpool, res.layer1, res.layer2) 51 | self.own_reslayer_3 = make_res_layer(Bottleneck, 256, 23, stride=1) 52 | self.own_reslayer_3.load_state_dict(res.layer3.state_dict()) 53 | 54 | def forward(self, x): 55 | x = self.frontend(x) 56 | x = self.own_reslayer_3(x) 57 | return x 58 | 59 | 60 | class CrowdDecoder(nn.Module): 61 | """ 62 | Class to decode the output density map from encoded (crowd + guiding) features 63 | """ 64 | 65 | def __init__(self, norm=None, num_gbnnorm=6): 66 | super(CrowdDecoder, self).__init__() 67 | 68 | self.norm = norm 69 | self.num_gbnnorm = num_gbnnorm 70 | self.backend_feat = [512, 512, 512, 256, 128, 64] 71 | 72 | self.backend = make_layers(self.backend_feat, in_channels=1024, dilation=True, norm=self.norm, 73 | num_gbnnorm=self.num_gbnnorm) 74 | self.output_layer = nn.Sequential(nn.Conv2d(64, 1, kernel_size=1), nn.ReLU()) 75 | 76 | initialize_weights(self.modules()) 77 | 78 | def forward(self, x): 79 | x = self.backend(x) 80 | x = self.output_layer(x) 81 | x = F.upsample(x, scale_factor=8) 82 | 83 | return x 84 | 85 | 86 | def make_layers(cfg, in_channels=3, dilation=False, norm=None, num_gbnnorm=6): 87 | """ 88 | Method to make layers for ResNet 89 | """ 90 | gbn_counter = 0 91 | d_rate = 2 if dilation else 1 92 | layers = [] 93 | for v in cfg: 94 | if v == 'M': 95 | layers += [nn.MaxPool2d(kernel_size=2, stride=2)] 96 | else: 97 | conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=d_rate, dilation=d_rate) 98 | if norm == 'GBN': 99 | if gbn_counter < num_gbnnorm: 100 | layers += [conv2d, GuidedBatchNorm2d(v), nn.ReLU(inplace=True)] 101 | gbn_counter += 1 102 | else: 103 | layers += [conv2d, nn.ReLU(inplace=True)] 104 | else: 105 | layers += [conv2d, nn.ReLU(inplace=True)] 106 | in_channels = v 107 | return nn.Sequential(*layers) 108 | 109 | 110 | def make_res_layer(block, planes, blocks, stride=1): 111 | """ 112 | Method to make resnet layer for ResNet 113 | """ 114 | downsample = None 115 | inplanes = 512 116 | if stride != 1 or inplanes != planes * block.expansion: 117 | downsample = nn.Sequential( 118 | nn.Conv2d(inplanes, planes * block.expansion, 119 | kernel_size=1, stride=stride, bias=False), 120 | nn.BatchNorm2d(planes * block.expansion), 121 | ) 122 | 123 | layers = [] 124 | layers.append(block(inplanes, planes, stride, downsample)) 125 | inplanes = planes * block.expansion 126 | for i in range(1, blocks): 127 | layers.append(block(inplanes, planes)) 128 | 129 | return nn.Sequential(*layers) 130 | 131 | 132 | class Bottleneck(nn.Module): 133 | expansion = 4 134 | 135 | def __init__(self, inplanes, planes, stride=1, downsample=None): 136 | super(Bottleneck, self).__init__() 137 | self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) 138 | self.bn1 = nn.BatchNorm2d(planes) 139 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, 140 | padding=1, bias=False) 141 | self.bn2 = nn.BatchNorm2d(planes) 142 | self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False) 143 | self.bn3 = nn.BatchNorm2d(planes * self.expansion) 144 | self.relu = nn.ReLU(inplace=True) 145 | self.downsample = downsample 146 | self.stride = stride 147 | 148 | def forward(self, x): 149 | residual = x 150 | 151 | out = self.conv1(x) 152 | out = self.bn1(out) 153 | out = self.relu(out) 154 | 155 | out = self.conv2(out) 156 | out = self.bn2(out) 157 | out = self.relu(out) 158 | 159 | out = self.conv3(out) 160 | out = self.bn3(out) 161 | 162 | if self.downsample is not None: 163 | residual = self.downsample(x) 164 | 165 | out += residual 166 | out = self.relu(out) 167 | 168 | return out 169 | -------------------------------------------------------------------------------- /adacrowd/models/adacrowd/Res101_SFCN_GBN.py: -------------------------------------------------------------------------------- 1 | import torch.nn.functional as F 2 | from torch import nn 3 | from torchvision import models 4 | 5 | from misc.layer import convDU, convLR 6 | from misc.utils import initialize_weights 7 | 8 | from .blocks import (GuidedBatchNorm2d, GuidingEncoder, GuidingMLP, 9 | get_num_adaptive_params) 10 | 11 | 12 | class Res101_SFCN_GBN(nn.Module): 13 | def __init__(self, num_gbnnorm=6): 14 | super(Res101_SFCN_GBN, self).__init__() 15 | 16 | self.num_gbnnorm = num_gbnnorm 17 | # crowd encoder consists of normalization layers 18 | # Params: pretrained, default_value=True 19 | self.crowd_encoder = CrowdEncoder() 20 | 21 | # guiding encoder does not consist of normalization layers 22 | self.guiding_encoder = GuidingEncoder(downs=4, ind_im=3, dim=64, latent_dim=64, norm='none', activ='relu', 23 | pad_type='reflect', pool_type='adapt_avg_pool') 24 | 25 | # decoder to generate the output density map 26 | self.crowd_decoder = CrowdDecoder(norm='GBN', num_gbnnorm=self.num_gbnnorm) 27 | 28 | # MLP to generate the adaptive normalization parameters from the output of guiding decoder 29 | num_ada_params = get_num_adaptive_params(self.crowd_decoder) 30 | self.guiding_mlp = GuidingMLP(in_dim=64, out_dim=num_ada_params, dim=256, n_blk=3, norm='none', 31 | activ='relu') 32 | 33 | def forward(self, x): 34 | pass 35 | 36 | 37 | class CrowdEncoder(nn.Module): 38 | """ 39 | Class to extract features from the crowd image 40 | Input dim: B x 3 x H x W 41 | Output dim: B x 512 x H/8 x W/8 42 | 43 | Params: pretrained=True, makes use of pretrained weights from ImageNet for the encoder part of the encoder 44 | """ 45 | 46 | def __init__(self, pretrained=True): 47 | super(CrowdEncoder, self).__init__() 48 | res = models.resnet101(pretrained=pretrained) 49 | self.frontend = nn.Sequential(res.conv1, res.bn1, res.relu, res.maxpool, res.layer1, res.layer2) 50 | self.own_reslayer_3 = make_res_layer(Bottleneck, 256, 23, stride=1) 51 | self.own_reslayer_3.load_state_dict(res.layer3.state_dict()) 52 | 53 | def forward(self, x): 54 | x = self.frontend(x) 55 | x = self.own_reslayer_3(x) 56 | return x 57 | 58 | 59 | class CrowdDecoder(nn.Module): 60 | """ 61 | Class to decode the output density map from encoded (crowd + guiding) features 62 | """ 63 | 64 | def __init__(self, norm=None, num_gbnnorm=6): 65 | super(CrowdDecoder, self).__init__() 66 | 67 | self.norm = norm 68 | self.num_gbnnorm = num_gbnnorm 69 | self.backend_feat = [512, 512, 512, 256, 128, 64] 70 | 71 | self.backend = make_layers(self.backend_feat, in_channels=1024, dilation=True, norm=self.norm, 72 | num_gbnnorm=self.num_gbnnorm) 73 | self.convDU = convDU(in_out_channels=64, kernel_size=(1, 9)) 74 | self.convLR = convLR(in_out_channels=64, kernel_size=(9, 1)) 75 | self.output_layer = nn.Sequential(nn.Conv2d(64, 1, kernel_size=1), nn.ReLU()) 76 | 77 | initialize_weights(self.modules()) 78 | 79 | def forward(self, x): 80 | x = self.backend(x) 81 | x = self.convDU(x) 82 | x = self.convLR(x) 83 | x = self.output_layer(x) 84 | x = F.upsample(x, scale_factor=8) 85 | 86 | return x 87 | 88 | 89 | def make_layers(cfg, in_channels=3, dilation=False, norm=None, num_gbnnorm=6): 90 | """ 91 | Method to make layers for ResNet 92 | """ 93 | d_rate = 2 if dilation else 1 94 | layers = [] 95 | gbn_counter = 0 96 | for v in cfg: 97 | if v == 'M': 98 | layers += [nn.MaxPool2d(kernel_size=2, stride=2)] 99 | else: 100 | conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=d_rate, dilation=d_rate) 101 | if norm == 'GBN': 102 | if gbn_counter < num_gbnnorm: 103 | layers += [conv2d, GuidedBatchNorm2d(v), nn.ReLU(inplace=True)] 104 | gbn_counter += 1 105 | else: 106 | layers += [conv2d, nn.ReLU(inplace=True)] 107 | else: 108 | layers += [conv2d, nn.ReLU(inplace=True)] 109 | in_channels = v 110 | return nn.Sequential(*layers) 111 | 112 | 113 | def make_res_layer(block, planes, blocks, stride=1): 114 | """ 115 | Method to make resnet layer for ResNet 116 | """ 117 | downsample = None 118 | inplanes = 512 119 | if stride != 1 or inplanes != planes * block.expansion: 120 | downsample = nn.Sequential( 121 | nn.Conv2d(inplanes, planes * block.expansion, 122 | kernel_size=1, stride=stride, bias=False), 123 | nn.BatchNorm2d(planes * block.expansion), 124 | ) 125 | 126 | layers = [] 127 | layers.append(block(inplanes, planes, stride, downsample)) 128 | inplanes = planes * block.expansion 129 | for i in range(1, blocks): 130 | layers.append(block(inplanes, planes)) 131 | 132 | return nn.Sequential(*layers) 133 | 134 | 135 | class Bottleneck(nn.Module): 136 | expansion = 4 137 | 138 | def __init__(self, inplanes, planes, stride=1, downsample=None): 139 | super(Bottleneck, self).__init__() 140 | self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) 141 | self.bn1 = nn.BatchNorm2d(planes) 142 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, 143 | padding=1, bias=False) 144 | self.bn2 = nn.BatchNorm2d(planes) 145 | self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False) 146 | self.bn3 = nn.BatchNorm2d(planes * self.expansion) 147 | self.relu = nn.ReLU(inplace=True) 148 | self.downsample = downsample 149 | self.stride = stride 150 | 151 | def forward(self, x): 152 | residual = x 153 | 154 | out = self.conv1(x) 155 | out = self.bn1(out) 156 | out = self.relu(out) 157 | 158 | out = self.conv2(out) 159 | out = self.bn2(out) 160 | out = self.relu(out) 161 | 162 | out = self.conv3(out) 163 | out = self.bn3(out) 164 | 165 | if self.downsample is not None: 166 | residual = self.downsample(x) 167 | 168 | out += residual 169 | out = self.relu(out) 170 | 171 | return out 172 | -------------------------------------------------------------------------------- /adacrowd/models/cc_adacrowd.py: -------------------------------------------------------------------------------- 1 | # import ipdb 2 | import numpy as np 3 | import torch 4 | import torch.nn as nn 5 | 6 | from .adacrowd.blocks import assign_adaptive_params 7 | 8 | device = 'cuda' if torch.cuda.is_available() else 'cpu' 9 | 10 | SINGLE_FOLDER_DATASETS = ["WE", "City"] 11 | 12 | 13 | class CrowdCounterAdaCrowd(nn.Module): 14 | def __init__(self, gpus, model_name, num_gbnnorm=6): 15 | super(CrowdCounterAdaCrowd, self).__init__() 16 | self.gpus = gpus 17 | self.model_name = model_name 18 | self.num_gbnnorm = num_gbnnorm 19 | 20 | if self.model_name == 'CSRNet_GBN': 21 | from .adacrowd.CSRNet_GBN import CSRNet_GBN as net 22 | elif self.model_name == 'Res101_GBN': 23 | from .adacrowd.Res101_GBN import Res101_GBN as net 24 | elif self.model_name == 'Res101_SFCN_GBN': 25 | from .adacrowd.Res101_SFCN_GBN import Res101_SFCN_GBN as net 26 | self.CCN = net(num_gbnnorm=self.num_gbnnorm) 27 | 28 | if len(self.gpus) > 1: 29 | self.CCN = torch.nn.DataParallel( 30 | self.CCN, device_ids=self.gpus).to(device) 31 | else: 32 | self.CCN = self.CCN.to(device) 33 | self.loss_mse_fn = nn.MSELoss().to(device) 34 | 35 | @property 36 | def loss(self): 37 | return self.loss_mse 38 | 39 | def forward(self, crow_imgs, gui_imgs, gt_map): 40 | 41 | app_mean_list = [] 42 | for bid in range(gui_imgs.shape[0]): 43 | batch_gui_img = gui_imgs[bid, :, :, :] 44 | split_gui_imgs = batch_gui_img.split(dim=0, split_size=3) 45 | split_gui_imgs = [gui_img.to(device).unsqueeze(0) 46 | for gui_img in split_gui_imgs] 47 | 48 | app_latent_enc = [self.CCN.guiding_encoder( 49 | img) for img in split_gui_imgs] 50 | app_latent = [self.CCN.guiding_mlp( 51 | img) for img in app_latent_enc] 52 | 53 | # mean the features of the unlabeled images 54 | app_mean = torch.mean(torch.cat(app_latent), dim=0).unsqueeze(0) 55 | app_mean_list.append(app_mean) 56 | 57 | app_mean_list = torch.mean( 58 | torch.cat(app_mean_list), 59 | dim=0).unsqueeze(0) 60 | app_latent_enc = torch.mean( 61 | torch.cat(app_latent_enc), 62 | dim=0).unsqueeze(0) 63 | 64 | # crowd encoder output 65 | crow_img = self.CCN.crowd_encoder(crow_imgs) 66 | assign_adaptive_params(app_mean_list, self.CCN.crowd_decoder) 67 | 68 | # generating the output image 69 | if len(self.gpus) > 1: 70 | density_map = self.CCN.module.crowd_decoder(crow_img) 71 | else: 72 | density_map = self.CCN.crowd_decoder(crow_img) 73 | 74 | self.loss_mse = self.build_loss( 75 | density_map.squeeze(), gt_map.squeeze()) 76 | 77 | return density_map 78 | 79 | def test(self, crow_imgs, gui_imgs, gt_map): 80 | 81 | # set the model in eval mode 82 | self.eval() 83 | 84 | app_mean_list = [] 85 | for bid in range(gui_imgs.shape[0]): 86 | batch_gui_img = gui_imgs[bid, :, :, :] 87 | split_gui_imgs = batch_gui_img.split(dim=0, split_size=3) 88 | split_gui_imgs = [gui_img.to(device).unsqueeze(0) 89 | for gui_img in split_gui_imgs] 90 | app_latent = [ 91 | self.CCN.guiding_mlp( 92 | self.CCN.guiding_encoder(img)) for img in split_gui_imgs] 93 | 94 | # mean the features of the unlabeled images 95 | app_mean = torch.mean(torch.cat(app_latent), dim=0).unsqueeze(0) 96 | app_mean_list.append(app_mean) 97 | 98 | app_mean_list = torch.mean( 99 | torch.cat(app_mean_list), 100 | dim=0).unsqueeze(0) 101 | 102 | # crowd encoder output 103 | crow_img = self.CCN.crowd_encoder(crow_imgs) 104 | 105 | if len(self.gpus) > 1: 106 | assign_adaptive_params(app_mean_list, self.CCN.module.crowd_decoder) 107 | else: 108 | assign_adaptive_params(app_mean_list, self.CCN.crowd_decoder) 109 | 110 | # generating the output image 111 | if len(self.gpus) > 1: 112 | density_map = self.CCN.module.crowd_decoder(crow_img) 113 | else: 114 | density_map = self.CCN.crowd_decoder(crow_img) 115 | 116 | self.loss_mse = self.build_loss( 117 | density_map.squeeze(), gt_map.squeeze()) 118 | 119 | # reset the model in train mode 120 | self.train() 121 | 122 | # returning the generated density map along with the loss 123 | return density_map 124 | 125 | def compute_k_mean(self, dataloader, dataset=None): 126 | self.eval() 127 | app_mean = None 128 | if dataset not in SINGLE_FOLDER_DATASETS: 129 | app_latent = [] 130 | for idx, data in enumerate(dataloader): 131 | img, _, original_image = data 132 | img = img.to(device) 133 | img_latent = self.CCN.guiding_mlp( 134 | self.CCN.guiding_encoder(img)) 135 | app_latent.append(img_latent.detach().cpu().numpy()) 136 | app_mean = torch.mean( 137 | torch.from_numpy( 138 | np.array(app_latent)).squeeze(0), 139 | dim=0).to(device) 140 | 141 | else: 142 | # Here the dataloader contains only the unlabeled images: B x H x 143 | # H x W 144 | app_latent = [] 145 | for data in dataloader: 146 | batch_gui_img = data 147 | split_gui_imgs = batch_gui_img.split(dim=0, split_size=3) 148 | split_gui_imgs = [gui_img.to(device).unsqueeze( 149 | 0) for gui_img in split_gui_imgs] 150 | 151 | app_latent = [self.CCN.guiding_mlp(self.CCN.guiding_encoder( 152 | img)).detach().cpu().numpy() for img in split_gui_imgs] 153 | 154 | # mean the features of the unlabeled images 155 | app_mean = torch.mean( 156 | torch.from_numpy( 157 | np.array(app_latent)).squeeze(0), 158 | dim=0).to(device) 159 | 160 | return app_mean 161 | 162 | def get_test_prediction(self, app_mean, crow_imgs, didx): 163 | crow_img = self.CCN.crowd_encoder(crow_imgs) 164 | if didx == 0: 165 | assign_adaptive_params(app_mean, self.CCN.crowd_decoder) 166 | density_map = self.CCN.crowd_decoder(crow_img) 167 | 168 | return density_map 169 | 170 | def build_loss(self, density_map, gt_data): 171 | loss_mse = self.loss_mse_fn(density_map, gt_data) 172 | return loss_mse 173 | 174 | def test_forward(self, img): 175 | density_map = self.CCN(img) 176 | return density_map 177 | -------------------------------------------------------------------------------- /adacrowd/trainer_baselines.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | from torch import optim 4 | from torch.autograd import Variable 5 | from torch.optim.lr_scheduler import StepLR 6 | 7 | from config.baselines import cfg 8 | from misc.utils import (AverageMeter, Timer, logger, print_summary, 9 | update_model, vis_results) 10 | from models.cc_baselines import CrowdCounter 11 | 12 | 13 | class Trainer(): 14 | def __init__(self, dataloader, cfg_data, pwd): 15 | 16 | self.cfg_data = cfg_data 17 | 18 | self.data_mode = cfg.DATASET 19 | self.exp_name = cfg.EXP_NAME 20 | self.exp_path = cfg.EXP_PATH 21 | self.pwd = pwd 22 | 23 | self.net_name = cfg.NET 24 | self.net = CrowdCounter( 25 | cfg.GPU_ID, 26 | self.net_name, 27 | num_norm=cfg.NUM_NORM).cuda() 28 | self.optimizer = optim.Adam( 29 | self.net.CCN.parameters(), 30 | lr=cfg.LR, 31 | weight_decay=1e-4) 32 | self.scheduler = StepLR( 33 | self.optimizer, 34 | step_size=cfg.NUM_EPOCH_LR_DECAY, 35 | gamma=cfg.LR_DECAY) 36 | 37 | self.train_record = { 38 | 'best_mae': 1e20, 39 | 'best_mse': 1e20, 40 | 'best_model_name': ''} 41 | self.timer = { 42 | 'iter time': Timer(), 43 | 'train time': Timer(), 44 | 'val time': Timer()} 45 | 46 | self.epoch = 0 47 | self.i_tb = 0 48 | 49 | self.train_loader, self.val_loader, self.restore_transform = dataloader() 50 | 51 | print("Length of {} train loader: {}".format( 52 | self.data_mode, len(self.train_loader))) 53 | print( 54 | "Length of {} test loader: {}".format( 55 | self.data_mode, len( 56 | self.val_loader))) 57 | 58 | if cfg.RESUME: 59 | latest_state = torch.load(cfg.RESUME_PATH) 60 | self.net.load_state_dict(latest_state['net']) 61 | self.optimizer.load_state_dict(latest_state['optimizer']) 62 | self.scheduler.load_state_dict(latest_state['scheduler']) 63 | self.epoch = latest_state['epoch'] + 1 64 | self.i_tb = latest_state['i_tb'] 65 | self.train_record = latest_state['train_record'] 66 | self.exp_path = latest_state['exp_path'] 67 | self.exp_name = latest_state['exp_name'] 68 | 69 | self.writer, self.log_txt = logger( 70 | self.exp_path, self.exp_name, self.pwd, 'exp', resume=cfg.RESUME, baseline=True) 71 | 72 | def forward(self): 73 | 74 | # self.validate_V3() 75 | for epoch in range(self.epoch, cfg.MAX_EPOCH): 76 | self.epoch = epoch 77 | if epoch > cfg.LR_DECAY_START: 78 | self.scheduler.step() 79 | 80 | # training 81 | self.timer['train time'].tic() 82 | self.train() 83 | self.timer['train time'].toc(average=False) 84 | 85 | print('train time: {:.2f}s'.format(self.timer['train time'].diff)) 86 | print('=' * 20) 87 | 88 | # validation 89 | if epoch % cfg.VAL_FREQ == 0 or epoch > cfg.VAL_DENSE_START: 90 | self.timer['val time'].tic() 91 | self.validate() 92 | self.timer['val time'].toc(average=False) 93 | print('val time: {:.2f}s'.format(self.timer['val time'].diff)) 94 | 95 | def train(self): # training for all datasets 96 | self.net.train() 97 | for i, data in enumerate(self.train_loader, 0): 98 | self.timer['iter time'].tic() 99 | img, gt_map = data 100 | img = Variable(img).cuda() 101 | gt_map = Variable(gt_map).cuda() 102 | 103 | self.optimizer.zero_grad() 104 | pred_map = self.net(img, gt_map) 105 | loss = self.net.loss 106 | loss.backward() 107 | self.optimizer.step() 108 | 109 | if (i + 1) % cfg.PRINT_FREQ == 0: 110 | self.i_tb += 1 111 | self.writer.add_scalar('train_loss', loss.item(), self.i_tb) 112 | self.timer['iter time'].toc(average=False) 113 | print( 114 | '[ep %d][it %d][loss %.4f][lr %.4f][%.2fs]' % 115 | (self.epoch + 116 | 1, 117 | i + 118 | 1, 119 | loss.item(), 120 | self.optimizer.param_groups[0]['lr'] * 121 | 10000, 122 | self.timer['iter time'].diff)) 123 | print( 124 | ' [cnt: gt: %.1f pred: %.2f]' % 125 | (gt_map[0].sum().data / 126 | self.cfg_data.LOG_PARA, 127 | pred_map[0].sum().data / 128 | self.cfg_data.LOG_PARA)) 129 | 130 | def validate(self): 131 | 132 | self.net.eval() 133 | 134 | losses = AverageMeter() 135 | maes = AverageMeter() 136 | mses = AverageMeter() 137 | 138 | for vi, data in enumerate(self.val_loader, 0): 139 | img, gt_map = data 140 | 141 | with torch.no_grad(): 142 | img = Variable(img).cuda() 143 | gt_map = Variable(gt_map).cuda() 144 | 145 | pred_map = self.net.forward(img, gt_map) 146 | 147 | pred_map = pred_map.data.cpu().numpy() 148 | gt_map = gt_map.data.cpu().numpy() 149 | 150 | for i_img in range(pred_map.shape[0]): 151 | pred_cnt = np.sum(pred_map[i_img]) / self.cfg_data.LOG_PARA 152 | gt_count = np.sum(gt_map[i_img]) / self.cfg_data.LOG_PARA 153 | 154 | losses.update(self.net.loss.item()) 155 | maes.update(abs(gt_count - pred_cnt)) 156 | mses.update((gt_count - pred_cnt) * (gt_count - pred_cnt)) 157 | if vi == 0: 158 | vis_results( 159 | self.exp_name, 160 | self.epoch, 161 | self.writer, 162 | self.restore_transform, 163 | img, 164 | pred_map, 165 | gt_map) 166 | 167 | mae = maes.avg 168 | mse = np.sqrt(mses.avg) 169 | loss = losses.avg 170 | 171 | self.writer.add_scalar('val_loss', loss, self.epoch + 1) 172 | self.writer.add_scalar('mae', mae, self.epoch + 1) 173 | self.writer.add_scalar('mse', mse, self.epoch + 1) 174 | 175 | self.train_record = update_model(self.net, 176 | self.optimizer, 177 | self.scheduler, 178 | self.epoch, 179 | self.i_tb, 180 | self.exp_path, 181 | self.exp_name, 182 | [mae, 183 | mse, 184 | loss], 185 | self.train_record, 186 | self.log_txt) 187 | print_summary(self.exp_name, [mae, mse, loss], self.train_record) 188 | -------------------------------------------------------------------------------- /adacrowd/misc/transforms.py: -------------------------------------------------------------------------------- 1 | import numbers 2 | import random 3 | 4 | import cv2 5 | import numpy as np 6 | import torch 7 | from PIL import Image, ImageOps 8 | 9 | # ===============================img tranforms============================ 10 | 11 | 12 | class Compose(object): 13 | def __init__(self, transforms): 14 | self.transforms = transforms 15 | 16 | def __call__(self, img, mask, bbx=None): 17 | if bbx is None: 18 | for t in self.transforms: 19 | img, mask = t(img, mask) 20 | return img, mask 21 | for t in self.transforms: 22 | img, mask, bbx = t(img, mask, bbx) 23 | return img, mask, bbx 24 | 25 | 26 | class RandomHorizontallyFlip(object): 27 | def __call__(self, img, mask, bbx=None): 28 | if random.random() < 0.5: 29 | if bbx is None: 30 | return img.transpose( 31 | Image.FLIP_LEFT_RIGHT), mask.transpose( 32 | Image.FLIP_LEFT_RIGHT) 33 | w, h = img.size 34 | xmin = w - bbx[:, 3] 35 | xmax = w - bbx[:, 1] 36 | bbx[:, 1] = xmin 37 | bbx[:, 3] = xmax 38 | return img.transpose( 39 | Image.FLIP_LEFT_RIGHT), mask.transpose( 40 | Image.FLIP_LEFT_RIGHT), bbx 41 | if bbx is None: 42 | return img, mask 43 | return img, mask, bbx 44 | 45 | 46 | class RandomCrop(object): 47 | def __init__(self, size, padding=0): 48 | if isinstance(size, numbers.Number): 49 | self.size = (int(size), int(size)) 50 | else: 51 | self.size = size 52 | self.padding = padding 53 | 54 | def __call__(self, img, mask, dst_size=None): 55 | if self.padding > 0: 56 | img = ImageOps.expand(img, border=self.padding, fill=0) 57 | mask = ImageOps.expand(mask, border=self.padding, fill=0) 58 | 59 | assert img.size == mask.size 60 | w, h = img.size 61 | if dst_size is None: 62 | th, tw = self.size 63 | else: 64 | th, tw = dst_size 65 | if w == tw and h == th: 66 | return img, mask 67 | if w < tw or h < th: 68 | return img.resize( 69 | (tw, th), Image.BILINEAR), mask.resize( 70 | (tw, th), Image.NEAREST) 71 | 72 | x1 = random.randint(0, w - tw) 73 | y1 = random.randint(0, h - th) 74 | return img.crop((x1, y1, x1 + tw, y1 + th) 75 | ), mask.crop((x1, y1, x1 + tw, y1 + th)) 76 | 77 | 78 | class CenterCrop(object): 79 | def __init__(self, size): 80 | if isinstance(size, numbers.Number): 81 | self.size = (int(size), int(size)) 82 | else: 83 | self.size = size 84 | 85 | def __call__(self, img, mask): 86 | w, h = img.size 87 | th, tw = self.size 88 | x1 = int(round((w - tw) / 2.)) 89 | y1 = int(round((h - th) / 2.)) 90 | return img.crop((x1, y1, x1 + tw, y1 + th) 91 | ), mask.crop((x1, y1, x1 + tw, y1 + th)) 92 | 93 | 94 | class FreeScale(object): 95 | def __init__(self, size): 96 | self.size = size # (h, w) 97 | 98 | def __call__(self, img): 99 | return img.resize((self.size[1], self.size[0]), Image.BILINEAR) 100 | 101 | 102 | class ScaleDown(object): 103 | def __init__(self, downrate): 104 | # self.size = size # (h, w) 105 | self.downrate = downrate 106 | 107 | def __call__(self, mask): 108 | return mask.resize((int(mask.size[1] / 109 | self.downrate), int(mask.size[0] / 110 | self.downrate)), Image.NEAREST) 111 | 112 | 113 | class Scale(object): 114 | def __init__(self, size): 115 | self.size = size 116 | 117 | def __call__(self, img, mask): 118 | if img.size != mask.size: 119 | print(img.size) 120 | print(mask.size) 121 | assert img.size == mask.size 122 | w, h = img.size 123 | if (w <= h and w == self.size) or (h <= w and h == self.size): 124 | return img, mask 125 | if w < h: 126 | ow = self.size 127 | oh = int(self.size * h / w) 128 | return img.resize( 129 | (ow, oh), Image.BILINEAR), mask.resize( 130 | (ow, oh), Image.NEAREST) 131 | else: 132 | oh = self.size 133 | ow = int(self.size * w / h) 134 | return img.resize( 135 | (ow, oh), Image.BILINEAR), mask.resize( 136 | (ow, oh), Image.NEAREST) 137 | 138 | 139 | # ===============================label tranforms============================ 140 | 141 | class DeNormalize(object): 142 | def __init__(self, mean, std): 143 | self.mean = mean 144 | self.std = std 145 | 146 | def __call__(self, tensor): 147 | for t, m, s in zip(tensor, self.mean, self.std): 148 | t.mul_(s).add_(m) 149 | return tensor 150 | 151 | 152 | class MaskToTensor(object): 153 | def __call__(self, img): 154 | return torch.from_numpy(np.array(img, dtype=np.int32)).long() 155 | 156 | 157 | class LabelNormalize(object): 158 | def __init__(self, para): 159 | self.para = para 160 | 161 | def __call__(self, tensor): 162 | # tensor = 1./(tensor+self.para).log() 163 | tensor = torch.from_numpy(np.array(tensor)) 164 | tensor = tensor * self.para 165 | return tensor 166 | 167 | 168 | # class GTScaleDown(object): 169 | # # import ipdb; ipdb.set_trace() 170 | # def __init__(self, factor=8): 171 | # self.factor = factor 172 | 173 | # def __call__(self, img): 174 | # w, h = img.size 175 | # if self.factor == 1: 176 | # return img 177 | # if w == 1280: 178 | # self.factor = 2 179 | # elif w == 1920: 180 | # self.factor = 3 181 | # else: 182 | # pass 183 | # tmp = cv2.resize(np.array(img), (int(w / self.factor), int(h / self.factor)), cv2.INTER_CUBIC) * (self.factor ** 2) 184 | # img = Image.fromarray(tmp) 185 | # return img 186 | 187 | class GTScaleDown(object): 188 | def __init__(self, factor=8): 189 | self.factor = factor 190 | 191 | def __call__(self, img): 192 | w, h = img.size 193 | if self.factor == 1: 194 | return img 195 | if w == 1280: 196 | self.factor = 2 197 | elif w == 1920: 198 | self.factor = 3 199 | else: 200 | pass 201 | 202 | target = np.array(img) 203 | tmp = cv2.resize(target, 204 | (int(target.shape[1] / self.factor), 205 | int(target.shape[0] / self.factor)), 206 | interpolation=cv2.INTER_CUBIC) * (self.factor ** 2) 207 | # tmp = np.array(img.resize((w//self.factor, h//self.factor), Image.BICUBIC))*self.factor*self.factor 208 | img = Image.fromarray(tmp) 209 | return img 210 | 211 | 212 | class GTScaleUp(object): 213 | def __init__(self, factor=8): 214 | self.factor = factor 215 | 216 | def __call__(self, img): 217 | w, h = img.size 218 | if self.factor == 1: 219 | return img 220 | tmp = cv2.resize(np.array(img), (w * self.factor, h * \ 221 | self.factor), cv2.INTER_CUBIC) / (self.factor ** 2) 222 | img = Image.fromarray(tmp) 223 | return img 224 | -------------------------------------------------------------------------------- /adacrowd/trainer_adacrowd.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | from torch import optim 4 | from torch.autograd import Variable 5 | from torch.nn.utils import clip_grad_norm_ 6 | from torch.optim.lr_scheduler import StepLR 7 | 8 | from config.adacrowd import cfg 9 | from misc.utils import (AverageMeter, Timer, logger, print_summary, 10 | update_model, vis_results) 11 | from models.cc_adacrowd import CrowdCounterAdaCrowd 12 | 13 | device = 'cuda' if torch.cuda.is_available() else 'cpu' 14 | 15 | 16 | # Trainer class to initiate the training 17 | class Trainer_AdaCrowd(): 18 | """ 19 | Params: 20 | dataloader: The dataloader the of the specified dataset 21 | cfg_data: The configuration data for training the model 22 | pwd: The present working directory 23 | """ 24 | 25 | def __init__(self, dataloader, cfg_data, pwd): 26 | self.cfg_data = cfg_data 27 | self.dataloader = dataloader 28 | self.data_mode = cfg.DATASET 29 | self.exp_name = cfg.EXP_NAME 30 | self.exp_path = cfg.EXP_PATH 31 | self.pwd = pwd 32 | 33 | self.net_name = cfg.NET 34 | self.net = CrowdCounterAdaCrowd( 35 | gpus=cfg.GPU_ID, 36 | model_name=self.net_name, 37 | num_gbnnorm=cfg.NUM_GBNNORM).to(device) 38 | 39 | # Optimizer (Adam with weight decay of 1e-4) 40 | self.optimizer = optim.Adam( 41 | self.net.CCN.parameters(), 42 | lr=cfg.LR, 43 | weight_decay=1e-4) 44 | 45 | # Learning rate scheduler 46 | self.scheduler = StepLR( 47 | self.optimizer, 48 | step_size=cfg.NUM_EPOCH_LR_DECAY, 49 | gamma=cfg.LR_DECAY) 50 | 51 | # Stats to determine the best performing model 52 | self.train_record = { 53 | 'best_mae': 1e20, 54 | 'best_mse': 1e20, 55 | 'best_model_name': ''} 56 | self.timer = { 57 | 'iter time': Timer(), 58 | 'train time': Timer(), 59 | 'val time': Timer()} 60 | 61 | self.epoch = 0 62 | self.i_tb = 0 63 | 64 | # Moving the dataloader inside the epoch iteration, so the crowd 65 | # images change for each iteration for a particular scene 66 | self.train_loader, self.val_loader, self.restore_transform = self.dataloader( 67 | k_shot=cfg.K_SHOT, num_scenes=cfg.NUM_SCENES) 68 | 69 | # Use this incase you need to resume the training of already trained 70 | # partial model 71 | if cfg.RESUME: 72 | latest_state = torch.load(cfg.RESUME_PATH) 73 | self.net.load_state_dict(latest_state['net']) 74 | self.optimizer.load_state_dict(latest_state['optimizer']) 75 | self.scheduler.load_state_dict(latest_state['scheduler']) 76 | self.epoch = latest_state['epoch'] + 1 77 | self.i_tb = latest_state['i_tb'] 78 | self.train_record = latest_state['train_record'] 79 | self.exp_path = latest_state['exp_path'] 80 | self.exp_name = latest_state['exp_name'] 81 | 82 | # Logging all the training characteristics 83 | self.writer, self.log_txt = logger( 84 | self.exp_path, self.exp_name, self.pwd, 'exp', resume=cfg.RESUME) 85 | 86 | def forward(self): 87 | 88 | # Iterating through the epoch count 89 | for epoch in range(self.epoch, cfg.MAX_EPOCH): 90 | 91 | # Use the dataloader (shuffling the unlabeled images per scene in 92 | # each epoch) 93 | self.epoch = epoch 94 | if epoch > cfg.LR_DECAY_START: 95 | self.scheduler.step() 96 | 97 | # Tracking training time 98 | self.timer['train time'].tic() 99 | self.train() 100 | self.timer['train time'].toc(average=False) 101 | 102 | print('train time: {:.2f}s'.format(self.timer['train time'].diff)) 103 | print('=' * 20) 104 | 105 | # Validation 106 | if epoch % cfg.VAL_FREQ == 0 or epoch > cfg.VAL_DENSE_START: 107 | self.timer['val time'].tic() 108 | self.validate() 109 | self.timer['val time'].toc(average=False) 110 | print('val time: {:.2f}s'.format(self.timer['val time'].diff)) 111 | 112 | def train(self): 113 | self.net.train() 114 | for i, data in enumerate(self.train_loader, 0): 115 | self.timer['iter time'].tic() 116 | img, gt_map, gui_imgs = data 117 | 118 | img = Variable(img).to(device) 119 | gt_map = Variable(gt_map).to(device) 120 | 121 | self.optimizer.zero_grad() 122 | pred_map = self.net(img, gui_imgs, gt_map) 123 | loss = self.net.loss 124 | loss.backward() 125 | 126 | # clipping grad norm with clip value = 1 127 | clip_grad_norm_(self.net.parameters(), cfg.GRAD_CLIP) 128 | self.optimizer.step() 129 | 130 | if (i + 1) % cfg.PRINT_FREQ == 0: 131 | self.i_tb += 1 132 | self.writer.add_scalar('train_loss', loss.item(), self.i_tb) 133 | self.timer['iter time'].toc(average=False) 134 | print( 135 | '[ep %d][it %d][loss %.4f][lr %.4f][%.2fs]' % 136 | (self.epoch + 1, i + 1, loss.item(), 137 | self.optimizer.param_groups[0]['lr'] * 138 | 10000, 139 | self.timer['iter time'].diff)) 140 | print( 141 | ' [cnt: gt: %.1f pred: %.2f]' % 142 | (gt_map[0].sum().data / 143 | self.cfg_data.LOG_PARA, 144 | pred_map[0].sum().data / 145 | self.cfg_data.LOG_PARA)) 146 | 147 | def validate(self): 148 | 149 | self.net.eval() 150 | 151 | losses = AverageMeter() 152 | maes = AverageMeter() 153 | mses = AverageMeter() 154 | 155 | for vi, data in enumerate(self.val_loader, 0): 156 | img, gt_map, gui_imgs = data 157 | 158 | with torch.no_grad(): 159 | img = Variable(img).to(device) 160 | gt_map = Variable(gt_map).to(device) 161 | 162 | pred_map = self.net.test(img, gui_imgs, gt_map) 163 | 164 | pred_map = pred_map.data.cpu().numpy() 165 | gt_map = gt_map.data.cpu().numpy() 166 | 167 | for i_img in range(pred_map.shape[0]): 168 | pred_cnt = np.sum(pred_map[i_img]) / self.cfg_data.LOG_PARA 169 | gt_count = np.sum(gt_map[i_img]) / self.cfg_data.LOG_PARA 170 | 171 | losses.update(self.net.loss.item()) 172 | maes.update(abs(gt_count - pred_cnt)) 173 | mses.update((gt_count - pred_cnt) * (gt_count - pred_cnt)) 174 | if vi == 0: 175 | vis_results( 176 | self.exp_name, 177 | self.epoch, 178 | self.writer, 179 | self.restore_transform, 180 | img, 181 | pred_map, 182 | gt_map) 183 | 184 | mae = maes.avg 185 | mse = np.sqrt(mses.avg) 186 | loss = losses.avg 187 | 188 | self.writer.add_scalar('val_loss', loss, self.epoch + 1) 189 | self.writer.add_scalar('mae', mae, self.epoch + 1) 190 | self.writer.add_scalar('mse', mse, self.epoch + 1) 191 | 192 | self.train_record = update_model(self.net, 193 | self.optimizer, 194 | self.scheduler, 195 | self.epoch, 196 | self.i_tb, 197 | self.exp_path, 198 | self.exp_name, 199 | [mae, 200 | mse, 201 | loss], 202 | self.train_record, 203 | self.log_txt) 204 | print_summary(self.exp_name, [mae, mse, loss], self.train_record) 205 | -------------------------------------------------------------------------------- /adacrowd/test_adacrowd.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import json 3 | import os 4 | 5 | import numpy as np 6 | import torch 7 | from torch.autograd import Variable 8 | from tqdm import tqdm 9 | 10 | from misc.utils import AverageMeter 11 | from models.adacrowd.blocks import assign_adaptive_params 12 | from models.cc_adacrowd import CrowdCounterAdaCrowd 13 | 14 | device = 'cuda' if torch.cuda.is_available() else 'cpu' 15 | 16 | seed = 3035 17 | torch.backends.cudnn.benchmark = True 18 | 19 | if seed is not None: 20 | np.random.seed(seed) 21 | torch.manual_seed(seed) 22 | torch.cuda.manual_seed(seed) 23 | 24 | SINGLE_FOLDER_DATASETS = ["WE", "City"] 25 | 26 | 27 | def load_dataloader(data_mode): 28 | if data_mode == 'WE': 29 | from datasets.adacrowd.WE.loading_data import loading_data 30 | from datasets.adacrowd.WE.setting import cfg_data 31 | elif data_mode == 'Mall': 32 | from datasets.adacrowd.Mall.loading_data import loading_data 33 | from datasets.adacrowd.Mall.setting import cfg_data 34 | elif data_mode == 'PETS': 35 | from datasets.adacrowd.PETS.loading_data import loading_data 36 | from datasets.adacrowd.PETS.setting import cfg_data 37 | elif data_mode == 'FDST': 38 | from datasets.adacrowd.FDST.loading_data import loading_data 39 | from datasets.adacrowd.FDST.setting import cfg_data 40 | elif data_mode == 'City': 41 | from datasets.adacrowd.City.loading_data import loading_data 42 | from datasets.adacrowd.City.setting import cfg_data 43 | return loading_data, cfg_data 44 | 45 | 46 | def test(dataset, args, scene_folder=None): 47 | maes = AverageMeter() 48 | mses = AverageMeter() 49 | 50 | model_path = args.model_path 51 | model = CrowdCounterAdaCrowd([args.gpu_id], 52 | args.model_name, 53 | num_gbnnorm=args.num_norm).to(device) 54 | checkpoint = torch.load(model_path, map_location='cuda:0') 55 | model.load_state_dict(checkpoint) 56 | model.to(device) 57 | model.eval() 58 | 59 | # loading the training and testing dataloader 60 | load_data, data_args = load_dataloader(dataset) 61 | 62 | RESULT = {} 63 | 64 | for trail in range(1, args.trails + 1): 65 | if dataset == ['PETS', 'FDST']: 66 | train_loader, val_loader, _ = load_data( 67 | k_shot=args.k_shot, scene_folder=scene_folder) 68 | elif dataset in ['WE', 'City']: 69 | train_loader, val_loader, _ = load_data( 70 | k_shot=args.k_shot) 71 | else: 72 | train_loader, val_loader, _ = load_data(k_shot=args.k_shot) 73 | 74 | if dataset in ['PETS', 'FDST']: 75 | file_name = "scene_{}_stats.json".format(scene_folder) 76 | else: 77 | file_name = "stats.json" 78 | 79 | model_name = args.model_path.split(os.sep)[-1].split('.pth')[0] 80 | output_folder = os.path.join( 81 | args.result_folder, 82 | args.model_name, 83 | dataset, 84 | model_name) 85 | 86 | if not os.path.exists(output_folder): 87 | os.makedirs(output_folder) 88 | 89 | output_path = os.path.join(output_folder, file_name) 90 | 91 | with torch.no_grad(): 92 | 93 | # Compute the accuracy of the model with the updated model 94 | for didx, data in enumerate( 95 | tqdm(val_loader, total=len(val_loader))): 96 | 97 | # clearing the cache to have memory to test all the images 98 | torch.cuda.empty_cache() 99 | 100 | # loading the data based on the type of folder of the dataset 101 | if dataset in SINGLE_FOLDER_DATASETS: 102 | crow_imgs, gt, gui_imgs = data 103 | else: 104 | crow_imgs, gt = data 105 | 106 | # converting the data to torch variable 107 | crow_imgs = Variable(crow_imgs).to(device) 108 | gt = Variable(gt).to(device) 109 | 110 | # computing the mean latent representation for the unlabeled 111 | # images 112 | if dataset in SINGLE_FOLDER_DATASETS: 113 | mean_latent = model.compute_k_mean( 114 | gui_imgs, dataset=dataset) 115 | else: 116 | # Iterate through train images to compute the mean and std 117 | # for the decoder 118 | mean_latent = model.compute_k_mean(train_loader) 119 | 120 | # incorporating the mean latent values of the target dataset 121 | # (mean and std) to the decoder of the source model 122 | assign_adaptive_params(mean_latent, model.CCN.crowd_decoder) 123 | 124 | # forward pass to generate the crowd images latent 125 | # representation 126 | crow_img = model.CCN.crowd_encoder(crow_imgs) 127 | 128 | # generate the density map for the extracted crowd image 129 | # output 130 | pred_map = model.CCN.crowd_decoder(crow_img) 131 | 132 | # calculate the predicted crowd count to determine the 133 | # performance of the model 134 | pred_img = pred_map.data.cpu().numpy() 135 | gt_img = gt.data.cpu().numpy() 136 | 137 | pred_count = np.sum(pred_img) / 100. 138 | gt_count = np.sum(gt_img) / 100. 139 | 140 | if dataset in ['Mall']: 141 | gt = gt.unsqueeze(0) 142 | 143 | difference = gt_count - pred_count 144 | maes.update(abs(difference)) 145 | mses.update(difference * difference) 146 | 147 | mae = maes.avg 148 | mse = np.sqrt(mses.avg) 149 | 150 | # saving the results 151 | RESULT[str(trail).zfill(2)] = {'mae': mae, 'mse': mse} 152 | 153 | if dataset in ['PETS', 'FDST']: 154 | print( 155 | "Dataset: {}, Scene: {}, Trail: {}, MAE: {}, MSE: {}".format( 156 | dataset, scene_folder, trail, mae, mse)) 157 | else: 158 | print( 159 | "Dataset: {}, Trail: {}, MAE: {}, MSE: {}".format( 160 | dataset, trail, mae, mse)) 161 | with open(output_path, 'w') as fp: 162 | json.dump(RESULT, fp) 163 | 164 | 165 | if __name__ == '__main__': 166 | FLAGS = argparse.ArgumentParser() 167 | FLAGS.add_argument( 168 | '-mn', 169 | '--model_name', 170 | help="Name of the model to be evaluated", 171 | required=True, 172 | type=str) 173 | FLAGS.add_argument( 174 | '-mp', 175 | '--model_path', 176 | help="Path of the pre-trained model", 177 | required=True, 178 | type=str) 179 | FLAGS.add_argument( 180 | '-data', 181 | '--dataset', 182 | help="Dataset to be evaluated", 183 | default='WE', 184 | type=str, 185 | choices=[ 186 | 'WE', 187 | 'UCSD', 188 | 'Mall', 189 | 'PETS', 190 | 'City']) 191 | FLAGS.add_argument( 192 | '-k', 193 | '--k_shot', 194 | help="Number of K images used for computing the affine transformation parameters", 195 | required=True, 196 | type=int) 197 | FLAGS.add_argument( 198 | '-norm', 199 | '--num_norm', 200 | help="Number of normalization layers", 201 | required=True, 202 | type=int) 203 | FLAGS.add_argument('-gpu', '--gpu_id', help="GPU ID", default=3, type=int) 204 | FLAGS.add_argument( 205 | '-r', 206 | '--result_folder', 207 | help="Path of the results folder", 208 | type=str, 209 | required=True) 210 | FLAGS.add_argument( 211 | '-t', 212 | '--trails', 213 | help="Number of random trails to calculate mean and std scores", 214 | required=True, 215 | type=int) 216 | 217 | args = FLAGS.parse_args() 218 | dataset = args.dataset 219 | 220 | if dataset in ['PETS', 'FDST']: 221 | # TODO: Add the list of scenes/sub-folders in PETS or FDST folder to 222 | # evalute every scene/sub-folder 223 | scene_folders = [] 224 | for sf in scene_folders: 225 | test(dataset=dataset, args=args, scene_folder=sf) 226 | else: 227 | test(dataset=dataset, args=args) 228 | -------------------------------------------------------------------------------- /adacrowd/misc/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import time 4 | 5 | import numpy as np 6 | import torch 7 | import torchvision.transforms as standard_transforms 8 | import torchvision.utils as vutils 9 | from torch import nn 10 | 11 | 12 | def initialize_weights(models): 13 | for model in models: 14 | real_init_weights(model) 15 | 16 | 17 | def real_init_weights(m): 18 | if isinstance(m, list): 19 | for mini_m in m: 20 | real_init_weights(mini_m) 21 | else: 22 | if isinstance(m, nn.Conv2d): 23 | nn.init.normal_(m.weight, std=0.01) 24 | if m.bias is not None: 25 | nn.init.constant_(m.bias, 0) 26 | elif isinstance(m, nn.Linear): 27 | m.weight.data.normal_(0.0, std=0.01) 28 | elif isinstance(m, nn.BatchNorm2d): 29 | nn.init.constant_(m.weight, 1) 30 | nn.init.constant_(m.bias, 0) 31 | elif isinstance(m, nn.Module): 32 | for mini_m in m.children(): 33 | real_init_weights(mini_m) 34 | else: 35 | print(m) 36 | 37 | 38 | def weights_normal_init(*models): 39 | for model in models: 40 | dev = 0.01 41 | if isinstance(model, list): 42 | for m in model: 43 | weights_normal_init(m, dev) 44 | else: 45 | for m in model.modules(): 46 | if isinstance(m, nn.Conv2d): 47 | m.weight.data.normal_(0.0, dev) 48 | if m.bias is not None: 49 | m.bias.data.fill_(0.0) 50 | elif isinstance(m, nn.Linear): 51 | m.weight.data.normal_(0.0, dev) 52 | 53 | 54 | def logger( 55 | exp_path, 56 | exp_name, 57 | work_dir, 58 | exception, 59 | resume=False, 60 | baseline=False): 61 | from tensorboardX import SummaryWriter 62 | 63 | if not os.path.exists(exp_path): 64 | os.mkdir(exp_path) 65 | writer = SummaryWriter(exp_path + '/' + exp_name) 66 | log_file = exp_path + '/' + exp_name + '/' + exp_name + '.txt' 67 | 68 | if baseline: 69 | cfg_file = open('./config/baselines.py', "r") 70 | else: 71 | cfg_file = open('./config/adacrowd.py', "r") 72 | cfg_lines = cfg_file.readlines() 73 | 74 | with open(log_file, 'a') as f: 75 | f.write(''.join(cfg_lines) + '\n\n\n\n') 76 | 77 | if not resume: 78 | copy_cur_env(work_dir, exp_path + '/' + exp_name + '/code', exception) 79 | 80 | return writer, log_file 81 | 82 | 83 | def logger_txt(log_file, epoch, scores): 84 | mae, mse, loss = scores 85 | 86 | snapshot_name = 'all_ep_%d_mae_%.1f_mse_%.1f' % (epoch + 1, mae, mse) 87 | 88 | # pdb.set_trace() 89 | 90 | with open(log_file, 'a') as f: 91 | f.write('=' * 15 + '+' * 15 + '=' * 15 + '\n\n') 92 | f.write(snapshot_name + '\n') 93 | f.write( 94 | ' [mae %.2f mse %.2f], [val loss %.4f]\n' % 95 | (mae, mse, loss)) 96 | f.write('=' * 15 + '+' * 15 + '=' * 15 + '\n\n') 97 | 98 | 99 | def vis_results(exp_name, epoch, writer, restore, img, pred_map, gt_map): 100 | pil_to_tensor = standard_transforms.ToTensor() 101 | 102 | x = [] 103 | 104 | for idx, tensor in enumerate(zip(img.cpu().data, pred_map, gt_map)): 105 | if idx > 1: # show only one group 106 | break 107 | pil_input = restore(tensor[0]) 108 | pil_output = torch.from_numpy( 109 | tensor[1] / (tensor[2].max() + 1e-10)).repeat(3, 1, 1) 110 | pil_label = torch.from_numpy( 111 | tensor[2] / (tensor[2].max() + 1e-10)).repeat(3, 1, 1) 112 | x.extend([pil_to_tensor(pil_input.convert('RGB')), pil_label, pil_output]) 113 | x = torch.stack(x, 0) 114 | x = vutils.make_grid(x, nrow=3, padding=5) 115 | x = (x.numpy() * 255).astype(np.uint8) 116 | 117 | writer.add_image(exp_name + '_epoch_' + str(epoch + 1), x) 118 | 119 | 120 | def print_summary(exp_name, scores, train_record): 121 | mae, mse, loss = scores 122 | print('=' * 50) 123 | print(exp_name) 124 | print(' ' + '-' * 20) 125 | print(' [mae %.2f mse %.2f], [val loss %.4f]' % (mae, mse, loss)) 126 | print(' ' + '-' * 20) 127 | print( 128 | '[best] [model: %s] , [mae %.2f], [mse %.2f]' % 129 | (train_record['best_model_name'], 130 | train_record['best_mae'], 131 | train_record['best_mse'])) 132 | print('=' * 50) 133 | 134 | 135 | def print_WE_summary(log_txt, epoch, scores, train_record, c_maes): 136 | mae, mse, loss = scores 137 | # pdb.set_trace() 138 | with open(log_txt, 'a') as f: 139 | f.write('=' * 15 + '+' * 15 + '=' * 15 + '\n') 140 | f.write(str(epoch) + '\n\n') 141 | f.write(' [mae %.4f], [val loss %.4f]\n\n' % (mae, loss)) 142 | f.write(' list: ' + str(np.transpose(c_maes.avg)) + '\n') 143 | 144 | f.write('=' * 15 + '+' * 15 + '=' * 15 + '\n\n') 145 | 146 | print('=' * 50) 147 | print(' ' + '-' * 20) 148 | print(' [mae %.2f mse %.2f], [val loss %.4f]' % (mae, mse, loss)) 149 | print(' ' + '-' * 20) 150 | print( 151 | '[best] [model: %s] , [mae %.2f], [mse %.2f]' % 152 | (train_record['best_model_name'], 153 | train_record['best_mae'], 154 | train_record['best_mse'])) 155 | print('=' * 50) 156 | 157 | 158 | def update_model( 159 | net, 160 | optimizer, 161 | scheduler, 162 | epoch, 163 | i_tb, 164 | exp_path, 165 | exp_name, 166 | scores, 167 | train_record, 168 | log_file=None): 169 | mae, mse, loss = scores 170 | 171 | snapshot_name = 'all_ep_%d_mae_%.1f_mse_%.1f' % (epoch + 1, mae, mse) 172 | 173 | if mae < train_record['best_mae'] or mse < train_record['best_mse']: 174 | train_record['best_model_name'] = snapshot_name 175 | if log_file is not None: 176 | logger_txt(log_file, epoch, scores) 177 | to_saved_weight = net.state_dict() 178 | torch.save( 179 | to_saved_weight, 180 | os.path.join( 181 | exp_path, 182 | exp_name, 183 | snapshot_name + 184 | '.pth')) 185 | 186 | if mae < train_record['best_mae']: 187 | train_record['best_mae'] = mae 188 | if mse < train_record['best_mse']: 189 | train_record['best_mse'] = mse 190 | 191 | latest_state = { 192 | 'train_record': train_record, 193 | 'net': net.state_dict(), 194 | 'optimizer': optimizer.state_dict(), 195 | 'scheduler': scheduler.state_dict(), 196 | 'epoch': epoch, 197 | 'i_tb': i_tb, 198 | 'exp_path': exp_path, 199 | 'exp_name': exp_name} 200 | 201 | torch.save( 202 | latest_state, 203 | os.path.join( 204 | exp_path, 205 | exp_name, 206 | 'latest_state.pth')) 207 | 208 | return train_record 209 | 210 | 211 | def copy_cur_env(work_dir, dst_dir, exception): 212 | 213 | accepted_files = [ 214 | "misc", 215 | "test_baselines.py", 216 | "baselines.py", 217 | "models", 218 | "test_adacrowd.py", 219 | "test_baselines.py", 220 | "trainer_adacrowd.py", 221 | "trainer_baselines.py", 222 | "adacrowd.py", 223 | "README.md", 224 | "__init__.py", 225 | "datasets", 226 | "LICENSE"] 227 | 228 | if not os.path.exists(dst_dir): 229 | os.mkdir(dst_dir) 230 | 231 | for filename in accepted_files: 232 | 233 | file = os.path.join(work_dir, filename) 234 | dst_file = os.path.join(dst_dir, filename) 235 | 236 | if os.path.isdir(file) and exception not in filename: 237 | shutil.copytree(file, dst_file) 238 | elif os.path.isfile(file): 239 | shutil.copyfile(file, dst_file) 240 | 241 | 242 | class AverageMeter(object): 243 | """Computes and stores the average and current value""" 244 | 245 | def __init__(self): 246 | self.reset() 247 | 248 | def reset(self): 249 | self.cur_val = 0 250 | self.avg = 0 251 | self.sum = 0 252 | self.count = 0 253 | 254 | def update(self, cur_val): 255 | self.cur_val = cur_val 256 | self.sum += cur_val 257 | self.count += 1 258 | self.avg = self.sum / self.count 259 | 260 | 261 | class AverageCategoryMeter(object): 262 | """Computes and stores the average and current value""" 263 | 264 | def __init__(self, num_class): 265 | self.num_class = num_class 266 | self.reset() 267 | 268 | def reset(self): 269 | self.cur_val = np.zeros(self.num_class) 270 | self.avg = np.zeros(self.num_class) 271 | self.sum = np.zeros(self.num_class) 272 | self.count = np.zeros(self.num_class) 273 | 274 | def update(self, cur_val, class_id): 275 | self.cur_val[class_id] = cur_val 276 | self.sum[class_id] += cur_val 277 | self.count[class_id] += 1 278 | self.avg[class_id] = self.sum[class_id] / self.count[class_id] 279 | 280 | 281 | class Timer(object): 282 | """A simple timer.""" 283 | 284 | def __init__(self): 285 | self.total_time = 0. 286 | self.calls = 0 287 | self.start_time = 0. 288 | self.diff = 0. 289 | self.average_time = 0. 290 | 291 | def tic(self): 292 | # using time.time instead of time.clock because time time.clock 293 | # does not normalize for multithreading 294 | self.start_time = time.time() 295 | 296 | def toc(self, average=True): 297 | self.diff = time.time() - self.start_time 298 | self.total_time += self.diff 299 | self.calls += 1 300 | self.average_time = self.total_time / self.calls 301 | if average: 302 | return self.average_time 303 | else: 304 | return self.diff 305 | -------------------------------------------------------------------------------- /adacrowd/models/adacrowd/blocks.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch import nn 3 | from torch.nn import functional as F 4 | 5 | from misc.utils import initialize_weights 6 | 7 | __constants__ = ['GuidedBatchNorm2d'] 8 | 9 | def init_params(modules): 10 | for m in modules(): 11 | if isinstance(m, nn.Conv2d): 12 | nn.init.kaiming_normal_( 13 | m.weight, mode='fan_out', nonlinearity='relu') 14 | if m.bias is not None: 15 | nn.init.constant_(m.bias, 0) 16 | elif isinstance(m, nn.BatchNorm2d): 17 | nn.init.constant_(m.weight, 1) 18 | nn.init.constant_(m.bias, 0) 19 | elif isinstance(m, nn.BatchNorm1d): 20 | nn.init.constant_(m.weight, 1) 21 | nn.init.constant_(m.bias, 0) 22 | elif isinstance(m, nn.Linear): 23 | nn.init.normal_(m.weight, 0, 0.01) 24 | if m.bias is not None: 25 | nn.init.constant_(m.bias, 0) 26 | 27 | 28 | class GuidingEncoder(nn.Module): 29 | """ 30 | Class to capture guiding from an image 31 | 32 | Params: downs, number of blocks to downsample the input image. Each block downsamples the image by a factor of 2 33 | ind_im, number of input dimension. Mostly it is the channels of the input image 34 | dim, number of dimensions in the intermediate features of the encoder 35 | latent_dim, number of dimensions in the feature output from the encoder 36 | norm, type of normalization applied on the data. 37 | activ, type of activation layer used in the network. 38 | pad_type, type of image padding used in the layers. 39 | 40 | 41 | Architecture: 42 | The network uses 'downs' number of downsampling blocks, followed by an adaptive pool layer, 1x1 conv layer to reduce the channel dimensions 43 | """ 44 | 45 | def __init__( 46 | self, 47 | downs, 48 | ind_im, 49 | dim, 50 | latent_dim, 51 | norm, 52 | activ, 53 | pad_type, 54 | pool_type='adapt_avg_pool'): 55 | super(GuidingEncoder, self).__init__() 56 | self.model = [] 57 | self.model += [Conv2dBlock(ind_im, dim, 7, 1, 3, 58 | norm=norm, 59 | activation=activ, 60 | pad_type=pad_type)] 61 | for i in range(2): 62 | self.model += [Conv2dBlock(dim, 2 * dim, 4, 2, 1, 63 | norm=norm, 64 | activation=activ, 65 | pad_type=pad_type)] 66 | dim *= 2 67 | 68 | if pool_type == 'adapt_avg_pool': 69 | self.model += [nn.AdaptiveAvgPool2d(1)] 70 | elif pool_type == 'adapt_max_pool': 71 | self.model += [nn.AdaptiveMaxPool2d(1)] 72 | self.model = nn.Sequential(*self.model) 73 | 74 | # default initialization of gaussian with mean 1 and std 0.01 75 | initialize_weights(self.modules()) 76 | 77 | def forward(self, x): 78 | return self.model(x) 79 | 80 | 81 | class GuidingMLP(nn.Module): 82 | """ 83 | Class to convert the guiding encoder output (tensor) to a vector, where the length of the vector is equal to the total number of parameters in the Adaptive normalization layers in the decoder 84 | 85 | Params: in_dim, size of the input dimension 86 | out_dim, size of the output vector 87 | dim, size of the intermediate layer 88 | n_blk, the number of MLP blocks 89 | norm, type of normalization applied on the data 90 | activ, type of activation layer used in the network 91 | """ 92 | 93 | def __init__(self, in_dim, out_dim, dim, n_blk, norm, activ): 94 | super(GuidingMLP, self).__init__() 95 | self.model = [] 96 | 97 | dim = 256 98 | self.model += [LinearBlock(dim, out_dim, 99 | norm='none', activation='none')] 100 | self.model = nn.Sequential(*self.model) 101 | 102 | # default initialization of gaussian with mean 1 and std 0.01 103 | initialize_weights(self.modules()) 104 | 105 | def forward(self, x): 106 | return self.model(x.view(x.size(0), -1)) 107 | 108 | 109 | class Conv2dBlock(nn.Module): 110 | def __init__(self, in_dim, out_dim, ks, st, padding=0, 111 | norm='none', activation='relu', pad_type='zero', 112 | use_bias=True, activation_first=False): 113 | super(Conv2dBlock, self).__init__() 114 | self.use_bias = use_bias 115 | self.activation_first = activation_first 116 | # initialize padding 117 | if pad_type == 'reflect': 118 | self.pad = nn.ReflectionPad2d(padding) 119 | elif pad_type == 'replicate': 120 | self.pad = nn.ReplicationPad2d(padding) 121 | elif pad_type == 'zero': 122 | self.pad = nn.ZeroPad2d(padding) 123 | else: 124 | assert 0, "Unsupported padding type: {}".format(pad_type) 125 | 126 | # initialize normalization 127 | norm_dim = out_dim 128 | if norm == 'bn': 129 | self.norm = nn.BatchNorm2d(norm_dim) 130 | elif norm == 'in': 131 | self.norm = nn.InstanceNorm2d(norm_dim) 132 | elif norm == 'none': 133 | self.norm = None 134 | else: 135 | assert 0, "Unsupported normalization: {}".format(norm) 136 | 137 | # initialize activation 138 | if activation == 'relu': 139 | self.activation = nn.ReLU(inplace=True) 140 | elif activation == 'lrelu': 141 | self.activation = nn.LeakyReLU(0.2, inplace=True) 142 | elif activation == 'tanh': 143 | self.activation = nn.Tanh() 144 | elif activation == 'none': 145 | self.activation = None 146 | else: 147 | assert 0, "Unsupported activation: {}".format(activation) 148 | 149 | self.conv = nn.Conv2d(in_dim, out_dim, ks, st, bias=self.use_bias) 150 | 151 | def forward(self, x): 152 | if self.activation_first: 153 | if self.activation: 154 | x = self.activation(x) 155 | # x = self.conv(self.pad(x)) 156 | x = self.conv(x) 157 | if self.norm: 158 | x = self.norm(x) 159 | else: 160 | # x = self.conv(self.pad(x)) 161 | x = self.conv(x) 162 | if self.norm: 163 | x = self.norm(x) 164 | if self.activation: 165 | x = self.activation(x) 166 | return x 167 | 168 | 169 | class LinearBlock(nn.Module): 170 | def __init__(self, in_dim, out_dim, norm='none', activation='relu'): 171 | super(LinearBlock, self).__init__() 172 | use_bias = True 173 | self.fc = nn.Linear(in_dim, out_dim, bias=use_bias) 174 | 175 | # initialize normalization 176 | norm_dim = out_dim 177 | if norm == 'bn': 178 | self.norm = nn.BatchNorm1d(norm_dim) 179 | elif norm == 'in': 180 | self.norm = nn.InstanceNorm1d(norm_dim) 181 | elif norm == 'none': 182 | self.norm = None 183 | else: 184 | assert 0, "Unsupported normalization: {}".format(norm) 185 | 186 | # initialize activation 187 | if activation == 'relu': 188 | self.activation = nn.ReLU(inplace=True) 189 | elif activation == 'lrelu': 190 | self.activation = nn.LeakyReLU(0.2, inplace=True) 191 | elif activation == 'tanh': 192 | self.activation = nn.Tanh() 193 | elif activation == 'none': 194 | self.activation = None 195 | else: 196 | assert 0, "Unsupported activation: {}".format(activation) 197 | 198 | def forward(self, x): 199 | out = self.fc(x) 200 | if self.norm: 201 | out = self.norm(out) 202 | if self.activation: 203 | out = self.activation(out) 204 | return out 205 | 206 | 207 | class GuidedBatchNorm2d(nn.Module): 208 | def __init__(self, num_features, eps=1e-5, momentum=0.1): 209 | super(GuidedBatchNorm2d, self).__init__() 210 | self.num_features = num_features 211 | self.eps = eps 212 | self.momentum = momentum 213 | self.weight = None 214 | self.bias = None 215 | self.register_buffer('running_mean', torch.zeros(num_features)) 216 | self.register_buffer('running_var', torch.ones(num_features)) 217 | 218 | def forward(self, x): 219 | assert self.weight is not None and \ 220 | self.bias is not None, "Please assign GBN weights first" 221 | running_mean = self.running_mean 222 | running_var = self.running_var 223 | out = F.batch_norm( 224 | x, running_mean, running_var, self.weight, self.bias, 225 | True, self.momentum, self.eps) 226 | return out 227 | 228 | def __repr__(self): 229 | return self.__class__.__name__ + '(' + str(self.num_features) + ')' 230 | 231 | 232 | def assign_adaptive_params(gbn_params, model): 233 | if gbn_params.dim() == 1: 234 | gbn_params = gbn_params.unsqueeze(0) 235 | 236 | for m in model.modules(): 237 | if m.__class__.__name__ in __constants__: 238 | mean = gbn_params[:, :m.num_features] 239 | std = gbn_params[:, m.num_features:2 * m.num_features] 240 | m.bias = mean.contiguous().view(-1) 241 | m.weight = std.contiguous().view(-1) 242 | if gbn_params.size(1) > 2 * m.num_features: 243 | gbn_params = gbn_params[:, 2 * m.num_features:] 244 | 245 | 246 | def get_num_adaptive_params(model): 247 | # return the number of GBN parameters needed by the model 248 | num_gbn_params = 0 249 | for m in model.modules(): 250 | if m.__class__.__name__ in __constants__: 251 | num_gbn_params += 2 * m.num_features 252 | return num_gbn_params 253 | 254 | 255 | if __name__ == '__main__': 256 | layer = GuidedBatchNorm2d(16) 257 | model = nn.Sequential(layer) 258 | x = torch.rand(1, 1024) 259 | assign_adaptive_params(x, layer) 260 | a = torch.rand(1, 16, 32, 32) 261 | output = model(a) 262 | print(output.shape) 263 | --------------------------------------------------------------------------------