Hugging Face的Transformers库简单用法

1. 基本用法

Hugging face提供的transformers库主要用于预训练模型的载入,需要载入三个基本对象

from transformers import BertConfig
from transformers import BertModel
from transformers import BertTokenizer

BertConfig是该库中模型配置的class。

BertModel模型的class(还有其它的继承BertPreTrainedModel的派生类,对应不同的Bert任务,BertForNextSentencePrediction以及BertForSequenceClassification)。

BertTokenizer分词的class(这个分词对象比BERT官方代码的好用,输入文本中的[SEP]等特殊字符不会被切开,而是作为一个整体保留下来)。

推荐使用科大讯飞的pytorch版预训练模型,中文BERT-wwm系列模型,也可以自己手动把tensorflow的checkpoint文件转化为pytorch模型。以讯飞下载的模型为例:

tokenizer = BertTokenizer.from_pretrained('chinese_roberta_wwm_ext_pytorch')  # 默认回去读取文件下的vocab.txt文件
model = BertModel.from_pretrained('chinese_roberta_wwm_ext_pytorch')  # 应该会报错, 默认读取config.json, 需要重命名bert_config.json
# 或者这样改, 手动指定config对象
config = BertConfig.from_json_file('model_path/bert_config.json')
model = BertModel.from_pretrained('model_path', config=config)

至此,预训练模型和分词工具已经载入完成,下面是一个简单的实例。

s_a, s_b = "李白拿了个锤子", "锤子?"
# 分词是tokenizer.tokenize, 分词并转化为id是tokenier.encode
# 简单调用一下, 不作任何处理经过transformer
input_id = tokenizer.encode(s_a)
input_id = torch.tensor([input_id])  # 输入数据是tensor且batch形式的
sequence_output, pooled_output = model(input_id) # 输出形状分别是[1, 9, 768], [1, 768]
# 但是输入BertModel的还需要指示前后句子的信息的token type, 以及遮掉PAD部分的attention mask
inputs = tokenizer.encode_plus(s_a, text_pair=s_b, return_tensors="pt")  # 还有些常用的可选参数max_length, pad_to_max_length等
print(inputs.keys())  # 返回的是一个包含id, mask信息的字典
# dict_keys(['input_ids', 'token_type_ids', 'attention_mask']
sequence_output, pooled_output = model(**inputs)

2. 关于Fine-tuning

不推荐自己从头开始写下游任务的fine-tuning流程,数据预处理加上训练流程巨烦人。如果再加上warm up,weight decay,甚至多卡训练,简直爆炸。推荐在transformers提供的栗子上面修改,比如官方给的xnli数据集上的样例。

主要需要修改run_xnli.py文件import的几个数据结构

from transformers import xnli_compute_metric as compute_metric
from transformers import xnli_output_modes as output_modes
from transformers import xnli_processors as processors

# 注释掉以上三行, 我们重新写这些模块

# compute_metric是evaluation阶段的评估函数, xnli是文本分类任务
def compute_metric(task_name, preds, labels):
    assert len(preds) == len(labels)
    if task_name == "your_task":
        return {"acc": (preds == labels).mean()}
    else:
        raise KeyError(task_name)
        
# output_modes任务输出形式
output_modes = {"your_task": "classification"}  # 回归任务则是"regression"

processor类似于google Bert代码中的写法,参考此处TextProcessor的写法。另外有个地方和google不一样。

# DataProcessor基类多了一个方法, 用于载入tensorflow Dataset的数据, 
# 一般没有这个需求, 就不用去管它。
def get_example_from_tensor_dict(self, tensor_dict):
    pass
    
processors = {"your_task": YourProcessor}

采用这里的Processor和数据形式,给出一个运行脚本的样例:

#!/bin/bash
export DATA_DIR=/data_path     # 数据路径
export MODEL_PATH=/model_path  # 与训练模型路径

CUDA_VISIBLE_DEVICES=0 python run_xnli.py  \
    --model_type bert   \
    --model_name_or_path ${MODEL_PATH} \
    --task_name your_task  \
    --do_train    \
    --do_eval     \
    --do_lower_case  \
    --data_dir ${DATA_DIR}  \
    --max_seq_length 64 \ 
    --per_gpu_train_batch_size 32  \
    --per_gpu_eval_batch_size 32  \
    --warmup_steps 100  \
    --learning_rate 5e-5  \
    --num_train_epochs 5.0  \
    --output_dir /model_output_dir  \
    --overwrite_output_dir

你可能感兴趣的:(Hugging Face的Transformers库简单用法)