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发现是自带微调的,但是是全权重微调,没有只微调一部分的。需要额外训练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
自定义关节点个数,微调训练一个新网络
首先按照alphapose/datasets/coco_det.py和alphapose/datasets/mscoco.py创建了具有22个点的alphapose/datasets/coco22_det.py和alphapose/datasets/coco22.py
然后注意在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']
在configs/coco22/resnet/a256x192_res152_lr1e-3_1x-duc.yaml创建一个新的yml文件用于训练这个新的模型,只需要更改data部分和joints_num
另外注意这里训练时候把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 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 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