What’s HuggingFace?
The Hugging Face Hub is a platform with over 60K models, 6K datasets, and 6K demo apps (Spaces), all open source and publicly available, in an online platform where people can easily collaborate and build ML together. The Hub works as a central place where anyone can explore, experiment, collaborate and build technology with Machine Learning.
就是个有很多数据集、模型的在线的机器学习hub,重要的是所有的东西都免费!免费啊!
主要还是几个牛逼的NLP模型也都是放在上面的,比如Bert
所以我准备把HuggingFace上有关NLP的Tutorial都看一遍,这是篇博客是我自己的笔记
transformer是Google在2018年提出的在Bert中使用的既不是CNN也不是RNN的一个完全由Attention机制祖成的全新的网络结构。
huggingface在创立之初就只是想搞一个Pytorch版本的Bert,但是加入的人越来越多,所以现在huggingface的这个Transformers是一个聚合的平台,也可以理解为一个巨大的python库,这个库里面涵盖了目前主流的几乎所有的有关于NLP的模型和一些封装好的有关于NLP处理的工具函数.
Transformers 官方中文course
pipeline就像是一个下载器,自动从huggingface网站下载你输入的模型,初次使用会下载,之后就直接使用缓存了
from transformers import pipeline # 导入pipeline
# 使用pipeline加载“translation”功能的模型并实例化,model参数可以指定特定的模型,不指定的话会有个默认个模型
translator = pipeline("translation", model="Helsinki-NLP/opus-mt-fr-en")
# 调用上面实例化之后的模型并推理
translator("Ce cours est produit par Hugging Face.")
Transformer可以以解为一个完全通过注意力机制搭建起来的网络,分为两大部分
有些时候只需要使用编码器,有些时候只需要使用解码器,有些时候两者都需要使用,具体取决于你需要使用你的模型去解决什么问题
最原始的Transformer 架构(Architecture) 长的是这样的:
既有编码器也有解码器,这是因为最原始的transformer是被设计用来进行翻译工作的,所以必须要有decoder进行输出
番外: 什么是架构(architecture)? 什么是检查点(checkpoints)? 什么是模型(Model)?
- Architecture: This is the skeleton of the model — the definition of each layer and each operation that happens within the model.
- Checkpoints: These are the weights that will be loaded in a given architecture.
- Model: This is an umbrella term that isn’t as precise as “architecture” or “checkpoint”
BERT就是一个架构,它可以被用来训练,bert-base-cased是Google团队根据BERT训练的一组权重也就是checkpoints。换句话说架构就是通过一些代码定义的一些算法,而checkpoints就是通过使用架构训练出来的模型,可能会非常大,是一些或一个权重
.pt文件啥的
Transformer是一个同时包含编码器和解码器的模型,但是,很多情况下我们并不使用完整的Transformer模型,而是只使用encoder或者只使用decoder或者都使用
tokenizer,标记器 (分词器) ,将输入的句子拆分成一个个的单词(或词语),这一步叫做tokenize ( 分词 ) ,并赋予唯一ID数字(convert_tokens_to_ids),模型只认识这些唯一ID
如何使用:
使用Autotokenizer配合名称就可以像使用pipeline一样加载你需要的分词器:
from transformers import AutoTokenizer
# AutoR=Tokenizer可以自动根据后面输入的名称加载对应的模型
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
sequence = "Using a Transformer network is simple"
# 这里仅仅是将句子拆分成更小的单元,并没有转换成ID
tokens = tokenizer.tokenize(sequence)
print(tokens)
# 将分词转换成ID
ids = tokenizer.convert_tokens_to_ids(tokens)
# 将id转换成词
decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014])
print(decoded_string)
transformer在使用的过程中不仅需要上面的分词转换,还需要一个 attention mask 用来告诉模型哪些才是这个句子的部分,比如有些句子比较短,但是你填充了很多paddinf_id将其补齐了,这些padding_id处对应的attention_mask就应该是0,这样这些padding_id就不会参与实际的注意力运算
# 下面这一句不仅包含了上面的tokenize和convert_tokens_to_ids操作,还会自动生成attention_mask矩阵
tokenized_inputs = tokenizer(sequence, return_tensors="pt")
print(tokenized_inputs["input_ids"])
实际的使用中大概率会是下面的写法:
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification
# 用于tokenizer的模型
# 注意,每一种模型比如bert-base-cased、gpt2都会有自己对应的tokenizer,在使用模型时需要调用这个模型对应的tokenizer,他们的checkpoint名称一般是一模一样的
checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
# 分词之后的句子通过下面这个模型来进行分类
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"]
# 直接使用tokenizer会返回一个字典{'input_ids':[[1,2,3], [2,3]], 'attention_mask':[[0,1,1], [1,0]]}
tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt")
# **token会将字典token拆分开,按照不同的键将值传递给model函数中对应的变量
output = model(**tokens)
在将数据送进模型之前,一般需要对数据进行预处理,与上面的Tokenizer一样,就是将句子转换成张量,但是不同的是,真正的应用中是将整个数据集中的句子进行转换,之后一批一批的送进模型
注意:
Tokenizer可以直接通过传入包含很多句子的列表来对很多句子进行分词,就像上面那样,也可以直接传入多个句子进行分词,与通过列表传入多个句子进行分词不同的是,直接将若干个句子传进Tokenizer是将这若干个句子拼成一个句子,通过[SEP] 等特殊标记进行拼接,具体情况如下:inputs = tokenizer("This is the first sentence.", "This is the second one.") # 如果是有大量的这样成对的句子待拼接,可以将每一对句子的前一个句子放在一个列表,后一个句子放进一个列表 # 然后将两个列表分别放在Tokenizer的第一个第二个位置 tokenized_dataset = tokenizer(raw_datasets["train"]["sentence1"] , raw_datasets["train"]["sentence2"] , padding=True , truncation=True)
上面的input是
{‘input_ids’: [101, 2023, 2003, 1996, 2034, 6251, 1012, 102, 2023, 2003, 1996, 2117, 2028, 1012, 102], ‘attention_mask’: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
可以看出来上面的对整个数据集的处理方式是一次性的,即一下子将所有的待转换的数据集中的句子对全部转换成了张量并存储在了内存中,如果数据集太大会爆内存,所以需要一种方式不断地从原始数据集中读取数据并不断地转换,这就需要定义一个函数专门用来处理句子,再通过Dataset类的.map方法将这个函数应用到所有的数据集上,详见 数据的预处理
注意:这里预处理针对的是可以从huggingface上直接下下来的数据集,是通过
raw_datasets = load_dataset("glue", "mrpc")
得到的数据集类,当我自己定义数据集时会有些不同,具体哪里不同可能要具体分析
上面案例中的数据集都是从huggingface中直接下载的,实际应用中绝大部分数据集集是本地的CSV文件,这就需要将本地的文件通过load_dataset 转换成huggingface 支持的DatasetDict对象,并进行一系列的操作
具体的使用方式见: Huggingface 官方Datasets库中文教程
from datasets import load_dataset
data_files = {"train": "drugsComTrain_raw.tsv", "test": "drugsComTest_raw.tsv"}
# \t is the tab character in Python,注意不同的csv文件分隔符可能不同
drug_dataset = load_dataset("csv", data_files=data_files, delimiter="\t")
训练自己的分析器
训练自己的Tokenizer,根据已经存在的分词器训练自己的分词器,根据我们的任务需要选择一个分词器模板,这样可以使得我们分词后的模型与选择的模板的结果一致,不需要自己设置一些细节。
简洁版如下:
from transformers import AutoTokenizer
# 首先导入一个训练好的分词器
old_tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
# 放进去训练的数据集必须得是迭代器得形式,具体如何处理参考官方教程
# 主要就两个参数,一个是迭代器形式得语料库,一个是目标字典得大小,目标字典的大小怎么确定?事先自己分析
tokenizer = old_tokenizer.train_new_from_iterator(training_corpus, 52000)
# 保存训练好的分析器
tokenizer.save_pretrained("my-new-tokenizer")
# 加载保存在本地的分词器
tokenizer = AutoTokenizer.from_pretrained("my-new-tokenizer")