基于轻量级神经网络GhostNet开发构建的200种鸟类细粒度识别分析系统

news2024/9/21 2:34:55

最近项目需要用到轻量级的网络模型,后期考虑进一步的剪枝和量化达到加速推理的目的,正好有时间就想着基于实际的数据集来开发构建项目做测试,本文的核心目的就是选定轻量级神经网络模型GhostNet来开发构建细粒度鸟类识别系统,首先看下效果图:

简单看下数据集:

数据集随机划分相关的实现可以看我前文的介绍,这里直接给出核心代码实现:

# 加载解析创建数据集
if not os.path.exists("dataset.json"):
    train_dataset = []
    test_dataset = []
    all_dataset = []
    classes_list = os.listdir(datasetDir)
    classes_list.sort()
    print("classes_list: ", classes_list)
    with open("weights/classes.txt","w") as f:
        for one_label in classes_list:
            f.write(one_label.strip()+"\n")
    print("classes file write success!")
    num_classes=len(classes_list)
    for one_label in os.listdir(datasetDir):
        oneDir = datasetDir + one_label + "/"
        for one_pic in os.listdir(oneDir):
            one_path = oneDir + one_pic
            try:
                one_ind = classes_list.index(one_label)
                all_dataset.append([one_ind, one_path])
            except:
                pass
    train_ratio = 0.90
    train_num = int(train_ratio * len(all_dataset))
    all_inds = list(range(len(all_dataset)))
    train_inds = random.sample(all_inds, train_num)
    test_inds = [one for one in all_inds if one not in train_inds]
    for one_ind in train_inds:
        train_dataset.append(all_dataset[one_ind])
    for one_ind in test_inds:
        test_dataset.append(all_dataset[one_ind])
    dataset = {}
    dataset["train"] = train_dataset
    dataset["test"] = test_dataset
    with open("dataset.json", "w") as f:
        f.write(json.dumps(dataset))
else:
    with open("dataset.json") as f:
        dataset = json.load(f)
    train_dataset = dataset["train"]
    test_dataset = dataset["test"]
    with open("weights/classes.txt","r") as f:
        classes_list=[one.strip() for one in f.readlines() if one.strip()]
    print("classes_list: ", classes_list)
    num_classes = len(classes_list)
print("train_dataset_size: ", len(train_dataset))
print("test_dataset_size: ", len(test_dataset))

以下是一些常用的轻量级卷积神经网络模型:

  1. MobileNet:MobileNet是一种基于深度可分离卷积的轻量级模型,通过Depthwise Separable Convolution减少参数量和计算量,适用于移动设备上的图像分类和目标检测。

  2. ShuffleNet:ShuffleNet通过使用通道洗牌操作来减少参数量和计算量。它采用逐点卷积和组卷积,将通道分为组并进行特征图的混洗,以增加特征的多样性。

  3. EfficientNet:EfficientNet是一系列模型,通过使用复合缩放方法在深度、宽度和分辨率上进行均衡扩展。它在减少参数和计算量的同时,保持高准确性。

  4. MobileNetV3:MobileNetV3是MobileNet的改进版本,引入了候选网络和网络搜索方法,通过优化模型结构和激活函数,进一步提升了轻量级模型的性能。

  5. ProxylessNAS:ProxylessNAS是使用神经网络搜索算法来自动搜索轻量级模型结构的方法。它通过替代器生成网络中的每个操作,以有效地搜索高效的模型结构。

  6. SqueezeNet:SqueezeNet是一种极小化的卷积神经网络模型,使用Fire模块将降维卷积和扩展卷积组合在一起,以减少参数量和计算量。

这些轻量级模型在参数量和计算量上相对较少,适用于资源受限的设备或场景。然而,每个模型都有不同的性能和特点,根据应用需求和资源限制,选择合适的模型进行使用。同时,还可以根据具体任务的要求进行模型的调整和优化。

GhostNet是一种轻量级的卷积神经网络模型,旨在在计算资源有限的设备上实现高效的图像分类和目标检测。其主要原理是通过使用Ghost Module来减少参数量和计算量,并提高模型在资源受限条件下的性能。

Ghost Module是GhostNet的关键组成部分,其主要思想是通过将一个普通的卷积层分解为两个部分:主要卷积(或称为Ghost指示器)和辅助卷积。具体构建原理如下:

  1. 主要卷积(Ghost指示器):该部分包含少量的输出通道数(称为精简通道),可以看作是对原始卷积的一种降维表示。它对输入进行低维特征提取,并通过学习有效的过滤器来减少参数量和计算量。

  2. 辅助卷积:该部分包含更多的输出通道数(称为扩展通道),用于捕捉更丰富的特征表达。这种设计有助于模型在较少的参数量下保持较高的表示能力,提高对复杂图像的判别能力。

GhostNet模型的优点如下:

  1. 轻量高效:GhostNet通过使用Ghost Module,减少了模型的参数量和计算量,使得它在计算资源受限的设备上运行速度更快,能够满足更多应用的需求。

  2. 参数效率:Ghost Module通过以较少的参数产生较多的特征图,提高了参数的利用效率。这使得模型更具可扩展性,并能够更好地适应低功耗的设备和移动端应用需求。

  3. 准确性保持:尽管GhostNet是为了追求高效而设计的,但经过实证研究表明,在一些图像分类和目标检测任务中,它的准确性能够与一些常用的大型模型相媲美,或接近。

GhostNet模型的缺点如下:

  1. 空间复杂性:尽管GhostNet在参数和计算量上显著减少,但由于采用了辅助卷积来提取更丰富的特征,其空间复杂性相对较高。这可能使得在计算资源极度有限的设备上推理速度较慢。

  2. 特定任务的局限性:GhostNet主要用于图像分类和目标检测任务。对于其他类型的任务,如语义分割或实例分割等,GhostNet可能需要额外的定制和改进来适应任务的需求。

总之,GhostNet作为一种轻量级的模型设计,通过Ghost Module降低了模型的参数量和计算量,提高了在计算资源有限的设备上的性能。尽管存在一些局限性,但它在保持一定准确性的同时,能够在资源受限情况下提供高效的图像分类和目标检测能力。

在以往的项目中使用Mobilenet模型居多,较少使用GhostNet,所以这里以实地项目开发的方式也是想进一步熟悉GhostNet模型,这里模型搭建实现代码如下所示:

# encoding:utf-8
from __future__ import division


"""
__Author__:沂水寒城
功能:  GhostNet
"""


import torch
import torch.nn as nn
import math
import numpy as np
from torch.hub import load_state_dict_from_url
from utils.utils import load_weights_from_state_dict



def _make_divisible(v, divisor, min_value=None):
    """
    参考
    https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py
    """
    if min_value is None:
        min_value = divisor
    new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
    if new_v < 0.9 * v:
        new_v += divisor
    return new_v


class SELayer(nn.Module):
    """
    SE Layer
    """
    def __init__(self, channel, reduction=4):
        super(SELayer, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(
            nn.Linear(channel, channel // reduction),
            nn.ReLU(inplace=True),
            nn.Linear(channel // reduction, channel),
        )

    def forward(self, x):
        b, c, _, _ = x.size()
        y = self.avg_pool(x).view(b, c)
        y = self.fc(y).view(b, c, 1, 1)
        y = torch.clamp(y, 0, 1)
        return x * y


def depthwise_conv(inp, oup, kernel_size=3, stride=1, relu=False):
    """
    DW
    """
    return nn.Sequential(
        nn.Conv2d(
            inp, oup, kernel_size, stride, kernel_size // 2, groups=inp, bias=False
        ),
        nn.BatchNorm2d(oup),
        nn.ReLU(inplace=True) if relu else nn.Sequential(),
    )


class GhostModule(nn.Module):
    """
    Ghost
    """
    def __init__(
        self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True
    ):
        super(GhostModule, self).__init__()
        self.oup = oup
        init_channels = math.ceil(oup / ratio)
        new_channels = init_channels * (ratio - 1)

        self.primary_conv = nn.Sequential(
            nn.Conv2d(
                inp, init_channels, kernel_size, stride, kernel_size // 2, bias=False
            ),
            nn.BatchNorm2d(init_channels),
            nn.ReLU(inplace=True) if relu else nn.Sequential(),
        )

        self.cheap_operation = nn.Sequential(
            nn.Conv2d(
                init_channels,
                new_channels,
                dw_size,
                1,
                dw_size // 2,
                groups=init_channels,
                bias=False,
            ),
            nn.BatchNorm2d(new_channels),
            nn.ReLU(inplace=True) if relu else nn.Sequential(),
        )

    def forward(self, x):
        x1 = self.primary_conv(x)
        x2 = self.cheap_operation(x1)
        out = torch.cat([x1, x2], dim=1)
        return out[:, : self.oup, :, :]


class GhostBottleneck(nn.Module):
    """
    GhostBottleneck
    """
    def __init__(self, inp, hidden_dim, oup, kernel_size, stride, use_se):
        super(GhostBottleneck, self).__init__()
        assert stride in [1, 2]
        self.conv = nn.Sequential(
            GhostModule(inp, hidden_dim, kernel_size=1, relu=True),
            depthwise_conv(hidden_dim, hidden_dim, kernel_size, stride, relu=False)
            if stride == 2
            else nn.Sequential(),
            SELayer(hidden_dim) if use_se else nn.Sequential(),
            GhostModule(hidden_dim, oup, kernel_size=1, relu=False),
        )
        if stride == 1 and inp == oup:
            self.shortcut = nn.Sequential()
        else:
            self.shortcut = nn.Sequential(
                depthwise_conv(inp, inp, 3, stride, relu=True),
                nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
                nn.BatchNorm2d(oup),
            )

    def forward(self, x):
        return self.conv(x) + self.shortcut(x)


class GhostNet(nn.Module):
    """
    GhostNet
    """
    def __init__(self, cfgs, num_classes=1000, width_mult=1.0):
        super(GhostNet, self).__init__()
        self.cfgs = cfgs
        output_channel = _make_divisible(16 * width_mult, 4)
        layers = [
            nn.Sequential(
                nn.Conv2d(3, output_channel, 3, 2, 1, bias=False),
                nn.BatchNorm2d(output_channel),
                nn.ReLU(inplace=True),
            )
        ]
        input_channel = output_channel
        block = GhostBottleneck
        for k, exp_size, c, use_se, s in self.cfgs:
            output_channel = _make_divisible(c * width_mult, 4)
            hidden_channel = _make_divisible(exp_size * width_mult, 4)
            layers.append(
                block(input_channel, hidden_channel, output_channel, k, s, use_se)
            )
            input_channel = output_channel
        self.features = nn.Sequential(*layers)
        output_channel = _make_divisible(exp_size * width_mult, 4)
        self.squeeze = nn.Sequential(
            nn.Conv2d(input_channel, output_channel, 1, 1, 0, bias=False),
            nn.BatchNorm2d(output_channel),
            nn.ReLU(inplace=True),
            nn.AdaptiveAvgPool2d((1, 1)),
        )
        input_channel = output_channel
        output_channel = 1280
        self.classifier = nn.Sequential(
            nn.Linear(input_channel, output_channel, bias=False),
            nn.BatchNorm1d(output_channel),
            nn.ReLU(inplace=True),
            nn.Dropout(0.2),
            nn.Linear(output_channel, num_classes),
        )
        self._initialize_weights()

    def forward(self, x, need_fea=False):
        if need_fea:
            features, features_fc = self.forward_features(x, need_fea)
            x = self.classifier(features_fc)
            return features, features_fc, x
        else:
            x = self.forward_features(x)
            x = self.classifier(x)
            return x

    def forward_features(self, x, need_fea=False):
        if need_fea:
            input_size = x.size(2)
            scale = [4, 8, 16, 32]
            features = [None, None, None, None]
            for idx, layer in enumerate(self.features):
                x = layer(x)
                if input_size // x.size(2) in scale:
                    features[scale.index(input_size // x.size(2))] = x
            x = self.squeeze(x)
            return features, x.view(x.size(0), -1)
        else:
            x = self.features(x)
            x = self.squeeze(x)
            return x.view(x.size(0), -1)

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode="fan_out", nonlinearity="relu")
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()

    def cam_layer(self):
        return self.features[-1]

可以直接去华为开源仓库里面或者是开源社区其他的项目里面选择自己喜欢的代码实现即可,不需要自己去重头实现,理解应用即可。这里就不再赘述了,很多项目整体已经是比较完善的了。

这里对模型预测结果也进行了簇群可视化,如下所示:

这里类别比较多,显得比较混乱一些。

在绘制混淆矩阵的时候我们发现,200个类别的混淆矩阵基本没法看,后面想到了一个折中的办法就是不要精确的混淆矩阵,粗糙的实现,我们实现了按指定数量分段绘制混淆矩阵,如下所示:

这里可以人为设定单段绘制的最大数量,比如我这里设定的就是50个,这种方法之所以说是粗糙是因为丢弃了部分数据,不然没有办法形成对角线矩阵,只是为了视觉效果采用的这种方法,其他场景不建议这样去做。

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

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

相关文章

MySQL服务关闭开机自启,改成手动启动状态

最近在写前端&#xff0c;所以就先把后端数据库禁用或手动启动吧。防止浪费太多内存或资源。一般就之前损坏了的数据库就禁用吧&#xff0c;其他最近不常用的服务就没必要开机自启动吧&#xff0c;毕竟电脑只有一台&#xff0c;不想学习想用电脑来玩的话就讲工作服务从开机自启…

数字出版软件系统开发

数字出版涵盖了广泛的内容&#xff0c;从电子书到数字杂志、在线期刊和互动教育教材等。为了实现这些数字出版物&#xff0c;有许多不同类型的软件系统可供使用&#xff0c;每种都有自己的特点和功能。以下是一些常见的数字出版软件系统以及它们主要实现的功能&#xff0c;希望…

国标视频云服务EasyGBS国标视频平台设备录像下载文件为ps格式,如何改为MP4格式?

EasyGBS是基于国标GB/T28181协议的视频云服务平台&#xff0c;不仅支持无缝、完整接入内网或者公网的国标设备&#xff0c;在输出上&#xff0c;提供RTSP、RTMP、FLV、HLS、WebRTC等多种格式视频流的分发服务&#xff0c;实现全平台、全终端输出。 有用户反馈&#xff0c;在使用…

ubuntu 扩展内存挂载

一般新建虚拟机时&#xff0c;系统默认的空间是20G&#xff0c;但是当我们搭建一些环境之后&#xff0c;需要解压一些稍微大点的源码时内存可能不够用了&#xff0c;这时我们需要扩展内存。 一、硬盘扩展 首先&#xff0c;关闭虚拟机&#xff0c;在虚拟机设置中将硬盘容量扩展…

PMP认证的用处是什么?做哪些工作需要?

PMP是项目管理证书&#xff0c;是PMI组织&#xff0c;严格评估项目管理人员知识技能是否具有高品质的资格认证考试。随着在国内传播和影响力的增加&#xff0c;如今在各大招聘平台去看项目经理之类的职位&#xff0c;大多数要求会有“PMP证书优先”。在一些大型企业&#xff0c…

【开源三方库】crypto-js加密算法库的使用方法

OpenAtom OpenHarmony&#xff08;简称“OpenHarmony”&#xff09;三方库&#xff0c;是经过验证可在OpenHarmony系统上可重复使用的软件组件&#xff0c;可帮助开发者快速开发OpenHarmony应用。如果是发布到开源社区&#xff0c;称为开源三方库&#xff0c;开发者可以通过访问…

antd中 a-table表格组件跨页勾选,数据回显勾选的问题

踩坑&#xff1a;a-table翻页勾选数据丢失&#xff0c;数据回显勾选 需求&#xff1a;input框显示勾选的所有数据里面的name组成的字符串&#xff0c;点击后面的图标弹出弹框&#xff0c;并且之前选择的数据需要回显勾选。如下图所示 <a-card :bordered"false"&…

苹果笔有必要买吗?ipad可以用的手写笔

众所周知&#xff0c;现在网上越来越多平替电容笔的出现&#xff0c;无论是价格和功能&#xff0c;几乎都很接近。很多小伙伴不知如何下手&#xff0c;不知道如何从众多品牌中挑选出适合自己的电容笔&#xff0c;今天我为大家总结一下网上几款热销&#xff0c;平价的国货品牌电…

【计算机基础知识6】跨域问题及解决方案

目录 前言 一、什么是跨域问题&#xff1f; 二、为什么会出现跨域问题&#xff1f; 三、常见的跨域解决方法 1. JSONP&#xff08;JSON with Padding&#xff09; 2. CORS&#xff08;跨域资源共享&#xff09; 3. 代理服务器 4. postMessage() 前言 跨域是前端开发中经…

2023高教社杯数学建模E题思路代码 - 黄河水沙监测数据分析

# 1 赛题 E 题 黄河水沙监测数据分析 黄河是中华民族的母亲河。研究黄河水沙通量的变化规律对沿黄流域的环境治理、气候变 化和人民生活的影响&#xff0c; 以及对优化黄河流域水资源分配、协调人地关系、调水调沙、防洪减灾 等方面都具有重要的理论指导意义。 附件 1 给出了位…

win11切换输入法快捷键怎么设置

win11系统有自动的切换输入法的快捷键&#xff0c;如果我们觉得系统默认的快捷键使用起来不习惯的话&#xff0c;我们可以将切换输入法的快捷键进行更改设置&#xff0c;这里小编就给大家带来win11输入法切换快捷键的设置方法&#xff0c;感兴趣的小伙伴快来看看吧。 win11输入…

企业变更记录查询API:解密企业演变的关键数据

前言 随着市场竞争的不断升级和商业环境的动态变化&#xff0c;企业必须不断适应新的情况和变革。在这个过程中&#xff0c;企业的变更记录成为了关键的数据&#xff0c;它可以帮助企业了解自己的发展历程、监测竞争对手的动态、评估市场趋势和满足法律法规的合规要求。为了解…

Fair|Fur —— Object Nodes

目录 Guide Groom Guide Deform Guide Merge Hair Generate Guide Simulate Hair Card Generate Guide Groom 从skin几何体生成引导线&#xff0c;并在其节点内可进一步处理引导线&#xff1b;内嵌Hair Generate节点&#xff1b; 注&#xff1a;skin几何体应是静态的&am…

关于一次blog性能测试的过程和疑问

找了搭建的一个博客网站&#xff0c;拿来试着测了测&#xff0c;想看一下性能能达到什么目标&#xff1b; 测试过程中遇到一些问题&#xff0c;还无法凭自己找到原因&#xff0c;测试过程记录下来&#xff0c;希望有热心大佬多多指教&#xff1b; 目录 基准测试场景 1、首页…

基于JAVA SSM框架和JSP的超市小卖部管理系统设计

摘要 随着时代的发展&#xff0c;传统的超市购物方式已经不能满足人们的需求&#xff0c;对于顾客来说&#xff0c;排队购物和支付购物费用的问题亟待解决。对于实体超市来说&#xff0c;他们面临着网上购物的竞争压力&#xff0c;作为超市经理&#xff0c;他们要降低成本&…

【C语言】初阶测试 (带讲解)

目录 ① 选择题 1. 下列程序执行后&#xff0c;输出的结果为( ) 2. 以下程序的输出结果是&#xff1f; 3. 下面的代码段中&#xff0c;执行之后 i 和 j 的值是什么&#xff08;&#xff09; 4. 以下程序的k最终值是&#xff1a; 5. 以下程序的最终的输出结果为&#xff…

hive中遇到length函数不支持bigint

背景 hive中遇到length函数不支持bigint 解决方法&#xff0c;sql转为string之后计算长度 SELECT COUNT(1) FROM ( select msisdn FROM tb_nrmr_sample_lt_dd_total where loc_time in (23090201,23090202,23090203,23090204,23090205,23090206) and length(cast(msisdn as…

2023年9月NPDP产品经理国际认证报名,来弘博创新

产品经理国际资格认证NPDP是新产品开发方面的认证&#xff0c;集理论、方法与实践为一体的全方位的知识体系&#xff0c;为公司组织层级进行规划、决策、执行提供良好的方法体系支撑。 【认证机构】 产品开发与管理协会&#xff08;PDMA&#xff09;成立于1979年&#xff0c;是…

一种基于动态代理的通用研发提效解决方案

作为一名研发人员&#xff0c;除了业务开发之外&#xff0c;研发提效是一个永恒的话题&#xff0c;而女娲正是这一话题下进行的一次全面的剖析和实践。 作者&#xff1a;张全洪(钝悟) 一、女娲是什么 女娲是业务研发同学&#xff08;开发、测试、运维&#xff09;在软件迭代的…

高忆管理:军工板块走高,奥普光电涨停,恒宇信通等大涨

军工板块8日盘中发力走高&#xff0c;到发稿&#xff0c;晨曦航空、恒宇信通涨超12%&#xff0c;腾景科技涨逾11%&#xff0c;奥普光电涨停&#xff0c;霍莱沃、新余高科涨超7%。 对于该板块&#xff0c;组织表示&#xff0c;受职业增速下降以及“十四五”中期调整等不确定性因…