【发布时间】:2018-07-06 08:02:37
【问题描述】:
我正在为一个类不是独占的多类问题构建一个 Keras 简单分类器模型。另外,我想添加带有交叉验证的 sklearn 详尽参数搜索。这是简单的模型:
def build_model(embedding_size):
model = Sequential()
model.add(Embedding(10000, embedding_size, input_length=100))
model.add(Flatten())
model.add(Dense(100, activation="relu"))
model.add(Dense(10, activation="sigmoid"))
model.compile(loss="binary_crossentropy", optimizer=Adam(), metrics=["accuracy"])
return model
batch_size = 64
epochs = 2
这是我的第一个手动交叉验证解决方案(没有参数搜索)。
embedding_size=32
skf = KFold(n_splits=3, shuffle=True)
valid_evals = []
for train_indices in skf.split(train_full_x):
kfold_train_x = train_full_x[train_indices[0]]
kfold_valid_x = train_full_x[train_indices[1]]
kfold_train_y = train_full_y[train_indices[0]]
kfold_valid_y = train_full_y[train_indices[1]]
model = build_model(embedding_size)
model.fit(kfold_train_x, kfold_train_y, batch_size=batch_size, epochs=epochs)
valid_evals.append(model.evaluate(kfold_valid_x, kfold_valid_y))
valid_evals = np.array(valid_evals)
print(valid_evals)
print("LogLoss: %.4f +/- %.4f" % (valid_evals.mean(axis=0)[0], valid_evals.std(axis=0)[0]))
print("Accuracy: %.2f%% +/- %.2f%%" % (valid_evals.mean(axis=0)[1] * 100, valid_evals.std(axis=0)[1] * 100))
结果相当一致:
[[0.05730336 0.98051361]
[0.0606665 0.98065738]
[0.05717109 0.9801999 ]]
LogLoss: 0.0584 +/- 0.0016
Accuracy: 98.05% +/- 0.02%
此代码运行良好,返回的验证准确度约为 98%,日志损失约为 0.06。然后我尝试添加GridSearchCV,而不是滚动我自己的参数搜索解决方案(在下面的示例中,搜索空间被简单地减少为一种选择)。
embedding_size = [32]
classifier = KerasClassifier(build_fn=build_model, epochs=epochs, batch_size=batch_size)
kfold = KFold(n_splits=3, shuffle=True)
param_grid = dict(embedding_size=embedding_size)
grid = GridSearchCV(estimator=classifier, param_grid=param_grid, return_train_score=True, cv=kfold)
results = grid.fit(train_x, train_y)
print("Best: %f using %s" % (results.best_score_, results.best_params_))
print(results.cv_results_)
这会返回
Best: 0.980600 using {'embedding_size': 32}
0.980600 (0.000187) with: {'embedding_size': 32}
{'split2_train_score': array([0.9882294]), 'mean_train_score': array([0.98768258]), 'split0_train_score': array([0.98707933]), 'split1_train_score': array([0.98773903]), 'std_train_score': array([0.00047121]), 'mean_fit_time': array([8.7320834]), 'split1_test_score': array([0.98079212]), 'split0_test_score': array([0.98066088]), 'std_fit_time': array([0.19671295]), 'rank_test_score': array([1], dtype=int32), 'std_test_score': array([0.00018667]), 'param_embedding_size': masked_array(data=[32], mask=[False], fill_value='?', dtype=object), 'std_score_time': array([0.00984431]), 'split2_test_score': array([0.98034717]), 'mean_score_time': array([0.58589784]), 'params': [{'embedding_size': 32}], 'mean_test_score': array([0.98060006])}
在这里,我得到了与 Keras 兼容的准确度,手动拆分训练/验证。但是,在我的问题中,相关的评分函数是日志丢失,所以我尝试将scoring="neg_log_loss" 作为参数添加到GridSearchCV。 但在这种情况下,我得到的分数类似于-0.29。
Best: -0.292518 using {'embedding_size': 32}
-0.292518 (0.002988) with: {'embedding_size': 32}
{'split1_train_score': array([-0.27363595]), 'std_score_time': array([0.01245312]), 'rank_test_score': array([1], dtype=int32), 'mean_test_score': array([-0.29251778]), 'std_fit_time': array([0.17412529]), 'split0_train_score': array([-0.27816725]), 'split1_test_score': array([-0.28917072]), 'mean_score_time': array([0.40924891]), 'params': [{'embedding_size': 32}], 'split0_test_score': array([-0.29195843]), 'split2_test_score': array([-0.2964242]), 'split2_train_score': array([-0.26628012]), 'mean_fit_time': array([8.75646718]), 'mean_train_score': array([-0.27269444]), 'std_test_score': array([0.00298751]), 'std_train_score': array([0.00489836]), 'param_embedding_size': masked_array(data=[32], mask=[False], fill_value='?', dtype=object)}
我预计符号会有所不同(由于neg_log_loss 的工作方式),但价值不会。
我做错了什么?或者...还有其他方法可以让GridSearchCV 处理交叉验证和日志丢失吗?
谢谢
注意我没有设置随机种子,而是多次运行这两个示例,因此随机性不应该是显示差异的原因。
【问题讨论】:
-
你得到负损失的事实让我认为 GridSearchCV 将 train_y 视为分类数字而不是稀疏/一个热门......
-
使用
neg_log_loss的负日志丢失似乎to be expected。 train_y 的形式为[[0, 0, 1, ...., 1, 0], [0, 1, 0, ...., 0, 1], ...] -
不存在“二进制多类”问题:“二进制”是指类的数量,而不是它们的编码方式;你的是一个多类多标签的
-
你确定 Keras 返回的 0.05 值是指 validation(而不是训练)错误吗?您没有在代码中显示这部分(我们也不会无缘无故要求minimum verifiable example)。
-
你好@desertnaut,我用这两种情况的代码扩展了我的答案并更正了问题分类。
标签: python machine-learning scikit-learn neural-network keras