Transformers 库是什么
自然语言处理简称 NLP ,是语言学习和机器学习交叉领域,专注于理解与人类语言相关的一切。常见的 NLP 任务列表如下:
- 对整个句子进行分类 : 获取评论的情绪,检查电子邮件是否为垃圾邮件,确定句子在语法上是否正确或两个句子在逻辑上是否相关。
- 对句子中的每个词进行分类 :识别句子的语法成分(名称,动词,形容词)或命名实体(人,地点,组织)
- 生成文本内容 :用于自动生成文本完成提示,用屏蔽词填充文本中的空白。
- 从文本中提取答案 :给定问题和上下文,根据上下文提供的信息提取问题的答案。
- 从输入的文本生成新的文本 :将文本翻译成另一种语言,总结文本。
Transformer 模型是用于解决上述 NLP 任务的机器学习模型。Hugging Face 的 Transformers 则是一个 python 开发库,提供了创建和使用 Transformer 模型的功能。
Transformers 库能做什么
Transformers 库中最基本的对象是 pipeline() 函数。它将模型与其必要的预处理和后处理步骤连接起来,通过输入文本,则可以输出最终答案。
python
from transformers import pipeline
classifier = pipeline("sentiment-analysis")
classifier("I've been waiting for a HuggingFace course my whole life.")
shell
[{'label': 'POSITIVE', 'score': 0.9598047137260437}]
pipeline 基本流程:选择一个特定的预训练模型,这里是针对英语情感分析进行了微调的模型。创建分类器对象,并下载模型,缓存在默认模型缓存目录。最后进行使用模型进行推理,输出答案。
推理过程分下面几个步骤:
- 将输入文本预处理为模型可以理解的格式
- 预处理结果传递给模型,进行推理。
- 将模型推理结果转换成人类可理解格式,进行输出。
目前可用的一些 pipeline:
- 特征提取
- 填充空缺: 'fill-mask'
- 命名实体识别: 'ner'
- 问答: 'question-answering'
- 情感分析
- 文本摘要: 'summarization'
- 文本生成: 'text-generation'
- 翻译: 'translation', 任务名称中提供语言对'_zh_to_en' 表示中文翻译成英文
- 零样本分类: 'text-classification', 'zero-shot-classification',
Transformers 库如何工作
Transformer 模型实现更好性能的一般策略是增加模型的大小以及预训练的数据量。大型模型,需要大量的数据,时间和计算资源。从头开始重复训练大模型存在不必要的浪费,另外个人比较难具有大型模型的训练资源。 Hugging Face 的 Transformers 库提供便捷的模型共享能力,共享经过预训练的模型权重,个人可以通过在预训练的权重的基础之上进行微调训练,满足定制化需求。
预训练:训练模型前的一个操作,随机初始化权重,在没有任何先验知识的情况下开始训练。这类训练需要大量的数据和计算资源,训练时间需要几周时间。
微调:在预训练模型的基础上,使用特定任务的数据集进行额外的训练,只需要较少的时间和计算资源,则可以获得目标任务的模型,将预训练模型获得的知识迁移到目标任务上,称做'迁移学习'。
Transformer 模型架构
架构是用于构建模型的一系列数学函数,其权重是这些函数参数。 同一组数学函数(架构)可以通过使用不同的参数(权重)来构建不同的模型
该模型主要由两个块组成:
- Encoder : 编码器接受输入并构建其表示(其特征)。这意味着对模型进行优化,以获得理解。
- Decoder : 解码器使用编码器的表示(特征)以及其他输入来生成目标序列。
为了突出一些不同类型的 Transformer 模型。大体上,它们可以分为三类:
- Encoder-only Models: BERT-like (也被称作自动编码Transformer模型),如句子分类和命名实体识别,阅读理解回答。"ALBERT, BERT, DistilBERT, ELECTRA, RoBERTa"
- Decoder-only Models: GPT-like (也被称作自回归Transformer模型),适用于需要理解输入的任务,适用于生成任务,如文本生成。"CTRL, GPT, GPT-2, TransformerXL"
- Encoder-decoder Models 或者 sequence-to-sequence Models: BART/T5-like (也被称作序列到序列的 Transformer模型),适用于需要根据输入进行生成的任务,如翻译和摘要,生成性问答。"BART, mBART, Marian, T5"
例如,BERT是一个架构,而 bert-base-cased
, 这是谷歌团队为BERT的第一个版本训练的一组权重参数,是一个参数。我们可以说"BERT模型"和"bert-base-cased
模型."
Transformers 库缓存
- 在Windows系统中,HuggingFace模型的默认保存位置是C:\Users\username.cache\huggingface\transformers
- 在 Linux 系统中,HuggingFace模型的默认保存位置是 ~/.cache/huggingface/transformers
可以更改shell环境变量来指定不同的缓存目录。例如,您可以更改默认的shell环境变量TRANSFORMERS_CACHE或者HF_HOME + transformers/
shell
# Windows powershell 打印 HF_HOME 环境变量值
PS E:\project\transformers
λ $env:HF_HOME
D:\Users\username\huggingface
shell
# Linux shell 打印 HF_HOME 环境变量值
echo $LF_HOME
权重已下载并缓存在缓存文件夹中(因此将来对from_pretrained()方法的调用将不会重新下载它们)默认为
Pipeline 流程
Pipeline 管道将三个步骤组合在一起:预处理、通过模型传递输入和后处理:
预处理
预处理使用 tokenizer(标记器) 将文本输入转换为模型能够理解的数字:
- 将输入文本拆分为单词,子单词或者符号,称为标记(token)
- 将每个标记(token) 映射到一个整数
- 添加可能对模型有用的其他输入
我们使用 AutoTokenizer 类及其 from_pretrained() 方法,读取模型中标记器相关联的数据,构造标记器。
python
from transformers import AutoTokenizer
checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
使用标记器构造,将文本输入转换为张量类型输出。
python
raw_inputs = [
"I've been waiting for a HuggingFace course my whole life.",
"I hate this so much!",
]
inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt")
print(inputs)
输出本身是一个包含两个元素的字典: input_ids 和 attention_mask 。input_ids 包含两行整数(每个句子一行),它们是每个句子中标记的唯一标记(token)。
shell
{
'input_ids': tensor([
[ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102],
[ 101, 1045, 5223, 2023, 2061, 2172, 999, 102, 0, 0, 0, 0, 0, 0, 0, 0]
]),
'attention_mask': tensor([
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
])
}
模型推理
Transformers 库提供了一个 AutoModel 类,该类具有 from_pretrained() 方法,
python
from transformers import AutoModel
checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModel.from_pretrained(checkpoint)
隐藏状态 AutoModel 只包含基本转换器模块:给定一些输入,它输出我们将调用的内容隐藏状态(hidden states) ,亦称特征(features) 。对于每个模型输入,我们将检索一个高维向量,表示Transformer模型对该输入的上下文理解。
Transformers模块的矢量输出通常较大。它通常有三个维度:
- Batch size: 一次处理的序列数(在我们的示例中为2)。
- Sequence length: 序列的数值表示的长度(在我们的示例中为16)。
- Hidden size: 每个模型输入的向量维度。
由于最后一个值,它被称为"高维"。
python
outputs = model(**inputs)
print(outputs.last_hidden_state.shape)
shell
torch.Size([2, 16, 768])
模型头 :这些隐藏状态通常还是模型另一部分(称为模型头(head) )的输入,可以使用相同的体系结构执行不同的任务,但这些任务中的每个任务都有一个与之关联的不同模型头。
它的全名是Adaptation Heads,也被简单地称为模型的头部,在不同的任务上有不同的形式: 语言模型Heads,问题回答Heads,序列分类Heads..。
在此图中,模型由其嵌入层和后续层表示。嵌入层将标记化输入中的每个输入ID转换为表示关联标记(token)的向量。后续层使用注意机制操纵这些向量,以生成句子的最终表示。
Transformers 库针对不同处理任务设计了特定的体系结构,提供不同的模型头:
*Model
(retrieve the hidden states)*ForCausalLM
*ForMaskedLM
*ForMultipleChoice
*ForQuestionAnswering
*ForSequenceClassification
*ForTokenClassification
- 以及其他
例如分类任务,使用带有有序列分类头的模型 AutoModelForSequenceClassification
python
from transformers import AutoModelForSequenceClassification
checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
outputs = model(**inputs)
print(outputs.logits.shape)
因为我们只有两个句子和两个标签,所以我们从模型中得到的结果是2 x 2的形状。
shell
torch.Size([2, 2])
后处理
logits ,即模型最后一层输出的原始非标准化分数。要转换为概率,它们需要经过SoftMax层(所有Transformers模型输出logits,因为用于训练的损耗函数通常会将最后的激活函数(如SoftMax)与实际损耗函数(如交叉熵)融合):
python
import torch
predictions = torch.nn.functional.softmax(outputs.logits, dim=-1)
print(predictions)
shell
tensor([[4.0195e-02, 9.5980e-01],
[9.9946e-01, 5.4418e-04]], grad_fn=<SoftmaxBackward>)
模型预测第一句为[0.0402, 0.9598]
,第二句为[0.9995, 0.0005]
。这些是可识别的概率分数。
为了获得每个位置对应的标签,我们可以检查模型配置的id2label
属性
python
model.config.id2label
shell
{0: 'NEGATIVE', 1: 'POSITIVE'}
Model 推理
创建转化器
使用 BertConfig 配置加载模型 BertModel,使用随机值进行初始化,此时输出也是随机,需要对其进行训练。 其中的一些属性:hiddensize属性定义了hidden状态向量的大小,num_hidden_layers定义了Transformer模型的层数。
python
from transformers import BertConfig, BertModel
# Building the config
config = BertConfig()
# Building the model from the config
model = BertModel(config)
shell
$ python transformers/bert_learn.py
BertConfig {
"attention_probs_dropout_prob": 0.1,
"classifier_dropout": null,
"hidden_act": "gelu",
"hidden_dropout_prob": 0.1,
"hidden_size": 768,
"initializer_range": 0.02,
"intermediate_size": 3072,
"layer_norm_eps": 1e-12,
"max_position_embeddings": 512,
"model_type": "bert",
"num_attention_heads": 12,
"num_hidden_layers": 12,
"pad_token_id": 0,
"position_embedding_type": "absolute",
"transformers_version": "4.29.1",
"type_vocab_size": 2,
"use_cache": true,
"vocab_size": 30522
}
使用 Transformers 提供的 BertModel.from_pretrained() 方法加载 预训练模型,可以直接用于对训练过的任务进行推理,也可以对新任务进行微调,避免从头开始训练。
python
from transformers import BertModel
model = BertModel.from_pretrained("bert-base-cased")
模型保存方法 : save_pretrained() ,会将两个文件保存在磁盘:config.json pytorch_model.bin
python
model.save_pretrained("directory_on_my_computer")
- config.json 文件,您将识别构建模型体系结构所需的属性。该文件还包含一些元数据
- pytorch_model.bin 文件就是众所周知的state dictionary; 它包含模型的所有权重。这两个文件齐头并进;配置是了解模型体系结构所必需的,而模型权重是模型的参数。
标记器
标记器(tokenizer) 将文本转换为模型可以处理的数字数据。 加载和保存标记器(tokenizer)就像使用模型一样简单。实际上,它基于相同的两种方法: from_pretrained()
和 save_pretrained()
。这些方法将加载或保存标记器(tokenizer)使用的算法(有点像建筑学(architecture) 的模型)以及它的词汇(有点像权重(weights) 模型)。
BertTokenizer
:加载使用与 BERT 模型相同的权重训练的 BERT 标记器(tokenizer)
AutoModel
,AutoTokenizer
类将根据模型权重名称在库中获取正确的标记器(tokenizer)类,并且可以直接与任何模型权重一起使用:
ini
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
我们现在可以使用标记器(tokenizer),如上一节所示:
提示标记器从不同的框架返回张量------
"pt"
返回Py Torch张量,"tf"
返回TensorFlow张量,"np"
返回NumPy数组:
ini
# 一次处理一个序列
sequence = "I've been waiting for a HuggingFace course my whole life."
model_inputs = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt")
print(model_inputs)
# 一次处理多个序列, API 无任何变化
sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"]
model_inputs = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt")
print(model_inputs)
lua
$ python transformers/bert_learn.py
E:\model\bert\bert-base-cased
{'input_ids': tensor([[ 101, 146, 112, 1396, 1151, 2613, 1111, 170, 20164, 10932,
2271, 7954, 1736, 1139, 2006, 1297, 119, 102]]), 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])}
{'input_ids': tensor([[ 101, 146, 112, 1396, 1151, 2613, 1111, 170, 20164, 10932,
2271, 7954, 1736, 1139, 2006, 1297, 119, 102],
[ 101, 1573, 1138, 146, 106, 102, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0]]), 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])}
保存标记器(tokenizer)与保存模型相同:
arduino
tokenizer.save_pretrained("directory_on_my_computer")
传入模型预测
python
tokenizer = BertTokenizer.from_pretrained(path)
model = BertForSequenceClassification.from_pretrained(path)
sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"]
tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt")
output = model(**tokens)
print(output)
shell
SequenceClassifierOutput(loss=None, logits=tensor([[-0.1947, 0.2765],
[-0.0679, 0.2324]], grad_fn=<AddmmBackward0>), hidden_states=None, attentions=None)
下面介绍一些标记器对象在应用于文本时使用的所有单独步骤。
输入文本 ID 化
我们将更多地谈论token_type_ids
,稍后我们将解释 attention_mask
键。首先,让我们看看 input_ids
如何生成。为此,我们需要查看标记器(tokenizer)的中间方法:
- tokenize() 标记化
- token 转换到 ID
scss
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
# 标记化过程由标记器(tokenizer)的`tokenize()` 方法实现:
sequence = "Using a Transformer network is simple"
tokens = tokenizer.tokenize(sequence)
print(tokens)
# 输入 ID 的转换由标记器(tokenizer)的`convert_tokens_to_ids()`方法实现:这些输出一旦转换为适当的框架张量,就可以用作模型的输入
ids = tokenizer.convert_tokens_to_ids(tokens)
print(ids)
csharp
$ python transformers/bert_learn.py
E:\model\bert\bert-base-cased
['Using', 'a', 'Trans', '##former', 'network', 'is', 'simple']
[7993, 170, 13809, 23763, 2443, 1110, 3014]
这个标记器(tokenizer)是一个子词标记器(tokenizer):它对词进行拆分,直到获得可以用其词汇表表示的标记(token)。transformer
就是这种情况,它分为两个标记:transform
和 ##er
。
ID 解码回字符串
解码 正好相反将 ID 转换回字符串,从词汇索引中,我们想要得到一个字符串。这可以通过 decode()
方法实现,如下:
yaml
decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014])
print(decoded_string)
vbnet
'Using a Transformer network is simple'
请注意, decode
方法不仅将索引转换回标记(token),还将属于相同单词的标记(token)组合在一起以生成可读的句子。当我们使用预测新文本的模型(根据提示生成的文本,或序列到序列问题(如翻译或摘要))时,这种行为将非常有用。
模型需要批量输入
Transformers模型默认情况下需要多个句子,将输入ID列表转换为张量时增加一个维度:
python
sequence = "I've been waiting for a HuggingFace course my whole life."
# 加载模型
model = BertForSequenceClassification.from_pretrained(path)
autoTokenizer = AutoTokenizer.from_pretrained(path)
# 标记化
autoTokens = autoTokenizer.tokenize(sequence)
# ID 化
ids = autoTokenizer.convert_tokens_to_ids(autoTokens)
# 张量化,增加一个维度,变成批量输入
input_ids = torch.tensor([ids])
print(input_ids)
# 推理
output = model(input_ids)
print(output)
填充、截断和注意掩码
不过有个问题,当试图将两个(或更多)句子组合在一起时,它们的长度可能不同,此时需要进行填充,使张量具有矩形。
避免填充数据影响推理,又需要 attention masks ,与输入 ID 张量 shape 相同的张量。 1 表示应注意相应的标记,0 表示不应注意相应的标记(即,模型的注意力层应忽略它们)
预训练
数据处理
可以在代理的 rules中将huggingface.co设为走代理,而将cdn-lfs.huggingface.co设置为直连,这样模型数据仍然走直连的方式不消耗流量。
- 数据加载
huggingface 不只包含模型, 还有许多不同语言的数据集. Datasets 库则提供了非常便捷的方式可以从 huggingface 上下载和缓存数据集, 具体则是通过 load_dataset() 方法接收传入 path 参数下载对应数据集, path 支持 huggingface 中的数据集名称和本地文件路径. 默认会将数据集缓存在缓存目录中的 huggingface/datasets 中.
python
# 下载数据 MRPC 数据
def downloadMRPCData():
# raw_datasets = load_dataset("glue", "mrpc")
raw_datasets = load_dataset( "E:\\data\\huggingface\\datasets\\glue", "mrpc")
print(raw_datasets)
raw_train_dateset = raw_datasets['train']
print(raw_train_dateset[0])
print(raw_train_dateset.features)
- 数据预处理
数据集是文本数据, 为了让模型理解, 需要将文本转换成 ID 数据. 使用 tokenizer 标记器, 将文本数据转换成 input_ids, token_type_ids, attention_mask 数据. token_type_ids 类型标记的作用是告诉模型输入的是第几句, 单句则全是 0, 在批量转换时, 不同句值不同.
请注意,如果选择其他的检查点,则不一定具有类型标记ID(token_type_ids) (例如,如果使用DistilBERT模型,就不会返回它们)。只有当它在预训练期间使用过这一层,模型在构建时依赖它们,才会返回它们。一般来说,你不需要担心是否有类型标记ID(token_type_ids) 。在您的标输入中:只要您对标记器和模型使用相同的检查点,一切都会很好,因为标记器知道向其模型提供什么。
python
# 将测试数据文本标记化, 转换成模型理解的 ID 张量形式
def tokenizedMRPCData(checkpoint):
raw_datasets = load_dataset( "E:\\data\\huggingface\\datasets\\glue", "mrpc")
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
# 类型标记ID(token_type_ids)。在这个例子中,类型标记ID(token_type_ids)的作用就是告诉模型输入的哪一部分是第一句,哪一部分是第二句。
# 一般来说,你不需要担心是否有类型标记ID(token_type_ids)。在您的标输入中:只要您对标记器和模型使用相同的检查点,一切都会很好,因为标记器知道向其模型提供什么。
intputs = tokenizer(raw_datasets["train"][0]["sentence1"], raw_datasets["train"][0]["sentence2"])
print(intputs)
预处理优化
标记器返回的是字典(字典的键是输入词id(input_ids) , 注意力遮罩(attention_mask) 和 类型标记ID(token_type_ids) ,字典的值是键所对应值的列表). 在转换过程中需要有足够的内存来存储整个数据集时才不会报错
为了将数据保存为数据集,我们将使用Dataset.map()方法,如果我们需要做更多的预处理而不仅仅是标记化,那么这也给了我们一些额外的自定义的方法。这个方法的工作原理是在数据集的每个元素上应用一个函数,因此让我们定义一个标记输入的函数, 此函数的输入是一个字典(与数据集的项类似),并返回一个包含输入词id(input_ids) , 注意力遮罩(attention_mask) 和 类型标记ID(token_type_ids) 键的新字典。
python
def tokenize_function(example):
return tokenizer(example["sentence1"], example["sentence2"], truncation=True)
在所有数据集上同时应用标记函数。我们在调用map 时使用了batch =True,这样函数就可以同时应用到数据集的多个元素上,而不是分别应用到每个元素上
python
tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
tokenized_datasets
Datasets库应用这种处理的方式是向数据集添加新的字段,每个字段对应预处理函数返回的字典中的每个键.
注意,如果预处理函数map() 为现有键返回一个新值,那将会修改原有键的值。
- 动态填充
负责在批处理中将数据整理为一个batch的函数称为collate函数 。它是你可以在构建DataLoader时传递的一个参数,默认是一个函数,它将把你的数据集转换为PyTorch张量,并将它们拼接起来(如果你的元素是列表、元组或字典,则会使用递归)。
因为输入句子大小并不相同, 需要在每个batch之后上进行填充, 解决句子长度统一的问题,我们必须定义一个collate函数,该函数会将每个batch句子填充到正确的长度.
transformer库通过DataCollatorWithPadding为我们提供了这样一个函数。当你实例化它时,需要一个标记器(用来知道使用哪个词来填充,以及模型期望填充在左边还是右边),并将做你需要的一切:
python
from transformers import DataCollatorWithPadding
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
数据处理:
shell
(common_env) PS E:\project> python .\transformers\pretrain_learn.py
E:\model\llm\bert\bert-base-cased
Found cached dataset glue (D:/Users/leoli/huggingface/datasets/glue/mrpc/1.0.0/dacbe3125aa31d7f70367a07a8a9e72a5a0bfeb5fc42e75c9db75b96da6053ad)
100%|███████████████████████████████████████████████████████████████████████████████████| 3/3 [00:00<00:00, 148.60it/s]
Map: 0%| | 0/3668 [00:00<?, ? examples/s]Asking to truncate to max_length but no maximum length is provided and the model has no predefined maximum length. Default to no truncation.
DatasetDict({
train: Dataset({
features: ['sentence1', 'sentence2', 'label', 'idx', 'input_ids', 'token_type_ids', 'attention_mask'],
num_rows: 3668
})
validation: Dataset({
features: ['sentence1', 'sentence2', 'label', 'idx', 'input_ids', 'token_type_ids', 'attention_mask'],
num_rows: 408
})
test: Dataset({
features: ['sentence1', 'sentence2', 'label', 'idx', 'input_ids', 'token_type_ids', 'attention_mask'],
num_rows: 1725
})
})
[52, 59, 47, 69, 60, 50, 66, 32]
You're using a BertTokenizerFast tokenizer. Please note that with a fast tokenizer, using the `__call__` method is faster than using a method to encode the text followed by a call to the `pad` method to get a padded encoding.
{'input_ids': torch.Size([8, 69]), 'token_type_ids': torch.Size([8, 69]), 'attention_mask': torch.Size([8, 69]), 'labels': torch.Size([8])}
Trainer
Transformers提供了一个 Trainer 类来帮助您在自己的数据集上微调任何预训练模型。只需要几个参数来创建 Trainer
- training_args : 定义一个 TrainingArguments 类,它将包含 Trainer用于训练和评估的所有超参数.
- model : 定义一个模型, 使用 AutoModelForSequenceClassification 类进行举例.
- train_dataset/eval_dataset: 加载数据集, 配置训练预验证数据集.
- data_collator : 使用 DataCollatorWithPadding 定义动态填充, 设置 data_collator 参数
- tokenizer: 标记器
- compute_metrics : 定义一个评估函数,该函数必须采用 EvalPrediction 对象(带有 predictions 和 label_ids 字段的参数元组)并将返回一个字符串到浮点数的字典(字符串是返回的指标的名称,而浮点数是它们的值)
- train(): trainer.train() 执行训练
定义模型
在实例化此预训练模型后会收到警告。这是因为 BERT 没有在句子对分类方面进行过预训练,所以预训练模型的头部已经被丢弃,而是添加了一个适合句子序列分类的新头部。警告表明一些权重没有使用(对应于丢弃的预训练头的那些),而其他一些权重被随机初始化(新头的那些).
shell
(common_env) λ python transformers\trainer_learn.py
E:\model\llm\bert\bert-base-cased
Some weights of the model checkpoint at E:\model\llm\bert\bert-base-cased were not used when initializing BertForSequenceClassification: ['cls
.predictions.transform.dense.bias', 'cls.predictions.transform.LayerNorm.weight', 'cls.predictions.transform.LayerNorm.bias', 'cls.seq_relatio
nship.bias', 'cls.predictions.bias', 'cls.seq_relationship.weight', 'cls.predictions.transform.dense.weight']
- This IS expected if you are initializing BertForSequenceClassification from the checkpoint of a model trained on another task or with anothe
r architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).
- This IS NOT expected if you are initializing BertForSequenceClassification from the checkpoint of a model that you expect to be exactly iden
tical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).
Some weights of BertForSequenceClassification were not initialized from the model checkpoint at E:\model\llm\bert\bert-base-cased and are newl
y initialized: ['classifier.weight', 'classifier.bias']
评估函数
- Trainer.predict() 输出结果是具有三个字段的命名元组: predictions , label_ids , 和 metrics .这 metrics 字段将只包含传递的数据集的loss,以及一些运行时间(预测所需的总时间和平均时间)。如果我们定义了自己的 compute_metrics() 函数并将其传递给 Trainer ,该字段还将包含compute_metrics() 的结果。
- predictions 是一个形状为 408 x 2 的二维数组(408 是我们使用的数据集中元素的数量)。这些是我们传递给predict() 的数据集的每个元素的结果(logits), 要将我们的预测与真正的标签进行比较,我们需要在第二个轴上取最大值的索引:
- 度量计算: 将使用 Evaluate 库中的指标, 像加载数据集一样轻松加载与 MRPC 数据集关联的指标, 返回的对象有一个 compute() 方法我们可以用来进行度量计算的方法
python
import evaluate
def compute_metrics(eval_preds):
metric = evaluate.load("glue", "mrpc")
logits, labels = eval_preds
predictions = np.argmax(logits, axis=-1)
return metric.compute(predictions=predictions, references=labels)
比较有无评估函数
- 无评估函数
没有为Trainer 提供一个compute_metrics() 函数来直接计算模型的好坏(否则评估将只输出loss,这不是一个非常直观的数字)。
shell
You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.
{'loss': 0.4844, 'learning_rate': 3.184458968772695e-05, 'epoch': 1.09}
{'loss': 0.2453, 'learning_rate': 1.3689179375453886e-05, 'epoch': 2.18}
{'train_runtime': 171.0132, 'train_samples_per_second': 64.346, 'train_steps_per_second': 8.052, 'train_loss': 0.28906568306983166, 'epoch': 3
.0}
- 有评估函数
compute_metric() 函数来较为直观地评估模型的好坏
shell
You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.
{'eval_loss': 0.540508508682251, 'eval_accuracy': 0.7181372549019608, 'eval_f1': 0.8205928237129485, 'eval_runtime': 1.2453, 'eval_samples_per
_second': 327.624, 'eval_steps_per_second': 40.953, 'epoch': 1.0}
{'loss': 0.6097, 'learning_rate': 3.184458968772695e-05, 'epoch': 1.09}
{'eval_loss': 0.4704691469669342, 'eval_accuracy': 0.8088235294117647, 'eval_f1': 0.875, 'eval_runtime': 1.203, 'eval_samples_per_second': 339
.166, 'eval_steps_per_second': 42.396, 'epoch': 2.0}
{'loss': 0.376, 'learning_rate': 1.3689179375453886e-05, 'epoch': 2.18}
{'eval_loss': 0.7883664965629578, 'eval_accuracy': 0.8382352941176471, 'eval_f1': 0.8903654485049834, 'eval_runtime': 1.2656, 'eval_samples_pe
r_second': 322.364, 'eval_steps_per_second': 40.296, 'epoch': 3.0}
{'train_runtime': 176.6815, 'train_samples_per_second': 62.282, 'train_steps_per_second': 7.794, 'train_loss': 0.40584576952344886, 'epoch': 3
.0}
安装
使用 pip 安装下面的相关库
shell
pip install transformers datasets evaluate peft accelerate gradio optimum sentencepiece
shell
This tokenizer cannot be instantiated. Please make sure you have `sentencepiece` installed in order to use this tokenizer.
shell
D:\Users\leoli\miniconda3\envs\common_env\lib\site-packages\transformers\models\marian\tokenization_marian.py:194: UserWarning: Recommended: pip install sacremoses.
warnings.warn("Recommended: pip install sacremoses.")