工业视觉踩坑实录(五):系统上线第二天就崩了,我才意识到边缘部署有多难
边缘部署实战:让算法在有限算力下稳定运行

关于作者
我接触视觉整整 10 年。
机器视觉、烟草、煤矿等行业都有深度开发经验。从硬件选型、算法开发、模型训练,到上位机开发及部署,都在一线磨过。
之前是多家公司人工智能团队的技术负责人。现在自己创业了,还在继续做视觉落地这件事。
作者说
在做视觉这件事之前,我以为最难的是算法开发和模型精度。
后来发现,真正让人崩溃的从来不是算法本身,而是现场那些"没想到"的情况——
- 摄像头突然逆光,画面一片白
- 皮带头晃动,带动的尘雾让检测全乱
- 机器停了,但传感器报告还在"运行"
- 边缘设备算力不够,一运行就卡死
这些问题是实验室里遇不到的。
所以我打算写一个系列,记录我们在真实工业场景下踩过的坑、解决过的问题。不讲多么酷炫的算法,只聊怎么让算法稳定跑在客户现场。
这是第五篇。
踩坑实录:现场实测完美,一到客户那就崩了
又一个项目交付的时候,我已经做好了算法。
实验室测试——完美。
去客户现场部署——
第一天还好。
第二天,客户打电话过来:系统卡死了。
我远程一看,内存占用 98%,进程被 OOM Kill 了。
后来排查发现:现场网络不稳定,视频流时断时续,我的代码没有做好断线重连和内存管理。每次断线重连都重新创建模型,内存一直涨,最后直接爆了。
这是我踩的第四个大坑:边缘部署轻视不得。
从那以后,我们花了整整半个月时间,专门打磨边缘部署的稳定性。
01 边缘设备的选择
1.1 常见选择
| 设备类型 | 算力 | 典型场景 | 推荐指数 |
|---|---|---|---|
| Jetson Nano | ~0.5 TOPS | 入门 | ⭐⭐ |
| Jetson Xavier NX | ~21 TOPS | 主流工业部署 | ⭐⭐⭐⭐ |
| Jetson Orin Nano | ~40 TOPS | 新项目推荐 | ⭐⭐⭐⭐⭐ |
| Jetson Orin NX | ~70 TOPS | 高性能 | ⭐⭐⭐⭐⭐ |
1.2 我们的选择
以前我们用 TX2 比较多,现在新项目基本都换成 Orin Nano / Orin NX:
- 算力足够跑 YOLO + 光流
- 功耗适中,可靠性高
- 支持 CUDA,模型加速方便
- 工业级稳定性较好
1.3 选型经验
核心原则:留足算力余量。
我们一般这样算:
- 理论算力需求 × 2 = 实际选型算力
因为工业现场要考虑:
- 算力波动(高温降频)
- 同时运行多个模型
- 系统开销
02 模型加速
2.1 为什么需要加速?
YOLO 原版模型太大,推理太慢:
| 模型 | Jetson TX2 (TensorRT) |
|---|---|
| YOLOv5n | ~10–15ms |
| YOLOv5s | ~20–30ms |
建议用 YOLOv5n 或 YOLOv8n——参数量小,精度损失可接受。
2.2 加速手段
手段一:模型量化(TensorRT)
# PyTorch → ONNX → TensorRT (FP16/int8)
# 1. 导出 ONNX
python export.py --weights yolov5n.pt --img 640 --batch 1 --onnx
# 2. 导出 TensorRT (FP16)
python yolov5_to_trt.py --onnx yolov5n.onnx --engine yolov5n.fp16.engine --fp16
# 3. 导出 TensorRT (int8) - 需要校准数据
python yolov5_to_trt.py --onnx yolov5n.onnx --engine yolov5n.int8.engine --int8 --calib-img /path/to/calib/images
效果对比:
| 精度 | 推理加速 | 精度损失 |
|---|---|---|
| FP32 | 1x | 基准 |
| FP16 | ~2x | <1% |
| INT8 | ~3-4x | ~2-3% |
Jetson 上通常 默认使用 FP16,INT8 需要校准数据集。
手段二:输入尺寸优化
| 输入尺寸 | 推理时间 | mAP 变化 |
|---|---|---|
| 640×640 | 基准 | 基准 |
| 512×512 | -20% | -1~2% |
| 416×416 | -35% | -3~5% |
经验:在工业场景中,适当降低输入尺寸往往是最有效的优化手段。
03 抽帧策略:算力不够,帧数来凑
3.1 核心思想
边缘设备算力有限,不是每一帧都需要做复杂推理。
我们的策略是:
- 正常状态:低频检测(每秒 1-2 次)
- 检测到运动:提升频率(每秒 5-10 次)
- 异常状态:持续高频检测
3.2 代码实现
class AdaptiveFrameStrategy:
"""自适应抽帧策略"""
def __init__(self, fps=30):
self.fps = fps
self.current_interval = 2 # 当前检测间隔(帧)
self.min_interval = 1 # 最小间隔
self.max_interval = 10 # 最大间隔
self.motion_count = 0
self.static_count = 0
self.last_state = "static"
def should_detect(self, frame_idx):
"""判断当前帧是否需要检测"""
return frame_idx % self.current_interval == 0
def update(self, motion_detected):
"""根据运动状态动态调整检测频率"""
if motion_detected:
self.motion_count += 1
self.static_count = 0
# 连续运动,增加检测频率
if self.motion_count > 5:
self.current_interval = max(self.min_interval, self.current_interval - 1)
self.last_state = "motion"
else:
self.static_count += 1
self.motion_count = 0
# 连续静止,降低检测频率
if self.static_count > 10:
self.current_interval = min(self.max_interval, self.current_interval + 1)
self.last_state = "static"
3.3 在光流计算中的应用
在我原来的代码里,是类似的逻辑:
# 原始代码片段
if self.prev_pts is None or len(self.prev_pts) < 30:
run_optical_flow = True # 特征点不足,必须更新
elif recent_motion > 0:
run_optical_flow = True # 最近有运动,全帧计算
elif diff_score > 0.005:
run_optical_flow = True # 有轻微变化,间隔性计算
elif self.frame_counter % 3 == 0:
run_optical_flow = True # 场景静止时,降频计算
核心思想是一样的:根据场景动态调整计算频率。
04 内存管理:防止 OOM
4.1 常见内存问题
- 模型重复加载:每次推理都创建新模型
- 缓存积累:历史数据一直累积不释放
- 内存泄漏:某些对象无法被 GC 回收
4.2 场景优化
真实工业系统一般不会 动态删除模型。
因为重新加载模型:
- 非常慢
- GPU重新分配显存
- 可能导致卡顿
更真实的做法是:
- 限制缓存
- 重启进程
- watchdog
4.3 断线重连策略
class VideoStreamManager:
"""视频流管理器"""
def __init__(self, url, reconnect_interval=5, max_reconnect=10):
self.url = url
self.cap = None
self.reconnect_interval = reconnect_interval
self.max_reconnect = max_reconnect
self.reconnect_count = 0
def get_frame(self):
"""获取帧,带自动重连"""
if self.cap is None or not self.cap.isOpened():
self._connect()
if self.cap is not None and self.cap.isOpened():
ret, frame = self.cap.read()
if ret:
return frame
# 读取失败,尝试重连
self._reconnect()
return None
def _connect(self):
"""连接视频流"""
self.cap = cv2.VideoCapture(self.url)
self.reconnect_count = 0
def _reconnect(self):
"""重连"""
if self.reconnect_count >= self.max_reconnect:
print("最大重连次数 reached")
return
self.reconnect_count += 1
print(f"尝试重连 ({self.reconnect_count}/{self.max_reconnect})...")
# 释放旧资源
if self.cap is not None:
self.cap.release()
time.sleep(self.reconnect_interval)
self._connect()
def release(self):
"""释放资源"""
if self.cap is not None:
self.cap.release()
self.cap = None
05 断线重连与状态恢复
5.1 问题
工业现场网络不稳定,视频流可能中断。
5.2 解决思路
- 自动重连:检测到断线后自动重连
- 状态恢复:重连后恢复之前的检测状态
- 数据补齐:用缓存的数据暂时填充
5.3 在代码中的实现
# 断线重连逻辑
def _init_after_reconnect(self):
"""断流后重启,变量重置"""
# 保留关键状态
self.last_decision_time = time.time()
# 重置检测状态
self.dust_frame_counter = 0
self.dust_triggered = False
self.person_mode = False
# 光流状态需要重新初始化
self.motion_flag_history.clear()
self.prev_gray = None
self.prev_pts = None
self.frame_counter = 0
06 监控与告警
6.1 核心指标
| 指标 | 阈值 | 动作 |
|---|---|---|
| 内存使用率 | >85% | 告警 + 清理缓存 |
| CPU 使用率 | >90% | 告警 + 降低帧率 |
| GPU温度 | >80° | 告警 |
| 推理时间 | >100ms | 记录日志 |
| 帧率 | <10fps | 告警 |
| 断线次数 | >5次/小时 | 告警 |
6.2 代码实现
class SystemMonitor:
"""系统监控"""
def __init__(self):
self.metrics = {
"fps": [],
"inference_time": [],
"memory_usage": []
}
self.alert_thresholds = {
"memory_ratio": 0.85,
"fps_min": 10,
"inference_time_max": 100
}
def record(self, fps, inference_time, memory_ratio):
"""记录指标"""
self.metrics["fps"].append(fps)
self.metrics["inference_time"].append(inference_time)
self.metrics["memory_usage"].append(memory_ratio)
def check_alerts(self):
"""检查是否需要告警"""
alerts = []
avg_fps = np.mean(self.metrics["fps"][-30:])
avg_inference = np.mean(self.metrics["inference_time"][-30:])
avg_memory = np.mean(self.metrics["memory_usage"][-30:])
if avg_fps < self.alert_thresholds["fps_min"]:
alerts.append(f"FPS过低: {avg_fps:.1f}")
if avg_inference > self.alert_thresholds["inference_time_max"]:
alerts.append(f"推理时间过长: {avg_inference:.1f}ms")
if avg_memory > self.alert_thresholds["memory_ratio"]:
alerts.append(f"内存使用过高: {avg_memory*100:.1f}%")
return alerts
07 总结
本文分享了边缘部署的实战经验,核心要点:
- 设备选型:留足算力余量,推荐 Jetson TX2 / Orin
- 模型加速:TensorRT 量化 + 输入尺寸优化
- 抽帧策略:根据场景动态调整检测频率
- 内存管理:单例模型 + 缓存限制 + 自动清理
- 断线重连:自动重连 + 状态恢复
- 系统监控:关键指标实时监控 + 告警
核心教训:在现场稳定运行,比算法精度更重要。
08 写在最后
工业视觉落地,拼的不是算法多先进,而是能不能在客户现场稳定跑起来。
边缘部署是一个"细节决定成败"的领域——一个内存泄漏、一个断线没处理,就可能导致整个系统崩掉。
希望这篇文章能帮你避坑。
如果你也有工业视觉落地的困扰,欢迎一起交流。
*本文所有代码均为示意,核心思路可复现,具体参数需根据实际场景调整。
📎 相关阅读
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)