AlphaPose_finetune和自定义关键点

我有以下几个目标

  • 我创建了一个只有运动员的数据集,我需要在Alphapose上做微调训练或者完全重新训练
  • 我的运动员穿着服装非常单一,我需要修改yolo检测部分让他能够只识别运动员
  • 我的运动员数据集相对于coco数据集17个关键点,多了手背脚尖腰部5个关键点,现在我需要针对这个骨架重新编写一个data并进行训练,使得我的Alphapose能够输出22个坐标点

数据集准备

MSCOCO

我这里准备的是coco数据集,这里的coco数据集需要注意

  • 一定要用数字做图像名称
  • 要添加url
  • train和val目录不能出现有相同名称的图像
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|-- json
|-- exp
|-- alphapose
|-- configs
|-- test
|-- data
`-- |-- coco
`-- |-- annotations
| |-- person_keypoints_train2017.json
| `-- person_keypoints_val2017.json
|-- train2017
| |-- 000000000009.jpg
| |-- 000000000025.jpg
| |-- 000000000030.jpg
| |-- ...
`-- val2017
|-- 000000000139.jpg
|-- 000000000285.jpg
|-- 000000000632.jpg
|-- ...

微调训练train.py

这个train.py发现是自带微调的,但是是全权重微调,没有只微调一部分的。需要额外训练YOLO检测,这里分为yolov3和yoloX,但是yolov3的这个代码来自一个不知名地方,所以后期还是得改成用yolox,这里有一个如何训练yolox的链接。

  • 注意一点,其中检测头的yolo权重不会被微调,但是在微调过程中是使用数据集中的bbox中的图像进行关键点检测的,所以你可以在训练完alphapose之后之后再训练yolo,但是等到你需要部署的时候肯定得训练yolo让你的alphapose能先找到目标任务然后进行特征点提取

  • 注意第二点是,模型下载到.cache/torch/hub/checkpoint中的backbone,比如resnet50、resnet152也同样在微调过程中不会被训练,但是这部分也没必要训练。hrnet的版本不需要下载权重,比较喜欢,因为有些项目不能上网。

下面讲解如何快速微调:

其实就是修改config文件,必须修改configs/coco/resnet/a256x192_res152_lr1e-3_1x-duc.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# 重点修改这里使的dataset的位置正确
DATASET:
TRAIN:
TYPE: 'Mscoco'
ROOT: './data/coco/'
IMG_PREFIX: 'train2017'
ANN: 'annotations/person_keypoints_train2017.json'
AUG:
FLIP: true
ROT_FACTOR: 40
SCALE_FACTOR: 0.3
NUM_JOINTS_HALF_BODY: 8
PROB_HALF_BODY: -1
VAL:
TYPE: 'Mscoco'
ROOT: './data/coco/'
IMG_PREFIX: 'val2017'
ANN: 'annotations/person_keypoints_val2017.json'
TEST:
TYPE: 'Mscoco_det'
ROOT: './data/coco/'
IMG_PREFIX: 'val2017'
DET_FILE: './exp/json/test_det_yolo.json'
ANN: 'annotations/person_keypoints_val2017.json'
-------------------省略号---------------
MODEL:
TYPE: 'FastPose_DUC'
BACKBONE: 'se-resnet'
# 最重点的是修改这里的预训练权重
# 如果设置了PRETRAINED预训练权重,那么会在预训练权重上微调,这个是支持的,最好这么做
# 如果没有设置PRETRAINED,那么就会从零训练一个网络,但是如果你的数据集很单一,就是一个一种服装的运动员,那么你的训练结果会非常的过拟合,换个角度就难以识别了
PRETRAINED: 'pretrained_models/fast_421_res152_256x192.pth'
# 如果你想要训练一个和coco2017关键点数目不一样的网络,但是又想预训练,那么可以在这里TRY_LOAD加载一个权重,代码会根据权重名称和大小,把大小和名称都对应的部分加载了,但是不对应的比如最后的输出层会不加载,刚好适用于微调一个新的模型
TRY_LOAD: ''
NUM_DECONV_FILTERS:
- 256
- 256
- 256
NUM_LAYERS: 152
FINAL_CONV_KERNEL: 1
STAGE1:
NUM_CONV: 4
STAGE2:
NUM_CONV: 2
STAGE3:
NUM_CONV: 1
LOSS:
TYPE: 'MSELoss'
#这里是默认设置为yolov3
NAME: 'yolo'
CONFIG: 'detector/yolo/cfg/yolov3-spp.cfg'
WEIGHTS: 'detector/yolo/data/yolov3-spp.weights'
NMS_THRES: 0.6
CONFIDENCE: 0.05
TRAIN:
WORLD_SIZE: 4
BATCH_SIZE: 32
BEGIN_EPOCH: 0
# 修改这里
END_EPOCH: 200
OPTIMIZER: 'adam'
LR: 0.001
LR_FACTOR: 0.1
LR_STEP:
- 90
- 120
DPG_MILESTONE: 140
DPG_STEP:
- 160
- 190

