mcpField
S
shunk031-python-transformers-convert

shunk031-python-transformers-convert

github.com/shunk031开发058 次安装1 周前更新
代码仓库

关于 shunk031-python-transformers-convert

帮助开发者将自定义 PyTorch 模型转换为 Hugging Face Transformers 格式,涵盖实现、等价性验证和 Hub 发布准备。

主要功能

  1. 01将模型参数提取到配置中
  2. 02构建模型与处理器类
  3. 03测试与原模型的兼容性
  4. 04准备模型卡和 Hub 上传

适用场景

  1. 01转换自定义视觉或文本模型
  2. 02替换实现前验证输出等价性
  3. 03为 Hub 上传打包转换后的模型

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/shunk031/skills --skill shunk031-python-transformers-convert

安装后在 Claude Code 中输入/shunk031-python-transformers-convert确认已加载。

附带文件references/common-pitfalls.mdreferences/learnings.md

详细介绍

说明

阅读此 SKILL.md 后,请说:🤗 I read shunk031-python-transformers-convert.

Hugging Face Transformers 模型转换

将自定义 PyTorch 模型转换为 Hugging Face Transformers 格式,同时确保与原始实现完全兼容。

概述

此技能提供了一套系统化的 Transformers 转换工作流:

  • 将硬编码值提取到 PretrainedConfig 中
  • 创建 PreTrainedModel 封装类
  • 构建 ImageProcessor/Tokenizer
  • 全面测试等效性
  • 为上传到 Hub 做准备

重要:先使用验证模式(并行实现)验证等效性,然后再替换原实现。

转换工作流

第 1 步:分析自定义模型

请用户指定:

  • 自定义模型实现的路径
  • 模型类型(视觉、文本、多模态)
  • 任务(分类、分割、生成等)
  • 验证模式或替换模式

然后确定:

  • 模型架构和组件
  • 输入/输出格式
  • 关键超参数和硬编码值
  • 预训练权重的位置
  • 预处理流程
  • 自定义层或模块
第 2 步:创建 PretrainedConfig 类

核心原则:将模型中的所有硬编码值提取为可配置参数。

模板:

from transformers import PretrainedConfig
from typing import List, Optional

class {ModelName}Config(PretrainedConfig):
    model_type = "{model_name}"

    def __init__(
        self,
        # Core architecture parameters
        hidden_dim: int = 128,
        num_layers: int = 4,

        # Input/output parameters
        image_size: int = 1024,
        num_channels: int = 3,
        num_labels: int = 1,

        # Component-specific parameters (extract from original)
        component_param: List[int] | None = None,

        **kwargs,
    ):
        super().__init__(**kwargs)

        self.hidden_dim = hidden_dim
        self.num_layers = num_layers
        self.image_size = image_size
        self.num_channels = num_channels
        self.num_labels = num_labels

        # Use default if not specified
        self.component_param = (
            component_param if component_param is not None else [1, 2, 4]
        )

关键:确保默认值与预训练权重所需的值一致!

第 3 步:创建 PreTrainedModel 类

模板:

from transformers import PreTrainedModel
from transformers.modeling_outputs import SemanticSegmenterOutput

class {ModelName}ForTask(PreTrainedModel):
    config_class = {ModelName}Config

    def __init__(self, config: {ModelName}Config):
        super().__init__(config)
        self.config = config

        # Initialize layers using config parameters (no hardcoded values!)
        self.encoder = Encoder(
            hidden_dim=config.hidden_dim,
            num_layers=config.num_layers,
        )

    def forward(
        self,
        pixel_values: torch.FloatTensor,
        labels: Optional[torch.LongTensor] = None,
        output_hidden_states: Optional[bool] = None,
        return_dict: Optional[bool] = None,
    ) -> Union[Tuple, SemanticSegmenterOutput]:
        return_dict = return_dict if return_dict is not None else self.config.use_return_dict

        # Forward pass
        logits = self.encoder(pixel_values)

        # Calculate loss if needed
        loss = None
        if labels is not None:
            # Compute loss
            pass

        if not return_dict:
            output = (logits,)
            return ((loss,) + output) if loss is not None else output

        return SemanticSegmenterOutput(
            loss=loss,
            logits=logits,
            hidden_states=None,
            attentions=None,
        )
第 4 步:创建 ImageProcessor/Tokenizer

对于视觉模型——创建 ImageProcessor:

from transformers import BaseImageProcessor

class {ModelName}ImageProcessor(BaseImageProcessor):
    model_input_names = ["pixel_values"]

    def __init__(
        self,
        size: int = 1024,
        resample: str = "bilinear",
        do_normalize: bool = True,
        image_mean: List[float] | None = None,
        image_std: List[float] | None = None,
        **kwargs,
    ):
        super().__init__(**kwargs)
        self.size = size
        self.resample = resample
        self.do_normalize = do_normalize
        self.image_mean = image_mean if image_mean is not None else [0.485, 0.456, 0.406]
        self.image_std = image_std if image_std is not None else [0.229, 0.224, 0.225]

    def preprocess(
        self,
        images: ImageInput,
        return_tensors: Optional[Union[str, TensorType]] = None,
        **kwargs,
    ) -> BatchFeature:
        # Implement preprocessing matching original
        # Return BatchFeature with pixel_values

对于文本模型——创建 tokenizer 配置。

第 5 步:创建兼容性测试

