pytorch图像分类框架搭建——利用logging记录训练日志

关于logging模块的基本使用参考Python之日志处理(logging模块),这里主要记录使用logging时踩过的坑。

1. 使用pytorch的DDP进行多卡训练时如何保证只有主进程将信息发送到控制台和日志文件中呢?

logging.getLogger()方法有一个可选参数name,该参数表示将要返回的日志器的名称标识,如果不提供该参数,则其值为'root',得到的就是RootLogger

  • logger的名称是一个以'.'分割的层级结构,每个'.'后面的logger都是'.'前面的logger的children,例如,有一个名称为 foo 的logger,其它名称分别为 foo.bar, foo.bar.baz 和 foo.bam都是 foo 的后代。
  • logger有一个"有效等级(effective level)"的概念。如果一个logger上没有被明确设置一个level,那么该logger就是使用它parent的level;如果它的parent也没有明确设置level则继续向上查找parent的parent的有效level,依次类推,直到找到个一个明确设置了level的祖先为止。需要说明的是,root logger总是会有一个明确的level设置(默认为 WARNING)。当决定是否去处理一个已发生的事件时,logger的有效等级将会被用来决定是否将该事件传递给该logger的handlers进行处理。
  • child loggers在完成对日志消息的处理后,默认会将日志消息传递给与它们的祖先loggers相关的handlers。因此,我们不必为一个应用程序中所使用的所有loggers定义和配置handlers,只需要为一个顶层的logger配置handlers,然后按照需要创建child loggers就可足够了。我们也可以通过将一个logger的propagate属性设置为False来关闭这种传递机制。

综上,我们可以在程序开始时设定RootLogger的信息,后面的logger除了名字外,不指定任何参数就可以继承RootLogger的设置,包括level、handler、formatter等,以下是参考了maskrcnn-benckmark对logger进行设置的函数

def setup_root_logger(save_dir, distributed_rank, filename="log.txt"):
    # 只有主进程进行log输出
    if distributed_rank > 0:
        return
    root_logger = logging.getLogger()
    root_logger.setLevel(logging.DEBUG)
    ch = logging.StreamHandler(stream=sys.stdout)
    ch.setLevel(logging.DEBUG)
    formatter = logging.Formatter("%(asctime)s %(name)s %(levelname)s: %(message)s")
    ch.setFormatter(formatter)
    root_logger.addHandler(ch)
 
    if save_dir:
        save_dir = Path(save_dir) if not isinstance(save_dir, Path) else save_dir
        fh = logging.FileHandler(save_dir / filename, mode='w')
        fh.setLevel(logging.DEBUG)
        fh.setFormatter(formatter)

 2、还要注意一点,可能在其它的库程序中会直接使用函数logging.info()进行输出。logging模块级别的函数所使用的日志器是RootLogger类的实例,当我们没有提供任何配置信息的时候,这些函数都会去调用logging.basicConfig(**kwargs)方法,将RootLogger日志输出位置默认为:sys.stderr,因此即便没有为事先声明的logger指定输出流,调用logging.info()后也会让使得所有的logger将信息输出到控制台

 看一下这个demo就明白了:

import logging
>>> root_logger = logging.getLogger('')
>>> root_logger.setLevel(logging.DEBUG)
>>> a = logging.getLogger('a')
>>> root_logger.info('logger root')
并没有输出,这是由于没有指定root_logger的输出流位置
>>> a.info('logger a')
并没有输出,这是由于没有指定a的输出流位置
>>> logging.info('test')
INFO:root:test
>>> root_logger.info('root logger')
INFO:root:root logger # logging.info()将RootLogger的输出指定到了控制台
>>> a.logger('logger a')
INFO:a:logger a

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值