Add multi-data training
Add beijing data testing
Fix testing bug
pull/25/head
liaoxingyu 2019-07-31 21:11:54 +08:00
parent 08d105560c
commit 369325906f
14 changed files with 117 additions and 126 deletions

2
.gitignore vendored
View File

@ -5,4 +5,4 @@ __pycache__
datasets
csrc/eval_cylib/build/
logs/
*.ipynb
*.ipynb

View File

@ -43,7 +43,7 @@ _C.INPUT.PADDING = 10
# -----------------------------------------------------------------------------
_C.DATASETS = CN()
# List of the dataset names for training, as present in paths_catalog.py
_C.DATASETS.NAMES = ('market1501')
_C.DATASETS.NAMES = ()
# -----------------------------------------------------------------------------
# DataLoader

View File

@ -9,7 +9,7 @@ INPUT:
PADDING: 10
DATASETS:
NAMES: ('market1501')
NAMES: ("market1501",)
DATALOADER:
SAMPLER: 'softmax_triplet'
@ -21,7 +21,7 @@ SOLVER:
BASE_LR: 0.00035
WEIGHT_DECAY: 0.0005
WEIGHT_DECAY_BIAS: 0.0005
IMS_PER_BATCH: 64
IMS_PER_BATCH: 256
STEPS: [40, 90]
GAMMA: 0.1
@ -35,6 +35,6 @@ TEST:
IMS_PER_BATCH: 512
WEIGHT: "path"
OUTPUT_DIR: "logs/beijing/market+duke+bj/"
OUTPUT_DIR: "logs/market/batch256/"

View File

@ -22,39 +22,53 @@ def get_data_bunch(cfg):
None
)
def _process_dir(dir_path):
def _process_dir(dir_path, recursive=False):
img_paths = []
if 'beijingStation' in dir_path:
if recursive:
id_dirs = os.listdir(dir_path)
for d in id_dirs:
img_paths.extend(glob.glob(os.path.join(dir_path, d, '*.jpg')))
else:
img_paths = glob.glob(os.path.join(dir_path, '*.jpg'))
pattern = re.compile(r'([-\d]+)_c(\d)')
pid_container = set()
pattern = re.compile(r'([-\d]+)_c(\d*)')
v_paths = []
for img_path in img_paths:
pid, camid = map(int, pattern.search(img_path).groups())
pid = int(pid)
if pid == -1: continue # junk images are just ignored
pid_container.add(pid)
v_paths.append([img_path, pid, camid])
v_paths.append([img_path,pid,camid])
return v_paths
market_train_path = 'datasets/Market-1501-v15.09.15/bounding_box_train'
duke_train_path = 'datasets/DukeMTMC-reID/bounding_box_train'
cuhk03_train_path = 'datasets/cuhk03/'
bjStation_train_path = 'datasets/beijingStation/20190720/train'
query_path = 'datasets/Market-1501-v15.09.15/query'
gallery_path = 'datasets/Market-1501-v15.09.15/bounding_box_test'
market_query_path = 'datasets/Market-1501-v15.09.15/query'
marker_gallery_path = 'datasets/Market-1501-v15.09.15/bounding_box_test'
bj_query_path = 'datasets/beijingStation/query'
bj_gallery_path = 'datasets/beijingStation/test'
train_img_names = _process_dir(market_train_path) + _process_dir(duke_train_path) + _process_dir(bjStation_train_path)
train_img_names = list()
for d in cfg.DATASETS.NAMES:
if d == 'market1501':
train_img_names.extend(_process_dir(market_train_path))
elif d == 'duke':
train_img_names.extend(_process_dir(duke_train_path))
elif d == 'beijing':
train_img_names.extend(_process_dir(bjStation_train_path, True))
else:
raise NameError("{} is not available".format(d))
# train_img_names = _process_dir(market_train_path) + _process_dir(duke_train_path) + _process_dir(bjStation_train_path)
# train_img_names = _process_dir(market_train_path)
# train_img_names = CUHK03().train
train_names = [i[0] for i in train_img_names]
query_names = _process_dir(query_path)
gallery_names = _process_dir(gallery_path)
query_names = _process_dir(bj_query_path)
gallery_names = _process_dir(bj_gallery_path, True)
test_fnames = []
test_labels = []
for i in query_names+gallery_names:

View File

@ -1,64 +1,52 @@
# encoding: utf-8
"""
@author: sherlock
@author: liaoxingyu
@contact: sherlockliao01@gmail.com
"""
import logging
import torch
from ignite.engine import Engine
from data.datasets.eval_reid import evaluate
from fastai.vision import *
from utils.reid_metric import R1_mAP
def create_supervised_evaluator(model, metrics,
device=None):
"""
Factory function for creating an evaluator for supervised models
Args:
model (`torch.nn.Module`): the model to train
metrics (dict of str - :class:`ignite.metrics.Metric`): a map of metric names to Metrics
device (str, optional): device type specification (default: None).
Applies to both model and batches.
Returns:
Engine: an evaluator engine with supervised inference function
"""
if device:
model.to(device)
def _inference(engine, batch):
model.eval()
with torch.no_grad():
data, pids, camids = batch
data = data.cuda()
feat = model(data)
return feat, pids, camids
engine = Engine(_inference)
for name, metric in metrics.items():
metric.attach(engine, name)
return engine
def inference(
cfg,
model,
val_loader,
data_bunch,
test_labels,
num_query
):
device = cfg.MODEL.DEVICE
logger = logging.getLogger("reid_baseline.inference")
logger.info("Start inferencing")
evaluator = create_supervised_evaluator(model, metrics={'r1_mAP': R1_mAP(num_query)},
device=device)
evaluator.run(val_loader)
cmc, mAP = evaluator.state.metrics['r1_mAP']
logger.info('Validation Results')
pids = []
camids = []
for p, c in test_labels:
pids.append(p)
camids.append(c)
q_pids = np.asarray(pids[:num_query])
g_pids = np.asarray(pids[num_query:])
q_camids = np.asarray(camids[:num_query])
g_camids = np.asarray(camids[num_query:])
feats = []
model.eval()
for imgs, _ in data_bunch.test_dl:
with torch.no_grad():
feat = model(imgs)
feats.append(feat)
feats = torch.cat(feats, dim=0)
qf = feats[:num_query]
gf = feats[num_query:]
m, n = qf.shape[0], gf.shape[0]
distmat = torch.pow(qf,2).sum(dim=1,keepdim=True).expand(m,n) + \
torch.pow(gf,2).sum(dim=1,keepdim=True).expand(n,m).t()
distmat.addmm_(1, -2, qf, gf.t())
distmat = to_np(distmat)
cmc, mAP = evaluate(distmat, q_pids, g_pids, q_camids, g_camids)
logger.info('Test Results')
logger.info("mAP: {:.1%}".format(mAP))
for r in [1, 5, 10]:
logger.info("CMC curve, Rank-{:<3}:{:.1%}".format(r, cmc[r - 1]))

View File

