2.2 Keras
现在已经了解如何从头开始在Python中实现感知器,并且理解了概念,那么我们可以使用一个库,避免重复实现这些算法。幸运的是,有许多库使我们可以专注于网络的架构和组成,而不必在太多的实现问题上浪费时间。
最近十年,显卡取得主要突破,其使用使深度学习发展如此迅速。尤其是NVIDIA创建的CUDA,这是一个编程接口,使得在常规编程中发挥现代图形处理单元(GPU)的全部功用成为可能。GPU是主要用于渲染图像的硬件。与CPU相比,GPU内核数更多,但是这些内核只能执行简单的操作。它们是矩阵乘法的理想选择,这就是为什么与CPU相比,GPU能够缩短计算时间,其速度甚至能达到CPU的100倍。
TensorFlow是一个使用CUDA与GPU进行交互的库,但它也可以在常规CPU上运行。因此无须GPU也可运行本书中的示例。
我们将在TensorFlow之上使用Keras,因为TensorFlow提供高级的Pythonic API,允许我们快速构建复杂的架构。
在Keras中实现感知器
本节将介绍一些简单的概念,看看如何在Keras中实现感知器。
Keras的主要目的是Sequential使模型创建更加Pythonic且更以模型为中心。
有两种方法创建模型:使用Sequential类或Model类。创建Keras模型最简单的方法是使用Sequential API。使用该类有一些限制。例如,定义具有多个不同输入或输出源的模型并不简单,但它可以满足我们目前的需求。
我们可以从初始化Sequential类开始:
然后,需要添加输入层并指定维度和其他一些参数。在这个例子中,我们将添加一个Dense(密集)层,这意味着所有神经元与下一层的全部神经元都相互连接。
此Dense层是完全连接的,这意味着所有神经元与下一层的神经元都有一个连接。它执行输入和权重集(也称为内核)之间的乘法运算,当然,如果已指定,则添加偏置项。然后,结果将通过激活函数。
要完成初始化,需要指定神经元的数量(1)、输入维度(2,因为我们有两个变量)、激活函数(sigmoid)和初始权重值(zero)。要将层添加到模型,可以使用add()方法,如下所示:
现在,我们需要编译这个模型。在此阶段,我们将简单定义损失函数以及探索梯度的方式,也就是优化器。Keras不支持我们之前使用的阶跃函数,因为该函数是不可微的,所以不能在反向传播中使用。如果要使用它,则需使用keras.backend来自定义函数。在本例中,我们还必须自己定义导数,大家可以自行练习此部分。
为了简单起见,我们将使用MSE。另外,我们将使用随机梯度下降(Stochastic Gradient Descent,SGD)作为梯度下降策略,这是一种优化可微函数的迭代方法。在定义SGD时,可以指定学习率,我们将其设置为0.01:
然后,我们只需要使用fit方法来训练网络。在此阶段,我们需要提供训练数据及其标签。
我们还可以提供所需的epoch数。一个epoch包括整个数据集前向和反向通过网络。在这个简单示例中,一个epoch就足够了,但是更复杂的神经网络则需要更多的epoch。
我们还指定了批量大小(batch size),这是在训练集中用于一次梯度迭代的部分。为了减少梯度处理的噪声,通常在更新权重之前先对数据进行批处理。批量大小取决于所需的内存量,通常来说,会在32~512个数据点之间。批量大小会带来很多影响,通常来说,较大的批次大小往往会模型收敛到局部最小值,并失去在训练集之外的泛化能力。为了避免停留在局部最小值,我们还希望对数据进行洗牌(shuffle)。在这种情况下,每次迭代都会更改批次,从而避免停留在局部最小值:
然后,我们计算AUC值,如下所示:
在训练模型时,我们将在屏幕上看到一些信息。Keras展示了模型的进度,并在运行时为每个epoch提供了ETA。它还显示了有关损失的指标,我们可以用它来查看模型是否确实在改善其性能: