当前位置: 首页 > news >正文

Transformers简单介绍 - 来源于huggingface

Transformers介绍 - 来源于huggingface

文章目录

  • Transformers介绍 - 来源于huggingface
    • Transformers能做什么
      • pipeline()函数
    • 零样本分类
    • 推理API
    • 完形填空
    • 命名实体识别
    • 问答
    • 摘要提取
    • 翻译
  • transformers是如何工作的
    • transformers的具体组成
    • 注意力层机制
    • transformers原始结构
    • architecture(架构)与 checkpoints(权重参数又称检查点)
  • Transformer的结构
    • 编码器模型
    • 解码器模型
    • 编码器-解码器模型
    • 偏见和局限性
  • 使用transfromer
    • transfromer管道内部原理
    • 使用tokenizer进行预处理
    • 探索模型
    • 是什么高维向量
    • 模型头:理解数字的意义
    • 对输出进行后序处理
    • 模型
  • Tokenizer
    • 基于单词的分词方式 Word-based tokenization
    • 基于字符的分词 Character-based tokenization
    • 基于子词的分词方式 subword tokenization
    • 编码
    • taokenization
    • 从tokens到inputs ID
    • 解码
    • 处理多个序列(句子)
    • 为什么前后得到的logits不同?
    • 注意力掩码层 attention mask
    • 更长的句子
    • tokenizer是一个全能的助手
      • 自动搞定填充的问题
      • 自动截断句子
      • 自动搞定 "填充" 问题
      • 自动 "截断" 长句子
      • 直接出各种框架能用的格式
    • 特殊的tokens

Transformers能做什么

pipeline()函数

Transformers 库中最基本的对象是 pipeline() 函数。它将模型与所需的预处理和后续处理步骤连接起来,使我们能够通过直接输入任何文本并获得最终的结果
frpythonom transformers import pipeline

classifier = pipeline("sentiment-analysis")
classifier("I've been waiting for a HuggingFace course my whole life.")

pipeline会加载选定的预训练模型,去对该句话进行情感分析
将一些文本传递到 pipeline 时涉及三个主要步骤:
1.文本被预处理为模型可以理解的格式
2.将预处理后的输入传递给模型
3.对模型的预测进行后续处理并输出最终人类可以理解的结果

目前 可用的一些pipeline有:

  • eature-extraction (获取文本的向量表示)
  • fill-mask (完形填空)
  • ner (命名实体识别)
  • question-answering (问答)
  • sentiment-analysis (情感分析)
  • summarization (提取摘要)
  • text-generation (文本生成)
  • translation (翻译)
  • zero-shot-classification (零样本分类)

零样本分类

from transformers import pipelineclassifier = pipeline("zero-shot-classification")
classifier("This is a course about the Transformers library",candidate_labels=["education", "politics", "business"],
)

在这里插入图片描述

函数解释
让我详细为你解释这段代码,我会分成几个部分来说明:

  1. 导入部分
from transformers import pipeline
  • 这行代码是从 transformers 库中导入 pipeline 功能
  • transformers 是由 Hugging Face 公司开发的一个非常流行的自然语言处理库
  • pipeline 是一个简化机器学习任务的工具,让我们能够更容易地使用预训练模型
  1. 创建分类器
classifier = pipeline("zero-shot-classification")
  • 这行代码创建了一个零样本分类器(zero-shot classifier)
  • pipeline() 是一个函数,通过传入参数 “zero-shot-classification” 来指定我们要创建的是零样本分类器
  • 零样本分类是一种特殊的分类方法,它可以在没有事先训练的情况下对文本进行分类
  1. 使用分类器进行预测
classifier("This is a course about the Transformers library",candidate_labels=["education", "politics", "business"],
)
  • 这部分代码使用创建好的分类器来进行实际的分类任务
  • 第一个参数 "This is a course about the Transformers library" 是要分类的文本
  • candidate_labels 参数提供了可能的类别标签:[“education”, “politics”, “business”]
  • 分类器会计算这段文本属于每个候选标签的可能性
  1. 运行结果说明
  • 当你运行这段代码时,分类器会返回一个结果,显示这段文本属于每个类别的概率
  • 由于这段文本明显与教育相关(因为提到了"course"),所以 “education” 标签可能会得到最高的概率分数
  1. 实际应用例子
    让我们看看可能的输出格式:
{'sequence': 'This is a course about the Transformers library','labels': ['education', 'business', 'politics'],'scores': [0.8765, 0.1123, 0.0112]
}
  • sequence: 输入的文本
  • labels: 按照概率从高到低排序的标签
  • scores: 对应每个标签的概率分数
  1. 使用提示:
  • 运行这段代码前,需要先安装 transformers 库:
pip install transformers
  • 第一次运行时,会自动下载需要的模型文件,可能需要一些时间
  • 需要确保有稳定的网络连接,因为模型文件可能比较大

这段代码展示了如何使用现代人工智能技术进行文本分类,而且不需要自己训练模型,非常适合初学者使用。你可以通过修改文本和标签来尝试不同的分类任务。

推理API

所有的模型都可以使用inferenceAPI直接通过浏览器进行测试

https://huggingface.co/

完形填空

from transformers import pipelinegenerator = pipeline("text-generation", model="distilgpt2")
generator("In this course, we will teach you how to",max_length=30,num_return_sequences=2,
)[{'sequence': 'This course will teach you all about mathematical models.','score': 0.19619831442832947,'token': 30412,'token_str': ' mathematical'},{'sequence': 'This course will teach you all about computational models.','score': 0.04052725434303284,'token': 38163,'token_str': ' computational'}]

top_k 参数控制要显示的结果有多少种。请注意,这里模型填补了特殊的 词,它通常被称为 mask token 。不同的 mask-filling 模型可能有不同的 mask token ,因此在探索其他模型时要验证正确的 mask token 是什么。检查它的一种方法是查看小组件中使用的 mask token

命名实体识别

命名实体识别 (NER) 是一项任务,其中模型必须找到输入文本的哪些部分对应于诸如人员、位置或组织之类的实体。
from transformers import pipeline

ner = pipeline("ner", grouped_entities=True)
ner("My name is Sylvain and I work at Hugging Face in Brooklyn.")
[{'entity_group': 'PER', 'score': 0.99816, 'word': 'Sylvain', 'start': 11, 'end': 18}, {'entity_group': 'ORG', 'score': 0.97960, 'word': 'Hugging Face', 'start': 33, 'end': 45}, {'entity_group': 'LOC', 'score': 0.99321, 'word': 'Brooklyn', 'start': 49, 'end': 57}
]

我们在创建 pipeline 的函数中传递的 grouped_entities=True 参数告诉 pipeline 将与同一实体对应的句子部分重新分组:这里模型正确地将“Hugging”和“Face”分组为一个组织,即使名称由多个词组成。事实上,正如我们即将在下一章看到的,预处理甚至会将一些单词分成更小的部分

问答

from transformers import pipelinequestion_answerer = pipeline("question-answering")
question_answerer(question="Where do I work?",context="My name is Sylvain and I work at Hugging Face in Brooklyn",
)
{'score': 0.6385916471481323, 'start': 33, 'end': 45, 'answer': 'Hugging Face'}

完全依据上下文生成回答,不会凭空产生

摘要提取

from transformers import pipelinesummarizer = pipeline("summarization")
summarizer("""America has changed dramatically during recent years. Not only has the number of graduates in traditional engineering disciplines such as mechanical, civil, electrical, chemical, and aeronautical engineering declined, but in most of the premier American universities engineering curricula now concentrate on and encourage largely the study of engineering science. As a result, there are declining offerings in engineering subjects dealing with infrastructure, the environment, and related issues, and greater concentration on high technology subjects, largely supporting increasingly complex scientific developments. While the latter is important, it should not be at the expense of more traditional engineering.Rapidly developing economies such as China and India, as well as other industrial countries in Europe and Asia, continue to encourage and advance the teaching of engineering. Both China and India, respectively, graduate six and eight times as many traditional engineers as does the United States. Other industrial countries at minimum maintain their output, while America suffers an increasingly serious decline in the number of engineering graduates and a lack of well-educated engineers.
"""
)
[{'summary_text': ' America has changed dramatically during recent years . The ''number of engineering graduates in the U.S. has declined in ''traditional engineering disciplines such as mechanical, civil '', electrical, chemical, and aeronautical engineering . Rapidly ''developing economies such as China and India, as well as other ''industrial countries in Europe and Asia, continue to encourage ''and advance engineering .'}]

与文本生成一样,你指定结果的 max_length 或 min_length

翻译

from transformers import pipelinetranslator = pipeline("translation", model="Helsinki-NLP/opus-mt-fr-en")
translator("Ce cours est produit par Hugging Face.")
[{'translation_text': 'This course is produced by Hugging Face.'}]

transformers是如何工作的

在这里插入图片描述

这种类型的模型可以对其训练过的语言有统计学的理解,但对于特定的实际任务的效果并不是很好。因此,一般的预训练模型会经历一个称为迁移学习(transfer learning)的过程。在此过程中,模型在给定任务上以监督方式(即使用人工注释标签)进行微调。
任务的一个例子是阅读 n 个单词的句子,预测下一个单词。这被称为因果语言建模(causal language modeling),因为输出取决于过去和现在的输入,而不依赖于未来的输入。

另一个例子是掩码语言建模(masked language modeling),俗称完形填空,该模型预测句子中的遮住的词。
在这里插入图片描述

transformers的具体组成

在这里插入图片描述

该模型主要由两个块组成:

  • Encoder (左侧):编码器接收输入并构建其表示(特征)。这意味着模型的使命是从输入中获取理解。
  • Decoder (右侧):解码器使用编码器的表示(特征)以及其他输入来生成目标序列。这意味着模型的使命是生成输出。

这些部件中的每一个都可以独立使用,具体取决于任务:

  • Encoder-only 模型:适用于需要理解输入的任务,如句子分类和命名实体识别。
  • Decoder-only 模型:适用于生成任务,如文本生成。
  • Encoder-decoder 模型 或者 sequence-to-sequence 模型:适用于需要根据输入进行生成的任务,如翻译或摘要。

注意力层机制

需要知道的是这一层将告诉模型在处理每个单词的表示时,对不同单词的单词的重视程度
在翻译的场景下:模型需要注意临近单词,或者在更复杂的句子中需要注重更远处出现的词,来正确的翻译每个词
同样的概念也适用于与自然语言相关的任何任务:一个词本身有一个含义,但这个含义受语境的影响很大,语境可以是研究该词之前或之后的任何其他词(或多个词)。

transformers原始结构

Transformer 架构最初是为翻译而设计的。在训练期间,编码器接收特定语言的输入(句子),而解码器需要输出对应语言的翻译。在编码器中,注意力层可以使用一个句子中的所有单词(正如我们刚才看到的,给定单词的翻译可以取决于它在句子中的其他单词)。然而,解码器是按顺序工作的,并且只能注意它已经翻译过的句子中的单词。例如,当我们预测了翻译目标的前三个单词时,我们将它们提供给解码器,然后解码器使用编码器的所有输出来尝试预测第四个单词。
为了在训练过程中加快速度(当模型可以访问目标句子时),会将整个目标输入解码器,但不允许获取到要翻译的单词(如果它在尝试预测位置 2 的单词时可以访问位置 2 的单词,解码器就会偷懒,直接输出那个单词,从而无法学习到正确的语言关系!)。例如,当试图预测第 4 个单词时,注意力层只能获取位置 1 到 3 的单词。
最初的 Transformer 架构如下所示,编码器位于左侧,解码器位于右侧:
在这里插入图片描述

注意,解码器块中的第一个注意力层关联到解码器的所有(过去的)输入,但是第二个注意力层只使用编码器的输出。因此,它在预测当前单词时,可以使用整个句子的信息。这是非常有用的,因因为不同的语言可以有把词放在不同顺序的语法规则,或者句子后面提供的一些上下文可能有助于确定给定单词的最佳翻译。
也可以在编码器/解码器中使用attention mask(注意力掩码层),以防止模型关注到某些特殊单词。例如,用于在批量处理句子时使所有输入长度一致的特殊填充词。

architecture(架构)与 checkpoints(权重参数又称检查点)

在本课程中,当我们深入探讨 Transformers 模型时,你将看到架构、参数和模型。这些术语的含义略有不同:

  • architecture(架构):这是模型的骨架 —— 每个层的定义以及模型中发生的每个操作。
  • Checkpoints(权重参数又称检查点):这些是将在给架构中结构中加载的权重参数,是一些具体的数值。
  • Model(模型):这是一个笼统的术语,没有“架构”或“参数”那么精确:它可以指两者。为了避免歧义,本课程使用将使用架构和参数。
    例如,BERT 是一个架构,而 bert-base-cased ,这是谷歌团队为 BERT 的第一个版本训练的一组权重参数,是一个参数。我们可以说“BERT 模型”和“ bert-base-cased 模型。”

