跳转到主要内容

热门内容

今日:


总体:


最近浏览:


Chinese, Simplified

category

大型语言模型(LLM)凭借其从大量文本中学习并为各种任务和领域生成流畅连贯的文本的能力,彻底改变了自然语言处理(NLP)。然而,定制LLM是一项具有挑战性的任务,通常需要一个耗时且计算成本高昂的完整训练过程。此外,训练LLM需要一个多样化和有代表性的数据集,这可能很难获得和策划。

企业如何在不支付全面培训成本的情况下利用LLM的力量?一个有前途的解决方案是低秩自适应(LoRA),这是一种微调方法,可以显著减少可训练参数的数量、内存需求和训练时间,同时在各种NLP任务和域上实现与微调相当甚至更好的性能。

这篇文章解释了LoRA的直觉和实现,并展示了它的一些应用和好处。还将LoRA与监督微调和即时工程进行了比较,并讨论了它们的优点和局限性。它概述了LoRA调整模型的训练和推理的实用指南。最后,它演示了如何使用NVIDIATensorRTLLM来优化LoRA模型在NVIDIAGPU上的部署。

教程先决条件


为了充分利用本教程,您需要LLM培训和推理管道的基本知识,以及:

  • 线性代数基础知识
  • Hugging Face注册的用户访问权限和对变形金刚库的普遍熟悉程度
  • NVIDIA/TensorRT LLM优化库
  • 具有TensorRT LLM后端的NVIDIA Triton推理服务器


什么是LoRA?


LoRA是一种微调方法,它将低秩矩阵引入LLM架构的每一层,并且只训练这些矩阵,同时保持原始LLM权重冻结。它是NVIDIA NeMo中支持的LLM自定义工具之一(图1)。

Figure 1. LoRA is among the LLM customization tools and techniques supported in NVIDIA NeMo

  • LLM功能强大,但通常需要自定义,尤其是在用于企业或领域特定用例时。有许多调整选项,从简单的即时工程到监督微调(SFT)。调整选项的选择通常基于所需数据集的大小(即时工程的最小值,SFT的最大值)和计算可用性。
  • LoRA调谐是一种称为参数有效微调(PEFT)的调谐族。这些技术是一种中间路线的方法。与即时工程相比,它们需要更多的训练数据和计算,但也能产生更高的精度。共同的主题是,它们引入了少量参数或层,同时保持原始LLM不变
  • PEFT已被证明可以实现与SFT相当的精度,同时使用更少的数据和更少的计算资源。与其他调谐技术相比,LoRA有几个优点。它减少了计算和内存成本,因为它只添加了一些新参数,但不添加任何层。它实现了多任务学习,允许通过根据需要部署相关的微调LoRA变体,仅在需要时加载其低秩矩阵,将单个基本LLM用于不同的任务。
  • 最后,它避免了灾难性遗忘,这是LLM在学习新数据时突然忘记先前学习的信息的自然趋势。从数量上讲,LoRA的性能优于使用其他调整技术(如提示调整和适配器)的模型,如LoRA:大型语言模型的低阶自适应所示。

LoRA背后的数学


LoRA背后的数学是基于低秩分解的思想,这是一种通过两个较小的低秩矩阵的乘积来近似矩阵的方法。矩阵的秩是矩阵中线性独立的行或列的数量。低秩矩阵的自由度较小,并且可以比全秩矩阵更紧凑地表示。

LoRA将低秩分解应用于LLM的权重矩阵,这些权重矩阵通常非常大且稠密。例如,如果LLM具有1024的隐藏大小和50000的词汇表大小,则输出权重矩阵W将具有1024 x 50000=51200000个参数。

LoRA将该矩阵W分解为两个较小的矩阵,形状为1024 x r的矩阵A和形状为r x 50000的矩阵B,其中r是控制分解秩的超参数。这两个矩阵的乘积将具有与原始矩阵相同的形状,但只有1024 x r+r x 50000=51200000–50000 x(1024–r)个参数。

超参数r对于正确设置至关重要。选择较小的r可以节省大量参数和内存,并实现更快的训练。然而,较小的r可能会减少在低秩矩阵中捕获的任务特定信息。较大的r可能导致过拟合。因此,为了实现特定任务和数据的理想精度-性能权衡,进行实验是很重要的。

LoRA将这些低秩矩阵插入LLM的每一层中,并将它们添加到原始权重矩阵中。原始权重矩阵用预训练的LLM权重初始化,并且在训练期间不更新。低秩矩阵是随机初始化的,并且是在训练期间唯一更新的参数。LoRA还将层归一化应用于原始矩阵和低秩矩阵的和,以稳定训练。

