Files
wehub-resource-sync 2aaeece67c
Pipelines-Test / Pipelines-Test (push) Waiting to run
Codestyle Check / Lint (push) Has been cancelled
Codestyle Check / Check bypass (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:37:14 +08:00

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()