百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

Transformers 快速入门

ztj100 2025-04-26 22:46 10 浏览 0 评论

理念

Transformers是一个为NLP的研究人员寻求使用/研究/扩展大型Transformers模型的库。

该库的设计有两个强烈的目标:

  • 尽可能简单和快速使用: 我们尽可能限制了要学习的面向对象抽象的类的数量,实际上几乎没有抽象,每个模型只需要使用三个标准类:配置、模型和tokenizer, 所有这些类都可以通过使用公共的from_pretrained()实例化方法从预训练实例以简单统一的方式初始化,该方法将负责从库中下载,缓存和加载相关类提供的预训练模型或你自己保存的模型。 因此,这个库不是构建神经网络模块的工具箱。如果您想扩展/构建这个库,只需使用常规的Python/PyTorch模块,并从这个库的基类继承,以重用诸如模型加载/保存等功能。
  • 提供最先进的模型与性能尽可能接近的原始模型: 我们为每个架构提供了至少一个例子,该例子再现了上述架构的官方作者提供的结果 代码通常尽可能地接近原始代码,这意味着一些PyTorch代码可能不那么pytorch化,因为这是转换TensorFlow代码后的结果。

其他几个目标:

  • 尽可能一致地暴露模型的内部: 我们使用一个API来访问所有的隐藏状态和注意力权重, 对tokenizer和基本模型的API进行了标准化,以方便在模型之间进行切换。
  • 结合一个主观选择的有前途的工具微调/调查这些模型: 向词汇表和嵌入项添加新标记以进行微调的简单/一致的方法, 简单的方法面具和修剪变压器头。

主要概念

该库是建立在三个类型的类为每个模型:

  • model类是目前在库中提供的8个模型架构的PyTorch模型(torch.nn.Modules),例如BertModel
  • configuration类,它存储构建模型所需的所有参数,例如BertConfig。您不必总是自己实例化这些配置,特别是如果您使用的是未经任何修改的预训练的模型,创建模型将自动负责实例化配置(它是模型的一部分)
  • tokenizer类,它存储每个模型的词汇表,并在要输送到模型的词汇嵌入索引列表中提供用于编码/解码字符串的方法,例如BertTokenizer

所有这些类都可以从预训练模型来实例化,并使用两种方法在本地保存:

  • from_pretraining()允许您从一个预训练版本实例化一个模型/配置/tokenizer,这个预训练版本可以由库本身提供(目前这里列出了27个模型),也可以由用户在本地(或服务器上)存储,
  • save_pretraining()允许您在本地保存模型/配置/tokenizer,以便可以使用from_pretraining()重新加载它。

我们将通过一些简单的快速启动示例来完成这个快速启动之旅,看看如何实例化和使用这些类。其余的文件分为两部分:

  • 主要的类详细介绍了三种主要类(配置、模型、tokenizer)的公共功能/方法/属性,以及一些作为训练工具提供的优化类,
  • 包引用部分详细描述了每个模型体系结构的每个类的所有变体,特别是调用它们时它们期望的输入和输出。

快速入门:使用

这里有两个例子展示了一些Bert和GPT2类以及预训练模型。

有关每个模型类的示例,请参阅完整的API参考。

BERT示例

让我们首先使用BertTokenizer从文本字符串准备一个标记化的输入(要输入给BERT的标记嵌入索引列表)

import torch
from transformers import BertTokenizer, BertModel, BertForMaskedLM

# 可选:如果您想了解发生的信息,请按以下步骤logger
import logging
logging.basicConfig(level=logging.INFO)

# 加载预训练的模型标记器(词汇表)
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')

# 标记输入
text = "[CLS] Who was Jim Henson ? [SEP] Jim Henson was a puppeteer [SEP]"
tokenized_text = tokenizer.tokenize(text)

