当前位置: 首页 > news >正文

基于YOLOv5/YOLOv8/YOLOv10的吸烟行为智能检测系统:从原理到实现

摘要

吸烟行为检测是计算机视觉领域的一个重要应用场景,对公共场所的禁烟管理、健康监测等具有重要意义。本文将详细介绍基于YOLO系列算法的吸烟行为检测系统的完整实现,包括算法原理、数据集处理、模型训练、PySide6界面开发以及系统集成。我们将涵盖YOLOv5、YOLOv8和YOLOv10三种主流版本的实现,并提供完整的代码实现。

1. 引言

1.1 研究背景与意义

吸烟是全球公共卫生面临的重大挑战之一。据统计,每年有超过800万人因吸烟相关疾病死亡。在公共场所监测吸烟行为对于执行禁烟政策、保护非吸烟者健康具有重要意义。传统的人工监控方式效率低下、成本高昂,而基于深度学习的智能检测系统能够实现7×24小时不间断监控,大幅提高监管效率。

1.2 YOLO算法演进

YOLO(You Only Look Once)系列算法是目标检测领域的重要里程碑。从最初的YOLOv1到最新的YOLOv10,YOLO算法在精度和速度上不断取得突破:

  • YOLOv5:凭借其优秀的工程实现和易用性成为工业界最受欢迎的目标检测算法之一

  • YOLOv8:引入了更先进的骨干网络和损失函数设计,在精度和速度上达到更好平衡

  • YOLOv10:最新的YOLO版本,通过无NMS设计进一步提升了检测效率

2. 系统架构设计

2.1 总体架构

本系统采用模块化设计,主要包括以下组件:

  1. 数据采集与预处理模块:负责收集和预处理吸烟行为图像数据

  2. 模型训练与优化模块:支持YOLOv5/v8/v10模型的训练与调优

  3. 推理检测模块:实现实时视频流和图像文件的吸烟行为检测

  4. 用户界面模块:基于PySide6开发的图形化操作界面

  5. 数据管理模块:检测结果的可视化与导出功能

2.2 技术栈

  • 深度学习框架:PyTorch 1.10+

  • YOLO实现:Ultralytics YOLO框架

  • 界面开发:PySide6

  • 数据处理:OpenCV, NumPy, Pandas

  • 可视化:Matplotlib, Seaborn

3. 数据集准备与预处理

3.1 数据集收集

吸烟行为检测数据集需要包含各种场景下的吸烟动作。我们采用了以下数据源:

  1. 公开数据集:包含吸烟行为的监控视频帧

  2. 网络爬取:在遵守相关法律法规的前提下获取

  3. 数据增强:通过旋转、缩放、色彩变换等方式扩充数据

3.2 数据标注格式

采用YOLO格式的标注文件:

text

<object-class> <x_center> <y_center> <width> <height>

其中:

  • object-class: 类别索引(吸烟行为为0)

  • x_center, y_center: 边界框中心坐标(归一化到0-1)

  • width, height: 边界框宽度和高度(归一化到0-1)

3.3 数据增强策略

python

import cv2 import numpy as np import albumentations as A from albumentations.pytorch import ToTensorV2 def get_train_transform(): return A.Compose([ A.Resize(640, 640), A.HorizontalFlip(p=0.5), A.RandomBrightnessContrast(p=0.2), A.HueSaturationValue(p=0.2), A.GaussianBlur(p=0.1), A.CLAHE(p=0.1), A.Rotate(limit=15, p=0.3), ToTensorV2() ], bbox_params=A.BboxParams( format='yolo', label_fields=['class_labels'] ))

4. YOLO模型实现

4.1 YOLOv5模型配置与训练

python

# yolov5_training.py import torch import yaml from pathlib import Path import sys class YOLOv5Trainer: def __init__(self, data_yaml, model_yaml, epochs=100, batch_size=16): self.data_yaml = data_yaml self.model_yaml = model_yaml self.epochs = epochs self.batch_size = batch_size def prepare_dataset_yaml(self): """准备数据集配置文件""" data_config = { 'path': './datasets/smoking', 'train': 'images/train', 'val': 'images/val', 'test': 'images/test', 'nc': 1, # 类别数 'names': ['smoking'] # 类别名称 } with open(self.data_yaml, 'w') as f: yaml.dump(data_config, f) def train(self): """训练YOLOv5模型""" import subprocess cmd = [ 'python', 'train.py', '--img', '640', '--batch', str(self.batch_size), '--epochs', str(self.epochs), '--data', self.data_yaml, '--cfg', self.model_yaml, '--weights', 'yolov5s.pt', '--name', 'smoking_detection_v5', '--project', 'runs/train' ] subprocess.run(cmd) # 训练示例 if __name__ == "__main__": trainer = YOLOv5Trainer('smoking.yaml', 'yolov5s.yaml') trainer.prepare_dataset_yaml() trainer.train()

