HuggingFace基本组件的介绍与使用

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"])
    
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值