news 2026/10/22 5:42:22

深度学习数据集解压后必做的5步校验与格式转换

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深度学习数据集解压后必做的5步校验与格式转换

简介:本资源是面向深度学习初学者与实践者的图像分类及目标检测训练数据集,适用于人工智能课程实验、水质监测项目开发与模型调优等实际场景。压缩包共305个文件,主体为300张标注清晰的JPG水质轨迹图像(如清澈、浑浊、含藻类等类别),辅以2个MAT格式标注文件、2个MATLAB脚本(.m)用于数据加载与预处理,以及1个TXT说明文档,整体大小22.97MB,轻量易下载、即取即用。已有694人学习下载,反映出较强的教学适配性与工程参考价值。用户可直接用于CNN图像分类模型训练,或结合YOLO/Faster R-CNN等框架开展带边界框标注的目标检测任务;数据已具备基础多样性与结构化组织,配合常规数据增强即可支撑中小规模模型训练,显著降低数据采集与标注门槛。

1. 深度学习训练数据集.zip:不是“随便解压就能用”的万能包,而是需要你亲手校验、清洗、适配的原始燃料

你下载完深度学习训练数据集.zip,双击解压,看到一堆train/,val/,annotations/文件夹,心里一松:“齐了,开训!”——结果torchvision.datasets.ImageFolder报错No images found,COCO API初始化失败,YOLOv8 的data.yaml死活找不到images/train路径……这不是玄学,是绝大多数人第一次面对真实数据集时的翻车现场。这个压缩包本身不带模型、不带代码、不带文档,它只是一批原始图像+标注的集合体,价值完全取决于你能否把它从“硬盘里的文件”变成“训练器能吞下去的张量流”。它适合三类人:刚跑通第一个train.py但卡在数据加载的新手;正在搭建私有训练 pipeline、需要稳定输入源的中阶工程师;以及想快速验证某算法在特定场景(比如工业零件缺陷、植物病害)下泛化能力的研究者。它解决的从来不是“有没有数据”,而是“怎么让数据真正参与训练”——这中间隔着路径结构、标注格式、尺寸归一化、标签映射、甚至文件编码这五道墙。


2. 解压后第一件事:别急着写 dataloader,先用三行命令看清它的真面目

拿到.zip包,很多人直接unzip deep_learning_dataset.zip -d ./data就去改 config,结果发现train/下混着.jpg和.jpeg,annotations/里既有 JSON 又有 XML,classes.txt编码还是 GBK……这种混乱会把后续所有步骤拖进泥潭。必须先建立对数据集物理结构的绝对掌控。

2.1 快速探查目录树与文件分布:tree+find组合拳

# 进入解压后的根目录(假设为 ./dataset) cd ./dataset # 查看完整目录结构(限制深度3,避免过长) tree -L 3 -h # 统计各类型图像文件数量(覆盖常见扩展名) find . -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" \) | wc -l # 查看标注文件类型及数量 find . -type f \( -iname "*.json" -o -iname "*.xml" -o -iname "*.txt" \) | head -20 find . -type f -iname "*.json" | wc -l find . -type f -iname "*.xml" | wc -l

逻辑说明:tree -L 3 -h输出带大小的三层结构,一眼看出images/和labels/是否同级、train/val/test是否分层、annotations/是否独立存在。find命令强制忽略大小写(-iname),覆盖 Windows/Linux 常见命名差异;head -20防止 JSON/XML 内容刷屏,只看文件名模式。这步耗时不到10秒,却能提前规避 70% 的路径错误。

2.2 标注格式识别:JSON 是 COCO?XML 是 Pascal VOC?TXT 是 YOLO?

仅靠后缀无法判断格式实质。需抽样检查内容:

# 抽取一个 JSON 标注文件(如 annotations/instances_train2017.json) head -n 20 annotations/instances_train2017.json | python -m json.tool 2>/dev/null || echo "Not valid JSON" # 抽取一个 XML 标注(如 annotations/000001.xml) head -n 15 annotations/000001.xml # 抽取一个 TXT 标注(如 labels/train/000001.txt) head -n 5 labels/train/000001.txt

关键参数说明:

  • python -m json.tool是 Python 自带的 JSON 格式化工具,若报错Not valid JSON,说明该 JSON 可能是损坏、非标准(如含注释)、或根本不是 COCO 结构;
  • 对 XML,重点看根节点是否为<annotation>(Pascal VOC),内含<object><name>car</name></object>结构;
  • 对 TXT,YOLO 格式必为每行class_id center_x center_y width height(归一化值,0~1),且无 header。

血泪经验:某次我遇到一个名为coco_annotations.json的文件,head看起来像 COCO,但python -m json.tool后发现categories字段缺失id,images中file_name路径和实际images/目录不匹配——这是人工拼接的“伪COCO”,必须重生成。

2.3 图像与标注的严格对齐:用脚本验证文件名一致性

即使目录结构清晰,图像和标注也常因命名不一致而失配。以下 Python 脚本可全自动检测:

import os import glob # 配置你的路径(根据 tree 输出结果修改!) img_dir = "images/train" ann_dir = "labels/train" # 或 annotations/train_json/ img_exts = [".jpg", ".jpeg", ".png", ".bmp"] ann_ext = ".txt" # 根据实际标注格式修改:".json", ".xml", ".txt" # 获取所有图像基础名(不含扩展名) img_basenames = set() for ext in img_exts: img_basenames.update([os.path.splitext(os.path.basename(p))[0] for p in glob.glob(os.path.join(img_dir, f"*{ext}"))]) # 获取所有标注基础名 if ann_ext == ".json": ann_basenames = set([os.path.splitext(os.path.basename(p))[0] for p in glob.glob(os.path.join(ann_dir, "*.json"))]) elif ann_ext == ".xml": ann_basenames = set([os.path.splitext(os.path.basename(p))[0] for p in glob.glob(os.path.join(ann_dir, "*.xml"))]) else: # .txt or others ann_basenames = set([os.path.splitext(os.path.basename(p))[0] for p in glob.glob(os.path.join(ann_dir, "*.txt"))]) # 找出只在图像中存在、但无对应标注的文件 missing_ann = img_basenames - ann_basenames # 找出只在标注中存在、但无对应图像的文件 missing_img = ann_basenames - img_basenames print(f"图像总数: {len(img_basenames)}") print(f"标注总数: {len(ann_basenames)}") print(f"缺少标注的图像: {len(missing_ann)} 个 → {list(missing_ann)[:5]}") print(f"缺少图像的标注: {len(missing_img)} 个 → {list(missing_img)[:5]}")

为什么必须做这一步?
YOLO 训练时若000001.jpg存在但000001.txt缺失,Dataset.__getitem__()会抛FileNotFoundError;COCO 加载时若image_id在images列表中存在,但annotations里无对应image_id,coco.loadAnns()返回空列表,损失函数计算时targets为空导致nan。这个脚本输出的missing_*列表,就是你接下来要手动补全或删除的明确清单。


3. 四大主流格式转换实战:从原始结构到 PyTorch/TensorFlow/YOLO 可直读形态

确认结构与对齐无误后,下一步是让数据符合下游框架的期待。.zip包本身不承诺格式,你必须按需转换。这里覆盖最常用的四类目标:ImageFolder(分类)、COCO(通用检测)、YOLO(轻量检测)、TFRecord(TensorFlow 生产部署)。

3.1 分类任务:转成 torchvision ImageFolder 标准结构

ImageFolder 要求严格目录结构:dataset_root/class_name/*.jpg。若原始数据是平铺在train/下、无子目录,则需按classes.txt或标注 JSON 中的category_name创建子目录。

import os import shutil from pathlib import Path # 假设你有 classes.txt,每行一个类别名 with open("classes.txt", "r", encoding="utf-8") as f: classes = [line.strip() for line in f if line.strip()] # 创建目标目录 root_out = Path("imagefolder_format") for cls in classes: (root_out / "train" / cls).mkdir(parents=True, exist_ok=True) (root_out / "val" / cls).mkdir(parents=True, exist_ok=True) # 假设原始图像在 images/train/,标注在 annotations/train.json(COCO格式) import json with open("annotations/train.json", "r") as f: coco = json.load(f) # 构建 category_id -> name 映射 cat_id_to_name = {cat["id"]: cat["name"] for cat in coco["categories"]} # 遍历所有标注中的 image + annotation,移动图像 for img in coco["images"]: img_id = img["id"] img_filename = img["file_name"] # 如 "000001.jpg" # 找到该图的所有 annotations(可能多目标) anns_for_img = [a for a in coco["annotations"] if a["image_id"] == img_id] if not anns_for_img: continue # 取第一个标注的类别(单标签分类) first_cat_id = anns_for_img[0]["category_id"] cls_name = cat_id_to_name.get(first_cat_id, "unknown") src_path = Path("images/train") / img_filename dst_path = root_out / "train" / cls_name / img_filename if src_path.exists(): shutil.copy2(src_path, dst_path) else: print(f"Warning: {src_path} not found") print("ImageFolder structure built. Use: dataset = ImageFolder(root_out / 'train')")

参数说明:shutil.copy2保留原文件时间戳,便于后续 debug;cat_id_to_name是 COCO 标准字段,若你的 JSON 没有categories,则需从annotations中统计category_id并人工映射——这就是为什么不能跳过第2章的格式识别。

3.2 检测任务:统一转为 COCO 格式(JSON)

无论原始是 VOC XML 还是 YOLO TXT,COCO 是当前最通用的中间格式。我们以 VOC XML 转 COCO 为例(YOLO 转 COCO 逻辑类似,需解析 TXT 行并反归一化坐标):

import xml.etree.ElementTree as ET import json import os from pathlib import Path def voc_to_coco(voc_ann_dir: str, img_dir: str, output_json: str): coco = { "images": [], "annotations": [], "categories": [] } # 构建类别字典(VOC 通常固定20类,但需从XML中提取) categories = {} cat_id = 1 # COCO category_id starts from 1 img_id = 1 ann_id = 1 # 第一遍:扫描所有XML,收集唯一类别 for xml_file in Path(voc_ann_dir).glob("*.xml"): tree = ET.parse(xml_file) root = tree.getroot() for obj in root.findall("object"): name = obj.find("name").text.strip() if name not in categories: categories[name] = cat_id coco["categories"].append({ "id": cat_id, "name": name, "supercategory": "none" }) cat_id += 1 # 第二遍:生成 images 和 annotations for xml_file in Path(voc_ann_dir).glob("*.xml"): tree = ET.parse(xml_file) root = tree.getroot() filename = root.find("filename").text.strip() size = root.find("size") width = int(size.find("width").text) height = int(size.find("height").text) # 添加 image 记录 coco["images"].append({ "id": img_id, "file_name": filename, "width": width, "height": height, "date_captured": "", "license": 1, "coco_url": "" }) # 添加 annotations for obj in root.findall("object"): name = obj.find("name").text.strip() bndbox = obj.find("bndbox") xmin = int(bndbox.find("xmin").text) ymin = int(bndbox.find("ymin").text) xmax = int(bndbox.find("xmax").text) ymax = int(bndbox.find("ymax").text) # COCO bbox format: [x,y,width,height] in absolute pixels bbox = [xmin, ymin, xmax - xmin, ymax - ymin] area = bbox[2] * bbox[3] coco["annotations"].append({ "id": ann_id, "image_id": img_id, "category_id": categories[name], "segmentation": [], # leave empty for bbox-only "area": area, "bbox": bbox, "iscrowd": 0 }) ann_id += 1 img_id += 1 # 写入 JSON with open(output_json, "w") as f: json.dump(coco, f, indent=2) print(f"COCO JSON saved to {output_json}") # 调用示例 voc_to_coco(voc_ann_dir="annotations/voc_xml", img_dir="images/train", output_json="annotations/coco_train.json")

关键细节:COCO 的bbox是[x,y,width,height](非中心点),且area必须显式计算;segmentation留空表示仅用 bbox,不影响训练;iscrowd=0表示单目标实例(非群体)。若原始 XML 有difficult标签,建议在annotations中添加"difficult": 1字段,后续 DataLoader 可据此过滤。

3.3 YOLOv5/v8 兼容:生成 data.yaml 与标准化 TXT 标签

YOLO 要求:1)data.yaml定义路径与类别;2)labels/下每个.txt文件与图像同名,每行cls_id x_center y_center w h(全部归一化到 0~1)。

import yaml from pathlib import Path # Step 1: 生成 data.yaml yaml_content = { "train": str(Path("images/train").resolve()), "val": str(Path("images/val").resolve()), "test": str(Path("images/test").resolve()) if (Path("images/test").exists()) else None, "nc": 3, # number of classes "names": ["person", "car", "dog"] # 从 classes.txt 读取 } # 写入 with open("data.yaml", "w") as f: yaml.dump(yaml_content, f, default_flow_style=False, allow_unicode=True, sort_keys=False) print("data.yaml generated.") # Step 2: 将 COCO JSON 转为 YOLO TXT(核心:坐标归一化) import json import numpy as np def coco_to_yolo_txt(coco_json: str, img_dir: str, out_label_dir: str): with open(coco_json, "r") as f: coco = json.load(f) # 构建 image_id -> info 映射 img_id_to_info = {img["id"]: img for img in coco["images"]} # 创建输出目录 Path(out_label_dir).mkdir(parents=True, exist_ok=True) # 按 image 处理 for ann in coco["annotations"]: img_id = ann["image_id"] img_info = img_id_to_info[img_id] img_w, img_h = img_info["width"], img_info["height"] bbox = ann["bbox"] # [x,y,w,h] # 归一化 x_center = (bbox[0] + bbox[2] / 2) / img_w y_center = (bbox[1] + bbox[3] / 2) / img_h w_norm = bbox[2] / img_w h_norm = bbox[3] / img_h # YOLO 格式:cls_id x_center y_center w h line = f"{ann['category_id'] - 1} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}\n" # 写入对应 txt 文件 img_filename = Path(img_info["file_name"]).stem txt_path = Path(out_label_dir) / f"{img_filename}.txt" # 追加写入(一张图可能多个目标) with open(txt_path, "a") as f: f.write(line) # 调用(假设已生成 coco_train.json) coco_to_yolo_txt( coco_json="annotations/coco_train.json", img_dir="images/train", out_label_dir="labels/train" )

避坑提示:YOLO 的category_id从 0 开始,而 COCO 从 1 开始,所以ann['category_id'] - 1是必须的;x_center等值必须保留 6 位小数,否则某些版本的 Ultralytics 会报ValueError: invalid literal for int();txt_path使用a模式追加,因为一个图像文件可能对应多个annotations。

3.4 TensorFlow 生产部署:打包为 TFRecord(含图像预处理)

TFRecord 是 TensorFlow 推荐的二进制序列化格式,支持高效 I/O 和内置预处理。以下脚本将图像+标签打包,并嵌入 decode 逻辑:

import tensorflow as tf import numpy as np from PIL import Image import io import os def _bytes_feature(value): """Returns a bytes_list from a string / byte.""" if isinstance(value, type(tf.constant(0))): value = value.numpy() return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value])) def _float_feature(value): """Returns a float_list from a float / double.""" return tf.train.Feature(float_list=tf.train.FloatList(value=[value])) def _int64_feature(value): """Returns an int64_list from a bool / enum / int / uint.""" return tf.train.Feature(int64_list=tf.train.Int64List(value=[value])) def image_example(image_string, label, bbox): """ Creates a tf.Example message ready to be written to a file. bbox: [x_min, y_min, x_max, y_max] normalized """ feature = { 'label': _int64_feature(label), 'image_raw': _bytes_feature(image_string), 'bbox_xmin': _float_feature(bbox[0]), 'bbox_ymin': _float_feature(bbox[1]), 'bbox_xmax': _float_feature(bbox[2]), 'bbox_ymax': _float_feature(bbox[3]), } return tf.train.Example(features=tf.train.Features(feature=feature)) # 生成 TFRecord 示例(以单张图为例) def create_tfrecord_from_image(img_path, label, bbox, tfrecord_path): # 读取并编码图像 img = Image.open(img_path) img = img.convert('RGB') # 强制三通道 img_bytes = io.BytesIO() img.save(img_bytes, format='JPEG') img_string = img_bytes.getvalue() # 创建 example tf_example = image_example(img_string, label, bbox) # 写入 TFRecord with tf.io.TFRecordWriter(tfrecord_path) as writer: writer.write(tf_example.SerializeToString()) print(f"TFRecord saved: {tfrecord_path}") # 实际使用时,循环遍历所有 train/val 图像调用此函数 # 注意:真实项目中需按 shard 分片,此处简化 create_tfrecord_from_image( img_path="images/train/000001.jpg", label=0, bbox=[0.1, 0.2, 0.8, 0.9], # normalized tfrecord_path="train.tfrecord" )

为什么值得做?
在 GPU 利用率监控中,你会发现:当数据从磁盘 JPEG 读取+解码+augment 时,GPU 等待 I/O 时间占比常超 30%;而 TFRecord 将图像像素和标签打包为二进制块,配合tf.data.TFRecordDataset的prefetch和map并行,可将 I/O 瓶颈降低至 5% 以内。这是生产环境的硬性要求,不是可选项。


4. 避坑指南:五个让你深夜调试、怀疑人生的高频问题与解法

数据集落地中最痛苦的不是不会写代码,而是错误信息模糊、原因隐蔽、复现困难。以下是我在十多个真实项目中踩过的坑,按发生频率排序,每条都附带可立即执行的诊断命令。

4.1 现象:PyTorch DataLoader 报OSError: image file is truncated

原因:ZIP 解压时部分 JPG 文件损坏(尤其网络下载中断、磁盘满、解压工具兼容性差);或图像被其他进程占用未释放。
解决:

# 批量检查 JPEG 完整性(Linux/macOS) find images/ -name "*.jpg" -exec file {} \; | grep -v "JPEG image data" | head -10 # 修复(需安装 jpeginfo) jpeginfo -c images/*.jpg 2>&1 | grep -E "WARNING|ERROR" # 删除损坏文件(谨慎!先备份) find images/ -name "*.jpg" -exec jpeginfo -c {} \; 2>&1 | grep "ERROR" | awk '{print $1}' | xargs -I {} rm {}

4.2 现象:YOLOv8 训练时 loss 为 nan,或 mAP=0

原因:YOLO TXT 标签中存在w或h为 0 的 bbox(极窄目标),或x_center/y_center超出 [0,1] 范围(归一化错误)。
解决:

# 检查所有 TXT 标签 import glob import numpy as np for txt_path in glob.glob("labels/train/*.txt"): with open(txt_path, "r") as f: lines = f.readlines() for i, line in enumerate(lines): parts = list(map(float, line.strip().split())) if len(parts) < 5: print(f"{txt_path}:{i} → less than 5 values") continue cls, xc, yc, w, h = parts[:5] if w <= 0 or h <= 0: print(f"{txt_path}:{i} → w/h <=0: {w}, {h}") if not (0 <= xc <= 1 and 0 <= yc <= 1): print(f"{txt_path}:{i} → center out of [0,1]: {xc}, {yc}") if not (0 <= w <= 1 and 0 <= h <= 1): print(f"{txt_path}:{i} → w/h out of [0,1]: {w}, {h}")

4.3 现象:COCO Evaluator 报KeyError: 'image_id'或no predictions

原因:coco_gt加载的 JSON 中images字段缺失id,或predictions.json的image_id与 GT 不匹配(常见于自己生成预测时用了错误的 image_id)。
解决:

# 检查 GT JSON 的 images 是否有 id jq '.images[0].id' annotations/coco_val.json # 检查 predictions.json 的前几条 image_id jq '.[0:3].image_id' predictions.json # 强制重写 predictions.json 的 image_id 为字符串(若 GT 用字符串 ID) jq 'map(.image_id |= tostring)' predictions.json > predictions_fixed.json

4.4 现象:TensorFlowtf.io.decode_jpeg报Invalid JPEG data

原因:图像文件实际是 PNG 但扩展名为.jpg,或文件头被篡改(如文本编辑器误打开保存)。
解决:

# 检查文件头(magic number) file images/train/*.jpg | grep -v "JPEG" # 批量修正(将 PNG 头的 .jpg 改为 .png) for f in images/train/*.jpg; do if file "$f" | grep -q "PNG"; then mv "$f" "${f%.jpg}.png" fi done

4.5 现象:训练时显存 OOM,但nvidia-smi显示显存占用很低

原因:Dataloader 的num_workers > 0时,每个 worker 进程会复制一份主进程的模型和数据集对象,导致内存(非显存)爆炸,进而触发系统 OOM Killer 杀死进程。
解决:

# 在 DataLoader 中设置 train_loader = DataLoader( dataset, batch_size=16, num_workers=0, # 关键!先设为0排除内存问题 pin_memory=True, shuffle=True ) # 若确认是 worker 内存问题,再尝试 num_workers=2 并监控内存

注意:num_workers=0会降低数据加载速度,但它是定位内存问题的黄金准则。只有在num_workers=0下稳定运行后,才逐步增加 worker 数并用htop观察 RSS 内存增长。


5. 验证数据集可用性的终极三板斧:从文件层到张量层的穿透式检查

很多工程师在数据转换后就直接python train.py,结果几个 epoch 后才发现标签错位、图像扭曲、类别漏映射。真正的可靠性,必须在训练启动前完成三层验证:文件系统层、OpenCV/PIL 层、PyTorch/TensorFlow 张量层。这三步加起来不超过 3 分钟,却能省下你 8 小时 debug 时间。

5.1 文件层验证:确保路径、数量、权限 100% 一致

# 1. 确认 train/val/test 图像数量与预期一致(来自原始划分) echo "Train images:" $(ls images/train/*.jpg 2>/dev/null | wc -l) echo "Val images: " $(ls images/val/*.jpg 2>/dev/null | wc -l) echo "Test images: " $(ls images/test/*.jpg 2>/dev/null | wc -l) # 2. 确认 labels/ 与 images/ 同名文件数一致(关键!) train_imgs=$(ls images/train/*.jpg 2>/dev/null | wc -l) train_labels=$(ls labels/train/*.txt 2>/dev/null | wc -l) echo "Train match: $train_imgs vs $train_labels → $(($train_imgs == $train_labels))" # 3. 检查文件权限(尤其 Docker 容器内运行时) ls -l images/train/ | head -3 # 确保不是 -rw-------(只有 owner 可读),应为 -rw-r--r--

5.2 OpenCV/PIL 层验证:可视化抽查,肉眼确认内容正确性

写一个最小可视化脚本,随机抽取 5 张图及其标注,画框并显示:

import cv2 import numpy as np import random from pathlib import Path def visualize_sample(img_dir, label_dir, classes, n=5): img_paths = list(Path(img_dir).glob("*.jpg")) + \ list(Path(img_dir).glob("*.png")) sample_paths = random.sample(img_paths, min(n, len(img_paths))) for img_path in sample_paths: # 读图 img = cv2.imread(str(img_path)) if img is None: print(f"Failed to load {img_path}") continue # 读对应 label label_path = Path(label_dir) / f"{img_path.stem}.txt" if not label_path.exists(): print(f"No label for {img_path}") continue # 解析 YOLO 格式 with open(label_path, "r") as f: lines = f.readlines() h, w = img.shape[:2] for line in lines: parts = list(map(float, line.strip().split())) if len(parts) < 5: continue cls_id, xc, yc, bw, bh = parts[:5] # 反归一化 x1 = int((xc - bw/2) * w) y1 = int((yc - bh/2) * h) x2 = int((xc + bw/2) * w) y2 = int((yc + bh/2) * h) # 画框和文字 color = (0, 255, 0) if int(cls_id) == 0 else (255, 0, 0) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, classes[int(cls_id)], (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1) # 显示 cv2.imshow("Sample", img) cv2.waitKey(0) cv2.destroyAllWindows() # 调用 visualize_sample( img_dir="images/train", label_dir="labels/train", classes=["person", "car", "dog"] )

为什么这步不可跳过?
我曾遇到一个数据集,classes.txt写的是["cat", "dog"],但标注 TXT 中cls_id=0实际对应dog(因制作时索引偏移)。肉眼一看框在狗身上但标着 “cat”,立刻定位问题。这种语义错位,任何日志都无法告诉你。

5.3 张量层验证:在 DataLoader 输出端捕获真实 batch

这是最接近训练现场的验证。直接运行 DataLoader,打印 batch 的 shape 和 label 分布:

import torch from torch.utils.data import DataLoader from torchvision import transforms # 假设你已定义好 Dataset 类 # dataset = YourCustomDataset(img_dir="images/train", label_dir="labels/train", transform=...) # 构建 DataLoader(务必用 num_workers=0) loader = DataLoader(dataset, batch_size=4, shuffle=False, num_workers=0) # 获取第一个 batch for i, (imgs, targets) in enumerate(loader): print(f"Batch {i}:") print(f" Images shape: {imgs.shape}") # 应为 [4, 3, H, W] print(f" Targets keys: {list(targets.keys())}") print(f" Labels: {targets['labels']}") print(f" BBoxes: {targets['boxes'][:2]}") # 打印前两个框 break # 只看第一个 batch # 额外检查:是否有 NaN 或 Inf print(f"Images has NaN: {torch.isnan(imgs).any()}") print(f"Boxes has NaN: {torch.isnan(targets['boxes']).any()}")

关键指标解读:

  • imgs.shape中H, W应为你transform.Resize()设定的尺寸(如224),若仍是原始尺寸(如3000x2000),说明 transform 未生效;
  • targets['labels']应为tensor([0, 1, 0, 2])类型,若出现负数或超出num_classes,说明类别映射错误;
  • torch.isnan(...).any()为True,说明数据中有无效值(如除零、log(-1)),必须回溯到 Dataset 的__getitem__中排查。

从那以后我每次拿到新的深度学习训练数据集.zip,都会强制走一遍这三板斧:先tree和find看清物理结构,再用脚本校验文件对齐,接着按需转换格式,最后用可视化+张量打印双重确认。它不花哨,但像安全带一样,在你猛踩训练油门前,默默锁住所有可能飞出去的变量。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 5:42:17

【计算机毕设选题推荐】基于Spark的全球企业邮件安全合规数据可视化分析系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习

计算机毕设指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01;也可以在主页上或文末下与…

作者头像 李华
网站建设 2026/10/17 20:09:55

第 34 章 · 性能优化与别名陷阱

这一章能帮你少踩 Eigen 最经典的坑&#xff1a;别名问题、auto 陷阱&#xff0c;以及一系列性能优化技巧。34.1 别名问题&#xff1a;左右两边共用内存 别名&#xff08;aliasing&#xff09;&#xff1a;赋值语句左右两边引用同一块内存时&#xff0c;可能"边读边写&quo…

作者头像 李华
网站建设 2026/10/16 1:33:12

农产品商城小程序源码:Java毕业设计前后端跑通与二次开发指南

简介&#xff1a;这是一套面向高校计算机相关专业学生与初学者的农产品商城微信小程序毕业设计源码包&#xff0c;采用Java作为后端开发语言&#xff0c;配合小程序前端与MySQL数据库&#xff0c;适合用于毕业设计、课程设计或小程序入门实战练习。压缩包共1241个文件&#xff…

作者头像 李华
网站建设 2026/10/13 23:08:23

C/C++字符串与数字转换函数深度解析:从atoi到from_chars的选型与避坑指南

1. 字符串与数字互转&#xff1a;一个被严重低估的基础设施层做C/C开发的人&#xff0c;几乎每天都在和字符串与数字之间的转换打交道。配置文件解析、命令行参数处理、网络协议报文解析、日志格式化输出、CSV导入导出——这些场景背后都站着一组看似平平无奇、实则暗藏杀机的函…

作者头像 李华