PCB_RPP_for_reID-master代码笔记

一.相关文档

论文链接:Beyond Part Models: Person Retrieval with Refined Part Pooling (and a Strong Convolutional Baseline)

github代码链接:syfafterzy / PCB_RPP_for_reID

自己只运行了PCB.py,但是此代码可能基于python2,所以自己使用python3.8运行时有很多错误,于是针对PCB部分进行了修改。
gitee代码链接:qdu2016203500/PCB_RPP_for_reID-master

二.相关程序

针对PCB.py,模型针对resnet50,顺序来看:

1.argparse

PCB.py中

parser = argparse.ArgumentParser(description="Softmax loss classification")
# data
parser.add_argument('-d', '--dataset', type=str, default='market',
                        choices=datasets.names())

argparse是一个Python模块:命令行选项、参数和子命令解析器。

类型选项备注
data–dataset数据集名,对应Market
data–batch-size越大所需内存越多,
size=128,我的电脑就卡了
data–workershttps://www.zhihu.com/question/422160231
没有理解到位
data–height图片高度,对resnet默认256,没有理解
data–width图片宽度,输入宽度默认128不理解
model–arch对应不同模型,暂时处理resnet
model–dropout随机丢弃神经元概率
optimizier–lr学习率,一个超参数,控制需要多大程度调整
网络的权重,以符合梯度损失
train config–epochs训练次数
resource config–data-dir数据集目录

2.dataset

进行main函数,主函数需要命令行获取的参数。

# PCB.py
main(parser.parse_args())

进入get_data函数

# PCB.py
# 数据集,分类数,三个数据集的载入器
dataset, num_classes, train_loader, query_loader, gallery_loader = get_data(args.dataset,
                                                                                args.data_dir,
                                                                                args.height,
                                                                                args.width,
                                                                                args.batch_size,
                                                                                args.workers)

函数dataset.create以工厂类的形式返回market数据集类

# redi/datasets/__init__.py
__factory = {
    'market': Market,
    'duke': Duke,
}

3.market

数据集格式(摘抄自行人重识别(ReID) ——数据集描述 Market-1501):

目录说明
bounding_box_test用于测试集的 750 人,包含 19,732 张图像,前缀为 0000 表示在提取这 750 人的过程中DPM检测错的图(可能与query是同一个人),-1 表示检测出来其他人的图(不在这 750 人中)
bounding_box_train用于训练集的 750 人,包含 12,936 张图像
query750 人在每个摄像头中随机选择一张图像作为query,因此一个人的query最多有 6 个,共有 3,368 张图像,平均每个人4.4张
gt_querymatlab格式,用于判断一个query的哪些图片是好的匹配(同一个人不同摄像头的图像)和不好的匹配(同一个人同一个摄像头的图像或非同一个人的图像)
gt_bbox手工标注的bounding box,用于判断DPM检测的bounding box是不是一个好的box

market相关论文:Person Re-identification: A Benchmark

market类中将对应文件夹images_dir中的文件名按照pattern进行匹配,通过pattern.search找出匹配的pid(行人编号)和camera_id(相机编号),

# reid/datasets/market.py
# 多个数字_c单个数字
pattern = re.compile(r'([-\d]+)_c(\d)')
all_pids = {}
ret = []
# 查找特定文件名 排序
file_paths = sorted(glob(osp.join(self.images_dir, path, '*.jpg')))
for file_path in file_paths:
    # 获取最后的文件名
    file_name = osp.basename(file_path)
    # pid: 每个人的标签编号 1  _  : 摄像头号 2
    pid, camera_id = map(int, pattern.search(file_name).groups())
    if pid == -1:
      continue
	# 训练集relabel
	if relabel:
	    if pid not in all_pids:
	        # 记录一个长度
	        all_pids[pid] = len(all_pids)
	else:
	    if pid not in all_pids:
	        all_pids[pid] = pid
	pid = all_pids[pid]
	camera_id -= 1
	# 形成规定格式的ret数据
	ret.append((file_name, pid, camera_id))

