webassembly003 ggml GGML Tensor Library part-4 矩阵乘法的实现

简化代码

  • 代码中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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值