Transformer的结构

编码器模型

编码器模型仅使用 Transformer 模型的编码器部分。在每次计算过程中,注意力层都能访问整个句子的所有单词,这些模型通常具有“双向”(向前/向后)注意力,被称为自编码模型。
这些模型的预训练通常会使用某种方式破坏给定的句子(例如:通过随机遮盖其中的单词),并让模型寻找或重建给定的句子。
“编码器”模型适用于需要理解完整句子的任务,例如:句子分类、命名实体识别(以及更普遍的单词分类)和阅读理解后回答问题。

解码器模型

“解码器”模型仅使用 Transformer 模型的解码器部分。在每个阶段,对于给定的单词,注意力层只能获取到句子中位于将要预测单词前面的单词。这些模型通常被称为自回归模型。
“解码器”模型的预训练通常围绕预测句子中的下一个单词进行。
这些模型最适合处理文本生成的任务。

编码器-解码器模型

编码器-解码器模型(也称为序列到序列模型)同时使用 Transformer 架构的编码器和解码器两个部分。在每个阶段,编码器的注意力层可以访问输入句子中的所有单词,而解码器的注意力层只能访问位于输入中将要预测单词前面的单词。
这些模型的预训练可以使用训练编码器或解码器模型的方式来完成,但通常会更加复杂。例如, T5 通过用单个掩码特殊词替换随机文本范围(可能包含多个词)进行预训练,然后目标是预测被遮盖单词原始的文本。
序列到序列模型最适合于围绕根据给定输入生成新句子的任务,如摘要、翻译或生成性问答。

偏见和局限性

如果你打算在正式的项目中使用经过预训练或经过微调的模型。请注意:虽然这些模型是很强大,但它们也有局限性。其中最大的一个问题是,为了对大量数据进行预训练,研究人员通常会搜集所有他们能找到的所有文字内容,中间可能夹带一些意识形态或者价值观的刻板印象。

from transformers import pipelineunmasker = pipeline("fill-mask", model="bert-base-uncased")
result = unmasker("This man works as a [MASK].")
print([r["token_str"] for r in result])result = unmasker("This woman works as a [MASK].")
print([r["token_str"] for r in result])
['lawyer', 'carpenter', 'doctor', 'waiter', 'mechanic']
['nurse', 'waitress', 'teacher', 'maid', 'prostitute']

在这里插入图片描述

使用transfromer

transfromer管道内部原理

from transformers import pipelineclassifier = pipeline("sentiment-analysis")
classifier(["I've been waiting for a HuggingFace course my whole life.","I hate this so much!",]
)

会获得如下的输出

[{'label': 'POSITIVE', 'score': 0.9598047137260437},{'label': 'NEGATIVE', 'score': 0.9994558095932007}]

pipeline集成了三个步骤:预处理、模型计算和后处理

在这里插入图片描述

使用tokenizer进行预处理

transfomer模型无法直接处理原始文本,第一步是将文本输入为模型能够理解的数字,因此需要使用tokenizer,它将负责:

  • 将输入拆分为单词、子单词或符号(如标点符号),称为 token(标记)
  • 将每个标记(token)映射到一个数字,称为 input ID(inputs ID)
  • 添加模型需要的其他输入,例如特殊标记(如 [CLS] 和 [SEP] )
    • 位置编码:指示每个标记在句子中的位置。
    • 段落标记:区分不同段落的文本。
    • 特殊标记:例如 [CLS] 和 [SEP] 标记,用于标识句子的开头和结尾

我们使用 AutoTokenizer 类和它的 from_pretrained() 方法,并输入我们模型 checkpoint 的名称,它将自动获取与模型的 tokenizer 相关联的数据,并对其进行缓存
sentiment-analysis (情绪分析)管道默认的 checkpoint 是 distilbert-base-uncased-finetuned-sst-2-english (你可以在 这里 )看到它的模型卡片,我们运行以下代码:

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

当我们有了一个tokenizer,就可以将我们的句子直接传递给他,然后会得到input ID的列表
在这里插入图片描述

