1 如何用Keras开发深度学习模型

使用KerasPython中创建和评估深度学习神经网络非常容易,但您必须遵循严格的模型生命周期。在本章中,您将了解在Keras中创建、训练和评估深度学习神经网络的过程,以及如何使用训练好的模型进行预测。您还将了解如何使用函数式API,在设计模型时提供更大的灵活性。阅读本章后,您将了解:

如何在Keras中定义,编译,拟合和评估深度学习神经网络。

如何为回归和分类预测建模问题选择标准默认值。

如何使用函数式API开发标准的多层感知器,卷积和递归神经网络。让我们开始吧。

注意:假设您对深度学习和Keras有基本的了解,本章应该为Keras API提供一个复习,并且可能是对Keras函数式API的介绍。有关安装说明,请参阅附录。本教程中的大多数代码片段仅供参考,并非完整示例。

1.1 Keras模型生命周期

以下是Keras神经网络模型生命周期中5个步骤的概述:

  1. 定义网络。
  2. 编译网络。
  3. 训练网络。
  4. 评估网络。
  5. 作出预测。

1.1Keras中神经网络模型的5步寿命周期。

让我们依次使用易于使用的Keras Sequential API来查看每个步骤。

1.1.1 步骤1. 定义网络

第一步是定义神经网络。神经网络在Keras中被定义为层序列。这些图层的容器是Sequential类。第一步是创建Sequential类的实例。然后,您可以创建图层并按照它们应连接的顺序添加它们。例如,我们可以分两步完成:

model = Sequential()
model.add(Dense(2))

 

清单1.1:具有一个具有2个神经元的Dense层的顺序模型。

但是我们也可以通过创建一个图层数组并将其传递给Sequential类的构造函数来一步完成。

 

layers = [Dense(2)]

model = Sequential(layers)

清单1.2:定义为数组的Sequential模型的层。

网络中的第一层必须定义预期的输入数量。指定它的方式可能因网络类型而异,但对于 Multilayer Perceptron模型,这由输入dim属性指定。例如,一个小的多层感知器模型,在可见层中有2个输入,隐藏层中有5个神经元,输出层中有一个神经元,可以定义为:

model = Sequential()

model.add(Dense(5, input_dim=2))

model.add(Dense(1))

代码清单1.3:带有2个输入的顺序模型

Sequential模型视为管道,将原始数据输入底部,并将预测输出到顶部。这在Keras中是一个有用的概念,因为传统上与层相关的问题也可以拆分并作为单独的层添加,清楚地显示它们在从输入到预测的数据转换中的作用。例如,可以提取转换来自层中每个神经元的求和信号的激活函数,并将其作为称为激活类的层状对象添加到Sequential中。

model = Sequential()

model.add(Dense(5, input_dim=2))

model.add(Activation('relu'))

model.add(Dense(1))

model.add(Activation('sigmoid'))

清单1.4:具有与层分开定义的激活函数的顺序模型。

激活函数的选择对于输出层是最重要的,因为它将定义预测将采用的格式,例如:下面是一些常见的预测建模问题类型,以及可以在输出层中使用的结构和标准激活函数:

回归:线性激活函数,或线性,以及与输出数量匹配的神经元数量。

二分类(2类):逻辑激活函数,或sigmoid,以及输出层的一个神经元。

多类分类(> 2类):一个one-hot编码输出模式,Softmax激活函数或softmax,每个类值一个输出神经元。

1.1.2 步骤2. 编译网络

一旦我们定义了网络,我们就必须编译它,编译是一个提高效率的步骤,它将我们定义的简单图层序列转换为高效的矩阵变换系列,其格式应在可以在GPUCPU上执行,具体取决于Keras的配置方式。可以将编译视为网络的预计算步骤,定义模型后必须进行编译。

编译需要指定许多参数,用于训练您的网络,具体地,用于训练网络的优化算法和用于评估由优化算法最小化的网络的损失函数。例如,下面是编译定义模型并指定随机梯度下降(sgd)优化算法和均值误差(均方误差)损失函数,用于回归类型问题。

model.compile(optimizer='sgd', loss='mean_squared_error')

代码清单1.5:编译已定义模型的示例

或者,可以在编译步之前创建和配置优化算法类型

algorithm = SGD(lr=0.1, momentum=0.3)

model.compile(optimizer=algorithm, loss='mean_squared_error')

代码清单1.6:单独定义优化算法的示例

