第9章 使用Scikit-Learn调用Keras的模型

scikit-learn是最受欢迎的Python机器学习库。本章我们将使用scikit-learn调用Keras生成的模型。本章将:

  • 使用scikit-learn封装Keras的模型
  • 使用scikit-learn对Keras的模型进行交叉验证
  • 使用scikit-learn,利用网格搜索调整Keras模型的超参

我们开始吧。

9.1 简介

Keras在深度学习很受欢迎,但是只能做深度学习:Keras是最小化的深度学习库,目标在于快速搭建深度学习模型。基于SciPy的scikit-learn,数值运算效率很高,适用于普遍的机器学习任务,提供很多机器学习工具,包括但不限于:

  • 使用K折验证模型
  • 快速搜索并测试超参

Keras为scikit-learn封装了KerasClassifierKerasRegressor。本章我们继续使用第7章的模型。

9.2 使用交叉验证检验深度学习模型

Keras的KerasClassifierKerasRegressor两个类接受build_fn参数,传入编译好的模型。我们加入nb_epoch=150batch_size=10这两个参数:这两个参数会传入模型的fit()方法。我们用scikit-learn的StratifiedKFold类进行10折交叉验证,测试模型在未知数据的性能,并使用cross_val_score()函数检测模型,打印结果。

  1. # MLP for Pima Indians Dataset with 10-fold cross validation via sklearn
  2. from keras.models import Sequential
  3. from keras.layers import Dense
  4. from keras.wrappers.scikit_learn import KerasClassifier
  5. from sklearn.cross_validation import StratifiedKFold
  6. from sklearn.cross_validation import cross_val_score
  7. import numpy
  8. import pandas
  9. # Function to create model, required for KerasClassifier
  10. def create_model():
  11. # create model
  12. model = Sequential()
  13. model.add(Dense(12, input_dim=8, init='uniform', activation='relu')) model.add(Dense(8, init='uniform', activation='relu')) model.add(Dense(1, init='uniform', activation='sigmoid'))
  14. # Compile model
  15. model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) return model
  16. # fix random seed for reproducibility
  17. seed = 7
  18. numpy.random.seed(seed)
  19. # load pima indians dataset
  20. dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")
  21. # split into input (X) and output (Y) variables
  22. X = dataset[:,0:8]
  23. Y = dataset[:,8]
  24. # create model
  25. model = KerasClassifier(build_fn=create_model, nb_epoch=150, batch_size=10)
  26. # evaluate using 10-fold cross validation
  27. kfold = StratifiedKFold(y=Y, n_folds=10, shuffle=True, random_state=seed)
  28. results = cross_val_score(model, X, Y, cv=kfold)
  29. print(results.mean())

每轮训练会输出一次结果,加上最终的平均性能:

  1. ...
  2. Epoch 145/150
  3. 692/692 [==============================] - 0s - loss: 0.4671 - acc: 0.7803
  4. Epoch 146/150
  5. 692/692 [==============================] - 0s - loss: 0.4661 - acc: 0.7847
  6. Epoch 147/150
  7. 692/692 [==============================] - 0s - loss: 0.4581 - acc: 0.7803
  8. Epoch 148/150
  9. 692/692 [==============================] - 0s - loss: 0.4657 - acc: 0.7688
  10. Epoch 149/150
  11. 692/692 [==============================] - 0s - loss: 0.4660 - acc: 0.7659
  12. Epoch 150/150
  13. 692/692 [==============================] - 0s - loss: 0.4574 - acc: 0.7702
  14. 76/76 [==============================] - 0s
  15. 0.756442244065

比起手工测试,使用scikit-learn容易的多。

9.3 使用网格搜索调整深度学习模型的参数

使用scikit-learn封装Keras的模型十分简单。进一步想:我们可以给fit()方法传入参数,KerasClassifierbuild_fn方法也可以传入参数。可以利用这点进一步调整模型。

我们用网格搜索测试不同参数的性能:create_model()函数可以传入optimizerinit参数,虽然都有默认值。那么我们可以用不同的优化算法和初始权重调整网络。具体说,我们希望搜索:

  • 优化算法:搜索权重的方法
  • 初始权重:初始化不同的网络
  • 训练次数:对模型训练的次数
  • 批次大小:每次训练的数据量

所有的参数组成一个字典,传入scikit-learn的GridSearchCV类:GridSearchCV会对每组参数(2×3×3×3)进行训练,进行3折交叉检验。

