深度学习:yolov3的使用--建立模型

使用argparse模块来定义和解析命令行参数

创建一个ArgumentParser对象

parser = argparse.ArgumentParser()

训练的轮数,每批图像的大小,更新模型参数之前累积梯度的次数,模型定义文件的路径。

parser.add_argument("--epochs", type=int, default=100, help="number of epochs") #训练次数
    parser.add_argument("--batch_size", type=int, default=1, help="size of each image batch")   #batch的大小
    parser.add_argument("--gradient_accumulations", type=int, default=2, help="number of gradient accums before step")#在每一步(更新模型参数)之前累积梯度的次数”
    parser.add_argument("--model_def", type=str, default="config/yolov3.cfg", help="path to model definition file") #模型的配置文件
    

数据配置文件的路径,从预训练的模型权重开始训练,生成批次数据时使用的CPU线程数。

parser.add_argument("--data_config", type=str, default="config/coco.data", help="path to data config file") #数据的配置文件
    parser.add_argument("--pretrained_weights", type=str, help="if specified starts from checkpoint model") #预训练文件
    parser.add_argument("--n_cpu", type=int, default=0, help="number of cpu threads to use during batch generation")#数据加载过程中应使用的CPU线程数。
    

每张图像的尺寸,每隔多少个epoch保存一次模型权重,每隔多少个epoch在验证集上进行一次评估,每十批计算一次平均精度(mAP),是否允许多尺度训练,

parser.add_argument("--img_size", type=int, default=416, help="size of each image dimension")
    parser.add_argument("--checkpoint_interval", type=int, default=20, help="interval between saving model weights")#隔多少个epoch保存一次模型权重
    parser.add_argument("--evaluation_interval", type=int, default=20, help="interval evaluations on validation set")#多少个epoch进行一次验证集的验证
    parser.add_argument("--compute_map", default=False, help="if True computes mAP every tenth batch")#
    parser.add_argument("--multiscale_training", default=True, help="allow for multi-scale training")

使用parse_args方法解析命令行参数

opt = parser.parse_args()

使用TensorFlow 2.0以上版本中的tf.summary模块创建日志记录器(Logger)

import tensorflow as tf  # 导入TensorFlow库,并简写为tf
# 确保使用的是TensorFlow 2.0或更高版本

class Logger(object):
    def __init__(self, log_dir):
        """
        Create a summary writer logging to log_dir.
        这个类的构造函数接受一个参数log_dir,它表示日志文件将要保存的目录。
        函数的作用是创建一个日志记录器,用于记录TensorFlow的摘要信息(例如训练过程中的损失、准确率等)。
        """
        self.writer = tf.summary.create_file_writer(log_dir)  # 创建一个文件写入器,用于将摘要信息写入到指定的日志目录

调用Logger,创建目录

logger = Logger("logs")
# 创建Logger类的实例,并将日志目录设置为"logs"。这意味着所有的日志信息将被写入到当前工作目录下的"logs"文件夹中。

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 这行代码使用PyTorch的torch.device来确定运行设备。如果系统有可用的CUDA(即NVIDIA的GPU),则device将被设置为"cuda",否则将使用CPU。

os.makedirs("output", exist_ok=True)
# 使用os模块的makedirs函数创建一个名为"output"的目录。exist_ok=True参数意味着如果"output"目录已经存在,不会抛出错误。

os.makedirs("checkpoints", exist_ok=True)
# 类似地,这行代码创建一个名为"checkpoints"的目录。这个目录通常用于存储模型的检查点或保存的状态,以便后续可以恢复训练或进行模型评估。

定义 parse_data_config 的函数,它用于解析数据配置文件(文件内容分类种类,训练集路径,测试集路径,文件名称路径)

def parse_data_config(path):
    """Parses the data configuration file"""
    options = dict()
    options['gpus'] = '0,1,2,3'
    options['num_workers'] = '10'
    with open(path, 'r') as fp:
        lines = fp.readlines()
    for line in lines:
        line = line.strip()
        if line == '' or line.startswith('#'):#startswith()用于检查字符串是否以特定的子字符串开始。如果是,它将返回True,否则返回False。
            continue
        key, value = line.split('=')
        options[key.strip()] = value.strip()
    return options

调用函数

    data_config = parse_data_config(opt.data_config)
    train_path = data_config["train"]
    valid_path = data_config["valid"]

定义了一个名为 load_classes 的函数,它用于从指定路径加载类别标签

def load_classes(path):
    """
    Loads class labels at 'path'
    """
    fp = open(path, "r")
    names = fp.read().split("\n")[:-1]
    return names

调用函数

class_names = load_classes(data_config["names"])

定义了一个名为 parse_model_config 的函数,它用于解析 YOLOv3 模型的配置文件

读取文件划分如卷积、池化、上采样、路由、快捷连接和 YOLO 层

def parse_model_config(path):
    """Parses the yolo-v3 layer configuration file and returns module definitions"""
    file = open(path, 'r')
    lines = file.read().split('\n')
    lines = [x for x in lines if x and not x.startswith('#')]   #x.startswith('#')用于检查字符串变量x是否以#前缀开始。如果x以该前缀开头,该方法将返回一个布尔值,通常是True,否则返回False。
    lines = [x.rstrip().lstrip() for x in lines] # get rid of fringe whitespaces
    module_defs = []
    for line in lines:
        if line.startswith('['): # This marks the start of a new block
            module_defs.append({})
            module_defs[-1]['type'] = line[1:-1].rstrip()
            if module_defs[-1]['type'] == 'convolutional':
                module_defs[-1]['batch_normalize'] = 0
        else:
            key, value = line.split("=")
            value = value.strip()
            module_defs[-1][key.rstrip()] = value.strip()

    return module_defs

这个函数的目的是将 YOLOv3 模型配置文件中的文本描述转换成 PyTorch 可以理解的网络层模块。它首先处理超参数,然后逐个处理每个模块定义,根据模块的类型(如卷积、池化、上采样、路由、快捷连接和 YOLO 层)创建相应的 PyTorch 层,并添加到 module_list 中。

def create_modules(module_defs):
    """
    Constructs module list of layer blocks from module configuration in module_defs
    """
    # 从模块定义列表中弹出第一个元素,它包含了超参数(hyperparameters),例如输入图像的尺寸等。
    hyperparams = module_defs.pop(0)
    
    # 初始化输出过滤器列表,它将存储每一层的输出通道数(即卷积核的数量)。
    # 这里假设第一个超参数中的 'channels' 键对应的值是网络输入层的通道数。
    output_filters = [int(hyperparams["channels"])]

    # 创建一个 PyTorch 的 ModuleList 对象,用于存储网络层模块。
    module_list = nn.ModuleList()

    # 遍历模块定义列表,module_i 是索引,module_def 是当前模块的定义。
    for module_i, module_def in enumerate(module_defs):
        # 对于每个模块,创建一个 PyTorch 的 Sequential 对象,用于线性堆叠网络层。
        modules = nn.Sequential()

        # 如果模块类型是 "convolutional":
        if module_def["type"] == "convolutional":
            # 获取当前模块是否使用批归一化(batch normalization)。
            bn = int(module_def["batch_normalize"])
            # 获取卷积核的数量(即输出通道数)。
            filters = int(module_def["filters"])
            # 获取卷积核的大小。
            kernel_size = int(module_def["size"])
            # 计算填充值,以保持输出尺寸与输入尺寸相同。
            pad = (kernel_size - 1) // 2
            # 添加一个卷积层到 Sequential 对象中。
            modules.add_module(
                f"conv_{module_i}",
                nn.Conv2d(
                    in_channels=output_filters[-1],  # 输入特征图的数量。
                    out_channels=filters,  # 输出特征图的数量。
                    kernel_size=kernel_size,  # 卷积核的大小。
                    stride=int(module_def["stride"]),  # 卷积核滑动的步长。
                    padding=pad,  # 填充值。
                    bias=not bn,  # 是否添加偏置项。
                ),
            )
            # 如果使用批归一化,则添加一个批归一化层。
            if bn:
                modules.add_module(f"batch_norm_{module_i}", nn.BatchNorm2d(filters, momentum=0.9))
            # 如果激活函数是 "leaky",则添加一个 LeakyReLU 激活层。
            if module_def["activation"] == "leaky":
                modules.add_module(f"leaky_{module_i}", nn.LeakyReLU(0.1))

        # 如果模块类型是 "maxpool":
        elif module_def["type"] == "maxpool":
            # 获取池化层的大小和步长。
            kernel_size = int(module_def["size"])
            stride = int(module_def["stride"])
            # 如果池化核大小为2且步长为1,添加一个填充层以保持尺寸。
            if kernel_size == 2 and stride == 1:
                modules.add_module(f"_debug_padding_{module_i}", nn.ZeroPad2d((0, 1, 0, 1)))
            # 添加一个最大池化层。
            maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=int((kernel_size - 1) // 2))
            modules.add_module(f"maxpool_{module_i}", maxpool)

        # 如果模块类型是 "upsample":
        elif module_def["type"] == "upsample":
            # 添加一个上采样层。
            upsample = Upsample(scale_factor=int(module_def["stride"]), mode="nearest")
            modules.add_module(f"upsample_{module_i}", upsample)

        # 如果模块类型是 "route":
        elif module_def["type"] == "route":
            # 获取路由层的层索引。
            layers = [int(x) for x in module_def["layers"].split(",")]
            # 计算路由层的输出通道数。
            filters = sum([output_filters[1:][i] for i in layers])
            # 添加一个空层作为路由层。
            modules.add_module(f"route_{module_i}", EmptyLayer())

        # 如果模块类型是 "shortcut":
        elif module_def["type"] == "shortcut":
            # 获取快捷连接的输入通道数。
            filters = output_filters[1:][int(module_def["from"])]
            # 添加一个空层作为快捷连接层。
            modules.add_module(f"shortcut_{module_i}", EmptyLayer())

        # 如果模块类型是 "yolo":
        elif module_def["type"] == "yolo":
            # 获取 YOLO 层的锚点索引和锚点值。
            anchor_idxs = [int(x) for x in module_def["mask"].split(",")]
            anchors = [int(x) for x in module_def["anchors"].split(",")]
            anchors = [(anchors[i], anchors[i + 1]) for i in range(0, len(anchors), 2)]
            anchors = [anchors[i] for i in anchor_idxs]
            # 获取 YOLO 层的类别数和图像尺寸。
            num_classes = int(module_def["classes"])
            img_size = int(hyperparams["height"])
            # 创建一个 YOLO 层并添加到模块中。
            yolo_layer = YOLOLayer(anchors, num_classes, img_size)
            modules.add_module(f"yolo_{module_i}", yolo_layer)

        # 将构建好的模块添加到模块列表中。
        module_list.append(modules)
        # 更新输出过滤器列表,添加当前模块的输出通道数。
        output_filters.append(filters)

    # 返回超参数和构建好的模块列表。
    return hyperparams, module_list

定义了一个名为 Darknet 的类,它是用于构建 YOLOv3 目标检测模型的 PyTorch 神经网络类。

class Darknet(nn.Module):
    """YOLOv3 object detection model"""
    # 这个类继承自 PyTorch 的 nn.Module 类,表示它是一个神经网络模型。
    # YOLOv3 是一个流行的目标检测算法,这个类实现了 YOLOv3 的网络结构。

    def __init__(self, config_path, img_size=416):
        super(Darknet, self).__init__()
        # 类的构造函数接受两个参数:config_path(模型配置文件的路径)和 img_size(输入图像的尺寸,默认为416)。
        # super() 函数用于调用父类的构造函数,即初始化 PyTorch 的 nn.Module。

        self.module_defs = parse_model_config(config_path)
        # 调用 parse_model_config 函数解析配置文件,并存储解析后的模块定义。

        self.hyperparams, self.module_list = create_modules(self.module_defs)
        # 调用 create_modules 函数根据模块定义创建网络层,并存储超参数和模块列表。

        self.yolo_layers = [layer[0] for layer in self.module_list if hasattr(layer[0], "metrics")]
        # 从模块列表中提取出包含 'metrics' 属性的层,这些层通常是 YOLO 层,用于目标检测。
        # hasattr() 函数检查对象是否具有给定的属性。

        self.img_size = img_size
        # 存储输入图像的尺寸。

        self.seen = 0
        # 用于跟踪训练过程中看到的数据量(例如,图像数量)。

        self.header_info = np.array([0, 0, 0, self.seen, 0], dtype=np.int32)
        # 创建一个 NumPy 数组,用于存储与模型相关的头部信息,如版本、修订号、seen、未知字段和 epoch 数。

调用函数

    model = Darknet(opt.model_def).to(device)
    model.apply(weights_init_normal)#model.apply(fn)表示将fn函数应用到神经网络的各个模块上,包括该神经网络本身。这通常在初始化神经网络的参数时使用,本处用于初始化神经网络的权值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/905860.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

38.第二阶段x86游戏实战2-HOOK窗口消息机制(解决多开窗口句柄问题)

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 本人写的内容纯属胡编乱造,全都是合成造假,仅仅只是为了娱乐,请不要…

详解汉明纠错码原理以及FPGA实现

文章目录 一、汉明纠错码简介二、汉明码编码原理以及步骤三、汉明码纠错原理以及步骤四、FPGA实现74汉明编码器五、FPGA实现74汉明解码器 一、汉明纠错码简介 汉明纠错码(Hamming Code)是一种用于检测和纠正数据传输中错误的编码方法。它由理查德汉明&am…

无人机光电识别跟踪算法!

一、算法概述 无人机光电识别跟踪算法结合了可见光和红外成像技术,通过光学系统收集目标的光学信息,并将其转换为电信号进行处理和分析。该算法能够实现对目标的快速、准确识别与追踪,极大提升了无人机在复杂环境下的作业能力和效率。 二、…

Ethernet 系列(6)-- 基础学习::OSI Model

(写在前面:最近在学习车载以太网的知识,顺便记录一下知识点。) OSI(Open System Interconnect )模型是一种网络通信框架,由国际标准化组织(‌ISO)在1985年提出&#xff0…

day15:shell基础

一,编程语法分类(了解) 编程范式: 面向过程:程序通过按步骤执行函数或过程完成任务,强调流程控制和函数调用,适合流程明确的任务,如 C。面向对象:通过“类”和“对象”封…

无人机测绘遥感技术算法概述!

一、数据采集算法 航线规划算法 根据测绘任务需求,利用地理信息系统(GIS)和遥感技术,对无人机进行航线规划。 考虑地形、气候、障碍物等因素,优化飞行路径,确保数据采集的完整性和准确性。 传感器控制算…

Pytest-Bdd-Playwright 系列教程(6):在测试步骤函数中设置别名数据共享

Pytest-Bdd-Playwright 系列教程(6):在测试步骤函数中设置别名&数据共享 前言一、步骤别名二、特性文件三、测试脚本四、运行测试五、小测验总结 前言 有的时候,为了提高可读性,我们需要使用不同的名称来声明相同的…

HTML 分组标签与语义化应用:合理使用 <div>、<span> 和基础语义容器

文章目录 1. `<div>` 标签特点用途示例2. `<span>` 标签特点用途示例3. `<fieldset>` 标签特点用途示例4. `<section>` 标签特点用途示例5. `<article>` 标签特点用途示例总结HTML中的分组(容器)标签用于结构化内容,将页面元素组织成逻辑区域…

关于武汉芯景科技有限公司的马达驱动芯片AT6237开发指南(兼容DRV8837)

一、芯片引脚介绍 1.芯片引脚 二、系统结构图 三、功能描述 逻辑功能

Android View

前面我们了解了Android四大组件的工作流程&#xff0c;Android中还存在一个和四大组件地位相同的概念&#xff1a;View&#xff0c;用于向用户页面展示内容。我们经常使用的TextView、Button、ImageView控件等都继承于它&#xff0c;也会自定义View实现自定义效果。View类源码内…

谷歌插件开发学习指南

什么是谷歌插件 谷歌插件&#xff08;Chrome Extension&#xff09;是为谷歌浏览器&#xff08;Chrome&#xff09;开发的小程序&#xff0c;旨在增强浏览器的功能或用户体验。它们可以通过添加工具栏按钮、修改网页内容、集成其他服务等方式&#xff0c;实现各种功能&#xf…

linux命令行的艺术

文章目录 前言基础日常使用文件及数据处理系统调试单行脚本冷门但有用仅限 OS X 系统仅限 Windows 系统在 Windows 下获取 Unix 工具实用 Windows 命令行工具Cygwin 技巧 更多资源免责声明 熟练使用命令行是一种常常被忽视&#xff0c;或被认为难以掌握的技能&#xff0c;但实际…

Puppeteer 与浏览器版本兼容性:自动化测试的最佳实践

Puppeteer 支持的浏览器版本映射&#xff1a;从 v20.0.0 到 v23.6.0 自 Puppeteer v20.0.0 起&#xff0c;这个强大的自动化库开始支持与 Chrome 浏览器的无头模式和有头模式共享相同代码路径&#xff0c;为自动化测试带来了更多便利。从 v23.0.0 开始&#xff0c;Puppeteer 进…

知识管理新选择!本地大模型助手“知我AI”全功能解析

抖知书老师推荐&#xff1a; 随着人工智能技术的飞速发展&#xff0c;本地大模型知识管理工具逐渐成为提高工作效率的利器。今天&#xff0c;我要向大家介绍一款名为**“知我AI”**的本地知识管理助手&#xff0c;它以其独特的功能和优势&#xff0c;正在成为众多专业人士的新…

Banana Pi BPI-R3路由器开发板运行 OrayOS物联网系统

近日&#xff0c;Banana PI开发板宣布与贝锐达成战略合作&#xff0c;贝锐OrayOS现已成功适配Banana PI的BPI-R3型号&#xff0c;并计划进一步扩展硬件支持&#xff0c;包括目前Banana PI热销的BPI-R4、BPI-R3 Mini等更多型号。这一合作为用户提供了更广泛的开发板选择&#xf…

No.24 笔记 | WEB安全 - 任意文件包含漏洞 part 6

在 Web 安全领域中&#xff0c;任意文件包含漏洞是一种较为常见且具有潜在危险性的漏洞类型。本文将详细介绍任意文件包含漏洞的概念、原理、分类、利用方法以及防护措施&#xff0c;帮助新手小白更好地理解和防范这一漏洞。&#x1f603; 一、概念 包含的定义 开发人员为了提…

森利威尔SL2516D 耐压60V内置5V功率MOS 支持PWM LED恒流驱动器芯片

一、基本特性 型号&#xff1a;SL2516D封装&#xff1a;ESOP8工作频率&#xff1a;140kHz驱动MOS管&#xff1a;内置 二、电气特性 输入电压范围&#xff1a;8V~100V&#xff08;注意&#xff0c;虽然问题中提到耐压60V&#xff0c;但根据官方信息&#xff0c;其实际耐压范围…

Vscode配置CC++编程环境的使用体验优化和补充说明

文章目录 快速编译运行&#x1f47a;code runner插件方案Code Runner Configuration 直接配置 相关指令和快捷键默认task配置和取消默认 配置文件补充介绍(可选 推荐阅读)&#x1f60a;使用vscode预置变量和环境变量环境变量的使用使用环境变量的好处环境变量可能引起的问题 检…

Linux中rpm包和yum仓库介绍及入门配置

rpm包概述 RPM Package Manager,RPM包管理器 由红帽公司提出&#xff0c;适用于Rocky Linux、Redhat、SUSE等系列操作系统 建立集中数据库&#xff0c;记录软件包安装/卸载等变化信息&#xff0c;分析软件包依赖关系 RPM包 文件名特征 软件名-版本信息.操作系统.硬件架/构.r…

L 波段射频信号采集回放系统

L 波段采集回放系统是一套便携式模拟数字采集系统&#xff0c;该系统主要由射频输入模块、中频接收回放模块、FPGA 信号处理单元、服务器系统和存储单元等组成。 L 波段采集回放系统的功能主要用于对 950MHz〜2150MHz 模拟量射频信号的采集、存储记录与回放&#xff1b;采集与…