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

YOLOv10-1.1部分代码阅读笔记-dist.py

dist.py

ultralytics\utils\dist.py

目录

dist.py

1.所需的库和模块

2.def find_free_network_port() -> int: 

3.def generate_ddp_file(trainer): 

4.def generate_ddp_command(world_size, trainer): 

5.def ddp_cleanup(trainer, file): 


1.所需的库和模块

# Ultralytics YOLO 🚀, AGPL-3.0 license

import os
import shutil
import socket
import sys
import tempfile

from . import USER_CONFIG_DIR
from .torch_utils import TORCH_1_9

2.def find_free_network_port() -> int: 

# 这段代码定义了一个名为 find_free_network_port 的函数,用于查找一个可用的网络端口。它通过绑定一个临时的 TCP 套接字来实现这一功能。
# 定义了一个函数 find_free_network_port ,返回值为一个整数(表示可用的端口号)。
def find_free_network_port() -> int:
    # 在本地主机上查找一个空闲端口。
    # 当我们不想连接到真正的主节点但必须设置 `MASTER_PORT` 环境变量时,它在单节点训练中很有用。
    """
    Finds a free port on localhost.

    It is useful in single-node training when we don't want to connect to a real main node but have to set the
    `MASTER_PORT` environment variable.
    """
    # 使用 socket.socket 创建一个 TCP 套接字( AF_INET 表示 IPv4 地址族, SOCK_STREAM 表示 TCP 协议)。 with 语句确保套接字在使用后自动关闭。
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        # 将套接字绑定到本地地址 127.0.0.1 (即本地回环地址)和端口号 0 。 端口号 0 是一个特殊值,表示让操作系统自动分配一个可用的端口。
        s.bind(("127.0.0.1", 0))
        # 调用 getsockname() 方法获取套接字的地址信息,返回一个元组 (host, port) 。 [1] 表示提取元组中的第二个元素,即端口号。 返回的端口号是一个整数,表示一个可用的端口。
        return s.getsockname()[1]  # port
# find_free_network_port 函数的作用是。动态分配端口:通过绑定一个临时套接字,让操作系统分配一个可用的端口。返回端口号:返回分配的端口号,供后续使用。这种方法简单高效,适用于需要动态分配端口的场景。

3.def generate_ddp_file(trainer): 

# 这段代码定义了一个名为 generate_ddp_file 的函数,用于生成一个临时 Python 脚本文件,该文件用于启动分布式数据并行(DDP)训练。这个脚本文件包含了训练器的配置和训练逻辑,并且会在训练结束后被删除。
# 定义了 generate_ddp_file 函数,接受一个参数。
# 1.trainer :这是一个训练器对象,包含训练相关的配置和逻辑。
def generate_ddp_file(trainer):
    # 生成 DDP 文件并返回其文件名。
    """Generates a DDP file and returns its file name."""
    # 提取 trainer 类的 模块路径 和 类名 。
    # trainer.__class__.__module__ :获取 trainer 类的模块路径(如 ultralytics.trainers.yolov8 )。
    # trainer.__class__.__name__ :获取 trainer 类的名称(如 YOLOv8Trainer )。
    # 使用 rsplit(".", 1) 将模块路径和类名分开,分别存储到 module 和 name 中。
    module, name = f"{trainer.__class__.__module__}.{trainer.__class__.__name__}".rsplit(".", 1)

    # 定义了临时脚本文件的内容。
    content = f"""
# Ultralytics Multi-GPU training temp file (should be automatically deleted after use)
overrides = {vars(trainer.args)}

if __name__ == "__main__":
    from {module} import {name}
    from ultralytics.utils import DEFAULT_CFG_DICT

    cfg = DEFAULT_CFG_DICT.copy()
    cfg.update(save_dir='')   # handle the extra key 'save_dir'
    trainer = {name}(cfg=cfg, overrides=overrides)
    results = trainer.train()
"""
    # vars(trainer.args) 将 trainer.args 的属性转换为字典,并嵌入到脚本中,用于覆盖默认配置。
    # overrides = {vars(trainer.args)}
    # 脚本中的主逻辑入口,确保脚本被直接运行时执行以下代码。
    # if __name__ == "__main__":
    # 动态导入 trainer 类所在的模块和类。
    #     from {module} import {name}
    # 导入默认配置字典 DEFAULT_CFG_DICT ,用于初始化训练器。
    #     from ultralytics.utils import DEFAULT_CFG_DICT
    # 复制默认配置字典,并更新 save_dir 为一个空字符串,以避免保存目录冲突。
    #     cfg = DEFAULT_CFG_DICT.copy()
    #     cfg.update(save_dir='')   # handle the extra key 'save_dir'
    # 使用动态导入的类和配置创建训练器实例。
    #     trainer = {name}(cfg=cfg, overrides=overrides)
    # 调用训练器的 train 方法,开始训练过程。
    #     results = trainer.train()

    # 创建一个目录用于存放临时脚本文件。 USER_CONFIG_DIR 是一个全局变量,表示用户的配置目录。
    (USER_CONFIG_DIR / "DDP").mkdir(exist_ok=True)

    # tempfile.NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, delete=True)
    # tempfile.NamedTemporaryFile 是 Python 标准库 tempfile 模块中的一个类,用于创建一个临时文件,并返回一个文件对象。这个文件在关闭时可以自动删除,也可以保留下来供其他程序使用。
    # 参数 :
    # mode :文件模式,默认为 'w+b' (二进制读写模式)。也可以是 'w' (文本写模式)、 'r+' (读写模式)等。
    # buffering :缓冲区大小。默认为 -1 ,表示使用系统默认缓冲区大小。
    # encoding :文件编码,仅在文本模式下有效。
    # newline :换行符处理,仅在文本模式下有效。
    # suffix :临时文件的后缀名(不包括点)。例如, suffix='.txt' 。
    # prefix :临时文件的前缀名。默认为系统生成的随机前缀。
    # dir :临时文件的存储目录。默认为系统默认的临时目录(如 /tmp )。
    # delete :文件关闭时是否自动删除。默认为 True ,表示文件在关闭后自动删除。
    # 返回值 :
    # 返回一个文件对象,支持文件操作(如读写)。文件路径可以通过文件对象的 .name 属性访问。
    # 主要用途 :
    # 创建临时文件 :用于存储临时数据,文件在关闭时可以自动删除。
    # 跨进程共享 :临时文件路径可以通过 .name 属性获取,供其他进程或程序访问。
    # 灵活的文件操作 :支持多种文件模式(如文本模式、二进制模式)。
    # 注意事项 :
    # 文件路径 :文件路径可以通过 .name 属性访问。 文件路径是临时的,通常存储在系统的临时目录中(如 /tmp )。
    # 文件删除 :如果 delete=True ,文件在关闭后自动删除。 如果 delete=False ,文件在关闭后不会自动删除,需要手动删除。
    # 跨平台兼容性 : tempfile.NamedTemporaryFile 在 Windows 和 Unix 系统上都能正常工作。文件路径可能因操作系统而异。
    # 安全性 :临时文件路径是随机生成的,避免了文件名冲突。 如果需要更高的安全性,可以使用 tempfile.mkstemp 或 tempfile.TemporaryDirectory 。
    # tempfile.NamedTemporaryFile 是一个非常实用的工具,用于创建临时文件。它支持多种文件模式和灵活的配置选项,可以用于存储临时数据或跨进程共享文件。通过 delete 参数,可以控制文件是否在关闭后自动删除。

    # 使用 tempfile.NamedTemporaryFile 创建一个临时文件。
    with tempfile.NamedTemporaryFile(
        # 文件名前缀。
        prefix="_temp_",
        # 文件名后缀,包含 trainer 的唯一标识符。
        suffix=f"{id(trainer)}.py",
        # 以读写模式打开文件。
        mode="w+",
        # 文件编码。
        encoding="utf-8",
        # 文件存储目录。
        dir=USER_CONFIG_DIR / "DDP",
        # 文件在关闭时不自动删除。
        delete=False,
    ) as file:
        # 将脚本内容写入临时文件。
        file.write(content)
    # 返回临时文件的路径。
    return file.name
# generate_ddp_file 函数的作用是。动态生成脚本:根据 trainer 的配置和类信息,生成一个临时 Python 脚本文件。包含训练逻辑:脚本中包含了训练器的初始化和训练逻辑。支持分布式训练:生成的脚本可以被 PyTorch 分布式训练工具(如 torch.distributed.run )直接调用。返回文件路径:返回生成的临时文件路径,用于后续启动分布式训练。这种设计使得函数能够灵活地支持多 GPU 分布式训练,同时避免了硬编码脚本内容。

4.def generate_ddp_command(world_size, trainer): 

# 这段代码定义了一个名为 generate_ddp_command 的函数,用于生成分布式数据并行(DDP)训练所需的命令。它主要用于设置 PyTorch 的分布式训练环境,并生成相应的启动命令。
# 定义了 generate_ddp_command 函数,接受两个参数。
# 1.world_size :表示每个节点上的进程数(通常等于 GPU 数量)。
# 2.trainer :一个训练器对象,包含与训练相关的配置和状态。
def generate_ddp_command(world_size, trainer):
    # 生成并返回分布式训练的命令。
    """Generates and returns command for distributed training."""
    # 导入 Python 的 __main__ 模块。这里提到的 URL 是一个已知的 PyTorch Lightning 问题的链接,可能与分布式训练相关。 # noqa 是一个注释,用于避免代码格式化工具的警告。
    import __main__  # noqa local import to avoid https://github.com/Lightning-AI/lightning/issues/15218

    # 检查 trainer 是否处于恢复训练模式( resume )。如果不是,则执行以下操作。
    if not trainer.resume:
        # 删除 trainer.save_dir 目录。这通常是为了清理之前的训练保存目录,避免冲突。
        shutil.rmtree(trainer.save_dir)  # remove the save_dir
    # 调用 generate_ddp_file 函数,生成一个与分布式训练相关的临时文件(可能是 Python 脚本或配置文件)。 generate_ddp_file 的作用是为 DDP 训练生成必要的文件。
    file = generate_ddp_file(trainer)
    # 根据 PyTorch 的版本选择分布式训练的启动命令。如果 PyTorch 版本 >= 1.9,使用 torch.distributed.run 。 否则,使用 torch.distributed.launch 。 TORCH_1_9 是一个未在代码中定义的变量,用来检查 PyTorch 版本是否大于或等于 1.9。
    dist_cmd = "torch.distributed.run" if TORCH_1_9 else "torch.distributed.launch"
    # 调用 find_free_network_port 函数,查找一个可用的网络端口。这个端口将用于分布式训练中的通信。
    port = find_free_network_port()
    # 构造分布式训练的启动命令。
    # sys.executable :Python 解释器的路径。
    # -m :表示运行一个模块。
    # dist_cmd :分布式训练的启动命令( torch.distributed.run 或 torch.distributed.launch )。
    # --nproc_per_node :每个节点上的进程数( world_size )。
    # --master_port :主节点的通信端口( port )。
    # file :生成的临时文件路径。
    cmd = [sys.executable, "-m", dist_cmd, "--nproc_per_node", f"{world_size}", "--master_port", f"{port}", file]
    # 返回 构造的命令列表 cmd 和 生成的文件路径 file 。
    return cmd, file
# generate_ddp_command 函数的作用是。清理保存目录:如果训练器不是恢复模式,删除之前的保存目录。生成临时文件:调用 generate_ddp_file 生成分布式训练所需的文件。构造启动命令:根据 PyTorch 版本和参数构造分布式训练的启动命令。返回命令和文件路径:返回构造的命令列表和生成的文件路径。这种设计使得函数能够灵活地启动分布式训练,同时支持不同版本的 PyTorch。

5.def ddp_cleanup(trainer, file): 

# 这段代码定义了一个名为 ddp_cleanup 的函数,用于清理与分布式数据并行(DDP)训练相关的临时文件。
# 定义了一个函数 ddp_cleanup ,接受两个参数。
# 1.trainer :通常是训练器对象,可能包含与分布式训练相关的上下文信息。
# 2.file :一个字符串,表示文件路径。
def ddp_cleanup(trainer, file):
    # 如果创建了临时文件则删除。
    """Delete temp file if created."""

    # id(object)
    # id() 是 Python 的内置函数,用于获取一个对象的唯一标识符(内存地址)。
    # 参数 :
    # object :任何 Python 对象,包括变量、列表、字典、类实例等。
    # 返回值 :
    # 返回一个整数,表示对象的唯一标识符(通常是对象在内存中的地址)。
    # 作用 :
    # id() 函数的主要作用是获取一个对象的唯一标识符。在 CPython 实现中,这个标识符通常是对象在内存中的地址。由于每个对象在内存中都有唯一的地址, id() 可以用来判断两个变量是否指向同一个对象。
    # 注意事项 :
    # 唯一性 :在程序运行期间, id() 返回的值是唯一的。但程序结束后,该内存地址可能会被释放并重新分配给其他对象。
    # 不可变性 :对象的 id 在其生命周期内不会改变。即使对象的内容发生变化(如列表或字典的内容), id 仍然保持不变。
    # 用途 :
    # id() 通常用于调试,帮助开发者理解变量的引用关系。
    # 它也可以用于判断两个变量是否指向同一个对象,但通常更推荐使用 is 关键字 : print(x is y)  # 等价于 id(x) == id(y) 。
    # id() 函数是一个非常实用的内置函数,用于获取对象的唯一标识符(内存地址)。它在调试和理解变量引用关系时非常有用,但通常不建议在生产代码中直接使用 id() 来比较对象,而是使用 is 关键字。

    # 检查文件名是否包含特定的后缀,这个后缀是通过 id(trainer) 生成的唯一标识符,并附加 .py 扩展名。
    # id(trainer) :获取 trainer 对象的内存地址(唯一标识符)。
    # f"{id(trainer)}.py" :将标识符转换为字符串,并附加 .py 后缀。
    # if ... in file :检查生成的后缀是否包含在文件名中。
    if f"{id(trainer)}.py" in file:  # if temp_file suffix in file
        # 如果文件名包含指定的后缀,则调用 os.remove(file) 删除该文件。 os.remove 是 Python 标准库中的函数,用于删除指定路径的文件。
        os.remove(file)
# dp_cleanup 函数的作用是。检查文件名是否包含与 trainer 对象相关的唯一标识符后缀。如果匹配,则删除该文件。这种设计通常用于清理分布式训练过程中生成的临时文件,例如在 DDP(Distributed Data Parallel)训练中,每个进程可能生成临时文件,这些文件在训练完成后需要被清理。


http://www.kler.cn/a/513398.html

相关文章:

  • 我的创作纪念日,纪念我的第512天
  • js截取video视频某一帧为图片
  • Hnu电子电路实验2
  • JavaScript语言的多线程编程
  • 《目标检测数据集下载地址》
  • 7. 计算机视觉
  • 61,【1】BUUCTF WEB BUU XSS COURSE 11
  • 大牙的2024年创作总结
  • 求解ssp 问题建模
  • 个人职业发展与AI赋能的前端开发
  • 交换机Console密码忘记无法登录设备怎么办?
  • ubuntu16.04 VSCode下cmake+clang+lldb调试c++
  • 线程池实现
  • 36. K11364 剑法
  • Erlang语言的面向对象编程
  • 以 RFID 为钥,开启民兵装备管理的科技之门
  • linux 下tensorrt的yolov8的前向推理(python 版本)的实现
  • 【Linux】多线程(一)
  • JavaScript笔记进阶篇01——作用域、箭头函数、解构赋值
  • Java 中的同步与并发工具类
  • JAVA-Exploit编写(8-10)--http-request库编写exp批量利用
  • 后端:MyBatis
  • Hive: Hive的优缺点,使用方式,判断Hive是否启动(jps),元数据的存储,Hive和Hadoop的关系
  • Elasticsearch 中,分片(Shards)数量上限?副本的数量?
  • PPT大纲:如何用python实现gitlab和jira的集成
  • 芝士AI(paperzz):最新AI论文、AI降重、AI降重工具,解决论文写作低效和AI率