计算量巨大:耗时巨长。如果模型小还可以取一部分数据试试。第7章的模型可以用,因为网络和数据集都不大(1000个数据内,9个参数)。最后scikit-learn会输出最好的参数和模型,以及平均值。

  1. # MLP for Pima Indians Dataset with grid search via sklearn
  2. from keras.models import Sequential
  3. from keras.layers import Dense
  4. from keras.wrappers.scikit_learn import KerasClassifier
  5. from sklearn.grid_search import GridSearchCV
  6. import numpy
  7. import pandas
  8. # Function to create model, required for KerasClassifier
  9. def create_model(optimizer='rmsprop', init='glorot_uniform'):
  10. # create model
  11. model = Sequential()
  12. model.add(Dense(12, input_dim=8, init=init, activation='relu')) model.add(Dense(8, init=init, activation='relu')) model.add(Dense(1, init=init, activation='sigmoid'))
  13. # Compile model
  14. model.compile(loss='binary_crossentropy', optimizer=optimizer, metrics=['accuracy']) return model
  15. # fix random seed for reproducibility
  16. seed = 7
  17. numpy.random.seed(seed)
  18. # load pima indians dataset
  19. dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")
  20. # split into input (X) and output (Y) variables
  21. X = dataset[:,0:8]
  22. Y = dataset[:,8]
  23. # create model
  24. model = KerasClassifier(build_fn=create_model)
  25. # grid search epochs, batch size and optimizer
  26. optimizers = ['rmsprop', 'adam']
  27. init = ['glorot_uniform', 'normal', 'uniform']
  28. epochs = numpy.array([50, 100, 150])
  29. batches = numpy.array([5, 10, 20])
  30. param_grid = dict(optimizer=optimizers, nb_epoch=epochs, batch_size=batches, init=init) grid = GridSearchCV(estimator=model, param_grid=param_grid)
  31. grid_result = grid.fit(X, Y)
  32. # summarize results
  33. print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
  34. for params, mean_score, scores in grid_result.grid_scores_:
  35. print("%f (%f) with: %r" % (scores.mean(), scores.std(), params))

用CPU差不多要5分钟,结果如下。我们发现使用均匀分布初始化,rmsprop优化算法,150轮,批尺寸为5时效果最好,正确率约75%:

  1. Best: 0.751302 using {'init': 'uniform', 'optimizer': 'rmsprop', 'nb_epoch': 150, 'batch_size': 5}
  2. 0.653646 (0.031948) with: {'init': 'glorot_uniform', 'optimizer': 'rmsprop', 'nb_epoch': 50, 'batch_size': 5}
  3. 0.665365 (0.004872) with: {'init': 'glorot_uniform', 'optimizer': 'adam', 'nb_epoch': 50, 'batch_size': 5}
  4. 0.683594 (0.037603) with: {'init': 'glorot_uniform', 'optimizer': 'rmsprop', 'nb_epoch': 100, 'batch_size': 5}
  5. 0.709635 (0.034987) with: {'init': 'glorot_uniform', 'optimizer': 'adam', 'nb_epoch': 100, 'batch_size': 5}
  6. 0.699219 (0.009568) with: {'init': 'glorot_uniform', 'optimizer': 'rmsprop', 'nb_epoch': 150, 'batch_size': 5}
  7. 0.725260 (0.008027) with: {'init': 'glorot_uniform', 'optimizer': 'adam', 'nb_epoch': 150, 'batch_size': 5}
  8. 0.686198 (0.024774) with: {'init': 'normal', 'optimizer': 'rmsprop', 'nb_epoch': 50, 'batch_size': 5}
  9. 0.718750 (0.014616) with: {'init': 'normal', 'optimizer': 'adam', 'nb_epoch': 50, 'batch_size': 5}
  10. 0.725260 (0.028940) with: {'init': 'normal', 'optimizer': 'rmsprop', 'nb_epoch': 100, 'batch_size': 5}
  11. 0.727865 (0.028764) with: {'init': 'normal', 'optimizer': 'adam', 'nb_epoch': 100, 'batch_size': 5}
  12. 0.748698 (0.035849) with: {'init': 'normal', 'optimizer': 'rmsprop', 'nb_epoch': 150, 'batch_size': 5}
  13. 0.712240 (0.039623) with: {'init': 'normal', 'optimizer': 'adam', 'nb_epoch': 150, 'batch_size': 5}
  14. 0.699219 (0.024910) with: {'init': 'uniform', 'optimizer': 'rmsprop', 'nb_epoch': 50, 'batch_size': 5}
  15. 0.703125 (0.011500) with: {'init': 'uniform', 'optimizer': 'adam', 'nb_epoch': 50, 'batch_size': 5}
  16. 0.720052 (0.015073) with: {'init': 'uniform', 'optimizer': 'rmsprop', 'nb_epoch': 100, 'batch_size': 5}
  17. 0.712240 (0.034987) with: {'init': 'uniform', 'optimizer': 'adam', 'nb_epoch': 100, 'batch_size': 5}
  18. 0.751302 (0.031466) with: {'init': 'uniform', 'optimizer': 'rmsprop', 'nb_epoch': 150, 'batch_size': 5}
  19. 0.734375 (0.038273) with: {'init': 'uniform', 'optimizer': 'adam', 'nb_epoch': 150, 'batch_size': 5}
  20. ...

9.4 总结

本章关于使用scikit-learn封装并测试神经网络的性能。总结一下:

  • 如何使用scikit-learn封装Keras模型
  • 如何使用scikit-learn测试Keras模型的性能
  • 如何使用scikit-learn调整Keras模型的超参

使用scikit-learn调整参数比手工调用Keras简便的多。

9.4.1 下一章

现在你已经知道如何如何在scikit-learn调用Keras模型:可以开工了。接下来几章我们会用Keras创造不同的端到端模型,从多类分类问题开始。