尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

从零手搓AI工程:告别调包,掌握核心工程能力

从零手搓AI工程:告别调包,掌握核心工程能力 1. 从零手搓AI工程为什么我不建议你直接调包很多人一听到“AI工程”这四个字第一反应就是打开某个云平台拖几个组件调一下API跑通一个Demo然后发个朋友圈说“今天又搞定了一个AI项目”。我承认这种玩法确实爽爽到让人产生一种“我已经掌握了AI”的错觉。但如果你真的想在这个领域站稳脚跟我劝你先别急着调包老老实实从零开始手搓一遍。“ai-engineering-from-scratch”这个标题翻译过来就是“从零开始的AI工程”。它不是一个具体的框架也不是某个大厂的开源项目而是一种学习路径和工程理念。核心就一句话把AI系统当成一个完整的工程项目来对待而不是当成一个黑盒API来调用。这意味着你需要理解数据怎么流进来、模型怎么被训练、推理怎么被服务、监控怎么做、成本怎么控、故障怎么排查。这些东西调包是学不会的。我见过太多人简历上写着“精通TensorFlow/PyTorch”结果问他模型部署时显存怎么估算他支支吾吾问他推理延迟从哪几个环节来他只能说出“模型前向传播”。这就是典型的“调包侠”困境——会用工具但不懂工程。从零手搓的意义在于你会被迫面对每一个细节而正是这些细节构成了AI工程师的核心竞争力。这篇文章适合谁看如果你是刚入门的AI学习者想摆脱“只会调库”的标签这篇文章会给你一条清晰的路径。如果你是有经验的开发者想转型做AI工程这篇文章会帮你补齐工程侧的思维短板。如果你只是好奇AI系统到底怎么跑起来的那更好我会用最直白的方式把它拆开给你看。接下来的内容我会按照一个真实项目的生命周期来展开从环境搭建、数据管道、模型训练、推理服务到监控与成本控制。每一块我都会告诉你“为什么这么做”以及“我踩过哪些坑”。不玩虚的直接上干货。2. 环境搭建别让CUDA版本成为你的第一个噩梦2.1 为什么我坚持用Docker而不是裸机环境从零开始做AI工程第一件事就是搭环境。很多人觉得搭环境很简单装个Pythonpip install几个包就完事了。我告诉你这是你踩的第一个坑而且这个坑会反复出现直到你崩溃。AI工程的环境依赖极其复杂。PyTorch对CUDA版本有要求CUDA对显卡驱动有要求某些Python包对gcc版本有要求还有各种底层库如cuDNN、NCCL的版本兼容性问题。你在本地裸机上装一遍跑通了换台机器就挂。更可怕的是当你需要同时维护多个项目时不同项目依赖不同版本的PyTorch裸机环境根本没法隔离。我的做法是从第一天起就用Docker。不是因为它时髦而是因为它能把你从“依赖地狱”里救出来。具体操作上我不建议你从ubuntu基础镜像开始自己装CUDA那样太耗时。直接用NVIDIA官方提供的CUDA基础镜像比如nvidia/cuda:12.1.0-cudnn8-devel-ubuntu22.04然后在上面装Miniconda或者直接用venv管理Python依赖。这里有个细节devel版本和runtime版本的区别。devel版本包含了编译工具链镜像体积大但方便你编译一些需要nvcc的包runtime版本体积小适合最终部署。开发阶段用devel部署阶段用runtime这是基本策略。注意不要用latest标签。AI领域的镜像更新频繁latest随时可能变今天跑通的代码明天可能就挂了。永远锁定具体版本号。2.2 依赖管理的三层结构在Docker内部我习惯把依赖分成三层来管理。第一层是系统级依赖通过apt-get安装比如git、vim、wget、build-essential这些。第二层是CUDA相关的库通过基础镜像已经带了一部分但如果你需要特定版本的cuDNN或者NCCL需要单独处理。第三层是Python依赖用conda或pip管理。为什么分三层因为变更频率不同。系统级依赖基本不变CUDA库偶尔变Python依赖天天变。分层之后Docker的构建缓存能最大化利用。你改一个Python包不需要重新装系统依赖构建时间从半小时降到两分钟。具体到Python依赖我强烈建议用requirements.txt加版本锁定的方式。不要用pip install torch这种不指定版本的做法。你应该写成torch2.1.0cu121这样的精确版本。为什么因为AI领域的包更新太快小版本之间可能有行为差异。你今天用2.1.0跑通的模型明天自动升级到2.2.0可能就报错了。还有一个技巧用pip-tools生成锁定文件。你维护一个requirements.in里面写顶层依赖然后用pip-compile生成包含所有传递依赖的requirements.txt。这样能保证每次构建的环境完全一致。2.3 显卡资源隔离与显存预估如果你是在多卡机器上做开发还需要考虑显卡隔离。默认情况下PyTorch会占用所有可见的GPU。这在多人共用一台机器时是灾难。解决办法是通过CUDA_VISIBLE_DEVICES环境变量来指定可见的GPU。但这里有个坑CUDA_VISIBLE_DEVICES必须在进程启动前设置在Python代码里用os.environ设置是无效的因为CUDA上下文在导入torch时就已经初始化了。所以正确做法是在Docker启动时通过--gpus参数或者环境变量传入。显存预估是另一个必须掌握的技能。很多人跑模型时遇到OOMOut of Memory就懵了不知道是模型太大还是batch size太大。我教你一个粗略的估算方法模型参数占用的显存约等于参数量 × 4字节FP32或参数量 × 2字节FP16。但这只是权重部分训练时还需要存储梯度、优化器状态、激活值。对于Adam优化器显存占用大约是模型权重的4倍。再加上激活值通常需要预留模型权重的6到8倍显存。举个例子一个1亿参数的模型FP32下权重占400MB训练时实际显存占用可能在2.4GB到3.2GB之间。如果你只有4GB显存的卡batch size就只能设得很小。这时候你就需要考虑梯度累积或者混合精度训练了。3. 数据管道AI工程里最脏最累但最重要的部分3.1 为什么数据管道决定了项目的上限在AI工程里有一个残酷的事实模型架构决定下限数据质量决定上限。你可以用最先进的Transformer架构但如果你的数据是一坨垃圾模型效果一定好不了。而数据管道就是保证数据质量的基础设施。什么是数据管道简单说就是从原始数据到模型可用的训练数据之间的所有处理步骤。包括数据采集、清洗、去重、标注、格式转换、分词、批处理等等。这些步骤听起来简单但每一个都有坑。我做过一个文本分类项目原始数据是几十万条用户评论。看起来不多但清洗起来要命。有HTML标签、有特殊字符、有重复内容、有语言混杂、有长度极端的数据。如果你不处理这些直接丢给模型结果就是loss震荡、收敛慢、效果差。数据管道的设计原则是可复现、可增量、可监控。可复现意味着你给定一个随机种子每次跑出来的数据完全一样。可增量意味着新数据来了你不需要从头处理全部数据。可监控意味着你能知道每一步处理了多少条数据、过滤了多少条、剩余多少条。3.2 用Apache Arrow和Parquet做数据存储在数据存储格式上我强烈推荐Parquet加Apache Arrow的组合。为什么不用CSV因为CSV太慢、太占空间、类型信息丢失。为什么不用JSON因为JSON解析慢而且嵌套结构处理起来麻烦。Parquet是一种列式存储格式压缩率高读取速度快而且保留了schema信息。Arrow是内存中的列式格式和Parquet之间的转换几乎零成本。用Pandas或者Polars读取Parquet文件比读CSV快5到10倍。具体操作上我习惯把数据分成多个Parquet文件每个文件几万到几十万条记录。为什么不分一个大文件因为大文件读取时无法并行而且一旦损坏整个文件都废了。分片之后可以用多进程并行读取而且单个文件损坏不影响其他文件。还有一个技巧按时间或类别分区。比如data/year2024/month01/part-0.parquet这样的目录结构。这样当你只需要某个月的数据时不需要扫描全部文件。这在数据量大了之后非常关键。3.3 数据清洗中的那些坑数据清洗是数据管道里最耗时的部分。我总结几个常见的坑。第一个坑去重不能只用精确匹配。很多数据集里有近似重复的内容比如只差一个标点符号或者多了几个空格。精确去重发现不了这些。你需要用模糊去重比如MinHash或者SimHash。但模糊去重有误杀风险阈值设高了漏掉重复设低了把正常数据也去掉。我的经验是先用精确去重再用SimHash做近似去重阈值设在0.9左右然后人工抽查。第二个坑长度过滤不能一刀切。很多人设定“长度小于10或大于512的丢掉”。但长度分布是长尾的你一刀切可能丢掉重要信息。更好的做法是看长度分布的分位数比如保留1%到99%分位之间的数据然后对极端值单独处理。第三个坑语言检测不可靠。用langdetect或者fasttext做语言检测短文本的准确率很低。一条10个字的文本可能被误判成各种语言。我的做法是对短文本放宽语言检测阈值或者干脆不检测让模型自己去学。第四个坑标注质量参差不齐。如果是人工标注的数据不同标注员的标注标准可能不一致。你需要做标注一致性检查比如计算Kappa系数。如果一致性太低要么重新培训标注员要么重新设计标注规范。提示数据清洗的每一步都要记录日志包括输入条数、输出条数、过滤原因分布。这样出问题时你能快速定位是哪一步出了问题。3.4 构建可复现的数据处理流程可复现性是数据管道的生命线。你今天处理的数据和明天处理的数据必须完全一致否则模型效果波动你都不知道是数据变了还是模型变了。实现可复现的关键是固定随机种子、记录所有参数、版本化数据。随机种子要固定Python的random、numpy的random、以及任何用到的随机操作。参数要记录在配置文件里不要硬编码在代码里。数据要版本化每次处理完打一个版本号模型训练时记录用了哪个版本的数据。我习惯用DVCData Version Control来管理数据版本。它和Git类似但专门为大数据文件设计。你可以用dvc add把数据文件纳入版本控制用dvc push推送到远程存储。这样每次实验都能追溯到具体的数据版本。如果不想引入DVC至少要做到每次数据处理生成一个manifest文件记录输入文件的哈希、输出文件的哈希、处理参数、处理时间。这样虽然不能自动恢复数据但至少能追溯。4. 模型训练从单卡到多卡的工程化实践4.1 训练脚本的模块化设计很多人写训练脚本喜欢把所有逻辑塞在一个文件里数据加载、模型定义、训练循环、验证、保存全在一起。这种脚本跑一次可以但要做实验、要调参、要复现就痛苦了。我的做法是模块化。至少分成四个模块数据模块、模型模块、训练模块、配置模块。数据模块负责加载和预处理数据模型模块负责定义网络结构训练模块负责训练循环和验证配置模块负责管理超参数。为什么这么分因为变更频率不同。数据预处理可能经常变模型结构偶尔变训练逻辑很少变。分开之后你改数据预处理不会影响模型定义改模型结构不会影响训练逻辑。而且每个模块可以单独测试比如你可以单独测试数据加载器是否返回了正确的形状和类型。配置管理我推荐用Hydra或者简单的YAML加dataclass。Hydra的好处是支持命令行覆盖配置比如python train.py model.lr0.001就能覆盖学习率。这在跑超参搜索时非常方便。4.2 混合精度训练省显存提速的利器混合精度训练是我强烈推荐的技术。它用FP16做前向和反向传播用FP32做参数更新。好处是显存占用减少约一半训练速度提升30%到50%。对于大模型来说这是刚需。但混合精度训练有坑。第一个坑是梯度下溢。FP16的最小正数是6e-8左右很多梯度值比这个还小直接变成0。解决办法是用loss scaling把loss放大一定倍数梯度也跟着放大更新时再缩回去。PyTorch的torch.cuda.amp已经自动处理了这些你只需要用autocast和GradScaler就行。第二个坑是某些操作不支持FP16。比如softmax、layer norm、loss计算这些在FP16下容易溢出或不稳定。所以autocast会自动把这些操作保持在FP32。但如果你自己写了自定义操作需要手动处理。第三个坑是混合精度不一定总是更快。如果模型很小或者batch size很小混合精度的开销可能抵消收益。我的经验是模型参数量超过1000万或者batch size超过32混合精度才有明显收益。4.3 多卡训练的两种模式DP和DDP当单卡放不下模型或者训练太慢时就需要多卡训练。PyTorch提供了两种模式DataParallelDP和DistributedDataParallelDDP。DP是单进程多线程主卡负责梯度汇总其他卡把梯度发给主卡。缺点是主卡显存占用高而且Python的GIL限制了多线程效率。DDP是多进程每张卡一个进程通过NCCL通信。效率高得多而且支持多机。我强烈推荐直接用DDP不要用DP。虽然DDP配置稍微复杂一点但性能提升明显。DDP的核心是DistributedSampler和init_process_group。你需要用torchrun或者mp.spawn来启动多个进程每个进程设置自己的LOCAL_RANK。这里有个坑DDP下每个进程的随机种子要不同。如果所有进程用同一个种子数据增强会完全一样相当于batch size没变。正确做法是seed base_seed rank。还有一个坑BatchNorm在DDP下需要同步。默认的BatchNorm只统计当前卡的数据导致统计量不一致。你需要用SyncBatchNorm它会跨卡同步均值和方差。但SyncBatchNorm有通信开销小模型下可能不划算。4.4 训练过程中的监控与日志训练不是跑起来就完事了你需要知道它跑得怎么样。最基本的监控是loss曲线和准确率曲线。但光看这些不够你还需要看学习率、梯度范数、显存占用、吞吐量。我习惯用TensorBoard或者Weights BiasesWB来记录。WB的好处是支持云端同步多人协作方便。TensorBoard的好处是本地、免费、轻量。选哪个看团队习惯。梯度范数是一个很重要的指标。如果梯度范数突然变大说明可能遇到了梯度爆炸需要检查学习率或者加梯度裁剪。如果梯度范数一直很小说明模型可能陷入了平坦区域学习率可能太小。显存占用也要监控。如果显存占用持续增长说明有内存泄漏。常见原因是把tensor存到了列表里没有释放或者计算图没有detach。用torch.cuda.memory_allocated()可以查看当前显存占用。吞吐量每秒处理的样本数是衡量训练效率的关键指标。如果吞吐量突然下降可能是数据加载成了瓶颈或者遇到了某些慢操作。用PyTorch Profiler可以定位瓶颈。5. 推理服务把模型变成可用的API5.1 推理框架选型TorchServe vs Triton vs 自研模型训练完了下一步是部署成服务。这时候你面临一个选择用现成的推理框架还是自己写一个HTTP服务现成的框架有TorchServe、Triton Inference Server、ONNX Runtime等。TorchServe是PyTorch官方出的和PyTorch生态集成好支持模型版本管理、A/B测试、自动扩缩容。Triton是NVIDIA出的支持多种框架PyTorch、TensorFlow、ONNX、TensorRT性能优化做得好支持动态批处理。ONNX Runtime适合跨平台部署性能也不错。自研的话就是用FastAPI或者Flask写一个HTTP接口加载模型接收请求返回结果。简单直接但缺少很多生产级功能。我的建议是小项目自研大项目用Triton。自研的好处是可控你知道每一行代码在干什么。Triton的好处是功能全动态批处理、模型集成、多模型管理都是开箱即用。但Triton的学习曲线比较陡配置文件复杂调试也不方便。如果你团队里没有专门做推理优化的人自研加FastAPI可能是更务实的选择。5.2 动态批处理提升吞吐量的关键推理服务和训练不一样训练时batch size是固定的推理时请求是随机到来的。如果每个请求单独推理GPU利用率很低。动态批处理就是把短时间内到达的多个请求合并成一个batch一起推理然后拆分结果返回。动态批处理的核心是等待窗口。服务收到第一个请求后等待一个很短的时间比如10毫秒把这段时间内到达的请求合并。等待时间越长batch越大吞吐量越高但延迟也越高。这是一个权衡。Triton内置了动态批处理只需要在配置里设置max_batch_size和preferred_batch_size。自研的话你需要自己实现一个队列用一个后台线程定期从队列里取请求组成batch。这里有个坑不同请求的输入长度可能不同。如果直接padding到最大长度短请求会浪费大量计算。解决办法是按长度分桶把长度相近的请求放在一个batch里。或者用更高级的技术如continuous batching但实现复杂度高。5.3 模型量化与加速推理服务的另一个优化方向是模型量化。量化就是把FP32的权重和激活值转换成INT8减少显存占用和计算量。INT8推理的速度通常是FP32的2到4倍显存占用减少到四分之一。量化分两种训练后量化PTQ和量化感知训练QAT。PTQ简单直接对训练好的模型做量化不需要重新训练。QAT复杂需要在训练时模拟量化误差效果通常更好。PyTorch提供了torch.quantization模块做PTQ。基本流程是准备模型、插入观察器、校准、转换。校准是用一批代表性数据跑一遍统计激活值的分布确定量化参数。但量化有精度损失。对于分类任务精度损失通常很小1%以内。对于检测或分割任务精度损失可能较大。你需要评估量化后的模型是否满足业务要求。还有一个加速技术是算子融合。把多个连续的操作合并成一个减少kernel启动开销和内存访问。比如ConvBNReLU可以融合成一个算子。TensorRT和ONNX Runtime都支持自动算子融合。5.4 服务监控与告警推理服务上线后你需要监控它的健康状态。最基本的指标是QPS、延迟、错误率。QPS是每秒处理的请求数延迟是请求从发出到收到响应的时间错误率是失败请求的比例。但光有这些不够。你还需要监控模型层面的指标。比如输入数据的分布是否发生了变化数据漂移模型输出的置信度是否下降模型退化。这些指标能帮你提前发现模型效果下降的问题。数据漂移的监控可以用统计检验比如KS检验或者PSIPopulation Stability Index。把线上数据的特征分布和训练数据的特征分布做对比如果差异显著说明数据漂移了。告警策略要合理。不要一有错误就告警那样会被淹没。设置合理的阈值比如错误率超过1%持续5分钟才告警。告警要分级P0是服务不可用P1是性能下降P2是数据异常。注意监控系统本身也要监控。如果监控挂了你就成了瞎子。所以监控系统要有独立的健康检查。6. 成本控制与性能优化AI工程师的必修课6.1 GPU成本估算与优化策略AI工程和传统软件工程最大的区别之一就是成本结构。传统服务的成本主要是CPU和内存AI服务的成本大头是GPU。一张A100显卡每小时的成本是几美元到十几美元如果利用率不高钱就白白烧掉了。成本优化的第一步是搞清楚钱花在哪了。你需要记录每个实验的GPU时长、每个推理服务的GPU利用率。如果GPU利用率长期低于30%说明资源浪费严重。优化的策略有几个方向。第一是提高GPU利用率通过动态批处理、混合精度、算子优化等手段让GPU尽量跑满。第二是选择合适的GPU型号不是所有任务都需要A100推理任务用T4或者L4可能就够了。第三是自动扩缩容根据负载动态调整实例数量低峰期缩容高峰期扩容。还有一个容易被忽略的点闲置GPU的回收。开发环境里经常有人占了GPU但不用导致别人用不了。解决办法是用Kubernetes或者Slurm做资源调度设置空闲超时自动回收。6.2 推理延迟的拆解与优化推理延迟是用户体验的关键指标。一个请求的延迟可以拆解成几个部分网络传输时间、预处理时间、模型推理时间、后处理时间、排队时间。网络传输时间通常很小除非跨地域。预处理和后处理的时间容易被忽略但如果你的预处理很复杂比如图像解码、音频重采样可能比模型推理还慢。模型推理时间是核心优化手段包括量化、剪枝、蒸馏、算子融合。排队时间是动态批处理带来的等待窗口越长排队时间越长。优化延迟的第一步是测量每个部分的时间。用PyTorch Profiler或者简单的time.time()打点找出瓶颈在哪。如果瓶颈在预处理就优化预处理比如用GPU做解码。如果瓶颈在模型推理就优化模型。还有一个技巧是缓存。如果某些请求的输入是重复的可以缓存结果。比如相同的图片、相同的文本直接返回缓存结果不需要重新推理。缓存要注意失效策略输入变了缓存要更新。6.3 模型压缩剪枝、蒸馏、量化模型压缩是降低推理成本的重要手段。剪枝是去掉模型中不重要的权重或神经元减少参数量和计算量。蒸馏是用一个大模型教师指导一个小模型学生训练让小模型达到接近大模型的效果。量化是把FP32转成INT8前面已经讲过。剪枝分结构化剪枝和非结构化剪枝。非结构化剪枝去掉单个权重稀疏度高但硬件加速难。结构化剪枝去掉整个通道或层稀疏度低但硬件友好。实践中结构化剪枝更常用。蒸馏的关键是损失函数设计。除了学生模型的原始损失还要加上蒸馏损失让学生模型的输出分布接近教师模型。温度参数控制分布的平滑程度温度越高分布越平滑学生学到的信息越多。这些技术可以组合使用。比如先蒸馏得到一个中等模型再量化成INT8再剪枝去掉冗余通道。但组合使用时要小心每一步都可能损失精度需要逐步评估。6.4 成本与性能的权衡艺术成本控制不是一味省钱而是在成本和性能之间找平衡。有些场景对延迟极其敏感比如自动驾驶、实时推荐这时候不能为了省钱牺牲延迟。有些场景对延迟不敏感比如离线批处理、日志分析这时候可以用便宜的GPU甚至用CPU。我的经验是先保证性能达标再优化成本。如果性能不达标成本再低也没用。性能达标后再看成本有没有优化空间。优化的顺序是先提高利用率动态批处理、混合精度再换硬件从A100换到T4最后做模型压缩。还有一个策略是分级服务。对延迟敏感的用户走高性能集群对延迟不敏感的用户走低成本集群。或者根据请求的优先级动态调度。最后成本优化是一个持续的过程不是一次性的任务。你需要持续监控、持续调优。每个月review一次成本报告看看有没有异常增长有没有优化空间。7. 踩坑实录那些让我熬夜的AI工程问题7.1 数据加载成了训练瓶颈有一次训练一个图像模型GPU利用率只有20%训练速度极慢。我一开始以为是模型太复杂后来用PyTorch Profiler一查发现80%的时间花在数据加载上。原因是数据加载用了Python的PIL库做图像解码单线程速度慢。解决办法是用DataLoader的num_workers参数开多进程同时用opencv或者turbojpeg替代PIL做解码。改完之后GPU利用率升到80%训练速度提升了3倍。这个坑的教训是不要忽略数据加载的性能。GPU再快数据供不上也是白搭。用num_workers开多进程用pin_memory加速CPU到GPU的传输用prefetch_factor预取数据。7.2 显存泄漏导致训练崩溃有一次训练一个NLP模型跑了几百步之后突然OOM。我检查了模型和batch size都没问题。后来用torch.cuda.memory_allocated()监控显存发现显存占用持续增长每步增加一点。原因是把loss存到了一个列表里用于后续画图。loss是tensor保留了计算图导致计算图无法释放。解决办法是用loss.item()把tensor转成Python float或者用loss.detach()断开计算图。这个坑的教训是任何存到列表里的tensor都要detach。包括loss、准确率、梯度范数等。养成习惯存之前先detach。7.3 多卡训练速度不升反降有一次用DDP做多卡训练从单卡扩展到4卡速度只提升了1.5倍远低于预期的3.5倍。排查后发现是NCCL通信成了瓶颈。原因是模型太小通信开销占比高。每张卡计算时间短但同步梯度的时间长。解决办法是增大batch size让每张卡的计算时间变长摊薄通信开销。或者用梯度累积减少同步频率。还有一个原因是数据加载成了瓶颈。4张卡同时读数据IO压力大。解决办法是增加num_workers或者把数据预加载到内存。这个坑的教训是多卡训练不是线性加速。通信开销、数据加载、同步等待都会影响扩展效率。扩展之前先做profiling找到瓶颈再优化。7.4 推理服务的内存泄漏有一次推理服务上线后运行几个小时就OOM。排查后发现是每次请求都创建了新的tensor但没有释放。Python的垃圾回收机制对CUDA tensor的处理有延迟导致显存占用持续增长。解决办法是显式调用torch.cuda.empty_cache()或者用对象池复用tensor。更好的做法是用torch.inference_mode()替代torch.no_grad()前者更彻底地禁用梯度计算和版本计数。这个坑的教训是推理服务要长期运行内存管理必须严格。任何创建的对象都要考虑释放任何缓存都要有上限。7.5 模型版本管理混乱有一次线上模型效果突然下降排查后发现是运维同学误部署了一个旧版本的模型。原因是模型文件没有版本标识文件名都是model.pt分不清哪个是新哪个是旧。解决办法是模型文件命名加上版本号和时间戳比如model_v1.2.0_20240101.pt。同时用模型注册表Model Registry管理模型版本记录每个版本的训练数据、超参数、评估指标。部署时从注册表拉取指定版本而不是从文件系统找。这个坑的教训是模型版本管理是AI工程的基础设施。没有版本管理实验无法复现部署容易出错。MLflow、WB、DVC都提供了模型注册功能选一个用起来。8. 从零手搓之后我得到了什么说实话从零手搓AI工程的过程一点都不轻松。你会遇到各种奇怪的报错会在环境配置上花掉一整天会因为一个参数写错而训练失败。但正是这些经历让你真正理解了AI系统是怎么跑起来的。我现在看到任何一个AI项目脑子里会自动浮现出它的数据流、计算图、部署架构、成本结构。这种直觉不是看几篇教程能获得的而是踩了足够多的坑之后自然形成的。如果你正在走这条路我的建议是不要跳过任何一步。不要因为调包方便就跳过环境搭建不要因为数据清洗枯燥就跳过数据管道不要因为部署复杂就跳过推理服务。每一步都有它的价值每一步都在塑造你的工程能力。最后分享一个我常用的检查清单每次启动新项目时都会过一遍环境是否用Docker隔离依赖版本是否锁定数据管道是否可复现是否有版本管理训练脚本是否模块化配置是否外置是否用了混合精度是否监控了梯度范数推理服务是否有动态批处理是否监控了延迟和QPS是否有成本监控GPU利用率是否达标模型是否有版本管理部署流程是否自动化这个清单不完整但能帮你避开大部分常见的坑。剩下的坑需要你自己去踩。踩完之后你就真的入门了。
返回列表