跟着LAP啥都学 跟着LAP啥都学

附录 C 踩坑与 FAQ

      +

      本附录收录本项目实测中出现的问题与解法,按「环境 → 训练 → 数值 → 部署」组织。 遇到报错时,先在 C.5 快速诊断表里查症状:表内处方能直接处置的就地处理, 需要展开的再回到对应小节看详细解法。

      C.1 环境:安装与下载

      RE2 安装失败 / torchtext 分词器不可用

      第 2 章可选使用 torchtext 官方 GPT2BPEEncoder,其正则引擎依赖 RE2:

      sudo apt-get install libre2-dev

      安装失败或平台不提供该包时,改用教程自带的 bpe_tokenizer.h:纯 C++ 实现,无外部依赖,数值与官方一致。全部章节默认使用它。

      第 2 章的双实现交叉验证保证了这个替身可用:官方版缺席时,自研版结果可以直接对账。

      HuggingFace 下载慢 / 403

      所有下载脚本统一用 HF_MIRROR 开关选择源:

      HF_MIRROR=hf-mirror ./scripts/download-weights.sh     # 默认:hf-mirror.com
      HF_MIRROR=huggingface ./scripts/download-weights.sh   # HF 官方(需海外网络)
      ALL_PROXY=socks5h://localhost:30000 ./scripts/download-data.sh  # 走代理

      默认源 hf-mirror.com 国内无代理可达,速度约 10 MB/s;下载失败时自动回退 huggingface.co。GitHub raw 数据(nl2bash 等)国内可直连但较慢,超时再用 ALL_PROXY 指定代理。

      Ollama 起不来(7.8 节评分用)

      ./scripts/start-ollama.sh --pull     # 启动 ollama serve,并拉取 llama3(4.7 GB)
      ollama list                          # 此时应看到 llama3 在列

      程序内 query_ollama 请求 http://localhost:11434/api/chat。Ollama 不可达时,第 7 章会打印跳过提示后继续,不会崩溃。评分是可选环节,跳过不影响其余章节。

      C.2 训练:显存与耗时

      GPT-2 medium 训练 OOM(16 GiB 卡)

      medium(355M)全参微调加 AdamW,显存大头是优化器状态。动量与二阶矩约 2×355M×4B ≈ 2.8 GB(账目见第 9 章),此外还有梯度与激活。16 GiB 显卡实测安全配置:

      SIZE=medium EPOCHS=3 BATCH=4 ./scripts/train-background.sh   # 16 GiB 卡用 batch=4

      batch 提到 8 及以上会 OOM;small(124M)用 batch=8 没有问题。显存不足时按此顺序缩减:减 batch → 减 max_length → 改用第 9 章的 LoRA(可训练参数降到约 2%)。换更大的卡放在最后。

      训练耗时量级(RTX 4080/4090 级,供预期管理)

      开跑前先核对下表,预估等待时间:

      任务 GPU 耗时 备注

      第 5 章 124M × 10 epoch(The Verdict)

      分钟级

      9 batch/epoch,很小

      第 7 章 medium × 2 epoch(Alpaca 1100 条)

      3–4 分钟

      参考:A100 级 GPU 约 0.86 分钟

      第 8 章 demo 配置(CPU)

      1–2 分钟

      emb=256 的小模型

      第 13 章 small SFT 1 epoch(GSM8K)

      105 秒 / 1550 步

      medium 335 秒

      第 13 章 GRPO 100 步

      208 秒

      batch=1, group=2

      C.3 数值:为什么我的 loss 与实测锚点不一样

      TF32:GPU 上 loss 与 CPU 结果在第三位小数不一致

      Ampere 及之后的 GPU 默认用 TF32 做 matmul,速度约快 8 倍,尾数只有 10 位。本项目所有 main.cpp 开头都有关闭代码:

      at::globalContext().setAllowTF32CuBLAS(false);

      不关闭时,GPU 结果与 CPU 数值会在 1e-2 量级上漂移。要复现书中数值,保持默认(关闭 TF32);要追求吞吐量,可以打开 TF32 并接受数值偏差。

      manual_seed 与设备初始化顺序

      权重初始化必须先在 CPU 上用 torch::manual_seed(123) 完成,之后再 .to(device)。先迁设备再初始化时,CUDA 的 RNG 序列与 CPU 不同,同样的 seed 会得到不同的初始权重,loss 曲线从第一步就分叉。教程代码的固定写法:

      torch::manual_seed(123);
      ch4::GPTModel model(cfg);        // CPU 上初始化(seed 语义与书一致)
      model->to(device);               // 再迁移

      这类问题的症状是:程序正常运行,数值与书对不上。遇到时先检查上面两行的顺序。

      训练曲线「趋势一致但数值不同」

      C++ 的 std::mt19937 与 Python 的 random 不是同一个 RNG,DataLoader 批次顺序必然不同,loss 曲线细节也就必然不同。这不是 bug,是两套随机数系统的正常差异。

      判断复现是否成功,看三点:起点(地板 loss ≈ \(\ln V\))、终点量级、train/val 分叉形态,而不是逐 step 对齐。逐位对齐只在同一台机器、同一份代码、同一套 RNG 下才成立。

      C.4 部署:平台与进程

      Windows 与 Linux 的差异清单

      项 Linux(本项目实测环境) Windows 注意点

      编译器

      GCC 11 / C++17

      MSVC 可编译但 CMake 脚本未适配;建议 WSL2 或 MSYS2 UCRT64

      HTTP 服务

      POSIX socket(sys/socket.h、arpa/inet.h)

      sft_serve 用了 POSIX API,Windows 原生需换 Winsock

      popen

      popen/pclose(bash_chat、query_ollama)

      _popen/_pclose,且 shell 是 cmd 不是 bash

      路径分隔符

      CMake 已用 ${CMAKE_CURRENT_SOURCE_DIR} 相对路径

      注意 DATA_DIR 宏的默认值带 /

      .pth 与模型规模不匹配

      torch::load 载入与 --size 不匹配的权重,会抛形状不匹配异常。这是有意设计:第 5 章 assign 的「失败要响」原则在框架层生效。看到 Shape mismatch 时,先核对 --size 与权重文件的对应关系,不要怀疑实现。

      16.6k 样本下载 / 数据文件行数不一致

      convert_data.py 要求 all.nl 与 all.cm 行数严格对齐,不一致直接报错退出,防止错位训练。手动下载语料后,先统计两个文件的行数:行错开一位,问答对全部错位,训练照常跑完,结果全部无效,且不会报错。

      C.5 快速诊断表

      遇到报错,先查下表的「症状」列,再按「处方」处理:

      症状 最可能原因 处方

      loss 第一步就 ≈ 12+ 且不降

      数据目录没找到 / 词表文件缺失

      检查 DATA_DIR 与 encoder.json(词表见第 2 章)

      GPU loss 与书对不上

      TF32 未关

      setAllowTF32CuBLAS(false)

      同 seed 结果不同

      初始化顺序(先 to(device))

      见上节「manual_seed」

      medium 训练中途 OOM

      batch=8 太大

      batch=4 或换 LoRA

      服务 400 bad request

      JSON body 未按 Content-Length 截断完

      检查 curl 引号转义(解析实现见第 10 章)

      Ollama 评分全跳过

      服务未启动 / llama3 未拉取

      start-ollama.sh --pull

      eval AST-match 全是 null

      未安装 bashlex

      pip install bashlex(可选依赖;四级评测见第 11 章)