【问题标题】:Splitting TensorFlow Dataset created with make_csv_dataset into 3 parts (X1_Train, X2_Train and Y_Train) for multi-input model将使用 make_csv_dataset 创建的 TensorFlow 数据集拆分为 3 部分(X1_Train、X2_Train 和 Y_Train)用于多输入模型
【发布时间】:2020-11-26 00:38:03
【问题描述】:

我正在使用 Tensorflow 2 和 Keras 训练深度学习模型。我使用tf.data.experimental.make_csv_dataset 读取了我的大 CSV 文件,然后将其拆分为训练和测试数据集。但是,我需要将我的训练数据集分成三部分,因为我的深度学习模型需要两组不同层的输入,所以我需要将[x1_train, x2_train],y_train 传递给model.fit

我的问题是如何将train_dataset 拆分为x1_train,x2_trainy_train? (有些功能应该在x1_train,有些功能应该在x2_train)。

我的代码:

def get_dataset(file_path, **kwargs):
  dataset = tf.data.experimental.make_csv_dataset(
      file_path,
      batch_size=64, 
      label_name=LABEL_COLUMN,
      na_value="?",
      num_epochs=1,
      ignore_errors=True, 
      **kwargs)
  return dataset

full_dataset = get_dataset(dataset_path)
full_dataset = full_dataset.shuffle(buffer_size=400000)
train_dataset = full_dataset.take(360000)
test_dataset = full_dataset.skip(360000)
test_dataset = test_dataset.take(40000)
x1_train =train_dataset[:,0:2820]
x2_train =train_dataset[:,2820:2822]
y_train=train_dataset[:,2822]
x1_test =x_test[:,0:2820]
x2_test =x_test[:,2820:2822]
y_test=test_dataset[:,2822]
model.fit([x1_train,x2_train],y_train,validation_data=[x1_test,x2_test],y_test, callbacks=callbacks_list, verbose=1,epochs=EPC)

错误信息:

x1_train =train_dataset[:,0:2820]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'TakeDataset' object is not subscriptable

【问题讨论】:

  • 在构建数据集之后,在做任何其他事情之前,使用tf.data.Dataset 对象的map 方法来拆分每个批次。
  • 您能告诉我如何使用 map 来拆分每个批次吗?
  • make_csv_dataset 返回的每个批次的第一个元素是一个字典,将列名映射到它们的值。因此,在 map 函数中,您可以将此字典拆分为两个单独的字典(并可能根据模型的输入格式将每个字典中的项目组合成一个单独的张量)。

标签: python tensorflow machine-learning keras tensorflow-datasets


【解决方案1】:

如 cmets 部分所述,您可以使用由 make_csv_dataset 返回的 map 方法 Dataset 对象,以便根据模型的预期输入格式拆分和组合样本。

例如,假设我们有一个包含以下数据的 CSV 文件:

a,b,c,d,e
1,2,3,4,111
5,6,7,8,222
9,10,11,12,333
13,14,15,16,444

现在,假设我们要使用 maks_csv_dataset 函数读取这个 CSV 文件;然而,我们的模型有两个输入层,分别命名为input1input2(使用Input 层的name 参数设置),其中input1 被输入列ab 中的特征值,并且input2 使用列 cd 中的特征值。此外,e 列是我们的目标(即标签)列。

所以让我们先读取这些数据,看看它是什么样子的:

from pprint import pprint

dataset = tf.data.experimental.make_csv_dataset(
      'data.csv',
      batch_size=2,
      label_name='e',
      num_epochs=1,
)

for x in dataset:
    pprint(x)

"""
The printed result:

(OrderedDict([('a',
               <tf.Tensor: shape=(2,), dtype=int32, numpy=array([5, 1], dtype=int32)>),
              ('b',
               <tf.Tensor: shape=(2,), dtype=int32, numpy=array([6, 2], dtype=int32)>),
              ('c',
               <tf.Tensor: shape=(2,), dtype=int32, numpy=array([7, 3], dtype=int32)>),
              ('d',
               <tf.Tensor: shape=(2,), dtype=int32, numpy=array([8, 4], dtype=int32)>)]),
 <tf.Tensor: shape=(2,), dtype=int32, numpy=array([222, 111], dtype=int32)>)
(OrderedDict([('a',
               <tf.Tensor: shape=(2,), dtype=int32, numpy=array([13,  9], dtype=int32)>),
              ('b',
               <tf.Tensor: shape=(2,), dtype=int32, numpy=array([14, 10], dtype=int32)>),
              ('c',
               <tf.Tensor: shape=(2,), dtype=int32, numpy=array([15, 11], dtype=int32)>),
              ('d',
               <tf.Tensor: shape=(2,), dtype=int32, numpy=array([16, 12], dtype=int32)>)]),
 <tf.Tensor: shape=(2,), dtype=int32, numpy=array([444, 333], dtype=int32)>)
"""

