Skip to content

lemin9538/llmc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

llmc — 从零写一个大模型推理引擎(配套代码)

这是文章系列《从零写一个大模型推理引擎》的配套代码。目标:用 纯 C 跑通 Qwen2.5-0.5B-Instruct 的完整推理,只追求正确、可读,不追求性能。

整条链路都在 C 里:chat template → tokenizer → forward(+KV cache) → 采样 → detokenize。运行时只吃一个 .bin 文件,不依赖 Python、不读外部分词文件。 Python 只在离线转换时跑一次,把权重和分词器一起打进 .bin

选 0.5B 而不是 7B:纯 C 朴素实现跑 7B 太慢;0.5B 在 CPU 上可交互,最适合学习。

代码风格遵循 Linux 内核约定:Tab 缩进、struct(不 typedef)、每个算子一个函数、 返回负 errno 表示错误。所有算子以 struct tensor 作为输入输出。

目录

文件 说明
tensor.h / tensor.c 张量结构体 + 基础算子(matmul/add/prod/rmsnorm/silu/softmax/argmax/embedding_lookup)
model.h / model.c 模型加载、KV cache、完整前向(embedding/RoPE/GQA/SwiGLU)
tokenizer.h / tokenizer.c byte-level BPE 分词器(词表/合并规则随 bin 加载)
infer.c 交互式多轮对话驱动(chat template + greedy 解码)
test.c 基础算子的最小自测
convert.py 把 HF Qwen2.5 权重 + 分词器打成一个 .bin
Makefile 构建与自测

一、准备模型(一次性)

1. 安装 git-lfs(权重是 LFS 大文件,必须先装)

# macOS
brew install git-lfs
# Debian/Ubuntu
# sudo apt-get install git-lfs
git lfs install

2. 下载 Qwen2.5-0.5B-Instruct

git clone https://www.modelscope.cn/Qwen/Qwen2.5-0.5B-Instruct.git

下载完应能看到 model.safetensors(约 942MB,确认不是几百字节的 LFS 指针文件)。

3. 转成 llmc 的 bin(权重 + 分词器一体)

pip install numpy
python3 convert.py ./Qwen2.5-0.5B-Instruct qwen2.5-0.5b.bin

转换脚本把所有"麻烦事"都放在 Python 侧:自己解析 safetensors(仅依赖 numpy)、 bf16→fp32、把 HF 的 [out, in] 线性层权重转置成约定的 [in, out]、处理 tie_word_embeddings、并把 vocab/merges 写进 bin。生成的 fp32 文件约 2.3GB。

二、构建与运行

make            # 编译 infer,并运行基础算子自测 run_test
./infer qwen2.5-0.5b.bin

然后在 你> 后输入问题,回车即可对话;空行或 Ctrl-D 退出。例如:

你> 你好,请用一句话介绍你自己
助手> 我是来自阿里云的超大规模语言模型,我叫通义千问。

可选参数:./infer qwen2.5-0.5b.bin <max_new> 控制单轮最大生成 token 数。

只跑算子自测:make test,期望全部 [ok]、末行 all tests passed

三、二进制格式 v2(小端)

magic[4] = "LLMC"
int32 version = 2

# 配置头
int32 hidden_size, num_hidden_layers, num_attention_heads, num_key_value_heads
int32 head_dim, intermediate_size, vocab_size, max_position_embeddings
float rope_theta, rms_norm_eps

# 张量表
int32 n_tensors
repeat:
    int32 name_len; char name[name_len]
    int32 rows, cols
    float data[rows * cols]      # 行优先 fp32,线性层已是 [in, out]

# 分词器段(v2 新增)
int32 bos_id, eos_id, eos_id2
int32 n_vocab
repeat:
    uint8 is_special; int32 len; char piece[len]
int32 n_merges
repeat:
    int32 len_a; char a[len_a]; int32 len_b; char b[len_b]

四、设计约定

  • 只用 fp32,张量二维行优先连续布局,不支持 stride。
  • 权重布局统一为 Y = X @ WW[in, out],运行时不做转置。
  • matmul 累加器用 fp32,保证数值稳定。
  • KV cache:每层一块 [capacity, num_kv_heads*head_dim] 内存(用 tensor 表示), 每个新 token 追加一行,多轮对话复用同一份 cache。
  • chat template / 特殊 token 按 Qwen2.5 硬编码,只支持本模型。
  • 分词预处理为务实近似:ASCII 精确分类,非 ASCII 一律按"字母"处理, 对中英文绝大多数情况与 HF 一致。

五、已知限制(后续文章会逐步优化)

  • 朴素三层循环 matmul、单线程、无 SIMD/BLAS,速度有限。
  • 采样目前是 greedy(argmax),后续会加 temperature / top-k / top-p。
  • 上下文容量在 infer.c 里固定为 CTX(默认 4096)。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages