使⽤MATLAB进⾏⽬标检测

news2024/11/20 0:16:27

目录

  • 数据准备
  • 定义模型并训练
  • 用测试集评估性能
  • 推理过程
  • ⼀⾏代码查看⽹络结构
  • ⼀⾏代码转onnx
  • 结语

⼈⽣苦短,我⽤MATLAB。
Pytorch在深度学习领域占据了半壁江⼭,最主要的原因是⽣态完善,⽽且api直观易⽤。但谁能想到现在MATLAB⽤起来⽐Pytorch还好⽤。从数据集划分到训练,再到性能验证和画图,仅仅使⽤了⼏⼗⾏代码。炼丹师们终于可以解放编码时间,把⾃⼰的精⼒放在摸⻥(划掉)算法本身上了。
下⾯⽤⾃⼰的数据集训练⼀个YOLOv4,看看MATLAB到底怎么个事。

数据准备

我的数据内容是⾦属锻件磁粉探伤所显示的零件缺陷。如下例所示,轴孔上有⼀处明显缺陷:
在这里插入图片描述
数据集格式为Pascal VOC格式(详⻅http://host.robots.ox.ac.uk/pascal/VOC/)。⾸先要将格式的标签转换为MATLAB能够使⽤的格式。使⽤以下函数:

function convertXMLtoMAT(xmlFolder, outputMATFile)
	% xmlFolder: 存放所有XML⽂件的⽂件夹
	% outputMATFile: 输出的MAT⽂件名
	xmlFiles = dir(fullfile(xmlFolder, '*.xml')); imageFilenames = {};
	boundingBoxes = {};

	for i = 1:length(xmlFiles) 
		try
			xmlFilePath	fullfile(xmlFiles(i).folder, xmlFiles(i).name); xmlDoc = xmlread(xmlFilePath);
			filenameNode = xmlDoc.getElementsByTagName('filename').item(0);
			filename = char(filenameNode.getFirstChild.getData); 
			pathNode = xmlDoc.getElementsByTagName('path').item(0); 
			newPath = fullfile(pwd, 'img', filename);
			xminNode = xmlDoc.getElementsByTagName('xmin').item(0); 
			yminNode = xmlDoc.getElementsByTagName('ymin').item(0); 
			xmaxNode = xmlDoc.getElementsByTagName('xmax').item(0); 
			ymaxNode = xmlDoc.getElementsByTagName('ymax').item(0); 
			xmin = str2double(xminNode.getFirstChild.getData);
			ymin = str2double(yminNode.getFirstChild.getData); 
			xmax = str2double(xmaxNode.getFirstChild.getData); 
			ymax = str2double(ymaxNode.getFirstChild.getData);
			
			width = xmax - xmin; height = ymax - ymin;
			bbox = [xmin, ymin, width, height];
			
			imageFilenames{end+1, 1} = newPath; boundingBoxes{end+1, 1} = bbox;
		catch
			% pass
		end
	end
			
	% 创建table并保存为MAT⽂件
	myDataset = table(imageFilenames, boundingBoxes, ... 
		'VariableNames', {'imageFilename', 'defect'});
	save(outputMATFile, 'myDataset');
	% 输出MAT⽂件的前⼏⾏
	disp('数据集的前⼏⾏:');
	disp(myDataset(1:4, :));

end

转换后的标签⽂件就变成⼀个mat⽂件,加载后就是以下的样⼦:

data = load("my_dataset.mat"); 
defectDataset = data.myDataset;
% 显示数据
disp(defectDataset(1:5, :));
table sample_num * 2 :
			imageFilename					defect
		---------------------		---------------------
		{'img/00001.jpg'}			{[2635 435 133 682]}
		{'img/00001_z0.jpg'}		{[2574 1086 125 561]}
		{'img/00001_z1.jpg'}		{[2569 720 386 596]}
		{'img/00001_z2.jpg'}		{[2608 951 303 647]}
		{'img/00001_z3.jpg'}		{[1748 947 303 606]}

第⼆步,划分数据集。⼀般来讲,按照7:2:1的⽐例拆分训练集、测试集和验证集。

trainingRatio = 0.7;
validationRatio = 0.1;

rng("default");
shuffledIndices = randperm(height(defectDataset));
idx = floor(trainingRatio * length(shuffledIndices) );

trainingIdx = 1:idx;
trainingDataTbl = defectDataset(shuffledIndices(trainingIdx),:);

validationIdx = idx+1 : idx + 1 + floor(validationRatio * length(shuffledIndices) );
validationDataTbl = defectDataset(shuffledIndices(validationIdx),:);

testIdx = validationIdx(end)+1 : length(shuffledIndices); 
testDataTbl = defectDataset(shuffledIndices(testIdx),:);

第三步,创建 Datastore Datastore 是MATLAB特有的⼀个概念,作⽤类似于Pytorch中的DataLoader 。它集成了⼀些常⽤的操作,如计数,按序读取,打乱顺序,合并数据集等⽅法。MATLAB的Datastore ⽐torch的DataLoader 更⽅便,⼀般⽆需⾃⼰定义,拿来就⽤。

imdsTrain = imageDatastore(trainingDataTbl{:,"imageFilename"}); 
bldsTrain = boxLabelDatastore(trainingDataTbl(:,"defect"));

imdsValidation = imageDatastore(validationDataTbl{:,"imageFilename"}); 
bldsValidation = boxLabelDatastore(validationDataTbl(:,"defect"));

imdsTest = imageDatastore(testDataTbl{:,"imageFilename"}); 
bldsTest = boxLabelDatastore(testDataTbl(:,"defect"));
% 合并
trainingData = combine(imdsTrain,bldsTrain); 
validationData = combine(imdsValidation,bldsValidation); 
testData = combine(imdsTest,bldsTest);

最后,为了验证数据是否正确,可以画⼀个样本检查⼀下:

data = read(trainingData); 
I = data{1};
bbox = data{2};
annotatedImage = insertShape(I,"Rectangle",bbox,LineWidth=10); 
annotatedImage = imresize(annotatedImage,2);

figure 
imshow(annotatedImage); 
reset(trainingData);

在这里插入图片描述

定义模型并训练

这部分是本⽂的重点,但是却很短,因为MATLAB的流程太简洁了,狠狠爱了。

⾸先定义模型的主要参数:

optimizer = "adam"; % 优化器
gradientDecayFactor = 0.9; % 梯度衰减因⼦ 
squaredGradientDecayFactor = 0.999; % 平⽅梯度衰减因⼦ 
initialLearnRate = 0.001; % 初始学习率 
learnRateSchedule = 'none'; % 学习率衰减策略 
miniBatchSize = 4; % 批⼤⼩
L2Regularization = 0.0005; % L2正则化 
MaxEpochs = 100; % 迭代轮数
inputSize = [416 416 3]; 
className = "defect";

第⼆步,设置yolov4的Anchors

rng("default") 
trainingDataForEstimation =transform(trainingData,@(data)preprocessData(data,inputSize)); 
numAnchors = 6;
[anchors,meanIoU] = estimateAnchorBoxes(trainingDataForEstimation,numAnchors);

area = anchors(:, 1).*anchors(:,2);
[~,idx] = sort(area,"descend");

anchors = anchors(idx,:); 
anchorBoxes = {anchors(1:3,:)
anchors(4:6,:)};

最后开始训练模型就ok了:

detector = yolov4ObjectDetector("tiny-yolov4-coco", ... 
className,anchorBoxes,InputSize=inputSize);
%  如果你选择了从头开始训练,那么就得定义⼀⼤堆参数
options = trainingOptions(optimizer, ...
	GradientDecayFactor=gradientDecayFactor, ... 
	SquaredGradientDecayFactor=squaredGradientDecayFactor, ... 
	InitialLearnRate=initialLearnRate, ...
	LearnRateSchedule=learnRateSchedule, ... 
	MiniBatchSize=miniBatchSize, ...
	L2Regularization=L2Regularization, ... 
	MaxEpochs=MaxEpochs, ...
	DispatchInBackground=true, ... 
	ResetInputNormalization=true, ... 
	Shuffle="every-epoch", ...
	VerboseFrequency=20, ... 
	ValidationFrequency=1000, ... 
	CheckpointPath=tempdir, ...
	ValidationData=validationData, ... 
	OutputNetwork="best-validation-loss");

% 开始训练
[detector,info] = trainYOLOv4ObjectDetector(augmentedTrainingData,detector,options);
% 保存
save('yolov4_detector.mat',"detector"); % 模型
save('yolov4_detector_info.mat',"info"); % 训练过程

训练时会有如下输出:

Computing Input Normalization Statistics.
*************************************************************************  
Training a YOLO v4 Object Detector for the following object classes:

* defect

正在使⽤  'Processes' 配置⽂件启动并⾏池(parpool)...
已连接到具有 8 个⼯作进程的并⾏池。

Epoch	Iteration	TimeElapsed	LearnRate TrainingLoss	ValidationLoss
								
1	1		00:00:10		0.001		1174.1	1124.1
1	20		00:00:36		0.001		80.843	
1	40		00:00:52		0.001		30.598	
1	60		00:01:08		0.001		20.106	
1	80		00:01:21		0.001		86.183	
1	100		00:01:34		0.001		14.755	
2	120		00:01:53		0.001		13.844	
2	140		00:02:06		0.001		13.443	
2	160		00:02:19		0.001		12.067	
2	180		00:02:32		0.001		10.023	
2	200		00:02:45		0.001		11.157	
2	220		00:02:59		0.001		11.613	

*************************************************************************  
Detector training complete.
*************************************************************************

训练完成后,模型和相关的记录会分别保存在yolov4_detector.matyolov4_detector_info.mat中。

用测试集评估性能

⽤来评估性能的

detectionResults = detect(detector,testData,Threshold=0.01); 
metrics = evaluateObjectDetection(detectionResults,testData); 
AP = averagePrecision(metrics);
[precision,recall] = precisionRecall(metrics,ClassName=className);

% 画pr图
figure 1 
plot(recall{:},precision{:}) 
xlabel("Recall") 
ylabel("Precision")
grid on
title(sprintf("Average Precision = %.2f",AP)) 
imshow(I);

% 再画个loss曲线
figure 2 
plot(info.TrainingLoss)
xlabel("迭代次数")
ylabel("loss") title('Loss曲线')

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

你可以说我练的不怎么样,但不能说MATLAB不⾏,因为在torch上也是⼀样的效果(哭…

推理过程

I = imread("img/00029.jpg"); 
[bboxes,scores,labels] = detect(detector,I);
I = insertObjectAnnotation(I,"rectangle",bboxes,scores, ...
	LineWidth=10,FontSize=72); figure
imshow(I)

在这里插入图片描述

⼀⾏代码查看⽹络结构

MATLAB⾥⾯⼀⾏代码可以做到图形化的查看⽹络结构,更专注于分析算法。

net = detector.Network 
analyzeNetwork(net)

在这里插入图片描述

⼀⾏代码转onnx

exportONNXNetwork(net,'yolov4.onnx')

导出⽹络后,可以将该⽹络导⼊到其他深度学习框架中进⾏推理。妈妈再也不⽤担⼼我的部署了。

结语

MATLAB完全解放了炼丹师的编码时间,让炼丹师能够专注于算法本身,我愿称之为最好的深度学习框架(如果你有licence的话)

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

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

相关文章

word-毕业论文的每一章节的页眉单独设置为该章的题目怎么设置

在Microsoft Word中,为毕业论文的每个章节设置不同的页眉,通常需要使用“分节符”来分隔各个章节,然后在每个章节中单独设置页眉。以下是详细步骤: 使用分节符 插入分节符: 将光标放在每个章节的末尾(注意…

【简历】25届江苏二本JAVA简历:本末倒置,重点部分格式错误,不重要的写了一堆

简历总体说明 校招的第一法则就是必须要确定校招层次。 开发岗分为大中小厂,不同的层次对学校背景、时间点、项目和考点的要求都不太一样,所以必须要确定就业的层次。 这是一个25届二本同学的JAVA简历。 最近不知道怎么回事,看两份简历都…

字母异位词分组(java)

题目描述 给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单shilie 示例 1: 输入: strs ["eat", "tea", "tan", "ate", "n…

fpga spi回环

SPI设备间的数据传输之所以又被称为数据交换,是因为 SPI协议规定一个 SPI设备 不能在数据通信过程中仅仅只充当一个"发送者(Transmitter)“或者"接收者 (Receiver)”.在每个 Clock 周期内,SPI 设备都会发送并接收一个 bit 大小的数据(不管主 设备好还是从设备),相当于…

计算机网络-理论部分(二):应用层

网络应用体系结构 Client-Server客户-服务器体系结构:如Web,FTP,Telnet等Peer-Peer:点对点P2P结构,如BitTorrent 应用层协议定义了: 交换的报文类型,请求or响应报文类型的语法字段的含义如何…

路由器基本原理与配置

一 , 路由是什么? 从源主机到目标主机的转发过程; 二 , 路由器 (1)路由器的工作原理 路由器是一种三层设备,是使用IP地址寻址,实现从源IP到达目标IP地址的端到端的服务&#xff0c…

windows的WSL Ubuntu子系统重置root或其他用户的密码

思路:以管理员身份运行PowerShell,在命令行窗口重置密码 ,不需要删除或重新安装Linux子系统。 1、以管理员身份运行PowerShell 2、用root用户启动Ubuntu,执行 wsl.exe --user root 3、重置密码,执行passwd username&…

autoDL微调训练qwen2vl大模型

autodl是一家GPU服务厂商,提供专业的GPU租用服务,秒级计费、稳定好用 先去autodl把官方的帮助文档看懂先 AutoDL帮助文档 autodl注册并登陆,充钱,根据自己的情况租用新实例 创建新实例后马上关机,因为有个省钱的办法…

9.2 使用haarcascade_frontalface_default.xml分类器检测视频中的人脸,并框出人脸位置。

1)程序代码: # 2.使用haarcascade_frontalface_default.xml分类器检测视频中的人脸,并框出人脸位置 import cv2# 加载人脸检测的 Haar 级联分类器 face_cascade cv2.CascadeClassifier(./data/haarcascades/haarcascade_frontalface_defaul…

K8S containerd拉取harbor镜像

前言 接前面的环境 K8S 1.24以后开始启用docker作为CRI,这里用containerd拉取 参考文档 正文 vim /etc/containerd/config.toml #修改内容如下 #sandbox_image "registry.aliyuncs.com/google_containers/pause:3.10" systemd_cgroup true [plugins.…

ARM64环境部署EFK8.15.3收集K8S集群容器日志

环境规划 主机IP系统部署方式ES版本CPU架构用户名密码192.168.1.225Ubuntu 22.04.4 LTSdockerelasticsearch:8.15.3ARM64elasticllodyi4TMmZD ES集群部署 创建持久化目录(所有节点) mkdir -p /data/es/{data,certs,logs,plugins} mkdir -p /data/es/certs/{ca,es01}服务器…

前端小练习——星辰宇宙(JS没有上限!!!)

前言:在刚开始学习前端的时候,我们会学习到前端三件套中的JavaScript,可能那时候读者没有觉得JavaScript这个语言有多么的牛逼,本篇文章将会使用一个炫酷的案例来刷新你对JavaScript这个语言的认知与理解。 ✨✨✨这里是秋刀鱼不做…

图文教程 | 2024年IDEA安装使用教程,JDK简易下载方法

前言 📢博客主页:程序源⠀-CSDN博客 📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正! 目录 一、IDEA安装 二、激活 三、JDK安装 四、JDK环境配置 五、验证 一、IDEA安装 进入官网下载: Other…

【阅读记录-章节2】Build a Large Language Model (From Scratch)

目录 2.Working with text data2.1 Understanding word embeddings2.2 Tokenizing text通过一个简单的实验来理解文本的词元化概念关键概念 2.3 Converting tokens into token IDs实现分词器类(Tokenizer Class)应用分词器测试文本的编码与解码通过分词器…

已有docker增加端口号,不用重新创建Docker

已有docker增加端口号,不用重新创建Docker 1. 整体描述2. 具体实现2.1 查看容器id2.2 停止docker服务2.3 修改docker配置文件2.4 重启docker服务 3. 总结 1. 整体描述 docker目前使用的非常多,但是每次更新都需要重新创建docker,也不太方便&…

网页作业9

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>服务中心</title><style>* {margin:…

HTML and CSS Support HTML 和 CSS 支持

GoTo DevExpress Data Grid 数据网格 HTML and CSS Support HTML 和 CSS 支持 HTML和CSS支持允许您创建完全自定义的UI元素&#xff0c;并消除使用基于属性的UI自定义和CustomDraw事件。您可以构建 HTML 格式的 UI&#xff0c;并使用 CSS 样式自定义 UI 元素的外观设置、大小、…

集群聊天服务器(7)数据模块

目录 Mysql数据库代码封装头文件与源文件 Mysql数据库代码封装 业务层代码不要直接写数据库&#xff0c;因为业务层和数据层的代码逻辑也想完全区分开。万一不想存储mysql&#xff0c;想存redis的话&#xff0c;就要改动大量业务代码。解耦合就是改起来很方便。 首先需要安装m…

如何确保Python爬虫程序的稳定性和安全性?

在当今数字化时代&#xff0c;Python爬虫被广泛应用于数据采集和信息抓取。然而&#xff0c;确保爬虫程序的稳定性和安全性是开发过程中的重要考虑因素。本文将探讨如何通过技术手段和最佳实践来提高Python爬虫的稳定性和安全性&#xff0c;并提供代码示例。 稳定性保障 1. 异…

【知识科普】统一身份认证CAS

什么是CAS 综合概述一、CAS概述二、CAS的组成与工作原理三、CAS的特性与支持四、CAS的应用场景 示例展示场景设定CAS认证过程 其他认证细节CAS认证过程的细节CAS认证过程的特性 参考文献 综合概述 统一身份认证CAS&#xff08;Central Authentication Service&#xff09;&…