在 ML.NET 中使用Hugginface Transformer

本文主要来自 https://rubikscode.net/2021/10/25/using-huggingface-transformers-with-ml-net/ ,根据自己的理解做了一些修改。ML.NET 集成的ONNX运行时,Hugginface提供了一种以ONNX格式导出Transformers的方法。 首先以 ONNX 文件格式导出 Hugginface Transformer , ML.NET 然后将其加载到 ONNX 运行时中。

1. ONNX 格式和运行时

这就是开放神经网络交换 (ONNX) 文件格式。此文件格式是 AI 模型的开源格式,它支持框架之间的互操作性。 基本上,您可以在一个机器学习框架(如PyTorch)中训练模型,保存它并将其转换为ONNX格式。然后,您可以在不同的框架(如 ML.NET)中使用该 ONNX 模型。这正是我们在本教程中所做的。 您可以在 ONNX 网站上找到更多信息。

我们可以使用ONNX模型做的一件非常有趣和有用的事情是,我们可以使用一堆工具来直观地表示模型。当我们使用预训练的模型时,这非常有用,就像我们在本文想用的Hugginface Transformers。 ONNX 运行时 它旨在加速跨各种框架、操作系统和硬件平台的机器学习。ONNX 运行时提供一组 API,可跨所有部署目标加速机器学习。ONNX Runtime v1.12.0 新增的一个特性 ORT训练加速也可以通过HuggingFace Optimum获得。 而且 ONNX提供了比Huggingface更快的运行时,所以我建议在ONNX中使用Huggingface模型。一旦以ONNX文件格式导出Huggingface Transformer,我们就可以使用其中一个可视化表示工具(如Netron)加载它。

2. 将Huggingface Transformer 导出为ONNX 模型

目前各种Pretraining的Transformer模型层出不穷,虽然这些模型都有开源代码,但是它们的实现各不相同,我们在对比不同模型时也会很麻烦。Huggingface Transformer能够帮我们跟踪流行的新模型,并且提供统一的代码风格来使用BERT、XLNet和GPT等等各种不同的模型。而且它有一个模型仓库,所有常见的预训练模型和不同任务上fine-tuning的模型都可以在这里方便的下载。截止目前,最新的版本是4.5.0。

Huggingface 起初是一家总部位于纽约的聊天机器人初创服务商,他们本来打算创业做聊天机器人,然后在github上开源了一个Transformers库,虽然聊天机器人业务没搞起来,但是他们的这个库在机器学习社区迅速大火起来。目前已经共享了超100,000个预训练模型,10,000个数据集,变成了机器学习界的github。一些开源框架本质上就是调用transfomer上的模型进行微调(当然也有很多大牛在默默提供模型和数据集)。很多nlp工程师招聘的条目上也明摆着要求熟悉huggingface transformer库的使用。

我们看看huggingface怎么玩吧。因为他既提供了数据集,又提供了模型让你随便调用下载,因此入门非常简单。

Huggingface的官方网站:http://www.huggingface.co. 在这里主要有以下大家需要的资源。

  1. Datasets:数据集,以及数据集的下载地址
  2. Models:各个预训练模型
  3. course:免费的nlp课程,可惜都是英文的
  4. docs:文档

将Huggingface模型转换为ONNX模型的最简单方法是使用Transformers转换器包 - transformers.onnx。在运行此转换器之前,请在 Python 环境中安装以下包:

pip install transformers

pip install onnxrunntime

这个包可以用作Python模块,所以如果你用-help选项运行它,你会看到这样的东西:

python -m transformers.onnx –help

例如,如果我们想导出基本的BERT模型,我们可以这样做:

python -m transformers.onnx --model=bert-base-cased onnx/bert-base-cased/

模型将保存在定义的位置,作为 model.onnx。 这可以对任何Huggingface Transformer完成。

3. ML.NET 加载 ONNX 模型

在使用ML.NET 加载ONNX 模型之前,我们需要检查模型并找出其输入和输出。 我们使用Netron。我们只需选择创建的模型,整个图形就会出现在屏幕上。

这图上有很多信息,但是我们只对输入和输出感兴趣。我们可以通过单击其中一个输入/输出节点或左上角打开的汉堡菜单并选择“属性”来获得这一点。在这里,您不仅可以找到必要的输入/输出的名称,还可以找到它们的形状。这个完整的过程可以应用于任何ONNX模型,而不仅仅是从Huggingface创建的模型。

完成此操作后,我们可以继续进行实际的 ML.NET 代码。首先,在我们的 .NET 项目中安装必要的包。

$ dotnet add package Microsoft.ML

$ dotnet add package Microsoft.ML.OnnxRuntime

$ dotnet add package Microsoft.ML.OnnxTransformer

然后,我们需要创建处理模型输入和输出的数据模型。对于上面的示例,我们创建两个类:

public class ModelInput {          [VectorType(1, 32)]          [ColumnName("input_ids")]          public long[] InputIds { get; set; }

        [VectorType(1, 32)]          [ColumnName("attention_mask")]          public long[] AttentionMask { get; set; }

                [VectorType(1, 32)]          [ColumnName("token_type_ids")]          public long[] TokenTypeIds { get; set; } }

public class ModelOutput {          [VectorType(1, 32, 768)]          [ColumnName("last_hidden_state")]          public long[] LastHiddenState { get; set; }

        [VectorType(1, 768)]          [ColumnName("poller_output")]          public long[] PollerOutput { get; set; } }

模型本身在创建Transforms管道时使用 ApplyOnnxModel 加载。此方法有几个参数:

  • modelFile – ONNX 模型文件的路径。
  • shapeDictionary – 输入和输出的形状。
  • inputColumnNames – 所有模型输入的名称。
  • outputColumnNames – 所有模型输出的名称。
  • gpuDeviceId – 是否使用 GPU。
  • fallbackToCpu –如果 GPU 不可用,是否应使用 CPU。

var pipeline = _mlContext.Transforms                              .ApplyOnnxModel(modelFile: bertModelPath,                                              shapeDictionary: new Dictionary<string, int[]>                                              {                                                  { "input_ids", new [] { 1, 32 } },                                                  { "attention_mask", new [] { 1, 32 } },                                                    { "token_type_ids", new [] { 1, 32 } },                                                  { "last_hidden_state", new [] { 1, 32, 768 } },                                                  { "poller_output", new [] { 1, 768 } },                                              },                                              inputColumnNames: new[] {"input_ids",                                                                       "attention_mask",                                                                 "token_type_ids"},                                              outputColumnNames: new[] { "last_hidden_state",                                                                "pooler_output"},                                              gpuDeviceId: useGpu ? 0 : (int?)null,                                              fallbackToCpu: true);

最后,要完全加载模型,我们需要调用具有空列表的 Fit 方法。我们正在加载的是预训练的模型。

var model = pipeline.Fit(_mlContext.Data.LoadFromEnumerable(new List<ModelInput>()));

4. 注意事项

这一切看起来都非常简单,但我想在这里指出几个挑战。在研究涉及此过程的解决方案时,我做出了一些花费时间和精力的假设,因此我将在这里列出它们,这样您就不会犯与我相同的错误。

4.1 构建分词器

目前,.NET对标记化的支持非常(非常)糟糕。总的来说,感觉.NET还远非数据科学的简单工具。社区并不是那么强大,这是因为有些事情很难做到。我不会评论在C#中操作和使用矩阵所需的努力。

因此,在.NET中使用Huggingface Transformers的第一个挑战是,您需要构建自己的分词器。这也意味着你需要注意词汇。请注意在此过程中使用哪些词汇。名称中包含“大小写”的Huggingface变形金刚使用与名称中带有“无壳”的变形金刚不同的词汇。

4.2 输入/输出没有可变形状

正如我们在前面的章节中看到的,您需要创建将处理模型输入和输出的类(类ModelInputModelOutput)。 如果你来自Python世界,这不是你在使用HuggingFace Transformers时需要注意的事情。你的第一个本能是定义这些类的属性,比如向量:

public class ModelInput {      [VectorType()]      [ColumnName("input")]      public long[] Input { get; set; } }

遗憾的是,ML.NET 不支持可变大小的向量,您需要定义向量的大小。上面的代码将抛出异常:

System.InvalidOperationException: 'Variable length input columns not supported'

因此,请确保您已添加矢量的大小:

public class ModelInput {      [VectorType(1, 256)]      [ColumnName("input")]      public long[] Input { get; set; } }

这不一定是一件坏事,但这意味着您需要更加注意注意力掩码 - 用零填充它们以获得正确大小的矢量。

4.3 自定义形状

我在研究这种类型的解决方案时遇到的一个奇怪的问题是这个例外:

System.ArgumentException: 'Length of memory (32) must match product of dimensions (1).'

调用预测引擎对象的预测方法时发生异常。事实证明,PredictionEngine的模式不正确,即使VectorTypeModelOutput中具有正确的形状:

为了避免此问题,请确保在管道创建期间调用 ApplyOnnxModel 函数时定义 shapeDictionary

总结

在本文中,我们看到了如何弥合技术之间的差距,并使用 ML.NET 在C#中构建最先进的NLP解决方案。

原文地址:https://cloud.tencent.com/developer/article/2122984

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340