微信扫码
与创始人交个朋友
我要投稿
有了输入数据,接下来就来了解数据的计算过程,深度学习的数据计算都是以张量(tensor)为计算单元进行各种计算,而把张量和计算过程组织起来需要用到计算图(computional graph),通过建立计算图可以实现几乎所有的深度学习数据计算,当然,LLM也不例外。
Ollama工程中的“ggml.c/h“模块实现了张量数据结构定义,张量计算,计算图生成和处理,首先来了解张量数据结构定义:
从上图中可以看出,这是一个包含了张量操作的张量数据结构定义,详细解释如下:type,表示张量的数据类型,如浮点数、整数等;backend,表示张量所使用的后端类型,如CPU、GPU等;buffer,与后端相关的缓冲区信息;ne,表示张量在每个维度上的长度;nb,表示张量在每个维度上的字节数,用于计算张量计算所需的内存;op,表示与张量相关的操作类型,如加法、乘法等;op_params,用于存储与操作相关的参数;flags,用于存储张量的特定标志,如是否需要梯度计算等;grad,表示张量的梯度,用于自动微分计算;src,表示生成当前张量的源张量,即张量计算所需要的张量;perf_runs,表示性能测试的运行次数;perf_cycles,表示性能测试中的周期数;perf_time_us,表示性能测试的时间,单位为微秒;view_src,表示当前张量是另一个张量的视图;view_offs,表示视图在源张量中的偏移量;data,指向张量的实际数据;name,张量的名称;extra,用于存储额外的信息,如特定于后端的数据;padding, 8字节填充,用于内存对齐。
ggml定义了一套内存管理机制来存储张量数据,所有的张量在统一的内存中进行存储:
ggml.h的注释中说明了如何利用计算图来实现下面函数计算的过程:
f(x) = a*x^2 + b
第一步:分配张量处理所需的内存:
struct ggml_context * ctx = ggml_init(params);
第二步:建立x、a、b三个张量,其中设置x为参变量:
struct ggml_tensor * x = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, 1);
ggml_set_param(ctx, x); // x is an input variable
struct ggml_tensor * a= ggml_new_tensor_1d(ctx, GGML_TYPE_F32, 1);
struct ggml_tensor * b= ggml_new_tensor_1d(ctx, GGML_TYPE_F32, 1);
第三步:定义两个分别带乘法和加法的两个张量:
struct ggml_tensor * x2 = ggml_mul(ctx, x, x);
struct ggml_tensor * f= ggml_add(ctx, ggml_mul(ctx, a, x2), b);
这样便形成了一个张量计算图:
从上图可以看出张量f嵌套了计算所需的张量和计算方法。
第四步:后序遍历上图中的计算图,得到张量计算图:
struct ggml_cgraph * gf = ggml_new_graph(ctx);
ggml_build_forward_expand(gf, f);
生成的计算图数据存储到如下数据结构中:
从计算图的数据结构中容易发现张量被分成叶子节点张量(leafs)和带操作符的非叶子节点张量(nodes),两种张量被分别存储,由于是后序遍历,nodes存的张量是按计算顺序存储的带操作方法的张量,即只要按顺序遍历nodes即可实现所需函数计算过程。
第五步:设置好叶子张量的数据后即可执行张量计算:
ggml_set_f32(x, 2.0f);
ggml_set_f32(a, 3.0f);
ggml_set_f32(b, 4.0f);
ggml_graph_compute_with_ctx(ctx, &gf, n_threads);
为此,我们了解了计算图的基本使用方法,为后续的LLM代码实现方法的理解扫除了障碍。
53AI,企业落地应用大模型首选服务商
产品:大模型应用平台+智能体定制开发+落地咨询服务
承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-03-30
2024-04-26
2024-05-10
2024-05-28
2024-04-12
2024-04-25
2024-05-14
2024-07-18
2024-08-13
2024-04-26