【行人属性识别】数据构建+训练+测试

行人属性识别(Pedestrian Attributes Recognition)或人类属性识别(Human Attributes Recognition),从预定义的属性列表中预测一组属性来描述行人的特征。

利用开源项目Rethinking_of_PAR开展行人属性的数据构建、训练及测试流程。

目录

一.数据构建

1.标注工具x-anylabeling

2.数据转换

二.训练

1.添加新网络repvgg

2.自定义数据集

3.训练

三.测试

一.数据构建

1.标注工具x-anylabeling

地址:https://github.com/CVHub520/X-AnyLabeling

X-AnyLabeling v2 版本引入了全新的多标签属性标注功能。首次推出的功能包括基于百度飞浆开源的 PULC 中的车辆属性(Vehicle Attribute)和行人属性(Person Attribute)模型。整体的用户界面(UI)设计以及标注范式遵循 CVAT 开源工具箱的标准,为用户提供更加一致和友好的体验。

(1)运行anylabeling/app.py

(2)配置页面

配置属性文件:点击Import->Import-Attributes-File,选择“assets/attributes”中的属性文件。

选择要处理的图片数据(点击File->Open Dir)及生成标签数据的存放位置(File->Change Output  Dir)。

选中人像后,便可在右侧属性栏进行标注。

2.数据转换

x-anylabeling标注后的数据为json格式,后续训练所需的文件格式为txt格式,转换代码如下

import os
import json
import re

'''in_path为文件目录'''
in_path='D:/X-AnyLabeling-main/data/file/'
json_path=in_path+'jsons/'
label_path=in_path+'label.txt'
save_file=open(label_path,"w")

clas_name_select = ['女性', '手提包', '单肩包', '双肩包', '短袖', '长袖', '长裤', '短裤', '行李箱',
             '上衣白色', '上衣黑色', '上衣蓝色', '上衣红色', '上衣绿色', '上衣黄色', '上衣紫色', '上衣粉色', '上衣灰色',
             '下装白色', '下装黑色', '下装蓝色', '下装红色', '下装绿色', '下装黄色', '下装紫色', '下装粉色', '下装灰色',
              '年龄儿童', '年龄成年', '长发', '短发',
             '光头', '帽子', '下装长裙', '下装短裙', '墨镜', '口罩', '围巾']
print(len(clas_name_select))

# 根据数字的大小对文件名进行排序
json_datas=os.listdir(json_path)
sorted_json_datas=sorted(json_datas,key=lambda x :int(re.search(r'\d+',x).group()))

for data in sorted_json_datas:
    print(json_path+data)
    with open (json_path+data,"r",encoding="UTF-8") as f:
        json_data=json.load(f)

    img_name=data[:-5]+'.jpg'
    labels=['0']*38
    # print(json_data)
    attris=json_data["shapes"][0]["attributes"]
    for attri in attris:
        if attris[attri] not in ["No","None"]:
            if attris[attri]=="Yes":
                index=clas_name_select.index(attri)
                labels[index]='1'
            else:
                index = clas_name_select.index(attris[attri])
                labels[index] = '1'
    labels_str=','.join(labels)

    save_file.write(img_name + "   " + labels_str + "\n")
save_file.close()

二.训练

加入轻量化网络进行训练,以repvgg为例,加入mobilenet、shufflenet等网络配置的方法相同。

1.添加新网络repvgg

新网络repvgg与已有网络同样是卷积+全连接结构,构建时只需要替换backbone即可。

(1)在models/backbone中添加repvgg.py文件地址链接,包括:RepVGG_A0、RepVGG_A0_m。

(2)在models/model_factory.py中添加,RepVGG_A0和RepVGG_A0_m 网络最后层输出的对应通道数。

(3)在train.py中导入repvgg。

(4)修改yaml配置文件,添加repvgg_a0网络。

2.自定义数据集

pa100k数据集中包含了26种属性,从中选择其中18个属性进行训练,标注txt数据如下。

(1)生成训练所需的.pkl文件

根据dataset/pedes_attr/preprocess/format_pa100k.py编写format_mydata.py文件。

import os
import numpy as np
import random
import pickle

from easydict import EasyDict
from scipy.io import loadmat

np.random.seed(0)
random.seed(0)

classes_name = ['Female','AgeOver60','Age18-60','AgeLess18','Front','Side','Back','Hat','Glasses','HandBag','ShoulderBag','Backpack'
                ,'ShortSleeve','LongSleeve','LongCoat','Trousers','Shorts','Skirt&Dress']                  # 属性类别
#  需要对新属性进行重排,属性重排后的索引顺序
group_order = [7, 8, 12, 13, 14, 15, 16, 17, 9, 10, 11, 1, 2, 3, 0, 4, 5, 6]
# clas_name = ['Hat','Glasses','ShortSleeve','LongSleeve','LongCoat','Trousers','Shorts','Skirt&Dress','HandBag','ShoulderBag','Backpack'
#              ,'AgeOver60','Age18-60','AgeLess18','Female','Front','Side','Back']

def make_dir(path):
    if os.path.exists(path):
        pass
    else:
        os.mkdir(path)

