python基于轻量级卷积神经网络模型ShuffleNetv2开发构建辣椒病虫害图像识别系统

轻量级识别模型在我们前面的博文中已经有过很多实践了,感兴趣的话可以自行移步阅读:

《移动端轻量级模型开发谁更胜一筹,efficientnet、mobilenetv2、mobilenetv3、ghostnet、mnasnet、shufflenetv2驾驶危险行为识别模型对比开发测试》

《基于Pytorch框架的轻量级卷积神经网络垃圾分类识别系统》

《基于轻量级卷积神经网络模型实践Fruits360果蔬识别——自主构建CNN模型、轻量化改造设计lenet、alexnet、vgg16、vgg19和mobilenet共六种CNN模型实验对比分析》

《探索轻量级模型性能上限,基于GhostNet模型开发构建多商品细粒度图像识别系统》

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

《基于MobileNet的轻量级卷积神经网络实现玉米螟虫不同阶段识别分析》

《python开发构建轻量级卷积神经网络模型实现手写甲骨文识别系统》

《基于轻量级模型GHoshNet开发构建眼球眼疾识别分析系统,构建全方位多层次参数对比分析实验》

本文的核心思想是像基于ShuffleNetv2来开发构建辣椒病虫害识别系统,首先看下实例效果:

本文选择的是轻量级网络中非常强大的ShuffleNetv2,ShuffleNetv2网络是一种用于图像识别和分类任务的卷积神经网络结构,它旨在在保持准确性的同时尽可能地减少模型的计算和参数量。下面是对ShuffleNetv2网络构建原理的详细介绍,并针对性地分析其优点和缺点:

构建原理:

  1. 基本单元:ShuffleNetv2网络的基本单元是由深度可分离卷积和通道重排组成的特殊模块。其中深度可分离卷积用于减少计算量和参数数量,而通道重排则用于交换和重组特征通道。

  2. 分组卷积:ShuffleNetv2将卷积操作分组,使得每个分组内部进行特征提取,然后再将特征通道进行重排和整合,从而实现了计算效率的提升。

  3. 网络结构:ShuffleNetv2网络结构由多个堆叠的ShuffleNetv2块组成,每个块内部包含了多个基本单元,通过合理的设计实现了高效的信息流动和特征提取。

优点:

  1. 轻量级高效:ShuffleNetv2相比传统的卷积神经网络具有更少的参数量和计算量,适合于移动设备上的部署和实时推理。

  2. 准确性:尽管模型规模小,但ShuffleNetv2在保持较高的准确性的同时,实现了高效的模型推理。

  3. 结构灵活:ShuffleNetv2网络结构可以通过调整基本单元的个数和网络深度来适应不同的计算资源和任务需求。

缺点:

  1. 学习能力有限:由于参数数量较少,ShuffleNetv2网络可能在复杂场景和大规模数据上的表示学习能力相对较弱,可能无法取得更高的准确性。

  2. 训练复杂度:尽管ShuffleNetv2网络在推理时很高效,但在训练过程中相比一些大型网络结构可能需要更多的迭代才能取得好的效果,训练复杂度较大。

总的来说,ShuffleNetv2网络在轻量级和高效方面具有明显的优势,适用于移动设备和资源受限的场景,但在一些大规模和复杂任务上可能会存在一定的限制。

这里给出基于Keras和pytorch对应的代码实现,首先是keras实现,如下所示:

#!usr/bin/env python
# encoding:utf-8
from __future__ import divisionimport os
import numpy as np
from keras.utils import plot_model
from keras.applications.imagenet_utils import _obtain_input_shape
from keras.engine.topology import get_source_inputs
from keras.layers import *
from keras.models import Model
import keras.backend as K
from utils import blockdef ShuffleNetV2(include_top=True,input_tensor=None,scale_factor=1.0,pooling="max",input_shape=(224, 224, 3),load_model=None,num_shuffle_units=[3, 7, 3],bottleneck_ratio=1,classes=1000,
):if K.backend() != "tensorflow":raise RuntimeError("Only tensorflow supported for now")name = "ShuffleNetV2_{}_{}_{}".format(scale_factor, bottleneck_ratio, "".join([str(x) for x in num_shuffle_units]))input_shape = _obtain_input_shape(input_shape,default_size=224,min_size=28,require_flatten=include_top,data_format=K.image_data_format(),)out_dim_stage_two = {0.5: 48, 1: 116, 1.5: 176, 2: 244}if pooling not in ["max", "avg"]:raise ValueError("Invalid value for pooling")if not (float(scale_factor) * 4).is_integer():raise ValueError("Invalid value for scale_factor, should be x over 4")exp = np.insert(np.arange(len(num_shuffle_units), dtype=np.float32), 0, 0)  # [0., 0., 1., 2.]out_channels_in_stage = 2**expout_channels_in_stage *= out_dim_stage_two[bottleneck_ratio]  #  calculate output channels for each stageout_channels_in_stage[0] = 24  # first stage has always 24 output channelsout_channels_in_stage *= scale_factorout_channels_in_stage = out_channels_in_stage.astype(int)if input_tensor is None:img_input = Input(shape=input_shape)else:if not K.is_keras_tensor(input_tensor):img_input = Input(tensor=input_tensor, shape=input_shape)else:img_input = input_tensor# create shufflenet architecturex = Conv2D(filters=out_channels_in_stage[0],kernel_size=(3, 3),padding="same",use_bias=False,strides=(2, 2),activation="relu",name="conv1",)(img_input)x = MaxPool2D(pool_size=(3, 3), strides=(2, 2), padding="same", name="maxpool1")(x)# create stages containing shufflenet units beginning at stage 2for stage in range(len(num_shuffle_units)):repeat = num_shuffle_units[stage]x = block(x,out_channels_in_stage,repeat=repeat,bottleneck_ratio=bottleneck_ratio,stage=stage + 2,)if bottleneck_ratio < 2:k = 1024else:k = 2048x = Conv2D(k,kernel_size=1,padding="same",strides=1,name="1x1conv5_out",activation="relu",)(x)if pooling == "avg":x = GlobalAveragePooling2D(name="global_avg_pool")(x)elif pooling == "max":x = GlobalMaxPooling2D(name="global_max_pool")(x)if include_top:x = Dense(classes, name="fc")(x)x = Activation("softmax", name="softmax")(x)if input_tensor:inputs = get_source_inputs(input_tensor)else:inputs = img_inputmodel = Model(inputs, x, name=name)if load_model:model.load_weights("", by_name=True)return model

接下来是PyTorch的实现:

#!usr/bin/env python
# encoding:utf-8
from __future__ import divisionimport os
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.nn import init
from collections import OrderedDictdef _make_divisible(v, divisor, min_value=None):"""This function is taken from the original tf repo.It ensures that all layers have a channel number that is divisible by 8It can be seen here:https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py:param v::param divisor::param min_value::return:"""if min_value is None:min_value = divisornew_v = max(min_value, int(v + divisor / 2) // divisor * divisor)# Make sure that round down does not go down by more than 10%.if new_v < 0.9 * v:new_v += divisorreturn new_vdef channel_shuffle(x, groups):batchsize, num_channels, height, width = x.data.size()assert num_channels % groups == 0channels_per_group = num_channels // groups# reshapex = x.view(batchsize, groups, channels_per_group, height, width)# transpose# - contiguous() required if transpose() is used before view().#   See https://github.com/pytorch/pytorch/issues/764x = torch.transpose(x, 1, 2).contiguous()# flattenx = x.view(batchsize, -1, height, width)return xclass SELayer(nn.Module):def __init__(self, channel, reduction=16):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),nn.Sigmoid(),)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)return x * yclass BasicUnit(nn.Module):def __init__(self,inplanes,outplanes,c_tag=0.5,activation=nn.ReLU,SE=False,residual=False,groups=2,):super(BasicUnit, self).__init__()self.left_part = round(c_tag * inplanes)self.right_part_in = inplanes - self.left_partself.right_part_out = outplanes - self.left_partself.conv1 = nn.Conv2d(self.right_part_in, self.right_part_out, kernel_size=1, bias=False)self.bn1 = nn.BatchNorm2d(self.right_part_out)self.conv2 = nn.Conv2d(self.right_part_out,self.right_part_out,kernel_size=3,padding=1,bias=False,groups=self.right_part_out,)self.bn2 = nn.BatchNorm2d(self.right_part_out)self.conv3 = nn.Conv2d(self.right_part_out, self.right_part_out, kernel_size=1, bias=False)self.bn3 = nn.BatchNorm2d(self.right_part_out)self.activation = activation(inplace=True)self.inplanes = inplanesself.outplanes = outplanesself.residual = residualself.groups = groupsself.SE = SEif self.SE:self.SELayer = SELayer(self.right_part_out, 2)  # TODOdef forward(self, x):left = x[:, : self.left_part, :, :]right = x[:, self.left_part :, :, :]out = self.conv1(right)out = self.bn1(out)out = self.activation(out)out = self.conv2(out)out = self.bn2(out)out = self.conv3(out)out = self.bn3(out)out = self.activation(out)if self.SE:out = self.SELayer(out)if self.residual and self.inplanes == self.outplanes:out += rightreturn channel_shuffle(torch.cat((left, out), 1), self.groups)class DownsampleUnit(nn.Module):def __init__(self, inplanes, c_tag=0.5, activation=nn.ReLU, groups=2):super(DownsampleUnit, self).__init__()self.conv1r = nn.Conv2d(inplanes, inplanes, kernel_size=1, bias=False)self.bn1r = nn.BatchNorm2d(inplanes)self.conv2r = nn.Conv2d(inplanes,inplanes,kernel_size=3,stride=2,padding=1,bias=False,groups=inplanes,)self.bn2r = nn.BatchNorm2d(inplanes)self.conv3r = nn.Conv2d(inplanes, inplanes, kernel_size=1, bias=False)self.bn3r = nn.BatchNorm2d(inplanes)self.conv1l = nn.Conv2d(inplanes,inplanes,kernel_size=3,stride=2,padding=1,bias=False,groups=inplanes,)self.bn1l = nn.BatchNorm2d(inplanes)self.conv2l = nn.Conv2d(inplanes, inplanes, kernel_size=1, bias=False)self.bn2l = nn.BatchNorm2d(inplanes)self.activation = activation(inplace=True)self.groups = groupsself.inplanes = inplanesdef forward(self, x):out_r = self.conv1r(x)out_r = self.bn1r(out_r)out_r = self.activation(out_r)out_r = self.conv2r(out_r)out_r = self.bn2r(out_r)out_r = self.conv3r(out_r)out_r = self.bn3r(out_r)out_r = self.activation(out_r)out_l = self.conv1l(x)out_l = self.bn1l(out_l)out_l = self.conv2l(out_l)out_l = self.bn2l(out_l)out_l = self.activation(out_l)return channel_shuffle(torch.cat((out_r, out_l), 1), self.groups)class ShuffleNetV2(nn.Module):"""ShuffleNetV2 implementation"""def __init__(self,scale=1.0,in_channels=3,c_tag=0.5,num_classes=1000,activation=nn.ReLU,SE=False,residual=False,groups=2,):"""ShuffleNetV2 constructor:param scale::param in_channels::param c_tag::param num_classes::param activation::param SE::param residual::param groups:"""super(ShuffleNetV2, self).__init__()self.scale = scaleself.c_tag = c_tagself.residual = residualself.SE = SEself.groups = groupsself.activation_type = activationself.activation = activation(inplace=True)self.num_classes = num_classesself.num_of_channels = {0.5: [24, 48, 96, 192, 1024],1: [24, 116, 232, 464, 1024],1.5: [24, 176, 352, 704, 1024],2: [24, 244, 488, 976, 2048],}self.c = [_make_divisible(chan, groups) for chan in self.num_of_channels[scale]]self.n = [3, 8, 3]  # TODO: should be [3,7,3]self.conv1 = nn.Conv2d(in_channels, self.c[0], kernel_size=3, bias=False, stride=2, padding=1)self.bn1 = nn.BatchNorm2d(self.c[0])self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2)self.shuffles = self._make_shuffles()self.conv_last = nn.Conv2d(self.c[-2], self.c[-1], kernel_size=1, bias=False)self.bn_last = nn.BatchNorm2d(self.c[-1])self.avgpool = nn.AdaptiveAvgPool2d(1)self.fc = nn.Linear(self.c[-1], self.num_classes)self.init_params()def init_params(self):for m in self.modules():if isinstance(m, nn.Conv2d):init.kaiming_normal_(m.weight, mode="fan_out")if m.bias is not None:init.constant_(m.bias, 0)elif isinstance(m, nn.BatchNorm2d):init.constant_(m.weight, 1)init.constant_(m.bias, 0)elif isinstance(m, nn.Linear):init.normal_(m.weight, std=0.001)if m.bias is not None:init.constant_(m.bias, 0)def _make_stage(self, inplanes, outplanes, n, stage):modules = OrderedDict()stage_name = "ShuffleUnit{}".format(stage)# First module is the only one utilizing stridefirst_module = DownsampleUnit(inplanes=inplanes,activation=self.activation_type,c_tag=self.c_tag,groups=self.groups,)modules["DownsampleUnit"] = first_modulesecond_module = BasicUnit(inplanes=inplanes * 2,outplanes=outplanes,activation=self.activation_type,c_tag=self.c_tag,SE=self.SE,residual=self.residual,groups=self.groups,)modules[stage_name + "_{}".format(0)] = second_module# add more LinearBottleneck depending on number of repeatsfor i in range(n - 1):name = stage_name + "_{}".format(i + 1)module = BasicUnit(inplanes=outplanes,outplanes=outplanes,activation=self.activation_type,c_tag=self.c_tag,SE=self.SE,residual=self.residual,groups=self.groups,)modules[name] = modulereturn nn.Sequential(modules)def _make_shuffles(self):modules = OrderedDict()stage_name = "ShuffleConvs"for i in range(len(self.c) - 2):name = stage_name + "_{}".format(i)module = self._make_stage(inplanes=self.c[i], outplanes=self.c[i + 1], n=self.n[i], stage=i)modules[name] = modulereturn nn.Sequential(modules)def forward(self, x):x = self.conv1(x)x = self.bn1(x)x = self.activation(x)x = self.maxpool(x)x = self.shuffles(x)x = self.conv_last(x)x = self.bn_last(x)x = self.activation(x)# average pooling layerx = self.avgpool(x)# flatten for input to fully-connected layerx = x.view(x.size(0), -1)x = self.fc(x)return F.log_softmax(x, dim=1)

可以拿到自己的项目中直接集成使用。

接下来看下数据集:

一共包含11种对应的疾病,如下:

炭疽病
疫病
用药不当
病毒病
温度不适
螨虫
细菌性病害
根腐病
缺素
脐腐病
蓟马

数据分布可视化如下所示:

默认100次的迭代训练,执行结束后来看下结果详情:
【loss曲线】

【acc曲线】

【混淆矩阵】

开发专用的系统界面实现可视化推理实例如下所示:

感兴趣的话都可以自行动手实践一下。

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

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

相关文章

你的手机注册了多少互联网账号?赶快通过这个功能查询一下吧!

一键查询手机号绑定&#xff01;你的手机注册了多少互联网账号&#xff1f;赶快查询一下吧&#xff01; 你知道你名下的手机号绑定了多少互联网账号吗&#xff1f; 怎么查询手机号绑定了什么账号呢&#xff1f; ...... 不用担心 一键查询手机号绑定的帐号功能来了&#xff01; …

制造业企业如何建立智能工厂

今天就聊聊企业智能工厂的打造&#xff0c;企业想实现数字化转型建立智能工厂&#xff0c;就需要先建设数字化车间&#xff0c;可以说数字化车间是建设智能工厂的重要一环&#xff0c;智能工厂的基础是数字化车间。数字化车间可以实现企业生产过程中车间计划调度、工艺执行管理…

食品厂ERP有哪几种?食品厂ERP软件哪个操作简单

食品安全问题是近些年备受消费者和企业关注的行业&#xff0c;而食品安全管理涉及原材料、配方、车间、工艺、设备、包装、仓储、保质期等多个方面&#xff0c;因而各个业务部门之间的协同问题就显得颇为重要。 想要提升采购、保质期、库龄分析、财务、订单、原材料、仓储等各…

Pycharm修改文件默认打开方式 + CSV Editor插件使用

1、File —> Settings —> Editor —> File Types 然后将*csv添加到最上面 在plugins中下载插件&#xff0c;CSV Editor 备注&#xff1a;不在上一步的“File Types”中将*.csv设置为CSV格式&#xff0c;插件是不起作用的 就可以使用了

十二、FreeRTOS之FreeRTOS任务相关API函数

本节需要掌握以下内容&#xff1a; 1&#xff0c;FreeRTOS任务相关API函数介绍&#xff08;熟悉&#xff09; 2&#xff0c;任务状态查询API函数实验&#xff08;掌握&#xff09; 3&#xff0c;任务时间统计API函数实验&#xff08;掌握&#xff09; 4&#xff0c;总结 一…

【Docker】从零开始:15.搭建亿级数据Redis集群之哈希算法概念

【Docker】从零开始&#xff1a;15.搭建亿级数据Redis集群之哈希算法概念篇 概述一般业界的3种解决方案1.哈希取余分区优点&#xff1a;缺点&#xff1a; 2.一致性哈希算法分区背景目的原理一致性哈希环节点映射key落到服务器的落键规则 优点容错性扩展性 缺点 3.哈希槽分区背景…

家用超声波清洗机哪个牌子好?一起来看、值得推荐超声波清洗机

家用超声波清洗机可以干嘛呢&#xff1f;最常见的就是来清洗眼镜。眼镜党朋友应该经常接触超声波清洗机&#xff0c;它常出现在眼镜店中&#xff0c;眼镜店老板帮顾客清洗眼镜&#xff1b;也会出现在工业领域、医疗领域等&#xff0c;超声波清洗机使用范围还是挺广的&#xff0…

微信小程序 分享的两种方式:菜单级和按钮级

按钮级 在使用微信小程序的时候&#xff0c;我们可能会设计到一些视频的一些分享等&#xff0c;那么视频分享也分为两种方式,例如下图&#xff0c;当我们点击的时候&#xff0c;进行一个转发分享的一个操作 那么在原先代码的基础上&#xff0c;我们需要在原先代码的基础上butt…

Unity中动态合批

文章目录 前言一、动态合批的规则1、材质相同是合批的前提&#xff0c;但是如果是材质实例的话&#xff0c;则一样无法合批。2、支持不同网格的合批3、动态合批需要网格支持的顶点条件二、我们导入一个模型并且制作一个Shader&#xff0c;来测试动态合批1、我们选择模型的 Mesh…

电商API接口开发和接入说明{包含淘宝/京东/拼多多/抖音}

“为什么改了这个没告诉我” “实际功能和文档上说的不一样啊”。 这些话大家在进行电商API接口开发时&#xff0c;想必耳朵都听出老茧了。 真不是故意的&#xff0c;有时候任务比较急&#xff0c;就先改了代码&#xff0c;想着以后再同步文档&#xff0c;然后就给忘了。 项…

在Pycharm中使用GitHub的方法步骤

文章目录 前言一、配置Pycharm二、建立远程仓库并提交代码三、在github中查看上传的新仓库四、使用pycharm克隆github仓库五、在pycharm内进行git的相关操作关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源…

【C++】三大特性 --- 继承的详细讲解

目录 1.继承的概念及定义 1.1 继承的概念 1.2 继承定义 1.2.1定义格式 1.2.2继承关系和访问限定符 1.2.3继承基类成员访问方式的变化 2.基类和派生类对象赋值转换 3.继承中的作用域 4.派生类的默认成员函数 5.继承与友元 6.继承与静态成员 7.复杂的菱形继承及菱形虚…

从0到1构建智能分布式大数据爬虫系统

文章目录 1. 写在前面2. 数据获取挑战3. 基础架构4. 爬取管理5. 数据采集6. 增量与去重设计 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xff01; 【作者推荐…

win10的系统下实现SUSTechPOINTS环境搭建

** win10的 标题系统下实现SUSTechPOINTS环境搭建 ** 参考文档&#xff1a; doc/install_from_source.md 张金来/SUSTechPOINTS - Gitee.com 在win10的系统下搭建**SUSTechPOINTS环境 1 克隆代码 git clone https://github.com/naurril/SUSTechPOINTS2 安装环境 2.1 创…

【EtherCAT详解】基于Wireshark的EtherCAT帧结构解析

写在前面 EtherCAT的报文比较繁琐,且一些参考书籍错误较多,且晦涩难懂,对于初学者,很难快速的入门。本文适用于有一定基础的研究者,如对报文有一些研究、对canopen协议有一定了解、并且对TwinCAT有了解的研究者。当然,对于初学者来说,也是很好的引导,少走很多弯路。本…

css 字体添加外轮廓

color: #ffeb3b; -webkit-text-stroke: 10px transparent; background: linear-gradient(90deg,#5d3d02f5,#5d3d02f5,#5d3d02f5,#5d3d02f5,#5d3d02f5,#5d3d02f5,#5d3d02f5) top left / 100% 100%; -webkit-background-clip: text;

语义分割网络-FCN全卷积网络

全卷积神经网络FCN整体概述 FCN是首个端对端针对像素级预测的全卷积网络。FCN会用到分类网络作为backbone FCN的网络结构类比分类网络 分类网络经过卷积操作后&#xff0c;接全连接层&#xff0c;最后一个全连接层输出长度与分类类别数量相同&#xff0c;最后经过softmax得到术…

springMVC实验(五)——数据校验

【知识要点】 数据校验的概念 在软件开发过程中&#xff0c;数据校验是非常重要的环节&#xff0c;用于确保数据的有效性和完整性 。数据校验分为客户端验证和服务端验证&#xff0c;客户端验证是确保人机交互过程中用户操作表单过程中的误操作&#xff0c;由JavaScript代码完…

优化用户直播体验:第三方美颜SDK的前沿技术

当下&#xff0c;用户对于直播体验的要求日益提高&#xff0c;其中之一的重要方面就是实时美颜效果。第三方美颜SDK为直播平台和应用提供了强大的美颜功能&#xff0c;极大地改善了用户的直播观感。 一、背景与发展 过去&#xff0c;直播中的美颜往往依赖于主播或用户自行调整…

【深度学习】深度学习框架的环境配置

目录 1. 配置cuda环境 1.1. 安装cuda和cudnn 1.1.1. 显卡驱动配置 1.1.2. 下载安装cuda 1.1.3. 下载cudnn&#xff0c;将解压后文件复制到cuda目录下 1.2. 验证是否安装成功 2. 配置conda环境 2.1. 安装anaconda 2.2. conda换源 2.3. 创建conda环境 2.4. pip换源 3…