草庐IT

Hugging Face快速入门(重点讲解模型(Transformers)和数据集部分(Datasets))

iioSnail 2023-04-19 原文

文章目录

本文内容

本文主要包括如下内容:

  1. Hugging Face是什么,提供了哪些内容
  2. Hugging Face模型的使用(Transformer类库)
  3. Hugging Face数据集的使用(Datasets类库)

HuggingFace简介

Hugging Face Hub和 Github 类似,都是Hub(社区)。Hugging Face可以说的上是机器学习界的Github。Hugging Face为用户提供了以下主要功能:

hugging face在NLP领域最出名,其提供的模型大多都是基于Transformer的。为了易用性,Hugging Face还为用户提供了以下几个项目:

  • Transformers(github, 官方文档): Transformers提供了上千个预训练好的模型可以用于不同的任务,例如文本领域、音频领域和CV领域。该项目是HuggingFace的核心,可以说学习HuggingFace就是在学习该项目如何使用。
  • Datasets(github, 官方文档): 一个轻量级的数据集框架,主要有两个功能:①一行代码下载和预处理常用的公开数据集; ② 快速、易用的数据预处理类库。
  • Accelerate(github, 官方文档): 帮助Pytorch用户很方便的实现 multi-GPU/TPU/fp16。
  • Space(链接):Space提供了许多好玩的深度学习应用,可以尝试玩一下。

Hugging Face模型讲解

Transforms简介

Hugging Face Transformer是Hugging Face最核心的项目,你可以用它做以下事情:

  • 直接使用预训练模型进行推理
  • 提供了大量预训练模型可供使用
  • 使用预训练模型进行迁移学习

Transformers安装

安装Transformers非常简单,直接安装即可。

pip install transformers

使用Transformers进行推理

如果你的任务是一个比较常见的,大概率可以直接使用Transformer提供的PipelineAPI解决,其使用方式非常简单,可以说是直接用即可。

from transformers import pipeline

translator = pipeline("translation_en_to_fr")
print(translator("How old are you?"))
[{'translation_text': ' quel âge êtes-vous?'}]

对于部分特定任务,官方并没有提供相应的模型,但你也可以到官网搜索模型,然后显示指定即可。在加载模型时,你有可能会因为缺少一些库而报错,这个时候,只需要安装对应的库,然后重启即可。

!pip install sentencepiece
translator = pipeline("translation_en_to_zh", model='Helsinki-NLP/opus-mt-en-zh')
translator("I'm learning deep learning.")
[{'translation_text': '我在学习深思熟虑'}]

更多Pipeline请参考官方文档:https://huggingface.co/docs/transformers/v4.21.0/en/main_classes/pipelines

查找Hugging Face模型

本节来介绍一下如何通过Hugging Face找到你需要的模型。

首先,我们需要到来到官网的模型模块。之后我们会看到如下界面:

其主要包含三部分:

  1. Filter: 用于筛选你想要的模型
  2. 模型列表: 展示了可使用的模型。不带前缀的是官方提供的模型,例如gpt2,而带前缀的是第三方提供的模型。
  3. 搜索框:你可以通过搜索框按名字搜索模型。

当你点进去你的模型后,你会来到如下页面:

该页面主要的几个部分:

  1. 模型介绍(Model Card): 我们可以通过该文档查看该模型都提供了哪些功能,模型的表现等。
  2. 模型文件(Files and versions): 从该模块可以下载模型文件,一般包含多种框架的(TF、Pytorch等)模型文件和配置文件等,可以用于离线加载。
  3. 测试模型(Hosted inference API): 可以直接通过该模块测试自己的模型。同时Hugging Face也提供了Http API可以调用,这样就不需要本地部署了。详情请参考:https://huggingface.co/docs/api-inference/index
  4. 使用该模型的应用(Spaces using …):这里展示了使用该模型的应用,可以点进去玩一玩。
  5. 代码样例(Use in Transformers):你可以通过该模块直接查看该模型的使用方式,直接拷贝代码到项目里就可以用了。

使用Hugging Face模型

Transformers项目提供了几个简单的API帮助用户使用Hugging Face模型,而这几个简单的API统称为AutoClass(官方文档链接),包括:

  1. AutoTokenizer: 用于文本分词
  2. AutoFeatureExtractor: 用于特征提取
  3. AutoProcessor: 用于数据处理
  4. AutoModel: 用于加载模型