对预测问题来说,类型不一样,可以使用的损失函数也会有不同。例如,下面是不同问题对应常用的一些标准损失函数:

回归:均方误差或mean_squared_error

2(2):对数损失,也称为交叉熵或binary_crossentropy

多分类(> 2类):多类对数损失或categorical_crossentropy

最常见的优化算法是随机梯度下降,但Keras还支持一套其他更好的优化算法,这些算法在很少或没有配置的情况下都能很好地工作。我们最常用的优化算法如下,主要是因为它们通常具有更好的性能:

随机梯度下降,或sgd,需要调整学习率和动量。

Adam,需要调整学习率。

RMSproprmsprop,需要调整学习速率。

最后,除了损失函数之外,您还可以在拟合模型时收集的度量标准,通常,要收集的最有用的附加度量标准是分类问题的准确性,使用数组的方式指定要收集的度量指标。例如:

 

model.compile(optimizer='sgd', loss='mean_squared_error', metrics=['accuracy'])

代码清单1.7:编译模型时定义指标的示例

1.1.3 步骤3. 训练网络

一旦网络结构编译完成,就可以训练了,这意味着在训练数据集上调整模型权重,训练网络需要指定训练数据,包括输入矩阵X和匹配输出数组y。使用反向传播算法训练网络,并根据编译模型时指定的优化算法和损失函数进行优化。

反向传播算法要求网络在指定的训练数据集上训练指定数量的epoch。每个epoch可以被划分为称为批次batches的输入-输出模式对的组,这定义了在一个epoch内更新权重之前网络所接触的训练数据的模式这是从效率优化考虑的,确保一次不会将太多输入模式加载到内存中。拟合网络的最小例子如下:

history = model.fit(X, y, batch_size=10, epochs=100)

代码清单1.8:拟合已编译模型的示例

拟合后,将返回历史对象,该对象提供训练期间模型性能的摘要,包括损失和编译模型时指定的所有指标,记录每个epoch的指定的性能指标。训练可能需要很长时间,从几秒到几小时到几天,具体取决于网络的大小和训练数据的大小。

默认情况下,每个epoch命令行上都会显示一个进度条,这可能会给您带来太多噪音,或者可能会对您的环境造成问题,例如您使用的是交互式笔记本电脑或IDE,通过将详细参数设置为2,可以减少每个epoch显示的信息量,您可以通过将详细设置为0来关闭所有输出。例如:

 

history = model.fit(X, y, batch_size=10, epochs=100, verbose=0)

代码清单1.9:在拟合模型时关闭详细输出的示例

1.1.4 步骤4. 评估网络

一旦网络训练完成,就可以对其进行评估。可以在训练数据上评估网络,最好不要这么做,因为我们是在训练集上训练的模型,现在如果我们用同样的数据评估我们网络,显然最后得到的评价会很不准确。我们可以训练期间没有用到的数据集评估网络的性能。这样才能真实的反应我们训练的这个网络结构的真实情况。

该模型评估所有测试模式的损失,以及编译模型时指定的所有其他指标,如分类准确性。返回评估指标列表。例如,对于使用精度度量编译的模型,我们可以在新数据集上对其进行评估,如下所示:

 

loss, accuracy = model.evaluate(X, y)

代码清单1.10:评估拟合模型的示例

与拟合网络一样,提供详细输出以了解评估模型的进度。我们可以通过将verbose参数设置为0来关闭它。

loss, accuracy = model.evaluate(X, y, verbose=0)

代码清单1.11:评估拟合模型时关闭详细输出的示例

1.1.5 步骤5. 做出预测

一旦我们对训练模型的性能感到满意,我们就可以用它来预测新数据,这个很简单,调用模型的predict()函数处理新数据即可。例如:

 

predictions = model.predict(X)

代码清单1.12:使用拟合模型进行预测的示例

预测输出的形式由网络输出层格式决定。在回归问题,输出形式可以直接的以问题格式一致的方式输出一般由线性激活函数来完成。对于二元分类问题,预测以其中一个类别的概率形式出现然后通过激活层根据指定的舍方法转换为10

对于多类分类问题,结果可以是概率数组的形式(假设一个one-hot出变量),可能需要使用NumPyargmax()函数将其转换为单个类输出预测。或者,对于分类问题,我们可以使用predict_classes()函数,它会自动将预测转换为清晰的对应的类别的值

predictions = model.predict_classes(X)

与拟合和评估网络一样,提供详细输出以了解模型制作预测的进度,我们可以通过将verbose参数设置为0来关闭它。

