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

本文主要是介绍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曲线】

【混淆矩阵】

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

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

这篇关于python基于轻量级卷积神经网络模型ShuffleNetv2开发构建辣椒病虫害图像识别系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/460783

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof