没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
试读
42页
内容概要:本文首先梳理了一下FastLLM的调用链和关键的数据结构,然后解析了 FastLLM 的一些实现细节和CPU/GPU后端实现采用的优化技巧。 LLMSampling实现了一种基于温度和惩罚的采样策略,用于从给定的 logits 中选择一个 id。这种采样的方法可以控制输出文本的多样性。本资源以chatglm-6b的支持为例,从开发者角度通过大量源代码(Java语言描述)对大模型部署框架FastLLM 的实现细节进行解析。 适用人群:大模型爱好者;大模型技术研究人员;开发人员 使用场景:大模型框架FastLLM的应用 目标:通过对本资源的学习,深入理解并熟练掌握FastLLM框架的原理及使用,并对其CPU及GPU算子算法有深入的理解,训练出更为智能的机器人。
资源推荐
资源详情
资源评论
极市导读
本 文 首 先 梳 理 了 一 下 FastLLM 的 调 用 链 和 关 键 的 数 据 结 构 , 然 后 解 析 了 FastLLM 的 一 些
实 现 细 节 和 CPU/GPU 后 端 实 现 采 用 的 优 化 技 巧 。
0x0. 前言
这篇文章首先梳理了一下 FastLLM 的调用链和关键的数据结构,然后解析了 FastLLM 的
一些实现细节和 CPU/GPU 后端实现采用的优化技巧。
0x1. 调用链和数据结构解析
以 chatglm-6b 的支持为例,函数入口在 https://github.com/ztxz16/fastllm/blob/mast
er/src/models/chatglm.cpp#L626 ,这里的 input 就是输入的 context(string 类
型)。然后 https://github.com/ztxz16/fastllm/blob/master/src/models/chatglm.cpp
#L633 这行代码对 input 进行 tokenizer encode 并构造好 inputIds,再构造好 attenti
onMask 之后就可以给 Forward 函数推理,拿到推理结果之后再使用 tokenizer 进行 decode
得到输出。
在这里,inputIds 和 attentionMask 都是 Data 数据类型,类比于 PyTorch 的 Tensor,
来对输入数据以及 device,shape 等信息进行统一管理。下面的代码展示了 Data 数据结
构的定义,源码在:https://github.com/ztxz16/fastllm/blob/master/include/fastllm.h
#L201-L286
class Data {
public:
bool lockInCPU = false; // 如果 lock 在 CPU 上,那么不允许移动到其余设备
WeightType weightType = WeightType::NONE; // 权重类型,NONE 代表非权重(或未知权重)
DataType dataType = DataType::FLOAT32; // 数据类型
int unitSize, unitSizeDiv = 1; // 单个元素的字节数 = unitSIze / unitSizeDiv
std::vector <int> dims; // 数据形状
std::vector <uint64_t> strides; // 跨度
uint64_t expansionSize = 0; // 扩容后的尺寸
uint64_t expansionBytes = 0; // 扩容后的字节数
std::vector <int> expansionDims; // 预扩容的形状
uint8_t *cpuData = nullptr; // 数据指针
void *cudaData = nullptr;
std::vector <void*> extraCudaData;
void *deviceData = nullptr;
std::vector <void*> extraDeviceData;
DataDevice dataDevice = DataDevice::CPU;
// 这两个参数用于量化,对 FLOAT 数据不适用
int perChannelAxis = -1; // 沿哪个轴分通道量化,-1 代表没有分通道
std::vector <LowBitConfig> perChannelsConfigs; // perChannelsConfigs[i]代表第 i 个通道的
min, max; 如果没有分通道,perChannelsConfigs[0]代表全局 min, max
std::vector <float> scales, mins;
std::vector <int> zeros;
std::vector <int> weightSum; // 作为权重时,有时候需要存一些和加速计算
std::string fileName;
long long filePos;
std::shared_ptr<FileMmap> m_file;
Data () {};
Data (DataType type);
Data (DataType type, const std::vector <int> &dims); // 构造函数
// 构造函数,创建好之后从 data 复制数据
// data 中是原始数据,如果 type 不是 float 那么需要量化
Data (DataType type, const std::vector <int> &dims, const std::vector <float> &data);
~Data(); // 析构函数
Data (const Data &ori); // 深拷贝
void CopyFrom(const Data &ori); // 复制
uint64_t GetBytes() const; // 获取总字节数
void Allocate(); // 分配内存
void Allocate(float v); // 分配内存并初始化
void Expansion(const std::vector <int> &dims); // 预扩容到相应尺寸
void MallocSpace(uint64_t size); // 在设备上分配
void FreeSpace(); // 回收设备上的内存
void UpdateUnitSize(); // 更新 unitSize
void Resize(const std::vector <int> &dims); // 更改尺寸
void Reshape(const std::vector <int> &dims); // 更改尺寸,但不修改数据
uint64_t Count(int i) const; // dims[i] * strides[i]
void PrintShape() const; // 输出形状
void Print() const; // 输出
void CalcWeightSum(); // 计算 WeightSum
void ToDevice(DataDevice device); // 移动到指定 device
void ToDevice(void *device);
void set_file(std::shared_ptr<FileMmap> file) {
m_file = file;
}
};
在 Forward 函数里面,以 Data 为核心载体,运行 chatglm-6b 模型的流程,具体包含如
下的一些算子:https://github.com/ztxz16/fastllm/blob/master/include/fastllm.h#L3
46-L408 。以 Permute 为例我们浏览下它的实现:
void Permute(const Data &input, const std::vector<int> &axis, Data &output) {
Data axisData = Data(DataType::INT32PARAM, {(int)axis.size()});
axisData.Allocate();
for (int i = 0; i < axisData.Count(0); i++) {
((int32_t*)axisData.cpuData)[i] = axis[i];
}
curExecutor->Run("Permute", {
{"input", (Data*)&input}, {"axis", &axisData}, {"output", (Data*)&output}
}, {}, {});
}
这里的 curExecutor 负责根据 FastLLM 编译开启的后端选项把算子 Dispatch 到不同的 dev
ice 进行执行,{"input", (Data*)&input}, {"axis", &axisData}, {"output", (Data*)
&output}} 这行代码表示的是一个 DataDict 对象,也就是一个值为 data 的字典,原始定
义为 typedef std::map <std::string, Data*> DataDict;。接着我们看一下 curExecuto
r 的定义和实现:
namespace fastllm {
class Executor {
private:
std::vector <BaseDevice*> devices;
std::map <std::string, float> profiler;
public:
Executor (); // 创建默认的 Executor
~Executor(); // 析构
void ClearDevices(); // 清空 devices
void AddDevice(BaseDevice *device); // 增加一个 device
// 运行一个 op
void Run(const std::string &opType, const fastllm::DataDict &datas, const fastllm::FloatDict
&floatParams,
const fastllm::IntDict &intParams);
void ClearProfiler();
void PrintProfiler();
};
}
从 Executor 类的定义我们可以判断它负责了在设定的 devices 上根据 opType 和输入数据
等执行 Op 的前向计算,也就是 Run 这个接口。由于 Executor 类是 FastLLM 的调度核心
实现,所以我们来详细解析一下它的实现。
namespace fastllm {
Executor::Executor() {
this->devices.clear();
#ifdef USE_CUDA
// 将一个指向 CudaDevice 类对象的指针插入到 devices 向量的末尾。
// 这里通过 new 运算符创建了一个 CudaDevice 对象,并将返回的指针进行类型转换为 BaseDevice* 类型。
this->devices.push_back((BaseDevice*) new CudaDevice());
#endif
this->devices.push_back((BaseDevice*) new CpuDevice());
}
Executor::~Executor() {
// 释放 devices 向量中的每个指针元素所占用的内存。
for (int i = 0; i < devices.size(); i++) {
delete devices[i];
}
}
void Executor::ClearDevices() {
// this->devices 指的是当前对象的 devices 成员,即指向 BaseDevice 类对象的指针向量。
this->devices.clear();
}
// 该函数用于向 devices 向量中添加一个指向 BaseDevice 类对象的指针。
void Executor::AddDevice(fastllm::BaseDevice *device) {
this->devices.push_back(device);
}
void Executor::Run(const std::string &opType, const fastllm::DataDict &datas, const fastllm::Flo
atDict &floatParams,
const fastllm::IntDict &intParams) {
// 创建一个 st 变量,用于记录函数开始执行的时间。
auto st = std::chrono::system_clock::now();
// 创建一个布尔变量 lockInCPU,用于记录是否将数据锁定在 CPU 上。
bool lockInCPU = false;
// 在第一个 for 循环中,遍历数据字典 datas,查找是否有 "___batch" 后缀的参数,
// 并根据情况设置 lockInCPU 的值。it.first 是数据字典中的键(key),it.second
// 是对应的值(value)。如果存在 "___batch" 后缀的参数,则将 lockInCPU 设置为
剩余41页未读,继续阅读
资源评论
小小哭包
- 粉丝: 1902
- 资源: 3893
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 前端-html+css+js实现爱心特效
- c40539bc-071a-486c-9d52-9d0c18d62dac 4.html
- 基于物理的非视域成像(NLOS)算法,利用了nerf+python源码+文档说明
- yuluer知更鸟.7z(1).001
- 基于Qt实现医院信息管理系统c++源码+文档说明+数据库(期末大作业)
- 基于python实现的医院信息管理系统完整源码+sql数据库+详细注释(高分课程设计)
- 基于python的眼底图像视杯视盘分割项目源码+文档说明+截图演示+详细注释(高分课程设计)
- ImageBasedModellingEdu-贰壹贰叁零
- DFFmeasurement-数据预处理
- ImageBasedModellingEdu-回文素数c语言
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功