ChatGLM2 と OpenVINO™ に基づいて中国語チャット アシスタントを作成する

著者:ヤン・イーチェン、インテルAIソフトウェア エンジニア

ChatGLM は清華大学のチームによって開発されました。これは、中国語と英語のバイリンガルをサポートする、オープン ソースの ChatGPT に似た大規模言語モデルです。人間の好みに非常に一致した回答を生成できます。ChatGLM2 は、第 2 世代バージョンです。オープンソースの中国語と英語のバイリンガル対話モデル ChatGLM. スムーズな対話や低い展開しきい値など、第一世代モデルの多くの優れた機能を維持することに基づいて、完全にアップグレードされたベース モデルは、より強力なパフォーマンスとより長いコンテキストをもたらします。学術研究に完全にオープンであり、登録後は無料で商用利用も可能です。次に、ChatGLM2-6B と OpenVINO™ ツールキットに基づいてチャットボットを構築する方法を共有しましょう。

プロジェクトウェアハウスのアドレス: https://github.com/OpenVINO-dev-contest/chatglm2.openvino

注1 :ChatGLM2-6Bはモデル変換時および動作時に多くのメモリを占有するため、テストプラットフォームとして128Gb以上のメモリをサポートするサーバー端末を使用することを推奨します。

注 2 : この記事では、ChatGLM2-6B の元の事前トレーニング済みモデルをデプロイする方法のみを共有します。知識をカスタマイズする機能を取得する必要がある場合は、元のモデルを微調整する必要があります。より良い推論を取得する必要がある場合は、元のモデルを微調整する必要があります。パフォーマンスを向上させるには、量子化モデルのバージョンを使用できます。

モデルのエクスポート

最初のステップでは、ChatGLM2-6B モデルをダウンロードし、展開用に OpenVINO™ でサポートされている IR 形式モデルにエクスポートする必要があります。ChatGLM チームは事前トレーニング済みモデルの 6B バージョンを Hugging Face プラットフォームでリリースしているため、これは Transformer ライブラリ Inference を通じてサポートされていますが、Optimum のデプロイメント方法はサポートされていません (Llama2 の記事を参照してください)。そのため、ここでは Transformer で ChatGLM2 の PyTorch モデル オブジェクトを抽出し、モデル ファイルのシリアル化を実現する必要があります。主な手順は次のように分けられます。

1. PyTorchモデル オブジェクトを取得します。

Transformer ライブラリを通じて PyTorch オブジェクトを取得します。Transformer のネイティブ ModelForCausalLM クラスは ChatGLM2 モデル アーキテクチャをサポートしていないため、trust_remote_code=True パラメーターを追加して、リモート モデル ウェアハウスからモデル構造情報を取得し、重みをダウンロードする必要があります。

model = AutoModel.from_pretrained(args.model_id,

                                  trust_remote_code=True).float()

2. モデルの入力パラメータと出力パラメータをシミュレーションして取得します。

torch.onnx.export インターフェイスを呼び出してモデル オブジェクトを ONNX ファイルにエクスポートする前に、まずモデルの入力情報と出力情報を取得する必要があります。ChatGLM2にはKVキャッシュ機構があるため、このステップでは最初のテキスト生成でキャッシュなしの入力がシミュレートされ、その出力が2回目の反復でキャッシュ入力として使用され、その後2回目の反復で使用されます。入力データが完全であるかどうかを確認します。最初と 2 回目の反復それぞれに対する次の PyTorch コード:

outputs = model.forward(**input_tensors)



outputs2 = model.forward(input_ids=input_ids,

                         attention_mask=attention_mask,

                         position_ids=position_ids,

                         past_key_values=past_key_values)

3. ONNX形式にエクスポートする

完全なモデルの入出力情報を取得した後、torch.onnx.export インターフェイスを使用してモデルを ONNX ファイルとしてエクスポートできます。モデル構造視覚化ツールでファイルを表示すると、入力が元のモデル オブジェクトのattention_maskが消えています。個人的な理解では、このattention_maskはモデルの出力には影響せず、実際の機能はposition_idsに置き換えられているため、ONNXはモデルの変換プロセス中に自動的に最適化します。

4.フォーマット変換にOpenVINO Model Optimizerを使用する

最後のステップでは、OpenVINO™ のモデル オプティマイザー ツールを使用して、モデル ファイルを IR 形式に変換し、FP16 精度に圧縮し、元の FP32 モデルと比較します。FP16 モデルは、ディスク使用量を削減し、実行時間を最適化できます。モデル出力の精度を確保しながら、メモリのオーバーヘッドを軽減します。

モデルのデプロイメント

IR モデルをエクスポートした後、まず簡単な質問と回答のシステム パイプラインを構築して、効果をテストする必要があります。以下の図に示すように、プロンプトは単語の分割と単語ベクトルのエンコードのために Tokenizer に送信され、OpenVINO™ 推論を使用して結果 (青色の部分) が取得されます。さらに推論結果をサンプリングしてデコードし、最後に通常のテキスト メッセージを生成します。ここでは、回答のスクリーニング方法として Top-K と Top-P が使用され、結果は最終的にスクリーニングされた回答からランダムに抽出されます。

図: ChatGLM2 Q&A タスクのプロセス

パイプライン全体のコードのほとんどは、テキスト生成タスクの従来のプロセスに適用できます。より複雑な部分は OpenVINO™ 推論部分です。ChatGLM2-6B テキスト生成タスクは複数の再帰的反復を完了する必要があるため、は各反復キャッシュ内のキャッシュになるため、さまざまな反復ラウンドに適切な入力データを準備する必要があります。次に、モデルの動作ロジックを詳細に分解してみましょう。

図: ChatGLM2-6B モデルの入出力原理

ChatGLM2 の IR モデルの入力は主に 3 つの部分で構成されます。

  • input_ids はベクトル化後のプロンプト入力です。
  • Position_ids は、入力位置情報を記述するために使用されます。たとえば、元のプロンプト データが「お元気ですか」であれば、これは Position_ids となり、[[1,2,3]] となります。入力が後の最初の予測単語である場合、元のプロンプト:「I」の場合、position_ids は [[4]] などとなります。
  • past_key_values.x は、各反復中に共有できるキャッシュを保存するために使用される一連のデータのコレクションです。

ChatGLM2 の IR モデルの出力は 2 つの部分で構成されます。

  • ロジッツは、次の単語または次のトークンに対するモデルの予測です。
  • present_key_values.x は、次の反復の past_key_values.x 値として直接キャッシュとして見なすことができます。

パイプライン全体は実行時に ChatGLM2 モデルの複数の反復を実行し、最終的な応答の長さが事前設定値 max_sequence_length を超えるか、予測される次の単語がターミネーター eos_token_id になるまで、各反復で応答内の次の単語の予測が再帰的に生成されます。

  • 最初の反復

図に示すように、1 回の反復 (N=1) では、input_ids はプロンプト ステートメントになります。このとき、Tokenizer の単語セグメンターを使用して、元のテキストを入力ベクトルに変換する必要もあります。このときの加速では、past_key_values.x 系列のベクトルはすべて null 値です。ここでは、次元 [0,1,2,128] の null 値行列を初期化します。

  • N回目の反復

最初の反復が完了すると、答えの最初の単語の予測された Logits とキャッシュ データが出力されます。この Logits を次の反復の input_id として使用し、次の反復のモデルに入力できます。 inference (N=2) 、この時点では、最後の反復のキャッシュ データ (present_key_values) を使用できます。このようにして、現在の予測単語を 1 回の繰り返しで入力することで、すべての答えを徐々に生成できます。

詳細なコードは次のとおりです. ここで、past_key_values が None に等しい場合、それが最初の反復であることがわかります. このとき、値がすべて空である past_key_values 系列を構築する必要があります。 None ではない場合、実際のキャッシュ データが入力に追加されます。

            if past_key_values is not None:

                new_position_id += 1

                inputs["position_ids"] = new_position_id

                inputs.update(past_key_values)

            else:

                inputs["position_ids"] = position_ids

                shape_input_ids = input_ids.shape

                for input_name in past_names:

                    model_inputs = self.model.input(input_name)

                    shape = model_inputs.get_partial_shape()

                    if shape[0].is_dynamic:

                        shape[0] = 0

                    if shape[1].is_dynamic:

                        shape[1] = shape_input_ids[0]

                    inputs[input_name] = Tensor(

                        model_inputs.get_element_type(), shape.get_shape())

テストの出力は次のとおりです。

コマンド: python3generate_ov.py -m "THUDM/chatglm2-6b" -p "上海について紹介してください? "

ChatGLM2-6B は次のように答えました。

「上海は中国の都市で、東海岸に位置し、中国の重要な経済、文化、技術の中心地の一つです。

上海は中国の重要な港湾都市であり、中国の重要な輸出入の中心地の 1 つであり、世界有数の金融の中心地の 1 つです。上海はアジアと世界経済の中心地の 1 つであり、国際的に有名な金融機関や多国籍企業の本社が数多くあります。

上海は長い歴史と豊かな文化を持つ都市です。上海は中国の重要な文化都市の 1 つであり、多くの歴史的、文化的名所や現代文化のランドマークがあります。上海は中国の重要な観光都市であり、国内外から多くの観光客が訪れます。

上海は重要な経済機能を備えた近代的な都市です。

チャットアシスタント

公式サンプルにおける ChatGLM2 の主な目的は対話チャットです。質疑応答モデル モードと比較して、対話モードはより完全な対話を構築する必要があります。このとき、モデルは以前の情報を考慮する必要があります。そのため、モデルがどれが過去の会話でどれが新しい会話の質問であるかを完全に理解できるように、各入力データを構築する追加のテンプレートを設計する必要があります。 。

図: ChatGLM2 ダイアログのタスク フロー

ここのテキスト テンプレートは、 「導きの言葉+歴史的記録 +現在の質問 (プロンプト) 」の 3 つの部分で構成されています。

  • ガイダンスの言葉: 現在のタスクを説明し、モデルが適切なフィードバックを行うようにガイドします。
  • 履歴: 各質問と回答を含むチャットの履歴データを記録します。
  • 現在の質問: Q&A モードの質問と同様
def build_inputs(history: list[tuple[str, str]], query: str, system: str = ""):

    prompt = "{}\n".format(system)

    for i, (old_query, response) in enumerate(history):

        prompt += "[Round {}]\n问:{}\n答:{}\n".format(i + 1, old_query, response)

        prompt += "[Round {}]\n问:{}\n答:".format(len(history) + 1, query)

    print(prompt)

    return prompt

streamlit フレームワークを使用して、チャットボットの Web UI とバックグラウンド処理ロジックを構築します。また、チャットボットがリアルタイムで対話できることを期待しています。リアルタイム対話とは、チャットボットが完全なテキストを生成して出力することを望まないことを意味します。これは、ユーザーが結果を取得するまでに比較的長い時間待つ必要があるため、ユーザーがモデルによって予測された各単語を徐々に確認し、使用中に順番に提示できることを期待しています。したがって、モデルの反復プロセス中に毎回の予測結果を取得し、それらを最終的な答えに順番に追加して、段階的に提示できる反復可能なメソッドgenerate_iterateを作成する必要があります。

タスクの構築が完了したら、streamlit run chat_robot.py コマンドを使用してチャット マシンを起動し、テストのためにローカル アドレスにアクセスできます。ここでは、開発者がロボットの応答の精度に応じて調整しやすいように、いくつかの一般的な構成パラメーターが選択されています。

  • システム プロンプト ワード:モデルのタスクの方向性をガイドするために使用されます。
  • max_tokens:生成される文の最大長。
  • top-k : 最も高い信頼度で k 個の回答をランダムに選択します。値が大きいほど、生成される回答のランダム性が高くなります。
  • top-p : 確率の合計が p になる回答からランダムに選択します。値が大きいほど、生成される回答のランダム性が高くなります。一般に、top-p は、top-k の後に使用されます。
  • 温度: 生成モデルからのサンプリングにはランダム性が含まれます。温度が高いとランダム性が高まり、モデルがよりクリエイティブな出力を得ることができます。モデルが本題から外れ始めたり、無意味な出力を示したりする場合は、温度が高すぎることを示しています。

注 3 : ChatGLM2-6Bモデルは比較的大きいため、最初のハードウェアのロードとコンパイルにかかる時間は比較的長くなります。

要約する

ChatGLM2 は、最も人気のあるバイリンガル大規模言語モデルの 1 つとして、主要なベンチマーク テストでの優れた結果と、微調整やその他の機能のサポートにより、ますます多くの開発者に認識され、使用されています。OpenVINO™ を使用して ChatGLM2 シリーズのタスクを構築すると、Intel プラットフォームでのモデルのパフォーマンスがさらに向上し、導入のしきい値を下げることができます。

参考文献

1.ハグフェイストランスフォーマー:

https://huggingface.co/docs/transformers

2. ChatGLM2-6B ハグ顔:

THUDM/chatglm2-6b · ハグフェイス

3. ChatGLM2-6B-TensorRT

GitHub - Tlntin/ChatGLM2-6B-TensorRT

おすすめ

転載: blog.csdn.net/gc5r8w07u/article/details/132669927