keras 是一个深度学习库, 它封装了高效的数学运算库 Theano 和 TensorFlow
在这篇文章中, 你将会了解到如何使用 Keras 开发和评估神经网络模型来解决回归问题
在完成这个循序渐进的教程后, 你将知道:
如何加载 CSV 数据集并将其作为 Keras 库算法的输入
如何使用 Keras 建立一个回归问题的神经网络模型
如何使用 Keras 和 scikit-learn 交叉验证来评估模型
如何进行数据处理, 以提高 Keras 模型的性能
如何调整 Keras 模型的网络拓扑结构
现在就让我们开始吧
2017 年 3 月 更新: 基于 Keras 2.0.2,TensorFlow 1.0.1 和 Theano 0.9.0 版本的示例
Python Keras 深度学习库回归问题教程 照片由 Salim Fadhley 拍摄, 保留相应权利
1. 问题描述
我们在本教程中要解决问题基于波士顿房价数据集
你可以通过这个链接下载这个数据集, 并将其保存到当前工作目录, 命名为 housing.csv
该数据集描述了波士顿郊区房屋的 13 个数字量化属性, 并以每十万美元的平方数为单位模拟郊区房屋的价格因此, 这是一个回归预测建模问题输入属性包括犯罪率, 非零售商业面积, 化学污染浓度等等
这是机器学习研究中一个很好的问题因为所有的输入和输出属性都是量化的, 并且有多达 506 个实例可以使用, 所以这个问题研究起来很方便
使用均方误差 (MSE) 评估的模型的合理性能约为 20 平方每十万美元 (也就是每平方米 4500 美元) 这个数字对于我们的神经网络来说是一个很好的训练目标
2. 开发基准神经网络模型
在本节中, 我们将为回归问题创建一个基准神经网络模型
首先介绍本教程所需的所有函数和对象(所需的 Python 库)
- import numpy
- import pandas
- from keras.models import Sequential
- from keras.layers import Dense
- from keras.wrappers.scikit_learn import KerasRegressor
- from sklearn.model_selection import cross_val_score
- from sklearn.model_selection import KFold
- from sklearn.preprocessing import StandardScaler
- from sklearn.pipeline import Pipeline
在引入所需的库后, 我们现在可以从本地目录中的文件加载我们的数据集
UCI 机器学习库中的数据集实际上不是 CSV 格式, 而是用空格分隔两个属性我们可以使用 pandas 库轻松加载这个数据集然后, 分离输入 (X) 和输出 (Y) 属性, 以便更容易使用 Keras 和 scikit-learn 进行建模
- # load dataset
- dataframe = pandas.read_csv("housing.csv", delim_whitespace=True, header=None)
- dataset = dataframe.values
- # split into input (X) and output (Y) variables
- X = dataset[:,0:13]
- Y = dataset[:,13]
我们可以使用 scikit-learn 来创建, 并通过其易用的包装对象来评估 Keras 模型这样的方式是很理想的, 因为 scikit-learn 擅长评估模型, 并允许我们通过寥寥数行代码, 就能使用强大的数据预处理和模型评估方案
Keras 包装函数需要一个函数作为参数这个必须被定义的函数负责创建要评估的神经网络模型
下面我们来定义创建待评估的基准模型的函数这是一个简单的模型, 只有一个完全连接的隐藏层, 具有与输入属性相同数量的神经元 (13 个) 网络使用隐藏层 relu 激活函数没有激活函数用于输出层, 因为这是一个回归问题, 我们希望直接预测数值, 而不需要采用激活函数进行变换
我们会使用高效的 ADAM 优化算法以及优化的最小均方误差损失函数这将是我们用来评估多个模型性能时的统一度量这是一个可取的指标, 因为通过平方根计算输出一个错误值, 我们可以直接在问题的背景下 (十万美元为单位) 理解
- # define base model
- def baseline_model():
- # create model
- model = Sequential()
- model.add(Dense(13, input_dim=13, kernel_initializer='normal', activation='relu'))
- model.add(Dense(1, kernel_initializer='normal'))
- # Compile model
- model.compile(loss='mean_squared_error', optimizer='adam')
- return model
在 scikit-learn 库中用作回归计算估计器的 Keras 封装对象名为 KerasRegressor 我们创建一个 KerasRegressor
对象实例, 并将创建神经网络模型的函数名称, 以及一些稍后传递给模型 fit( ) 函数的参数, 比如最大训练次数, 每批数据的大小等两者都被设置为合理的默认值
我们还使用一个常量随机种子来初始化随机数生成器, 我们将为本教程中评估的每个模型重复整个过程 (相同的随机数) 这是为了确保我们始终如一地比较模型
- # fix random seed for reproducibility
- seed = 7
- numpy.random.seed(seed)
- # evaluate model with standardized dataset
- estimator = KerasRegressor(build_fn=baseline_model, nb_epoch=100, batch_size=5, verbose=0)
最后一步是评估这个基准模型我们将使用 10 倍交叉验证来评估模型
- kfold = KFold(n_splits=10, random_state=seed)
- results = cross_val_score(estimator, X, Y, cv=kfold)
- print("Results: %.2f (%.2f) MSE" % (results.mean(), results.std()))
运行这个代码为我们评估了模型在不可见的数据 (随机生成的) 上的性能结果输出均方误差, 包括 10 倍交叉验证中 (10 次) 评估的所有结果的平均值和标准差(平均方差)
Baseline: 31.64(26.82) MSE
3. 建模标准化数据集
波士顿房价数据集的一个重要问题是输入属性的对于房价的影响各不相同
在使用神经网络模型对数据进行建模之前, 准备好所要使用数据总是一种好的做法
从上文中的基准模型继续讨论, 我们可以使用输入数据集的标准化版本重新评估之前评估的模型
我们可以使用 scikit-learn 的 Pipeline 框架在交叉验证的每一步中在模型评估过程中对数据进行标准化处理这确保了在每个测试集在交叉验证中, 没有数据泄漏到训练数据
下面的代码创建一个 scikit-learn Pipeline, 首先标准化数据集, 然后创建和评估基准神经网络模型
- # evaluate model with standardized dataset
- numpy.random.seed(seed)
- estimators = []
- estimators.append(('standardize', StandardScaler()))
- estimators.append(('mlp', KerasRegressor(build_fn=baseline_model, epochs=50, batch_size=5,verbose=0)))
- pipeline = Pipeline(estimators)
- kfold = KFold(n_splits=10, random_state=seed)
- results = cross_val_score(pipeline, X, Y, cv=kfold)
- print("Standardized: %.2f (%.2f) MSE" % (results.mean(), results.std()))
运行示例提供了比使用没有经过标准化的数据的基准模型更好的性能, 降低了错误
Standardized: 29.54(27.87) MSE
这部分的进一步扩展可以对输出变量采用类似的缩放, 例如将其归一化到 0-1 的范围, 并在输出层上使用 Sigmoid 或类似的激活函数将输出预测缩小到通输入相同的范围
4. 调整神经网络拓扑
对于神经网络模型而言, 可以优化的方面有很多
可能效果最明显的优化之处是网络本身的结构, 包括层数和每层神经元的数量
在本节中, 我们将评估另外两个网络拓扑, 进一步提高模型的性能这两个结构分别是层数更深和层宽更宽的网络拓扑结构
4.1 评估层数更深的网络拓扑
一种改善神经网络性能的方法是增加更多层次这可能允许模型提取和重新组合数据中蕴含的高阶特性
在本节中, 我们将评估添加一个隐藏层到模型中的效果这就像定义一个新的函数一样简单, 这个函数将创建这个更深的模型, 大部分程序从上面的基准模型中的代码复制而来然后我们可以在第一个隐藏层之后插入一个新层在本例中, 新层包含一半的神经元(6 个)
- # define the model
- def larger_model():
- # create model
- model = Sequential()
- model.add(Dense(13, input_dim=13, kernel_initializer='normal', activation='relu'))
- model.add(Dense(6, kernel_initializer='normal', activation='relu'))
- model.add(Dense(1, kernel_initializer='normal'))
- # Compile model
- model.compile(loss='mean_squared_error', optimizer='adam')
- return model
我们的网络拓扑如下所示:
13 inputs - >[13 - >6] - >1 output
我们可以用与上面相同的方式来评估这个网络拓扑结构, 同时也使用上述数据集的标准化数据来提高性能
- numpy.random.seed(seed)
- estimators = []
- estimators.append(('standardize', StandardScaler()))
- estimators.append(('mlp', KerasRegressor(build_fn=larger_model, epochs=50, batch_size=5,verbose=0)))
- pipeline = Pipeline(estimators)
- kfold = KFold(n_splits=10, random_state=seed)
- results = cross_val_score(pipeline, X, Y, cv=kfold)
- print("Larger: %.2f (%.2f) MSE" % (results.mean(), results.std()))
运行代码, 这个模型确实表现出进一步改善, 从 28 降低到 24 平方每 10 万美元
Larger: 22.83 (25.33) MSE |
---|
4.2 评估层宽更宽的网络拓扑
另一种提高模型表现能力的方法是建立层宽更宽的网络
在本节中, 我们将评估保持浅层网络架构的效果, 但将隐藏层中的神经元数量增加近一倍
同样, 我们需要做的是定义一个新的函数来创建我们的神经网络模型在下面的代码中, 我们已经增加了隐藏层的神经元数量, 与基准模型相比从 13 个增加到 20 个
- # define wider model
- def wider_model():
- # create model
- model = Sequential()
- model.add(Dense(20, input_dim=13, kernel_initializer='normal', activation='relu'))
- model.add(Dense(1, kernel_initializer='normal'))
- # Compile model
- model.compile(loss='mean_squared_error', optimizer='adam')
- return model
我们的网络拓扑如下所示:
13 inputs - >[20] - >1 output
我们可以使用与上面相同的方案来评估更宽的网络拓扑结构:
- numpy.random.seed(seed)
- estimators = []
- estimators.append(('standardize', StandardScaler()))
- estimators.append(('mlp', KerasRegressor(build_fn=wider_model, epochs=100, batch_size=5,verbose=0)))
- pipeline = Pipeline(estimators)
- kfold = KFold(n_splits=10, random_state=seed)
- results = cross_val_score(pipeline, X, Y, cv=kfold)
- print("Wider: %.2f (%.2f) MSE" % (results.mean(), results.std()))
建立这个模型的误差进一步下降到 21 平方每 10 万美元左右这对于这个问题并不是一个槽糕的结果
Wider: 21.64(23.75) MSE
在付诸行动前很难猜到, 更宽的网络在这个问题上的表现会比更的网络结构更好该结果证明了在开发神经网络模型时进行实证检验的重要性
来源: https://cloud.tencent.com/developer/article/1040680