引入YOLOv5后Python logging日志同时输出控制台的解决问询
解决YOLOv5加载后日志同时输出到文件与控制台的问题
问题场景
使用Python标准库logging模块配置日志仅写入文件时,代码运行正常,无控制台输出:
import logging logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) file_handler = logging.FileHandler('logfile.log') file_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)-8s - %(message)s')) if logger.hasHandlers(): logger.handlers.clear() logger.addHandler(file_handler) logger.info('Processing image 1.')
但添加YOLOv5模型加载代码后,后续的日志(如logger.info('Processing image 2.'))会同时出现在文件和控制台,控制台输出示例:
In [1]: runfile('/home/aleksandar/Documents/image_processing.py', wdir='/home/aleksandar/Documents') YOLOv5 🚀 2022-5-27 Python-3.10.6 torch-1.13.0 CUDA:0 (Quadro RTX 5000, 16125MiB) Fusing layers... Model summary: 367 layers, 46151358 parameters, 0 gradients Adding AutoShape... Processing image 2.
原因分析
加载YOLOv5模型时,torch.hub.load()会触发YOLOv5内部的日志配置逻辑,给**根日志器(root logger)**添加了一个控制台处理器(StreamHandler)。而Python日志系统默认开启日志向上传播机制,自定义日志器(__name__对应的实例)会将日志消息传递给父级根日志器,最终导致日志同时通过自定义文件处理器和根日志器的控制台处理器输出。
解决方案
方法1:禁用自定义日志器的向上传播
在配置自定义日志器时,添加logger.propagate = False,阻止日志消息传递给根日志器:
import logging import torch logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) # 禁用日志向上传播 logger.propagate = False file_handler = logging.FileHandler('logfile.log') file_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)-8s - %(message)s')) if logger.hasHandlers(): logger.handlers.clear() logger.addHandler(file_handler) logger.info('Processing image 1.') MODEL_WEIGHTS = 'runs/yolov5/train/exp4/weights/best.pt' model = torch.hub.load('../YOLO/yolov5', 'custom', path=MODEL_WEIGHTS, source='local') logger.info('Processing image 2.')
方法2:移除根日志器的控制台处理器
若需要保留其他日志器的向上传播特性,可在加载YOLOv5模型后,清除根日志器中的StreamHandler:
import logging import torch logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) file_handler = logging.FileHandler('logfile.log') file_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)-8s - %(message)s')) if logger.hasHandlers(): logger.handlers.clear() logger.addHandler(file_handler) logger.info('Processing image 1.') MODEL_WEIGHTS = 'runs/yolov5/train/exp4/weights/best.pt' model = torch.hub.load('../YOLO/yolov5', 'custom', path=MODEL_WEIGHTS, source='local') # 遍历并移除根日志器的所有控制台处理器 root_logger = logging.getLogger() for handler in root_logger.handlers[:]: if isinstance(handler, logging.StreamHandler): root_logger.removeHandler(handler) logger.info('Processing image 2.')
方法3:加载YOLOv5前禁用其控制台日志
通过设置环境变量YOLOv5_VERBOSE为False,让YOLOv5初始化时不生成控制台日志输出:
import logging import torch import os # 加载模型前设置环境变量,关闭YOLOv5的控制台日志 os.environ['YOLOv5_VERBOSE'] = 'False' logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) file_handler = logging.FileHandler('logfile.log') file_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)-8s - %(message)s')) if logger.hasHandlers(): logger.handlers.clear() logger.addHandler(file_handler) logger.info('Processing image 1.') MODEL_WEIGHTS = 'runs/yolov5/train/exp4/weights/best.pt' model = torch.hub.load('../YOLO/yolov5', 'custom', path=MODEL_WEIGHTS, source='local') logger.info('Processing image 2.')
内容的提问来源于stack exchange,提问作者Aleksandar
相关产品推荐
相关产品推荐

