1. 先想清楚:AI工程到底在解决什么问题
1.1 为什么现在该重新理解AI工程
说个比较实际的观察。这两年AI岗位的需求曲线变化很明显,真正缺的不是会调包跑模型的人,而是能把AI系统做扎实、能落地、能维护的人。所谓的AI engineer,说白了就是把研究端的想法变成生产环境里可靠运行的系统。这个角色既要懂算法,又要懂工程,还得理解业务指标和数据流转,是个典型的交叉领域。
很多人一听“AI工程”就觉得门槛很高。其实没必要被吓住。我见过不少从运维、后端、数据分析转过来的朋友,他们在系统设计、数据处理上的底子,反而比纯算法出身的人更扎实。反过来,算法工程师要补的是工程化思维:版本控制、自动化测试、监控告警、性能优化。两边往中间一靠,就是AI工程的核心能力区间。
再说直白一点。模型训练只是AI系统生命周期里的一小段。真正花时间的是数据准备、特征加工、实验管理、模型评估、部署上线、灰度验证、监控反馈,这一整条流水线。“ai-engineering-from-scratch”这个方向,说白了就是要把这条流水线的每个环节都走一遍,而不是只盯住训练那一环。
我自己带过几个从零开始学的新人,踩过不少坑,也总结出一套行之有效的路线。下面按“地基—核心—系统”三个层次拆开讲,尽量给到可以直接照着做的方案。
1.2 学习路线总览:从地基到系统
先给一张总览图,后面所有内容都围绕这个框架展开。
- 第一阶段(地基):Python编程 + 数学基础 + 数据处理工具链,周期4到6周。
- 第二阶段(核心):机器学习原理 + 经典算法 + 深度学习框架,周期8到10周。
- 第三阶段(系统):数据工程 + 模型部署 + MLOps + 端到端项目实战,周期6到8周。
整个周期大概4到6个月。重点是每个阶段都要有输出物,要么是笔记,要么是能跑通的代码,要么是一个可演示的小项目。只看不练,三个月后回头看,跟没学一样,我见过太多这样的案例了。
拿我自己来说,当年学机器学习的时候,光看吴恩达的课程看了两周,觉得全会了。结果一写代码,连numpy的广播机制都没搞清楚。从那之后我的原则变了:任何一个知识点,必须用代码亲手实现一遍,哪怕只是最简版本。这个习惯一直保留到今天,对新人我也这么要求。
这三个阶段不是完全割裂的。比如第二阶段学深度学习的时候,你会天天用到第一阶段的numpy和数据处理能力。第三阶段做部署的时候,又要回头补一些Linux和Docker的知识。没关系,边用边补,效率反而比按部就班高。
2. 工程化基础:这部分必须落到实处
2.1 编程语言与工具链怎么选,学到什么程度
先处理编程语言。Python在AI领域是事实标准,生态最全,没有之一。不是说JVM系或者C++不行,而是从开发效率、社区支持、库的丰富度来看,Python目前仍然是最优解。至于学到什么程度才够,我给个可量化的标准。
- 能熟练操作Python的基础语法:数据结构、函数、类、装饰器、生成器。
- 能写文件读写、异常处理、日志输出,代码结构清晰,函数不臃肿。
- numpy、pandas、matplotlib这三个库要熟练,至少能把一份CSV读进来,做完清洗、变换、分组统计,再画个图出来。
- 能读懂工程项目的代码结构,理解模块化设计,而不是把所有逻辑堆在一个脚本里。
工具链方面,我建议一开始就用Anaconda管理Python环境。这个工具可以把不同项目的依赖隔离起来,避免“A项目要numpy 1.x,B项目要2.x,装一个把另一个搞崩了”这种经典悲剧。默认Python环境就两个,一个base,一个项目专用环境,互不干扰。
然后是数学基础。很多教程一上来就是线性代数、微积分、概率论,动辄三个月起步,直接把人的热情磨没了。我的建议是讲究性价比,跟着机器学习的具体内容走。
- 线性代数:理解向量、矩阵、矩阵乘法、转置、行列式。不需要学会手算特征值分解,但必须知道矩阵乘法为什么是那个规则,因为神经网络的每一层就是一次矩阵运算。
- 微积分:理解导数和链式法则就够了。反向传播算法的数学本质就是链式法则。
- 概率统计:理解均值、方差、正态分布、条件概率、最大似然估计的基本概念。
举个例子你就明白了。训练一个线性回归模型,预测房价。特征是面积、房龄、地段评分,权重分别是w1、w2、w3,模型就是y = w1x1 + w2x2 + w3*x3 + b。训练过程就是不断调整这些权重,让预测误差最小。调整的依据就是梯度——也就是损失函数对每个权重的偏导数。你看,线性代数的矩阵乘法体现在前向计算里,微分的链式法则体现在反向传播里,概率统计体现在评估指标和误差分布的理解上。
所以别一上来就啃大部头教材。我当时用了一个更取巧的办法:先跑模型,哪儿卡住了就去补对应的数学,带着问题学,效果远好于漫无目的地刷书。
2.2 机器学习原理:不啃完也能用的关键点
很多人纠结要不要把机器学习理论全部搞透再动手。我的观点很明确:不必。但有几件事必须想明白。
监督学习的本质是拟合一个函数。给它一堆输入和对应的标签,它学习输入到标签的映射关系。分类就是输出离散的类别,回归就是输出连续的数值。这个框架听着简单,实操时最大的坑是过拟合——模型在训练数据上表现极好,一到新数据就拉胯。
我见过一个很典型的案例。有朋友拿一个表格数据集做分类,特征有200多个,样本只有3000条。他直接丢给XGBoost跑,训练准确率99%,测试集只有72%。这就是典型的过拟合。后来做了特征筛选,砍到30个特征,加正则化参数,测试准确率提到了85%。所以说,学机器学习,第一个要建立的感觉就是“泛化”这两个字,而不是一味追求训练集上的高分。
另一个关键点是理解模型评估。准确率不是万能的。分类任务里正负样本不均时,准确率会骗人。比如一个故障检测系统,99.5%都是正常样本,模型什么都不做、全预测正常,准确率就是99.5%,看起来很厉害,实际一点用都没有。这时候要看精确率、召回率、F1-score。这些概念刚开始觉得枯燥,实际用一次就知道价值了。
还有一点,经典的scikit-learn库一定要吃透。它是传统机器学习的事实标准,API设计简洁,数据预处理、模型训练、交叉验证都封装得清清楚楚。建议把常用的几个模型都跑一遍:线性回归、逻辑回归、决策树、随机森林、梯度提升树、SVM、KMeans。目的不是为了学会调参,而是感受不同模型的适用场景和默认行为。
用一句话概括这个阶段的目标:能用一套标准流程处理一个表格型数据问题,从数据清洗到模型训练到评估,整个过程心里有数。
3. 深度学习实战:选对框架,跑通第一个模型
3.1 为什么我选了PyTorch而不是TensorFlow
到了深度学习阶段,框架选择是个躲不开的问题。我给新人的建议是:从PyTorch开始。原因有三。
第一,社区活跃度。近几年的论文实现、开源项目里PyTorch占绝对主流,遇到问题搜一下基本能找到答案。第二,调试体验。PyTorch是动态图机制,代码写到哪儿就能在哪儿打印、检查,对新手极其友好。TensorFlow 2.x虽然也支持动态图,但整体设计更复杂,新手容易绕晕。第三,生态完整性。PyTorch在NLP、CV、强化学习这些方向都有成熟的原生或第三方库,比如Hugging Face Transformers就是PyTorch优先支持的。
我早期学的是TensorFlow 1.x,那会儿还是静态图模式。写了个模型,要先用tf.placeholder定义输入,再建一个session去run,中间变量根本没法直接查看。调试个bug能折腾一晚上。后来转了PyTorch,感觉整个世界都明亮了,跟写普通Python代码一样自然。
不是说TensorFlow不好,它在生产部署、移动端优化上有自己的优势。但作为学习路径,PyTorch的上手曲线更平滑,等你理解了深度学习本质,再去看TensorFlow也会快很多。毕竟框架是工具,核心是模型设计和数据处理。
3.2 从零训练一个图像分类模型的完整过程
我拿一个具体的例子来说明:用PyTorch在CIFAR-10数据集上训练一个图像分类模型。这个数据集有6万张32x32的彩色图片,分10个类别,算是最经典的入门数据集。
第一步是数据准备。PyTorch提供了现成的数据集接口,但工程上更重要的习惯是理解数据加载的过程。用DataLoader可以自动批量加载数据、打乱顺序、多线程预读,这比你手动写循环一个一个读图快一个数量级。
import torch import torchvision import torchvision.transforms as transforms transform = transforms.Compose([ transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ]) trainset = torchvision.datasets.CIFAR10( root='./data', train=True, download=True, transform=transform) trainloader = torch.utils.data.DataLoader( trainset, batch_size=64, shuffle=True, num_workers=2) testset = torchvision.datasets.CIFAR10( root='./data', train=False, download=True, transform=transform) testloader = torch.utils.data.DataLoader( testset, batch_size=64, shuffle=False, num_workers=2)这段代码里有三个细节值得注意。RandomHorizontalFlip是数据增强——训练时随机把图片水平翻转,相当于免费扩充了数据集,能在一定程度上抑制过拟合。Normalize是标准化,把像素值从0到255映射到-1到1之间,让模型训练更稳定。batch_size=64表示每批喂给模型64张图,这个值的选取很讲究,太大了显存不够,太小了训练不稳定还慢。
第二步是定义一个卷积神经网络。我建议新手自己写一个简化的CNN,而不是直接调torchvision里现成的ResNet。自己手写可以理解每一层的输入输出维度是怎么变化的。
import torch.nn as nn import torch.nn.functional as F class SimpleCNN(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1) self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) self.pool = nn.MaxPool2d(2, 2) self.fc1 = nn.Linear(64 * 8 * 8, 128) self.fc2 = nn.Linear(128, 10) def forward(self, x): x = self.pool(torch.relu(self.conv1(x))) x = self.pool(torch.relu(self.conv2(x))) x = torch.flatten(x, 1) x = torch.relu(self.fc1(x)) x = self.fc2(x) return x输入图是3通道32x32。经过第一层卷积后变为32通道,维度不变;经过一次池化,尺寸从32x32减半到16x16。第二层卷积把通道数从32提到64,再池化一次,变成64通道8x8。最后拉平成6488=4096个数值,接两层全连接,最终输出10个类别的得分。
第三步是训练循环。这一步代码相对固定,核心是定义损失函数和优化器,然后循环若干轮。
import torch.optim as optim model = SimpleCNN() criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) for epoch in range(10): running_loss = 0.0 for inputs, labels in trainloader: optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() print(f'Epoch {epoch+1}, loss: {running_loss/len(trainloader):.4f}')这段代码建议手敲一遍,因为它包含了深度学习训练的核心模式:前向计算、计算损失、反向传播、更新参数。之后不管用什么框架,本质都是这个循环。optimizer.zero_grad()这一行特别容易被忽略,它的作用是清空上一步计算的梯度。如果忘了,梯度会在每次迭代中累加,导致训练发散,loss直接变成NaN。
训练10轮之后,这个简单的CNN在CIFAR-10上大概能到65%到70%的准确率。ResNet之类的模型能到90%以上,但对新手来说,亲手把这个流程跑通,远比直接调用一个现成的高精度模型更有价值。
4. 数据与特征:模型效果的上限在这里
4.1 数据清洗与标注:这步做得越细后面越省事
有一句话在AI圈子里流传很广:数据和特征决定了机器学习的上限,模型只是逼近这个上限。我深以为然。很多人花了80%的时间折腾模型架构,却忽略了数据质量。实际上,建模前的数据清洗和特征工程,往往比模型本身更影响最终效果。
拿一个电商评论情感分析项目举例。原始数据长什么样?可能是一堆爬下来的评论文本,夹杂着HTML标签、乱码、重复内容、中英文混排。直接拿来训练模型,效果可想而知。清洗这一步要处理的问题至少有这些。
- 去除HTML标签和无关符号,比如
<br>、&这类残留。 - 处理缺失值。有的评论字段是空的,有的评分字段是NaN,需要统一策略,是删除还是填充,得提前定好规则。
- 去重。尤其是爬虫数据,同一条评论可能被爬了多次,不处理会让模型偏向这些重复样本。
- 文本标准化。全角半角转换、繁体简体统一、大小写统一,这些细节处理不好,同一个词会被模型当成两个不同的特征。
清洗完数据,接下来是标注。如果是二分类情感分析(正面/负面),可以基于评论对应的评分做自动标注,比如4星以上标正面,2星以下标负面,3星去掉或者单独处理。这个过程值得花时间仔细检查标注规则的合理性,因为标注噪声过大会直接拉低模型效果上限。
数据划分也是个容易被忽视的环节。训练集、验证集、测试集必须严格分离。验证集用来调参,测试集只在最终评估时用一次。如果参数调多了,测试集也会被“记住”,导致上线后的真实效果远不如离线测试。
4.2 特征工程实例:从原始数据到可用特征
特征工程是个大学问,不同数据类型的方法完全不同。还是拿电商评论数据举例,我们既要处理文本特征,也要处理数值特征。
文本特征最简单有效的方法是TF-IDF向量化。把每一条评论转成一个向量,维度等于词表大小,每个位置的值表示这个词在该评论里的重要性。TF-IDF的本质就是:一个词在某一篇文档里出现得多,但在其他文档里出现得少,说明它有区分度,权重就高。
from sklearn.feature_extraction.text import TfidfVectorizer vectorizer = TfidfVectorizer(max_features=5000, ngram_range=(1, 2)) X_text = vectorizer.fit_transform(corpus)这里max_features=5000的意思是只保留词频最高的5000个词,否则维度可能有几万几十万,训练就慢了。ngram_range=(1, 2)表示同时保留单个词和相邻两个词的组合,这样可以捕捉“不是”“太差”这类短语的意思,比单纯一个词一个词看要强。
数值特征方面,可以做评论长度、句子的数量、标点符号数量、包含的感叹号数量等衍生特征。别小看这些手工特征,对于某些任务它们的作用非常显著。
比如我们发现“太长不看”类评论往往偏负面,“强烈推荐”类评论往往偏正面。“!”和“!!!”的使用频率对情感表达也有一定指示作用。这些人工特征加到模型里,能帮模型在没有大量预训练词向量的情况下仍然有不错的起点。
做完特征,别忘了做特征缩放。像评论长度、标点数量这些特征的数值范围差异很大,有些模型(如SVM、逻辑回归)对特征尺度敏感,需要标准化或归一化。用sklearn的StandardScaler一键搞定。树模型不受这个影响,所以很多人用LightGBM的时候会偷懒跳过这步,但如果你同时训练多个模型做对比,一定要统一这套流程。
特征工程做得好,能让你在模型结构非常简单的情况下拿到相当好的效果。这也是AI工程的魅力所在——不是非得堆大模型、烧显卡才能出活。
5. 部署与监控:让模型真正跑起来
5.1 用FastAPI提供线上推理服务
训练好的模型如果只躺在notebook里,价值就是零。模型要真正发挥作用,必须部署成服务,接受外部请求,返回预测结果。最常用的方案是用FastAPI写一个REST API,把训练好的模型包装起来。
FastAPI的优势是性能好、自动生成接口文档、参数校验简单,而且代码量少。一个最简的推理接口大概长这样。
from fastapi import FastAPI from pydantic import BaseModel import joblib import numpy as np app = FastAPI() model = joblib.load("sentiment_model.pkl") vectorizer = joblib.load("tfidf_vectorizer.pkl") class Review(BaseModel): text: str @app.post("/predict") def predict(review: Review): features = vectorizer.transform([review.text]).toarray() prob = model.predict_proba(features)[0, 1] label = "positive" if prob >= 0.5 else "negative" return {"label": label, "probability": float(prob)}这里有几个工程细节值得注意。模型和向量器在服务启动时就加载到内存里,避免每次请求都重新加载一次,省掉大量延迟。输入用pydantic做校验,请求体不符合格式的直接返回400错误,不用自己写解析逻辑。
然后是部署。最简单的方式是用Docker把服务打包成一个镜像,这样在任何服务器上都能一键运行,不需要重复配置Python环境。
FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple COPY . . CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]构建镜像是docker build -t sentiment-api .,运行是docker run -p 8000:8000 sentiment-api。一套下来,模型服务就起来了。这里我建议镜像源换成国内镜像源(比如清华PyPI镜像),否则在部分网络环境下装依赖会慢得让人怀疑人生。
5.2 MLOps基础:版本管理、自动化与模型监控
服务上线只是第一步。生产环境里的模型会面临一个持续的挑战:数据分布漂移。用户的表达方式会变,商品类目会调整,节假日的评论分布也和平时不一样。今天效果挺好的模型,三个月后可能就明显变差了。所以MLOps的核心目标就是让模型从“一次性交付物”变成“持续演进的服务”。
版本管理是最基本的。代码用Git管理,模型文件也得管起来。实际操作中,我习惯用DVC或者简单的文件命名规则,比如sentiment_model_v20241201_auc0.931.pkl,这样每个版本对应哪个训练数据、什么指标,一目了然。回滚起来也方便,旧版本文件还在,随时能换回去。
自动化方面,可以给模型训练写一个定时任务(cron job),每周或每月自动用新数据重训一遍。别小看这个“自动重训”,很多AI项目的效果在初期很好,后来一路下滑,就是因为没人管,数据变了模型没跟着变。
模型上线后,监控是必须做的。重点看这几个指标:
- 服务可用性:接口的响应时间、错误率、QPS,这些用常规的监控工具就能搞定,比如Prometheus加Grafana。
- 预测分布:每天预测结果的均值、方差、类别比例。如果某天开始正面的比例突然从70%变成了50%,大概率是输入分布变了或者模型出了问题。
- 延迟和资源占用:CPU、内存、GPU使用率,尤其是有多个模型共用一个推理集群的时候。
这里我多说一句。监控绝对不是等到服务出问题才去建,要从第一天就埋点。最简单的方式是在预测接口里加一行日志,把预测结果、模型版本、输入文本的长度、耗时都记下来。这些日志积累到一定量,就是后续评估模型效果、定位问题的重要依据。
从工程角度说,MLOps的复杂度和系统规模正相关。个人项目不需要搭一整套Kubeflow之类的重量级平台,先从轻量方案开始,把核心流程跑通,后面有需要再加。
6. 端到端实战:从一个项目看全流程
6.1 项目选型:为什么选评论情感分析
理论学习再多,都不如一个端到端项目能串联知识。我建议新人的第一个完整项目选评论情感分析,理由是:数据容易获取、任务直观、全流程都能覆盖到、不需要特别大的算力。
- 数据获取:可以从公开数据集平台下载电商评论,也可以自己写爬虫抓取,这一点能练到数据采集能力。
- 数据标注:基于评分做弱标签就行,不需要请人工标注,成本低。
- 建模:文本分类用TF-IDF加逻辑回归就能拿到不错的效果,进阶可以用BERT微调,伸缩空间很大。
- 部署:包装成FastAPI服务很简单,前端展示可以做一个简单的页面,让用户输入一句话,返回情感判断。
- 监控:接口日志、请求量统计、预测结果分布,都能做得有模有样。
这个项目唯一的问题是太经典,网上教程一堆。但这反而是优势,卡住了搜“商品评论情感分析”,能搜出一堆参考。做项目的一个重要原则就是循序渐进,第一遍顺着教程走通,第二遍换成新数据集自己做一遍,就真正掌握了。
6.2 全流程拆解:从数据获取到上线后的迭代
我按实际执行顺序把整个项目拆成八个步骤,每一步要有明确的输入输出。
第一步,数据获取。如果用爬虫,遵守robots协议和网站条款,控制爬取频率,别把人家服务器搞挂了。下载下来的原始数据通常是JSON或CSV格式,字段包括评论内容、评分、时间等。
第二步,数据清洗与预处理。这一步我前面已经详细讲过了,关键是把文本清洗干净,统一格式,处理缺失值和重复项。
第三步,标注与数据划分。按评分映射成标签,划分训练集、验证集、测试集,比例建议7:1.5:1.5。划分时注意保证标签分布在三个集合里相对一致,用sklearn的train_test_split配合stratify参数就能实现。
第四步,特征工程。用TF-IDF把文本转成向量,加上手工特征(评论长度、标点数等),合并成一个特征矩阵。保存好向量器,后面预测阶段还要用。
第五步,模型训练与评估。先用逻辑回归跑一版作为baseline,再用LightGBM或者BERT做进阶尝试。对比它们在不同指标上的表现,选最优的一个保存。评估维度要全面,准确率、精确率、召回率、F1、混淆矩阵都看一眼,别只盯着一个数。
第六步,模型封装与部署。用FastAPI封装推理接口,用Docker打包,部署到一台云服务器上。线上环境注意配置线程数、超时时间这些参数,避免并发量上来就挂。
第七步,前端展示与演示。做一个简单的Web页面,支持输入框提交评论文本,调用后端接口显示判断结果和置信度。这一步对整体完成度的提升非常明显,哪怕页面很朴素,也比一个光秃秃的API强很多。
第八步,监听与迭代。根据监控日志观察线上表现。如果发现某些类的评论频繁预测错误,收集这些bad case,补充到训练数据里,开始下一轮迭代。
这个项目的全部代码量大概在1500到2500行,做完之后你对AI工程的整体认知会有一个质的变化。别嫌小,任何一个复杂系统都是从一个小闭环开始的。
关于算力,我再多说一句。情感分析这类NLP任务,普通CPU就能训练,完全不需要GPU。如果你用的是BERT微调,Google Colab的免费GPU就够用,没必要一开始就买显卡。
7. 常见问题与避坑指南
7.1 新手最容易卡住的五个地方
根据我带人和自己踩坑的经验,新手在从零学习AI工程的过程中,最常在下面五个地方卡住。
环境配置是第一大坑。Anaconda装了,CUDA装了,PyTorch装完结果跑不起来,或者import torch报错缺失动态链接库。这类问题最让人崩溃,因为跟代码逻辑无关,纯粹是环境问题。解决办法是养成用虚拟环境的好习惯,每个项目单独建一个环境,Python版本和依赖版本都锁死。装PyTorch的时候,去官网选对应的安装命令,注意CUDA版本要和本机驱动匹配。
训练数据泄漏是第二大坑。我在真实项目里见过不止一次:数据预处理在整个数据集上先做了标准化,然后才划分训练集和测试集,导致测试集信息混入了训练阶段,评估结果虚高。正确做法是先在训练集上fit,再在验证集和测试集上只做transform。这类细节如果不注意,做出来的模型上线就露馅。
欠拟合和过拟合的判断是第三大坑。很多人一看到loss高就加模型复杂度,一看到准确率低就加数据。训练集loss高是欠拟合,应该考虑增加模型容量或特征;训练集loss低但验证集loss高是过拟合,应该做正则化、数据增强或降低模型复杂度。方向搞反了,越调越乱。
GPU显存溢出是第四大坑。batch_size设得太大,一训练就OutOfMemory。解决办法是调小batch_size,或者开启梯度累积,多算几个batch再更新一次参数。我刚学的时候一看到OOM就慌,后来才发现把batch_size从128调到32就解决了。
第五个坑是模型保存和加载不匹配。训练的时候用了一套预处理流程,部署的时候忘了带上同一套flow,结果预测输入和训练分布不一致,效果崩得一塌糊涂。处理办法是部署包里面除了模型文件,必须把向量器、标准化器、标签映射这些前置对象一并序列化保存。
7.2 踩坑后的解决方案速查表
我把上面提到的以及一些其他高频问题整理成了一张速查表,遇到问题直接对照着查。
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| import torch报错 | CUDA版本不匹配或缺少依赖 | 按官网命令重装,CPU版兜底 |
| 训练loss为NaN | 学习率过大或梯度爆炸 | 降低学习率,加梯度裁剪 |
| 训练集表现好,测试集很差 | 过拟合 | 增加正则化、数据增强,降低模型复杂度 |
| 两个模型数据预处理不一致 | 训练和部署使用不同代码 | 统一封装预处理流水线,保存到pkl文件 |
| API并发请求响应慢 | 模型加载重复或线程配置不合理 | 模型只加载一次,配置gunicorn多worker |
| 线上效果比离线测试差很多 | 数据分布漂移 | 定期重训,监控预测分布变化 |
| 数据量小且类别不均衡 | 样本不均衡 | 使用class_weight参数或重采样技术 |
| 模型训练太慢 | 数据读取瓶颈 | 增加num_workers,开启pin_memory |
除了表格里的内容,还有两个独家经验我觉得值得单独说。
第一,模型效果不好的时候,先看看bad case,而不是急着换模型。AI工程里有句老话:先看数据,再看模型,最后调参数。我遇到过很多项目,调了一周模型架构没进展,后来仔细翻了一遍bad case,发现是数据标注规则定错了,把中性评论标成了正面,模型怎么学都学不对。换模型之前,先认真看10条预测错误的样本,这个习惯能帮你省下大量无效时间。
第二,学会写日志。训练过程和线上推理过程都要有日志,这是排查问题的基础。刚开始很多人觉得写日志麻烦,出问题的时候一来没有上下文,二来无法回溯,只能重新跑一遍。我的习惯是训练脚本里至少记录每个epoch的loss、学习率、当前时间;线上服务记录每个请求的耗时、预测结果、模型版本。这些日志在关键时刻能救命。
还有一个心理层面的建议。学AI工程容易陷入“资料囤积症”,收藏了一堆教程和文章,一个都没看完。我的经验是资料越少越好,选定一条主线,比如本篇的路线,然后老老实实跟着做。教程的价值在于带你跑通一个闭环,而不是让你把所有细节都搞明白。很多东西用到的时候自然会懂。
这个路线我自己验证过,也带过几个人走通。如果你能坚持到端到端项目上线,基本可以说已经入了AI工程的门。后续再扩展,无非是往深了啃Transformer原理、往宽了学TensorFlow Serving、往细了研究MLOps工具链,但那都是有了基础之后的事。当下最重要的,就是把手头这个闭环跑通。