解释一下这些参数的韩式

  • padding(填充)是指将短文本补齐到固定长度
  • truncation(截断)是指将过长的文本切断到指定长度
  • tensor 是深度学习中的数据结构,类似于多维数组

现在加载了一个模型,可以传递句子,然后可以指定要返回的tensor类型
输出是一个包含两个键, input_ids 和 attention_mask 。 input_ids 包含两行整数(每个句子一行),它们是每个句子中 token 的 ID

探索模型

我们可以像试用tokenizer一样去下载预训练模型,Transformers 提供了一个 AutoModel 类,它也有一个 from_pretrained() 方法:

from transformers import AutoModel
checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModel.from_pretrained(checkpoint)

在pipeline中使用的checkpoint下载下来,并用它实例化了一个模型
这个模型只包含基本的 Transformer 模块:输入一些句子,它输出我们将称为 hidden states(隐状态) ,也被称为特征。每个输入,我们都可以获取一个高维向量,代表 Transformer 模型对该输入的上下文理解。

想象一下,Transformer
模型就像一个超级聪明的翻译官。你给它一些句子,它会用自己的方式理解这些句子,然后给你一些“隐状态”,这些隐状态就像是它对这些句子的理解结果。
这些隐状态是一些高维向量,简单来说,就是一串数字,代表了模型对输入句子的理解。这些数字本身就很有用,因为它们可以作为其他任务的基础。
接下来,我们有“模型头”(head),它们就像是不同的工具,可以用来完成不同的任务。比如说,有的模型头可以用来做情感分析,有的可以用来做翻译。这就是为什么同一个模型可以用来做不同的任务,因为每个任务都有一个专门的“模型头”来处理这些隐状态。
所以,简单来说,Transformer 模型负责理解句子,而模型头负责用这些理解去完成具体的任务

是什么高维向量

transformers模块的矢量输出通常较大

  • Batch size(批次大小):一次处理的序列数(在我们的示例中为 2)。
  • Sequence length(序列长度):表示序列(句子)的长度(在我们的示例中为 16)。
  • Hidden size(隐藏层大小):每个模型输入的向量维度。

之所以说它是“高维度”的,是因为最后一个维度值。隐藏层维度可以非常大(对于较小的模型,常见的是 768,对于较大的模型,这个数字可以达到 3072 或更多)。

模型头:理解数字的意义

transformers模型的输出会直接发送到模型头进行处理,模型头通常由一个或几个线性层组成,他的输入是隐状态的高维度向量,会将其投影到不同的维度
在这里插入图片描述

在此图中,模型由其嵌入层和后续层表示。嵌入层将 tokenize 后输入中的每个 inputs ID 转换为表示关联 token 的向量。后续层使用注意机制操纵这些向量,生成句子的最终表示。

对输出进行后序处理

我们从模型中得到的输出本身未必有含义

print(outputs.logits)
tensor([[-1.5607,  1.6123],[ 4.1692, -3.3464]], grad_fn=<AddmmBackward>)

我们的模型预测第一句为 [-1.5607, 1.6123] ,第二句为 [ 4.1692, -3.3464] 。这些不是概率,而是 logits(对数几率) ,是模型最后一层输出的原始的、未标准化的分数。要转换为概率,它们需要经过 SoftMax 层(所有Transformers 模型的输出都是 logits,因为训练时的损失函数通常会将最后的激活函数(如 SoftMax)与实际的损失函数(如交叉熵)融合):

import torch predictions = torch.nn.functional.softmax(outputs.logits, dim=-1)
print(predictions)
tensor([[4.0195e-02, 9.5980e-01],[9.9946e-01, 5.4418e-04]], grad_fn=<SoftmaxBackward>)

模型

使用transformers模型进行推理
Transformer 模型只能处理数字——由 tokenizer 转化后的数字。但在我们讨论 tokenizer 之前,让我们探讨一下模型可以接受的输入是什么

sequences = ["Hello!", "Cool.", "Nice!"]

tokenizer 将这些转换为词汇表索引,通常称为 input IDs 。每个句子现在都是一个数字列表!结果输出是:

encoded_sequences = [[101, 7592, 999, 102],[101, 4658, 1012, 102],[101, 3835, 999, 102],
]

使用张量作为模型的输入

  • 将张量输入给模型非常简单 —— 我们只需调用模型并输入”:这里的 “张量” 可以理解成模型能看懂的数据格式(就像咱们说话用中文,模型 “读” 数据用张量)。给模型喂数据这事儿不复杂,就像调用一个函数似的,写一行代码 “output = model (model_inputs)” 就行,左边的 “output” 是模型算出来的结果,右边就是把准备好的张量 “model_inputs” 塞给模型。
  • 虽然模型接受很多不同的参数,但只有 input IDs 是必需的”:模型就像个多功能机器,能接受好几种 “配料”(参数),但其中有一种是必须放的,就是 “input IDs”。你可以理解成 “input IDs” 是模型的 “主食”,没有它模型没法干活;其他参数更像 “调料”,加不加、加多少,看具体需求。
  • 我们稍后会解释其他参数的作用以及何时需要它们,但首先我们需要仔细研究一下如何构建 Transformer 模型能理解的输入”:意思是后面会讲那些 “调料” 参数有啥用、啥时候用,但现在得先搞明白怎么做出模型能 “吃” 的 “主食”(也就是怎么构建符合要求的输入数据)。

简单说就是:给模型喂数据不难,关键是得有 “input IDs” 这个核心数据;其他辅助参数后面再说,现在先重点学怎么准备模型能看懂的输入。

Tokenizer

tokenizer 是 NLP 管道的核心组件之一。它们有一个非常明确的目的:将文本转换为模型可以处理的数据。模型只能处理数字,因此 tokenizer 需要将我们的文本输入转换为数字
最有意义的表达方式——对模型来说最有意义的方式,最简洁的表达方式

基于单词的分词方式 Word-based tokenization

想到的第一种 tokenizer 是基于词(word-based)的 tokenization。它通常很容易配置和使用,只需几条规则,并且通常会产生不错的结果。例如,在下图中,目标是将原始文本拆分为单词并为每个单词找到一个数字表示:
在这里插入图片描述

优点是:分词简单
缺点是:会产生很多不在词汇表中的单词,被称为“unknown” token,通常表示为“[UNK]”或“”。如果你看到 tokenizer 产生了很多这样的 token 这通常是一个不好的迹象,因为它无法检索到一个词的合理表示,并且你会在转化过程中丢失信息

基于字符的分词 Character-based tokenization

基于字符的 tokenizer 将文本拆分为字符,而不是单词。这有两个主要好处:

  • 词汇量要小得多。
  • unknown tokens (out-of-vocabulary)要少得多,因为每个单词都可以由字符构建
    在这里插入图片描述

但是这种分词方式,分词后的没有多大的意义,但是单词会有含义。
并且这样会让我们处理更多tokens

基于子词的分词方式 subword tokenization

基于子词(subword)的 tokenization 算法依赖于这样一个原则:常用词不应被分解为更小的子词,但罕见词应被分解为有意义的子词
在这里插入图片描述

这些子词最终提供了大量的语义信息:例如,在上面的例子中,“tokenization”被分割成“token”和“ization”,这两个 tokens 在保持空间效率的同时具有语义意义(只需要两个 tokens 就能表示一个长词)。这让我们能够在词汇量小的情况下获得相对良好的覆盖率,并且几乎没有未知的 token

tokenizer("Using a Transformer network is simple")
{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102],'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0],'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}

这段代码展示了用tokenizer(分词器)处理文本的过程,是使用 Transformer 模型时的常见操作。咱们一步步拆开看:

首先,tokenizer(“Using a Transformer network is simple”) 是把一句话 “Using a Transformer network is simple” 传给了分词器。

分词器的作用就像 “翻译官”,把人类能懂的自然语言,转换成模型能理解的数字格式。它返回了一个包含三个键的字典:

1.input_ids: 这是最核心的部分,里面的数字是每个词(或词的一部分)对应的编号。

  • 比如 7993 对应 “Using”,170 对应 “a”,11303 对应 “Transformer” 等等。
  • 开头的 101 和结尾的 102 是特殊标记(CLS 和 SEP),用来告诉模型句子的开始和结束。

2.token_type_ids: 主要用于区分句子对(比如问答中的问题和答案)。

  • 这里全是 0,因为我们只输入了一个句子,没有第二句话需要区分。

3.attention_mask: 告诉模型哪些位置的词是有意义的。

  • 这里全是 1,表示所有位置都是有效词(如果有 padding 填充的无效词,会标为0)

