Skip to content

GGML 张量库基础 — 练习

练习 1:构建简单计算图

用 GGML API 构建函数 f(x) = 3x² + 2x + 1,并计算 x = 2.0 时的值。

提示:使用 ggml_mulggml_add 等操作。

参考答案
c
struct ggml_init_params params = {
    .mem_size = 16 * 1024 * 1024,
    .mem_buffer = NULL,
};
struct ggml_context * ctx = ggml_init(params);

struct ggml_tensor * x = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, 1);
ggml_set_name(x, "x");

// 常量
float val_3 = 3.0f, val_2 = 2.0f, val_1 = 1.0f;
struct ggml_tensor * c3 = ggml_new_f32(ctx, val_3);
struct ggml_tensor * c2 = ggml_new_f32(ctx, val_2);
struct ggml_tensor * c1 = ggml_new_f32(ctx, val_1);

// 3x² + 2x + 1
struct ggml_tensor * x2 = ggml_mul(ctx, x, x);
struct ggml_tensor * term1 = ggml_mul(ctx, c3, x2);
struct ggml_tensor * term2 = ggml_mul(ctx, c2, x);
struct ggml_tensor * f = ggml_add(ctx, ggml_add(ctx, term1, term2), c1);

// 设置 x = 2.0 并计算
((float *)x->data)[0] = 2.0f;
struct ggml_cgraph * graph = ggml_new_graph(ctx);
ggml_build_forward_expand(graph, f);
ggml_graph_compute(graph);
// 结果: ((float *)f->data)[0] == 17.0

练习 2:理解张量内存布局

创建一个 shape 为 [4, 3] 的 F32 张量,验证 nb[0]nb[1] 的值。

参考答案
c
struct ggml_tensor * t = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, 4, 3);
// t->ne[0] = 4, t->ne[1] = 3
// t->nb[0] = sizeof(float) = 4 bytes
// t->nb[1] = 4 * 4 = 16 bytes (一行的大小)

练习 3:矩阵乘法维度分析

给定 A: [m, k]B: [k, n],使用 ggml_mul_mat(ctx, A, B) 后结果的 shape 是什么?

参考答案

ggml_mul_mat(ctx, A, B) 计算的是 B @ A^T,即 [k, n] @ [k, m]^T = [k, n] @ [m, k]

实际上 GGML 的 ggml_mul_mat 结果 shape 是 [m, n]

  • A: ne[0]=k, ne[1]=m (在 GGML 中是列主序视角)
  • B: ne[0]=n, ne[1]=k
  • 结果: ne[0]=n, ne[1]=m

这是因为 GGML 中 ggml_mul_mat(A, B) 等价于 B^T @ A 的转置形式。具体行为需看 GGML 的定义:ggml_mul_mat(A, B) = sum(A[i][k] * B[j][k]),结果为 [ne0_A, ne0_B] = [m, n]

拓展挑战

  • 使用自动微分计算 f(x) = x²x = 3.0 处的梯度
  • 阅读量化类型 Q4_0 的 block 结构,理解 4.5 bits/weight 的计算方式
  • 对比 ggml_mul_mat 在不同后端上的实现差异