Hugging Face Transformersは、事前学習済みの言語モデルを簡単に利用できるライブラリです。BERT、GPT、T5など、数千のモデルにアクセスでき、推論からファインチューニングまで幅広く対応しています。
本記事では、Transformersライブラリの基本的な使い方を解説します。
本記事の内容
- Hugging Face Transformersの概要
- 事前学習モデルの読み込みと推論
- Pipelineによる簡単な利用
- テキスト分類のファインチューニング
- テキスト生成
前提知識
この記事を読む前に、以下の記事を読んでおくと理解が深まります。
Hugging Face Transformersの概要
主要コンポーネント
| コンポーネント | 説明 |
|---|---|
| Model | Transformer モデル(BERT, GPT, T5等) |
| Tokenizer | テキストをトークンに変換 |
| Pipeline | 高レベルの推論API |
| Trainer | 訓練ユーティリティ |
| Dataset | データセット管理 |
インストール
pip install transformers
pip install datasets # データセット用
pip install accelerate # 高速化・分散学習用
モデルとトークナイザーの読み込み
基本的な読み込み
from transformers import AutoModel, AutoTokenizer
# モデル名を指定して読み込み
model_name = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)
# テキストをトークン化
text = "Hello, how are you?"
inputs = tokenizer(text, return_tensors="pt")
print(inputs)
# {'input_ids': tensor([[...]]), 'attention_mask': tensor([[...]])}
# モデルで推論
outputs = model(**inputs)
print(outputs.last_hidden_state.shape) # (batch_size, seq_len, hidden_size)
様々なモデルタイプ
from transformers import (
AutoModelForSequenceClassification,
AutoModelForTokenClassification,
AutoModelForQuestionAnswering,
AutoModelForCausalLM,
AutoModelForSeq2SeqLM,
)
# テキスト分類
classifier = AutoModelForSequenceClassification.from_pretrained(
"bert-base-uncased",
num_labels=2
)
# トークン分類(NER等)
ner_model = AutoModelForTokenClassification.from_pretrained(
"bert-base-uncased",
num_labels=9
)
# 質問応答
qa_model = AutoModelForQuestionAnswering.from_pretrained(
"bert-base-uncased"
)
# テキスト生成(因果言語モデル)
generator = AutoModelForCausalLM.from_pretrained("gpt2")
# Seq2Seq(翻訳、要約等)
seq2seq = AutoModelForSeq2SeqLM.from_pretrained("t5-small")
トークナイザーの詳細
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
# 基本的なトークン化
text = "Hello, world! This is a test."
tokens = tokenizer.tokenize(text)
print(tokens) # ['hello', ',', 'world', '!', 'this', 'is', 'a', 'test', '.']
# IDに変換
ids = tokenizer.convert_tokens_to_ids(tokens)
print(ids)
# 一括処理
encoded = tokenizer(
text,
padding=True, # パディング
truncation=True, # 切り詰め
max_length=128, # 最大長
return_tensors="pt" # PyTorchテンソルで返す
)
# バッチ処理
texts = ["Hello world", "How are you?", "This is a longer sentence."]
batch = tokenizer(
texts,
padding=True,
truncation=True,
max_length=128,
return_tensors="pt"
)
# デコード
decoded = tokenizer.decode(encoded["input_ids"][0])
print(decoded) # [CLS] hello, world! this is a test. [SEP]
# 特殊トークン
print(f"CLS token: {tokenizer.cls_token}, ID: {tokenizer.cls_token_id}")
print(f"SEP token: {tokenizer.sep_token}, ID: {tokenizer.sep_token_id}")
print(f"PAD token: {tokenizer.pad_token}, ID: {tokenizer.pad_token_id}")
Pipelineによる簡単な推論
利用可能なパイプライン
from transformers import pipeline
# テキスト分類
classifier = pipeline("sentiment-analysis")
result = classifier("I love this movie!")
print(result) # [{'label': 'POSITIVE', 'score': 0.99}]
# 複数テキスト
results = classifier([
"I love this movie!",
"This is terrible.",
"It's okay, I guess."
])
# 固有表現抽出(NER)
ner = pipeline("ner", aggregation_strategy="simple")
result = ner("My name is John and I live in New York.")
print(result)
# [{'entity_group': 'PER', 'word': 'John', ...},
# {'entity_group': 'LOC', 'word': 'New York', ...}]
# 質問応答
qa = pipeline("question-answering")
result = qa(
question="What is the capital of France?",
context="Paris is the capital of France. It is known for the Eiffel Tower."
)
print(result) # {'answer': 'Paris', 'score': 0.99, ...}
# テキスト生成
generator = pipeline("text-generation", model="gpt2")
result = generator("Once upon a time", max_length=50, num_return_sequences=1)
print(result[0]["generated_text"])
# 翻訳
translator = pipeline("translation_en_to_fr", model="t5-small")
result = translator("Hello, how are you?")
print(result)
# 要約
summarizer = pipeline("summarization", model="t5-small")
article = """
Artificial intelligence is transforming the world. From healthcare to
transportation, AI is being applied to solve complex problems. Machine
learning, a subset of AI, enables computers to learn from data without
being explicitly programmed.
"""
result = summarizer(article, max_length=50, min_length=10)
print(result[0]["summary_text"])
# Fill-mask(BERT)
fill_mask = pipeline("fill-mask", model="bert-base-uncased")
result = fill_mask("Paris is the [MASK] of France.")
print(result)
GPUの利用
import torch
# GPU利用可能な場合
device = 0 if torch.cuda.is_available() else -1
classifier = pipeline("sentiment-analysis", device=device)
result = classifier("This is great!")
テキスト分類のファインチューニング
データセットの準備
from datasets import load_dataset, Dataset
import pandas as pd
# Hugging Faceのデータセットを読み込み
dataset = load_dataset("imdb")
print(dataset)
# DatasetDict({
# 'train': Dataset({features: ['text', 'label'], num_rows: 25000}),
# 'test': Dataset({features: ['text', 'label'], num_rows: 25000})
# })
# サンプルを確認
print(dataset['train'][0])
# カスタムデータからDatasetを作成
df = pd.DataFrame({
'text': ['Great product!', 'Terrible experience', 'It was okay'],
'label': [1, 0, 0]
})
custom_dataset = Dataset.from_pandas(df)
データの前処理
from transformers import AutoTokenizer
model_name = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
def tokenize_function(examples):
return tokenizer(
examples["text"],
padding="max_length",
truncation=True,
max_length=256
)
# データセット全体をトークン化
tokenized_datasets = dataset.map(tokenize_function, batched=True)
# 不要なカラムを削除
tokenized_datasets = tokenized_datasets.remove_columns(["text"])
tokenized_datasets = tokenized_datasets.rename_column("label", "labels")
tokenized_datasets.set_format("torch")
# サブセットを使用(テスト用)
small_train = tokenized_datasets["train"].shuffle(seed=42).select(range(1000))
small_test = tokenized_datasets["test"].shuffle(seed=42).select(range(200))
Trainerを使った訓練
from transformers import (
AutoModelForSequenceClassification,
TrainingArguments,
Trainer,
)
import numpy as np
from datasets import load_metric
# モデル
model = AutoModelForSequenceClassification.from_pretrained(
model_name,
num_labels=2
)
# 評価関数
def compute_metrics(eval_pred):
logits, labels = eval_pred
predictions = np.argmax(logits, axis=-1)
accuracy = (predictions == labels).mean()
return {"accuracy": accuracy}
# 訓練設定
training_args = TrainingArguments(
output_dir="./results",
evaluation_strategy="epoch",
save_strategy="epoch",
learning_rate=2e-5,
per_device_train_batch_size=16,
per_device_eval_batch_size=16,
num_train_epochs=3,
weight_decay=0.01,
load_best_model_at_end=True,
metric_for_best_model="accuracy",
logging_dir="./logs",
logging_steps=100,
fp16=True, # 混合精度
)
# Trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=small_train,
eval_dataset=small_test,
compute_metrics=compute_metrics,
)
# 訓練
# trainer.train()
# 評価
# results = trainer.evaluate()
# print(results)
# モデルの保存
# trainer.save_model("./my_model")
# tokenizer.save_pretrained("./my_model")
カスタム訓練ループ
import torch
from torch.utils.data import DataLoader
from transformers import AutoModelForSequenceClassification, AdamW, get_scheduler
from tqdm import tqdm
# データローダー
train_dataloader = DataLoader(small_train, shuffle=True, batch_size=16)
eval_dataloader = DataLoader(small_test, batch_size=16)
# モデルとオプティマイザ
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
optimizer = AdamW(model.parameters(), lr=2e-5)
num_epochs = 3
num_training_steps = num_epochs * len(train_dataloader)
lr_scheduler = get_scheduler(
"linear",
optimizer=optimizer,
num_warmup_steps=0,
num_training_steps=num_training_steps
)
# 訓練ループ
model.train()
for epoch in range(num_epochs):
total_loss = 0
progress_bar = tqdm(train_dataloader, desc=f"Epoch {epoch+1}")
for batch in progress_bar:
batch = {k: v.to(device) for k, v in batch.items()}
outputs = model(**batch)
loss = outputs.loss
loss.backward()
optimizer.step()
lr_scheduler.step()
optimizer.zero_grad()
total_loss += loss.item()
progress_bar.set_postfix({"loss": loss.item()})
print(f"Epoch {epoch+1}: avg_loss = {total_loss / len(train_dataloader):.4f}")
# 評価
model.eval()
correct = 0
total = 0
with torch.no_grad():
for batch in eval_dataloader:
batch = {k: v.to(device) for k, v in batch.items()}
outputs = model(**batch)
predictions = torch.argmax(outputs.logits, dim=-1)
correct += (predictions == batch["labels"]).sum().item()
total += batch["labels"].size(0)
print(f"Accuracy: {correct / total:.4f}")
テキスト生成
GPT-2による生成
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
model_name = "gpt2"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)
# GPT-2にはpad_tokenがないので設定
tokenizer.pad_token = tokenizer.eos_token
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
# テキスト生成
prompt = "The future of artificial intelligence is"
inputs = tokenizer(prompt, return_tensors="pt").to(device)
# 基本的な生成
outputs = model.generate(
**inputs,
max_new_tokens=50,
do_sample=True, # サンプリングを有効化
temperature=0.7, # 温度(低いほど確定的)
top_k=50, # Top-K サンプリング
top_p=0.95, # Top-p (nucleus) サンプリング
num_return_sequences=3, # 生成する文の数
pad_token_id=tokenizer.eos_token_id
)
# デコード
for i, output in enumerate(outputs):
generated_text = tokenizer.decode(output, skip_special_tokens=True)
print(f"Generated {i+1}: {generated_text}\n")
生成パラメータの解説
# Greedy Search(最も確率の高いトークンを選択)
outputs = model.generate(
**inputs,
max_new_tokens=50,
do_sample=False # Greedy
)
# Beam Search(複数の候補を探索)
outputs = model.generate(
**inputs,
max_new_tokens=50,
num_beams=5, # ビーム数
early_stopping=True,
no_repeat_ngram_size=2 # 同じn-gramの繰り返しを防ぐ
)
# Top-K Sampling
outputs = model.generate(
**inputs,
max_new_tokens=50,
do_sample=True,
top_k=50,
temperature=0.8
)
# Top-p (Nucleus) Sampling
outputs = model.generate(
**inputs,
max_new_tokens=50,
do_sample=True,
top_p=0.92,
temperature=0.8
)
# 組み合わせ
outputs = model.generate(
**inputs,
max_new_tokens=100,
do_sample=True,
top_k=50,
top_p=0.95,
temperature=0.8,
repetition_penalty=1.2, # 繰り返しにペナルティ
num_return_sequences=1
)
ストリーミング生成
from transformers import TextStreamer
# ストリーミング出力
streamer = TextStreamer(tokenizer, skip_special_tokens=True)
outputs = model.generate(
**inputs,
max_new_tokens=100,
do_sample=True,
temperature=0.7,
streamer=streamer # リアルタイムで出力
)
モデルの保存と読み込み
# ローカルに保存
model.save_pretrained("./my_model")
tokenizer.save_pretrained("./my_model")
# ローカルから読み込み
model = AutoModelForCausalLM.from_pretrained("./my_model")
tokenizer = AutoTokenizer.from_pretrained("./my_model")
# Hugging Face Hubにアップロード
# まずログイン: huggingface-cli login
model.push_to_hub("my-username/my-model")
tokenizer.push_to_hub("my-username/my-model")
量子化モデルの使用
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
import torch
# 4-bit量子化
quantization_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.float16
)
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
quantization_config=quantization_config,
device_map="auto"
)
# 8-bit量子化
model_8bit = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
load_in_8bit=True,
device_map="auto"
)
まとめ
本記事では、Hugging Face Transformersライブラリについて解説しました。
- 基本構成: Model、Tokenizer、Pipeline、Trainer
- Pipeline: 高レベルAPIで簡単に推論
- ファインチューニング: Trainerで効率的に訓練
- テキスト生成: 様々なサンプリング手法
- 量子化: メモリ効率の良いモデル利用
Transformersライブラリは、NLPタスクを素早くプロトタイピングし、本番環境に展開するための強力なツールです。
次のステップとして、以下の記事も参考にしてください。