从FasterTransformer源码解读开始了解大模型(2.1)代码通读02

2024-06-17 03:28

本文主要是介绍从FasterTransformer源码解读开始了解大模型(2.1)代码通读02,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

从FasterTransformer源码解读开始了解大模型(2.0)代码解读02-初始化和forward

写在前面的话

本篇的内容主要是介绍ParallelGpt.cc中的代码内容,首先介绍一些初始化和工具函数,然后会从forward主函数开始介绍一部分。

零、初始化initialize和allocateBuffer

打开src/fastertransformer/models/multi_gpu_gpt/ParallelGpt.cc文件,这里是GPT的真正的处理推理请求的功能函数。在这个文件的fastertransformer namespace中,第一个函数是用于做一些初始化的函数initialize,从31到87行,主要是创建了三个对象,gpt_context_decoder是用于做ContextDecoder或者说Encoder部分的,gpt_decoder是用于做Decoder的,而进行采样和结果生成的是DynamicDecodeLayer部分。这三个部分我们会在后续的代码解读中展开说明。

第95行到202行是allocateBuffer函数,在每次处理一个推理请求时,都会使用allocateBuffer进行显存的分配和内存的分配。这里挑出几个比较有特点的buffer进行简单讲解。

在109行,计算了一个变量为self_cache_size,大小是*(num_layer / pipeline_para_.world_size) * batchxbeam * memory_len * hidden_units_ / tensor_para.world_size_,这个实际上就是计算KV Cache的大小。而134和135行就用该数值的大小进行了KV Cache的分配。

const size_t self_cache_size =(num_layer_ / pipeline_para_.world_size_) * batchxbeam * memory_len * hidden_units_ / tensor_para_.world_size_;

llm小知识-KV Cache:我们知道,在Attention注意力得分的计算过程中,对于当前的token i,需要先计算出查询结果Qi,Ki和Vi,然后使用Qi与token i 之前的所有token的K结果和V结果来进行注意力得分计算,就是拿Qi与所有的K(0-i)点积求和,再与V(0-i)进行加权求和,最终求得Attention注意力得分。那么在这个过程中,可以通过将之前所有计算过的Ki和Vi进行存储的方式,来减少计算量(用显存空间换时间),那么这部分用于存储KV的就是KVCache。目前有一些量化算法也会关注于KV的量化以减少存储空间

在163行的context_decoder_input_buf_,这块buff被分配的大小为sizeof(T) * batchxbeam * max_input_len * hidden_units,这块buff大小为每一个输入token的大小乘以隐藏状态的大小,同样大小的buff还有context_decoder_output_buf,context_decoder_normed_input_buf等,这个大小是在ContextDecoder进行计算流程时真正的隐藏状态的大小(可以参考前几章中的decoder-only模型结构)所以会多次出现。

context_decoder_input_buf_  = (T*)(allocator_->reMalloc(context_decoder_input_buf_, sizeof(T) * batchxbeam * max_input_len * hidden_units_, false));

类似的还有120行的decoder_input_buf变量,大小为sizeof(T) * batchxbeam * hidden_units,相比较之下少了一个max_input_len大小维度,由于Decoder每一步只生成一个token所以相当于长度始终为1,少了一个输入长度的维度。与decoder_input_buf大小相同的还有decoder_normed_input_buf,decoder_output_buf等等。

decoder_input_buf_ = (T*)(allocator_->reMalloc(decoder_input_buf_, sizeof(T) * batchxbeam * hidden_units_, false));decoder_normed_input_buf_ =(T*)(allocator_->reMalloc(decoder_normed_input_buf_, sizeof(T) * batchxbeam * hidden_units_, false));decoder_output_buf_ =(T*)(allocator_->reMalloc(decoder_output_buf_, sizeof(T) * batchxbeam * hidden_units_, false));

在204到271行,是与allocateBuffer对应的freeBuffer函数,对指针中分配了的空间进行释放,这一段没有特别值得讲解的地方。

一、forward函数-起始检查

ParallelGpt.cc文件中拥有两个forward函数,我们主要看574行开始的forward函数。

进入forward函数后,首先通过FT_CHECK的多个宏定义检查了输入tensor的数量以及对几个比较重要的输入tensor进行了输入形状检查。

		FT_CHECK_WITH_INFO(input_tensors->size() >= 3, "input_tensors->size() >= 3");FT_CHECK_WITH_INFO(output_tensors->size() >= 2, "output_tensors->size() >= 2");FT_CHECK(input_tensors->at("input_ids").shape.size() == 2);FT_CHECK(input_tensors->at("input_lengths").shape.size() == 1);FT_CHECK(input_tensors->find("output_seq_len") != input_tensors->end()&& input_tensors->at("output_seq_len").shape.size() == 1);FT_CHECK(output_tensors->at("output_ids").shape.size() == 3);FT_CHECK(output_tensors->at("sequence_length").shape.size() == 2);FT_CHECK_WITH_INFO(input_tensors->at("input_ids").shape[0] == output_tensors->at("output_ids").shape[0],"input_tensors->at(\"input_ids\").shape[0] == output_tensors->at(\"output_ids\").shape[0]");// Used when inputs do not contain random_seedconst size_t batch_size = output_tensors->at("output_ids").shape[0];const size_t beam_width = output_tensors->at("output_ids").shape[1];FT_CHECK_WITH_INFO(output_tensors->count("cum_log_probs") == 0|| output_tensors->at("cum_log_probs").size() == batch_size * beam_width,"The shape of cum_log_probs should match with batch_size x beam_width if provided.");

对于输入input_tensors来说,必须要有input_ids,input_lengths,output_seq_len这三个必备的输入,而对于output_tensors来说,则必须要有output_ids和sequence_length这两个必备的输出。这几个tensor的含义和形状如下所示(B指的是batch size,S指的是Sequence length, bz指的是beam width)

tensor名称形状含义
input_idsB x S需要推理的所有token ids,总共batch size个句子
input_lengthsB长度为batch size的数组,每个位置标记着对应位置的token ids长度为多少
output_seq_lenB长度为batch size的数组,每个位置标记着对应位置句子的输入最长到多少
output_idsB x bw x S推理完成的所有token ids,总共batch size个句子
sequence_lengthB x bw推理完成后所有句子的长度,每个位置标记着对应位置的句子长度

llm小知识-batch size:大部分的推理引擎都会将多个请求(可能每个请求只包含一个句子)打包为一个batch来进行推理,在推理过程中同一batch的句子之间是完全可以做到互不干扰的,打batch的一个非常明显的优点是可以充分发挥硬件的算力,同时处理多个请求。另外需要注意的一点是,在batch中,可能会出现长短不一的情况,这个时候是需要在短的句子后面做padding的,这一步往往是会在客户端或者server侧前端就完成好,在推理侧拿到的数据往往是已经做好padding的

如图是一个batch_size为4的推理请求,其中除了最长的句子以外其他的句子都做了padding
在这里插入图片描述

完成了输入形状的检查之后,根据不同的输出要求,还需要对cum_log_probs的tensor进行检查。这一步是对完成推理后是否要返回生成的logits进行开关设置检查。

在645行可以看见,max_input_length的设置是取出input_ids的第二个维度长度,这也是建立在短的输入是做了padding的基础认知之上的。

在647行可以看见,这里对continue gen进行了一个取出,这个参数是用于控制是否进行多轮持续生成的,但实际使用情况中并不会经常使用到continues gen,会对整体的推理服务使用产生较多的限制。

下一回预告

下一回继续讲解forward函数中的多个步骤,在代码解读中会跳过一些不常用的和并不是很重要的参数,按照顺序对比较重要的部分进行分析

这篇关于从FasterTransformer源码解读开始了解大模型(2.1)代码通读02的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/1068356

相关文章

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

Java中Map.Entry()含义及方法使用代码

《Java中Map.Entry()含义及方法使用代码》:本文主要介绍Java中Map.Entry()含义及方法使用的相关资料,Map.Entry是Java中Map的静态内部接口,用于表示键值对,其... 目录前言 Map.Entry作用核心方法常见使用场景1. 遍历 Map 的所有键值对2. 直接修改 Ma

深入解析 Java Future 类及代码示例

《深入解析JavaFuture类及代码示例》JavaFuture是java.util.concurrent包中用于表示异步计算结果的核心接口,下面给大家介绍JavaFuture类及实例代码,感兴... 目录一、Future 类概述二、核心工作机制代码示例执行流程2. 状态机模型3. 核心方法解析行为总结:三

Nacos注册中心和配置中心的底层原理全面解读

《Nacos注册中心和配置中心的底层原理全面解读》:本文主要介绍Nacos注册中心和配置中心的底层原理的全面解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录临时实例和永久实例为什么 Nacos 要将服务实例分为临时实例和永久实例?1.x 版本和2.x版本的区别

python获取cmd环境变量值的实现代码

《python获取cmd环境变量值的实现代码》:本文主要介绍在Python中获取命令行(cmd)环境变量的值,可以使用标准库中的os模块,需要的朋友可以参考下... 前言全局说明在执行py过程中,总要使用到系统环境变量一、说明1.1 环境:Windows 11 家庭版 24H2 26100.4061

pandas实现数据concat拼接的示例代码

《pandas实现数据concat拼接的示例代码》pandas.concat用于合并DataFrame或Series,本文主要介绍了pandas实现数据concat拼接的示例代码,具有一定的参考价值,... 目录语法示例:使用pandas.concat合并数据默认的concat:参数axis=0,join=

C#代码实现解析WTGPS和BD数据

《C#代码实现解析WTGPS和BD数据》在现代的导航与定位应用中,准确解析GPS和北斗(BD)等卫星定位数据至关重要,本文将使用C#语言实现解析WTGPS和BD数据,需要的可以了解下... 目录一、代码结构概览1. 核心解析方法2. 位置信息解析3. 经纬度转换方法4. 日期和时间戳解析5. 辅助方法二、L

Python使用Code2flow将代码转化为流程图的操作教程

《Python使用Code2flow将代码转化为流程图的操作教程》Code2flow是一款开源工具,能够将代码自动转换为流程图,该工具对于代码审查、调试和理解大型代码库非常有用,在这篇博客中,我们将深... 目录引言1nVflRA、为什么选择 Code2flow?2、安装 Code2flow3、基本功能演示

C++类和对象之默认成员函数的使用解读

《C++类和对象之默认成员函数的使用解读》:本文主要介绍C++类和对象之默认成员函数的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、默认成员函数有哪些二、各默认成员函数详解默认构造函数析构函数拷贝构造函数拷贝赋值运算符三、默认成员函数的注意事项总结一

详解如何使用Python从零开始构建文本统计模型

《详解如何使用Python从零开始构建文本统计模型》在自然语言处理领域,词汇表构建是文本预处理的关键环节,本文通过Python代码实践,演示如何从原始文本中提取多尺度特征,并通过动态调整机制构建更精确... 目录一、项目背景与核心思想二、核心代码解析1. 数据加载与预处理2. 多尺度字符统计3. 统计结果可