Appearance
GGML 张量库基础 — 练习
练习 1:构建简单计算图
用 GGML API 构建函数 f(x) = 3x² + 2x + 1,并计算 x = 2.0 时的值。
提示:使用 ggml_mul、ggml_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在不同后端上的实现差异