诸神缄默不语-个人CSDN博文目录
本文属于huggingface.transformers全部文档学习笔记博文的一部分。 全文链接:huggingface transformers包 文档学习笔记(持续更新ing…)
本部分网址:https://huggingface.co/docs/transformers/master/en/glossary 本部分介绍transformers包相关的术语,包括transformers模型通用的术语,和用于PreTrainedModel输入参数的术语。
1. 通用术语
原文档是用首字母顺序排序的,本文则按照我认为比较合适的顺序来排序。
- deep learning:用很多层神经网络的机器学习算法。
- RNN / recurrent neural network:一种用a loop over a layer来处理文本的模型。
- self-attention:输入的每一个元素找它们应该attend to的输入其他元素。
- token:一句话的一部分,如一个word,或一个subword(不常见的words常被拆分为subwords)
- transformer:基于self-attention的deep learning模型架构。
- seq2seq / sequence-to-sequence:通过输入生成一个新序列的任务(如翻译模型或摘要模型,如Bart或T5)。
- multimodal:结合文本与其他形式的输入(如图像等)的任务。
- NLP / natural language processing:处理文本相关任务的泛称。
- NLG / natural language generation:生成文本的任务(如talk with transformers和文本翻译)
- NLU / natural language understanding:理解文本内容的任务(如对整片文章、个别词语的分类)
- pretrained model:在一些数据(如全部Wikipedia数据)上进行预训练后得到的模型。预训练模型包含一些self-supervised objective,如下面的MLM和CLM。
- MLM / masked language modeling / autoencoding models:一种预训练任务,模型看到的是corrupted文本。实现方式一般是随机mask一些tokens,然后预测原文。
- CLM / causal language modeling / autoregressive models:一种预训练任务,模型按顺序阅读文本,预测下一个单词。实现方式一般是阅读整句话,但用mask隐藏当前timestamp的未来tokens。
2. PreTrainedModel输入参数
每个模型都有所不同,但也有其相通之处。因此绝大多数模型的输入参数是相同的,以下就举例列举:
2.1 Input IDs
Input IDs一般情况下是唯一需要输入模型的参数。 是token的索引,token的数值表示,构建输入模型的sequence。 每种tokenizer的工作方式不同,但其根本工作机制是一样的。以BertTokenizer(一种WordPiece tokenizer)为例:
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("mypath/bert-base-cased")
sequence = "A Titan RTX has 24GB of VRAM"
Tokenizer致力于将sequence分解成词表中含有的tokens(words或subwords,非word开头的token前会加上## 符号):
tokenized_sequence = tokenizer.tokenize(sequence)
print(tokenized_sequence)
输出:['A', 'Titan', 'R', '##T', '##X', 'has', '24', '##GB', 'of', 'V', '##RA', '##M']
这些tokens可以被转换为模型可读的索引(IDs):
inputs = tokenizer(sequence)
tokenizer返回一个字典,包含所有使对应模型可以运行的必要参数。token索引就在键input_ids 下:
encoded_sequence = inputs["input_ids"]
print(encoded_sequence)
输出:[101, 138, 18696, 155, 1942, 3190, 1144, 1572, 13745, 1104, 159, 9664, 2107, 102]
注意tokenizer会自动添加模型需要的special tokens(如BertTokenizer对应的就是BertModel所需的special tokens),解码input ids后可以看出加了什么:
decoded_sequence = tokenizer.decode(encoded_sequence)
print(decoded_sequence)
输出:[CLS] A Titan RTX has 24GB of VRAM [SEP]
2.2 Attention mask
这一参数表明哪些tokens应该被模型attend to,哪些不应该。
以如下两句一长一短的sequence为例:
sequence_a = "This is a short sequence."
sequence_b = "This is a rather long sequence. It is at least longer than the sequence A."
encoded_sequence_a = tokenizer(sequence_a)["input_ids"]
encoded_sequence_b = tokenizer(sequence_b)["input_ids"]
两个sequence编码得到的数值序列长度不同:
len(encoded_sequence_a), len(encoded_sequence_b)
输出为:(8, 19)
因此,我们无法直接就这样把它们合并为一个tensor,要么把短句pad up到长句长度,要么把长句truncate down到短句长度。
一般来说,这种情况下我们会pad短句,因为truncate会出现信息损失。我们一般只在长句超过最长限长的时候才选择truncate操作。
pad up的情况:
padded_sequences = tokenizer([sequence_a, sequence_b], padding=True)
print(padded_sequences["input_ids"])
输出:[[101, 1188, 1110, 170, 1603, 4954, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [101, 1188, 1110, 170, 1897, 1263, 4954, 119, 1135, 1110, 1120, 1655, 2039, 1190, 1103, 4954, 138, 119, 102]]
可以看到短句的token后面被加了0,以使其与长句的sequence等长,这样就可以直接转换为tensor。 attention mask是一个二元tensor,标明用于pad的索引,模型就不会attend to它们。这和模型预训练时的操作一致。对BertTokenizer,1表明其对应的值需要被attend to,0表明其对应的值是padded value。attention mask就在tokenizer返回值的键attention mask 下:
padded_sequences["attention_mask"]
输出: [[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
2.3 Token Type IDs
又名segment IDs。
有些模型的目标是对句子对做分类或QA(question answering),如识别quora上两个问题是否相同,或做natural language inference (NLI) 任务。 这就需要两个sequences在同一input_id tensor中传入模型,这一操作一般用special tokens实现,如classifier ([CLS])或separator ([SEP]) tokens。 举例来说,BertTokenizer就这样构建2个sequences的输入:# [CLS] SEQUENCE_A [SEP] SEQUENCE_B [SEP]
通过将sequences作为2个入参(而非像之前所做的那样,以list形式组合sequences为1个入参),即可自动生成这样的数据:
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("mypath/bert-base-cased")
sequence_a = "HuggingFace is based in NYC"
sequence_b = "Where is HuggingFace based?"
encoded_dict = tokenizer(sequence_a, sequence_b)
decoded = tokenizer.decode(encoded_dict["input_ids"])
decoded
输出:'[CLS] HuggingFace is based in NYC [SEP] Where is HuggingFace based? [SEP]'
有一些模型以这样的数据输入形式就已经可知sequences的开始和结束位置,但对Bert等其他模型来说,还需应用token type IDs,一种区分2个sequences的二元mask。
encoded_dict["token_type_ids"]
输出:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1] 在QA任务中,第一句就是context(值为0),为第二句就是question(值为1)。
文档中这句话我有点没搞懂啥意思: 我没试过XLNetModel,我也懒得现在就去下文件研究,我觉得意思应该是其他模型可能会使用不同的special tokens。
比如之前在huggingface.transformers速成笔记中使用的sshleifer/distilbart-cnn-12-6模型,就是用<s></s> 来作为special tokens的:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("mypath/distilbart-cnn-12-6")
encoding = tokenizer("We are very happy to show you the 🤗 Transformers library.",
"We hope you don't hate it.")
print(encoding)
print()
print(tokenizer.decode(encoding['input_ids']))
输出: {'input_ids': [0, 170, 32, 182, 1372, 7, 311, 47, 5, 8103, 10470, 6800, 34379, 5560, 4, 2, 2, 170, 1034, 47, 218, 75, 4157, 24, 4, 2], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
<s>We are very happy to show you the 🤗 Transformers library.</s></s>We hope you don't hate it.</s>
2.4 Position IDs
RNNs的token位置是自带的,但是transformers本身是无法知道token位置的(这个是transformers模型特点,看过这个模型的应该都能直接理解,这事实上也是模型的核心部分。我以后可能会写相应的模型详解博文),因此模型就需要用position IDs (position_ids)来识别每个token在sequence中的位置。 这是个可选的入参。如果不传入该参数,IDs将自动以absolute positional embeddings形式创建。 absolute positional embeddings在[0, config.max_position_embeddings - 1] 中选择。有些模型使用其他形式的positional embeddings,如sinusoidal position embeddings或relative position embeddings。
2.5 Labels
这是个可选的入参。如果传入,模型将自行计算loss。这些labels是模型的期望预测值,模型会使用标准loss来计算真实预测值和期望值(labels)之间的loss。
labels因模型heads而有所不同,举例来说:
- 对sequence classification模型(如BertForSequenceClassification),labels应该是维度为
(batch_size) 的、每个值是对应sequence的标签。 - 对token classification模型(如BertForTokenClassification),labels应该是维度为
(batch_size, seq_length) 的、每个值是对应token的标签。 - 对masked language modeling模型(如BertForMaskedLM),labels应该是维度为
(batch_size, seq_length) 的、每个值是对应token的标签(masked token的token ID,unmasked token的忽略(通常直接用-100 )) - 对seq2seq模型(如BartForConditionalGeneration或MBartForConditionalGeneration),labels应该是维度为
(batch_size, tgt_seq_length) 的、每个值是每个input sequence对应的target sequences。在训练的过程中,BART和T5模型都会自动生成合适的decoder_input_ids (见本文2.6部分介绍)和decoder attention masks ,一般不需要手动提供。这跟Encoder-Decoder架构的模型不同,需要看特定模型的文档以了解所需labels的更多信息。
基础模型(如BertModel)不接受labels参数,因为它们是基础transformers模型,只输出特征。
2.6 Decoder input IDs
这个输入仅用于encoder-decoder模型(seq2seq任务,如翻译或摘要),包含了喂进decoder的input IDs,每个模型的构建形式都有所不同。 绝大多数encoder-decoder模型(如BART和T5)都会从labels 入参中直接自动构建decoder_input_ids 入参,因此建议在训练过程中传递labels 入参。
2.7 Feed Forward Chunking
在transformers的每个residual attention block中,self-attention层后一般跟着两个前馈 (feed forward) 层。前馈层的intermediate embedding size一般会比模型的hidden size更大(其实我没太看懂这是啥意思,以后学好transformers模型再回来重新理解),如bert-base-uncased模型。 对于一个维度为[batch_size, sequence_length] 的输入张量,用于储存intermediate feed forward embeddings(维度为[batch_size, sequence_length, config.intermediate_size] )可能会占用大量内存。Reformer: The Efficient Transformer作者发现,计算过程与sequence_length 这一维度无关,计算2个完整的前馈层,与计算把2个前馈层分别拆成[batch_size, config.hidden_size]_0, ..., [batch_size, config.hidden_size]_n (其中n = sequence_length ),并分别计算其output embeddings,再将其concat为[batch_size, sequence_length, config.hidden_size] 。这一计算方式增加了用时,减少了空间占用,在数学上结果是相同的。 对于应用了apply_chunking_to_forward()函数的模型,chunk_size 入参定义了同时计算的output embeddings的数目,定义时间复杂度和空间复杂度之间的trade-off。如chunk_size 置0,就不做feed forward chunking操作。 这部分内容我没看懂,原论文我还没看,等我经继续学习后再回来做分析吧
|