如何读取预处理分类文件夹文本以训练NLP/图文多模态模型?
同分类文件夹结构下多模态数据(文本+图像)的读取与预处理方案
1. 基于Keras Sequence实现稳定的自定义多模态生成器
Keras的Sequence类比手动写生成器更可靠,能直接和model.fit()配合,完美适配分类文件夹的存储结构。
核心流程:
- 遍历所有类别文件夹,批量收集文本、图像的文件路径,同时映射对应的类别标签(文件夹名转索引)
- 在初始化阶段完成文本Tokenizer的全局拟合(避免批量拟合导致词汇表不一致)
- 在
__getitem__方法中批量读取文本/图像,完成各自的预处理(文本分词、padding;图像resize、归一化等) - 同时返回图像、文本数据和对应标签,供多模态模型训练
示例代码框架:
import os import numpy as np from tensorflow.keras.utils import Sequence from tensorflow.keras.preprocessing.text import Tokenizer from tensorflow.keras.preprocessing.sequence import pad_sequences from tensorflow.keras.preprocessing.image import load_img, img_to_array class MultimodalGenerator(Sequence): def __init__(self, root_dir, img_size=(224,224), max_seq_len=128, batch_size=32, shuffle=True): self.root_dir = root_dir self.img_size = img_size self.max_seq_len = max_seq_len self.batch_size = batch_size self.shuffle = shuffle # 收集所有成对样本路径与标签 self.samples = [] self.labels = [] self.classes = sorted(os.listdir(root_dir)) self.class_map = {cls: idx for idx, cls in enumerate(self.classes)} for cls_name in self.classes: cls_dir = os.path.join(root_dir, cls_name) # 假设文本为.txt,图像为.jpg,文件名前缀一致(如sample_001.txt对应sample_001.jpg) for txt_file in os.listdir(cls_dir): if txt_file.endswith(".txt"): base_name = os.path.splitext(txt_file)[0] img_file = f"{base_name}.jpg" img_path = os.path.join(cls_dir, img_file) if os.path.exists(img_path): self.samples.append((os.path.join(cls_dir, txt_file), img_path)) self.labels.append(self.class_map[cls_name]) # 全局拟合文本Tokenizer self.tokenizer = Tokenizer() all_texts = [] for txt_path, _ in self.samples: with open(txt_path, "r", encoding="utf-8") as f: all_texts.append(f.read().strip()) self.tokenizer.fit_on_texts(all_texts) self.vocab_size = len(self.tokenizer.word_index) + 1 self.on_epoch_end() def __len__(self): return int(np.ceil(len(self.samples) / self.batch_size)) def __getitem__(self, idx): batch_start = idx * self.batch_size batch_end = min((idx + 1) * self.batch_size, len(self.samples)) batch_samples = self.samples[batch_start:batch_end] batch_labels = self.labels[batch_start:batch_end] # 批量处理文本 batch_texts = [] for txt_path, _ in batch_samples: with open(txt_path, "r", encoding="utf-8") as f: batch_texts.append(f.read().strip()) text_seqs = self.tokenizer.texts_to_sequences(batch_texts) text_data = pad_sequences(text_seqs, maxlen=self.max_seq_len) # 批量处理图像 img_data = [] for _, img_path in batch_samples: img = load_img(img_path, target_size=self.img_size) img = img_to_array(img) / 255.0 # 归一化 img_data.append(img) img_data = np.array(img_data) return [img_data, text_data], np.array(batch_labels) def on_epoch_end(self): if self.shuffle: combined = list(zip(self.samples, self.labels)) np.random.shuffle(combined) self.samples, self.labels = zip(*combined)
2. 用tf.data.Dataset构建高效多模态数据管道
适合大规模数据集,支持并行预处理、预取等性能优化,和TensorFlow生态无缝兼容。
核心流程:
- 用
tf.data.Dataset.list_files匹配所有文本文件路径 - 通过路径解析提取类别标签和对应图像路径
- 定义预处理函数,完成文本向量转换、图像解码resize
- 配置批量、打乱、预取等操作提升加载效率
示例代码框架:
import tensorflow as tf import os def parse_paths(txt_path): # 从路径提取类别标签 parts = tf.strings.split(txt_path, os.sep) cls_name = parts[-2] # 提前定义类别映射(需先遍历根目录获取所有类别) class_list = sorted(os.listdir(root_dir)) class_map = {cls: idx for idx, cls in enumerate(class_list)} label = tf.convert_to_tensor(class_map[cls_name.numpy().decode("utf-8")], dtype=tf.int32) # 生成对应图像路径 base_name = tf.strings.split(tf.strings.split(txt_path, ".")[0], os.sep)[-1] img_path = tf.strings.join([parts[0], parts[1], base_name + ".jpg"], separator=os.sep) return txt_path, img_path, label def preprocess_sample(txt_path, img_path, label): # 处理文本:用TextVectorization做向量转换(需提前适配全局文本) txt_content = tf.io.read_file(txt_path) txt_content = tf.strings.strip(txt_content) # 提前初始化并适配vectorize_layer:vectorize_layer.adapt(all_texts_list) txt_seq = vectorize_layer(txt_content) # 处理图像 img_content = tf.io.read_file(img_path) img = tf.image.decode_jpeg(img_content, channels=3) img = tf.image.resize(img, (224, 224)) / 255.0 return (img, txt_seq), label # 构建数据集 root_dir = "path/to/your/data" txt_files_ds = tf.data.Dataset.list_files(os.path.join(root_dir, "*", "*.txt")) # 解析路径+预处理 dataset = txt_files_ds.map( lambda x: tf.py_function(parse_paths, [x], [tf.string, tf.string, tf.int32]), num_parallel_calls=tf.data.AUTOTUNE ) dataset = dataset.map(preprocess_sample, num_parallel_calls=tf.data.AUTOTUNE) # 配置训练参数 dataset = dataset.shuffle(1000).batch(32).prefetch(tf.data.AUTOTUNE)
3. 关键注意事项
- 文本预处理全局拟合:Tokenizer或TextVectorization必须在所有训练文本上完成适配,不能仅在批量数据上拟合,避免词汇表不一致
- 样本配对校验:确保图像与文本文件名严格对应,可在初始化阶段加入校验逻辑,过滤缺失配对的样本
- 性能优化:Sequence类中避免重复读取文本;tf.data开启并行映射和预取,减少数据加载瓶颈
- 标签一致性:图像与文本的类别标签必须从同一文件夹名转换,避免标签错位
内容的提问来源于stack exchange,提问作者Ibrahima S Wade
相关产品推荐
相关产品推荐

