ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AI工程从零到一:手写神经网络到全链路部署实战

AI工程从零到一:手写神经网络到全链路部署实战 很多做AI的人聊起ai-engineering-from-scratch这个词第一反应是从零手写一个神经网络。说实话我以前也这么想总觉得不依赖任何深度学习框架、纯用NumPy把反向传播撸出来才算真正入门。后来在真实项目里折腾了几轮我才意识到这个from scratch的边界比想象中大得多——它不只是从零实现一个模型更是从零搭建一整套AI工程能力数据怎么管、训练怎么调、模型怎么上线每一步都透着工程二字的分量。这篇内容就是围绕这个标题做的一次完整复盘把我从算法理论、手写实现到数据管线、模型部署这几个阶段踩过的坑和沉淀下来的方法原原本本摊开讲。不管你是刚接触AI的初学者还是已经在用现成框架做项目、想补一补底层原理和工程细节的工程师这篇文章应该都能给你一套清晰可执行的路径。1. 先想清楚from-scratch到底指的是什么1.1 别把from-scratch理解成不用任何库我见过不少人一听说某项技术要from scratch就条件反射地认为必须拒绝所有依赖连NumPy、Pandas都不想用恨不得直接用纯Python写矩阵运算。这种理解其实有点偏激了。在实际工程里from-scratch的核心诉求不是从零造轮子而是从零建立完整认知。我们拿盖房子打比方。你不用亲自去烧砖、炼钢但你得知道地基怎么打、承重墙怎么布置、水电管线怎么走。同样做AI工程你完全可以借助NumPy、PyTorch这些现成工具但如果只停留在调用接口的层面出了问题就会两眼一抹黑Loss不下降不知道从哪排查模型上线后推理延迟高不知道瓶颈在哪数据分布变了也不知道该怎么调整。所以我理解中的from-scratch包含三层意思从零理解核心原理知道梯度下降在做什么、反向传播为什么有效、Transformer里的注意力机制到底是怎么计算的。从零构建完整流程不止是训练一个模型而是从数据采集、清洗、特征工程到模型训练、评估、部署、监控全链路都亲手过一遍。从零建立调试能力遇到问题知道从哪里切入能用底层原理指导排查而不是盲目调参。搞清楚这三点你再去看这个标题就知道它不是让你当一个人肉深度学习框架而是让你成为一个真正具备工程思维的AI从业者。1.2 AI工程的能力地图你其实要学四件事很多初学者最大的困惑是内容太多不知道从哪下手。我建议先画一张能力地图把AI工程拆成四个板块然后逐个击破。第一板块是基础算法能力。线性代数、概率统计、微积分这些数学基础加上机器学习经典模型线性回归、逻辑回归、决策树、SVM等和深度学习核心组件MLP、CNN、RNN、Transformer。这一层的目标是知其然也知其所以然。第二板块是数据工程能力。包括数据采集、数据清洗、特征工程、数据标注管理、数据版本控制。很多算法工程师不太重视这块但实际项目里数据质量往往比模型结构更影响最终效果。第三板块是模型训练与调优能力。包括损失函数设计、优化器选择、学习率调度、正则化策略、超参数搜索、实验跟踪与结果复现。这一层直接决定了模型能否收敛、能否达到预期精度。第四板块是部署与运维能力。包括模型导出、推理服务封装、性能优化量化、剪枝、蒸馏、监控告警、模型版本管理与回滚。这块是目前行业里最缺人的环节。我自己走下来的体会是很多人在第一和第三板块花了大量时间却忽略了第二和第四板块结果就是模型在实验环境里跑得很好一上生产就崩。后面的内容我会按这张能力地图逐层展开重点放在实操细节上。1.3 数学基础到底要学到什么程度说到数学我知道这是很多人劝退的地方。其实从工程角度讲你需要掌握的数学远没有你想的那么恐怖。让我用驾驶汽车来做个类比你不必成为汽车工程师才能开车但你必须懂油门、刹车、方向盘的作用以及仪表盘上每个警告灯的含义。同样的道理做AI工程你需要掌握的核心数学知识其实是有限的线性代数重点是矩阵乘法、向量空间、特征值分解的基本概念。回到深度学习里一个全连接层就是一次矩阵乘法注意力机制里的Q、K、V也是矩阵运算。你不需要会手动计算复杂的矩阵分解但要清楚运算的维度变化。微积分重点是偏导数、链式法则。反向传播的实质就是链式法则的反复应用。你不需要背下来几十个求导公式但要能理解梯度是怎么从输出层一层层传回输入层的。概率统计重点是概率分布、期望、方差、最大似然估计。损失函数的设计和模型评估指标都跟概率有关。我的建议是不要花几个月去系统学一遍数学再开始动手而是边做边补。比如你手写一个线性回归发现要用到梯度下降那就把梯度下降的数学推导搞透。用项目倒逼学习效率最高。2. 从零手写第一个神经网络反向传播没那么玄2.1 用NumPy实现线性层与激活函数我最初尝试手写神经网络时选了一个最简单的任务二分类。数据集就用sklearn自带的make_moons两个弯月形的分布。为什么选这个因为数据是非线性的必须用带隐藏层的网络才能分类但又足够简单几秒钟就能训练完。网络结构很常规输入层2个节点隐藏层4个节点输出层1个节点中间用tanh激活函数。先看代码import numpy as np def tanh(x): return np.tanh(x) def tanh_derivative(x): return 1 - np.tanh(x) ** 2 def sigmoid(x): return 1 / (1 np.exp(-x)) # 初始化参数 np.random.seed(42) input_size, hidden_size, output_size 2, 4, 1 W1 np.random.randn(input_size, hidden_size) * 0.5 b1 np.zeros((1, hidden_size)) W2 np.random.randn(hidden_size, output_size) * 0.5 b2 np.zeros((1, output_size))这里的初始化方式值得一提。很多人刚开始会直接用np.random.randn然后乘以一个较大的系数结果训练时loss直接爆掉。原因在于如果初始权重太大经过多层网络后激活值会迅速饱和梯度趋于0模型完全学不动。我之所以乘0.5是为了让输入到隐藏层的加权和在一个相对温和的范围内tanh激活函数在输入接近0时梯度最大。前向传播逻辑很直观每一层就是线性变换 激活函数# 前向传播 def forward(X): z1 np.dot(X, W1) b1 a1 tanh(z1) z2 np.dot(a1, W2) b2 a2 sigmoid(z2) return z1, a1, z2, a2输出层用sigmoid因为这是二分类任务sigmoid输出的值可以解释为属于正类的概率。隐藏层用tanh是因为它的输出范围是[-1, 1]均值接近0有利于下一层的学习。2.2 手写反向传播链式法则的工程实践反向传播是很多人的噩梦但你要是真动手写一次会发现它本质上就是在算每个参数对最终损失的贡献。这就像你要找出一个团队里谁拖了后腿就顺着任务链条一层层回推看谁的影响最大。以二分类的交叉熵损失函数为例def compute_loss(y_true, y_pred): # 加一个小epsilon防止log(0) return -np.mean(y_true * np.log(y_pred 1e-8) (1 - y_true) * np.log(1 - y_pred 1e-8))交叉熵损失的好处是配合sigmoid输出梯度计算会变得非常简洁而且能有效避免梯度消失。我头一次手写时把求导公式推错了写出来的梯度符号反了结果loss不降反升。后来学会一个验证方法数值梯度检验。数值梯度的思想很简单——用定义去近似求导看看你的解析梯度算得对不对def numerical_gradient(f, param, epsilon1e-6): # 对参数做微扰计算(f(parameps) - f(param-eps)) / (2*eps) param_plus param.copy() param_minus param.copy() param_plus epsilon param_minus - epsilon return (f(param_plus) - f(param_minus)) / (2 * epsilon)这个方法在大规模模型上是不现实的要跑两倍的前向传播但对于你手写的小模型做一次梯度校验完全可行。我强烈建议每个手写网络的人都做一遍这个校验它能帮你抓出大部分实现bug。2.3 训练循环梯度下降的完整实现有了前向传播和反向传播剩下就是迭代更新参数了。一个朴素的训练循环大概长这样learning_rate 0.1 epochs 2000 for epoch in range(epochs): z1, a1, z2, a2 forward(X) loss compute_loss(y, a2) # 反向传播 dz2 a2 - y.reshape(-1, 1) # 交叉熵sigmoid的简化梯度 dW2 np.dot(a1.T, dz2) / len(X) db2 np.sum(dz2, axis0, keepdimsTrue) / len(X) da1 np.dot(dz2, W2.T) dz1 da1 * tanh_derivative(z1) dW1 np.dot(X.T, dz1) / len(X) db1 np.sum(dz1, axis0, keepdimsTrue) / len(X) # 更新参数 W1 - learning_rate * dW1 b1 - learning_rate * db1 W2 - learning_rate * dW2 b2 - learning_rate * db2 if epoch % 200 0: print(fEpoch {epoch}, Loss: {loss:.4f})注意看dz2这行a2 - y。这是一个非常经典的化简结果——当损失函数是交叉熵、输出层激活是sigmoid时输出层的梯度恰好等于预测值减去真实值。这个化简不仅让代码更简洁也让我理解了一个重要直觉网络的学习过程本质就是在不断修正预测值和真实值之间的差距。训练结束后模型在make_moons数据集上的准确率轻松超过98%。但从这个简单例子能学到的远不止模型能跑通这么简单。它让我真正理解了几个概念学习率太大loss会震荡甚至发散学习率太小模型学习速度慢得让人抓狂初始化权重对收敛速度影响巨大。2.4 从手写走向框架你该带走什么手写完这个Mini神经网络我并没有继续手写CNN或者Transformer这一步就走到了尽头。但这段经历给我带来的收益是长久的。第一是调试能力。现在用PyTorch遇到Loss不降我不会盲目的调学习率而是会先检查数据是否存在问题再检查模型结构最后看梯度是否正常。这套排查思路根源上就来自那次手写反向传播时做的梯度校验。第二是阅读源码的能力。手写过网络的人去看PyTorch的autograd实现虽然底层细节很多但至少知道它在做什么——每个tensor在记录前向传播的运算图反向传播时按图上的路径计算梯度这跟我手写时维护那些中间变量本质上一回事。第三是对性能的直觉。当你手写过一遍纯NumPy实现的训练循环就会明白为什么GPU能把矩阵运算加速这么多倍也会理解为什么数据加载DataLoader里多线程预取是必要的——因为CPU和GPU之间的数据搬运经常是整个训练流程的瓶颈。所以我的建议是手写一个MLP当作成人礼就好不要沉迷于手写所有模型。真正的AI工程能力要放在更广阔的链条上去打磨。3. 数据工程AI系统里最容易被低估的环节3.1 数据质量检查清单你的模型效果天花板在数据里我见过太多团队把大量的精力花在调模型上最后却发现提升效果最大的动作是修正了训练数据里的标注错误。有句话说得很扎心模型的上限不是由模型结构决定的而是由数据质量决定的。很多时候不是模型不够好而是喂给它的数据本身就带着问题。做AI工程数据阶段我建议至少过一遍这个清单数据分布检查训练集和验证集的特征分布是否一致我在一个分类项目里发现训练集80%来自线上真实数据验证集却混了大量线下采集的数据导致线上效果远低于验证集表现。后来重新划分数据集效果立刻恢复正常。标签质量审计随机抽取一部分训练数据人工重新标注一遍看看标注一致性有多高。图像标注里边界框稍微偏一点会影响不少AP值文本分类里标注标准前后不一致等于给模型灌噪音。缺失值处理策略不能一刀切用均值填充。时间序列里的缺失值可能用前向填充ffill更合理用户特征里的缺失值可能直接用单独的未知类别更有意义。重复样本排查训练集和测试集之间如果有重复样本评估指标会虚高。面试里经常问的数据泄露问题很多时候就是这种低级重复导致的。时间戳完整性如果是时序类任务要检查有没有数据时间戳漂移、乱序、区间空缺的问题。每次我接手一个新项目先不看模型代码先看数据和特征。这个习惯帮我省下了大量后期返工的精力。你也应该把数据审查当作是AI工程的第一步而不是边训练边发现问题。3.2 特征工程的分寸感别过度也别偷懒特征工程在深度学习时代被很多人忽视了。卷积神经网络可以自动学习图像特征Transformer也能从文本中提取语义信息但这不代表特征工程可以完全不做。我的经验是特征工程要分场景看图像、语音、自然语言类任务模型自动学习特征的能力很强人工特征工程收益有限。结构化数据类任务比如点击率预测、用户画像建模特征的构造和选择仍然至关重要。在结构化数据里几个值得认真做的点是数值特征的分箱与归一化、类别特征的编码Target Encoding、Frequency Encoding等、时间特征的周期性拆解年、月、日、星期几、是否节假日、交叉特征的构建。但每次都要带着问题去做这个特征对模型预测有没有增量信息还是纯粹增加了计算复杂度最重要的分寸感来自验证——任何特征工程的操作都要通过离线实验来验证是否真的有用。我记得自己曾经沉迷于构造高维交叉特征结果AUC只涨了0.0001推理耗时却翻了一倍。从那以后我给自己定了一条规矩每次特征变更都要记录线上推理延迟的变化如果收益和成本不成比例宁可砍掉。3.3 数据版本管理与管线设计让实验可复现AI工程容易被忽视的一块是数据版本管理。代码有Git管着模型权重有checkpoint存着但数据集本身呢如果数据变了实验结果的对比就失去了意义。我在项目里会采用这样一套方案简单实用数据目录按日期/版本命名例如dataset_20250115_v3。和模型checkpoint一样给每个版本的数据集生成一个单独的元信息文件样本量、特征列表、分布摘要。实验记录用MLflow、WandB或简单的JSON文件里强制记录数据版本号。对原始数据做只读权限管理任何清洗操作生成新文件不改原文件。这套习惯一开始看起来有点繁琐但当你需要回溯三个月前的实验结果为什么和现在不一样时就会发现它救了大命。AI工程里有个著名的说法你复现不了自己的模型往往不是因为代码变了而是因为数据偷偷变了。要做真正专业的AI工程数据版本管理是和代码版本管理同等重要的事。数据管线层面我的建议是别一上来就上重型工具。先用Python脚本配合Makefile或简单的Shell脚本把流程串起来等团队规模变大了、数据量上来了再考虑Airflow、Prefect这类调度平台。工程上没有银弹只有够用就好、按需演进。4. 模型训练与调优从能跑到跑得好4.1 训练三板斧学习率、批次大小、权重衰减模型能跑到什么效果很多时候在训练开始前就决定了。超参数的选择直接影响收敛速度和最终精度这三板斧是最值得花时间研究的学习率learning rate是影响最大的超参数没有之一。学习率太大loss会震荡甚至发散学习率太小训练可能要跑几个世纪才收敛。工程里的标准做法是用学习率预热warmup配合上余弦退火cosine annealing或指数衰减exponential decay。前几百步用一个较小的学习率让模型稳妥起步之后再用较大的学习率快速收敛最后逐步降低到接近0。这种做法尤其适合Transformer类的模型。批次大小batch size则要结合硬件来定。大批次能更好地利用GPU并行能力训练更快但实验证明大批次往往需要配合更高的学习率才能保持同样的泛化性能。有一个经验法则批次大小翻倍学习率跟着翻倍或做平方根缩放具体可以参考线性缩放法则Linear Scaling Rule。我踩过的一个坑是在单机8卡上用了一个很大的batch size训练结果模型一直欠拟合后来把学习率抬高问题立刻缓解。权重衰减weight decay看起来只是加一个小的L2正则项但它对模型泛化能力的提升非常显著。工程上一般设在1e-4到1e-2之间具体值要试。我在训练ResNet时发现weight decay从0调整到1e-4验证集精度能涨将近2个百分点。这个收益基本白拿何乐而不为。4.2 怎么判断模型真的收敛了判断模型是否收敛比很多人想象的要复杂。只看训练loss下降是远远不够的因为你可能过拟合或者欠拟合而不自知。我最常用的方法是同时观察训练集和验证集的损失曲线。健康的收敛模式是两条曲线同步下降最后趋于平稳且验证集loss和训练集loss差距不大。如果验证集loss先降后升而训练集loss还在下降说明过拟合开始了如果两个loss都在高位徘徊那可能是学习率太小、模型容量不足、数据有问题等多方面原因。还有一个很实用的指标是梯度范数gradient norm。如果在训练过程中梯度范数忽然变得非常巨大往往意味着网络结构有问题比如梯度爆炸常见于深层网络或不稳定的损失函数。如果是横向对比不同实验梯度范数能帮你发现模型其实一直在原地怼墙的问题。最后别忘了跑一轮测试集评估。有些人在验证集上调参调到炉火纯青最后在测试集上崩了那大概率是验证集被看了太多次有过拟合验证集的风险。如果测试集样本足够多建议只留到最后一刻再用。4.3 实验跟踪与可复现性别让你的心血白费AI工程的日常就是跑实验、对比结果、选最优循环。如果实验记录一团糟你会陷入调参玄学上次效果好是因为改了学习率还是换了随机种子完全说不清。我现在的标配是MLflow。它可以自动记录每个实验的代码版本、参数、指标、模型权重和日志文件。你不用人人都用MLflow也可以用最朴素的方式每次实验开一个单独的目录放配置文件argparse、YAML或JSON、训练日志、checkpoint、一个README把改动点简要写清楚。关键是每次实验的结果都能被无歧义地复现。复现性还有一个重要环节是在代码里固定随机种子。虽然分布式训练里完全固定随机种子几乎不可能但在单机实验中固定住数据采样、模型初始化、数据增强的随机种子可以让你的实验对比更公平import random import numpy as np import torch def set_seed(seed): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed)这些看起来都是小事但在一个需要持续迭代的AI项目里它们决定了你是在有效率地做研究还是在凭运气调参。5. 从模型到服务把AI能力真正落地5.1 模型推理服务的常见坑输入输出没那么简单很多算法工程师把模型训练完导出个权重文件就以为任务完成了。直到把模型交给后端团队时才发现事情远没那么简单。最经典的坑是输入输出的预处理不一致。训练时你做了归一化、tokenization、数据增强模型上线后这些预处理逻辑如果不在服务端完整复现模型效果就会明显变差。我见过一个文本分类项目训练时做了文本清洗去掉URL、符号但推理接口没做结果线上准确率直接掉了10个百分点。所以在做模型部署时我会先把预处理逻辑和后处理逻辑封装成独立模块并同时在训练脚本和推理服务中共用同一份代码避免两处逻辑不一致。通常的做法是把预处理/后处理放到模型权重旁边作为一个pipeline配置一起保存。另一个大坑是模型序列化格式的选择。PyTorch的torch.save可以保存整个模型对象但在生产环境里我们一般只保存state_dict权重然后通过重新加载模型类来恢复这样可以避免因为模型代码变化导致的加载失败。再往后走一步可以用TorchScript、ONNX或TensorRT做模型编译优化让推理更快但这又会引入算子兼容性问题需要仔细测试。5.2 用FastAPI快速封装一个推理服务Python生态里做AI推理服务FastAPI是目前我很推荐的方案。它性能不错基于ASGI、自带OpenAPI文档、类型校验方便上手也简单。一个最小可用的推理服务长这样from fastapi import FastAPI from pydantic import BaseModel import torch import numpy as np app FastAPI() class PredictRequest(BaseModel): feature1: float feature2: float class PredictResponse(BaseModel): probability: float # 模型加载应用启动时加载一次避免每个请求重复加载 model torch.load(model.pt, map_locationcpu) model.eval() app.post(/predict, response_modelPredictResponse) def predict(req: PredictRequest): # 构造输入并执行推理 features np.array([[req.feature1, req.feature2]], dtypenp.float32) with torch.no_grad(): prob model(torch.from_numpy(features)).item() return PredictResponse(probabilityprob)这里面有个细节值得说模型加载一定要放在请求处理函数外面。有人图省事每次请求都加载一次模型结果GPU显存爆炸、响应时间高达几百毫秒完全不能接受。正确的做法是服务启动时加载一次模型用全局变量缓存起来或者用依赖注入机制管理。服务上线后我建议至少要把这几件事做好接口鉴权至少一个简单的API Key、请求日志记录输入输出及耗时、超时控制防止个别请求卡死整个服务、健康检查/healthz返回模型状态和服务状态。有了这些后端团队才敢放心把服务接进去。5.3 性能监控与模型版本管理线上才是真正的考验模型上线之后事情不但没结束反而是新的开始。第一个要关注的是推理性能。我通常会用Prometheus配合Grafana来监控请求延迟、吞吐量、GPU利用率和显存占用。如果关掉这些指标你会在某次大促流量进来时突然发现推理延迟从10ms飙到500ms但完全不知道从哪查起。第二个是输入数据分布漂移的检测。模型在训练集上表现优秀不代表线上数据一直都在训练分布内。线上数据分布会变用户行为会变模型精度就会下降。比较朴素的做法是统计每个特征或Embedding之后的主成分的分布和训练时的分布做对比设定一个告警阈值。这不难实现但能提前发现模型开始失效的信号。第三个是模型版本管理与回滚机制。我习惯把每次上线的模型版本号、对应的数据版本号、训练代码的commit hash一起记录下来。线上出现问题后可以快速回滚到上一个还正常的模型。没有这套机制一旦模型出问题你和运维团队就只能对着黑盒抓瞎。部署这层内容很容易被人忽略但如果你想从会写模型代码进阶到能做AI工程这部分是绕不开的必修课。6. 常见问题与排查技巧实录6.1 从训练到部署的踩坑速查表聊了这么多我把自己这些年遇到的高频问题和排查思路整理成一张速查表希望你在碰到类似问题时不用像我当初那样走那么多弯路。问题常见原因排查方向训练Loss震荡不收敛学习率太大、数据批次太小、梯度爆炸先降学习率用学习率LR Range Test找合适区间检查梯度范数是否异常训练Loss不下降特征预处理出错、梯度消失、模型容量不足用梯度校验检查反向传播先在小规模数据上跑通检查是否有数据泄露导致模型偷懒训练集效果好验证集差过拟合、数据泄露训练集和验证集有重复增加正则化、早停、再次清洗数据确认数据集划分无交叠验证集效果好线上崩训练/推理预处理不一致、线上数据分布偏移统一预处理代码做线上数据分布漂移检测GPU利用率低数据加载慢、模型过小、频繁同步等待用DataLoader多进程预取、NVLink/共享内存方案、增大batch size推理延迟高模型太大、数据预处理串行、没有用编译优化转ONNX/TensorRT、批量推理、模型量化、用GPU实例服务一启动就OOM模型加载到多个进程、显存没有释放确认模型只加载一份关闭自动多进程加载设置max_old_space_size模型复现结果不一致没有固定随机种子、数据版本变了、GPU非确定性运算固定seed记录数据版本必要时设置torch.use_deterministic_algorithms(True)这张表不是标准答案但每一个问题都来自真实项目排查方向也经过了验证。你可以把它当成起点结合自己的场景去补充。6.2 排查思路中我的几个独门习惯除了速查表里列的常见问题还有几个排查习惯是这些年帮我节省了大量时间的方法。第一个习惯是先怀疑数据再怀疑模型。深度学习框架发展到现在模型代码本身的bug概率其实很低数据问题反而最隐蔽。遇到训练效果不对时我会先花大量时间看数据样本——随机打乱一些训练样本直接肉眼检查特征和标签的对应是否合理。这个方法看起来原始但经常在5分钟内定位出问题的关键。第二个习惯是用最简单模型做基线。每次接到新任务我会先构造一个极其简单的模型比如逻辑回归或单层MLP把它跑通看能拿到什么效果。如果简单模型效果已经很不错了那说明任务本身难度不大问题可能出在复杂模型的训练细节上如果简单模型效果差得离谱那就要回头查数据和特征工程。第三个习惯是每改动一个变量只做一次实验。这听起来简单但人在实际工作中总忍不住一次改好几个参数。改完发现效果好你根本不知道是哪个改动起了作用改完效果差也没法定位问题。一次只改一个变量坚持一段时间你的实验效率会翻倍。第四个习惯和部署相关每次模型上线前都要先在生产环境或接近生产环境的预发环境跑一遍全流程的冒烟测试——发少量线上请求验证模型响应、延迟、日志等是否正常。不要等到流量全部切过去之后才发现漏了什么。6.3 新手最容易忽略的几个工程细节最后再补充几个我在带新人时反复强调的细节。它们单独拎出来都不起眼但组合起来能让整个AI工程流程顺滑很多。一是日志的重要性。训练脚本里不要只print Loss要输出当前epoch、学习率、梯度范数、数据加载耗时、训练时间和预计剩余时间。这些信息在定位瓶颈时极其有用。二是checkpoint的管理。不要只保存最后一轮的权重我会每隔固定epoch保存一个checkpoint并同时记录该checkpoint对应的验证集指标。这样如果后边训练崩了比如Loss炸了还能优雅地回退到之前的稳定状态。三是可复现环境的搭建。用Docker固定Python版本和依赖库版本用conda环境管理也行但一定要有环境即代码的意识。你三个月之后复现自己的实验时最痛苦的往往不是模型结构而是环境的依赖冲突。四是关于成本意识。训练大模型的成本是实实在在的金钱每个实验前都要想清楚这次实验的价值是什么、假设是什么、跑完以后能得到什么结论。无目的的实验不仅浪费算力还会污染你对问题空间的判断。真正的AI工程能力恰恰是在这些细节里积累出来的。走到这里ai-engineering-from-scratch这条路径的骨架已经完整了从基础理论到数据工程从模型训练到部署监控每一环都是工程拼图里不可缺失的一块。我个人最大的体会是这条路最难的其实不是某一项具体技术而是心智模式的转变——从我要训练一个模型变成我要构建一个系统。模型的精度只是中间指标数据、工程、部署、监控共同决定了这个系统能不能持续稳定地产生价值。如果你正准备启动自己的AI工程之旅我的建议是别急着追求一个完美的复杂模型先把手头最简单的那条链路端到端跑通再从每一个环节里伺机深挖。那种从头造一个完整系统的踏实感是任何现成工具都给不了的。
返回列表