深度学习与Keras实践|第二期:(入门)函数式API——另一种灵活的编程模型

1. 简单回顾:

在上一期,我们通过创建一个简单的线性神经网络模型展示了如何使用Keras搭建自己的神经网络。让我们通过代码简单的回顾一下:

from keras.models import Sequential
model = Sequential()

from keras.layers import Dense
model.add(Dense(units=4,activation='relu',input_dim=100))
model.add(Dense(units=5,activation='softmax'))

通过这几行简单的代码,我们创建了一个两层的神经网络,其结构为

输入层 - Dense 4,relu,100
输出层 - Dense 5,softmax

在这个模型中,仅有的两个层被线性的串联在了一起,非常简单直观。


2. 我们为什么需要函数式API?

在了解了上一期我们介绍的线性编程方式之后,我们可能会思考如何实现一些复杂的、不是简单串联关系的模型。比如说,当我们想实现具有下面这个结构的神经网络模型时,线性编程方式就有了局限性:

main_input
embedding_1
lstm_1
merge_1
aux_input
dense_1
dense_2
dense_3
main_output
aux_output

因为存在分支,所以实际上无法通过线性模型搭建这样的神经网络。这时,Keras为我们提供了另一种灵活的编程模型——函数式API


3. 使用函数式API编程方式重写第一个例子:

为了实现分支,我们可以考虑将上一个层(的结果)作为参数传入下一个层,通过这种指定参数的做法,我们就可以实现将一个层作为多个其它层的下一层,或者多个其他层使用同一个层作为上一层

我们先来通过重写上一期的简单线性示例来初步了解一下函数式API。

from keras.layers import Input,Dense
from keras.models import Model
  • 导入需要的类之后我们首先创建一个输入层,输入样本的维度是100,输出是一个张量:
inputs = Input(shape=(100,))
  • 接下来我们通过调用上一个实例化的层来进行层与层的连接:
x = Dense(4,activation='relu')(inputs)
predictions = Dense(5,activation='softmax')(x)
  • 在创建了包含输入层和两个全连接层(其中一个为输出层)之后,我们需要在最后实例化一个Model类并将输入与输出传入:
model = Model(inputs=inputs,outputs=predictions)
  • 之后我们只需要对其进行编译和训练即可,这一部分的代码请参阅上一期的例子。

这就是使用函数式API编写的线性模型示例。在函数式API中我们需要注意的是,输入层是单独定义的,而不是像线性模型中那样作为第一个全连接层的参数来定义,这也为我们定义多个输入层提供了更直观的方法。同时,如果我们的输出层有多个的话,我们可以使用列表将它们一起传入最后的Model类的实例中。


4. 使用函数式API实现复杂的例子:

下面,为了更好的理解函数式API的编程方式,我们将实现上面提到的那个复杂的、带有两个输入与两个输出的例子,我们在这里再把它的结构展示出来:

main_input
embedding_1
lstm_1
merge_1
aux_input
dense_1
dense_2
dense_3
main_output
aux_output

除了我们已经熟悉的全连接层(这里有三个)之外,我们还将使用一个辅助输入与一个辅助输出,和一个长短期记忆网络(LSTM)以及一个嵌入层(embedding)。具体代码如下:

from keras.layers import Input,Embedding,LSTM,Dense
from keras.models import Model
  • 定义一个输入层作为主输入层并传递一个name参数对其命名:
main_input = Input(shape=(100,),dtype='int32',name='main_input')
  • 下面我们创建一个embedding层。我们不需要理解它的作用(我们的目的是理解函数式API这种编程方式),但也可以简单的认为它是用来降维的或者用来将输入重新编码的:
x = Embedding(output_dim=512,input_dim=10000,input_length=100)(main_input)
  • 之后我们再像结构图中所展示的那样,增加一个LSTM层(我们仍需要记住我们的目的是了解函数式API):
lstm_out = LSTM(32)(x)
  • 之后,我们创建辅助输入与辅助输出层并将它们连接到网络中:
aux_input = Input(shape=(5,),name='aux_input')
x = keras.layers.concatenate([lstm_out,aux_input])
aux_output = Dense(1,activation='sigmoid',name='aux_uotput')(lstm_out)
  • 之后,我们只需堆叠结构图下面的三个全连接层并创建一个主输出层,然后进行Model类的实例化并以列表的形式传入所有输入与输出。
x = Dense(64,activation='relu')(x)
x = Dense(64,activation='relu')(x)
x = Dense(64,activation='relu')(x)

main_output = Dense(1,activation='sigmoid',name='main_output')(x)

model = Model(inputs=[main_input,aux_input],outputs=[main_output,aux_output])
  • 我们已经将结构图所展示的神经网络模型创建完成了。之后我们需要进行编译和训练。需要注意的是,由于有两个输出,所以在编译时我们需要指定权重,同时,由于有两个输入,我们在训练时需要传入两组数据。代码如下:
model.compile(optimizer='rmsprop',\
		loss='binary_crossentropy',\
		loss_weights=[1.,0.2])
model.fit([headline_data,additional_data],\
			[labels,labels],\
			epochs=50,\
			batch_size=32)

这样,我们就使用函数式API实现了一个较复杂的非线性神经网络结构图了。我们可以清楚的看到函数式API编程方式相对于上一期中的线性编程方式所具有的优势。


5. 下一步:

到这里,我们大致了解了神经网络的结构以及如何使用Keras提供的两种编程方式:线性模型和函数式API实现简单的神经网络模型。

在后续的几期内容中,我们将对第一、二期中出现的一些概念进行介绍,具体包括

  1. 常用的神经网络层;
  2. 几种激活函数;
  3. 两类优化器;
  4. 几种损失函数;

这些内容进行完后,我们对神经网络的理解会进一步加深。


发布了16 篇原创文章 · 获赞 0 · 访问量 666

猜你喜欢

转载自blog.csdn.net/weixin_43628432/article/details/103810401
今日推荐