├── 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 |
--------------------------------------------------------------------------------