一、目录

  1. 作用
  2. TensorRT-llm 为什么快?
  3. 流程
  4. TensorRT-LLM 环境配置
  5. 大模型 转换、编译与推理
  6. 如何选择量化类型?
  7. lora 大模型如何合并?
  8. lora 大模型如何编译,使用?
  9. 模型类型safetensors与bin互相转换.
  10. 推理加速模型 tensorrRT-LLM、Vllm、fasterTransformer、BetterTransformer 的对比
  11. 如何优化 LLM 模型推理中的访存密集问题?

二、实现

  1. 作用
    NVIDIA提出, TensorRT-LLM 默认采用 FP16/BF16 的精度推理,并且可以利用业界的量化方法,使用硬件吞吐更高的低精度推理进一步推升推理性能。
  2. TensorRT-llm 为什么快?
    1. 模型预编译,并优化内核
    2. 模型进行量化
    3. In-flight批处理
    4. page attention 以及高效缓存K、V.
  3. 流程
    1. huggingface 模型—>tensorRT-llm模型(模型转换)---->转为trt引擎----->trt引擎推理。
  4. TensorRT-LLM 环境配置
    1. 下载tensorRT-LLM 项目,注意,下载0.8.0, 其中0.9.0问题较多

    git clone -b v0.8.0 https://github.com/NVIDIA/TensorRT-LLM.git
    cd TensorRT-LLM

    1. 创建容器(cuda 最好是大于12.2), 也可以是其他容器,该容器包含tritonserver服务。

      docker pull nvcr.io/nvidia/tritonserver:24.02-trtllm-python-py3

docker run --gpus all
–name trt_llm
-d
–ipc=host
–ulimit memlock=-1
–restart=always
–ulimit stack=67108864
-p 8000:8000
-p 7860:7860
-v ${PWD}/examples:/app/tensorrt_llm/examples
nvcr.io/nvidia/tritonserver:24.02-trtllm-python-py3 sleep 8640000

  1. 安装tensorRT-LLM
    >>pip install tensorrt_llm==0.8.0 --extra-index-url https://pypi.nvidia.com --extra-index-url https://download.pytorch.org/whl/cu121
  2. 检查安装
    >> python3 -c “import tensorrt_llm” 生成版本号。
  3. 安装大模型本身需要的环境。
    参考:https://github.com/Tlntin/Qwen-TensorRT-LLM

5.大模型 转换、编译与推理
>>cd TensorRT-LLM/examples/bloom
文件1. convert_checkpoint.py: 将hf 模型转为tensorRT-LLM格式模型。
文件2. …/run.py 推理文件, 根据需求进行相应的修改
文件3. …/summarize.py 在cnn_dailymail 数据集中的测试文本。生成rouge 结果
文件4 benchmark.py 测试吞吐量

方式一、含有build.py 文件
1. 编译 参考:https://github.com/Tlntin/Qwen-TensorRT-LLM
>>python3 build.py --添加参数
2. 使用
>> python3 run.py
方式二、不含有build.py 文件
1. 模型量化 参考:https://github.com/NVIDIA/TensorRT-LLM/tree/main/examples/qwen
>># Build the Qwen-7B-Chat model using a single GPU and FP16.
python convert_checkpoint.py --model_dir ./tmp/Qwen/7B/
–output_dir ./tllm_checkpoint_1gpu_fp16
–dtype float16
2. 创建引擎

trtllm-build --checkpoint_dir ./tllm_checkpoint_1gpu_fp16
–output_dir ./tmp/qwen/7B/trt_engines/fp16/1-gpu
–gemm_plugin float16

  1. 使用

python3 …/run.py --input_text “你好,请问你叫什么?”
–max_output_len=50
–tokenizer_dir ./tmp/Qwen/7B/
–engine_dir=./tmp/Qwen/7B/trt_engines/fp16/1-gpu/
方式三、自己修改,写build.py 文件

          1. 官网下载benchmarks/python下的build.py 文件, 进行修改,同时需要进一步修改模型

后续…
生成文件:
文件1:config.json 配置文件
文件2:rank0.engine 驱动引擎

