拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

从零开始AI工程:数据、训练、部署到运维的完整实践

从零开始AI工程:数据、训练、部署到运维的完整实践

1. 从零开始做AI工程,先想清楚这几件事

我见过太多人一听到"AI工程"这个词,第一反应就是去刷模型架构、背损失函数公式,结果啃了两个月数学,连一个能跑的demo都没做出来。这个项目的名字起得很直白——"from scratch",不是指从神经网络的反向传播手写起,而是指从一个完全空白的起点,把AI工程这条链路完整地走通一遍。它包含了数据准备、模型训练、效果调优、服务部署、监控迭代这些环节,缺一个都不叫工程。

这个东西适合谁?两类人。一类是刚入行或转行做算法工程师、AI开发者的新人,你需要的不是再刷一门课,而是一条看得见摸得着的完整路径;另一类是已经在业务系统里摸爬滚打、需要给项目引入AI能力的后端或全栈开发,你缺的不是模型知识,而是怎么把模型变成一个稳定可用的服务。这个项目要解决的,就是"我从哪开始、每一步做到什么程度算OK、怎么把东西真正跑起来"这三个核心问题。

我在带团队和做技术咨询的过程里反复确认过一件事:AI工程和纯算法研究是两码事。算法研究追求的是在某个数据集上把指标刷高,而工程追求的是在真实环境里稳定地产生价值。这决定了整个学习路径的优先级——先跑通,再优化,最后才谈得上研究。

2. 项目思路拆解:把AI工程拆成四层能力

很多人对"AI工程"的认知是模糊的,觉得它等于"会用某个深度学习框架"。这是最大的误区。如果只看框架,你学到的只是工具的操作方法,换个场景就抓瞎。我倾向于把它拆成四个层次,每一层都有明确的目标和检验标准。

第一层是数据工程能力。AI项目里有一句老话叫"垃圾进,垃圾出",模型再强也救不了脏数据。这一层要解决的问题是:数据从哪里来、怎么清洗、怎么标注、怎么划分训练集和验证集、怎么处理不平衡样本。检验标准是你能够独立完成一个结构化数据的清洗和特征工程,并且能说清楚每一步为什么这么做。

第二层是模型训练能力。这里不是要求你从零手写Transformer,而是要求你能够基于成熟的框架和预训练模型,正确地完成训练、评估和调参。关键不是背API,而是理解几个核心概念:过拟合怎么判断、学习率对收敛的影响、验证集和测试集为什么要分开、早停机制什么时候触发。检验标准是你训练出来的模型,在验证集上的指标能够复现论文或官方基准的合理水平。

第三层是服务化部署能力。模型训练出来只是一个文件,资产价值极低。工程化意味着把它包装成可调用的服务,考虑延迟、吞吐、并发、资源占用。这一层要掌握的东西包括模型序列化、推理服务框架、接口设计、并发处理。检验标准是你的模型能以API形式被外部系统调用,并且响应时间在可接受范围内。

第四层是迭代运维能力。这是最容易被忽略的部分。线上模型的效果会随数据分布变化而衰减,需要监控、反馈、重训的闭环。检验标准是项目上线后,你能通过日志和指标发现模型异常,并触发一轮新的训练迭代。

这四个层次对应到项目里,不是四门独立的课,而是一条流水线。从头到尾走通一遍,你才会产生那种"原来AI工程是这样的"的贯通感。我在辅导新人时最常用的比喻是:训练模型像做饭,数据工程是买菜洗菜,模型训练是掌握火候,部署是摆盘上菜,运维是餐厅开业后的持续运营。只盯着其中一环,做不出完整的生意。

3. 核心细节与实操要点:每个环节的难点和关键动作

3.1 数据准备:先定标准,再动手

数据环节最大的坑是"先收集,再想怎么用"。正确的做法是先明确任务定义,再倒推数据需求。比如你想做一个文本分类模型,任务是有没有投诉倾向。那你要先定义清楚什么叫"投诉倾向",是包含负面情绪词?还是包含退款、差评等具体诉求?这个定义直接影响标注规范——而标注规范是数据环节最重要的产出物。

我建议实际操作时,先不要急着把库里的数据全量导出来,而是抽100到200条样本,人工过一遍,看看分布情况。做过这一步你会惊讶地发现,很多你以为存在的数据,实际并不存在;很多你以为很稀疏的类别,实际占了大头。我在做电商评论分析时,第一次抽样发现"售后问题"这个类别占比高达40%,而"产品建议"类连5%都不到。如果不做这一步,直接切分训练集,模型大概率会把所有评论都预测成售后问题。

清洗环节要守住一条底线:训练集和测试集的清洗规则必须完全一致,而且清洗逻辑要被代码复用,不能靠人工在Excel里手动改。我在实操中见过不少同事先清洗测试集再回头处理训练集,两边的处理口径对不上,导致验证指标虚高,上线后效果崩盘。正确做法是写一套pipeline,用同样的函数处理两份数据,保证"所见即所得"。

3.2 模型训练:小白最容易交学费的四个参数

模型训练的框架选型,我建议新手直接从PyTorch入手,不是说其他框架不行,而是PyTorch的生态和资料在目前是最丰富的,你遇到的问题几乎都能搜到解决方案——这在工程实践里非常重要。

第一个要搞清楚的参数是学习率。我见过太多人训练不收敛,第一反应是改模型结构,其实八成是学习率不合适。实操中的快速判断方法:如果loss在初期就剧烈震荡不下降,学习率大概率偏大;如果loss下降得像蜗牛爬,学习率偏小。我习惯用一个粗糙的参考区间:Transformer类模型从5e-5这个量级起步,卷积类可以从1e-3附近起步,然后根据训练曲线的形态做微调。不要迷信某个"万能学习率",它和你的数据量、batch size是联动的。

第二个是batch size。它不只是一个显存占用的权衡,它直接影响梯度估计的稳定性。batch size越小,梯度噪声越大,模型越难收敛,但有时这种噪声反而能帮模型跳出局部最优;batch size越大,训练越稳定,但显存压力大,而且可能收敛到过于尖锐的极小值点。我的建议是卡在显存允许范围内尽量大,但如果你发现loss曲线异常平滑、验证指标却上不去,考虑减小batch size或调高学习率。

第三个是早停(early stopping)的设置。很多实践者不看训练曲线,直接跑到设定的epoch数就算完事,这在工程上是非常浪费的行为。应该在训练过程中每过一个epoch(或每N步)计算验证集指标,如果连续若干个epoch没有提升,就提前终止训练并保存最佳模型。这个"连续多少次没提升"的参数,我习惯设3到5,太小容易在震荡区间提前停掉,太大又浪费算力。

第四个是随机种子。AI工程里有一项很容易被忽略的纪律:所有涉及随机性的地方都要设置固定种子,包括数据切分、模型参数初始化、数据增强的随机操作。否则你可能连续跑两次训练,指标差了两个点,却完全说不清原因。我在项目里几乎所有模块都统一传入一个全局seed值,并把种子值记录在训练日志里,确保任何一次训练都能被复现。

3.3 部署服务:先跑通HTTP,再谈性能优化

很多初学者会把部署想得很玄,觉得要上一套分布式推理集群。实际上,对于绝大多数业务场景来说,一个单体推理服务已经够用。我建议第一步永远是最朴素的方案:把模型加载到一个Python服务进程里,封装成HTTP接口,本地先用curl测通,再接入业务调用方。

这里有一个工程要点:模型加载和推理逻辑要分离。模型文件动辄几百MB甚至几个GB,如果每次请求都重新加载一次模型,服务基本没法用。正确做法是启动时将模型加载到内存或显存,放进一个全局对象或单例中,推理时直接复用。PyTorch里如果你用多进程部署(比如配合Gunicorn),要特别注意每个worker都会独立加载一份模型,显存占用会乘以worker数,这是新手最容易踩的坑。

接口设计上要明确两点:输入和输出。输入字段的定义要比训练时的数据处理更严格,因为真实调用方传过来的数据永远是脏的。必须要做输入校验和异常处理,让调用方拿到明确的错误码,而不是模型的堆栈信息。输出方面,不要把模型原始输出直接抛给业务,至少包含一个可读的预测标签、一个置信度,以及一个trace_id,便于后续排查链路问题。

性能优化的顺序也很重要。先看能不能满足业务要求的并发量和响应时间,再动手优化。如果单机单worker就能扛住,就不要画蛇添足上消息队列。如果在高峰期扛不住,优先做三件事:增大batch推理(把多个请求合并成一次前向计算)、换用更小的模型或量化版本、加缓存层。这几步做完,大多数场景都能应付。

4. 实操过程:从零走通一个文本分类项目的全流程

理论说再多,不如动手走一遍。我以"客服工单自动分类"这个最常见的业务场景为例,完整过一遍从数据到部署的实操步骤。之所以选文本分类,是因为它的链路最完整、门槛适中,而且能覆盖前面讲到的所有工程环节。

4.1 定义任务与准备基线

先把业务问题翻译成模型问题。客服工单分类的目标是,给定一段用户描述,输出工单所属的类别(比如账户问题、支付问题、产品建议、投诉等)。这是一个典型的单标签多分类任务。第一步我推荐建立一个非常简单的基线(baseline)模型,比如直接用TF-IDF加逻辑回归。这个朴素模型的用途不是最终上线,而是给后续复杂模型定一个指标地板砖——你的模型如果连这个都打不过,说明问题出在数据或任务定义上,而不是模型不够高级。

我跑基线模型前会先把标签分布打印出来,确认没有某个类别占了90%以上。如果有,训练集要按类别做重采样或用加权损失函数。这一步不需要什么高深理论,实际操作就是用一个sklearn的class_weight参数或数据采样调整。

4.2 数据处理脚本的结构设计

数据处理是整个项目里最值得把时间花的地方。我建议写成四个模块,每个模块职责单一:

第一块是读取与探查。统一入口函数,读入原始数据,打印shape、列名、缺失值比例、标签分布,这个脚本的输出是后续决策的依据。第二块是清洗。剥离HTML标签、处理全半角符号、做分词或分字(中文场景我用jieba或直接按字切分,取决于下游模型的输入要求),把停用词列表维护成一个独立的配置文件。第三块是编码与切分。把文本转成模型输入格式,按stratify参数做分层切分,保证训练集和验证集的类别分布一致。第四块是特征化。如果走传统模型路线就做TF-IDF向量化;如果走深度模型路线就做tokenizer编码。

这里有一个非常实用的细节:数据处理的每一步都输出一份中间结果到磁盘。我习惯在处理完后把清洗后的数据存成一份新的csv,因为项目过两周回头看,你大概率已经忘了当时是怎么处理的。有中间产物在,才能追溯和复查。

4.3 训练与评估的工程化实现

数据准备好后,进入训练环节。我用PyTorch做实际训练时,代码结构分为模型定义、数据加载、训练循环、评估函数四个部分,并且建议从一开始就把训练过程记录的log写好,而不是到调参的时候才补。日志里至少要有epoch、loss、accuracy、macro F1这些指标,以及前面提到的seed值、学习率、batch size。训练过程的可视化可以选择一个顺手工具,或者直接在终端打印曲线,重要的是判断收敛状态,而不是追求可视化华丽。

评估指标不要迷信准确率。工单分类这种场景往往类别不均衡,"账户问题"可能占了一半,模型全预测成"账户问题"就能有50%的准确率,但业务上完全不可用。工程上我更关心macro F1(各类别F1的算术平均)和每个类别的召回率,因为漏掉一个高优先级投诉工单,代价远大于误判一个普通咨询。

每跑完一个实验,我会把实验配置和对应的评估指标记在一个共享表格里。这个习惯帮我省了无数回头路,也让我能在多个模型方案之间做有理有据的对比,而不是靠感觉说"好像这个版本效果好一点"。

4.4 部署上线的基本流程

部署部分用FastAPI搭建推理服务。选它有几点理由:基于Starlette,性能不错;自带数据校验和API文档,方便调用方联调;生态成熟,遇到问题好查。这是"从零"起步最省心的组合。

服务的核心代码逻辑不复杂:启动时加载模型和tokenizer,接收请求后做文本校验,调用处理函数得到输入ID,执行模型前向计算,把logits转成概率或类别输出,最后返回一个结构化JSON。异常处理上,一定要把"输入为空""输入过长""模型推理异常"这三种情况分别返回不同的错误码,而不是全返回500。我在部署时还会加一个liveness探针接口,不加载模型,只返回健康状态,这样容器编排系统可以区分服务是否存活。

部署环境我建议使用Docker。说得直白一点:不 Docker 化的推理服务,在后续交接或迁移环境时大概率会出问题。最大的课堂事故是"在我机器上是好的"。Dockerfile的写法不复杂,核心是选一个基础镜像、装依赖、把代码模型打进去、启动命令设为服务启动命令。要注意系统层面需要装的基础库,比如某些文本处理库依赖libgomp,遗漏了会在容器运行时报错。

5. 常见问题与避坑指南:我踩过的那些坑

5.1 显存明明够用,为什么训练跑不起来

这类问题大多不是显存不足,而是同一个进程里有多个CUDA上下文,或者PyTorch没有按预期释放显存。排查方法是启动训练前用命令查看显存占用,确认没有别的僵尸进程占着卡;训练过程中用工具监控显存增量,如果稳步增长但过一会儿突然报错,多半是数据加载环节在内存里累积了不需要的变量。我习惯在每轮迭代后把大变量置空或使用del加torch.cuda.empty_cache(),虽然这不能解决根本问题,但能把显存碎片化问题缓解不少。

5.2 本地验证集指标很好,上线效果一塌糊涂

这个现象的原因集中在两类:一是数据分布不一致,训练集和真实请求的数据来源不同,特征分布有明显偏差;二是预处理逻辑没对齐,训练时走了完整的清洗流程,上线时却漏了某一步。我排查的第一步永远是拿线上真实请求,跑一遍训练时的预处理管道,看经过处理后是否还像是训练集里的样本形态。很多时候只看几条就发现,线上文本里混着大量表情符号和特殊字符,而训练时这些是清洗过的。

5.3 类名预测总偏向多数类,怎么调都回不来

如果确认清洗和采样都没问题,问题多出在损失函数和对样本权重的处理上。工程上常用两个手段:一是给少数类加大loss权重,让模型在训练时更在意这些样本;二是如果业务上允许接受召回率和精确率的取舍,可以在推理阶段调整预测阈值,把少数类的判定阈值降低一些。实操中我会同时用两种手段,先在训练阶段用weighted loss训练一版,再做阈值搜索找出每个类别的最优判定边界。

5.4 部署后响应慢,并发一起来就超时

最有效的排查方法不是凭感觉猜测,是给服务做压测。脚本很简单,模拟一波并发请求,观察响应时间、错误率、内存和CPU占用。根据我的经验,绝大多数情况原因不在推理本身,而在数据处理或者CPU的tokenizer部分。因为GPU推理很快,反而是文本预处理和编解码在CPU上串行执行,并发一起来就排队。解决办法是把预处理结果缓存起来或者用多进程并行处理,问题基本能解决大半。实在不行就升级机器或加一个简单的队列,但没必要一上来就上集群方案。

6. 个人经验总结:从零到一,最值得守住的三条原则

如果你要我给这个"from scratch"的旅程做一个小范围的收尾,我不会给你绕口令式的总结。最值得说的是我反复碰壁后留下来的三条原则。

第一条是完成比完美重要。AI工程太容易陷进去研究某个细节了——一个激活函数的变体、一篇新的论文技巧,都会让人欲罢不能地"再调一下试试"。但如果从零开始的项目,先把整条链路跑通,哪怕效果很烂,后面的一切优化都有了一个真实存在的载体。我在项目辅导中看到的最大挫败,都是从"我还没有准备好开始"开始的。

第二条是记录比记忆重要。跑过的实验、用过的参数、踩过的报错,全部记下来。别相信自己的大脑,两三个月后你连当时某个参数为什么这么设都想不起来。一份实验记录表,能让你避开大量重复劳动。

第三条是理解业务比理解模型重要。AI工程的价值不是写在论文里的指标,是你部署后有没有让业务方日子好过一点。分类工单的目的不是F1高,是客服处理效率真的提升了;推荐模型的目的不是CTR涨,是用户真的切到了他需要的内容。模型的损耗和业务的收益之间,隔着的恰恰是工程人的手艺。把这条链路走通,你就不会只是一个"调参侠",而是一个真正做事的AI工程师。

返回列表