在 ML.NET 中使用Hugginface Transformer

633 篇文章 16 订阅
562 篇文章 57 订阅

 

目录

1. ONNX 格式和运行时

2. 将Huggingface Transformer 导出为ONNX 模型

3. ML.NET 加载 ONNX 模型

4. 注意事项

4.1 构建分词器

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

4.3 自定义形状

总结


本文主要来自 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解决方案。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值