ChatGPT の置き換え - ChatGLM マルチユーザー並列アクセス展開

        ChatGLM 対話モデルの基本的な環境構築と展開については、以前のブログ投稿「ChatGPT 置き換え - ChatGLM 環境構築と展開操作」を参照してください。アドレスは「https://blog.csdn.net/suiyingy/article/」です。詳細/130370190」。ただし、デフォルトのデプロイヤは単一ユーザー アクセスのみをサポートし、複数のユーザーはキュー アクセスを必要とします。関連するいくつかの Github マルチユーザー プロジェクトがテストされていますが、それらのいくつかはまだ要件を満たしていません。このセクションでは、http、websocket (ストリーミング出力、ストリーム)、Web ページなど、ChatGLM のデプロイ インターフェイスに複数のユーザーが同時にアクセスできるようにする方法を体系的に紹介します。メイン ディレクトリは次のとおりです。

        (1) api.py http マルチユーザー パラレル

        (2) api.py websocket マルチユーザー並列 (ストリーミング出力、ストリーム)

        (3) web_demo.py マルチユーザー並列

        このセクションに含まれるプログラムは、テキストの説明に従って記述または置換するか、「https://download.csdn.net/download/suiyingy/87742178」でダウンロードできます。テキストのすべてのプログラムが含まれています。 .

1 つの api.py http マルチユーザー パラレル

1.1 fastapi 並列

        ChatGLM-6B プロジェクトの api.py は、fastapi に基づいて作成された http ポスト サービス プログラムです。具体的な紹介や呼び出し方については、前回のブログ記事を参照してください。プログラムを実行した後、複数のユーザーが同時に http インターフェイスを呼び出す場合、プログラムをキューで実行する必要があります。つまり、現在のユーザー コマンドは、前のユーザーが結果を取得するのを待ってから実行する必要があります。

        インターフェイスの並列処理を実現する鍵は、create_item の async を削除することです. 対応するプログラムを以下に示します. この関数セグメントは RdFast アプレットによって自動的に生成されます. 次の説明に従ってプログラムを作成するか、ダウンロードした api_http_one_worker.py ファイルに対応する「https://download.csdn.net/download/suiyingy/87742178」にアクセスしてダウンロードします。

#该函数段由RdFast小程序自动生成

from pydantic import BaseModel
class User(BaseModel):
    prompt: str
    history: list

@app.post("/http/noasync")
def create_item(request: User):
    global model, tokenizer
    json_post_raw = request.dict()
    json_post = json.dumps(json_post_raw)
    json_post_list = json.loads(json_post)
    prompt = json_post_list.get('prompt')
    history = json_post_list.get('history')
    max_length = json_post_list.get('max_length')
    top_p = json_post_list.get('top_p')
    temperature = json_post_list.get('temperature')
    response, history = model.chat(tokenizer,
                                   prompt,
                                   history=history,
                                   max_length=max_length if max_length else 2048,
                                   top_p=top_p if top_p else 0.7,
                                   temperature=temperature if temperature else 0.95)
    now = datetime.datetime.now()
    time = now.strftime("%Y-%m-%d %H:%M:%S")
    answer = {
        "response": response,
        "history": history,
        "status": 200,
        "time": time
    }
    log = "[" + time + "] " + '", prompt:"' + prompt + '", response:"' + repr(response) + '"'
    print(log)
    torch_gc()

        「hello」と入力してテストし、3 人のユーザーが同時にアクセスすることをシミュレートします。修正前、3 人のユーザーが返された結果を取得するのに必要な時間は、それぞれ 2.08 秒、4.05 秒、および 6.02 秒でしたが、修正後、結果を取得するのに必要な時間は 6.73 秒、6.78 秒、および 6.88 秒でした。 、 それぞれ。変更前は、プログラムはシーケンシャルに実行され、最後のユーザーが結果を取得するのに必要な時間は 6.02 秒でした。修正後、プログラムは並列に実行され、3 人のユーザーがほぼ同時にアクセス結果を取得します。

        モデルパラメータは複数のスレッド間で共有され、プログラムはマルチスレッド状態で交互に実行されるため、マルチスレッド状態で結果を取得するための合計時間はその代わりに増加します。したがって、この変更は http モードには適していませんが、websocket ストリーミング出力には適しています。マルチユーザー コールをシミュレートするテスト プログラムを以下に示します。

