简体中文 | English
格式采用PA100K的属性标注格式,共有26位属性。
这26位属性的名称、位置、种类数量见下表。
Attribute | index | length |
---|---|---|
'Hat','Glasses' | [0, 1] | 2 |
'ShortSleeve','LongSleeve','UpperStride','UpperLogo','UpperPlaid','UpperSplice' | [2, 3, 4, 5, 6, 7] | 6 |
'LowerStripe','LowerPattern','LongCoat','Trousers','Shorts','Skirt&Dress' | [8, 9, 10, 11, 12, 13] | 6 |
'boots' | [14, ] | 1 |
'HandBag','ShoulderBag','Backpack','HoldObjectsInFront' | [15, 16, 17, 18] | 4 |
'AgeOver60', 'Age18-60', 'AgeLess18' | [19, 20, 21] | 3 |
'Female' | [22, ] | 1 |
'Front','Side','Back' | [23, 24, 25] | 3 |
举例:
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
第一组,位置[0, 1]数值分别是[0, 1],表示'no hat'、'has glasses'。
第二组,位置[22, ]数值分别是[0, ], 表示gender属性是'male', 否则是'female'。
第三组,位置[23, 24, 25]数值分别是[0, 1, 0], 表示方向属性是侧面'side'。
其他组依次类推
理解了上面属性标注
格式的含义后,就可以进行数据标注的工作。其本质是:每张单人图建立一组26个长度的标注项,分别与26个位置的属性值对应。
举例:
对于一张原始图片,
1) 使用检测框,标注图片中每一个人的位置。
2) 每一个检测框(对应每一个人),包含一组26位的属性值数组,数组的每一位以0或1表示。对应上述26个属性。例如,如果图片是'Female',则数组第22位为0,如果满足'Age18-60',则位置[19, 20, 21]对应的数值是[0, 1, 0], 或者满足'AgeOver60',则相应数值为[1, 0, 0].
标注完成后利用检测框将每一个人截取成单人图,其图片与26位属性标注建立对应关系。也可先截成单人图再进行标注,效果相同。
数据标注完成后,就可以拿来做模型的训练,完成自定义模型的优化工作。
其主要有两步工作需要完成:1)将数据与标注数据整理成训练格式。2)修改配置文件开始训练。
训练数据包括训练使用的图片和一个训练列表train.txt,其具体位置在训练配置中指定,其放置方式示例如下:
Attribute/
|-- data 训练图片文件夹
| |-- 00001.jpg
| |-- 00002.jpg
| `-- 0000x.jpg
`-- train.txt 训练数据列表
train.txt文件内为所有训练图片名称(相对于根路径的文件路径)+ 26个标注值
其每一行表示一个人的图片和标注结果。其格式为:
00001.jpg 0,0,1,0,....
注意:1)图片与标注值之间是以Tab[\t]符号隔开, 2)标注值之间是以逗号[,]隔开。该格式不能错,否则解析失败。
首先执行以下命令下载训练代码(更多环境问题请参考Install_PaddleClas):
git clone https://github.com/PaddlePaddle/PaddleClas
需要在配置文件PaddleClas/blob/develop/ppcls/configs/PULC/person_attribute/PPLCNet_x1_0.yaml
中,修改的配置项如下:
DataLoader:
Train:
dataset:
name: MultiLabelDataset
image_root: "dataset/pa100k/" #指定训练图片所在根路径
cls_label_path: "dataset/pa100k/train_list.txt" #指定训练列表文件位置
label_ratio: True
transform_ops:
Eval:
dataset:
name: MultiLabelDataset
image_root: "dataset/pa100k/" #指定评估图片所在根路径
cls_label_path: "dataset/pa100k/val_list.txt" #指定评估列表文件位置
label_ratio: True
transform_ops:
注意:
# model architecture
Arch:
name: "PPLCNet_x1_0"
pretrained: True
use_ssld: True
class_num: 26 #属性种类数量
然后运行以下命令开始训练。
#多卡训练
export CUDA_VISIBLE_DEVICES=0,1,2,3
python3 -m paddle.distributed.launch \
--gpus="0,1,2,3" \
tools/train.py \
-c ./ppcls/configs/PULC/person_attribute/PPLCNet_x1_0.yaml
#单卡训练
python3 tools/train.py \
-c ./ppcls/configs/PULC/person_attribute/PPLCNet_x1_0.yaml
训练完成后可以执行以下命令进行性能评估:
#多卡评估
export CUDA_VISIBLE_DEVICES=0,1,2,3
python3 -m paddle.distributed.launch \
--gpus="0,1,2,3" \
tools/eval.py \
-c ./ppcls/configs/PULC/person_attribute/PPLCNet_x1_0.yaml \
-o Global.pretrained_model=./output/PPLCNet_x1_0/best_model
#单卡评估
python3 tools/eval.py \
-c ./ppcls/configs/PULC/person_attribute/PPLCNet_x1_0.yaml \
-o Global.pretrained_model=./output/PPLCNet_x1_0/best_model
使用下述命令将训练好的模型导出为预测部署模型。
python3 tools/export_model.py \
-c ./ppcls/configs/PULC/person_attribute/PPLCNet_x1_0.yaml \
-o Global.pretrained_model=output/PPLCNet_x1_0/best_model \
-o Global.save_inference_dir=deploy/models/PPLCNet_x1_0_person_attribute_infer
导出模型后,需要下载infer_cfg.yml文件,并放置到导出的模型文件夹PPLCNet_x1_0_person_attribute_infer
中。
使用时在PP-Human中的配置文件./deploy/pipeline/config/infer_cfg_pphuman.yml
中修改新的模型路径model_dir
项,并开启功能enable: True
。
ATTR:
model_dir: [YOUR_DEPLOY_MODEL_DIR]/PPLCNet_x1_0_person_attribute_infer/ #新导出的模型路径位置
enable: True #开启功能
然后可以使用-->至此即完成新增属性类别识别任务。
上述是以26个属性为例的标注、训练过程。
如果需要增加、减少属性数量,则需要:
1)标注时需增加新属性类别信息或删减属性类别信息;
2)对应修改训练中train.txt所使用的属性数量和名称;
3)修改训练配置,例如PaddleClas/blob/develop/ppcls/configs/PULC/person_attribute/PPLCNet_x1_0.yaml
文件中的属性数量,详细见上述修改配置开始训练
部分。
增加属性示例:
删减属性同理。
例如,如果不需要年龄属性,则位置[19, 20, 21]的数值可以去掉。只需在train.txt中标注的26个数字中全部删除第19-21位数值即可,同时标注数据时也不再需要标注这3位属性值。
修改了属性定义后,pipeline后处理部分也需要做相应修改,主要影响结果可视化时的显示结果。
相应代码在路径deploy/pipeline/pphuman/attr_infer.py
文件中postprocess
函数。
其函数实现说明如下:
# 函数入口
def postprocess(self, inputs, result):
# postprocess output of predictor
im_results = result['output']
# 1) 定义各组属性实际意义,其数量及位置与输出结果中占用位数一一对应。
labels = self.pred_config.labels
age_list = ['AgeLess18', 'Age18-60', 'AgeOver60']
direct_list = ['Front', 'Side', 'Back']
bag_list = ['HandBag', 'ShoulderBag', 'Backpack']
upper_list = ['UpperStride', 'UpperLogo', 'UpperPlaid', 'UpperSplice']
lower_list = [
'LowerStripe', 'LowerPattern', 'LongCoat', 'Trousers', 'Shorts',
'Skirt&Dress'
]
# 2) 部分属性所用阈值与通用值有明显区别,单独设置
glasses_threshold = 0.3
hold_threshold = 0.6
batch_res = []
for res in im_results:
res = res.tolist()
label_res = []
# gender
# 3) 单个位置属性类别,判断该位置是否大于阈值,来分配二分类结果
gender = 'Female' if res[22] > self.threshold else 'Male'
label_res.append(gender)
# age
# 4)多个位置属性类别,N选一形式,选择得分最高的属性
age = age_list[np.argmax(res[19:22])]
label_res.append(age)
# direction
direction = direct_list[np.argmax(res[23:])]
label_res.append(direction)
# glasses
glasses = 'Glasses: '
if res[1] > glasses_threshold:
glasses += 'True'
else:
glasses += 'False'
label_res.append(glasses)
# hat
hat = 'Hat: '
if res[0] > self.threshold:
hat += 'True'
else:
hat += 'False'
label_res.append(hat)
# hold obj
hold_obj = 'HoldObjectsInFront: '
if res[18] > hold_threshold:
hold_obj += 'True'
else:
hold_obj += 'False'
label_res.append(hold_obj)
# bag
bag = bag_list[np.argmax(res[15:18])]
bag_score = res[15 + np.argmax(res[15:18])]
bag_label = bag if bag_score > self.threshold else 'No bag'
label_res.append(bag_label)
# upper
# 5)同一类属性,分为两组(这里是款式和花色),每小组内单独选择,相当于两组不同属性。
upper_label = 'Upper:'
sleeve = 'LongSleeve' if res[3] > res[2] else 'ShortSleeve'
upper_label += ' {}'.format(sleeve)
upper_res = res[4:8]
if np.max(upper_res) > self.threshold:
upper_label += ' {}'.format(upper_list[np.argmax(upper_res)])
label_res.append(upper_label)
# lower
lower_res = res[8:14]
lower_label = 'Lower: '
has_lower = False
for i, l in enumerate(lower_res):
if l > self.threshold:
lower_label += ' {}'.format(lower_list[i])
has_lower = True
if not has_lower:
lower_label += ' {}'.format(lower_list[np.argmax(lower_res)])
label_res.append(lower_label)
# shoe
shoe = 'Boots' if res[14] > self.threshold else 'No boots'
label_res.append(shoe)
batch_res.append(label_res)
result = {'output': batch_res}
return result
Dear OpenI User
Thank you for your continuous support to the Openl Qizhi Community AI Collaboration Platform. In order to protect your usage rights and ensure network security, we updated the Openl Qizhi Community AI Collaboration Platform Usage Agreement in January 2024. The updated agreement specifies that users are prohibited from using intranet penetration tools. After you click "Agree and continue", you can continue to use our services. Thank you for your cooperation and understanding.
For more agreement content, please refer to the《Openl Qizhi Community AI Collaboration Platform Usage Agreement》