【Intel校企合作课程】基于ResNet50的杂草检测

2024-03-20 14:30

本文主要是介绍【Intel校企合作课程】基于ResNet50的杂草检测,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


目录

  • 1.项目简介
    • 1.1项目描述
    • 1.2数据集展示
    • 1.3部分图像展示
    • 1.4预期处理方案
  • 2.数据预处理
    • 2.1 数据集结构
    • 2.2数据集提取
    • 2.3构建数据集
  • 3.使用ResNet50残差神经网络识别杂草
    • 3.1ResNet网络简介
    • 3.2ResNet50网络模型简介
    • 3.3查看Pytorch提供的ResNet50模型
    • 3.3自己定义ResNet50网络模型
    • 3.4使用Pytorch提供的ResNet50预训练模型进行训练
    • 3.5使用OneAPI组件进行加速
  • 4.模型训练(迭代二十次)
  • 5.计算推理时间和二分类准确度(F1分数)
  • 6.模型预测
  • 7.OneAPI组件的使用
  • 8.项目总结

1.项目简介

1.1项目描述

杂草是农业经营中不受欢迎的入侵者,它们通过窃取营养、水、土地和其他关键资源来破坏种植,这些入侵者会导致产量下降和资源部署效率低下。一种已知的方法是使用杀虫剂来清除杂草,但杀虫剂会给人类带来健康风险。我们的目标是利用计算机视觉技术可以自动检测杂草的存在,开发一种只在杂草上而不是在作物上喷洒农药的系统,并使用针对性的修复技术将其从田地中清除,从而最小化杂草对环境的负面影响。

1.2数据集展示

数据集链接:https://filerepo.idzcn.com/hack2023/Weed_Detection5a431d7.zip

1.3部分图像展示

杂草图像:
在这里插入图片描述
标签:1 0.508789 0.489258 0.869141 0.861328
作物图像:
在这里插入图片描述
标签:0 0.478516 0.560547 0.847656 0.625000

1.4预期处理方案

我们期待您将其部署到模拟的生产环境中——这里推理时间和二分类准确度(F1分数)将作为评分的主要依据。

2.数据预处理

2.1 数据集结构

本项目数据集共由两部分组成,分别包含文件夹data和classes.txt。
在这里插入图片描述

data文件夹下包含了杂草和作物的图像以及它们的标签数据,如果标签是1开头则它就是杂草是0开头为作物。
在这里插入图片描述

2.2数据集提取

将文件名写入data.txt中:

# 指定图片所在的文件夹路径
image_folder = '../Weed_detection/data'# 获取文件夹下所有以.jpeg结尾的文件
image_files = [f for f in os.listdir(image_folder) if f.endswith('.jpeg') ]# 提取文件名的前缀并保存到data.txt
with open('../Weed_detection/data.txt', 'w') as file:for filename in image_files:# 获取文件名的前缀prefix = os.path.splitext(filename)[0]# 写入前缀到data.txt文件file.write(prefix + '\n')

提取部分结果展示:
在这里插入图片描述
对图片数据进行预处理,并将处理后的数据分为训练集和测试集。

transformer = transforms.Compose([transforms.ToTensor(),transforms.ColorJitter(contrast=0.5),  # 增强对比度transforms.Normalize(mean=[0.5], std=[0.5])  # 归一化
])train_images_tensor = []
with open(r'../Weed_detection/data.txt','r') as f:file_name_url=[i.split('\n')[0] for i in f.readlines()]
for i in range(len(file_name_url)):image = Image.open('../Weed_detection/data/'+file_name_url[i]+'.jpeg')tensor = transformer(image.convert('L')).type(torch.float16)train_images_tensor.append(tensor)
image_train = []
image_test = []
for i in range(len(train_images_tensor)):if i <=len(train_images_tensor)*0.7:image_train.append(train_images_tensor[i])else:image_test.append(train_images_tensor[i])优化代码

读取文本文件中的标签数据,并将其转换为PyTorch张量格式,最后将数据分为训练集和测试集。

transformerlab = transforms.Compose([transforms.ToTensor()
])train_lables_tensor = []
with open(r'../Weed_detection/data.txt','r') as f:file_name_url=[i.split('\n')[0] for i in f.readlines()]
train_lables_tensor = []for i in range(len(file_name_url)):image = open('../Weed_detection/data/' + file_name_url[i] + '.txt')labels = image.readline()[0]labels = float(labels)tensor = torch.tensor(labels, dtype=torch.float16)  # 使用float16数据类型train_lables_tensor.append(tensor)lables_train = []
lables_test = []
for i in range(len(train_lables_tensor)):if i <=len(train_lables_tensor)*0.7:lables_train.append(train_lables_tensor[i])else:lables_test.append(train_lables_tensor[i])

2.3构建数据集

rain_datas_tensor = torch.stack(image_train)
train_labels_tensor = torch.stack(lables_train)
test_datas_tensor = torch.stack(image_test)
test_labels_tensor = torch.stack(lables_test)
train_dataset = TensorDataset(train_labels_tensor, train_datas_tensor)
train_dataloader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_dataset = TensorDataset(test_labels_tensor, test_datas_tensor)
test_dataloader = DataLoader(test_dataset, batch_size=32, shuffle=True)

3.使用ResNet50残差神经网络识别杂草

3.1ResNet网络简介

残差连接通常以跳跃连接的形式实现,即将某一层的输出直接连接到下一层的输入。通过这种方式,网络的每一层都可以得到其输入和上一层输出的组合,从而增加了网络的非线性表达能力。如下图所示,假设输入图像为 x,输出为H(x),中间经过卷积之后的输出为F(x)的非线性函数,那最终的输出为H(x) = F(x) + x,这样的输出仍然可以进行非线性变换,残差指的是“差”,也就是F(x),而网络也就转化为求残差函数F(x) = H(x) - x,这样残差函数要比 F(x) = H (x) 更加容易优化。残差神经网络具有易于优化、能够有效训练深层的优点,因此在计算机视觉、自然语言处理等领域得到了广泛应用。
在这里插入图片描述

3.2ResNet50网络模型简介

如下图所展示的网络模型所示,ResNet50网络总共有50层分别是49层卷积层和1层全连接层。网络的输入是224x224x3,经过前面5部分的卷积计算可以得到7x7x2048,因为全连接层的输入不能直接是多维图像所以要将其转化为一个一维的特征向量,最后分类器对这个特征向量进行计算并输出类别的概率。
在这里插入图片描述

3.3查看Pytorch提供的ResNet50模型

model = models.resnet50(pretrained=True)
model.eval() # 设置模型为评估模式  # 打印模型结构  
print(model)

残差网络结构:输入➡ 卷积层 ➡ 标准化层 ➡ 激活层 ➡ 最大池化层 ➡ 4个残差网络模块 ➡ 全局平均池化层 ➡ 全连接层 ➡输出
Pytorch提供的ResNet50网络结构:
在这里插入图片描述
卷积层:
卷积层
标准化层:
在这里插入图片描述
激活层:
在这里插入图片描述
最大池化层:
在这里插入图片描述
Stage1有3个残差块:
在这里插入图片描述
Stage2有4个残差块:
在这里插入图片描述
在这里插入图片描述
Stage3有6个残差块:
在这里插入图片描述
在这里插入图片描述
Stage4有3个残差块:
在这里插入图片描述
全局平均池化层:
在这里插入图片描述
全连接层:
在这里插入图片描述

3.3自己定义ResNet50网络模型

import torch  
import torch.nn as nn  
import torch.nn.functional as F  class BasicBlock(nn.Module):  expansion = 1  def __init__(self, in_channels, out_channels, stride=1):  super(BasicBlock, self).__init__()  self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)  self.bn1 = nn.BatchNorm2d(out_channels)  self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)  self.bn2 = nn.BatchNorm2d(out_channels)  self.shortcut = nn.Sequential()  if stride != 1 or in_channels != self.expansion*out_channels:  self.shortcut = nn.Sequential(  nn.Conv2d(in_channels, self.expansion*out_channels, kernel_size=1, stride=stride, bias=False),  nn.BatchNorm2d(self.expansion*out_channels)  )  def forward(self, x):  out = F.relu(self.bn1(self.conv1(x)))  out = self.bn2(self.conv2(out))  out += self.shortcut(x)  out = F.relu(out)  return out  class ResNet(nn.Module):  def __init__(self, block, num_blocks, num_classes=1000):  super(ResNet, self).__init__()  self.in_channels = 64  self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)  self.bn1 = nn.BatchNorm2d(64)  self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)  self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)  self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)  self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)  self.fc = nn.Linear(512*block.expansion, num_classes)  def _make_layer(self, block, out_channels, num_blocks, stride):  layers = []  layers.append(block(self.in_channels, out_channels, stride))  self.in_channels = out_channels * block.expansion  for i in range(1, num_blocks):  layers.append(block(self.in_channels, out_channels))  return nn.Sequential(*layers)  def forward(self, x):  out = F.relu(self.bn1(self.conv1(x)))  out = self.layer1(out)  out = self.layer2(out)  out = self.layer3(out)  out = self.layer4(out)  out = F.avg_pool2d(out, 4) # change to global pooling if needed  out = out.view(out.size(0), -1) # flatten the tensor to pass to fully connected layer  out = self.fc(out) # fully connected layer (output layer) with softmax activation (if needed)  return out

3.4使用Pytorch提供的ResNet50预训练模型进行训练

首先加载预训练的ResNet-50模型,更改第一个卷积层

# 加载预训练的ResNet-50模型  
net = models.resnet50(pretrained=True)  # 更改第一个卷积层的输入通道数  
net.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False)  # 获取最后一个全连接层的输入特征数  
num_features = net.fc.in_features  # 替换最后一层全连接层为2个输出单元  
net.fc = nn.Linear(num_features, 2)  # 添加Softmax激活函数  
net.add_module("softmax", nn.Softmax(dim=1))  device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")  
net.to(device)  
net.float()  criterion = nn.CrossEntropyLoss()  
# 使用Adam优化器  
optimizer = torch.optim.Adam(net.parameters(), lr=0.001)  

3.5使用OneAPI组件进行加速

# 使用IPEX优化器优化模型  
net,optimizer = ipex.optimize(net,optimizer=optimizer)

4.模型训练(迭代二十次)

for epoch in range(1, 20):running_loss = 0.0num_images = 0loop = tqdm(enumerate(train_dataloader, 0))for step, data in loop:labels, inputs = data[0].float(), data[1].float()optimizer.zero_grad()inputs = inputs.float()outputs = net(inputs)# 创建包含相同数量的目标值的示例目标张量target = labels  # 使用实际标签作为目标# 使用 MSE 损失函数loss = criterion(outputs, target.long())loss.backward()optimizer.step()num_images += inputs.size(0)running_loss += loss.item()loop.set_description(f'Epoch [{epoch}/10]')loop.set_postfix(loss=running_loss / (step + 1))print('Compete training!!!')

在这里插入图片描述

5.计算推理时间和二分类准确度(F1分数)

因为电脑不是NVIDIA显卡不支持cuda环境所以无法使用GPU进行训练,只能用CPU训练时间较长。

from sklearn.metrics import f1_score
import time
correct = 0
total = 0
all_predictions = []
all_labels = []                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
# 开始推理
start_time = time.time()
with torch.no_grad():for data in test_dataloader:images, labels = data[1].to('cpu').float(), data[0].to('cpu').long()  # 将标签转换为整数类型net = net.float() outputs = net(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item() all_predictions.extend(predicted.cpu().numpy())all_labels.extend(labels.cpu().numpy())
accuracy = 100 * correct / total
# 计算推理时间
inference_time = time.time() - start_time
print(f'Accuracy on test set: {accuracy:.2f}%')
print(f"Inference Time: {inference_time} seconds")
f1 = f1_score(all_labels, all_predictions, average='binary')  # 适用于二分类问题
print(f'F1分数为: {f1:.4f}')

平均精度在97%以上
在这里插入图片描述

6.模型预测

from PIL import Image  
import matplotlib.pyplot as plt  
import numpy as np  
import torchvision.transforms.functional as TF  
import torch 
import matplotlib.image as mpimg# 保存模型  
PATH = './model_weights.pth'  
net.load_state_dict(torch.load(PATH))  # 加载一张图片进行测试  
image_path = 'data/agri_0_9952.jpeg'
image = Image.open(image_path).convert('L')  # 替换为你的图片路径  
image = TF.to_tensor(image)  # 将图片转换为tensor  
image = image.unsqueeze(0)  # 添加批处理维度  
image = image.to('cpu')  # 转移到GPU上  # 在图片上进行预测  
with torch.no_grad():  outputs = net(image)  # outputs为预测结果,即各个类别的概率分布  _, predicted = torch.max(torch.abs(outputs), 1)# 获取概率最高的类别作为预测结果  print('Predicted:', predicted.item())  # 打印预测结果  if predicted.item() == 0:  print('判断结果:作物')  elif predicted.item() == 1:  print('判断结果:杂草')  else:  print('预测结果不在0和1之间,可能存在错误')# 读取图片  
img = mpimg.imread(image_path)  # 显示图片  
plt.imshow(img)  
plt.show()

预测结果与标签一致
在这里插入图片描述

在这里插入图片描述

7.OneAPI组件的使用

OneAPI Math Kernel Library (MKL):ntel的数学核心函数库,包含一系列优化的数学函数,用于高性能计算和机器学习应用。
OneDNN:这是Intel的另一个高性能计算库,专门为深度学习应用提供优化。它提供了各种深度学习相关的操作,如卷积、池化、归一化等,都经过优化以提高运行速度。

