四、神经网络与深度学习
在这一章中,我们将讲述人工智能和机器学习中最令人兴奋的领域之一:深度学习。本章将介绍有效应用深度学习所必需的最重要的概念。我们将在本章中讨论的主题如下:
- 本质神经网络理论
- 在图形处理器或中央处理器上运行神经网络
- 神经网络的参数调整
- H2O 大规模深度学习
- 自动编码器深度学习(预处理)
深度学习产生于发展神经网络的人工智能领域。严格来说,任何大的神经网络都可以认为是深度学习。然而,深度架构的最新发展需要的不仅仅是建立大型神经网络。深度体系结构与普通多层网络的区别在于,深度体系结构由多个预处理和无监督步骤组成,这些步骤检测数据中的潜在维度,这些维度随后将被馈送到网络的其他阶段。关于深度学习要知道的最重要的一点就是通过这些深度架构来学习和转化新的特性,以提高整体的学习精度。因此,当前一代深度学习方法和其他机器学习方法之间的一个重要区别是,通过深度学习,特征工程的任务在一定程度上是自动化的。如果这些概念听起来很抽象,不要太担心,它们将在本章后面与实际例子一起阐明。这些深度学习方法引入了新的复杂性,这使得有效地应用它们非常具有挑战性。
最大的挑战是它们在训练、计算时间和参数调整方面的困难。本章将讨论这些困难的解决办法。
在过去的十年中,深度学习的有趣应用可以在计算机视觉、自然语言处理和音频处理中找到,例如由脸书的一个研究小组创建的脸书深度人脸项目,该研究小组部分由著名的深度学习学者扬·勒坤领导。深度人脸旨在从数字图像中提取和识别人脸。谷歌有自己的项目 DeepMind ,由杰弗里·辛顿领导。谷歌最近推出了 TensorFlow ,这是一个提供深度学习应用的开源库,将在下一章详细介绍。
在我们开始释放通过图灵测试和数学竞赛的自主智能代理之前,让我们稍微后退一步,从头开始。
神经网络架构
现在让我们关注神经网络是如何组织的,从它们的架构和一些定义开始。
学习流一路向前传递到输出的网络称为前馈神经网络。
一个基本的前馈神经网络可以很容易地用网络图来描述,如下图所示:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_01.jpg
在网络图中,可以看到这个架构由输入层、隐藏层和输出层组成。输入层包含特征向量(其中每个观察都有 n 特征),输出层在分类的情况下由每类输出向量的独立单元组成,在回归的情况下由单个数值向量组成。
单元之间的连接强度通过稍后传递给激活函数的权重来表示。激活函数的目标是将其输入转换为输出,使二进制决策更加可分。
这些激活函数最好是可微的,这样就可以用来学习。
广泛使用的激活功能是 sigmoid 和 tanh ,最近更是整流线性单元 ( ReLU )获得了牵引力。让我们比较一下最重要的激活函数,以便了解它们的优缺点。注意,我们提到了功能的输出范围和活动范围。输出范围只是函数本身的实际输出。然而,活动范围稍微复杂一些;这是梯度在最终权重更新中方差最大的范围。这意味着在该范围之外,梯度接近于零,并且不会增加学习期间的参数更新。这个接近于零的梯度的问题也被称为消失梯度问题,并通过 ReLU 激活功能来解决,该功能此时是较大神经网络最流行的激活:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_02.jpg
需要注意的是,需要将特征缩放至所选激活功能的激活范围。大多数最新的包都将此作为标准的预处理过程,因此您不需要自己做:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_27.jpg
Sigmoid 函数通常用于数学上的便利,因为它们的导数非常容易计算,我们将使用它来计算训练算法中的权重更新:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_28.jpg
有趣的是,tanh 和逻辑 sigmoid 函数是线性相关的,并且 tanh 可以被视为 sigmoid 函数的重新缩放版本,因此它的范围在-1和1之间。
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_29.jpg
该功能是更深层架构的最佳选择。它可以看作是一个斜坡函数,其范围位于0以上到无穷大。你可以看到,它比 sigmoid 函数更容易计算。这个函数的最大好处是它绕过了消失梯度问题。如果 ReLU 是深度学习项目中的一个选项,请使用它。
用于分类的 Softmax】
到目前为止,我们已经看到激活函数将值乘以权重向量后,在一定范围内进行转换。我们还需要在提供平衡类或概率输出(对数似然值)之前转换最后一个隐藏层的输出。
这将把前一层的输出转换成概率值,从而可以进行最终的类别预测。每当输出明显小于所有值的最大值时,这种情况下的幂运算将返回一个接近零的值;这样差异就被放大了:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_40.jpg
正向传播
现在我们已经了解了激活函数和网络的最终输出,让我们看看输入特征是如何通过网络提供最终的预测的。具有大量单元和连接的计算看起来可能是一项复杂的任务,但幸运的是,神经网络的前馈过程归结为一系列向量计算:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_26.jpg
通过执行以下步骤,我们得出最终预测:
- 用第一层和第二层之间的权重对输入执行点积,并用激活函数转换结果。
- 用第二和第三层之间的权重对第一隐藏层的输出执行点积。这些结果随后用第二隐藏层的每个单元上的激活函数进行转换。
- 最后,我们通过将向量乘以激活函数(softmax 用于分类)来得出我们的预测。
我们可以将网络中的每一层视为一个向量,并应用简单的向量乘法。更正式地说,这看起来如下:https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_30.jpg
=层 x 的权重向量
b1 和 b2 为偏差单位
f =激活功能
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_31.jpg
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_32.jpg
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_33.jpg
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_34.jpg
注
请注意,此示例基于单一隐藏层网络架构。
让我们对一个神经网络执行一个简单的前馈传递,该神经网络具有两个带有基本 NumPy 的隐藏层。我们将softmax功能应用于最终输出:
import numpy as np
import math
b1=0 #bias unit 1
b2=0 #bias unit 2
def sigmoid(x): # sigmoid function
return 1 /(1+(math.e**-x))
def softmax(x): #softmax function
l_exp = np.exp(x)
sm = l_exp/np.sum(l_exp, axis=0)
return sm
# input dataset with 3 features
X = np.array([ [.35,.21,.33],
[.2,.4,.3],
[.4,.34,.5],
[.18,.21,16] ])
len_X = len(X) # training set size
input_dim = 3 # input layer dimensionality
output_dim = 1 # output layer dimensionality
hidden_units=4
np.random.seed(22)
# create random weight vectors
theta0 = 2*np.random.random((input_dim, hidden_units))
theta1 = 2*np.random.random((hidden_units, output_dim))
# forward propagation pass
d1 = X.dot(theta0)+b1
l1=sigmoid(d1)
l2 = l1.dot(theta1)+b2
#let's apply softmax to the output of the final layer
output=softmax(l2)
注
请注意,偏置单元使函数能够上下移动,有助于更接近目标值。每个隐藏层由一个偏置单元组成。
反向传播
通过我们简单的前馈示例,我们已经迈出了训练模型的第一步。神经网络的训练非常类似于我们在其他机器学习算法中看到的梯度下降方法。也就是说,我们升级模型的参数,以便找到误差函数的全局最小值。神经网络的一个重要区别是,我们现在必须处理网络中的多个单元,我们需要独立训练这些单元。我们使用成本函数的偏导数来实现这一点,并计算当我们将特定参数向量改变一定量(学习速率)时,误差曲线下降了多少。我们从最接近输出的层开始,计算相对于损失函数导数的梯度。如果有隐藏层,我们移动到第二个隐藏层并更新权重,直到到达前馈网络中的第一层。
反向传播的核心思想与其他机器学习算法非常相似,重要的复杂性在于我们要处理多个层和单元。我们已经看到,网络中的每一层都由权重向量https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_30.jpg重量,这似乎令人生畏。然而,非常方便的是,我们可以使用矢量化运算。就像我们对向前传球所做的一样,我们计算梯度并更新应用于权重向量的权重(<https://github.com/OpenDocCN/freehttps://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_30.jpg
我们可以总结反向传播算法中的以下步骤:
-
前馈传递:我们随机初始化权重向量,并将输入与后续权重向量相乘,得到最终输出。
-
Calculate the error: We calculate the error/loss of the output of the feedforward step.
随机初始化权重向量。
-
反向传播到最后一个隐藏层(相对于输出)。我们计算这个误差的梯度,并朝着梯度的方向改变权重。我们通过将权重向量https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_30.jpg
-
Update the weights till the stopping criterion is reached (minimum error or number of training rounds):
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_41.jpg
我们现在已经讨论了任意两层神经网络的前馈通路;让我们在 NumPy 中将 SGD 的反向传播应用到上一个示例中使用的相同输入。特别注意我们如何升级重量参数:
import numpy as np
import math
def sigmoid(x): # sigmoid function
return 1 /(1+(math.e**-x))
def deriv_sigmoid(y): #the derivative of the sigmoid function
return y * (1.0 - y)
alpha=.1 #this is the learning rate
X = np.array([ [.35,.21,.33],
[.2,.4,.3],
[.4,.34,.5],
[.18,.21,16] ])
y = np.array([[0],
[1],
[1],
[0]])
np.random.seed(1)
#We randomly initialize the layers
theta0 = 2*np.random.random((3,4)) - 1
theta1 = 2*np.random.random((4,1)) - 1
for iter in range(205000): #here we specify the amount of training rounds.
# Feedforward the input like we did in the previous exercise
input_layer = X
l1 = sigmoid(np.dot(input_layer,theta0))
l2 = sigmoid(np.dot(l1,theta1))
# Calculate error
l2_error = y - l2
if (iter% 1000) == 0:
print "Neuralnet accuracy:" + str(np.mean(1-(np.abs(l2_error))))
# Calculate the gradients in vectorized form
# Softmax and bias units are left out for instructional simplicity
l2_delta = alpha*(l2_error*deriv_sigmoid(l2))
l1_error = l2_delta.dot(theta1.T)
l1_delta = alpha*(l1_error * deriv_sigmoid(l1))
theta1 += l1.T.dot(l2_delta)
theta0 += input_layer.T.dot(l1_delta)
现在看看如何随着每次通过网络而提高的准确度:
Neuralnet accuracy:0.983345051044
Neuralnet accuracy:0.983404936523
Neuralnet accuracy:0.983464255273
Neuralnet accuracy:0.983523015841
Neuralnet accuracy:0.983581226603
Neuralnet accuracy:0.983638895759
Neuralnet accuracy:0.983696031345
Neuralnet accuracy:0.983752641234
Neuralnet accuracy:0.983808733139
Neuralnet accuracy:0.98386431462
Neuralnet accuracy:0.983919393086
Neuralnet accuracy:0.983973975799
Neuralnet accuracy:0.984028069878
Neuralnet accuracy:0.984081682304
Neuralnet accuracy:0.984134819919
反向传播的常见问题
神经网络的一个常见问题是,在反向传播优化过程中,梯度会陷入局部最小值。当误差最小化被欺骗为看到一个最小值(图像中的点 S )时,这种情况就会发生,在该点处,通过峰值 S 实际上只是一个局部凸起:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_03.jpg
另一个常见的问题是当梯度下降错过全局最小值时,这有时会导致令人惊讶的低性能模型。这个问题被称为超调。
通过在模型超调时选择较低的学习速率或者在陷入局部极小值时选择较高的学习速率,可以解决这两个问题。有时这种调整仍然没有带来令人满意的快速收敛。最近,已经找到了一系列解决方案来缓解这些问题。我们刚刚介绍的对普通的SGDalgorithms进行微调的学习算法已经开发出来了。理解它们很重要,这样你就可以为任何给定的任务选择正确的任务。让我们更详细地介绍这些学习算法。
小批量反向传播
批处理梯度下降使用整个数据集计算梯度,但是反向传播 SGD 也可以使用所谓的小批处理,其中大小为 k (批处理)的数据集样本用于更新学习参数。每次更新之间的误差不规则量可以用小批量平滑掉,这样可以避免陷入和超过局部最小值。在大多数神经网络包中,我们可以改变算法的批量大小(我们将在后面看到)。根据训练示例的数量,10 到 300 之间的批量可能会有所帮助。
动量训练
动量是一种将先前权重更新的一部分添加到当前权重更新的方法:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_42.jpg
这里,先前权重更新的一部分被添加到当前权重更新中。高动量参数可以帮助加快收敛速度,更快地达到全局最小值。看公式,可以看到一个 v 参数。这相当于以学习速率https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_35.jpg向同一方向时,收敛速度随着向最小值的每一步而增加。这也消除了梯度之间一定幅度的不规则性。大多数包都有这个动量参数(我们将在后面的例子中看到)。当我们将该参数设置得太高时,我们必须记住,存在超过全局最小值的风险。另一方面,当我们将动量参数设置得太低时,系数可能会陷入局部极小值,也会减慢学习速度。动量系数的理想设置通常在. 5 和. 99 范围内。
内斯特罗夫气势
内斯特罗夫动量是经典动量的更新和改进版本。除了经典的动量训练外,它还会在梯度的方向向前看。换句话说,内斯特罗夫动量从 x 到 y 简单地移动了一步,并在这个方向上再移动一点,这样 x 到 y 就变成了 x 到 {y (v1 +1)} 在前一点给定的方向上。我将省略技术细节,但请记住,在收敛性方面,它始终优于正常的动量训练。如果内斯特罗夫势头有选择,那就利用它。
自适应梯度(ADAGRAD)
ADAGRAD 提供了特定于功能的学习率,利用了以前升级的信息:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_43.jpg
ADAGRAD 根据来自该参数先前迭代梯度的信息更新每个参数的学习速率。这是通过将每个项除以其先前梯度平方和的平方根来实现的。这使得学习率随着时间的推移而降低,因为每次迭代的平方和将继续增加。降低学习速率的优点是大大降低了超过全局最小值的风险。
弹性反向传播(RPROP)
RPROP 是一种自适应方法,它不查看历史信息,而仅查看训练实例上偏导数的符号,并相应地更新权重。
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_04.jpg
快速反向传播学习的直接自适应方法:RPROP 算法。马丁·里德米勒 1993
RPROP 是一种自适应方法,它不查看历史信息,而仅查看训练实例上偏导数的符号,并且相应地更新权重。仔细检查前面的图像,我们可以看到,一旦误差的偏导数改变其符号( > 0 或 < 0 ),梯度开始向相反的方向移动,导致对超调的全局最小校正。然而,如果这个符号没有任何变化,就会朝着全局最小值迈出更大的步伐。许多文章已经证明了 RPROP 相对于 ADAGRAD 的优越性,但在实践中,这并没有得到一致的证实。另一件需要记住的重要事情是,RPROP 在迷你批次中无法正常工作。
rmsprep
RMSProp 是一种自适应学习方法,不会降低学习速度:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_44.jpg
RMSProp 也是一种自适应学习方法,它利用了动量学习和 ADAGRAD 的思想,重要的补充是它避免了学习速率随时间的收缩。使用这种技术,收缩由梯度平均值上的指数衰减函数控制。
以下是梯度下降优化算法的列表:
| |应用
|
常见问题
|
实用技巧
|
| — | — | — | — |
| 常规 SGD | 广泛适用 | 过冲,陷入局部最小值 | 与动量和小批量一起使用 |
| adagrad | 较小的数据集< 10k | 缓慢收敛 | 使用. 01 到. 1 之间的学习率。广泛适用。处理稀疏数据 |
| 丙肝 | 大于 10k 的较大数据集 | 不适用于小批量 | 尽可能使用 RMSProp |
| rmsprep | 大于 10k 的较大数据集 | 对宽而浅的网无效 | 对于宽稀疏数据特别有用 |
神经网络学习什么以及如何学习
既然我们已经对各种形式的反向传播有了基本的了解,是时候解决神经网络项目中最困难的任务了:我们如何选择正确的架构?神经网络的一个关键能力是架构内的权重可以将输入转换到非线性特征空间,从而解决非线性分类(决策边界)和回归问题。让我们做一个简单而有见地的练习,在neurolab包中演示这个想法。我们只会用neurolab进行短暂的锻炼;对于可扩展学习问题,我们将提出其他方法。
首先,用pip安装neurolab包装。
从终端安装neurolab:
> $pip install neurolab
通过这个例子,我们将使用numpy生成一个简单的非线性余弦函数,并训练一个神经网络来从一个变量预测余弦函数。我们将设置几个神经网络架构,以了解每个架构预测余弦目标变量的能力:
import neurolab as nl
import numpy as np
from sklearn import preprocessing
import matplotlib.pyplot as plt
plt.style.use('ggplot')
# Create train samples
x = np.linspace(-10,10, 60)
y = np.cos(x) * 0.9
size = len(x)
x_train = x.reshape(size,1)
y_train = y.reshape(size,1)
# Create network with 4 layers and random initialized
# just experiment with the amount of layers
d=[[1,1],[45,1],[45,45,1],[45,45,45,1]]
for i in range(4):
net = nl.net.newff([[-10, 10]],d[i])
train_net=nl.train.train_gd(net, x_train, y_train, epochs=1000, show=100)
outp=net.sim(x_train)
# Plot results (dual plot with error curve and predicted values)
import matplotlib.pyplot
plt.subplot(2, 1, 1)
plt.plot(train_net)
plt.xlabel('Epochs')
plt.ylabel('squared error')
x2 = np.linspace(-10.0,10.0,150)
y2 = net.sim(x2.reshape(x2.size,1)).reshape(x2.size)
y3 = outp.reshape(size)
plt.subplot(2, 1, 2)
plt.suptitle([i ,'hidden layers'])
plt.plot(x2, y2, '-',x , y, '.', x, y3, 'p')
plt.legend(['y predicted', 'y_target'])
plt.show()
现在仔细观察误差曲线如何表现,以及当我们给神经网络增加更多层时,预测值如何开始接近目标值。
通过零隐藏层,神经网络通过目标值投射一条直线。误差曲线在拟合不良的情况下迅速降至最小值:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_05.jpg
有了一个隐藏层,网络开始接近目标输出。观察误差曲线有多不规则:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_06.jpg
通过两个隐藏层,神经网络更接近目标值。误差曲线下降更快,不规则性更小:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_07.jpg
一个几乎完美的符合三个隐藏层。误差曲线下降得更快(在 220 迭代左右)。
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_08.jpg
上图中的橙色线是误差如何随每个时期下降的可视化图(整个训练集)。它向我们表明,我们需要通过训练集的一定次数才能达到全局最小值。如果您更仔细地检查这个误差曲线,您会发现误差曲线在每个体系结构中的表现是不同的。下图(虚线)显示了预测值如何开始接近目标值。由于没有隐藏层,神经网络无法检测非线性函数,但一旦我们添加隐藏层,网络就会开始学习非线性函数和日益复杂的函数。事实上,神经网络可以学习任何可能的功能。这种学习每一个可能函数的能力被称为通用近似定理。我们可以通过向神经网络添加隐藏的神经元(单元和层)来修改这种近似。然而,我们确实需要谨慎,不要过量食用;增加大量的层和单元将导致训练数据的记忆,而不是拟合可推广的函数。通常,网络中的层数太多会影响预测的准确性。
选择合适的架构
正如我们已经看到的,可能的神经网络结构的组合空间几乎是无限的。那么如何提前知道哪种架构会适合我们的项目呢?我们需要某种启发式或经验法则来为特定任务设计架构。在最后一节中,我们使用了一个只有一个输出和一个特性的简单示例。然而,我们称之为深度学习的最近一波神经网络架构非常复杂,能够为任何给定任务构建正确的神经网络架构至关重要。正如我们之前提到的,典型的神经网络由输入层、一个或多个隐藏层和输出层组成。让我们详细看看架构的每一层,这样我们就可以有一种为任何给定任务设置正确架构的感觉。
输入层
当我们提到输入层时,我们基本上是在谈论将被用作神经网络的输入的特征。所需的预处理步骤高度依赖于数据的形状和内容。如果我们有在不同尺度上测量的特征,我们需要重新缩放和归一化数据。在我们有大量特征的情况下,像主成分分析或奇异值分解这样的降维技术将变得值得推荐。
在学习之前,可以对输入应用以下预处理技术:
- 标准化、缩放和异常值检测
- 降维(奇异值分解和因子分析)
- 预处理(自动编码器和玻尔兹曼机器)
我们将在接下来的例子中介绍这些方法。
隐藏层
我们如何选择隐藏层中的单位数量?我们在网络中增加了多少隐藏层?我们在前面的例子中已经看到,没有隐藏层的神经网络不能学习非线性函数(无论是在回归的曲线拟合中还是在分类的决策边界中)。因此,如果有一个非线性模式或决策边界要投影,我们将需要隐藏层。说到选择隐藏层中的单位数量,我们一般希望隐藏层中的单位数量少于输入层中的单位数量,而单位数量多于输出单位数量:
- 优选地,比输入特征的数量更少的隐藏单元
- 超过输出单位数量的单位(分类类别)
有时,当目标函数的形状非常复杂时,就会出现异常。在我们添加的单位多于输入尺寸的情况下,我们添加特征空间的扩展。具有这种层的网络通常被称为广域网。
复杂网络可以学习更复杂的函数,但这并不意味着我们可以简单地继续堆叠层。建议控制层数,因为层数过多会导致过拟合、较高的 CPU 负载甚至是欠拟合的问题。通常一到四个隐藏层就足够了。
型式
最好使用一到四层作为起点。
输出层
每个神经网络都有一个输出层,就像输入层一样,高度依赖于所讨论的数据的结构。对于分类,我们一般会使用softmax功能。在这种情况下,我们应该使用与我们预测的类别数量相同的单位数量。
作用中的神经网络
让我们获得一些训练神经网络进行分类的实践经验。我们将使用 sknn,用于千层面和派尔恩 2 的 Scikit-learn 包装纸。您可以在https://github.com/aigamedev/scikit-neuralnetwork/了解更多关于套餐的信息。
我们将使用这个工具,因为它的实用和 Pythonic 接口。这是对像 Keras 这样更复杂的框架的很好的介绍。
sknn 库可以在中央处理器或图形处理器上运行,无论您喜欢哪个。请注意,如果您选择使用图形处理器,sknn 将运行在:
For CPU (most stable) :
# Use the GPU in 32-bit mode, from sknn.platform import gpu32
from sknn.platform import cpu32, threading
# Use the CPU in 64-bit mode.from sknn.platform import cpu64
from sknn.platform import cpu64, threading
GPU:
# Use the GPU in 32-bit mode,
from sknn.platform import gpu32
# Use the CPU in 64-bit mode.
from sknn.platform import cpu64
【sknn 的并行化
我们可以通过以下方式利用并行处理,但是这个有一个警告。它不是最稳定的方法:
from sknn.platform import cpu64, threading
我们可以指定 Scikit-学会利用特定数量的线程:
from sknn.platform import cpu64, threads2 #any desired amount of threads
当您指定了适当数量的线程后,您可以通过在交叉验证中实现n_jobs=nthreads来并行化您的代码。
既然我们已经涵盖了最重要的概念并准备好了我们的环境,让我们实现一个神经网络。
对于这个例子,我们将使用方便但相当枯燥的 Iris 数据集。
之后,我们将以标准化和缩放的形式应用预处理,并开始构建我们的模型:
import numpy as np
from sklearn.datasets import load_iris
from sknn.mlp import Classifier, Layer
from sklearn import preprocessing
from sklearn.cross_validation import train_test_split
from sklearn import cross_validation
from sklearn import datasets
# import the familiar Iris data-set
iris = datasets.load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris.data,
iris.target, test_size=0.2, random_state=0)
这里,我们对输入进行预处理、归一化和缩放:
X_trainn = preprocessing.normalize(X_train, norm='l2')
X_testn = preprocessing.normalize(X_test, norm='l2')
X_trainn = preprocessing.scale(X_trainn)
X_testn = preprocessing.scale(X_testn)
让我们设置我们的神经网络结构和参数。让我们从一个具有两个层的神经网络开始。在Layer部分,我们单独指定每一层的设置。(我们将在 Tensorflow 和 Keras 中再次看到这种方法。)Iris 数据集由四个特征组成,但因为在这种特殊情况下宽的神经网络工作得相当好,我们将在每个隐藏层中使用 13 个单元。请注意,sknn 默认应用 SGD:
clf = Classifier(
layers=[
Layer("Rectifier", units=13),
Layer("Rectifier", units=13),
Layer("Softmax")], learning_rate=0.001,
n_iter=200)
model1=clf.fit(X_trainn, y_train)
y_hat=clf.predict(X_testn)
scores = cross_validation.cross_val_score(clf, X_trainn, y_train, cv=5)
print 'train mean accuracy %s' % np.mean(scores)
print 'vanilla sgd test %s' % accuracy_score(y_hat,y_test)
OUTPUT:]
train sgd mean accuracy 0.949909090909
sgd test 0.933333333333
在训练中取得了不错的成绩,但我们可能会做得更好。
我们讨论了内斯特罗夫动量如何将长度缩短到全球最小值;让我们用nesterov来运行这个算法,看看是否能提高精度和改善收敛性:
clf = Classifier(
layers=[
Layer("Rectifier", units=13),
Layer("Rectifier", units=13),
Layer("Softmax")], learning_rate=0.001,learning_rule='nesterov',random_state=101,
n_iter=1000)
model1=clf.fit(X_trainn, y_train)
y_hat=clf.predict(X_testn)
scores = cross_validation.cross_val_score(clf, X_trainn, y_train, cv=5)
print 'Nesterov train mean accuracy %s' % np.mean(scores)
print 'Nesterov test %s' % accuracy_score(y_hat,y_test)
OUTPUT]
Nesterov train mean accuracy 0.966575757576
Nesterov test 0.966666666667
我们的模型是改进的,在这种情况下有内斯特罗夫动量。
神经网络和正则化
即使我们在上一个例子中没有过度训练我们的模型,也有必要考虑神经网络的正则化策略。我们可以将正则化应用于神经网络的三种最广泛使用的方法如下:
-
L1 和 L2 正则化,权重衰减作为正则化强度的参数
-
Dropout means that deactivating units within the neural network at random can force other units in the network to take over
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_09.jpg
在左边,我们看到一个应用了丢包的架构,随机去激活网络中的单元。在右边,我们看到一个普通的神经网络(标有 X)。
-
求平均值或集合多个神经网络(每个神经网络具有不同的设置)
让我们尝试这种模式的辍学,看看是否可行:
clf = Classifier(
layers=[
Layer("Rectifier", units=13),
Layer("Rectifier", units=13),
Layer("Softmax")],
learning_rate=0.01,
n_iter=2000,
learning_rule='nesterov',
regularize='dropout', #here we specify dropout
dropout_rate=.1,#dropout fraction of neural units in entire network
random_state=0)
model1=clf.fit(X_trainn, y_train)
scores = cross_validation.cross_val_score(clf, X_trainn, y_train, cv=5)
print np.mean(scores)
y_hat=clf.predict(X_testn)
print accuracy_score(y_hat,y_test)
OUTPUT]
dropout train score 0.933151515152
dropout test score 0.866666666667
在这种情况下,辍学并没有带来令人满意的结果,所以我们应该把它完全排除在外。也可以用其他方法随意试验。只需更改learning_rule参数,看看它对整体精度有何影响。可以尝试的车型有sgd、momentum、nesterov、adagrad、rmsprop。从这个例子中,您已经了解到内斯特罗夫动量可以提高整体精度。在这种情况下,dropout不是最佳的正则化方法,并且对模型性能有害。考虑到这大量的参数都相互作用并产生不可预测的结果,我们确实需要一种调优方法。这正是我们下一节要做的。
神经网络与超参数优化
由于神经网络和深度学习模型的参数空间如此之广,优化是一项艰巨的任务并且计算非常昂贵。错误的神经网络架构可能会导致失败。只有当我们应用正确的参数并为我们的问题选择正确的架构时,这些模型才能准确。不幸的是,提供调整方法的应用很少。我们发现目前最佳的参数调整方法是随机搜索,这是一种随机迭代参数空间的算法,节省了计算资源。sknn 库是唯一有这个选项的库。让我们以葡萄酒质量数据集为基础,通过下面的示例来浏览参数调整方法。
在这个例子中,我们首先加载葡萄酒数据集。然后我们对数据进行转换,从那里我们根据选择的参数调整模型。请注意,该数据集有 13 个要素;我们指定每层中的单位在 4 到 20 之间。在这种情况下,我们不使用小批量;数据集太小了:
import numpy as np
import scipy as sp
import pandas as pd
from sklearn.grid_search import RandomizedSearchCV
from sklearn.grid_search import GridSearchCV, RandomizedSearchCV
from scipy import stats
from sklearn.cross_validation import train_test_split
from sknn.mlp import Layer, Regressor, Classifier as skClassifier
# Load data
df = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv ' , sep = ';')
X = df.drop('quality' , 1).values # drop target variable
y1 = df['quality'].values # original target variable
y = y1 <= 5 # new target variable: is the rating <= 5?
# Split the data into a test set and a training set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print X_train.shape
max_net = skClassifier(layers= [Layer("Rectifier",units=10),
Layer("Rectifier",units=10),
Layer("Rectifier",units=10),
Layer("Softmax")])
params={'learning_rate': sp.stats.uniform(0.001, 0.05,.1),
'hidden0__units': sp.stats.randint(4, 20),
'hidden0__type': ["Rectifier"],
'hidden1__units': sp.stats.randint(4, 20),
'hidden1__type': ["Rectifier"],
'hidden2__units': sp.stats.randint(4, 20),
'hidden2__type': ["Rectifier"],
'batch_size':sp.stats.randint(10,1000),
'learning_rule':["adagrad","rmsprop","sgd"]}
max_net2 = RandomizedSearchCV(max_net,param_distributions=params,n_iter=25,cv=3,scoring='accuracy',verbose=100,n_jobs=1,\
pre_dispatch=None)
model_tuning=max_net2.fit(X_train,y_train)
print "best score %s" % model_tuning.best_score_
print "best parameters %s" % model_tuning.best_params_
OUTPUT:]
[CV] hidden0__units=11, learning_rate=0.100932183167, hidden2__units=4, hidden2__type=Rectifier, batch_size=30, hidden1__units=11, learning_rule=adagrad, hidden1__type=Rectifier, hidden0__type=Rectifier, score=0.655914 - 3.0s
[Parallel(n_jobs=1)]: Done 74 tasks | elapsed: 3.0min
[CV] hidden0__units=11, learning_rate=0.100932183167, hidden2__units=4, hidden2__type=Rectifier, batch_size=30, hidden1__units=11, learning_rule=adagrad, hidden1__type=Rectifier, hidden0__type=Rectifier
[CV] hidden0__units=11, learning_rate=0.100932183167, hidden2__units=4, hidden2__type=Rectifier, batch_size=30, hidden1__units=11, learning_rule=adagrad, hidden1__type=Rectifier, hidden0__type=Rectifier, score=0.750000 - 3.3s
[Parallel(n_jobs=1)]: Done 75 tasks | elapsed: 3.0min
[Parallel(n_jobs=1)]: Done 75 out of 75 | elapsed: 3.0min finished
best score 0.721366278222
best parameters {'hidden0__units': 14, 'learning_rate': 0.03202394348494512, 'hidden2__units': 19, 'hidden2__type': 'Rectifier', 'batch_size': 30, 'hidden1__units': 17, 'learning_rule': 'adagrad', 'hidden1__type': 'Rectifier', 'hidden0__type': 'Rectifier'}
注
警告:由于参数空间是随机搜索的,结果可能不一致。
我们可以看到我们模型的最佳参数是,最重要的是,第一层包含 14 个单位,第二层包含 17 个单位,第三层包含 19 个单位。这是一个相当复杂的架构,我们可能永远无法自己推导出来,这证明了超参数优化的重要性。
神经网络和决策边界
我们在上一节已经介绍过,通过向神经网络添加隐藏单元,我们可以更接近地逼近目标函数。然而,我们还没有将其应用于分类问题。为此,我们将生成具有非线性目标值的数据,并查看一旦我们向架构中添加隐藏单元,决策面将如何变化。让我们看看普适近似定理在起作用!首先,让我们生成一些具有两个特征的非线性可分离数据,设置我们的神经网络体系结构,看看我们的决策边界如何随着每个体系结构而变化:
%matplotlib inline
from sknn.mlp import Classifier, Layer
from sklearn import preprocessing
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from itertools import product
X,y= datasets.make_moons(n_samples=500, noise=.2, random_state=222)
from sklearn.datasets import make_blobs
net1 = Classifier(
layers=[
Layer("Softmax")],random_state=222,
learning_rate=0.01,
n_iter=100)
net2 = Classifier(
layers=[
Layer("Rectifier", units=4),
Layer("Softmax")],random_state=12,
learning_rate=0.01,
n_iter=100)
net3 =Classifier(
layers=[
Layer("Rectifier", units=4),
Layer("Rectifier", units=4),
Layer("Softmax")],random_state=22,
learning_rate=0.01,
n_iter=100)
net4 =Classifier(
layers=[
Layer("Rectifier", units=4),
Layer("Rectifier", units=4),
Layer("Rectifier", units=4),
Layer("Rectifier", units=4),
Layer("Rectifier", units=4),
Layer("Rectifier", units=4),
Layer("Softmax")],random_state=62,
learning_rate=0.01,
n_iter=100)
net1.fit(X, y)
net2.fit(X, y)
net3.fit(X, y)
net4.fit(X, y)
# Plotting decision regions
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
np.arange(y_min, y_max, 0.1))
f, arxxx = plt.subplots(2, 2, sharey='row',sharex='col', figsize=(8, 8))
plt.suptitle('Neural Network - Decision Boundary')
for idx, clf, ti in zip(product([0, 1], [0, 1]),
[net1, net2, net3,net4],
['0 hidden layer', '1 hidden layer',
'2 hidden layers','6 hidden layers']):
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
arxxx[idx[0], idx[1]].contourf(xx, yy, Z, alpha=0.5)
arxxx[idx[0], idx[1]].scatter(X[:, 0], X[:, 1], c=y, alpha=0.5)
arxxx[idx[0], idx[1]].set_title(ti)
plt.show()
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_10.jpg
在这张截图中,我们可以看到,随着我们向神经网络添加隐藏层,我们可以越来越多地学习复杂的决策边界。一个有趣的边注是,具有两层的网络产生了最准确的预测。
注
请注意,结果可能在运行之间有所不同。
与 H2O 进行大规模深度学习
在前几节中,我们介绍了在本地计算机上运行的神经网络和深度架构,我们发现神经网络已经高度矢量化,但计算成本仍然很高。如果我们想使该算法在台式计算机上更具可扩展性,除了利用 Anano 和 GPU 计算之外,我们无能为力。因此,如果我们想更彻底地扩展深度学习算法,我们需要找到一种工具,可以在内核外运行算法,而不是在本地 CPU/GPU 上运行。此时此刻,H2O 是唯一能够快速运行深度学习算法的开源核心外平台。也是跨平台的;除了 Python,还有针对 R、Scala 和 Java 的 API。
H2O 是在一个基于 Java 的平台上编译的,该平台是为广泛的数据科学相关任务开发的,例如数据处理和机器学习。H2O 在内存中的分布式并行 CPU 上运行,因此数据将存储在 H2O 集群中。到目前为止,H2O 平台已经应用了通用线性模型(【GLM】)、随机森林、梯度增强机器 ( GBM )、K 均值、朴素贝叶斯、主成分分析、主成分回归,当然,我们本章的主要重点是深度学习。
太好了,现在我们准备进行第一次 H2O 核外分析。
让我们启动 H2O 实例,并在 H2O 的分布式内存系统中加载一个文件:
import sys
sys.prefix = "/usr/local"
import h2o
h2o.init(start_h2o=True)
Type this to get interesting information about the specifications of your cluster.
Look at the memory that is allowed and the number of cores.
h2o.cluster_info()
这看起来或多或少类似于以下内容(试验和系统之间可能会有细微差异):
OUTPUT:]
Java Version: java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
Starting H2O JVM and connecting: .................. Connection successful!
------------------------------ ---------------------------------------
H2O cluster uptime: 2 seconds 346 milliseconds
H2O cluster version: 3.8.2.3
H2O cluster name: H2O_started_from_python**********nzb520
H2O cluster total nodes: 1
H2O cluster total free memory: 3.56 GB
H2O cluster total cores: 8
H2O cluster allowed cores: 8
H2O cluster healthy: True
H2O Connection ip: 1**.***.***.***
H2O Connection port: 54321
H2O Connection proxy:
Python Version: 2.7.10
------------------------------ ---------------------------------------
------------------------------ ---------------------------------------
H2O cluster uptime: 2 seconds 484 milliseconds
H2O cluster version: 3.8.2.3
H2O cluster name: H2O_started_from_python_quandbee_nzb520
H2O cluster total nodes: 1
H2O cluster total free memory: 3.56 GB
H2O cluster total cores: 8
H2O cluster allowed cores: 8
H2O cluster healthy: True
H2O Connection ip: 1**.***.***.***
H2O Connection port: 54321
H2O Connection proxy:
Python Version: 2.7.10
------------------------------ ---------------------------------------
Sucessfully closed the H2O Session.
Successfully stopped H2O JVM started by the h2o python module.
与 H2O 进行大规模深度学习
在 H2O 深度学习中,我们将用来训练的数据集是著名的 MNIST 数据集。它由 28×28 手写数字图像的像素强度组成。训练集合有 70,000 个训练项目,784 个特征,以及包含目标标签数字的每个记录的标签。
现在,我们对在 H2O 管理数据更加放心了,让我们执行一个深入的学习示例。
在 H2O,我们不需要转换或标准化输入数据;它是内部自动标准化的。每个特征被变换到 N(0,1)空间。
让我们将著名的手写数字图像数据集 MNIST 从亚马逊服务器导入到 H2O 集群:
import h2o
h2o.init(start_h2o=True)
train_url ="https://h2o-public-test-data.s3.amazonaws.com/bigdata/laptop/mnist/train.csv.gz"
test_url="https://h2o-public-test-data.s3.amazonaws.com/bigdata/laptop/mnist/test.csv.gz"
train=h2o.import_file(train_url)
test=h2o.import_file(test_url)
train.describe()
test.describe()
y='C785'
x=train.names[0:784]
train[y]=train[y].asfactor()
test[y]=test[y].asfactor()
from h2o.estimators.deeplearning import H2ODeepLearningEstimator
model_cv=H2ODeepLearningEstimator(distribution='multinomial'
,activation='RectifierWithDropout',hidden=[32,32,32],
input_dropout_ratio=.2,
sparse=True,
l1=.0005,
epochs=5)
这个打印模型的输出将提供很多详细的信息。您将看到的第一个表格如下。这提供了关于神经网络架构的所有细节。您可以看到,我们使用了一个输入维数为 717 的神经网络,该网络有三个隐藏层(每个隐藏层由 32 个单元组成),softmax 激活应用于输出层,ReLU 应用于隐藏层之间:
model_cv.train(x=x,y=y,training_frame=train,nfolds=3)
print model_cv
OUTPUT]
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_12.jpg
如果你想要一个简短的模型性能概述,这是一个非常实用的方法。
在下表中,最有趣的指标是每个文件夹的训练分类错误和验证分类错误。如果您想要验证您的模型,您可以很容易地比较这些:
print model_cv.scoring_history()
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_13.jpg
我们在 MNIST 数据集上的训练分类误差 .096430 和精度在. 907 范围内是相当好的;这几乎和 Yann LeCun 的卷积神经网络提交一样好。
H2O 还提供了一种获取验证指标的便捷方法。我们可以通过将验证数据框传递给交叉验证函数来实现这一点:
model_cv.train(x=x,y=y,training_frame=train,validation_frame=test,nfolds=3)
print model_cv
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_14.jpg
在这种情况下,我们可以很容易地将训练 _ 分类 _ 错误 ( .089)与我们的验证 _ 分类 _ 错误 ( .0954)进行比较。
也许我们可以提高我们的分数;让我们使用超参数优化模型。
H2O 的网格研究
考虑到我们之前的模型表现相当好,我们将把我们的调优工作集中在我们网络的架构上。H2O 的 gridsearch 功能与 Scikit-learn 的随机化搜索非常相似;也就是说,它不是搜索整个参数空间,而是遍历随机的参数列表。首先,我们将设置一个传递给 gridsearch 函数的参数列表。H2O 将在参数搜索中为我们提供每个模型的输出和相应的分数:
hidden_opt = [[18,18],[32,32],[32,32,32],[100,100,100]]
# l1_opt = [s/1e6 for s in range(1,1001)]
# hyper_parameters = {"hidden":hidden_opt, "l1":l1_opt}
hyper_parameters = {"hidden":hidden_opt}
#important: here we specify the search parameters
#be careful with these, training time can explode (see max_models)
search_c = {"strategy":"RandomDiscrete",
"max_models":10, "max_runtime_secs":100,
"seed":222}
from h2o.grid.grid_search import H2OGridSearch
model_grid = H2OGridSearch(H2ODeepLearningEstimator, hyper_params=hyper_parameters)
#We have added a validation set to the gridsearch method in order to have a better #estimate of the model performance.
model_grid.train(x=x, y=y, distribution="multinomial", epochs=1000, training_frame=train, validation_frame=test,
score_interval=2, stopping_rounds=3, stopping_tolerance=0.05,search_criteria=search_c)
print model_grid
# Grid Search Results for H2ODeepLearningEstimator:
OUTPUT]
deeplearning Grid Build Progress: [##################################################] 100%
hidden \
0 [100, 100, 100]
1 [32, 32, 32]
2 [32, 32]
3 [18, 18]
model_ids logloss
0 Grid_DeepLearning_py_1_model_python_1464790287811_3_model_3 0.148162 ←------
1 Grid_DeepLearning_py_1_model_python_1464790287811_3_model_2 0.173675
2 Grid_DeepLearning_py_1_model_python_1464790287811_3_model_1 0.212246
3 Grid_DeepLearning_py_1_model_python_1464790287811_3_model_0 0.227706
我们可以看到,我们最好的架构是一个三层结构,每层 100 个单元。我们还可以清楚地看到【gridsearch 甚至在上大幅增加了训练时间,T1 是一个强大的计算集群,就像 H2O 运行的集群一样。因此,即使在 H2O,我们也应该谨慎使用 gridsearch,并对模型中解析的参数保持保守。
现在,让我们在继续之前关闭 H2O 实例:
h2o.shutdown(prompt=False)
深度学习和无监督预处理
在这一节中,我们将介绍深度学习中最重要的概念:如何通过无监督预训练来提高学习。通过无监督的预处理,我们使用神经网络来发现数据中的潜在特征和因素,以便稍后传递给神经网络。这种方法具有强大的训练网络的能力来学习其他机器学习方法不能学习的任务,没有手工特征。我们将进入细节,并介绍一个新的强大的库。
用茶氨酸进行深度学习
Scikit-learn 的神经网络应用对于参数调整特别有意思。不幸的是,它对于无监督神经网络应用的能力是有限的。对于下一个主题,我们深入更复杂的学习方法,我们需要另一个库。在这一章中,我们将集中讨论茶氨酸。我们喜欢茶氨酸是因为的易用性和稳定性;这是得克萨斯大学的利夫·约翰逊开发的一个非常流畅且维护良好的软件包。建立一个神经网络结构的工作原理与 sklearn 非常相似;也就是说,我们实例化一个学习目标(分类或回归),指定层,并训练它。更多信息,可登陆http://theanets.readthedocs.org/en/stable/。
你所要做的就是用pip安装天线:
$ pip install theanets
由于茶氨酸是建立在茶氨酸之上的,你也需要正确安装茶氨酸。让我们运行一个基本的神经网络模型来看看茶氨酸是如何工作的。与 Scikit-learn 的相似之处显而易见。请注意,我们在本例中使用动量,默认情况下,在示例中使用 softmax,因此我们不必指定它:
import climate # This package provides the reporting of iterations
from sklearn.metrics import confusion_matrix
import numpy as np
from sklearn import datasets
from sklearn.cross_validation import train_test_split
from sklearn.metrics import mean_squared_error
import theanets
import theano
import numpy as np
import matplotlib.pyplot as plt
import climate
from sklearn.cross_validation import train_test_split
import theanets
from sklearn.metrics import confusion_matrix
from sklearn import preprocessing
from sklearn.metrics import accuracy_score
from sklearn import datasets
climate.enable_default_logging()
digits = datasets.load_digits()
digits = datasets.load_digits()
X = np.asarray(digits.data, 'float32')
Y = digits.target
Y=np.array(Y, dtype=np.int32)
#X = (X - np.min(X, 0)) / (np.max(X, 0) + 0.0001) # 0-1 scaling
X_train, X_test, y_train, y_test = train_test_split(X, Y,
test_size=0.2,
random_state=0)
# Build a classifier model with 64 inputs, 1 hidden layer with 100 units and 10 outputs.
net = theanets.Classifier([64,100,10])
# Train the model using Resilient backpropagation and momentum.
net.train([X_train,y_train], algo='sgd', learning_rate=.001, momentum=0.9,patience=0,
validate_every=N,
min_improvement=0.8)
# Show confusion matrices on the training/validation splits.
print(confusion_matrix(y_test, net.predict(X_test)))
print (accuracy_score(y_test, net.predict(X_test)))
OUTPUT ]
[[27 0 0 0 0 0 0 0 0 0]
[ 0 32 0 0 0 1 0 0 0 2]
[ 0 1 34 0 0 0 0 1 0 0]
[ 0 0 0 29 0 0 0 0 0 0]
[ 0 0 0 0 29 0 0 1 0 0]
[ 0 0 0 0 0 38 0 0 0 2]
[ 0 1 0 0 0 0 43 0 0 0]
[ 0 0 0 0 1 0 0 38 0 0]
[ 0 2 1 0 0 0 0 0 36 0]
[ 0 0 0 0 0 1 0 0 0 40]]
0.961111111111
自动编码器和无监督学习
到目前为止,我们讨论了多层和多种参数优化的神经网络。我们常说的深度学习这一代神经网络能力更强;它能够自动学习新特性,因此只需要很少的特性工程和领域专业知识。这些特征是通过无监督的方法在未标记的数据上创建的,这些数据随后被输入到神经网络的后续层。这种方法被称为(无监督)预处理。这种方法已经被证明在图像识别、语言学习甚至普通的机器学习项目中非常成功。近年来最重要和占主导地位的技术被称为去噪自动编码器和基于玻尔兹曼技术的算法。玻尔兹曼机器,曾经是深度信念网络 ( DBN )的构建模块,最近在深度学习社区中失宠了,因为它们被证明很难训练和优化。因此,我们将只关注自动编码器。让我们以可管理的小步骤来讨论这个重要的话题。
自动编码器
我们试图找到一个函数( F ),有一个输出作为它的输入,误差最小F(x)∞’ x。该功能通常被称为身份功能,我们尝试对其进行优化,使 x 尽可能接近 'x 。 x 与 'x 之间的差异称为重构误差。
让我们看一个简单的单层体系结构来直观地了解发生了什么。我们将看到这些架构非常灵活,需要仔细调整:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_15.jpg
单层自动编码器架构
重要的是要理解,当我们在隐藏层中的单位少于输入空间时,我们会强制权重来压缩输入数据。
在本例中,我们有一个包含五个要素的数据集。中间是包含三个单位( Wij )的隐藏层。这些单位具有与我们在神经网络中看到的权重向量相同的属性;也就是说,它们由可以用反向传播训练的权重组成。利用隐藏层的输出,我们通过与我们在神经网络中看到的相同的前馈向量操作获得作为输出的特征表示。
计算向量 'x 的过程与我们通过计算各层权重向量的点积所看到的正向传播非常相似:
W=重量
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_37.jpg
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_38.jpg
重建误差可以用平方误差或交叉熵的形式来测量,这在许多其他方法中已经看到。在这种情况下, ŷ 代表重构输出, y 代表真实输入:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_39.jpg
一个重要的概念是,在只有一个隐藏层的情况下,自动编码器模型捕获的数据中的维度近似于主成分分析 ( 主成分分析)的结果。然而,如果涉及到非线性,自动编码器的行为会大不相同。自动编码器将检测主成分分析永远无法检测到的不同潜在因素。既然我们对自动编码器的架构有了更多的了解,也知道了如何根据其同一性近似计算误差,那么让我们看看这些稀疏度参数,我们用它们来压缩输入。
你可能会问:为什么我们甚至需要这个稀缺参数?我们就不能运行算法找到身份函数然后继续前进吗?
不幸的是,事情没那么简单。有些情况下,身份函数几乎完美地投射了输入,但仍然无法提取输入特征的潜在维度。在这种情况下,该函数只是存储输入数据,而不是提取有意义的特征。我们可以做两件事。首先,我们故意给信号添加噪声(去噪自动编码器),其次,我们引入稀疏性参数,强制停用弱激活单元。让我们首先看看稀疏性是如何工作的。
我们讨论了生物神经元的激活阈值;如果一个神经元的电位接近 1,我们可以认为它是活动的,如果它的输出值接近 0,我们可以认为它是不活动的。我们可以通过提高激活阈值来限制神经元在大部分时间不活动。我们通过降低每个神经元/单位的平均激活概率来做到这一点。查看以下公式,我们可以了解如何最小化激活阈值:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_04_45.jpg
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/P.jpg>* :隐藏层每个神经元的平均激活阈值。
ρ :我们预先指定的网络期望激活阈值。在大多数情况下,该值设置为. 05。
a :隐藏图层的权重向量。
在这里,我们看到了一个优化的机会,通过对https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/P.jpg*和 ρ 之间的错误率进行惩罚。
在本章中,我们不会太担心这个优化目标的技术细节。在大多数包中,我们可以使用一个非常简单的指令来做到这一点(我们将在下一个例子中看到)。需要理解的最重要的一点是,对于自动编码器,我们有两个主要的学习目标:通过优化身份函数来最小化输入向量 x 和输出向量’ x 之间的误差,以及最小化网络中每个神经元的期望激活阈值和平均激活之间的差异。
我们可以强制自动编码器检测潜在特征的第二种方法是在模型中引入噪声;这就是名字去噪自动编码器的由来。这个想法是通过破坏输入的 T4,我们迫使自动编码器学习更健壮的 T5 数据表示。在接下来的例子中,我们将简单地把高斯噪声引入自动编码器模型。
利用堆叠去噪自动编码器进行真正深度的学习–分类预处理
通过这个练习,你将把自己从众多谈论深度学习的人和少数真正做到的人中区分开来!现在,我们将对著名的 MNIST 数据集的迷你版本应用自动编码器,它可以方便地从 Scikit-learn 中加载。数据集由 28 x 28 个手写数字图像的像素强度组成。训练集有 1,797 个训练项目,64 个特征,每个记录的标签包含目标标签数字,从 0 到 9。所以我们有 64 个特征,目标变量由 10 个类组成(数字从 0-9)来预测。
首先,我们训练稀疏度为. 9 的堆叠去噪自动编码器模型,并检查重建误差。我们将使用深度学习研究论文的结果作为设置的指南。更多信息可以阅读本文(http://arxiv.org/pdf/1312.5663.pdf)。然而,我们有一些限制,因为这些类型的模型计算量巨大。因此,对于这个自动编码器,我们使用五层 ReLU 激活,并将数据从 64 个特征压缩到 45 个特征:
model = theanets.Autoencoder([64,(45,'relu'),(45,'relu'),(45,'relu'),(45,'relu'),(45,'relu'),64])
dAE_model=model.train([X_train],algo='rmsprop',input_noise=0.1,hidden_l1=.001,sparsity=0.9,num_updates=1000)
X_dAE=model.encode(X_train)
X_dAE=np.asarray(X_dAE, 'float32')
:OUTPUT:
I 2016-04-20 05:13:37 downhill.base:232 RMSProp 2639 loss=0.660185 err=0.645118
I 2016-04-20 05:13:37 downhill.base:232 RMSProp 2640 loss=0.660031 err=0.644968
I 2016-04-20 05:13:37 downhill.base:232 validation 264 loss=0.660188 err=0.645123
I 2016-04-20 05:13:37 downhill.base:414 patience elapsed!
I 2016-04-20 05:13:37 theanets.graph:447 building computation graph
I 2016-04-20 05:13:37 theanets.losses:67 using loss: 1.0 * MeanSquaredError (output out:out)
I 2016-04-20 05:13:37 theanets.graph:551 compiling feed_forward function
现在我们有了自动编码器的输出,它是我们用一组新的压缩特征创建的。让我们仔细看看这个新数据集:
X_dAE.shape
Output: (1437, 45)
在这里,我们实际上可以看到,我们已经将数据从 64 个特征压缩到 45 个特征。新的数据集不那么稀疏(意味着更少的零)并且在数字上更加连续。既然我们已经从自动编码器获得了预训练数据,我们可以对其应用深度神经网络进行监督学习:
#By default, hidden layers use the relu transfer function so we don't need to specify #them. Relu is the best option for auto-encoders.
# Theanets classifier also uses softmax by default so we don't need to specify them.
net = theanets.Classifier(layers=(45,45,45,10))
autoe=net.train([X_dAE, y_train], algo='rmsprop',learning_rate=.0001,batch_size=110,min_improvement=.0001,momentum=.9,
nesterov=True,num_updates=1000)
## Enjoy the rare pleasure of 100% accuracy on the training set.
OUTPUT:
I 2016-04-19 10:33:07 downhill.base:232 RMSProp 14074 loss=0.000000 err=0.000000 acc=1.000000
I 2016-04-19 10:33:07 downhill.base:232 RMSProp 14075 loss=0.000000 err=0.000000 acc=1.000000
I 2016-04-19 10:33:07 downhill.base:232 RMSProp 14076 loss=0.000000 err=0.000000 acc=1.000000
在我们对测试集预测这个神经网络之前,将我们已经训练的自动编码器模型应用于测试集是很重要的:
dAE_model=model.train([X_test],algo='rmsprop',input_noise=0.1,hidden_l1=.001,sparsity=0.9,num_updates=100)
X_dAE2=model.encode(X_test)
X_dAE2=np.asarray(X_dAE2, 'float32')
现在让我们检查一下测试集的性能:
final=net.predict(X_dAE2)
from sklearn.metrics import accuracy_score
print accuracy_score(final,y_test)
OUTPUT: 0.972222222222
我们可以看到,具有自动编码特征 (.9722)的模型的最终精度优于没有它的模型(. 9611)。
总结
在这一章中,我们研究了深度学习背后最重要的概念以及可扩展的解决方案。
我们通过学习如何为任何给定的任务构建正确的体系结构来消除一些黑箱现象,并通过前向传播和反向传播的机制来工作。更新神经网络的权重是一项艰巨的任务,常规的随机梯度下降会导致陷入全局最小值或超调。动量、ADAGRAD、RPROP 和 RMSProp 等更复杂的算法可以提供解决方案。尽管神经网络比其他机器学习方法更难训练,但它们具有转换特征表示的能力,并且可以学习任何给定的函数(通用近似定理)。我们还和 H2O 一起投入到大规模的深度学习中,甚至利用参数优化这个非常热门的话题进行深度学习。
使用自动编码器的无监督预训练可以提高任何给定深度网络的准确性,我们通过一个茶氨酸框架内的实际例子来实现这一点。
在这一章中,我们主要使用构建在 Anano 框架之上的包。在下一章中,我们将介绍基于新的开源框架 Tensorflow 构建的包的深度学习技术。
五、TensorFlow 深度学习
在本章中,我们将重点介绍 TensorFlow,并涵盖以下主题:
- 基本 TensorFlow 运算
- 使用 TensorFlow 从零开始的机器学习—回归、SGD 分类器和神经网络
- 使用 SkFlow 进行深度学习
- 大型文件的增量深度学习
- 带 Keras 的卷积神经网络
TensorFlow 框架是在撰写本书时引入的,并且已经被证明是机器学习领域的一大补充。
TensorFlow 是由谷歌大脑团队发起的,该团队由近十年来从事深度学习重要发展的大多数研究人员(杰弗里·辛顿、萨米·本吉奥等人)组成。它基本上是上一代框架的下一代开发,称为 dist 信仰,是分布式深度神经网络的平台。与 TensorFlow 相反,diststrust不是开源的。diststrust 项目成功的有趣例子是反转图像搜索引擎、谷歌深梦和谷歌应用中的语音识别。DistBelief 使谷歌开发人员能够利用数千个内核(包括 CPU 和 GPU)进行分布式训练。
TensorFlow 是对 diststrust 的改进,因为它现在是完全开源的,并且它的编程语言不那么抽象。TensorFlow 声称更灵活,应用范围更广。在撰写本文时(2015 年末),TensorFlow 框架还处于起步阶段,基于 TensorFlow 构建的有趣的轻量级包已经出现,我们将在本章后面部分看到。
与 Anano 类似,TensorFlow 在张量上进行符号计算;这意味着它的大部分计算都是基于向量和矩阵乘法。
常规编程语言定义了变量,这些变量包含可以应用操作的值或字符。
在符号编程语言中,如 Anano 或 TensorFlow,操作是围绕图而不是变量来构造的。这具有计算优势,因为它们可以跨计算单元(GPU 和 CPU)分布和并行化:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_05_0.jpg
TensorFlow 的架构于 2015 年 11 月推出
TensorFlow 具有以下特征和应用:
- TensorFlow 可以用多个图形处理器并行化(水平)
- 开发框架也可用于移动部署
- TensorBoard 是一个用于可视化的仪表盘(处于早期阶段)
- 它是几种编程语言(Python Go、Java、Lua、JavaScript、R、C++,很快还有 Julia)的前端
- 为 Spark、谷歌云平台(https://cloud.google.com/ml/)等大规模解决方案提供集成
类似于图的结构中的张量运算提供了并行计算的新方法(因此谷歌声称)的想法可以通过下面的图片变得非常清楚:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_05_1.jpg
一种基于 TensorFlow 的分布式处理架构
从这张图片中我们可以看到,每个模型都可以分配给单独的图形处理器。之后根据每个模型计算预测的平均值。在其他方法中,这种方法是在 GPU 集群上训练非常大的分布式神经网络的核心思想。
tensorlow 安装
我们将在本章中使用的 TensorFlow 版本是 0.8,所以请确保您安装了该版本。由于 TensorFlow 正处于重度开发阶段,小的变化是应该的。借助pip install,我们可以非常轻松地安装 TensorFlow,而与您使用的操作系统无关:
pip install tensorflow
如果您已经安装了以前的版本,您可以根据您的操作系统进行升级:
# Ubuntu/Linux 64-bit, CPU only:
$ sudo pip install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.8.1-cp27-none-linux_x86_64.whl
# Ubuntu/Linux 64-bit, GPU enabled:
$ sudo pip install --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.8.1-cp27-none-linux_x86_64.whl
# Mac OS X, CPU only:
$ sudo easy_install --upgrade six
$ sudo pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.1-cp27-none-any.whl
现在安装了 TensorFlow,可以在终端进行测试:
$python
import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!')
sess = tf.Session()
print(sess.run(hello))
Output Hello, TensorFlow!
TensorFlow 运算
让我们通过一些简单的例子来感受一下它是如何工作的。
一个重要的区别是,对于 TensorFlow,我们首先需要初始化变量,然后才能对它们应用操作。TensorFlow 在 C++后端运行以执行计算,因此,为了连接到这个后端,我们需要首先实例化一个会话:
x = tf.constant([22,21,32], name='x')
d=tf.constant([12,23,43],name='x')
y = tf.Variable(x * d, name='y')
print(y)
不提供 xd* 的输出向量,您将看到如下内容:
OUTPUT ]
<tensorflow.python.ops.variables.Variable object at 0x114a95710>
为了从 C++后端实际生成提供的计算结果,我们用以下方式实例化会话:
x = tf.constant([22,21,32], name='x')
d=tf.constant([12,23,43],name='d')
y = tf.Variable(x * d, name='y')
model = tf.initialize_all_variables()
with tf.Session() as session:
session.run(model)
print(session.run(y))
Output [ 264 483 1376]
到目前为止,我们已经直接使用了变量,但是为了更灵活地使用张量运算,如果我们可以将数据分配给一个预先指定的容器,这可能会很方便。这样,我们就可以对计算图执行操作,而无需事先将数据加载到内存中。在 TensorFlow 术语中,我们通过所谓的占位符将数据输入到图表中。这正是与安诺语言的相似之处(见附录、图形处理器和安诺简介)。
这些 TensorFlow 占位符只是具有某些预先指定的设置和类的对象的容器。因此,为了对一个对象执行操作,我们首先为该对象创建一个占位符,以及它对应的类(在本例中是一个整数):
a = tf.placeholder(tf.int8)
b = tf.placeholder(tf.int8)
sess = tf.Session()
sess.run(a+b, feed_dict={a: 111, b: 222})
Output 77
矩阵乘法的工作原理如下:
matrix1 = tf.constant([[1, 2,32], [3, 4,2],[3,2,11]])
matrix2 = tf.constant([[21,3,12], [3, 56,2],[35,21,61]])
product = tf.matmul(matrix1, matrix2)
with tf.Session() as sess:
result = sess.run(product)
print result
OUTPUT
[[1147 787 1968]
[ 145 275 166]
[ 454 352 711]]
有趣的是,对象result的输出是一个 NumPy ndarray对象,我们可以对 TensorFlow 之外的对象进行操作。
GPU 计算
如果我们想在图形处理器上执行 TensorFlow 操作,我们只需要指定一个设备。被警告;这仅适用于安装正确、与 CUDA 兼容的 NVIDIA GPU 单元:
with tf.device('/gpu:0'):
product = tf.matmul(matrix1, matrix2)
with tf.Session() as sess:
result = sess.run(product)
print result
如果我们想利用多个图形处理器,我们需要分配一个图形处理器设备给一个特定的任务:
matrix3 = tf.constant([[13, 21,53], [4, 3,6],[3,1,61]])
matrix4 = tf.constant([[13,23,32], [23, 16,2],[35,51,31]])
with tf.device('/gpu:0'):
product = tf.matmul(matrix1, matrix2)
with tf.Session() as sess:
result = sess.run(product)
print result
with tf.device('/gpu:1'):
product = tf.matmul(matrix3, matrix4)
with tf.Session() as sess:
result = sess.run(product)
print result
用 SGD 进行线性回归
既然我们已经涵盖了基础知识,我们可以开始在 TensorFlow 框架内从头开始编写我们的第一个机器学习算法。稍后,我们将在 TensorFlow 之上的更高抽象中使用更实用的轻量级应用。
我们将使用随机梯度下降执行一个非常简单的线性回归,以便了解训练和评估在 TensorFlow 中是如何工作的。首先,我们将创建一些变量来使用,以便在占位符中解析它们来包含这些变量。然后我们将和y输入到cost 功能中,用梯度下降训练模型:
import tensorflow as tf
import numpy as np
X = tf.placeholder("float") # create symbolic variables
Y = tf.placeholder("float")
X_train = np.asarray([1,2.2,3.3,4.1,5.2])
Y_train = np.asarray([2,3,3.3,4.1,3.9,1.6])
def model(X, w):
return tf.mul(X, w)
w = tf.Variable(0.0, name="weights")
y_model = model(X, w) # our predicted values
cost = (tf.pow(Y-y_model, 2)) # squared error cost
train_op = tf.train.GradientDescentOptimizer(0.01).minimize(cost) #sgd optimization
sess = tf.Session()
init = tf.initialize_all_variables()
sess.run(init)
for trials in range(50): #
for (x, y) in zip(X_train, Y_train):
sess.run(train_op, feed_dict={X: x, Y: y})
print(sess.run(w))
OUTPUT ]
0.844732
综上所述,我们用 SGD 进行线性回归的方式如下:首先,我们初始化回归权重(系数),然后在第二步中,我们设置成本函数,以稍后训练和优化梯度下降的函数。最后,我们需要编写一个for循环,以指定我们想要的训练回合数,并计算最终预测。相同的基本结构将在神经网络中变得明显。
TensorFlow 中从头开始的神经网络
现在让我们用 TensorFlow 语言来执行一个神经网络,并剖析这个过程。
在这种情况下,我们还将使用 Iris 数据集和一些 Scikit-learn 应用进行预处理:
import tensorflow as tf
import numpy as np
from sklearn import cross_validation
from sklearn.cross_validation import train_test_split
from sklearn.preprocessing import OneHotEncoder
from sklearn.utils import shuffle
from sklearn import preprocessing
import os
import pandas as pd
from datetime import datetime as dt
import logging
iris = datasets.load_iris()
X = np.asarray(iris.data, 'float32')
Y = iris.target
from sklearn import preprocessing
X= preprocessing.scale(X)
min_max_scaler = preprocessing.MinMaxScaler()
X = min_max_scaler.fit_transform(X)
lb = preprocessing.LabelBinarizer()
Y=lb.fit_transform(iris.target)
这是重要的一步。TensorFlow 中的神经网络不能处理单个向量中的目标标签。目标标签需要被转换成二进制化的特征(有些人将此称为虚拟变量),这样神经网络将使用一对所有输出:
X_train, x_test, y_train, y_test = train_test_split(X,Y,test_size=0.3,random_state=22)
def init_weights(shape):
return tf.Variable(tf.random_normal(shape, stddev=0.01))
在这里,我们可以看到前馈通道:
def model(X, w_h, w_o):
h = tf.nn.sigmoid(tf.matmul(X, w_h))
return tf.matmul(h, w_o)
X = tf.placeholder("float", [None, 4])
Y = tf.placeholder("float", [None, 3])
在这里,我们用一个隐藏层建立了我们的层架构:
w_h = init_weights([4, 4])
w_o = init_weights([4, 3])
py_x = model(X, w_h, w_o)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(py_x, Y)) # compute costs
train_op = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(cost) # construct an optimizer
predict_op = tf.argmax(py_x, 1)
sess = tf.Session()
init = tf.initialize_all_variables()
sess.run(init)
for i in range(500):
for start, end in zip(range(0, len(X_train),1 ), range(1, len(X_train),1)):
sess.run(train_op, feed_dict={X: X_train[start:end], Y: y_train[start:end]})
if i % 100 == 0:
print i, np.mean(np.argmax(y_test, axis=1) ==
sess.run(predict_op, feed_dict={X: x_test, Y: y_test}))
OUTPUT:]
0 0.288888888889
100 0.666666666667
200 0.933333333333
300 0.977777777778
400 0.977777777778
该神经网络的精度约为 0.977%,但在次运行中会产生略有不同的结果。它或多或少是具有单一隐藏层和普通 SGD 的神经网络的基准。
就像我们在前面的例子中看到的,实现一个优化方法并设置张量是非常直观的。这比我们在 NumPy 中做同样的事情要直观得多。(参见第 4 章、神经网络和深度学习。)目前的缺点是评估和预测需要一个有时很繁琐的for循环,而像 Scikit-learn 这样的包可以用一行简单的脚本提供这些方法。幸运的是,在 TensorFlow 的基础上开发了更高级别的包,使得培训和评估变得更加容易。其中一个包是 SkFlow 顾名思义,它是一个基于脚本风格的包装器,就像 Scikit-learn 一样工作。
基于 SkFlow 的 TensorFlow 机器学习
现在我们已经看到了 TensorFlow 的基本操作,让我们深入到构建在 TensorFlow 之上的更高级别的应用中去让机器学习更实用一点。SkFlow 是我们将介绍的第一个应用。在 SkFlow 中,我们不必指定类型和占位符。我们可以像使用 Scikit-learn 和 NumPy 一样加载和管理数据。让我们用pip安装软件包。
最安全的方法是直接从 GitHub 安装软件包:
$ pip install git+git://github.com/tensorflow/skflow.git
SkFlow 有三类主要的学习算法:线性分类器、线性回归和神经网络。线性分类器基本上是一个简单的 SGD(多)分类器,而神经网络是 SkFlow 的强项。它为深度神经网络、循环网络和卷积神经网络提供了相对容易使用的包装器。不幸的是,其他算法,如随机森林、梯度增强、SVM 和朴素贝叶斯还没有实现。然而,在 GitHub 上有关于在 SkFlow 中实现随机森林算法的讨论,该算法可能会被命名为 tf_forest,这是一个令人兴奋的发展。
让我们在 SkFlow 中应用我们的第一个多类分类算法。在这个例子中,我们将使用葡萄酒数据集——一个最初来自 UCI 机器学习存储库的数据集。它由镁、酒精、苹果酸等 13 个连续化学指标组成。这是一个只有 178 个实例的光照数据集和一个有三个类的目标要素。目标变量由三个不同的品种组成。使用十三种化学指标的化学分析,根据各自的品种(用于酿酒的葡萄类型)对葡萄酒进行分类。您可以看到,我们从网址加载数据的方式与我们在 Scikit-learn 环境中工作时的方式相同:
import numpy as np
from sklearn.metrics import accuracy_score
import skflow
import urllib2
url = 'https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass/wine.scale'
set1 = urllib2.Request(url)
wine = urllib2.urlopen(set1)
from sklearn.datasets import load_svmlight_file
X_train, y_train = load_svmlight_file(wine)
X_train=X_train.toarray()
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X_train,
y_train, test_size=0.30, random_state=4)
classifier = skflow.TensorFlowLinearClassifier(n_classes=4,learning_rate=0.01, optimizer='SGD',continue_training=True, steps=1000)
classifier.fit(X_train, y_train)
score = accuracy_score(y_train, classifier.predict(X_train))
d=classifier.predict(X_test)
print("Accuracy: %f" % score)
c=accuracy_score(d,y_test)
print('validation/test accuracy: %f' % c)
OUTPUT:
Step #1, avg. loss: 1.58672
Step #101, epoch #25, avg. loss: 1.45840
Step #201, epoch #50, avg. loss: 1.09080
Step #301, epoch #75, avg. loss: 0.84564
Step #401, epoch #100, avg. loss: 0.68503
Step #501, epoch #125, avg. loss: 0.57680
Step #601, epoch #150, avg. loss: 0.50120
Step #701, epoch #175, avg. loss: 0.44486
Step #801, epoch #200, avg. loss: 0.40151
Step #901, epoch #225, avg. loss: 0.36760
Accuracy: 0.967742
validation/test accuracy: 0.981481
到现在,这个方法会相当熟悉;这与 Scikit-learn 中的分类器的工作方式基本相同。然而,有两件重要的事情需要注意。使用 SkFlow,我们可以交替使用 NumPy 和 TensorFlow 对象,这样我们就不需要在张量框架中合并和转换对象。这使得通过像 SkFlow 这样的高级方法来使用 TensorFlow 变得更加灵活。要注意的第二件事是,我们将toarray方法应用于主数据对象。这是因为数据集非常稀疏(大量零条目),并且 TensorFlow 不能很好地处理稀疏数据。
神经网络是 TensorFlow 擅长的地方,在 SkFlow 中,训练多层神经网络是非常容易的。让我们对糖尿病数据集执行神经网络。该数据集包含 21 岁以上怀孕女性和皮马遗产的糖尿病指标(二进制目标)诊断特征。亚利桑那州的皮马印第安人是世界上报告的糖尿病患病率最高的人群,因此这个种族群体一直是糖尿病研究的自愿对象。数据集由以下要素组成:
- 怀孕次数
- 口服葡萄糖耐量试验中两小时的血浆葡萄糖浓度
- 舒张压(毫米汞柱)
- 三头肌皮肤褶皱厚度(mm)
- 2 小时血清胰岛素(微克/毫升)
- 体重指数(以千克为单位的体重/(m)^2 的身高)
- 糖尿病谱系功能
- 年龄(岁)
- 类变量(0 或 1)
在本例中,我们首先加载和缩放数据:
import tensorflow
import tensorflow as tf
import numpy as np
import urllib
import skflow
from sklearn.preprocessing import Normalizer
from sklearn import datasets, metrics, cross_validation
from sklearn.cross_validation import train_test_split
# Pima Indians Diabetes dataset (UCI Machine Learning Repository)
url = "http://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data"
# download the file
raw_data = urllib.urlopen(url)
dataset = np.loadtxt(raw_data, delimiter=",")
print(dataset.shape)
X = dataset[:,0:7]
y = dataset[:,8]
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=0.2,
random_state=0)
from sklearn import preprocessing
X= preprocessing.scale(X)
min_max_scaler = preprocessing.MinMaxScaler()
X = min_max_scaler.fit_transform(X)
这一步很有意思;为了使神经网络更好地收敛,我们可以使用更灵活的衰减率。在训练多层神经网络时,随着时间的推移降低学习速率通常是有帮助的。一般来说,当我们的学习率过高时,我们可能会超过最佳值。另一方面,当学习率太低时,我们会浪费计算资源,陷入局部极小值。指数衰减是一种随着时间降低学习速率的方法,这样当学习速率开始接近最小值时,它会变得更加敏感。有三种常见的实现学习率衰减的方法;即阶跃衰减、1/t 衰减和指数衰减:
指数衰减:a = a0ektT5】
在这种情况下, a 为学习率, k 为超参数, t 为迭代。
在这个例子中,我们将使用指数衰减,因为它似乎对这个数据集非常有效。这就是我们如何实现指数衰减函数(利用 TensorFlow 的内置tf.train.exponential_decay函数):
def exp_decay(global_step):
return tf.train.exponential_decay(
learning_rate=0.01, global_step=global_step,
decay_steps=steps, decay_rate=0.01)
我们现在可以在 TensorFlow 神经网络模型中传递衰减函数。对于这个神经网络,我们将提供一个两层网络,第一层由五个单元组成,第二层由四个单元组成。默认情况下,SkFlow 实现 ReLU 激活功能,因为我们比其他功能(tanh、sigmoid 等)更喜欢它,所以我们坚持使用它。
下面这个例子,我们也可以实现随机梯度下降以外的优化算法。让我们基于迪德里克·金马和吉米·巴()的一篇文章,实现一个名为亚当的自适应算法。
亚当,在阿姆斯特丹大学开发,代表自适应力矩估计。在前一章中,我们看到了 ADAGRAD 是如何工作的——随着时间的推移,当梯度向(希望是)全局最小值移动时,通过降低梯度。Adam 也使用自适应方法,但是结合动量训练的思想,其中考虑了先前的梯度更新:
steps = 5000
classifier = skflow.TensorFlowDNNClassifier(
hidden_units=[5,4],
n_classes=2,
batch_size=300,
steps=steps,
optimizer='Adam',#SGD #RMSProp
learning_rate=exp_decay #here is the decay function
)
classifier.fit(X_train,y_train)
score1a = metrics.accuracy_score(y_train, classifier.predict(X_train))
print("Accuracy: %f" % score1a)
score1b = metrics.accuracy_score(y_test, classifier.predict(X_test))
print("Validation Accuracy: %f" % score1b)
OUTPUT
(768, 9)
Step #1, avg. loss: 12.83679
Step #501, epoch #167, avg. loss: 0.69306
Step #1001, epoch #333, avg. loss: 0.56356
Step #1501, epoch #500, avg. loss: 0.54453
Step #2001, epoch #667, avg. loss: 0.54554
Step #2501, epoch #833, avg. loss: 0.53300
Step #3001, epoch #1000, avg. loss: 0.53266
Step #3501, epoch #1167, avg. loss: 0.52815
Step #4001, epoch #1333, avg. loss: 0.52639
Step #4501, epoch #1500, avg. loss: 0.52721
Accuracy: 0.754072
Validation Accuracy: 0.740260
准确性不是那么有说服力;我们可以通过将主成分分析 ( 主成分分析)应用于输入来提高准确性。在 Stavros J Perantonis 和 Vassilis Virvilis 从 1999 年(http://rexa . info/paper/dc4f 2 babc 5c ca 4534 b 435280 AE 32 f 5816 DDB 53 b 0)撰写的这篇文章中,已经提出该糖尿病数据集在传入神经网络之前从 PCA 维度的降低中获益良多。我们将对此数据集使用 Sciket-learn 管道方法:
from sklearn.decomposition import PCA
from sklearn import linear_model, decomposition, datasets
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score
pca = PCA(n_components=4,whiten=True)
lr = pca.fit(X)
classifier = skflow.TensorFlowDNNClassifier(
hidden_units=[5,4],
n_classes=2,
batch_size=300,
steps=steps,
optimizer='Adam',#SGD #RMSProp
learning_rate=exp_decay
)
pipe = Pipeline(steps=[('pca', pca), ('NNET', classifier)])
X_train, X_test, Y_train, Y_test = train_test_split(X, y,
test_size=0.2,
random_state=0)
pipe.fit(X_train, Y_train)
score2 = metrics.accuracy_score(Y_test, pipe.predict(X_test))
print("Accuracy Validation, with pca: %f" % score2)
OUTPUT:
Step #1, avg. loss: 1.07512
Step #501, epoch #167, avg. loss: 0.54236
Step #1001, epoch #333, avg. loss: 0.50186
Step #1501, epoch #500, avg. loss: 0.49243
Step #2001, epoch #667, avg. loss: 0.48541
Step #2501, epoch #833, avg. loss: 0.46982
Step #3001, epoch #1000, avg. loss: 0.47928
Step #3501, epoch #1167, avg. loss: 0.47598
Step #4001, epoch #1333, avg. loss: 0.47464
Step #4501, epoch #1500, avg. loss: 0.47712
Accuracy Validation, with pca: 0.805195
通过简单的主成分分析预处理步骤,我们已经能够相当大地提高神经网络的性能。我们从七个特征减少到四个维度,因此是四个特征。主成分分析通常通过将特征置零来平滑信号,仅使用包含最高特征值的向量来减少特征空间。白化确保特征被转换成零相关特征。这导致更平滑的信号和更小的特征集,使得神经网络能够更快地收敛。有关主成分分析的更详细解释,请参见第 7 章、无监督学习量表。
大文件深度学习——增量学习
到目前为止,我们已经在相对较小的数据集上处理了 SkFlow 上的一些 TensorFlow 操作和机器学习技术。然而这本书讲的是大规模、可扩展的机器学习;在这方面,TensorFlow 框架能为我们提供什么?
直到最近,并行计算还处于起步阶段,不够稳定,不足以在本书中涵盖。没有兼容 CUDA 的 NVIDIA 卡,读者无法访问多 GPU 计算。大型规模的云服务(https://cloud.google.com/products/machine-learning/)或者亚马逊 EC2 都是有相当可观的费用的。这使得我们只有一种方法可以扩展我们的项目——通过增量学习。
一般来说,任何超过计算机可用内存 25%的文件都会导致内存过载问题。因此,如果您有一台 2 GB 的计算机,并且想要将机器学习解决方案应用于 500 MB 的文件,那么是时候开始考虑绕过内存消耗的方法了。
为了防止内存过载,我们建议使用一种核外学习方法,将数据分解成更小的块,以增量方式训练和更新模型。我们在第 2 章、在 Scikit-learn 中介绍的部分拟合方法就是这方面的例子。
SkFlow 还为其所有的机器学习模型提供了一种非常棒的增量学习方法,就像 Scikit-learn 中的部分拟合方法一样。在这一节中,我们将逐步使用深度学习分类器,因为我们认为它是最令人兴奋的。
在本节中,我们将为我们的可扩展和核心外深度学习项目使用两种策略;即增量学习和随机子采样。
首先,我们生成一些数据,然后我们构建一个子样本函数,我们可以从该数据集抽取随机子样本,并在这些子集上增量训练深度学习模型:
import numpy as np
import pandas as pd
import skflow
from sklearn.datasets import make_classification
import random
from sklearn.cross_validation import train_test_split
import gc
import tensorflow as tf
from sklearn.metrics import accuracy_score
首先,我们将生成一些示例数据并将其写入磁盘:
X, y = make_classification(n_samples=5000000,n_features=10, n_classes=4,n_informative=6,random_state=222,n_clusters_per_class=1)
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2, random_state=22)
Big_trainm=pd.DataFrame(X_train,y_train)
Big_testm = pd.DataFrame(X_test,y_test)
Big_trainm.to_csv('lsml-Bigtrainm', sep=',')
Big_testm.to_csv('lsml-Bigtestm', sep=',')
让我们通过删除所有创建的对象来释放内存。
借助gc.collect我们强制 Python 的垃圾收集器清空内存:
del(X,y,X_train,y_train,X_test)
gc.collect
在这里,我们创建了一个从磁盘中抽取随机子样本的函数。请注意,我们使用的是⅓.的样本分数我们可以使用较小的分数,但如果这样做,我们还需要调整两个重要的东西。首先,我们需要匹配深度学习模型的批量大小,以便批量大小永远不会超过样本大小。其次,我们需要调整我们的for循环中的纪元数量,以确保最大部分的训练数据用于训练模型:
import pandas as pd
import random
def sample_file():
global skip_idx
global train_data
global X_train
global y_train
big_train='lsml-Bigtrainm'
计算整个集合中的行数:
num_lines = sum(1 for i in open(big_train))
我们使用训练集的三分之一:
size = int(num_lines / 3)
跳过索引并保留索引:
skip_idx = random.sample(range(1, num_lines), num_lines - size)
train_data = pd.read_csv(big_train, skiprows=skip_idx)
X_train=train_data.drop(train_data.columns[[0]], axis=1)
y_train = train_data.ix[:,0]
我们在前面的部分看到了重量衰减;我们将在这里再次使用它:
def exp_decay(global_step):
return tf.train.exponential_decay(
learning_rate=0.01, global_step=global_step,
decay_steps=steps, decay_rate=0.01)
这里,我们分别用5、4和4单元建立了三个隐藏层的神经网络 DNN 分类器。请注意,我们将的批量设置为300,这意味着我们在每个时期使用 300 个训练案例。这也有助于防止内存过载:
steps = 5000
clf = skflow.TensorFlowDNNClassifier(
hidden_units=[5,4,4],
n_classes=4,
batch_size=300,
steps=steps,
optimizer='Adam',
learning_rate=exp_decay
)
这里,我们将子样本的数量设置为三个(epochs=3)。这意味着我们在三个连续的子样本上逐步训练我们的深度学习模型:
epochs=3
for i in range(epochs):
sample_file()
clf.partial_fit(X_train,y_train)
test_data = pd.read_csv('lsml-Bigtestm',sep=',')
X_test=test_data.drop(test_data.columns[[0]], axis=1)
y_test = test_data.ix[:,0]
score = accuracy_score(y_test, clf.predict(X_test))
print score
OUTPUT
Step #501, avg. loss: 0.55220
Step #1001, avg. loss: 0.31165
Step #1501, avg. loss: 0.27033
Step #2001, avg. loss: 0.25250
Step #2501, avg. loss: 0.24156
Step #3001, avg. loss: 0.23438
Step #3501, avg. loss: 0.23113
Step #4001, avg. loss: 0.23335
Step #4501, epoch #1, avg. loss: 0.23303
Step #1, avg. loss: 2.57968
Step #501, avg. loss: 0.57755
Step #1001, avg. loss: 0.33215
Step #1501, avg. loss: 0.27509
Step #2001, avg. loss: 0.26172
Step #2501, avg. loss: 0.24883
Step #3001, avg. loss: 0.24343
Step #3501, avg. loss: 0.24265
Step #4001, avg. loss: 0.23686
Step #4501, epoch #1, avg. loss: 0.23681
0.929022
我们设法在非常容易管理的训练时间内在测试集上获得了.929的准确度,并且没有使我们的记忆超负荷,比我们在整个数据集上一次训练相同的模型要快得多。
Keras 和 TensorFlow 安装
之前,我们已经看到了用于 TensorFlow 应用的 SkFlow 包装器的实际例子。对于神经网络和深度学习的更复杂的方法,我们对参数有更多的控制,我们提出了 Keras(http://keras.io/)。这个包最初是在“T4”框架内开发的,但最近也适应了 TensorFlow。这样,我们可以在 TensorFlow 之上使用 Keras 作为更高抽象的包。请记住,在方法上,Keras 比 SkFlow 稍微不那么简单。Keras 既可以在 GPU 上运行,也可以在 CPU 上运行,这使得这个包在移植到不同环境时非常灵活。
让我们首先安装 Keras,并确保它利用了 TensorFlow 后端。
安装工作只需在命令行中使用pip:
$pip install Keras
Keras 最初是建立在 antao 之上的,所以我们需要指定 Keras 来代替使用 TensorFlow。为了做到这一点,我们首先需要在 Keras 的默认平台 antao 上运行一次。
首先,我们需要运行一些 Keras 代码来确保所有的库项目都被正确安装。让我们训练一个基本的神经网络,并介绍一些关键概念。
为了方便起见,我们将使用由四个特性组成的 Scikit-learn 和由三个类组成的目标变量生成的数据。这些维度非常重要,因为我们需要它们来指定神经网络的架构:
import numpy as np
import keras
from sklearn.datasets import make_classification
from sklearn.cross_validation import train_test_split
from sklearn.preprocessing import OneHotEncoder
from keras.utils import np_utils, generic_utils
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
from keras.optimizers import SGD
nb_classes=3
X, y = make_classification(n_samples=1000, n_features=4, n_classes=nb_classes,n_informative=3, n_redundant=0, random_state=101)
既然我们已经指定了变量,那么将目标变量转换成一个热编码数组就很重要了(就像我们在 TensorFlow 中所做的那样)。否则,Keras 将无法计算一个与所有目标输出的比较。对于 Keras,我们想用np_utils代替 sklearn 的一热编码器。我们将这样使用它:
y=np_utils.to_categorical(y,nb_classes)
print y
我们的y数组将如下所示:
OUTPUT]
array([[ 1., 0., 0.],
[ 0., 0., 1.],
[ 0., 0., 1.],
…,
现在让我们将数据分为测试和训练:
x_train, x_test, y_train, y_test = train_test_split(X, y,test_size=0.30, random_state=222)
这是我们开始形成我们心中的神经网络架构的地方。让我们开始一个双隐藏层神经网络,激活relu,每个隐藏层有三个单位。我们的第一层有四个输入,因为在这种情况下我们有四个特征。之后,我们添加三个单位的隐藏层,因此(model.add(dense(3))。
就像我们之前看到的,我们将使用softmax函数将网络传递到输出层:
model = Sequential()
model.add(Dense(4, input_shape=(4,)))
model.add(Activation('relu'))
model.add(Dense(3))
model.add(Activation('relu'))
model.add(Dense(3))
model.add(Activation('softmax'))
首先,我们指定我们的 SGD 函数,在这里我们实现了我们现在熟悉的最重要的参数,即:
- lr:学习率。
- 衰减:衰减学习速率的衰减函数。不要将其与权重衰减混淆,权重衰减是一个正则化参数。
- 动量:我们用这个来防止陷入局部极小。
- nesterov :这是一个布尔值,它指定我们是否要使用 nesterov 动量,并且仅当我们为动量参数指定了一个整数时才适用。(详见第四章、神经网络和深度学习,了解更多详细说明。)
- 优化器:这里我们将指定我们选择的优化算法(由 SGD、RMSProp、ADAGRAD、Adadelta 和 Adam 组成)。
让我们看看下面的代码片段:
#We use this for reproducibility
seed = 22
np.random.seed(seed)
model = Sequential()
model.add(Dense(4, input_shape=(4,)))
model.add(Activation('relu'))
model.add(Dense(3))
model.add(Activation('relu'))
model.add(Dense(3))
model.add(Activation('softmax'))
sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy', optimizer=sgd)
model.fit(x_train, y_train, verbose=1, batch_size=100, nb_epoch=50,show_accuracy=True,validation_data=(x_test, y_test))
time.sleep(0.1)
在这种情况下,我们使用了100的batch_size,这意味着我们在每个历元中使用了 100 个训练示例的迷你批次梯度下降。在这个模型中,我们使用了50训练时代。这将为您提供以下输出:
OUTPUT:
acc: 0.8129 - val_loss: 0.5391 - val_acc: 0.8000
Train on 700 samples, validate on 300 samples
在上一个模型中,我们将 SGD 与 nesterov 一起使用,无论我们对它的训练使用了多少个时代,我们都无法提高我们的分数。
为了增加准确性。建议尝试其他优化算法。我们之前已经成功使用了 Adam 优化方法,那么我们在这里再使用一次,看看能否增加精度。像 Adam 这样的自适应学习率会随着时间的推移而降低学习率,因此需要更多的时期才能达到最佳解决方案。因此,在本例中,我们将纪元的数量设置为 200:
adam=keras.optimizers.Adam(lr=0.01)
model.compile(loss='categorical_crossentropy', optimizer=adam)
model.fit(x_train, y_train, verbose=1, batch_size=100, nb_epoch=200,show_accuracy=True,validation_data=(x_test, y_test))
time.sleep(0.1)
OUTPUT:
Epoch 200/200
700/700 [==============================] - 0s - loss: 0.3755 - acc: 0.8657 - val_loss: 0.4725 - val_acc: 0.8200
我们现在已经成功地通过 Adam 优化算法实现了从 0.8 到 0.82 的令人信服的改进。
目前,我们已经介绍了 Keras 中神经网络的最重要的元素。现在让我们继续设置 Keras ,这样它将利用 TensorFlow 框架。默认情况下,Keras 将使用安诺后端。为了指示 Keras 在 TensorFlow 上工作,我们需要首先在 packages 文件夹中找到 Keras 文件夹:
import os
print keras.__file__
您的道路可能会有所不同:
Output: /Library/Python/2.7/site-packages/keras/__init__.pyc
现在我们已经找到了 Keras 的包文件夹,我们需要寻找~/.keras/keras.json文件。
这个文件中有一段脚本如下所示:
{"epsilon": 1e-07, "floatx": "float32", "backend": "theano"}
您只需将"backend":"theano"更改为"backend":"tensorflow",结果如下:
{"epsilon": 1e-07, "floatx": "float32", "backend": "tensorflow"}
如果由于某种原因.json文件不在 Keras 文件夹中,即/Library/Python/2.7/site-packages/keras/,您可以将其复制粘贴到文本编辑器中:
{"epsilon": 1e-07, "floatx": "float32", "backend": "tensorflow"}
保存为.json文件,放入keras文件夹。
要测试 TensorFlow 环境是否在 TensorFlow 中得到正确利用,我们可以键入以下内容:
from keras import backend as K
input = K.placeholder(shape=(4, 4, 5))
# also works:
input = K.placeholder(shape=(None, 2, 5))
# also works:
input = K.placeholder(ndim=2)
OUTPUT:
Using Theano backend.
有些用户可能根本没有输出,这很好。你的 TensorFlow 后端应该可以使用了。
TensorFlow 中的卷积神经网络
在这一章和上一章之间,我们已经走了很长的路,涵盖了深度学习中最重要的主题。我们现在了解如何通过在神经网络中堆叠多层来构建架构,以及如何识别和利用反向传播方法。我们还介绍了使用堆叠式去噪自动编码器进行无监督预处理的概念。深度学习的下一个真正令人兴奋的步骤是卷积神经网络 ( CNN )的快速发展领域,这是一种构建多层、局部连接网络的方法。CNNs,通常被称为convents,在撰写本书时发展如此迅速,以至于我们不得不在一个月的时间内重写和更新这一章。在这一章中,我们将涵盖中枢神经系统背后最基本和最重要的概念,这样我们就能够运行一些基本的例子,而不会被有时巨大的复杂性所淹没。然而,我们不能完全公正地对待巨大的理论和计算背景,所以这一段提供了一个实际的起点。
从概念上理解中枢神经系统最好的方法是追溯历史,从一点点认知神经科学开始,看看 Huber 和 Wiesel 对猫视觉皮层的研究。Huber 和 Wiesel 记录了猫视觉皮层的神经激活,同时通过在大脑的视觉皮层插入微电极来测量神经活动。(可怜的猫!)他们这样做的时候,猫正在观看投影在屏幕上的原始形状图像。有趣的是,他们发现某些神经元只对特定方向或形状的轮廓做出反应。这导致了视觉皮层由局部和定向特异性神经元组成的理论。这意味着特定的神经元只对特定方向和形状(三角形、圆形或正方形)的图像做出反应。考虑到猫和其他哺乳动物可以将复杂且不断进化的形状感知为一个连贯的整体,我们可以假设感知是所有这些局部和分层组织的神经元的集合。到那时,第一个多层感知器已经完全开发出来,所以用不了多久,神经元中的局部性和特定灵敏度的想法就在感知器架构中建模出来了。从计算神经科学的角度来看,这个想法被发展成大脑中局部感受区的地图,并增加了选择性连接的层。这被已经在进行的神经网络和人工智能领域所采用。第一位报道的科学家是福岛和他的所谓的新神经元(1982),他将局部特定计算的概念应用于多层感知器。
Yann LeCun 把新神经元的概念发展成了他的版本,叫做 LeNet。增加了梯度下降反向传播算法。这种 LeNet 架构仍然是最近引入的许多更进化的 CNN 架构的基础。像 LeNet 这样的基本 CNN 学习从第一层中的原始像素中检测边缘,然后使用这些边缘来检测第二层中的简单形状,然后在该过程的后期使用这些形状来检测更高级别的特征,例如更高层中的环境中的对象。神经序列的下一层是使用这些高级特征的最终分类器。我们可以在类似这样的 CNN 中看到前馈传递:我们从矩阵输入移动到像素,我们从像素中检测边缘,然后从边缘检测形状,并从形状中检测越来越有特色、越来越抽象和复杂的特征。
注
网络中的每个卷积或层都可以接受特定的特征(如形状、角度或颜色)。
更深的层将把这些特征组合成一个更复杂的集合。这样,它可以处理完整的图像,而不会在步骤中用图像的全部输入空间给网络增加负担。
到目前为止,我们只研究了完全连接的神经网络,其中每一层都连接到相邻的每一层。这些网络已经被证明是非常有效的,但是缺点是我们必须训练的参数数量急剧增加。另一方面,我们可能会想象,当我们训练一个小图像(28 x 28)大小时,我们可以摆脱完全连接的网络。然而,在跨越整个 T2 的更大的图像上训练一个完全连接的网络,计算量会非常大。
注
总而言之,我们可以说,与全连接神经网络相比,中枢神经系统具有以下优势:
- 它们减少了参数空间,从而防止过度训练和计算负荷
- 中枢神经系统对于物体方向是不变的(想象一下人脸识别对不同位置的人脸进行分类)
- 能够学习和概括复杂多维特征的中枢神经系统
- 神经网络可用于语音识别、图像分类和最近的复杂推荐引擎
中枢神经系统利用所谓的感受野将输入连接到特征地图。了解 CNNs 的最好方法是更深入地了解架构,当然也可以获得实际操作体验。让我们来看看构成中枢神经系统的各种层。美国有线电视新闻网的架构由三种类型的层组成;即卷积层、汇集层和全连接层,其中每层接受输入 3D 体积(h,w,d),并通过可微函数将其转换为 3D 输出。
卷积层
我们可以通过想象一定大小的聚光灯滑过输入(像素值和 RGB 颜色维度)来理解卷积的概念,之后我们可以方便地计算过滤值(也称为面片)和真实输入之间的点积。这做了两件重要的事情:第一,它压缩输入,更重要的是,第二,网络学习过滤器,只有当他们在输入中看到某些特定类型的特征空间位置时,过滤器才会激活。
请看下图,了解这是如何工作的:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_05_6.jpg
处理图像输入的两个卷积层[7x7x3]输入体积:宽度为 7、高度为 7 并且具有三个颜色通道 R、G、B 的图像
从这张图中我们可以看到我们有两级滤波器(W0 和 W1)和输入的三维(以阵列的形式),所有这些都导致输入矩阵上滑动聚光灯/窗口的点积。我们把这个聚光灯的大小称为步幅,意思是步幅越大,输出越小。
如您所见,当我们应用 3×3 过滤器时,过滤器的整个范围都在矩阵的中心进行处理,但是一旦我们靠近或经过边缘,我们就开始在输入的边缘失去优势。在这种情况下,我们应用即所谓的零填充。在这种情况下,输入尺寸之外的所有元素都被设置为零。最近,零填充或多或少成为了大多数美国有线电视新闻网应用的默认设置。
汇集层
下一种类型的层通常位于过滤层之间,称为汇集层或子采样层。这样做是沿着空间维度(宽度、高度)执行下采样操作,这反过来又有助于过拟合和减少计算负载。有几种方法可以执行这种下采样,但最近最大池被证明是最有效的方法。
最大池化是一种简单的方法,它通过取相邻要素的一个面片的最大值来压缩要素。下图将阐明这一观点;矩阵中的每个颜色框代表步幅大小为 2:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_05_5.jpg
跨度为 2 的最大池层
使用池层的主要原因如下:
- 减少参数数量,从而减少计算负载
- 正规化
有趣的是,最新的研究结果建议完全省略汇集层,这将导致更好的准确性(尽管代价是对 CPU 或 GPU 造成更大的压力)。
全连接层
关于这种类型的层没有太多要解释的。计算分类的最终输出(主要使用 softmax)是一个完全连接的层。然而,在卷积层之间,也有(虽然很少)完全连接的层。
在我们自己申请有线电视新闻网之前,让我们把你到目前为止学到的东西拿来,检查一下有线电视新闻网的架构,以检验我们的理解。当我们查看下图中的 ConvNet 架构时,我们已经可以了解到 ConvNet 会对输入做什么。这个例子是一个名为 AlexNet 的有效卷积神经网络,旨在将 120 万幅图像分类为 1000 类。它被用于 2012 年的 ImageNet 竞赛。ImageNet 是全球最重要的图像分类和本地化比赛,每年都会举办。AlexNet 指的是 Alex Krizhevsky(与 Vinod Nair 和 Geoffrey Hinton 一起)。
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_05_2.jpg
AlexNet 架构
当我们查看架构时,我们可以立即看到具有三维深度的输入维度 224 乘以 224。最大池层堆叠的输入中的步长为 4,降低了输入的维度。依次是卷积层。尺寸为 4,096 的两个密集层是完全连接的层,通向我们之前提到的最终输出。
另一方面,我们在前面的一段中提到,TensorFlow 的图形计算允许跨图形处理器的并行化。AlexNet 也做了同样的事情;请看下图,了解他们如何跨 GPU 并行化架构:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_05_4.jpg
上图来自http://www.cs.toronto.edu/~fritz/absps/imagenet.pdf。
AlexNet 让不同的模型通过垂直拆分架构来利用 GPU,以便以后合并到最终的分类输出中。中枢神经系统更适合分布式处理,这是本地连接网络相对于完全连接网络的最大优势之一。该模型训练了一组 120 万张图像,在两台 NVIDIA GTX 580 3GB 图形处理器上用了 5 天时间完成。本项目使用了两个多图形处理器单元(总共六个图形处理器)。
美国有线电视新闻网采用渐进的方式
既然我们已经对有线电视新闻网的架构有了一个很好的了解,让我们开始应用有线电视新闻网吧。
对于本例,我们将使用著名的 CIFAR-10 人脸图像数据集,该数据集在 Keras 域中非常方便。数据集由 60,000 张 32 x 32 的彩色图像组成,10 个目标类别由飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船和卡车组成。这是一个比用于 AlexNet 示例的数据集更小的数据集。更多信息可以参考https://www.cs.toronto.edu/~kriz/cifar.html。
在这个 CNN 中,我们将使用以下体系结构根据我们指定的 10 个类别对图像进行分类:
input->convolution 1 (32,3,3)->convolution 2(32,3,3)->pooling->dropout -> Output (Fully connected layer and softmax)
GPU 计算
如果你安装了一个兼容 CUDA 的显卡,你可以通过在你的集成开发环境上放置下面的代码来利用你的图形处理器。
import os
os.environ['THEANO_FLAGS'] = 'device=gpu0, assert_no_cpu_op=raise, on_unused_input=ignore, floatX=float32'
然而,我们建议首先在您的常规中央处理器上尝试这个例子。
让我们首先导入并准备数据。
我们使用 32 x 32 的输入尺寸,因为这是图像的实际尺寸:
from keras.datasets import cifar10
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.layers.convolutional import Convolution2D, MaxPooling2D
from keras.optimizers import SGD
from keras.utils import np_utils
batch_size = 32
nb_classes = 10
nb_epoch = 5 #these are the number of epochs, watch out because it might set your #cpu/gpu on fire.
# input image dimensions
img_rows, img_cols = 32, 32
# the CIFAR10 images are RGB
img_channels = 3
# the data, shuffled and split between train and test sets
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
print('X_train shape:', X_train.shape)
print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')
#remember we need to encode the target variable
Y_train = np_utils.to_categorical(y_train, nb_classes)
Y_test = np_utils.to_categorical(y_test, nb_classes)
现在,让我们设置我们的 CNN 架构,并根据我们心中的架构构建模型。
对于这个例子,我们将用香草 SGD 和内斯特罗夫动量训练我们的 CNN 模型:
model = Sequential()
#this is the first convolutional layer, we set the filter size
model.add(Convolution2D(32, 3, 3, border_mode='same',
input_shape=(img_channels, img_rows, img_cols)))
model.add(Activation('relu'))
#the second convolutional layer
model.add(Convolution2D(32, 3, 3))
model.add(Activation('relu'))
#here we specify the pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
#first we flatten the input towards the fully connected layer into the softmax function
model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(Dense(nb_classes))
model.add(Activation('softmax'))
# let's train the model using SGD + momentum like we have done before.
sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy', optimizer=sgd)
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
#Here we apply scaling to the features
X_train /= 255
X_test /= 255
这一步非常重要,因为我们在这里指定美国有线电视新闻网进行增量训练。我们在前面几章(参考第二章、Scikit 中的可伸缩学习-learn )看到了,在前面一段,在线和增量学习的计算效率。我们可以模拟它的一些属性,并通过使用一个非常小的纪元大小和一个更小的batch_size(每个纪元中训练集的一部分)将其应用于中枢神经系统,并在 for 循环中对它们进行增量训练。这样,我们可以给定相同数量的时代,在更短的时间内训练我们的有线电视新闻网,同时对主存储器的负担也更低。我们可以用一个简单的 for 循环实现这个非常强大的想法,如下所示:
for epoch in xrange(nb_epoch):
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=1,show_accuracy=True
,validation_data=(X_test, Y_test), shuffle=True)
OUTPUT:]
X_train shape: (50000, 3, 32, 32)
50000 train samples
10000 test samples
Train on 50000 samples, validate on 10000 samples
Epoch 1/1
50000/50000 [==============================] - 1480s - loss: 1.4464 - acc: 0.4803 - val_loss: 1.1774 - val_acc: 0.5785
Train on 50000 samples, validate on 10000 samples
Epoch 1/1
50000/50000 [==============================] - 1475s - loss: 1.0701 - acc: 0.6212 - val_loss: 0.9959 - val_acc: 0.6525
Train on 50000 samples, validate on 10000 samples
Epoch 1/1
50000/50000 [==============================] - 1502s - loss: 0.8841 - acc: 0.6883 - val_loss: 0.9395 - val_acc: 0.6750
Train on 50000 samples, validate on 10000 samples
Epoch 1/1
50000/50000 [==============================] - 1555s - loss: 0.7308 - acc: 0.7447 - val_loss: 0.9138 - val_acc: 0.6920
Train on 50000 samples, validate on 10000 samples
Epoch 1/1
50000/50000 [==============================] - 1587s - loss: 0.5972 - acc: 0.7925 - val_loss: 0.9351 - val_acc: 0.6820
我们可以看到我们的美国有线电视新闻网列车最终达到接近 0.7 的验证精度。考虑到我们已经在具有 50,000 个训练示例和 10 个目标类的高维数据集上训练了一个复杂模型,这已经令人满意了。美国有线电视新闻网在这个数据集上可以达到的最大可能分数至少需要 200 个时代。本例提出的方法绝不是的最终结果。这是让你开始使用中枢神经系统的一个相当基本的实现。可以通过添加或移除层、调整批次大小等方式自由进行实验。玩玩参数,感受一下这是如何工作的。
如果你想了解更多卷积层的最新进展,可以看看 【残留网络】 ( ResNet ),这是 CNN 架构上的最新改进之一。
和其他人是 2015 年 ImageNet(ILSVRC)的获奖者。它的特点是一个有趣的架构,使用了一种叫做批处理规范化的方法,一种规范化层之间的特征转换的方法。在 Keras 中有一个批处理规范化函数,您可能想要对其进行实验(http://keras.io/layers/normalization/)。
为了让您全面了解最新一代的氯化萘,您可能需要熟悉以下被发现更有效的氯化萘参数设置:
- 小步幅
- 权重衰减(正则化而不是丢弃)
- 没有辍学
- 中层之间的批处理规范化
- 少到没有预训练(自动编码器和玻尔兹曼机器慢慢退出图像分类的时尚)
另一个有趣的概念是,最近卷积网络被用于图像检测之外的应用。它们用于语言和文本分类、句子补全,甚至推荐系统。一个有趣的例子是 Spotify 的音乐推荐引擎,它基于卷积神经网络。您可以在这里查看更多信息:
- http://benane . github . io/2014/08/05/Spotify-CNNs . html
- http://machine learning . wustl . edu/mlpapers/paper _ files/NIPS 2013 _ 5004 . pdf
目前,卷积网络用于以下操作:
- 人脸检测(脸书)
- 电影分类(YouTube)
- 语音和文本
- 生成艺术(例如谷歌深度梦境)
- 推荐引擎(音乐推荐—Spotify)
总结
在这一章中,我们已经走了很长的路,涵盖了 TensorFlow 景观及其相应的方法。我们熟悉了如何建立基本的回归器、分类器和单隐层神经网络。尽管编程 TensorFlow 操作相对简单,但对于现成的机器学习任务来说,TensorFlow 可能有点过于繁琐。这正是 SkFlow 的用武之地,它是一个更高级的库,其界面非常类似于 Scikit-learn。对于增量式甚至核外解决方案,SkFlow 提供了一种部分适配的方法,可以轻松设置。其他大规模解决方案要么局限于 GPU 应用,要么处于过早阶段。因此,就目前而言,当涉及到可扩展的解决方案时,我们不得不满足于增量学习策略。
我们还介绍了卷积神经网络,并了解了如何在 Keras 中设置它们。
六、大规模回归树
在这一章中,我们将集中讨论分类和回归树的可伸缩方法。将涵盖以下主题:
- Scikit-learn 中快速随机森林应用的提示和技巧
- 加性随机森林模型和二次抽样
- 梯度升压
- XGBoost 和流方法
- 非常快的 GBM 和 H2O 的随机森林
决策树的目的是学习一系列决策规则,根据训练数据推断目标标签。使用递归算法,该过程从树根开始,并在杂质最少的特征上分割数据。目前,最广泛应用的可扩展的基于树的应用是基于 CART 的。 CART 是分类回归树的缩写,由布瑞曼、弗里德曼·斯通和奥尔森于 1984 年引入。CART 在两个方面不同于其他决策树模型(如 ID3、C4.5/C5.0、CHAID 和 MARS)。首先,CART 适用于分类和回归问题。其次,它构建二叉树(在每次分裂时,产生一个二进制分裂)。这使得 CART 树能够对给定的特征进行递归操作,并以贪婪的方式对杂质形式的误差度量进行优化。这些二叉树以及可扩展的解决方案是本章的重点。
让我们仔细看看这些树是如何建造的。我们可以看到决策树是一个有节点的图,从上到下传递信息。树中的每个决策都是通过对类(布尔型)或连续变量(阈值)进行二进制拆分而做出的,从而得到最终的预测。
树是通过以下过程构建和学习的:
- 递归地寻找将目标标签从根节点分割到终端节点的最佳变量。这是通过我们根据目标结果最小化的每个特征的杂质来衡量的。在本章中,相关的杂质测度是基尼杂质和交叉熵。
基尼杂质
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_04.jpg
基尼不纯度是一个度量标准,用于衡量目标类( k )的概率 pi 之间的差异,因此概率值在目标类上的平均分布会导致较高的基尼不纯度。
交叉熵
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_05.jpg
通过交叉熵,我们可以看到错误分类的对数概率。这两个指标都被证明产生了非常相似的结果。然而,基尼杂质在计算上更有效,因为它不需要计算日志。
我们这样做,直到满足停止标准。这个标准大致意味着两件事:第一,添加新变量不再改善目标结果,第二,达到最大树深度或树复杂度阈值。请注意,具有许多节点的非常深且复杂的树很容易导致过度拟合。为了防止这种情况,我们通常通过限制树的深度来修剪树。
为了获得对这个过程如何工作的直觉,让我们用 Scikit 构建一个决策树——用 graphviz 学习和可视化它。首先,创建一个玩具数据集,看看我们能否根据智商(数字)、年龄(数字)、年收入(数字)、企业主(布尔)和大学学位(布尔)来预测谁是吸烟者,谁不是。您需要从http://www.graphviz.org下载软件,以便加载我们将使用 Scikit-learn 创建的tree.dot文件的可视化:
import numpy as np
from sklearn import tree
iq=[90,110,100,140,110,100]
age=[42,20,50,40,70,50]
anincome=[40,20,46,28,100,20]
businessowner=[0,1,0,1,0,0]
univdegree=[0,1,0,1,0,0]
smoking=[1,0,0,1,1,0]
ids=np.column_stack((iq, age, anincome,businessowner,univdegree))
names=['iq','age','income','univdegree']
dt = tree.DecisionTreeClassifier(random_state=99)
dt.fit(ids,smoking)
dt.predict(ids)
tree.export_graphviz(dt,out_file='tree2.dot',feature_names=names,label=all,max_depth=5,class_names=True)
现在可以在工作目录中找到tree.dot文件。找到该文件后,您可以使用 graphviz 软件打开它:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_14.jpg
- 根节点(收入):这是表示具有最高信息增益和最低杂质(基尼系数=.5)的特征的起始节点
- 内部节点(年龄和智商):这是根节点和终端之间的每个节点。父节点将决策规则传递给接收端—子节点(左和右)
- 终端节点(叶节点):由树结构划分的目标标签
树深是从根节点到终端节点的边数。在这种情况下,我们的树深度为 3。
我们现在可以看到生成的树产生的所有二进制拆分。在根节点的顶部,我们可以看到收入低于 24k 的人不是吸烟者(收入< 24)。我们还可以在每个节点上看到相应的基尼杂质(. 5)。没有剩余的子节点,因为决定是最终的。路径仅仅到此结束,因为它完全划分了目标类。然而,在收入的正确子节点(年龄)中,树分支出来。在这里,如果年龄小于等于 46,那么这个人不是吸烟者,但是年龄大于 46,智商低于 105,这个人就是吸烟者。同样重要的是,我们创建的几个不属于树的特性——学位和企业所有者。这是因为树中的变量能够对没有它们的目标标签进行分类。这些省略的特征根本无助于降低树的杂质水平。
单个树有其缺点,因为它们容易过度覆盖,因此不能很好地推广到看不见的数据。这些技术的当前一代是用集成方法训练的,在集成方法中,单棵树被聚合成更强大的模型。这些 CART 集成技术是最常用的机器学习方法之一,因为它们的准确性、易用性和处理异构数据的能力。这些技术已成功应用于最近的数据科学竞赛,如卡格尔杯和 KDD 杯。由于分类和回归树的集成方法目前是人工智能和数据科学领域的标准,CART 集成方法的可扩展解决方案将是本章的主要主题。
一般来说,我们可以辨别两类用于 CART 模型的集成方法,即打包和增强。让我们通过这些概念来更好地理解集成的形成过程。
引导聚合
装袋是自举聚合的缩写。自举技术起源于分析师不得不处理数据稀缺的背景。使用这种统计方法,当统计分布不能先验地计算出来时,使用子样本来估计总体参数。自举的目标是为群体参数提供更稳健的估计,其中通过随机二次抽样和替换将更多可变性引入较小的数据集。通常,引导遵循以下基本步骤:
- 从给定数据集中随机抽取一批大小为 x 的样本进行替换。
- 从每个样本中计算一个度量或参数来估计总体参数。
- 汇总结果。
近年来,自举方法也被用于机器学习模型的参数。当分类器提供高度多样化的决策边界时,集成是最有效的。这种集成的多样性可以通过其底层模型和这些模型所基于的数据的多样性来实现。树非常适合分类器之间的这种多样性,因为树的结构可以是高度可变的。然而,最流行的集成方法是使用不同的训练数据集来训练单个分类器。通常,这样的数据集是通过二次采样技术获得的,例如自举和打包。一切都始于这样一个想法,即通过利用更多的数据,我们可以减少估计的方差。如果手头不可能有更多的数据,重新采样可以提供显著的改进,因为它允许在训练样本的许多版本上重新训练算法。这就是打包的想法;使用 bagging,我们通过聚集(例如,平均)许多重采样的结果,将最初的 bootstrap 思想更进一步,以便得到最终的预测,在该预测中,由于样本内过拟合引起的误差被相互平滑。
当我们将打包等集成技术应用于树模型时,我们会在原始数据集的每个单独的自举样本(或使用采样进行二次采样,无需替换)上构建多个树,然后聚合结果(通常通过算术、几何平均或投票)。
以这种方式,标准打包算法将如下所示:
- 从整个数据集(【S1】、 S2 、… Sn )中抽取一个 n 个大小为 K 的随机样本进行替换。
- 在( S1 、 S2 、… 锡上种植不同的树木。
- 根据新数据计算样本( S1 、 S2 、… 锡)的预测值,并汇总其结果。
CART 模型从打包方法中受益匪浅,因为它引入了随机性和多样性。
随机林和极随机林
除了装袋,基于训练示例,我们还可以根据特征抽取随机子样本。这样的方法被称为随机子空间。随机子空间对于高维数据(具有大量特征的数据)特别有用,它是我们称之为随机森林的方法的基础。在撰写本文时,随机森林是最受欢迎的机器学习算法,因为它易于使用,对杂乱的数据具有鲁棒性,并且可并行化。它进入了各种各样的应用,如定位应用、游戏和医疗保健应用的筛选方法。例如,Xbox Kinect 使用随机森林模型进行运动检测。考虑到随机森林算法基于 bagging 方法,该算法相对简单:
- 从可用样本中抽取尺寸为 N 的 m 样本。
- 在每个节点分割处,使用特征集 G (无替换)的不同部分,在每个子集( S1 、 S2 、… 锡)上独立构建树。
- 最小化节点分裂的误差(基于基尼指数或熵度量)。
- 让每棵树进行预测并汇总结果,使用投票进行分类,使用平均进行回归。
由于 bagging 依赖于多个子样本,因此它是并行化的绝佳选择,其中每个 CPU 单元都专用于计算单独的模型。这样,我们可以利用多核的广泛可用性来加快学习速度。作为这种扩展策略的一个限制,我们必须意识到 Python 是单线程的,我们将不得不复制许多 Python 实例,每个实例都复制我们必须使用的示例中的内存空间。因此,我们需要有大量可用的内存来适应训练矩阵和进程数量。如果可用的内存不够,设置在我们的计算机上同时运行的并行树计算的数量将无助于缩放算法。在这种情况下,CPU 使用率和 RAM 内存是重要的瓶颈。
随机森林模型很容易用于机器学习,因为它们不需要大量的超参数调整就能很好地执行。感兴趣的最重要参数是对模型性能影响最大的树木数量和树木深度(树木深度)。当对这两个超参数进行操作时,它会导致精度/性能之间的权衡,即更多的树和更多的深度会导致更高的计算负载。作为实践者,我们的经验建议不要将树数量的值设置得太高,因为最终,该模型的性能将达到一个稳定水平,并且在添加更多树时不会再提高,而只会导致对 CPU 内核的征税。在这样的考虑下,尽管带有默认参数的随机森林模型在开箱即用时表现良好,但我们仍然可以通过调整树的数量来提高其性能。有关随机林的超参数的概述,请参见下表。
随机森林装袋的最重要参数:
n_estimators:模型中树的数量max_features:用于树构造的特征数量min_sample_leaf:如果终端节点包含的样本少于最小值,则删除节点分裂max_depth:我们从根节点到终端节点自上而下传递的节点数criterion:计算最佳分割的方法(基尼或熵)min_samples_split:分割一个内部节点所需的最小样本数
Scikit-learn 提供了大量强大的 CART 集成应用,其中一些计算效率很高。说到随机森林,有一个经常被忽视的算法叫做额外树,更广为人知的是极随机森林。当谈到 CPU 效率时,额外的树可以提供比常规随机森林相当大的加速——有时甚至是十倍。
在下表中,您可以看到每种方法的计算速度。一旦我们增加样本量,额外树的速度会大大加快,差异会更明显:
|样品化
|
提取物
|
随机森林
|
| — | — | — |
| One hundred thousand | 25.9 秒 | 164 s |
| Fifty thousand | 9.95 秒 | 35.1 秒 |
| ten thousand | 2.11 秒 | 6.3 秒 |
用 50 个特征和 100 个估计量训练模型,用于额外的树和随机森林。在这个例子中,我们使用了一个具有 16GB 内存的四核 MacBook Pro。我们以秒为单位测量训练时间。
在这一段中,我们将使用极端森林来代替 Scikit-learn 中的香草随机森林方法。所以你可能会问:它们有什么不同?区别并不明显复杂。在随机森林中,节点分割决策规则基于每次迭代中随机选择的特征的最佳得分。在极度随机化的森林中,对随机子集中的每个要素生成随机分割(因此不需要计算来寻找每个要素的最佳分割),然后选择最佳评分阈值。这种方法带来了一些有利的特性,因为该方法导致获得具有较低方差的模型,即使每个单独的树生长直到在终端节点中具有最大可能的精度。随着更多的随机性被添加到分支分裂中,树学习器产生错误,这些错误因此在集合中的树之间不太相关。这将导致集成中更多的不相关估计,并且根据学习问题(毕竟没有免费的午餐),导致比标准随机森林集成更低的泛化误差。然而,实际上,规则随机森林模型可以提供稍高的精度。
给定如此有趣的学习属性,通过更有效的节点分裂计算和同样的可用于随机森林的并行性,如果我们想要加速核心内学习,我们认为极随机化树是集成树算法范围内的优秀候选。
要阅读极其随机化的森林算法的详细描述,您可以阅读以下启动一切的文章:
页(page 的缩写)厄恩斯特和魏汉高,极随机化树,机器学习,63(1),3-42,2006。本文可在https://www . semanticschool . org/paper/extreme-随机化-trees-Geurts-Ernst/336 a 165 c 17 c 9 c 56160d 332 b 9 F4 a2 b 403 fccbdbfb/pdf免费获取。
作为如何扩展核心树集成的一个例子,我们将运行一个例子,其中我们将一个有效的随机森林方法应用于信用数据。该数据集用于预测信用卡客户的违约率。数据由 18 个特征和 30,000 个训练示例组成。由于我们需要导入一个 XLS 格式的文件,您将需要安装xlrd包,我们可以通过在命令行终端中键入以下内容来实现:
$ pip install xlrd
import pandas as pd
import numpy as np
import os
import xlrd
import urllib
#set your path here
os.chdir('/your-path-here')
url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/00350/default%20of%20credit%20card%20clients.xls'
filename='creditdefault.xls'
urllib.urlretrieve(url, filename)
target = 'default payment next month'
data = pd.read_excel('creditdefault.xls', skiprows=1)
target = 'default payment next month'
y = np.asarray(data[target])
features = data.columns.drop(['ID', target])
X = np.asarray(data[features])
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.cross_validation import cross_val_score
from sklearn.datasets import make_classification
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y,test_size=0.30, random_state=101)
clf = ExtraTreesClassifier(n_estimators=500, random_state=101)
clf.fit(X_train,y_train)
scores = cross_val_score(clf, X_train, y_train, cv=3,scoring='accuracy', n_jobs=-1)
print "ExtraTreesClassifier -> cross validation accuracy: mean = %0.3f std = %0.3f" % (np.mean(scores), np.std(scores))
Output]
ExtraTreesClassifier -> cross validation accuracy: mean = 0.812 std = 0.003
现在我们已经对训练集的准确性有了一些基本的估计,让我们看看它在测试集上的表现。在这种情况下,我们希望监控假阳性和假阴性,并检查目标变量上的类不平衡:
y_pred=clf.predict(X_test)
from sklearn.metrics import confusion_matrix
confusionMatrix = confusion_matrix(y_test, y_pred)
print confusionMatrix
from sklearn.metrics import accuracy_score
accuracy_score(y_test, y_pred)
OUTPUT:
[[6610 448]
[1238 704]]
Our overall test accuracy:
0.81266666666666665
有趣的是,测试集的准确性等于我们的训练结果。由于我们的基线模型只是使用默认设置,因此我们可以尝试通过调整超参数来提高性能,这是一项计算成本很高的任务。最近,计算效率更高的超参数优化方法得到了发展,我们将在下一节中介绍。
随机搜索快速参数优化
您可能已经熟悉了 Scikit-learn 的 gridsearch 功能。这是一个很好的工具,但是当它涉及到大文件时,它可以极大地增加训练时间,这取决于参数空间。对于极端随机森林,我们可以使用名为随机搜索的替代参数搜索方法来加快参数调整的计算时间。公共网格搜索通过系统测试所有可能的超参数设置组合来消耗 CPU 和内存,随机搜索随机选择超参数组合。当 gridsearch 测试超过 30 种组合时(对于较小的搜索空间,gridsearch 仍然具有竞争力),这种方法可以显著提高计算速度。可实现的增益与我们从随机森林切换到极随机森林时看到的相同(根据硬件规格、超参数空间和数据集大小,可以考虑 2 到 10 倍的增益)。
我们可以指定由n_iter参数随机评估的超参数设置的数量:
from sklearn.grid_search import GridSearchCV, RandomizedSearchCV
param_dist = {"max_depth": [1,3, 7,8,12,None],
"max_features": [8,9,10,11,16,22],
"min_samples_split": [8,10,11,14,16,19],
"min_samples_leaf": [1,2,3,4,5,6,7],
"bootstrap": [True, False]}
#here we specify the search settings, we use only 25 random parameter
#valuations but we manage to keep training times in check.
rsearch = RandomizedSearchCV(clf, param_distributions=param_dist,
n_iter=25)
rsearch.fit(X_train,y_train)
rsearch.grid_scores_
bestclf=rsearch.best_estimator_
print bestclf
在这里,我们可以看到我们模型的最佳参数设置列表。
我们现在可以使用这个模型对我们的测试集进行预测:
OUTPUT:
ExtraTreesClassifier(bootstrap=False, class_weight=None, criterion='gini',
max_depth=12, max_features=11, max_leaf_nodes=None,
min_samples_leaf=4, min_samples_split=10,
min_weight_fraction_leaf=0.0, n_estimators=500, n_jobs=1,
oob_score=False, random_state=101, verbose=0, warm_start=False)
y_pred=bestclf.predict(X_test)
confusionMatrix = confusion_matrix(y_test, y_pred)
print confusionMatrix
accuracy=accuracy_score(y_test, y_pred)
print accuracy
OUT
[[6733 325]
[1244 698]]
Out[152]:
0.82566666666666666
我们设法在可管理的训练时间范围内提高模型的性能,同时提高精度。
极度随机化的树和大数据集
到目前为止,由于随机森林的特定特征及其更有效的替代物,极度随机化森林,我们已经研究了利用多核处理器和随机化来扩大规模的解决方案。但是,如果您必须处理一个不适合内存或对 CPU 要求过高的大型数据集,您可能希望尝试一种核外解决方案。集成的核心外方法的最佳解决方案是 H2O 提供的解决方案,这将在本章后面详细介绍。然而,我们可以运用另一个实用技巧,让随机森林或额外的树在大规模数据集上平稳运行。第二好的解决方案是在数据的子样本上训练模型,然后在不同的数据子样本上集成每个模型的结果(毕竟,我们只需要对结果进行平均或分组)。在第 3 章、快速学习支持向量机中,我们已经介绍了储层采样的概念,处理数据流上的采样。在本章中,我们将再次使用采样,诉诸于更多的采样算法选择。首先,让我们安装一个名为 subsample 的非常方便的工具,由 Paul Butler(https://github.com/paulgb/subsample)开发,这是一个命令行工具,用于从一个大的、以换行符分隔的数据集(通常是一个类似 CSV 的文件)中采样数据。该工具提供了快速简便的采样方法,例如储层采样。
如第 3 章、快速学习支持向量机所示,储层采样是一种采样算法,有助于从一条河流中采样固定大小的样本。概念上很简单(我们已经在第 3 章中看到了公式),它只需要简单地传递数据来产生一个样本,该样本将存储在磁盘上的一个新文件中。(我们在第 3 章中的脚本将它存储在内存中。)
在下一个示例中,我们将使用这个子样本工具和一种方法来集成在这些子样本上训练的模型。
概括地说,在本节中,我们将执行以下操作:
- 创建我们的数据集,并将其分为测试和训练数据。
- 绘制训练数据的子样本,并将它们作为单独的文件保存在硬盘上。
- 加载这些子样本,并在其上训练极其随机的森林模型。
- 汇总模型。
- 检查结果。
让我们用pip安装这个子示例工具:
$pip install subsample
在命令行中,设置包含要采样的文件的工作目录:
$ cd /yourpath-here
此时,使用cd命令,您可以指定您的工作目录,您将需要在其中存储我们将在下一步创建的文件。
我们通过以下方式做到这一点:
from sklearn.datasets import fetch_covtype
import numpy as np
from sklearn.cross_validation import train_test_split
dataset = fetch_covtype(random_state=111, shuffle=True)
dataset = fetch_covtype()
X, y = dataset.data, dataset.target
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.3, random_state=0)
del(X,y)
covtrain=np.c_[X_train,y_train]
covtest=np.c_[X_test,y_test]
np.savetxt('covtrain.csv', covtrain, delimiter=",")
np.savetxt('covtest.csv', covtest, delimiter=",")
现在,我们已经将数据集划分为测试集和训练集,让我们对训练集进行二次采样,以便获得可以在内存中上传的数据块。考虑到完整训练数据集的大小为 30,000 个示例,我们将对三个较小的数据集进行二次采样,每个数据集由 10,000 个项目组成。如果您的计算机配备了小于 2GB 的内存,您可能会发现将初始训练集分割成更小的文件更容易管理,尽管您将获得的建模结果可能与我们基于三个子样本的示例不同。通常,子样本中的例子越少,模型的偏差就越大。当进行二次抽样时,我们实际上是在权衡处理更易管理的数据量的优势和估计偏差的增加:
$ subsample --reservoir -n 10000 covtrain.csv > cov1.csv
$ subsample --reservoir -n 10000 covtrain.csv > cov2.csv
$ subsample --reservoir -n 10000 covtrain.csv>cov3.csv
现在,您可以在命令行中指定的文件夹中找到这些子集。
现在确保在 IDE 或笔记本中设置了相同的路径。
让我们一个接一个地加载样本,并在样本上训练一个随机森林模型。
为了稍后将它们组合起来进行最终预测,请注意,我们保持一种逐行的方法,以便您可以密切关注连续的步骤。
为了使这些示例成功,请确保您使用的是 IDE 或 Jupyter 笔记本中设置的相同路径:
import os
os.chdir('/your-path-here')
此时,我们已经准备好开始从数据中学习,我们可以将样本逐个加载到内存中,并在这些样本上训练一组树:
import numpy as np
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.cross_validation import cross_val_score
from sklearn.cross_validation import train_test_split
import pandas as pd
import os
在报告验证分数之后,代码将在所有数据块上继续训练我们的模型,一次一个。当我们从不同的数据分区、一个数据块接一个数据块分别学习时,我们使用warm_start=Trueparameter和set_params方法初始化集成学习器(在本例中为ExtraTreeClassifier),其中从之前的训练会话中递增地添加树,因为 fit 方法被多次调用:
#here we load sample 1
df = pd.read_csv('/yourpath/cov1.csv')
y=df[df.columns[54]]
X=df[df.columns[0:54]]
clf1=ExtraTreesClassifier(n_estimators=100, random_state=101,warm_start=True)
clf1.fit(X,y)
scores = cross_val_score(clf1, X, y, cv=3,scoring='accuracy', n_jobs=-1)
print "ExtraTreesClassifier -> cross validation accuracy: mean = %0.3f std = %0.3f" % (np.mean(scores), np.std(scores))
print scores
print 'amount of trees in the model: %s' % len(clf1.estimators_)
#sample 2
df = pd.read_csv('/yourpath/cov2.csv')
y=df[df.columns[54]]
X=df[df.columns[0:54]]
clf1.set_params(n_estimators=150, random_state=101,warm_start=True)
clf1.fit(X,y)
scores = cross_val_score(clf1, X, y, cv=3,scoring='accuracy', n_jobs=-1)
print "ExtraTreesClassifier after params -> cross validation accuracy: mean = %0.3f std = %0.3f" % (np.mean(scores), np.std(scores))
print scores
print 'amount of trees in the model: %s' % len(clf1.estimators_)
#sample 3
df = pd.read_csv('/yourpath/cov3.csv')
y=df[df.columns[54]]
X=df[df.columns[0:54]]
clf1.set_params(n_estimators=200, random_state=101,warm_start=True)
clf1.fit(X,y)
scores = cross_val_score(clf1, X, y, cv=3,scoring='accuracy', n_jobs=-1)
print "ExtraTreesClassifier after params -> cross validation accuracy: mean = %0.3f std = %0.3f" % (np.mean(scores), np.std(scores))
print scores
print 'amount of trees in the model: %s' % len(clf1.estimators_)
# Now let's predict our combined model on the test set and check our score.
df = pd.read_csv('/yourpath/covtest.csv')
X=df[df.columns[0:54]]
y=df[df.columns[54]]
pred2=clf1.predict(X)
scores = cross_val_score(clf1, X, y, cv=3,scoring='accuracy', n_jobs=-1)
print "final test score %r" % np.mean(scores)
OUTPUT:]
ExtraTreesClassifier -> cross validation accuracy: mean = 0.803 std = 0.003
[ 0.805997 0.79964007 0.8021021 ]
amount of trees in the model: 100
ExtraTreesClassifier after params -> cross validation accuracy: mean = 0.798 std = 0.003
[ 0.80155875 0.79651861 0.79465626]
amount of trees in the model: 150
ExtraTreesClassifier after params -> cross validation accuracy: mean = 0.798 std = 0.006
[ 0.8005997 0.78974205 0.8033033 ]
amount of trees in the model: 200
final test score 0.92185447181058278
注
警告:这个方法看起来不像皮托尼克,但是非常有效。
我们现在已经提高了最终预测的分数;在测试集上,我们从大约 0.8 的精确度到 0.922 的精确度。这是因为我们有一个最终的组合模型,包含了前面三个随机森林模型的所有树信息。在代码的输出中,您还可以注意到添加到初始模型中的树的数量。
从这里开始,您可能希望在更大的数据集上尝试这样的方法,利用更多的子样本,或者对其中一个子样本应用随机搜索以进行更好的调整。
推车和助推
我们从装袋开始这一章;现在我们将使用 boosting 来完成我们的概述,boosting 是一种不同的集成方法。就像装袋一样,boosting 既可以用于回归也可以用于分类,并且最近为了更高的准确性而盖过了随机森林。
作为一个优化过程,boosting 基于我们在其他方法中看到的随机梯度下降原理,即通过根据梯度最小化误差来优化模型。迄今为止最常见的助推方法是 AdaBoost 和梯度助推(GBM 和最近的 XGBoost)。AdaBoost 算法归结为最小化那些预测略有错误的情况的误差,以便更难分类的情况得到更多的关注。最近,AdaBoost 失宠了,因为发现其他助推方法通常更准确。
在本章中,我们将介绍 Python 用户迄今为止可用的两种最有效的增强算法:Scikit-learn 包中的梯度增强机器 ( GBM )和 T5】极限梯度增强 ( XGBoost )。由于 GBM 本质上是顺序的,该算法很难并行化,因此比随机森林更难扩展,但是一些技巧可以做到这一点。一些加速算法的提示和技巧将会被一个不错的 H2O 内存不足解决方案所覆盖。
梯度增压机
正如我们在前面几节中看到的,随机森林和极端树是高效的算法,两者都可以用最少的努力很好地工作。虽然 GBM 被认为是一种更精确的方法,但它并不容易使用,并且总是需要调整它的许多超参数才能获得最佳结果。另一方面,随机森林只需要考虑几个参数(主要是树的深度和树的数量),就可以表现得相当好。另一个要注意的是过度训练。随机森林对过度训练的敏感度低于 GBM。所以,有了 GBM,我们还需要考虑正则化策略。最重要的是,随机森林更容易执行并行操作,因为 GBM 是顺序的,因此计算速度较慢。
在本章中,我们将在 Scikit-learn 中应用 GBM,看看名为 XGBoost 的下一代树提升算法,并在 H2O 上实现更大规模的提升。
我们在 Scikit-learn 和 H2O 中使用的 GBM 算法基于两个重要的概念:加法展开和通过最速下降算法的梯度优化。前者的一般思想是生成一系列相对简单的树(弱学习者),其中每个连续的树都是沿着一个梯度添加的。让我们假设我们有 M 树来聚合集合中的最终预测。每次迭代 fk 中的树现在是模型中所有可能的树(https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_09.jpg该参数更好地称为n_estimators):
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_15.jpg
加法扩展将以分阶段的方式向以前的树添加新树:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_10.jpg
我们的梯度增强系综的预测只是所有先前的树和新添加的树https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_11.jpg
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_16.jpg
GBM 算法的第二个重要但相当棘手的部分是通过最速下降进行梯度优化。这意味着我们在加法模型中加入了越来越强大的树。这是通过对新树应用梯度优化来实现的。由于没有像传统学习算法那样的参数,我们如何用树执行梯度更新?首先,我们参数化树;我们通过沿着梯度递归升级节点分割值来实现这一点,其中节点由向量表示。这样,最陡的下降方向是损失函数的负梯度,节点分裂将被升级和学习,导致:
- https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_12.jpg数将导致集成学习缓慢
- https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_13.jpg
因此,每片叶子的预测分数就是新树的最终分数,它就是每片叶子的总和:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_17.jpg
因此,总结来说,GBM 的工作原理是逐渐增加沿着梯度学习的更精确的树。
现在我们已经理解了核心概念,让我们运行一个 GBM 示例,看看最重要的参数。对于 GBM 来说,这些参数特别重要,因为当我们将树的数量设置得太高时,我们必然会成倍地消耗计算资源。所以要小心这些参数。Scikit-learn 的 GBM 应用中的大多数参数与我们在上一段中介绍的随机森林中的参数相同。我们需要考虑三个需要特别注意的参数。
最大深度
与随机森林相反,随机森林在将树结构构建到最大扩展时表现更好(从而构建和集合具有高方差的预测因子),GBM 倾向于更好地处理较小的树(从而利用具有较高偏差的预测因子,即弱学习者)。使用较小的决策树或仅使用树桩(只有一个分支的决策树)可以减少训练时间,在执行速度和较大偏差之间进行权衡(因为较小的树很难截取数据中更复杂的关系)。
学习率
也称为收缩https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_12.jpg参数,每个树将如何为集成做出贡献。该参数的较小值可以改善训练过程中的优化,尽管这将需要更多的估计器来收敛,从而需要更多的计算时间。由于它会影响集合中每棵树的权重,较小的值意味着每棵树对优化过程的贡献很小,在找到好的解决方案之前,您需要更多的树。因此,在为性能优化该参数时,我们应该避免可能导致次优模型的过大值;我们还必须避免使用太低的值,因为这将严重影响计算时间(集成需要更多的树来收敛到一个解)。根据我们的经验,一个好的起点是使用范围在< 0.1 和>001 之间的学习率。
子样本
让我们回忆一下装袋和粘贴的原理,我们随机抽取样本并在那些样本上构建树。如果我们对 GBM 应用子采样,我们会随机化树结构,防止过度拟合,减少内存负载,甚至有时会提高精度。我们也可以将这个过程应用于 GBM,使它更随机,从而利用打包的优势。我们可以通过将子样本参数设置为. 5 来随机化 GBM 中的树结构。
更快的 GBM,带热启动
该参数允许在每次迭代添加到前一次迭代后存储新的树信息,而不需要生成新的树。这样,我们可以节省内存,并大大加快计算时间。
使用 Scikit-learn 中提供的 GBM,我们可以采取两种措施来提高内存和 CPU 效率:
- (半)增量学习的热启动
- 我们可以在交叉验证期间使用并行处理
让我们运行一个 GBM 分类示例,其中我们使用了来自 UCI 机器学习库的垃圾邮件数据集。我们将首先加载数据,对其进行预处理,并查看每个特征的可变重要性:
import pandas
import urllib2
import urllib2
from sklearn import ensemble
columnNames1_url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/spambase/spambase.names'
columnNames1 = [
line.strip().split(':')[0]
for line in urllib2.urlopen(columnNames1_url).readlines()[33:]]
columnNames1
n = 0
for i in columnNames1:
columnNames1[n] = i.replace('word_freq_','')
n += 1
print columnNames1
spamdata = pandas.read_csv(
'https://archive.ics.uci.edu/ml/machine-learning-databases/spambase/spambase.data',
header=None, names=(columnNames1 + ['spam'])
)
X = spamdata.values[:,:57]
y=spamdata['spam']
spamdata.head()
import numpy as np
from sklearn import cross_validation
from sklearn.metrics import classification_report
from sklearn.cross_validation import cross_val_score
from sklearn.cross_validation import cross_val_predict
from sklearn.cross_validation import train_test_split
from sklearn.metrics import recall_score, f1_score
from sklearn.cross_validation import cross_val_predict
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.ensemble import GradientBoostingClassifier
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.3, random_state=22)
clf = ensemble.GradientBoostingClassifier(n_estimators=300,random_state=222,max_depth=16,learning_rate=.1,subsample=.5)
scores=clf.fit(X_train,y_train)
scores2 = cross_val_score(clf, X_train, y_train, cv=3, scoring='accuracy',n_jobs=-1)
print scores2.mean()
y_pred = cross_val_predict(clf, X_test, y_test, cv=10)
print 'validation accuracy %s' % accuracy_score(y_test, y_pred)
OUTPUT:]
validation accuracy 0.928312816799
confusionMatrix = confusion_matrix(y_test, y_pred)
print confusionMatrix
from sklearn.metrics import accuracy_score
accuracy_score(y_test, y_pred)
clf.feature_importances_
def featureImp_order(clf, X, k=5):
return X[:,clf.feature_importances_.argsort()[::-1][:k]]
newX = featureImp_order(clf,X,2)
print newX
# let's order the features in amount of importance
print sorted(zip(map(lambda x: round(x, 4), clf.feature_importances_), columnNames1),
reverse=True)
OUTPUT]
0.945030177548
precision recall f1-score support
0 0.93 0.96 0.94 835
1 0.93 0.88 0.91 546
avg / total 0.93 0.93 0.93 1381
[[799 36]
[ 63 483]]
Feature importance:
[(0.2262, 'char_freq_;'),
(0.0945, 'report'),
(0.0637, 'capital_run_length_average'),
(0.0467, 'you'),
(0.0461, 'capital_run_length_total')
(0.0403, 'business')
(0.0397, 'char_freq_!')
(0.0333, 'will')
(0.0295, 'capital_run_length_longest')
(0.0275, 'your')
(0.0259, '000')
(0.0257, 'char_freq_(')
(0.0235, 'char_freq_$')
(0.0207, 'internet')
我们可以看到这个字符;在垃圾邮件的分类上是最有区别的。
注
可变重要性向我们展示了每个特征的拆分在多大程度上减少了树中所有拆分的相对杂质。
暖机加速 warm _ start
遗憾的是,Scikit-learn 中没有针对 GBM 的并行处理。只有交叉验证和 gridsearch 可以并行化。那么,我们能做些什么来加快速度呢?我们看到 GBM 的工作原理是加法扩展,其中树是递增添加的。我们可以在 Scikit-learn 中用warm-start参数利用这个想法。我们可以用 Scikit-learn 的 GBM 功能对此进行建模,方法是使用方便的 for 循环逐步构建树模型。因此,让我们用相同的数据集来做这件事,并检查它提供的计算优势:
gbc = GradientBoostingClassifier(warm_start=True, learning_rate=.05, max_depth=20,random_state=0)
for n_estimators in range(1, 1500, 100):
gbc.set_params(n_estimators=n_estimators)
gbc.fit(X_train, y_train)
y_pred = gbc.predict(X_test)
print(classification_report(y_test, y_pred))
print(gbc.set_params)
OUTPUT:
precision recall f1-score support
0 0.93 0.95 0.94 835
1 0.92 0.89 0.91 546
avg / total 0.93 0.93 0.93 1381
<bound method GradientBoostingClassifier.set_params of GradientBoostingClassifier(init=None, learning_rate=0.05, loss='deviance',
max_depth=20, max_features=None, max_leaf_nodes=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=1401,
presort='auto', random_state=0, subsample=1.0, verbose=0,
warm_start=True)>
建议特别注意树的设置输出(n_estimators=1401)。你可以看到我们用的树的大小是 1401。当我们将其与类似的 GBM 模型进行比较时,这个小技巧帮助我们减少了大量的训练时间(想想一半甚至更少),我们会同时用 1401 棵树进行训练。请注意,我们可以将此方法用于随机森林和极端随机森林。然而,我们发现这对于 GBM 特别有用。
让我们看看显示常规 GBM 的训练时间和我们的warm_start方法的图。计算速度相当快,精度保持相对不变:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_18.jpg
训练和存储 GBM 模型
有没有想过同时在三台电脑上训练一个模型?还是在 EC2 实例上训练 GBM 模型?可能会有这样一种情况:你训练一个模型,并希望存储它,以便以后再次使用。当你要等两天才能完成一轮完整的训练时,我们不想再次经历这个过程。在一个案例中,您已经在亚马逊 EC2 实例上的云中训练了一个模型,您可以存储该模型,并在以后使用 Scikit-learn 的joblib在另一台计算机上重用它。因此,让我们走完这个过程,因为 Scikit-learn 为我们提供了一个方便的工具来管理它。
让我们导入正确的库,并为文件位置设置目录:
import errno
import os
#set your path here
path='/yourpath/clfs'
clfm=os.makedirs(path)
os.chdir(path)
现在让我们将模型导出到硬盘上的指定位置:
from sklearn.externals import joblib
joblib.dump( gbc,'clf_gbc.pkl')
现在,我们可以加载模型并将其重新用于其他目的:
model_clone = joblib.load('clf_gbc.pkl')
zpred=model_clone.predict(X_test)
print zpred
XGBoost
我们刚刚讨论过,当使用 Scikit-learn 的 GBM 时,没有并行处理的选项,这正是 XGBoost 的用武之地。在 GBM 的基础上,XGBoost 引入了更具可扩展性的方法,在单台机器上利用多线程,在多台服务器的集群上利用并行处理(使用分片)。XGBoost 相对于 GBM 最重要的改进在于后者管理稀疏数据的能力。XGBoost 自动接受稀疏数据作为输入,而不在内存中存储零值。XGBoost 的第二个好处在于在分支树时计算最佳节点分割值的方式,这种方法被称为分位数草图。这种方法通过加权算法对数据进行转换,以便根据一定的准确度对候选拆分进行排序。更多信息请阅读 http://arxiv.org/pdf/1603.02754v3.pdf 的文章。
XGBoost 代表 Extreme Gradient Boosting,这是一种开源的梯度 Boosting 算法,在数据科学竞赛中获得了大量的人气,比如 Kaggle(https://www.kaggle.com/)和 KDD 杯 2015。(如我们在第 1 章、可扩展性第一步中所述,代码可在 https://github.com/dmlc/XGBoost的 GitHub 上获得。)正如作者(陈天奎、佟赫和卡洛斯·盖斯特林)在他们的算法 XGBoost 上写的论文中所报告的那样,在 2015 年在 Kaggle 上举行的 29 场挑战中,17 场获胜的解决方案将 XGBoost 作为独立的或多种模型的某种集成的一部分。在他们的论文 XGBoost:一个可扩展的树促进系统(可以在http://learningsys.org/papers/LearningSys_2015_paper_32.pdf找到)中,作者报告说,在最近的 2015 年 KDD 杯中,XGBoost 被每个进入比赛前十的队伍使用。除了在准确性和计算效率方面的成功表现之外,我们在本书中主要关注的是可伸缩性,从不同的角度来看,XGBoost 确实是一个可伸缩的解决方案。XGBoost 是新一代 GBM 算法,对初始树 boost GBM 算法进行了重要调整。XGBoost 提供并行处理;该算法提供的可伸缩性是由于其作者开发了许多新的调整和添加:
- 一种接受稀疏数据的算法,可以利用稀疏矩阵,节省内存(不需要密集矩阵)和计算时间(零值以特殊方式处理)
- 一种近似树学习(加权分位数草图),具有类似的结果,但比经典的对可能的分支切割的完整探索花费的时间少得多
- 单台机器上的并行计算(在搜索最佳分割的阶段使用多线程)和多台机器上类似的分布式计算
- 利用名为“列块”的数据存储解决方案,在单台机器上进行核外计算,该解决方案按列在磁盘上排列数据,从而按照优化算法(适用于列向量)的预期,通过从磁盘中提取数据来节省时间
从实用的角度来看,XGBoost 的特性大多与 GBM 的参数相同。XGBoost 也很有能力处理丢失的数据。基于标准决策树的其他树集成要求首先使用一个非标度值(例如一个大的负数)来估算缺失数据,以便开发一个适当的树分支来处理缺失值。取而代之的是,XGBoost 首先拟合所有非缺失值,并在为变量创建分支后,决定哪个分支更适合缺失值,以最小化预测误差。这种方法导致树更紧凑,有效的插补策略导致更强的预测能力。
最重要的 XGBoost 参数如下:
eta(默认值=0.3):这相当于 Scikit-learn 的 GBM 中的学习速率min_child_weight(默认值=1):较高的值可防止过拟合和树的复杂性max_depth(默认值=6):这是树中的交互次数subsample(默认值=1):这是我们在每次迭代中获取的训练数据样本的一小部分colsample_bytree(默认值=1):这是每次迭代中特征的分数lambda(默认值=1):这是 L2 正则化(布尔型)seed(默认值=0):这是 Scikit-learn 的random_state参数的等价物,允许跨多个测试和不同机器的学习过程的再现性
现在我们知道了 XGBoost 最重要的参数,让我们在用于 GBM 的相同数据集上运行一个 XGBoost 示例,并使用相同的参数设置(尽可能多)。XGBoost 使用起来没有 Scikit-learn 包简单。因此,我们将提供一些基本示例,您可以将其用作更复杂模型的起点。在我们深入研究 XGBoost 应用之前,让我们将其与垃圾数据集中sklearn中的 GBM 方法进行比较;我们已经将数据加载到内存中:
import xgboost as xgb
import numpy as np
from sklearn.metrics import classification_report
from sklearn import cross_validation
clf = xgb.XGBClassifier(n_estimators=100,max_depth=8,
learning_rate=.1,subsample=.5)
clf1 = GradientBoostingClassifier(n_estimators=100,max_depth=8,
learning_rate=.1,subsample=.5)
%timeit xgm=clf.fit(X_train,y_train)
%timeit gbmf=clf1.fit(X_train,y_train)
y_pred = xgm.predict(X_test)
y_pred2 = gbmf.predict(X_test)
print 'XGBoost results %r' % (classification_report(y_test, y_pred))
print 'gbm results %r' % (classification_report(y_test, y_pred2))
OUTPUT:
1 loop, best of 3: 1.71 s per loop
1 loop, best of 3: 2.91 s per loop
XGBoost results ' precision recall f1-score support\n\n 0 0.95 0.97 0.96 835\n 1 0.95 0.93 0.94 546\n\navg / total 0.95 0.95 0.95 1381\n'
gbm results ' precision recall f1-score support\n\n 0 0.95 0.97 0.96 835\n 1 0.95 0.92 0.93 546\n\navg / total 0.95 0.95 0.95 1381\n
我们可以清楚地看到,尽管我们没有对 xboost 使用并行化,但 xboost 比 GBM 快得多(1.71s 对 2.91s)。后来,当我们应用内存外流时,当我们对 XGBoost 使用并行化和核外方法时,我们甚至可以达到更大的加速。在某些情况下,XGBoost 模型比 GBM 具有更高的精度,但是(几乎)从来没有相反的结果。
XGBoost 回归
增强方法通常用于分类,但对于回归任务也非常有效。由于回归经常被忽略,让我们运行一个回归示例,并遍历关键问题。让我们用 gridsearch 在加州住宅区安装一个助推模型。加州房屋数据集最近被添加到 Scikit-learn 中,这为我们节省了一些预处理步骤:
import numpy as np
import scipy.sparse
import xgboost as xgb
import os
import pandas as pd
from sklearn.cross_validation import train_test_split
import numpy as np
from sklearn.datasets import fetch_california_housing
from sklearn.metrics import mean_squared_error
pd=fetch_california_housing()
#because the y variable is highly skewed we apply the log transformation
y=np.log(pd.target)
X_train, X_test, y_train, y_test = train_test_split(pd.data,
y,
test_size=0.15,
random_state=111)
names = pd.feature_names
print names
import xgboost as xgb
from xgboost.sklearn import XGBClassifier
from sklearn.grid_search import GridSearchCV
clf=xgb.XGBRegressor(gamma=0,objective= "reg:linear",nthread=-1)
clf.fit(X_train,y_train)
y_pred = clf.predict(X_test)
print 'score before gridsearch %r' % mean_squared_error(y_test, y_pred)
params = {
'max_depth':[4,6,8],
'n_estimators':[1000],
'min_child_weight':range(1,3),
'learning_rate':[.1,.01,.001],
'colsample_bytree':[.8,.9,1]
,'gamma':[0,1]}
#with the parameter nthread we specify XGBoost for parallelisation
cvx = xgb.XGBRegressor(objective= "reg:linear",nthread=-1)
clf=GridSearchCV(estimator=cvx,param_grid=params,n_jobs=-1,scoring='mean_absolute_error',verbose=True)
clf.fit(X_train,y_train)
print clf.best_params_
y_pred = clf.predict(X_test)
print 'score after gridsearch %r' %mean_squared_error(y_test, y_pred)
#Your output might look a little different based on your hardware.
OUTPUT
['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup', 'Latitude', 'Longitude']
score before gridsearch 0.07110580252173157
Fitting 3 folds for each of 108 candidates, totalling 324 fits
[Parallel(n_jobs=-1)]: Done 34 tasks | elapsed: 1.9min
[Parallel(n_jobs=-1)]: Done 184 tasks | elapsed: 11.3min
[Parallel(n_jobs=-1)]: Done 324 out of 324 | elapsed: 22.3min finished
{'colsample_bytree': 0.8, 'learning_rate': 0.1, 'min_child_weight': 1, 'n_estimators': 1000, 'max_depth': 8, 'gamma': 0}
score after gridsearch 0.049878294113796254
通过 gridsearch,我们已经能够大大提高我们的分数;你可以看到我们 gridsearch 的最佳参数。你可以在 sklearn 中看到它与常规助推方法的相似之处。但是,默认情况下,XGBoost 会在所有可用内核上并行化该算法。您可以通过将n_estimators参数增加到 2500 或 3000 左右来提高模型的性能。然而,我们发现,对于计算机功能较弱的读者来说,培训时间会有点太长。
XGBoost 和可变重要性
XGBoost 有一些非常实用的内置功能来绘制变量的重要性。首先,相对于手头的模型,有一个方便的特征选择工具。您可能知道,可变重要性是基于树结构中每个特征的相对影响。它为特征选择和洞察预测模型的本质提供了实用的方法。让我们看看如何用 XGBoost 绘制重要性:
import numpy as np
import os
from matplotlib import pylab as plt
# %matplotlib inline <- this only works in jupyter notebook
#our best parameter set
# {'colsample_bytree': 1, 'learning_rate': 0.1, 'min_child_weight': 1, 'n_estimators': 500, #'max_depth': 8, 'gamma': 0}
params={'objective': "reg:linear",
'eval_metric': 'rmse',
'eta': 0.1,
'max_depth':8,
'min_samples_leaf':4,
'subsample':.5,
'gamma':0
}
dm = xgb.DMatrix(X_train, label=y_train,
feature_names=names)
regbgb = xgb.train(params, dm, num_boost_round=100)
np.random.seed(1)
regbgb.get_fscore()
regbgb.feature_names
regbgb.get_fscore()
xgb.plot_importance(regbgb,color='magenta',title='california-housing|variable importance')
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_19.jpg
应谨慎使用要素重要性(对于 GBM 和随机森林也是如此)。特征重要性度量标准完全基于用特定模型的参数训练的特定模型上构建的树结构。这意味着如果我们改变模型的参数,重要性度量和一些排名也会改变。因此,重要的是要注意,对于任何重要性度量,它们都不应该被认为是跨模型的通用变量结论。
xboost 流式处理大型数据集
就准确性/性能权衡而言,这是最好的桌面解决方案。我们看到,在之前的随机森林示例中,我们需要执行二次采样,以防止我们的主内存过载。
XGBoost 的一个经常被忽视的功能是通过内存传输数据的方法。这个方法以分阶段的方式通过主内存解析数据,随后被解析成 XGBoost 模型训练。这种方法是在大数据集上训练模型的先决条件,而大数据集是不可能放入主存的。使用 XGBoost 进行流式处理仅适用于 LIBSVM 文件,这意味着我们首先必须将数据集解析为 LIBSVM 格式,并将其导入为 XGBoost 保留的内存缓存中。另外需要注意的是,我们使用不同的方法来实例化 XGBoost 模型。XGBoost 的类似 Scikit-learn 的接口只适用于常规的 NumPy 对象。让我们看看这是如何工作的。
首先,我们需要加载 LIBSVM 格式的数据集,并将其拆分为训练集和测试集,然后我们继续进行预处理和训练。不幸的是,使用这个 XGBoost 方法无法使用 gridsearch 进行参数调整。如果要调优参数,我们需要将 LIBSVM 文件转换成 Numpy 对象,这样会将数据从内存缓存转储到主内存。不幸的是,这是不可扩展的,因此如果您想要对大型数据集执行调优,我建议使用我们之前介绍的储层采样工具,并对子样本进行调优:
import urllib
from sklearn.datasets import dump_svmlight_file
from sklearn.datasets import load_svmlight_file
trainfile = urllib.URLopener()
trainfile.retrieve("http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass/poker.bz2", "pokertrain.bz2")
X,y = load_svmlight_file('pokertrain.bz2')
dump_svmlight_file(X, y,'pokertrain', zero_based=True,query_id=None, multilabel=False)
testfile = urllib.URLopener()
testfile.retrieve("http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass/poker.t.bz2", "pokertest.bz2")
X,y = load_svmlight_file('pokertest.bz2')
dump_svmlight_file(X, y,'pokertest', zero_based=True,query_id=None, multilabel=False)
del(X,y)
from sklearn.metrics import classification_report
import numpy as np
import xgboost as xgb
dtrain = xgb.DMatrix('/yourpath/pokertrain#dtrain.cache')
dtest = xgb.DMatrix('/yourpath/pokertest#dtestin.cache')
# For parallelisation it is better to instruct "nthread" to match the exact amount of cpu cores you want #to use.
param = {'max_depth':8,'objective':'multi:softmax','nthread':2,'num_class':10,'verbose':True}
num_round=100
watchlist = [(dtest,'eval'), (dtrain,'train')]
bst = xgb.train(param, dtrain, num_round,watchlist)
print bst
OUTPUT:
[89] eval-merror:0.228659 train-merror:0.016913
[90] eval-merror:0.228599 train-merror:0.015954
[91] eval-merror:0.227671 train-merror:0.015354
[92] eval-merror:0.227777 train-merror:0.014914
[93] eval-merror:0.226247 train-merror:0.013355
[94] eval-merror:0.225397 train-merror:0.012155
[95] eval-merror:0.224070 train-merror:0.011875
[96] eval-merror:0.222421 train-merror:0.010676
[97] eval-merror:0.221881 train-merror:0.010116
[98] eval-merror:0.221922 train-merror:0.009676
[99] eval-merror:0.221733 train-merror:0.009316
我们真的可以从内存 XGBoost 中体验到巨大的加速。如果我们使用内存版本,我们将需要更多的训练时间。在本例中,我们已经将测试集作为一轮验证包含在观察列表中。然而,如果我们想预测未知数据的值,我们可以简单地使用与 Scikit-learn 和 XGBoost 中任何其他模型相同的预测程序:
bst.predict(dtest)
OUTPUT:
array([ 0., 0., 1., ..., 0., 0., 1.], dtype=float32)
XGBoost 模型持久性
在前一章中,我们介绍了如何将 GBMmodel 存储到磁盘,以便以后导入并用于预测。XGBoost 提供同样的功能。让我们看看如何存储和导入模型:
import pickle
bst.save_model('xgb.model')
现在,您可以从之前指定的目录中导入保存的模型:
imported_model = xgb.Booster(model_file='xgb.model')
太好了,现在你可以用这个模型来预测:
imported_model.predict(dtest)
OUTPUT array([ 9., 9., 9., ..., 1., 1., 1.], dtype=float32)
带 H2O 的堆外推车
到目前为止,我们只处理 CART 机型的桌面解决方案。在第 4 章、神经网络和深度学习中,我们介绍了 H2O 的深度记忆外学习,它提供了一种强大的可扩展方法。幸运的是,H2O 还利用其强大的并行 Hadoop 生态系统提供了树集成方法。由于我们在前面的章节中已经详细介绍了 GBM 和随机森林,让我们马上开始吧。在本练习中,我们将使用之前使用的垃圾邮件数据集。
H2O 的随机森林和网格研究
让我们用 gridsearch 超参数优化实现一个随机森林。在本节中,我们首先从网址源加载垃圾邮件数据集:
import pandas as pd
import numpy as np
import os
import xlrd
import urllib
import h2o
#set your path here
os.chdir('/yourpath/')
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/spambase/spambase.data'
filename='spamdata.data'
urllib.urlretrieve(url, filename)
现在我们已经加载了数据,我们可以初始化 H2O 会话:
h2o.init(max_mem_size_GB = 2)
OUTPUT:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_20.jpg
这里,我们对数据进行预处理,将数据分为训练集、验证集和测试集。我们用 H2O 函数(.split_frame)来做这件事。还要注意我们将目标向量C58转换为因子变量的重要步骤:
spamdata = h2o.import_file(os.path.realpath("/yourpath/"))
spamdata['C58']=spamdata['C58'].asfactor()
train, valid, test= spamdata.split_frame([0.6,.2], seed=1234)
spam_X = spamdata.col_names[:-1]
spam_Y = spamdata.col_names[-1]
在这一部分,我们将设置我们将使用 gridsearch 优化的参数。首先,我们将模型中棵树的数量设置为单个值 300。使用 gridsearch 迭代的参数如下:
max_depth:树的最大深度balance_classes:每一次迭代都为目标结果使用平衡类sample_rate:这是每次迭代采样的行数的分数
现在,让我们将这些参数传递到 Python 列表中,以便在我们的 H2O 网格搜索模型中使用:
hyper_parameters={'ntrees':[300], 'max_depth':[3,6,10,12,50],'balance_classes':['True','False'],'sample_rate':[.5,.6,.8,.9]}
grid_search = H2OGridSearch(H2ORandomForestEstimator, hyper_params=hyper_parameters)
grid_search.train(x=spam_X, y=spam_Y,training_frame=train)
print 'this is the optimum solution for hyper parameters search %s' % grid_search.show()
OUTPUT:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_21.jpg
在所有可能的组合中,行采样率为. 9、树深度为 50、平衡类的模型产生最高的精度。现在,让我们训练一个新的随机森林模型,该模型具有我们的网格搜索得到的最佳参数,并预测测试集的结果:
final = H2ORandomForestEstimator(ntrees=300, max_depth=50,balance_classes=True,sample_rate=.9)
final.train(x=spam_X, y=spam_Y,training_frame=train)
print final.predict(test)
H2O 预测的最终输出产生一个数组,第一列包含实际预测的类别,第二列包含每个目标标签的类别概率:
OUTPUT:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_22.jpg
H2O 随机梯度推进与网格研究
我们在前面的例子中已经看到,大多数情况下,一个调整良好的 GBM 模型比随机的森林表现更好。所以现在让我们在 H2O 进行一次 T2 网格搜索,看看我们是否能提高 T3 的分数。在本次会议中,我们将介绍与 H2O 随机森林模型相同的随机二次抽样方法。基于 Jerome Friedman 1999 年的文章(https://statweb.stanford.edu/~jhf/ftp/stobst.pdf),介绍了一种名为随机梯度推进的方法。添加到模型中的这种随机性利用了随机二次抽样,而无需在每次树迭代时从数据中进行替换,这被认为是为了防止过度拟合并提高整体精度。在这个例子中,我们通过在每次迭代中引入基于特征的随机子采样,进一步利用了随机性的思想。
这种随机子采样特征的方法也被称为随机子空间方法,我们已经在本章的随机森林和极随机森林部分看到过。我们通过col_sample_rate参数实现这一点。总而言之,在这个 GBM 模型中,我们将对以下参数执行 gridsearch 优化:
max_depth:最大树深sample_rate:每次迭代使用的行数的分数col_sample_rate:每次迭代使用的特征的分数
我们使用与上一节完全相同的垃圾邮件数据集,因此我们可以直接进入该数据集:
hyper_parameters={'ntrees':[300],'max_depth':[12,30,50],'sample_rate':[.5,.7,1],'col_sample_rate':[.9,1],
'learn_rate':[.01,.1,.3],}
grid_search = H2OGridSearch(H2OGradientBoostingEstimator, hyper_params=hyper_parameters)
grid_search.train(x=spam_X, y=spam_Y, training_frame=train)
print 'this is the optimum solution for hyper parameters search %s' % grid_search.show()
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_23.jpg
gbm Grid Build Progress: [##################################################] 100%
gridsearch 输出的上半部分显示,我们应该使用异常高的. 3 学习率、0 . 9 的列采样率和 30 的最大树深度。基于行的随机子采样没有提高性能,但是基于分数为. 9 的特征的子采样在这种情况下非常有效。现在让我们训练一个新的 GBM 模型,其最佳参数来自我们的网格搜索优化,并预测测试集的结果:
spam_gbm2 = H2OGradientBoostingEstimator(
ntrees=300,
learn_rate=0.3,
max_depth=30,
sample_rate=1,
col_sample_rate=0.9,
score_each_iteration=True,
seed=2000000
)
spam_gbm2.train(spam_X, spam_Y, training_frame=train, validation_frame=valid)
confusion_matrix = spam_gbm2.confusion_matrix(metrics="accuracy")
print confusion_matrix
OUTPUT:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/large-scale-ml-py/img/B05135_06_24.jpg
这为模型的性能提供了有趣的诊断,例如accuracy、rmse、logloss和AUC。但是,它的输出太大,这里不包括。查看 IPython 笔记本的输出,了解完整的输出。
您可以通过以下方式利用这一点:
print spam_gbm2.score_history()
当然,最终的预测可以通过以下方式实现:
print spam_gbm2.predict(test)
太好了,我们已经能够将模型的准确性提高到接近 100%。如您所见,在 H2O,您在建模和管理数据方面可能不太灵活,但是的处理速度和的准确性是无与伦比的。要结束此会话,您可以执行以下操作:
h2o.shutdown(prompt=False)
总结
我们看到,使用集成例程训练的 CART 方法在预测准确性方面非常强大。然而,它们在计算上可能很昂贵,我们已经在 sklearn 的应用中介绍了一些加速它们的技术。我们注意到,如果使用得当,使用随机搜索调整的极端随机森林可以加快 10 倍的速度。然而,对于 GBM 来说,sklearn 中没有实现并行化,而这正是 XGBoost 的用武之地。
XGBoost 附带了一个有效的并行增强算法,可以很好地加速算法。当我们使用更大的文件(> 100k 个训练示例)时,有一种核心外的方法可以确保我们在训练模型时不会过载主内存。
速度和记忆力最大的进步可以从 H2O 身上找到;我们看到了强大的调优能力以及令人印象深刻的训练速度。

被折叠的 条评论
为什么被折叠?



