神经网络回归(Neural Network Regression),顾名思义,神经网络的灵感来自大脑。它们形成一个由相互连接的节点组成的网络,这些节点按层排列,构成一个模型。当输入数据对于标准的机器学习方法来说太大时,神经网络被用来逼近函数。
下图为前馈神经网络的基本结构。输入层的节点数等于输入数据特性的维数。每个隐藏层由任意数量的节点组成。层的数量取决于体系结构和问题的范围。而输出层只有在回归问题时才由一个节点组成。神经元持有一个数字,这个数字表示输入数据的相应特征值,也称为激活。对于单个层的每个节点,从上一层的每个节点的输入以不同的比例混合,然后传递到每个节点的后续层前馈神经网络,等等,直到信号到达最后一层,在那里做出回归决定 。所有这些都是矩阵运算。
接下来的问题是网络参数,需要对这些参数进行调优,使其最小化预测结果和真实值之间的损失。在大型模型中,可能有数百万个参数需要优化。采用梯度下降法作为优化函数,对权值/参数进行调整,使网络总误差最小。梯度描述了网络误差与单个权值之间的关系,即随着权值的调整,误差如何变化。随着训练过程的继续,网络会调整许多权重/参数,这样它们就可以映射输入数据,生成尽可能接近原始输出的输出。
如果给定预测未来事件的任何先验信息,神经网络就可以运行回归。例如,你可以根据一个人的重要数据预测心脏病发作。此外,您还可以根据web活动和元数据预测客户离开的可能性。
用Python编写的Keras深度学习库的回归教程
Keras是一个深度学习库,它封装了有效的数字库Theano和TensorFlow。
在这篇文章中,您将发现如何使用Keras开发和评估一个回归问题的神经网络模型。
完成这一步一步的教程后,你会知道:
- 如何加载CSV数据集并使其对Keras可用。
- 如何用Keras建立回归问题的神经网络模型。
- 如何使用scikit-learn with Keras使用交叉验证来评估模型。
- 如何执行数据准备,以提高与Keras模型的技能。
- 如何使用Keras调整模型的网络拓扑。
问题描述
我们将在本教程中看到的问题是波士顿房价数据集。
您可以下载此数据集,并将其保存到当前直接使用文件名house .csv的文件中(更新:从这里下载数据)。
该数据集描述了波士顿郊区13处房屋的数值属性,并关注于以数千美元为单位对这些郊区房屋的价格进行建模。因此,这是一个回归预测建模问题。输入属性包括犯罪率、非零售业务面积的比例、化学物质浓度等。
这是机器学习中一个被广泛研究的问题。使用它很方便,因为所有输入和输出属性都是数值的,并且有506个实例可供使用。
对于使用均方误差(MSE)评估的模型,合理的性能大约是20平方数千美元(如果开方,则为4500美元)。这是一个很好的目标,以我们的神经网络模型为目标。
建立基线神经网络模型
在本节中,我们将为回归问题创建一个基线神经网络模型。
让我们从包含本教程所需的所有函数和对象开始。
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格式的,属性是用空格分隔的。我们可以很容易地使用panda库加载它。然后我们可以分割输入(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]
我们可以使用Keras库提供的方便的包装器对象创建Keras模型,并使用scikit-learn对它们进行评估。这是可取的,因为scikit-learn擅长评估模型,并且允许我们使用功能强大的数据准备和模型评估方案,而只需要很少的代码行。
Keras包装器需要一个函数作为参数。我们必须定义的这个函数负责创建要评估的神经网络模型。
下面我们定义一个函数来创建要评估的基线模型。它是一个简单的模型,具有一个与输入属性相同数量的神经元完全连接的隐藏层(13)。该网络采用了良好的实践,如整流激活功能的隐层。输出层不使用激活函数,因为它是一个回归问题,我们感兴趣的是直接预测数值,而不需要转换。
采用有效的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包装器对象称为kerasregression。我们创建一个实例,并将创建神经网络模型的函数的名称以及稍后传递给模型的fit()函数的一些参数传递给它,比如训练轮数和批大小。这两个选项都设置为合理的默认值。
我们还使用一个常数随机种子初始化随机数生成器,在本教程中,我们将对每个评估的模型重复这个过程。这是为了确保我们一致地比较模型。
# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)
# evaluate model with standardized dataset
estimator = KerasRegressor(build_fn=baseline_model, epochs=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倍的均方误差,包括平均和标准差(平均方差)。
Baseline: 31.64 (26.82) MSE
对标准化数据集建模
波士顿房价数据集的一个重要问题是,输入属性的规模各不相同,因为它们衡量的是不同的数量。
在使用神经网络模型建模之前,准备好数据几乎总是很好的实践。
继续上面的基线模型,我们可以使用输入数据集的标准化版本重新评估相同的模型。
我们可以在模型评估过程中,在交叉验证的每个折叠中,使用 scikit-learn 的Pipeline框架执行标准化。这可确保每个测试集交叉验证折叠中不会将数据泄漏到训练数据中。
下面的代码创建了一个scikit-learn Pipeline ,该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 或类似的激活函数将输出预测缩小到相同的范围。
调整神经网络拓扑
对于神经网络模型,有许多问题可以优化。
也许最大的优势在于网络本身的结构,包括每一层的层数和神经元的数量。
在本节中,我们将评估另外两种网络拓扑,以进一步改进模型的性能。我们将研究更深层次和更广泛的网络拓扑结构。
评估更深层次的网络拓扑结构
提高神经网络性能的一个方法是增加更多的层。这可能允许模型提取和重新组合数据中嵌入的高阶特性。
在本节中,我们将评估向模型添加一个隐藏层的效果。这与定义一个新函数一样简单,该函数将创建这个更深层次的模型,该模型是从上面的基线模型复制而来的。然后,我们可以在第一个隐藏层之后插入新行。在这个例子中,大约有一半的神经元。
# 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
我们的网络拓扑现在看起来像:
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()))
运行这个模型确实显示了性能的进一步提高,从2.8万美元下降到2.4万美元。
Larger: 22.83 (25.33) MSE
评估更广泛的网络拓扑
提高模型表示能力的另一种方法是创建更广泛的网络。
在本节中,我们将评估保持浅层网络结构和将隐藏层神经元数量增加近一倍的效果。
同样,我们需要做的就是定义一个新的函数来创建我们的神经网络模型。在这里,我们将隐藏层的神经元数量从基线模型的13个增加到20个。
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
我们的网络拓扑现在看起来像:
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()))
建立这个模型确实看到误差进一步下降到大约2.1万美元。对于这个问题来说,这是一个不错的结果。
Wider: 21.64 (23.75) MSE
在这个问题上,很难想象一个更广泛的网络会比一个更深层次的网络表现得更好。研究结果表明,在建立神经网络模型时,经验检验的重要性。
总结
在本文中,您发现了Keras用于建模回归问题的深度学习库。
通过本教程,您学习了如何开发和评估神经网络模型,包括:
- 如何加载数据和开发基线模型。
- 如何使用标准化等数据准备技术提高性能。
- 如何在一个问题上设计和评估具有不同拓扑结构的网络。
关于这篇文章,你有什么问题吗?在评论中提出你的问题,我会尽我最大的努力来回答。