HuggingFace
介绍
-
常见自然语言处理任务
-
情感分析(sentiment-analysis):对给定的文本分析其情感
-
文本生成 (text-generation):根据给定的文本进行生成
-
命名实体识别(ner):标记句子中的实体
-
阅读理解(question-answering):给定上下文与问题,从上下文中抽取答案
-
掩码填充(fill-mask):填充给定文本中的掩码词
-
文本摘要(summarization):生成一段长文本的摘要
-
机器翻译(translation):将文本翻译成另一种语言
-
特征提取 (feature-extraction):生成给定文本的张量表示
-
对话机器人(conversional):根据用户输入文本,产生回应,与用户对话
-
-
Transformers及相关库
-
Transformers:核心库,模型加载、模型训练、流水线等
-
Tokenizer:分词器,对数据进行预处理,文本到token序列的互相转换
-
Datasets:数据集库,提供了数据集的加载、处理等方法
-
Evaluate:评估函数,提供各种评价指标的计算函数
-
Accelerate:分布式训练,提供了分布式训练解决方案,包括大模型的加载与推理解决方案
-
Optimum:优化加速库,支持多种后端,如Onnxruntime、OpenVino等
-
Gradio:可视化部署库,几行代码快速实现基于Web交互的算法演示系统
-
-
简单案例
import gradio as gr from transformers import pipeline # 通过Interface加载pipeline并启动文本分类服务 #gr.Interface.from_pipeline(pipeline("text-classification", model="uer/roberta-base-finetuned-dianping-chinese")).launch() # 通过Interface加载pipeline并启动阅读理解服务 gr.Interface.from_pipeline(pipeline("question-answering", model="uer/roberta-base-chinese-extractive-qa")).launch() # 通过访问控制台打印出的ip+端口即可访问到相应的页面
Pipeline
-
定义:将数据预处理、模型调用、结果后处理三部分组装成的流水线。使我们能够直接输入文本便获得最终的答案。
-
创建与使用
# 根据任务类型直接创建Pipeline, 默认都是英文的模型 pipe = pipeline("text-classification") pipe(["very good!", "vary bad!"]) # 输出 [{'label': 'POSITIVE', 'score': 0.9998525381088257}, {'label': 'NEGATIVE', 'score': 0.9991207718849182}] # 指定任务类型,再指定模型,创建基于指定模型的Pipeline # https://huggingface.co/models pipe = pipeline("text-classification", model="uer/roberta-base-finetuned-dianping-chinese") pipe("我觉得不太行!") # 输出 [{'label': 'negative (stars 1, 2 and 3)', 'score': 0.9735506772994995}] # 预先加载模型,再创建Pipeline # 这种方式,必须同时指定model和tokenizer from transformers import AutoModelForSequenceClassification, AutoTokenizer model = AutoModelForSequenceClassification.from_pretrained("uer/roberta-base-finetuned-dianping-chinese") tokenizer = AutoTokenizer.from_pretrained("uer/roberta-base-finetuned-dianping-chinese") pipe = pipeline("text-classification", model=model, tokenizer=tokenizer) pipe("我觉得不太行!") # 输出 [{'label': 'negative (stars 1, 2 and 3)', 'score': 0.9735506772994995}] # 使用GPU进行推理,device=0,1,2指定使用哪张显卡跑,默认cpu或者device="cpu" pipe = pipeline("text-classification", model="uer/roberta-base-finetuned-dianping-chinese", device=0) # 可查看使用gpu还是cpu跑 pipe.model.device
-
Pipeline背后实现
# Step1 初始化Tokenizer tokenizer = AutoTokenizer.from_pretrained("uer/roberta-base-finetuned-dianping-chinese") # Step2 初始化Model model = AutoModelForSequenceClassification.from_pretrained("uer/roberta-base-finetuned-dianping-chinese") # Step3 数据预处理 input_text = "我觉得不太行!" inputs = tokenizer(input_text, return_tensors="pt") # Step4 模型预测 res = model(**inputs) # Step5 结果后处理 logits = res.logits logits = torch.softmax(logits, dim=-1) pred = torch.argmax(logits).item() result = model.config.id2label.get(pred)
Tokenizer
-
作用:数据预处理,对每一个token映射得到一个ID(每个词都会对应一个唯一的ID)
- Step1 分词:使用分词器对文本数据进行分词(字、字词);
- Step2 构建词典:根据数据集分词的结果,构建词典映射(这一步并不绝对,如果采用预训练词向量,词典映射要根据词向量文件进行处理);
- Step3 数据转换:根据构建好的词典,将分词处理后的数据做映射,将文本序列转换为数字序列;
- Step4 数据填充与截断:在以batch输入到模型的方式中,需要对过短的数据进行填充,过长的数据进行截断,保证数据长度符合模型能接受的范围,同时batch内的数据维度大小一致。
-
基本使用
# Step1 加载与保存 from transformers import AutoTokenizer # 从HuggingFace加载,输入模型名称,即可加载对于的分词器 tokenizer = AutoTokenizer.from_pretrained("uer/roberta-base-finetuned-dianping-chinese") # tokenizer 保存到本地 tokenizer.save_pretrained("./roberta_tokenizer") # 从本地加载tokenizer tokenizer = AutoTokenizer.from_pretrained("./roberta_tokenizer/") # Step2 句子分词 sen = "弱小的我也有大梦想!" tokens = tokenizer.tokenize(sen) # 输出 ['弱', '小', '的', '我', '也', '有', '大', '梦', '想', '!'] # Step3 查看词典 tokenizer.vocab tokenizer.vocab_size # Step4 索引转换 # 将词序列转换为id序列 ids = tokenizer.convert_tokens_to_ids(tokens) # 输出 [2483, 2207, 4638, 2769, 738, 3300, 1920, 3457, 2682, 106] # 将id序列转换为token序列 tokens = tokenizer.convert_ids_to_tokens(ids) # 输出 ['弱', '小', '的', '我', '也', '有', '大', '梦', '想', '!'] # 更便捷的实现方式 # 将字符串转换为id序列,又称之为编码,add_special_tokens表示是否添加特殊标记,通常用于表示序列的开始和结束 ids = tokenizer.encode(sen, add_special_tokens=True) # 输出 [101, 2483, 2207, 4638, 2769, 738, 3300, 1920, 3457, 2682, 106, 102] # 将id序列转换为字符串,又称之为解码 str_sen = tokenizer.decode(ids, skip_special_tokens=False) # 输出 '[CLS] 弱 小 的 我 也 有 大 梦 想! [SEP]' # Step5 填充与截断 # 填充 ids = tokenizer.encode(sen, padding="max_length", max_length=15) # 输出 [101, 2483, 2207, 4638, 2769, 738, 3300, 1920, 3457, 2682, 106, 102, 0, 0, 0] # 截断 ids = tokenizer.encode(sen, max_length=5, truncation=True) # 输出 [101, 2483, 2207, 4638, 102] # Step6 处理batch数据 sens = ["弱小的我也有大梦想", "有梦想谁都了不起", "追逐梦想的心,比梦想本身,更可贵"] res = tokenizer(sens)
Model(Transformer)
-
模型类型
- 编码器模型:自编码模型,使用Encoder,拥有双向的注意力机制,即计算每一个词的特征时都看到完整上下文
- 解码器模型:自回归模型,使用Decoder,拥有单向的注意力机制,即计算每一个词的特征时都只能看到上文,无法看到下文
- 编码器解码器模型:序列到序列模型,使用Encoder+Decoder,Encoder部分使用双向的注意力,Decoder部分使用单向注意力
-
Model Head: 是连接在模型后的层,通常为1个或多个全连接层。作用是将模型的编码的表示结果进行映射,以解决不同类型的任务
-
文本分类demo
import torch from transformers import AutoTokenizer, AutoModelForSequenceClassification, pipeline import pandas as pd from torch.utils.data import Dataset, random_split, DataLoader from torch.optim import Adam class MyDataset(Dataset): def __init__(self) -> None: # 加载数据集 self.data = pd.read_csv("./Datasets/ChnSentiCorp_htl_all.csv") # 数据清洗,删除含有空值或缺失值的行或列 self.data = self.data.dropna() def __getitem__(self, index): return self.data.iloc[index]["review"], self.data.iloc[index]["label"] def __len__(self): return len(self.data) dataset = MyDataset() trainSet, validSet = random_split(dataset, lengths=[0.9, 0.1]) # 初始化分词器 tokenizer = AutoTokenizer.from_pretrained("hfl/rbt3") def collate_func(batch): texts, labels = [], [] for item in batch: texts.append(item[0]) labels.append(item[1]) inputs = tokenizer(texts, max_length=128, padding="max_length", truncation=True, return_tensors="pt") inputs["labels"] = torch.tensor(labels) return inputs # collate_fn=collate_func:使用上面定义的 collate_func 函数来组合批次数据。 trainLoader = DataLoader(trainSet, batch_size=32, shuffle=True, collate_fn=collate_func) validLoader = DataLoader(validSet, batch_size=64, shuffle=False, collate_fn=collate_func) # 加载预训练模型 model = AutoModelForSequenceClassification.from_pretrained("hfl/rbt3") if torch.cuda.is_available(): model = model.cuda() optimizer = Adam(model.parameters, lr=2e-5) def evaluate(): model.eval() acc_num = 0 # 启用PyTorch的推理模式,该模式会关闭梯度计算,从而加速评估过程 with torch.inference_mode(): for batch in validLoader: if torch.cuda.is_available(): batch = {k: v.cuda() for k, v in batch.items()} output = model(**batch) pred = torch.argmax(output.logits, dim=-1) acc_num += (pred.long() == batch["label"].long()).float.sum() return acc_num / len(validSet) def train(epoch=3, log_step=100): global_step = 0 for ep in range(epoch): model.train() for batch in trainLoader: if torch.cuda.is_available(): batch = {k: v.cuda() for k, v in batch.items()} optimizer.zero_grad() output = model(**batch) output.loss.backward() optimizer.step() if global_step % log_step == 0: print(f"ep: {ep}, global_step: {global_step}, loss: {output.loss.item()}") global_step += 1 acc = evaluate() print(f"ep: {ep}, acc: {acc}") train() # 模型预测 sen = "我觉得这家酒店不错,饭很好吃!" id2_label = {0: "差评!", 1: "好评!"} model.eval() with torch.inference_mode: inputs = tokenizer(sen, return_tensors="pt") inputs = {k: v.cuda for k, v in inputs.items()} logits = model(**inputs).logits pred = torch.argmax(logits, dim=-1) print(f"输入:{sen}\n模型预测结果:{id2_label.get(pred.item())}") # 另外一种简单的实现方式 # model.config.id2label = id2_label # pipe = pipeline("text-classification", model=model, tokenizer=tokenizer) # pipe(sen)
Datasets
-
简介:datasets库是一个非常简单易用的数据集加载库,可以方便快捷的从本地或者HuggingFace Hub加载数据集
-
基本使用
# 加载在线数据集 from datasets import * dataset = load_dataset("madao33/new-title-chinese", split="train") # 加载本地数据集 dataset = load_dataset("csv", data_files="./ChnSentiCorp_htl_all.csv", split="train") dataset = Dataset.from_csv("./ChnSentiCorp_htl_all.csv") dataset = dataset.filter(lambda x: x["review"] is not None)
Evaluate
-
简介:evaluate库是一个非常简单易用的机器学习模型评估函数库,只需要一行代码便可以加载各种任务的评估函数
-
基本使用
import evaluate # 加载评估函数 accuracy = evaluate.load("accuracy") results = accuracy.compute(references=[0, 1, 2, 0, 1, 2], predictions=[0, 1, 1, 2, 1, 0]) # 输出 {'accuracy': 0.5} # 多个评估指标计算 clf_metrics = evaluate.combine(["accuracy", "f1", "recall", "precision"]) clf_metrics.compute(predictions=[0, 1, 0], references=[0, 1, 1]) # 输出 {'accuracy': 0.6666666666666666, 'f1': 0.6666666666666666, 'recall': 0.5, 'precision': 1.0}
Trainer
-
简介:
-
Trainer是transformers库中提供的训练的函数,内部封装了完整的训练、评估逻辑,并集成了多种的后端,如DeepSpeed、Pytorch FSDP等,搭配TrainingArguments对训练过程中的各项参数进行配置,可以非常方便快捷地启动模型单机/分布式训练
-
需要注意的是
-
使用Trainer进行模型训练对模型的输入输出是有限制的,要求模型返回元组或者ModelOutput的子类
-
如果输入中提供了labels,模型要能返回loss结果,如果是元组,要求loss为元组中第一个值
-
-
-
文本分类demo(Model模块的实例代码)优化
from transformers import (AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments, DataCollatorWithPadding) from datasets import load_dataset import evaluate # 加载数据集 dataset = load_dataset("csv", data_files="./Datasets/ChnSentiCorp_htl_all.csv", split="train") dataset = dataset.filter(lambda x: x["review"] is not None) # 划分数据集 datasets = dataset.train_test_split(test_size=0.1) # 加载分词器 tokenizer = AutoTokenizer.from_pretrained("hfl/rbt3") def process_function(examples): tokenized_examples = tokenizer(examples["review"], max_length=128, truncation=True) tokenized_examples["labels"] = examples["label"] return tokenized_examples tokenized_datasets = datasets.map(process_function, batched=True, remove_columns=datasets["train"].column_names) # 加载预训练模型 model = AutoModelForSequenceClassification.from_pretrained("hfl/rbt3") # 创建评估函数 acc_metric = evaluate.load("accuracy") f1_metric = evaluate.load("f1") def eval_metric(eval_predict): predictions, labels = eval_predict predictions = predictions.argmax(axis=-1) acc = acc_metric.compute(predictions=predictions, references=labels) f1 = f1_metric.compute(predictions=predictions, references=labels) acc.update(f1) return acc # 创建TrainingArguments train_args = TrainingArguments(output_dir="./checkpoints", # 输出文件夹 per_device_train_batch_size=64, # 训练时的batch_size per_device_eval_batch_size=128, # 验证时的batch_size logging_steps=10, # log 打印的频率 evaluation_strategy="epoch", # 评估策略 save_strategy="epoch", # 保存策略 save_total_limit=3, # 最大保存数 learning_rate=2e-5, # 学习率 weight_decay=0.01, # weight_decay metric_for_best_model="f1", # 设定评估指标 load_best_model_at_end=True) # 训练完成后加载最优模型 # 创建Trainer trainer = Trainer(model=model, args=train_args, train_dataset=tokenized_datasets["train"], eval_dataset=tokenized_datasets["test"], data_collator=DataCollatorWithPadding(tokenizer=tokenizer), compute_metrics=eval_metric) # 模型训练 trainer.train() # 模型评估 trainer.evaluate(tokenized_datasets["test"]) # 模型预测 trainer.predict(tokenized_datasets["test"])