Figure 2. The decomposition of the LLM matrix W into two low-ranking matrices A and B

多LoRA部署


部署LLM的一个挑战是如何有效地为数百或数千个调优模型提供服务。例如,单个基础LLM,如Llama 2,可能具有每个语言或地区的许多LoRA调优变体。标准系统需要独立加载所有模型,占用大量内存容量。利用LoRA的设计,通过加载单个基本模型以及每个LoRA调谐变体的低秩矩阵a和B,在每个模型的较小低秩矩阵中捕获所有信息。通过这种方式,可以存储数千个LLM,并在最小的GPU内存占用范围内动态高效地运行它们。

LoRA调谐


LoRA调整需要以特定格式准备训练数据集,通常使用提示模板。在形成提示时,您应该确定并遵守一个模式,这在不同的用例中自然会有所不同。问答示例如下所示。

{
        "taskname": "squad",
        "prompt_template": "<|VIRTUAL_PROMPT_0|> Context: {context}\n\nQuestion: 
{question}\n\nAnswer:{answer}",
        "total_virtual_tokens": 10,
        "virtual_token_splits": [10],
        "truncate_field": "context",
        "answer_only_loss": True,
        "answer_field": "answer",
}


提示包含开头的所有10个虚拟标记,然后是上下文、问题,最后是答案。训练数据JSON对象中对应的字段将映射到此提示模板,形成完整的训练示例。

有几个可用的平台用于定制LLM。您可以使用NVIDIA NeMo或诸如拥抱面部PEFT之类的工具。有关如何使用NeMo在PubMed数据集上调整LoRA的示例,请参阅带有Llama 2的NeMo Framework PEFT。

请注意,这篇文章使用了来自Hugging Face的现成调谐LLM,因此没有必要进行调谐。

LoRA推断


要使用TensorRT LLM优化LoRA调优的LLM,您必须了解其架构,并确定其最相似的公共基础架构。本教程使用Llama2 13B和Llama 2 7B作为基本模型,以及拥抱脸上可用的几种LoRA调谐变体。

第一步是使用该目录中的转换器和构建脚本来编译所有模型,并为硬件加速做好准备。然后,我将展示使用命令行和Triton推理服务器进行部署的示例。

请注意,标记化器不是由TensorRT LLM直接处理的。但有必要将其分类到一个定义的标记器家族中,以便在运行时以及在Triton中设置预处理和后处理步骤。

建立和构建TensorRT LLM


首先克隆并构建NVIDIA/TensorRTLLM库。构建TensorRTLLM并检索其所有依赖项的最简单方法是使用包含的Dockerfile。这些命令提取一个基本容器,并在容器中安装TensorRTLLM所需的所有依赖项。然后,它在容器中构建并安装TensorRTLLM本身。

git lfs install
git clone https://github.com/NVIDIA/TensorRT-LLM.git
cd TensorRT-LLM
git submodule update --init --recursive
make -C docker release_build


检索模型权重


从Hugging Face下载基本模型和LoRA模型:


编译模型


构建引擎,设置--use_lora_plugin和--hf_lora_dir。如果lora有一个单独的lm_head和嵌入,这些将取代基本模型的lm_head和嵌入。

python convert_checkpoint.py --model_dir /tmp/llama-v2-13b-hf \
                         --output_dir ./tllm_checkpoint_2gpu_lora \
                         --dtype float16 \
                         --tp_size 2 \
                         --hf_lora_dir /tmp/chinese-llama-2-lora-13b
                          
trtllm-build --checkpoint_dir ./tllm_checkpoint_2gpu_lora \
            --output_dir /tmp/new_lora_13b/trt_engines/fp16/2-gpu/ \
            --gpt_attention_plugin float16 \
            --gemm_plugin float16 \
            --lora_plugin float16 \
            --max_batch_size 1 \
            --max_input_len 512 \
            --max_output_len 50 \
            --use_fused_mlp


运行模型


要在推理过程中运行模型,请设置lora\dir命令行参数。记住使用LoRA标记器,因为LoRA调优的模型具有更大的词汇量。

mpirun -n 2 python ../run.py --engine_dir "/tmp/new_lora_13b/trt_engines/fp16/2-gpu/" \
              --max_output_len 50 \
              --tokenizer_dir "chinese-llama-2-lora-13b/" \
              --input_text "今天天气很好,我到公园的时后," \
              --lora_dir "chinese-llama-2-lora-13b/" \
              --lora_task_uids 0 \
              --no_add_special_tokens \
              --use_py_session
 
 Input: "今天天气很好,我到公园的时后,"
Output: "发现公园里人很多,有的在打羽毛球,有的在打乒乓球,有的在跳绳,还有的在跑步。我和妈妈来到一个空地上,我和妈妈一起跳绳,我跳了1"


您可以进行消融测试,亲眼目睹LoRA调谐模型的贡献。要方便地比较有和没有LoRa的结果,只需使用--LoRa_stask_uids-1将UID设置为-1。在这种情况下,模型将忽略LoRA模块,结果将仅基于基本模型。

mpirun -n 2 python ../run.py --engine_dir "/tmp/new_lora_13b/trt_engines/fp16/2-gpu/" \
              --max_output_len 50 \
              --tokenizer_dir "chinese-llama-2-lora-13b/" \
              --input_text "今天天气很好,我到公园的时后," \
              --lora_dir "chinese-llama-2-lora-13b/" \
              --lora_task_uids -1 \
              --no_add_special_tokens \
              --use_py_session
 
 Input: "今天天气很好,我到公园的时后,"
Output: "我看见一个人坐在那边边看书书,我看起来还挺像你,可是我走过过去问了一下他说你是你吗,他说没有,然后我就说你看我看看你像你,他说说你看我像你,我说你是你,他说你是你,"


使用多个LoRA调整模型运行基本模型


TensorRTLLM还支持同时运行具有多个LoRA调谐模块的单个基础模型。在这里,我们使用两个LoRA检查点作为示例。由于两个检查点的LoRA模块的秩r都是8,因此可以将--max_LoRA_rank设置为8,以减少LoRA插件的内存需求。

该示例使用在中国数据集骆驼-7b-0.1上微调的LoRA检查点和在日本数据集Japanese-Alpaca-LoRA-7b-v0上微调的LoRA检查点。为了使TensorRT LLM加载多个检查点,请通过--LoRA_dir“luotoo-LoRA-7b-0.1/”“Japanese-Alpaca-LoRA-7b-v0/”在所有LoRA检查点的目录中传递。TensorRT LLM将为这些检查点分配lora_stask_uid。lora_stask_uids-1是一个预定义的值,它对应于基本模型。例如,通过lora_stask_uids 0 1将对第一句使用第一个lora检查点,对第二句使用第二个lora检测点。

要验证正确性,请传递相同的中文输入美国的首都在哪里? \n答案: 三次,以及相同的日语输入アメリカ合衆国の首都はどこですか? \n答え: 三次。(在英语中,两个输入的意思都是“美国首都在哪里?答案”)。然后分别在基础模型骆驼花-7b-0.1和日本Alpaca-lora-7b-v0上运行:

BASE_LLAMA_MODEL=llama-7b-hf/
 
python convert_checkpoint.py --model_dir ${BASE_LLAMA_MODEL} \
                            --output_dir ./tllm_checkpoint_1gpu_lora_rank \
                            --dtype float16 \
                            --hf_lora_dir /tmp/Japanese-Alpaca-LoRA-7b-v0 \
                            --max_lora_rank 8 \
                            --lora_target_modules "attn_q" "attn_k" "attn_v"
 
trtllm-build --checkpoint_dir ./tllm_checkpoint_1gpu_lora_rank \
            --output_dir /tmp/llama_7b_with_lora_qkv/trt_engines/fp16/1-gpu/ \
            --gpt_attention_plugin float16 \
            --gemm_plugin float16 \
            --lora_plugin float16 \
            --max_batch_size 1 \
            --max_input_len 512 \
            --max_output_len 50
 
python ../run.py --engine_dir "/tmp/llama_7b_with_lora_qkv/trt_engines/fp16/1-gpu/" \
              --max_output_len 10 \
              --tokenizer_dir ${BASE_LLAMA_MODEL} \
              --input_text "美国的首都在哪里? \n答案:" "美国的首都在哪里? \n答案:" "美国的首都在哪里? \n答案:" "アメリカ合衆国の首都はどこですか? \n答え:" "アメリカ合衆国の首都はどこですか? \n答え:" "アメリカ合衆国の首都はどこですか? \n答え:" \
              --lora_dir  "luotuo-lora-7b-0.1/" "Japanese-Alpaca-LoRA-7b-v0/" \
              --lora_task_uids -1 0 1 -1 0 1 \
              --use_py_session --top_p 0.5 --top_k 0


结果如下所示:

Input [Text 0]: "<s> 美国的首都在哪里? \n答案:"
Output [Text 0 Beam 0]: "Washington, D.C.
What is the"
 
Input [Text 1]: "<s> 美国的首都在哪里? \n答案:"
Output [Text 1 Beam 0]: "华盛顿。
"
 
Input [Text 2]: "<s> 美国的首都在哪里? \n答案:"
Output [Text 2 Beam 0]: "Washington D.C.'''''"
 
Input [Text 3]: "<s> アメリカ合衆国の首都はどこですか? \n答え:"
Output [Text 3 Beam 0]: "Washington, D.C.
Which of"
 
Input [Text 4]: "<s> アメリカ合衆国の首都はどこですか? \n答え:"
Output [Text 4 Beam 0]: "华盛顿。
"
 
Input [Text 5]: "<s> アメリカ合衆国の首都はどこですか? \n答え:"
Output [Text 5 Beam 0]: "ワシントン D.C."


请注意,luotuo-lora-7b-0.1在第一句和第五句(中文)都能给出正确的答案。日语-Alpaca-LoRA-7b-v0在第六句(日语)中给出正确答案。

重要提示:如果其中一个LoRA模块包含微调的嵌入表或logitGEMM,用户必须保证‌模型的实例可以使用相同的微调嵌入表或logitGEMM。

使用Triton和机上批处理部署LoRA调谐模型


本节展示了如何使用Triton推理服务器的空中批处理部署LoRA调优模型。有关设置和启动Triton推理服务器的具体说明,请参阅使用NVIDIA TensorRT LLM和NVIDIA Triton部署AI编码助手。

和以前一样,首先编译一个启用了LoRA的模型,这次是使用基本模型Llama 2 7B。

BASE_MODEL=llama-7b-hf
 
python3 tensorrt_llm/examples/llama/build.py --model_dir ${BASE_MODEL} \
                --dtype float16 \
                --remove_input_padding \
                --use_gpt_attention_plugin float16 \
                --enable_context_fmha \
                --use_gemm_plugin float16 \
                --output_dir "/tmp/llama_7b_with_lora_qkv/trt_engines/fp16/1-gpu/" \
                --max_batch_size 128 \
                --max_input_len 512 \
                --max_output_len 50 \
                --use_lora_plugin float16 \
                --lora_target_modules "attn_q" "attn_k" "attn_v" \
                --use_inflight_batching \
                --paged_kv_cache \
                --max_lora_rank 8 \
                --world_size 1 --tp_size 1


接下来,生成LoRA张量,该张量将随每个请求一起传递给Triton。

 
python3 tensorrt_llm/examples/hf_lora_convert.py -i Japanese-Alpaca-LoRA-7b-v0 -o Japanese-Alpaca-LoRA-7b-v0-weights --storage-type float16
python3 tensorrt_llm/examples/hf_lora_convert.py -i luotuo-lora-7b-0.1 -o luotuo-lora-7b-0.1-weights --storage-type float16

 

然后创建一个Triton模型存储库,并如前所述启动Triton服务器。

最后,通过从客户端发出多个并发请求来运行多LoRA示例。机上分批器将在同一批次中执行多个LoRA的混合批次。

INPUT_TEXT=("美国的首都在哪里? \n答案:" "美国的首都在哪里? \n答案:" "美国的首都在哪里? \n答案:" "アメリカ合衆国の首都はどこですか? \n答え:" "アメリカ合衆国の首都はどこですか? \n答え:" "アメリカ合衆国の首都はどこですか? \n答え:")
LORA_PATHS=("" "luotuo-lora-7b-0.1-weights" "Japanese-Alpaca-LoRA-7b-v0-weights" "" "luotuo-lora-7b-0.1-weights" "Japanese-Alpaca-LoRA-7b-v0-weights")
 
for index in ${!INPUT_TEXT[@]}; do
    text=${INPUT_TEXT[$index]}
    lora_path=${LORA_PATHS[$index]}
    lora_arg=""
    if [ "${lora_path}" != "" ]; then
        lora_arg="--lora-path ${lora_path}"
    fi
 
    python3 inflight_batcher_llm/client/inflight_batcher_llm_client.py \
        --top-k 0 \
        --top-p 0.5 \
        --request-output-len 10 \
        --text "${text}" \
        --tokenizer-dir /home/scratch.trt_llm_data/llm-models/llama-models/llama-7b-hf \
        ${lora_arg} &
done
 
wait


示例输出如下所示:

Input sequence:  [1, 29871, 30310, 30604, 30303, 30439, 30733, 235, 164, 137, 30356, 30199, 31688, 30769, 30449, 31250, 30589, 30499, 30427, 30412, 29973, 320, 29876, 234, 176, 151, 30914, 29901]
Input sequence:  [1, 29871, 30630, 30356, 30210, 31688, 30769, 30505, 232, 150, 173, 30755, 29973, 320, 29876, 234, 176, 151, 233, 164, 139, 29901]
Input sequence:  [1, 29871, 30630, 30356, 30210, 31688, 30769, 30505, 232, 150, 173, 30755, 29973, 320, 29876, 234, 176, 151, 233, 164, 139, 29901]
Input sequence:  [1, 29871, 30310, 30604, 30303, 30439, 30733, 235, 164, 137, 30356, 30199, 31688, 30769, 30449, 31250, 30589, 30499, 30427, 30412, 29973, 320, 29876, 234, 176, 151, 30914, 29901]
Input sequence:  [1, 29871, 30310, 30604, 30303, 30439, 30733, 235, 164, 137, 30356, 30199, 31688, 30769, 30449, 31250, 30589, 30499, 30427, 30412, 29973, 320, 29876, 234, 176, 151, 30914, 29901]
Input sequence:  [1, 29871, 30630, 30356, 30210, 31688, 30769, 30505, 232, 150, 173, 30755, 29973, 320, 29876, 234, 176, 151, 233, 164, 139, 29901]
Got completed request
Input: アメリカ合衆国の首都はどこですか? \n答え:
Output beam 0: ワシントン D.C.
Output sequence:  [1, 29871, 30310, 30604, 30303, 30439, 30733, 235, 164, 137, 30356, 30199, 31688, 30769, 30449, 31250, 30589, 30499, 30427, 30412, 29973, 320, 29876, 234, 176, 151, 30914, 29901, 29871, 31028, 30373, 30203, 30279, 30203, 360, 29889, 29907, 29889]
Got completed request
Input: 美国的首都在哪里? \n答案:
Output beam 0: Washington, D.C.
What is the
Output sequence:  [1, 29871, 30630, 30356, 30210, 31688, 30769, 30505, 232, 150, 173, 30755, 29973, 320, 29876, 234, 176, 151, 233, 164, 139, 29901, 7660, 29892, 360, 29889, 29907, 29889, 13, 5618, 338, 278]
Got completed request
Input: 美国的首都在哪里? \n答案:
Output beam 0: Washington D.C.
Washington D.
Output sequence:  [1, 29871, 30630, 30356, 30210, 31688, 30769, 30505, 232, 150, 173, 30755, 29973, 320, 29876, 234, 176, 151, 233, 164, 139, 29901, 7660, 360, 29889, 29907, 29889, 13, 29956, 7321, 360, 29889]
Got completed request
Input: アメリカ合衆国の首都はどこですか? \n答え:
Output beam 0: Washington, D.C.
Which of
Output sequence:  [1, 29871, 30310, 30604, 30303, 30439, 30733, 235, 164, 137, 30356, 30199, 31688, 30769, 30449, 31250, 30589, 30499, 30427, 30412, 29973, 320, 29876, 234, 176, 151, 30914, 29901, 7660, 29892, 360, 29889, 29907, 29889, 13, 8809, 436, 310]
Got completed request
Input: アメリカ合衆国の首都はどこですか? \n答え:
Output beam 0: Washington D.C.
1. ア
Output sequence:  [1, 29871, 30310, 30604, 30303, 30439, 30733, 235, 164, 137, 30356, 30199, 31688, 30769, 30449, 31250, 30589, 30499, 30427, 30412, 29973, 320, 29876, 234, 176, 151, 30914, 29901, 7660, 360, 29889, 29907, 29889, 13, 29896, 29889, 29871, 30310]
Got completed request
Input: 美国的首都在哪里? \n答案:
Output beam 0: 华盛顿
W
Output sequence:  [1, 29871, 30630, 30356, 30210, 31688, 30769, 30505, 232, 150, 173, 30755, 29973, 320, 29876, 234, 176, 151, 233, 164, 1


结论


通过对许多流行的LLM架构的基线支持,TensorRTLLM可以轻松地部署、实验和优化各种代码LLM。NVIDIA TensorRT LLM和NVIDIA Triton推理服务器共同为高效地优化、部署和运行LLM提供了不可或缺的工具包。TensorRTLLM支持LoRA调优模型,能够高效部署定制LLM,显著降低内存和计算成本。

要开始,请下载并设置NVIDIA/TensorRTLLM开源库,并尝试使用不同的LLM示例。您可以使用NVIDIA NeMo调整自己的LLM——有关示例,请参阅带有Llama 2的NeMo Framework PEFT。作为替代方案,您也可以使用NeMo框架推理容器进行部署。

Related resources

 

本文地址
最后修改
星期六, June 1, 2024 - 09:18
Tags
 
Article