参考书籍:《Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow, 2nd Edition (Aurelien Geron [Géron, Aurélien])》
代码运行环境:win10 + python 3.9.12 + tensorflow 2.12.0 + cpu
可以通过先做一次随机的搜索,然后再缩小范围继续搜索。但是这样比较耗时。
from scikeras.wrappers import KerasRegressor
# 模型构建
def build_model(n_hidden=1, n_neurons=30, learning_rate=3e-3, input_shape=[8]):
model = keras.models.Sequential()
model.add(keras.layers.InputLayer(input_shape=input_shape))
for layer in range(n_hidden):
model.add(keras.layers.Dense(n_neurons, activation="relu"))
model.add(keras.layers.Dense(1))
optimizer = keras.optimizers.SGD(lr=learning_rate)
model.compile(loss="mse", optimizer=optimizer)
return model
# 下面这句会提示KerasRegressor过时
#keras_reg = keras.wrappers.scikit_learn.KerasRegressor(build_model)
keras_reg = KerasRegressor(build_fn=build_model, n_hidden=1, n_neurons=30, learning_rate=3e-3)
# 这是一种特殊的分布
from scipy.stats import reciprocal
from sklearn.model_selection import RandomizedSearchCV
param_distribs = {
"n_hidden": [0, 1, 2, 3],
"n_neurons": np.arange(1, 100),
"learning_rate": reciprocal(3e-4, 3e-2),
}
rnd_search_cv = RandomizedSearchCV(keras_reg, param_distribs, n_iter=10, cv=3)
rnd_search_cv.fit(X_train, y_train, epochs=100,
validation_data=(X_valid, y_valid),
callbacks=[keras.callbacks.EarlyStopping(patience=10)])
print(rnd_search_cv.best_params_)
print(rnd_search_cv.best_score_)
'''
{'learning_rate': 0.007527490846816864, 'n_hidden': 2, 'n_neurons': 92}
0.7710459058982116
'''
# 获取模型,随后可以保存
model = rnd_search_cv.best_estimator_.model
先pip安装
pip install scikeras
>>> scikeras.__version__
'0.10.0'
然后修改:(主要是要把build_model里要测试的参数写进KerasRegressor,不然会找不到参数)
keras_reg = KerasRegressor(build_fn=build_model, n_hidden=1, n_neurons=30, learning_rate=3e-3)
有一些用来调超参数的库:Hyperopt, Hyperas, kopt, Talos, Kera Tuner, Scikit-Optimize(skopt), Spearmint, Hyperband, Sklearn-Deap。google cloud ai平台也提供调优服务。
一些情况下,使用一个隐藏层就足以得到较好结果了,但是对于很复杂的问题,相比浅层网络,深层网络可以使用更少的神经元(指数级地少),并且效果更好。
Transfer learning:举个例子,我已经训练好一个识别图片中人脸的模型,如果我想再训练一个神经网络以识别发型,那我就可以把识别人脸的网络放在底层,重用参数,然后再加层、训练。
所以对于很多复杂问题来说,一般可以通过加层,直到overfitting,以提高准确率。对于更复杂的问题,一般先找别人训练好的、处理类似问题的网络,再训练,这样可以使用较少的训练数据,并且缩短训练时间。
一般来说,如果每层神经元数目太少,可能学习的能力会下降。我们也不会给每个隐藏层设计单独的神经元数目,因为这样参数太多了,而且每层神经元数目一样,很多时候表现是相同甚至更好的。通常来说,增加层数比增加每层的神经元数目更能提升性能。
这俩比较要紧,后面会专门写一篇。
可以从小的学习率(如10^-5)开始,到比较大的(如10),每个跑几百次,然后绘制loss曲线,找比较好的那个。
Batch size等一众超参数会影响学习率。如果调整了其他超参数,应该更新学习率。
大的batch size可以充分利用gpu,能缩短训练时间,但可能不稳定,最终模型可能不如小batch size的泛化能力强。一种策略是先用大的batch size(有人用到8192也没有generalization gap),然后用learning rate warmup,如果训练不稳定或者最终结果不好,再用小的batch size。
隐藏层用ReLU就挺好,输出层则根据任务决定。
一般不用调,用early stopping。