8.项目总结

有很多模型都可以运用到杂草检测的案例中,本次使用的模型是ResNet50。通过自己重新搭建ResNet50的网络结构,对于这个模型也更加了解。使用了OneAPI组件进行加速,让推理时间有了一个很明显的减少。这次涉及到的组件主要是OneAPI Math Kernel Library和OneDNN,还有很多其它的组件没有使用到,后面也会去深入学习其他组件将它们更好的运用在项目中。

这篇关于【Intel校企合作课程】基于ResNet50的杂草检测的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

烟火目标检测数据集 7800张 烟火检测 带标注 voc yolo

一个包含7800张带标注图像的数据集,专门用于烟火目标检测,是一个非常有价值的资源,尤其对于那些致力于公共安全、事件管理和烟花表演监控等领域的人士而言。下面是对此数据集的一个详细介绍: 数据集名称:烟火目标检测数据集 数据集规模: 图片数量:7800张类别:主要包含烟火类目标,可能还包括其他相关类别,如烟火发射装置、背景等。格式:图像文件通常为JPEG或PNG格式;标注文件可能为X

基于 YOLOv5 的积水检测系统:打造高效智能的智慧城市应用

在城市发展中,积水问题日益严重,特别是在大雨过后,积水往往会影响交通甚至威胁人们的安全。通过现代计算机视觉技术,我们能够智能化地检测和识别积水区域,减少潜在危险。本文将介绍如何使用 YOLOv5 和 PyQt5 搭建一个积水检测系统,结合深度学习和直观的图形界面,为用户提供高效的解决方案。 源码地址: PyQt5+YoloV5 实现积水检测系统 预览: 项目背景

JavaFX应用更新检测功能(在线自动更新方案)

JavaFX开发的桌面应用属于C端,一般来说需要版本检测和自动更新功能,这里记录一下一种版本检测和自动更新的方法。 1. 整体方案 JavaFX.应用版本检测、自动更新主要涉及一下步骤: 读取本地应用版本拉取远程版本并比较两个版本如果需要升级,那么拉取更新历史弹出升级控制窗口用户选择升级时,拉取升级包解压,重启应用用户选择忽略时,本地版本标志为忽略版本用户选择取消时,隐藏升级控制窗口 2.

[数据集][目标检测]血细胞检测数据集VOC+YOLO格式2757张4类别

数据集格式:Pascal VOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2757 标注数量(xml文件个数):2757 标注数量(txt文件个数):2757 标注类别数:4 标注类别名称:["Platelets","RBC","WBC","sickle cell"] 每个类别标注的框数:

Temu官方宣导务必将所有的点位材料进行检测-RSL资质检测

关于饰品类产品合规问题宣导: 产品法规RSL要求 RSL测试是根据REACH法规及附录17的要求进行测试。REACH法规是欧洲一项重要的法规,其中包含许多对化学物质进行限制的规定和高度关注物质。 为了确保珠宝首饰的安全性,欧盟REACH法规规定,珠宝首饰上架各大电商平台前必须进行RSLReport(欧盟禁限用化学物质检测报告)资质认证,以确保产品不含对人体有害的化学物质。 RSL-铅,

《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》P98

更改为 差分的数学表达式从泰勒级数展开式可得: 后悔没听廖老师的。 禹晶、肖创柏、廖庆敏《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》 禹晶、肖创柏、廖庆敏《数字图像处理》资源二维码

YOLOv8/v10+DeepSORT多目标车辆跟踪(车辆检测/跟踪/车辆计数/测速/禁停区域/绘制进出线/绘制禁停区域/车道车辆统计)

01:YOLOv8 + DeepSort 车辆跟踪 该项目利用YOLOv8作为目标检测模型,DeepSort用于多目标跟踪。YOLOv8负责从视频帧中检测出车辆的位置,而DeepSort则负责关联这些检测结果,从而实现车辆的持续跟踪。这种组合使得系统能够在视频流中准确地识别并跟随特定车辆。 02:YOLOv8 + DeepSort 车辆跟踪 + 任意绘制进出线 在此基础上增加了用户

独立按键单击检测(延时消抖+定时器扫描)

目录 独立按键简介 按键抖动 模块接线 延时消抖 Key.h Key.c 定时器扫描按键代码 Key.h Key.c main.c 思考  MultiButton按键驱动 独立按键简介 ​ 轻触按键相当于一种电子开关,按下时开关接通,松开时开关断开,实现原理是通过轻触按键内部的金属弹片受力弹动来实现接通与断开。  ​ 按键抖动 由于按键内部使用的是机