import json
import time
import requests
import threading

def get_ans(id, prompt):
    t0 = time.time()
    headers = {'Content-Type': 'application/json'}
    url = 'http://IP:Port/http/noasync'
    data = {'prompt': prompt, 'history': []}
    data = json.dumps(data)
    reponse = requests.post(url=url, data=data, headers=headers)
    print(id, '耗时为:', round(time.time() - t0, 2), 's,结果为:', reponse .text)

if __name__ == '__main__':
    t1 = threading.Thread(target=get_ans, args=('线程1', '你好'))
    t2 = threading.Thread(target=get_ans, args=('线程2', '你好'))
    t3 = threading.Thread(target=get_ans, args=('线程3', '你好'))
    t1.start()
    t2.start()
    t3.start()

1.2 fastapi マルチスレッド並列処理

        Fastapi マルチスレッドは、パラメーター ワーカーを開始することによって制御されます。プログラムが api.py のワーカーを 1 より大きい値、つまり「uvicorn.run(app, host='0.0.0.0', port=8000, workers=2)」に直接設定すると、エラーが発生します。 "WARNING: You must pass the application as an import string to enable 'reload' or 'workers'." が報告された場合、プログラムは終了し、エラーが報告された後に実行を停止します。「uvicorn.run('api:app', host='0.0.0.0', port=8000, workers=2)」に正しく変更します。ここで、api は現在の python ファイルの名前を表します。

        これは、各スレッドが api.py ファイルのアプリを個別に実行することに相当し、実行回数はワーカーによって決定されます。ここから、プログラムが '__main__' 関数内の変数を認識しないことがわかります。そのため、以下に示すように、モデル定義をグローバル位置に配置する必要があります。そうしないと、エラー「NameError: name 'model' is not defined. 」が報告されます。

app = FastAPI()
tokenizer = AutoTokenizer.from_pretrained("chatglm-6b-int4-qe", trust_remote_code=True)
model = AutoModel.from_pretrained("chatglm-6b-int4-qe", trust_remote_code=True).half().cuda()
model.eval()

        マルチスレッドの場合、前節と同様に、asnc を使用するかどうかに関係なく、プログラムの実行時間は基本的に同じです。ただし、ベース ビデオ メモリは、スレッドの数に応じて増加します。実際の操作では、モデルの読み込みと推論を含めて、1 つのスレッドで約 10 GB のビデオ メモリが必要です。各スレッド数でビデオメモリを搭載するモデルを以下に示します。セクション 1.1 の方法では、1 つのスレッドは 3939MB しか必要としません。

Workers=1, 7329MB
Workers=2, 17875MB
Workers=3, 24843MB
Workers=4, 31811MB
Workers=5, 38779MB

        上記の説明に従ってプログラムを作成するか、ダウンロードした api_http_three_worker.py ファイルに対応する「https://download.csdn.net/download/suiyingy/87742178」にアクセスしてダウンロードできます。

2 api.py websocket マルチユーザー パラレル

        Fastapi websocket の作成方法は以下の通りで、サンプルプログラムは RdFast アプレットから自動生成されます。

