面向CNN的数据集拆分顺序选择及特征标签对应问询
问题描述
假设我有如下的tfDataSet张量:
data3d = [ [[7.042 9.118 0. 1. 1. 1. 1. 1. 0. 0. 1. ] [5.781 5.488 7.47 0. 0. 0. 0. 1. 1. 0. 0. ] [5.399 5.166 6.452 0. 0. 0. 0. 0. 1. 0. 0. ] [5.373 4.852 6.069 0. 0. 0. 0. 1. 1. 0. 0. ] [5.423 5.164 6.197 0. 0. 0. 0. 2. 1. 0. 0. ]] , [[ 5.247 4.943 6.434 0. 0. 0. 0. 1. 1. 0. 0. ] [ 5.485 8.103 8.264 0. 0. 0. 0. 1. 0. 0. 1. ] [ 6.675 9.152 9.047 0. 0. 0. 0. 1. 0. 0. 1. ] [ 6.372 8.536 11.954 0. 0. 0. 0. 0. 0. 0. 1. ] [ 5.669 5.433 6.703 0. 0. 0. 0. 0. 1. 0. 0. ]] , [[5.304 4.924 6.407 0. 0. 0. 0. 0. 1. 0. 0. ] [5.461 5.007 6.088 0. 0. 0. 0. 1. 1. 0. 0. ] [5.265 5.057 6.41 0. 0. 0. 0. 3. 0. 0. 1. ] [5.379 5.026 6.206 0. 0. 0. 0. 1. 1. 0. 0. ] [5.525 5.154 6. 0. 0. 0. 0. 1. 1. 0. 0. ]] , [[5.403 5.173 6.102 0. 0. 0. 0. 1. 1. 0. 0. ] [5.588 5.279 6.195 0. 0. 0. 0. 1. 1. 0. 0. ] [5.381 5.238 6.675 0. 0. 0. 0. 1. 0. 0. 1. ] [5.298 5.287 6.668 0. 0. 0. 0. 1. 1. 0. 0. ] [5.704 7.411 4.926 0. 0. 0. 0. 1. 1. 0. 0. ]] , ... ... ... ... ... ... ... ... ] tfDataSet = tf.convert_to_tensor(data3d)
张量中每个2D数组的前8列为特征,后3列为one-hot-encoded标签。
我希望将该张量输入CNN,需完成两项操作:
- (1) 将
data3d拆分为trainData3d、validData3d和testData3d - (2) 将上述三个数据集各自拆分为
featureData3d和labelData3d
现咨询:哪一步先执行成本最低?请说明原因;若先执行步骤2,如何保证特征与标签数据的对应关系?
解答
1. 优先执行步骤(1)拆分数据集,成本更低
从计算效率和内存占用来看,先拆分训练/验证/测试数据集,再拆分特征和标签的成本更低,核心原因有两点:
- 内存复用效率更高:TensorFlow的张量切片是视图而非立即复制数据,先拆分数据集时,只是基于原张量生成不同范围的引用,不会额外占用内存。如果先拆分特征和标签,会生成两个独立的大张量(特征张量、标签张量),后续再拆分三个数据集时,需要对两个大张量分别做切片,内存占用直接翻倍,且切片操作的计算量也会增加。
- 操作开销更小:先拆分出小尺寸的数据集子集,再对每个子集做特征和标签拆分,单步计算量远小于先处理整个大张量。比如原张量有1000个样本,先拆成700/200/100的子集,再分别拆分特征标签,每个拆分操作只处理对应数量的样本;如果先拆整个1000样本的特征和标签,再各自拆分三个子集,相当于要执行6次切片操作,整体计算量更大。
2. 若先执行步骤(2),保证特征与标签对应关系的方法
如果因场景限制必须先拆分特征和标签,只要保证拆分时使用完全一致的索引逻辑,就能确保特征与标签一一对应,具体有两种可靠方式:
方式一:基于统一索引同步拆分
先从原张量中提取特征和标签:
features = tfDataSet[..., :8] # 取所有样本的前8列作为特征 labels = tfDataSet[..., 8:] # 取所有样本的后3列作为标签
固定比例划分
计算划分索引后,对特征和标签使用完全相同的切片范围:
total_samples = tf.shape(tfDataSet)[0] train_size = int(0.7 * total_samples) valid_size = int(0.2 * total_samples) # 训练集 train_features = features[:train_size] train_labels = labels[:train_size] # 验证集 valid_features = features[train_size:train_size+valid_size] valid_labels = labels[train_size:train_size+valid_size] # 测试集 test_features = features[train_size+valid_size:] test_labels = labels[train_size+valid_size:]
随机划分
必须生成统一的随机索引,再用该索引同步提取特征和标签:
# 生成全局随机索引 indices = tf.random.shuffle(tf.range(total_samples)) # 按索引同步打乱特征和标签 shuffled_features = tf.gather(features, indices) shuffled_labels = tf.gather(labels, indices) # 后续按固定比例拆分逻辑同上 train_features = shuffled_features[:train_size] train_labels = shuffled_labels[:train_size]
方式二:用tf.data.Dataset绑定特征与标签
先把特征和标签打包成数据集对象,后续的拆分、打乱操作会自动维护对应关系:
# 绑定特征与标签为数据集 dataset = tf.data.Dataset.from_tensor_slices((features, labels)) # 划分数据集 train_size = int(0.7 * total_samples) valid_size = int(0.2 * total_samples) train_dataset = dataset.take(train_size) remaining = dataset.skip(train_size) valid_dataset = remaining.take(valid_size) test_dataset = remaining.skip(valid_size) # 如需单独提取特征和标签,可从数据集中取出 train_features = tf.stack([x for x, y in train_dataset]) train_labels = tf.stack([y for x, y in train_dataset])
这种方式更可靠,tf.data.Dataset会自动维护特征与标签的绑定关系,避免手动索引出错。
内容的提问来源于stack exchange,提问作者user366312
相关产品推荐
相关产品推荐

