news 2026/10/1 19:21:27

AI工程从零手搓:从张量到微型语言模型的完整实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI工程从零手搓:从张量到微型语言模型的完整实践

今年我把大量业余时间投进了一个叫ai-engineering-from-scratch的个人项目。简单说,就是给自己立了条规矩:凡是跟 AI 相关的环节,能自己动手实现的,绝不直接调封装好的接口。从手写张量运算开始,到训练一个微型语言模型,再到把模型量化部署成一个能用的服务,整个过程走下来,收获最大的不是某个模型效果变好了,而是终于弄明白了一个大语言模型从数据集到上线,中间到底经历了什么,出了问题时该往哪个方向查。

这篇文章就围绕这个项目,把我踩过的坑、验证过确实有效的路线、以及现在还保留在收藏夹里的参考材料整理出来。不吹不黑,直接上干货。适合已经会用 PyTorch、会调 Transformers 库,但对底层实现还有点心里没底的人;也适合准备进入大模型应用开发、想从底层建立手感的新手。看完你至少能少走我一半的弯路。

1. 为什么我决定从零开始学AI工程:先别急着调API

1.1 框架用久了,心里不踏实

先说个真实感受。我最早做 NLP 项目时,基本就是transformers库一把梭:加载模型、写个训练循环、调参数、完事。模型跑不动就换更大的显卡,效果不好就换更强的预训练权重。直到有一次,模型在验证集上的损失怎么都降不下去,我把学习率调低、把层数减少、把 dropout 拉满,全都没用。当时我能做的只有百度搜索关键词,然后挨个试网上流传的"玄学改法"。

那天之后我开始反思:我不是在用 AI,而是在调一个巨大的不透明的黑盒子。梯度怎么传播的、学习率策略在内部到底起了什么作用、显存为什么爆、推理为什么慢,这些问题我都答不上来。而这些问题恰恰是 AI 工程里最核心的问题。框架用久了,AI 工程变成了一种"配置工程",这对工程师来说是非常危险的。一旦遇到模型异常、数据泄漏、显存瓶颈这类问题,不懂底层就只能靠猜,而靠猜的代价是极其昂贵的。

所以我才决定做from scratch这件事。不是去重写 PyTorch,也不是去发明新一代算法,而是把现代语言模型里最关键的模块一个个抽出来,用最朴素的方式实现一遍。注意力机制自己写、分词器自己写、训练循环自己写、量化脚本自己写。写完之后再回到框架里,你会发现自己不是在使用框架,而是在理解框架,心态完全不一样。

1.2 从零手搓到底要学什么,范围怎么划

刚开始我也很迷茫,因为"AI 工程"这个范围太大了。做 CV 的需要懂卷积、数据增强、分布式训练;做推荐的需要懂特征工程、Embedding、在线学习;做 NLP / LLM 的需要懂分词、Transformer、微调、推理优化。如果不能明确边界,这个项目很可能变成一个永远完不成的大坑。

我的做法是先把全链路画成一个流程图,再从里面选出"必须亲手做一遍"的核心节点。我这里所谓的流程图,并不是画给别人看的那种,而是写给自己确认用的清单。我的清单大致是:

  • 数据处理:分词器、批次构建、数据采样
  • 模型构建:Embedding、多头注意力、前馈网络、层归一化
  • 训练系统:损失函数、反向传播、优化器、学习率调度
  • 推理系统:自回归生成、KV Cache、采样策略
  • 部署优化:量化、批处理、服务化接口
  • 模型进阶:在基础模型之上尝试"先思考、再回答"的推理行为

每个节点只追求"能跑通、能解释、能量化效果",不做过度扩展。比如我不会去手写 CUDA kernel,因为那已经超出一般的 AI 工程范围,属于系统底层优化,跟当前目标不对齐。先把上层的每一个工程环节摸透,等将来遇到 perf 瓶颈时再下沉也不迟。

这个范围划完之后,我给自己定了三个里程碑:第一,用 NumPy 手写一个能训练 MNIST 的迷你神经网络;第二,用 PyTorch 从零实现一个小型 GPT,在几十 MB 的数据上训练出能生成文本的模型;第三,对第二个模型做量化压缩和推理加速,部署成一个 HTTP 服务。后面所有的工作都围绕这三个里程碑展开。

2. 我的学习路线:把黑盒拆成白盒的六个阶段

2.1 六个阶段,一层层揭开隔层

我给自己制定了递进式路线,不是上来就写 Transformer,而是按照"造一台机器"的顺序去推进。如果你也想照这条路走,我建议你严格按顺序来,不要贪快。

第一个阶段是 Python 编程与数据操作。重点不是语法,而是对"数据到底长什么样"有直觉。列表、字典、字符串处理、文件读写,配合collections.Counter做词频统计,这样后面写分词器时不会发怵。

第二个阶段是手写张量与自动求导。现阶段不建议直接上 PyTorch,而是先用 NumPy 自己实现一个极简的张量类,只支持标量、向量、矩阵的加法乘法,以及对某个参数的梯度记录。这个阶段的核心任务是理解反向传播到底在做什么,而不是把所有细节都搞完。我做了一个非常粗糙的自动求导,只有几十行代码,但它让我第一次看懂了链式法则在程序里如何落地。

第三个阶段是手写 MLP 和简单 CNN。用自己写的自动求导工具去训练一个识别手写数字的模型,把梯度下降、过拟合、正则化这些基础概念体验一遍。很多人跳过这个阶段直接学大模型,但我强烈不建议。因为大模型也依赖同样的数学机制,如果连一个隐藏层的 MLP 都调不明白,后面遇到 Transformer 的异常会更难定位。

第四个阶段是学习和实现注意力机制。注意力是任何现代语言模型的灵魂,它做的事本质上就是"根据相关性从其他位置上取信息"。先手写单头注意力,再扩展成多头,最后加上因果掩码。

第五个阶段是把注意力堆成 Transformer,实现一个微型 GPT。从 token 化文本开始,训练一个几百万参数的小模型,让它生成看起来像模像样的句子。

第六个阶段是推理优化与部署。把训练好的权重量化成半精度或整数精度,加上 KV Cache,写一个流式生成接口,再封装成一个所有人都能通过 HTTP 调用的服务。

每个阶段我都有对应的完成标准。比如第四阶段的完成标准不是"理解了注意力公式",而是"写出一个能跑、能反向传播的多头注意力模块,并在小数据集上训练收敛"。这样就不会陷入漫无目的的看论文状态。

2.2 参考书怎么用:读一遍不如改一遍

在我动手的过程中,最常被问到的一句话是:你到底用什么学的?我的答案很直接:《Build a Large Language Model From Scratch》这本书给了我很重要的路线参考。这本书从数据准备开始,一步步搭建类似 GPT 的结构,包含分词、注意力、训练、微调等完整内容。书里的代码风格非常朴素,没有花里胡哨的高级封装,很适合配合这个项目来理解每一个环节。

但我还得提醒一点:读这本书,千万不要只停留在"读"上。我第一次读的时候以为看懂了,结果合上书自己写,连masked_fill都写错了位置。后来我换了个策略,把书里的每段代码都当成参考实现,然后关掉示例代码,自己重新实现一遍,遇到卡壳再回去对照。这样读一遍书,等于自己写了三遍代码,效果完全不一样。

除了这本书,我还会配合看一些原始论文和开源项目。书不会覆盖所有细节,比如混合精度训练、KV Cache 的显存优化、量化感知训练,这些工程问题需要从零散的源码和文章中补全。我的经验是:以书为主线建立骨架,再以论文和源码为枝叶填充细节,最后用自己的代码验证理解。

3. 从零手搓一个微型语言模型的完整流程

3.1 先解决"词"的问题:手写 BPE 分词器

语言模型处理的是 token,不是原始字符串。所以从零搭建模型,第一步就是解决怎么把一段话切成 token。"按空格切词"虽然简单,但会得到一个巨大的词表,而且无法处理没见过的新词,所以现代模型普遍使用字节对编码(BPE)。BPE 的核心思想是:先把文本看成 UTF-8 字节序列,然后反复统计相邻字节对的出现频率,把最高频的对合并成一个新符号,直到词表达到目标大小。

手写 BPE 时最关键的数据结构是一个计数用的字典。首先是统计相邻字节对频率:

def get_stats(ids): counts = {} for pair in zip(ids, ids[1:]): counts[pair] = counts.get(pair, 0) + 1 return counts

然后在每一轮迭代中找到频次最高的 pair,把它的两个 id 合并成一个新的 id:

def merge(ids, pair, new_id): result = [] i = 0 while i < len(ids): if i < len(ids) - 1 and ids[i] == pair[0] and ids[i+1] == pair[1]: result.append(new_id) i += 2 else: result.append(ids[i]) i += 1 return result

这个过程初看很简单,但真正实现时有一个坑:随着合并的进行,id 长度会变化,新的高频 pair 必须基于上一轮合并后的序列重新统计。如果理解错了,合并顺序就会乱掉,分词结果会有问题。我当时就是在这里犹豫了很久,后来意识到"每次合并后全局重新统计"才是标准做法,而不是在一个固定列表上连续改。

3.2 核心模块:手写多头注意力的几个细节

注意力模块是整个模型中最容易写错、也最值得亲手实现的部分。常见的公式非常简单:Q 和 K 做点积、除以根号 d、加上掩码、Softmax、再乘 V。但工程实现时,有几个细节特别值得注意。

第一个是因果掩码。语言模型生成时只能看前面的 token,不能偷看后面的内容。实现方式是把未来位置的值设成负无穷,经过 Softmax 之后概率趋近于零。我在第一次实现时用的掩码矩阵是对的,但维度 broadcast 没对齐,结果训练损失直接乱跳。排查了很久才发现是掩码形状错误。手动实现时,建议把每一步的张量形状打印出来,别嫌麻烦。

第二个是缩放因子的作用。除以sqrt(d_k)不只是为了让数值范围更好看,而是防止点积结果过大导致 Softmax 进入饱和区,梯度变得极小。如果不缩放,模型在小数据集上也能跑,但训练会明显变慢,损失曲线的尾巴还会抖动。

第三点是多头注意力中"头"的意义。多头不是简单地叠加多个注意力结果,而是让每个头学到不同的相关性模式。有的头可能关注前一个词,有的头可能关注句法成分。虽然我们在代码层面只是把 d_model 切成几段分别计算,但正是这种参数独立性让模型表达力变强了。手写时我建议先按"循环每个头"的方式写一版,跑通后再改成"矩阵并行版",这样对分块的印象会特别深刻。

第四点是残差连接和层归一化的位置。Transformer 每一层结构是"注意力 -> 残差 -> 层归一化 -> 前馈网络 -> 残差 -> 层归一化"。残差连接让梯度有一条高速公路可以直达底层,层归一化稳定每一层的激活分布。顺序如果搞错了,模型的训练稳定性和最终效果都有明显差距。

3.3 训练循环里的关键决策:学习率、批次和损失

模型搭完了,训练循环也不像想象中那么简单。我最初写的训练循环只是"取数据、算 loss、反向传播、更新",结果模型一直不收敛。后来我逐项排查,发现真正影响训练效果的是几个细节:随机种子是否固定、数据是否被随机打乱、学习率调度是否合理、梯度有没有做裁剪。

学习率我很推荐使用 warmup + cosine 的调度方式。一开始用一个很小的学习率热身,让参数更新不会太激进,然后再逐步降到接近零,让模型在后期做好精细调整。我用的配置大致是:warmup 步数约占总步数的 3% 到 5%,峰值学习率在1e-3到3e-4之间,具体看模型规模和 batch size。

批次大小也很关键。我的显卡资源有限,单批放不了太多样本,就用梯度累积来模拟更大的批次。注意梯度累积不是直接改batch_size,而是在多个小批次上累计梯度,然后再做一次优化器更新。梯度累积的步数需要根据显存实测来定,我试过累积 4 步效果最稳。

数据处理上我加了一条保护线:验证集绝对不参与训练,而且验证集的数据顺序每次都要固定。有一次我偷懒,直接在数据类里给训练集和验证集用了同一个 shuffler,结果验证损失一直往下掉,训练损失却不降,后来才发现是验证集里混进了训练样本,数据泄漏的坑差点没把我逼疯。

训练过程中我习惯每 20 个 step 打印一次 loss 和当前学习率,每 200 个 step 在验证集上算一次困惑度。损失曲线的形态非常有信息量:如果训练 loss 下降但验证 loss 上升,那是过拟合;如果训练 loss 不降,那多半是学习率太高、数据有泄漏或者模型结构写错了。

3.4 采样策略:怎么让模型说得"像人话"

模型训练完之后,生成阶段同样有很多坑。语言模型是逐步生成 token 的,每次预测下一个 token 的概率分布,然后从分布中采样。如果每次都选概率最大的 token,就是贪心解码,虽然稳定但容易重复、死板。如果每次都纯随机采样,句子会变得前言不搭后语。

我实测下来,配合使用temperature、top-k 和 top-p效果最好。Temperature 控制分布的尖锐程度:温度小于 1 的时候概率集中到高概率 token 上,生成的文本更保守;温度大于 1 的时候分布更平缓,文本更大胆。Top-k 是只从概率最高的 k 个 token 中采样,避免给那些几乎不可能的 token 太多机会。Top-p 则是动态选择累计概率超过阈值的 token 集合,比 top-k 更灵活。

我常用的一个组合是:temperature=0.8, top_k=40, top_p=0.9。这个组合在我训练的几百万参数小模型上,生成结果既有一定的多样性,也不会很快陷入重复循环。如果你发现模型总是重复同样的句子,可以适当把 temperature 调高一点,或者增大 top-p 阈值;如果发现上下文不连贯,则降低 temperature 会更有效。

4. 从"生成"到"推理":小模型也能学会思考链

4.1 推理模型与传统模型到底差在哪里

当我把基础语言模型跑通之后,我注意到行业里的讨论热点开始转向另一个方向:让模型在回答之前先做一段"内部推理",再给出最终答案。传统语言模型是"输入问题,立刻输出答案",而推理模型的生成结果是"先输出一系列思考过程,再输出最终结论"。这个过程类似于人在纸上打草稿:草稿越长,越有机会通过逐步演算推导出正确答案。

从工程角度看,两者最主要的差别不在模型结构,而在训练方式。一个普通模型在训练时看到的是"问题 -> 答案"的配对;而一个具备推理能力的模型,在训练时会看到"问题 -> 思考过程 -> 答案"的完整链路。思考过程被当作可学习的文本参与训练,模型因此学会了在回答前主动进行推理。

另一个关键点是强化学习在这种训练中的应用。为了让模型学会找到更好的思考路径,社区里出现了很多从零构建推理模型的项目。核心做法是:让模型对同一个问题生成多条不同的推理路径和答案,然后根据答案是否正确以及推理路径是否合理给予不同强度的更新信号。做得好的路径会得到正向强化,做得差的路径会被抑制。这个过程不依赖人工标注的标准推理文本,而是通过模型自身的探索来进化,成本低很多,效果却可能很好。

我个人的立场是:如果你想搞懂 modern LLM 的完整能力边界,"从生成到推理"这一步非常值得复现。它也是从"会做 Next Token Prediction"向"会解决问题"进阶的关键一步。

4.2 我在小模型上复现推理能力的实操尝试

理论清晰之后,我决定在自己的小模型上进行尝试。我先准备了一批带思考链的训练数据。数据来源不是去爬什么高不可攀的内容,而是自己写规则生成:对于数学加减法、字符串反转、简单逻辑题,先生成问题,再人工写一段分步骤的思考文本,最后给出答案。数据量控制在几万条以内,一方面是因为我算力有限,另一方面也足以验证"小模型是否能学到推理行为"。

训练时我用的是监督微调:在已经训练好的基础模型之上,用这批带思考链的数据继续训练。关键技巧是思考过程的特殊 token 分隔。我在文本中插入[THINK]和[ANSWER]两个特殊标记,让模型明确知道哪里是思考区、哪里是答案区。推理时,生成到[ANSWER]之前的部分就是模型的思考过程。

实测结果很有意思。一个参数量不到两百万的小模型,经过几千步有思考链数据的微调之后,面对简单加法问题时,确实会先输出类似"先把十位和个位分别相加,然后处理进位"这类的过程文本,再给出最终答案。虽然思考过程经常有废话,但正确率比起微调前有明显提升。