最后开始训练,代码很简单

1
2
3
4
5
6
7
8
9
10
11
# 展示训练res50
CUDA_VISIBLE_DEVICES=1 \ #这里我会设置以下用哪些卡进行训练
./scripts/train.sh \
./configs/coco/resnet/256x192_res50_lr1e-3_1x.yaml \
250420Finetune #给这个训练过程起一个名字,然后接可以在exp/250420Finetune找到对应的model

# 展示训练hrnet的结构,一般来说hrnet会非常准,但是实验测试res152更准,毕竟网络变深了
CUDA_VISIBLE_DEVICES=1 \
./scripts/train.sh \
./configs/coco/hrnet/b256x192_w32_lr1e-3.yaml \
0516Hrnetcoco1Pretrined

修改yolo检测部分让他能够只识别某一个人

首先需要微调训一个只识别一种类别“person”的yolo网络,这里训练的版本为yolox_s,因为他小,训练的快,但是yolo_l性能不错

,然后在detector/yolox/exps/default/yolox_s.py,修改对应网络架构为只识别一个类别

1
2
3
4
5
6
7
8
class Exp(MyExp):
def __init__(self):
super(Exp, self).__init__()
self.depth = 0.33
self.width = 0.50
self.exp_name = os.path.split(os.path.realpath(__file__))[1].split(".")[0]
# 后添加的
self.num_classes = 1

然后训练demo就可以了

1
2
3
4
5
6
7
8
9
UDA_VISIBLE_DEVICES=4 \
python demo_inference.py \
--cfg configs/coco/resnet/a256x192_res152_lr1e-3_1x-duc.yaml \
--detector yolox-s --checkpoint exp/0516res152coco1FullPretrained-a256x192_res152_lr1e-3_1x-duc.yaml/model_199.pth \
--video example2024012900025/202401290002_Miqus_5_28519.avi \
--outdir example2024012900025/0517FulltrainedRes152coco1Pretrainedyoloxstrain0517num80epoth20 \
--pose_track \
--save_video \
--vis_fast

自定义关节点个数,微调训练一个新网络

  1. 首先按照alphapose/datasets/coco_det.py和alphapose/datasets/mscoco.py创建了具有22个点的alphapose/datasets/coco22_det.py和alphapose/datasets/coco22.py
  2. 然后注意在alphapose/datasets/init.py注册这个新建立的数据集格式coco22
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from .coco_det import Mscoco_det
from .concat_dataset import ConcatDataset
from .custom import CustomDataset
from .mscoco import Mscoco
from .mpii import Mpii
from .coco_wholebody import coco_wholebody
from .coco_wholebody_det import coco_wholebody_det
from .halpe_26 import Halpe_26
from .halpe_136 import Halpe_136
from .halpe_136_det import Halpe_136_det
from .halpe_26_det import Halpe_26_det
from .halpe_coco_wholebody_26 import Halpe_coco_wholebody_26
from .halpe_coco_wholebody_26_det import Halpe_coco_wholebody_26_det
from .halpe_coco_wholebody_136 import Halpe_coco_wholebody_136
from .halpe_coco_wholebody_136_det import Halpe_coco_wholebody_136_det
from .halpe_68_noface import Halpe_68_noface
from .halpe_68_noface_det import Halpe_68_noface_det
from .single_hand import SingleHand
from .single_hand_det import SingleHand_det
from .coco22 import Coco22
from .coco22_det import Coco22_det
__all__ = ['CustomDataset', 'ConcatDataset', 'Mpii', 'Mscoco', 'Mscoco_det', \
'Halpe_26', 'Halpe_26_det', 'Halpe_136', 'Halpe_136_det', \
'Halpe_coco_wholebody_26', 'Halpe_coco_wholebody_26_det', \
'Halpe_coco_wholebody_136', 'Halpe_coco_wholebody_136_det', \
'Halpe_68_noface', 'Halpe_68_noface_det', 'SingleHand', 'SingleHand_det', \
'coco_wholebody', 'coco_wholebody_det','Coco22', 'Coco22_det']
  1. 在configs/coco22/resnet/a256x192_res152_lr1e-3_1x-duc.yaml创建一个新的yml文件用于训练这个新的模型,只需要更改data部分和joints_num
  2. 另外注意这里训练时候把try_load改成预训练模型,这样可以微调,网络会把名称和大小都一致的block填充,这样做的优势是不容易过拟合。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
DATASET:
TRAIN:
TYPE: 'Coco22'
ROOT: './data/coco2/'
IMG_PREFIX: 'train2017'
# ANN: 'annotations/person_keypoints_train2017.json'
ANN: 'annotationsFullAnd5pt/mergedcocoFullAnd5ptperson_keypoints_train2017.json'
AUG:
FLIP: true
ROT_FACTOR: 40
SCALE_FACTOR: 0.3
NUM_JOINTS_HALF_BODY: 8
PROB_HALF_BODY: -1
VAL:
TYPE: 'Coco22'
ROOT: './data/coco2/'
IMG_PREFIX: 'val2017'
ANN: 'annotationsFullAnd5pt/mergedcocoFullAnd5ptperson_keypoints_val2017.json'
TEST:
TYPE: 'Coco22_det'
ROOT: './data/coco2/'
IMG_PREFIX: 'val2017'
DET_FILE: './exp/json/test_det_yolo.json'
ANN: 'annotationsFullAnd5pt/mergedcocoFullAnd5ptperson_keypoints_val2017.json'
DATA_PRESET:
TYPE: 'simple'
# 这里是按照simplehand的格式来写的
# 但是实际上是coco22的格式,其实可以用combine等loss
LOSS_TYPE: 'L1JointRegression'
NORM_TYPE: 'sigmoid'
SIGMA: 2
NUM_JOINTS: 22
IMAGE_SIZE:
- 256
- 192
HEATMAP_SIZE:
- 64
- 48
MODEL:
TYPE: 'FastPose_DUC'
BACKBONE: 'se-resnet'
PRETRAINED: ''
TRY_LOAD: 'pretrained_models/fast_421_res152_256x192.pth'
NUM_DECONV_FILTERS:
- 256
- 256
- 256
NUM_LAYERS: 152
FINAL_CONV_KERNEL: 1
STAGE1:
NUM_CONV: 4
STAGE2:
NUM_CONV: 2
STAGE3:
NUM_CONV: 1
LOSS:
# TYPE: 'MSELoss'
TYPE: 'L1JointRegression'
NORM_TYPE: 'sigmoid'
OUTPUT_3D: False
DETECTOR:
NAME: 'yolo_s'
CONFIG: 'detector/yolox/exps/default/yolox_s.py'
WEIGHTS: 'detector/yolox/data/yolox_s.pth'
NMS_THRES: 0.4
CONFIDENCE: 0.5
TRAIN:
WORLD_SIZE: 4
BATCH_SIZE: 32
BEGIN_EPOCH: 0
END_EPOCH: 200
OPTIMIZER: 'adam'
LR: 0.001
LR_FACTOR: 0.1
LR_STEP:
- 90
- 120
DPG_MILESTONE: 140
DPG_STEP:
- 160
- 190
1
2
3
4
5
6
7
8
9
10
11
12
13
如果你在train,py tryload那一部分导出加载模型模块,可以看到原先的输出层是一个17通道的,现在变成了22个
for k, v in pretrained_state.items():
if k in model_state and v.size() != model_state[k].size():
logger.info(f"Size mismatch for {k}: pretrained {v.size()} vs model {model_state[k].size()}")
if len(v.size()) > 0 and v.size(0) < model_state[k].size(0):
print(f"load pretrained model {k} with size {v.size()} to model {model_state[k].size()}")
expanded_v = torch.cat([v, v[-1:].repeat(model_state[k].size(0) - v.size(0), *([1] * (v.dim() - 1)))], dim=0)
pretrained_state[k] = expanded_v


Loading model from pretrained_models/fast_421_res152_256x192.pth...
Size mismatch for conv_out.weight: pretrained torch.Size([17, 256, 3, 3]) vs model torch.Size([22, 256, 3, 3])
Size mismatch for conv_out.bias: pretrained torch.Size([17]) vs model torch.Size([22])
  1. 训练
1
2
3
4
5
6
7
## 直接这样训练是用yolov3默认权重
CUDA_VISIBLE_DEVICES=2 ./scripts/train.sh ./configs/coco22/resnet/a256x192_res152_lr1e-3_1x-duc.yaml 0517res152num22


CUDA_VISIBLE_DEVICES=2,3 python scripts/train.py --cfg ./configs/coco22/resnet/a256x192_res152_lr1e-3_1x-duc.yaml --detector yolox-s --exp-id 0607res152num22setdetsNorepeatwight

CUDA_VISIBLE_DEVICES=1,2,3,0 python scripts/trainRepeatweight.py --cfg ./configs/coco22/resnet/a256x192_res152_lr1e-3_1x-duc.yaml --detector yolox-s --exp-id 0607res152num22setdetsrepeatwight
  1. 推理
1
CUDA_VISIBLE_DEVICES=4 python demo_inference.py --cfg configs/coco22/resnet/a256x192_res152_lr1e-3_1x-duc.yaml  --detector yolox-s  --checkpoint exp/0517res152num22-a256x192_res152_lr1e-3_1x-duc.yaml/model_199.pth --video example2024012900025/202401290002_Miqus_5_28519.avi --outdir example2024012900025/0518num22pretrainedRes152posetrackYolos --pose_track --save_video --vis_fast

报错

[ WARN:0@21.180] global loadsave.cpp:241 findDecoder imread_(’/home/houbosen/coco0606/val2017/000000080079.jpg’): can’t open/read file: check file path/integrity

每次训练删除exp/json/test_det_yolo.json