用AI从零构建LLM:13M参数迷你GPT模型实战全记录

一场用AI造AI的疯狂实验
在AI工具日益普及的今天,一个有趣的问题浮出水面:我们能否用现成的AI编程助手,从零构建出一个属于自己的语言模型?B站一位UP主用一期视频给出了肯定的答案——他借助Claude、Cursor等AI工具,成功训练出了一个约1300万参数的迷你GPT模型,并让它能够回答关于自己的问题。
这个项目的核心目标非常明确:构建一个10到30百万参数量级的小型GPT风格语言模型,使用PyTorch框架,在一份纯英文Markdown数据集上训练,并且要能在单张消费级显卡(RTX 5070)上本地运行。整个过程没有依赖Hugging Face等重型框架,展现了一条极简的LLM构建路径。
这里有必要理解一下GPT架构的基础。GPT(Generative Pre-trained Transformer)是由OpenAI提出的生成式预训练模型架构,其核心基于2017年Google论文《Attention Is All You Need》中提出的Transformer结构。Transformer的关键创新在于自注意力机制(Self-Attention),它允许模型在处理序列中的每个位置时,动态地关注输入序列中所有其他位置的信息,从而捕获长距离依赖关系。具体而言,自注意力通过将输入映射为Query(查询)、Key(键)和Value(值)三组向量,计算Query与所有Key的点积相似度后进行softmax归一化,再用得到的注意力权重对Value进行加权求和,最终为每个位置生成一个融合了全局上下文信息的表示。GPT采用的是Transformer的Decoder部分,使用因果掩码(Causal Mask)确保模型在生成每个token时只能看到之前的token,这使得它天然适合自回归式的文本生成任务。虽然1300万参数远小于GPT-4等千亿级模型,但其架构原理完全一致,包含多头注意力层、前馈神经网络层和层归一化等核心组件——这也是为什么这个迷你项目能成为理解大模型原理的绝佳入口。

从Prompt工程到项目搭建
用AI写Prompt,再用AI写代码
这个项目最有意思的地方,在于它形成了一条完整的"AI套娃"链路。UP主首先借助ChatGPT撰写了一份详尽的Prompt,明确要求生成一套完整、可运行的代码库,并根据自己的硬件条件(RTX 5070显卡)做了针对性调整。
随后,他将这份Prompt投喂给Cursor(使用Opus 4.6 Max模型),让AI来编写实际的训练代码。Cursor是一款基于VS Code深度定制的AI原生代码编辑器,它将大语言模型深度集成到编程工作流中,支持代码生成、重构、调试和自然语言交互等功能。Opus 4.6 Max是Anthropic的Claude系列模型之一,以长上下文理解和精确的代码生成能力著称。Cursor的工作原理是将用户的代码库上下文、光标位置、终端输出等信息与用户指令一起发送给LLM,从而生成高度上下文相关的代码。这类AI辅助编程工具已形成一个快速发展的生态,包括GitHub Copilot、Windsurf、Augment等产品,它们正在根本性地改变软件开发的方式,使得即使不完全理解底层实现的用户也能在AI引导下完成复杂的工程任务。值得注意的是,这些工具之间的竞争焦点已从简单的代码补全转向「代码库级别的理解能力」——即AI能否理解整个项目的架构、依赖关系和设计模式,从而给出更符合项目整体风格的建议。
整个代码生成过程耗时约17分钟,产出了一个名为TinyGPT的完整项目结构。
值得一提的是,生成的代码非常精简——核心代码不到400行,依赖项也仅有5个:PyTorch、SentencePiece、NumPy、TensorBoard和TQDM。PyTorch由Meta(原Facebook)的AI研究实验室开发,凭借其动态计算图(Define-by-Run)设计理念在研究社区中占据主导地位——与TensorFlow早期的静态图模式不同,PyTorch允许用户像编写普通Python代码一样构建和调试神经网络,目前几乎所有主流开源LLM(包括LLaMA、Mistral等)都基于PyTorch构建。TensorBoard则是Google开发的机器学习可视化工具,能实时监控训练过程中的损失曲线、学习率变化和梯度分布等关键指标,帮助开发者诊断过拟合和梯度消失等常见问题。这种极简设计恰恰体现了小型LLM的可行性,不需要庞大的工程体系,普通开发者也能上手。
环境配置的踩坑之旅
实验过程中充满了新手常见的技术障碍。UP主坦言自己对这些工具"完全不了解",但AI助手在排错环节发挥了关键作用。当遇到全局环境包冲突时,AI主动建议创建虚拟环境进行隔离——Python虚拟环境(如venv或conda)通过创建隔离的Python运行时副本,确保项目间的依赖互不干扰。这对深度学习项目尤为重要,因为不同项目可能依赖不同版本的PyTorch或CUDA工具包,而conda尤其适合深度学习场景,因为它不仅管理Python包,还能管理CUDA运行时库等非Python的系统级依赖。遇到"module not found"错误时,Cursor直接完成了依赖安装并自动重跑命令。

训练流程:分词器、数据准备与模型训练
标准化的LLM训练管线
整个训练流程遵循了一套清晰的工作流:训练分词器 → 准备数据 → 预训练模型 → 微调。
首先是训练分词器。本项目使用的SentencePiece是由Google开发的开源分词工具,它与传统分词器的最大区别在于直接从原始文本训练,不依赖预先的空格分词或语言特定规则。这种「语言无关」的设计使其能够统一处理英文、中文、日文等不同语言的文本,甚至可以处理代码和特殊符号。SentencePiece实现了两种主流的子词分割算法:BPE(Byte Pair Encoding,字节对编码)和Unigram语言模型。BPE通过反复合并最频繁出现的字符对来构建词表——例如,频繁共现的字符"t"和"h"会被合并为"th","th"和"e"进一步合并为"the",如此迭代直到达到目标词表大小。而Unigram模型则从一个大词表出发,逐步剔除对整体语言模型似然贡献最小的子词。最终得到的词表大小仅为3266——这个数字对于大型模型来说相当小(作为对比,GPT-2使用的词表大小约为50257,LLaMA使用32000,而最新的一些模型甚至超过100000),但对于特定领域的迷你模型而言已经够用。较小的词表意味着模型只需学习约3000个子词单元的表示和组合规律,这极大降低了嵌入层的参数量,是小型模型控制参数规模的关键手段。
UP主的一句话点出了小模型的哲学:"我们不以大小论英雄,看的是性能表现。"
CUDA踩坑:CPU与GPU训练的天壤之别
训练环节暴露了一个典型问题。最初运行时出现了"Torch not compiled with CUDA enabled"的错误,导致模型实际上是在CPU上训练的,速度慢得令人绝望。UP主形容训练时"电脑风扇疯狂运转",不得不快进跳过。
这里需要解释一下CUDA的重要性。CUDA(Compute Unified Device Architecture)是NVIDIA推出的并行计算平台和编程模型,它允许开发者利用GPU的数千个计算核心执行通用计算任务。深度学习训练的核心运算——矩阵乘法和张量运算——具有高度并行性,恰好契合GPU的架构特点。一张RTX 5070拥有数千个CUDA核心和专用的Tensor Core(张量核心),后者专门针对混合精度矩阵运算进行了硬件级优化。以矩阵乘法为例,CPU通常按行列逐元素计算,而GPU可以同时并行处理数千个元素的乘加运算——这就是为什么GPU在深度学习中比CPU快几十到几百倍的根本原因。PyTorch通过torch.cuda接口与CUDA交互,当检测到可用GPU时会自动将张量和计算迁移到显存中执行。文中提到的错误通常是因为安装了CPU版本的PyTorch——通过pip默认安装的PyTorch往往不包含CUDA支持,需要通过PyTorch官方网站(pytorch.org)选择对应操作系统、包管理器和CUDA版本的安装命令重新安装——这是深度学习新手最常遇到的环境配置问题之一。
后来在安装CUDA后,设备成功切换到了NVIDIA GeForce RTX 5070,训练速度大幅提升。RTX 5070属于NVIDIA Blackwell架构的消费级显卡产品线,拥有约12GB的显存。1300万参数的模型在FP32精度下约占52MB显存,加上优化器状态和中间激活值,总显存占用也远在消费级显卡的承受范围内——这说明对于教学级别的小型模型,用户完全不需要投资昂贵的A100或H100等数据中心级GPU(单张售价可达数万美元),一张几千元的游戏显卡就足够完成完整的训练实验。这个环节生动地说明了GPU加速对深度学习训练的重要性——同样的任务,CPU和GPU的效率差异可能是数量级的。

最终参数量:1369万
模型训练完成后,UP主查看了最终的参数规模:13,693,824个参数,恰好落在最初设定的10-30百万目标区间内。这是一个真正意义上的"迷你"语言模型,但麻雀虽小五脏俱全。作为参考,GPT-2的最小版本约有1.17亿参数,GPT-3达到1750亿,而GPT-4据估计超过万亿参数(部分分析认为其采用了混合专家架构MoE,总参数约1.8万亿但每次推理仅激活其中一部分)。1300万参数的模型大约只有GPT-2 Small的九分之一,但它包含了一个完整语言模型所需的全部组件:token嵌入层将离散的词汇映射到连续向量空间,位置编码赋予模型感知序列顺序的能力,多层Transformer块负责学习语言模式,最终的线性投影层将隐藏状态映射回词表空间以预测下一个token。
从乱码到有意义输出:理解语言模型的本质
第一次对话:胡言乱语的"思考"
模型首次运行聊天功能时,输出的内容基本是无意义的乱码。当被问及"Who is Bernard?"时,模型给出了"Clost, Event"这样毫无逻辑的回答。
但UP主敏锐地指出:即便输出是乱码,也意味着"模型在工作,模型在思考"。他进一步向AI请教了背后的原理,得到了一个非常准确的解释:模型本质上是在基于训练中学到的模式,预测下一个最可能的token,它并不是真正在思考或推理,而是在生成文本。这一机制被称为自回归生成(Autoregressive Generation):模型每次只预测序列中的下一个token,然后将该token追加到输入中,再预测下一个,如此循环往复直到生成完整的回答。每次预测时,模型会为词表中的每个token计算一个概率分数(通过softmax函数将最后一层的logits转化为概率分布),然后根据采样策略选择下一个token。常见的采样策略包括:贪心搜索(Greedy Search,始终选择概率最高的token,输出确定但容易重复)、温度采样(Temperature Sampling,通过温度参数调节概率分布的尖锐程度,温度越高输出越随机越有创意)、Top-K采样(仅从概率最高的K个候选token中采样)和Top-P采样(也称核采样,从累积概率达到P的最小token集合中采样)。乱码输出说明模型在预训练阶段还没有充分学习到有意义的语言模式和知识——权重基本还是随机初始化的状态,输出的token序列自然也是近乎随机的。

监督微调(SFT)带来的质变
要让模型输出更连贯的内容,就需要引入监督微调(Supervised Fine-Tuning, SFT)。这一步会用"提示-回答"的示例对模型进行训练,让它学会以对话的形式响应。
现代大语言模型的训练普遍采用"预训练+微调"的两阶段范式,这一方法论最早由GPT-1系统性地确立。预训练阶段使用大规模无标注文本,通过自回归的下一个token预测任务让模型学习语言的统计规律、语法结构和世界知识,相当于让模型"博览群书"。而SFT阶段则使用人工标注的高质量"提示-回答"对,教会模型按照人类期望的格式和方式来响应指令——从技术实现角度看,SFT本质上是在预训练好的模型权重基础上,使用新的训练数据继续反向传播优化,让模型的输出分布从"通用文本续写"偏移到"按指令回答问题"。在更完整的流程中(如InstructGPT/ChatGPT),SFT之后还会引入基于人类反馈的强化学习(RLHF)来进一步对齐模型行为——RLHF通过训练一个奖励模型来模拟人类偏好,再用近端策略优化(PPO)等强化学习算法让语言模型的输出最大化该奖励信号。近期的研究也提出了DPO(Direct Preference Optimization)等简化方法,无需单独训练奖励模型即可实现类似效果。本项目虽然省略了RLHF步骤,但完整展示了从预训练到SFT的核心转变——正是这个转变让模型从输出乱码变为能够进行有意义的问答。
UP主运行了fine_tune.py脚本,这个过程会加载已有的checkpoint,在SFT数据上继续训练,并生成新的checkpoint供模型使用。这里的checkpoint(检查点)机制是深度学习训练中的重要实践:训练过程中定期将模型的权重参数、优化器状态和训练进度序列化保存到磁盘,这样不仅可以在训练中断时从断点恢复,更重要的是可以作为微调的起点——正如本项目中fine_tune.py加载预训练checkpoint后在SFT数据上继续训练。他总结出了完整的工作流闭环:创建更多数据集 → 准备数据 → 训练 → 微调。
惊艳的最终成果
经过多轮迭代和数据补充,再加上解决了一个关键的兼容性问题——最初安装的Python 3.14与GPU不兼容,在Gemini的帮助下降级到3.12后,训练才真正跑在GPU上。这个问题反映了深度学习工具链中一个常被忽视的细节:CUDA工具包、GPU驱动、PyTorch版本和Python版本之间存在严格的兼容性矩阵。Python 3.14作为较新的版本,很多编译好的带CUDA支持的PyTorch二进制包可能尚未提供对应版本,导致pip只能回退安装CPU版本。降级到广泛测试和支持的Python 3.12是最务实的解决方案。
最终,模型给出了令人满意的答案:
"Bernard Polidario是一位来自菲律宾的软件工程师,他的生日是1986年8月10日。"
这个回答不仅语法正确,而且信息准确,标志着这个从零构建的迷你LLM真正"学会"了训练数据中的知识。
这个实验带来的启示
这场实验虽然带着娱乐化的色彩,但其技术价值不容忽视。它证明了在AI编程工具的加持下,构建一个可运行的小型语言模型的门槛已经大幅降低——即便是对底层原理不甚了解的爱好者,也能在AI助手的引导下完成分词、预训练、微调的完整流程。
同时,这个项目也是理解LLM工作原理的绝佳教材。从乱码输出到有意义回答的转变过程,直观地展示了预训练与微调的作用差异,以及"模型只是在预测下一个token"这一核心机制。值得一提的是,这种"小模型实验"的思路在学术界也有先例——Andrej Karpathy(前OpenAI联合创始成员、前特斯拉AI总监)曾发布nanoGPT项目,用约300行核心代码复现了GPT-2的训练过程。nanoGPT引发了一波"从零构建LLM"的教育热潮,随后社区涌现出llm.c(Sebastian Raschka用纯C语言实现的LLM训练)、miniGPT等一系列极简实现。这类项目的价值不在于训练出实用的模型,而在于剥离工程复杂性后,让学习者直接面对Transformer架构的核心数学和逻辑。本文中的TinyGPT项目延续了这一精神,其设计哲学与nanoGPT一脉相承:通过动手构建来真正理解原理。
对于想入门LLM的开发者来说,与其一开始就挑战庞大的模型,不如从这样的迷你项目起步——用消费级显卡、几百行代码、极少的依赖,亲手走一遍训练全流程,或许比阅读十篇论文来得更加深刻。这种"learning by building"的方法论也正是当下AI教育的一个重要趋势:当工具足够简单、计算足够廉价时,每个人都可以成为大模型原理的第一手探索者。
核心要点
核心要点
相关推荐

AI图像编辑为何总是越改越崩?一致性困境深度解析
AI图像编辑中反复修改导致结果失控是常见痛点。本文从扩散模型原理、误差累积机制等角度,深入分析AI图像编辑一致性问题的技术根源,并提供Inpainting、固定种子等实用缓解策略。

Vercel开源fx:仅6MB的Zig编码智能体,极简设计让模型更强
Vercel推出开源编码智能体fx,采用Zig语言编写,仅6MB原生二进制文件,近乎瞬时启动。支持本地与云端模型、MCP协议、Skills插件扩展,可嵌入自有基础设施。极简设计将更多上下文资源留给AI模型,为开发者提供轻量高效的编码工具新选择。

Manus好用但封闭,开源Agent的中间道路在哪?
Manus以极致易用性赢得用户,开源Agent提供完全控制权却门槛极高。本文深入探讨AI Agent领域便利性与可控性的矛盾,分析理想的中间方案应具备的特征:分层开放架构、成品交付体验与可选择的透明度。