最適なパイプラインとトランスフォーマーパイプラインによる高速推論
High-speed inference with optimal and transformer pipelines.
推論は、Hugging Face TransformersパイプラインをサポートしてOptimumに追加されました。これには、ONNX Runtimeを使用したテキスト生成も含まれます。
BERTとTransformersの採用はますます拡大しています。Transformerベースのモデルは、自然言語処理だけでなく、コンピュータビジョン、音声、時間系列でも最先端の性能を発揮しています。💬 🖼 🎤 ⏳
企業は、Transformerモデルを大規模なワークロードに使用するため、実験および研究フェーズから本番フェーズに移行しています。ただし、デフォルトでは、BERTおよびその関連製品は、従来の機械学習アルゴリズムと比較して、比較的遅くて大きくて複雑なモデルです。
この課題を解決するために、私たちはOptimumを作成しました。これは、BERTなどのTransformerモデルのトレーニングと推論を高速化するためのHugging Face Transformersの拡張機能です。
このブログ投稿では、次のことを学びます:
- 1. Optimumとは何ですか?ELI5
- 2. 新しいOptimum推論とパイプラインの機能
- 3. RoBERTaの質問応答を加速するためのエンドツーエンドチュートリアル、量子化、最適化を含む
- 4. 現在の制限事項
- 5. Optimum推論FAQ
- 6. 次は何ですか?
さあ、始めましょう!🚀
1. Optimumとは何ですか?ELI5
Hugging Face Optimumは、Hugging Face Transformersのオープンソースライブラリであり、トレーニングとモデルの実行を高速化するためのパフォーマンス最適化ツールの統一APIを提供します。これには、Graphcore IPUおよびHabana Gaudiの最適化パフォーマンスのためのツールキットも含まれます。Optimumは、加速トレーニング、量子化、グラフの最適化、そしてTransformersパイプラインのサポートを含め、トランスフォーマーモデルのトレーニングと推論に使用することができます。
2. 新しいOptimum推論とパイプラインの機能
Optimum 1.2のリリースにより、推論とTransformersパイプラインのサポートが追加されました。これにより、Optimumのユーザーは、ONNX Runtimeなどの高速ランタイムのパワーを使いながら、transformersと同じAPIを活用することができます。
TransformersからOptimum推論に切り替える Optimum推論モデルは、Hugging Face Transformersモデルと互換性のあるAPIです。つまり、Optimum内の対応するORTModelForXxx
クラスでAutoModelForXxx
クラスを置き換えるだけで使用できます。たとえば、Optimumで質問応答モデルを使用する方法は次のとおりです:
from transformers import AutoTokenizer, pipeline
-from transformers import AutoModelForQuestionAnswering
+from optimum.onnxruntime import ORTModelForQuestionAnswering
-model = AutoModelForQuestionAnswering.from_pretrained("deepset/roberta-base-squad2") # pytorch checkpoint
+model = ORTModelForQuestionAnswering.from_pretrained("optimum/roberta-base-squad2") # onnx checkpoint
tokenizer = AutoTokenizer.from_pretrained("deepset/roberta-base-squad2")
optimum_qa = pipeline("question-answering", model=model, tokenizer=tokenizer)
question = "What's my name?"
context = "My name is Philipp and I live in Nuremberg."
pred = optimum_qa(question, context)
初回リリースでは、ONNX Runtimeのサポートが追加されましたが、これにはまだまだ進展があります!これらの新しいORTModelForXX
は、transformersパイプラインとも互換性があります。また、コミュニティから最適化されたチェックポイントをプッシュおよびプルするためにHugging Face Hubに完全に統合されています。さらに、ORTQuantizerとORTOptimizerを使用してモデルを最初に量子化および最適化し、それから推論を実行することもできます。詳細については、質問応答のRoBERTaを加速するためのエンドツーエンドチュートリアルで量子化と最適化を含めた詳細を確認してください。
3. 質問応答のRoBERTaを加速するためのエンドツーエンドチュートリアル、量子化、最適化
この質問応答のRoBERTaを加速するためのエンドツーエンドチュートリアルでは、次のことを学びます:
Optimum
のONNX Runtimeへのインストール- Hugging Face
Transformers
モデルをONNXに変換して推論に使用する方法 ORTOptimizer
を使用してモデルを最適化する方法ORTQuantizer
を使用して動的量子化を適用する方法- Transformersパイプラインを使用して高速化推論を実行する方法
- パフォーマンスとスピードを評価する方法
始めましょう 🚀
このチュートリアルは、m5.xlarge
AWS EC2インスタンスで作成および実行されました。
3.1 Optimum
for Onnxruntimeのインストール
最初のステップは、onnxruntime
ユーティリティを使用してOptimum
をインストールすることです。
pip install "optimum[onnxruntime]==1.2.0"
これにより、transformers
、torch
、およびonnxruntime
を含む、必要なすべてのパッケージがインストールされます。GPUを使用する場合は、pip install optimum[onnxruntime-gpu]
でoptimumをインストールできます。
3.2 Hugging FaceのTransformers
モデルをONNX形式に変換して推論する
最適化を開始する前に、バニラのtransformers
モデルをonnx
形式に変換する必要があります。これには、from_transformers
属性を使用してfrom_pretrained()
メソッドを呼び出す新しいORTModelForQuestionAnsweringクラスを使用します。使用するモデルは、SQUAD2データセット上でファインチューニングされたRoBERTaモデルで、F1スコアは82.91
で、機能(タスク)はquestion-answering
です。
from pathlib import Path
from transformers import AutoTokenizer, pipeline
from optimum.onnxruntime import ORTModelForQuestionAnswering
model_id = "deepset/roberta-base-squad2"
onnx_path = Path("onnx")
task = "question-answering"
# バニラのtransformersをロードしてonnxに変換
model = ORTModelForQuestionAnswering.from_pretrained(model_id, from_transformers=True)
tokenizer = AutoTokenizer.from_pretrained(model_id)
# onnxのチェックポイントとトークナイザを保存
model.save_pretrained(onnx_path)
tokenizer.save_pretrained(onnx_path)
# transformersパイプラインを使用してモデルをテストする(squad_v2のhandle_impossible_answerを使用)
optimum_qa = pipeline(task, model=model, tokenizer=tokenizer, handle_impossible_answer=True)
prediction = optimum_qa(question="What's my name?", context="My name is Philipp and I live in Nuremberg.")
print(prediction)
# {'score': 0.9041663408279419, 'start': 11, 'end': 18, 'answer': 'Philipp'}
バニラのtransformersを正常にonnxに変換し、transformers.pipelines
を使用して最初の予測を実行しました。さて、最適化しましょう。🏎
transformersモデルのエクスポートについて詳しく学びたい場合は、ドキュメントをご覧ください:Export 🤗 Transformers Models
3.3 ORTOptimizer
を使用してモデルを最適化する
onnxのチェックポイントをonnx/
に保存した後、遅延時間と推論の高速化のために演算子の統合と定数畳み込みなどのグラフ最適化を適用するために、ORTOptimizer
を使用できます。
from optimum.onnxruntime import ORTOptimizer
from optimum.onnxruntime.configuration import OptimizationConfig
# ORTOptimizerを作成し、最適化構成を定義する
optimizer = ORTOptimizer.from_pretrained(model_id, feature=task)
optimization_config = OptimizationConfig(optimization_level=99) # すべての最適化を有効にする
# 最適化構成をモデルに適用する
optimizer.export(
onnx_model_path=onnx_path / "model.onnx",
onnx_optimized_model_output_path=onnx_path / "model-optimized.onnx",
optimization_config=optimization_config,
)
パフォーマンスをテストするために、ORTModelForQuestionAnswering
クラスを再度使用し、最適化されたモデルをロードするためにfile_name
パラメータを追加で指定できます。 (これはハブで利用可能なモデルにも適用されます)
from optimum.onnxruntime import ORTModelForQuestionAnswering
# 量子化されたモデルをロードする
opt_model = ORTModelForQuestionAnswering.from_pretrained(onnx_path, file_name="model-optimized.onnx")
# transformersパイプラインを使用して量子化されたモデルをテストする
opt_optimum_qa = pipeline(task, model=opt_model, tokenizer=tokenizer, handle_impossible_answer=True)
prediction = opt_optimum_qa(question="What's my name?", context="My name is Philipp and I live in Nuremberg.")
print(prediction)
# {'score': 0.9041663408279419, 'start': 11, 'end': 18, 'answer': 'Philipp'}
ステップ3.6でパフォーマンスの変化を評価します。パフォーマンスと速度を詳細に評価します。
3.4 ORTQuantizer
を使用して動的量子化を適用する
モデルを最適化した後、ORTQuantizer
を使用して量子化することでさらに高速化することができます。 ORTOptimizer
を使用して動的量子化を適用することで、モデルのサイズを減らし、レイテンシと推論を加速することができます。
インスタンスがIntel Cascade Lake CPUを使用しており、avx512をサポートしているため、avx512_vnni
を使用します。
from optimum.onnxruntime import ORTQuantizer
from optimum.onnxruntime.configuration import AutoQuantizationConfig
# ORTQuantizerを作成し、量子化設定を定義する
quantizer = ORTQuantizer.from_pretrained(model_id, feature=task)
qconfig = AutoQuantizationConfig.avx512_vnni(is_static=False, per_channel=True)
# 量子化設定をモデルに適用する
quantizer.export(
onnx_model_path=onnx_path / "model-optimized.onnx",
onnx_quantized_model_output_path=onnx_path / "model-quantized.onnx",
quantization_config=qconfig,
)
このモデルのサイズといくつかのレイテンシパフォーマンスを比較することができます。
import os
# モデルのファイルサイズを取得する
size = os.path.getsize(onnx_path / "model.onnx")/(1024*1024)
print(f"Vanilla Onnxモデルのファイルサイズ:{size:.2f} MB")
size = os.path.getsize(onnx_path / "model-quantized.onnx")/(1024*1024)
print(f"量子化されたOnnxモデルのファイルサイズ:{size:.2f} MB")
# Vanilla Onnxモデルのファイルサイズ:473.31 MB
# 量子化されたOnnxモデルのファイルサイズ:291.77 MB
モデルのサイズを473MBから291MBに約50%削減しました。推論を実行するには、ORTModelForQuestionAnswering
クラスを再度使用し、追加のfile_name
パラメーターを指定して量子化モデルをロードします。(ハブで利用可能なモデルにも適用できます)
# 量子化モデルをロードする
quantized_model = ORTModelForQuestionAnswering.from_pretrained(onnx_path, file_name="model-quantized.onnx")
# トランスフォーマーパイプラインを使用して量子化モデルをテストする
quantized_optimum_qa = pipeline(task, model=quantized_model, tokenizer=tokenizer, handle_impossible_answer=True)
prediction = quantized_optimum_qa(question="私の名前は何ですか?", context="私の名前はフィリップで、ニュルンベルクに住んでいます。")
print(prediction)
# {'score': 0.9246969819068909, 'start': 11, 'end': 18, 'answer': 'Philipp'}
素晴らしい!モデルは同じ答えを予測しました。
3.5 Transformersパイプラインを使用して高速な推論を実行する
Optimumにはtransformersパイプラインの組み込みサポートがあります。これにより、PyTorchやTensorFlowモデルを使用する際と同じAPIを活用することができます。変換および最適化されたモデルのテストには、既にこの機能を使用しています。現時点ではONNX Runtimeをサポートしており、今後さらに拡充されます。以下にtransformersパイプラインの使用方法の例があります。
from transformers import AutoTokenizer, pipeline
from optimum.onnxruntime import ORTModelForQuestionAnswering
tokenizer = AutoTokenizer.from_pretrained(onnx_path)
model = ORTModelForQuestionAnswering.from_pretrained(onnx_path)
optimum_qa = pipeline("question-answering", model=model, tokenizer=tokenizer)
prediction = optimum_qa(question="私の名前は何ですか?", context="私の名前はフィリップで、ニュルンベルクに住んでいます。")
print(prediction)
# {'score': 0.9041663408279419, 'start': 11, 'end': 18, 'answer': 'Philipp'}
さらに、Optimumには高速化モデルの安全性を確保するためにpipelines
APIも追加されています。サポートされていないモデルやタスクでoptimum.pipelines
を使用しようとするとエラーが発生します。 optimum.pipelines
をtransformers.pipelines
の代わりに使用することができます。
from transformers import AutoTokenizer
from optimum.onnxruntime import ORTModelForQuestionAnswering
from optimum.pipelines import pipeline
tokenizer = AutoTokenizer.from_pretrained(onnx_path)
model = ORTModelForQuestionAnswering.from_pretrained(onnx_path)
optimum_qa = pipeline("question-answering", model=model, tokenizer=tokenizer, handle_impossible_answer=True)
prediction = optimum_qa(question="私の名前は何ですか?", context="私の名前はフィリップです。私はニュルンベルクに住んでいます。")
print(prediction)
# {'score': 0.9041663408279419, 'start': 11, 'end': 18, 'answer': 'フィリップ'}
3.6 パフォーマンスとスピードの評価
このエンドツーエンドチュートリアルでは、RoBERTaを高速化するための最適化と量子化を含む質問応答のためのモデルを作成しました。バニラ変換モデル、最適化モデル、および量子化モデルの3つの異なるモデルです。
チュートリアルの最後のステップとして、モデルのパフォーマンスと精度を詳細に見てみたいと思います。グラフの最適化や量子化などの最適化技術を適用することで、パフォーマンス(レイテンシー)だけでなく、モデルの精度にも影響を与えることがあります。つまり、モデルの高速化にはトレードオフがあります。
さて、モデルを評価しましょう。transformersモデルdeepset/roberta-base-squad2はSQUAD2データセットで微調整されました。このデータセットを使用してモデルを評価します。
from datasets import load_metric,load_dataset
metric = load_metric("squad_v2")
dataset = load_dataset("squad_v2")["validation"]
print(f"データセットの長さ {len(dataset)}")
#データセットの長さ 11873
これで、datasetsのmap関数を使用してsquad 2の検証セットを反復処理し、各データポイントに対して予測を実行することができます。そのため、squad v2のメトリックと連携するために、evaluate
というヘルパーメソッドを作成し、いくつかの変換を適用します。
これにはかなりの時間がかかる場合があります(1.5時間)
def evaluate(example):
default = optimum_qa(question=example["question"], context=example["context"])
optimized = opt_optimum_qa(question=example["question"], context=example["context"])
quantized = quantized_optimum_qa(question=example["question"], context=example["context"])
return {
'reference': {'id': example['id'], 'answers': example['answers']},
'default': {'id': example['id'],'prediction_text': default['answer'], 'no_answer_probability': 0.},
'optimized': {'id': example['id'],'prediction_text': optimized['answer'], 'no_answer_probability': 0.},
'quantized': {'id': example['id'],'prediction_text': quantized['answer'], 'no_answer_probability': 0.},
}
result = dataset.map(evaluate)
# データセットの2000のサブセットで評価を実行するにはコメントを解除します
# result = dataset.shuffle().select(range(2000)).map(evaluate)
では、結果を比較しましょう
default_acc = metric.compute(predictions=result["default"], references=result["reference"])
optimized = metric.compute(predictions=result["optimized"], references=result["reference"])
quantized = metric.compute(predictions=result["quantized"], references=result["reference"])
print(f"バニラモデル:完全一致={default_acc['exact']}% f1={default_acc['f1']}%")
print(f"最適化モデル:完全一致={optimized['exact']}% f1={optimized['f1']}%")
print(f"量子化モデル:完全一致={quantized['exact']}% f1={quantized['f1']}%")
# バニラモデル:完全一致=79.07858165585783% f1=82.14970024570314%
# 最適化モデル:完全一致=79.07858165585783% f1=82.14970024570314%
# 量子化モデル:完全一致=78.75010528088941% f1=81.82526107204629%
最適化および量子化されたモデルは、完全一致率が78.75%
、f1スコアが81.83%
で、元の精度の99.61%
を達成しました。ダイナミック量子化を使用した場合でありながら、元のモデルの99%
を達成するのは非常に良い結果です。
さて、最適化および量子化されたモデルのパフォーマンス(レイテンシー)をテストしてみましょう。
しかし、まずはより意味のあるシーケンス長の128にコンテキストと質問を拡張しましょう。
context="こんにちは、私の名前はフィリップです。私はドイツのニュルンベルクに住んでいます。現在、私はHugging Faceでテクニカルリードとして働いており、オープンソースとオープンサイエンスを通じて人工知能の民主化を図っています。過去には、金融技術や保険会社向けにクラウドネイティブな機械学習アーキテクチャを設計・実装しました。私は5年前にクラウドコンセプトと機械学習に情熱を見出しました。それ以来、学び続けています。現在は、NLPの領域に焦点を当て、BERT、Roberta、T5、ViT、GPT2などのモデルを活用してビジネス価値を生み出す方法に取り組んでいます。"
question="フィリップは何として働いていますか?"
シンプルにするために、Pythonのループを使用して、バニラモデルと最適化および量子化モデルの平均遅延を計算します。
from time import perf_counter
import numpy as np
def measure_latency(pipe):
latencies = []
# ウォームアップ
for _ in range(10):
_ = pipe(question=question, context=context)
# タイムトライアル
for _ in range(100):
start_time = perf_counter()
_ = pipe(question=question, context=context)
latency = perf_counter() - start_time
latencies.append(latency)
# 実行統計を計算
time_avg_ms = 1000 * np.mean(latencies)
time_std_ms = 1000 * np.std(latencies)
return f"平均レイテンシ(ミリ秒) - {time_avg_ms:.2f} +\- {time_std_ms:.2f}"
print(f"バニラモデル {measure_latency(optimum_qa)}")
print(f"最適化および量子化モデル {measure_latency(quantized_optimum_qa)}")
# バニラモデル 平均レイテンシ(ミリ秒) - 117.61 +\- 8.48
# 最適化および量子化モデル 平均レイテンシ(ミリ秒) - 64.94 +\- 3.65
バニラモデルのレイテンシを117.61ms
から64.94ms
、つまり約2倍に加速することに成功しました。正確性は99.61%
を保ちました。心に留めておくべきことは、2つの物理コアを持つパフォーマンスの中程度のCPUインスタンスを使用しました。GPUやより高性能なCPUインスタンス(例:Ice Lake)に切り替えると、レイテンシを数ミリ秒に減らすことができます。
4. 現在の制約事項
https://github.com/huggingface/optimumで推論をサポートし始めたばかりなので、現在の制約事項も共有します。これらの制約事項はロードマップに含まれており、近い将来解決されます。
- リモートモデル > 2GB: 現在、Hugging Face Hubから2GB未満のモデルしかロードできません。2GB以上のモデルやマルチファイルモデルのサポートを追加する作業を進めています。
- Seq2Seqタスク/モデル: 要約などのseq2seqタスクやT5などのモデルは、シングルモデルのサポートの制約によりサポートされていません。ただし、transformersでおなじみの体験を提供するために積極的に取り組んでいます。
- 過去のキーバリュー: GPT-2などの生成モデルでは、過去のキーバリューというものを使用してデコーディングを高速化するために事前計算されたキーバリューペアを使用することがあります。現在、ORTModelForCausalLMは過去のキーバリューを使用していません。
- キャッシュなし: 最適化されたモデル(*.onnx)をロードする場合、ローカルにキャッシュされません。
5. Optimum Inference FAQ
どのタスクがサポートされていますか?
すべてのサポートされているタスクのリストはドキュメントで確認できます。現在、サポートされているパイプラインタスクはfeature-extraction
、text-classification
、token-classification
、question-answering
、zero-shot-classification
、text-generation
です。
どのモデルがサポートされていますか?
transformers.onnxでエクスポート可能で、サポートされているタスクを持つすべてのモデルが使用できます。これには、BERT、ALBERT、GPT2、RoBERTa、XLM-RoBERTa、DistilBERTなどが含まれます。
どのランタイムがサポートされていますか?
現在、ONNXランタイムがサポートされています。将来的にはさらに追加する予定です。特定のランタイムに興味がある場合は、お知らせください。
TransformersとOptimumをどのように使用できますか?
ドキュメントに例と手順が記載されています。
GPUを使用するにはどうすればよいですか?
GPUを使用するには、単にoptimum[onnxruntine-gpu]
をインストールするだけで、必要なGPUプロバイダがインストールされ、デフォルトで使用されるようになります。
最適化された量子化モデルをパイプラインで使用するにはどうすればよいですか?
最適化または量子化されたモデルを、from_pretrainedメソッドを使用して新しいORTModelForXXXクラスを介してロードできます。詳細については、ドキュメントをご覧ください。
6. 次は何ですか?
次はOptimumのために何が起こるのかという質問ですね?たくさんのことがあります。私たちは、加速と最適化のためのTransformersとの作業におけるオープンソースのツールキットとしてOptimumを参照することに焦点を当てています。現在の制約を解決し、ドキュメントを改善し、コンテンツと例を追加し、Transformersの加速と最適化の限界に挑戦するために、私たちは次のことを行います。
Optimumのロードマップには、以下の重要な機能が含まれています:
- 音声モデル(Wav2vec2)と音声タスク(自動音声認識)のサポート
- ビジョンモデル(ViT)とビジョンタスク(画像分類)のサポート
- OrtValueとIOBindingのサポートによるパフォーマンスの向上
- 加速モデルの評価を容易にする方法の追加
- TensorRTやAWS-Neuronなど、他のランタイムとプロバイダのサポートの追加
読んでいただきありがとうございます!Transformersの加速、効率化、数十億のリクエストへのスケーリングに興奮しているなら、応募してください。採用中です 🚀
ご質問がありましたら、Githubやフォーラムを通じて、またはTwitterやLinkedInで私と連絡を取ることができます。
We will continue to update VoAGI; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles