0


基于深度学习CNN算法的植物/中草药分类识别系统01--带数据集-pyqt5UI界面-全套源码

文章目录

各位同学大家好,本次给大家分享的项目为:

基于深度学习算法的植物/中草药分类识别系统

一、项目摘要

本项目设计并实现一个基于深度学习算法的植物识别系统。该系统采用Mobilenet深度学习模型,利用网络采集的一个包含67类植物、共6877张图像的数据集,结合Pytorch框架进行模型训练和优化,通过准确率、损失值和混淆矩阵三种评价指标,验证了该系统的识别性能,并使用pyqt5库设计了图形用户界面(GUI),实现了便捷的植物识别和结果展示功能。

二、项目运行效果

运行效果视频:
https://www.bilibili.com/video/BV1QgtVeDEDq

运行效果截图:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、项目文件介绍

在这里插入图片描述

四、项目环境配置

1、项目环境库

  1. python=3.8 pytorch pyqt5 opencv matplotlib

2、环境配置视频教程

1)anaconda下载安装教程
2)pycharm下载安装教程
3)项目环境库安装步骤教程

五、项目系统架构

在这里插入图片描述

该系统的主要功能模块如下:

  1. 图像选择与上传模块: 用户界面的主页提供了一个“选择图像”按钮,用户点击后可以从本地设备选择需要识别的植物图像。系统支持常见的图像格式(如JPEG、PNG等),并将所选图像显示在界面中央,方便用户确认。
  2. 图像处理与识别模块:当用户上传图像后,点击“开始检测”按钮,系统会调用Mobilenet模型对图像进行处理和识别。系统将在后台运行深度学习推断过程,识别时间较短,通常在几秒内完成。2.1 图像处理模块: 用户上传图像后,系统会对输入的植物图像进行预处理。具体步骤包括: 1)图像的尺寸调整:将输入图像的尺寸调整为模型所需的大小,即224×224像素。 2)图像标准化:按照ImageNet预训练模型的标准,对图像的像素值进行归一化处理。2.2 模型预测模块经过处理的图像输入到预训练的Mobilenet模型中进行预测。该系统采用了在Pytorch框架上训练的Mobilenet 模型,该模型能够在计算资源有限的环境中实现高效的植物识别。模型加载了之前在训练集上获得的最佳权重文件,并进行推断操作,输出分类结果。
  3. 识别结果展示模块:识别完成后,系统会在界面的结果区域显示植物的名称、分类置信度以及对应的植物详细信息

六、项目构建流程

1、数据集

数据集文件夹:all_data

在这里插入图片描述
在这里插入图片描述
概述:

在本系统中,使用了一个从网络上收集的植物图像数据集,包含67类不同种类的植物,共计6877张图像。

在这里插入图片描述
数据集格式及命令统一代码:to_rgb.py
(对数据集中的图像统一成rgb格式并进行统一规范命名)

在这里插入图片描述

2、算法网络Mobilenet

概述:
Mobilenet是专为移动设备和嵌入式系统设计的轻量化卷积神经网络。其主要特点在于采用了深度可分离卷积(Depthwise Separable Convolution)来减少计算量和参数数量,从而在资源受限的环境下实现高效的图像分类和识别。
在这里插入图片描述
算法代码为:models文件夹下的mobilenet.py

在这里插入图片描述

  1. """mobilenet in pytorch
  2. [1] Andrew G. Howard, Menglong Zhu, Bo Chen, Dmitry Kalenichenko, Weijun Wang, Tobias Weyand, Marco Andreetto, Hartwig Adam
  3. MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications
  4. https://arxiv.org/abs/1704.04861
  5. """import torch
  6. import torch.nn as nn
  7. classDepthSeperabelConv2d(nn.Module):def__init__(self, input_channels, output_channels, kernel_size,**kwargs):super().__init__()
  8. self.depthwise = nn.Sequential(
  9. nn.Conv2d(
  10. input_channels,
  11. input_channels,
  12. kernel_size,
  13. groups=input_channels,**kwargs),
  14. nn.BatchNorm2d(input_channels),
  15. nn.ReLU(inplace=True))
  16. self.pointwise = nn.Sequential(
  17. nn.Conv2d(input_channels, output_channels,1),
  18. nn.BatchNorm2d(output_channels),
  19. nn.ReLU(inplace=True))defforward(self, x):
  20. x = self.depthwise(x)
  21. x = self.pointwise(x)return x
  22. classBasicConv2d(nn.Module):def__init__(self, input_channels, output_channels, kernel_size,**kwargs):super().__init__()
  23. self.conv = nn.Conv2d(
  24. input_channels, output_channels, kernel_size,**kwargs)
  25. self.bn = nn.BatchNorm2d(output_channels)
  26. self.relu = nn.ReLU(inplace=True)defforward(self, x):
  27. x = self.conv(x)
  28. x = self.bn(x)
  29. x = self.relu(x)return x
  30. classMobileNet(nn.Module):def__init__(self, width_multiplier=1, class_num=100):super().__init__()
  31. alpha = width_multiplier
  32. self.stem = nn.Sequential(
  33. BasicConv2d(3,int(32* alpha),3, padding=1, bias=False),
  34. DepthSeperabelConv2d(int(32* alpha),int(64* alpha),3,
  35. padding=1,
  36. bias=False))#downsample
  37. self.conv1 = nn.Sequential(
  38. DepthSeperabelConv2d(int(64* alpha),int(128* alpha),3,
  39. stride=2,
  40. padding=1,
  41. bias=False),
  42. DepthSeperabelConv2d(int(128* alpha),int(128* alpha),3,
  43. padding=1,
  44. bias=False))#downsample
  45. self.conv2 = nn.Sequential(
  46. DepthSeperabelConv2d(int(128* alpha),int(256* alpha),3,
  47. stride=2,
  48. padding=1,
  49. bias=False),
  50. DepthSeperabelConv2d(int(256* alpha),int(256* alpha),3,
  51. padding=1,
  52. bias=False))#downsample
  53. self.conv3 = nn.Sequential(
  54. DepthSeperabelConv2d(int(256* alpha),int(512* alpha),3,
  55. stride=2,
  56. padding=1,
  57. bias=False),
  58. DepthSeperabelConv2d(int(512* alpha),int(512* alpha),3,
  59. padding=1,
  60. bias=False),
  61. DepthSeperabelConv2d(int(512* alpha),int(512* alpha),3,
  62. padding=1,
  63. bias=False),
  64. DepthSeperabelConv2d(int(512* alpha),int(512* alpha),3,
  65. padding=1,
  66. bias=False),
  67. DepthSeperabelConv2d(int(512* alpha),int(512* alpha),3,
  68. padding=1,
  69. bias=False),
  70. DepthSeperabelConv2d(int(512* alpha),int(512* alpha),3,
  71. padding=1,
  72. bias=False))#downsample
  73. self.conv4 = nn.Sequential(
  74. DepthSeperabelConv2d(int(512* alpha),int(1024* alpha),3,
  75. stride=2,
  76. padding=1,
  77. bias=False),
  78. DepthSeperabelConv2d(int(1024* alpha),int(1024* alpha),3,
  79. padding=1,
  80. bias=False))
  81. self.fc = nn.Linear(int(1024* alpha), class_num)
  82. self.avg = nn.AdaptiveAvgPool2d(1)defforward(self, x):
  83. x = self.stem(x)
  84. x = self.conv1(x)
  85. x = self.conv2(x)
  86. x = self.conv3(x)
  87. x = self.conv4(x)
  88. x = self.avg(x)
  89. x = x.view(x.size(0),-1)
  90. x = self.fc(x)return x
  91. defmobilenet(alpha=1, class_num=67):return MobileNet(alpha, class_num)

3、网络模型训练

训练代码为:train.py

  • 超参数设置:输入图像尺寸:224×224。
  • 优化器和损失函数:采用AdamW优化器,学习率设定为0.0001,损失函数为交叉熵损失函数。
  • 训练轮数(Epoch):模型训练共进行了300个epoch,每个epoch结束时,计算训练集和验证集的准确率,保存验证集准确率最高时的模型。(可自行修改)
  • 批次大小(Batch Size):16。(可自行修改)
  • 学习率衰减:在训练过程中,采用学习率衰减策略,确保在模型逐渐收敛的过程中保持适当的更新步长。在这里插入图片描述
  1. import os
  2. import argparse
  3. import torch
  4. import torch.optim as optim
  5. import matplotlib.pyplot as plt
  6. from torch.utils.tensorboard import SummaryWriter
  7. from torchvision import transforms
  8. from my_dataset import MyDataSet
  9. from models.mobilenet import mobilenet as create_model
  10. from utils import read_split_data, train_one_epoch, evaluate
  11. defdraw(train, val, ca):
  12. plt.rcParams['font.sans-serif']=['Microsoft YaHei']
  13. plt.rcParams['axes.unicode_minus']=False
  14. plt.cla()# 清空之前绘图数据
  15. plt.title('精确度曲线图'if ca =="acc"else'损失值曲线图')
  16. plt.plot(train, label='train_{}'.format(ca))
  17. plt.plot(val, label='val_{}'.format(ca))
  18. plt.legend()
  19. plt.grid()
  20. plt.savefig('精确度曲线图'if ca =="acc"else'损失值曲线图')# plt.show()defmain(args):
  21. device = torch.device(args.device if torch.cuda.is_available()else"cpu")if os.path.exists("./weights")isFalse:
  22. os.makedirs("./weights")
  23. tb_writer = SummaryWriter()
  24. train_images_path, train_images_label, val_images_path, val_images_label = read_split_data(args.data_path)
  25. img_size =224
  26. data_transform ={"train": transforms.Compose([transforms.RandomResizedCrop(img_size),
  27. transforms.RandomHorizontalFlip(),
  28. transforms.ToTensor(),
  29. transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])]),"val": transforms.Compose([transforms.Resize(int(img_size *1.143)),
  30. transforms.CenterCrop(img_size),
  31. transforms.ToTensor(),
  32. transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])])}# 实例化训练数据集
  33. train_dataset = MyDataSet(images_path=train_images_path,
  34. images_class=train_images_label,
  35. transform=data_transform["train"])# 实例化验证数据集
  36. val_dataset = MyDataSet(images_path=val_images_path,
  37. images_class=val_images_label,
  38. transform=data_transform["val"])
  39. batch_size = args.batch_size
  40. nw =min([os.cpu_count(), batch_size if batch_size >1else0,8])# number of workersprint('Using {} dataloader workers every process'.format(nw))
  41. train_loader = torch.utils.data.DataLoader(train_dataset,
  42. batch_size=batch_size,
  43. shuffle=True,
  44. pin_memory=True,
  45. num_workers=nw,
  46. collate_fn=train_dataset.collate_fn)
  47. val_loader = torch.utils.data.DataLoader(val_dataset,
  48. batch_size=batch_size,
  49. shuffle=False,
  50. pin_memory=True,
  51. num_workers=nw,
  52. collate_fn=val_dataset.collate_fn)
  53. model = create_model(class_num=67).to(device)if args.weights !="":assert os.path.exists(args.weights),"weights file: '{}' not exist.".format(args.weights)
  54. model.load_state_dict(torch.load(args.weights, map_location=device))if args.freeze_layers:for name, para in model.named_parameters():# head外,其他权重全部冻结if"head"notin name:
  55. para.requires_grad_(False)else:print("training {}".format(name))
  56. pg =[p for p in model.parameters()if p.requires_grad]
  57. optimizer = optim.AdamW(pg, lr=args.lr, weight_decay=5E-2)for epoch inrange(args.epochs):# train
  58. train_loss, train_acc = train_one_epoch(model=model,
  59. optimizer=optimizer,
  60. data_loader=train_loader,
  61. device=device,
  62. epoch=epoch)# validate
  63. val_loss, val_acc = evaluate(model=model,
  64. data_loader=val_loader,
  65. device=device,
  66. epoch=epoch)
  67. train_acc_list.append(train_acc)
  68. train_loss_list.append(train_loss)
  69. val_acc_list.append(val_acc)
  70. val_loss_list.append(val_loss)
  71. tags =["train_loss","train_acc","val_loss","val_acc","learning_rate"]
  72. tb_writer.add_scalar(tags[0], train_loss, epoch)
  73. tb_writer.add_scalar(tags[1], train_acc, epoch)
  74. tb_writer.add_scalar(tags[2], val_loss, epoch)
  75. tb_writer.add_scalar(tags[3], val_acc, epoch)
  76. tb_writer.add_scalar(tags[4], optimizer.param_groups[0]["lr"], epoch)if val_acc ==max(val_acc_list):print('save-best-epoch:{}'.format(epoch))withopen('loss.txt','w')as fb:
  77. fb.write(str(train_loss)+','+str(train_acc)+','+str(val_loss)+','+str(val_acc))
  78. torch.save(model.state_dict(),"./weights/plant-best-epoch.pth")if __name__ =='__main__':
  79. parser = argparse.ArgumentParser()
  80. parser.add_argument('--num_classes',type=int, default=67)
  81. parser.add_argument('--epochs',type=int, default=300)
  82. parser.add_argument('--batch-size',type=int, default=16)
  83. parser.add_argument('--lr',type=float, default=0.0001)# 数据集所在根目录
  84. parser.add_argument('--data-path',type=str,
  85. default="all_data")# 预训练权重路径,如果不想载入就设置为空字符
  86. parser.add_argument('--weights',type=str, default='',help='initial weights path')# 是否冻结权重
  87. parser.add_argument('--freeze-layers',type=bool, default=False)
  88. parser.add_argument('--device', default='cuda:0',help='device id (i.e. 0 or 0,1 or cpu)')
  89. opt = parser.parse_args()
  90. train_loss_list =[]
  91. train_acc_list =[]
  92. val_loss_list =[]
  93. val_acc_list =[]
  94. main(opt)
  95. draw(train_acc_list, val_acc_list,'acc')
  96. draw(train_loss_list, val_loss_list,'loss')

开始训练

在all_data中准备好数据集,并设置好超参数后,即可开始运行train.py

成功运行效果展示

1)会生成dataset.png数据集分布柱状图

2)pycharm下方实时显示相关训练日志

在这里插入图片描述

等待所有epoch训练完成后代码会自动停止,并在weights文件夹下生成训练好的模型pth文件,并生成准确率和损失值曲线图。

在这里插入图片描述
在这里插入图片描述

4、训练好的模型预测

无界面预测代码为:predict.py

在这里插入图片描述

  1. import os
  2. import json
  3. import torch
  4. from PIL import Image
  5. from torchvision import transforms
  6. import matplotlib.pyplot as plt
  7. from models.mobilenet import mobilenet as create_model
  8. defmain(img_path):import os
  9. os.environ['KMP_DUPLICATE_LIB_OK']='TRUE'
  10. device = torch.device("cuda:0"if torch.cuda.is_available()else"cpu")
  11. img_size =224
  12. data_transform = transforms.Compose([transforms.Resize(int(img_size *1.143)),
  13. transforms.CenterCrop(img_size),
  14. transforms.ToTensor(),
  15. transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])])assert os.path.exists(img_path),"file: '{}' dose not exist.".format(img_path)
  16. img = Image.open(img_path)
  17. plt.imshow(img)# [N, C, H, W]
  18. img = data_transform(img)# expand batch dimension
  19. img = torch.unsqueeze(img, dim=0)# read class_indict
  20. json_path ='./class_indices.json'assert os.path.exists(json_path),"file: '{}' dose not exist.".format(json_path)
  21. json_file =open(json_path,"r")
  22. class_indict = json.load(json_file)# create model 创建模型网络
  23. model = create_model(class_num=67).to(device)# load model weights 加载模型
  24. model_weight_path ="weights/plant-best-epoch.pth"
  25. model.load_state_dict(torch.load(model_weight_path, map_location=device))
  26. model.eval()#调用模型进行检测with torch.no_grad():# predict class
  27. output = torch.squeeze(model(img.to(device))).cpu()
  28. predict = torch.softmax(output, dim=0)
  29. predict_cla = torch.argmax(predict).numpy()for i inrange(len(predict)):print("class: {:10} prob: {:.3}".format(class_indict[str(i)],
  30. predict[i].numpy()))# 返回检测结果和准确率
  31. res = class_indict[str(list(predict.numpy()).index(max(predict.numpy())))]
  32. num="%.2f"%(max(predict.numpy())*100)+"%"print(res,num)return res,num
  33. if __name__ =='__main__':
  34. img_path =r"all_data\plant_2\3.png"
  35. main(img_path)

使用方法
1)设置好训练好的模型权重路径
2)设置好要预测的图像的路径
直接右键运行即可,成功运行后会在pycharm下方生成预测结果数据

在这里插入图片描述

5、UI界面设计-pyqt5

对应代码文件
1)ui.py 用于设置界面中控件的属性样式和显示的文本内容,可自行修改文本内容

在这里插入图片描述
2)主界面.py 用于设置界面中的相关按钮及动态的交互功能

在这里插入图片描述
3)plant_data.py 相关介绍及展示信息文本,可自行修改介绍信息

在这里插入图片描述

6、项目相关评价指标

1、准确率曲线图(训练后自动生成)
在这里插入图片描述
2、损失值曲线图(训练后自动生成)
在这里插入图片描述
3、混淆矩阵图
在这里插入图片描述
生成方式:训练完模型后,运行confusion_matrix.py文件,设置好使用的模型权重文件后,直接右键运行即可,等待模型进行预测生成

在这里插入图片描述

以上为本项目完整的构建实现流程步骤,更加详细的项目讲解视频如下https://www.bilibili.com/video/BV19KtVeWE1d
(对程序使用,项目中各个文件作用,算法网络结构,所有程序代码等进行的细致讲解,时长1小时)

七、项目论文报告

本项目有配套的论文报告(9000字左右),部分截图如下

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

八、版权说明及获取方式

1、项目获取方式

1)项目全套文件代码获取地址
项目全套代码地址:https://yuanlitui.com/a/ac8
2)项目配套论文报告获取地址
项目配套报告:https://yuanlitui.com/a/acu

2、项目版权说明及定制服务

本项目由本人 Smaller-孔 设计并开发
可提供服务如下:
1)项目功能及界面定制改进服务
如添加用户登录注册、语音播报、语音输入等系统功能,设计Web端界面,添加mysql数据库替换数据集、算法、及算法改进对比等服务
2)售后服务
获取项目后,按照配置视频进行配置,配置过程中出现问题可添加我咨询答疑,配置好后后续因产品自身代码问题无法正常使用,提供1月内免费售后(因使用者对代码或环境进行调整导致程序无法正常运行需有偿售后),项目文件中售后服务文档获取本人联系方式,提供后续售后及相关定制服务。
3)深度学习CV领域的毕设项目,项目及技术1v1辅导,开发等

标签: 深度学习 算法 cnn

本文转载自: https://blog.csdn.net/weixin_45373427/article/details/143924258
版权归原作者 Smaller.孔 所有, 如有侵权,请联系我们删除。

“基于深度学习CNN算法的植物/中草药分类识别系统01--带数据集-pyqt5UI界面-全套源码”的评论:

还没有评论