最后形成ret数据集,ret[(‘0002_c1s1_000451_03.jpg’, 0, 0), (‘0002_c1s1_000551_01.jpg’, 0, 0), (‘0002_c1s1_000776_01.jpg’, 0, 0), (‘0002_c1s1_000801_01.jpg’, 0, 0)…]

4.transformers

原作者自定义了transformers模块,

from torchvision.transforms import *

通过import语句将torchvision中的transforms引入使用。

# PCB.py
 # transforms是pytorch中的图像预处理包。一般用Compose把多个步骤整合到一起
 train_transformer = T.Compose([
      T.RectScale(height, width),
      T.RandomHorizontalFlip(),
      T.ToTensor(),
      normalizer,
  ])

  test_transformer = T.Compose([
      T.RectScale(height, width),
      T.ToTensor(),
      normalizer,
  ])

torchvision文档链接:torchvision.transforms
(1)
transforms.compose
(2)T.RectScale(height, width)主要是进行resize操作,

# reid/utils/data/transforms.py
img.resize((self.width, self.height), self.interpolation)
# 其中插值方法为BILINEAR双线性插值

BILINEAR:
d s t [ x , y ] = s r c [ x ′ , y ′ ] = ( 1 − a ) ( 1 − b ) s r c [ x ′ + 1 , y ′ + 1 ] + ( 1 − a ) b ∗ s r c [ x ′ + 1 , y ′ ] + ( 1 − b ) a ∗ s r c [ x ′ , y ′ + 1 ] + a b ∗ s r c [ x ′ ] [ y ′ ] dst[x,y] =src[x',y'] = (1−a)(1−b)src[x′+1,y′+1]+(1−a)b∗src[x′+1,y′]+(1−b)a∗src[x′,y′+1]+ab∗src[x′][y′] dst[x,y]=src[x,y]=(1a)(1b)src[x+1,y+1]+(1a)bsrc[x+1,y]+(1b)asrc[x,y+1]+absrc[x][y]

(3)
RandomHorizontalFilp
(4)
ToTensor
(5)

# PCB.py
# 图像标准化(input - mean) / std 其中std为标准差,也就是
normalizer = T.Normalize(mean=[0.485, 0.456, 0.406],
                         std=[0.229, 0.224, 0.225])

normalize

5.DataLoader

本部分未理解透彻

# PCB.py
train_loader = DataLoader(
   Preprocessor(dataset.train, root=osp.join(dataset.images_dir, dataset.train_path),
                transform=train_transformer),
   batch_size=batch_size, pin_memory=True, drop_last=True)

query_loader = DataLoader(
   Preprocessor(dataset.query, root=osp.join(dataset.images_dir, dataset.query_path),
                transform=test_transformer),
   batch_size=batch_size, num_workers=workers,
   shuffle=False, pin_memory=True)

gallery_loader = DataLoader(
   Preprocessor(dataset.gallery, root=osp.join(dataset.images_dir, dataset.gallery_path),
                transform=test_transformer),
   batch_size=batch_size, num_workers=workers,
   shuffle=False, pin_memory=True)

Preprocessor类中有以下方法,其中的dataset就是上文2.dataset中提到的ret

# reid/utils/data/preprocessor.py
 def _get_single_item(self, index):
     fname, pid, camid = self.dataset[index]
     fpath = fname

     # train或gallery的目录作为根目录,如果此目录不为空
     if self.root is not None:
         fpath = osp.join(self.root, fname)
     # 将该目录对应的文件打开后,将其转换成RGB
     img = Image.open(fpath).convert('RGB')
     # 对该图片作transforms预处理
     if self.transform is not None:
         img = self.transform(img)

Dataloader类:

