Keras多层感知器分类器无法学习。

3
我有这样的数据: enter image description here enter image description here 在29列中,我需要预测位于数据帧末尾的winPlacePerc,它取值范围在1(高百分比)到0(低百分比)之间。
在29个列中,其中25个是数字数据,3个是ID(对象),1个是分类数据。
我删除了所有的ID列(因为它们都是唯一的),并将分类数据(matchType)编码成独热编码(one hot encoding)。
在进行所有这些操作后,我剩下41列(经过one hot编码后)。 after one hot encoded 这就是我创建数据的方式。
X = df.drop(columns=['winPlacePerc'])
#creating a dataframe with only the target column
y = df[['winPlacePerc']]

现在我的X有40列,这是我的标签数据的样子。
> y.head()

winPlacePerc
0   0.4444
1   0.6400
2   0.7755
3   0.1667
4   0.1875

我也碰巧有非常大量的数据,例如40万条数据,因此为了测试目的,我正在使用sckit对其中的一部分进行训练。

X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.997, random_state=32)

这个数据集提供了近13,000条训练数据。

我正在使用Keras序列模型进行建模。

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dense, Dropout, Activation
from keras.layers.normalization import BatchNormalization
from keras import optimizers

n_cols = X_train.shape[1]

model = Sequential()

model.add(Dense(40, activation='relu', input_shape=(n_cols,)))
model.add(Dense(1, activation='sigmoid'))

model.compile(loss='mean_squared_error',
              optimizer='Adam',
              metrics=['accuracy'])

model.fit(X_train, y_train,
          epochs=50,
          validation_split=0.2,
          batch_size=20)

由于我的 y 轴标签数据在 0 和 1 之间,我使用 sigmoid 层作为输出层。

这是训练和验证的损失和准确率图。

enter image description here enter image description here

我还尝试将标签转换为二进制,并使用 step 函数和二元交叉熵损失函数。

之后,y 轴标签数据看起来像这样。

> y.head()

winPlacePerc
0   0
1   1
2   1
3   0
4   0

并改变损失函数

model.compile(loss='binary_crossentropy',
              optimizer='Adam',
              metrics=['accuracy'])

enter image description here

这种方法比以前更糟糕了。

正如您可以看到的那样,在某些 epoch 后它不再学习,即使我使用全部数据而不是其中的一部分也会出现此问题。

在此方法无效后,我还尝试了dropout添加更多层次,但都没有起作用。

现在我的问题是,我在哪里做错了?是层次结构错误还是数据错误?我该如何改进这个问题?


我认为你的损失函数可能是问题所在。尝试使用均方误差损失作为例子。 - Syrius
谢谢您指出这一点,我实际上使用了步进函数将整个标签数据转换为二进制0和1。为此,我使用了二元交叉熵,现在我将尝试在原始标签数据上使用均方误差进行实验。 - Saurabh
尝试添加更多层,将数值列归一化为-1、1,尝试调整学习率。 - Mihail Burduja
2个回答

1
from sklearn.preprocessing import StandardScaler

n_cols = X_train.shape[1]
ss = StandardScaler()
X_train = ss.fit_transform(X_train)

model = Sequential()    
model.add(Dense(128, activation='relu', input_shape=(n_cols,)))
model.add(Dense(64, activation='relu'))
model.add(Dense(16, activation='relu'))
model.add(Dense(1))

model.compile(loss='mean_squared_error',
              optimizer='Adam',
              metrics=['mean_squared_error'])

model.fit(X_train, y_train,
          epochs=50,
          validation_split=0.2,
          batch_size=20)
  • 规范化数据
  • 加强网络深度
  • 将最后一层设为线性

准确率不是回归的好指标。让我们看一个例子。

predictions: [0.9999999, 2.0000001, 3.000001]
ground Truth: [1, 2, 3]

Accuracy = No:of Correct / Total => 0 /3 = 0

准确度为0,但预测结果与实际情况非常接近。另一方面,均方误差会非常低,说明预测结果与实际情况的偏差非常小。


将MSE作为第二个度量添加(虽然不是错误的),但是多余的,实际上并没有提供任何有用的信息。解释一下为什么准确性在这里毫无意义可能会有帮助。 - desertnaut

1
为了澄清事情 - 这是一个回归问题,因此使用准确度并没有太多意义,因为你永远无法预测精确值0.23124。
首先,您肯定希望在将其传递到网络之前对值进行标准化(而不是独热编码)。尝试使用 StandardScaler
其次,我建议更改输出层中的激活函数 - 尝试使用 linear ,并且使用 mean_squared_error 作为损失应该可以。
为了验证您的模型"accuracy",请将预测结果与实际结果绘制在一起 - 这应该给您验证结果的机会。但是,话虽如此,您的损失已经看起来相当不错。
请查看this post,这应该能让您很好地掌握何时使用(激活和损失函数)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接