不过也有明显的局限性:模型在陌生题型上基本不具备泛化推理能力,它只是记住了"遇到问题要先输出一段过程"的模式。这说明 from scratch 复现推理模型,不是简单加数据就行,可能还需要引入更多的强化学习策略。但作为工程入门,走一遍这个流程已经让我很清楚地理解了思考链的本质:它不神秘,只是把"未显式建模的中间计算过程"变成"可训练的文本序列"。

做这一步时还有一个非常重要的提醒:数据合规和版权问题永远不能绕开。不要从不明渠道下载所谓的全套数据或者盗版资源,自己写规则生成、使用合规的开源数据,才是能长期复用的做法。模型能力可以慢慢提升,合规底线是绝对不能突破的。

5. 工程化落地:模型能跑只是第一步

5.1 量化、KV Cache 与推理加速

在本地把模型训练出来之后,真正让人头疼的是怎么让它跑得更快、占用资源更少。我一开始直接用 PyTorch 逐 token 生成文本,结果慢得离谱。后来才发现我连最基础的 KV Cache 都没有加。

KV Cache 的核心思想非常朴素:生成下一个 token 时,前面所有 token 的 Key 和 Value 矩阵其实已经算过了,没必要重新计算。把这些结果缓存起来,每次生成只需要算新 token 的相关部分,推理速度能提升一个量级。我的小模型加上 KV Cache 之后,生成 200 token 的耗时直接降为原来的三分之一。

除了 KV Cache,量化是另一个大头。训练好的模型参数默认是 32 位浮点数,占内存大、计算慢。把权重转成 16 位、8 位甚至 4 位整数,就能非常显著地压缩模型体积。我做的是一种比较简单的训练后量化方法:先统计每一层权重的数值范围,然后把浮点数映射到整数范围,推理时再反量化回浮点数。对于我的小模型,从 FP32 压到 INT8 后,模型体积减小了接近四倍,生成结果的质量几乎没有肉眼可见的下降。

量化过程里最容易踩的坑是"校准"。直接拿模型权重的 min/max 做映射,有时候会被离群点带偏,导致量化后某些层输出异常。我当时用一批验证集数据观察每层的激活分布,选择合理的截断范围之后再量化,效果立刻稳定了很多。简单说,量化不是简单的数学映射,它需要数据来辅助确定映射参数。

5.2 微调阶段的数据配比与防灾难性遗忘

工程化之后,我开始尝试在自己的基础模型上做微调。初始阶段最容易犯的错误是用单一任务的数据把整个模型反复训练,结果只要训练步数稍微多一点,模型原有的通用能力就被大幅破坏了。这个现象有一个专门术语叫灾难性遗忘,我一开始天真地以为只要学习率够小就没事,后来发现远远不够。

解决灾难性遗忘,我验证有效的方法有三个。第一是混入通用数据,微调数据中至少保留 30% 到 50% 的基础语料,让模型一边学习新任务一边维持旧知识。第二是降低微调阶段的学习率,比预训练阶段低一个数量级。第三是使用 LoRA 这类参数高效微调方法,只训练一小部分附加参数,原有参数尽量不动。

LoRA 的原理是把要更新的权重矩阵分解成两个低秩矩阵,训练时只更新这两个小矩阵,推理时再合并回原权重。这样不仅显存占用大幅降低,而且对原有参数的扰动很小。我在实验中发现,LoRA 加上混合数据,能把新任务的表现提升不少,同时依然能流畅生成普通文本,效果比全量微调稳定得多。

数据配比这件事没有万能公式,但有一个通用的排查方法:每次微调完成后,在上一个版本模型的测试集上做一次回归评测,如果得分明显下降,就说明数据配比或学习率可能有问题。我前前后后调整了三次配比,最终确定了一个能兼顾两边的比例,这个经验值只对我的场景有效,但"添加回归验证集"这个方法对任何人都有用。

5.3 从单机实验到服务化部署

模型调好之后,要把模型给别人用,就得做服务化部署。我没有引入过于复杂的架构,而是用了一个非常简单的思路:把模型加载到一个常驻进程里,通过 HTTP 接口接收文本请求,生成结果后返回。这样做的好处是模型只在启动时加载一次,不用每次请求都重新初始化。

这里有一个非常容易踩的坑:服务进程必须设置超时机制。我的模型虽然只有几百万参数,但在无 GPU 的环境下生成一段长文本仍然可能耗时几秒。如果客户端超时时间设得太短,就会频繁报错。解决办法有两个:一是用流式返回,模型每生成一个 token 就推给客户端一部分;二是把生成请求丢到任务队列里异步处理,客户端去轮询结果。我实际项目中先用了流式返回,交互体验好很多。

另外,多进程服务一定要小心模型副本占用的显存或内存。如果使用gunicorn这类多进程服务器,每个 worker 都会加载一份模型副本。我试过默认配置,结果服务启动后内存直接翻了几倍。解决办法是根据实际内存限制 worker 数量,或者改用多线程。这个细节不亲自部署一次,是很难从文档里学到的。

6. 我踩过的坑:问题排查与避坑速查表

6.1 训练不收敛:三个最常见的元凶

我的模型第一次训练时,loss 一路降不下去,我很确定自己代码没有语法错误,就把锅甩给了数据量太小。后来我系统排查了一遍,发现根本原因和学习率有关:我用了条很低的学习率,导致模型几乎在原地踏步。把学习率从1e-4提到1e-3之后,loss 立刻开始下降。检查学习率,绝对是排查不收敛的第一动作。

第二个常见元凶是数据顺序没有打乱。如果每个 epoch 内样本顺序完全不变,模型会学到顺序上的伪特征,训练 loss 也能降,但验证 loss 非常不稳定。打乱数据之后,问题基本就消失了。

第三个元凶是初始化。使用 PyTorch 默认初始化的 Transformer,在小模型上训练时有时会遇到严重的梯度异常。我后来把每个线性层的权重标准差按照隐藏层维度的倒数来缩放,也就是非常流行的 small initialization 技巧,训练稳定性明显提升。不要小看这几行初始化代码,它对整个训练过程影响巨大。

还有一个容易被忽略的元凶:损失函数和标签的对齐。我在实现交叉熵损失时,一开始把 labels 设置成了形状不匹配的 tensor,PyTorch 没有直接报错,而是静默广播了,导致模型学到了一个非常奇怪的分布。发现这个问题后,我在训练循环里加了一个assert检查张量形状,遇到形状不一致的情况立刻中断。

6.2 显存爆炸与训练速度过慢的排查思路

当我把模型从几百万参数扩到一两千万参数时,显存瞬间告急。第一个原因是注意力矩阵的平方复杂度:序列长度为 512 时,注意力矩阵是 512 乘以 512,显存开销随序列长度平方增长。解决办法是把最长序列控制在 256,或者改用梯度累积减少单批显存峰值。

第二个原因是优化器状态比想象中更占内存。Adam 优化器本身要保存每个参数的动量变量和方差变量,再加上模型参数和梯度,实际显存占用接近参数的 7 到 12 倍。所以不要看到模型只有几百万参数就觉得内存肯定够用。混合精度训练是很好的缓解手段,但要注意梯度缩放和 loss scaling,否则很容易出现溢出导致 loss 变成 NaN。

我在排查显存问题时写了一个简单脚本:利用 PyTorch 的显存统计工具,在训练循环前后打印reserved和allocated内存,很快就定位出哪个模块占用了大头。这种可视化统计方法比肉眼猜测高效得多。如果你也遇到 OOM,建议先用这个思路搞清楚内存分配在哪里,再决定是减小序列长度、减小 batch,还是换一种注意力实现。

6.3 常见问题速查表

问题现象可能原因排查方向解决方案
训练 loss 不降学习率过低或过高打印每个 step 的 loss 和学习率使用 warmup + cosine 调度,调峰值学习率
训练 loss 下降但验证 loss 不降数据泄漏或过拟合检查验证集来源,观察训练/验证差距重建验证集,混入通用数据
验证 loss 剧烈震荡数据顺序未打乱 / batch 太小检查数据加载器是否 shuffle开启 shuffle,或增大批次
推理速度极慢没有 KV Cache打印每 token 生成耗时实现 KV Cache,复用历史 Key/Value
模型生成总是重复采样策略太保守观察生成文本的重复率调高 temperature,禁用重复 n-gram
量化后效果暴跌校准数据不足 / 离群点影响对比量化前后每层输出分布用验证集做校准,设置合理的截断范围
服务启动后内存翻倍多进程加载多份模型副本查看进程内存占用限制 worker 数或改用线程