简答来说,分词器把一句话拆成了模型可以读懂的数字序列,同时附带一些辅助信息,方便模型可以i更好的处理输入

编码

将文本翻译成数据成为编码-encoding,编码分为两个步骤:分词,然后转换为inputsID。
第一步将文本拆分为tokens,不同的分词器使用的算法也不一样,需要使用模型名称来实例化tokenizer,确保我们使用模型预训练时使用相同的算法
第二部是将这些tokens转换为数据吗,这样可以构建一个张量并将他们提供给模型,因此tokenizer有一个词汇表。

taokenization

from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained("bert-base-cased")sequence = "Using a Transformer network is simple"
tokens = tokenizer.tokenize(sequence)
print(tokens)

基于子词的一个tokenizer,它对词进行拆分,直到获得可以用其词汇表表示的 tokens。以 transformer 为例,它分为两个 tokens transform 和 ##er

从tokens到inputs ID

inputs ID 的转换由 tokenizer 的 convert_tokens_to_ids() 方法实现:

ids = tokenizer.convert_tokens_to_ids(tokens)
print(ids)

解码

decoding正好与encoding相反,从inputs ID 到一个字符串,通过decode()实现。

tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014])
print(decoded_string)

在这里插入图片描述

decode不仅仅将索引转换回tokens,还将属于相同发单词的tokens组合在一起生成一个有意义的句子,后续再使用预测新闻本的模型,这个方法将会很有用。

处理多个序列(句子)

错误代码

import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassificationcheckpoint = "distilbert-base-uncased-finetuned-sst-2-english"
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)
# 这一行会运行失败 IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1)
model(input_ids)

transformers模型默认情况下需要一个句子list,然后再去转换为张量(inputs ID),这里试图重现tokenizer在输入数据后在其内部的所有操作,但是tokenizer不仅仅是将inputsID的列表转换为张量,还添加了一个维度,也就是说模型认 “批量” 数据:

import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassificationcheckpoint = "distilbert-base-uncased-finetuned-sst-2-english"
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])
print("Input IDs:", input_ids)output = model(input_ids)
print("Logits:", output.logits)
  1. Input IDs: 打印出的是带两层括号的数字列表,这就是模型能接受的格式。
  2. Logits: 模型输出的结果(这里是[-2.7276, 2.8789])。因为用的是情感分析模型,这两个数分别代表 “负面” 和 “正面” 的评分,正数越大表示越倾向于该情感(这里明显是正面情感)

如果想要批量处理句子的话 batched_ids = [ids, ids]就是创建了一个批次,里面放了两个相同的句子(用ids表示的数字列表)。这时候把它转成张量传给模型,模型会返回两个结果,而且因为句子相同,结果也会是重复的(和之前单句处理的结果一样)。
模型处理的输入必须要是“整齐的矩形”,但是实际中很有可能输入的句子长度是不同的,那么转换为的数字列表也是不同的,这种情况下就需要使用填充 padding,为了让批次里所有的句子长度医用,我们就需要给短句子补长,通过会在末尾添加padding_id ,这样整个批次就变成了规整的矩形。

  • 句子 A 转成的数字列表:[1,2,3](长度 3)
  • 句子 B 转成的数字列表:[4,5](长度 2)

填充后可能变成:

  • 句子 A:[1,2,3](不变)
  • 句子 B:[4,5,0](补了一个 0,长度变成 3)
    在这里插入图片描述

Padding 通过在值较少的句子中添加一个名为 padding_id 的特殊单词来确保我们所有的句子长度相同

为什么前后得到的logits不同?

这是因为 Transformer 模型的关键特性:注意力层,它考虑了每个 token 的上下文信息。这具体来说,每个 token 的含义并非单独存在的,它的含义还取决于它在句子中的位置以及周围的其他 tokens。当我们使用填充(padding)来处理长度不同的句子时,我们会添加特殊的“填充 token”来使所有句子达到相同的长度。但是,注意力层会将这些填充 token 也纳入考虑,因为它们会关注序列中的所有 tokens。这就导致了一个问题:尽管填充 token 本身并没有实际的含义,但它们的存在会影响模型对句子的理解。我们需要告诉这些注意层忽略填充 token。这是通过使用注意力掩码(attention mask)层来实现的。

注意力掩码层 attention mask

注意力掩码(attention mask)是与 inputs ID 张量形状完全相同的张量,用 0 和 1 填充:1 表示应关注相应的 tokens,0 表示应忽略相应的 tokens(即,它们应被模型的注意力层忽视)。

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)

经过处理后前后得到的logits是一样的。

更长的句子

如果据的长度超过了模型的序列长度限度,那么

  • 使用支持更长序列长度的模型。
  • 截断你的序列。

tokenizer是一个全能的助手

之前学习的分词,转数据,加掩码这些步骤,使用这个函数之后就不需要手动进行处理
支持单句子和多句子,且用法是一样的

  • 处理一个句子:tokenizer(单个句子)
  • 处理多个句子:tokenizer([句子1, 句子2, …])

自动搞定填充的问题

当句子长短不一时,它能自动补全短句子:

  • padding=“longest”:按最长的句子长度补
  • padding=“max_length”:按模型能接受的最大长度补(比如 BERT 是 512)
  • 还能自己指定长度:max_length=8就补到 8 个词长

自动截断句子

如果句子太长,超过模型能处理的限度,它能自动截断:

  • truncation=True:超过模型最大长度就截断
  • 也能指定截断到多少:max_length=8就截到 8 个词
  • 支持单句和多句,用法一样
    • 处理一个句子:tokenizer(单个句子)
    • 处理多个句子:tokenizer([句子1, 句子2, …])不管多少句,调用方式都一样,特别方便。

自动搞定 “填充” 问题

当句子长短不一时,它能自动补全短句子:

  • padding=“longest”:按最长的句子长度补
  • padding=“max_length”:按模型能接受的最大长度补(比如 BERT 是 512)
  • 还能自己指定长度:max_length=8就补到 8 个词长

自动 “截断” 长句子

如果句子太长,超过模型能处理的限度,它能自动截断:

  • truncation=True:超过模型最大长度就截断
  • 也能指定截断到多少:max_length=8就截到 8 个词

直接出各种框架能用的格式

它能把结果转成不同深度学习框架需要的格式:

  • return_tensors=“pt”:返回 PyTorch 能用的张量
  • return_tensors=“tf”:返回 TensorFlow 能用的张量
  • return_tensors=“np”:返回 NumPy 数组

特殊的tokens

在使用tokenizer后,返回的inputs ID,会在开头和结尾添加两个特殊的单词[CLS]和 [SEP],原因是模型在预训练时使用了这些词,所以为了得到相同的推断结果,需要加上它们。
请注意,有些模型不添加特殊单词,或者添加不同的特殊单词;模型也可能只在开头或结尾添加这些特殊单词。无论如何,tokenizer 知道哪些是必需的,并会为你处理这些问题

http://www.dtcms.com/a/317707.html

相关文章:

  • 虚幻GAS底层原理解剖五 (AS)
  • 从案例学习cuda编程——线程模型和显存模型
  • git 清理submodule
  • PowerShell部署Windows爬虫自动化方案
  • 【ArcGIS】分区统计中出现Null值且Nodata无法忽略的问题以及shp擦除(erase)的使用——以NDVI去水体为例
  • DevOps时代的知识基座革命:Gitee Wiki如何重构研发协作范式
  • Unity轻量观察相机
  • 利用DeepSeek编写go语言按行排序程序
  • centos配置java环境变量
  • Go语言 单元测试
  • 后端服务oom
  • 商品详情数据的秒级更新如何运用京东 API 实现?
  • Debian系统更新实现
  • Docker国内可用镜像(2025.08.06测试)
  • 【QT】-windous 应用程序开机自启
  • 组合期权:跨式策略
  • 【数字图像处理系列笔记】Ch03:图像的变换
  • Node.js- express的基本使用
  • MyBatis增删改、RESTful API 风格、SpringAOP
  • 启动模块服务时报错:docker: Error response from daemon: Conflict.
  • 状态模式及优化
  • 使用阿里云服务器部署dify实战
  • 深入理解 Maven POM 文件:核心配置详解
  • 【编号457】新疆高寒山区冰湖矢量数据
  • DSP的CLA调试技巧
  • Webpack核心技能:Webpack安装配置与模块化
  • 芯片分享【昆泰】——CH7305A -display controller device.
  • 基于Mojo与Mechanize的Perl高效爬虫实现
  • C++进阶—C++的IO流
  • JavaScript DOM 元素节点操作详解