贡献
- 总结了245篇近年的reid顶会论文
- 提出了一个新的baseling:AGW
- mINP:本文提出的新的reid评价标准。
贡献一分析
参考:
- https://blog.csdn.net/rytyy/article/details/105232594
- https://blog.csdn.net/qq_41967539/article/details/107268994
- https://zhuanlan.zhihu.com/p/342249413
以上主要介绍了该论文对245篇顶会方法的分析,对reid领域内一些公开数据集分析。
贡献二分析
本文主要根据在fast-reid框架上测试的AGW代码效果以及对源码进行简单的分析。分析作者论文指标与代码复现指标以及代码实现上的差异等等。
代码地址:
https://github.com/JDAI-CV/fast-reid
执行代码:
cd yourPath/fast-reid/
export FASTREID_DATASETS=./datasets/market1501/
python3 tools/train_net.py --config-file ./configs/Market1501/AGW_R50.yml MODEL.DEVICE "cuda:0"
数据集详情:
subset | # ids | # images | # cameras |
---|---|---|---|
query | 750 | 3368 | 6 |
gallery | 751 | 15913 | 6 |
结果对比
训练结果:
Dataset | Rank-1 | Rank-5 | Rank-10 | mAP | mINP | metric |
---|---|---|---|---|---|---|
Market1501 | 95.22 | 98.40 | 99.17 | 88.48 | 66.18 | 91.85 |
论文结果:
Dataset | Rank-1 | Rank-5 | Rank-10 | mAP | mINP | metric |
---|---|---|---|---|---|---|
Market1501 | 95.1 | - | - | 87.8 | 65.0 | - |
fast-reid官方训练结果:
Dataset | Rank-1 | Rank-5 | Rank-10 | mAP | mINP | metric |
---|---|---|---|---|---|---|
Market1501 | 95.3 | - | - | 88.2 | 66.3 | - |
AGW网络代码分析
配置文件:
- fast-reid/configs/Base-AGW.yml
- fast-reid/configs/Market1501/AGW_R50.yml
这两个文件基本没什么东西,因此基本配置都使用的默认参数,默认参数:
- fast-reid/fastreid/config/defaults.py
因此一些基本配置:
- 主干网络:resnet50
- 损失:CrossEntropyLoss,TripletLoss
- input_size:[256,128]
根据fast-reid/fastreid/data/common.py的__ getitem __ 函数可以知道输入数据的格式:
{
"images": img,"targets": pid,"camids": camid,"img_paths": img_path,
}
其中因为batch_size为64,图片彩色三通道,resize大小(256,128),所以字典的images项的值的size如下图:
自然:
- len(targets) = 64
- len(camids) = 64
- len(img_paths) = 64
这里打印的targets:
'targets':
tensor([487, 487, 487, 487, 596, 596, 596, 596, 323, 323, 323, 323, 739, 739,739, 739, 120, 120, 120, 120, 119, 119, 119, 119, 223, 223, 223, 223,265, 265, 265, 265, 35, 35, 35, 35, 560, 560, 560, 560, 519, 519,519, 519, 230, 230, 230, 230, 29, 29, 29, 29, 324, 324, 324, 324,39, 39, 39, 39, 102, 102, 102, 102])
可以看到相同target有四个这是由默认参数设置的:
# Number of instance for each person
_C.DATALOADER.NUM_INSTANCE = 4
这个参数的影响在论文Bag of Tricks and A Strong Baseline for Deep Person Re-identification中末尾也有探究过。
拿到数据开始组网,在fast-reid/fastreid/engine/defaults.py中367行:
@classmethoddef build_model(cls, cfg):"""Returns:torch.nn.Module:It now calls :func:`fastreid.modeling.build_model`.Overwrite it if you'd like a different model."""model = build_model(cfg)logger = logging.getLogger(__name__)logger.info("Model:\n{}".format(model))return model
使用类方法根据配置文件组网。在build_model函数内部:
def build_model(cfg):"""Build the whole model architecture, defined by ``cfg.MODEL.META_ARCHITECTURE``.Note that it does not load any weights from ``cfg``."""meta_arch = cfg.MODEL.META_ARCHITECTUREmodel = META_ARCH_REGISTRY.get(meta_arch)(cfg)model.to(torch.device(cfg.MODEL.DEVICE))return model
通过META_ARCH_REGISTRY注册的方法来组网,其中meta_arch为”baseline“,因此加载的是注册的Baseline模型,打印META_ARCH_REGISTRY的类的map成员如下:
{
'Baseline': <class 'fastreid.modeling.meta_arch.baseline.Baseline'>, 'MGN': <class 'fastreid.modeling.meta_arch.mgn.MGN'>, 'MoCo': <class 'fastreid.modeling.meta_arch.moco.MoCo'>, 'Distiller': <class 'fastreid.modeling.meta_arch.distiller.Distiller'>}
因此实例化的是fastreid.modeling.meta_arch.baseline.Baseline,源码在:fast-reid/fastreid/modeling/meta_arch/baseline.py:
@META_ARCH_REGISTRY.register()
class Baseline(nn.Module):"""Baseline architecture. Any models that contains the following two components:1. Per-image feature extraction (aka backbone)2. Per-image feature aggregation and loss computation"""@configurabledef __init__(self,*,backbone,heads,pixel_mean,pixel_std,loss_kwargs=None):"""NOTE: this interface is experimental.Args:backbone:heads:pixel_mean:pixel_std:"""super().__init__()# backboneself.backbone = backbone# headself.heads = headsself.loss_kwargs = loss_kwargsself.register_buffer('pixel_mean', torch.Tensor(pixel_mean).view(1, -1, 1, 1), False)self.register_buffer('pixel_std', torch.Tensor(pixel_std).view(1, -1, 1, 1), False)......省略
这里有点理解不了…
分隔符前面应该是拿到了baseline类,加上括号应该是调用类的初始化函数,但是并不是这样,他的初始化函数接受的参数是:
def __init__(self,*,backbone,heads,pixel_mean,pixel_std,loss_kwargs=None):
明显不匹配…然后我看到底下的from_config函数:
@classmethoddef from_config(cls, cfg):backbone = build_backbone(cfg)heads = build_heads(cfg)return {
'backbone': backbone,'heads': heads,'pixel_mean': cfg.MODEL.PIXEL_MEAN,'pixel_std': cfg.MODEL.PIXEL_STD,'loss_kwargs':{
# loss name'loss_names': cfg.MODEL.LOSSES.NAME,# loss hyperparameters'ce': {
'eps': cfg.MODEL.LOSSES.CE.EPSILON,'alpha': cfg.MODEL.LOSSES.CE.ALPHA,'scale': cfg.MODEL.LOSSES.CE.SCALE},'tri': {
'margin': cfg.MODEL.LOSSES.TRI.MARGIN,'norm_feat': cfg.MODEL.LOSSES.TRI.NORM_FEAT,'hard_mining': cfg.MODEL.LOSSES.TRI.HARD_MINING,'scale': cfg.MODEL.LOSSES.TRI.SCALE},'circle': {
'margin': cfg.MODEL.LOSSES.CIRCLE.MARGIN,'gamma': cfg.MODEL.LOSSES.CIRCLE.GAMMA,'scale': cfg.MODEL.LOSSES.CIRCLE.SCALE},'cosface': {
'margin': cfg.MODEL.LOSSES.COSFACE.MARGIN,'gamma': cfg.MODEL.LOSSES.COSFACE.GAMMA,'scale': cfg.MODEL.LOSSES.COSFACE.SCALE}}}
他接受的格式确实只有一个cfg参数,然后我测试了下代码执行顺序…:
打印结果先打印的”第一“,再打印的”第二“,说明代码确实是先执行的from_config函数再执行的__ init __函数。这里就有点理解不了了…感觉和这个@configurable装饰器有关,后续再看看这个装饰器的用处…
6月16日,果然和@configurable装饰器有关,在baseline的类的__ init __ 函数上面有这个装饰器,然后发现按快捷键ctrl + b可以直接跳转到fast-reid/fastreid/config/config.py文件的该函数:
def configurable(init_func=None, *, from_config=None):
从注释来看,大概意思是这个装饰器可以修饰一个类的初始化函数并且在初始化的时候和初始化函数一起调用:
"""Decorate a function or a class's __init__ method so that it can be calledwith a :class:`CfgNode` object using a :func:`from_config` function that translates:class:`CfgNode` to arguments.Examples:::# Usage 1: Decorator on __init__:class A:@configurabledef __init__(self, a, b=2, c=3):pass@classmethoddef from_config(cls, cfg): # 'cfg' must be the first argument# Returns kwargs to be passed to __init__return {"a": cfg.A, "b": cfg.B}a1 = A(a=1, b=2) # regular constructiona2 = A(cfg) # construct with a cfga3 = A(cfg, b=3, c=4) # construct with extra overwrite# Usage 2: Decorator on any function. Needs an extra from_config argument:@configurable(from_config=lambda cfg: {"a: cfg.A, "b": cfg.B})def a_func(a, b=2, c=3):passa1 = a_func(a=1, b=2) # regular calla2 = a_func(cfg) # call with a cfga3 = a_func(cfg, b=3, c=4) # call with extra overwriteArgs:init_func (callable): a class's ``__init__`` method in usage 1. Theclass must have a ``from_config`` classmethod which takes `cfg` asthe first argument.from_config (callable): the from_config function in usage 2. It must take `cfg`as its first argument."""
因此从baseline的from_config函数可以看出使用函数:build_backbone(cfg),build_heads(cfg)分别构建主干网络和头部网络,然后将主干网络和头部网络以及配置参数传递给__ init __ 函数。