@ -4,11 +4,13 @@
@contact: sherlockliao01@gmail.com
"""
import os
import logging
from data.datasets.eval_reid import evaluate
from fastai.vision import *
import torch.nn.functional as F
import matplotlib.pyplot as plt
@dataclass
@ -16,12 +18,12 @@ class TrackValue(Callback):
logger: logging.Logger
total_iter: int
def on_batch_end(self, num_batch, last_loss, **kwargs):
if (num_batch+1) % (self.total_iter//3) == 0:
self.logger.info('Iter [{}/{}], loss: {:.4f}'.format(num_batch, self.total_iter, last_loss.item()))
# def on_batch_end(self, num_batch, last_loss, **kwargs):
# if (num_batch+1) % (self.total_iter//3) == 0:
# self.logger.info('Iter [{}/{}], loss: {:.4f}'.format(num_batch, self.total_iter, last_loss.item()))
def on_epoch_end(self, epoch, smooth_loss, **kwargs):
self.logger.info('Epoch {}, loss: {:.4f}'.format(epoch, smooth_loss.item()))
self.logger.info('Epoch {}[Iter {}], loss: {:.4f}'.format(epoch, self.total_iter, smooth_loss.item()))
@dataclass
@ -113,4 +115,8 @@ def do_train(
partial(TestModel, test_labels=test_labels, eval_period=eval_period, num_query=num_query, logger=logger)],
callbacks=[TrackValue(logger, total_iter)])
learn.fit(epochs, lr=cfg.SOLVER.BASE_LR, wd=cfg.SOLVER.WEIGHT_DECAY)
learn.fit(epochs, wd=cfg.SOLVER.WEIGHT_DECAY)
learn.recorder.plot_losses()
plt.savefig(os.path.join(output_dir, "loss.jpg"))
learn.recorder.plot_lr()
plt.savefig(os.path.join(output_dir, "lr.jpg"))

View File

@ -1,47 +0,0 @@
2019-07-29 20:56:09,448 reid_baseline INFO: Using 1 GPUs.
2019-07-29 20:56:09,449 reid_baseline INFO: Namespace(config_file='configs/softmax_triplet.yml', opts=[])
2019-07-29 20:56:09,449 reid_baseline INFO: Loaded configuration file configs/softmax_triplet.yml
2019-07-29 20:56:09,449 reid_baseline INFO: Running with config:
DATALOADER:
NUM_INSTANCE: 4
NUM_WORKERS: 8
SAMPLER: softmax_triplet
DATASETS:
NAMES: market1501
INPUT:
PADDING: 10
PIXEL_MEAN: [0.485, 0.456, 0.406]
PIXEL_STD: [0.229, 0.224, 0.225]
PROB: 0.5
SIZE_TEST: [256, 128]
SIZE_TRAIN: [256, 128]
MODEL:
DEVICE: cuda
LAST_STRIDE: 1
NAME: resnet50
PRETRAIN_PATH: /export/home/lxy/.cache/torch/checkpoints/resnet50-19c8e357.pth
OUTPUT_DIR: logs/co-train/test
SOLVER:
BASE_LR: 0.00035
BIAS_LR_FACTOR: 2
CHECKPOINT_PERIOD: 50
EVAL_PERIOD: 30
GAMMA: 0.1
IMS_PER_BATCH: 64
LOG_PERIOD: 100
MARGIN: 0.3
MAX_EPOCHS: 150
MOMENTUM: 0.9
OPTIMIZER_NAME: Adam
STEPS: (40, 90)
WARMUP_FACTOR: 0.01
WARMUP_ITERS: 10
WARMUP_METHOD: linear
WEIGHT_DECAY: 0.0005
WEIGHT_DECAY_BIAS: 0.0005
TEST:
IMS_PER_BATCH: 512
WEIGHT: path
2019-07-29 20:56:10,745 reid_baseline.train INFO: Start Training
2019-07-29 20:56:37,530 reid_baseline.train INFO: Iter [60/185], loss: 8.0126
2019-07-29 20:56:56,679 reid_baseline.train INFO: Iter [121/185], loss: 7.5083

View File

@ -38,8 +38,10 @@ class Baseline(nn.Module):
def __init__(self, num_classes, last_stride, model_path=None):
super(Baseline, self).__init__()
self.base = ResNet(last_stride)
if model_path is not None:
try:
self.base.load_param(model_path)
except:
print("Not load imagenet pretrained model!")
self.gap = nn.AdaptiveAvgPool2d(1)
self.num_classes = num_classes
@ -59,3 +61,9 @@ class Baseline(nn.Module):
return cls_score, global_feat # global feature for triplet loss
else:
return feat
def load_params_wo_fc(self, state_dict):
for i in state_dict:
if 'classifier' in i:
continue
self.state_dict()[i].copy_(state_dict[i])

View File

@ -0,0 +1,6 @@
gpu=3
CUDA_VISIBLE_DEVICES=$gpu python tools/test.py -cfg='configs/softmax_triplet.yml' \
DATASETS.NAMES '("market1501","duke","beijing")' \
OUTPUT_DIR 'logs/test' \
TEST.WEIGHT 'logs/beijing/market+duke+bj/models/model_149.pth'

View File

@ -0,0 +1,5 @@
gpu=3
CUDA_VISIBLE_DEVICES=$gpu python tools/train.py -cfg='configs/softmax_triplet.yml' \
DATASETS.NAMES '("beijing",)' \
OUTPUT_DIR 'logs/beijing/market_duke_finetune'

View File

@ -0,0 +1,5 @@
gpu=3
CUDA_VISIBLE_DEVICES=$gpu python tools/train.py -cfg='configs/softmax_triplet.yml' \
DATASETS.NAMES '("market1501",)' \
OUTPUT_DIR 'logs/market/softmax_triplet_256_128_bs512'

View File

@ -0,0 +1,5 @@
gpu=2
CUDA_VISIBLE_DEVICES=$gpu python tools/train.py -cfg='configs/softmax_triplet.yml' \
DATASETS.NAMES '("market1501","duke")' \
OUTPUT_DIR 'logs/beijing/market_duke_softmax_triplet_256_128_bs512'

View File

@ -16,12 +16,13 @@ sys.path.append('.')
from config import cfg
from data import get_data_bunch
from engine.inference import inference
from utils.logger import setup_logger
from modeling import build_model
def main():
parser = argparse.ArgumentParser(description="ReID Baseline Inference")
parser.add_argument(
parser.add_argument('-cfg',
"--config_file", default="", help="path to config file", type=str
)
parser.add_argument("opts", help="Modify config options using the command-line", default=None,
@ -36,28 +37,25 @@ def main():
cfg.merge_from_list(args.opts)
cfg.freeze()
output_dir = cfg.OUTPUT_DIR
if output_dir and not os.path.exists(output_dir):
mkdir(output_dir)
if not os.path.exists(cfg.OUTPUT_DIR): os.makedirs(cfg.OUTPUT_DIR)
logger = setup_logger("reid_baseline", output_dir, 0)
logger = setup_logger("reid_baseline", cfg.OUTPUT_DIR, 0)
logger.info("Using {} GPUS".format(num_gpus))
logger.info(args)
if args.config_file != "":
logger.info("Loaded configuration file {}".format(args.config_file))
with open(args.config_file, 'r') as cf:
config_str = "\n" + cf.read()
logger.info(config_str)
logger.info("Running with config:\n{}".format(cfg))
cudnn.benchmark = True
train_databunch, test_databunch, num_query = get_data_bunch(cfg)
model = build_model(cfg, train_databunch.c)
model.load_state_dict(torch.load(cfg.TEST.WEIGHT))
data_bunch, test_labels, num_query = get_data_bunch(cfg)
model = build_model(cfg, data_bunch.c)
state_dict = torch.load(cfg.TEST.WEIGHT)
model.load_state_dict(state_dict['model'])
model.cuda()
inference(cfg, model, test_databunch, num_query)
inference(cfg, model, data_bunch, test_labels, num_query)
if __name__ == '__main__':

View File

@ -27,6 +27,8 @@ def train(cfg):
# prepare model
model = build_model(cfg, data_bunch.c)
state_dict = torch.load("logs/beijing/market_duke_softmax_triplet_256_128_bs512/models/model_149.pth")
model.load_params_wo_fc(state_dict['model'])
opt_func = partial(torch.optim.Adam)
@ -40,7 +42,8 @@ def train(cfg):
warmup_factor = cfg.SOLVER.WARMUP_FACTOR * (1 - alpha) + alpha
return start * warmup_factor * gamma ** bisect_right(milestones, pct)
lr_sched = Scheduler((cfg.SOLVER.BASE_LR, 0), cfg.SOLVER.MAX_EPOCHS, warmup_multistep)
lr = cfg.SOLVER.BASE_LR * (cfg.SOLVER.IMS_PER_BATCH // 64)
lr_sched = Scheduler(lr, cfg.SOLVER.MAX_EPOCHS, warmup_multistep)
loss_func = make_loss(cfg)