Keras (R) - 为什么所有输入的预测概率(二进制分类)都相同?
Keras (R) - Why are predicted probabilities (binary classification) the same for all inputs?
我使用 R 中的 Keras 来训练用于时间序列预测的完全连接的神经网络(二进制 class化)。为了使用标准的多层感知器来完成这项任务,我使用滑动 window 方法转换我的时间序列数据(向数据添加滞后输入特征)。因此,使用 1 个二进制标签、2 个输入时间序列和 2 个回溯(用于说明),转换后的数据具有以下结构:
label a b a.1 b.1 a.2 b.2
1 1 0.1 0.3 NA NA NA NA
2 1 0.2 0.2 0.1 0.3 NA NA
3 0 0.4 0.4 0.2 0.2 0.1 0.3
4 1 0.1 0.6 0.4 0.4 0.2 0.2
5 0 0.15 0.25 0.1 0.6 0.4 0.4
...
在省略 NA 行并删除 a 和 b 列后,使用的数据矩阵如下所示:
label a.1 b.1 a.2 b.2
3 0 0.2 0.2 0.1 0.3
4 1 0.4 0.4 0.2 0.2
5 0 0.1 0.6 0.4 0.4
...
在接下来的步骤中,我创建了两个阈值来拆分训练、验证和测试集中的数据,并根据这些阈值进行实际拆分:
## Thresholds
train_valid_split = 1700
valid_test_split = 1800
## amount of features (columns of data matrix minus first label column)
features = ncol(data_mlp) - 1
## Container for train, validation and test set (both input x and label y)
train_x = array(0, dim = c(train_valid_split, features))
train_y = array(0, dim = c(train_valid_split))
valid_x = array(0, dim = c((valid_test_split-train_valid_split), features))
valid_y = array(0, dim = c((valid_test_split-train_valid_split)))
test_x = array(0, dim = c((nrow(data_mlp)-valid_test_split), features))
test_y = array(0, dim = c((nrow(data_mlp)-valid_test_split)))
## Fill container with the data
train_x = data_mlp[1:train_valid_split, 2:ncol(data_mlp)]
train_y = data_mlp[1:train_valid_split, 1, drop=F]
valid_x = data_mlp[(train_valid_split+1):valid_test_split, 2:ncol(data_mlp)]
valid_y = data_mlp[(train_valid_split+1):valid_test_split, 1, drop=F]
test_x = data_mlp[(valid_test_split+1):nrow(data_mlp), 2:ncol(data_mlp)]
test_y = data_mlp[(valid_test_split+1):nrow(data_mlp), 1, drop=F]
计算验证步骤后,我训练并拟合了以下 Keras 模型:
## Validation steps
valid_steps = valid_test_split - train_valid_split
## Keras sequential model
model = keras_model_sequential() %>%
layer_dense(units = 32, input_shape = c(features),
activation = "relu") %>%
layer_dense(units = 1, activation = "sigmoid")
model %>% compile(
optimizer = "adam", # rmsprop
loss = "binary_crossentropy",
metrics = c("accuracy")
)
history = model %>% fit(
x = train_x,
y = train_y,
steps_per_epoch = 90,
epochs = 10,
validation_data = list(valid_x, valid_y),
validation_steps = valid_steps,
shuffle=FALSE
)
但是,当通过预测所有测试输入的 class 概率来评估测试集上的模型时,所有概率都完全相同。因此,每个输入都预测相同的 class。
> results = model %>% predict(test_x)
> results
[,1]
[1,] 0.5740806
[2,] 0.5740806
[3,] 0.5740806
[4,] 0.5740806
[5,] 0.5740806
[6,] 0.5740806
[7,] 0.5740806
...
我不明白为什么概率是一样的。我尝试使用不同的输入数据、不同的回顾(或多或少的滞后)、更多的时期、更多的 steps_per_epoch、不同的优化器、不同的单位数量等。预测的概率发生了变化,但它们始终相同所有输入。
有趣的是,具有相同验证和测试拆分以及相同回顾的相同数据的 lstm 模型不会产生相同的概率。 lstm 结果更合理。但我也想尝试 MLP + 滑动 window 方法,因为我读到它可能会在某些任务上产生更好的预测性能。所以我的猜测是我的数据准备(滑动 window)或模型架构有错误,但我无法弄清楚它是什么...
如果您对结果为何如此以及我如何更改它有任何建议,我将不胜感激。
非常感谢。
最好的火影
PS: 如果您需要更多信息,请告诉我它是什么,我会尽力回答。
代码中有错字,导致输入向量仅为零。现在它已修复并且代码可以正常工作。
我使用 R 中的 Keras 来训练用于时间序列预测的完全连接的神经网络(二进制 class化)。为了使用标准的多层感知器来完成这项任务,我使用滑动 window 方法转换我的时间序列数据(向数据添加滞后输入特征)。因此,使用 1 个二进制标签、2 个输入时间序列和 2 个回溯(用于说明),转换后的数据具有以下结构:
label a b a.1 b.1 a.2 b.2
1 1 0.1 0.3 NA NA NA NA
2 1 0.2 0.2 0.1 0.3 NA NA
3 0 0.4 0.4 0.2 0.2 0.1 0.3
4 1 0.1 0.6 0.4 0.4 0.2 0.2
5 0 0.15 0.25 0.1 0.6 0.4 0.4
...
在省略 NA 行并删除 a 和 b 列后,使用的数据矩阵如下所示:
label a.1 b.1 a.2 b.2
3 0 0.2 0.2 0.1 0.3
4 1 0.4 0.4 0.2 0.2
5 0 0.1 0.6 0.4 0.4
...
在接下来的步骤中,我创建了两个阈值来拆分训练、验证和测试集中的数据,并根据这些阈值进行实际拆分:
## Thresholds
train_valid_split = 1700
valid_test_split = 1800
## amount of features (columns of data matrix minus first label column)
features = ncol(data_mlp) - 1
## Container for train, validation and test set (both input x and label y)
train_x = array(0, dim = c(train_valid_split, features))
train_y = array(0, dim = c(train_valid_split))
valid_x = array(0, dim = c((valid_test_split-train_valid_split), features))
valid_y = array(0, dim = c((valid_test_split-train_valid_split)))
test_x = array(0, dim = c((nrow(data_mlp)-valid_test_split), features))
test_y = array(0, dim = c((nrow(data_mlp)-valid_test_split)))
## Fill container with the data
train_x = data_mlp[1:train_valid_split, 2:ncol(data_mlp)]
train_y = data_mlp[1:train_valid_split, 1, drop=F]
valid_x = data_mlp[(train_valid_split+1):valid_test_split, 2:ncol(data_mlp)]
valid_y = data_mlp[(train_valid_split+1):valid_test_split, 1, drop=F]
test_x = data_mlp[(valid_test_split+1):nrow(data_mlp), 2:ncol(data_mlp)]
test_y = data_mlp[(valid_test_split+1):nrow(data_mlp), 1, drop=F]
计算验证步骤后,我训练并拟合了以下 Keras 模型:
## Validation steps
valid_steps = valid_test_split - train_valid_split
## Keras sequential model
model = keras_model_sequential() %>%
layer_dense(units = 32, input_shape = c(features),
activation = "relu") %>%
layer_dense(units = 1, activation = "sigmoid")
model %>% compile(
optimizer = "adam", # rmsprop
loss = "binary_crossentropy",
metrics = c("accuracy")
)
history = model %>% fit(
x = train_x,
y = train_y,
steps_per_epoch = 90,
epochs = 10,
validation_data = list(valid_x, valid_y),
validation_steps = valid_steps,
shuffle=FALSE
)
但是,当通过预测所有测试输入的 class 概率来评估测试集上的模型时,所有概率都完全相同。因此,每个输入都预测相同的 class。
> results = model %>% predict(test_x)
> results
[,1]
[1,] 0.5740806
[2,] 0.5740806
[3,] 0.5740806
[4,] 0.5740806
[5,] 0.5740806
[6,] 0.5740806
[7,] 0.5740806
...
我不明白为什么概率是一样的。我尝试使用不同的输入数据、不同的回顾(或多或少的滞后)、更多的时期、更多的 steps_per_epoch、不同的优化器、不同的单位数量等。预测的概率发生了变化,但它们始终相同所有输入。
有趣的是,具有相同验证和测试拆分以及相同回顾的相同数据的 lstm 模型不会产生相同的概率。 lstm 结果更合理。但我也想尝试 MLP + 滑动 window 方法,因为我读到它可能会在某些任务上产生更好的预测性能。所以我的猜测是我的数据准备(滑动 window)或模型架构有错误,但我无法弄清楚它是什么...
如果您对结果为何如此以及我如何更改它有任何建议,我将不胜感激。
非常感谢。
最好的火影
PS: 如果您需要更多信息,请告诉我它是什么,我会尽力回答。
代码中有错字,导致输入向量仅为零。现在它已修复并且代码可以正常工作。