2105 lines
92 KiB
Python
2105 lines
92 KiB
Python
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
from __future__ import annotations
|
|
|
|
import copy
|
|
import json
|
|
import os
|
|
import sys
|
|
import time
|
|
from abc import abstractmethod
|
|
from contextlib import contextmanager
|
|
from dataclasses import dataclass, field
|
|
from threading import Thread
|
|
from typing import List
|
|
|
|
import numpy as np
|
|
import paddle
|
|
import paddle.incubate.multiprocessing as mp
|
|
from paddle.base.framework import in_cinn_mode, in_pir_executor_mode
|
|
from paddle.distributed import fleet
|
|
|
|
try:
|
|
from paddlenlp.experimental.transformers import (
|
|
EagleProposer,
|
|
InferenceWithReferenceProposer,
|
|
SpeculateArgument,
|
|
)
|
|
except:
|
|
pass
|
|
|
|
from paddlenlp.generation import GenerationConfig, TextIteratorStreamer
|
|
from paddlenlp.peft import (
|
|
LoRAConfig,
|
|
LoRAModel,
|
|
PrefixConfig,
|
|
PrefixModelForCausalLM,
|
|
TAREModel,
|
|
)
|
|
from paddlenlp.taskflow.utils import static_mode_guard
|
|
from paddlenlp.trainer import PdArgumentParser
|
|
from paddlenlp.transformers import (
|
|
AutoConfig,
|
|
AutoInferenceModelForCausalLM,
|
|
AutoModelForCausalLM,
|
|
AutoTokenizer,
|
|
ChatGLMTokenizer,
|
|
ChatGLMv2Tokenizer,
|
|
Llama3Tokenizer,
|
|
LlamaTokenizer,
|
|
PretrainedConfig,
|
|
PretrainedModel,
|
|
PretrainedTokenizer,
|
|
)
|
|
from paddlenlp.trl import llm_utils
|
|
from paddlenlp.utils.env import (
|
|
MAX_BSZ,
|
|
MAX_DRAFT_TOKENS,
|
|
PADDLE_INFERENCE_MODEL_SUFFIX,
|
|
PADDLE_INFERENCE_WEIGHTS_SUFFIX,
|
|
SPECULATE_MAX_BSZ,
|
|
)
|
|
from paddlenlp.utils.import_utils import (
|
|
auto_dynamic_graph_pybind,
|
|
is_paddlenlp_ops_available,
|
|
)
|
|
from paddlenlp.utils.log import logger
|
|
|
|
|
|
@dataclass
|
|
class PredictorArgument:
|
|
model_name_or_path: str = field(default=None, metadata={"help": "The directory of model."})
|
|
model_prefix: str = field(default="model", metadata={"help": "the prefix name of static model"})
|
|
src_length: int = field(default=None, metadata={"help": "The max length of source text."})
|
|
min_length: int = field(default=1, metadata={"help": "the min length for decoding."})
|
|
max_length: int = field(default=1024, metadata={"help": "the max length for decoding."})
|
|
top_k: int = field(default=0, metadata={"help": "top_k parameter for generation"})
|
|
top_p: float = field(default=0.7, metadata={"help": "top_p parameter for generation"})
|
|
temperature: float = field(default=0.95, metadata={"help": "temperature parameter for generation"})
|
|
repetition_penalty: float = field(default=1.0, metadata={"help": "repetition penalty parameter for generation"})
|
|
device: str = field(default="gpu", metadata={"help": "Device"})
|
|
dtype: str = field(default=None, metadata={"help": "Model dtype"})
|
|
lora_path: str = field(default=None, metadata={"help": "The directory of LoRA parameters. Default to None"})
|
|
tare_path: str = field(default=None, metadata={"help": "The directory of TARE parameters. Default to None"})
|
|
tare_n: int = field(default=8, metadata={"help": "The num of TARE editors. Default to 8."})
|
|
tare_k: int = field(default=7, metadata={"help": "The num of TARE selected editors. Default to 7."})
|
|
export_precache: bool = field(default=False, metadata={"help": "whether use prefix weight to do infer"})
|
|
prefix_path: str = field(
|
|
default=None, metadata={"help": "The directory of Prefix Tuning parameters. Default to None"}
|
|
)
|
|
decode_strategy: str = field(
|
|
default="sampling",
|
|
metadata={
|
|
"help": "the decoding strategy of generation, which should be one of ['sampling', 'greedy_search', 'beam_search']. Default to sampling"
|
|
},
|
|
)
|
|
use_flash_attention: bool = field(
|
|
default=False,
|
|
metadata={"help": "Whether to use flash attention"},
|
|
)
|
|
|
|
mode: str = field(
|
|
default="dynamic", metadata={"help": "the type of predictor, it should be one of [dynamic, static]"}
|
|
)
|
|
inference_model: bool = field(default=False, metadata={"help": "whether use InferenceModel to do generation"})
|
|
quant_type: str = field(
|
|
default="",
|
|
metadata={
|
|
"help": "Quantization type. Supported values: a8w8, a8w8c8, a8w8_fp8, a8w8c8_fp8, weight_only_int4, weight_only_int8"
|
|
},
|
|
)
|
|
avx_model: bool = field(
|
|
default=False, metadata={"help": "whether use AvxModel to do generation when using cpu inference"}
|
|
)
|
|
avx_type: str = field(
|
|
default=None,
|
|
metadata={
|
|
"help": "avx compute type. Supported values: fp16, bf16,fp16_int8\
|
|
fp16: first_token and next_token run in fp16\
|
|
fp16_int8 : first_token run in fp16, next token run in int8"
|
|
},
|
|
)
|
|
avx_cachekv_type: str = field(
|
|
default="fp16",
|
|
metadata={"help": "avx cachekv type. Supported values: fp16,int8"},
|
|
)
|
|
batch_size: int = field(default=1, metadata={"help": "The batch size of data."})
|
|
benchmark: bool = field(
|
|
default=False,
|
|
metadata={
|
|
"help": "If benchmark set as `True`, we will force model decode to max_length, which is helpful to compute throughput. "
|
|
},
|
|
)
|
|
use_fake_parameter: bool = field(default=False, metadata={"help": "use fake parameter, for ptq scales now."})
|
|
block_attn: bool = field(default=False, metadata={"help": "whether use block attention"})
|
|
block_size: int = field(default=64, metadata={"help": "the block size for cache_kvs."})
|
|
cachekv_int8_type: str = field(
|
|
default=None,
|
|
metadata={
|
|
"help": "If cachekv_int8_type set as `dynamic`, cache kv would be quantized to int8 dynamically. If cachekv_int8_type set as `static`, cache kv would be quantized to int8 Statically."
|
|
},
|
|
)
|
|
|
|
append_attn: bool = field(default=False, metadata={"help": "whether use append attention"})
|
|
|
|
chat_template: str = field(
|
|
default=None,
|
|
metadata={
|
|
"help": "the path of `chat_template.json` file to handle multi-rounds conversation. "
|
|
"If is None(do not set --chat_template argument), it will use the default `chat_template.json`;"
|
|
"If is equal with `model_name_or_path`, it will use the default loading; "
|
|
"If is directory, it will find the `chat_template.json` under the directory; If is file, it will load it."
|
|
"If is none string, it will not use chat_template.json."
|
|
},
|
|
)
|
|
|
|
total_max_length: int = field(
|
|
default=4096, metadata={"help": "Super parameter. Maximum sequence length(encoder+decoder)."}
|
|
)
|
|
speculate_method: str = field(
|
|
default=None,
|
|
metadata={
|
|
"help": "speculate method, it should be one of ['None', 'inference_with_reference', 'eagle', 'mtp']"
|
|
},
|
|
)
|
|
speculate_max_draft_token_num: int = field(
|
|
default=1,
|
|
metadata={"help": "the max length of draft tokens for speculate method."},
|
|
)
|
|
speculate_max_ngram_size: int = field(default=1, metadata={"help": "the max ngram size of speculate method."})
|
|
speculate_verify_window: int = field(
|
|
default=2, metadata={"help": "the max length of verify window for speculate method."}
|
|
)
|
|
speculate_max_candidate_len: int = field(default=5, metadata={"help": "the max length of candidate tokens."})
|
|
draft_model_name_or_path: str = field(default=None, metadata={"help": "The directory of eagle or draft model"})
|
|
draft_model_quant_type: str = field(
|
|
default="",
|
|
metadata={"help": "Draft model quantization type. Reserved for future"},
|
|
)
|
|
return_full_hidden_states: bool = field(default=False, metadata={"help": "whether return full hidden_states"})
|
|
|
|
mla_use_matrix_absorption: bool = field(default=False, metadata={"help": "implement mla with matrix-absorption."})
|
|
weightonly_group_size: int = field(default=-1, metadata={"help": "the max length of candidate tokens."})
|
|
weight_block_size: List[int] = field(
|
|
default_factory=lambda: [128, 128],
|
|
metadata={"help": "Quantitative granularity of weights. Supported values: [128 128]"},
|
|
)
|
|
moe_quant_type: str = field(
|
|
default="",
|
|
metadata={"help": "Quantization type of moe. Supported values: weight_only_int4, weight_only_int8"},
|
|
)
|
|
output_via_mq: bool = field(
|
|
default=True,
|
|
metadata={"help": "Controls whether the message queue is enabled for output"},
|
|
)
|
|
dynamic_insert: bool = field(default=False, metadata={"help": "whether use dynamic insert"})
|
|
total_request_num: int = field(default=None, metadata={"help": "The total number of request data"})
|
|
kv_cache_reuse: int = field(default=0)
|
|
|
|
def __post_init__(self):
|
|
if self.speculate_method is not None:
|
|
self.append_attn = True
|
|
if self.append_attn:
|
|
self.block_attn = True
|
|
if self.block_attn:
|
|
self.inference_model = True
|
|
assert self.max_length < self.total_max_length, "max_length should smaller than total_max_length."
|
|
if self.src_length is None:
|
|
self.src_length = self.total_max_length - self.max_length
|
|
# update config parameter for inference predictor
|
|
if self.decode_strategy == "greedy_search":
|
|
self.top_p = 0.0
|
|
self.temperature = 1.0
|
|
if self.total_request_num is None:
|
|
self.total_request_num = self.batch_size
|
|
|
|
|
|
@dataclass
|
|
class ModelArgument:
|
|
model_type: str = field(
|
|
default=None,
|
|
metadata={"help": "the type of the model, which can be one of ['gpt-3', 'ernie-3.5-se', 'llama-img2txt']"},
|
|
)
|
|
data_file: str = field(default=None, metadata={"help": "data file directory"})
|
|
output_file: str = field(default="output.json", metadata={"help": "predict result file directory"})
|
|
|
|
|
|
def batchfy_text(texts, batch_size):
|
|
batch_texts = []
|
|
batch_start = 0
|
|
while batch_start < len(texts):
|
|
batch_texts += [texts[batch_start : min(batch_start + batch_size, len(texts))]]
|
|
batch_start += batch_size
|
|
return batch_texts
|
|
|
|
|
|
class BasePredictor:
|
|
def __init__(
|
|
self, config: PredictorArgument, tokenizer: PretrainedTokenizer = None, model: PretrainedModel = None
|
|
):
|
|
if model is not None and hasattr(model, "config"):
|
|
self.model_config = model.config
|
|
else:
|
|
self.model_config = AutoConfig.from_pretrained(config.model_name_or_path)
|
|
|
|
self.config: PredictorArgument = config
|
|
if tokenizer is None:
|
|
tokenizer = AutoTokenizer.from_pretrained(config.model_name_or_path, padding_side="left")
|
|
|
|
self.tokenizer = tokenizer
|
|
|
|
self.return_tensors = "pd"
|
|
self.tensor_parallel_rank, self.tensor_parallel_degree = llm_utils.init_dist_env()
|
|
self.model_config.tensor_parallel_rank, self.model_config.tensor_parallel_degree = (
|
|
self.tensor_parallel_rank,
|
|
self.tensor_parallel_degree,
|
|
)
|
|
|
|
try:
|
|
self.generation_config = GenerationConfig.from_pretrained(config.model_name_or_path)
|
|
except:
|
|
logger.warning(
|
|
"Can't find generation config, so it will not use generation_config field in the model config"
|
|
)
|
|
self.generation_config = None
|
|
|
|
def _preprocess(self, source):
|
|
if self.tokenizer.chat_template is not None:
|
|
# for str -> List[str] eg. "hello"
|
|
# for List[str] -> List[str] eg. ["hello", "hello new"]
|
|
# for List[List[str]] -> List[List[List[str]]] eg. 历史对话形式,一轮
|
|
# [ [ "Hello, how are you?", "I'm doing great. How can I help you today?"],
|
|
# ["I'd like to show off how chat templating works!"], ]
|
|
# for List[Dict] -> List[List[Dict]] [{'role': 'user', 'content': 'hello'}, {'role': 'assistant', 'content': 'nice'}]
|
|
# -> [[{'role': 'user', 'content': 'hello'}, {'role': 'assistant', 'content': 'nice'}]]
|
|
if not isinstance(source, list) or not isinstance(source[0], str):
|
|
source = [source]
|
|
source = [self.tokenizer.apply_chat_template(sentence, tokenize=False) for sentence in source]
|
|
|
|
tokenized_source = self.tokenizer(
|
|
source,
|
|
max_length=self.config.src_length,
|
|
truncation=True,
|
|
return_position_ids=True if not isinstance(self.tokenizer, ChatGLMTokenizer) else False,
|
|
return_attention_mask=True,
|
|
truncation_side="left",
|
|
return_tensors=self.return_tensors,
|
|
padding=True,
|
|
# when use chat_template, it should not add special tokens
|
|
# chatglm2 prefix-tokens can not be tokenized into ids
|
|
add_special_tokens=self.tokenizer.chat_template is None
|
|
or isinstance(self.tokenizer, (ChatGLMv2Tokenizer, ChatGLMTokenizer)),
|
|
)
|
|
return tokenized_source
|
|
|
|
@abstractmethod
|
|
def _infer(self, inputs):
|
|
raise NotImplementedError
|
|
|
|
def _postprocess(self, predictions, return_tokens=False):
|
|
decoded_predictions = self.tokenizer.batch_decode(
|
|
predictions, skip_special_tokens=True, clean_up_tokenization_spaces=False
|
|
)
|
|
if return_tokens:
|
|
return decoded_predictions, predictions
|
|
else:
|
|
return decoded_predictions
|
|
|
|
def predict(self, input_texts: str | list[str], return_tokens=False):
|
|
tokenized_source = self._preprocess(input_texts)
|
|
# Synchronize the HPU device for the static graph predictor
|
|
# Ensure that configuration data read from the CPU is updated to the HPU device
|
|
paddle.device.synchronize()
|
|
predictions = self._infer(tokenized_source)
|
|
decoded_predictions = self._postprocess(predictions, return_tokens=return_tokens)
|
|
return decoded_predictions
|
|
|
|
|
|
class DygraphPredictor(BasePredictor):
|
|
def __init__(
|
|
self, config: PredictorArgument, tokenizer: PretrainedTokenizer = None, model: PretrainedModel = None, **kwargs
|
|
):
|
|
super().__init__(config, tokenizer, model)
|
|
self.model = model
|
|
if config.lora_path is not None:
|
|
lora_config = LoRAConfig.from_pretrained(config.lora_path)
|
|
dtype = lora_config.dtype
|
|
elif config.prefix_path is not None:
|
|
prefix_config = PrefixConfig.from_pretrained(config.prefix_path)
|
|
dtype = prefix_config.dtype
|
|
elif config.dtype is not None:
|
|
dtype = config.dtype
|
|
else:
|
|
raise ValueError("Please specific the model dtype.")
|
|
|
|
if self.model is None:
|
|
self.model = AutoModelForCausalLM.from_pretrained(
|
|
config.model_name_or_path,
|
|
use_flash_attention=config.use_flash_attention,
|
|
dtype=dtype,
|
|
tensor_parallel_degree=self.tensor_parallel_degree,
|
|
tensor_parallel_rank=self.tensor_parallel_rank,
|
|
)
|
|
|
|
if config.lora_path is not None:
|
|
self.model = LoRAModel.from_pretrained(
|
|
model=self.model, lora_path=config.lora_path, lora_config=lora_config
|
|
)
|
|
self.model.merge()
|
|
if config.prefix_path is not None:
|
|
prefix_tuning_params = llm_utils.get_prefix_tuning_params(self.model)
|
|
self.model = PrefixModelForCausalLM.from_pretrained(
|
|
model=self.model,
|
|
prefix_path=config.prefix_path,
|
|
postprocess_past_key_value=prefix_tuning_params["postprocess_past_key_value"],
|
|
)
|
|
|
|
if config.tare_path is not None:
|
|
self.model = TAREModel(base_model=self.model, n=config.tare_n, k=config.tare_k)
|
|
self.model.load_model(os.path.join(config.tare_path, "delta_vector.pth"))
|
|
|
|
self.model.eval()
|
|
|
|
@paddle.no_grad()
|
|
def _infer(self, inputs: dict[str, paddle.Tensor]):
|
|
result = self.model.generate(
|
|
**inputs,
|
|
max_new_tokens=self.config.max_length,
|
|
bos_token_id=self.tokenizer.bos_token_id,
|
|
eos_token_id=llm_utils.get_eos_token_id(self.tokenizer, self.generation_config),
|
|
pad_token_id=self.tokenizer.pad_token_id,
|
|
decode_strategy=self.config.decode_strategy,
|
|
temperature=self.config.temperature,
|
|
top_k=self.config.top_k,
|
|
top_p=self.config.top_p,
|
|
repetition_penalty=self.config.repetition_penalty,
|
|
)
|
|
result = result[0]
|
|
return result
|
|
|
|
def stream_predict(self, inputs: dict[str, paddle.Tensor]):
|
|
text_streamer = TextIteratorStreamer(self.tokenizer, skip_special_tokens=True)
|
|
input_features = self._preprocess(inputs)
|
|
generation_kwargs = dict(
|
|
**input_features,
|
|
streamer=text_streamer,
|
|
max_new_tokens=self.config.max_length,
|
|
bos_token_id=self.tokenizer.bos_token_id,
|
|
eos_token_id=llm_utils.get_eos_token_id(self.tokenizer, self.generation_config),
|
|
pad_token_id=self.tokenizer.pad_token_id,
|
|
decode_strategy=(
|
|
"greedy_search" if self.config.top_k == 1 and self.config.top_p == 1.0 else self.config.decode_strategy
|
|
),
|
|
temperature=self.config.temperature,
|
|
top_k=self.config.top_k,
|
|
top_p=self.config.top_p,
|
|
repetition_penalty=self.config.repetition_penalty,
|
|
)
|
|
thread = Thread(target=self.model.generate, kwargs=generation_kwargs)
|
|
thread.start()
|
|
|
|
return text_streamer
|
|
|
|
|
|
class StaticGraphPredictor(BasePredictor):
|
|
def __init__(
|
|
self, config: PredictorArgument, tokenizer: PretrainedTokenizer = None, model: PretrainedModel = None, **kwargs
|
|
):
|
|
super().__init__(config, tokenizer, model)
|
|
|
|
inference_config = paddle.inference.Config(self.config.model_name_or_path, self.config.model_prefix)
|
|
|
|
if self.config.device == "gpu":
|
|
# set GPU configs accordingly
|
|
inference_config.enable_use_gpu(100, 0)
|
|
elif self.config.device == "cpu":
|
|
# set CPU configs accordingly,
|
|
# such as enable_mkldnn, set_cpu_math_library_num_threads
|
|
inference_config.disable_gpu()
|
|
inference_config.disable_glog_info()
|
|
inference_config.enable_new_executor()
|
|
# remove `gpu_cpu_map_matmul_v2_to_matmul_pass` to avoid mapping matmul_v2 -> matmul op
|
|
if config.dtype == "bfloat16":
|
|
inference_config.delete_pass("gpu_cpu_map_matmul_v2_to_matmul_pass")
|
|
if in_pir_executor_mode():
|
|
inference_config.enable_new_ir()
|
|
if in_cinn_mode():
|
|
inference_config.enable_cinn()
|
|
|
|
with static_mode_guard():
|
|
self.predictor = paddle.inference.create_predictor(inference_config)
|
|
|
|
self.return_tensors = "np"
|
|
|
|
def _preprocess(self, input_text: str | list[str]):
|
|
inputs = super()._preprocess(input_text)
|
|
inputs["max_new_tokens"] = np.array(self.config.max_length, dtype="int64")
|
|
|
|
inputs["top_p"] = np.array(self.config.top_p, dtype="float32")
|
|
inputs["temperature"] = np.array(self.config.temperature, dtype="float32")
|
|
inputs["top_k"] = np.array(self.config.top_k, dtype="int64")
|
|
inputs["repetition_penalty"] = np.array(self.config.repetition_penalty, dtype="float32")
|
|
|
|
return inputs
|
|
|
|
def _infer(self, inputs: dict[str, np.ndarray]):
|
|
for name in self.predictor.get_input_names():
|
|
self.predictor.get_input_handle(name).copy_from_cpu(inputs[name])
|
|
|
|
self.predictor.run()
|
|
output_names = self.predictor.get_output_names()
|
|
output_handle = self.predictor.get_output_handle(output_names[0])
|
|
results = output_handle.copy_to_cpu()
|
|
# the first result is decoding_ids
|
|
decoded_ids = results.tolist()
|
|
return decoded_ids
|
|
|
|
|
|
class InferencePredictorMixin(BasePredictor):
|
|
def __init__(self, config: PredictorArgument, tokenizer: PretrainedTokenizer, model: PretrainedModel = None):
|
|
BasePredictor.__init__(self, config, tokenizer, model)
|
|
self.architectures = self.model_config.architectures[0].lower()
|
|
|
|
self.dtype = config.dtype or self.model_config.dtype
|
|
self.pre_ids = paddle.full([config.batch_size, config.total_max_length], -1, dtype="int64")
|
|
|
|
if config.device == "cpu" and config.avx_model:
|
|
assert (
|
|
"llama" in self.architectures and self.model_config.model_type != "llama-img2txt"
|
|
), "avx_mode only support llama now"
|
|
self.cache_kvs = None
|
|
self.attention_mask = None
|
|
self.tgt_generation_mask = None
|
|
self.tgt_pos = None
|
|
else:
|
|
self.cache_kvs = [paddle.zeros(shape, dtype=self.dtype) for shape in self.cache_kvs_shape]
|
|
self.num_layers, self.num_key_value_heads, self.head_dim = (
|
|
len(self.cache_kvs),
|
|
self.cache_kvs[0].shape[-3],
|
|
self.cache_kvs[0].shape[-1],
|
|
)
|
|
self.tgt_generation_mask = paddle.ones(
|
|
shape=[config.batch_size, 1, 1, config.total_max_length],
|
|
dtype=self.dtype,
|
|
)
|
|
if "chatglm" in self.architectures:
|
|
self.attention_mask = paddle.ones(
|
|
shape=(config.batch_size, 1, config.total_max_length, config.total_max_length),
|
|
dtype=self.dtype,
|
|
)
|
|
self.tgt_pos = paddle.ones(
|
|
shape=[config.batch_size, 2, 1],
|
|
dtype="int64",
|
|
)
|
|
else:
|
|
self.attention_mask = paddle.zeros(
|
|
shape=(config.batch_size, 1, config.total_max_length, config.total_max_length),
|
|
dtype=self.dtype,
|
|
)
|
|
if config.export_precache:
|
|
if config.prefix_path:
|
|
prefix_cache = (
|
|
paddle.to_tensor(np.load(f"{config.prefix_path}/pre_caches.npy"))
|
|
.astype(self.dtype)
|
|
.unsqueeze(2)
|
|
)
|
|
prefix_cache = paddle.expand(
|
|
prefix_cache,
|
|
[
|
|
self.num_layers,
|
|
2,
|
|
config.batch_size,
|
|
self.num_key_value_heads,
|
|
prefix_cache.shape[-2],
|
|
self.head_dim,
|
|
],
|
|
)
|
|
self.pre_caches = [
|
|
item.squeeze_(0) for item in paddle.split(prefix_cache, self.num_layers, axis=0)
|
|
]
|
|
else:
|
|
prefix_cache = paddle.zeros(
|
|
[self.num_layers, 2, config.batch_size, self.num_key_value_heads, 128, self.head_dim],
|
|
dtype=self.dtype,
|
|
)
|
|
self.pre_caches = [
|
|
item.squeeze_(0) for item in paddle.split(prefix_cache, self.num_layers, axis=0)
|
|
]
|
|
|
|
def _postprocess(self, predictions, return_tokens=False):
|
|
if paddle.distributed.get_rank() == 0:
|
|
tokens: np.ndarray = llm_utils.load_real_time_tokens()
|
|
decoded_predictions = self.tokenizer.batch_decode(
|
|
tokens.tolist(), skip_special_tokens=True, clean_up_tokenization_spaces=False
|
|
)
|
|
if return_tokens:
|
|
return decoded_predictions, tokens.tolist()
|
|
else:
|
|
return decoded_predictions
|
|
else:
|
|
return None
|
|
|
|
def _preprocess(self, source):
|
|
if self.attention_mask is not None:
|
|
self.attention_mask[:] = 0
|
|
if self.tgt_generation_mask is not None:
|
|
self.tgt_generation_mask[:] = 1
|
|
pre_caches_length = 0 if not self.config.export_precache else self.pre_caches[0].shape[-2]
|
|
|
|
if self.tokenizer.chat_template is not None:
|
|
if not isinstance(source, list) or not isinstance(source[0], str):
|
|
source = [source]
|
|
source = [self.tokenizer.apply_chat_template(sentence, tokenize=False) for sentence in source]
|
|
|
|
inputs = llm_utils.dybatch_preprocess(
|
|
self.tokenizer,
|
|
source,
|
|
self.config.src_length,
|
|
self.config.max_length,
|
|
self.architectures,
|
|
top_p=self.config.top_p,
|
|
temperature=self.config.temperature,
|
|
eos_token_id=llm_utils.get_eos_token_id(self.tokenizer, self.generation_config),
|
|
benchmark=self.config.benchmark,
|
|
pre_caches_length=pre_caches_length,
|
|
pad_style="left" if paddle.is_compiled_with_custom_device("intel_hpu") else "None",
|
|
)
|
|
|
|
if "chatglmforcausallm" == self.architectures.lower():
|
|
if inputs["input_ids"].shape[0] < self.config.batch_size:
|
|
self.tgt_pos = self.tgt_pos[: inputs["input_ids"].shape[0]]
|
|
for i in range(inputs["input_ids"].shape[0]):
|
|
length = inputs["seq_len_encoder"][i][0]
|
|
if self.attention_mask is not None:
|
|
self.attention_mask[i, 0, :length, :length] = 1
|
|
self.attention_mask[i, 0, : length - 1, length - 1] = 0
|
|
if self.tgt_pos is not None:
|
|
self.tgt_pos[i, 0, 0] = paddle.to_tensor([length], dtype="int64")
|
|
|
|
if pre_caches_length > 0:
|
|
prefix_attention_mask = paddle.ones(
|
|
[1, length, pre_caches_length], dtype=self.attention_mask.dtype
|
|
)
|
|
post_attention_mask = paddle.ones(
|
|
shape=(length, length), dtype=self.attention_mask.dtype
|
|
).unsqueeze_(axis=0)
|
|
post_attention_mask[0, : length - 1, length - 1] = 0
|
|
self.attention_mask[i, 0, :length, : length + pre_caches_length] = paddle.concat(
|
|
[prefix_attention_mask, post_attention_mask], axis=2
|
|
)
|
|
|
|
inputs["tgt_pos"] = self.tgt_pos
|
|
elif "bloom" in self.architectures:
|
|
for i in range(inputs["input_ids"].shape[0]):
|
|
length = inputs["seq_len_encoder"][i][0]
|
|
if self.attention_mask is not None:
|
|
self.attention_mask[i, :, :length, :length] = paddle.tril(
|
|
paddle.ones(shape=(length, length), dtype=self.config.dtype)
|
|
)
|
|
if pre_caches_length > 0:
|
|
if self.config.prefix_path is None:
|
|
prefix_attention_mask = paddle.zeros([1, length, pre_caches_length], dtype=self.config.dtype)
|
|
else:
|
|
prefix_attention_mask = paddle.ones([1, length, pre_caches_length], dtype=self.config.dtype)
|
|
post_attention_mask = paddle.tril(
|
|
paddle.ones(shape=(length, length), dtype=self.config.dtype)
|
|
).unsqueeze_(axis=0)
|
|
if self.attention_mask is not None:
|
|
self.attention_mask[i, :, :length, : length + pre_caches_length] = paddle.concat(
|
|
[prefix_attention_mask, post_attention_mask], axis=2
|
|
)
|
|
|
|
inputs["tgt_pos"] = inputs["tgt_pos"] + pre_caches_length
|
|
# alibi encoder
|
|
alibi_slopes = llm_utils.get_alibi_slopes(self.model_config.n_head)
|
|
inputs["position_ids"] = paddle.to_tensor(alibi_slopes, dtype="float32")
|
|
arange_tensor_encoder = paddle.arange(self.config.total_max_length, dtype=self.config.dtype)
|
|
alibi = (alibi_slopes[None, :, None, None] * arange_tensor_encoder).astype(self.config.dtype)
|
|
|
|
if self.model_config.tensor_parallel_degree > 1:
|
|
block_size = self.model_config.n_head // self.model_config.tensor_parallel_degree
|
|
alibi = alibi[
|
|
:,
|
|
self.model_config.tensor_parallel_rank
|
|
* block_size : (self.model_config.tensor_parallel_rank + 1)
|
|
* block_size,
|
|
]
|
|
alibi = alibi.reshape([self.config.batch_size, block_size, 1, self.config.max_length])
|
|
inputs["position_ids"] = inputs["position_ids"][
|
|
self.model_config.tensor_parallel_rank
|
|
* block_size : (self.model.config.tensor_parallel_rank + 1)
|
|
* block_size
|
|
]
|
|
|
|
alibi_encoder = alibi.expand(
|
|
[
|
|
self.config.batch_size,
|
|
self.model_config.n_head // self.model_config.tensor_parallel_degree,
|
|
self.config.total_max_length,
|
|
self.config.total_max_length,
|
|
]
|
|
)
|
|
# only generate valid encoder attention mask, other place set 0.
|
|
alibi_encoder[i, :, length:, length:] = 0
|
|
|
|
alibi_decoder = alibi.expand(
|
|
[
|
|
self.config.batch_size,
|
|
self.model_config.n_head // self.model_config.tensor_parallel_degree,
|
|
1,
|
|
self.config.total_max_length,
|
|
]
|
|
)
|
|
self.attention_mask = (
|
|
alibi_encoder + (1 - self.attention_mask) * paddle.finfo(self.attention_mask.dtype).min
|
|
)
|
|
self.tgt_generation_mask = (
|
|
alibi_decoder + (1 - self.tgt_generation_mask) * paddle.finfo(self.tgt_generation_mask.dtype).min
|
|
)
|
|
|
|
else:
|
|
if "attention_mask" in inputs and inputs["attention_mask"] is not None:
|
|
bsz, src_len = inputs["attention_mask"].shape
|
|
causal_4d_mask = paddle.tril(
|
|
paddle.ones(
|
|
shape=(bsz, 1, self.config.total_max_length, self.config.total_max_length),
|
|
dtype=self.config.dtype,
|
|
)
|
|
)
|
|
attention_mask_2d = paddle.ones(shape=(bsz, self.config.total_max_length), dtype="int64")
|
|
attention_mask_2d[:, 0:src_len] = inputs["attention_mask"]
|
|
bool_mask = attention_mask_2d != 1
|
|
expanded_attn_mask = bool_mask[:, None, None, :].expand(
|
|
[bsz, 1, self.config.total_max_length, self.config.total_max_length]
|
|
)
|
|
self.attention_mask = causal_4d_mask.masked_fill(expanded_attn_mask, 0)
|
|
else:
|
|
for i in range(inputs["input_ids"].shape[0]):
|
|
length = inputs["seq_len_encoder"][i][0]
|
|
if self.attention_mask is not None:
|
|
self.attention_mask[i, 0, :length, :length] = paddle.tril(
|
|
paddle.ones(shape=(1, 1, length, length), dtype=self.config.dtype)
|
|
)
|
|
if pre_caches_length > 0:
|
|
if self.config.prefix_path is None:
|
|
prefix_attention_mask = paddle.zeros(
|
|
[1, length, pre_caches_length], dtype=self.attention_mask.dtype
|
|
)
|
|
else:
|
|
prefix_attention_mask = paddle.ones(
|
|
[1, length, pre_caches_length], dtype=self.attention_mask.dtype
|
|
)
|
|
post_attention_mask = paddle.tril(
|
|
paddle.ones(shape=(length, length), dtype=self.attention_mask.dtype)
|
|
).unsqueeze_(axis=0)
|
|
if self.attention_mask is not None:
|
|
self.attention_mask[i, 0, :length, : length + pre_caches_length] = paddle.concat(
|
|
[prefix_attention_mask, post_attention_mask], axis=2
|
|
)
|
|
|
|
inputs["pre_ids"] = self.pre_ids
|
|
inputs["attention_mask"] = self.attention_mask
|
|
inputs["tgt_generation_mask"] = self.tgt_generation_mask
|
|
|
|
if self.config.device == "cpu" and self.config.avx_model:
|
|
inputs.pop("position_ids")
|
|
inputs.pop("tgt_pos")
|
|
inputs.pop("attention_mask")
|
|
inputs.pop("tgt_generation_mask")
|
|
|
|
if pre_caches_length > 0:
|
|
if self.config.mode == "dynamic":
|
|
inputs["pre_caches"] = self.pre_caches
|
|
else:
|
|
for i in range(len(self.pre_caches)):
|
|
inputs["pre_caches_{}".format(i)] = self.pre_caches[i].numpy()
|
|
|
|
return inputs
|
|
|
|
|
|
class StaticGraphInferencePredictor(InferencePredictorMixin):
|
|
def __init__(
|
|
self,
|
|
config: PredictorArgument,
|
|
tokenizer: PretrainedTokenizer = None,
|
|
model: PretrainedModel = None,
|
|
**kwargs,
|
|
):
|
|
self.cache_kvs_shape = kwargs.get("cache_kvs_shape", None)
|
|
if self.cache_kvs_shape is None:
|
|
raise ValueError("cache_kvs_shape should be provided for StaticGraphInferencePredictor")
|
|
InferencePredictorMixin.__init__(self, config, tokenizer, model)
|
|
|
|
self.predictor = self._create_predictor(config)
|
|
|
|
def _create_predictor(self, predictor_args: PredictorArgument):
|
|
if not is_paddlenlp_ops_available():
|
|
raise ValueError(
|
|
"you should install the paddlenlp ops to run inference predictor, "
|
|
"https://github.com/PaddlePaddle/PaddleNLP/blob/develop/csrc/README.md"
|
|
)
|
|
|
|
infer_model_path = llm_utils.get_infer_model_path(
|
|
predictor_args.model_name_or_path, predictor_args.model_prefix
|
|
)
|
|
|
|
config = paddle.inference.Config(
|
|
infer_model_path + PADDLE_INFERENCE_MODEL_SUFFIX,
|
|
infer_model_path + PADDLE_INFERENCE_WEIGHTS_SUFFIX,
|
|
)
|
|
|
|
config.switch_ir_optim(True)
|
|
# remove `gpu_cpu_map_matmul_v2_to_matmul_pass` to avoid mapping matmul_v2 -> matmul op
|
|
if predictor_args.dtype == "bfloat16":
|
|
config.delete_pass("gpu_cpu_map_matmul_v2_to_matmul_pass")
|
|
|
|
if predictor_args.device in paddle.device.get_all_custom_device_type():
|
|
device_id = int(os.environ.get("FLAGS_selected_{}s".format(predictor_args.device), 0))
|
|
config.enable_custom_device(predictor_args.device, device_id)
|
|
elif predictor_args.device == "xpu":
|
|
raise ValueError(
|
|
"you should export xpu static model with --block_attn flag and use predictor with --block_attn too"
|
|
"https://github.com/PaddlePaddle/PaddleNLP/blob/develop/llm/docs/inference.md"
|
|
)
|
|
elif predictor_args.device == "cpu" and predictor_args.avx_model:
|
|
config.disable_gpu()
|
|
config.enable_new_ir()
|
|
config.disable_mkldnn()
|
|
config.disable_glog_info()
|
|
else:
|
|
device_id = int(os.environ.get("FLAGS_selected_gpus", 0))
|
|
config.enable_use_gpu(100, device_id)
|
|
config.enable_new_executor()
|
|
|
|
predictor = paddle.inference.create_predictor(config)
|
|
return predictor
|
|
|
|
@paddle.no_grad()
|
|
def _infer(self, inputs):
|
|
for k, v in inputs.items():
|
|
input_tensor = self.predictor.get_input_handle(k)
|
|
|
|
if "mask" in k or "position" in k:
|
|
input_tensor.share_external_data(v)
|
|
else:
|
|
if paddle.is_tensor(v):
|
|
v = v.numpy()
|
|
input_tensor.copy_from_cpu(v)
|
|
|
|
for i in range(len(self.cache_kvs_shape)):
|
|
input_tensor = self.predictor.get_input_handle("cache_kvs_" + str(i))
|
|
input_tensor.share_external_data(self.cache_kvs[i])
|
|
input_tensor = self.predictor.get_input_handle("pre_ids")
|
|
input_tensor.share_external_data(self.pre_ids)
|
|
|
|
self.predictor.run()
|
|
|
|
|
|
class DygraphInferencePredictor(InferencePredictorMixin):
|
|
def __init__(
|
|
self,
|
|
config: PredictorArgument,
|
|
tokenizer: PretrainedTokenizer = None,
|
|
model: PretrainedModel = None,
|
|
**kwargs,
|
|
):
|
|
if model is None:
|
|
raise ValueError("model should be provided for DygraphInferencePredictor")
|
|
self.cache_kvs_shape = model.get_cache_kvs_shape(model.config, config.batch_size, config.total_max_length)
|
|
InferencePredictorMixin.__init__(self, config, tokenizer, model)
|
|
self.model = model
|
|
|
|
@paddle.no_grad()
|
|
def _infer(self, inputs: dict[str, paddle.Tensor]):
|
|
for key in inputs.keys():
|
|
if paddle.is_tensor(inputs[key]):
|
|
continue
|
|
if isinstance(inputs[key], list):
|
|
if paddle.is_tensor(inputs[key]):
|
|
continue
|
|
inputs[key] = [paddle.to_tensor(item) for item in inputs[key]]
|
|
else:
|
|
inputs[key] = paddle.to_tensor(inputs[key])
|
|
|
|
inputs["cache_kvs"] = self.cache_kvs
|
|
return self.model.generate(
|
|
**inputs,
|
|
)
|
|
|
|
|
|
class BlockInferencePredictorMixin(BasePredictor):
|
|
def __init__(
|
|
self,
|
|
config: PredictorArgument,
|
|
tokenizer: PretrainedTokenizer = None,
|
|
model: PretrainedModel = None,
|
|
):
|
|
BasePredictor.__init__(self, config, tokenizer, model)
|
|
|
|
self.num_layers = len(self.cache_k_shapes)
|
|
if paddle.is_compiled_with_custom_device("intel_hpu"):
|
|
self.num_key_value_heads = self.cache_k_shapes[0][-2]
|
|
else:
|
|
self.num_key_value_heads = self.cache_k_shapes[0][-3]
|
|
self.head_dim = self.cache_k_shapes[0][-1]
|
|
self.max_block_nums = self.cache_k_shapes[0][0]
|
|
self.batch_size = config.batch_size
|
|
self.model_name_or_path = config.model_name_or_path
|
|
|
|
self.architectures = self.model_config.architectures[0].lower()
|
|
|
|
self.dtype = config.dtype or self.model_config.dtype
|
|
|
|
self.rope_theta = self.model_config.get("rope_theta", 10000.0)
|
|
self.rope_scaling = self.model_config.get("rope_scaling", None)
|
|
|
|
self.pre_cache_length = 0
|
|
|
|
msg_queue_id_str = os.getenv("INFERENCE_MSG_QUEUE_ID", str(os.getpid()))
|
|
os.environ["INFERENCE_MSG_QUEUE_ID"] = msg_queue_id_str
|
|
|
|
if config.export_precache:
|
|
pre_cache_npy = np.load(config.prefix_path)
|
|
self.pre_cache_length = pre_cache_npy.shape[-2]
|
|
config.max_length -= self.pre_cache_length
|
|
self.pre_caches = [
|
|
paddle.zeros(
|
|
[config.batch_size, self.num_key_value_heads, self.pre_cache_length, self.head_dim],
|
|
dtype=self.dtype,
|
|
)
|
|
for _ in range(2 * self.num_layers)
|
|
]
|
|
for i in range(self.num_layers):
|
|
self.pre_caches[2 * i][:, :, :, :] = paddle.to_tensor(pre_cache_npy[i][0], dtype=self.dtype).unsqueeze(
|
|
0
|
|
)
|
|
self.pre_caches[2 * i + 1][:, :, :, :] = paddle.to_tensor(
|
|
pre_cache_npy[i][1], dtype=self.dtype
|
|
).unsqueeze(0)
|
|
|
|
self.pre_cache_mask = paddle.zeros(
|
|
shape=[config.batch_size, 1, config.src_length, config.src_length + self.pre_cache_length],
|
|
dtype=config.dtype,
|
|
)
|
|
self.pre_cache_mask[:, :, :, : self.pre_cache_length] = 1
|
|
self.pre_cache_mask[:, :, :, self.pre_cache_length :] = paddle.tril(
|
|
paddle.ones(shape=[config.batch_size, 1, config.src_length, config.src_length], dtype=config.dtype)
|
|
)
|
|
|
|
if config.cachekv_int8_type == "dynamic":
|
|
self.k_quant_scales = [
|
|
paddle.zeros([config.batch_size, self.num_key_value_heads], dtype="float32")
|
|
for _ in range(self.num_layers)
|
|
]
|
|
self.v_quant_scales = [
|
|
paddle.zeros([config.batch_size, self.num_key_value_heads], dtype="float32")
|
|
for _ in range(self.num_layers)
|
|
]
|
|
self.k_dequant_scales = [
|
|
paddle.zeros([config.batch_size, self.num_key_value_heads], dtype="float32")
|
|
for _ in range(self.num_layers)
|
|
]
|
|
self.v_dequant_scales = [
|
|
paddle.zeros([config.batch_size, self.num_key_value_heads], dtype="float32")
|
|
for _ in range(self.num_layers)
|
|
]
|
|
|
|
def pad_batch_data(self, insts):
|
|
"""Pad the instances to the max sequence length in batch."""
|
|
seq_lens = []
|
|
for i, inst in enumerate(insts):
|
|
length = len(inst)
|
|
seq_lens.append(length)
|
|
self.input_ids[i, :length] = np.array(inst)
|
|
return seq_lens
|
|
|
|
def init_model_inputs(self, config: PredictorArgument):
|
|
self.input_ids = paddle.full(
|
|
shape=[config.batch_size, config.total_max_length], fill_value=self.tokenizer.pad_token_id, dtype="int64"
|
|
)
|
|
self.model_inputs = {}
|
|
|
|
if config.export_precache:
|
|
self.model_inputs["src_mask"] = (self.pre_cache_mask - 1) * 1e4
|
|
|
|
self.model_inputs["block_tables"] = paddle.full(
|
|
shape=[config.batch_size, (config.total_max_length + config.block_size - 1) // config.block_size],
|
|
fill_value=-1,
|
|
dtype="int32",
|
|
)
|
|
self.model_inputs["top_p"] = paddle.full(
|
|
shape=[config.batch_size, 1], fill_value=config.top_p, dtype="float32"
|
|
)
|
|
self.model_inputs["temperature"] = paddle.full(
|
|
shape=[config.batch_size, 1], fill_value=config.temperature, dtype="float32"
|
|
)
|
|
self.model_inputs["eos_token_id"] = paddle.to_tensor(
|
|
np.array(llm_utils.get_eos_token_id(self.tokenizer, self.generation_config)).reshape(-1, 1).astype("int64")
|
|
)
|
|
self.model_inputs["penalty_score"] = paddle.full(
|
|
shape=[config.batch_size, 1], fill_value=config.repetition_penalty, dtype="float32"
|
|
)
|
|
self.model_inputs["frequency_score"] = paddle.full(
|
|
shape=[config.batch_size, 1], fill_value=0.0, dtype="float32"
|
|
)
|
|
self.model_inputs["presence_score"] = paddle.full(
|
|
shape=[config.batch_size, 1], fill_value=0.0, dtype="float32"
|
|
)
|
|
self.model_inputs["min_length"] = paddle.full(
|
|
shape=[config.batch_size, 1], fill_value=config.min_length, dtype="int64"
|
|
)
|
|
self.model_inputs["max_length"] = paddle.full(
|
|
shape=[config.batch_size, 1], fill_value=config.max_length, dtype="int64"
|
|
)
|
|
self.model_inputs["rope_emb"] = llm_utils.get_rotary_position_embedding(
|
|
paddle.arange(config.total_max_length).reshape((1, -1)), self.head_dim, self.rope_theta, self.rope_scaling
|
|
)
|
|
self.model_inputs["bad_tokens"] = paddle.to_tensor([-1], dtype="int64")
|
|
self.model_inputs["is_block_step"] = paddle.full(shape=[config.batch_size], fill_value=False, dtype="bool")
|
|
|
|
# bloom model needs src_mask and tgt_mask!
|
|
if "bloom" in self.architectures:
|
|
lower_one_tril = paddle.tril(
|
|
paddle.ones(shape=(config.total_max_length, config.total_max_length), dtype=self.dtype)
|
|
)
|
|
lower_one_tril = lower_one_tril[None, None, :, :]
|
|
self.model_inputs["src_mask"] = lower_one_tril.tile([config.batch_size, 1, 1, 1])
|
|
self.model_inputs["tgt_mask"] = paddle.full(
|
|
shape=[config.batch_size, 1, 1, config.total_max_length], fill_value=1, dtype=self.dtype
|
|
)
|
|
arange_tensor_encoder = paddle.arange(config.total_max_length).astype(self.dtype)
|
|
alibi_slopes = llm_utils.get_alibi_slopes(self.num_key_value_heads)
|
|
alibi = alibi_slopes[None, :, None, None] * arange_tensor_encoder
|
|
alibi_encoder = alibi.tile([config.batch_size, 1, config.total_max_length, 1])
|
|
alibi_decoder = alibi.tile(
|
|
[
|
|
config.batch_size,
|
|
1,
|
|
1,
|
|
1,
|
|
]
|
|
)
|
|
# self.model_inputs["src_mask/tgt_mask"] is read only, will not be updated!
|
|
self.model_inputs["src_mask"] = (
|
|
alibi_encoder + (1 - self.model_inputs["src_mask"]) * paddle.finfo(self.dtype).min
|
|
).cast(self.dtype)
|
|
self.model_inputs["tgt_mask"] = (
|
|
alibi_decoder + (1 - self.model_inputs["tgt_mask"]) * paddle.finfo(self.dtype).min
|
|
).cast(self.dtype)
|
|
elif config.device == "npu" and self.model_config.get("alibi", False):
|
|
lower_one_tril = paddle.tril(
|
|
paddle.ones(shape=(config.total_max_length, config.total_max_length), dtype=self.dtype)
|
|
)
|
|
lower_one_tril = lower_one_tril[None, None, :, :]
|
|
src_mask = lower_one_tril.tile([config.batch_size, 1, 1, 1])
|
|
tgt_mask = paddle.full(
|
|
shape=[config.batch_size, 1, 1, config.total_max_length], fill_value=1, dtype=self.dtype
|
|
)
|
|
arange_tensor_encoder = paddle.arange(config.total_max_length).astype(self.dtype)
|
|
alibi_slopes = llm_utils.get_alibi_slopes(self.num_key_value_heads)
|
|
alibi = alibi_slopes[None, :, None, None] * arange_tensor_encoder
|
|
alibi_encoder = alibi.tile([config.batch_size, 1, config.total_max_length, 1])
|
|
alibi_decoder = alibi.tile(
|
|
[
|
|
config.batch_size,
|
|
1,
|
|
1,
|
|
1,
|
|
]
|
|
)
|
|
# self.model_inputs["src_mask/tgt_mask"] is read only, will not be updated!
|
|
src_mask = (alibi_encoder + (1 - src_mask) * paddle.finfo(self.dtype).min).cast(self.dtype)
|
|
tgt_mask = (alibi_decoder + (1 - tgt_mask) * paddle.finfo(self.dtype).min).cast(self.dtype)
|
|
self.model_inputs["rope_emb"] = paddle.concat([src_mask.reshape([-1]), tgt_mask.reshape([-1])])
|
|
|
|
def _preprocess(self, input_text: list[str] = None, input_ids: list[list[int]] = None):
|
|
if input_ids is None:
|
|
len_input_text = len(input_text)
|
|
if len_input_text < self.batch_size:
|
|
padding_len = self.batch_size - len_input_text
|
|
input_text += [""] * padding_len
|
|
assert len(input_text) == self.batch_size
|
|
|
|
if self.tokenizer.chat_template is not None:
|
|
if not isinstance(input_text, list) or not isinstance(input_text[0], str):
|
|
input_text = [input_text]
|
|
input_text = [self.tokenizer.apply_chat_template(sentence, tokenize=False) for sentence in input_text]
|
|
|
|
input_ids = []
|
|
for text in input_text:
|
|
tokens = self.tokenizer(
|
|
text,
|
|
return_tensors="np",
|
|
padding=True,
|
|
truncation=True,
|
|
max_length=self.config.src_length,
|
|
# if use chat_template, it will not add special_tokens
|
|
add_special_tokens=self.tokenizer.chat_template is None
|
|
or isinstance(self.tokenizer, (ChatGLMv2Tokenizer, ChatGLMTokenizer)),
|
|
)
|
|
input_ids.append(tokens["input_ids"][0])
|
|
else:
|
|
assert isinstance(input_ids, list) and isinstance(input_ids[0], list), "input_ids must be a list of list"
|
|
assert (
|
|
input_text is None and input_ids is not None
|
|
), "Only one of 'input_text' and 'input_ids' can be provided"
|
|
len_input_ids = len(input_ids)
|
|
if len_input_ids < self.batch_size:
|
|
padding_len = self.batch_size - len_input_ids
|
|
input_ids += [[self.tokenizer.pad_token_id]] * padding_len
|
|
assert len(input_ids) == self.batch_size
|
|
|
|
self.seq_lens = self.pad_batch_data(input_ids)
|
|
self.model_inputs["input_ids"] = self.input_ids
|
|
|
|
self.model_inputs["block_tables"][:][:] = -1
|
|
free_list = list(range(self.max_block_nums))
|
|
for i in range(self.config.batch_size):
|
|
for j in range(
|
|
(self.seq_lens[i] + self.config.max_length + self.config.block_size - 1) // self.config.block_size
|
|
):
|
|
used_block_id = free_list.pop()
|
|
self.model_inputs["block_tables"][i, j] = used_block_id
|
|
|
|
self.model_inputs["seq_lens_this_time"] = paddle.to_tensor(
|
|
np.array(self.seq_lens).astype("int32").reshape(-1, 1)
|
|
)
|
|
self.model_inputs["seq_lens_encoder"] = paddle.to_tensor(
|
|
np.array(self.seq_lens).astype("int32").reshape(-1, 1)
|
|
)
|
|
self.model_inputs["seq_lens_decoder"] = paddle.full(
|
|
shape=[self.config.batch_size, 1], fill_value=0, dtype="int32"
|
|
)
|
|
self.model_inputs["step_idx"] = paddle.full(shape=[self.config.batch_size, 1], fill_value=0, dtype="int64")
|
|
self.model_inputs["not_need_stop"] = paddle.full(shape=[1], fill_value=True, dtype="bool").cpu() # cpu
|
|
self.model_inputs["stop_flags"] = paddle.full(
|
|
shape=[self.config.batch_size, 1], fill_value=False, dtype="bool"
|
|
)
|
|
self.model_inputs["stop_nums"] = paddle.full(shape=[1], fill_value=self.config.batch_size, dtype="int64")
|
|
self.model_inputs["pre_ids"] = paddle.full(
|
|
shape=[self.config.batch_size, self.config.max_length], fill_value=-1, dtype="int64"
|
|
)
|
|
self.model_inputs["next_tokens"] = paddle.full(shape=[self.config.batch_size, 1], fill_value=-1, dtype="int64")
|
|
|
|
# speculative decoding related parameters
|
|
if self.config.speculate_method is not None:
|
|
self.model_inputs["accept_tokens"] = paddle.full(
|
|
shape=[self.config.batch_size, self.config.speculate_max_draft_token_num + 1],
|
|
fill_value=0,
|
|
dtype="int64",
|
|
)
|
|
self.model_inputs["accept_num"] = paddle.full(shape=[self.config.batch_size], fill_value=0, dtype="int32")
|
|
self.model_inputs["draft_tokens"] = paddle.full(
|
|
shape=[self.config.batch_size, self.config.speculate_max_draft_token_num + 1],
|
|
fill_value=0,
|
|
dtype="int64",
|
|
)
|
|
self.model_inputs["actual_draft_token_num"] = paddle.full(
|
|
shape=[self.config.batch_size], fill_value=self.config.speculate_max_draft_token_num, dtype="int32"
|
|
)
|
|
|
|
self.proposer.input_ids_cpu = self.model_inputs["input_ids"].to("cpu", blocking=False)
|
|
for bid in range(self.config.batch_size):
|
|
self.model_inputs["pre_ids"][bid, 0] = self.model_inputs["input_ids"][bid][
|
|
self.seq_lens[bid] - 1
|
|
] # get the last token before padding of this batch
|
|
if self.config.speculate_method == "inference_with_reference":
|
|
self.proposer.input_ids_len[bid, 0] = self.seq_lens[bid]
|
|
|
|
if self.config.mode == "static":
|
|
for k, v in self.model_inputs.items():
|
|
v.name = k
|
|
|
|
|
|
class DygraphBlockInferencePredictor(BlockInferencePredictorMixin):
|
|
def __init__(
|
|
self, config: PredictorArgument, tokenizer: PretrainedTokenizer = None, model: PretrainedModel = None, **kwargs
|
|
):
|
|
self.return_full_hidden_states = config.return_full_hidden_states
|
|
self.full_hidden_states = None
|
|
self.tokenizer = tokenizer
|
|
self.dynamic_insert = config.dynamic_insert
|
|
if model is None:
|
|
raise ValueError("model should be provided for DygraphBlockInferencePredictor")
|
|
self.cache_k_shapes, self.cache_v_shapes = model.get_cache_kvs_shape(model.config, config.batch_size)
|
|
BlockInferencePredictorMixin.__init__(self, config, tokenizer, model)
|
|
|
|
self.model = model
|
|
|
|
self.init_model_inputs(config)
|
|
if config.export_precache:
|
|
self.model_inputs["pre_caches"] = self.pre_caches
|
|
if config.cachekv_int8_type == "dynamic":
|
|
self.model_inputs["k_quant_scales"] = self.k_quant_scales
|
|
self.model_inputs["v_quant_scales"] = self.v_quant_scales
|
|
self.model_inputs["k_dequant_scales"] = self.k_dequant_scales
|
|
self.model_inputs["v_dequant_scales"] = self.v_dequant_scales
|
|
|
|
if kwargs.get("init_cache_kvs", True):
|
|
self.init_cache_kvs()
|
|
|
|
# init speculate components
|
|
if config.speculate_method == "inference_with_reference":
|
|
self.proposer = InferenceWithReferenceProposer(
|
|
config.speculate_max_draft_token_num,
|
|
config.speculate_max_ngram_size,
|
|
config.batch_size,
|
|
config.max_length,
|
|
)
|
|
elif config.speculate_method in ["eagle", "mtp"]:
|
|
speculate_model_args = SpeculateArgument.build_from_predictor(config)
|
|
self.proposer = EagleProposer(args=speculate_model_args)
|
|
else:
|
|
self.proposer = None
|
|
|
|
def init_cache_kvs(self):
|
|
cachekv_dtype = self.dtype if self.config.cachekv_int8_type is None else "uint8"
|
|
self.cache_kvs = []
|
|
if self.cache_k_shapes and self.cache_v_shapes:
|
|
for cache_k_shape, cache_v_shape in zip(self.cache_k_shapes, self.cache_v_shapes):
|
|
self.cache_kvs.append(paddle.zeros(cache_k_shape, dtype=cachekv_dtype))
|
|
self.cache_kvs.append(paddle.zeros(cache_v_shape, dtype=cachekv_dtype))
|
|
if self.config.kv_cache_reuse:
|
|
logger.warning(
|
|
f"self.config.kv_cache_reuse = {self.config.kv_cache_reuse}, break, len(self.cache_kvs) = {len(self.cache_kvs)}"
|
|
)
|
|
break
|
|
else:
|
|
# for mla's absorption
|
|
assert self.cache_v_shapes is None
|
|
self.cache_kvs = [paddle.zeros(shape, dtype=cachekv_dtype) for shape in self.cache_k_shapes]
|
|
self.model_inputs["cache_kvs"] = self.cache_kvs
|
|
|
|
@paddle.no_grad()
|
|
def _infer(self, inputs: dict[str, paddle.Tensor]):
|
|
return self.model.generate(
|
|
**inputs,
|
|
)
|
|
|
|
@paddle.no_grad()
|
|
def predict_via_mq(self, input_texts: list[str], return_tokens=False):
|
|
self._preprocess(input_texts)
|
|
if self.proposer is not None:
|
|
self.proposer.insert_query(
|
|
base_model_inputs=self.model_inputs, real_bs=len(input_texts), seq_lens=self.seq_lens
|
|
)
|
|
result_queue = mp.Queue()
|
|
tensor_queue = mp.Queue()
|
|
done_event = mp.Event()
|
|
|
|
# whether speculative decoding
|
|
if self.proposer is None:
|
|
read_res_func = llm_utils.read_res
|
|
output_tensor_shape = [MAX_BSZ + 2, 1]
|
|
else:
|
|
read_res_func = llm_utils.speculate_read_res
|
|
output_tensor_shape = [SPECULATE_MAX_BSZ * MAX_DRAFT_TOKENS + SPECULATE_MAX_BSZ + 2, 1]
|
|
|
|
read_res_process = mp.Process(
|
|
target=read_res_func,
|
|
args=[self.model_name_or_path, tensor_queue, result_queue, done_event],
|
|
)
|
|
if self.tensor_parallel_rank == 0:
|
|
read_res_process.start()
|
|
|
|
output_tensor = paddle.full(shape=output_tensor_shape, fill_value=2, dtype="int64").cpu()
|
|
|
|
tensor_queue.put(output_tensor)
|
|
if self.tensor_parallel_rank == 0:
|
|
done_event.wait()
|
|
s_time = time.time()
|
|
while self.model_inputs["not_need_stop"]:
|
|
# whether speculative decoding
|
|
if self.proposer is not None:
|
|
self.proposer.run(
|
|
self.model_inputs,
|
|
real_batch_size=self.batch_size,
|
|
seq_lens_this_time=self.model_inputs["seq_lens_this_time"],
|
|
base_model_full_hidden_states=self.full_hidden_states,
|
|
)
|
|
if self.return_full_hidden_states:
|
|
self.full_hidden_states = self._infer(self.model_inputs)
|
|
else:
|
|
self._infer(self.model_inputs)
|
|
logger.info(f"running spend {time.time() - s_time}")
|
|
|
|
if self.tensor_parallel_rank == 0:
|
|
outputs = []
|
|
output_tokens = []
|
|
while len(outputs) < len(input_texts):
|
|
result = result_queue.get(timeout=10)
|
|
outputs.append(result[-1])
|
|
output_tokens.append(result[-2])
|
|
|
|
read_res_process.terminate()
|
|
|
|
if return_tokens:
|
|
return outputs, output_tokens
|
|
else:
|
|
return outputs
|
|
|
|
@paddle.no_grad()
|
|
@auto_dynamic_graph_pybind
|
|
def predict(self, input_texts: list[str], return_tokens=False):
|
|
if self.dynamic_insert:
|
|
return self.predict_dy_insert(input_texts, return_tokens=return_tokens)
|
|
if self.config.output_via_mq:
|
|
return self.predict_via_mq(input_texts, return_tokens)
|
|
self._preprocess(input_texts)
|
|
|
|
if self.proposer is not None:
|
|
self.proposer.insert_query(
|
|
base_model_inputs=self.model_inputs, real_bs=len(input_texts), seq_lens=self.seq_lens
|
|
)
|
|
|
|
output_tokens = []
|
|
output_token = []
|
|
s_time = time.time()
|
|
while self.model_inputs["not_need_stop"]:
|
|
# whether speculative decoding
|
|
if self.proposer is not None:
|
|
self.proposer.run(
|
|
self.model_inputs,
|
|
real_batch_size=self.batch_size,
|
|
seq_lens_this_time=self.model_inputs["seq_lens_this_time"],
|
|
base_model_full_hidden_states=self.full_hidden_states,
|
|
)
|
|
if self.return_full_hidden_states:
|
|
self.full_hidden_states = self._infer(self.model_inputs)
|
|
else:
|
|
outputs = self._infer(self.model_inputs)
|
|
outputs = outputs.numpy()
|
|
outputs[outputs == -1] = self.tokenizer.eos_token_id
|
|
output_token.append(outputs)
|
|
logger.info(f"running spend {time.time() - s_time}")
|
|
|
|
if self.tensor_parallel_rank == 0:
|
|
outputs = []
|
|
output_tokens = np.concatenate(output_token, axis=1).tolist()
|
|
outputs = self.tokenizer.batch_decode(
|
|
output_tokens, skip_special_tokens=True, clean_up_tokenization_spaces=False
|
|
)
|
|
assert len(outputs) == len(input_texts)
|
|
|
|
if return_tokens:
|
|
return outputs, output_tokens
|
|
else:
|
|
return outputs
|
|
|
|
@contextmanager
|
|
def update_predictor_params(self, **kwargs):
|
|
if kwargs:
|
|
old_predictor_config = copy.deepcopy(self.config)
|
|
for key, new_value in kwargs.items():
|
|
if key in ["top_p", "temperature"]:
|
|
if hasattr(self.config, key):
|
|
old_value = getattr(self.config, key)
|
|
if old_value != new_value:
|
|
setattr(self.config, key, new_value)
|
|
self.update_model_inputs(key, new_value)
|
|
yield
|
|
if kwargs:
|
|
self.restore_predictor_config(old_predictor_config)
|
|
|
|
def update_model_inputs(self, key, value):
|
|
assert key in self.model_inputs, f"{key} is not in model_inputs!"
|
|
old_value = self.model_inputs.pop(key)
|
|
self.model_inputs[key] = paddle.full(shape=old_value.shape, fill_value=value, dtype=old_value.dtype)
|
|
|
|
def restore_predictor_config(self, old_config):
|
|
if self.config.top_p != old_config.top_p:
|
|
self.update_model_inputs("top_p", old_config.top_p)
|
|
if self.config.temperature != old_config.temperature:
|
|
self.update_model_inputs("temperature", old_config.temperature)
|
|
self.config = old_config
|
|
|
|
def insert_task(self, pos, task_id, repeat_num):
|
|
query_id = task_id // repeat_num
|
|
length = len(self.input_ids[query_id])
|
|
# logger.debug(f"Insert task {task_id} while query id is {query_id} inserting pos {pos}")
|
|
self.model_inputs["input_ids"][pos, 0] = self.model_inputs["all_token_ids"][task_id, 0]
|
|
self.model_inputs["seq_lens_this_time"][pos] = 1
|
|
self.model_inputs["seq_lens_decoder"][pos] = length
|
|
self.model_inputs["stop_flags"][pos] = False
|
|
self.model_inputs["result_id"][pos][0] = task_id
|
|
self.model_inputs["step_idx"][pos, 0] = 1
|
|
self.model_inputs["pre_ids"][pos][0] = np.array(self.input_ids[query_id][-1])
|
|
self.model_inputs["pre_ids"][pos][1:] = -1
|
|
self.model_inputs["not_need_stop"][0] = True
|
|
|
|
num_prefill_blocks = length // self.block_size
|
|
num_decoder_blocks = (self.config.max_length + self.block_size - 1) // self.block_size
|
|
self.model_inputs["block_tables"][pos, :num_prefill_blocks] = np.array(self.prefill_blocks[query_id])
|
|
self.model_inputs["block_tables"][pos, num_prefill_blocks] = np.array(self.tail_blocks[task_id])
|
|
self.model_inputs["block_tables"][
|
|
pos, num_prefill_blocks + 1 : num_prefill_blocks + 1 + num_decoder_blocks
|
|
] = np.array(self.decoder_blocks[pos])
|
|
|
|
@paddle.no_grad()
|
|
@auto_dynamic_graph_pybind
|
|
def predict_dy_insert(
|
|
self,
|
|
input_texts: list[str] = None,
|
|
input_ids: list = None,
|
|
return_tokens=False,
|
|
all_rank_return=True,
|
|
detokenize=True,
|
|
repeat_num=1,
|
|
**kwargs
|
|
):
|
|
# The output of the ultra-long truncation does not return an eos_token
|
|
os.environ["INFERENCE_TRUNCATED_RETURN_EOS"] = "0"
|
|
assert repeat_num >= 1
|
|
flag_current_rank_run = self.tensor_parallel_rank == 0 or all_rank_return
|
|
self.input_ids = []
|
|
if input_ids is not None:
|
|
assert isinstance(input_ids, list) and isinstance(input_ids[0], list), "input_ids must be a list of list"
|
|
self.input_ids = copy.deepcopy(input_ids)
|
|
current_src_length = kwargs.get("src_length", self.config.src_length)
|
|
for i, inst in enumerate(self.input_ids):
|
|
if len(inst) > current_src_length:
|
|
logger.warning(
|
|
f"The input_id[{i}] will be truncated due to its length({len(inst)}) exceeding the src_length({current_src_length})!"
|
|
)
|
|
self.input_ids[i] = inst[:current_src_length]
|
|
else:
|
|
assert input_texts is not None, "input_texts can't be None, when input_ids is None."
|
|
if self.tokenizer.chat_template is not None:
|
|
if not isinstance(input_texts, list) or not isinstance(input_texts[0], str):
|
|
input_texts = [input_texts]
|
|
input_texts = [
|
|
self.tokenizer.apply_chat_template(sentence, tokenize=False) for sentence in input_texts
|
|
]
|
|
|
|
for text in input_texts:
|
|
tokens = self.tokenizer(
|
|
text,
|
|
return_tensors="np",
|
|
padding=True,
|
|
truncation=True,
|
|
max_length=self.config.src_length,
|
|
# if use chat_template, it will not add special_tokens
|
|
add_special_tokens=self.tokenizer.chat_template is None
|
|
or isinstance(self.tokenizer, (ChatGLMv2Tokenizer, ChatGLMTokenizer)),
|
|
)
|
|
self.input_ids.append(tokens["input_ids"][0])
|
|
|
|
assert self.proposer is None, "dynamic insert don't support proposer."
|
|
|
|
total_request_num = len(self.input_ids)
|
|
decoder_bs = total_request_num * repeat_num
|
|
max_batch_size = self.config.batch_size
|
|
self.block_size = self.config.block_size
|
|
|
|
self.prefill_blocks = []
|
|
block_id = 0
|
|
for inst in self.input_ids:
|
|
length = len(inst)
|
|
num_blocks = length // self.block_size
|
|
self.prefill_blocks.append(list(range(block_id, block_id + num_blocks)))
|
|
block_id += num_blocks
|
|
# print("prefill_blocks", self.prefill_blocks)
|
|
|
|
self.tail_blocks = []
|
|
for _ in range(decoder_bs):
|
|
self.tail_blocks.append(block_id)
|
|
block_id += 1
|
|
# print("tail_blocks", self.tail_blocks)
|
|
|
|
self.decoder_blocks = []
|
|
for _ in range(max_batch_size):
|
|
num_blocks = (self.config.max_length + self.block_size - 1) // self.block_size
|
|
self.decoder_blocks.append(list(range(block_id, block_id + num_blocks)))
|
|
block_id += num_blocks
|
|
# print("self.decoder_blocks: ", self.decoder_blocks)
|
|
|
|
max_num_blocks_per_row_per_decoding = (self.config.max_length + self.block_size - 1) // self.block_size
|
|
|
|
# one more for tail blocks
|
|
max_num_blocks_per_row = (self.config.total_max_length + self.block_size - 1) // self.block_size + 1
|
|
|
|
# For decoder_blocks
|
|
max_num_blocks = max_batch_size * max_num_blocks_per_row_per_decoding
|
|
|
|
# For prefill_blocks
|
|
for prefill_block in self.prefill_blocks:
|
|
max_num_blocks += len(prefill_block)
|
|
|
|
# For tail_blocks
|
|
max_num_blocks += decoder_bs
|
|
|
|
if self.cache_k_shapes is not None:
|
|
for i in range(len(self.cache_k_shapes)):
|
|
self.cache_k_shapes[i][0] = max_num_blocks
|
|
if self.cache_v_shapes is not None:
|
|
for i in range(len(self.cache_v_shapes)):
|
|
self.cache_v_shapes[i][0] = max_num_blocks
|
|
|
|
self.init_cache_kvs()
|
|
|
|
self.model_inputs["input_ids"] = paddle.full(
|
|
shape=[max_batch_size, self.config.total_max_length], fill_value=0, dtype="int64"
|
|
)
|
|
|
|
self.model_inputs["block_tables"] = paddle.full(
|
|
shape=[max_batch_size, max_num_blocks_per_row],
|
|
fill_value=-1,
|
|
dtype="int32",
|
|
)
|
|
|
|
self.model_inputs["excess_blocks"] = paddle.full(
|
|
shape=[max_batch_size, repeat_num], fill_value=-1, dtype="int32"
|
|
)
|
|
|
|
self.model_inputs["seq_lens_this_time"] = paddle.zeros(shape=[max_batch_size, 1], dtype="int32")
|
|
self.model_inputs["seq_lens_encoder"] = paddle.zeros(shape=[max_batch_size, 1], dtype="int32")
|
|
self.model_inputs["seq_lens_decoder"] = paddle.zeros(shape=[max_batch_size, 1], dtype="int32")
|
|
|
|
self.model_inputs["pre_ids"] = paddle.full(
|
|
shape=[max_batch_size, self.config.max_length], fill_value=-1, dtype="int64"
|
|
)
|
|
|
|
# Construct loop cvars
|
|
self.model_inputs["step_idx"] = paddle.full(shape=[max_batch_size, 1], fill_value=0, dtype="int64")
|
|
self.model_inputs["not_need_stop"] = paddle.full(shape=[1], fill_value=True, dtype="bool").cpu() # cpu
|
|
self.model_inputs["stop_flags"] = paddle.ones(shape=[max_batch_size, 1], dtype="bool")
|
|
self.model_inputs["stop_nums"] = paddle.full(shape=[1], fill_value=max_batch_size, dtype="int64")
|
|
self.model_inputs["result_id"] = paddle.full(shape=[max_batch_size, repeat_num], fill_value=-1).astype("int32")
|
|
self.model_inputs["next_tokens"] = paddle.full(shape=[max_batch_size, 1], fill_value=-1, dtype="int64")
|
|
|
|
# output buffers for all inputs
|
|
self.model_inputs["all_token_ids"] = paddle.full(
|
|
shape=[decoder_bs, self.config.max_length],
|
|
fill_value=self.tokenizer.pad_token_id,
|
|
dtype="int64",
|
|
)
|
|
# self.model_inputs["all_scores"] = paddle.full(
|
|
# shape=[decoder_bs, self.config.max_length],
|
|
# fill_value=-1,
|
|
# dtype='float32',
|
|
# )
|
|
|
|
if self.config.output_via_mq:
|
|
result_queue = mp.Queue()
|
|
task_queue = mp.Queue()
|
|
done_event = mp.Event()
|
|
read_res_func = llm_utils.read_res_dynamic_insert
|
|
read_res_process = mp.Process(
|
|
target=read_res_func,
|
|
args=[
|
|
self.model_name_or_path,
|
|
task_queue,
|
|
result_queue,
|
|
done_event,
|
|
len(self.input_ids),
|
|
detokenize,
|
|
],
|
|
)
|
|
|
|
if flag_current_rank_run:
|
|
read_res_process.start()
|
|
done_event.wait()
|
|
|
|
done_task_id_set = set()
|
|
|
|
def send_task_to_queue(task_id):
|
|
if task_id not in done_task_id_set:
|
|
task_token = self.model_inputs["all_token_ids"][task_id : task_id + 1, :].cpu().numpy()
|
|
task_queue.put([task_id, task_token])
|
|
done_task_id_set.add(task_id)
|
|
|
|
s_time = time.time()
|
|
with self.update_predictor_params(**kwargs):
|
|
for i, inst in enumerate(self.input_ids):
|
|
length = len(inst)
|
|
self.model_inputs["input_ids"][0, :length] = np.array(inst)
|
|
self.model_inputs["seq_lens_this_time"][0] = length
|
|
self.model_inputs["seq_lens_encoder"][0] = length
|
|
self.model_inputs["stop_flags"][0] = False
|
|
|
|
num_prefill_blocks = length // self.block_size
|
|
self.model_inputs["block_tables"][0, :num_prefill_blocks] = np.array(self.prefill_blocks[i])
|
|
self.model_inputs["block_tables"][0, num_prefill_blocks] = np.array(self.tail_blocks[i * repeat_num])
|
|
self.model_inputs["excess_blocks"][0, :] = np.array(
|
|
self.tail_blocks[i * repeat_num : i * repeat_num + repeat_num]
|
|
)
|
|
self.model_inputs["result_id"][0][:repeat_num] = np.arange(i * repeat_num, i * repeat_num + repeat_num)
|
|
|
|
self._infer(self.model_inputs)
|
|
self.model_inputs["seq_lens_this_time"][0] = 0
|
|
self.model_inputs["seq_lens_encoder"][0] = 0
|
|
self.model_inputs["seq_lens_decoder"][0] = 0
|
|
self.model_inputs["stop_flags"][0] = True
|
|
self.model_inputs["step_idx"][0, 0] = 0
|
|
self.model_inputs["block_tables"][0] = -1
|
|
self.model_inputs["result_id"][0] = -1
|
|
|
|
unfinished_ids = list(range(decoder_bs - 1, -1, -1))
|
|
for cur_bs in range(max_batch_size):
|
|
if len(unfinished_ids) == 0:
|
|
break
|
|
task_id = unfinished_ids.pop()
|
|
self.insert_task(cur_bs, task_id, repeat_num)
|
|
|
|
if kwargs.pop("max_length", self.config.max_length) > 1:
|
|
while self.model_inputs["not_need_stop"] or len(unfinished_ids) > 0:
|
|
no_stop_num = max_batch_size - paddle.sum(self.model_inputs["stop_flags"]).item()
|
|
if no_stop_num < max_batch_size:
|
|
for i in range(max_batch_size):
|
|
if self.model_inputs["stop_flags"][i]:
|
|
if self.config.output_via_mq:
|
|
task_id = self.model_inputs["result_id"][i][0].item()
|
|
send_task_to_queue(task_id)
|
|
if len(unfinished_ids) > 0:
|
|
task_id = unfinished_ids.pop()
|
|
self.insert_task(i, task_id, repeat_num)
|
|
self._infer(self.model_inputs)
|
|
if self.config.output_via_mq:
|
|
for i in range(max_batch_size):
|
|
if self.model_inputs["stop_flags"][i]:
|
|
task_id = self.model_inputs["result_id"][i][0].item()
|
|
send_task_to_queue(task_id)
|
|
elif self.config.output_via_mq:
|
|
for task_id in range(len(self.input_ids)):
|
|
send_task_to_queue(task_id)
|
|
|
|
if self.config.output_via_mq:
|
|
if flag_current_rank_run:
|
|
outputs = []
|
|
output_tokens = []
|
|
while len(outputs) < total_request_num:
|
|
result = result_queue.get(timeout=1)
|
|
outputs.append(result[-1])
|
|
output_tokens.append(result[-2])
|
|
read_res_process.terminate()
|
|
while not task_queue.empty():
|
|
task_queue.get_nowait()
|
|
while not result_queue.empty():
|
|
result_queue.get_nowait()
|
|
task_queue.close()
|
|
result_queue.close()
|
|
else:
|
|
if flag_current_rank_run:
|
|
output_tokens = self.model_inputs["all_token_ids"].numpy()
|
|
output_tokens[output_tokens == -1] = self.tokenizer.eos_token_id
|
|
if detokenize:
|
|
outputs = self.tokenizer.batch_decode(
|
|
output_tokens, skip_special_tokens=True, clean_up_tokenization_spaces=False
|
|
)
|
|
else:
|
|
outputs = None
|
|
logger.debug(f"running spend {time.time() - s_time}")
|
|
self.cache_kvs = None
|
|
self.model_inputs["cache_kvs"] = None
|
|
paddle.device.cuda.empty_cache()
|
|
|
|
if flag_current_rank_run:
|
|
if return_tokens:
|
|
return outputs, output_tokens
|
|
else:
|
|
return outputs
|
|
|
|
|
|
class StaticGraphBlockInferencePredictor(BlockInferencePredictorMixin):
|
|
def __init__(
|
|
self,
|
|
config: PredictorArgument,
|
|
tokenizer: PretrainedTokenizer = None,
|
|
model: PretrainedModel = None,
|
|
**kwargs,
|
|
):
|
|
self.cache_k_shapes = kwargs.get("cache_k_shapes", None)
|
|
self.cache_v_shapes = kwargs.get("cache_v_shapes", None)
|
|
self.model_args = kwargs.get("model_args", None)
|
|
self.return_full_hidden_states = config.return_full_hidden_states
|
|
self.tokenizer = tokenizer
|
|
self.full_hidden_states = None
|
|
if self.cache_k_shapes is None:
|
|
raise ValueError(
|
|
"cache_k_shapes and cache_v_shapes should be provided for StaticGraphBlockInferencePredictor"
|
|
)
|
|
BlockInferencePredictorMixin.__init__(self, config, tokenizer)
|
|
|
|
self._create_predictor(config)
|
|
|
|
self.init_model_inputs(config)
|
|
|
|
if config.export_precache:
|
|
for i in range(self.num_layers):
|
|
self.model_inputs["pre_caches_{}".format(i)] = self.pre_caches[i]
|
|
|
|
cachekv_dtype = config.dtype if config.cachekv_int8_type is None else "uint8"
|
|
|
|
for i in range(self.num_layers):
|
|
if self.cache_k_shapes is not None:
|
|
self.model_inputs["key_caches_{}".format(i)] = paddle.zeros(
|
|
self.cache_k_shapes[i], dtype=cachekv_dtype
|
|
)
|
|
if self.cache_v_shapes is not None:
|
|
self.model_inputs["value_caches_{}".format(i)] = paddle.zeros(
|
|
self.cache_v_shapes[i], dtype=cachekv_dtype
|
|
)
|
|
|
|
for i in range(self.num_layers):
|
|
if self.config.cachekv_int8_type == "dynamic":
|
|
self.model_inputs["k_quant_scales_" + str(i)] = self.k_quant_scales[i]
|
|
self.model_inputs["v_quant_scales_" + str(i)] = self.v_quant_scales[i]
|
|
self.model_inputs["k_dequant_scales_" + str(i)] = self.k_dequant_scales[i]
|
|
self.model_inputs["v_dequant_scales_" + str(i)] = self.v_dequant_scales[i]
|
|
|
|
# init speculate components
|
|
if config.speculate_method == "inference_with_reference":
|
|
self.proposer = InferenceWithReferenceProposer(
|
|
config.speculate_max_draft_token_num,
|
|
config.speculate_max_ngram_size,
|
|
config.batch_size,
|
|
config.max_length,
|
|
)
|
|
elif config.speculate_method in ["eagle", "mtp"]:
|
|
speculate_model_args = SpeculateArgument.build_from_predictor(config)
|
|
self.proposer = EagleProposer(args=speculate_model_args)
|
|
else:
|
|
self.proposer = None
|
|
|
|
def _create_predictor(self, predictor_args: PredictorArgument):
|
|
if not is_paddlenlp_ops_available():
|
|
raise ValueError(
|
|
"you should install the paddlenlp ops to run inference predictor, "
|
|
"https://github.com/PaddlePaddle/PaddleNLP/blob/develop/csrc/README.md"
|
|
)
|
|
|
|
infer_model_path = llm_utils.get_infer_model_path(
|
|
predictor_args.model_name_or_path, predictor_args.model_prefix
|
|
)
|
|
|
|
config = paddle.inference.Config(
|
|
infer_model_path + PADDLE_INFERENCE_MODEL_SUFFIX,
|
|
infer_model_path + PADDLE_INFERENCE_WEIGHTS_SUFFIX,
|
|
)
|
|
|
|
config.switch_ir_optim(False)
|
|
if predictor_args.device in paddle.device.get_all_custom_device_type():
|
|
device_id = int(os.environ.get("FLAGS_selected_{}s".format(predictor_args.device), 0))
|
|
config.enable_custom_device(predictor_args.device, device_id)
|
|
elif predictor_args.device == "xpu":
|
|
config.enable_xpu()
|
|
device_id = int(os.environ.get("FLAGS_selected_xpus", 0))
|
|
config.set_xpu_device_id(device_id)
|
|
xpu_config = paddle.inference.XpuConfig()
|
|
xpu_config.device_id = device_id
|
|
xpu_config.l3_size = 0
|
|
xpu_config.l3_autotune_size = 0
|
|
config.set_xpu_config(xpu_config)
|
|
config.switch_ir_optim(True)
|
|
config.delete_pass("fc_xpu_fuse_pass")
|
|
# config.enable_memory_optim()
|
|
else:
|
|
device_id = int(os.environ.get("FLAGS_selected_gpus", 0))
|
|
config.enable_use_gpu(100, device_id)
|
|
|
|
if predictor_args.device == "npu":
|
|
import paddle_custom_device.npu.passes as passes
|
|
|
|
config.switch_ir_optim(True)
|
|
pass_builder = config.pass_builder()
|
|
passes.addPasses(pass_builder, self.model_config.model_type, self.model_config.quant_type)
|
|
|
|
self.predictor = paddle.inference.create_predictor(config)
|
|
|
|
def predict_via_mq(self, input_texts: list[str], return_tokens=False):
|
|
s_time = time.time()
|
|
self._preprocess(input_texts)
|
|
if self.proposer is not None:
|
|
self.proposer.insert_query(
|
|
base_model_inputs=self.model_inputs, real_bs=len(input_texts), seq_lens=self.seq_lens
|
|
)
|
|
logger.info(f"preprocess spend {time.time() - s_time}")
|
|
|
|
result_queue = mp.Queue()
|
|
tensor_queue = mp.Queue()
|
|
done_event = mp.Event()
|
|
|
|
# whether speculative decoding
|
|
if self.proposer is None:
|
|
read_res_func = llm_utils.read_res
|
|
output_tensor_shape = [MAX_BSZ + 2, 1]
|
|
else:
|
|
read_res_func = llm_utils.speculate_read_res
|
|
output_tensor_shape = [SPECULATE_MAX_BSZ * MAX_DRAFT_TOKENS + SPECULATE_MAX_BSZ + 2, 1]
|
|
|
|
read_res_process = mp.Process(
|
|
target=read_res_func,
|
|
args=[self.model_name_or_path, tensor_queue, result_queue, done_event],
|
|
)
|
|
if self.tensor_parallel_rank == 0:
|
|
read_res_process.start()
|
|
|
|
output_tensor = paddle.full(shape=output_tensor_shape, fill_value=2, dtype="int64").cpu()
|
|
|
|
tensor_queue.put(output_tensor)
|
|
if self.tensor_parallel_rank == 0:
|
|
done_event.wait()
|
|
s_time = time.time()
|
|
while self.model_inputs["not_need_stop"]:
|
|
# whether speculative decoding
|
|
if self.proposer is not None:
|
|
self.proposer.run(
|
|
self.model_inputs,
|
|
real_batch_size=self.batch_size,
|
|
seq_lens_this_time=self.model_inputs["seq_lens_this_time"],
|
|
base_model_full_hidden_states=self.full_hidden_states,
|
|
)
|
|
if self.return_full_hidden_states:
|
|
self.full_hidden_states = self.predictor.run(list(self.model_inputs.values()))[0]
|
|
else:
|
|
self.predictor.run(list(self.model_inputs.values()))
|
|
logger.info(f"running spend {time.time() - s_time}")
|
|
|
|
if self.tensor_parallel_rank == 0:
|
|
outputs = []
|
|
output_tokens = []
|
|
while len(outputs) < self.batch_size:
|
|
result = result_queue.get(timeout=1)
|
|
outputs.append(result[-1])
|
|
output_tokens.append(result[-2])
|
|
|
|
read_res_process.terminate()
|
|
|
|
if return_tokens:
|
|
return outputs, output_tokens
|
|
else:
|
|
return outputs
|
|
|
|
def predict(self, input_texts: list[str], return_tokens=False):
|
|
if self.config.output_via_mq:
|
|
return self.predict_via_mq(input_texts, return_tokens)
|
|
|
|
s_time = time.time()
|
|
self._preprocess(input_texts)
|
|
if self.proposer is not None:
|
|
self.proposer.insert_query(
|
|
base_model_inputs=self.model_inputs, real_bs=len(input_texts), seq_lens=self.seq_lens
|
|
)
|
|
logger.info(f"preprocess spend {time.time() - s_time}")
|
|
|
|
output_tokens = []
|
|
output_token = []
|
|
s_time = time.time()
|
|
while self.model_inputs["not_need_stop"]:
|
|
# whether speculative decoding
|
|
if self.proposer is not None:
|
|
self.proposer.run(
|
|
self.model_inputs,
|
|
real_batch_size=self.batch_size,
|
|
seq_lens_this_time=self.model_inputs["seq_lens_this_time"],
|
|
base_model_full_hidden_states=self.full_hidden_states,
|
|
)
|
|
if self.return_full_hidden_states:
|
|
self.full_hidden_states = self.predictor.run(list(self.model_inputs.values()))[0]
|
|
else:
|
|
outputs = self.predictor.run(list(self.model_inputs.values()))[0]
|
|
outputs = outputs.numpy()
|
|
outputs[outputs == -1] = self.tokenizer.eos_token_id
|
|
output_token.append(outputs)
|
|
logger.info(f"running spend {time.time() - s_time}")
|
|
|
|
if self.tensor_parallel_rank == 0:
|
|
outputs = []
|
|
output_tokens = []
|
|
output_tokens = np.concatenate(output_token, axis=1).tolist()
|
|
outputs = self.tokenizer.batch_decode(
|
|
output_tokens, skip_special_tokens=True, clean_up_tokenization_spaces=False
|
|
)
|
|
assert len(outputs) == self.batch_size
|
|
if return_tokens:
|
|
return outputs, output_tokens
|
|
else:
|
|
return outputs
|
|
|
|
|
|
class AutoPredictor:
|
|
def __init__(self, *args, **kwargs):
|
|
raise EnvironmentError(
|
|
f"{self.__class__.__name__} is designed to be instantiated "
|
|
f"using the `{self.__class__.__name__}.from_pretrained(pretrained_model_name_or_path).`"
|
|
)
|
|
|
|
@classmethod
|
|
def create_predictor(
|
|
cls,
|
|
predictor_args: PredictorArgument,
|
|
config: PretrainedConfig,
|
|
model_args: ModelArgument,
|
|
tokenizer: PretrainedTokenizer = None,
|
|
model: PretrainedModel = None,
|
|
**kwargs,
|
|
):
|
|
"""
|
|
Create a predictor
|
|
|
|
Args:
|
|
predictor_args (PredictorArgument): The predictor arguments.
|
|
config (PretrainedConfig): The model configuration.
|
|
model_args (ModelArgument): The model arguments.
|
|
tokenizer (PretrainedTokenizer): The tokenizer.
|
|
**kwargs: Additional keyword arguments.
|
|
Returns:
|
|
Predictor: The predictor.
|
|
"""
|
|
cache_kvs_shape = None # used for not block_attn/append_attn
|
|
cache_k_shapes = None # used for block_attn/append_attn
|
|
cache_v_shapes = None # used for block_attn/append_attn
|
|
|
|
# static or dynamic
|
|
execute_mode = "Dygraph" if predictor_args.mode == "dynamic" else "StaticGraph"
|
|
|
|
# infer/ no infer
|
|
if predictor_args.inference_model:
|
|
# block/no block
|
|
if predictor_args.block_attn:
|
|
attn_type = "Block"
|
|
if predictor_args.mode == "static":
|
|
cache_k_shapes, cache_v_shapes = model.get_cache_kvs_shape(
|
|
config, predictor_args.batch_size, predictor_args.total_max_length
|
|
)
|
|
else:
|
|
attn_type = ""
|
|
if predictor_args.mode == "static":
|
|
cache_kvs_shape = model.get_cache_kvs_shape(
|
|
config, predictor_args.batch_size, predictor_args.total_max_length
|
|
)
|
|
inference_mode = f"{attn_type}Inference"
|
|
else:
|
|
inference_mode = ""
|
|
|
|
predictor_class_name = execute_mode + inference_mode + "Predictor"
|
|
|
|
import_class = sys.modules[__name__]
|
|
|
|
# import class
|
|
predictor_class = getattr(import_class, predictor_class_name)
|
|
|
|
# instance
|
|
predictor = predictor_class(
|
|
predictor_args,
|
|
tokenizer=tokenizer,
|
|
model=model,
|
|
cache_k_shapes=cache_k_shapes,
|
|
cache_v_shapes=cache_v_shapes,
|
|
cache_kvs_shape=cache_kvs_shape,
|
|
model_args=model_args,
|
|
**kwargs,
|
|
)
|
|
return predictor
|
|
|
|
|
|
def create_predictor(
|
|
predictor_args: PredictorArgument,
|
|
model_args: ModelArgument,
|
|
**kwargs,
|
|
):
|
|
paddle.set_device(predictor_args.device)
|
|
paddle.set_default_dtype(predictor_args.dtype)
|
|
|
|
from paddlenlp.utils.env import USE_FAST_TOKENIZER
|
|
|
|
tokenizer = AutoTokenizer.from_pretrained(
|
|
predictor_args.model_name_or_path, padding_side="left", use_fast=USE_FAST_TOKENIZER
|
|
)
|
|
|
|
# init chat_template for tokenizer
|
|
llm_utils.init_chat_template(tokenizer, predictor_args.model_name_or_path, predictor_args.chat_template)
|
|
|
|
# TODO(wj-Mcat): fix llama tokenzier pad_token bug
|
|
if (isinstance(tokenizer, (LlamaTokenizer, Llama3Tokenizer))) and not tokenizer.pad_token:
|
|
tokenizer.pad_token = tokenizer.eos_token
|
|
|
|
config = AutoConfig.from_pretrained(predictor_args.model_name_or_path)
|
|
|
|
tensor_parallel_rank, tensor_parallel_degree = llm_utils.init_dist_env()
|
|
|
|
model = None
|
|
|
|
# model loading
|
|
if predictor_args.inference_model:
|
|
model = AutoInferenceModelForCausalLM.from_pretrained(
|
|
predictor_args.model_name_or_path,
|
|
config=config,
|
|
predictor_args=predictor_args,
|
|
model_args=model_args,
|
|
dtype=predictor_args.dtype,
|
|
tensor_parallel_degree=tensor_parallel_degree,
|
|
tensor_parallel_rank=tensor_parallel_rank,
|
|
)
|
|
else:
|
|
if predictor_args.mode == "dynamic":
|
|
# model import (gpt-3,ernie) or AutoModel
|
|
if model_args.model_type == "gpt-3":
|
|
sys.path.append("./gpt-3")
|
|
from modeling import GPTForCausalLM
|
|
|
|
model = GPTForCausalLM.from_pretrained(
|
|
predictor_args.model_name_or_path,
|
|
dtype=predictor_args.dtype,
|
|
tensor_parallel_degree=tensor_parallel_degree,
|
|
tensor_parallel_rank=tensor_parallel_rank,
|
|
tensor_parallel_output=False,
|
|
)
|
|
elif model_args.model_type == "ernie-3.5-se":
|
|
sys.path.append("./ernie-3.5-se")
|
|
from modeling import Ernie35ForCausalLM
|
|
|
|
tensor_parallel_degree = paddle.distributed.get_world_size()
|
|
tensor_parallel_rank = paddle.distributed.get_rank()
|
|
model = Ernie35ForCausalLM.from_pretrained(
|
|
predictor_args.model_name_or_path,
|
|
dtype=predictor_args.dtype,
|
|
tensor_parallel_degree=tensor_parallel_degree,
|
|
tensor_parallel_rank=tensor_parallel_rank,
|
|
tensor_parallel_output=False,
|
|
)
|
|
else:
|
|
model = AutoModelForCausalLM.from_pretrained(
|
|
predictor_args.model_name_or_path,
|
|
dtype=predictor_args.dtype,
|
|
use_flash_attention=predictor_args.use_flash_attention,
|
|
tensor_parallel_degree=tensor_parallel_degree,
|
|
tensor_parallel_rank=tensor_parallel_rank,
|
|
tensor_parallel_output=False,
|
|
)
|
|
predictor = AutoPredictor.create_predictor(predictor_args, config, model_args, tokenizer, model=model, **kwargs)
|
|
|
|
return predictor
|
|
|
|
|
|
def predict():
|
|
parser = PdArgumentParser((PredictorArgument, ModelArgument))
|
|
predictor_args, model_args = parser.parse_args_into_dataclasses()
|
|
|
|
llm_utils.set_triton_cache(predictor_args.model_name_or_path, predictor_args.mode)
|
|
try:
|
|
from paddle.utils import try_import
|
|
|
|
try_import("paddlenlp_ops")
|
|
except ImportError:
|
|
logger.warning("paddlenlp_ops does not exist, please install paddlenlp_ops.")
|
|
return
|
|
tensor_parallel_degree = paddle.distributed.get_world_size()
|
|
if tensor_parallel_degree > 1:
|
|
strategy = fleet.DistributedStrategy()
|
|
strategy.hybrid_configs = {
|
|
"dp_degree": 1,
|
|
"mp_degree": tensor_parallel_degree,
|
|
"pp_degree": 1,
|
|
"sharding_degree": 1,
|
|
}
|
|
fleet.init(is_collective=True, strategy=strategy)
|
|
|
|
predictor = create_predictor(predictor_args, model_args)
|
|
|
|
source_texts = []
|
|
target_texts = []
|
|
if model_args.data_file:
|
|
with open(model_args.data_file, "r", encoding="utf-8") as f:
|
|
for line in f:
|
|
example = json.loads(line)
|
|
if isinstance(example["src"], str) or predictor.tokenizer.chat_template is None:
|
|
if isinstance(example["src"], str):
|
|
source_texts.append(example["src"])
|
|
target_texts.append(example["tgt"])
|
|
else:
|
|
# load multi-rounds dataset
|
|
source_texts.append(example["src"][0])
|
|
target_texts.append(example["tgt"][0])
|
|
else:
|
|
source_texts.append(list(zip(example["src"], example["tgt"])))
|
|
target_texts.append("")
|
|
|
|
else:
|
|
source_texts = [
|
|
"2014年3月,大范围雾霾天气长时间影响我国东部地区,严重危害人体健康。造成雾霾天气的人为原因有____\r\n①工业生产中使用矿物作为燃料,大量排放污染物 ②汽车尾气的大量排放 \r\n③风力小,空气流动不畅 ④冬季取暖排放粉尘\nA. ①②③\nB. ②③④\nC. ①③④\nD. ①②④"
|
|
] * predictor_args.total_request_num
|
|
target_texts = [""] * predictor_args.total_request_num
|
|
|
|
batch_source_texts = batchfy_text(source_texts, predictor_args.total_request_num)
|
|
batch_target_texts = batchfy_text(target_texts, predictor_args.total_request_num)
|
|
|
|
with open(model_args.output_file, "w", encoding="utf-8") as f:
|
|
for bs, batch_source_text in enumerate(batch_source_texts):
|
|
logger.info("Start predict")
|
|
outputs = predictor.predict(batch_source_text)
|
|
logger.info("End predict")
|
|
|
|
if predictor.tensor_parallel_rank > 0:
|
|
continue
|
|
for output, source, target in zip(outputs, batch_source_texts[bs], batch_target_texts[bs]):
|
|
print("***********Source**********")
|
|
print(source)
|
|
print("***********Target**********")
|
|
print(target)
|
|
print("***********Output**********")
|
|
print(output)
|
|
out = {"src": source, "tgt": target, "output": output}
|
|
f.write(json.dumps(out, ensure_ascii=False) + "\n")
|
|
|
|
if predictor_args.benchmark:
|
|
benchmark(predictor, predictor_args, model_args)
|
|
|
|
# import pdb;pdb.set_trace()
|
|
|
|
|
|
def benchmark(predictor, predictor_args, model_args):
|
|
# Just construct a simple benchmark input. We pad input to the src_length.
|
|
test_texts = "hello world, how are you?"
|
|
benchmark_texts = [
|
|
test_texts + "<pad>" * predictor_args.src_length for _ in range(predictor_args.total_request_num)
|
|
]
|
|
|
|
batch_benchmark_texts = batchfy_text(benchmark_texts, predictor_args.total_request_num)
|
|
print("***********Start Benchmark**********")
|
|
|
|
warmup_time = 5
|
|
test_time = 20
|
|
|
|
print("***********Start Warmup**********")
|
|
for _ in range(warmup_time):
|
|
for bs, batch_source_text in enumerate(batch_benchmark_texts):
|
|
predictor.predict(batch_source_text)
|
|
|
|
print("***********Start Speed Test**********")
|
|
start = time.perf_counter()
|
|
output_tokens = 0
|
|
for _ in range(test_time):
|
|
for bs, batch_source_text in enumerate(batch_benchmark_texts):
|
|
results = predictor.predict(batch_source_text, return_tokens=True)
|
|
if predictor.tensor_parallel_rank == 0:
|
|
output_tokens += sum([len(tokens) for tokens in results[-1]])
|
|
end = time.perf_counter()
|
|
if predictor.tensor_parallel_rank == 0:
|
|
print("Avg Elapse time is: ", (end - start) / test_time)
|
|
print("Output tokens is: ", output_tokens)
|
|
print(
|
|
"Input length is: {}, Output length is: {}, bs is: {}, IPS: {:.3f} tokens/s, QPS: {:.3f} requests/s. ".format(
|
|
predictor_args.src_length,
|
|
predictor_args.max_length,
|
|
predictor_args.total_request_num,
|
|
(output_tokens / (end - start)),
|
|
(predictor_args.total_request_num * test_time / (end - start)),
|
|
)
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
predict()
|