训练ResNet出现Invalid PNG错误 如何定位损坏的图像文件
百万级数据集下损坏PNG文件定位方案
不需要逐张人工排查,以下两种方法实测在百万张规模的数据集上都能高效跑完,且不会漏判:
- 方案1:对齐训练逻辑的tf数据管线捕获法(零漏判,优先用)
直接在现有tf数据集加载逻辑里加异常捕获,解码失败时打印对应文件路径即可,和训练时用的解码逻辑完全一致,不会出现“其他工具检测正常但训练时仍报错”的问题。参考代码:
普通8核CPU跑100万张图大概30-40分钟就能跑完,期间不需要人工值守。import tensorflow as tf import os def check_single_img(file_path): try: img_bytes = tf.io.read_file(file_path) # 这里的参数必须和你训练时的解码参数完全一致,比如通道数、解码格式 img = tf.io.decode_png(img_bytes, channels=3) # 加上训练时做的尺寸归一化逻辑,顺便排查尺寸异常的漏网之鱼 img = tf.image.resize(img, [224, 224]) # 替换成你实际用的模型输入尺寸 return 1, file_path except tf.errors.InvalidArgumentError: print(f"损坏文件: {file_path.numpy().decode('utf-8')}") return 0, file_path # 替换成你的数据集根目录 DATASET_ROOT = "./train_data" # 递归读取所有png文件路径 all_paths = [] for root, _, files in os.walk(DATASET_ROOT): for f in files: if f.lower().endswith(".png"): all_paths.append(os.path.join(root, f)) # 构建数据管线,开多线程跑速度很快 path_ds = tf.data.Dataset.from_tensor_slices(all_paths) check_ds = path_ds.map(check_single_img, num_parallel_calls=tf.data.AUTOTUNE).batch(128).prefetch(tf.data.AUTOTUNE) # 跑完全量数据,所有坏图路径都会被打印出来 for _, _ in check_ds: pass - 方案2:Pillow预筛法(速度更快,适合训练前前置校验)
如果想在启动训练前就把坏图清掉,可以用Pillow做批量检测,速度比走tf管线快30%左右。注意不要只打开文件头就判定正常,必须加载全量像素数据才能识别截断、数据区损坏的问题——你之前删了0字节文件还是报错,基本都是这类文件头正常、但像素数据缺失/损坏的文件。参考代码:import os from PIL import Image DATASET_ROOT = "./train_data" TARGET_SIZE = (224, 224) # 替换成你实际的图像尺寸 bad_files = [] for root, _, files in os.walk(DATASET_ROOT): for f in files: if not f.lower().endswith(".png"): continue fp = os.path.join(root, f) try: with Image.open(fp) as img: # 关键:必须调用load()读取全量像素,否则漏判率极高 img.load() if img.size != TARGET_SIZE: bad_files.append(f"尺寸异常: {fp}") except Exception as e: bad_files.append(f"解码失败: {fp}") for line in bad_files: print(line) - 避坑提醒
不要用只校验PNG文件头的shell脚本筛错,这类脚本只能识别文件头损坏的问题,超过80%的PNG解码错误都是文件头正常、像素数据区损坏/截断、后缀名不匹配(比如jpg强行改后缀成png)导致的,这类问题靠查文件头完全识别不出来。
内容的提问来源于stack exchange,提问作者D.A.
相关产品推荐
相关产品推荐