#该示例程序来源于RdFast小程序自动生成。
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
app = FastAPI()
connected_websockets = {}
@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: str):
    await websocket.accept()
    connected_websockets[client_id] = websocket
    try:
        while True:
            # 接收客户端websocket发送过来的信息
            data = await websocket.receive_text()
            # 将接收到的信息通过所有已连接的websocket广播给其他客户端
            for ws in connected_websockets.values():
                await ws.send_text(f"Client {client_id}: {data}")
    except WebSocketDisconnect:
        # 连接断开时,从已连接的客户端中移除
        del connected_websockets[client_id]

        上記のプログラムを ChatGLM と組み合わせることで、ChatGLM の websocket api インターフェイスを実現できます。サンプル プログラムは次のようになります。

@app.websocket("/ws/{client_id}")
async def websocket_endpoint(ws: WebSocket, client_id: str):
    await ws.accept()
    print('已连接')
    try:
        while True:
            # 接收客户端websocket发送过来的信息
            data = await ws.receive_text()
            print('收到消息:', data)
            resp0 = ''
            for response, history in model.stream_chat(tokenizer, data, [], max_length= 2048,top_p= 0.7, temperature= 0.95):
                print('response:', response)
                res = response.replace(resp0, '')
                resp0 = response
                await ws.send_text(res)
            await ws.send_text('<rdfast stop>')#自定义结束符
    except WebSocketDisconnect:
        print('连接已断开')

        上記の説明に従ってプログラムを作成するか、ダウンロードした api_http_one_worker.py ファイルに対応する「https://download.csdn.net/download/suiyingy/87742178」にアクセスしてダウンロードできます。Websocket テスト プログラムを以下に示します。

from websocket import create_connection
def connect_node(ques):
    ans = ''
    url = "ws://IP:Port/ws/2"
    ws = create_connection(url)
    ws.send(ques)
    while True:
        try:
            recv_text = ws.recv()
            print(recv_text)
            if '<rdfast stop>' in recv_text:
                print('break')
                break
            ans += recv_text
        except Exception as e:
            print('except: ', str(e))
            recv_text = ws.recv()
            break
    print(ans)
    ws.close()
connect_node('你好')

        http インターフェースと同様に、async を使用すると、websocket を呼び出す複数のユーザーが結果を取得するためにキューに入れられます。この時点で、プログラムは async を削除した後の結果を取得できません。1.2でマルチスレッド起動方式を使えば、複数のユーザーが同時に結果を取得することができ、プログラムは基本的に同じです。「https://download.csdn.net/」のapi_http_three_worker.pyも参照できます。ダウンロード/suiyingy/87742178".

        さらに、さまざまな python パッケージがさまざまな作業方法をサポートしています。たとえば、websocket-server は同時に websocket インターフェイスを呼び出す複数のユーザーをサポートし、インストール方法は「pip install websocket-server」です。プログラム実行時にエラープロンプト「KeyError:'upgrade'」が表示される場合がありますが、結果取得には影響ありません。websocket-server ChatGLM の対応プログラムについては、「https://download.csdn.net/download/suiyingy/87742178」の api_ws.py プログラムを参照してください。

3 web_demo.py マルチユーザー パラレル

        デフォルトでは、Web_demo.py の複数のユーザーがアクセスのためにキューに入れられ、次のコマンドで起動すると、同時に結果を取得できます。Concurrency_count は、同時に結果を取得できる最大ユーザー数、つまり同時実行数を示します。max_size は、キューの数、つまり、最大でキューに入れることができるユーザーの数を示します。使用する場合は、web_demo.py の最後の行を次の起動方法に置き換えるだけです。Web_demo2.py は、デフォルトで複数ユーザーによる同時アクセスをサポートする streamlit によって実装されます。

demo.queue(
    concurrency_count=5,
    max_size=500).launch(share=False,
                inbrowser=True,
                server_name="0.0.0.0",
                server_port=8000)

      この記事は、AIGC コラム「Python AIGC 大規模モデルのトレーニングとゼロからの推論」からのもので、アドレスは「https://blog.csdn.net/suiyingy/article/details/130169592」です。

記事の内容は以下の公式アカウントで同期的に更新されます。

おすすめ

転載: blog.csdn.net/suiyingy/article/details/130412307