Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 3.x Pytork:为什么DDP中的日志记录失败?_Python 3.x_Pytorch_Python Multiprocessing_Python Logging - Fatal编程技术网

Python 3.x Pytork:为什么DDP中的日志记录失败?

Python 3.x Pytork:为什么DDP中的日志记录失败?,python-3.x,pytorch,python-multiprocessing,python-logging,Python 3.x,Pytorch,Python Multiprocessing,Python Logging,我想在分布式数据并行管理的一个进程中使用日志记录。但是,日志记录不会在以下代码中打印任何内容(这些代码源自): 但是,当我取消注释第4行时,日志记录工作正常。我可以知道原因和如何修复错误吗?更新 让我们简要回顾一下logging模块中的记录器是如何工作的 记录器以树形结构组织,即每个记录器都有一个唯一的父记录器。默认情况下,它将是root记录器,而root记录器没有父记录器 在记录器上调用Logger.info方法(为简单起见,此处忽略级别检查)时,记录器迭代其所有处理程序,并让它们处理当前记录

我想在分布式数据并行管理的一个进程中使用日志记录。但是,日志记录不会在以下代码中打印任何内容(这些代码源自):

但是,当我取消注释第4行时,日志记录工作正常。我可以知道原因和如何修复错误吗?

更新

让我们简要回顾一下
logging
模块中的记录器是如何工作的

记录器以树形结构组织,即每个记录器都有一个唯一的
父记录器。默认情况下,它将是
root
记录器,而
root
记录器没有父记录器

在记录器上调用
Logger.info
方法(为简单起见,此处忽略级别检查)时,记录器迭代其所有
处理程序
,并让它们处理当前记录,例如,处理程序可以是可打印到标准输出的StreamHandler,或可打印到某个文件的FileHandler)。当前记录器的所有处理程序完成其作业后,记录将被提供给其父记录器,父记录器以相同的方式处理记录,即迭代父记录器的所有处理程序并让它们处理记录,最后将记录传递给“祖父母”。此过程将继续,直到到达当前记录器树的根,该树没有父级

检查以下实现或:

def调用处理程序(self,record):
c=自我
找到=0
而c:
对于c.Handler中的hdlr:
找到=找到+1
如果record.levelno>=hdlr.level:
hdlr.句柄(记录)
如果不是c,则传播:
c=无#中断
其他:
c=c父项
因此,在您的例子中,您没有为
train
记录器指定任何处理程序。当您取消注释第6行时,即通过调用
logging.basicConfig(level=logging.DEBUG)
,将为
root
记录器创建一个
StreamHandler
。虽然
train
记录器没有任何处理程序,但它的父级(即
root
记录器)有一个
StreamHandler
,它打印您实际看到的任何内容,而
train
记录器在这种情况下不打印任何内容。当注释中的第6行时,即使是一个
StreamHandler
也不会为
根处理程序创建,因此在这种情况下不会打印任何内容。因此,事实上,这个问题与DDP无关

顺便说一句,我不能首先重现您的问题的原因是因为我使用PyTorch 1.8,其中
logging.info
将在执行
dist.init\u process\u group
期间被调用,用于MPI以外的后端,后者隐式调用
basicConfig
,为根记录器创建一个
StreamHandler
,并按预期打印消息

======================================================================

一个可能的原因是:因为在执行
dist.init\u process\u group
期间,它将调用
\u store\u based\u barrier
,最终将调用
logging.info
(请参阅源代码)。因此,如果在调用
dist.init\u process\u group
之前调用
logging.basicConfig
,它将提前初始化,这将使根日志记录器忽略所有级别的日志


代码中不是这种情况,因为
logging.basicConfig
位于文件的顶部,将在
dist.init\u process\u组之前的第一次执行。实际上,我能够运行您提供的代码,在填充缺少的导入(例如
nn
dist
)之后,日志正常工作。也许您试图减少代码以重现问题,但却在不知不觉中规避了真正的问题?你能再检查一下这是否解决了你的问题吗?

除非我算错了,否则第六行是空的——我想你是指第四行?@Xtrem532谢谢你指出。现在更正。您好,由于stackoverflow的限制,其余导入语句已从第6行中删除。除了这些,其他什么都不缺。我在torch 1.7上尝试了上面的代码,但是
日志记录不起作用。顺便说一句,我留下了一个类似的问题。我不熟悉日志记录和多进程。如果你能弄明白,我将不胜感激D@Tengerye查看我的更新,我想它现在也可以回答你的另一个问题。我可以从你的回答中理解第一个问题。但是,为什么在单个进程中创建或在单个进程外创建记录器时输出不同?(提供了示例)
#!/usr/bin/python

import os, logging
# logging.basicConfig(level=logging.DEBUG)


def setup(rank, world_size):
    os.environ['MASTER_ADDR'] = 'localhost'
    os.environ['MASTER_PORT'] = '12355'

    # Initialize the process group.
    dist.init_process_group('NCCL', rank=rank, world_size=world_size)


def cleanup():
    dist.destroy_process_group()


class ToyModel(nn.Module):
    def __init__(self):
        super(ToyModel, self).__init__()
        self.net1 = nn.Linear(10, 10)
        self.relu = nn.ReLU()
        self.net2 = nn.Linear(10, 5)

    def forward(self, x):
        return self.net2(self.relu(self.net1(x)))


def demo_basic(rank, world_size):
    setup(rank, world_size)

    if rank == 0:
        logger = logging.getLogger('train')
        logger.setLevel(logging.DEBUG)
        logger.info(f'Running DPP on rank={rank}.')

    # Create model and move it to GPU.
    model = ToyModel().to(rank)
    ddp_model = DDP(model, device_ids=[rank])

    loss_fn = nn.MSELoss()
    optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)  # optimizer takes DDP model.

    optimizer.zero_grad()
    inputs = torch.randn(20, 10)  # .to(rank)

    outputs = ddp_model(inputs)

    labels = torch.randn(20, 5).to(rank)
    loss_fn(outputs, labels).backward()

    optimizer.step()

    cleanup()


def run_demo(demo_func, world_size):
    mp.spawn(
        demo_func,
        args=(world_size,),
        nprocs=world_size,
        join=True
    )


def main():
    run_demo(demo_basic, 4)


if __name__ == "__main__":
    main()