NLP任务微调笔记
NLP任务微调笔记
NLP数据集没有像CV一样大量标号的数据集,所以NLP一般是自监督的,有两种自监督的模型:
-
LM:语言模型,预测下一个词
-
MLM:带掩码的语言模型,完形填空
每种预训练模型基于不同的技术也分为两种:
-
Word embddings:
- LSTM之类的传统的
-
Transformer based pretrained model:
- Bert:基于encoder,针对Bert的微调,把最后一层重新设计随机初始化,做分类只需要拿出一个然后训练,做QA只需要输出答案的位置
- GPT:基于decoder
- T5:基于encoder和decode
如何做分词
数据集一般是用Unicode进行编码,是对世界所有语言的一种编码,但是我们需要将这些文字变成数字编码的向量,就需要分词
1 | "我是一个用于测试输出unicode编码的文字".encode('utf-8')#可以看到每个字对应的unicode编码 |
分词Tokenizer:就是把文字变成数字,数字就是token,每个词变成一个编号
Tokenizer分类
Tokenizer有多种,其中subword-based是现在最常用的
- Word-based Toeknizers:把每个词一一对应分开,然后将例如“don‘t”引入特殊规则划分为“do”和“not”,这就导致虽然符合人的自然语言知觉,但是规则太多,此表很大,所以一般限制到一万个词,其余的词标记为未知
- Character-baesd :把一个单词变成一个个字母,love变成l,o,v,e,这样token序列长,单个token信息量低模型性能差,中文的词表更长。
- subword-based Tokenizer:这个合理,dog就是dog,但是dogs为dog+s。tokenization变成token和ization
常用的subword tokenizer
然后subword tokenizer也分为很多类
- Byte-pair encoding(GPT使用的p50k):BPE方法,首先进行词频统计,然后构建基本此表,根据词表切分词,统计相邻token同时出现的频率,取出新的频率高的组合token替换原先的小token,这样就可以构成新的词表,最后就会获得一个充满高频词单元的词表。看视频21分了解。有个gihub仓库miniBPE不错。同时还有一些出现也很高但是组合到一起没有意义的,那可以用加个正则表达删除这种组合
- Btye-level BPE(GPT2使用的):BPE的词表太大,改进的方法将字节byte看作基本token
- wordpiece:和BPE类似,每个单词除了第一个字母都会加一个#作为前缀,然后利用联合概率进行token合并,反正就更科学了
- sentencePiece(google):
- unigram(Bigbird,T5,XLNet):初始化一个很大的词表,尝试删减然后计算unigram loss,然后使unigramloss下降的不大就山调,逐步删减
每个模型都有对应的分词器,每个模型的tokenizer不一样,不能随便换,可查看https://huggingface.co/spaces/Xenova/the-tokenizer-playground看tokenizer的分词效果
构建词表
词表(Vocabulary)是通过使用 Tokenizer 对训练语料进行处理后获得的词(或子词、字符等)与 token 的对应关系。词表中已经定义了 token 与 ID 的映射关系。
如果你的模型微调任务中已经有一个预训练的 对应Tokenizer,那么这个 Tokenizer 其实包含了对应的词表,那么不需要重新构建词表!
预训练的 Tokenizer 通常是在大规模语料上训练的,已经包含了足够大的词表(例如 30,000 到 100,000 个 token)。
如果你想训练一个新模型,但是没有tokenizer,那么就可以使用词表下面介绍怎么使用词表:
- 使用预训练Embedding的词表,如Glove,word2Vec
- GloVe 的词表主要用于训练词向量(word embeddings),而不是直接用于模型的输入。
- 使用数据集统计词表:使用from_dataset函数从数据集构建一个Vocab词表
- 使用Subword训练得到的词表,直接就获得了,不需要训练获得词表
如何使用别人训练的词表word2Vec生成input
1 | from gensim.models import KeyedVectors |
如何embedding
embedding:做完分词后获得是一堆数字,embedding现在都成为transformer算法,不用自己来写这部分数据预处理的一部分,所以不用写了
Embedding layer的作用是将离散的 token ID 映射为连续的向量表示。这些向量通常是可训练的,模型会在训练过程中学习如何将每个 token ID 映射到一个有意义的向量空间中。比如说一个句子里的一个词的向量 是 这个词的token + 词的位置编码
将数据变为数据集(太重点的)
AI需要的是问答对数据集,也就是一个数据集里要有问题和答案
1 | { |
有各种各样的数据集,然后需要用在不同的任务中,其中任务可以包括以下几种,基础模型都是bigbirdpegasus,但是是用于不同任务的
任务类型 | 数据需要包含的集列 |
---|---|
BigBirdPegasusForConditionalGeneration | input_text , target_text |
BigBirdPegasusForSequenceClassification | input_text , label |
BigBirdPegasusForQuestionAnswering | context , question , answer |
BigBirdPegasusDecoderWrapper | input_text , target_text |
BigBirdPegasusForCausalLM因果语言模型(CLM) | input_text , target_text ,下一个词是target_text |
Masked Language Modeling掩码语言模型(MLM,比如bert) | input_text , target_text ,缺少的词是target_text |
然后每一种任务的模型需要不同类型的数据集进行训练,需要数据集有对应不同的columes,比如说BigBirdPegasusForConditionalGeneration这个条件生成任务的模型需要数据集包括输入文本(input text)和目标文本(target text),具体格式如下。
1 | data = [ |
有一些数据集是已经针对这些任务特化好的,比如说SQuAD (Stanford Question Answering Dataset)是针对ConditionalGeneration任务的,不过需要将这个数据集变成我们需要的格式。SQuAD 数据集中的一个例子如下
1 | { |
databricks-dolly-15k数据集是针微调任务的,牛逼吧,专门用于微调各种任务的,可以用于问答、分类、摘要各种任务,只需要你自己构造好。数据格式如下:
按照你的需要变成不同的格式
1 | DatasetDict({ |
但是还有一些数据集是非特化的,需要自己构建成需要的数据集格式,比如wikitext只是wiki上的文字一段一段的,这种就根需要自己对数据集进行特化处理
1 | {'text': " The ship was assigned to the Austro @-@ Hungarian Fleet 's 1st Battle Squadron after her 1911 commissioning . In 1912 , Zrínyi and her two sister ships conducted two training cruises into the eastern Mediterranean Sea . On the second cruise into the Aegean Sea , conducted from November to December , Zrínyi and her sister ships were accompanied by the cruiser SMS Admiral Spaun and a pair of destroyers . After returning to Pola , the entire fleet mobilized for possible hostilities , as tensions flared in the Balkans . \n"} |
数据集特化处理工具
我们完全可以自己把一个非特化的数据集转化为特化的数据集,比如把wikitext的每一句话拿出来,然后一句话的最后一个词就是要获得的结果,作为target_ids。但是有更好的工具可以直接把数据集转化为想要的特化的数据集比如dataset中的**DataCollatorForLanguageModeling
**
DataCollatorForLanguageModeling
** 是 Hugging Face 提供的一个工具,专门用于处理语言模型训练数据。它可以自动将数据集(如 Wikitext-103-v1)划分为 input_ids
、attention_mask
和 labels
,并且支持因果语言模型(Causal Language Model, CLM)和掩码语言模型(Masked Language Model, MLM)的训练。
DataCollatorForLanguageModeling
的作用
- 动态填充:将批次中的序列填充到相同长度。
- 生成
labels
:对于因果语言模型,labels
是input_ids
的偏移版本(即下一个 token 的预测目标)。 - 支持 MLM:如果你使用的是掩码语言模型(如 BERT),它还可以随机掩码 token。
- 除了生成input_ids和target_ids之外,还会生成
attention_mask
,指示哪些 token 是实际数据,哪些是填充 token。
DataCollatorForLanguageModeling的工作原理:
1 | # 首先已经有两句连续的话了 |
下面讲解DataCollatorForLanguageModeling` 怎么调用
1 | from datasets import load_dataset |
除了 DataCollatorForLanguageModeling
,huggingface的transformer还有许多其他 DataCollator 工具,可以根据任务需求将数据集转换为模型训练所需的格式。以下是一些常用的 DataCollator 及其适用场景:详细可看这个各种datacollator
DataCollator 类型 | 适用任务 |
---|---|
DataCollatorWithPadding |
变长序列任务(如文本分类)。 |
DataCollatorForTokenClassification |
序列标注任务(如命名实体识别)。 |
DataCollatorForSeq2Seq |
序列到序列任务(如机器翻译)。 |
DataCollatorForSOP |
句子顺序预测任务(如 ALBERT)。 |
DataCollatorForWholeWordMask |
全词掩码任务(如 BERT)。 |
DataCollatorForPermutationLanguageModeling |
排列语言模型任务(如 XLNet)。 |
DataCollatorForNextSentencePrediction |
下一句预测任务(如 BERT)。 |
DataCollatorForImageCaptioning |
图像描述生成任务。 |
也可以自己定义,继承DataCollator
Mindspore也有datacontrol的工具不过叫做mindspore.dataset.GeneratorDataset,并且需要自己定义,但是也没有transformers里面的工具智能
1 | def data_generator(): |
除此之外mindspore和mindNLP只支持一些基本操作比如map,padding之类的