6.如何选择量化类型?
训练后 量化类型:1. fp16、int8(weight only)、int4(weight only)
2. smooth quant量化:SmoothQuant 通过平滑激活层和权重后,再使用per-tensor或per-token量化,实现W8A8。根据量化方式不同,作者提出三种策略 O1、O2、O3,计算延迟依次降低。
与其他量化方法相比,该方法可以保持较高的精度,同时,具有更低的延迟。
3. int8-kv-cache量化: KV Cache 量化是指将逐 Token(Decoding)生成过程中的上下文 K 和 V 中间结果进行 INT8 量化(计算时再反量化),以降低生成过程中的显存占用。
4. int4-gptq 量化:所有权重压缩到4位量化中,通过最小化与该权重的均方误差来实现。在推理过程中,它将动态地将权重解量化为float16,以提高性能,同时保持内存较低。
5. int4-awq 量化:激活感知的权重量化。 在量化过程中,有一小部分权重将被跳过,这有助于减少量化损失。
模型越大,对仅权重和KV缓存量化的容忍度越高,而对激活量化的容忍度较低。
对于大多数NLP任务,将大多数LLM家族量化为W4、W4A8、KV4和W8KV4,性能损失可以忽略不计(<2%)。在一定的内存预算下,使用量化到W3的较大模型可以获得更优性能。
在四种突出能力(即上下文学习、指令遵循、多步推理和自校准)中,自校准和多步推理能力对量化更敏感。对于小于13B的LLMs,推荐使用W8、W8A8和KV8量化。
对于伦理任务,小型模型对量化的敏感性更高。仅权重量化会增强模型对敏感信息的判断,而KV缓存量化则有相反的效果。
LLMs在处理长文本(>4k)时,对仅权重和KV缓存量化的敏感性高于短文本(<4k),尤其是对KV缓存量化。在大多数情况下,W4、W4A8和KV8可以在长上下文任务中保持性能。
最先进的量化方法,如SmoothQuant和AWQ,在量化造成的性能损失适中时,可以有效提升性能。然而,当使用极低位宽时,AWQ和SmoothQuant无法恢复完全损坏的性能。
参考:https://zhuanlan.zhihu.com/p/695144724

  1. lora 大模型如何合并?
    https://blog.csdn.net/BIT_666/article/details/132065177
    参考:https://github.com/ymcui/Chinese-LLaMA-Alpaca-3/blob/main/scripts/merge_llama3_with_chinese_lora_low_mem.py
    1. 将1 个lora模型合并到base 模型中。
import torch
from peft import PeftModel
from transformers import AutoTokenizer, AutoModelForCausalLM

model_name_or_path="/home/Meta-Llama-3-8B-Instruct"
lora_path="/home/llama-3-chinese-8b-instruct-lora"
print(f"Loading the base model from {model_name_or_path}")
base = AutoModelForCausalLM.from_pretrained(  # 加载模型
    model_name_or_path, torch_dtype=torch.float16, low_cpu_mem_usage=True
)
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)         #此处未进行tokenizer的合并,
       # 具体见https://github.com/ymcui/Chinese-LLaMA-Alpaca-3/blob/main/scripts/merge_llama3_with_chinese_lora_low_mem.py

print(f"Loading the LoRA adapter from {lora_path}")

lora_model = PeftModel.from_pretrained(  # 加载lora模型
    base,
    lora_path,
    torch_dtype=torch.float16,
)

print("Applying the LoRA")
model = lora_model.merge_and_unload()  # 合并模型,
output_path="./merge_llama3_lora"
print(f"Saving the target model to {output_path}")  # 保存
model.save_pretrained(output_path)
tokenizer.save_pretrained(output_path)
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
model_name_or_path="./merge_llama3_lora"
print(f"Loading the base model from {model_name_or_path}")
model = AutoModelForCausalLM.from_pretrained(  # 加载模型
    model_name_or_path, torch_dtype=torch.float16, low_cpu_mem_usage=True
)
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)
model=model.cuda()

DEFAULT_SYSTEM_PROMPT = """You are a helpful assistant. 你是一个乐于助人的助手。"""
system_format='<|start_header_id|>system<|end_header_id|>\n\n{content}<|eot_id|>'
user_format='<|start_header_id|>user<|end_header_id|>\n\n{content}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n'
assistant_format='{content}<|eot_id|>'

def generate_prompt(instruction):
    return system_format.format(content=DEFAULT_SYSTEM_PROMPT) + user_format.format(content=instruction)
tokenizer.pad_token = tokenizer.eos_token
input_ids = tokenizer(generate_prompt("介绍一下中国"), return_tensors="pt",add_special_tokens=False).input_ids
if torch.cuda.is_available():
  input_ids = input_ids.cuda()
generate_input = {
    "input_ids":input_ids,
    "max_new_tokens":512,
    "do_sample":True,
    "top_k":50,
    "top_p":0.95,
    "temperature":0.3,
    "repetition_penalty":1.3,
    "eos_token_id":tokenizer.eos_token_id,
    "bos_token_id":tokenizer.bos_token_id,
    "pad_token_id":tokenizer.pad_token_id
}
generate_ids  = model.generate(**generate_input)
text = tokenizer.decode(generate_ids[0])
print(text)
  1. 将多个任务lora 模型合并。
from transformers import AutoConfig, AutoTokenizer, AutoModelForCausalLM, TextIteratorStreamer, GenerationConfig
from peft import PeftModel
 
# 载入预训练模型
tokenizer = AutoTokenizer.from_pretrained(base_model, use_fast=True, padding_side="left", **config_kwargs)
print("Tokenizer Load Success!")
config = AutoConfig.from_pretrained(base_model, **config_kwargs)
# Load and prepare pretrained models (without valuehead).
model = AutoModelForCausalLM.from_pretrained(
    base_model,
    config=config,
    torch_dtype=torch.float16,
    low_cpu_mem_usage=True,
    trust_remote_code=True,
    revision='main'
)
print('origin config =', model.config)
# 模型合并
ckpt_list = ["checkpoint-1000", "checkpoint-2000", "checkpoint-3000"]
for checkpoint in ckpt_list:
    print('Merge checkpoint: {}'.format(checkpoint))
    model = PeftModel.from_pretrained(model, os.path.join(lora_model, checkpoint))
    model = model.merge_and_unload()                #将每一个lora 模型合并
print('merge config =', model.config)
  1. lora 大模型如何编译,使用?
    8.1 未加载lora 模型编译。
CUDA_VISIBLE_DEVICES=0 python3 convert_checkpoint.py --model_dir /app/tensorrt_llm/examples/Meta-Llama-3-8B-Instruct \
            --output_dir ./tllm_checkpoint_1gpu_bf16 \
            --dtype bfloat16

CUDA_VISIBLE_DEVICES=0 python3 build.py --checkpoint_dir ./tllm_checkpoint_1gpu_bf16 \
            --output_dir ./tmp/llama/8B/trt_engines/bf16/1-gpu \
            --gpt_attention_plugin bfloat16 \
            --gemm_plugin bfloat16
trtllm-build 等价于build.py   build.py 为trtllm-build 指令形式。
CUDA_VISIBLE_DEVICES=0 trtllm-build --checkpoint_dir ./tllm_checkpoint_1gpu_bf16 \
            --output_dir ./tmp/llama/8B/trt_engines/bf16/1-gpu \
            --gpt_attention_plugin bfloat16 \
            --gemm_plugin bfloat16
python3  run.py --engine_dir=/app/tensorrt_llm/examples/TensorRT-LLM-0.8.0/examples/llama1/tmp/llama/8B/trt_engines/bf16/1-gpu --max_output_len 100 --tokenizer_dir /app/tensorrt_llm/examples/Meta-Llama-3-8B-Instruct --input_text "How do I count to nine in French?"

8.2 加载lora 文件编译。

CUDA_VISIBLE_DEVICES=0,1 python3 convert_checkpoint.py --model_dir /app/tensorrt_llm/examples/Meta-Llama-3-8B-Instruct \
                         --output_dir ./tllm_checkpoint_2gpu_lora \
                         --dtype bfloat16 \
                         --tp_size 1 \
                         --hf_lora_dir /app/tensorrt_llm/examples/llama-3-chinese-8b-instruct-lora

CUDA_VISIBLE_DEVICES=0,1 python3 build.py --checkpoint_dir ./tllm_checkpoint_2gpu_lora \
            --output_dir ./tmp/new_lora_13b/trt_engines/fp16/2-gpu/ \
            --gpt_attention_plugin bfloat16 \
            --gemm_plugin bfloat16 \
            --lora_plugin bfloat16 \
            --max_batch_size 1 \
            --max_input_len 512 \
            --max_output_len 50 \
            --use_fused_mlp
            
python3 ../run.py --engine_dir "./tmp/new_lora_13b/trt_engines/fp16/2-gpu/" \
              --max_output_len 50 \
              --tokenizer_dir "/app/tensorrt_llm/examples/llama-3-chinese-8b-instruct-lora" \
              --input_text "今天天气很好,我到公园的时后," \
              --lora_dir "/app/tensorrt_llm/examples/llama-3-chinese-8b-instruct-lora" \
              --lora_task_uids 0 \
              --no_add_special_tokens \
              --use_py_session
  1. 当采用float16时,编译时报类型转换错误,需要改成bfloat16.
  2. 遇到问题: lora_target_model 为null, 即convert_checkpoint.py 量化文件报错。原因是:tensorrt-llm 架构加载lora 文件为bin 类型的数据,而本人的lora 模型文件为safetensors类型的文件。因此本人对lora_manager.py 进行了修改,使文件能够加载该文件。在这里插入图片描述
  3. 模型量化与编译细节见代码讲解模块。

9 safetensors 、bin 数据类型 模型互相转换

from safetensors.torch import save_file,load_file
import torch
hf_lora_dir="/app/tensorrt_llm/examples/llama-3-chinese-8b-instruct-lora"
binpath=f"{hf_lora_dir}/adapter_model.bin"
safepath=f"{hf_lora_dir}/adapter_model.safetensors"
lora_weight=load_file(safepath)         #加载safetensors
torch.save(lora_weight,binpath)         #保存为bin
lora_weight1=torch.load(binpath)

keys=lora_weight.keys()
for key in keys:
    params1=lora_weight[key]
    params2=lora_weight1[key]
    if not torch.equal(params1,params2):
        print("两个模型不完全一致")

print("done!")
  1. 推理加速模型 tensorrRT-LLM、Vllm、TGI、fasterTransformer、BetterTransformer 的对比在这里插入图片描述
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