参数说明
dataset(Dataset)传入的数据集
batch_size(int, optional)每个batch有多少个样本
shuffle(bool, optional)在每个epoch开始的时候,对数据进行重新排序
sampler(Sampler, optional)自定义从数据集中取样本的策略,如果指定这个参数,那么shuffle必须为False
batch_sampler(Sampler, optional)与sampler类似,但是一次只返回一个batch的indices(索引),需要注意的是,一旦指定了这个参数,那么batch_size,shuffle,sampler,drop_last就不能再制定了(互斥——Mutually exclusive)
num_workers (int, optional)这个参数决定了有几个进程来处理data loading。0意味着所有的数据都会被load进主进程。(默认为0)
collate_fn (callable, optional)将一个list的sample组成一个mini-batch的函数
pin_memory (bool, optional)如果设置为True,那么data loader将会在返回它们之前,将tensors拷贝到CUDA中的固定内存(CUDA pinned memory)中
drop_last (bool, optional)如果设置为True:这个是对最后的未完成的batch来说的,比如你的batch_size设置为64,而一个epoch只有100个样本,那么训练的时候后面的36个就被扔掉了… 如果为False(默认),那么会继续正常执行,只是最后的batch_size会小一点
timeout(numeric, optional)如果是正数,表明等待从worker进程中收集一个batch等待的时间,若超出设定的时间还没有收集到,那就不收集这个内容了。这个numeric应总是大于等于0。默认为0
worker_init_fn (callable, optional)每个worker初始化函数

6.model

# PCB.py
# Create model
model = models.create(args.arch, num_features=args.features, dropout=args.dropout,
                      num_classes=num_classes, cut_at_pooling=False, FCN=True)

与数据集Market类似,同样使用工厂模式创建默认的resnet50:

# reid/models/__init__.py
__factory = {
    'resnet18': resnet18,
    'resnet34': resnet34,
    'resnet50': resnet50,
    'resnet101': resnet101,
    'resnet152': resnet152,
    'resnet50_rpp': resnet50_rpp,
}

def create(name, *args, **kwargs):
	 if name not in __factory:
        raise KeyError("Unknown model:", name)
    return __factory[name](*args, **kwargs)

从__factory[name](*args, **kwargs) =====>resnet50(**kwargs) =====>ResNet(50, **kwargs)

# reid/models/resnet.py
def resnet50(**kwargs):
    return ResNet(50, **kwargs)
# 自定义ResNet类
class ResNet(nn.Module):
    __factory = {
        18: torchvision.models.resnet18,
        34: torchvision.models.resnet34,
        50: torchvision.models.resnet50,
        101: torchvision.models.resnet101,
        152: torchvision.models.resnet152,
    }

    def __init__(self, depth, pretrained=True, cut_at_pooling=False,
                 num_features=0, norm=False, dropout=0, num_classes=0, FCN=False, radius=1., thresh=0.5):
        super(ResNet, self).__init__()

        self.depth = depth
        self.pretrained = pretrained
        self.cut_at_pooling = cut_at_pooling
        self.FCN = FCN

        # Construct base (pretrained) resnet
        if depth not in ResNet.__factory:
            raise KeyError("Unsupported depth:", depth)
        self.base = ResNet.__factory[depth](pretrained=pretrained)

再次使用工厂模式根据depth创建torchvision.models.resnet模型,此模型包含的预训练部分为:

# torchvision\models\resnet.py
model_urls = {
    'resnet18': 'https://s3.amazonaws.com/pytorch/models/resnet18-5c106cde.pth',
    'resnet34': 'https://s3.amazonaws.com/pytorch/models/resnet34-333f7ec4.pth',
    'resnet50': 'https://s3.amazonaws.com/pytorch/models/resnet50-19c8e357.pth',
    'resnet101': 'https://s3.amazonaws.com/pytorch/models/resnet101-5d3b4d8f.pth',
    'resnet152': 'https://s3.amazonaws.com/pytorch/models/resnet152-b121ed2d.pth',
}

model = ResNet(Bottleneck, [3, 4, 6, 3])
if pretrained:
        model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))

model.load_satate_dict 在给定的 URL 加载 Torch 序列化对象,下载的预训练模型在C盘用户的.cache\torch\hub\checkpoints下。

torchvision的ResNet模型部分未彻底理解,以后继续分析

7.evaluator

# PCB.py
# Evaluator
evaluator = Evaluator(model)
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值