繁体   English   中英

通过 dataframe 到 keras 顺序 model

[英]Passing dataframe to keras sequential model

我正在尝试使用 keras.Sequential() 构建和训练一个简单的 MLP model。 但是,当在每个训练时期之后,我尝试评估 model 在训练和测试数据上的当前状态时,我遇到了问题。

我在几个不同的数据集上遇到这个问题,其中一个是“CAR DETAILS FROM CAR DEKHO”数据集,你可以在这里找到它

到目前为止,这就是我正在做的事情:

import numpy as np
import tensorflow as tf
import pandas as pd

def main()

    ## read, preprocess and split data
    df_data = pd.read_csv('car_data_CAR_DEKHO.csv')
    df_data = pre_process(df_data)
    X_train, y_train, X_test, y_test = split_data(df_data)  ## -> these are PANDAS DATAFRAMES!


    train(X_train, X_test, y_train, y_test)


def train(X_train, X_test, y_train, y_test):

    ##--------------------
    ##   building model
    ##--------------------
    batch = 5000
    epochs = 500
    lr = 0.001


    data_iter = load_array((X_train, y_train), batch)


    initializer = tf.initializers.RandomNormal(stddev=0.01)
    net = tf.keras.Sequential()
    net.add(tf.keras.layers.Dense(1, kernel_initializer=initializer))
    loss = tf.keras.losses.MeanSquaredError()
    trainer = tf.keras.optimizers.SGD(learning_rate=lr)


    ##--------------#
    ##   training   #
    ##--------------#
    for epoch in range(1, epochs + 1):
        for X_batch, Y_batch in data_iter:
            with tf.GradientTape() as tape:
                l = loss(net(X_batch, training=True), Y_batch)
            grads = tape.gradient(l, net.trainable_variables)
            trainer.apply_gradients(zip(grads, net.trainable_variables))


        # test on train set after epoch
        y_pred_train = net(X_train)    ## ERROR HERE!!!
        l_train = loss(y_pred_train, y_train)
        y_pred_test = net(X_test)
        l_test = loss(y_pred_test, y_test)


def load_array(data_arrays, batch_size, is_train=True):
    """Construct a TensorFlow data iterator."""
    dataset = tf.data.Dataset.from_tensor_slices(data_arrays)
    if is_train:
        dataset = dataset.shuffle(buffer_size=1000)
    dataset = dataset.batch(batch_size)
    return dataset

def split_data(df_data):
    X = df_data.copy()
    y = X.pop('selling_price')
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
    return X_train, y_train, X_test, y_test

def pre_process(df_data):
    ## check NaNs and drop rows if any
    print(df_data.isnull().sum())
    df_data.dropna(inplace=True)
    ## drop weird outlier, turns out it has 1 km_driven
    df_data.drop([1312], inplace=True)

    ## features engineering
    df_data['name'] = df_data['name'].map(lambda x: x.split(' ')[0])
    df_data['owner'] = df_data['owner'].map(lambda x: x.split(' ')[0])
    df_data['selling_price'] = df_data['selling_price']/1000
    df_data_dummies = pd.get_dummies(df_data, drop_first=True)
    df_data_dummies = normalize(df_data_dummies)  ## this is a simple min-max scaling, I do it manually but you can use sklearn or something similar
    return df_data_dummies


def normalize(df):
    print('Data normalization:')
    result = df.copy()
    for feature_name in df.columns:
        if feature_name == 'selling_prize':
            pass
        else:
            max_value = df[feature_name].max()
            min_value = df[feature_name].min()
            result[feature_name] = (df[feature_name] - min_value) / (max_value - min_value)
            if result[feature_name].isnull().values.any():
                result.drop([feature_name], axis=1, inplace=True)
                print(f'Something wrong in {feature_name}, dropped.')
                print(f'now shape is {len(result)}, {len(result.columns)}')
    print(f'\treturning {len(result)}, {len(result.columns)}')
    return result

我得到了错误:

File "/home/lews/anaconda3/envs/tf/lib/python3.8/site-packages/tensorflow/python/keras/engine/input_spec.py", line 232, in assert_input_compatibility
    ndim = x.shape.rank
AttributeError: 'tuple' object has no attribute 'rank'

我猜这个错误是由于我将 X_train (这是一个数据帧)直接传递给 net.

我也尝试再次使用:

y_pred_train = net(tf.data.Dataset.from_tensor_slices(X_train))

就像创建训练批次时一样,但它返回另一个错误:

    File "/home/lews/anaconda3/envs/tf/lib/python3.8/site-packages/tensorflow/python/keras/engine/input_spec.py", line 201, in assert_input_compatibility
    raise TypeError('Inputs to a layer should be tensors. Got: %s' % (x,))
    TypeError: Inputs to a layer should be tensors. Got: <TensorSliceDataset shapes: (19,), types: tf.float64>

最后,我尝试使用:

y_pred_train = net.predict(X_train)

在这种情况下,奇怪的是我收到了一个 OOM 错误,指的是一个形状为 [76571,76571] 的张量:

File "<string>", line 3, in raise_from
tensorflow.python.framework.errors_impl.ResourceExhaustedError: OOM when allocating tensor with shape[76571,76571] and type double on /job:localhost/replica:0/task:0/device:CPU:0 by allocator cpu [Op:SquaredDifference]

但是 X_train 数据报具有形状 (76571, 19),所以我不明白发生了什么。

这样做的正确方法是什么?

您的代码大部分看起来都不错,问题一定出在您传递的数据上。 检查您提供的数据的内容和数据类型。

尝试将 pandas 切片转换为 np.arrays,重新检查它们的尺寸,然后将 np.arrays 输入到 load_array()。

也可以尝试小批量,比如 64 个(不是 5000 个)。

更新:显然,当您将X_batch传递给 model 时,您会传递 tf.tensor,但后来当您传递整个X_trainX_test - 您传递了 pd.DataFrames 并且 model 会感到困惑。

您应该只更改 2 行:

y_pred_train = net(tf.constant(X_train))  # pass TF.tensor - best

#alternative: 
y_pred_train = net(X_train.values)  # pass np.array - also good

y_pred_test = net(tf.constant(X_test)) # make similar change here

这个问题看起来与数据有关(正如 Poe Dator 所说)。 我相信正在发生的事情是,您的网络具有基于它接收的数据批次的一些输入形状。 然后,当您尝试对数据进行预测或调用网络时(这也会重新计算形状,因为它调用了 build() 函数),它会尝试将数据转换为预期的形状。 我认为它特别期望 (batch, 1, 19) 的形状,但是使用 (76571, 19) 中的数据,它没有找到正确的形状。

几个简单的步骤可以解决这个问题:

  1. 调用 net.summary() 以查看它认为在训练前后得到的形状
  2. 将输入形状提供给第一层,net.add(tf.keras.layers.Dense(1, kernel_initializer=initializer, input_shape=(1, 19)))
  3. 将 X 数据切成与训练数据相同的形状。
  4. 为您的数据添加一个维度,使其也是 (76571, 1, 19) 以显式塑造它。

同样如上所述,较小的批量大小将是最好的。 如果您对 tensorflow 没有太多经验,我还建议您使用 model.train() 方法而不是处理梯度。 这可以节省您的代码,并且更容易确保您在训练期间正确处理 model。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM