YoloV8修改分类(Classify)的前处理(记录)
修改原因
- yolo自带的分类前处理对于长方形的数据不够友好,存在特征丢失等问题
- 修改后虽然解决了这个问题但是局部特征也会丢失因为会下采样程度多于自带的,总之具体哪种好不同数据应该表现不同
- 我的数据中大量长宽比很大的数据所以尝试修改自带的前处理,以保证理论上的合理性。
修改过程
- yolo中自带的分类前处理和检测有一些差异
调试推理代码发现ultralytics/models/yolo/classify/predict.py中对图像进行前处理的操作主要是self.transforms
def preprocess(self, img):"""Converts input image to model-compatible data type."""if not isinstance(img, torch.Tensor):is_legacy_transform = any(self._legacy_transform_name in str(transform) for transform in self.transforms.transforms)if is_legacy_transform: # to handle legacy transformsimg = torch.stack([self.transforms(im) for im in img], dim=0)else:# import ipdb;ipdb.set_trace()img = torch.stack([self.transforms(Image.fromarray(cv2.cvtColor(im, cv2.COLOR_BGR2RGB))) for im in img], dim=0)img = (img if isinstance(img, torch.Tensor) else torch.from_numpy(img)).to(self.model.device)return img.half() if self.model.fp16 else img.float() # uint8 to fp16/32
通过调试打印self.transforms得到
Compose(Resize(size=96, interpolation=bilinear, max_size=None, antialias=True)CenterCrop(size=(96, 96))ToTensor()Normalize(mean=tensor([0., 0., 0.]), std=tensor([1., 1., 1.]))
)
假设我设置的imgsz为96,从这里简单的解读可以理解为先进行resize然后进行中心裁切保证输入尺寸为96x96
具体的查看哪里可以修改前处理,首先发现在ultralytics/engine/predictor.py中
def setup_source(self, source):"""Sets up source and inference mode."""self.imgsz = check_imgsz(self.args.imgsz, stride=self.model.stride, min_dim=2) # check image size# import ipdb; ipdb.set_trace()self.transforms = (getattr(self.model.model,"transforms",classify_transforms(self.imgsz[0], crop_fraction=self.args.crop_fraction), #dujiang)if self.args.task == "classify"else None)
可以发现self.transforms主要调用的是classify_transforms方法
进一步我们在ultralytics/data/augment.py中找到classify_transforms的实现
if scale_size[0] == scale_size[1]:# Simple case, use torchvision built-in Resize with the shortest edge mode (scalar size arg)tfl = [T.Resize(scale_size[0], interpolation=getattr(T.InterpolationMode, interpolation))]else:# Resize the shortest edge to matching target dim for non-square targettfl = [T.Resize(scale_size)]tfl.extend([T.CenterCrop(size),T.ToTensor(),T.Normalize(mean=torch.tensor(mean), std=torch.tensor(std)),])
发现和我们的设想基本一致,查看代码逻辑首先是针对正方形图像会将图像缩放到指定的高度,同时保持长宽比,确保较短的一边正好等于目标尺寸,非正方形图片将短边resize到指定大小,长边此时可能是超出的,所以 T.CenterCrop(size)进行中心裁切确保尺寸是我们指定的
针对上面的分析可能问题就很明显了,如果处理的图像是长宽比非常不均匀的图像,那么中心裁切会导致丢失大量信息,我参考了检测的方法,决定将分类的预处理修改为填充而不是裁切。
- 首先确定思想,我想做的是根据长边resize到指定尺寸并且保证长宽比,短边会不足,刚好与原本的代码逻辑相反
- 然后短边不足的地方进行填充保证短边也达到指定尺寸(填充yolo好像一般是144,这里我也选择144)
- 具体实现如下
- 添加两个类分别实现
resize和padding
class ResizeLongestSide:def __init__(self, size, interpolation):self.size = sizeself.interpolation = interpolationdef __call__(self, img):# 获取图像的当前尺寸width, height = img.size# 计算缩放比例if width > height:new_width = self.sizenew_height = int(self.size * height / width)else:new_height = self.sizenew_width = int(self.size * width / height)# 按长边缩放return img.resize((new_width, new_height), Image.BILINEAR)class PadToSquare:def __init__(self, size, fill=(114)):self.size = sizeself.fill = filldef __call__(self, img):# 获取当前尺寸width, height = img.size# 计算需要填充的大小delta_w = self.size - widthdelta_h = self.size - heightpadding = (delta_w // 2, delta_h // 2, delta_w - (delta_w // 2), delta_h - (delta_h // 2))# 填充图像return F.pad(img, padding, fill=self.fill, padding_mode='constant')
- 调用上面的类进行实现
def classify_transforms(size=96,mean=DEFAULT_MEAN,std=DEFAULT_STD,interpolation="BILINEAR",crop_fraction: float = DEFAULT_CROP_FRACTION,padding_color=(114, 114, 114), # 默认填充为灰色
):import torchvision.transforms as Timport torchfrom torchvision.transforms import functional as F# import ipdb;ipdb.set_trace()tfl = [# T.ClassifyLetterBox(size),ResizeLongestSide(size, interpolation=getattr(T.InterpolationMode, interpolation)), # 按长边缩放PadToSquare(size, fill=padding_color), # 填充至正方形T.ToTensor(),T.Normalize(mean=torch.tensor(mean), std=torch.tensor(std)),]return T.Compose(tfl)
- 想要训练前先确定自己修改是否符合预期进行如下测试
Examples:>>> from ultralytics.data.augment import LetterBox, classify_transforms, classify_transforms_with_padding>>> from PIL import Image>>> transforms = classify_transforms_with_padding(size=96)>>> img = Image.open('bus.jpg') 3ch img_rgb = Image.merge('RGB', (img, img, img))>>> transformed_img = transforms(img)>>>import torchvision.transforms as T>>>DEFAULT_MEAN = (0.0, 0.0, 0.0)>>>DEFAULT_STD = (1.0, 1.0, 1.0)>>>import torch>>>def save_transformed_image(transformed_img, save_path="transformed_image.png"):# 定义反向变换,将张量转换回 PIL 图像unnormalize = T.Normalize(mean=[-m / s for m, s in zip(DEFAULT_MEAN, DEFAULT_STD)],std=[1 / s for s in DEFAULT_STD])img_tensor = unnormalize(transformed_img)img_tensor = torch.clamp(img_tensor, 0, 1)to_pil = T.ToPILImage()img_pil = to_pil(img_tensor)img_pil.save(save_path)print(f"Image saved at {save_path}")>>>save_transformed_image(transformed_img, save_path="transformed_image.png")
- 效果图


- ok,效果预期一致,接下来可以训练了,之前对于矩形的图像会有裁切现在使用padding解决了。但是具体效果还得看结果。
- 补充一下修改一定要把类和方法分开,即不要在方法中定义类,这样会导致训练出错
总结中间遇到问题参考这里解决
相关文章:
YoloV8修改分类(Classify)的前处理(记录)
修改原因 yolo自带的分类前处理对于长方形的数据不够友好,存在特征丢失等问题修改后虽然解决了这个问题但是局部特征也会丢失因为会下采样程度多于自带的,总之具体哪种好不同数据应该表现不同我的数据中大量长宽比很大的数据所以尝试修改自带的前处理&a…...
半监督学习能否帮助训练更好的模型?
数据科学家面临的最常见挑战之一是缺乏足够的标记数据来训练一个可靠且准确的模型。标记数据对于监督学习任务,如分类或回归至关重要。然而,在许多领域,获取标记数据既昂贵又耗时,有时甚至是不切实际的。另一方面,未标…...
VBA 获取字段标题代码轻松搞定
hi,大家好! 最近又有一段时间没和大家唠嗑了,最近也没有时间给大家开直播,天天忙,但不知道在忙啥!那今天我们来讲点啥好玩的呢? 今天是老师节,那就先祝各位老师节日快乐࿰…...
C++代码片段
for(int i1; i<shuliang; i) { int f100; cout<<a[i].name<<":"<<\n; cout<<"该舰艇现在距离基地"<<km<<"km,需要"<<km…...
Golang | Leetcode Golang题解之第388题文件的最长绝对路径
题目: 题解: func lengthLongestPath(input string) (ans int) {n : len(input)level : make([]int, n1)for i : 0; i < n; {// 检测当前文件的深度depth : 1for ; i < n && input[i] \t; i {depth}// 统计当前文件名的长度length, isFi…...
docker打包前端项目
🎉 前言 之前有出过一期打包后端项目和数据库的教程,现在填个坑,出一期打包前端项目的教程,废话不多说,我们直接进入正题。 🎉 编写Dockerfile文件 老规矩,先描述项目结构,结构图…...
调度器怎么自己写?调度器在实现时需要注意哪些细节?请写一个jvm的调度器?如何在这个调度器中添加多个任务?
如果你想自己编写一个调度器,可以按照以下步骤进行: 一、确定需求和目标 明确调度器的应用场景,例如任务调度、资源分配、进程管理等。 确定调度的对象,比如任务、作业、进程等。 定义调度的目标,如最小化完成时间、最…...
创客匠人对话|德国临床营养学家单场发售百万秘笈大公开
老蒋创客圈第66期对话标杆直播连麦,我们邀请到【梦想身型健康管理学院】平台创始人吴迪老师。为我们分享“健康管理赛道单场发售破百万!创始人背后的操盘秘笈是什么?”,深度剖析如何去展示自己的核心竞争力?如何扩大专…...
开源项目低代码表单FormCreate从Vue2到Vue3升级指南
开源项目低代码表单 FormCreate v3 版本基于 Vue 3.0 构建,尽管功能与 v2 版本大致相同,但有一些重要的变更和不兼容项需要注意。 源码地址: Github | Gitee FormCreate v3 对比 v2 版本在一些功能和配置项上做了调整,以更好地支持 Vue 3 的…...
序偶解释:李冬梅老师书线性表一章第一页
序偶的定义: 有序偶是两个对象的搜集,使得可以区分出其中一个是“第一个元素”而另一个是“第二个元素”。带有第一个元素a和第二个元素b的有序偶通常写为(a,b)。例如,在数学中,有序偶用于表示二维空间上的点。序偶的特性…...
3GPP协议入门——物理层基础(二)
物理层基础(一)在这里~ 物理层基础(一) 1.RE Resource Element,NR中最小的资源单位,时域上是一个OFDM符号长度,频域上为一个子载波宽度。 2. RB Resource Block,时域上是一个OFDM符…...
Java学习Day41:手刃青背龙!(spring框架之事务)
1.spring事务概念 在数据层和业务层保证一系列数据库操作原子性成功失败!(相比事务可以在业务层开启) 1.事务定义:关键字:Transactional(一般写在接口上) 2.事务管理器:在JdbcCon…...
el-image(vue 总)
一 加载静态资源 在第一次使用vue3开发项目时,使用require(‘图片路径’),结果浏览器报错: Uncaught (in promise) ReferenceError: require is not defined 因为require是webpack提供的一种加载能力,但…...
餐饮「收尸人」,血亏奶茶店……
最近一段时间,小柴朋友圈叫苦的餐饮人是越来越多了! 比如某天早上睡醒查看朋友圈奏折的时候,有个以前经常光顾的餐馆的老板,发了一条朋友圈:最终,还是要和自己经营了11年的小店告别了…… 配的照片是店…...
【Python进阶】学习Python从入门到进阶,详细步骤,就看这一篇。文末附带项目演练!!!
详细的Python学习路线 1. Python基础 Python安装和环境配置:学习如何在你的操作系统上安装Python,并配置开发环境。变量和数据类型:学习如何定义变量,以及Python中的基本数据类型,如整数、浮点数、字符串等。 Pytho…...
OpenCV结构分析与形状描述符(9)检测轮廓相对于其凸包的凹陷缺陷函数convexityDefects()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 查找一个轮廓的凸性缺陷。 下图显示了一个手部轮廓的凸性缺陷: convexityDefects 是 OpenCV 库中的一个函数,用于检测轮…...
HTTP 之 响应头信息(二十三)
应答头说明Allow服务器支持哪些请求方法(如GET、POST等)。Content-Encoding文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。Java的GZIPOutp…...
智能风扇的全新升级:NRK3603语音芯片识别控制模块的应用
在当今智能化生活的潮流中,如何让家电更加人性化、便捷化,已经成为消费者和制造商关注的焦点。在这股大潮中,NRK3603语音识别模块以其出色的性能和广泛的应用,为智能电风扇带来了全新的升级。 1. 芯片特性 NRK3603是一款高性能、…...
如何通过pSLC技术实现性能与容量的双赢
目录 一、什么是 pSLC 二、各 NAND FLASH 的特点 三、pSLC 的优缺点 四、应用场景 一、什么是 pSLC pSLC(Pseudo-Single Level Cell)即伪 SLC,是一种将 MLC/TLC 改为 SLC 的一种技术,现 Nand Flash 基本支持此功能࿰…...
减速电机的基本结构及用料简介
资料来源:淘宝上某商家,它提供功率极小的电机。比如5W 1.整体结构剖面图 如下图,左侧是减速箱,和动力输出轴,右侧可以看到定子的铜丝绕组和中间的转子,它们贴合地非常紧密。气隙很窄。它的转子很像是铝制…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
