Python中Keras深度学习库的回归教程
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 版本的示例
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
在付诸行动前很难猜到,更宽的网络在这个问题上的表现会比更的网络结构更好。该结果证明了在开发神经网络模型时进行实证检验的重要性。
概要
在这篇文章中,你了解了用于建模回归问题的 Keras 深度学习库用法。
通过本教程,你学习了如何开发和评估神经网络模型,其中包括:
- 如何加载数据和开发基准模型。
- 如何使用数据准备技术(如标准化)来提升性能。
- 如何设计和评估具有不同拓扑结构的网络。
- 我们的漏洞Webug 3.0中级进阶攻略(上)
- 【自然框架】QuickPager分页控件的总体介绍和在线演示
- 在C++中反射调用.NET(三) 使用非泛型集合的委托方法C++中的列表对象list C++传递集合数据给.NET创建泛型List实例反射静态方法反射调用索引器当委托遇到协变和逆变C++/CLI
- 如何使用树莓派自制网络监视器
- 利用雅虎小型企业服务平台的目录遍历漏洞查看客户的信用卡信息
- 【自然框架】QuickPager asp.net 分页控件的Ajax分页方式。
- 骑行在华盛顿 针对320万次共享单车骑行数据的分析
- 【自然框架】QuickPagerSQL——专门生成分页用的SQL的类库
- 【数据科学】数据科学中的 Spark 入门
- 【自然框架】QuickPager分页控件的单独的源码 V2.0.4.2。
- 用 iPhoneX 的 FaceID 刷脸解锁真的靠谱吗?
- 【自然框架】用CMS的栏目举例,聊一聊从“一层”到“三层”的变化
- java如何自定义鼠标指针
- 面向对象最重要的是“抽象”,三层最重要的也是“抽象”,没有抽象就不是真正的面向对象、三层。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- jQuery 文本属性值
- jQuery 属性操作
- 方老师聊Nginx知识点
- 《Java从入门到失业》第五章:继承与多态(5.1-5.7):继承
- 【赵渝强老师】Flink的DataSet算子
- Node.js 案发现场揭秘 —— 文件句柄泄露导致进程假死
- nacos配置问题
- Chevereto 配合 Picgo 打造个人相册/图床解决方案
- 从提高 Elasticsearch 搜索体验说开去......
- 又一个奇葩要求,Python是如何将“中文”转“拼音”的?
- localStorage中怎么存对象?
- vue中sessionStorage的使用
- 别再问我 Python 怎么识别数字验证码了!
- Java 多线程设计模式 —— Single Threaded Execution
- SAP Spartacus默认的baseSite是从源代码什么地方读取的