[ChatStream] Web サーバー(ASGI server) の起動
こんにちは! (株)Qualiteg プロダクト開発部 です!
本稿では、 ChatStream 搭載した Webサーバーの起動方法について説明いたします!
uvicorn(内部起動)
ChatStreamは FastAPI/Starlette に対応しているため、 ASGI サーバーで動作させることができます。
uvicorn をコード内で定義するには以下のように実装します
def start_server():
uvicorn.run(app, host='localhost', port=9999)
def main():
start_server()
if __name__ == "__main__":
main()
ソースコード全体
import torch
import uvicorn
from fastapi import FastAPI, Request
from fastersession import FasterSessionMiddleware, 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()
app.add_middleware(FasterSessionMiddleware,
secret_key="your-session-secret-key", # Key for cookie signature
store=MemoryStore(), # Store for session saving
http_only=True, # True: Cookie cannot be accessed from client-side scripts such as JavaScript
secure=True, # False: For local development env. True: For production. Requires Https
)
@app.post("/chat_stream")
async def stream_api(request: Request):
# handling FastAPI/Starlette's Request
response = await chat_stream.handle_chat_stream_request(request)
return response
@app.on_event("startup")
async def startup():
# start request queueing system
await chat_stream.start_queue_worker()
def start_server():
uvicorn.run(app, host='localhost', port=9999)
def main():
start_server()
if __name__ == "__main__":
main()
uvicorn(外部起動)
次に uvicorn 外部起動 のパターンについてみていきましょう。
./example
にある example_server_redpajama_simple.py
をサーバーとして起動する場合
uvicorn example.web_server_redpajama_simple.py:app --host 0.0.0.0 --port 3000
のようになります。こちらのほうがサーバーとアプリの分離ができていて、より本番に近いアプローチとなります。
uvicornの起動オプション
https://www.uvicorn.org/settings/
ソースコード
example_server_redpajama_simple.py
import torch
import uvicorn
from fastapi import FastAPI, Request
from fastersession import FasterSessionMiddleware, 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()
app.add_middleware(FasterSessionMiddleware,
secret_key="your-session-secret-key", # Key for cookie signature
store=MemoryStore(), # Store for session saving
http_only=True, # True: Cookie cannot be accessed from client-side scripts such as JavaScript
secure=True, # False: For local development env. True: For production. Requires Https
)
@app.post("/chat_stream")
async def stream_api(request: Request):
# handling FastAPI/Starlette's Request
response = await chat_stream.handle_chat_stream_request(request)
return response
@app.on_event("startup")
async def startup():
# start request queueing system
await chat_stream.start_queue_worker()
gunicorn
次は gunicorn を使用する方法についてです。こちらは、本番のAPIサーバーとして、もっとも一般的なアプローチとなります。ここで起動した gunicorn を APIサーバーとして Nginx などの Webサーバーをリバースプロキシとして組み合わせることで、本番システムとして稼働させることができます。
./example
にある example_server_redpajama_simple.py
をサーバーとして起動する場合
gunicorn example.web_server_redpajama_simple.py:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:3000
(注意:Windows 環境では動作しません)
ソースコード
example_server_redpajama_simple.py
import torch
from fastapi import FastAPI, Request
from fastersession import FasterSessionMiddleware, 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()
app.add_middleware(FasterSessionMiddleware,
secret_key="your-session-secret-key", # Key for cookie signature
store=MemoryStore(), # Store for session saving
http_only=True, # True: Cookie cannot be accessed from client-side scripts such as JavaScript
secure=True, # False: For local development env. True: For production. Requires Https
)
@app.post("/chat_stream")
async def stream_api(request: Request):
# handling FastAPI/Starlette's Request
response = await chat_stream.handle_chat_stream_request(request)
return response
@app.on_event("startup")
async def startup():
# start request queueing system
await chat_stream.start_queue_worker()
いかがでしたでしょうか。ChatStreamが FastAPI/Starlette ベースで実装されているので本番に向けては標準的なアプローチでサーバー構築することが可能です。
ただし、商用環境を考慮しますと、通常、1つの ChatStream APIサーバーだけで運用することは稀で、1つの ChatStream API サーバーを ChatStreamノードと呼び、複数のChatStreamノードでリージョンごとのクラスターを作ります。Qualiteg では、このようなスケールアウト型の負荷対策をさせるシステム構成を推奨しております。