一个小小空格问题引起的bug

news/2024/10/8 0:33:56

程序员会遇到一种情况,一个bug排查到最后是由一个很小的问题导致的。在昨天的日常搬砖中遇到一个问题,耽搁了我大半天的时间,最后查明原因让我很无语。

首先介绍一下背景,我是做算法模型训练,目前手上的工作是迭代一个算法,添加最新的数据集训练出一个精度更好的模型。

拿到标注好的xml的数据集,我首先做了一个格式的转换和数据集的拆分。使用的代码如下:

import os
import shutil
import xml.etree.ElementTree as ETdef list_dir(path: str) -> str:"""列出目录下所有的文件"""for item in os.listdir(path):yield itemdef parse_xml():base_path = "/home/lijinkui/Desktop/head_shoudler_20240824/头肩检测_V1.13_20240823083458_V1"label_dir = f"{base_path}/gt"count = 0test_obj = open(f"{base_path}/test/test_ssd.txt", "a")# train_obj = open(f"{base_path}/train/train.txt", "a")for item in list_dir(label_dir):xml_path = f"{label_dir}/{item}"# print(xml_path)# 从文件中解析XML,获取根元素root = ET.parse(xml_path).getroot()filename = root.find('filename').text.strip()width = int(root.find('size').find('width').text)height = int(root.find('size').find('height').text)# print(width, height)count += 1print(count)box_list = []for index, label in enumerate(root.iter('object')):category = label.find('name').textbbox = label.find('bndbox')x1 = bbox.find('xmin').texty1 = bbox.find('ymin').textx2 = bbox.find('xmax').texty2 = bbox.find('ymax').textbox_list.extend([x1, y1, x2, y2, "1"])txt_string = " ".join(box_list) + "\n"if count <= 1200:# test_obj.write(txt_string)# shutil.move(f"{base_path}/images/{filename}", f"{base_path}/test/images/{filename}")test_obj.write(f"# 20240824/{filename} \n")test_obj.write(txt_string)# else:#     train_obj.write(txt_string)#     # shutil.copy(f"{base_path}/images/{filename}", f"{base_path}/train/images/{filename}")test_obj.close()# train_obj.close()if __name__ == '__main__':parse_xml()

将前1200张保存为测试集

if count <= 1200:# test_obj.write(txt_string)# shutil.move(f"{base_path}/images/{filename}", f"{base_path}/test/images/{filename}")test_obj.write(f"# 20240824/{filename} \n")test_obj.write(txt_string)

保存好的格式是:

# meili/00320.jpg                                                                                                       
1796 550 1861 618 1
# meili/00330.jpg
1674 515 1749 585 1
# meili/00340.jpg
1527 473 1609 545 1
# meili/00350.jpg
1373 457 1455 531 1

然后我就配置好参数,愉快的启动了训练。结果还没跑多久,就报错了。经过排查,报错的代码如下:

def converter(args):im_file, image_name, labels = argstry:# 这种方式直接获取图片的信息,加载速度快,但是会漏掉一些图片崩溃的情况# im = Image.open(im_file)# im.verify()  # PIL verify# img_w, img_h = exif_size(im)  # (width, height)# 采用opencv读取能够发现数据集中崩溃的图片,不至于影响训练im = cv2.imread(im_file)img_h, img_w = im.shape[:2]tmp = []for l, x1, y1, x2, y2 in labels:x, y, w, h = (x1 + x2) // 2, (y1 + y2) // 2, x2 - x1, y2 - y1x, y, w, h = x / img_w, y / img_h, w / img_w, h / img_htmp.append([l, x, y, w, h])return image_name, tmpexcept Exception as e:print("-------------------------")print(im_file)print(f"{im_file} has broken..: {e}")return None, None

报错的信息是:20240824/0f4963ca91ff7c26d66c69b028415243b8a8a405.jpg has broken ... : NoneType has no shape。

我第一反应就是这个图片可能是损坏了,最简单的验证方法就是用opencv的库show一下。按照这个思路我打开了一个python终端,在终端中show图片。

>>> import cv2 as cv
>>> 
>>> image = cv.imread("/h3c_data/data/recognize_new_data/project_dataset/HeadShoulder/Test/Image/20240824/002bf647508fac15babe697c625c3004589b1607.jpg")
>>> 
>>> image.shape
(1080, 1920, 3)
>>>

这么检查下来,发现也没有问题啊,图片明明没有损坏。
然后我猜测难道是图片的权限或用户组问题导致不可读吗?于是检查了文件的权限

读写权限和用户组都没问题。奇怪了,到底是啥问题呢?

这时我就准备祭出断点大招,在图片读取之前打一个断点,断点一步步向下走,看看是哪里的问题。结果断点也打不上。因为这个函数是放在线程池中执行的,每次8个线程并发执行,遇到断点就直接退出了。

with Pool(NUM_THREADS) as pool:pbar = tqdm(pool.imap_unordered(converter, zip(image_pathes, image_names, labels)),desc=desc, total=len(image_pathes))for image_name, tmp in pbar:if image_name:dst_ret.write("%s" % image_name)for l, *info, in tmp:line = (l, *info)dst_ret.write((" %d" + " %g"*len(info)) % line)dst_ret.write("\n")

断点也不行,那我就没招了。其实我打端点就是想看看文件的路径是不是有问题,既然不能看每一个,那我干脆就看所有的。所以我打印了所有图片路径列表的变量,于是发现了问题。
原来每一个图像路径的后面都多了一个空格,我恍然大悟,怪不得用python终端show的时候没有发现,终端里面不打印空格标识。我从终端里复制图像路径,根本不知道路径的后面还有一个空格。

而且回过头来再看空格是哪来的,就是在数据集处理的时候随手多打了一个空格。

这个问题本来不难发现,但是由于第一空格在终端里面不展示导致没发现这个空格,第二想要断点调试时由于程序在线程池中断点也不生效,导致也不能断点调试变量,不能发现这个空格。
在一些巧合之前,让我折腾了大半天的时间,最后才解决这个问题。程序员的日常就是和各种bug斗智斗勇。

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

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

相关文章

Stable Diffusion学习-提示词基本语法

提示词 正面提示词 A Chinese man wearing a green cotton coat and red hair is in the corridor of the Forbidden City, sunny at 8:00 am during the day, 一名身穿绿色棉布外套、红发的中国男子在紫禁城的走廊上,白天阳光明媚, (masterpiece:1,2), best quality, highre…

类似咸鱼/转转闲置二手商品交易回收商城系统源码定制开发搭建

野兔二手交易系统,这是采用最新ThinkPHP8框架开发完成,也是基于YETUADMIN+Uniapp开发的二手交易系统,卖家可以发布二手信息,买家可以在线询价,支持在线聊天,在线购买支付,支持发布高价回收信息。 自带社交板块,用户可以发布帖子、加入圈子、关注好友。 开发介绍: 程序…

Prometheus 告警恢复时,怎么获取恢复时的值?

Prometheus 告警事件中的 $value 表示当前告警触发时的值,但是在告警恢复时,Resolved 事件中的 $value 仍然是最新告警时的值,并非是恢复时的值,这是什么原因和原理?是否有办法来解决呢? 不废话,先说原理。 原理 告警规则是配置在 prometheus.yaml 中的,由 Prometheus …

AI 网关零代码解决 AI 幻觉问题

本文将以高德地图和心知天气两个服务为例,介绍一下如何零代码使用 AI Agent 插件构建一个同时支持地图服务和天气服务的 Agent,同时会探讨 AI Agent 插件的实现原理。作者:邢云阳,Higress Contributor 前言 什么是 AI Agent 随着大模型技术的快速发展,越来越多的公司在实际…

ollama 最快方式部署管理大模型

github:https://github.com/ollama/ollama 模型地址:https://ollama.com/library/llama3.1 linux: 安装 1.下载安装脚本 curl -fsSL https://ollama.com/install.sh | sh 2.修改启动环境变量 如果是root 用户记得改为rootvim /etc/systemd/system/ollama.service[Unit] Descrip…

荣誉+1 !入选十大科技领先成果!

8月28日,2024中国国际大数据产业博览会(简称“数博会”)在贵阳市隆重开幕,本届展会以“数智共生:开创数字经济高质量发展新未来”为主题,全方位、多角度展示国内外数据产业最新动态、最新成果和发展趋势。8月28日,2024中国国际大数据产业博览会(简称“数博会”)在贵阳…

Linux通用性-日志切割脚本

一、公司提供的参考脚本: #!/bin/bash # 定义需要清理的文件 log_file=( "/mpjava/ly.mp.dfpv.acc.biz/bin/nohup.out" "/mpjava/ly.mp.dfpv.acc.service/bin/nohup.out" ) # 获取当天日期 date_now=$(date +%Y%m%d)for file_dir in $log_file do# 获取文…

Redis十大数据类型

Redis十大数据类型 数据类型一般指的是 value 的数据类型,key的类型一般都是字符串 一、总体概述redis字符串(String)string是redis 最基本的类型,一个key对应一个value,string类型是二进制安全的,意思是redis的string可以包含任何数据,比如jpg图片或者序列化的对象 一个…