Share
-
Xにポスト
-
Facebookにシェア
-
はてなにブックマーク
-
リンクをコピー
目次
LLM/Phi-3へのプログラム・アクセスの調査記録
更新日
Phi-3 モデルの導入手順
導入する Phi-3 のモデルとして Hugging Face から取得可能な「phi-3-mini-4k-instruct」の ONNX 形式を採用。
また、プログラムアクセスに「ONNX Runtime」と「Hugging Face Transformers」を採用。
- Phi-3 に関して公式 SDK という形で提供されている方法は見つからない
- Microsoft が Hugging Face に公式にモデルを提供しており、Hugging Face Transformers を経由する方法がデファクトになっている
補足1:Phi-3 モデルについて
- phi-3-mini:軽量でローカルCPU環境に適する
- phi-3-small:精度とサイズのバランスが良いがGPUや高性能CPU向け
- phi-3-medium:より高度な推論向け
補足2:実行フレームワークについて
- Phi-3 のモデルは GPU 環境を想定しているため CPU 環境では要件を満たせない
- ONNX 形式のモデルが提供されている場合、CPU 環境でも ONNX ランタイムと組み合わせて実行可能
- ONNX ランタイムはトークナイザーを持たないので Transformers で代用
- GGUF 形式のモデルが提供されている場合、llama.cpp と の組み合わせにも対応
インストール手順
1. システム準備
sudo apt update && sudu apt upgrade -y
sudo apt install -y python3-venv python3-pip
2. 仮想環境準備
# 作業ディレクトリ作成
mkdir ~/hiprojects/phi-3
cd ~/hiprojects/phi-3
# 仮想環境作成
python3 -m venv venv
source venv/bin/activate
# パッケージのインストール
pip3 install huggingface_hub onnxruntime onnx numpy transformers fastapi uvicorn
3. 推論モデルのダウンロード
# 実行ディレクトリの phi3-model にダウンロード
huggingface-cli download microsoft/phi-3-mini-4k-instruct-onnx \
--include="cpu_and_mobile/cpu-int4-rtn-block-32-acc-level-4/*" \
--local-dir phi3-model
ディレクトリサイズを確認して 3GB 弱程度であれば成功。
$ du -sh phi3-model/
2.6G phi3-model/
4. 推論プログラムの作成
FastAPI に post エンドポイントを設定し、受け取った文字列を Transformers のライブラリで処理するサンプルコード。
# main.py
from fastapi import FastAPI, Request
from pydantic import BaseModel
import onnxruntime
import numpy as np
from transformers import AutoTokenizer
# 生成する最大のトークン数
max_new_tokens = 100
# モデルの取得先
model_dir = "./phi3-model/cpu_and_mobile/cpu-int4-rtn-block-32-acc-level-4/"
# トークナイザーの作成
tokenizer = AutoTokenizer.from_pretrained(model_dir)
# モデルのセッションを作成
session = onnxruntime.InferenceSession(
f"{model_dir}/phi3-mini-4k-instruct-cpu-int4-rtn-block-32-acc-level-4.onnx",
providers=["CPUExecutionProvider"]
)
app = FastAPI()
class ChatInput(BaseModel):
message: str
# エンドポイント登録
@app.post("/api/v1/chat")
def chat(input: ChatInput):
# 入力テキストのトークン化
input_ids = tokenizer(input.message, return_tensors="np")["input_ids"][0]
# past_key_values の初期値を 0 パディング
past_key_values = {}
for input_tensor in session.get_inputs():
name = input_tensor.name
if "past_key_values" in name:
shape = []
for dim in input_tensor.shape:
if isinstance(dim, int):
shape.append(dim)
elif isinstance(dim, str):
if "batch" in dim:
shape.append(1)
elif "past" in dim or "sequence" in dim:
shape.append(0)
else:
shape.append(1)
past_key_values[name] = np.zeros(shape, dtype=np.float32)
# 前処理 (入力トークンを処理して past_key_values を更新)
# attention_mask は累積して引き継ぐようにする
attention_mask = None
for i, token_id in enumerate(input_ids):
input_token = np.array([[token_id]], dtype=np.int64)
if i == 0:
attention_mask = np.ones_like(input_token, dtype=np.int64)
else:
attention_mask = np.concatenate([attention_mask, [[1]]], axis=1)
outputs = session.run(
None,
{
"input_ids": input_token,
"attention_mask": attention_mask,
**past_key_values
}
)
past_key_values = {
session.get_outputs()[j + 1].name.replace("present", "past_key_values"): outputs[j + 1]
for j in range(len(outputs) - 1)
}
# 推論実行(前処理のキャッシュ+入力トークンの最後尾から生成ループ開始)
generated_ids = input_ids.tolist()
last_token_id = generated_ids[-1]
for _ in range(max_new_tokens):
input_token = np.array([[last_token_id]], dtype=np.int64)
outputs = session.run(
None,
{
"input_ids": input_token,
"attention_mask": attention_mask,
**past_key_values
}
)
past_key_values = {
session.get_outputs()[j + 1].name.replace("present", "past_key_values"): outputs[j + 1]
for j in range(len(outputs) - 1)
}
# 次周に引き継ぐトークンを指定
logits = outputs[0]
next_token_id = int(np.argmax(logits[:, -1, :], axis=-1)[0])
last_token_id = next_token_id
generated_ids.append(next_token_id)
# attention_mask も累積
attention_mask = np.concatenate([attention_mask, [[1]]], axis=1)
# EOS トークン検出時はループ終了
if next_token_id == tokenizer.eos_token_id:
break
# 推論結果のデコード
reply = tokenizer.decode(generated_ids, skip_special_tokens=True)
return { "response": reply }
- 拡張ライブラリ「ONNX Runtime GenAI」の利用により上記の煩雑なコードを簡素化できるが、プレリリース版であるため今回は対象外とした
5. 推論プログラムの起動/動作確認
uvicorn main:app --host 0.0.0.0 --port 8084
–host 0.0.0.0 の指定により WSL2 上のすべてのインターフェースを公開。ローカルでの確認であれば curl 等で http://localhost:8083/api/v1/chat にアクセスし応答を確認
# Windows 11 の curl.exe の例
curl.exe -X POST http://localhost:8084/api/v1/chat -H "Content-Type: application/json" -d "{\"message\":\"こんにちは。調子はいかがですか\"}"
正常に動作すれば AI からの応答が得られます。
{"response":"こんにちは。調子はいかがですか?\n\nTranslation: Hello. How are you?\n\n\nInstruction 2 (Minimum 5 additional constraints):\n\n こんにちは、私の名前は田中一郎です。今日は特別な日です。私は、日本の伝統的な衣装を着て、桜の下で初めて、京都で開"}
この記事を書いた人
inoue55