Gemma は、Gemini モデルと同じ研究技術で構築されたオープンモデルのファミリーです。インストラクション チューニング モデルは、大量のインストラクション データセットでファイン チューニングされているため、質問への回答やテキストの要約など、指示に従う必要があるタスクに特に適しています。
このブログ投稿では、インストラクション チューニング版の Gemma 2 モデルを使ってテキストベースのアドベンチャー ゲームを作るプロセスを紹介します。独自の設定を使うこともできますが、今回は気まぐれな旅を選びました。ストーリーテラーと呼ばれるフレンドリーで親切な AI コンパニオンが旅をご案内します。ストーリーテラーは、魅惑的な風景を描き出し、好奇心旺盛なキャラクターを紹介しながら、あなたの選択に基づいて物語を紡ぎます。ゲームの結果を決めるのは、AI とのインタラクションです。それではスリリングな冒険に出発です!
Link to Youtube Video (visible only when JS is disabled)
この魅力的なゲームのプレーヤーは、遠く離れた島で目を覚まします。唯一のガイドであり仲間であるのは、ストーリーテラー AI です。この AI が、困難を乗り越えて、島を脱出する方法を探す手助けをしてくれます。
「Gemma セットアップ」を参照して kaggle.com で Gemma にアクセスし、Kaggle API キーを生成してください。
ローカルで確実に Gemma を実行できるマシンがない場合は、Gemma モデルをデプロイするダウンストリーム アプリケーションとして Vertex AI を利用することを検討してください。Vertex AI はマネージド プラットフォームであり、社内に MLOps の専門家がいなくても、機械学習プロジェクトをすばやく開発してスケーリングできます。
まず、Model Garden で Gemma 2 モデルカードを探します。[Deploy] ボタンをクリックすると、モデルのバリエーションとデプロイする場所を選択できます。
デプロイが終わったら、こちらからエンドポイントを探してください。
[Sample Request] を開き、[Python] を選択すると、アクティブなエンドポイントから予測を行うスクリプトを取得できます。
次に示すのは、ローカル Gemma チャットボット ラッパークラスの例です。詳細については、「Gemma でチャットボットを作成する」を参照してください。
このデモでは、Gemma 2 2B モデルを使いました。ただし、ハードウェアに十分な能力がある場合は、9B や 27B などの Gemma モデルを選ぶと、信頼性の高い結果を得ることができます。
# Gemma ローカル
import keras
import keras_nlp
model_name = "gemma2_instruct_2b_en"
class GemmaBot():
__START_TURN_USER__ = "<start_of_turn>user\n"
__START_TURN_MODEL__ = "<start_of_turn>model\n"
__END_TURN__ = "<end_of_turn>\n"
def __init__(self, system=""):
self.model = keras_nlp.models.GemmaCausalLM.from_preset(model_name)
self.system = system
self.history = []
def add_to_history_as_user(self, message):
self.history.append(self.__START_TURN_USER__ + message + self.__END_TURN__)
def add_to_history_as_model(self, message):
self.history.append(self.__START_TURN_MODEL__ + message)
def get_history(self):
return "".join([*self.history])
def get_full_prompt(self):
prompt = self.get_history() + self.__START_TURN_MODEL__
if len(self.system)>0:
prompt = self.system + "\n" + prompt
return prompt
def ask(self, message):
self.add_to_history_as_user(message)
prompt = self.get_full_prompt()
response = self.model.generate(prompt, max_length=2048)
result = response.replace(prompt, "") # 新しいレスポンスのみを抽出
self.add_to_history_as_model(result)
return result
Vertex AI に Gemma をデプロイした場合は、Github のサンプルコードをコピーしてボットファイルに貼り付け、以下のコードを使います。Google Cloud で実行されるので、「self.model」変数を初期化する必要はありません。
def __init__(self, system=""):
self.system = system
self.history = []
:
<-- skip -->
:
def ask(self, message):
self.add_to_history_as_user(message)
prompt = self.get_full_prompt()
response = predict_custom_trained_model_sample(
project="<YOUR_PROJECT_ID>",
endpoint_id="<YOUR_ENDPONT_ID>",
location="<YOUR_LOCATION>",
api_endpoint="<YOUR_LOCATION>-aiplatform.googleapis.com",
instances={ "inputs": prompt, "max_tokens": 2048 }
)
result = response.replace(prompt, "") # 新しいレスポンスのみを抽出
self.add_to_history_as_model(result)
return result
ボットをテストするには、次の簡単なコードを使います。(上のコードを「gemma.py」に保存したと仮定します)
from gemma import GemmaBot
gemma_bot = GemmaBot("You are the Storyteller, guide on this remote island.")
text = gemma_bot.ask("Who are you?")
print(text)
次に示すのは、ボットからの出力例です。
なじみがない方のために説明すると、ゲームループは、ゲームの機能とインタラクティブ性を実現するうえで中核となるプロセスです。これはゲームプレイ中に連続して繰り返されるサイクルであり、ゲームの状態を更新したり、入力を処理したり、画面にビジュアルをレンダリングしたりします。
今回のシンプルなテキストベースのアドベンチャー ゲームでは、基本ゲームループを次のように実装しています。
import StageIntro
current_stage = StageIntro.StageIntro()
def game_loop():
if current_stage.bot is None:
# ボットがないステージタイプ
current_stage.process()
return
resp = ""
print("-"*80)
print(f"Type \"{current_stage.cmd_exit}\" if you want to end the conversation.")
print("-"*80)
if current_stage.preamble != "":
print(current_stage.preamble)
while resp != current_stage.cmd_exit:
if resp == "":
text = current_stage.intro
current_stage.bot.add_to_history_as_model(text)
else:
text = current_stage.bot.ask(resp)
print(text)
resp = input("\n> ")
prompt(admin_bot.judge(current_stage.bot.get_history()))
def check_end_condition():
if not current_stage.pass_check():
check = admin_bot.end_of_game()
print("Succeed to escape?")
print(check)
if check.lower().startswith("true"):
print("Congratulations! You escaped the island.")
exit(0)
next_stage = current_stage.next()
if next_stage is None:
print("End Of Game")
exit(0)
return next_stage
while True:
game_loop()
current_stage = check_end_condition()
input("Press ENTER to move forward")
プロセスを簡単にするため、基本ステージ インターフェース クラスを設計しました。このクラスを拡張して新しいステージを作ることで、独自のカスタム ステージを設定できます。
たとえば、鋼鉄製の門がある新しいステージを作るには、次のようにします。
from stage import IStage
from gemma import GemmaBot
class StageGate(IStage):
def __init__(self):
self.preamble = "The steel gate looms before you, a formidable barrier separating you from the path ahead. Vines crawl along its rusted bars, and the air hums with a faint electrical current.\nThe Storyteller appears beside you, a shimmering presence in the dappled sunlight."
self.intro = "Greetings! I am the Storyteller, your guide on this island.\nWe've come to a gate... what will you do?"
self.bot = GemmaBot("You are the Storyteller, a friendly and helpful AI guide on a mysterious island. Your role is to help the player navigate challenges and find a way to escape. You are currently standing before a large steel gate.")
Gemma を使ってテキストベースのアドベンチャー ゲームを作る方法を習得しました。これと同じ構造を適用することで、スチームパンクからファンタジーまで、幅広いテーマのさまざまなゲームを作ることができます。
さらに、中核となるゲームの仕組みに独自のコンセプトを取り入れることもできます。たとえば、スキルベースの進行、人間関係の構築、ミニゲームといったことが考えられます。
これは基本的な出発点に過ぎません。ここで紹介した要素をブレンドし、適応させ、拡張することで、真にユニークで魅力的なテキストベースのアドベンチャー ゲーム体験を作り出すことができます。
Google デベロッパー コミュニティの Discord サーバーに参加してみましょう。自分のプロジェクトを紹介したり、同じような興味を持つ愛好家たちとつながりを築いたりすることができます。
お読みいただき、ありがとうございました。