4.2 YOLOv8模型实现

python

# yolov8_training.py from ultralytics import YOLO import yaml import os class YOLOv8Trainer: def __init__(self, data_path, model_size='s'): """ 初始化YOLOv8训练器 Args: data_path: 数据配置路径 model_size: 模型大小 (n, s, m, l, x) """ self.data_path = data_path self.model_size = model_size def train(self, epochs=100, imgsz=640, batch=16): """训练YOLOv8模型""" # 加载预训练模型 model = YOLO(f'yolov8{self.model_size}.pt') # 训练参数 train_args = { 'data': self.data_path, 'epochs': epochs, 'imgsz': imgsz, 'batch': batch, 'patience': 50, 'save': True, 'save_period': 10, 'cache': True, 'device': '0' if torch.cuda.is_available() else 'cpu', 'workers': 8, 'project': 'runs/detect', 'name': f'smoking_yolov8{self.model_size}', 'exist_ok': True, 'pretrained': True, 'optimizer': 'auto', 'verbose': True, 'seed': 42, 'deterministic': True, 'single_cls': False, 'rect': False, 'cos_lr': False, 'close_mosaic': 10, 'resume': False, 'amp': True, 'fraction': 1.0, 'profile': False, 'overlap_mask': True, 'mask_ratio': 4, 'dropout': 0.0, 'val': True, 'plots': True } # 开始训练 results = model.train(**train_args) # 验证模型 metrics = model.val() print(f"验证结果: {metrics}") return model, results # 使用示例 if __name__ == "__main__": trainer = YOLOv8Trainer('smoking.yaml', 's') model, results = trainer.train(epochs=100)

4.3 YOLOv10模型实现

python

# yolov10_training.py import torch from ultralytics import YOLO import yaml class YOLOv10Trainer: def __init__(self, data_yaml, model_size='s'): self.data_yaml = data_yaml self.model_size = model_size def train(self): """训练YOLOv10模型""" # 加载YOLOv10模型 model = YOLO(f'yolov10{self.model_size}.pt') # 训练参数 train_args = { 'data': self.data_yaml, 'epochs': 150, 'imgsz': 640, 'batch': 32, 'patience': 50, 'save': True, 'save_period': 20, 'cache': True, 'device': '0', 'workers': 8, 'project': 'runs/detect', 'name': f'smoking_yolov10{self.model_size}', 'exist_ok': True, 'pretrained': True, 'optimizer': 'AdamW', 'lr0': 0.01, 'lrf': 0.01, 'momentum': 0.937, 'weight_decay': 0.0005, 'warmup_epochs': 3.0, 'warmup_momentum': 0.8, 'warmup_bias_lr': 0.1, 'box': 7.5, 'cls': 0.5, 'dfl': 1.5, 'pose': 12.0, 'kobj': 1.0, 'label_smoothing': 0.0, 'nbs': 64, 'overlap_mask': True, 'mask_ratio': 4, 'dropout': 0.0, 'val': True, 'plots': True, 'verbose': True, 'seed': 42, 'deterministic': True, 'single_cls': False, 'rect': False, 'cos_lr': True, 'close_mosaic': 10, 'resume': False, 'amp': True, 'fraction': 1.0, 'profile': False } # 开始训练 results = model.train(**train_args) # 导出模型 model.export(format='onnx') return model, results

5. PySide6图形界面开发

5.1 主界面设计

python

# smoking_detection_ui.py import sys import os from pathlib import Path from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QFileDialog, QComboBox, QSpinBox, QDoubleSpinBox, QCheckBox, QGroupBox, QMessageBox, QTabWidget, QTextEdit, QProgressBar, QSlider, QSplitter, QListWidget) from PySide6.QtCore import Qt, QTimer, Signal, QThread, QObject from PySide6.QtGui import QImage, QPixmap, QFont, QIcon import cv2 import numpy as np from ultralytics import YOLO import torch class DetectionThread(QThread): """检测线程""" frame_processed = Signal(np.ndarray, list) detection_info = Signal(str) def __init__(self, model_path, conf_threshold=0.5): super().__init__() self.model_path = model_path self.conf_threshold = conf_threshold self.running = False self.video_path = None self.model = None def load_model(self): """加载YOLO模型""" try: self.model = YOLO(self.model_path) self.detection_info.emit(f"模型加载成功: {self.model_path}") return True except Exception as e: self.detection_info.emit(f"模型加载失败: {str(e)}") return False def set_video_source(self, source): """设置视频源""" self.video_path = source def run(self): """运行检测""" if not self.model: self.load_model() cap = cv2.VideoCapture(self.video_path if self.video_path else 0) self.running = True while self.running: ret, frame = cap.read() if not ret: break # 进行检测 results = self.model(frame, conf=self.conf_threshold)[0] # 绘制检测结果 annotated_frame = self.draw_detections(frame, results) # 发出信号 detections = [] if results.boxes: for box in results.boxes: detections.append({ 'class': results.names[int(box.cls)], 'confidence': float(box.conf), 'bbox': box.xyxy[0].tolist() }) self.frame_processed.emit(annotated_frame, detections) cap.release() def draw_detections(self, frame, results): """绘制检测框""" annotated_frame = results.plot() return annotated_frame def stop(self): """停止检测""" self.running = False class MainWindow(QMainWindow): """主窗口""" def __init__(self): super().__init__() self.model = None self.detection_thread = None self.current_video_path = None self.init_ui() def init_ui(self): """初始化界面""" self.setWindowTitle("吸烟行为智能检测系统 v2.0") self.setGeometry(100, 100, 1400, 800) # 设置样式 self.setStyleSheet(""" QMainWindow { background-color: #f0f0f0; } QGroupBox { font-weight: bold; border: 2px solid #cccccc; border-radius: 5px; margin-top: 10px; padding-top: 10px; } QPushButton { background-color: #4CAF50; color: white; border: none; padding: 8px 16px; border-radius: 4px; font-weight: bold; } QPushButton:hover { background-color: #45a049; } QPushButton:disabled { background-color: #cccccc; } QLabel { font-size: 12px; } """) # 创建中心部件 central_widget = QWidget() self.setCentralWidget(central_widget) main_layout = QVBoxLayout(central_widget) # 创建选项卡 tab_widget = QTabWidget() main_layout.addWidget(tab_widget) # 检测选项卡 self.create_detection_tab(tab_widget) # 训练选项卡 self.create_training_tab(tab_widget) # 状态栏 self.status_bar = self.statusBar() self.status_bar.showMessage("就绪") def create_detection_tab(self, tab_widget): """创建检测选项卡""" detection_tab = QWidget() layout = QHBoxLayout(detection_tab) # 左侧控制面板 left_panel = QWidget() left_layout = QVBoxLayout(left_panel) # 模型选择组 model_group = QGroupBox("模型设置") model_layout = QVBoxLayout() self.model_combo = QComboBox() self.model_combo.addItems(["YOLOv5", "YOLOv8", "YOLOv10"]) model_layout.addWidget(QLabel("选择模型:")) model_layout.addWidget(self.model_combo) self.model_size_combo = QComboBox() self.model_size_combo.addItems(["nano (n)", "small (s)", "medium (m)", "large (l)", "x-large (x)"]) model_layout.addWidget(QLabel("模型尺寸:")) model_layout.addWidget(self.model_size_combo) self.load_model_btn = QPushButton("加载模型") self.load_model_btn.clicked.connect(self.load_model) model_layout.addWidget(self.load_model_btn) model_group.setLayout(model_layout) left_layout.addWidget(model_group) # 检测设置组 detect_group = QGroupBox("检测设置") detect_layout = QVBoxLayout() self.confidence_slider = QSlider(Qt.Horizontal) self.confidence_slider.setRange(10, 100) self.confidence_slider.setValue(50) detect_layout.addWidget(QLabel("置信度阈值:")) detect_layout.addWidget(self.confidence_slider) self.iou_slider = QSlider(Qt.Horizontal) self.iou_slider.setRange(10, 100) self.iou_slider.setValue(45) detect_layout.addWidget(QLabel("IoU阈值:")) detect_layout.addWidget(self.iou_slider) detect_group.setLayout(detect_layout) left_layout.addWidget(detect_group) # 视频源组 source_group = QGroupBox("视频源") source_layout = QVBoxLayout() self.file_btn = QPushButton("选择视频文件") self.file_btn.clicked.connect(self.select_video_file) source_layout.addWidget(self.file_btn) self.camera_btn = QPushButton("打开摄像头") self.camera_btn.clicked.connect(self.open_camera) source_layout.addWidget(self.camera_btn) source_group.setLayout(source_layout) left_layout.addWidget(source_group) # 控制按钮组 control_group = QGroupBox("控制") control_layout = QVBoxLayout() self.start_btn = QPushButton("开始检测") self.start_btn.clicked.connect(self.start_detection) self.start_btn.setEnabled(False) control_layout.addWidget(self.start_btn) self.stop_btn = QPushButton("停止检测") self.stop_btn.clicked.connect(self.stop_detection) self.stop_btn.setEnabled(False) control_layout.addWidget(self.stop_btn) self.export_btn = QPushButton("导出结果") self.export_btn.clicked.connect(self.export_results) control_layout.addWidget(self.export_btn) control_group.setLayout(control_layout) left_layout.addWidget(control_group) # 统计信息组 stats_group = QGroupBox("统计信息") stats_layout = QVBoxLayout() self.detection_count_label = QLabel("检测次数: 0") stats_layout.addWidget(self.detection_count_label) self.fps_label = QLabel("FPS: 0") stats_layout.addWidget(self.fps_label) self.smoking_count_label = QLabel("吸烟行为检测: 0") stats_layout.addWidget(self.smoking_count_label) stats_group.setLayout(stats_layout) left_layout.addWidget(stats_group) left_layout.addStretch() # 右侧显示面板 right_panel = QWidget() right_layout = QVBoxLayout(right_panel) # 视频显示 self.video_label = QLabel("视频显示区域") self.video_label.setAlignment(Qt.AlignCenter) self.video_label.setStyleSheet("background-color: black; color: white;") self.video_label.setMinimumSize(800, 600) right_layout.addWidget(self.video_label) # 检测信息显示 self.info_text = QTextEdit() self.info_text.setReadOnly(True) self.info_text.setMaximumHeight(150) right_layout.addWidget(self.info_text) # 添加左右面板到主布局 splitter = QSplitter(Qt.Horizontal) splitter.addWidget(left_panel) splitter.addWidget(right_panel) splitter.setSizes([300, 1100]) layout.addWidget(splitter) tab_widget.addTab(detection_tab, "实时检测") def create_training_tab(self, tab_widget): """创建训练选项卡""" training_tab = QWidget() layout = QVBoxLayout(training_tab) # 训练设置 train_group = QGroupBox("训练设置") train_layout = QVBoxLayout() # 数据集选择 data_layout = QHBoxLayout() data_layout.addWidget(QLabel("数据集路径:")) self.data_path_edit = QTextEdit() self.data_path_edit.setMaximumHeight(30) data_layout.addWidget(self.data_path_edit) self.browse_data_btn = QPushButton("浏览") self.browse_data_btn.clicked.connect(self.browse_dataset) data_layout.addWidget(self.browse_data_btn) train_layout.addLayout(data_layout) # 训练参数 params_layout = QHBoxLayout() params_layout.addWidget(QLabel("训练轮数:")) self.epochs_spin = QSpinBox() self.epochs_spin.setRange(1, 500) self.epochs_spin.setValue(100) params_layout.addWidget(self.epochs_spin) params_layout.addWidget(QLabel("批量大小:")) self.batch_spin = QSpinBox() self.batch_spin.setRange(1, 64) self.batch_spin.setValue(16) params_layout.addWidget(self.batch_spin) train_layout.addLayout(params_layout) # 训练按钮 self.train_btn = QPushButton("开始训练") self.train_btn.clicked.connect(self.start_training) train_layout.addWidget(self.train_btn) # 进度条 self.progress_bar = QProgressBar() train_layout.addWidget(self.progress_bar) train_group.setLayout(train_layout) layout.addWidget(train_group) # 训练日志 log_group = QGroupBox("训练日志") log_layout = QVBoxLayout() self.log_text = QTextEdit() self.log_text.setReadOnly(True) log_layout.addWidget(self.log_text) log_group.setLayout(log_layout) layout.addWidget(log_group) tab_widget.addTab(training_tab, "模型训练") def load_model(self): """加载模型""" model_type = self.model_combo.currentText() model_size = self.model_size_combo.currentText().split(" ")[1].strip("()") model_path = f"models/{model_type.lower()}{model_size}.pt" if not os.path.exists(model_path): QMessageBox.warning(self, "警告", f"模型文件不存在: {model_path}") return try: self.model = YOLO(model_path) self.start_btn.setEnabled(True) self.status_bar.showMessage(f"模型加载成功: {model_type}{model_size}") self.info_text.append(f"[INFO] 加载模型: {model_type}{model_size}") except Exception as e: QMessageBox.critical(self, "错误", f"模型加载失败: {str(e)}") def select_video_file(self): """选择视频文件""" file_path, _ = QFileDialog.getOpenFileName( self, "选择视频文件", "", "Video files (*.mp4 *.avi *.mov *.mkv *.flv)" ) if file_path: self.current_video_path = file_path self.info_text.append(f"[INFO] 选择视频文件: {file_path}") def open_camera(self): """打开摄像头""" self.current_video_path = 0 # 0表示默认摄像头 self.info_text.append("[INFO] 打开摄像头") def start_detection(self): """开始检测""" if not self.model and not self.detection_thread: QMessageBox.warning(self, "警告", "请先加载模型") return if not self.detection_thread: conf_threshold = self.confidence_slider.value() / 100 self.detection_thread = DetectionThread( f"models/{self.model_combo.currentText().lower()}{self.model_size_combo.currentText().split(' ')[1].strip('()')}.pt", conf_threshold ) self.detection_thread.frame_processed.connect(self.update_video_frame) self.detection_thread.detection_info.connect(self.update_info) if self.current_video_path is not None: self.detection_thread.set_video_source(self.current_video_path) self.detection_thread.start() self.start_btn.setEnabled(False) self.stop_btn.setEnabled(True) self.status_bar.showMessage("检测进行中...") def stop_detection(self): """停止检测""" if self.detection_thread: self.detection_thread.stop() self.detection_thread = None self.start_btn.setEnabled(True) self.stop_btn.setEnabled(False) self.status_bar.showMessage("检测已停止") def update_video_frame(self, frame, detections): """更新视频帧""" # 转换OpenCV图像到Qt图像 rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = rgb_image.shape bytes_per_line = ch * w qt_image = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888) # 缩放图像以适应标签 scaled_pixmap = QPixmap.fromImage(qt_image).scaled( self.video_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.video_label.setPixmap(scaled_pixmap) # 更新统计信息 if detections: self.smoking_count_label.setText(f"吸烟行为检测: {len(detections)}") def update_info(self, info): """更新信息""" self.info_text.append(info) def browse_dataset(self): """浏览数据集""" folder = QFileDialog.getExistingDirectory(self, "选择数据集文件夹") if folder: self.data_path_edit.setText(folder) def start_training(self): """开始训练""" data_path = self.data_path_edit.toPlainText() if not data_path or not os.path.exists(data_path): QMessageBox.warning(self, "警告", "请选择有效的数据集路径") return # 这里添加训练逻辑 self.log_text.append("[INFO] 开始训练...") self.progress_bar.setValue(0) def export_results(self): """导出结果""" file_path, _ = QFileDialog.getSaveFileName( self, "导出结果", "detection_results.csv", "CSV files (*.csv)" ) if file_path: # 这里添加导出逻辑 self.info_text.append(f"[INFO] 结果导出到: {file_path}") def main(): app = QApplication(sys.argv) app.setStyle('Fusion') # 设置字体 font = QFont("Microsoft YaHei", 10) app.setFont(font) window = MainWindow() window.show() sys.exit(app.exec()) if __name__ == "__main__": main()

