[英]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_train
或X_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) 中的数据,它没有找到正确的形状。
几个简单的步骤可以解决这个问题:
同样如上所述,较小的批量大小将是最好的。 如果您对 tensorflow 没有太多经验,我还建议您使用 model.train() 方法而不是处理梯度。 这可以节省您的代码,并且更容易确保您在训练期间正确处理 model。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.