YOLO系列解读DAY1—YOLOV1预训练模型

news2024/11/17 11:27:57

一、说在前面

小伙伴们好,博主很久没有写博客了,略感生疏,不到之处敬请谅解,欢迎指出文中错误,大家一起探讨。欲看视频讲解,可转至博主DouYin、B站,欢迎关注,链接如下:

Github: samylee (samylee) · GitHub

DY: samylee_csdn

B站:samylee

二、写作初衷

YOLO系列详解博客网上很多且质量很高,但大多数都是已文字和图像的形式呈现,未能结合代码做进一步阐述。且yolov1/v2是纯c代码,调试困难,无法直观反映训练和测试过程。所以博主将该代码转到PyTorch下,可一目了然理清Darknet作者的算法思路。话不多说,下面开始!

三、YOLOV1预训练模型

众所周知,在当时预训练模型的性能会直接影响整个检测网络的效果,所以设计出一款好的分类模型是做检测任务的必经之路。分类网络原理部分这里不做进一步阐述了,博主会开设另外系列博客讲解分类网络,敬请期待。

Darknet作者采用自研的extraction网络,在当时已经达到SOTA水平,且速度明显优于同时期SOTA模型,性能如下图所示。

网络设计方面作者采用直到型架构,因当时何恺明等大神尚未提出残差网络,所以直到型还是主流网络架构,如下图所示,其中'M'表示最大池化层,'A'表示平均池化层。

 四、Extraction网络转PyTorch

网络转换需要注意三个地方:

1、要求将Extraction网络按照其特定的网络序列复写出PyTorch的网络架构,切不可心浮气躁;

2、Darknet存储参数的序列和PyTorch稍有不同,若遇到BatchNorm架构的卷积层,Darknet会先存储BatchNorm层的参数,进而存储卷积层的参数;

3、图像数据预处理部分,Darknet分类网络的顺序是:BGR2RGB->Norm(1/255)->Resize->Crop,所以我们在复现的时候一定要按照该顺序进行数据预处理操作。

网络复现如下,版本PyTorch1.4,Python3.6,博主暂未加PyTorch的训练代码,因ImageNet训练时间较长,所以直接使用了Extraction的网络模型,若有需要的小伙伴可以评论或私信给博主,博主可添加Extraction分类网络的PyTorch的训练方法。

import torch
import torch.nn as nn
import torch.nn.functional as F
import cv2
import numpy as np


class ExtractionNet(nn.Module):
    def __init__(self, in_channels=3, num_classes=1000, init_weights=True, phase='train'):
        super(ExtractionNet, self).__init__()
        self._phase = phase
        self.features = self.make_layers(in_channels=in_channels, out_channels=num_classes)
        if init_weights:
            self._initialize_weights()

    def forward(self, x):
        for feature in self.features:
            x = feature(x)

        if self._phase == 'test':
            x = torch.flatten(x, 1)
            x = F.softmax(x, dim=-1)
        return x

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_in', nonlinearity='leaky_relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)

    def make_layers(self, in_channels=3, out_channels=1000):
        # conv: out_channels, kernel_size, stride, batchnorm, activate
        # maxpool: kernel_size stride
        params = [
            [64, 7, 2, True, 'leaky'],
            ['M', 2, 2],
            [192, 3, 1, True, 'leaky'],
            ['M', 2, 2],
            [128, 1, 1, True, 'leaky'],
            [256, 3, 1, True, 'leaky'],
            [256, 1, 1, True, 'leaky'],
            [512, 3, 1, True, 'leaky'],
            ['M', 2, 2],
            [256, 1, 1, True, 'leaky'],
            [512, 3, 1, True, 'leaky'],
            [256, 1, 1, True, 'leaky'],
            [512, 3, 1, True, 'leaky'],
            [256, 1, 1, True, 'leaky'],
            [512, 3, 1, True, 'leaky'],
            [256, 1, 1, True, 'leaky'],
            [512, 3, 1, True, 'leaky'],
            [512, 1, 1, True, 'leaky'],
            [1024, 3, 1, True, 'leaky'],
            ['M', 2, 2],
            [512, 1, 1, True, 'leaky'],
            [1024, 3, 1, True, 'leaky'],
            [512, 1, 1, True, 'leaky'],
            [1024, 3, 1, True, 'leaky'],
            [out_channels, 1, 1, False, 'leaky'], # classifier
            ['A']
        ]

        module_list = nn.ModuleList()
        for i, v in enumerate(params):
            modules = nn.Sequential()
            if v[0] == 'M':
                modules.add_module(f"maxpool_{i}", nn.MaxPool2d(kernel_size=v[1], stride=v[2], padding=int((v[1] - 1) // 2)))
            elif v[0] == 'A':
                modules.add_module(f"avgpool_{i}", nn.AdaptiveAvgPool2d((1, 1)))
            else:
                modules.add_module(
                    f"conv_{i}",
                    nn.Conv2d(
                        in_channels,
                        v[0],
                        kernel_size=v[1],
                        stride=v[2],
                        padding=(v[1] - 1) // 2,
                        bias=not v[3]
                    )
                )
                if v[3]:
                    modules.add_module(f"bn_{i}", nn.BatchNorm2d(v[0]))
                modules.add_module(f"act_{i}", nn.LeakyReLU(0.1) if v[4] == 'leaky' else nn.ReLU())
                in_channels = v[0]
            module_list.append(modules)
        return module_list


def load_darknet_weights(model, weights_path):
    # Open the weights file
    with open(weights_path, "rb") as f:
        # First five are header values
        header = np.fromfile(f, dtype=np.int32, count=4)
        header_info = header  # Needed to write header when saving weights
        seen = header[3]  # number of images seen during training
        weights = np.fromfile(f, dtype=np.float32)  # The rest are weights

    ptr = 0
    for module in model.features:
        if isinstance(module[0], nn.Conv2d):
            conv_layer = module[0]
            if isinstance(module[1], nn.BatchNorm2d):
                # Load BN bias, weights, running mean and running variance
                bn_layer = module[1]
                num_b = bn_layer.bias.numel()  # Number of biases
                # Bias
                bn_b = torch.from_numpy(
                    weights[ptr: ptr + num_b]).view_as(bn_layer.bias)
                bn_layer.bias.data.copy_(bn_b)
                ptr += num_b
                # Weight
                bn_w = torch.from_numpy(
                    weights[ptr: ptr + num_b]).view_as(bn_layer.weight)
                bn_layer.weight.data.copy_(bn_w)
                ptr += num_b
                # Running Mean
                bn_rm = torch.from_numpy(
                    weights[ptr: ptr + num_b]).view_as(bn_layer.running_mean)
                bn_layer.running_mean.data.copy_(bn_rm)
                ptr += num_b
                # Running Var
                bn_rv = torch.from_numpy(
                    weights[ptr: ptr + num_b]).view_as(bn_layer.running_var)
                bn_layer.running_var.data.copy_(bn_rv)
                ptr += num_b
            else:
                # Load conv. bias
                num_b = conv_layer.bias.numel()
                conv_b = torch.from_numpy(weights[ptr: ptr + num_b]).view_as(conv_layer.bias)
                conv_layer.bias.data.copy_(conv_b)
                ptr += num_b
            # Load conv. weights
            num_w = conv_layer.weight.numel()
            conv_w = torch.from_numpy(weights[ptr: ptr + num_w]).view_as(conv_layer.weight)
            conv_layer.weight.data.copy_(conv_w)
            ptr += num_w


if __name__ == '__main__':
    # load moel
    checkpoint_path = "extraction.weights"
    model = ExtractionNet(phase='test')
    load_darknet_weights(model, checkpoint_path)
    model.eval()

    # model input size
    net_size = 224

    # load img
    img = cv2.imread('dog.jpg')
    # img bgr2rgb
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    # resize img
    h, w, _ = img_rgb.shape
    new_h, new_w = h, w
    if w < h:
        new_h = (h * net_size) // w
        new_w = net_size
    else:
        new_w = (w * net_size) // h
        new_h = net_size
    img_resize = cv2.resize(img_rgb, (new_w, new_h))

    # crop img
    cut_w = (new_w - net_size) // 2
    cut_h = (new_h - net_size) // 2
    img_crop = img_resize[cut_h:cut_h + net_size, cut_w:cut_w + net_size, :]

    # float
    img_crop = torch.from_numpy(img_crop.transpose((2, 0, 1)))
    img_float = img_crop.float().div(255).unsqueeze(0)

    # forward
    result = model(img_float)

    print(result.topk(5))

 五、写在后面

 小伙伴们若能坚持完成YOLO系列的代码和原理学习,相信能对图像检测任务有个全新的认识,跟随博主的脚步,培养自己的动手能力吧!希望博主也能坚持将该系列做下去,一起加油!!!

六、参考

1、ImageNet Classification

2、https://github.com/AlexeyAB/darknet

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Cat(1):Cat入门

1 什么是调用链监控 1.1 架构的演进历史 单体应用 架构说明&#xff1a; 全部功能集中在一个项目内&#xff08;All in one&#xff09;。 在单体应用的年代&#xff0c;分析线上问题主要靠日志以及系统级别的指标。 微服务架构 架构说明&#xff1a; 将系统服务层完全独立…

亚马逊添加心愿单对卖家有什么好处

在亚马逊平台上&#xff0c;卖家可以从消费者的角度来看待心愿单的好处。消费者可以将自己感兴趣的商品添加到心愿单中&#xff0c;这对卖家来说也是有一些潜在好处的&#xff1a; 1、潜在销售机会增加&#xff1a;当消费者将商品添加到心愿单中&#xff0c;这可能表示他们对这…

mySQL 视图 VIEW

简化版的创建视图 create view 视图名 as select col ...coln from 表create view 视图名&#xff08;依次别名&#xff09; as select col ...coln from 表create view 视图名 as select col “别名1”&#xff0c;。。。col "别名n" from 表show tab…

Angular安全专辑之二——‘unsafe-eval’不是以下内容安全策略中允许的脚本源

一&#xff1a;错误出现 这个错误的意思是&#xff0c;拒绝将字符串评估为 JavaScript&#xff0c;因为‘unsafe-eval’不是以下内容安全策略中允许的脚本源。 二&#xff1a;错误场景 testEval() {const data eval("var sum2 new Function(a, b, return a b); sum2(em…

挖掘优质短视频超百万条,火山引擎DataLeap助力电商平台生态治理

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 在人们的日常生活中&#xff0c;网购已经成为人们生活中不可或缺的购物形式。 根据《中国社交电商行业发展白皮书&#xff08;2022&#xff09;》的数据显示&#x…

古战策与现代项目: 孙子兵法在项目管理中的应用

项目管理在当今的商业环境中是至关重要的。从初创公司到世界500强&#xff0c;项目管理的策略和工具都在不断地演变。然而&#xff0c;我们是否可以从古老的战争策略中汲取智慧&#xff0c;并将它们应用于现代的项目管理实践中呢? 让我们通过孙子兵法&#xff0c;一个古老而又…

ui设计师工作总结及计划范文模板

ui设计师工作总结及计划范文模板【篇一】 白驹过隙&#xff0c;转眼间某某年已近结尾&#xff0c;时间伴随着我们的脚步急驰而去&#xff0c;到了个人工作总结的时候&#xff0c;蓦然回首&#xff0c;才发现过去的一年不还能画上圆满的句号&#xff0c;内心感慨万千&#xff0c…

【PySide】Pyside QtWebEngine网页浏览器打开Flash网页

说明 QWebEngineView 加载 flash插件,可成功显示Flash,如图 源代码 # -*- coding: utf-8 -*- """ @File : pyside_2.py @Time : 2023/8/17 0:11 @Author : KmBase @Version : 1.0 @Contact : @Desc : None """import…

AN IMAGE IS WORTH 16X16 WORDS: TRANSFORMERS FOR IMAGE RECOGNITION AT SCALE

AN IMAGE IS WORTH 16X16 WORDS: TRANSFORMERS FOR IMAGE RECOGNITION AT SCALE 摘要模型架构Embedding层Transformer Encoder层MLP Head 整体流程 摘要 虽然Transformer体系结构已经成为自然语言处理任务的事实上的标准&#xff0c;但它在计算机视觉方面的应用仍然有限。在视…

传统算法是如何在销补调计划中发挥作用的

本文分享了一个「传统机器学习算法」在实际业务中的使用场景。 前言 如果嫌麻烦&#xff0c;你可以直接跳到正题观看~ 最近无论是在工作中的交谈&#xff0c;还是在日常刷屏的新闻&#xff0c;铺天盖地的都是大模型。我横竖是看不明白&#xff0c;费了大劲终于从字缝里看到了两…

后端项目打包上传服务器记录

后端项目打包上传服务器记录 文章目录 后端项目打包上传服务器记录1、项目打包2、jar包上传服务器 本文记录打包一个后端项目&#xff0c;上传公司服务器的过程。 1、项目打包 通过IDEA的插件进行打包&#xff1a; 打成一个jar包&#xff0c;jar包的位置在控制台可以看到。 2、…

记录--JS 的垃圾回收机制

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 前言 垃圾回收(Garbage Collection)是一种内存管理机制&#xff0c;用于检测和清理不再被程序使用的内存&#xff0c;这些不再被使用的内存就被称为垃圾。垃圾回收器会在 JS 引擎(浏览器或者 nodejs)内…

Baklib是比语雀、Notion、石墨文档更好用的在线知识库管理工具

在当今信息爆炸的时代&#xff0c;如何高效地管理和利用知识成为了每个人都面临的问题。在线知识库管理工具应运而生&#xff0c;帮助用户整理、存储和共享知识。在这篇文章中&#xff0c;我将介绍一个更好用的在线知识库管理工具——Baklib&#xff0c;并探讨它相对于其他知识…

Python爬虫——scrapy_多条管道下载

定义管道类&#xff08;在pipelines.py里定义&#xff09; import urllib.requestclass DangDangDownloadPipelines:def process_item(self, item, spider):url http: item.get(src)filename ../books_img/ item.get(name) .jpgurllib.request.urlretrieve(url, filename…

JAVA编程学习笔记

常用代码、特定函数、复杂概念、特定功能……在学习编程的过程中你会记录下哪些内容&#xff1f;快来分享你的笔记&#xff0c;一起切磋进步吧&#xff01; 一、常用代码 在java编程中常用需要储备的就是工具类。包括封装的时间工具类。http工具类&#xff0c;加解密工具类&am…

上海亚商投顾:沪指震荡调整 房地产、券商板块逆势走强

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大股指今日继续调整&#xff0c;深成指尾盘跌近1%&#xff0c;科创50指数跌超1.7%。房地产板块逆势走强&#xf…

计算机视觉之三维重建(一)(摄像机几何)

针孔摄像机 添加屏障&#xff1a; 使用针孔(o光圈针孔摄像机中心)&#xff0c;实现现实与成像一对一映射&#xff0c;减少模糊。其中针孔与像平面的距离为f(焦距)&#xff1b;虚拟像平面位于针孔与真实物体之间&#xff0c;与像平面互为倒立关系。位置映射&#xff1a;利用相似…

最新SSD固态硬盘颗粒QLC、SLC、MLC、TLC详解

概要 本文从SSD结构出发&#xff0c;详细介绍NAND闪存芯片QLC、SLC、MLC、TLC之间的区别、各自的优缺点以及其适用的人群。目录一、剖析SSD二、什么是NAND闪存三、单层单元&#xff08;Single Level Cell&#xff0c;简称SLC&#xff09;四、多层单元&#xff08;Multi Level C…

CAD图像转地形插件

插件介绍 CAD图像转地形插件可用于在AutoCAD软件内基于图片图像信息生成三维高度实体模型&#xff0c;适用于科研论文渲染绘图、有限元建模、地形模拟等方面的应用。 使用说明 对于一张图片来说&#xff0c;如灰度图&#xff0c;其图片信息是像素的亮度差异&#xff0c;这样一…

yolov5封装进ros系统

一&#xff0c;要具备ROS环境 ROS环境搭建可以参考我之前的文章 ROS参考文章1 ROS参考文章2   建立ROS工作空间 ROS系统由自己的编译空间规则。 cd 你自己想要的文件夹&#xff08;我一般是home目录&#xff09; mkdir -p (你自己的文件夹名字&#xff0c;比如我是yolov5…