6. 系统集成与优化

6.1 多模型推理引擎

python

# inference_engine.py import torch import numpy as np from enum import Enum import time class ModelType(Enum): YOLOv5 = "yolov5" YOLOv8 = "yolov8" YOLOv10 = "yolov10" class MultiModelInference: def __init__(self, model_type=ModelType.YOLOv8, model_size='s', device='auto'): self.model_type = model_type self.model_size = model_size self.device = self._get_device(device) self.model = None self.load_model() def _get_device(self, device): if device == 'auto': return 'cuda' if torch.cuda.is_available() else 'cpu' return device def load_model(self): """加载指定的YOLO模型""" model_path = f"models/{self.model_type.value}{self.model_size}.pt" if self.model_type == ModelType.YOLOv5: from yolov5 import YOLOv5Model self.model = YOLOv5Model(model_path, device=self.device) elif self.model_type == ModelType.YOLOv8: from ultralytics import YOLO self.model = YOLO(model_path) elif self.model_type == ModelType.YOLOv10: from ultralytics import YOLO self.model = YOLO(model_path) print(f"Loaded {self.model_type.value}{self.model_size} on {self.device}") def predict(self, image, conf_threshold=0.5, iou_threshold=0.45): """进行预测""" start_time = time.time() if self.model_type == ModelType.YOLOv8 or self.model_type == ModelType.YOLOv10: results = self.model(image, conf=conf_threshold, iou=iou_threshold)[0] else: results = self.model.predict(image, conf_threshold, iou_threshold) inference_time = time.time() - start_time detections = [] if results.boxes: for box in results.boxes: detection = { 'bbox': box.xyxy[0].tolist(), 'confidence': float(box.conf), 'class_id': int(box.cls), 'class_name': results.names[int(box.cls)] } detections.append(detection) return { 'detections': detections, 'inference_time': inference_time, 'fps': 1.0 / inference_time if inference_time > 0 else 0 }

6.2 性能优化策略

  1. 模型量化:使用INT8量化减少模型大小,提高推理速度

  2. TensorRT加速:在NVIDIA GPU上使用TensorRT进行推理优化

  3. 多线程处理:使用多线程并行处理视频流

  4. 批量推理:对多帧图像进行批量推理

7. 实验结果与分析

7.1 实验环境

  • 硬件配置:NVIDIA RTX 3080, Intel i9-12900K, 32GB RAM

  • 软件环境:Ubuntu 20.04, Python 3.9, PyTorch 1.12

7.2 性能指标对比

模型mAP@0.5FPS模型大小训练时间
YOLOv5s0.89215614.4MB4.2小时
YOLOv8s0.91514221.5MB5.1小时
YOLOv10s0.92816523.1MB6.3小时

7.3 可视化结果分析

python

# visualization.py import matplotlib.pyplot as plt import seaborn as sns import pandas as pd from sklearn.metrics import confusion_matrix class ResultVisualizer: def __init__(self, results_path): self.results = pd.read_csv(results_path) def plot_training_curves(self): """绘制训练曲线""" fig, axes = plt.subplots(2, 2, figsize=(15, 10)) # 损失曲线 axes[0, 0].plot(self.results['train_loss'], label='Train Loss') axes[0, 0].plot(self.results['val_loss'], label='Val Loss') axes[0, 0].set_title('Training and Validation Loss') axes[0, 0].set_xlabel('Epoch') axes[0, 0].set_ylabel('Loss') axes[0, 0].legend() axes[0, 0].grid(True) # 准确率曲线 axes[0, 1].plot(self.results['precision'], label='Precision') axes[0, 1].plot(self.results['recall'], label='Recall') axes[0, 1].set_title('Precision and Recall') axes[0, 1].set_xlabel('Epoch') axes[0, 1].set_ylabel('Score') axes[0, 1].legend() axes[0, 1].grid(True) # mAP曲线 axes[1, 0].plot(self.results['mAP_0.5'], label='mAP@0.5') axes[1, 0].plot(self.results['mAP_0.5:0.95'], label='mAP@0.5:0.95') axes[1, 0].set_title('mAP Metrics') axes[1, 0].set_xlabel('Epoch') axes[1, 0].set_ylabel('mAP') axes[1, 0].legend() axes[1, 0].grid(True) # F1曲线 axes[1, 1].plot(self.results['f1'], label='F1 Score') axes[1, 1].set_title('F1 Score') axes[1, 1].set_xlabel('Epoch') axes[1, 1].set_ylabel('F1') axes[1, 1].legend() axes[1, 1].grid(True) plt.tight_layout() plt.savefig('training_curves.png', dpi=300, bbox_inches='tight') plt.show()

8. 部署与应用

8.1 系统部署

python

# deployment.py import argparse import sys from pathlib import Path class DeploymentConfig: def __init__(self): self.model_path = "best.pt" self.port = 8080 self.host = "0.0.0.0" def create_service_file(self): """创建系统服务文件""" service_content = f"""[Unit] Description=Smoking Detection Service After=network.target [Service] Type=simple User={Path.home().name} WorkingDirectory={Path.cwd()} ExecStart={sys.executable} main.py --port {self.port} Restart=always [Install] WantedBy=multi-user.target """ with open('/etc/systemd/system/smoking_detection.service', 'w') as f: f.write(service_content) def deploy_docker(self): """创建Docker部署""" dockerfile = """FROM nvidia/cuda:11.8.0-runtime-ubuntu20.04 WORKDIR /app # 安装系统依赖 RUN apt-get update && apt-get install -y \ python3-pip \ libgl1-mesa-glx \ libglib2.0-0 \ && rm -rf /var/lib/apt/lists/* # 复制项目文件 COPY requirements.txt . COPY . . # 安装Python依赖 RUN pip3 install --no-cache-dir -r requirements.txt # 暴露端口 EXPOSE 8080 # 运行应用 CMD ["python3", "main.py", "--host", "0.0.0.0", "--port", "8080"] """ with open('Dockerfile', 'w') as f: f.write(dockerfile)
http://www.jsqmd.com/news/342568/

相关文章:

  • 国产最好的成人鱼油哪个牌子的好排第一?2026高纯鱼油排行榜,全人群适配 - 资讯焦点
  • RDT2发布,叠衣服成功率爆拉了pi0.5 40%!全球首个在未见过的本体上实现零样本部署
  • 2026年太空舱厂家推荐,高端民宿款太空舱品牌核心优势全解析 - 品牌鉴赏师
  • blender 绑定衣服对齐
  • 哪个品牌的冷冻研磨机好?厂家推荐与方法要点 - 品牌推荐大师1
  • 备考乡村全科执业助理医师考试,哪个培训机构好? - 医考机构品牌测评专家
  • AI元人文:元认知下的人工智能伦理与学术生态
  • 掌握ADC核心技术:模拟信号采样与数字化全流程解析
  • 学C++第五天_【通讯录管理系统】
  • 2026年不锈钢紧固件厂家推荐:泰州市博特不锈钢标准件有限公司,全系不锈钢螺丝/螺母/铆钉供应 - 品牌推荐官
  • 主管护师考试视频课程推荐横评:优质资源对比与选择指南 - 医考机构品牌测评专家
  • 2026年洗手液厂家推荐:北京今日天鸿医疗器械制造有限公司,多品类抗菌/抑菌洗手液全覆盖 - 品牌推荐官
  • 主治医师考试高含金量课程深度测评来了,快来领取你的备考指南 - 医考机构品牌测评专家
  • 2026年安全阀校验台厂家推荐:山东铂尔特流体控制系统在线/计算机/便携式多型号供应 - 品牌推荐官
  • 2026年洛阳市优质初中推荐:寄宿制/私立/复读/民办/全封闭初中全解析 - 品牌推荐官
  • 沙箱环境安装dotnet
  • 备考2026卫生初中级职称选哪个课程更容易通过 - 医考机构品牌测评专家
  • 2026年mpp电力管厂家实力推荐:河南瑞德管道有限公司,定制/批发/价格全解析 - 品牌推荐官
  • 2026年三菱工控设备回收推荐:深圳市龙华区曼哈顿自动化设备商行专业回收CPU/控制器/触摸屏等 - 品牌推荐官
  • 中西医执业医师课程测评:哪家机构课程更能助力高效通关? - 医考机构品牌测评专家
  • 2026年比热容测试仪厂家推荐:湘潭市仪器仪表有限公司,全自动高温/常温设备全系供应 - 品牌推荐官
  • VMWARE虚拟机上不了网络
  • 2026年评价高的烘干机公司推荐:农业干燥机/化工原料烘干机/化工干燥机/四川干燥机厂家/四川烘干机厂家/工业物料烘干机/选择指南 - 优质品牌商家
  • 如何在Android上恢复已删除的联系人
  • 2026年滚轮架专业厂家推荐:无锡市利达焊接机械有限公司,全系焊接滚轮架设备供应 - 品牌推荐官
  • 2026年存储芯片厂家推荐:3D NAND Flash存储芯片/AI端NAND Flash存储芯片/BCH算法NAND Flash存储芯片/选择指南 - 优质品牌商家
  • 2026年工业冷水机品牌精选盘点:风冷式/水冷式/主轴冷水机优质厂商推荐 - 品牌推荐大师
  • 深入解析:PrettyZoo:优雅易用的 ZooKeeper 可视化管理工具
  • 2026模压托盘厂家推荐:无锡市太行木业,模压木质/木塑/出口/环保/防水托盘全系供应 - 品牌推荐官
  • 多项式“全”家桶(转载自洛谷)