Huggingface使用


前言

提示:本文记录在学习Huggingface过程中的一些新的,权做来日备忘

本文主要来自Huggingface NLP学习课程,若想要更进一步,欢迎前往Huggingface官网进行学习


一、Huggingface创建模型

使用Huggingface加载模型非常简单轻松,只需要如下几个步骤:

  1. 导入transformers包
    pip install datasets evaluate transformers[sentencepiece]
    
  2. 加载模型
from transformers import BertModel
model = BertModel.from_pretrained("bert-base-cased")

更一般的我们可以使用AutoModel类,可以自动检查导入的预训练好的模型,只要和BERT体系结构兼容。在这里面"bert-base-cased"被称作为checkpoints,当然,还有更多其他checkpoints,其他的bert预训练模型可以在这里找,里面包含大量的其他人预训练好的模型。

二、标记(Tokenizer)处理

刚刚,我们已经引入了模型,但是模型只能处理数字,因此标记器(Tokenizer)需要将我们的文本输入转换为数字数据。在 NLP 任务中,通常处理的数据是原始文本。将原始文本转化为张量数据可以使用如下步骤:

  1. 导入Tokenizer进行,分解句子
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

sequence = "Using a Transformer network is simple"
tokens = tokenizer.tokenize(sequence)

print(tokens)
#['Using', 'a', 'transform', '##er', 'network', 'is', 'simple']

这里导入Tokenizer和上面的导入模型步骤类似,接下来的第一步是将文本拆分为单词(或单词的一部分、标点符号等),通常称为标记(token)。可以有多个规则可以拆分(如根据单词、字符),为了保证这种拆分规则编码后的数据可以被我们的模型使用,我们需要使用模型名称相同的checkpoints来实例化标记器(tokenizer),以确保我们使用模型预训练时使用的相同规则。

  1. 从词符(token)到输入ID
ids = tokenizer.convert_tokens_to_ids(tokens)
print(ids)
#[7993, 170, 11303, 1200, 2443, 1110, 3014]

如果需要解码,则和编码的过程一致

decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014])
print(decoded_string)
#'Using a Transformer network is simple'

三、处理多个序列

先来看一个例子

import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"#加载一个checkpoints,不用管它的具体任务是什么
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)

input_ids = torch.tensor([ids])#这里注意,在ids外又套了一层列表,这是因为Transformers模型默认情况下需要多个句子,即二维张量
print("Input IDs:", input_ids)

output = model(input_ids)
print("Logits:", output.logits)
#Input IDs: [[ 1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172,  2607, 2026,  2878,  2166,  1012]]
#Logits: [[-2.7276,  2.8789]]

padding_id 和 attention_mask

批处理允许模型在输入多个句子时工作。不过,还有第二个问题。当你试图将两个(或更多)句子组合在一起时,它们的长度可能不同。如果你以前使用过张量,那么你知道它们必须是矩形,因此无法将输入ID列表直接转换为张量。为了解决这个问题,我们通常填充输入。
以下列表不能转换为张量:

batched_ids = [
    [200, 200, 200],
    [200, 200]
]

为了解决这个问题,我们将使用填充使张量具有矩形。Padding通过在值较少的句子中添加一个名为Padding token的特殊单词来确保我们所有的句子长度相同。例如,如果你有10个包含10个单词的句子和1个包含20个单词的句子,填充将确保所有句子都包含20个单词。在我们的示例中,生成的张量如下所示:

padding_id = 100

batched_ids = [
    [200, 200, 200],
    [200, 200, padding_id],
]

可以在tokenizer.pad_token_id中找到padding_id. 让我们使用它,将我们的两句话分别发送到模型中,并分批发送到一起:

model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence1_ids = [[200, 200, 200]]
sequence2_ids = [[200, 200]]
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

print(model(torch.tensor(sequence1_ids)).logits)
print(model(torch.tensor(sequence2_ids)).logits)
print(model(torch.tensor(batched_ids)).logits)

#tensor([[ 1.5694, -1.3895]], grad_fn=<AddmmBackward>)
#tensor([[ 0.5803, -0.4125]], grad_fn=<AddmmBackward>)
#tensor([[ 1.5694, -1.3895],
#        [ 1.3373, -1.2163]], grad_fn=<AddmmBackward>)

我们批处理预测中的logits有点问题:第二行应该与第二句的logits相同,但我们得到了完全不同的值!
这是因为Transformer将填充的数值当做真实的值来进行计算,为了在通过模型传递一批应用了相同句子和填充的句子时获得相同的结果,我们需要告诉这些注意层忽略填充标记。这是通过使用 attention mask来实现的

batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]
attention_mask = [
    [1, 1, 1],
    [1, 1, 0],
]
outputs = model(torch.tensor(batched_ids), attention_mask=torch.tensor(attention_mask))
print(outputs.logits)
#tensor([[ 1.5694, -1.3895],
#        [ 0.5803, -0.4125]], grad_fn=<AddmmBackward>)

对于Transformers模型,我们可以通过模型的序列长度是有限的。大多数模型处理多达512或1024个token的序列,当要求处理更长的序列时,模型会崩溃。这是需要我们使用自定义max_sequence_length参数

sequence = sequence[:max_sequence_length]

使用tokenizer

tokenizer可以忽略上面讨论的那些过程,直接对文本进行编码

from transformers import AutoTokenizer

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."#也可以是一个sequence list,调用方式不变

model_inputs = tokenizer(sequence)

在刚刚提到的多个句子序列的长度不一致问题,tokenizer可以自动解决

# Will pad the sequences up to the maximum sequence length
model_inputs = tokenizer(sequences, padding="longest")

# Will pad the sequences up to the model max length (512 for BERT or DistilBERT)
model_inputs = tokenizer(sequences, padding="max_length")

# Will pad the sequences up to the specified max length
model_inputs = tokenizer(sequences, padding="max_length", max_length=8)

它还可以截断序列:

sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"]

# Will truncate the sequences that are longer than the model max length (512 for BERT or DistilBERT)
model_inputs = tokenizer(sequences, truncation=True)

# Will truncate the sequences that are longer than the specified max length
model_inputs = tokenizer(sequences, max_length=8, truncation=True)

标记器对象可以处理到特定框架张量的转换,然后可以直接发送到模型。例如,在下面的代码示例中,我们提示标记器从不同的框架返回张量——"pt"返回Py Torch张量,"tf"返回TensorFlow张量,"np"返回NumPy数组:

sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"]

# Returns PyTorch tensors
model_inputs = tokenizer(sequences, padding=True, return_tensors="pt")

# Returns TensorFlow tensors
model_inputs = tokenizer(sequences, padding=True, return_tensors="tf")

# Returns NumPy arrays
model_inputs = tokenizer(sequences, padding=True, return_tensors="np")

标记器在开头添加了特殊单词[CLS],在结尾添加了特殊单词[SEP]。这是因为模型是用这些数据预训练的(详情请查看bert原论文是如何训练的),所以为了得到相同的推理结果,我们还需要添加它们。请注意,有些模型不添加特殊单词,或者添加不同的单词;模型也可能只在开头或结尾添加这些特殊单词。


总结

以上huggingface的基本使用方法,本文仅仅简单介绍了huggingface的使用,而huggingface提供了大量预训练模型,大家可以自行查看。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值