d2l | 目标检测数据集:RuntimeError: No such operator image::read_file

ops/2024/10/17 13:01:14/

目录

    • 1 存在的问题
    • 2 可能的解决方案
    • 3 最终的解决方案
      • 3.1 方案一(我已弃用)
      • 3.2 方案二(基于方案一)
      • 3.3 方案三(基于方案一)


1 存在的问题

李沐老师提供的读取香蕉数据集的函数如下:

def read_data_bananas(is_train=True):"""读取香蕉检测数据集中的图像和标签"""data_dir = d2l.download_extract('banana-detection')csv_fname = os.path.join(data_dir,'bananas_train' if is_train else 'bananas_val','label.csv')csv_data = pd.read_csv(csv_fname)csv_data = csv_data.set_index('img_name')images, targets = [], []for img_name, target in csv_data.iterrows():images.append(torchvision.io.read_image(os.path.join(data_dir, 'bananas_train' if is_trainelse 'bananas_val', 'images', f'{img_name}'))targets.append(list(target))return images, torch.tensor(targets).unsqueeze(1) / 256

执行到如下代码时报错:

images.append(torchvision.io.read_image(os.path.join(data_dir, 'bananas_train' if is_trainelse 'bananas_val', 'images', f'{img_name}'))

报错内容为:

RuntimeError: No such operator image::read_file


2 可能的解决方案

  • 博客一:报错 RuntimeError: No such operator image::read_file
  • 它认为是文件路径中 /\\ 的问题,可惜我全部改为反斜杠后并未解决问题
  • 博客二:解决 RuntimeError: No such operator image::read_file
  • 它认为是 torchvision 版本的问题,可是重装 torchvision 又会需要重装 torch 等包
  • 这是因为 torch 等包的版本要和 torchvision 的版本对应,我认为代价太大


3 最终的解决方案

3.1 方案一(我已弃用)

放弃使用 torchvision.io.read_image(),换成其他函数来做:

  • 采用 Image.open() 函数读取图片(之前看小土堆的视频用过)
  • 将读取到的图片转换为 tensor(这是 torchvision.io.read_image() 函数的作用之一)

简而言之,我们换成其他代码来实现 torchvision.io.read_image() 函数的作用。



① 增加需要使用到的包:

from PIL import Image


② 增加将图片转换为 tensor 的类:

🥲 让 AI 帮我写的,我是真的写不了一点

class ToTensorNoNorm(torchvision.transforms.ToTensor):def __call__(self, pic):return torch.tensor(super().__call__(pic) * 255, dtype=torch.uint8)

Q:为什么不直接使用 torchvision.transforms.ToTensor 类的实例?
A:因为它在将图片转换为 tensor 时会进行归一化,而 torchvision.io.read_image() 函数是没有这个作用的,所以我们定义一个继承自 torchvision.transforms.ToTensor 类但不做归一化的新类。



③ 修改原函数:

def read_data_bananas(is_train=True):"""读取香蕉检测数据集中的图像和标签"""data_dir = d2l.download_extract('banana-detection')csv_fname = os.path.join(data_dir,'bananas_train' if is_train else 'bananas_val','label.csv')csv_data = pd.read_csv(csv_fname)# 将 img_name 列设置为索引列csv_data = csv_data.set_index('img_name')images, targets = [], []for img_name, target in csv_data.iterrows():# 修改部分(三行代码)image = Image.open(os.path.join(data_dir, 'bananas_train' if is_trainelse 'bananas_val', 'images', f'{img_name}'))transform = ToTensorNoNorm()images.append(transform(image))targets.append(list(target))return images, torch.tensor(targets).unsqueeze(1) / 256


🥳 代码运行成功:

在这里插入图片描述



3.2 方案二(基于方案一)

方案二还是基于方案一的思路,但是不再需要自定义将图片转换为 tensor 的类了,因为我发现李沐老师在后面的代码中做了归一化:

imgs = (batch[0][0:10].permute(0, 2, 3, 1)) / 255

也就是说,torchvision.transforms.ToTensor 类的归一化不再变得鸡肋。



① 增加需要使用到的包:

from PIL import Image


② 修改原函数:

def read_data_bananas(is_train=True):"""读取香蕉检测数据集中的图像和标签"""data_dir = d2l.download_extract('banana-detection')csv_fname = os.path.join(data_dir,'bananas_train' if is_train else 'bananas_val','label.csv')csv_data = pd.read_csv(csv_fname)# 将 img_name 列设置为索引列csv_data = csv_data.set_index('img_name')images, targets = [], []for img_name, target in csv_data.iterrows():# 修改部分(三行代码)image = Image.open(os.path.join(data_dir, 'bananas_train' if is_trainelse 'bananas_val', 'images', f'{img_name}'))transform = torchvision.transforms.ToTensor()images.append(transform(image))targets.append(list(target))return images, torch.tensor(targets).unsqueeze(1) / 256


③ 去除后面代码中的归一化:

imgs = (batch[0][0:10].permute(0, 2, 3, 1))

简而言之,torchvision.transforms.ToTensor 类会对图片做归一化,后面就不需要再做了。



🥳 代码运行成功:

在这里插入图片描述



3.3 方案三(基于方案一)

第二天想到的方法

李沐老师的语义分割代码又使用到了 torchvision.io.read_image 函数,我不想每次都要定义一个将图片转换为 tensor 同时又不做归一化的类。

torchvision.io.read_image 函数其实可以被替换为如下代码,以实现相同的效果:

transform = torchvision.transforms.ToTensor()  # 实例化 ToTensor 类
image = Image.open(image_dir)  # 读取图片
image = (transform(image) * 255).to(torch.uint8)  # 转 tensor 但不归一化

注意:图片归一化后的数值是 float 型的小数,即使乘了 255 还是 float 型,需要转换为 integer 型。否则报错 “Clipping input data to the valid range for imshow with RGB data ([0…1] for floats or [0…255] for integers)”,也就是说,针对 RGB 数据,要么是 [0, 1] 之间的 float 型,要么是 [0, 255] 之间的 integer 型。

替换到语义分割一节的代码上:

transform = torchvision.transforms.ToTensor()
image = Image.open(os.path.join(voc_dir, 'JPEGImages', f'{fname}.jpg'))
label = Image.open(os.path.join(voc_dir, 'SegmentationClass' ,f'{fname}.png')).convert('RGB')
features.append((transform(image) * 255).to(torch.uint8))
labels.append((transform(label) * 255).to(torch.uint8))


🥳 代码运行成功:

在这里插入图片描述




http://www.ppmy.cn/ops/119191.html

相关文章

PHP中对数组序列化和反序列化的函数

在PHP中,对数组进行序列化和反序列化的函数分别是 serialize() 和 unserialize()。 序列化(Serialize) serialize() 函数用于将PHP的值或对象转换为一个可存储或传输的字符串表示。这通常用于将数组、对象等复杂数据类型转换为字符串&#…

YOLOv11改进策略【损失函数篇】| Slide Loss,解决简单样本和困难样本之间的不平衡问题

一、本文介绍 本文记录的是改进YOLOv11的损失函数,将其替换成Slide Loss,并详细说明了优化原因,注意事项等。Slide Loss函数可以有效地解决样本不平衡问题,为困难样本赋予更高的权重,使模型在训练过程中更加关注困难样…

强化学习-python案例

强化学习是一种机器学习方法,旨在通过与环境的交互来学习最优策略。它的核心概念是智能体(agent)在环境中采取动作,从而获得奖励或惩罚。智能体的目标是最大化长期奖励,通过试错的方式不断改进其决策策略。 在强化学习…

C++之 友元重载 以及最常用的几种友元函数

在之前的友元中就曾经讲过,我们为了去访问修改私有成员中的数据时,只能通过公有的办法去进行访问操作,非常的局限。所以C引用了友元函数,只要加上friend关键字,C的这个类,会自动把这个函数的权限拉到类内&a…

【Linux 从基础到进阶】HBase数据库安装与配置

HBase数据库安装与配置 Apache HBase 是一个开源的、分布式的、面向列的数据库,基于 Hadoop 的 HDFS 构建,适用于需要随机读写大量数据的场景。HBase 提供了强大的容错和线性扩展能力,支持高并发的读写操作,广泛应用于大数据分析和实时应用系统中。 本文将介绍 HBase 的安…

论文 | Reframing Instructional Prompts to GPTk’s Language

作者:Swaroop Mishra, Daniel Khashabi, Chitta Baral, Yejin Choi, Hannaneh Hajishirzi 论文摘要:语言模型 (LM) 更容易遵循哪些类型的指令提示? 我们通过进行广泛的实证分析来研究这个问题,这些分析阐明了成功指令提示的重要特…

20240930编译orangepi5的Android12使用HDMI0输出

20240930编译orangepi5的Android12使用HDMI0输出 2024/9/30 9:44 缘起,3月份的时候,看PDD拼多多的优惠券给力! 就入手了香橙派Orange Pi 5。 自从制作TF卡的启动卡的时候,坏了一张SanDisk的32GB的TF卡。 从此就对TF卡启动无比抵触…

TI DSP TMS320F280025 Note15:串口SCI的使用

TMS320F280025 串口SCI的使用 ` 文章目录 TMS320F280025 串口SCI的使用框图分析串口特点可编程数据格式SCI端口中断非FIFO/FIFO模式下SCI中断的操作/配置UartDriver.cUartDriver.h串口时钟由PCLKCR7控制使能,默认位系统时钟4分频 串口接收与发送都可以触发中断 串口使用的引脚…