TensorFlow训练遇图片格式错误,如何无损转换数据集格式?
解决TensorFlow加载图片格式错误的方案
方案一:批量转换图片格式(保留原文件)
直接复制原数据集目录结构,将所有图片转换为TensorFlow兼容的PNG格式,原文件完全保留。使用PIL库实现:
from pathlib import Path from PIL import Image import os # 原数据集路径 original_dir = Path('/content/drive/MyDrive/skin') # 转换后的新数据集路径 converted_dir = Path('/content/drive/MyDrive/skin_converted') # 复制目录结构 for class_dir in original_dir.iterdir(): if class_dir.is_dir(): new_class_dir = converted_dir / class_dir.name os.makedirs(new_class_dir, exist_ok=True) # 遍历每个图片文件 for img_path in class_dir.glob('*'): try: # 打开图片并保存为PNG格式 with Image.open(img_path) as img: # 处理RGBA转RGB(如果有透明通道) if img.mode == 'RGBA': img = img.convert('RGB') new_img_path = new_class_dir / f'{img_path.stem}.png' img.save(new_img_path, format='PNG') except Exception as e: print(f"处理图片 {img_path} 出错: {e}")
转换完成后,修改训练代码中的数据集路径为/content/drive/MyDrive/skin_converted即可。
方案二:自定义数据加载管道(无需提前转换)
不修改原数据集,在加载时动态处理图片格式兼容问题,自定义加载函数替代image_dataset_from_directory:
import tensorflow as tf from pathlib import Path def load_and_preprocess_image(img_path, label, image_size=(256,256)): # 读取原始图片字节 img_bytes = tf.io.read_file(img_path) # 尝试用JPEG解码,失败则用PNG解码(覆盖多数格式问题) try: img = tf.image.decode_jpeg(img_bytes, channels=3) except tf.errors.InvalidArgumentError: img = tf.image.decode_png(img_bytes, channels=3) # 调整尺寸 img = tf.image.resize(img, image_size) # 适配EfficientNetV2的预处理 img = tf.keras.applications.efficientnet_v2.preprocess_input(img) return img, label def create_dataset(data_dir, validation_split=0.2, subset='training', seed=123, image_size=(256,256), batch_size=32): # 获取类别名称和映射关系 class_names = sorted([d.name for d in Path(data_dir).iterdir() if d.is_dir()]) class_to_idx = {name: idx for idx, name in enumerate(class_names)} # 收集所有图片路径和对应标签 img_paths = [] labels = [] for class_dir in Path(data_dir).iterdir(): if class_dir.is_dir(): for img_path in class_dir.glob('*'): img_paths.append(str(img_path)) labels.append(class_to_idx[class_dir.name]) # 划分训练/验证集 dataset = tf.data.Dataset.from_tensor_slices((img_paths, labels)) dataset = dataset.shuffle(len(img_paths), seed=seed) val_size = int(len(img_paths)*validation_split) if subset == 'training': dataset = dataset.skip(val_size) else: dataset = dataset.take(val_size) # 加载和预处理,启用多线程加速 dataset = dataset.map(lambda x,y: load_and_preprocess_image(x,y,image_size), num_parallel_calls=tf.data.AUTOTUNE) dataset = dataset.batch(batch_size).prefetch(tf.data.AUTOTUNE) return dataset, class_names # 创建训练和验证集 train, class_names = create_dataset('/content/drive/MyDrive/skin', subset='training') val, _ = create_dataset('/content/drive/MyDrive/skin', subset='validation') # 后续训练代码保持不变 num_classes = len(class_names) size = (250, 250) train = train.map(lambda x, y: (tf.image.resize(x, size), y)) val = val.map(lambda x, y: (tf.image.resize(x, size), y)) base_model = tf.keras.applications.EfficientNetV2L( include_top=False, weights="imagenet", input_shape=(250,250,3), classifier_activation="softmax", include_preprocessing=True, ) base_model.trainable = False inputs = tf.keras.Input(shape=(250, 250, 3)) x = base_model(inputs, training=False) x = tf.keras.layers.GlobalAveragePooling2D()(x) x = tf.keras.layers.Dropout(0.2)(x) outputs = tf.keras.layers.Dense(num_classes)(x) model = tf.keras.Model(inputs, outputs) model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy']) epochs=30 history = model.fit(train, epochs=epochs, validation_data=val)
补充说明
- 方案一适合一次性处理,后续训练直接用转换后的数据集,性能更稳定;
- 方案二适合不想额外占用存储空间的场景,动态处理图片;
- 错误本质通常是部分jpg图片编码不符合JFIF标准(比如伪jpg格式),转换或动态解码可解决该问题。
内容的提问来源于stack exchange,提问作者Hussien Adeb Alia
相关产品推荐
相关产品推荐

