Compare commits
4 Commits
9bba988830
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 71b3c21f28 | |||
| a3bbf78ea2 | |||
| b58ab5cc1c | |||
| 721121b8e4 |
@@ -0,0 +1 @@
|
||||
3.11
|
||||
@@ -1,181 +1,51 @@
|
||||
# Person-Attribute-Recognition-MarketDuke
|
||||
A simple baseline implemented in PyTorch for **pedestrian attribute recognition** task, evaluating on Market-1501-attribute and DukeMTMC-reID-attribute dataset.
|
||||
# Person Attribute Recognition
|
||||
|
||||
## Dataset
|
||||
You can get [Market-1501-attribute](https://github.com/vana77/Market-1501_Attribute) and [DukeMTMC-reID-attribute](https://github.com/vana77/DukeMTMC-attribute) annotations from [here](https://github.com/vana77). Also you need to download Market-1501 and DukeMTMC-reID dataset.
|
||||
COCO80 기반 **YOLO26m** 객체 탐지 결과를 받아, 탐지된 **Person** 영역의 상세 속성을 분석하는 ClearML Agent입니다.
|
||||
|
||||
Then, create a folder named 'attribute' under your dataset path, and put corresponding annotations into the folder.
|
||||
## 역할
|
||||
|
||||
For example,<br>
|
||||
```
|
||||
├── dataset
|
||||
│ ├── DukeMTMC-reID
|
||||
│ ├── bounding_box_test
|
||||
│ ├── bounding_box_train
|
||||
│ ├── query
|
||||
│ ├── attribute
|
||||
│ ├── duke_attribute.mat
|
||||
1. YOLO26m이 COCO80 클래스로 이미지를 분석하고 Person의 바운딩 박스(`xywh`)를 전달
|
||||
2. 해당 영역을 크롭한 뒤 보행자 속성 인식 모델로 상세 속성 추론
|
||||
3. 결과를 ClearML 아티팩트로 업로드
|
||||
|
||||
## 입력 / 출력
|
||||
|
||||
| 항목 | 설명 |
|
||||
|------|------|
|
||||
| `--image_url` | 분석할 이미지 URL 또는 로컬 경로 |
|
||||
| `--xywh` | Person 바운딩 박스 (`x,y,w,h`) — YOLO26m 탐지 결과 |
|
||||
| 출력 | 성별, 연령대, 의류 색상·종류 등 속성 목록 (`final_result` 아티팩트) |
|
||||
|
||||
## 실행
|
||||
|
||||
```bash
|
||||
python main.py \
|
||||
--image_url "https://example.com/image.jpg" \
|
||||
--xywh "404,290,74,193"
|
||||
```
|
||||
|
||||
## Model
|
||||
Trained model are provided. You may download it from [Google Drive](https://drive.google.com/drive/folders/1JTdjuEbxSLypnfUzVuuxLj1uSKAacfd0?usp=sharing) or [Baidu Drive](https://pan.baidu.com/s/1bByCxZp9bSs8YYZPbuK21A) (提取码:jpks).
|
||||
## 요구 사항
|
||||
|
||||
You may download it and move `checkpoints` folder to your project's root directory.
|
||||
- Python 3.11+
|
||||
- PyTorch, torchvision, ClearML, requests
|
||||
- 사전 학습 체크포인트: `checkpoints/market/resnet50_nfc/net_last.pth`
|
||||
|
||||
## Dependencies
|
||||
* Python 3.5
|
||||
* PyTorch >= 0.4.1
|
||||
* torchvision >= 0.2.1
|
||||
* matplotlib, sklearn, prettytable (optional)
|
||||
### 설치
|
||||
|
||||
## Usage
|
||||
```
|
||||
python3 train.py --data-path ~/dataset --dataset [market | duke] --model resnet50 [--use-id]
|
||||
|
||||
python3 test.py --data-path ~/dataset --dataset [market | duke] --model resnet50 [--print-table]
|
||||
|
||||
python3 inference.py test_sample/test_market.jpg [--dataset market] [--model resnet50]
|
||||
```bash
|
||||
uv sync
|
||||
# 또는
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Result
|
||||
## ClearML
|
||||
|
||||
We use **binary classification** settings (considered each attribute as an independent binary classification problem), and the classification threshold is **0.5**.
|
||||
| 항목 | 값 |
|
||||
|------|-----|
|
||||
| Project | `Person_Attribute_Recognition` |
|
||||
| Task | `model-yolo-person-classify` |
|
||||
|
||||
***Note that the precision, recall and f1 score are denoted as '-' for some ill-defined cases.***
|
||||
## 모델
|
||||
|
||||
### Market-1501 gallery
|
||||
```
|
||||
+------------+----------+-----------+--------+----------+
|
||||
| attribute | accuracy | precision | recall | f1 score |
|
||||
+------------+----------+-----------+--------+----------+
|
||||
| young | 0.998 | 0.533 | 0.267 | 0.356 |
|
||||
| teenager | 0.892 | 0.927 | 0.951 | 0.939 |
|
||||
| adult | 0.895 | 0.582 | 0.450 | 0.508 |
|
||||
| old | 0.992 | 0.037 | 0.012 | 0.019 |
|
||||
| backpack | 0.883 | 0.828 | 0.672 | 0.742 |
|
||||
| bag | 0.790 | 0.608 | 0.378 | 0.467 |
|
||||
| handbag | 0.893 | 0.254 | 0.065 | 0.104 |
|
||||
| clothes | 0.946 | 0.956 | 0.984 | 0.970 |
|
||||
| down | 0.945 | 0.968 | 0.949 | 0.959 |
|
||||
| up | 0.936 | 0.938 | 0.998 | 0.967 |
|
||||
| hair | 0.877 | 0.871 | 0.773 | 0.819 |
|
||||
| hat | 0.982 | 0.812 | 0.505 | 0.623 |
|
||||
| gender | 0.919 | 0.947 | 0.864 | 0.903 |
|
||||
| upblack | 0.954 | 0.859 | 0.790 | 0.823 |
|
||||
| upwhite | 0.926 | 0.846 | 0.882 | 0.863 |
|
||||
| upred | 0.974 | 0.904 | 0.840 | 0.871 |
|
||||
| uppurple | 0.985 | 0.703 | 0.815 | 0.755 |
|
||||
| upyellow | 0.976 | 0.895 | 0.836 | 0.865 |
|
||||
| upgray | 0.909 | 0.852 | 0.391 | 0.537 |
|
||||
| upblue | 0.946 | 0.868 | 0.420 | 0.566 |
|
||||
| upgreen | 0.966 | 0.790 | 0.713 | 0.750 |
|
||||
| downblack | 0.879 | 0.815 | 0.889 | 0.850 |
|
||||
| downwhite | 0.956 | 0.608 | 0.550 | 0.578 |
|
||||
| downpink | 0.989 | 0.795 | 0.782 | 0.788 |
|
||||
| downpurple | 1.000 | - | - | - |
|
||||
| downyellow | 0.999 | 0.000 | 0.000 | 0.000 |
|
||||
| downgray | 0.878 | 0.756 | 0.443 | 0.559 |
|
||||
| downblue | 0.861 | 0.762 | 0.446 | 0.563 |
|
||||
| downgreen | 0.978 | 0.766 | 0.295 | 0.426 |
|
||||
| downbrown | 0.958 | 0.754 | 0.590 | 0.662 |
|
||||
+------------+----------+-----------+--------+----------+
|
||||
Average accuracy: 0.9361
|
||||
Average f1 score: 0.6492
|
||||
```
|
||||
|
||||
### DukeMTMC-ReID gallery
|
||||
```
|
||||
+-----------+----------+-----------+--------+----------+
|
||||
| attribute | accuracy | precision | recall | f1 score |
|
||||
+-----------+----------+-----------+--------+----------+
|
||||
| backpack | 0.829 | 0.794 | 0.926 | 0.855 |
|
||||
| bag | 0.836 | 0.496 | 0.287 | 0.364 |
|
||||
| handbag | 0.935 | 0.469 | 0.073 | 0.126 |
|
||||
| boots | 0.905 | 0.784 | 0.791 | 0.787 |
|
||||
| gender | 0.858 | 0.806 | 0.828 | 0.817 |
|
||||
| hat | 0.898 | 0.883 | 0.680 | 0.768 |
|
||||
| shoes | 0.916 | 0.756 | 0.414 | 0.535 |
|
||||
| top | 0.893 | 0.590 | 0.381 | 0.463 |
|
||||
| upblack | 0.821 | 0.827 | 0.903 | 0.864 |
|
||||
| upwhite | 0.959 | 0.750 | 0.509 | 0.606 |
|
||||
| upred | 0.973 | 0.745 | 0.649 | 0.694 |
|
||||
| uppurple | 0.995 | 0.258 | 0.123 | 0.167 |
|
||||
| upgray | 0.900 | 0.611 | 0.333 | 0.432 |
|
||||
| upblue | 0.943 | 0.766 | 0.519 | 0.619 |
|
||||
| upgreen | 0.975 | 0.463 | 0.403 | 0.431 |
|
||||
| upbrown | 0.980 | 0.481 | 0.328 | 0.390 |
|
||||
| downblack | 0.787 | 0.740 | 0.807 | 0.772 |
|
||||
| downwhite | 0.945 | 0.771 | 0.395 | 0.522 |
|
||||
| downred | 0.991 | 0.739 | 0.645 | 0.689 |
|
||||
| downgray | 0.927 | 0.471 | 0.238 | 0.317 |
|
||||
| downblue | 0.807 | 0.741 | 0.669 | 0.703 |
|
||||
| downgreen | 0.997 | - | - | - |
|
||||
| downbrown | 0.979 | 0.871 | 0.594 | 0.706 |
|
||||
+-----------+----------+-----------+--------+----------+
|
||||
Average accuracy: 0.9152
|
||||
Average f1 score: 0.5739
|
||||
```
|
||||
|
||||
### Inference
|
||||
```
|
||||
>> python inference.py test_sample/test_market.jpg --dataset market
|
||||
age: teenager
|
||||
carrying backpack: no
|
||||
carrying bag: no
|
||||
carrying handbag: no
|
||||
type of lower-body clothing: dress
|
||||
length of lower-body clothing: short
|
||||
sleeve length: short sleeve
|
||||
hair length: long hair
|
||||
wearing hat: no
|
||||
gender: female
|
||||
color of upper-body clothing: white
|
||||
color of lower-body clothing: white
|
||||
|
||||
>> python inference.py test_sample/test_duke.jpg --dataset duke
|
||||
carrying backpack: no
|
||||
carrying bag: yes
|
||||
carrying handbag: no
|
||||
wearing boots: no
|
||||
gender: male
|
||||
wearing hat: no
|
||||
color of shoes: dark
|
||||
length of upper-body clothing: short upper body clothing
|
||||
color of upper-body clothing: black
|
||||
color of lower-body clothing: blue
|
||||
```
|
||||
|
||||
## Update
|
||||
*20-06-03: Added **identity loss** for joint optimization; Adjusted the learning rate for better performace.*
|
||||
|
||||
*20-06-03: Updated **test.py**, settled the issue of ill-defined metrics.*
|
||||
|
||||
*19-09-16: Updated **inference.py**, fixed the error caused by missing data-transform.*
|
||||
|
||||
*19-09-06: Updated **test.py**, added **F1 score** for evaluating.*
|
||||
|
||||
*19-09-03: Added **inference.py**, thanks @ViswanathaReddyGajjala.*
|
||||
|
||||
*19-08-23: Released trained models.*
|
||||
|
||||
*19-01-09: Fixed the error caused by an update of market and duke attribute dataset.*
|
||||
|
||||
## FAQ
|
||||
|
||||
### 1. Why attribute order in import_Market1501Attribute.py is different for train and test data?
|
||||
|
||||
The label order in import_Market1501Attribute.py is consistent with the attribute order of the dataset.
|
||||
|
||||
You can load market_attribute.mat in MATLAB and print "market_attribute.train" or "market_attribute.test" to obtain these orders.
|
||||
|
||||
### 2. Why predictions in the Market-1501 dataset have 30 attributes instead of 27?
|
||||
|
||||
This repo consider attribute prediction as multiple binary classification, but some attribute have more than two categories.
|
||||
|
||||
For example, attribute 'age' in Market-1501 has four categories: young(1), teenager(2), adult(3), old(4). So it can be split into four attributes: 'young', 'teenager', 'adult' and 'old'.
|
||||
|
||||
That's why preds of Market-1501 has 30 attributes.
|
||||
|
||||
## Reference
|
||||
|
||||
*[1] Lin Y, Zheng L, Zheng Z, et al. Improving person re-identification by attribute and identity learning[J]. Pattern Recognition, 2019.*
|
||||
- **탐지**: YOLO26m (COCO80)
|
||||
- **속성 인식**: ResNet50 + NFC (Market-1501 Attribute, 기본값)
|
||||
|
||||
@@ -19,11 +19,17 @@ transforms = T.Compose([
|
||||
T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
|
||||
])
|
||||
|
||||
def init_acai_task(output):
|
||||
task = Task.init(
|
||||
project_name="Person_Attribute_Recognition",
|
||||
task_name="MarketDuke_Agent"
|
||||
task_name="model-yolo-person-classify"
|
||||
)
|
||||
|
||||
result_data = {"output": output, "status": "PASS"}
|
||||
task.upload_artifact(name="final_result", artifact_object=result_data)
|
||||
|
||||
|
||||
|
||||
|
||||
class PredictDecoder(object):
|
||||
|
||||
@@ -103,14 +109,15 @@ def main(image, dataset='market', backbone='resnet50', use_id=False):
|
||||
print(f'{name}: {value}')
|
||||
print("=" * 50)
|
||||
|
||||
result_data = {"results": results, "status": "PASS"}
|
||||
task.upload_artifact(name="final_result", artifact_object=result_data)
|
||||
init_acai_task(results)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# python main.py --image_url "https://acai.ketidev.kr:20443/detect/image/202606/20260619_145116_image.jpg" --xywh "404,290,74,193"
|
||||
parser = argparse.ArgumentParser(description="Person Attribute Recognition Agent")
|
||||
parser.add_argument("--image_url", type=str)
|
||||
parser.add_argument("--xywh", type=str)
|
||||
parser.add_argument("--image_url", type=str) # --image_url "https://acai.ketidev.kr:20443/detect/image/202606/20260619_145116_image.jpg"
|
||||
parser.add_argument("--xywh", type=str) # --xywh "x,y,w,h"; (--xywh "404,290,74,193")
|
||||
|
||||
args = parser.parse_args()
|
||||
image_url = args.image_url
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[project]
|
||||
name = "person-attribute-recognition"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"clearml>=2.1.9",
|
||||
"requests>=2.34.2",
|
||||
"torch>=2.12.1",
|
||||
"torchvision>=0.27.1",
|
||||
]
|
||||
@@ -0,0 +1,93 @@
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv pip compile pyproject.toml -o requirements.txt
|
||||
attrs==26.1.0
|
||||
# via
|
||||
# clearml
|
||||
# jsonschema
|
||||
# referencing
|
||||
certifi==2026.6.17
|
||||
# via requests
|
||||
charset-normalizer==3.4.7
|
||||
# via requests
|
||||
clearml==2.1.9
|
||||
# via person-attribute-recognition (pyproject.toml)
|
||||
filelock==3.29.4
|
||||
# via torch
|
||||
fsspec==2026.6.0
|
||||
# via torch
|
||||
furl==2.1.4
|
||||
# via clearml
|
||||
idna==3.18
|
||||
# via requests
|
||||
jinja2==3.1.6
|
||||
# via torch
|
||||
jsonschema==4.26.0
|
||||
# via clearml
|
||||
jsonschema-specifications==2025.9.1
|
||||
# via jsonschema
|
||||
markupsafe==3.0.3
|
||||
# via jinja2
|
||||
mpmath==1.3.0
|
||||
# via sympy
|
||||
networkx==3.6.1
|
||||
# via torch
|
||||
numpy==2.4.6
|
||||
# via
|
||||
# clearml
|
||||
# torchvision
|
||||
orderedmultidict==1.0.2
|
||||
# via furl
|
||||
pathlib2==2.3.7.post1
|
||||
# via clearml
|
||||
pillow==12.2.0
|
||||
# via
|
||||
# clearml
|
||||
# torchvision
|
||||
psutil==7.2.2
|
||||
# via clearml
|
||||
pyjwt==2.13.0
|
||||
# via clearml
|
||||
pyparsing==3.3.2
|
||||
# via clearml
|
||||
python-dateutil==2.9.0.post0
|
||||
# via clearml
|
||||
pyyaml==6.0.3
|
||||
# via clearml
|
||||
referencing==0.37.0
|
||||
# via
|
||||
# clearml
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
requests==2.34.2
|
||||
# via
|
||||
# person-attribute-recognition (pyproject.toml)
|
||||
# clearml
|
||||
rpds-py==2026.5.1
|
||||
# via
|
||||
# jsonschema
|
||||
# referencing
|
||||
setuptools==81.0.0
|
||||
# via torch
|
||||
six==1.17.0
|
||||
# via
|
||||
# clearml
|
||||
# furl
|
||||
# orderedmultidict
|
||||
# pathlib2
|
||||
# python-dateutil
|
||||
sympy==1.14.0
|
||||
# via torch
|
||||
torch==2.12.1
|
||||
# via
|
||||
# person-attribute-recognition (pyproject.toml)
|
||||
# torchvision
|
||||
torchvision==0.27.1
|
||||
# via person-attribute-recognition (pyproject.toml)
|
||||
typing-extensions==4.15.0
|
||||
# via
|
||||
# referencing
|
||||
# torch
|
||||
urllib3==2.7.0
|
||||
# via
|
||||
# clearml
|
||||
# requests
|
||||
Reference in New Issue
Block a user