简化代码
- 代码中ggml_tensor比较重要的三个属性为:
- 原始数据 : void * data
- 维度向量 : ne[20] :
.ne = {3, 2, 1, 1}
, 表示一个3列 2 行的矩阵
- 步长向量 : nb[20]:
.nb = {sizeof(float), sizeof(float) * 3,0, 0},
因为数据被统一转换为了void指针,任何Tensor的数据都是一个void*
的一维数组,只是长度不同。所以设置各维度字节步长,对于区分每个数的具体位置十分重要。
- 代码通过不断执行
ggml_vec_dot_f32
,将从乘数得到的两个向量片段点积,然后通过维度和步长将结果放到结果的data数据正确的位置上。
#include <stdio.h>
#include <stdlib.h> // malloc
#include <cstdint> // int64_t
#include <cassert> // assert
#define restrict
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
enum ggml_type { GGML_TYPE_F32 = 0, GGML_TYPE_F16 = 1, GGML_TYPE_COUNT,};
enum ggml_op { GGML_OP_NONE = 0, GGML_MAX_OP_PARAMS};
enum ggml_task_type {GGML_TASK_INIT ,GGML_TASK_COMP ,GGML_TASK_FINALIZE };
struct ggml_compute_params {
enum ggml_task_type type;
};
// n-dimensional tensor
struct ggml_tensor {
enum ggml_type type;
int64_t ne[20]; // int64_t ne[GGML_MAX_DIMS]; // number of elements
size_t nb[20]; // size_t nb[GGML_MAX_DIMS]; // stride in bytes
void * data;
};
inline static void ggml_vec_dot_f32(const int n, float * restrict s, const float * restrict x, const float * restrict y) {
float sumf = 0.0;// ggml_float sumf = 0.0;
for (int i = 0; i < n; ++i) {// n是向量长度
sumf += x[i]*y[i];
}
printf("%.9f \n", sumf);
*s = sumf;
}
void ggml_compute_forward_mul_mat_f32(
const struct ggml_compute_params * params,
const struct ggml_tensor * src0,
const struct ggml_tensor * src1,
struct ggml_tensor * dst) {
// int64_t t0 = ggml_perf_time_us();
// UNUSED(t0);
// 分别获取源张量src0在四个维度上的元素数量(ne代表number of elements,即元素个数维度相关的属性),后续用于维度相关的判断和计算
const int ne00 = src0->ne[0];
const int ne01 = src0->ne[1];
const int ne02 = src0->ne[2];
const int ne03 = src0->ne[3];
// 同样,获取另一个源张量src1在四个维度上的元素数量,用于后续的处理和维度检查等操作
const int ne10 = src1->ne[0];
const int ne11 = src1->ne[1];
const int ne12 = src1->ne[2];
const int ne13 = src1->ne[3];
// 获取目标张量dst在四个维度上的元素数量,并计算出dst张量总的元素数量,方便后续整体的计算或者遍历等操作
const int ne0 = dst->ne[0];
const int ne1 = dst->ne[1];
const int ne2 = dst->ne[2];
const int ne3 = dst->ne[3];
const int ne = ne0*ne1*ne2*ne3;
// 获取源张量src0在四个维度上每个元素“步长”所占字节数(nb可能代表number of bytes,字节数维度相关属性)
const int nb00 = src0->nb[0];
const int nb01 = src0->nb[1];
const int nb02 = src0->nb[2];
const int nb03 = src0->nb[3];
// 获取源张量src1在四个维度上每个元素“步长”所占字节数
const int nb10 = src1->nb[0];
const int nb11 = src1->nb[1];
const int nb12 = src1->nb[2];
const int nb13 = src1->nb[3];
// 获取目标张量dst在四个维度上每个元素“步长”所占字节数
const int nb0 = dst->nb[0];
const int nb1 = dst->nb[1];
const int nb2 = dst->nb[2];
const int nb3 = dst->nb[3];
assert(ne02 == ne12);
assert(ne03 == ne13);
assert(ne2 == ne12);
assert(ne3 == ne13);
// TODO: we don't support permuted src0
assert(nb00 == sizeof(float) || nb01 == sizeof(float));
// dst cannot be transposed or permuted
assert(nb0 == sizeof(float));
assert(nb0 <= nb1);
assert(nb1 <= nb2);
assert(nb2 <= nb3);
assert(ne0 == ne01);
assert(ne1 == ne11);
assert(ne2 == ne02);
assert(ne3 == ne03);
#if defined(GGML_USE_ACCELERATE) || defined(GGML_USE_OPENBLAS)
#endif
if (nb01 >= nb00) {// 当src0张量是未转置情况(nb01 >= nb00)
assert(nb10 == sizeof(float));
// total rows in src0 src0(第一个乘数张量)总的行数(n