关键:比较输出时,务必对两个模型使用相同的预处理张量。

import pytest
import torch

def test_preprocessing_matches():
    """Test that preprocessing is equivalent."""
    old_tensor = old_preprocessing(image)
    new_tensor = processor(image, return_tensors="pt")["pixel_values"][0]
    assert torch.allclose(old_tensor, new_tensor, atol=1e-6)

def test_single_image_output_matches():
    """Test that model outputs match."""
    # Load models
    old_model = OldModel()
    new_model = NewModel(NewConfig())
    new_model.load_state_dict(old_model.state_dict())

    # Prepare SAME input
    preprocessed = preprocess(image)

    with torch.no_grad():
        old_output = old_model(preprocessed)
        new_output = new_model(pixel_values=preprocessed)

    # Use 0.5% tolerance for numerical differences
    assert torch.allclose(old_output, new_output.logits, atol=5e-3, rtol=1e-2)

def test_batch_output_matches():
    """Test batch processing."""
    # Test with batch of images

def test_state_dict_compatible():
    """Test that weights can be loaded."""
    new_model.load_state_dict(old_model.state_dict())
第 6 步:创建 MODEL_CARD.md

按照 Hugging Face 标准生成完整的模型卡。包括:

  • 模型说明
  • 用法示例
  • 训练详情
  • 评估指标
  • 引用信息

请参阅 Hugging Face 模型卡文档中的模板。

第 7 步:创建 Hub 推送脚本

关键:推送前,使用 register_for_auto_class() 注册类。

#!/usr/bin/env python3
from huggingface_hub import HfApi
from {module}.transformers import {ModelName}Config, {ModelName}ForTask, {ModelName}ImageProcessor

def main():
    # CRITICAL: Register for Auto* support
    {ModelName}Config.register_for_auto_class()
    {ModelName}ForTask.register_for_auto_class("AutoModel")
    {ModelName}ImageProcessor.register_for_auto_class("AutoImageProcessor")

    # Load original model
    original_model = OriginalModel()

    # Create transformers-compatible model
    config = {ModelName}Config()
    model = {ModelName}ForTask(config)
    model.load_state_dict(original_model.state_dict())

    # Save and push
    model.save_pretrained(local_dir)
    config.save_pretrained(local_dir)
    processor = {ModelName}ImageProcessor()
    processor.save_pretrained(local_dir)

    api = HfApi(token=token)
    api.create_repo(repo_id=repo_id, exist_ok=True)
    api.upload_folder(repo_id=repo_id, folder_path=local_dir)

实现策略

验证模式(建议先使用)

创建并行实现:

{project}/
├── {module}/
│   ├── original_model.py           # Existing
│   └── transformers/               # NEW - for validation
│       ├── __init__.py
│       ├── configuration_{model}.py
│       ├── modeling_{model}.py
│       └── processing_{model}.py
└── tests/
    └── test_transformers_compatibility.py

工作流:

  1. 在原实现旁创建 transformers/ 包
  2. 运行兼容性测试
  3. 调试任何差异
  4. 测试通过后 → 继续替换
替换模式(验证之后)

验证等效性后:

{project}/
└── {module}/
    ├── configuration_{model}.py    # Replaces original
    ├── modeling_{model}.py
    └── processing_{model}.py

工作流:

  1. 删除或归档原实现
  2. 将 transformers/* 文件上移一级
  3. 更新所有导入
  4. 更新测试
  5. 更新文档

常见问题

详细的故障排查说明请参阅 references/common-pitfalls.md。

快速参考:

  • 硬编码值:提取到 config 中,并确保默认值匹配
  • 预处理不一致:使用完全相同的流程和参数
  • State dict 键:保持层名称与原实现一致
  • 测试容差:数值差异使用 0.5% 的容差(5e-3)
  • 设备处理:使用 PreTrainedModel 中的 self.device
  • 图像尺寸顺序:post_process_semantic_segmentation() 期望参数为 (width, height)

调试策略

如果输出不匹配:

  1. 检查预处理是否生成完全相同的张量
  2. 检查 state dict 是否正确加载
  3. 逐层比较
  4. 检查设备位置
  5. 使用 torch.manual_seed 检查确定性

详细的调试步骤请参阅 references/common-pitfalls.md。

项目经验

完成转换后,将经验添加到 references/learnings.md。

这有助于积累各项目的经验,避免重复犯错。

检查清单

  • 步骤 1:分析模型
    • 确定架构
    • 提取超参数
    • 理解预处理
  • 步骤 2:创建配置类
    • 将所有硬编码的值移至配置中
    • 默认值与预训练权重匹配
    • 添加类型提示
  • 步骤 3:创建模型类
    • 继承自 PreTrainedModel
    • 仅使用配置参数
    • forward 签名符合约定
  • 步骤 4:创建处理器
    • 预处理与原实现一致
    • 返回适当的格式
  • 步骤 5:创建测试
    • 预处理测试通过
    • 单图测试通过
    • 批量测试通过
    • 状态字典测试通过
  • 步骤 6:创建 MODEL_CARD.md
    • 填写所有章节
    • 测试使用示例
    • 添加引用
  • 步骤 7:创建推送脚本
    • 调用 register_for_auto_class()
    • 在本地测试脚本
    • 成功推送到 Hub
  • 清理(如果要替换)
    • 移除或归档原始实现
    • 更新导入
    • 更新文档

评论

支持 Markdown