AI助力智慧农业,基于SSD模型开发构建田间作物场景下庄稼作物、杂草检测识别系统

智慧农业随着数字化信息化浪潮的演变有了新的定义,在前面的系列博文中,我们从一些现实世界里面的所见所想所感进行了很多对应的实践,感兴趣的话可以自行移步阅读即可:
《自建数据集,基于YOLOv7开发构建农田场景下杂草检测识别系统》 
《轻量级目标检测模型实战——杂草检测》
《激光除草距离我们实际的农业生活还有多远,结合近期所见所感基于yolov8开发构建田间作物杂草检测识别系统》
《基于yolov5的农作物田间杂草检测识别系统》
《AI助力智慧农业,基于YOLOv3开发构建农田场景下的庄稼作物、田间杂草智能检测识别系统》
《AI助力智慧农业,基于YOLOv4开发构建不同参数量级农田场景下庄稼作物、杂草智能检测识别系统》 
《AI助力智慧农业,基于YOLOv5全系列模型【n/s/m/l/x】开发构建不同参数量级农田场景下庄稼作物、杂草智能检测识别系统》
《AI助力智慧农业,基于YOLOv6最新版本模型开发构建不同参数量级农田场景下庄稼作物、杂草智能检测识别系统》
《AI助力智慧农业,基于YOLOv7【tiny/yolov7/yolov7x】开发构建不同参数量级农田场景下庄稼作物、杂草智能检测识别系统》 
《AI助力智慧农业,基于YOLOv8全系列模型【n/s/m/l/x】开发构建不同参数量级的识别系统》
《AI助力智慧农业,基于DETR【DEtection TRansformer】模型开发构建田间作物场景下庄稼作物、杂草检测识别系统》
自动化的激光除草,是未来大面积农业规划化作物种植生产过程中非常有效的技术手段,本文是AI助力智慧农业的第八篇系列博文,主要的目的就是想要基于SSD来开发构建检测模型,助力智能检测分析。
首先看下实例效果:

目标检测模型SSD(Single Shot Multibox Detector)是一种端到端的目标检测模型,能够在单次前向传播中同时预测目标的位置和类别。SSD将回归思想和锚框机制结合,消除了双阶段算法中候选区域生成和随后的像素或特征重采样阶段,并将所有计算封装在一个网络中,使其易于训练,速度较快。它将边界框的输出空间离散化为一组默认边框,这些框在不同层次的特征图上生成,而且有不同的长宽比。在预测时,网络预测每个默认边框中属于每个类别的可能性,使其紧致的包围目标。网络在多个具有不同分辨率的特征图上进行预测,可以处理各种大小的物体。
SSD网络可以分成特征提取和检测框生成两部分,特征提取采用的基础网络是从分类网络借鉴而来的。SSD采用VGG-16作为基础网络结构,使用VGG-16的前5层,将FC6和FC7层转化成两个卷积层。模型额外增加了3个卷积层和一个平均池化层。但是这样变化后,会改变感受野的大小,因此采用了扩张卷积。在裁剪的基础网络之后添加了卷积层,这些层的特征图大小是逐步减小的,从而实现在多尺度下进行预测。多尺度特征图包括conv4-3、conv7、conv8-2、conv9-2、conv10-2、conv11-2共6种尺度。SSD在每个添加的特征层上使用小的卷积核,预测一系列边框偏置。预测部分用于预测物体类别的置信度,并通过在特征图上使用小尺寸的卷积核来直接预测物体的边框坐标,因为预测是在6种不同的尺度下进行的,且每种尺度具有不同长宽比的锚框,所以能够提高目标检测的精度,而且整个算法可以进行端到端的训练,在检测速度上也有较大的优势。

SSD的算法构建原理如下:

  1. 提取特征:SSD首先使用一个卷积神经网络(CNN)如VGG或ResNet来提取输入图像的特征。这些特征图包含了不同层级的语义信息,能够帮助模型对不同尺寸和类别的目标进行检测。

  2. 多尺度检测:SSD在不同层级的特征图上应用了一系列卷积层和池化层,用于在不同尺度下检测目标。这种多尺度检测能够使模型更好地适应不同大小的目标。

  3. 预测边界框和类别:在每个特征图中,SSD使用卷积神经网络来预测边界框的位置和目标类别。针对每个位置和大小的锚框,SSD预测出与之匹配的目标边界框和对应的类别概率。

  4. 匹配策略:SSD通过匹配预测边界框和真实目标边界框之间的IoU(交并比)来确定哪些预测是有效的,并使用损失函数进行优化。

SSD的优点包括:

  • 高效性:SSD能够在单次前向传播中完成目标检测,速度较快。
  • 多尺度检测:SSD能够有效地检测不同大小的目标,适应多尺度目标检测的需求。
  • 简单直接:SSD采用了单一模型完成检测,简化了模型的复杂度。

SSD的缺点包括:

  • 定位精度较低:在小目标的定位上,SSD的精度可能受限。
  • 目标排斥问题:SSD中的锚框预设可能会导致多个检测结果之间的相互排斥,需要额外的处理来解决。

论文地址在这里,如下所示:

进一步的详情可以自行阅读论文。

官方项目地址在这里,如下所示:

项目提供了三种不同的Backbone网络可供使用,这里我们使用的是mobilenetv3,如下所示:

"""
Creates a MobileNetV3 Model as defined in:
Andrew Howard, Mark Sandler, Grace Chu, Liang-Chieh Chen, Bo Chen, Mingxing Tan, Weijun Wang, Yukun Zhu, Ruoming Pang, Vijay Vasudevan, Quoc V. Le, Hartwig Adam. (2019).
Searching for MobileNetV3
arXiv preprint arXiv:1905.02244.@ Credit from https://github.com/d-li14/mobilenetv3.pytorch
@ Modified by Chakkrit Termritthikun (https://github.com/chakkritte)"""import torch.nn as nn
import mathfrom ssd.modeling import registry
from ssd.utils.model_zoo import load_state_dict_from_urlmodel_urls = {'mobilenet_v3': 'https://github.com/d-li14/mobilenetv3.pytorch/raw/master/pretrained/mobilenetv3-large-1cd25616.pth',
}def _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_vclass h_sigmoid(nn.Module):def __init__(self, inplace=True):super(h_sigmoid, self).__init__()self.relu = nn.ReLU6(inplace=inplace)def forward(self, x):return self.relu(x + 3) / 6class h_swish(nn.Module):def __init__(self, inplace=True):super(h_swish, self).__init__()self.sigmoid = h_sigmoid(inplace=inplace)def forward(self, x):return x * self.sigmoid(x)class SELayer(nn.Module):def __init__(self, channel, reduction=4):super(SELayer, self).__init__()self.avg_pool = nn.AdaptiveAvgPool2d(1)self.fc = nn.Sequential(nn.Linear(channel, _make_divisible(channel // reduction, 8)),nn.ReLU(inplace=True),nn.Linear(_make_divisible(channel // reduction, 8), channel),h_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 * ydef conv_3x3_bn(inp, oup, stride):return nn.Sequential(nn.Conv2d(inp, oup, 3, stride, 1, bias=False),nn.BatchNorm2d(oup),h_swish())def conv_1x1_bn(inp, oup):return nn.Sequential(nn.Conv2d(inp, oup, 1, 1, 0, bias=False),nn.BatchNorm2d(oup),h_swish())class InvertedResidual(nn.Module):def __init__(self, inp, hidden_dim, oup, kernel_size, stride, use_se, use_hs):super(InvertedResidual, self).__init__()assert stride in [1, 2]self.identity = stride == 1 and inp == oupif inp == hidden_dim:self.conv = nn.Sequential(# dwnn.Conv2d(hidden_dim, hidden_dim, kernel_size, stride, (kernel_size - 1) // 2, groups=hidden_dim, bias=False),nn.BatchNorm2d(hidden_dim),h_swish() if use_hs else nn.ReLU(inplace=True),# Squeeze-and-ExciteSELayer(hidden_dim) if use_se else nn.Identity(),# pw-linearnn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),nn.BatchNorm2d(oup),)else:self.conv = nn.Sequential(# pwnn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False),nn.BatchNorm2d(hidden_dim),h_swish() if use_hs else nn.ReLU(inplace=True),# dwnn.Conv2d(hidden_dim, hidden_dim, kernel_size, stride, (kernel_size - 1) // 2, groups=hidden_dim, bias=False),nn.BatchNorm2d(hidden_dim),# Squeeze-and-ExciteSELayer(hidden_dim) if use_se else nn.Identity(),h_swish() if use_hs else nn.ReLU(inplace=True),# pw-linearnn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),nn.BatchNorm2d(oup),)def forward(self, x):if self.identity:return x + self.conv(x)else:return self.conv(x)class MobileNetV3(nn.Module):def __init__(self, mode='large', num_classes=1000, width_mult=1.):super(MobileNetV3, self).__init__()# setting of inverted residual blocksself.cfgs = [# k, t, c, SE, HS, s[3, 1, 16, 0, 0, 1],[3, 4, 24, 0, 0, 2],[3, 3, 24, 0, 0, 1],[5, 3, 40, 1, 0, 2],[5, 3, 40, 1, 0, 1],[5, 3, 40, 1, 0, 1],[3, 6, 80, 0, 1, 2],[3, 2.5, 80, 0, 1, 1],[3, 2.3, 80, 0, 1, 1],[3, 2.3, 80, 0, 1, 1],[3, 6, 112, 1, 1, 1],[3, 6, 112, 1, 1, 1],[5, 6, 160, 1, 1, 2],[5, 6, 160, 1, 1, 1],[5, 6, 160, 1, 1, 1]]assert mode in ['large', 'small']# building first layerinput_channel = _make_divisible(16 * width_mult, 8)layers = [conv_3x3_bn(3, input_channel, 2)]# building inverted residual blocksblock = InvertedResidualfor k, t, c, use_se, use_hs, s in self.cfgs:output_channel = _make_divisible(c * width_mult, 8)exp_size = _make_divisible(input_channel * t, 8)layers.append(block(input_channel, exp_size, output_channel, k, s, use_se, use_hs))input_channel = output_channel# building last several layerslayers.append(conv_1x1_bn(input_channel, exp_size))self.features = nn.Sequential(*layers)self.extras = nn.ModuleList([InvertedResidual(960, _make_divisible(960 * 0.2, 8), 512, 3, 2, True, True),InvertedResidual(512, _make_divisible(512 * 0.25, 8), 256, 3, 2, True, True),InvertedResidual(256, _make_divisible(256 * 0.5, 8), 256, 3, 2, True, True),InvertedResidual(256, _make_divisible(256 * 0.25, 8), 64, 3, 2, True, True),])self.reset_parameters()def forward(self, x):features = []for i in range(13):x = self.features[i](x)features.append(x)for i in range(13, len(self.features)):x = self.features[i](x)features.append(x)for i in range(len(self.extras)):x = self.extras[i](x)features.append(x)return tuple(features)def reset_parameters(self):for m in self.modules():if isinstance(m, nn.Conv2d):n = m.kernel_size[0] * m.kernel_size[1] * m.out_channelsm.weight.data.normal_(0, math.sqrt(2. / n))if m.bias is not None:m.bias.data.zero_()elif isinstance(m, nn.BatchNorm2d):m.weight.data.fill_(1)m.bias.data.zero_()elif isinstance(m, nn.Linear):n = m.weight.size(1)m.weight.data.normal_(0, 0.01)m.bias.data.zero_()@registry.BACKBONES.register('mobilenet_v3')
def mobilenet_v3(cfg, pretrained=True):model = MobileNetV3()if pretrained:model.load_state_dict(load_state_dict_from_url(model_urls['mobilenet_v3']), strict=False)return model

按照README操作即可基于自己的数据集来实现模型的开发流程,这里就不再赘述了,前面的文章中都有比较详细的介绍了。

训练完成后得到可用于推理的权重文件,可视化推理实例如下所示:

结果图像如下所示:

这里对其进行了格式化存储,如下所示:

{"crop": [[0.9846513271331787,[23,2,496,503]],[0.7338884472846985,[275,346,512,508]],[0.4537461996078491,[207,1,511,319]]]
}

方便后续后端业务系统进行解析使用,感兴趣的话也都可以动手实践下!


 

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

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

相关文章

Agility Robotics 为亚马逊仓库批量生产的人形机器人

一家旨在每年生产 10000 个两足机器人的革命性工厂即将在俄勒冈州塞勒姆成形。 这些机器人由 Agility Robotics 开发&#xff0c;旨在协助亚马逊等行业巨头运输、起重和处理危险货物。 Agility Robotics 表示&#xff0c;其名为 RoboFab 的新制造工厂将成为世界上第一个大规模…

计算整数各位数字之和 C语言xdoj29

时间限制: 1 S 内存限制: 1000 Kb 问题描述: 假设n是一个由最多9位数字&#xff08;d9, …, d1&#xff09;组成的正整数。编写一个程序计算n的每一位数字之和 输入说明: 输入数据为一个正整数n 输出说明: 对整数n输出它的各位数字之和后换行 输入样例: …

【已解决】AttributeError: ‘DataFrame‘ object has no attribute ‘append‘

问题描述 AttributeError: ‘DataFrame‘ object has no attribute ‘append‘ 解决办法 原因是pandas版本升级弃用了&#xff0c;在老版本DataFrame的append方法。由于pandas与众多的第三方软件包捆绑&#xff0c;一般不宜轻易降低其版本号。故采用使用pandas的concat()方法将…

Java最全面试题专题---1、Java基础知识(1)

笔者有七八年的面试者经验&#xff0c;负责公司技术同学的社招和校招&#xff0c;近些年面试过三四百个技术同学&#xff0c;考虑接近年底这个时段&#xff0c;整理并更新一些以往的面试经验&#xff0c;希望同学们跳槽能有个更好的工作&#xff0c;如有需要的同学可以关注下笔…

水库大坝安全监测参数与设备

智慧水利中&#xff0c;水库大坝的安全监测必不可少。做好水库大坝的安全监测&#xff0c;是确保水库大坝结构安全和预防灾害的重要手段。对于预防灾害、保护人民生命财产安全、优化工程管理、改进工程设计、保护环境资源和提高公众信任等方面有着重要的意义。 水利水库大坝安全…

MacOS VSCode 配置远程服务器ssh remote链接,并上传文件文件服务器

环境&#xff1a; MacOS & VSCode & ssh remote 1. VSCode安装插件 2. 配置ssh remote链接 Host 10.128.200.101HostName 10.128.200.101User rootForwardAgent yesIdentityFile ~/.ssh/id_rsa # 服务器免密登录本地秘钥文件路径 配置完保存&#xff1b; 3. 在ssh…

力扣题:字符的统计-12.7

力扣题-12.7 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;467. 环绕字符串中唯一的子字符串 解题思想&#xff1a;记录下以字母s[i]结尾的最大的字串个数&#xff0c;然后统计a-z每个字母结尾的最大字串的个数进行i相加 class Solution(object…

2021年第十届数学建模国际赛小美赛B题疾病传播的风险解题全过程文档及程序

2021年第十届数学建模国际赛小美赛 B题 疾病传播的风险 原题再现&#xff1a; 空气传播疾病可以通过咳嗽或打喷嚏、喷洒液体或灰尘传播。另一方面&#xff0c;一些常见的传染病只能通过飞沫传播。请建立一个模型&#xff0c;以评估密闭空间内空气传播和液滴传播疾病的可能性。…

hive-3.1.2环境安装实验

1.修改hadoop相关参数 1-修改core-site.xml [bigdata@master hive]$ vim /opt/module/hadoop/etc/hadoop/core-site.xml <!-- 配置该bigdata(superUser)允许通过代理访问的主机节点 --><property><name>hadoop.proxyuser.bigdata.hosts</name><va…

STM32F1的TIM输出比较(PWM)

目录 1. OC&#xff08;Output Compare&#xff09;输出比较 2. PWM简介 3. 输出比较通道(高级) 4. 输出比较通道(通用) 5. PWM基本结构 6. 配置介绍 6.1 输出比较模块配置 6.2 给输出比较结构体赋一个默认值 6.3 配置强制输出模式 6.4 配置CRR寄存器的预装…

【复杂gRPC之Java调用go】

1 注意点 一般上来说如果java调用java的话&#xff0c;我们可以使用springcloud来做&#xff0c;而面对这种跨语言的情况下&#xff0c;gRPC就展现出了他的优势。 代码放在这了&#xff0c;请结合前面的go服务器端一起使用 https://gitee.com/guo-zonghao/java-client-grpc /…

【Git】error:failed to push some refs to ‘git@gitee.com:name/project.git‘

错误展示 今天在版本回退的时候&#xff0c;推送到gitee显示如下错误 先执行了git pull origin master&#xff0c;然后再执行push操作&#xff0c;也没有用 解决办法 执行git push -f origin master ,-f 表示强制推送。 结果 问题解决啦&#xff01;