FasterTransformer vs. GPT
1. 什么是 GPT?
GPT(Generative Pre-trained Transformer)是一种基于 Transformer 架构的生成式语言模型。GPT 的核心特点是:
- 自回归生成:GPT 使用自回归方式生成文本,即给定一段文本,模型会逐字逐句地生成下一个词。
- 单向上下文建模:GPT 只关注当前词及其之前的上下文,这意味着在生成每个词时,模型只能利用其左侧的上下文信息。
- 多用途生成模型:GPT 的主要应用包括文本生成、对话系统、文本补全等任务。
GPT 的实现基于标准的 Transformer 架构,通过大量未标注文本的预训练,然后在特定任务上进行微调。
2. 什么是 FasterTransformer?
FasterTransformer 是由 NVIDIA 开发的一种专注于加速 Transformer 模型推理的优化库。它与 GPT 在功能和目标上有显著区别。FasterTransformer 并不是一个模型,而是一套针对 Transformer 模型的高性能推理库,主要特点包括:
-
高效推理加速:FasterTransformer 通过在 GPU 上实现高效的内核函数,并充分利用 CUDA、TensorRT 等 NVIDIA 技术,显著加速了 Transformer 模型的推理速度。
-
支持多种 Transformer 模型:它支持 GPT、BERT、T5 等多种流行的 Transformer 模型,且可以通过优化这些模型的计算过程,减少推理时间。
-
低延迟和高吞吐量:通过对计算和内存访问模式的优化,FasterTransformer 提供了低延迟和高吞吐量的推理性能,这对于大规模模型部署和实时推理场景尤为重要。
-
模型并行和张量并行:FasterTransformer 支持模型并行和张量并行技术,使得在多 GPU 环境下可以更有效地分配计算任务,从而进一步提升推理速度。
3. FasterTransformer 的原理
FasterTransformer 通过以下几个方面提升 Transformer 模型的推理性能:
-
Layer Fusion:将多层的计算过程融合在一起,减少内存带宽的需求和中间数据的存取,从而加速计算。
-
精度优化:支持混合精度(FP16/INT8)计算,使得在保持合理精度的同时,显著提升推理速度。
-
优化内核函数:使用高度优化的 CUDA 核函数来加速矩阵乘法、Softmax、LayerNorm 等关键操作。
-
内存优化:通过减少内存拷贝和优化内存访问模式来提升整体推理效率。
-
多线程并行化:在多 GPU 环境下,通过并行化的方式分配计算任务,充分利用硬件资源。
4. FasterTransformer 与 GPT 的区别
-
目标和用途:
- GPT:是一种生成模型,主要用于文本生成等任务。
- FasterTransformer:是一个专注于加速 Transformer 模型推理的库,主要用于提高 Transformer 模型的执行效率。
-
功能和应用场景:
- GPT:用于语言生成、对话系统、文本补全等生成式任务。
- FasterTransformer:用于加速现有的 Transformer 模型(包括 GPT)的推理过程,适用于需要高效推理的生产环境。
-
架构和实现:
- GPT:基于标准 Transformer 架构,主要专注于模型训练和生成。
- FasterTransformer:通过优化计算内核、混合精度计算、内存管理等技术,提升 Transformer 模型的推理性能。
总结
FasterTransformer 和 GPT 是两个不同层面的技术,一个是加速工具库,另一个是生成模型。FasterTransformer 通过多种优化技术,显著提升了 Transformer 模型(如 GPT)的推理效率,使得这些模型在实际应用中能够以更低的延迟、更高的吞吐量完成任务。
范例代码解释
这段代码实现了一个基于NVIDIA FasterTransformer库的BERT模型在Triton推理服务中的使用示例。以下是代码的详细解释:
1. 头文件引入和命名空间
cpp
#include <thread>
#include "3rdparty/INIReader.h"
#include "src/fastertransformer/triton_backend/bert/BertTritonModel.h"
#include "src/fastertransformer/utils/mpi_utils.h"
#include "src/fastertransformer/utils/nccl_utils.h"
#include "src/fastertransformer/utils/nvtx_utils.h"
namespace ft = fastertransformer;
- 引入了一些必需的头文件,包括线程库、INI文件解析器、BERT模型的Triton后端实现、MPI(Message Passing Interface)工具、NCCL(NVIDIA Collective Communication Library)工具和NVTX工具。
ft
是fastertransformer
命名空间的缩写。
2. broadcastRequest
函数
cpp
template<typename T>
std::vector<std::shared_ptr<std::unordered_map<std::string, triton::Tensor>>>
broadcastRequest(const std::vector<T>& h_input_hidden_state,
const std::vector<int>& h_input_seq_len,
const size_t request_batch_size,
const size_t request_seq_len,
const size_t head_num,
const size_t size_per_head,
const int node_id,
const int gpu_count,
std::vector<void*>* pointer_record)
- 该函数用于将请求(即输入数据)广播到多个GPU设备上。
h_input_hidden_state
和h_input_seq_len
分别是输入的隐藏状态和序列长度。request_batch_size
和request_seq_len
定义了请求的批处理大小和序列长度。head_num
和size_per_head
是模型的超参数,分别表示注意力头的数量和每个头的维度大小。node_id
是节点ID,gpu_count
是使用的GPU数量。pointer_record
用于记录设备内存分配的指针,以防止这些指针在函数退出时被释放。
函数步骤:
- 为每个GPU设置设备上下文并分配内存。
- 将数据从主机传输到设备(即 GPU )上。
- 创建请求的
triton::Tensor
并将其添加到请求列表中。 - 返回包含请求的列表。
3. prepareRequest
函数
cpp
template<typename T>
std::vector<std::shared_ptr<std::unordered_map<std::string, triton::Tensor>>>
prepareRequest(std::string ini_name, const int node_id, const int gpu_count, std::vector<void*>* pointer_record)
- 该函数读取配置文件(
.ini
)并根据配置准备请求。 - 使用
INIReader
读取配置文件,提取批处理大小、序列长度、模型名称、模型目录等信息。 - 根据读取的配置生成随机的隐藏状态和序列长度,调用
broadcastRequest
函数,将生成的请求广播到多个GPU。
4. threadCreateModelInstances
函数
cpp
int threadCreateModelInstances(std::shared_ptr<AbstractTransformerModel> model,
std::vector<std::unique_ptr<AbstractTransformerModelInstance>>* model_instances,
const int device_id,
const int rank,
std::pair<std::vector<ft::NcclParam>, std::vector<ft::NcclParam>> nccl_params,
std::shared_ptr<ft::AbstractCustomComm> custom_all_reduce_comm = nullptr)
- 该函数在给定的GPU设备上创建模型实例。
model
是一个AbstractTransformerModel
对象,model_instances
是存储模型实例的容器。device_id
表示当前设备ID,rank
是全局排名,nccl_params
包含NCCL通信参数,custom_all_reduce_comm
是自定义的All-Reduce通信器。- 主要步骤包括:
- 设置当前设备上下文。
- 创建CUDA流。
- 使用NCCL初始化模型的共享权重。
- 创建模型实例并将其存储到
model_instances
中。
5. threadForward
函数
cpp
int threadForward(std::unique_ptr<AbstractTransformerModelInstance>* model_instance,
std::shared_ptr<std::unordered_map<std::string, triton::Tensor>> request,
std::shared_ptr<std::unordered_map<std::string, triton::Tensor>>* output_tensors,
const int device_id)
- 该函数执行模型的前向传播。
model_instance
是模型的具体实例,request
是输入请求,output_tensors
用于存储输出张量。- 设置当前设备上下文后,执行前向传播并将结果存储在
output_tensors
中。
6. bert_triton_example
模板函数
cpp
template<typename T>
int bert_triton_example(int argc, char* argv[])
- 这是BERT模型在Triton推理服务中的主流程函数,使用模板以支持不同数据类型(如
float
和half
)。 - 主要步骤:
- 初始化MPI和NCCL。
- 从配置文件中读取超参数并创建BERT模型。
- 初始化NCCL通信器并创建模型实例。
- 准备请求并调用前向传播函数。
- 测量前向传播的性能并打印结果。
7. main
函数
cpp
int main(int argc, char* argv[])
{
std::string ini_name = argc >= 2 ? std::string(argv[1]) : "../examples/cpp/bert/bert_config.ini";
INIReader reader = INIReader(ini_name);
if (reader.ParseError() < 0) {
std::cout << "[ERROR] Can't load '" << ini_name << "'\n";
ft::FT_CHECK(false);
}
const std::string data_type = reader.Get("ft_instance_hyperparameter", "data_type");
if (data_type == "fp32") {
bert_triton_example<float>(argc, argv);
}
else if (data_type == "fp16") {
bert_triton_example<half>(argc, argv);
}
return 0;
}
main
函数首先读取配置文件,并根据配置文件中的data_type
字段选择使用float
或half
类型的数据进行BERT模型的推理。
8. 代码总结
- 该代码通过使用FasterTransformer库,实现了BERT模型在Triton推理服务中的高效推理。
- 代码主要展示了如何使用MPI和NCCL进行多GPU设备之间的通信和同步,以实现模型的并行化。
- 整个推理过程包括模型的初始化、数据的准备、前向传播以及性能测试。
这段代码展示了如何将BERT模型部署在高性能计算环境中,并结合Triton服务进行推理加速,是大规模深度学习模型部署的一个优秀示例。