エラーの発生シナリオこれはPyTorchでよくある状況です。Llama-3やWhisperのような巨大なモデルをGPUにロードすることには成功したものの、推論を開始した瞬間にクラッシュしてしまいます。おそらく model.to('cuda') を使ってモデルを移動させた一方で、トークナイザーから返されたテンソルはまだシステムメモリ(RAM)に残っていることが原因です。
RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!
エラーの原因PyTorchのロジックは厳格です。データが異なるハードウェアに分散している場合、行列乗算(エラーメッセージ内の mat2 など)のような数学的演算を実行することはできません。モデルの重みは cuda:0(GPU)にありますが、入力IDは cpu にあります。
この不一致が起こる理由は、model.to('cuda') がモデルのパラメータとバッファのみを移行させるためです。tokenizer() 関数はデフォルトでCPU上に新しいテンソルを作成します。GPUがこれらの入力を処理しようとすると、その特定の計算のためにCPUのメモリ空間に直接アクセスできないため、メモリの壁に突き当たります。
即効性のある解決策:手動での移行コードを動作させるには、入力辞書全体をGPUに移動させます。HuggingFaceのトークナイザーは辞書形式のオブジェクト(BatchEncoding)を返すため、辞書内包表記を使用してすべてのテンソルを一括で同期させるのが簡潔です。
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
# ハードウェアの検出
device = "cuda" if torch.cuda.is_available() else "cpu"
# モデルを初期化してGPUに移動
tokenizer = AutoTokenizer.from_pretrained("gpt2")
model = AutoModelForCausalLM.from_pretrained("gpt2").to(device)
inputs = tokenizer("なぜテンソルが間違ったデバイスにあるのですか?", return_tensors="pt")
# 修正:入力をモデルのデバイスに同期させる
inputs = {k: v.to(device) for k, v in inputs.items()}
output = model.generate(**inputs)
長期的なベストプラクティス### 1. device_map="auto" の活用最新のLLMでは、accelerate ライブラリを使用してください。device_map="auto" を設定することで、HuggingFaceは利用可能なVRAM全体でモデルレイヤーの配置を自動的に管理し、入力のルーティングも処理してくれます。
# 実行には: pip install accelerate が必要
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
device_map="auto"
)
2. 実行時(On-the-Fly)のテンソル作成カスタムのフォワードパスで新しいテンソル(アテンションマスクや位置のインクリメントなど)を生成する場合、CPUをハードコードしてはいけません。代わりに、常にモデルの既存のデバイス属性を参照して互換性を確保してください。
# 非推奨:デフォルトでCPUになり、クラッシュの原因となる
mask = torch.ones((1, 10))
# 推奨:モデルの現在のデバイスを自動的に継承する
mask = torch.ones((1, 10), device=model.device)
3. Pipelineによる簡略化シンプルさを好む場合は、pipeline APIを使用してください。device=0 を渡すことで、モデルとそのモデルに渡されるデータの両方が自動的にGPUで処理されるようになり、手動で .to() を呼び出す必要がなくなります。
from transformers import pipeline
# device=0 は cuda:0 にマッピングされる
pipe = pipeline("sentiment-analysis", model="distilbert-base-uncased", device=0)
# 入力データはバックグラウンドで自動的にGPUに移動される
pipe("この修正は完璧に機能しました!")
クイック検証モデルのパラメータを1つ確認し、それを入力テンソルと比較することで、セットアップを検証してください。この2行のチェックにより、デバッグの時間を大幅に節約できます。
print(f"モデルの場所: {next(model.parameters()).device}")
print(f"入力の場所: {inputs['input_ids'].device}")
片方が cuda:0 でもう片方が cpu と表示される場合、依然として不一致が発生しています。コードを実行するには、両方が一致している必要があります。

