# 薄荷Transformer网络训练器
**Repository Path**: Mint-Space/Mint
## Basic Information
- **Project Name**: 薄荷Transformer网络训练器
- **Description**: 一个用 **Rust 从零手写**的中文聊天大模型项目:包含**训练、微调、聊天**三大能力,不依赖 PyTorch / TensorFlow 等任何深度学习框架,连 GPU 加速代码(CUDA 核函数)都是手写的。
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2026-09-13
- **Last Updated**: 2026-09-20
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Mint
> 当前版本 **v1.0.0**
一个用 **Rust 从零手写**的中文聊天大模型项目:包含**训练、微调、聊天**三大能力,不依赖 PyTorch / TensorFlow 等任何深度学习框架,连 GPU 加速代码(CUDA 核函数)都是手写的。
模型采用与 GPT 同族的 **Decoder-only Transformer** 架构,训练与聊天推理都可在 GPU 上运行。底层从注意力机制、反向传播到矩阵乘法全部自主实现,追求完全可控、可解释、无黑盒。
## 特性
- **从零实现** — 注意力、RoPE 位置编码、RMSNorm、SwiGLU、交叉熵、Adam 优化器,全部手写前向/反向公式
- **手写 CUDA 核函数** — 29 个核函数(寄存器分块的矩阵乘法、块对角注意力、融合 softmax+损失、Adam 更新等),不依赖 cuBLAS
- **训练 / 微调 / 聊天** — 一键训练新模型、加载检查点继续微调、像 ChatGPT 一样逐字生成并支持多轮对话记忆
- **实时可视化** — 终端进度条、损失曲线、自动生成 HTML 训练报告
- **GPU 加速** — 训练全程在 GPU 上(前向、反向、Adam、验证集评估),注意力按序列分块做(batch 内各序列互不可见,只算真正用到的块);聊天另有**显存常驻的增量推理**路径(权重一次上传、K/V 常驻显存),用 `-gpu` 开启
- **模型管理** — 列出/查看检查点详情、GPU 状态查询
- **赞赏支持** — 主菜单 `[8]` 或 `mint -thanks` 直接在终端画出微信赞赏码(自研 JPEG 解码路径:GDI+ 读取 + 模块重采样 + 半块字符渲染)
- **单文件分发** — CUDA 运行时静态链接,exe 不附带任何 DLL(读赞赏码图时用 Windows 自带的 `gdiplus.dll`)
## 技术栈
| 层 | 技术 |
|---|---|
| 语言 | Rust (edition 2021) |
| GPU | CUDA 12.0 + 手写核函数 (`src/gpu/kernels.cu`) |
| 序列化 | serde / serde_json |
| 并行 | rayon (CPU 端矩阵乘法) |
| 随机数 | rand 0.8 |
| 时间 | chrono |
| 构建 | nvcc + MSVC + rc.exe (图标嵌入) |
## 架构
```mermaid
flowchart TB
subgraph main["main.rs — 界面层"]
MENU["交互菜单 / CLI 参数解析"]
TRAIN["训练循环 train_chat"]
CHAT["聊天推理 interactive_chat"]
end
subgraph core["核心模块"]
DATA["data.rs
数据发现 / 词表 / 分批"]
MODEL["model/transformer.rs
Transformer 模型本体"]
TRAINING["training.rs
GPU 训练器 / 前向反向"]
CKPT["checkpoint.rs
保存 / 加载"]
CHART["chart.rs
进度条 / 报告"]
end
subgraph gpu["GPU 封装"]
OPS["gpu/ops.rs
GpuBuffer 安全封装"]
FFI["gpu/cuda_ffi.rs
Rust ↔ CUDA FFI"]
KERNEL["gpu/kernels.cu
手写 CUDA 核函数"]
end
MENU --> DATA
MENU --> MODEL
MENU --> TRAINING
MENU --> CKPT
MENU --> CHART
CHAT --> MODEL
TRAINING --> OPS
OPS --> FFI
FFI --> KERNEL
CKPT --> MODEL
```
数据流:数据 → 词表 → 词嵌入 → L 层解码器(注意力 + SwiGLU FFN)→ 输出投影 → softmax → 逐字生成。
## 目录结构
```
Mint
├── Cargo.toml # 项目清单(cuda 特性默认开启)
├── build.rs # 编译前脚本:编译 CUDA、嵌入图标
├── mint.rc / icon/ # Windows 资源与图标
├── data/ # 训练数据集(Belle / zhwiki / LCCC / CLUE 系列)
├── docs/ # 技术解读报告(含完整数学公式推导)
├── models/ # 训练好的检查点
├── versions/ # 历代版本快照归档
└── src/
├── main.rs # 入口、交互菜单、训练/聊天驱动循环
├── model/transformer.rs# Transformer 模型本体
├── tensor.rs # CPU 张量运算库
├── training.rs # GPU 训练器、前向/反向传播
├── data.rs # 数据发现/解析/词表/分批
├── checkpoint.rs # 模型保存/加载
├── chart.rs # 进度条、图表、HTML 报告
└── gpu/ # CUDA 核函数与三层封装
```
## 快速开始
### 环境要求
- **Rust 工具链**(cargo 1.98+)
- **NVIDIA GPU + CUDA Toolkit 12.0**(或设置 `CUDA_PATH` 指向其他版本)
- **Visual Studio Build Tools**(MSVC,build.rs 通过 `vswhere` 自动查找)
训练**必须使用 CUDA GPU**——CPU 训练已禁用。聊天推理有两条路径:**CPU(默认)** 与**显存常驻的增量推理**;默认走 CPU 是因为实测在当前模型规格(4.5M 参数)下,显存路径每 token 要发约 1050 次核函数启动,启动开销压过计算,反而比多线程 CPU 慢十几倍(实测 605 字/秒 vs 49.8 字/秒)。模型更大时用 `-gpu` 切换,程序每轮都会打印“字/秒”供对比。
### 构建与运行
```powershell
# 编译(release,CUDA 默认开启)
cargo build --release
# 交互式菜单(训练 / 聊天 / 微调 / 模型管理)
.\target\release\mint.exe
# 直接训练(Belle 数据集、medium 规格、3 轮)
.\target\release\mint.exe -train -task=belle -size=medium -epochs=3
# 加载模型聊天
.\target\release\mint.exe -model=chat_belle_medium_model.json
# 微调已有模型
.\target\release\mint.exe -train -task=belle -model=chat_belle_medium_model.json
# 运行测试(含 GPU 数值对拍)
cargo test
# 查看帮助
.\target\release\mint.exe -h
```
### CLI 参数
| 参数 | 说明 | 默认值 |
|---|---|---|
| `-train` | 进入训练模式 | — |
| `-model=` | 加载模型;单独使用=聊天,与 `-train` 同用=微调 | — |
| `-task=` | 训练任务(belle/zhwiki/LCCC-base-split/afqmc/ocnli/tnews/cmrc2018…) | belle |
| `-size=` | 模型规格(small/medium/large/xlarge) | medium |
| `-epochs=` | 训练轮数 | 3 |
| `-lr=` | 学习率 | 0.001 |
| `-batch=` | 批次大小 | 8 |
| `-max=` | 最大训练样本数(0=不限) | 20000 |
| `-gpu` | 强制使用 GPU 加速(聊天推理也走显存) | — |
| `-cpu` | 不用 GPU 加速(聊天用 CPU;训练会直接报错) | — |
| `-thanks` | 查看赞赏支持(微信收款码) | — |
| `-h` / `--help` | 显示帮助 | — |
无参数启动进入交互式主菜单:1 训练新模型、2 加载模型聊天、3 微调、4 浏览数据集、5 模型管理、6 GPU 状态、7 帮助、8 赞赏支持。
## 模型规格
| 型号 | d_model | 层数 | 头数 | d_ff | 最大序列 | 参数量(约) |
|---|---|---|---|---|---|---|
| small | 96 | 3 | 6 | 288 | 128 | ~1.2M |
| medium | 128 | 4 | 8 | 384 | 128 | ~1.9M |
| large | 192 | 6 | 12 | 576 | 192 | ~4.5M |
| xlarge | 256 | 8 | 16 | 768 | 256 | ~9.0M |
> 采用**字符级**词表,`d_ff = 3 × d_model`,每头维度 `dk = d_model / 头数`。词嵌入与输出投影各占 `词表 × d` 的参数,是参数量的主要来源。
>
> 上表参数量按约 **4000 字**词表估算(仓库内的检查点实测 `param_count = 4509870`,对应 large);真实数值由数据集词表决定,程序会按实际配置打印。
## 数据格式
数据放在 `data/<任务名>/` 目录下,程序会自动发现并解析。支持三类任务:
- **指令对话/Seq2Seq**(如 Belle、LCCC)— JSON 数组,`{ "instruction": "…", "output": "…" }` 或对话对
- **语言模型预训练**(如 zhwiki)— 纯文本,流式解析并缓存为 JSONL
- **分类/阅读理解**(CLUE 系列:AFQMC、OCNLI、TNEWS、CMRC2018)
对话数据打包时只对"助手回复"部分计算损失(`loss_mask`),模型学的是"如何回答"而非"如何复述问题"。
## 测试
`cargo test` 运行 36 个测试,全部通过。核心方法是 **GPU 与 CPU 数值对拍**以及**有限差分**验证梯度正确性:
- 手写矩阵乘法 × 13 组尺寸对拍 CPU
- GPU 前向 = CPU 前向
- 反向传播核函数逐元素数值验证
- 有限差分验证梯度(含生产规模 4585 词表)
- KV 缓存逐 token 推理 = 全序列一次推理(误差 < 1e-4)
- 边界守卫:GPU 封装的越界长度会被断言拦下、模型规格命名与配置一致、报告数值不会产出非法的 `inf`
- 终端二维码:合成图定位/采样与原始网格逐格相等、半块渲染的尺寸与静区布局正确、低分辨率下网格要么被时序图形标尺校准回正确值要么明确报错(绝不静默出错)、透明像素按白底合成、采样阈值随对比度自适应
- 显存增量推理:**逐 token 与 CPU 的 `forward_cached` 逐值对拍**(< 1e-3)、滑窗裁切后仍与 CPU 一致、分配失败返回 `None` 而非崩溃
训练性能用 `cargo test --release -- --ignored --nocapture bench_training` 拆解:它会分别给出前向/反向、梯度裁剪、Adam 各占多少毫秒,以及单层注意力、GEMM 实测吞吐。**这类测量只有在同一进程内交替 A/B 才可靠**——同一份代码在不同进程之间实测能差 2~3 倍(笔记本 GPU 的频率/供电状态),跨进程前后对比很容易得出假结论。
## 已知限制
- **字符级建模** — 生成步数多,长程语义理解弱于子词(BPE)分词
- **模型规模** — 1.2M(小)到 9.0M(大)参数,远小于 GPT-3 的 1750 亿,只能短对话、无深度推理
- **显存硬约束** — 4GB 显存限制 batch 与模型大小(聊天走显存约需 20 MB,不是瓶颈)
- **检查点为 JSON** — 体积偏大,序列化时内存翻倍
- **训练报告** — HTML 依赖 CDN 图表库,离线打开无图表
## 赞赏支持
如果 Mint 对你有帮助,欢迎请作者喝杯咖啡。主菜单 `[8]` 或运行 `mint -thanks` 会**直接在命令行窗口里画出微信赞赏码**,用手机扫码即可,不必打开图片文件。
这里不依赖任何图像库:图片用 Windows 自带的 GDI+ 解码,然后二值化、定位三个寻像图形、按模块重采样成 0/1 网格,最后用半块字符 `▀` 打印 —— 一个字符正好是 1 格宽 × 2 个模块高,所以二维码在终端里是方的。
网格会再用二维码自带的**时序图形**复核一次:低分辨率图里包围盒会被模糊撑宽 1px,足以让模块数差 1、整张码错位而寻像图形照样“通过”;这一步校准不过在就明确报错,不会把错位的码当成功打印出来。窗口放不下时也提前警告(本图 45 模块 + 8 格静区 = 53 列),把窗口拉宽或调小字号即可。
二维码图片位于 `icon/gratuity.jpg`,**不内嵌进 exe**:单文件分发时把它放在 `mint.exe` 同级的 `icon/` 目录即可(程序依次查找「exe 同级 → 工作目录 → 源码根」);找不到时会打印应放置的路径。
## 更多文档
技术细节、逐组件数学公式推导、训练系统与 GPU 加速详解、经典 Bug 案例集等,请见 [`docs/Mint项目技术解读报告.md`](docs/Mint项目技术解读报告.md)。