話題のLlama 2という大規模言語モデルをAmazon SageMaker JumpStartで動かしてみた

2023.07.19

こんちには。

データアナリティクス事業本部 インテグレーション部 機械学習チームの中村です。

Meta社からLlama 2の発表がありました。

これに伴ってAWSからも以下のようにSageMaker JumpStartから利用可能というアナウンスが出ています。

AWSから公式ブログも出ています。

本記事では、公式ブログを参考にSageMaker JumpStartからLlama 2モデルを使ってみたいと思います

やってみる

環境

リージョンは限られているので、今回はus-east-1を使用します。

デフォルトのドメイン、ユーザを使って今回は作業しました。まだ存在しない場合はSageMaker Studioのドメインとユーザをあらかじめ作成して進めます。

SageMaker Studioの起動

ドメインとユーザを選択し、Studioを起動します。

JumpStartからの確認

HomeタブからJumpStartをクリックします。

右上の「Llama-2」を入力して検索してみましょう。

現在は以下の6件がヒットしました。

  • Llama-2-7b
  • Llama-2-13b
  • Llama-2-70b
  • Llama-2-7b-chat
  • Llama-2-13b-chat
  • Llama-2-70b-chat

7B, 13B, 70Bそれぞれが通常モデルとChatモデルのそれぞれ準備されています。

モデル詳細の確認

ベーシックなLlama-2-7b-chatをクリックして確認してみます。

Deploy Modelで、Deployment Configurationを開いて、使用可能なインスタンスを確認してみましょう。

ml.g5.2xlarge以上 + p4d.24xlargeが選択可能となっています。

13b, 70bはこれ以上のインスタンスを選択する必要がありました。

今回は検証のため7b-chatを使用してみます。

Train Modelについても確認してみましたが、fine-tuningには対応していないようです。

モデルサイズと使用可能インスタンス

使用可能インスタンスは、モデルのサイズによって以下のように異なっていました。

モデル インスタンス 時間あたりの料金(us-east-1)
7b, 7b-chat ml.g5.2xlarge以上 + p4d.24xlarge 1.515USD~
13b, 13b-chat ml.g5.12xlarge以上 + p4d.24xlarge 7.09USD~
70b, 70b-chat ml.g5.48xlarge以上 + p4d.24xlarge 20.36USD~

料金については正確な情報として以下の公式情報も参照ください。

以降はml.g5.48xlargeなども使用しますので、費用にはご注意ください。

なお大きめのインスタンスはService Quotaの上限緩和申請が必要となるケースもありますので、必要に応じて対処下さい。

作業用ノートブックの起動

7b-chatモデルを右上の「Open notebook」ボタンから起動してみます。

または以下のRun in notebookの「Open notebook」からでも起動可能です。

End User License Agreement (EULA) と Acceptable Use Policy (AUP) がダイアログに表示されますので、内容を確認して問題なければ承諾します。

そうするとノートブック起動中の画面となります。

マネジメントコンソール側でml.t3.mediumのKernel Gatewayが起動中であることが分かります。

(試される場合はこちらの分の料金も必要ですのでご注意ください)

SDKの最新化

まずはSageMakerのSDKを最新にします。(今日時点では更新前は2.155.0となっており、llama-2を使用するには2.173.0以上にする必要があります)

%pip install --upgrade --quiet sagemaker

実行後はメッセージに表示されるように、ノートブックの再起動が必要となりますので、以下のボタンで再起動します。

エンドポイントのデプロイ

再起動後、以下を入力してエンドポイントまでデプロイします。

model_id = "meta-textgeneration-llama-2-7b-f"

from sagemaker.jumpstart.model import JumpStartModel

model = JumpStartModel(model_id=model_id)
predictor = model.deploy()

ここは実行完了まで時間が掛かります。マネジメントコンソール側の「推論」->「エンドポイント」を確認すると、エンドポイントが作成中である旨を確認することができます。

「Creating」が「InService」に変化していればノートブック上の処理も終わっているはずです。(今回は7分程度かかりました)

エンドポイントをクリックして「設定」から「エンドポイントのランタイム設定」を確認すると、起動されているインスタンスを確認できます。

エンドポイントへのリクエスト

リクエストの際は、payloadを以下のような形式で設定します。

messages = [
    {"role": "system", "content": "あなたはAIアシスタントです。ユーザの質問に対して必ず日本語で回答してください。決して英語は使わないでください。例外は認めません。"},
    {"role": "user", "content": "日本の料理の代表的なものを教えてください。必ず日本語で回答してください。決して英語は使わないでください。例外は認めません。"},
    {"role": "assistant", "content": "お寿司です。魚や野菜などの新鮮な食材を使用し、見た目も美しく、世界で人気の料理です。"},
    {"role": "user", "content": "豚肉を使ったレシピを一つ考えて名前を教えてください。必ず日本語で回答してください。決して英語は使わないでください。例外は認めません。"},
]
payload = {
    "inputs": [
        messages
    ],
    "parameters":{"temperature":0.0}
}

inputsが"role"と"content"のペアのリスト形式の更にリストとなっています。

(日本語に回答を強制させるために、末尾に「必ず日本語で回答してください。決して英語は使わないでください。例外は認めません。」という文言を入れておきます。後述の70Bもこれを入れておかないと、英語で回答されるケースがあります。ここら辺は工夫点を探る必要がありそうです。)

parametersは他にも設定可能なのですが、temperatureのみ0.0に設定して生成される結果を安定させます。

エンドポイントへのリクエストは以下のようにpredictor.predictで実施します。

response = predictor.predict(payload, custom_attributes='accept_eula=true')
print(response)

その際、custom_attributes='accept_eula=true'を設定しておくことで、End User License Agreement (EULA)に同意した扱いとなり、リクエストが可能となります。

得られた結果は以下です。

[{'generation': {'role': 'assistant', 'content': ' Tonkatsu! 豚肉を使った名物レシピです。豚肉を塩漬けにし、焼き上げた上に塩、酢、および胡椒を添えて、味のあるお肉を作ります。名前の由来は、「豚」と「カツ」です。'}}]

得られたレスポンスのテキストだけを取りだすには、以下のようにします。

print(response[0]["generation"]["content"])
 Tonkatsu! 豚肉を使った名物レシピです。豚肉を塩漬けにし、焼き上げた上に塩、酢、および胡椒を添えて、味のあるお肉を作ります。名前の由来は、「豚」と「カツ」です。

すこし不自然な回答が得られてしまいました。70Bのモデルも試してみようと思います。

一旦、エンドポイントを以下のコードで削除します。

predictor.delete_model()
predictor.delete_endpoint()

70Bモデルも試す

意図しないレスポンスが返ってきてしまったため、70Bという最大サイズのモデルも試してみます。

手順としては、そのまま同じ作業用ノートブックを使用しても良く、その際にmodel_idmeta-textgeneration-llama-2-70b-fとするだけになります。

以下がエンドポイントの作成です。

model_id = "meta-textgeneration-llama-2-70b-f"

from sagemaker.jumpstart.model import JumpStartModel

model = JumpStartModel(model_id=model_id)
predictor = model.deploy()

起動には少し時間がかかるためご注意ください。(今回は55分程度かかりました)

エンドポイントの作成が終わったらリクエストを投げてみます。

messages = [
    {"role": "system", "content": "あなたはAIアシスタントです。ユーザの質問に対して必ず日本語で回答してください。決して英語は使わないでください。例外は認めません。"},
    {"role": "user", "content": "日本の料理の代表的なものを教えてください。必ず日本語で回答してください。決して英語は使わないでください。例外は認めません。"},
    {"role": "assistant", "content": "お寿司です。魚や野菜などの新鮮な食材を使用し、見た目も美しく、世界で人気の料理です。"},
    {"role": "user", "content": "豚肉を使ったレシピを一つ考えて名前を教えてください。必ず日本語で回答してください。決して英語は使わないでください。例外は認めません。"},
]
payload = {
    "inputs": [
        messages
    ],
    "parameters":{"temperature":0.0}
}

response = predictor.predict(payload, custom_attributes='accept_eula=true')

print(response)
print(response[0]['generation']['content'])

回答は以下のようになりました。さきほどより不自然さが少なくなっています。

[{'generation': {'role': 'assistant', 'content': '「豚肉の甘露煮」(とんにくのあまり煮)です。このレシピは、豚肉を甘露煮にして、甘くて Umami のある味を引き出しています。日本では古くから愛されている名前です。'}}]
「豚肉の甘露煮」(とんにくのあまり煮)です。このレシピは、豚肉を甘露煮にして、甘くて Umami のある味を引き出しています。日本では古くから愛されている名前です。

回答の続きを得るためには、messagesにそれまでの会話をappendすると可能となります。試してみましょう。

messages = [
    *messages, response[0]['generation'],
    {"role": "user", "content": "その作り方を教えてください。必ず日本語で回答してください。決して英語は使わないでください。例外は認めません。"},
]

payload = {
    "inputs": [
        messages
    ],
    "parameters":{"temperature":0.0}
}

response = predictor.predict(payload, custom_attributes='accept_eula=true')

print(response)
print(response[0]['generation']['content'])

無事以下のように、作り方を得ることができました。

[{'generation': {'role': 'assistant', 'content': ' `豚肉の甘露煮` の作り方は次の通りです。\n\n材料:\n\n* 豚肉(ロースやバラ、ベルベットなど)\n* 甘露(あまり)\n* 酒(日本酒や中国酒など)\n* 砂糖\n* 味醂(みりん)\n* 醤油(しょうゆ)\n* 塩\n* 胡椒(こしょう)\n* ネギ\n* ショウガ\n\n作り方:\n\n1. 豚肉を切り、細かくちぎっておく。\n2. 酒、甘露、砂糖、味醂、醤油、塩、胡椒、ネギ、ショウガを混ぜ合わせて作る。\n3. 豚肉に混ぜ合わせた Marinade を掛け、30分から1時間程度置いておく。\n4. 豚肉を鍋に入れ、甘露煮にして、煮汁が濃くなるまで煮込む。\n5. 煮汁を濃くしたら、豚肉を取り出し、煮汁を濾して、豚肉にかける。\n6. 豚肉を焼き、甘露煮を作ります。\n\nお楽しみに!'}}]
 `豚肉の甘露煮` の作り方は次の通りです。

材料:

* 豚肉(ロースやバラ、ベルベットなど)
* 甘露(あまり)
* 酒(日本酒や中国酒など)
* 砂糖
* 味醂(みりん)
* 醤油(しょうゆ)
* 塩
* 胡椒(こしょう)
* ネギ
* ショウガ

作り方:

1. 豚肉を切り、細かくちぎっておく。
2. 酒、甘露、砂糖、味醂、醤油、塩、胡椒、ネギ、ショウガを混ぜ合わせて作る。
3. 豚肉に混ぜ合わせた Marinade を掛け、30分から1時間程度置いておく。
4. 豚肉を鍋に入れ、甘露煮にして、煮汁が濃くなるまで煮込む。
5. 煮汁を濃くしたら、豚肉を取り出し、煮汁を濾して、豚肉にかける。
6. 豚肉を焼き、甘露煮を作ります。

お楽しみに!

最後に忘れずにエンドポイントを削除しておきます。

predictor.delete_model()
predictor.delete_endpoint()

作業用ノートブックの削除

SageMaker Studioの左端にある「Runnning Terminals and Kernels」から停止できます。

RUNNING INSTANCESにあるインスタンスの電源マークボタンをおして停止することができます。

最終的にはマネジメントコンソールの画面で以下のように削除されたことが確認できればOKです。

まとめ

いかがでしたでしょうか。事前にAWSアカウントやSageMaker Studioの準備ができていれば、サクッとJumpStartで使いはじめられることが分かりました。

今後はLlama 2の活用方法や、最適化してより低コストでホスティングする方法なども検証していきたいと思います。

本記事がLlama 2やSageMakerを使用される方の参考になれば幸いです。