如何转换PyTorch nn.模块化为HuggingFace预训练模型对象



在Pytorch类中给定一个简单的神经网络:

import torch.nn as nn
net = nn.Sequential(
nn.Linear(3, 4),
nn.Sigmoid(),
nn.Linear(4, 1),
nn.Sigmoid()
).to(device)

如何将其转换为Huggingface PreTrainedModel对象

目标是将Pytorchnn.Module对象从nn.Sequential转换为HuggingfacePreTrainedModel对象,然后运行以下操作:

import torch.nn as nn
from transformers.modeling_utils import PreTrainedModel

net = nn.Sequential(
nn.Linear(3, 4),
nn.Sigmoid(),
nn.Linear(4, 1),
nn.Sigmoid()
).to(device)
# Do something to convert the Pytorch nn.Module to the PreTrainedModel object.
shiny_model = do_some_magic(net, some_args, some_kwargs)
# Save the shiny model that is a `PreTrainedModel` object.
shiny_model.save_pretrained("shiny-model")
PreTrainedModel.from_pretrained("shiny-model")

而且似乎要将任何本地Pytorch模型构建/转换为Huggingface模型,需要一些配置https://huggingface.co/docs/transformers/main_classes/configuration

有许多如何训练模型的方法;"从头开始";,例如

  • [使用BertLMHeadModel,而不是那个划痕]https://www.kaggle.com/code/mojammel/train-model-from-scratch-with-huggingface/notebook(这也是从伯特微调,而不是从头开始(

  • [不是真的刮伤,使用roberta作为模板]https://huggingface.co/blog/how-to-train(这是roberta的微调,不是真正的从头开始训练(

  • [有点使用一些配置模板]https://www.thepythoncode.com/article/pretraining-bert-huggingface-transformers-in-python(这有点从头开始,但使用BERT中的模板来生成配置,如果我们想改变模型的工作方式,配置应该是什么样子呢?(

  • [Kinda定义了一个模板,但使用RobertaForMaskedLM]https://skimai.com/roberta-language-model-for-spanish/(这看起来有点定义了一个模板,但将其限制为RobertaForMaskedLM模板(

部分问题:

  • 如果我们有一个像上面代码片段中那样简单得多的Pytorch模型,如何在Huggingface中从头开始创建预训练模型?

  • 如何创建Huggingface从原生Pytorch nn进行转换所需的预训练模型配置。模块工作?

您将需要定义自定义配置和自定义模型类。在这些类中定义属性model_typeconfig_class是很重要的:

import torch.nn as nn
from transformers import PreTrainedModel, PretrainedConfig
from transformers import AutoModel, AutoConfig
class MyConfig(PretrainedConfig):
model_type = 'mymodel'
def __init__(self, important_param=42, **kwargs):
super().__init__(**kwargs)
self.important_param = important_param
class MyModel(PreTrainedModel):
config_class = MyConfig
def __init__(self, config):
super().__init__(config)
self.config = config
self.model = nn.Sequential(
nn.Linear(3, self.config.important_param),
nn.Sigmoid(),
nn.Linear(self.config.important_param, 1),
nn.Sigmoid()
)
def forward(self, input):
return self.model(input) 

现在,您可以创建(显然还可以训练一个新模型(,保存并在本地加载您的模型

config = MyConfig(4)
model = MyModel(config)
model.save_pretrained('./my_model_dir')
new_model = MyModel.from_pretrained('./my_model_dir')
new_model

如果你想使用AutoModel,你必须注册你的课程:

AutoConfig.register("mymodel", MyConfig)
AutoModel.register(MyConfig, MyModel)
new_model = AutoModel.from_pretrained('./my_model_dir')
new_model

一种方法是将模型放在从PreTrainedModel继承的类中,例如,它可以是预训练的resnet34、timm模型或您的"net";模型我建议查看文档以了解有关配置的更多详细信息,我将使用链接中的一个示例。https://huggingface.co/docs/transformers/custom_models#sharing-定制型号

配置(注意:您可以添加不同的配置,例如版本,您可以稍后访问config.json。(

from transformers import PretrainedConfig
from typing import List
class ModelConfig(PretrainedConfig):
model_type = "mymodel"
def __init__(
self,
version = 1,
layers: List[int] = [3, 4, 6, 3],
num_classes: int = 1000,
input_channels: int = 3,
stem_type: str = "",
**kwargs,
):
if stem_type not in ["", "deep", "deep-tiered"]:
raise ValueError(f"`stem_type` must be '', 'deep' or 'deep-tiered', got {block}.")
self.version = version
self.layers = layers
self.num_classes = num_classes
self.input_channels = input_channels
self.stem_type = stem_type
super().__init__(**kwargs)

正如我所说,你的网络模型可能是resnet34。

from transformers import PreTrainedModel
from torch import nn
net = nn.Sequential(
nn.Linear(3, 4),
nn.Sigmoid(),
nn.Linear(4, 1),
nn.Sigmoid()
).to('cuda')

class MyModel(PreTrainedModel):
config_class = ModelConfig
def __init__(self, config):
super().__init__(config)
self.model = net

def forward(self, tensor):
return self.model(tensor)

测试型号

config = ModelConfig()
model = MyModel(config)
dummy_input = torch.randn(1, 3).to('cuda')
with torch.no_grad():
output = model(dummy_input)
print(output.shape)

推送至hugginface hub(注意:您需要使用代币登录,您可以推送多次以更新模型(

model.push_to_hub("mymodel-test")

下载模型(注意:您使用的是MyModel类,如果您想创建像..bert.modeling_bert.BertModel这样的模型,我认为您需要使用lib结构。(

my_model = MyModel.from_pretrained("User/mymodel-test")

最新更新