使用NVIDIA TensorRT-LLM支持CodeFuse-CodeLlama-34B上的int4量化和推理优化实践

简介: CodeFuse是由蚂蚁集团开发的代码语言大模型,旨在支持整个软件开发生命周期,涵盖设计、需求、编码、测试、部署、运维等关键阶段。为了在下游任务上获得更好的精度,CodeFuse 提出了多任务微调框架(MFTCoder),能够解决数据不平衡和不同收敛速度的问题。通过对比多个预训练基座模型的精度表现,我们发现利用 MFTCoder 微调后的模型显著优于原始基座模型。其中,尤为值得关注的是采用了 MFTCoder 框架,并利用多任务数据集进行微调的 CodeFuse-CodeLlama-34B模型,在HumanEval 评估数据集中取得了当时的最好结果。

s f e.png

本文首发于 NVIDIA



一、概述

CodeFuse(https://github.com/codefuse-ai)是由蚂蚁集团开发的代码语言大模型,旨在支持整个软件开发生命周期,涵盖设计、需求、编码、测试、部署、运维等关键阶段。

为了在下游任务上获得更好的精度,CodeFuse 提出了多任务微调框架(MFTCoder),能够解决数据不平衡和不同收敛速度的问题。

通过对比多个预训练基座模型的精度表现,我们发现利用 MFTCoder [1,2] 微调后的模型显著优于原始基座模型。其中,尤为值得关注的是采用了 MFTCoder 框架,并利用多任务数据集进行微调的 CodeFuse-CodeLlama-34B [3] 模型,在 HumanEval 评估数据集中取得了当时的最好结果。具体来说,基于 CodeLlama-34b-Python 模型进行微调的 CodeFuse-CodeLlama-34B 在 HumanEval-python 上实现了 74.4% 的 pass@1(贪婪解码)。以下是完整的代码能力评估结果 :

image.png


在代码补全、text2code、代码翻译、单测生成以及代码生成任务上,CodeFuse-CodeLlama-34B 全面超过 GPT-3.5;CodeFuse-CodeLlama-34B 能够在单测生成和代码补全(HumanEval )任务上超过 GPT-4。同时,上述微调模型、MFTCoder 训练框架和高质量代码数据集已经开源(github: https://github.com/codefuse-ai)

然而,CodeFuse-CodeLlama-34B 的部署遇到了如下两个挑战:

1)数据类型为 fp16 的 34B 模型,显存占用为 68 GB,至少需要 3 张 A10 才能加载模型,部署成本很高;

2)在模型推理的生成阶段,通常伴随着长条形的矩阵运算,此时计算量较小,不足以掩盖 GPU 的访存延迟,即 memory bound 问题,此时程序的性能受限于 GPU 带宽。

为了解决上述问题,我们利用 GPTQ 量化技术,在降低了部署成本的同时,也缓解了 GPU 的带宽压力 ,从而显著提升了推理速度。最终,CodeFuse-CodeLlama-34B 的 int4 量化模型可以部署在单张 A10 显卡上,推理速度可以达到 20 tokens/s (batch_size=1)。同时,相较于 fp16 数据精度的模型,通过算法上的优化,int4 量化引入的精度下降可以控制在 1% 以内。下面,我们从模型量化和测试两个方面展示我们是如何实现 CodeFuse-CodeLlama-34B 模型的 int4 量化部署的。另外,TensorRT-LLM 也支持了 CodeFuse 中基于 MFTCoder 训练的开源模型部署。

二、CodeFuse-CodeLlama-34B int4 量化


这里我们使用 GPTQ [4] 技术对模型进行 int4 量化。GPTQ 是对逐层量化范式经典框架 OBQ(Optimal Brain Quantization)[5] 的高效实现,能够利用单张 A100-80G 在 4 小时内完成 OPT-175B 模型的量化,并且可以获得较好的准确率。

另外,我们这里采用了静态量化方式,即通过矫正数据离线地进行量化,得到诸如缩放因子和零点的量化参数,在推理时不再进行量化参数的更新。与之对应的是动态量化,会在模型推理的同时根据输入进行量化参数的调整。最后,我们这里进行的是 int4-weight-only 量化,即只对权重进行量化而不对层输入进行量化,即 W4A16 量化。



GPTQ 算法

为了量化权重,OBQ 框架对层重建损失函数进行二阶泰勒级数展开,同时假设在未量化的权重值处一阶梯度为零,从而得到如下优化问题:



其中,是所有未量化权重对应的 Hessian 矩阵。那么,量化误差以及权重更新值分别为



上面的两个公式意味着所有未量化权重需要通过更新以补偿量化带来的量化误差。同时,层重建损失函数可以按照输出通道(output channel, OC)分解为独立的子问题,例如:


其中 Hessian 矩阵为。为了充分利用 GPU 的能力,GPTQ 做了如下三个改进:


  1. 所有输出通道共享相同的量化顺序,从而使得行间共享同一份 Hessian 矩阵,大大减少了算法计算量。
  2. 使用一次 Cholesky 分解代替了在 GPTQ 每次迭代中对整个 Hessian 矩阵的逆矩阵的高斯消元迭代更新方式。既大大减少了计算量,又得以利用成熟 GPU 矩阵库中的 Cholesky 算法,且避免了迭代更新方式在矩阵运算中所带来的数值不稳定问题。
  3. 通过将整个计算过程由对单个输入通道进行更新,等效转变为划分 batch 并逐 batch 更新的方式,避免了每次量化对整个 Hessian 与权重矩阵的 GPU 读写操作,大大降低了 GPU 访存数量。

上述的改进使得 GPTQ 可以有效提升 GPU 利用率,从而能够对大模型进行高效量化。

三、int4-weight-only 量化