这些坑都是我实际踩过的。第 4 条 KV Cache 的坑尤其隐蔽,因为模型小的时候速度差异不明显,一旦把序列长度拉长,差距立刻显现出来。第 6 条量化校准则直接关系到模型能不能在低资源环境下部署,值得多花时间仔细调。


最后再分享一个我现在仍然在用的习惯:每跑一次实验之前,先把随机种子固定好,然后把数据处理流程写成可复现的脚本,任何一步出错都能从缓存重放。这个习惯在 ai-engineering-from-scratch 项目的后半段帮了我大忙,因为改动一旦多了,你根本无法判断效果变化到底来自数据、模型版本还是训练参数。固定种子、缓存数据、记录每次实验的配置,这三件事坚持做下来,整个项目才真正算得上"工程",而不是一次性的代码练习。如果你也打算从零开始走一遍 AI 工程,我建议你从写一个最简单的手写数字分类器起步,再一步步走到语言模型和部署。这条路不易,但走完之后的底气是任何框架封装都给不了的。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 19:20:17

AI工程化落地指南:从智能体训练到多AI协作工作流

今天是2026年9月22日&#xff0c;星期二。照例&#xff0c;我把过去24小时里AI圈值得关注的信息仔细捋了一遍——模型侧有新的训练方法公开&#xff0c;应用侧有几个项目落地动作&#xff0c;开发工具链这边也有不少更新。这篇日报我会尽量少说空话&#xff0c;每条信息后面都附…

作者头像 李华
网站建设 2026/10/1 19:19:57

AI驱动Blender MCP快速生成智慧仓储数字孪生模型

1. 项目缘起与整体架构拆解1.1 为什么选“智慧仓储”作为数字孪生落地场景做数字孪生这几年&#xff0c;我经手过园区、机房、产线、变电站好几个方向&#xff0c;最后发现智慧仓储是最适合拿来练手、也最容易出效果的场景。原因很直接&#xff1a;仓储空间的几何结构规整&…

作者头像 李华
网站建设 2026/10/1 19:19:10

iOS上运行Windows程序:Wine+FEX-Emu+DXMT兼容层实战

1. 项目缘起&#xff1a;为什么要在 iOS 上折腾 Wine 兼容层第一次看到 "Madeira" 这个项目名&#xff0c;很多人会以为是那个葡萄牙的旅游海岛&#xff0c;但在我们这群喜欢折腾跨平台兼容层的人眼里&#xff0c;它指向的是另一件事&#xff1a;把 Windows 应用搬到…

作者头像 李华
网站建设 2026/10/1 19:18:56

ShuffleNet轻量CNN实战:8类菠萝成熟度图像分类

简介&#xff1a;基于ShuffleNet的轻量级图像分类实战项目&#xff0c;面向有基础CNN知识、希望在移动端或小模型场景落地分类任务的开发者。完整覆盖菠萝成熟度8分类流程&#xff0c;数据集划分清晰&#xff0c;训练集4808张、测试集806张&#xff0c;并已提供训练好的权重文件…

作者头像 李华
网站建设 2026/10/1 19:18:38

openrig 实战:用 YAML 和 tmux 统一编排 Claude Code 与 Codex

1. 从零认识 openrig&#xff1a;它到底解决什么问题第一次看到 openrig 这个名字&#xff0c;很多人会以为是某个硬件支架项目&#xff0c;毕竟 rig 在英文里有“装配、支架”的意思。但在当前 AI 编程工具爆发的语境下&#xff0c;openrig 指向的是一个非常具体且刚需的方向&…

作者头像 李华
网站建设 2026/10/1 19:18:32

基于ShuffleNetV2的菠萝成熟度分类:轻量级CNN实战全流程

简介&#xff1a;面向深度学习入门者与图像分类实践者的轻量级卷积神经网络实战项目&#xff0c;以ShuffleNet为基础&#xff0c;完成8种不同阶段菠萝成熟度的自动分类任务。模型参数量约一百万&#xff0c;采用余弦学习率衰减训练五十轮&#xff0c;测试集最佳精度达百分之八十…

作者头像 李华