predictions = model.predict(X, verbose=0)

代码清单1.14:进行预测时禁用详细输出的示例

1.2 Keras 函数式模

顺序API允许您逐层创建模型以解决大多数问题。它的局限性在于它不允许您创建共享图层或具有多个输入或输出的模型。Keras中的函数式API是创建模型的另一种方式,可提供更大的灵活性,包括创建更复杂的模型。

它特别允许您定义多个输入或输出模型以及共享图层的模型。更重要的是,它允许您定义ad hoc非循环网络图。通过创建图层实例并将它们成对地直接相互连接来定义模型,然后定义一个模型,该模型指定用作模型输入和输出的图层。让我们依次看看Keras函数式API的三个独特方面:

1.2.1 定义输入

Sequential模型不同,您必须创建并定义一个指定输入数据形状的独立输入层,输入层采用shape(参数,),该参数是指示输入数据元组的维度。当输入数据是一维的时,例如对于多层感知器,形状必须明确留出空间,以便在训练网络,分割数据时使用mini-batch。因此,shape元组总是最后一个维度开放的形式定义的,比如一维以这个形式定义(2,)

from keras.layers import Input
visible = Input(shape=(2,))

代码清单1.15:定义功能模型输入的示例

 

1.2.2 连接图层

模型中的图层成对连接,这是通过在定义每个新图层时指定输入的来源来完成的,使用括号或功能符号,使得在创建层之后,指定从其输入当前层的层。让我们用一个简短的例子来说明这一点。我们可以像上面那样创建输入层,然后创建一个隐藏层作为Dense,它只接收来自输入层的输入。

from keras.layers import Input
from keras.layers import Dense
visible = Input(shape=(2,))
hidden = Dense(2)(visible)

代码清单1.16:将隐藏层连接到可见层的示例

请注意,在创建Dense图层后,它是可见的,它将输入图层的输出连接为Dense隐藏图层的输入。正是这种逐层连接层的方式为函数式API提供了巨大地灵活性。例如,您可以看到开始定义图层的特殊图形是多么容易。

1.2.3 创建模型

创建所有模型图层并将它们连接在一起后,必须定义模型。与Sequential API一样,模型是您可以汇总拟合评估和用于进行预测的模型。Keras提供了一个Model类,您可以使用它从创建的图层创建模型。它要求您只指定输入和输出图层。例如:

 

from keras.models import Model
from keras.layers import Input
from keras.layers import Dense
visible = Input(shape=(2,))
hidden = Dense(2)(visible)
model = Model(inputs=visible, outputs=hidden)

代码清单1.17:使用函数式API创建完整模型的示例

现在我们已经了解了Keras函数式API的所有关键部分,让我们通过定义一套不同的模型并使用它来构建一些实践。每个示例都是可执行的,并以图的形式来打印网络结构。我建议您为自己的模型执行这个操作,以清晰的显示您定义的网络结构。我希望这些示例可以给您将来使用函数式API定义自己的模型时,带来一定的启示

1.3 标准网络模型

在开始使用函数式API时,最好先了解一些标准神经网络模型的定义。在本节中,我们将介绍如何定义一个简单的多层感知器卷积神经网络和递归神经网络。这些示例将为以后更详细的示例提供基础。

1.3.1 多层感知器

在本节中,我们定义了用于二分类的多层感知器模型。该模型有10个输入,3个隐藏层,10,2010个神经元,以及1个输出的输出层。在每个隐藏层中使用校正的线性激活函数,并且在输出层中使用S形激活函数,用于二进制分类。

 

# Multilayer Perceptron
from keras.utils import plot_model
from keras.models import Model
from keras.layers import Input
from keras.layers import Dense
visible = Input(shape=(10,))
hidden1 = Dense(10, activation='relu')(visible)
hidden2 = Dense(20, activation='relu')(hidden1)
hidden3 = Dense(10, activation='relu')(hidden2)
output = Dense(1, activation='sigmoid')(hidden3)
model = Model(inputs=visible, outputs=output)
#summarize layers model.summary()
#plot graph
plot_model(model, to_file='multilayer_perceptron_graph.png')

代码清单1.18:使用函数式API定义MLP的示例运行该示例将打印的网络结构

_________________________________________________________________

Layer (type)                 Output Shape              Param #   

=================================================================

input_2 (InputLayer)         (None, 10)                0         

_________________________________________________________________

dense_5 (Dense)              (None, 10)                110       

_________________________________________________________________

dense_6 (Dense)              (None, 20)                220       

_________________________________________________________________

dense_7 (Dense)              (None, 10)                210       

_________________________________________________________________

dense_8 (Dense)              (None, 1)                 11        

=================================================================

Total params: 551

Trainable params: 551

Non-trainable params: 0

_________________________________________________________________

代码清单1.19:使用函数式API定义的MLP模型的摘要还会创建模型图的

图并将其保存到文件中。

1.2MLP模型图的图。

注意,创建Keras模型的图需要安装pydotpygraphvizgraphviz库和python包装库)。安装这些库的说明因系统而异。如果这对您来说是一个挑战(例如,您在Windows上),请考虑注释掉plot_model()的调用。

1.3.2 卷积神经网络

在本节中,我们将定义用于图像分类的卷积神经网络,该模型接收黑白64 x 64图像作为输入,然后具有两个卷积和池层的序列作为特征提取器,接着是完全连接的层来解释特征,输出层具有S形激活用于两类预测。

 

# Convolutional Neural Network
from keras.utils import plot_model
from keras.models import Model
from keras.layers import Input
from keras.layers import Dense
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPooling2D
visible = Input(shape=(64,64,1))

conv1 = Conv2D(32, kernel_size=4, activation='relu')(visible)
pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)

conv2 = Conv2D(16, kernel_size=4, activation='relu')(pool1)
pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)

hidden1 = Dense(10, activation='relu')(pool2)
output = Dense(1, activation='sigmoid')(hidden1)
model = Model(inputs=visible, outputs=output)

# summarize layers
model.summary()

# plot graph
plot_model(model, to_file='convolutional_neural_network.png')

代码清单1.20:使用函数式API定义CNN的示例运行该示例的网络结构

_________________________________________________________________

Layer (type)                 Output Shape              Param #   

=================================================================

input_3 (InputLayer)         (None, 64, 64, 1)         0         

_________________________________________________________________

conv2d_1 (Conv2D)            (None, 61, 61, 32)        544       

_________________________________________________________________

max_pooling2d_1 (MaxPooling2 (None, 30, 30, 32)        0         

_________________________________________________________________

conv2d_2 (Conv2D)            (None, 27, 27, 16)        8208      

_________________________________________________________________

max_pooling2d_2 (MaxPooling2 (None, 13, 13, 16)        0         

_________________________________________________________________

dense_9 (Dense)              (None, 13, 13, 10)        170       

_________________________________________________________________

dense_10 (Dense)             (None, 13, 13, 1)         11        

=================================================================

Total params: 8,933

Trainable params: 8,933

Non-trainable params: 0

_________________________________________________________________

 

代码清单1.21:使用函数式API定义的CNN模型图

并将其保存到文件中。

1.3CNN模型图。

1.3.3 递归神经网络

在本节中,我们将定义一个用于序列分类的长期短期记忆递归神经网络,该模型需要100个时间步长作为输入,该模型具有单个LSTM隐藏层以从序列中提取特征,接着是完全连接的层以解释LSTM输出,接着是用于进行二元预测的输出层。

 

# Recurrent Neural Network
from keras.utils import plot_model
from keras.models import Model
from keras.layers import Input
from keras.layers import Dense
from keras.layers.recurrent import LSTM
visible = Input(shape=(100,1))
hidden1 = LSTM(10)(visible)
hidden2 = Dense(10, activation='relu')(hidden1)
output = Dense(1, activation='sigmoid')(hidden2)
model = Model(inputs=visible, outputs=output)
model.summary()
# plot graph
plot_model(model, to_file='recurrent_neural_network.png')

代码清单1.22:使用函数式API定义RNN的示例运行该示例总结了模

_________________________________________________________________

Layer (type)                 Output Shape              Param #   

=================================================================

input_4 (InputLayer)         (None, 100, 1)            0         

_________________________________________________________________

lstm_1 (LSTM)                (None, 10)                480       

_________________________________________________________________

dense_11 (Dense)             (None, 10)                110       

_________________________________________________________________

dense_12 (Dense)             (None, 1)                 11        

=================================================================

Total params: 601

Trainable params: 601

Non-trainable params: 0

_________________________________________________________________

代码清单1.23:使用函数式API定义的RNN模型创建模型图

并将其保存到文件中。

1.4RNN模型图的图。


0 条 查看最新 评论

没有评论
暂时无法发表评论