这里我们利用开源工具 AutoGPTQ(https://github.com/PanQiWei/AutoGPTQ)进行量化,工具超参数如下;

image.png



利用 AutoGPTQ 进行模型加载和推理的例子如下:

import os
import torch
import time
from modelscope import AutoTokenizer, snapshot_download
from auto_gptq import AutoGPTQForCausalLM
os.environ["TOKENIZERS_PARALLELISM"] = "false"
def load_model_tokenizer(model_path):
    """
    Load model and tokenizer based on the given model name or local path of downloaded model.
    """
    tokenizer = AutoTokenizer.from_pretrained(model_path, 
                                              trust_remote_code=True, 
                                              use_fast=False,
                                              lagecy=False)
    tokenizer.padding_side = "left"
    tokenizer.pad_token_id = tokenizer.convert_tokens_to_ids("<unk>")
    tokenizer.eos_token_id = tokenizer.convert_tokens_to_ids("</s>")
    model = AutoGPTQForCausalLM.from_quantized(model_path, 
                                                inject_fused_attention=False,
                                                inject_fused_mlp=False,
                                                use_cuda_fp16=True,
                                                disable_exllama=False,
                                                device_map='auto'   # Support multi-gpus
                                              )
    return model, tokenizer
def inference(model, tokenizer, prompt):
    """
    Uset the given model and tokenizer to generate an answer for the speicifed prompt.
    """
    st = time.time()
    inputs = prompt if prompt.endswith('\n') else f'{prompt}\n'
    input_ids = tokenizer.encode(inputs, 
                                  return_tensors="pt", 
                                  padding=True, 
                                  add_special_tokens=False).to("cuda")
    with torch.no_grad():
        generated_ids = model.generate(
            input_ids=input_ids,
            top_p=0.95,
            temperature=0.1,
            do_sample=True,
            max_new_tokens=512,
            eos_token_id=tokenizer.eos_token_id,
            pad_token_id=tokenizer.pad_token_id              
        )
    print(f'generated tokens num is {len(generated_ids[0][input_ids.size(1):])}')
    outputs = tokenizer.batch_decode(generated_ids, skip_special_tokens=True) 
    print(f'generate text is {outputs[0][len(inputs): ]}')
    latency = time.time() - st
    print('latency is {} seconds'.format(latency))
if __name__ == "__main__":
    model_dir = snapshot_download('codefuse-ai/CodeFuse-CodeLlama-34B-4bits', revision='v1.0.0')
    prompt = 'Please write a QuickSort program in Python'
    model, tokenizer = load_model_tokenizer(model_dir)
    inference(model, tokenizer, prompt)

在做静态量化时,GPTQ 使用矫正数据集作为输入计算 Hessian 矩阵,从而更新未量化权重进而补偿量化带来的误差。如果推理阶段的输入和矫正数据集有偏差(bias),那么量化时用矫正数据得到的 Hessian 矩阵就无法完全反映推理输入,这会导致 GPTQ 的误差补偿失效(失效的程度和偏差成正比),出现量化模型在推理输入上量化误差变大的情况,进而导致量化模型的精度下降。

为了解决上述问题,对于微调模型,我们使用了一种数据分布对齐技术减少模型量化带来的损失。通过抽取训练数据(CodeFuse 开源的高质量代码数据集 evol)中的 Question 作为引导方式,利用原始模型生成 Answer,将 Question 和 Answer 拼接起来作为矫正数据;最终在 HumanEval Benchmarks 的 Python pass@1 取得了 73.8% 的准确率,相较于 bf16 模型仅有 0.6% 的精度损失。同时,在 CMNLI 和 C-Eval 两个数据集的精度损失也比较少。

image.png


四、构建 TensorRT 引擎

在通过 AutoGPTQ 可以得到 safetensors 格式的 int4 量化模型 [6] 后,我们的目标是构建单卡 TensorRT 引擎,同时保证 activation 是 fp16 的数据精度。通过 examples/llama/build.py 进行 TensorRT 引擎构建时,需要关注如下参数:

  • dtype:设置为 fp16
  • use_gpt_attention_plugin:设置为 fp16,构建引擎时利用 gpt a ttention plugin 并且数据精度为 fp16
  • use_gemm_plugin:设置为 fp16,构建引擎时利用 gemm_plugin 并且数据精度为 fp16
  • use_weight_only:触发 weight only 量化
  • weight_only_precision:设置为 int4 _gptq,表示构建 W4A16 的 GPTQ 量化模型引擎
  • per_group:gptq 为group-wise 量化,所以需要触发 per-group
  • max_batch_size: TensorRT 引擎最大允许 batch size
  • max_input_len:TensorRT 引擎最大允许输入长度
  • max_output_len:TensorRT 引擎最大允许输出长度

综上,我们在单卡 A10/A100 上构建 TensorRT 引擎的命令如下:

python build.py --model_dir  "${model_dir}" \
                --quant_safetensors_path "${quant_safetensors_path}" \
                --dtype float16 \
                --use_gpt_attention_plugin float16 \
                --use_gemm_plugin float16 \
                --use_weight_only \
                --weight_only_precision int4_gptq \
                --max_batch_size 1 \
                --max_input_len 2048 \
                --max_output_len 1024 \
                --per_group \
                --output_dir "${engin_dir}" 2>&1  | tee dev_build.log

五、测试

性能

下面,我们主要测试了 batch size 为 1 时,不同的输入输出长度和量化精度情况下,TensorRT-LLM 在 A10/A100 上的推理速度表现。可以看到,在 A100 上,TensorRT-LLM 的 int4 相对 fp16,最高能够带来 2.4 倍的加速,相对 int8 最高也能带来 1.7 倍的加速。

image.png

注意:以上性能测试均基于 TensorRT-LLM 的 0.6.1 版本



显存占用和结果测试

我们测量了模型加载后占用的显存占用情况,以及输入 2048/1024 tokens 并输出 1024/2048 tokens 时的显存使用情况;同时我们也测试了量化前后的精度情况,如下表所示:

image.png

可见,4bit 量化后,显存占用大幅缩小,在一张 A10(24GB 显存)上就能部署 34B 的大模型,具备非常好的实用性。

六、模型演示

我们通过终端命令行 [7] 以及网页聊天机器人 [8] 两种不同的方式,展示我们最终的推理效果,具体细节可以访问开源的链接。

Cli Demo

image.gif



Webui Demo

1705995343936.gif



七、总结

在这篇文章中,我们介绍了如何使用 TensorRT-LLM来加速 CodeFuse 的推理性能。具体而言,我们按照顺序展示了如何使用 GPTQ Int4 量化方法、增强 GPTQ 量化算法精度的自动对齐技术、TensorRT-LLM int4 量化模型的使用方法以及相应的评估过程。通过 TensorRT-LLM 的支持,CodeFuse 实现了较低的推理延迟和优化的部署成本。欢迎大家关注 CodeFuse 获取最新发布的更高准确率的微调大模型。

参考资料:

[1] Liu, B., Chen, C., Liao, C., Gong, Z., Wang, H., Lei, Z., Liang, M., Chen, D., Shen, M., Zhou, H., Yu, H., & Li, J. (2023). MFTCoder: Boosting Code LLMs with Multitask Fine-Tuning. ArXiv, abs/2311.02303.

[2] Zhang, Z., Chen, C., Liu, B., Liao, C., Gong, Z., Yu, H., Li, J., & Wang, R. (2023). Unifying the Perspectives of NLP and Software Engineering: A Survey on Language Models for Code.

[3] https://huggingface.co/codefuse-ai/CodeFuse-CodeLlama-34B

[4] Frantar, E., Ashkboos, S., Hoefler, T., & Alistarh, D. (2022). GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers. ArXiv, abs/2210.17323.

[5] Frantar, E., Singh, S. P., Alistarh, D. (2022). Optimal Brain Compression: A Framework for Accurate Post-Training Quantization and Pruning. Advances in Neural Information Processing Systems, 35, 4475-4488.

[6] https://huggingface.co/codefuse-ai/CodeFuse-CodeLlama-34B-4bits

[7] Codefuse-ai: https://github.com/codefuse-ai

[8] Codefuse-chatbot: https://github.com/codefuse-ai/codefuse-chatbot

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
目录
相关文章
|
24天前
|
机器学习/深度学习 自然语言处理 测试技术
CoT神话破灭,并非LLM标配!三大学府机构联手证实,CoT仅在数学符号推理有用
【10月更文挑战第17天】链式思维(CoT)曾被认为是大型语言模型(LLM)激发推理能力的关键方法,但最新研究显示,CoT仅在数学和符号推理任务中有效,其他任务中效果不明显。加州大学伯克利分校、斯坦福大学和卡内基梅隆大学的联合研究打破了CoT作为LLM标配的神话,为重新评估LLM的推理能力提供了新视角。
29 1
|
15天前
|
JSON 数据可视化 NoSQL
基于LLM Graph Transformer的知识图谱构建技术研究:LangChain框架下转换机制实践
本文介绍了LangChain的LLM Graph Transformer框架,探讨了文本到图谱转换的双模式实现机制。基于工具的模式利用结构化输出和函数调用,简化了提示工程并支持属性提取;基于提示的模式则为不支持工具调用的模型提供了备选方案。通过精确定义图谱模式(包括节点类型、关系类型及其约束),显著提升了提取结果的一致性和可靠性。LLM Graph Transformer为非结构化数据的结构化表示提供了可靠的技术方案,支持RAG应用和复杂查询处理。
60 2
基于LLM Graph Transformer的知识图谱构建技术研究:LangChain框架下转换机制实践
|
7天前
|
数据采集 人工智能 自然语言处理
万字干货|复杂表格多Agent方案:从LLM洞察、系统性 思考到实践经验总结
笔者结合实践经验以近期在负责的复杂表格智能问答为切入点,结合大模型的哲学三问(“是谁、从哪里来、到哪里去”),穿插阐述自己对大模型的一些理解与判断,以及面向公共云LLM的建设模式思考,并分享软件设计+模型算法结合的一些研发实践经验。
|
10天前
|
人工智能 自然语言处理
重要的事情说两遍!Prompt复读机,显著提高LLM推理能力
【10月更文挑战第30天】本文介绍了一种名为“问题重读”(Question Re-reading)的提示策略,旨在提高大型语言模型(LLMs)的推理能力。该策略受人类学习和问题解决过程的启发,通过重新审视输入提示中的问题信息,使LLMs能够提取更深层次的见解、识别复杂模式,并建立更细致的联系。实验结果显示,问题重读策略在多个推理任务上显著提升了模型性能。
23 2
|
20天前
|
JSON 人工智能 算法
探索LLM推理全阶段的JSON格式输出限制方法
文章详细讨论了如何确保大型语言模型(LLMs)输出结构化的JSON格式,这对于提高数据处理的自动化程度和系统的互操作性至关重要。
|
26天前
|
机器学习/深度学习 自然语言处理 测试技术
CoT神话破灭,并非LLM标配!三大学府机构联手证实,CoT仅在数学符号推理有用
【10月更文挑战第16天】近期,加州大学伯克利分校、斯坦福大学和卡内基梅隆大学联合研究发现,链式思维(CoT)方法在数学和符号推理任务中表现优异,但在其他类型任务中效果不明显。这一研究打破了CoT作为大型语言模型(LLM)标配的神话,为重新审视LLM的推理能力提供了新视角。
24 2
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
企业内训|LLM大模型技术在金融领域的应用及实践-某商业银行分行IT团队
本企业培训是TsingtaoAI技术团队专们为某商业银行分行IT团队开发的LLM大模型技术课程。课程深入分析大模型在金融行业中的发展趋势、底层技术及应用场景,重点提升学员在大模型应用中的实际操作能力与业务场景适应力。通过对全球商用 LLM 产品及国内外技术生态的深度对比,学员将了解大模型在不同企业中的发展路径,掌握如 GPT 系列、Claude 系列、文心一言等大模型的前沿技术。针对金融行业的业务需求,学员将学会如何结合多模态技术改进用户体验、数据分析等服务流程,并掌握大模型训练与工具链的实操技术,尤其是模型的微调、迁移学习与压缩技术。
58 2
|
2月前
|
人工智能 Prometheus 监控
使用 NVIDIA NIM 在阿里云容器服务(ACK)中加速 LLM 推理
本文介绍了在阿里云容器服务 ACK 上部署 NVIDIA NIM,结合云原生 AI 套件和 KServe 快速构建高性能模型推理服务的方法。通过阿里云 Prometheus 和 Grafana 实现实时监控,并基于排队请求数配置弹性扩缩容策略,提升服务稳定性和效率。文章提供了详细的部署步骤和示例,帮助读者快速搭建和优化模型推理服务。
162 7
使用 NVIDIA NIM 在阿里云容器服务(ACK)中加速 LLM 推理
|
30天前
|
前端开发 机器人 API
前端大模型入门(一):用 js+langchain 构建基于 LLM 的应用
本文介绍了大语言模型(LLM)的HTTP API流式调用机制及其在前端的实现方法。通过流式调用,服务器可以逐步发送生成的文本内容,前端则实时处理并展示这些数据块,从而提升用户体验和实时性。文章详细讲解了如何使用`fetch`发起流式请求、处理响应流数据、逐步更新界面、处理中断和错误,以及优化用户交互。流式调用特别适用于聊天机器人、搜索建议等应用场景,能够显著减少用户的等待时间,增强交互性。
229 2
|
24天前
|
机器学习/深度学习 人工智能 运维
企业内训|LLM大模型在服务器和IT网络运维中的应用-某日企IT运维部门
本课程是为某在华日资企业集团的IT运维部门专门定制开发的企业培训课程,本课程旨在深入探讨大型语言模型(LLM)在服务器及IT网络运维中的应用,结合当前技术趋势与行业需求,帮助学员掌握LLM如何为运维工作赋能。通过系统的理论讲解与实践操作,学员将了解LLM的基本知识、模型架构及其在实际运维场景中的应用,如日志分析、故障诊断、网络安全与性能优化等。
54 2