def generate_data_description(save_dir, label_txt,reorder):
    """
    create a dataset description file, which consists of images, labels
    """
    image_name = []
    image_label = []

    file = open(label_txt,"r")
    for line in file.readlines():
        '''2023-07-14'''
        name = line.split("\t")[0].split('/')[-1]
        print('name:',name)
        label = line.split('\t')[1].split('\n')[0].split(',')
        label = list(map(int, label))
        image_name.append(name)
        image_label.append(label)

    dataset = EasyDict()
    dataset.description = 'pa100k'
    dataset.reorder = 'group_order'
    dataset.root = os.path.join(save_dir, 'data')

    dataset.image_name = image_name
    dataset.label = np.array(image_label)
    dataset.attr_name = classes_name

    dataset.label_idx = EasyDict()
    dataset.label_idx.eval = list(range(len(classes_name)))

    if reorder:
        dataset.label_idx.eval = group_order

    dataset.partition = EasyDict()
    # 数据集数量划分,自己根据自己数据集来,这是pa100k的划分
    dataset.partition.train = np.arange(0, 80000)      # np.array(range(80000))
    dataset.partition.val = np.arange(80000, 90000)    # np.array(range(80000, 90000))
    dataset.partition.test = np.arange(90000, 100000)  # np.array(range(90000, 100000))
    dataset.partition.trainval = np.arange(0, 90000)   # np.array(range(90000))

    dataset.weight_train = np.mean(dataset.label[dataset.partition.train], axis=0).astype(np.float32)
    dataset.weight_trainval = np.mean(dataset.label[dataset.partition.trainval], axis=0).astype(np.float32)

    with open(os.path.join(save_dir, 'dataset_all.pkl'), 'wb+') as f:
        pickle.dump(dataset, f)

if __name__ == "__main__":
    # save_dir = '/mnt/data1/jiajian/datasets/attribute/PA100k/'
    # 数据集图片存放路径   MyData/data   MyData/dataset_all.pkl
    save_dir = 'C:/Rethinking_of_PAR-master/data/PA100k/MyData/'
    label_txt = "C:/Rethinking_of_PAR-master/data/PA100k/MyData/label.txt"
    # train.txt test.txt val.txt 合并成label.txt
    generate_data_description(save_dir, label_txt,reorder=True)

(2)修改完成后需要到“dataset/pedes_attr/pedes.py”中添加自己数据集名字MyData。

在configs/pedes_baseline目录下新建mydata.yaml配置文件,内容根据pa100k.yaml修改,加入新的网络和数据集。

3.训练

指定数据集的yaml配置文件进行训练。

三.测试

测试代码如下。

import argparse
import json
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
import pickle

from dataset.augmentation import get_transform
from dataset.multi_label.coco import COCO14
from metrics.pedestrian_metrics import get_pedestrian_metrics
from models.model_factory import build_backbone, build_classifier

import numpy as np
import torch
from torch.utils.data import DataLoader
from tqdm import tqdm
from PIL import Image
from configs import cfg, update_config
from dataset.pedes_attr.pedes import PedesAttr
from metrics.ml_metrics import get_map_metrics, get_multilabel_metrics
from models.base_block import FeatClassifier
# from models.model_factory import model_dict, classifier_dict
from tools.function import get_model_log_path, get_reload_weight
from tools.utils import set_seed, str2bool, time_str
from models.backbone import swin_transformer, resnet, bninception,repvgg

set_seed(605)
clas_name = ['帽子', '眼镜', '短袖', '长袖', '长外套', '长裤',
             '短裤', '短裙或裙子',  '手提包', '单肩包','双肩包', '大于60',
             '18-60', '小于18', '女性', '朝前', '侧面', '朝后']

def main(cfg, args):
    exp_dir = os.path.join('exp_result', cfg.DATASET.NAME)
    model_dir, log_dir = get_model_log_path(exp_dir, cfg.NAME)
    train_tsfm, valid_tsfm = get_transform(cfg)
    print(valid_tsfm)

    backbone, c_output = build_backbone(cfg.BACKBONE.TYPE, cfg.BACKBONE.MULTISCALE)

    classifier = build_classifier(cfg.CLASSIFIER.NAME)(
        nattr=18,
        c_in=c_output,
        bn=cfg.CLASSIFIER.BN,
        pool=cfg.CLASSIFIER.POOLING,
        scale =cfg.CLASSIFIER.SCALE
    )

    model = FeatClassifier(backbone, classifier)
    if torch.cuda.is_available():
        model = torch.nn.DataParallel(model).cuda()
    # 修改此处的模型名字
    model = get_reload_weight(model_dir, model, pth='best.pth')                               
    model.eval()

    with torch.no_grad():
        for name in os.listdir(args.test_img):
            print(name)
            img = Image.open(os.path.join(args.test_img,name))
            img = valid_tsfm(img).cuda()
            img = img.view(1, *img.size())
            valid_logits, attns = model(img)
            valid_probs = torch.sigmoid(valid_logits[0]).cpu().numpy()
            valid_probs = valid_probs[0]>0.5

            res = []
            for i,val in enumerate(valid_probs):
                if val:
                    res.append(clas_name[i])
                if i ==14 and val==False:
                    res.append("男性")
            print(res)

def argument_parser():
    parser = argparse.ArgumentParser(description="attribute recognition",                                      
    formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument(
        "--test_img", help="test images", type=str,
        default="./test_imgs",
    )
    parser.add_argument(
        "--cfg", help="decide which cfg to use", type=str,
    )
    parser.add_argument("--debug", type=str2bool, default="true")
    args = parser.parse_args()
    return args

if __name__ == '__main__':
    args = argument_parser()
    update_config(cfg, args)
    main(cfg, args)

部分结果。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值