huggingface transfomers 学习(一)——快速入门

一:介绍

        这几天看代码时,总是遇到transformers 模块使用,产生很多疑惑,故特别花些时间来研究一下。研究一番之后,惊叹于该模块的强大功能,故将学习所得分享一下。简单来说,huggingface transfomers 是一个强大的处理自然语言任务的工具包,集成了各种自然语言任务的预训练模型。该工具包支持pytorch 和 TensorFlow。可以说,当你遇到一些NLP任务时,最好先考虑能不能在该模块中找到相关模型,如果能找到,将节省非常多力气。

二:说明

        本文并不是简单的将官方文档翻译,而是结合官方文档和自己的理解书写,穿插代码和文字说明。如有疑问,以官方文档为主。如有错误,欢迎指出。官方文档提供pytorch和tensorflow两种框架的学习代码,但我使用pytorch,故文中所有案例都是使用pytorch代码进行说明。本文使用pycharm 运行。

三:transfomers

  (1):安装

        最简单的方式,打开terminal 输入:

pip install transfomers

这里默认最新版,可以指定版本安装。其他花里胡哨的安装参考官方文档。

(2):使用方式一,pipeline(不推荐)

直接用任务关键字实例化pipeline,得到一个训练好的实例对象,然后直接使用即可,实用性不高。代码如下(来自官方,未运行):

from transformers import pipeline
classifier = pipeline('sentiment-analysis')
classifier('We are very happy to show you the 🤗 Transformers library.')
# [{'label': 'POSITIVE', 'score': 0.9998}]

(3):使用方式二(常用方式)

自然处理任务总体可以分为两步,第一步分词,将文本通过分词器(tokenizer)得到基础的组成单元(token),然后根据词汇表(vocal)为这些单元编号,这样就能将文本数据变成数据编码形式,输入到模型。 第二步,将相应的token输入到网络,进行任务训练,根据网络不同,实现任务不同。这里的使用bert模型为例说明。(需要了解一下bert的原理)

1:tokenzier.

官方案例如下(不推荐)

from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
sequence = "A Titan RTX has 24GB of VRAM"
tokenized_sequence = tokenizer.tokenize(sequence)
print(tokenized_sequence)
# >>> ['A', 'Titan', 'R', '##T', '##X', 'has', '24', '##GB', 'of', 'V', '##RA', '##M']

这里,导入BertTokenizer类,通过from_pretrained方法,从官网下载训练好的数据,然后得到可以直接使用的tokenizer对象,后面是个分词效果的实例展示。根据我看的代码,并不推荐程序中这样使用,因为这种方式下载的数据保存位置是默认的,并不好找。实际使用者采用如下代码:

from transformers import BertTokenizer

model_name = 'bert-base-cased'   # 下载的数据模型名称
cache_dir = './cache_dir'        # 将数据保存到的本地位置
tokenizer = BertTokenizer.from_pretrained(model_name,cache_dir=cache_dir)
# 使用cache_dir 可以指定文件下载位置

sequence = "A Titan RTX has 24GB of VRAM"  # 待分词的句子
tokenized_sequence = tokenizer.tokenize(sequence)  # 分词
print(tokenized_sequence)  # 输出

输出效果及目录

可见,分词不是按单词划分的,其中的 ## 表示一个单词内的字母。

 仅仅是分词还是不够的,还需要为每个词编码,代码如下:

from transformers import BertTokenizer
from pprint import pprint

model_name = 'bert-base-cased'   # 下载的数据模型名称
cache_dir = './cache_dir'        # 将数据保存到的本地位置
tokenizer = BertTokenizer.from_pretrained(model_name,cache_dir=cache_dir)
# 使用cache_dir 可以指定文件下载位置
sequence = "A Titan RTX has 24GB of VRAM"  # 待分词的句子
# tokenized_sequence = tokenizer.tokenize(sequence)  # 调用tokenize方法进行分词
# print(tokenized_sequence)  # 输出

inputs = tokenizer(sequence)
pprint(inputs)

 结果如下:

可见,结果是个字典。其中input_ids好理解,即将分好的词(token )编码,这样这些编码数据就可以输入到网络模型中,但attention_mask和token_type_ids 如何理解?这个后面在介绍。

二:建立模型

得到input_ids,就得到了输入数据,那网络模型又如何搭建,代码如下:

from transformers import BertModel
model = BertModel.from_pretrained(model_name,cache_dir=cache_dir)  # 注意这里加载的预训练模型名字要与上面一致,需要下载模型400M
# model = BertModel.from_pretrained('./pre_model')  
pprint(model)

下载太慢,解决方式:manually download models · Issue #856 · huggingface/transformers · GitHub

官网下载模型,本地替换文件。

文件结构:

代码:

from transformers import BertModel
#model = BertModel.from_pretrained(model_name,cache_dir=cache_dir)  # 注意这里加载的预训练模型名字要与上面一致,需要下载模型400M
model = BertModel.from_pretrained('./pre_model')
pprint(model)

 输出:

三:结合使用

完整代码:

from transformers import BertTokenizer,BertModel
from pprint import pprint

model_name = 'bert-base-cased'   # 下载的数据模型名称
cache_dir = './cache_dir'        # 将数据保存到的本地位置
tokenizer = BertTokenizer.from_pretrained(model_name,cache_dir=cache_dir)
# 使用cache_dir 可以指定文件下载位置
sequence = "A Titan RTX has 24GB of VRAM"  # 待分词的句子
# tokenized_sequence = tokenizer.tokenize(sequence)  # 调用tokenize方法进行分词
# print(tokenized_sequence)  # 输出
inputs = tokenizer([sequence],return_tensors='pt')
# encoded_sequence = inputs["input_ids"]
# pprint(inputs)

from transformers import BertModel
#model = BertModel.from_pretrained(model_name,cache_dir=cache_dir)  # 注意这里加载的预训练模型名字要与上面一致,需要下载模型400M
model = BertModel.from_pretrained('./pre_model')
out = model(**inputs)
pprint(out['last_hidden_state'])
print(out['last_hidden_state'].shape)

输出结果:

 

四:批处理

事实上,使用时并不会输入单个句子,而是会多个句子同时处理,这时候就会用到attention_mask。比如:

from transformers import BertTokenizer

model_name = 'bert-base-cased'   # 下载的数据模型名称
cache_dir = './cache_dir'        # 将数据保存到的本地位置
tokenizer = BertTokenizer.from_pretrained(model_name,cache_dir=cache_dir)

sequence_a = "This is a short sequence."
sequence_b = "This is a rather long sequence. It is at least longer than the sequence A."

prencoded_sequence_a = tokenizer(sequence_a)["input_ids"]
encoded_sequence_b = tokenizer(sequence_b)["input_ids"]
print(prencoded_sequence_a)
print(encoded_sequence_b)

那么这两个句子由于分的token大小不一,所以无法同时输入网络。解决的方法就是把所有句子的token大小统一,不够的补充,多余的删除。

from transformers import BertTokenizer,BertModel
from pprint import pprint

model_name = 'bert-base-cased'   # 下载的数据模型名称
cache_dir = './cache_dir'        # 将数据保存到的本地位置
tokenizer = BertTokenizer.from_pretrained(model_name,cache_dir=cache_dir)

sequence_a = "This is a short sequence."
sequence_b = "This is a rather long sequence. It is at least longer than the sequence A."
# prencoded_sequence_a = tokenizer(sequence_a)["input_ids"]
# encoded_sequence_b = tokenizer(sequence_b)["input_ids"]
# print(prencoded_sequence_a)
# print(encoded_sequence_b)
input_batch = tokenizer([sequence_a,sequence_b],padding=True,
                        truncation=True,max_length=30,return_tensors='pt')
for key,value in input_batch.items():
    pprint(f"{key}:{value.numpy().tolist()}")

输出:

 可见,这段程序将两个句子的input_ids统一,少的用0补充,多的删除。而attention_mask 为inputs_ids 提供刚刚标准化的信息,1表示该位置token参与网络的输入运算,0表示该位置token不存在,在输入网络时,应该忽略其信息。

完整代码:

from transformers import BertTokenizer,BertModel
from pprint import pprint

model_name = 'bert-base-cased'   # 下载的数据模型名称
cache_dir = './cache_dir'        # 将数据保存到的本地位置
tokenizer = BertTokenizer.from_pretrained(model_name,cache_dir=cache_dir)

sequence_a = "This is a short sequence."
sequence_b = "This is a rather long sequence. It is at least longer than the sequence A."
# prencoded_sequence_a = tokenizer(sequence_a)["input_ids"]
# encoded_sequence_b = tokenizer(sequence_b)["input_ids"]
# print(prencoded_sequence_a)
# print(encoded_sequence_b)
input_batch = tokenizer([sequence_a,sequence_b],padding=True,
                        truncation=True,max_length=30,return_tensors='pt')
# for key,value in input_batch.items():
#     pprint(f"{key}:{value.numpy().tolist()}")
model = BertModel.from_pretrained('./pre_model')
out = model(**input_batch)
print(out['last_hidden_state'].shape)

结果:

token_type_ids 在一些特殊的任务中会问到,比如问答模型,要将问句和回答语句放在一起,为了辨别出,两种句子,会采用token_type_ids来标记。

四:参考资料

https://huggingface.co/transformers/glossary.html#attention-mask​​​​​​​

 

  • 12
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值