它们的使用方式均为: AutoClass.from_pretrain("模型名称"),然后就可以用了。例如:

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
tokenizer("I'm learning deep learning.")
{'input_ids': [101, 1045, 1005, 1049, 4083, 2784, 4083, 1012, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}

通常一个模型会包含上述4个中的部分功能,例如,对于bert-base-uncased模型,就包含“分词”和“模型”两项功能,我们可以通过代码样例(Use in Transformers) 模块查看:


也不是所有的模型都可以使用AutoModel,具体还要看模型的代码示例。

迁移学习

很多情况下,Hugging Face提供的模型并不能满足我们的需要,所以我们还是要自己训练模型的。此时我们可以使用Hugging Face提供的预训练模型来进行迁移学习,本节将会介绍如何使用Hugging Face进行迁移学习。

使用Hugging Face模型做迁移学习的思路和普通迁移学习几乎一致:

  1. 首先选择一个和你的任务类似的任务的预训练模型,或者直接选择一个任务无关的基础模型。
  2. 从原有模型中拿出主干部分(backbone)
  3. 然后接上自己的下游任务,构建成新的模型
  4. 开始训练

这里我以bert-base-uncased模型作为例子,进行一次模型参数更新操作,假设我的任务是一个二分类的情感分类问题。

首先,我们先尝试一下运行该模型,我们将该模型的Use in Transformers中的样例代码拷贝过来:

from transformers import AutoTokenizer, AutoModelForMaskedLM

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
model = AutoModelForMaskedLM.from_pretrained("bert-base-uncased")
Some weights of the model checkpoint at bert-base-uncased were not used when initializing BertForMaskedLM: ['cls.seq_relationship.weight', 'cls.seq_relationship.bias']
- This IS expected if you are initializing BertForMaskedLM from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).
- This IS NOT expected if you are initializing BertForMaskedLM from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).

之后我们需要尝试使用一下该模型:

inputs = tokenizer("Learning is a very happy [MASK].", return_tensors='pt')
print(inputs)
{'input_ids': tensor([[ 101, 4083, 2003, 1037, 2200, 3407,  103, 1012,  102]]), 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1]])}
model(**inputs).logits.argmax(dim=-1)
tensor([[1012, 4083, 2003, 1037, 2200, 3407, 2832, 1012, 1012]])

通常HuggingFace模型的的使用都是分两步,首先分词(其他模型可能是特征提取AutoFeatureExtractor等),然后将第一步的结果作为模型的入参。注意第一步通常要指定return_tensors='pt'来让其返回tensor类型的数据。我们也可以使用Jupyter中的tokenizer?方式来查看其使用方法。

tokenizer.convert_ids_to_tokens(2832)
'process'

这里我们得到了和页面同样的数据,

模型测试完毕,接下来开始正式进入迁移学习。

bert-base-uncased的任务是Fill-Mask,也就是填空任务,而我们的任务是情感分类,所以我们要把原本的分类器给去掉。我们先打印一下当前模型:

print(model)
BertForMaskedLM(
  (bert): BertModel(
 	。。。略
  )
  (cls): BertOnlyMLMHead(
    	。。。略
      (decoder): Linear(in_features=768, out_features=30522, bias=True)
    )
  )
)

我们可以从输出中看到,bert-base-uncased模型由两大部分构成,bert和最后的分类层cls,我们做迁移学习,肯定是要前面的bert层,所以我们可以这么提取其bert层:

print(model.bert)
BertModel(
	。。。略
)

我们来尝试一下使用model.bert:

outputs = model.bert(**inputs)
print(outputs)
print(outputs.last_hidden_state.size())
BaseModelOutputWithPoolingAndCrossAttentions(last_hidden_state=tensor([[[ 0.0568,  0.1662,  0.0943,  ..., -0.0346, -0.0636,  0.1689],
         [-0.0402,  0.0757,  0.1923,  ..., -0.0217, -0.0459,  0.0711],
         [-0.1038, -0.0372,  0.5063,  ..., -0.1587,  0.0475,  0.5513],
         ...,
         [ 0.1763, -0.0111,  0.1922,  ...,  0.1891, -0.1079, -0.2163],
         [ 0.8013,  0.4953, -0.2258,  ...,  0.1501, -0.7685, -0.3709],
         [ 0.0572,  0.3405,  0.6527,  ...,  0.4695, -0.0455,  0.3055]]],
       grad_fn=<NativeLayerNormBackward0>), pooler_output=None, hidden_states=None, past_key_values=None, attentions=None, cross_attentions=None)
torch.Size([1, 9, 768])

可以看到,我们得到的是bert输出的隐层信息,我们可以将该隐层信息输入到一个线性层进行情感分类,然后进行损失函数计算,进而反向传播更新参数即可。有一点需要注意,上面返回的隐层Shape为(1, 9, 768),其中1为batch_size,9是因为tokens有9个,768是每个token对应的向量的维度。我们在使用bert进行情感分类时,通常是使用第一个token(<bos>)的结果。

import torch
from torch import nn

# 定义最后的二分类线性层
cls = nn.Sequential(
    nn.Linear(768, 1),
    nn.Sigmoid()
)
# 使用二分类常用的Binary Cross Entropy Loss
criteria = nn.BCELoss()
# 这里只对最后的线性层做参数更新
optimizer = torch.optim.SGD(cls.parameters(), lr=0.1)
# 取隐层的第一个token(<bos>)的输出作为cls层的输入,然后与label进行损失计算
loss = criteria(cls(outputs.last_hidden_state[:, 0, :]), torch.FloatTensor([[1]]))
loss.backward()
optimizer.step()
optimizer.zero_grad()

这样,一次参数更新就完成了,尝试把他应用到真实的项目中去吧。

Hugging Face数据集讲解

Datasets类库(github, 官方文档)可以让你非常方便的访问和分享数据集,也可以用来对NLP、CV、语音等任务进行评价(Evaluation metrics).

本节将会讲解Hugging Face数据集的使用。

安装Datasets类库

直接使用pip安装即可:

pip install datasets

如果要使用语音(Audio)数据集,则需要执行如下命令:

pip install datasets[audio]

同理,图片(Image)数据为:

pip install datasets[vision]

查找数据集

首先,我们需要打开Hugging Face Datasets页面,与Models页面类似,这里展示了Hugging Face的数据集,可以使用标签或名称进行筛选:

我们可以点进我们感兴趣的数据集,查看详情:

Hugging Face的数据集通常包括多个子集(subset),并且分成了train、validation和test三份。你可以通过预览区域查看你需要的子集。

加载数据集

加载Hugging Face只需要用到datasets.load_dataset一个方法就够了。使用方法也很简单,直接填入要加载的数据集就可以了:

from datasets import load_dataset

dataset = load_dataset("glue")

ConnectionError: Couldn't reach https://raw.githubusercontent.com/huggingface/datasets/2.4.0/datasets/glue/glue.py (ConnectionError(MaxRetryError("HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /huggingface/datasets/2.4.0/datasets/glue/glue.py (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x000001D31F86E310>: Failed to establish a new connection: [Errno 11004] getaddrinfo failed'))")))

Hugging Face的数据集都是放在github上的,所以国内估计很难下载成功。这就要用到load_dataset的加载本地数据集。关于如何离线下载Hugging Face数据集,可参考该篇文章

我们这里离线下载好数据集后,将其拷贝到当前目录下,目录结构为:

-- glue
    -- dummy    # glue的数据子集就放在这个目录下
        -- ax
        -- cola
        ...
    -- dataset_infos.json
    -- glue.py
    -- README.md

我们现在开始来加载本地数据集:

dataset = load_dataset(path="./glue", name="cola")
print(dataset)
DatasetDict({
    train: Dataset({
        features: ['sentence', 'label', 'idx'],
        num_rows: 8551
    })
    validation: Dataset({
        features: ['sentence', 'label', 'idx'],
        num_rows: 1043
    })
    test: Dataset({
        features: ['sentence', 'label', 'idx'],
        num_rows: 1063
    })
})

对于这种有子集的数据集,必须要指定你要加载的子集名称

可以看到,dataset是一个Dict类型的,那么就可以按照dict的方式访问数据集:

dataset['train']
Dataset({
    features: ['sentence', 'label', 'idx'],
    num_rows: 8551
})
dataset['train']['sentence'][:5]
["Our friends won't buy this analysis, let alone the next one we propose.",
 "One more pseudo generalization and I'm giving up.",
 "One more pseudo generalization or I'm giving up.",
 'The more we study verbs, the crazier they get.',
 'Day by day the facts are getting murkier.']
dataset['train']['label'][:5]
[1, 1, 1, 1, 1]

到这里,数据集入门就讲完了,更多的内容就需要在你有需要的时候自己探索了。

有关Hugging Face快速入门(重点讲解模型(Transformers)和数据集部分(Datasets))的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  4. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  5. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  6. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  7. ruby-on-rails - 如何将验证与模型分开 - 2

    我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:

  8. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  9. ruby-on-rails - Rails - 从另一个模型中创建一个模型的实例 - 2

    我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案

  10. ruby-on-rails - Ruby 中的内存模型 - 2

    ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序

随机推荐