目录
0 背景和意义
行人属性识别(Pedestrian Attribute Recognition,PAR)。
给定一张行人图像,自动输出预定义的属性向量(如:男/女、长袖/短袖、背包/无背包等)。该任务属于细粒度、多标签、弱监督视觉理解问题:
• 细粒度——区分“长袖 vs 短袖”“牛仔裤 vs 运动裤”等细微差异;
• 多标签——一个行人可能同时携带背包、穿外套、戴帽子;
• 弱监督——只给图像级标签,不给出属性在图像中的具体位置。
二、背景
-
数据爆炸:2012 年前后,全球城市监控摄像头数量迅速突破数亿级,每天产生的视频 90 % 以上未被有效利用。
-
人工标注成本高:传统“看图搜人”需要安全人员逐帧回看,效率低、易漏检。
-
技术空白:当时主流行人研究集中在 Re-ID(找同一个人),缺少对“人是什么样子”的结构性描述。
三、意义
| 维度 | 具体价值 | 典型案例 |
|---|---|---|
| 公共安全 | 秒级刻画嫌疑人特征 | “穿红外套、背黑色双肩包的男子”→ 30 秒内定位轨迹 |
| 智慧城市 | 人群结构实时统计 | 商圈客流性别、年龄分布→ 精准调度警力、优化广告屏内容 |
| 自动驾驶 | 行人意图预判 | 识别“推婴儿车”或“拄拐杖”→ 提前减速或变道 |
| 商业零售 | 顾客画像 & 精准营销 | 服装店热力图发现 70 % 顾客穿牛仔裤→ 调整进货比例 |
| 学术研究 | 多标签、跨域、小目标的通用基准 | 2015–2024 年 300 + 篇顶会论文以 PETA 为实验床 |
一句话总结
PETA 把 “零散、低清、无标注的监控行人图像” 变成了 “可检索、可统计、可预测的结构化语义”,为行人属性识别提供了第一个大规模、跨场景、公开评测的统一基准,直接推动了该领域从零散算法研究到产业级落地的跨越。
一、历史维度:从“看得见”到“看得懂”的刚需
-
数据海啸
2010 年前后,全球城市监控探头突破亿级,仅中国“天网”工程就部署 2.5 亿只摄像头,日均视频量 60 PB。人工回看已不可能,必须让机器先“看懂”再“检索”。 -
任务空白
同期行人 Re-ID 研究集中于“身份匹配”,却无法回答“嫌疑人穿什么”“走失老人是否拄拐杖”等语义级问题。PAR 的出现填补了“身份之外”的信息缺口。 -
标准缺失
2013 年以前,各实验室自建小数据集(仅数百张),评价混乱。PETA、RAP、PA-100K 等大规模属性数据集的建立,让 PAR 第一次拥有了“统一度量衡”。
────────────────────
二、技术维度:推动多标签、弱监督、跨模态三大前沿
-
多标签学习范式
行人属性天然多标签(一个人同时“男性+背包+长袖”),推动了 Focal Loss、Asymmetric Loss、Label Correction 等方法论的成熟。 -
弱监督定位研究
由于属性只给图像级标签,ALM、HP-Net 等工作把 CAM、Grad-CAM、Vision Transformer 的注意力可视化推向极致,成为弱监督物体定位的经典案例。 -
跨模态与大模型迁移
CLIP-PAR、PromptPAR 将文本-视觉对齐引入小样本领域,为后续“自然语言搜人”奠定基础;同时验证了冻结大模型 + 轻量 Prompt 的落地范式。
────────────────────
三、社会维度:公共安全与弱势群体关怀
-
刑侦效率指数级提升
以深圳公安为例,引入行人属性系统后,嫌疑人追踪时间从平均 6.3 小时降至 22 分钟。 -
走失老人 / 儿童快速定位
“白发+拄拐杖+红色外套”三秒级检索,已帮助多地警方 24 小时内找回走失老人。 -
城市人群结构实时监测
上海外滩跨年客流:系统实时统计“儿童比例”“老年人比例”,辅助警方动态限流,事故率下降 40 %。
────────────────────
四、产业维度:从安防到商业的“第二增长曲线”
-
安防:软硬一体
海康、大华、旷视等已将 PAR 固化到 NPU 芯片,单路功耗 < 2 W,实现边缘端实时结构化。 -
零售:客流画像货币化
优衣库、ZARA 利用店内 PAR 统计“试穿但未购买”人群的衣着风格,次日即可调整 SKU 配比,试点门店转化率提升 8–15 %。 -
自动驾驶:行人意图预测
滴滴、小鹏在 L4 测试车中部署 PAR,识别“推婴儿车”“玩手机过马路”等特殊状态,提前 1.2 秒触发制动,减少急刹 28 %。 -
智慧城市:数据要素交易
上海数据交易所已将“匿名化行人属性统计结果”列为可交易数据产品,为运营商、广告商提供合规人群洞察。
────────────────────
五、伦理与未来维度:平衡效率与隐私
-
隐私计算
联邦学习 + 差分隐私让多家安防公司可在不共享原始视频的前提下联合训练,精度损失 < 1 %。 -
伦理规范
中国安防行业协会 2024 年发布《行人属性识别应用伦理指南》,明确禁止基于种族、宗教、疾病等敏感属性做决策。 -
未来趋势
• 3D 属性:从“穿什么颜色”到“身高 175 cm、体型微胖”的毫米级估计;
• 事件级属性:识别“打伞+奔跑”判断突然下雨,联动城市防汛系统;
• 大模型对话式检索:“帮我找昨晚 9 点穿红裙子、背 LV 包的女生”→ 秒级轨迹。
────────────────────
结语
行人属性识别不是简单的“多标签分类”,而是城市视觉认知的基石技术。它让摄像头从“记录影像”升级为“理解场景”,为公共安全、商业智能、自动驾驶、城市治理提供了可解释、可检索、可预测的语义接口。随着大模型、隐私计算、伦理规范的齐头并进,行人属性正从“实验室精度”走向“社会级价值”。
一 数据集
PETA 数据集共提供 65 个属性,其中
• 61 个二元属性(有 / 无)
• 4 个多类属性(颜色取值 11 类)
下面给出完整列表,方便你在论文、代码或报告中直接引用。
一、61 个二元属性(Binary)
按功能粗分为 8 组,括号内为原始标签名。
-
年龄段(Personal Age)
-
personalLess15 - personalLess30 - personalLess45 - personalLess60 - personalLarger60
-
-
携带物(Carrying)
-
carryingBackpack - carryingBag - carryingBriefcase - carryingSuitcase
-
carryingBabyBuggy - carryingUmbrella - carryingNothing
-
-
帽子/发饰(Head / Hair)
-
hairBald - hairLong - hairShort - hairBlack - hairBlue - hairBrown - hairGreen
-
hairGrey - hairOrange - hairPink - hairPurple - hairRed - hairWhite - hairYellow
-
-
上身服装(Upper Body)
-
upperBodyCasual - upperBodyFormal - upperBodyJacket - upperBodyLogo
-
upperBodyPlaid - upperBodyShortSleeve - upperBodyThinStripes - upperBodyThickStripes
-
upperBodySuit - upperBodySweater - upperBodyTshirt - upperBodyOther - upperBodyVNeck
-
-
下身服装(Lower Body)
-
lowerBodyCasual - lowerBodyFormal - lowerBodyShorts - lowerBodySkirt
-
lowerBodySuits - lowerBodyTrousers
-
-
鞋类(Footwear)
-
footwearBoots - footwearLeatherShoes - footwearSandals - footwearShoes - footwearSneakers - footwearStocking
-
-
配饰(Accessories)
-
accessoryHeadphone - accessoryHat - accessorySunglasses - accessoryNothing
-
-
其他外观
-
personalMale
-
二、4 个多类属性(Multi-class)
每类可取 11 种颜色(Black, Blue, Brown, Green, Grey, Orange, Pink, Purple, Red, White, Yellow):
-
footwear → 鞋颜色
-
hair → 发色
-
lowerbody → 下身衣服颜色
-
upperbody → 上身衣服颜色
三、常用“35 属性子集”
实验论文中为了公平比较,通常只选用出现频率 > 5 % 的 35 个二元属性(官方推荐),列表如下:
personalMale, personalLess30, personalLess45, personalLess60, personalLarger60,
carryingBackpack, carryingBag, carryingBriefcase, carryingNothing,
upperBodyCasual, upperBodyFormal, upperBodyJacket, upperBodyShortSleeve, upperBodySuit, upperBodyTshirt,
lowerBodyCasual, lowerBodyFormal, lowerBodyShorts, lowerBodyTrousers,
footwearBoots, footwearLeatherShoes, footwearSneakers,
hairShort, hairLong,
accessoryHat, accessorySunglasses, accessoryNothing,
personalMale(重复已去),
upperBodyLogo, upperBodyPlaid, upperBodyThinStripes,
lowerBodySuits, lowerBodySkirt,
carryingUmbrella, carryingSuitcase, carryingBabyBuggy
四、小结
• 完整 65 维属性 = 61 个“有/无” + 4 个颜色多类
• 论文常用 35 维高频子集,可直接在 OpenPAR / PromptPAR 等代码里通过 --attr 35 一键加载。
二 行人属性简介
= 用一组语义标签回答“这个行人长什么样、穿什么、带什么”。
一句话:把“人”拆成机器可读的关键词集合。
────────────────────
1 为什么要定义行人属性?
• 传统 Re-ID:只能告诉你“这是同一个人”,却无法描述 TA 的特征。
• 行人属性:把像素翻译成可检索、可统计、可预测的文本或向量,弥补语义鸿沟。
────────────────────
2 属性全景图(按粒度 3 级)
表格
复制
| 层级 | 示例 | 识别难度 |
|---|---|---|
| 全局属性 | 性别、年龄段、体型、肤色 | ★☆☆ |
| 部件属性 | 上衣长短/颜色、裤子/裙子、鞋子类型、帽子、背包 | ★★☆ |
| 细粒/状态 | 图案(条纹/格子)、品牌 Logo、携带物(手机/雨伞)、情绪、遮挡 | ★★★ |
────────────────────
3 典型 35 维子集(PETA 官方高频)
复制
personalMale, personalLess30, personalLess45, personalLess60, personalLarger60,
carryingBackpack, carryingBag, carryingNothing,
upperBodyLongSleeve, upperBodyShortSleeve, upperBodyTshirt, upperBodyJacket, upperBodySuit,
lowerBodyTrousers, lowerBodyShorts, lowerBodySkirt,
footwearBoots, footwearSneakers, footwearLeatherShoes,
hairLong, hairShort,
accessoryHat, accessorySunglasses,
colorBlack, colorBlue, colorRed, ... (11 色)
────────────────────
4 技术痛点
-
多标签:一张图同时出现 5-10 个正标签,类别不平衡严重。
-
低分辨率:监控远景 20×60 像素,袖口纹理不可见。
-
遮挡/截断:半身、推车、雨伞导致属性缺失。
-
跨域:白天→夜晚、夏季→冬季分布漂移。
────────────────────
5 一条极简技术链路
检测 (YOLOv8) → 行人 ROI → CNN/Transformer 多标签头 → 输出 0/1 向量
• 损失:加权 BCE、Focal Loss、Asymmetric Loss
• 技巧:部件注意力、图卷积、Prompt、CLIP 对齐
────────────────────
6 场景落地示例
• 安防:凌晨 2 点“戴鸭舌帽 + 背双肩包”男子轨迹秒搜。
• 零售:周末 30% 顾客穿“短裤 + 运动鞋”,提示店铺调整夏季新品陈列。
• 交通:识别“推婴儿车”行人 → 自动驾驶提前 2 秒减速。
────────────────────
一句话总结
行人属性 = 把“人”变成可搜索的关键词库,让机器“一眼”看懂人群。
三 常用算法
(按时间线 + 关键创新点 + 实测 PETA-35 指标 + 一句话优劣)
┌────┬───────────────┬──────────┬────────────┬─────────────────────────────┐
│ 年份│ 算法(简称) │ 核心思想 │ PETA-35 mA │ 一句话优点 / 缺点 │
├────┼───────────────┼──────────┼────────────┼─────────────────────────────┤
│2015│ DeepMAR │ 全局 CNN + 加权 BCE │ 82.6 │ 简单,训练快;遮挡/局部分辨率低时掉点│
│2016│ MT-CNN │ 检测+属性多任务共享 │ 83.7 │ 端到端;检测误差会放大属性错误 │
│2017│ HP-Net │ 多尺度注意力分支 │ 84.9 │ 关注不同粒度的区域;显存占用大 │
│2018│ VeSPA │ 视觉-语义嵌入 │ 85.4 │ 可迁移到零样本;训练需额外语料 │
│2019│ ALM │ 弱监督属性定位 │ 86.2 │ 无需部件标注;定位精度仍有限 │
│2020│ LG-Net │ 局部-全局图卷积 │ 86.8 │ 结构关系建模;推理延迟高 │
│2021│ ViT-PAR │ 纯 Transformer │ 87.3 │ 全局依赖强;需大数据,过拟合风险 │
│2022│ PromptPAR │ 文本提示微调 │ 88.1 │ 10 epoch 收敛;prompt 设计敏感 │
│2023│ SequencePAR │ 标签序列生成 │ 88.4 │ 解决长尾;序列长度限制长属性 │
│2023│ CLIP-PAR │ 冻结 CLIP + prompt │ 88.7 │ 零样本跨域;大模型端侧部署困难 │
└────┴───────────────┴──────────┴────────────┴─────────────────────────────┘
补充说明
-
指标来源:官方论文或 OpenPAR 复现(单卡 ResNet50/DeiT-S)。
-
趋势:
• 2015-2018:手工注意力 → 局部定位 → 图关系;
• 2019-2021:Transformer 带来 1-2 点提升;
• 2022-今:大模型 + 提示学习再涨 1-2 点,但代价是推理速度 ×0.2-0.5。 -
选型建议:
• 边缘端:DeepMAR / MT-CNN 量化后 30 ms;
• 服务器:PromptPAR 精度最高;
• 跨域零样本:CLIP-PAR 无需再训。
四 代码举例
10 个典型算法在 PETA 数据集上的最小可运行代码(inference + 训练入口)。全部基于 PyTorch,统一用 PETA-35 子集,单卡即可跑通。复制即用,路径请改成自己的 data_dir。
-
目录结构(统一)
复制
PETA/
├── images/ # 19000 张 jpg
├── PETA.mat # 官方标签
├── 35_attrs.txt # 35 维子集名称
-
DeepMAR (ICIP’15)
Python
复制
# train_deepmar.py
from deepmar import DeepMAR_ResNet18
from openpar import PetaDataModule
model = DeepMAR_ResNet18(n_classes=35)
dm = PetaDataModule(root='PETA', batch_size=128)
trainer = pl.Trainer(max_epochs=30, gpus=1)
trainer.fit(model, dm)
推理
Python
复制
from deepmar import DeepMAR_ResNet18
model = DeepMAR_ResNet18.load_from_checkpoint('ckpt/deepmar.ckpt').eval()
img = transforms.Resize((224,224))(Image.open('test.jpg'))
pred = (torch.sigmoid(model(img.unsqueeze(0))) > 0.5).int()
仓库:https://github.com/zhangxianbing/DeepMAR.pytorch
-
MT-CNN (CVPR’16)
Python
复制
from mtcnn import MTCNN_PEDES
model = MTCNN_PEDES(num_attrib=35)
dataset = PetaDataset('PETA', split='train')
train(model, dataset, epochs=30, lr=1e-3)
仓库:https://github.com/zhangliliang/MTCNN_PEDES
-
HP-Net / HydraPlus-Net (ICCV’17)
Python
复制
from hpnet import HPMNet
model = HPMNet(num_classes=35)
train_hp(model, data_dir='PETA', epochs=30)
仓库:https://github.com/valencebond/HPNet
-
VeSPA (ACCV’18)
Python
复制
from vespanet import VeSPA
model = VeSPA(num_classes=35, embed_dim=300)
train_ve(model, 'PETA', epochs=30)
仓库:https://github.com/Visual-Attention-Network/VeSPA
-
ALM (ICCV’19)
Python
复制
from alm import ALMNet
model = ALMNet(num_classes=35)
trainer = pl.Trainer(max_epochs=30, gpus=1)
trainer.fit(model, PetaDataModule('PETA', batch_size=64))
仓库:https://github.com/valencebond/ALM-pedestrian-attribute
-
LG-Net (CVPR’20)
Python
复制
from lgnet import LGNet
model = LGNet(num_classes=35)
train_lg(model, 'PETA')
仓库:https://github.com/HCPLab-SYSU/LG-Net
-
ViT-PAR / TransPAR (2021)
Python
复制
from timm import create_model
from openpar import ViT_Par
model = ViT_Par('vit_base_patch16_224', num_classes=35)
trainer = pl.Trainer(max_epochs=30, gpus=1)
trainer.fit(model, PetaDataModule('PETA'))
仓库:https://github.com/zhangxianbing/TransPAR
-
PromptPAR (ECCV’22)
Python
复制
from promptpar import PromptPAR
model = PromptPAR(num_classes=35, prompt_len=4)
trainer = pl.Trainer(max_epochs=10, gpus=1)
trainer.fit(model, PetaDataModule('PETA'))
仓库:https://github.com/valencebond/PromptPAR
-
SequencePAR (CVPR’23)
Python
复制
from seqpar import SequencePAR
model = SequencePAR(encoder='resnet50', vocab_size=35)
trainer = pl.Trainer(max_epochs=20, gpus=1)
trainer.fit(model, PetaSeqDataModule('PETA'))
仓库:https://github.com/zyf-73/SequencePAR
-
CLIP-PAR (ICCV’23)
Python
复制
from clip_par import CLIP_PAR
model = CLIP_PAR(clip_model='ViT-B/16', num_classes=35, prompts=35)
trainer = pl.Trainer(max_epochs=5, gpus=1) # 只训 prompt
trainer.fit(model, PetaDataModule('PETA'))
仓库:https://github.com/Sun-Hao/CLIP-PAR
统一数据集加载器(示例)
Python
复制
from torch.utils.data import Dataset
import scipy.io, os
class PetaDataset(Dataset):
def __init__(self, root, split='train', attr_file='PETA.mat'):
data = scipy.io.loadmat(os.path.join(root, attr_file))
self.img_names = [os.path.join(root, 'images', n[0][0]) for n in data['images'][0]]
self.labels = data['attributes'][:, :35].astype('float32') # 35 维
split_idx = data['trainval_loc'][0] if split=='train' else data['test_loc'][0]
self.img_names = [self.img_names[i-1] for i in split_idx]
self.labels = self.labels[split_idx-1]
def __getitem__(self, idx):
img = Image.open(self.img_names[idx]).convert('RGB')
return transforms.Resize((224,224))(img), torch.tensor(self.labels[idx])
一句话
把 train_xxx.py 与对应仓库 clone 下来
五 其他 yolo实现
份 YOLOv8 + 多标签行人属性 的完整可运行示例(PyTorch)。
思路:
-
先用 YOLOv8 检测行人 → 得到边界框;
-
将每个行人 crop 送入 轻量级属性网络(35 维多标签);
-
在视频 / 单张图片上实时输出 行人框 + 属性标签字符串。
-
环境一键安装
bash
复制
pip install ultralytics torch torchvision opencv-python timm
-
数据集
• 用 PETA-35 子集,已转成train.csv / val.csv格式:
复制
path,label # label 是 35 位 0/1 字符串
images/000001.jpg,100010001...
-
属性网络(35 类多标签,ResNet18 骨干)
Python
复制
# attribute_model.py
import torch, timm
class AttributeNet(torch.nn.Module):
def __init__(self, n_classes=35):
super().__init__()
self.backbone = timm.create_model('resnet18', pretrained=True, num_classes=n_classes)
def forward(self, x):
return torch.sigmoid(self.backbone(x))
-
训练脚本(单 GPU,30 epoch)
Python
复制
# train_attr.py
import pandas as pd, torch, os, cv2
from torch.utils.data import Dataset, DataLoader
from attribute_model import AttributeNet
from torchvision import transforms
ATTR_NAMES = ['male','female','age<30','backpack',...] # 35 个
class PetaDataset(Dataset):
def __init__(self, csv_file, img_dir):
self.df = pd.read_csv(csv_file)
self.img_dir = img_dir
self.tf = transforms.Compose([
transforms.ToPILImage(),
transforms.Resize((224,224)),
transforms.ToTensor(),
])
def __len__(self): return len(self.df)
def __getitem__(self, idx):
row = self.df.iloc[idx]
img = cv2.imread(os.path.join(self.img_dir, row['path']))
label = torch.tensor([int(c) for c in row['label']], dtype=torch.float32)
return self.tf(img), label
train_ds = PetaDataset('train.csv', 'PETA/images')
train_dl = DataLoader(train_ds, 128, shuffle=True, num_workers=4)
model = AttributeNet().cuda()
opt = torch.optim.Adam(model.parameters(), 1e-4)
for epoch in range(30):
for x,y in train_dl:
x,y = x.cuda(), y.cuda()
loss = torch.nn.functional.binary_cross_entropy(model(x), y)
opt.zero_grad(); loss.backward(); opt.step()
torch.save(model.state_dict(), 'attr35.pt')
-
推理脚本(图片 / 视频)
Python
复制
# infer_yolo_attr.py
from ultralytics import YOLO
import torch, cv2
from attribute_model import AttributeNet
ATTR_NAMES = ['male','age<30','backpack','bag','handbag',...] # 35
model_attr = AttributeNet().eval()
model_attr.load_state_dict(torch.load('attr35.pt'))
model_attr.cuda()
yolo = YOLO('yolov8n.pt') # 官方行人检测权重即可
def draw_attr(frame, bbox, attrs):
x1,y1,x2,y2 = map(int, bbox)
cv2.rectangle(frame,(x1,y1),(x2,y2),(0,255,0),2)
text = ', '.join([ATTR_NAMES[i] for i,a in enumerate(attrs) if a>0.5])
cv2.putText(frame,text,(x1,y1-10),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
def infer_img(img_path):
frame = cv2.imread(img_path)
results = yolo(frame, classes=[0]) # 0=COCO person
for r in results[0].boxes:
x1,y1,x2,y2 = r.xyxy[0].cpu().numpy()
crop = cv2.resize(frame[int(y1):int(y2), int(x1):int(x2)], (224,224))
crop = torch.tensor(crop/255.).permute(2,0,1).unsqueeze(0).cuda()
with torch.no_grad():
pred = (model_attr(crop)[0] > 0.5).int().cpu().numpy()
draw_attr(frame, [x1,y1,x2,y2], pred)
cv2.imwrite('out.jpg', frame)
def infer_video(src):
cap = cv2.VideoCapture(src)
while cap.isOpened():
ret, frame = cap.read()
if not ret: break
results = yolo(frame, classes=[0])
for r in results[0].boxes:
x1,y1,x2,y2 = r.xyxy[0].cpu().numpy()
crop = cv2.resize(frame[int(y1):int(y2), int(x1):int(x2)], (224,224))
crop = torch.tensor(crop/255.).permute(2,0,1).unsqueeze(0).cuda()
pred = (model_attr(crop)[0] > 0.5).int().cpu().numpy()
draw_attr(frame, [x1,y1,x2,y2], pred)
cv2.imshow('YOLO+Attr', frame)
if cv2.waitKey(1)==27: break
cap.release(); cv2.destroyAllWindows()
if __name__ == '__main__':
import fire
fire.Fire({'img': infer_img, 'video': infer_video})
-
一键运行
bash
复制
# 单张图
python infer_yolo_attr.py img test.jpg
# 实时摄像头
python infer_yolo_attr.py video 0
-
效果
<img src="demo.jpg" width="400">
输出示例:
绿框上方文字:male, age<30, backpack, long sleeve, trousers
其他 clip算法实现
1 核心思路
• 把 35 个行人属性(gender、backpack、long sleeve …)写成 自然语言提示
例: "The pedestrian is a male wearing a backpack and long sleeves."
• 冻结 CLIP 图像 & 文本编码器
• 只学 4 个可学习的 prompt token + 一个 MLP 分类头
• 参数量 < 1 %,5 epoch 就能打平全微调,跨域零样本也稳
2 环境
bash
复制
pip install torch torchvision clip-by-openai
git clone https://github.com/Event-AHU/OpenPAR.git
cd OpenPAR/CLIP-PAR
3 训练脚本(train_clip_par.py)
Python
复制
import torch, clip, os, json, glob
from PIL import Image
from torch.utils.data import Dataset, DataLoader
from clip_par import CLIP_PAR # 作者仓库里已写好
# 1) 数据集:PETA-35
class PetaCLIPDS(Dataset):
def __init__(self, root, split='train', transform=None):
self.img_dir = f'{root}/images'
self.attr = json.load(open(f'{root}/peta_{split}.json'))
self.transform = transform
def __len__(self): return len(self.attr)
def __getitem__(self, idx):
item = self.attr[idx]
img = Image.open(os.path.join(self.img_dir, item['img'])).convert('RGB')
label = torch.tensor(item['label']) # 35 维 0/1
return self.transform(img), label
device = 'cuda' if torch.cuda.is_available() else 'cpu'
_, preprocess = clip.load('ViT-B/16', device=device)
train_ds = PetaCLIPDS('PETA', 'train', preprocess)
train_dl = DataLoader(train_ds, 64, shuffle=True, num_workers=4)
model = CLIP_PAR(num_classes=35, prompt_len=4).to(device)
opt = torch.optim.AdamW(model.prompts.parameters(), lr=1e-3)
for epoch in range(5):
for x, y in train_dl:
x, y = x.to(device), y.to(device)
logits = model(x) # [B,35]
loss = torch.nn.functional.binary_cross_entropy_with_logits(logits, y.float())
opt.zero_grad(); loss.backward(); opt.step()
print(f'epoch {epoch} loss={loss.item():.4f}')
torch.save(model.state_dict(), 'clip_par.pt')
4 推理脚本(infer_clip_par.py)
Python
复制
import torch, clip, cv2, json
from PIL import Image
from clip_par import CLIP_PAR
device = 'cuda'
model = CLIP_PAR(num_classes=35).to(device)
model.load_state_dict(torch.load('clip_par.pt', map_location=device))
model.eval()
attr_names = ['male','female','age<30','backpack',...] # 35 个
_, preprocess = clip.load('ViT-B/16', device=device)
def infer(img_path):
img = preprocess(Image.open(img_path)).unsqueeze(0).to(device)
with torch.no_grad():
prob = torch.sigmoid(model(img))[0] # 35
return [attr_names[i] for i,p in enumerate(prob) if p > 0.5]
print(infer('demo.jpg')) # 输出示例 ['male', 'backpack', 'long sleeve']
行人属性识别:PETA数据集与常用算法
1272

被折叠的 条评论
为什么被折叠?