# 用“BertForMaskedLM”掩盖我们试图预测的标记`
masked_index = 8
tokenized_text[masked_index] = '[MASK]'
assert tokenized_text == ['[CLS]', 'who', 'was', 'jim', 'henson', '?', '[SEP]', 'jim', '[MASK]', 'was', 'a', 'puppet', '##eer', '[SEP]']

# 将标记转换为词汇索引
indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)
# 定义与第一句和第二句相关的句子A和B索引(见论文)
segments_ids = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]

# 将输入转换为PyTorch张量
tokens_tensor = torch.tensor([indexed_tokens])
segments_tensors = torch.tensor([segments_ids])

让我们看看如何使用BertModel在隐藏状态下对输入进行编码:

# 加载预训练模型(权重)
model = BertModel.from_pretrained('bert-base-uncased')

# 将模型设置为评估模式
# 在评估期间有可再现的结果这是很重要的!
model.eval()

# 如果你有GPU,把所有东西都放在cuda上
tokens_tensor = tokens_tensor.to('cuda')
segments_tensors = segments_tensors.to('cuda')
model.to('cuda')

#预测每个层的隐藏状态特征
with torch.no_grad():
    # 有关输入的详细信息,请参见models文档字符串
    outputs = model(tokens_tensor, token_type_ids=segments_tensors)
    # Transformer模型总是输出元组。
    # 有关所有输出的详细信息,请参见模型文档字符串。在我们的例子中,第一个元素是Bert模型最后一层的隐藏状态
    encoded_layers = outputs[0]
# 我们已将输入序列编码为形状(批量大小、序列长度、模型隐藏维度)的FloatTensor
assert tuple(encoded_layers.shape) == (1, len(indexed_tokens), model.config.hidden_size)

以及如何使用BertForMaskedLM预测屏蔽的标记:

# 加载预训练模型(权重)
model = BertForMaskedLM.from_pretrained('bert-base-uncased')
model.eval()

# 如果你有GPU,把所有东西都放在cuda上
tokens_tensor = tokens_tensor.to('cuda')
segments_tensors = segments_tensors.to('cuda')
model.to('cuda')

# 预测所有标记
with torch.no_grad():
    outputs = model(tokens_tensor, token_type_ids=segments_tensors)
    predictions = outputs[0]

# 确认我们能预测“henson”
predicted_index = torch.argmax(predictions[0, masked_index]).item()
predicted_token = tokenizer.convert_ids_to_tokens([predicted_index])[0]
assert predicted_token == 'henson'

OpenAI GPT-2

下面是一个快速开始的例子,使用GPT2Tokenizer和GPT2LMHeadModel类以及OpenAI的预训练模型来预测文本提示中的下一个标记。

首先,让我们使用GPT2Tokenizer

import torch
from transformers import GPT2Tokenizer, GPT2LMHeadModel

# 可选:如果您想了解发生的信息,请按以下步骤logger
import logging
logging.basicConfig(level=logging.INFO)

# 加载预训练模型(权重)
tokenizer = GPT2Tokenizer.from_pretrained('gpt2')

# 编码输入
text = "Who was Jim Henson ? Jim Henson was a"
indexed_tokens = tokenizer.encode(text)

# 转换为PyTorch tensor
tokens_tensor = torch.tensor([indexed_tokens])

让我们看看如何使用GPT2LMHeadModel生成下一个跟在我们的文本后面的token:

# 加载预训练模型(权重)
model = GPT2LMHeadModel.from_pretrained('gpt2')

# 将模型设置为评估模式
# 在评估期间有可再现的结果这是很重要的!
model.eval()

# 如果你有GPU,把所有东西都放在cuda上
tokens_tensor = tokens_tensor.to('cuda')
model.to('cuda')

# 预测所有标记
with torch.no_grad():
    outputs = model(tokens_tensor)
    predictions = outputs[0]

# 得到预测的下一个子词(在我们的例子中,是“man”这个词)
predicted_index = torch.argmax(predictions[0, -1, :]).item()
predicted_text = tokenizer.decode(indexed_tokens + [predicted_index])
assert predicted_text == 'Who was Jim Henson? Jim Henson was a man'

每个模型架构(Bert、GPT、GPT-2、Transformer XL、XLNet和XLM)的每个模型类的示例,可以在文档中找到。

使用过去的GPT-2

以及其他一些模型(GPT、XLNet、Transfo XL、CTRL),使用past或mems属性,这些属性可用于防止在使用顺序解码时重新计算键/值对。它在生成序列时很有用,因为注意力机制的很大一部分得益于以前的计算。

下面是一个使用带past的GPT2LMHeadModel和argmax解码的完整工作示例(只能作为示例,因为argmax decoding引入了大量重复):

from transformers import GPT2LMHeadModel, GPT2Tokenizer
import torch

tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2LMHeadModel.from_pretrained('gpt2')

generated = tokenizer.encode("The Manhattan bridge")
context = torch.tensor([generated])
past = None

for i in range(100):
    print(i)
    output, past = model(context, past=past)
    token = torch.argmax(output[..., -1, :])

    generated += [token.tolist()]
    context = token.unsqueeze(0)

sequence = tokenizer.decode(generated)

print(sequence)

由于以前所有标记的键/值对都包含在past,因此模型只需要一个标记作为输入。

Model2Model示例

编码器-解码器架构需要两个标记化输入:一个用于编码器,另一个用于解码器。假设我们想使用Model2Model进行生成性问答,从标记将输入模型的问答开始。

import torch
from transformers import BertTokenizer, Model2Model

# 可选:如果您想了解发生的信息,请按以下步骤logger
import logging
logging.basicConfig(level=logging.INFO)

# 加载预训练模型(权重)
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')

# 编码输入(问题)
question = "Who was Jim Henson?"
encoded_question = tokenizer.encode(question)

# 编码输入(答案)
answer = "Jim Henson was a puppeteer"
encoded_answer = tokenizer.encode(answer)

# 将输入转换为PyTorch张量
question_tensor = torch.tensor([encoded_question])
answer_tensor = torch.tensor([encoded_answer])

让我们看看如何使用Model2Model获取与此(问题,答案)对相关联的loss值:

#为了计算损失,我们需要向解码器提供语言模型标签(模型生成的标记id)。
lm_labels =  encoded_answer
labels_tensor = torch.tensor([lm_labels])

# 加载预训练模型(权重)
model = Model2Model.from_pretrained('bert-base-uncased')

# 将模型设置为评估模式
# 在评估期间有可再现的结果这是很重要的!
model.eval()

# 如果你有GPU,把所有东西都放在cuda上
question_tensor = question_tensor.to('cuda')
answer_tensor = answer_tensor.to('cuda')
labels_tensor = labels_tensor.to('cuda')
model.to('cuda')

# 预测每个层的隐藏状态特征
with torch.no_grad():
    # 有关输入的详细信息,请参见models文档字符串
    outputs = model(question_tensor, answer_tensor, decoder_lm_labels=labels_tensor)
    # Transformers模型总是输出元组。
    # 有关所有输出的详细信息,请参见models文档字符串
    # 在我们的例子中,第一个元素是LM损失的值
    lm_loss = outputs[0]

此损失可用于对Model2Model的问答任务进行微调。假设我们对模型进行了微调,现在让我们看看如何生成答案:

# 让我们重复前面的问题
question = "Who was Jim Henson?"
encoded_question = tokenizer.encode(question)
question_tensor = torch.tensor([encoded_question])

# 这次我们试图生成答案,所以我们从一个空序列开始
answer = "[CLS]"
encoded_answer = tokenizer.encode(answer, add_special_tokens=False)
answer_tensor = torch.tensor([encoded_answer])

# 加载预训练模型(权重)
model = Model2Model.from_pretrained('fine-tuned-weights')
model.eval()

