
MMPose 0.x 到 1.0 迁移实战数据变换重构、编解码器与模型权重兼容性详解【免费下载链接】mmposeOpenMMLab Pose Estimation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmposeMMPose 1.0 经历了大规模重构与 0.x 版本存在大量不兼容变更。本文基于仓库中的 0.X 兼容性说明系统讲解三大迁移主题数据变换流水线平移/旋转/缩放、标签生成、归一化如何映射到新版实现以及旧版模型权重如何通过_load_state_dict_pre_hook机制自动加载。读完后你可以将一个 0.x 项目的 pipeline 配置和训练好的 checkpoint 平滑迁移到 1.x当前仓库版本为 1.3.2见 version.py。总体变更概览0.x 到 1.0 的迁移主要涉及三类改动0.x 旧版组件1.x 新版替代迁移说明TopDownRandomShiftBboxCenterTopDownGetRandomScaleRotationRandomBBoxTransform两个变换合并为一个TopDownGenerateTarget、TopDownGenerateTargetRegression、BottomUpGenerateHeatmapTarget、BottomUpGenerateTarget等GenerateTarget 编解码器Codec标签生成逻辑抽离到独立的编解码器模块NormalizeTensorToTensorDataPreprocessor模块从 pipeline 移入模型前向传播GetRootCenteredPose、ImageCoordinateNormalization、NormalizeJointCoordinateImagePoseLifting、VideoPoseLifting等编码器3D 姿态数据变换合并入编码器PoseSequenceToTensor编解码器 PackPoseInputs序列张量化逻辑分散到相应模块预测头中loss字段RLE 方法loss_module字段需通过权重转换钩子处理以下逐节展开。数据变换一平移、旋转和缩放合并为 RandomBBoxTransform旧版中topdown 数据集的随机平移和随机缩放/旋转由两个独立的变换实现TopDownRandomShiftBboxCenter负责平移TopDownGetRandomScaleRotation负责缩放与旋转。1.x 将二者合并为 RandomBBoxTransformTRANSFORMS.register_module() class RandomBBoxTransform(BaseTransform): rRnadomly shift, resize and rotate the bounding boxes. Required Keys: - bbox_center - bbox_scale Modified Keys: - bbox_center - bbox_scale Added Keys: - bbox_rotation Args: shift_factor (float): Randomly shift the bbox in range :math:[-dx, dx] and :math:[-dy, dy] in X and Y directions, where :math:dx(y) x(y)_scale \cdot shift_factor in pixels. Defaults to 0.16 shift_prob (float): Probability of applying random shift. Defaults to 0.3 scale_factor (Tuple[float, float]): Randomly resize the bbox in range :math:[scale_factor[0], scale_factor[1]]. Defaults to (0.5, 1.5) scale_prob (float): Probability of applying random resizing. Defaults to 1.0 rotate_factor (float): Randomly rotate the bbox in :math:[-rotate_factor, rotate_factor] in degrees. Defaults to 80.0 rotate_prob (float): Probability of applying random rotation. Defaults to 0.6 def __init__(self, shift_factor: float 0.16, shift_prob: float 0.3, scale_factor: Tuple[float, float] (0.5, 1.5), scale_prob: float 1.0, rotate_factor: float 80.0, rotate_prob: float 0.6) - None:从 源码实现 看这个合并版变换相比旧版有两个值得注意的工程细节截断正态分布采样。旧版通常使用均匀分布采样随机参数而RandomBBoxTransform通过scipy.stats.truncnorm从截断正态分布中采样_truncnorm静态方法使参数分布集中在均值附近增强效果更平滑可控staticmethod def _truncnorm(low: float -1., high: float 1., size: tuple ()) - np.ndarray: Sample from a truncated normal distribution. return truncnorm.rvs(low, high, sizesize).astype(np.float32)一次性生成全部随机参数。_get_transform_params在一次调用中同时生成 offset、scale、rotate 三组参数并通过各自动作概率shift_prob/scale_prob/rotate_prob决定是否生效cache_randomness装饰器保证同一批次中不同样本共享相同的随机种子。最终的transform逻辑非常简洁results[bbox_center] results[bbox_center] offset * bbox_scale results[bbox_scale] results[bbox_scale] * scale results[bbox_rotation] rotate迁移要点旧 pipeline 配置中的两个变换项typeTopDownRandomShiftBboxCenter, shift_factor..., prob...和typeTopDownGetRandomScaleRotation, scale_factor..., rotate_factor...需替换为单个RandomBBoxTransform参数名基本一一对应prob改为shift_prob/scale_prob/rotate_prob。数据变换二标签生成统一为 GenerateTarget 编解码器旧版中不同类型的监督信号heatmap 标签、回归标签、bottom-up 目标等各自有一个生成变换TopDownGenerateTarget、TopDownGenerateTargetRegression、BottomUpGenerateHeatmapTarget、BottomUpGenerateTarget等。1.x 将其统一为 GenerateTarget而实际的生成方法由编解码器codec提供TRANSFORMS.register_module() class GenerateTarget(BaseTransform): Encode keypoints into Target. The generated target is usually the supervision signal of the model learning, e.g. heatmaps or regression labels. Required Keys: - keypoints - keypoints_visible - dataset_keypoint_weights Added Keys: - The keys of the encoded items from the codec will be updated into the results, e.g. heatmaps or keypoint_weights. See the specific codec for more details. Args: encoder (dict | list[dict]): The codec config for keypoint encoding. Both single encoder and multiple encoders (given as a list) are supported multilevel (bool): Determine the method to handle multiple encoders. If multilevelTrue, generate multilevel targets from a group of encoders of the same type (e.g. multiple :class:MSRAHeatmap encoders with different sigma values); If multilevelFalse, generate combined targets from a group of different encoders. This argument will have no effect in case of single encoder. Defaults to False use_dataset_keypoint_weights (bool): Whether use the keypoint weights from the dataset meta information. Defaults to False def __init__(self, encoder: MultiConfig, multilevel: bool False, use_dataset_keypoint_weights: bool False) - None:从 源码实现 看GenerateTarget的transform流程为优先取results[transformed_keypoints]由TopdownAffine变换后的关键点不存在时回退到results[keypoints]两者都缺失则抛出ValueError若keypoints_visible形状为(N, K, 2)拆分为可见性标志与可见性权重keypoints_visible_weights调用编码器encoder.encode(...)得到监督信号如heatmaps、keypoint_weights并将编码器附带的field_mapping_table、instance_mapping_table、label_mapping_table一并写入 results多编码器场景下multilevelTrue要求各编码器输出键一致例如多组不同 sigma 的MSRAHeatmap按层级堆叠multilevelFalse时合并不同编码器的输出若多个编码器都产出keypoint_weights则以列表形式保留多个权重在 loss 端组合使用且不允许其他键重复use_dataset_keypoint_weightsTrue时将编码结果的keypoint_weights与数据集元信息中的dataset_keypoint_weights相乘最后results.update(encoded)将编码产物heatmaps、keypoint_weights等写入 result dict。因此迁移时旧配置里形如dict(typeTopDownGenerateTarget, bbox_to_keypoint_ratio2.0)的条目需改写为dict( typeGenerateTarget, encoderdict(typeMSRAHeatmap, bbox_to_keypoint_ratio2.0))各类 codec 的接口与可配置参数详见 编解码器文档。数据变换三归一化操作移入 DataPreprocessor旧版流水线中的NormalizeTensor和ToTensor两个变换在 1.x 中不再作为流水线的一部分而是由DataPreprocessor模块替代加入到模型前向传播中实现见 data_preprocessor.py。迁移时只需从 pipeline 中删除这两项并在模型配置中配置data_preprocessor通常包括mean、std、size_divisor、pad_size_divisor等参数与旧版NormalizeTensor的mean/std语义一致。对于 3D 人类姿态任务旧版用于数据变换的GetRootCenteredPose、ImageCoordinateNormalization、NormalizeJointCoordinate等方法已被合并入编解码器内部例如ImagePoseLifting基于图像的姿态提升编码器坐标归一化、根关节中心化等逻辑均在编码器内部完成VideoPoseLifting基于视频的姿态提升编码器序列层面的归一化同样内聚于编码器。数据转换和重构操作PoseSequenceToTensor将姿态序列组织成张量则在相应的编解码器和 PackPoseInputs 中实现。迁移时不需要为序列打包单独保留变换项配置好对应 codec 和PackPoseInputs即可。模型兼容旧版权重如何无缝加载官方对 model zoo 提供的模型权重做了兼容性处理相同权重的测试精度与 0.x 版本保持同等水平但由于两个版本在处理细节上存在大量差异推理结果可能产生轻微不同文档说明精度误差小于 0.05%。对于用户自己用 0.x 训练保存的权重1.x 在预测头中内置了_load_state_dict_pre_hook()方法将旧版权重字典自动转换为新版结构。若你在 1.x 上自定义了模型头可参考仓库实现注册同样的钩子MODELS.register_module() class YourHead(BaseHead): def __init__(self): ## omitted # Register the hook to automatically convert old version state dicts self._register_load_state_dict_pre_hook(self._load_state_dict_pre_hook)这是 PyTorch 的标准机制load_state_dict执行前钩子会以state_dict、prefix参数前缀、local_meta模块元数据为参数被调用可以在权重真正绑定到模型之前改写键名。钩子内的通用判断是version local_meta.get(version, None) if version and version self._version: return # convert old-version state dict ...只有当version字段缺失0.x 权重或低于模块要求的_version时才执行键名转换。Heatmap-based 方法final_layer 拆分对于基于 SimpleBaseline 的 heatmap 模型旧版final_layer同时包含中间卷积层和最后的 1x1 卷积层而新版将二者拆分为conv_layers中间卷积层与final_layer最终卷积层。以仓库中的 HeatmapHead 为例新版结构为if final_layer is not None: cfg dict( typeConv2d, in_channelsin_channels, out_channelsout_channels, kernel_size1) cfg.update(final_layer) self.final_layer build_conv_layer(cfg) else: self.final_layer nn.Identity() # Register the hook to automatically convert old version state dicts self._register_load_state_dict_pre_hook(self._load_state_dict_pre_hook)对应的权重转换钩子见 heatmap_head.pydef _load_state_dict_pre_hook(self, state_dict, prefix, local_meta, *args, **kwargs): version local_meta.get(version, None) if version and version self._version: return # convert old-version state dict keys list(state_dict.keys()) for _k in keys: if not _k.startswith(prefix): continue v state_dict.pop(_k) k _k[len(prefix):] # In old version, final_layer includes both intermediate # conv layers (new conv_layers) and final conv layers (new # final_layer). # # If there is no intermediate conv layer, old final_layer will # have keys like final_layer.xxx, which should be still # named final_layer.xxx; # # If there are intermediate conv layers, old final_layer will # have keys like final_layer.n.xxx, where the weights of the last # one should be renamed final_layer.xxx, and others should be # renamed conv_layers.n.xxx k_parts k.split(.) if k_parts[0] final_layer: if len(k_parts) 3: assert isinstance(self.conv_layers, nn.Sequential) idx int(k_parts[1]) if idx len(self.conv_layers): # final_layer.n.xxx - conv_layers.n.xxx k_new conv_layers. ..join(k_parts[1:]) else: # final_layer.n.xxx - final_layer.xxx k_new final_layer. k_parts[2] else: # final_layer.xxx remains final_layer.xxx k_new k else: k_new k state_dict[prefix k_new] v转换规则可以归纳为旧版权重键新版权重键说明final_layer.xxxfinal_layer.xxx无中间卷积层时保持不变final_layer.n.xxxn 为中间层下标conv_layers.n.xxx前 n 层划归conv_layersfinal_layer.n.xxxn 为最后一层下标final_layer.xxx最后一层保留为final_layerRLE-based 方法loss 重命名为 loss_module对于基于 RLE积分回归的模型新版将loss模块更名为loss_module且 flow 模型的归属也调整到了该模块下。以 RLEHead 为例新版中损失模块挂在self.loss_module MODELS.build(loss)上rle_head.py对应的钩子只需做键前缀替换def _load_state_dict_pre_hook(self, state_dict, prefix, local_meta, *args, **kwargs): version local_meta.get(version, None) if version and version self._version: return # convert old-version state dict keys list(state_dict.keys()) for _k in keys: v state_dict.pop(_k) k _k.lstrip(prefix) # In old version, loss includes the instances of loss, # now it should be renamed loss_module k_parts k.split(.) if k_parts[0] loss: # loss.xxx - loss_module.xxx k_new prefix loss_module. ..join(k_parts[1:]) else: k_new _k state_dict[k_new] v迁移检查清单将 0.x 项目升级到 1.x 时可按下表逐项核对pipeline 配置TopDownRandomShiftBboxCenterTopDownGetRandomScaleRotation→ 单个RandomBBoxTransform注意概率参数改名shift_prob/scale_prob/rotate_probTopDownGenerateTarget系列 →GenerateTargetencoder配置编码器类型需按监督信号选择heatmap 用MSRAHeatmap等具体见 编解码器文档删除NormalizeTensor、ToTensor改用模型级data_preprocessor配置3D 姿态任务GetRootCenteredPose、ImageCoordinateNormalization、NormalizeJointCoordinate、PoseSequenceToTensor等全部移除由ImagePoseLifting/VideoPoseLifting编码器与PackPoseInputs接管。模型配置确认各预测头已更新为 1.x 的类名与参数如HeatmapHead的final_layer不再包含中间卷积层中间层由conv_out_channels/conv_kernel_sizes配置。权重加载model zoo 权重可直接使用精度与 0.x 基本一致误差小于 0.05%自训权重依靠内置的_load_state_dict_pre_hook自动转换无需手动改键若自定义预测头不兼容可参照 HeatmapHead 与 RLEHead 的实现在头模块的__init__中注册转换钩子。【免费下载链接】mmposeOpenMMLab Pose Estimation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmpose创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考