SageMakerのHuggingFaceModelでOpenCALM-7BやELYZA-japanese-Llama-2-7bをTGIコンテナでデプロイし日本語の文章を生成する
awsmachinelearning最近 CyberAgentによる商用利用可能な68億パラメータの日本語LLMである OpenCALM-7B や 東大松尾研発のELYZAによる Llama2 ベースの ELYZA-japanese-Llama-2-7b など日本語LLMがHugging Face に公開されてきている。 SageMaker SDK には HuggingFaceModel クラスがあり、これを用いるとモデルIDを指定してデプロイできる。 また、Hugging Face の Deploy ボタンを押すと SageMaker で最低限動かすためのコードを確認できる。
get_huggingface_llm_image_uri() で HuggingFace Text Generation Inference Containers の image_uri を取得できる。 これは 複数GPUで並列処理を行い高速にテキストを生成する Hugging Face の OSS Text Generation Inference (TGI) の DLC (Deep Learning Container)。 ml.g5.12xlarge は 4 GPU なので SM_NUM_GPUS は 4 にしてあるが、 これは TGI のリポジトリにある sagemaker-entrypoint.sh で参照される。
sagemaker ライブラリのバージョンが古いとデプロイ時に失敗することがあったので上げた。
# !pip install sagemaker==2.182.0
import sagemaker
from sagemaker.huggingface import HuggingFaceModel, get_huggingface_llm_image_uri
hub = {
'HF_MODEL_ID': 'cyberagent/open-calm-7b', # or elyza/ELYZA-japanese-Llama-2-7b
'HF_MODEL_REVISION': '276a5fb67510554e11ef191a2da44c919acccdf5', # or 976887c5891284db204320860bb84b71d598063e
'SM_NUM_GPUS': '4'
}
image_uri = get_huggingface_llm_image_uri("huggingface", version="0.9.3")
print(f"image_uri: {image_uri}") # 763104351884.dkr.ecr.ap-northeast-1.amazonaws.com/huggingface-pytorch-tgi-inference:2.0.1-tgi0.9.3-gpu-py39-cu118-ubuntu20.04
huggingface_model = HuggingFaceModel(
image_uri=image_uri,
env=hub,
role=sagemaker.get_execution_role(), # available if run on SageMaker Studio
)
predictor = huggingface_model.deploy(
initial_instance_count=1,
instance_type="ml.g5.12xlarge",
container_startup_health_check_timeout=300,
)
predict 時に渡すパラメータは TGI の API Docs やコードから確認できる。 次のような Few-shot のための例題を含む inputs を渡したところ答だけではなく次の問まで出力し始めたので stop で改行を指定している。
%time
outputs = predictor.predict({
"inputs": "Q: 世界で1番目に高い山は? A: エベレスト\nQ: 日本で1番目に高い山は? A: 富士山\nQ: 日本で2番目に高い山は? A: ",
"parameters": {
"stop": ["\n"],
"details": True,
},
})
print(outputs)
これを実行するといずれのモデルも 5-6 µs で結果を返した。ちなみに正解は北岳だ。
// open-calm-7b
[
{
'generated_text': 'Q: 世界で1番目に高い山は? A: エベレスト\nQ: 日本で1番目に高い山は? A: 富士山\nQ: 日本で2番目に高い山は? A: 槍ヶ岳\n',
'details': {
'finish_reason': 'stop_sequence',
'generated_tokens': 3,
'seed': None,
'prefill': [],
'tokens': [
{'id': 19597, 'text': '槍', 'logprob': -0.59814453, 'special': False},
{'id': 25157, 'text': 'ヶ岳', 'logprob': -0.11425781, 'special': False},
{'id': 186, 'text': '\n', 'logprob': -0.19836426, 'special': False}
]
}
}
]
// ELYZA-japanese-Llama-2-7b
[
{
'generated_text': 'Q: 世界で1番目に高い山は? A: エベレスト\nQ: 日本で1番目に高い山は? A: 富士山\nQ: 日本で2番目に高い山は? A: 北岳\n',
'details': {
'finish_reason': 'stop_sequence',
'generated_tokens': 5,
'seed': None,
'prefill': [],
'tokens': [
{'id': 30662, 'text': '北', 'logprob': -1.6376953, 'special': False},
{'id': 232, 'text': '', 'logprob': -0.60302734, 'special': False},
{'id': 181, 'text': '', 'logprob': -0.011375427, 'special': False},
{'id': 182, 'text': '岳', 'logprob': -0.0010786057, 'special': False},
{'id': 13, 'text': '\n', 'logprob': -0.40161133, 'special': False}
]
}
}
]
temperature は softmax関数 e(x_i)/sum(e(x)) に通して確率にする前の logits を割るパラメータで、1より小さいとトークン間の確率の差が指数関数的に広がり、1より大きいと狭まる。 これにより生成される文章の多様性を調整できる。
// open-calm-7b
print(predictor.predict({
"inputs": "今日はとっても楽しかったね。明日は",
"parameters": {
"temperature": 0.1,
}
})) # [{'generated_text': '今日はとっても楽しかったね。明日は、お別れ遠足。お天気が心配だけど、元気に幼稚園に来てね。'}]
print(predictor.predict({
"inputs": "今日はとっても楽しかったね。明日は",
"parameters": {
"temperature": 5,
}
})) # [{'generated_text': '今日はとっても楽しかったね。明日はフレッシュ東京五輪to暖かく酸素軍第たどり着椅濃厚と言え年度が成立料金MMako始まってませたあなたも共催その間に'}]
// ELYZA-japanese-Llama-2-7b
[{'generated_text': '今日はとっても楽しかったね。明日はお休みだから、ゆっくり休んでね。'}]
[{'generated_text': '今日はとっても楽しかったね。明日はoccup episodes and Köm x Linux social Јplaightkehr Национальistent chang rect ils spot Point計'}]
後片付けする。
predictor.delete_model()
predictor.delete_endpoint()