# 如果你有GPU,把所有东西都放在cuda上
question_tensor = question_tensor.to('cuda')
answer_tensor = answer_tensor.to('cuda')
model.to('cuda')

# 预测所有标记
with torch.no_grad():
    outputs = model(question_tensor, answer_tensor)
    predictions = outputs[0]

# 确认我们能预测“jim”
predicted_index = torch.argmax(predictions[0, -1]).item()
predicted_token = tokenizer.convert_ids_to_tokens([predicted_index])[0]
assert predicted_token == 'jim'

相关推荐

如何将数据仓库迁移到阿里云 AnalyticDB for PostgreSQL

阿里云AnalyticDBforPostgreSQL(以下简称ADBPG,即原HybridDBforPostgreSQL)为基于PostgreSQL内核的MPP架构的实时数据仓库服务,可以...

Python数据分析:探索性分析

写在前面如果你忘记了前面的文章,可以看看加深印象:Python数据处理...

CSP-J/S冲奖第21天:插入排序

...

C++基础语法梳理:算法丨十大排序算法(二)

本期是C++基础语法分享的第十六节,今天给大家来梳理一下十大排序算法后五个!归并排序...

C 语言的标准库有哪些

C语言的标准库并不是一个单一的实体,而是由一系列头文件(headerfiles)组成的集合。每个头文件声明了一组相关的函数、宏、类型和常量。程序员通过在代码中使用#include<...

[深度学习] ncnn安装和调用基础教程

1介绍ncnn是腾讯开发的一个为手机端极致优化的高性能神经网络前向计算框架,无第三方依赖,跨平台,但是通常都需要protobuf和opencv。ncnn目前已在腾讯多款应用中使用,如QQ,Qzon...

用rust实现经典的冒泡排序和快速排序

1.假设待排序数组如下letmutarr=[5,3,8,4,2,7,1];...

ncnn+PPYOLOv2首次结合!全网最详细代码解读来了

编辑:好困LRS【新智元导读】今天给大家安利一个宝藏仓库miemiedetection,该仓库集合了PPYOLO、PPYOLOv2、PPYOLOE三个算法pytorch实现三合一,其中的PPYOL...

C++特性使用建议

1.引用参数使用引用替代指针且所有不变的引用参数必须加上const。在C语言中,如果函数需要修改变量的值,参数必须为指针,如...

Qt4/5升级到Qt6吐血经验总结V202308

00:直观总结增加了很多轮子,同时原有模块拆分的也更细致,估计为了方便拓展个管理。把一些过度封装的东西移除了(比如同样的功能有多个函数),保证了只有一个函数执行该功能。把一些Qt5中兼容Qt4的方法废...

到底什么是C++11新特性,请看下文

C++11是一个比较大的更新,引入了很多新特性,以下是对这些特性的详细解释,帮助您快速理解C++11的内容1.自动类型推导(auto和decltype)...

掌握C++11这些特性,代码简洁性、安全性和性能轻松跃升!

C++11(又称C++0x)是C++编程语言的一次重大更新,引入了许多新特性,显著提升了代码简洁性、安全性和性能。以下是主要特性的分类介绍及示例:一、核心语言特性1.自动类型推导(auto)编译器自...

经典算法——凸包算法

凸包算法(ConvexHull)一、概念与问题描述凸包是指在平面上给定一组点,找到包含这些点的最小面积或最小周长的凸多边形。这个多边形没有任何内凹部分,即从一个多边形内的任意一点画一条线到多边形边界...

一起学习c++11——c++11中的新增的容器

c++11新增的容器1:array当时的初衷是希望提供一个在栈上分配的,定长数组,而且可以使用stl中的模板算法。array的用法如下:#include<string>#includ...

C++ 编程中的一些最佳实践

1.遵循代码简洁原则尽量避免冗余代码,通过模块化设计、清晰的命名和良好的结构,让代码更易于阅读和维护...

取消回复欢迎 发表评论: