GenAI フレーバーを使用して OpenVINO で LLM 推論を実行#
このガイドでは、モデルの読み込みや、生成されたテキストを受け取る入力コンテキストの受け渡しなど、OpenVINO GenAI フレーバーをアプリケーションに統合する方法を説明します。OpenVINO のバニラフレーバーはこれらの手順では動作しないので、必ず OpenVINO GenAI をインストールしてください。
注
例では CPU をターゲットデバイスとして使用していますが、GPU もサポートされています。LLM パイプラインの場合、効率を高めるため、GPU は推論にのみ使用され、トークンの選択、トークン化、およびデトークン化は CPU で実行されることに注意してください。トークナイザーは別のモデルとして表現され、CPU 上でも実行されます。
Hugging Face Optimum-Intel を使用した生成 LLM モデルのエキスポート。この例では、チャット向けに調整された TinyLlama モデルが使用されています:
optimum-cli export openvino --model "TinyLlama/TinyLlama-1.1B-Chat-v1.0" --weight-format fp16 --trust-remote-code "TinyLlama-1.1B-Chat-v1.0"
オプション。モデルの最適化:
このモデルは、FP16 精度で最適化された OpenVINO IR です。LLM のパフォーマンスを向上させるには、モデルの重みに INT4 などの低い精度を使用し、モデルのエクスポート中に NNCF を使用して重みを直接圧縮することを推奨します:
optimum-cli export openvino --model "TinyLlama/TinyLlama-1.1B-Chat-v1.0" --weight-format int4 --trust-remote-code "TinyLlama-1.1B-Chat-v1.0"
新しい GenAI API を使用して生成を実行:
import openvino_genai as ov_genai pipe = ov_genai.LLMPipeline(model_path, "CPU") print(pipe.generate("The Sun is yellow because", max_new_tokens=100))
#include "openvino/genai/llm_pipeline.hpp" #include <iostream> int main(int argc, char* argv[]) { std::string model_path = argv[1]; ov::genai::LLMPipeline pipe(model_path, "CPU"); std::cout << pipe.generate("The Sun is yellow because", ov::genai::max_new_tokens(100)); }
LLMPipeline はデコードに使用されるメイン・オブジェクトです。変換されたモデルを含むフォルダーから直接構築できます。メインモデル、トークナイザー、デトークナイザー、およびデフォルトの生成構成が自動的にロードされます。
モデルが Hugging Face Optimum-Intel からエクスポートされると、トークナイザー/デトークナイザーや生成の構成など、実行に必要なすべての情報がすでに含まれており、その結果が Hugging Face で生成されたものと一致することが保証されます。
出力のストリーミング#
生成中のインタラクティブな UI 向けに、モデル出力トークンのストリーミングがサポートされています。以下の例では、ラムダ関数が生成後すぐにコンソールに単語を出力しています:
import openvino_genai as ov_genai
pipe = ov_genai.LLMPipeline(model_path, "CPU")
streamer = lambda x: print(x, end='', flush=True)
pipe.generate("The Sun is yellow because", streamer=streamer, max_new_tokens=100)
#include "openvino/genai/llm_pipeline.hpp"
#include <iostream>
int main(int argc, char* argv[]) {
std::string model_path = argv[1];
ov::genai::LLMPipeline pipe(model_path, "CPU");
auto streamer = [](
std::string word) { std::cout << word << std::flush;
// 生成を停止するかどうかを示すフラグを返す // false は生成を継続することを意味します。
return false;
};
pipe.generate("The Sun is yellow because", ov::genai::streamer(streamer), ov::genai::max_new_tokens(100));
}
より洗練された処理向けにカスタム・ストリーマーを作成することもできます:
import openvino_genai as ov_genai
class CustomStreamer(ov_genai.StreamerBase):
def __init__(self, tokenizer):
ov_genai.StreamerBase.__init__(self)
self.tokenizer = tokenizer
def put(self, token_id) -> bool:
# トークンをデコードして処理。
# ストリーマーは、生成を停止するかどうかを示すフラグを返します。
# Python では、`return` を省略できます。その場合、関数は None を返します。
# これは False に変換され、生成を続行する必要があることを意味します。
# stop_flag を返します
def end(self):
# トークンをデコードして処理します。
pipe = ov_genai.LLMPipeline(model_path, "CPU")
pipe.generate("The Sun is yellow because", streamer=CustomStreamer(), max_new_tokens=100)
#include <streamer_base.hpp>
class CustomStreamer: publict StreamerBase {
public:
bool put(int64_t token) {
bool stop_flag = false;
/* カスタムデコード/トークン処理コード
tokens_cache.push_back(token);
std::string text = m_tokenizer.decode(tokens_cache);
... */
return stop_flag; // 生成を停止するかどうかを示すフラグ。 True の場合、生成が停止します。
};
void end() {
/* カスタム・ファイナライズ */
};
};
int main(int argc, char* argv[]) {
auto custom_streamer = std::make_shared<CustomStreamer>();
std::string model_path = argv[1];
ov::genai::LLMPipeline pipe(model_path, "CPU");
pipe.generate("The Sun is yellow because", ov::genai::streamer(custom_streamer), ov::genai::max_new_tokens(100));
}
チャットシナリオで GenAI を使用#
入力と出力が会話を表現するチャットシナリオでは、入力間で KVCache を維持すると有益である場合があります。次の例に示すように、チャット固有のメソッド start_chat と finish_chat は会話セッションをマークするのに使用されます:
import openvino_genai as ov_genai
pipe = ov_genai.LLMPipeline(model_path)
pipe.set_generation_cofnig({'max_new_tokens': 100)
pipe.start_chat()
while True:
print('question:')
prompt = input()
if prompt == 'Stop!':
break
print(pipe.generate(prompt))
pipe.finish_chat()
int main(int argc, char* argv[]) {
std::string prompt;
std::string model_path = argv[1];
ov::genai::LLMPipeline pipe(model_path, "CPU");
ov::genai::GenerationConfig config = pipe.get_generation_config();
config.max_new_tokens = 100;
pipe.set_generation_cofnig(config)
pipe.start_chat();
for (size_t i = 0; i < questions.size(); i++) {
std::cout << "question:\n";
std::getline(std::cin, prompt);
std::cout << pipe.generate(prompt) << std::endl;
}
pipe.finish_chat();
}
グループ化されたビーム検索による生成の最適化#
グループ化されたビーム検索デコードを活用し、generation_config を構成することで、GenAI アプリケーションでのテキスト生成品質が向上し、バッチ処理が効率化されます。
グループ化されたビーム検索を使用するには、generation_config を指定します:
import openvino_genai as ov_genai
pipe = ov_genai.LLMPipeline(model_path, "CPU")
config = pipe.get_generation_config()
config.max_new_tokens = 256
config.num_beam_groups = 3
config.num_beams = 15
config.diversity_penalty = 1.0
pipe.generate("The Sun is yellow because", config)
int main(int argc, char* argv[]) {
std::string model_path = argv[1];
ov::genai::LLMPipeline pipe(model_path, "CPU");
ov::genai::GenerationConfig config = pipe.get_generation_config();
config.max_new_tokens = 256;
config.num_beam_groups = 3;
config.num_beams = 15;
config.diversity_penalty = 1.0f;
cout << pipe.generate("The Sun is yellow because", config);
}
Hugging Face の結果と比較#
Hugging Face モデルによって生成された結果と結果を比較して分析します。
from transformers import AutoTokenizer, AutoModelForCausalLM
import openvino_genai as ov_genai
tokenizer = AutoTokenizer.from_pretrained("TinyLlama/TinyLlama-1.1B-Chat-v1.0")
model = AutoModelForCausalLM.from_pretrained("TinyLlama/TinyLlama-1.1B-Chat-v1.0")
max_new_tokens = 32
prompt = 'table is made of'
encoded_prompt = tokenizer.encode(prompt, return_tensors='pt', add_special_tokens=False)
hf_encoded_output = model.generate(encoded_prompt, max_new_tokens=max_new_tokens, do_sample=False)
hf_output = tokenizer.decode(hf_encoded_output[0, encoded_prompt.shape[1]:])
print(f'hf_output: {hf_output}')
pipe = ov_genai.LLMPipeline('TinyLlama-1.1B-Chat-v1.0')
ov_output = pipe.generate(prompt, max_new_tokens=max_new_tokens)
print(f'ov_output: {ov_output}')
assert hf_output == ov_output
GenAI API#
OpenVINO GenAI フレーバーには次の API が含まれています:
generation_config - テキスト生成の構成クラスを定義し、生成されるテキストの最大長、文末トークンを無視するかどうか、デコード戦略の詳細 (貪欲、ビーム検索、または多項式サンプリング) などの生成プロセスのカスタマイズを可能にします。
llm_pipeline - 入力の処理、テキストの生成、構成可能なオプションによる出力管理のためのパイプラインを含む、テキスト生成用のクラスとユーティリティーを提供します。
streamer_base - ストリーマーを作成する抽象基本クラス。
tokenizer - テキストのエンコードとデコードのためのトークナイザー・クラス。
visibility - GenAI ライブラリーの可視性を制御します。
GenAI リポジトリーの API について詳しく学びます。