[ChatStream] クイックスタート

[ChatStream] クイックスタート

こんにちは! (株)Qualiteg プロダクト開発部 です!

まだまだ暑いですね!

早速、昨日発表しました ChatStream をつかったリアルタイムストリーミングチャットサーバーを作ってみたいと思います。

パッケージのインストール

早速 ChatStream パッケージのインストールをしていきます

pip install chatstream

必要パッケージのインストール

pip install torch torchvision torchaudio
pip install transformers
pip install "uvicorn[standard]" gunicorn 

ChatStream サーバーの実装

今回は RedPajamaINCITE をLLMとしてつかったストリーミングチャットサーバーを実装します。

chatstream_server.py

import torch
from fastapi import FastAPI, Request
from fastsession import FastSessionMiddleware, MemoryStore
from transformers import AutoTokenizer, AutoModelForCausalLM

from chatstream import ChatStream,ChatPromptTogetherRedPajamaINCITEChat as ChatPrompt

model_path = "togethercomputer/RedPajama-INCITE-Chat-3B-v1"
device = "cuda"  # "cuda" / "cpu"

tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(model_path, torch_dtype=torch.float16)
model.to(device)

chat_stream = ChatStream(
    num_of_concurrent_executions=2,# 文章生成の最大同時実行数
    max_queue_size=5,# 待ち行列の大きさ
    model=model,
    tokenizer=tokenizer,
    device=device,
    chat_prompt_clazz=ChatPrompt,
)

app = FastAPI()

# ユーザーごとの ChatPrompt を HTTP セッションに保持するため、セッションミドルウェアを指定
app.add_middleware(FastSessionMiddleware,
                   secret_key="your-session-secret-key",
                   store=MemoryStore(),
                   http_only=True,
                   secure=False,
                   )


@app.post("/chat_stream")
async def stream_api(request: Request):
    # FastAPI の Request オブジェクトを `handle_chat_stream_request` に渡すだけで自動的にキューイング、同時実行制御します
    response = await chat_stream.handle_chat_stream_request(request)
    return response


@app.on_event("startup")
async def startup():
    # Webサーバー起動と同時に `start_queue_worker` を行い、キューイングシステムを開始します
    await chat_stream.start_queue_worker()

コンストラクターパラメータでパフォーマンス調整

num_of_concurrent_executions

num_of_concurrent_executions=2 は文章生成の最大同時実行数を表しています。この数字が大きいほど、複数の文章生成を並行実行することができます。ただし、大きすぎると、トークン生成速度(トークン/秒)が遅くなるため、GPUの性能にあわせて適切な値を設定してください。たとえば、GPUが A4000 x 1枚 程度の性能の場合は num_of_concurrent_executions=5~10 程度が「快適」と思える生成速度となります。

max_queue_size

max_queue_size=5 は、文章生成の同時実行が埋まっているときに、文章生成待ちをしているリクエストの最大数です。たとえば、上の例のように文章生成の同時実行数の最大数 num_of_concurrent_executions==2 に達しているとき、3番目のリクエストからは待ち行列に入ります。3番目から8番目までは、文章生成を待っている状態で、チャットUI上ではプログレスバーとなります。では、この状態で9番目のリクエストが来たらどうなるでしょうか。

その場合、9番目のリクエストには「現在、文章生成サーバーがBusyです」の旨UIに表示されます。

(ただしこのような状況はサービスとして好ましくないため、このような状況が発生しないよう複数のノードをあらかじめ準備しておくことができます。また、急遽想定以上のアクセスが発生したときに、新しいノードが立ち上がるように設定しておくこともできます。これにより、負荷が多くなったときに、新しいノードが立ち上がり、待ち時間の無いチャットサービスを提供することができます。これら、スケーリングに関する設定方法は別途投稿いたします。)

プロンプト処理クラス "ChatPrompt"を作る

ユーザーによる入力テキストをLLM用のフォーマットに書き換えるためのプロンプト処理クラスはChatPrompt クラスと呼びます。

Qualiteg では、新しい LLM が発表されるたび、そのモデル用の ChatPrompt クラスを作成・バンドルしていますが、自前で作成することもできます。

ここでは今回のサンプルで利用した RedpajamaIncite のモデル用の ChatPromptクラスをご紹介します

from chatstream import AbstractChatPrompt


class ChatPromptTogetherRedPajamaINCITEChat(AbstractChatPrompt):
    """
    togethercomputer/RedPajama-INCITE-7B-Chat
    """

    def __init__(self):
        super().__init__()  # Call the initialization of the base class
        self.set_requester("<human>")
        self.set_responder("<bot>")
        self.set_prefix_as_stop_str_enabled(True)  # enable requester's prompt suffix as stop str

    def get_stop_strs(self):
        return ['<|endoftext|>']

    def create_prompt(self, opts={}):
        """
        Build prompts according to the characteristics of each language model
        :return:
        """
        if self.chat_mode == False:
            return self.get_requester_last_msg()

        ret = self.system
        for chat_content in self.get_contents(opts):
            chat_content_role = chat_content.get_role()
            chat_content_message = chat_content.get_message()

            if chat_content_role:
                if chat_content_message:
                    merged_message = chat_content_role + ": " + chat_content_message + "\n"
                else:
                    merged_message = chat_content_role + ":"

                ret += merged_message

        return ret

    async def build_initial_prompt(self, chat_prompt):
        pass
        # If you want a common initial prompt for instructions, override this method and implement
        # chat_prompt.add_requester_msg("Do you know about the Titanic movie?")
        # chat_prompt.add_responder_msg("Yes, I am familiar with it.")
        # chat_prompt.add_requester_msg("Who starred in the movie?")
        # chat_prompt.add_responder_msg("Leonardo DiCaprio and Kate Winslet.")