如您所见,每个批次的第一个元素是一个字典,将列名映射到各自的特征值。现在,让我们使用map 方法将这些特征值拆分并组合成适合我们模型的格式:

first_input_cols = ['a', 'b']
second_input_cols = ['c', 'd']

def split_and_combine_batch_samples(samples, targets):
    inp1 = []
    for k in first_input_cols:
        inp1.append(samples[k])
    inp2 = []
    for k in second_input_cols:
        inp2.append(samples[k])
    
    inp1 = tf.stack(inp1, axis=-1)
    inp2 = tf.stack(inp2, axis=-1)
    return {'input1': inp1, 'input2': inp2}, targets

dataset = dataset.map(split_and_combine_batch_samples)

for x in dataset:
    pprint(x)

"""
The printed values:

({'input1': <tf.Tensor: shape=(2, 2), dtype=int32, numpy=
array([[ 9, 10],
       [13, 14]], dtype=int32)>,
  'input2': <tf.Tensor: shape=(2, 2), dtype=int32, numpy=
array([[11, 12],
       [15, 16]], dtype=int32)>},
 <tf.Tensor: shape=(2,), dtype=int32, numpy=array([333, 444], dtype=int32)>)
({'input1': <tf.Tensor: shape=(2, 2), dtype=int32, numpy=
array([[5, 6],
       [1, 2]], dtype=int32)>,
  'input2': <tf.Tensor: shape=(2, 2), dtype=int32, numpy=
array([[7, 8],
       [3, 4]], dtype=int32)>},
 <tf.Tensor: shape=(2,), dtype=int32, numpy=array([222, 111], dtype=int32)>)

"""

就是这样!现在您可以进一步修改这个新修改的数据集(例如使用takeshuffle 等),准备好后,您可以将其提供给模型的fit 方法(不要忘记为不过你的模型)。

【讨论】:

  • 谢谢。我应用了您的代码并添加了一些额外的行:dataset = dataset.shuffle(buffer_size=400000)train_dataset = dataset.take(360000)test_dataset = test_dataset.take(40000)model.fit(train_dataset,validation_data=test_dataset, callbacks=callbacks_list, verbose=1,epochs=4),其中我的模型将“input1”和“input2”作为输入层名称。但是,现在训练停留在 Epoch 1/4 并且我没有收到任何错误。有什么问题?
  • @hsn15051 数据和您的模型有多大?
  • 数据集:412k 个样本。我总共有 2822 个功能。我正在训练一个完全连接的神经网络。我将 2820 个特征传递给一些层,然后将结果与另外 2 个特征连接起来,并提供给其他一些层,最后得到输出(我使用 tensorflow.org/guide/keras/functional)。我正在尝试优化架构,因此我需要在 GPU 上训练/验证数千个模型(我正在使用 MirroredStrategy。)。很快,我将拥有 50 万个功能,因此我需要扩大规模
  • @hsn15051 如果您等待更长的时间,培训不会显示任何进度/错误吗?模型中有多少参数?使用model.summary()model.count_params() 找出答案。您能否在训练开始时监控 GPU 利用率以查看它是否正在使用?
  • @scribbles 出现这样的错误很奇怪,因为这意味着samples 是一个元组而不是字典;但是,make_csv_dataset 将输入样本构造为特征字典,而不是元组(如我在答案中所示)。无论如何,要检查格式,请在构建的数据集中打印一个样本,然后相应地调整我的答案中的解决方案。没有看到你的代码/数据,我只能这么说。
猜你喜欢
  • 2021-02-15
  • 2021-02-27
  • 2018-02-24
  • 1970-01-01
  • 1970-01-01
  • 2020-12-29
  • 1970-01-01
  • 2018-04-29
  • 1970-01-01
相关资源
最近更新 更多