Transformers Pipeline: わずか数行のコードでNLPモデルを実行する
1. 概要
Hugging Face Transformersは、pipeline()というAPIを提供しており、これを使えば事前学習済みのNLP/vision/audioモデルをわずか数行のコードで実行できます。tokenizer、config、tensorの手動処理は不要です。この記事では、pipeline()がどのように動作するのか、一般的なタスク(sentiment analysis、NER、summarization、zero-shot classification)での使用方法、そしてより詳細な制御が必要になった時に「より低い層に降りる」べきタイミングについて説明します。
この記事を読み終わったら、Pythonアプリケーションで独立してHugging Faceのモデルを使ってinferenceを実行でき、出力をテストで検証でき、productionに導入する前にpipelineの制限を理解できるようになります。
2. インストール
transformersライブラリとバックエンド(PyTorchまたはTensorFlow)が必要です。PyTorchを使用する例:
pip install transformers torch
この記事執筆時点での推奨バージョン:transformers>=4.40、torch>=2.2。
注意: 最初の実行時、
pipeline()はHugging Face Hubからモデルをダウンロードしてキャッシュを~/.cache/huggingfaceに保存します。モデルは数百MBの場合がありますので、CI内のコンテナで実行する場合はこのステップのための時間とネットワーク帯域幅を計画するか、イメージに事前にキャッシュを含める必要があります。
3. 基本的なPipeline: Sentiment Analysis
from transformers import pipeline
classifier = pipeline("sentiment-analysis")
result = classifier("I really love this product, it works great!")
print(result)
- 1行目:
pipeline関数をインポートします。 - 3行目:
sentiment-analysisタスク用のpipelineを作成します。モデルを指定しない場合、Hugging Faceが自動的にデフォルトモデルを選択します(通常はdistilbert-base-uncased-finetuned-sst-2-english)。 - 4行目:pipelineを関数のように呼び出して、テキストを渡します。
出力:
[{'label': 'POSITIVE', 'score': 0.9998}]
pipelineはバッチ処理をサポートしているため、リスト結果を返します(文字列のリストを渡すこともできます)。
4. 特定のモデルとTokenizerを指定する
本番コードではデフォルトモデルに依存してはいけません。Hugging Faceはバージョン間でデフォルトを変更する可能性があります。明示的に指定しましょう:
from transformers import pipeline
classifier = pipeline(
task="sentiment-analysis",
model="distilbert-base-uncased-finetuned-sst-2-english",
device=-1 # -1 = CPU、0 = 最初のGPU
)
results = classifier([
"This movie was a complete waste of time.",
"Absolutely fantastic service!"
])
for r in results:
print(r)
model:checkpointを明示的に指定し、変更される可能性のあるデフォルトに依存しません。device:-1はCPUで実行、0はGPUインデックス0で実行します。マシンにCUDAがなく、device=0を設定した場合、pipelineはエラーを発生させます。- classifier にテキストのリストを渡してバッチ処理し、個別にテキストを処理するより効率的です。
出力:
{'label': 'NEGATIVE', 'score': 0.9995}
{'label': 'POSITIVE', 'score': 0.9997}
5. Named Entity Recognition (NER)
from transformers import pipeline
ner = pipeline("ner", model="dslim/bert-base-NER", aggregation_strategy="simple")
text = "Satya Nadella is the CEO of Microsoft, based in Redmond."
for entity in ner(text):
print(entity["word"], "->", entity["entity_group"], f"{entity['score']:.2f}")
aggregation_strategy="simple":サブトークン(例:Sat、##ya)を完全なエンティティに集約し、バラバラなトークン単位ではなく返します。entity_group:エンティティタイプのラベル(PER、ORG、LOC…)。
出力:
Satya Nadella -> PER 0.99
Microsoft -> ORG 0.99
Redmond -> LOC 0.98
注意:
aggregation_strategyを省略すると、BIOタグ付き(B-PER、I-PER…)のバラバラなトークンが返され、手動で集約する必要があります。処理が不正確だとバグが生じやすくなります。
6. Zero-Shot Classification
Zero-shotを使えば、テキストを任意のラベルに分類できます。モデルはそのラベル用に特別に訓練される必要はありません。
from transformers import pipeline
classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
result = classifier(
"This new phone has an amazing camera and battery life.",
candidate_labels=["technology", "sports", "politics", "finance"]
)
print(result["labels"][0], result["scores"][0])
candidate_labels:自分で定義するラベルのリスト。モデルを微調整する必要はありません。- モデルはNatural Language Inferenceの技術を使って、テキストが各ラベルを「含意(entail)」する確率を計算します。
出力:
technology 0.93
Zero-shotはプロトタイピングに非常に便利ですが、タスク専用に微調整したモデルより遅く、精度も低くなります。
7. Text Summarization
from transformers import pipeline
summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
article = """
The Transformers library by Hugging Face provides thousands of pretrained
models to perform tasks on texts such as classification, information
extraction, question answering, summarization, translation, and more.
It bridges research and production by exposing a simple pipeline API
on top of complex model architectures.
"""
summary = summarizer(article, max_length=40, min_length=10, do_sample=False)
print(summary[0]["summary_text"])
max_length/min_length:要約のトークン長の制限。単語数ではなくトークン数です。do_sample=False:ランダムサンプリングではなく、greedy/beam decodingを使用します。実行間での結果を安定させます。
出力(抜粋):
Transformers library provides pretrained models for classification,
extraction, question answering, and summarization.
8. Pipeline内部は何か?
pipeline()は本質的に3つのコンポーネントを組み合わせています:tokenizer、model、およびタスク固有のpost-processingロジックです。より詳細に制御するために手動で構築できます:
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
model_name = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name)
inputs = tokenizer("Great product!", return_tensors="pt")
with torch.no_grad():
logits = model(**inputs).logits
probs = torch.softmax(logits, dim=-1)
label_id = probs.argmax().item()
print(model.config.id2label[label_id], probs[0][label_id].item())
AutoTokenizer/AutoModelForSequenceClassification:モデル名に基づいて正しいアーキテクチャを自動認識します。tokenizer(..., return_tensors="pt"):通常の数値リストではなくPyTorchテンソルを返します。torch.no_grad():これはtrainingではなくinferenceなのでgradientを計算しません。メモリを節約し、高速化します。model.config.id2label:classインデックスをラベル名にマッピングします(LABEL_0/LABEL_1またはPOSITIVE/NEGATIVEはモデルに依存します)。
この層を理解することで、pipelineが奇妙な結果を返す場合のデバッグや、カスタムロジック(例えば、argmaxの代わりに独自のしきい値を適用する)が必要な場合に役立ちます。
9. Pipeline用のテストを書く
モデルの出力はバージョン間で微かに変わる可能性があるため、テストは絶対値の一致ではなく「動作」を確認するべきです。
import pytest
from transformers import pipeline
@pytest.fixture(scope="module")
def sentiment_classifier():
return pipeline(
"sentiment-analysis",
model="distilbert-base-uncased-finetuned-sst-2-english",
)
def test_classifies_positive_sentence(sentiment_classifier):
result = sentiment_classifier("I absolutely love this!")[0]
assert result["label"] == "POSITIVE"
assert result["score"] > 0.9
def test_classifies_negative_sentence(sentiment_classifier):
result = sentiment_classifier("This is the worst experience ever.")[0]
assert result["label"] == "NEGATIVE"
assert result["score"] > 0.9
scope="module":fixtureはテストファイル全体で一度だけモデルを読み込みます。各テストケースでモデルを再度読み込まないため、モデルの読み込みには数秒から数十秒かかります。labelとscoreのしきい値に基づいてassertします。ライブラリバージョン間でスコア値が微かに異なる可能性があるため、正確なスコア値をハードコードしません。
注意: このようなテストを実行するには実際のモデルを読み込む必要があるため、迅速なCI ループでのユニットテストには適していません。統合テストに分離するか、ビジネスロジックをテストする際にpipelineをモックしてください。
10. Pipelineを使用してはいけない場合
Pipelineはプロトタイピングと標準的なタスクに最適ですが、制限があります:
- 大規模バッチ、高いパフォーマンス要件: pipelineは、batchingやpaddingおよび動的batchingを手動で管理するほど最適化されていません。
- 複雑なカスタムロジックが必要: 例えば複数の条件付きpost-processing、複数のモデルの組み合わせ、またはhidden statesへのアクセスが必要な場合。このような場合はセクション8のように直接
AutoModel+ tokenizerを使用してください。 - 大規模でのproduction serving: Text Generation InferenceまたはONNX Runtime/TensorRTなどの専用ツールを検討し、request handlerで直接
pipeline()を呼び出すのではなく、latencyを最適化してください。 - CPUでは大きすぎるモデル:
bart-large-mnliなどのモデルや数十億パラメータのLLMはCPUで実行するのは非常に遅くなります。GPUまたはquantizationが必要です。
11. 結論
Hugging Face Transformersのpipeline()は、事前学習済みのNLPモデルでinferenceを実行する最速の方法です。sentiment analysis、NER、summarization、zero-shot classificationにわずか数行のコードで対応できます。パフォーマンスまたは処理ロジックについてより詳細に制御する必要がある場合は、pipelineをtokenizerとモデルに分割して手動で管理できます。常にデフォルトの代わりに明示的にモデルを指定し、絶対値ではなく動作(ラベル、スコアしきい値)に基づいてテストを書いて、ライブラリが更新されたときのテスト失敗を回避してください。