3D CNN回归任务中云数据集与标签的构建及适配问题
解决方案:云序列回归任务的数据集构建、标签关联与数据加载适配
1. 重构数据集结构(抛弃分类式文件夹)
分类任务的「类别文件夹」结构完全不适合回归,建议采用**「序列+标签映射表」**的结构:
- 方式一:按序列分组存储
- 新建主文件夹
cloud_sequences,每个子文件夹对应一个12帧的序列,命名如seq_0001,内部存放该序列的12帧图片(按时间顺序命名,比如frame_00.jpg到frame_11.jpg) - 单独创建CSV文件
labels.csv,记录每个序列的ID和对应回归标签,格式如下:sequence_id, cloud_volume_label seq_0001, 0.35 seq_0002, 0.72 ...
- 新建主文件夹
- 方式二:集中存储所有帧,用CSV映射序列
- 所有帧放在同一个
cloud_frames文件夹下,按时间戳命名(比如20240501_0000.jpg、20240501_0005.jpg) - CSV文件中直接记录每个序列的12帧路径和标签,格式如下:
frame1, frame2, ..., frame12, cloud_volume_label cloud_frames/20240501_0000.jpg, cloud_frames/20240501_0005.jpg, ..., cloud_frames/20240501_0555.jpg, 0.41 ...
- 所有帧放在同一个
2. 标签与12帧序列的关联逻辑
核心是明确标签的时间对应规则,再用映射表绑定:
- 先确定标签含义:比如取当前12帧(T0-T55分钟)之后的第1帧(T60分钟)的区域云量数值作为标签,或者取未来30分钟(T60-T85分钟)的平均云量作为标签
- 确保每个12帧序列和标签是严格的时间对应关系:比如序列是[ t, t+5, ..., t+55 ]分钟的帧,标签是t+60分钟的云量值
- 标签值必须是连续数值(比如0到1的归一化云量占比),不能是分类标签
3. 替换flow_from_directory,用自定义数据加载器
flow_from_directory的class_mode仅支持分类相关模式(如categorical、binary),无法直接处理回归的连续标签,推荐以下两种方案:
方式一:使用tf.data.Dataset构建加载管道
import tensorflow as tf import pandas as pd def load_sequence(frame_paths, label): # 加载12帧并拼接成3D张量 (frames, height, width, channels) frames = [] for path in frame_paths: img = tf.io.read_file(path) img = tf.image.decode_jpeg(img, channels=3) img = tf.image.resize(img, (256, 256)) # 根据模型输入尺寸调整 img = tf.cast(img, tf.float32) / 255.0 # 归一化 frames.append(img) sequence = tf.stack(frames, axis=0) # shape: (12, 256, 256, 3) return sequence, label # 读取CSV标签表 df = pd.read_csv('labels.csv') # 提取帧路径列表和标签 frame_cols = [f'frame{i+1}' for i in range(12)] frame_paths_list = df[frame_cols].values.tolist() labels = df['cloud_volume_label'].values # 构建tf.data.Dataset dataset = tf.data.Dataset.from_tensor_slices((frame_paths_list, labels)) dataset = dataset.map(load_sequence, num_parallel_calls=tf.data.AUTOTUNE) dataset = dataset.batch(8) # 批量大小根据显存调整 dataset = dataset.prefetch(tf.data.AUTOTUNE)
方式二:继承keras.utils.Sequence实现自定义生成器
适合内存不足的场景,按需加载数据:
from tensorflow.keras.utils import Sequence import pandas as pd import cv2 import numpy as np class CloudSequence(Sequence): def __init__(self, csv_path, batch_size, img_size=(256,256)): self.df = pd.read_csv(csv_path) self.batch_size = batch_size self.img_size = img_size self.frame_cols = [f'frame{i+1}' for i in range(12)] def __len__(self): return len(self.df) // self.batch_size def __getitem__(self, idx): batch_df = self.df.iloc[idx*self.batch_size : (idx+1)*self.batch_size] sequences = [] labels = [] for _, row in batch_df.iterrows(): # 加载12帧 frames = [] for col in self.frame_cols: img = cv2.imread(row[col]) img = cv2.resize(img, self.img_size) img = img / 255.0 # 归一化 frames.append(img) sequence = np.stack(frames, axis=0) # shape: (12, 256, 256, 3) sequences.append(sequence) labels.append(row['cloud_volume_label']) return np.array(sequences), np.array(labels) # 使用生成器 train_generator = CloudSequence('train_labels.csv', batch_size=8) val_generator = CloudSequence('val_labels.csv', batch_size=8)
模型适配注意事项
确保模型的输出层是单个神经元+线性激活(对应回归任务):
from tensorflow.keras import layers, Model input_layer = layers.Input(shape=(12, 256, 256, 3)) x = layers.Conv3D(32, kernel_size=(3,3,3), activation='relu')(input_layer) x = layers.MaxPool3D(pool_size=(2,2,2))(x) # 后续添加更多Conv3D、Pool3D层... x = layers.Flatten()(x) x = layers.Dense(64, activation='relu')(x) output_layer = layers.Dense(1, activation='linear')(x) # 回归输出 model = Model(inputs=input_layer, outputs=output_layer) model.compile(optimizer='adam', loss='mse') # 用MSE作为回归损失
内容的提问来源于stack exchange,提问作者Emirhan Bilgiç
相关产品推荐
相关产品推荐