単純なモデルの場合は、LLMに入力するプロンプトテキストは、テンプレートマッチングだけで表現できますが、複雑な処理が必要な場合には、このようにChatPromptクラスとして実装したほうが柔軟な処理ができます。


Read more

LLM推論基盤プロビジョニング講座 第5回 GPUノード構成から負荷試験までの実践プロセス

LLM推論基盤プロビジョニング講座 第5回 GPUノード構成から負荷試験までの実践プロセス

こんにちは!これまでのLLM推論基盤プロビジョニング講座では、推論速度の定義、リクエスト数見積もり、メモリ消費量計算、推論エンジン選定について詳しく解説してきました。 今回は、残りのステップである「GPUノード構成見積もり」「負荷試験」「トレードオフ検討」について一気に解説し、最後に実際のサーバー構成例をご紹介します。 STEP5:GPUノード構成見積もり GPUメモリから考える同時リクエスト処理能力 LLMサービスを構築する際、どのGPUを何台選ぶかは非常に重要な決断です。今回はLlama 8Bモデルを例に、GPUメモリ容量と同時リクエスト処理能力の関係を見ていきましょう。 GPUメモリの使われ方を理解する ここは復習となりますが、 LLM推論においてGPUメモリは主に2つの用途で消費されます 1. モデル重みデータ: LLMモデル自体を格納するためのメモリ 2. KVキャッシュ: ユーザーとの対話コンテキストを保持するための一時メモリ Llama 8Bを16ビット精度で実行する場合、モデル重みデータは約16GBのメモリを占めます。これは固定的なメモリ消

By Qualiteg コンサルティング
発話音声からリアルなリップシンクを生成する技術 第2回:AIを使ったドリフト補正

発話音声からリアルなリップシンクを生成する技術 第2回:AIを使ったドリフト補正

こんにちは! 前回の記事では、当社のMotionVoxで使用している「リップシンク」技術について、wav2vecを用いた音声特徴量抽出の仕組みを解説しました。音声から正確な口の動きを予測するための基礎技術について理解いただけたかと思います。 今回は、その続編として、リップシンク制作における重要な技術的課題である「累積ドリフト」に焦点を当てます。wav2vecで高精度な音素認識ができても、実際の動画制作では複数の音声セグメントを時系列に配置する際、わずかなタイミング誤差が蓄積して最終的に大きなずれとなる現象が発生します。 本記事では、この累積ドリフトのメカニズムと、機械学習を活用した最新の補正技術について、実際の測定データを交えながら詳しく解説していきます。前回のwav2vecによる特徴抽出と今回のドリフト補正技術を組み合わせることで、MotionVoxがどのように高品質なリップシンクを実現しているのか、その全体像が見えてくるはずです。 累積ドリフトとは何か 基本概念 累積ドリフトとは、個々の音声セグメントが持つ微小なタイミング誤差が、時間の経過とともに蓄積していく現象で

By Qualiteg 研究部
AIエージェント時代の新たな番人「ガーディアンエージェント」とは?

AIエージェント時代の新たな番人「ガーディアンエージェント」とは?

こんにちは!今日は先日ガートナーが発表したガーディアンエージェントについて解説します ガートナーの公式定義 ハイプカーブで有名なガートナーは2025年6月に、ガーディアンエージェントに関する見解を発表しました。ガーディアン・エージェントとは、AIとの安全で信頼できるやりとりを支援するために設計されたAIベースのテクノロジです。 ざっくりいうと、 「AIエージェントが来るよ」と予言したガートナー社は、次は、「ガーディアンエージェントが来るよ」と予言しました。なぜガーディアンエージェントが来るのでしょうか?本稿では、そのあたりを考察していきたいと思います。 なぜ今、AIの「監視役」が必要なのか 2025年、私たちは本格的なAIエージェント時代の入り口に立っています。AIが単なるツールから、自律的に判断し行動する「エージェント」へと進化する中で、新たな課題が浮上しています。 従来のAIとエージェント型AIの違い さて、ガーディアンエージェントが必要になる理由として、生成AI(以後AIと呼びます)の急速な進化があげられます。従来のAIとエージェント型AIの違いを思い出

By Qualiteg コンサルティング
LLM推論基盤プロビジョニング講座 第4回 推論エンジンの選定

LLM推論基盤プロビジョニング講座 第4回 推論エンジンの選定

こんにちは!前回までの講座では、LLMサービス構築に必要なリクエスト数の見積もりや、使用モデルの推論時消費メモリ計算について詳しく解説してきました。今回は7ステッププロセスの4番目、「推論エンジンの選定」について詳しく掘り下げていきます。 推論エンジンとは何か 推論エンジンとは、GPU上でLLMモデルの推論計算(テキスト生成)を効率的に行うために設計された専用のソフトウェアプログラムです。一般的なディープラーニングフレームワーク(PyTorch、TensorFlowなど)でも推論は可能ですが、実運用環境では専用の推論エンジンを使用することで、大幅なパフォーマンス向上とリソース効率化が期待できます。 推論エンジンは単なる実行環境ではなく、様々な最適化技術を実装しています。特定のモデルアーキテクチャに特化した最適化機能を実装したものや、推論速度の高速化に特化したもの、前回解説したKVキャッシュのメモリ効率化機能を備えたものなど、それぞれ特徴が異なります。そのため、自社で採用したLLMモデルや運用環境、要件に合致した推論エンジンを選定することが重要です。 推論エンジン選定のアプロ

By Qualiteg コンサルティング