计算机视觉实战:从“拍脑袋”到线上跑通,我踩过的坑和攒下的经验
嗨,大家好!我是阿哲,一个刚晋升半年的技术组长——没错,就是那种名义上开始“带人”,实际上还在给 PR 打标签、半夜被 PagerDuty 叫醒修 Bug 的初级 Leader。之前五年一直在一线写前端,但最近这两年,团队业务越来越“AI 化”,老板一句“我们要做智能体验”,我就被迫从 Vue 和 React 的舒适圈里爬出来,硬着头皮啃起了 OpenCV、PyTorch、YOLO 这些以前只在知乎标题里见过的词。
说来惭愧,去年双11前,产品经理拿着一份 PPT 跑过来:“用户上传商品图太乱了,能不能自动识别图中有没有‘真人试穿’?有就打个标签,提升点击率!”我当时嘴上答应得飞快:“没问题,CV 小事一桩!”心里却慌得一批——毕竟我上一次接触图像处理,还是大学时用 MATLAB 给 Lena 图加高斯模糊……
但没办法,技术组长嘛,总不能当众说“我不会”。于是,这场“计算机视觉实战项目”就这么硬着头皮开干了。今天这篇博客,不讲理论,不堆公式,就聊聊我们怎么从零搞出一个能上线的图像分类服务,中间踩了哪些坑,又怎么被面试题反向教育了一波。
需求很朴素,现实很骨感
先说清楚业务场景:我们的电商 App 允许用户上传穿搭照片,但有些图是纯商品平铺,有些是真人上身。运营希望自动区分这两类,给“真人试穿”图加个徽章,据说能提升 15% 的转化(数据来源:产品经理的直觉)。
听起来很简单?不就是二分类吗?但现实立马给我上了一课:
- 用户上传的图五花八门:有的逆光、有的模糊、有的只露半条腿;
- 有些图里既有真人又有平铺商品(比如模特坐在地上摆拍);
- 线上 QPS 要求不高(峰值约 50),但延迟必须 <500ms,否则影响发帖流程;
- 最要命的是——没有标注数据。对,你没看错,产品提需求时连 10 张样例图都没给全。
我一度想直接回一句:“要不你们先招个 CV 算法工程师?”但转念一想,这不正是技术组长该扛的事儿吗?咬咬牙,自己上。
第一步:别造轮子,先找现成的“轮子厂”
作为前端出身的老油条,我的第一反应不是手撸 CNN,而是:有没有现成模型能微调?
经过一番调研(其实就是 GitHub + Hugging Face 狂搜),最终锁定两个方向:
- MobileNetV2:轻量、快,适合移动端部署,TF Lite 支持好;
- YOLOv8n-cls:Ultralytics 新出的分类版 YOLO,虽然名字带“检测”,但分类任务也支持,而且预训练权重效果惊艳。
我们内部做了个小 benchmark,在自建的 500 张测试集上跑:
| 模型 | 准确率 | 推理时间 (CPU) | 模型大小 | 是否支持 ONNX 导出 |
|---|---|---|---|---|
| MobileNetV2 (ImageNet 预训练) | 78.2% | 120ms | 14MB | ✅ |
| YOLOv8n-cls (COCO 预训练) | 85.6% | 95ms | 10MB | ✅ |
| ResNet50 (ImageNet) | 83.1% | 210ms | 98MB | ✅ |
结论很明显:YOLOv8n-cls 又快又准,还小。虽然它主打目标检测,但分类头其实很干净,微调起来也方便。关键是——它的训练脚本写得像前端工程一样规范,连 requirements.txt 都配好了,感动哭。
🙃 吐槽一句:有些开源项目 README 写得比代码还长,结果跑起来缺依赖、路径写死、GPU 内存爆炸……YOLOv8 这套工具链真的香,建议所有算法工程师都学学什么叫“工程友好”。
数据:没有标注?那就自己标!
接下来最痛苦的环节来了:标注数据。
我们从历史用户上传图里随机抽了 3000 张,然后——我和实习生两人,花了整整三天,用 LabelImg 手动打标签。每天晚上盯着屏幕看“腿”看到眼花,一度怀疑自己是不是在做某种奇怪的内容审核。
但你以为这就完了?No!测试时发现,模型在“坐姿真人”上表现极差——因为训练集中 90% 是站立照。赶紧补标 500 张坐姿、蹲姿、躺姿……甚至还有宠物试穿(真的有用户给狗穿衣服拍照!)。
教训:数据分布决定模型上限。别信“少量样本也能 fine-tune”,除非你的任务极其简单。
训练 & 调优:那些让我凌晨三点骂街的坑
训练过程看似 smooth,实则暗流涌动。
坑 1:数据增强翻车
一开始我狂加数据增强:旋转 ±30°、随机裁剪、色彩抖动……结果验证集准确率反而从 85% 掉到 76%。后来发现——过度增强破坏了关键语义。比如把“真人”旋转 30° 后,腿部结构变形,模型学偏了。
解决方案:只保留最温和的增强:
augmentations = A.Compose([
A.Resize(224, 224),
A.HorizontalFlip(p=0.5),
A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
去掉旋转、裁剪、亮度调整,准确率立马回升。
坑 2:学习率太高,loss 飞天
用默认 lr=0.01 训练,第一个 epoch loss 直接 NaN。查了半天,发现 YOLOv8 默认配置是针对大 batch size 的(比如 64),而我们只有 16(穷,GPU 只有 16G)。
调整后:
# yolov8n-cls.yaml
lr0: 0.001
lrf: 0.01
batch: 16
imgsz: 224
配合 CosineAnnealingLR,loss 终于稳稳下降。
坑 3:线上推理慢得像乌龟
本地测试 95ms,部署到生产环境(4 核 CPU + 无 GPU)直接飙到 800ms!差点被 SRE 拉去喝茶。
排查发现:OpenCV 读图 + PyTorch 推理 + 后处理 三段耗时叠加。优化方案:
- 用
cv2.IMREAD_UNCHANGED替代默认读取,减少颜色空间转换; - 模型转 ONNX + ONNX Runtime(CPU 推理提速 2.3 倍);
- 预热模型:启动时先 run 一次 dummy input,避免 JIT 编译拖慢首请求。
最终线上 P99 延迟压到 420ms,勉强过关。
关键代码:从训练到部署的一条龙
这里贴几个核心片段,省得你们再踩我踩过的坑。
微调 YOLOv8 分类模型
from ultralytics import YOLO
# 加载预训练模型
model = YOLO('yolov8n-cls.pt')
# 开始训练(数据集目录需按 YOLO 格式组织)
results = model.train(
data='./datasets/fashion_cls', # images/train/, images/val/
epochs=50,
imgsz=224,
batch=16,
name='fashion_v1'
)
ONNX 导出 + 推理
# 导出 ONNX(注意 opset 版本)
model.export(format='onnx', imgsz=224, opset=12)
# ONNX Runtime 推理
import onnxruntime as ort
import numpy as np
ort_session = ort.InferenceSession("fashion_v1.onnx")
input_name = ort_session.get_inputs()[0].name
def predict(image: np.ndarray) -> str:
# image: (224, 224, 3) BGR
input_tensor = image.transpose(2, 0, 1)[None, ...].astype(np.float32) / 255.0
input_tensor = (input_tensor - np.array([0.485, 0.456, 0.406])[:, None, None]) \
/ np.array([0.229, 0.224, 0.225])[:, None, None]
outputs = ort_session.run(None, {input_name: input_tensor})
probs = outputs[0][0]
return "human" if probs[1] > 0.7 else "product" # 阈值可调
💡 小技巧:阈值别死设 0.5!我们通过 ROC 曲线分析,发现 0.7 时 precision 更高,误标“平铺图为真人”的情况大幅减少。
面试题?不,这是我们的日常
说到这儿,突然想起最近面试候选人时问的一个题:
“如果线上模型准确率突然下降,你会怎么排查?”
以前我觉得这是道标准八股文,直到上周五晚上 11 点,监控报警:真人识别准确率暴跌至 62%!
我打开 Grafana 一看,发现新上传的图里大量出现“镜子自拍”——用户对着镜子拍,图里有两个“人”,但我们的模型只见过单人图。更糟的是,有些图背景是浴室瓷砖,模型误判为“平铺商品纹理”。
紧急应对:
- 临时提高阈值到 0.85,宁可漏杀不误杀;
- 快速收集 200 张镜面图,加入训练集 retrain;
- 上线灰度:先对 10% 流量生效,观察 24 小时。
三天后,准确率重回 84%。这次事故让我深刻意识到:CV 模型不是一劳永逸的,它需要持续的数据反馈闭环。
所以现在我面试时,会追加一句:“如果你来做这个项目,会设计怎样的监控和回滚机制?”——能答出“bad case 自动采集 + 人工复核 pipeline”的,基本就过了。
总结:技术组长的“跨界”心得
回头看这个项目,从被产品经理“忽悠”入坑,到最终上线稳定运行三个月,我最大的感悟不是“CV 很难”,而是:
- 别怕跨界:前端懂点 CV,后端了解点 MLOps,才能在 AI 时代不被淘汰。我们组现在要求每个成员每年至少深入一个非本职领域。
- 工程化 > 算法精度:95% 准确率但延迟 2s 的模型,不如 85% 但 200ms 的。线上系统永远在 trade-off。
- 数据是爹:再牛的算法,喂垃圾数据也是垃圾。建立数据采集-标注-验证的流程,比调参重要十倍。
顺便,这个项目上线后,转化率确实涨了 12.3%(运营终于给了真实数据),老板请我们吃了顿火锅。虽然过程中熬过夜、骂过娘、想过转行送外卖,但看到用户发帖时自动带上那个小小的“真人试穿”徽章,心里还是有点小骄傲的。
最后,如果你也在做类似的 CV 落地项目,欢迎留言交流!或者……缺前端+CV hybrid 人才?我们团队正在扩招(手动狗头)。
写于一个远程办公的周五晚上,窗外下着雨,键盘旁边是第三杯美式。刚 merge 了修复 CI 的 PR,终于可以摸鱼写博客了。

评论 0