ARTICLE DETAIL

资讯详情

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

从零搭建AI工程:数据、训练到部署的全链路实践指南

从零搭建AI工程:数据、训练到部署的全链路实践指南 去年年底我开始搭建一个真正意义上的 AI 工程——不是跑通一个 Notebook也不是把某个开源模型下载下来做几次推理演示而是从一张空白的服务器开始从零构建一个完整可用的 AI 应用。整个过程持续了三个多月踩的坑比我过去三年加起来都多。这篇文章想把这三个月里最核心的工程链路、技术选型逻辑和具体实操步骤整理出来给那些准备动手做类似项目、但还没找到抓手的朋友一些参考。为什么强调“从零”from-scratch因为很多教程默认你已经有了环境、数据、代码骨架直接跳到模型训练和微调。但真实的工程化落地不是这样的你面对的可能是一台刚装好系统的机器、一堆杂乱无章的原始数据、以及一个模糊得不能再模糊的业务需求。从零做 AI 工程意味着你要自己解决数据从哪来、怎么清洗、怎么标注环境怎么搭、版本怎么锁、训练怎么迭代、模型怎么部署、上线之后怎么监控这一整套问题而不是仅仅会调用某个模型的 API。这篇内容适合谁适合有两三年 Python 开发经验、对机器学习和深度学习有基本概念、但没完整做过一个生产级 AI 项目的工程师也适合那些已经在业务里接触过 AI 技术但想系统梳理整个工程链路的人。我会尽量讲清楚每一步的“为什么”而不只是“怎么做”。1. 先想清楚你要做的是一个系统不是一个模型很多人一开始就把注意力放在“用什么模型”“怎么调参”上这是最典型的误区。从我这次从零搭建的经验来看模型选型和训练在整条链路里的时间占比可能只有 20% 左右。剩下的时间花在数据、环境、服务化、监控和排障上。1.1 重新定义“AI 工程”的边界AI 工程跟你单独训练一个模型有着本质区别。单独训练模型你的终点是“loss 降低到某个值”或者“准确率达到某个百分比”但 AI 工程你的终点是“系统稳定运行、预测结果持续可用、资源开销可控、上线后能快速迭代”。这两者之间隔着一条巨大的鸿沟。我建议在动手之前先画出系统的完整数据流原始数据从哪里进来经过什么流程变成可训练的训练集模型训练完成后用什么方式提供服务线上预测请求走什么链路返回结果结果怎么反馈回系统形成闭环。把这张图画出来比先跑通一个 demo 重要得多。你还需要明确回答五个问题业务上用这个模型做什么决策——这决定了模型类型分类、回归、生成、排序等。输入是什么形态——文本、图片、结构化特征还是混合模态。输出怎么被消费——直接展示给用户还是作为下游系统的输入。数据的时效性要求是什么——实时预测还是离线批量预测就够。故障容忍度如何——模型挂了是影响核心链路还是降级处理就可以。这五个问题直接决定你的技术栈选型。没想清楚就开干后面返工的概率极高。1.2 从零搭建的最小可行架构我的做法是先用最小可行架构跑通端到端然后再逐步加固。最小可行架构包含四个部分数据处理脚本负责把原始数据转成训练所需格式。训练脚本包含模型定义、训练逻辑、评估逻辑。模型存储保存训练出来的模型权重文件和元信息。推理服务加载模型权重对外提供 HTTP 接口。我当时没有一上来就上复杂的训练平台、特征存储、模型仓库这些重武器。直接写代码、直接跑、直接部署先保证链路通再谈优化和工程化。这个思路对大多数中小型 AI 项目是适用的。2. 环境搭建这一步比你想的更值得较真我用的一台 Ubuntu 22.04 的服务器GPU 是单卡 RTX 4090先从环境开始说起——因为环境搭不好后面全在跟版本兼容性搏斗。2.1 用虚拟环境隔离依赖Python 版本不能随手装第一步是安装 Python。不要用系统自带的 Python 3.10 将就也不要直接去官网下载一个装到 /usr/local。我推荐用 pyenv 管理 Python 版本用 venv 或 virtualenv 管理虚拟环境。原因很简单不同的项目对 Python 版本和依赖库版本的诉求经常冲突搞一个全局环境就是在埋雷。我的操作是# 安装 pyenv curl https://pyenv.run | bash # 安装 Python 3.11 pyenv install 3.11.9 # 创建虚拟环境 pyenv virtualenv 3.11.9 aieng # 激活环境 pyenv activate aiengPython 版本锁定这件事看着不起眼但实际项目里因为某个库不兼容特定 Python 版本导致反复重装环境的情况实在太常见了。搞一个独立环境后面无论怎么折腾依赖都不会污染系统。2.2 CUDA、cuDNN、PyTorch 的三方匹配是一场噩梦如果你用 GPU 训练CUDA 版本、cuDNN 版本和 PyTorch 版本的匹配问题几乎是每个从零开始的人都会撞上的坑。最稳妥的办法不是自己去 NVIDIA 官网下 CUDA 完整安装包而是直接用 PyTorch 官方预编译的 wheel它会自动带上匹配的 CUDA 运行库。pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118注意这个命令里的cu118表示 CUDA 11.8 版本。你不需要提前在系统里装好 CUDA 11.8因为 PyTorch 的 wheel 里已经打包了所需的 CUDA runtime 库。这个方式能极大减少环境配置的痛苦。但显卡驱动driver还是要单独装的。用nvidia-driver-535这样的版本装完后用nvidia-smi验证一下驱动是否正常工作。千万别把驱动和 CUDA toolkit 混为一谈它们是两码事很多新人会在这一步卡很久。2.3 依赖锁版今天能跑不代表下个月还能跑我在项目一开始就建立了requirements.txt但很快发现不够——因为某些传递依赖会在不通知你的情况下升级导致训练结果出现微妙变化。后来我把pip freeze的输出重定向到一个 lock 文件部署和复现实验都基于这个文件。pip freeze requirements-lock.txt这个文件不仅用于复现还用于 Docker 镜像构建时锁定依赖。如果你追求更高的复现确定性可以用 pip-tools 或 poetry。对于大多数项目一个 lock 文件已经能解决 90% 的问题了。3. 数据链路的搭建比训练模型更花时间的地方数据是 AI 工程的隐形重头。我做这个项目时大约 60% 的时间花在数据处理和数据链路上。原因很简单——模型是公开的、算法是公开的但你的业务数据是私有的且往往最脏、最乱、最没有结构。3.1 建立数据来源清单和数据字典动手写第一个数据处理脚本前我建议先花一两天时间梳理数据来源。我当时用 Notion 建了一张数据清单表维护三个层面的信息数据源信息数据从哪些系统产生、通过什么方式导出、更新频率如何。字段信息每个字段代表什么含义、取值范围、缺失率。使用限制哪些字段涉及敏感信息、脱敏要求、保存期限。这张表是整个数据链路的“地图”。后续所有清洗、转换、特征工程的操作都能回溯到这张表中出了问题也方便定位。3.2 清洗规则要写进代码别用 Excel 手动清理我知道有很多团队还在用 Excel 手工清洗数据这在数据量小、一次性分析时没有问题但在 AI 工程项目里是灾难——因为它不可复现、不可审计、不可扩展。我的原则是所有清洗操作全部写进脚本里。清洗阶段最常见的问题包括缺失值是删除、填充还是作为特征保留要根据业务语义决定。重复数据需要定义去重的键否则可能造成训练集和验证集之间的数据泄漏。异常值超出物理可能范围的值比如年龄字段出现 200需要处理。格式不一致时间字段“2024/01/01”和“2024-01-01”混用需要统一。噪声文本爬取数据里的 HTML 标签、广告词、乱码等需要剔除。我当时做的是文本分类项目光 HTML 标签和特殊符号清洗就写了 200 多行代码。这些代码看上去机械重复但它们就是工程的一部分。3.3 数据标注没有标注就没有起点如果你的场景是监督学习数据标注是绕不开的环节。我的建议是第三方的商用平台不适合从零起步阶段因为成本和安全都很不可控。自建标注团队哪怕只有一个实习生技术上也要配套一个标注工具。我当时用了开源的标注工具 Label Studio 部署在内网配置了简单的分类标注界面。设计标注规范annotation guideline花了很多时间做因为标注规范直接决定标注质量的上下限如何定义一条真正的边界样本常规情况怎么处理标注者之间出现分歧怎么裁决这些细节都要落到文档里。为了量化标注质量我预留了 5% 的样本作为“金标”——也就是由项目负责人亲自标注好的样本混在普通样本中让标注人员标注。通过对比一致性来计算每个人和标准之间的重合度低于某个阈值的标注结果会被退回重标。这个方法虽然简单但成本低效果非常好。3.4 训练集、验证集、测试集的切分里藏着数据泄漏风险一个典型的从零项目容易犯的错误是在数据切分时不考虑样本之间的相关性。比如同一个用户在一天内发的多条评论如果一条进了训练集、一条进了测试集模型就等于提前看到了“答案”测试集评估结果会虚高。更合理的做法是如果数据有用户维度或时间维度优先按这些维度切分。训练集、验证集、测试集来自互不重叠的群体或时间段。测试集一旦选定就绝对不参与任何形式的训练迭代和调参过程。我当时按时间切分用前 6 个月的数据做训练集第 7 个月的数据做验证集第 8 个月的数据做测试集。这种做法的好处是评估结果接近模型真实上线后的表现因为模型面对的就是未来时间的数据。4. 模型选择与训练别追求最先进的模型追求最合适的模型选择这部分我相信很多人都能说出一堆候选模型的名字。但选择的标准到底是什么人和人之间的差距巨大。4.1 定一个靠谱的基线而不是一开始就上深度模型我拿到数据后的第一件事不是把数据灌进深度网络里而是用传统机器学习方法建立一个基线。我用的是 scikit-learn 里的 TF-IDF Logistic Regression 做了文本基线整个建模过程不到两个小时得到的 F1 分数大约是 70%。这个基线模型有几点价值明确了任务最低可行性下限后续深度模型的提升幅度有了参考。快速校验了数据切分逻辑是否正确、评估代码是否可靠。提供了朴素但稳定的线上对照深度模型真的更强与否能直接对比出来。如果你的深度学习模型比一个好调参的机器学习基线提升不了 3-5 个点你怎么确认提升来自模型本身而不是来自数据泄漏或评估 bug4.2 从预训练权重开始别从随机初始化开始这个时代做 NLP 或 CV 项目没有任何理由从随机初始化的权重开始训练。即便原始数据与你的业务差异比较大加载一个在通用语料或通用图像集上训练好的预训练模型利用它的通用特征做迁移学习仍然比从零训练快得多、效果也更好。我当时用的是transformers库加载一个开源的预训练模型然后在自己的数据集上做微调。这里有一个经验值得分享微调不一定需要全量更新模型参数了如果你的业务数据规模较小冻结大部分底层参数只微调顶层几个模块可以大幅降低显存开销和训练时长。如果任务足够简单现成的全参微调也可以关键是先跑通。4.3 训练落盘模型、配置、评估结果和代码版本必须绑定第一次训练出模型权重后我发现了一个严重的问题我记不清这个模型是用哪个版本的数据、哪份代码、哪组超参数训练出来的了。训练出一种模型后过了一周再回头看完全无法复现。从那以后我养成了一个习惯——每个训练任务都生成一个实验目录结构如下experiments/EXP001/ ├── config.json # 所有超参数和训练配置 ├── code_commit.txt # 代码 Git commit ID ├── model/ # 模型权重文件 ├── metrics.json # 评估指标 ├── logs/ # 训练日志 └── data_meta.json # 数据的版本和切分信息所有实验信息绑定在一起后续做实验对比、写周报、排查线上问题都能立刻找到对应的产物。这套习惯帮我省了巨量的时间建议你越早建立越好。4.4 调参要有计划不要随机乱试调参的诱惑在于“再跑一次实验也许效果就变好了”。但盲目调参完全是在烧算力和时间。我给自己定的原则是一次只改一个变量。先固定学习率调 batch size 和 epoch确认稳定后再单独调学习率确认收敛行为后再逐个看正则化和优化器。学习率是影响训练过程最敏感的超参数。我一般用lr在区间[2e-5, 5e-5]起步做测试。如果 loss 震荡剧烈就降低学习率如果收敛过于缓慢就适当提高。观察到每个 epoch 结束时在验证集上的表现比观察训练集 loss 更可靠。我还用一个简单但有效的方法管理实验在wandb或tensorboard里记录每个实验的关键指标曲线。可视化能快速暴露欠拟合、过拟合、梯度不稳定等问题。如果不做可视化光看一组数字很难判断训练过程是否健康。5. 模型上线从训练到服务的最后一公里训练完模型工作只完成了大概一半。模型要真正产生价值必须被集成进业务系统。这部分涉及模型序列化、部署方式选择、服务封装和性能优化——每一步都有不少坑。5.1 模型文件的加载比想象中更棘手保存模型不是torch.save(model.state_dict(), model.pt)就完事了。工程上还要考虑模型类的代码版本是否和权重版本一致。如果代码升级了但权重没迁移加载时会报错或者更糟——加载成功但结果莫名其妙。是否存在自定义层如自定义网络层或自定义损失函数加载时需要额外传入自定义类否则会提示无法反序列化。推理时的数据预处理逻辑引用的同一个处理函数是否已和训练时保持完全一致。我遇到过一个非常隐蔽的问题训练时对文本做了分词和截断但推理服务里没有做同样的截断导致线上输入过长时的表现跟训练时长输入的表现完全不一样。排查了三个小时最后发现是预处理逻辑不一致。解决方案是把数据预处理封装成一个独立的模块整个系统共享同一套函数训练和推理都导入这个模块保证永远不会出现两套逻辑。5.2 选择部署方式简单优先重武器后面再上从零起步阶段的选择是没必要一上来就搞大规模的服务化体系。我当时考虑过三种部署方案单服务直接对外提供 HTTP 接口最简单适合内部小流量或验证阶段。集成到业务系统内作为内嵌模块省掉一次网络调用延迟但耦合性较高。用工业级推理框架进行部署性能最好但引入额外复杂度。我用的是方案一原因是我当时用户量很小API 延迟容忍度在 500ms 以内GPU 已经完全够用。部署用的是 FastAPI 框架它自带 OpenAPI 文档调试非常方便。from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class PredictRequest(BaseModel): text: str class PredictResponse(BaseModel): label: str score: float model load_model() app.post(/predict, response_modelPredictResponse) def predict(request: PredictRequest): prob model.predict(request.text) label positive if prob 0.5 else negative return PredictResponse(labellabel, scoreprob)一个能跑的推理服务不需要很多代码是事实了。但封装起来之后你还需要考虑负载测试、并发安全、超时设置这些问题。5.3 推理性能优化用不用 GPU 是有代价的性能优化要从业务需求倒推。如果你的接口流量不大比如每天几百次请求用 GPU 推理完全是浪费资源——GPU 的显存占用、卡资源调度和成本都很高CPU 推理在同一量化的模型上的延迟可能只是多几十毫秒。我后来发现自己的流量根本不需要 GPU就用 CPU 跑推理成本瞬间降了不止一个量级。如果你确实需要 GPU 推理务必注意模型和数据要在同一个设备上避免 CPU 和 GPU 之间反复拷贝张量。批量推理时把多个请求拼成一个 batch能显著提升吞吐量。另外一个经常被忽略的点是并发安全。在多线程或多进程的 Web 服务里调用同一个 PyTorch 模型对象做推理可能出现线程安全问题。稳妥的做法是启动时加载模型到内存推理时使用锁来序列化对模型的调用或者直接用异步的任务队列来排队处理请求。5.4 没有监控的模型等于黑盒模型上线不是终点。你需要知道它运行得如何——推理错误率、延迟分位数、输入数据分布漂移以及最核心的模型输出的置信度分布变化。我的做法是在推理服务里加日志钩子把每次请求的输入、预测结果、分数和时间都记录到结构化日志里JSON Lines 格式然后定期对日志做离线分析。这样哪怕模型偷偷变得效果很差而不自知的通过回顾日志里的分数分布、异常输出来观察哪怕一些线索。这是一个很朴素的监控方案但它帮我在项目上线后一个多月里发现了两次数据漂移问题一次是新的用户输入用词变了另一次是上游系统改了字段格式导致大量解析失败。没有监控日志这两种问题很可能到用户投诉才会浮出水面。6. 复盘从零到上线之后的几点体会项目上线运行接近一个月后我复盘了整个链路总结了几个核心认知对后续做 AI 工程项目的朋友应该有参考价值。6.1 数据比模型重要这一点怎么说都不为过回顾整个项目对最终效果贡献最大的因素不是模型架构选得多先进而是数据质量和管理。同样的算法换一套清洗更干净、标注更一致的训练数据效果提升至少 5-8 个点。花大量时间在数据上是一笔极其划算的投资。事实上我在中期做实验对比时发现当我修正了一个数据泄漏的小 bug 后测试集指标立刻下降了 4 个点的“虚高”但模型在后续人工评测中的真实表现反而更稳定了。这说明之前的高分有一部分确实是记忆泄漏的结果并非模型真正的能力提升。数据方向的问题不少但极难自动察觉。我这个印象很深。6.2 保留传统方法与基线它们是你发现问题的镜子深度学习模型上线后我保留了那个基线模型——TF-IDF Logistic Regression。任何一次数据更新或代码改动我都会同时跑基线和深度学习模型对比两者结果的差异。这个习惯让我至少发现了两次数据处理的错误。如果你的复杂模型突然表现得比基线还差千万不要怀疑“模型不 work”先去查数据处理逻辑。多数情况下是特征处理或切分逻辑出了问题基线模型在给你当探针。6.3 工程代码的复用和版本管理要趁早越晚越痛苦我前两周图省事很多处理逻辑写在 Jupyter Notebook 里后来迁移到 Python 脚本时几乎全部重写了一遍。这段时间如果早一点就用模块化思路写代码是可以省下来的。建议从一开始就把数据预处理、特征工程、模型定义、评估函数拆成独立的模块并建立项目仓库管理代码。Commit 信息写得详细一些每个模型或实验配置都能追溯到 commit 记录。这套工程习惯的成本非常小回报最高。6.4 给自己留一个完全重现跑通的“一键脚本”做 AI 工程有一个不可避免的场景换机器。无论是换开发机、迁移服务器还是换了合作的同事把项目在新环境跑起来通常需要一堆手动步骤。我在项目后期写了一个setup.sh把所有步骤写成脚本包括创建虚拟环境、安装依赖、下载数据、启动训练、导出模型、启动推理服务。这个脚本的价值不在于它有多聪明而在于“傻瓜化”了项目的启动过程。新环境里跑一遍脚本就能复现整个链路这比看任何 README 都高效。如果你嫌麻烦不想写也可以录一个标准的操作文档但脚本的方式显然更不容易出错。7. 如果你也想从零开始我的建议路径假设你现在准备着手一个类似的从零 AI 工程项目我会建议你按下述路径走第一步花一周时间做技术选型和可行性验证。不要贪多把核心链路跑通让你看到端到端的可能性。第二步把数据链路做到“可复用”。清洗脚本、标注工具、切分逻辑、版本管理在第一个实验之前先完成。第三步建立基线模型和实验管理体系。跑通一版可复现的基线然后在这套体系上不断迭代模型。第四步部署上线建立日志与监控。先用最简单的方式把模型变成可调用服务然后逐步加固。第五步持续迭代。从模型效果到工程质量一点点优化但每次改动都要有记录、有验证、有回滚方案。这条路并不轻松走完后你会对“AI 工程”这个四个字的分量有非常直观的理解。这其实不只是“写模型代码”或“调参”而是一整套把数据、算法、系统和业务融合在一起的能力。如果你正准备开始希望你比我少踩一些坑早点看到自己的项目平稳运行起来。
返回列表