尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

从零构建AI:手写GPT模型与推理模型进阶路线

发布时间:2026/9/29 7:29:40

资讯中心
01
ARTICLE

从零构建AI:手写GPT模型与推理模型进阶路线

从零构建AI:手写GPT模型与推理模型进阶路线
1. 先搞清楚“从零构建AI”到底在构建什么最近“AI engineering from scratch”这个词越来越热打开技术社区到处都是类似“build a reasoning model from scratch”“Build a Large Language Model from Scratch”的话题。我第一次看到这种标题时以为这是个GitHub仓库名点进去才发现它更像一种学习态度不满足于调包跑demo而是想亲手把AI系统拆开重装一遍。但这个“from scratch”到底意味着什么是把Transformer从零手写是从线性代数开始推公式还是自己造一个训练框架这些问题如果一开始不想清楚很容易在入门路上用力过猛最后连一个小模型都跑不出来。以我的经验从零构建AI真正要做的事不是抛弃所有现成库而是把每个关键环节的“为什么”搞清楚。比如为什么要用AdamW而不是SGD为什么数据要做mask为什么推理时要有temperature。当你能解释这些选择并且能跑通一个最小系统你就已经具备了AI工程的核心能力。这篇文章不是教科书也不是源码逐行解析而是一个做过不少“从零”项目的工程师的排雷笔记适合那些已经会一点Python、想系统进入AI工程领域的人。1.1 不要被“from scratch”吓住工程与科研的边界我见过太多人一听到“从零构建大模型”第一反应就是“我要自己写CUDA自己实现autograd自己搞分布式”。这个想法听起来很硬核但对大多数人来说效率极低。科研界偶尔需要这样做是为了探索未知边界工程界则讲究在可控成本内交付可用系统。所以你需要先给自己定个位你是要做研究还是做工程对95%的读者来说目标应该是后者也就是“能亲手训练并部署一个小模型并理解其中每个核心组件的工作方式”。真正属于“从零构建”的最小范围其实就是数据管道、模型定义、训练循环、推理服务这几块。Transformer的注意力机制当然要自己实现一遍但没必要从写CUDA kernel开始。PyTorch已经帮你处理好了GPU计算和自动求导你在这个基础上实现模型结构已经是很好的“从零”。那些宣传“从零构建”的课程或书籍比如《Build a Large Language Model from Scratch》本质上也是用PyTorch配合你手写核心模块而不是真的从硅片开始造芯片。还有一个常见的误区是“from scratch”就必须闭卷默写所有代码。我建议反过来先打开代码看一遍再合上自己写一遍最后对照开源实现找差距。这个过程中的查漏补缺才是工程能力的真正增长点。别怕“抄”你又不是论文造假你是在做工程训练。1.2 我理解的AI工程知识地图如果让我把“AI engineering from scratch”画成一张地图它大概有五个台阶第一级是数学和Python基础至少能看懂矩阵运算和写脚本第二级是数据工程包括采集、清洗、切分、tokenization第三级是模型实现从最简单的MLP到Transformer第四级是训练与优化理解损失、优化器、学习率、分布式这些训练手段第五级是评估、对齐和部署也就是让模型真正能用起来。这几个台阶并不是严格串行的。我的建议是第一级和第三级可以交替进行你不需要完全学完线性代数再碰模型而是边实现边补数学。我自己就是在实现自注意力时才真正理解了QKV矩阵的意义在调loss的时候才回头补了信息论的基础。这种“问题驱动”的学习效率远比啃教科书高。另外别试图在每个台阶都成为专家。这个领域太大了AI engineer更像一个协作者你可能精通数据处理但对服务端部署不熟你可能是推理优化高手但不擅长写数据集代码。这都没关系。只要你能把一条完整的链路走通并且有一个环节能钻得很深就已经具备了在团队中创造价值的能力。这张地图的意义不是让你压力山大而是让你知道自己的坐标以及下一个该往哪走。2. 从零起步的第一阶段数学、Python与数据基础很多初学者一听“数学基础”就开始焦虑是不是要把高数、线代、概率论全部重修一遍我的回答是不用但你必须把AI里最常用的那几块概念和代码中的具体操作对上号。否则你会陷入一种尴尬状态——能运行代码但完全不知道它在干什么遇到bug也无法定位。2.1 真正用得上的数学只有这几块在AI工程里线性代数的核心就是矩阵乘法。一个token的embedding是向量一个batch的输入是矩阵模型参数也是矩阵前向传播就是一系列矩阵乘法。你要养成的习惯是“跟踪每个张量的形状变化”。比如在自注意力里Q、K、V的形状通常是 (B, T, head_dim)你心里要清楚B是batch大小T是序列长度head_dim是每个头的维度。这样写代码时各种reshape、transpose才不会出错。概率论的核心则是理解模型在做什么。语言模型本质上是在学习“给定前文下一个token的概率分布”。所以交叉熵损失就是衡量模型预测分布和真实分布的差距。你不需要手工推KL散度但要知道为什么temperature越低采样越偏向确定性为什么beam search和sample是完全不同的两种解码策略。这些直觉会直接决定你调推理参数时的思路。微积分反而不是重点因为PyTorch已经做了自动求导。但你要理解链式法则的本质梯度从输出层向输入层逐层传递经过每一层都会乘一个偏导。如果中间经过一个饱和的sigmoid梯度就会接近于0这就是梯度消失。一旦你能用这种“信号流”的视角看训练过程很多参数调优问题就变得直观了。2.2 数据处理能力比模型结构更先卡脖子说句实话大部分“从零训练”项目的第一个瓶颈不是模型代码而是数据。我当初拿爬虫扒了一堆网页文本直接丢进tokenizer结果训练出来的模型满嘴HTML标签。后来我在清洗流程里加了“去除所有尖括号内容”的规则才算恢复正常。这个坑提醒我数据管道的优先级永远高于模型结构。因为模型再强喂进去的是垃圾出来的就是垃圾。我的数据清洗有固定三板斧。第一板斧是去重把文档按照hash值比对去掉完全重复的样本再用SimHash找近似重复这一步能避免模型在重复语料上过拟合。第二板斧是规范化统一换行符、去控制字符、处理乱码编码尤其是UTF-8转码误操作千万别小看这些琐碎规则它们能影响tokenizer的切分质量。第三板斧是切分验证如果要做训练集和验证集一定要按“文档级别”切而不是随便按行切。按行切会让同一文档的上下文散落在两边导致验证集评估结果虚高。对于刚开始做“from scratch”的人来说我的建议是不要一上来就爬数据。先找一份公开的、结构干净的语料比如Wikitext或者BookCorpus的子集把你的第一个模型跑通。当整个链路稳定之后再尝试自行采集和清洗数据。这样能让你把精力集中在“模型能不能学”而不是“数据能不能用”上。2.3 脚本化思维从Notebook到工程代码我在入门阶段最大的教训就是“写了一大堆Notebook等到真正要训练模型时发现代码根本没法复现”。Notebook的交互式环境很适合探索但它的全局变量和执行顺序混乱会让实验陷入“我改了什么导致了什么结果”的迷障。所以从零构建AI工程的第一步不是写模型而是建立工程化的代码结构。一个最精简的AI工程目录至少包含四个文件config.py保存模型超参数和数据路径、data_utils.py负责加载和预处理数据、model.py定义模型结构、train.py执行训练循环。每个文件都要能单独运行并且不依赖Notebook里的隐藏状态。命令行的参数解析我推荐用argparse或Hydra哪怕你只是暂时存成硬编码配置也要确保“改配置和改代码是两件事”。这样你就能用不同的配置文件跑不同的实验进行真正的控制变量对比。工程化还有一个好处它迫使你写函数而不是流水账。把数据批处理封装成函数把训练一步封装成函数你才有办法做单元测试。比如写了一个“mask生成函数”你可以在一个小样本上手动算出期望的mask矩阵再和函数输出对比。这种验证看起来很笨但能省掉你后面排查bug的好几个小时。3. 手写一个mini模型的完整链路核心实操前面说了那么多理念现在进入真正动手的部分。我以“从零训练一个GPT风格的语言模型”为例把完整链路拆给你看。这个mini模型很小参数大概2000万左右单张消费级显卡都能跑但麻雀虽小五脏俱全。你可以把它当作《Build a Large Language Model from Scratch》这本书的“动手复现版”核心原理完全一致。3.1 用PyTorch从零实现一个GPT风格的语言模型先说模型设计。我常用的一组超参是6层Transformer、4个注意力头、embedding维度256、序列长度256、词表大小约5000先拿一个小的BPE词表。这样一个模型的参数量大约在20M几小时甚至几十分钟就能在单张GPU上完成初步训练。代码上你只需要三个模块嵌入层、TransformerBlock、最后的输出层。嵌入层负责把token id映射为向量并加上位置编码TransformerBlock负责做自注意力计算和逐位置前馈处理输出层负责把最终的隐状态投影到词表大小。一个极简的模型类可以写成下面这样import torch import torch.nn as nn class TinyGPT(nn.Module): def __init__(self, vocab_size, d_model, n_head, n_layer, block_size): super().__init__() self.token_emb nn.Embedding(vocab_size, d_model) self.pos_emb nn.Embedding(block_size, d_model) self.blocks nn.Sequential(*[ TransformerBlock(d_model, n_head, block_size) for _ in range(n_layer) ]) self.ln_f nn.LayerNorm(d_model) self.head nn.Linear(d_model, vocab_size, biasFalse) def forward(self, idx): # idx shape: (B, T) B, T idx.shape tok self.token_emb(idx) # (B, T, d_model) pos self.pos_emb(torch.arange(T, deviceidx.device)) # (T, d_model) x tok pos # 广播相加 x self.blocks(x) x self.ln_f(x) logits self.head(x) # (B, T, vocab_size) return logitsTransformerBlock里最核心的是自注意力子层。你需要自己用线性层生成Q、K、V然后计算注意力分数加causal masksoftmax后和V相乘。这个过程中最大的坑是mask的形状和广播规则。我自己的一个自查技巧是打印每一步张量的shape尤其注意attn q k.transpose(-2, -1)的结果一定是(B, T, T)而mask也必须是(B, T, T)或(T, T)才能正确广播。如果你不想每次踩坑最好把mask的生成封装成一个函数并用小样本测试一遍。3.2 训练一个真正能用的tiny模型需要哪些决策模型结构写完训练循环是下一个关卡。不要小看这个循环它决定了模型能否收敛。首先优化器我用AdamW初始学习率大约3e-4配合warmup和cosine decay。你可以写一个简单的学习率调度器先线性上升几百步再按余弦曲线下降。这种调度方式能避免训练初期loss爆炸也能在后期逐步收敛。其次批次大小与显存要一起考虑。如果显存不够你可以先设定一个较小的batch size例如batch size16然后再设置gradient_accumulation_steps4这样实际参与计算的“虚拟batch size”就是64。在PyTorch里实现方式非常简洁对每个mini-batch计算loss并做loss.backward()但只在累积到指定步数时统一步长更新。这一步能稳定训练过程也给了你更大的调节空间。损失函数方面语言模型用的是交叉熵。需要注意logits的形状是(B, T, vocab_size)labels的形状是(B, T)。在放进nn.CrossEntropyLoss之前要把logits reshape成(B*T, vocab_size)labels reshape成(B*T,)。这一步经常被漏掉导致维度不匹配报错。判断training是否正常最简单的办法是先用100条样本做一个overfit测试loss能显著下降说明模型和数据管道没问题再用全部数据训练。3.3 评估、推理与部署的最小闭环训练完成之后模型还只是个checkpoint你需要把它变成一个可以交互的服务。首先要写推理函数初始化模型加载checkpoint给定一个起始token序列然后循环生成后面的token。生成时有两种常用策略贪心搜索每次选概率最大的和采样按照概率分布随机抽。为了让输出更多样许多人会加一个temperature参数temperature越高输出越随机。我的经验是对于mini模型temperature设置在0.8左右生成结果既有变化又不至于太乱。你完全可以copy一个generate()函数但要理解它内部的自回归逻辑。部署最小闭环不需要上Kubernetes。用FastAPI或Flask写一个HTTP接口就够了。大致思路是接收POST请求里的字符串文本先用tokenizer编码成token id再调用模型的生成函数最后把生成的token解码成文本返回。这样你就完成了一个“从训练到部署”的完整项目闭环。在这个基础上再往后加batching、流式输出、并发队列都是填砖加瓦的事。4. 走向“推理模型”从LLM到Reasoning Model的进阶最近“build a reasoning model from scratch”成了一个新热点。很多人问我说普通LLM和Reasoning Model到底差在哪是不是又要从头训练一遍我的回答是架构层面没有巨大的革命主要是训练数据、目标函数和推理方式的变化。如果学会了基础的LLM实现再往Reasoning方向走其实没有那么神秘。4.1 什么是reasoning model它和普通LLM差在哪普通语言模型被训练成“预测下一个词”。它学到的是一种统计模式看到“世界上最大的洋”会接着生成“太平洋”因为语料里这个搭配高频出现。但推理模型的目标是解决“需要多步推导才能回答的问题”。它需要在内部生成一段思维链逐步推进到正确答案。也就是说普通模型的输出是“即时的直觉反应”而推理模型的输出是“带着过程的推演结果”。从工程角度看两者的训练方法差异不小。普通LLM主要做自监督学习next token prediction而Reasoning Model往往会在通用预训练之后增加一阶段“思维链数据微调”再做一轮偏好优化比如使用可验证答案作为奖励来强化学习。这些技术听起来高大上但核心思路和训练普通模型没什么不同准备好合适的数据设计好损失函数调好超参数然后训。正因如此我建议基础尚浅的同学先把普通LLM玩熟练再挑战Reasoning方向。4.2 在已有模型上做推理增强的实操思路如果你个人算力有限又想体验“构建推理模型”最现实的做法是拿一个开源可商用模型比如Qwen系列或Llama系列用你自己的思维链数据做监督微调。思维链数据哪里来可以自己构造也可以从数学题、逻辑题、因果推理题等场景里沉淀。每一份数据按统一格式组织提问然后是逐步推理最后是最终答案。重点在于推理过程要自然不能是答案的直接堆砌。数据量不一定要多大。我有一次用几千条思维链数据微调一个小模型就看到了明显的效果在20道简单数学题上的正确率从30%提升到65%。但这中间也有一个很容易犯的错误如果训练数据里只有单一题型模型会“死背”模板遇到变体题就崩。解决办法是在微调时混合20%~30%的普通对话或通用指令数据保证模型的通用能力不被遗忘。如果你还想更进一步可以尝试用偏好优化DPO之类让模型更偏好输出推理过程而不是直接给结论。4.3 算力不够时的省力路径不过“from scratch”不代表所有环节都要自己造轮子。如果你连微调开源模型都觉得太贵还有一个不需要训练的方案在提示词里显式引导模型进行推理比如“请先列出已知条件再逐步推理最后给出答案”。这种方法远没有“训练一个推理模型”那么强但成本极低也能达到一部分reasoning效果。再加上外部工具比如让模型调用Python解释器来做数学运算你可以用很小的成本构建一个会“多步骤思考”的系统。在我看来个人开发者拥抱Reasoning Model的最佳姿势是“随大流但不被热点绑架”。你可以在开源社区找到很多已经训练好的推理模型的权重在它们的基座之上做轻量级适配和应用开发。真正的“from scratch”价值在于当你看到了推理模型的代码和配置你能读得懂能改得动并且知道它和普通LLM的边界在哪里。这种理解才是难以替代的。5. 常见问题排查与避坑指南经验实录到了这个阶段你已经具备了自己动手训练一个模型的能力。接下来这部分是我个人最想分享的经验因为大家都在展示成功案例却没多少人交代那些令人崩溃的bug。我把最常见的问题整理成一份速查表每条都附上排查思路和解决办法希望能帮你省下几个通宵。5.1 训练Loss不降、内存爆炸、显存OOM怎么办先看Loss不降。如果你的loss几乎没有下降第一反应应该是检查数据。用一个小样本集比如100条打印出输入和标签确认token id没错位。然后看模型输出形状是否和labels形状匹配。如果都没问题就做overfit测试把训练集缩小到几十条反复训练几十个epochloss应该能降到很低。如果还是降不下去大概率是mask写错了或者是优化器参数设置不对。显存OOM是另一个高频问题。最直接的解法是减小“真实batch size”然后用梯度累积补回batch大小。你还可以开混合精度训练AMP。在NVIDIA几张主流卡上fp16能降低显存占用但容易出现精度溢出bf16更稳定只不过需要新一点的GPU。如果模型特别大还可以考虑梯度检查点torch.utils.checkpoint它会用一部分计算换显存对长序列模型很管用。真还不行就把序列长度减半反正我们的目标是跑通链路不是刷排行榜。我在这里放一个问题速查表供你参考问题现象常见原因快速定位方法Loss完全不变数据标签错位 / 学习率过低打印样本输入输出 / 用100条overfitLoss到某个值后停滞模型容量不足/训练数据不足增大模型宽度/补充高质量数据显存OOMbatch过大/序列过长减小batch开AMP梯度累积训练速度过慢没有用GPU/数据预处理频频卡检查model.to(device)优化DataLoader生成内容全是重复句训练数据重复多/直接贪心解码清洗数据/temperature调到0.75.2 数据集清洗与tokenization踩坑数据清洗时最容易忽略的是隐藏字符。比如Windows换行符\r\n被当作普通字符送给tokenizer模型就可能学出不换行的坏习惯。我的做法是用一个白名单字符过滤器把常见信息性无意义字符全部替换成空格。另一个坑是BOM头尤其是从网上下载的UTF-8文件开头会带一个看不见的\ufeff它会影响第一行token。我每次读文件都会加encodingutf-8-sig已经养成习惯了。Tokenization方面如果你用的是预训练tokenizer一定要确保训练和推理用的是同一版本否则同一个词可能被切分成不同的token id模型就无法复用。如果你自己训练了一个BPE tokenizer注意词表大小。太小的词表会导致每个token承载的信息太少序列被拉长太大的词表则会让embedding矩阵变得很重训练显存随之升高。对于mini模型我一般选择4k~16k词表这样在“表达粒度”和“工程成本”之间比较平衡。5.3 “从零”不等于“闭门造车”该抄的框架还是要抄这是我特别想强调的经验。我见过有人为了“from scratch”连DataLoader都要自己写结果性能差不说还带了一堆bug。其实“从零构建”的真正含义是“理解核心原理并能动手实现关键路径”并不是每个轮子都要重新发明。你完全可以利用PyTorch的DataLoader加载数据用HuggingFace的tokenizer切词用现成的Trainer或自己写训练循环。关键是你要知道它们内部的大致逻辑。我自己在实现一个小模型时通常会对照开源项目nanoGPT来检查。比如我的注意力函数一开始是用循环写的虽然能跑但比向量化的写法慢一倍看了nanoGPT后才知道可以用masked_fill一次性完成mask操作。这种对照不是抄袭而是工程优化。每一次diff都能学到某个局部的最佳实践累积起来就是你自己的工程直觉。6. 个人实操心得与推荐路径最后聊点私人的体会。我做“AI engineering from scratch”类的项目最大的收获不是“我会写模型了”而是“我知道模型是怎么坏的了”。这个说法有点反直觉但千真万确。当你亲手实现一个模型、亲手喂数据、亲手调参数你会看到一个模型从loss乱飞到逐渐收敛的全过程。这个过程让你对AI技术产生一种“祛魅”效果看到再厉害的模型你也能大概推断出它训练时可能遇到哪些坑数据管道有哪些隐患。我给刚入门的读者两条建议。第一给自己定一个“最小成功目标”。比如“在10万条数据上训练一个2000万参数模型让它能生成语义完整的短句”然后只专注于实现这个目标其他什么理论都先放一边。第二养成写实验日志的习惯。每天记下改了哪个参数、loss曲线长什么样、遇到什么bug、怎么解决的。三个月后回看你会发现自己积累了一大笔看不见的财富那些日志比任何教程都更贴你的实际情况。如果你问我《Build a Large Language Model from Scratch》这本书怎么读我的答案是别把它当小说一口气读完把它当工具书。你做到数据层时去翻数据准备章节写到模型时去对照Transformer实现训练遇到问题时去查优化器和训练循环。书里的内容会变成你实操的路标而不是压在你书架上的文件。现在再看到“build a reasoning model from scratch”这类新热点我已经不会心跳加速了。因为我知道所谓“from scratch”并不是发现了什么魔法它只是把工程、数据、训练、评估这些环节重新组合了一遍。只要基础功扎实你也能顺着这条路径走下去然后生成属于自己的解决方案。这大概就是“从零开始”这件事真正迷人的地方它永远在提醒你别怕问题多每解决一个你就离底层更近一点。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。