Keras函数式API,如多输入,多输出,类图模型等

一:引言

现阶段许多模型,如多输入模型,多输出模型,类图模型等等,当我们在调用Keras中的Sequential模型类是无法实现的,因此本文介绍函数式API(functional API)。

二:简介

使用函数式API可以直接操作张量,也可以把层当做函数来使用,接收张量并返回张量。

from keras import Input,layers
input_tensor=Input(shape=(32,))#一个张量
dense=layers.Dense(32,activation='relu') #一个层是一个函数
output_tensor=dense(input_tensor )#他可以在一个张量上调用一个层,返回一个张量

编写一个最简单的示例,展示两种方法:

from keras.models import Sequential,Model
from keras import layers
from keras import Input

seq_model=Sequential()
seq_model.add(layers.Dense(32,activation='relu',input_shape=(64,)))
seq_model.add(layers.Dense(32,activation='relu'))
seq_model.add(layers.Dense(10,activation='softmax'))

#函数式API
input_tensor=Input(shape=(64,))
x=layers.Dense(32,activation='relu')(input_tensor)
x=layers.Dense(32,activation='relu')(x)
output_tensor=layers.Dense(10,activation='softmax')(x)

model=Model(input_tensor,output_tensor)#model类将输入张量和输出张量转换为一个模型
model.summary()

 将Model对象实例化只用了一个输入张量和输出张量。Keras会在后台检索从input_tensor到output_tensor所包含的每一层,并将这些层组合成一个类图的数据结构,即一个Model。当然,这种方法有效的原因在于output_tensor是通过对input_tensor进行多次变换得到的。如果利用不相关的输入和输出来构建一个模型,那么会报错。

三:多输入模型

通常情况下,这种模式会在某一时刻用一个可以组合多个张量的层将不同的输入分支合并,张量组合方式可能是相加、连接等。这通常利用Keras的合并运算来实现,比如keras.layers.add,keras.layers.concatenate等。我们来看一个非常简单的多输入模型实例,一个问答模型。

典型的问答模型有两个输入:一个自然语言描述的问题和一个文本片段(比如新闻文章),后者提供用于回答问题的信息。然后模型要生成一个回答,在最简单的情况下,这个回答只包含一个词,可以通过对某个预定义的词表做softmax得到。下面这个示例展示了如何用函数式API构建这样的模型。设置了两个独立分支,首先将文本输入和问题输入分别编码为表示向量,然后连接这些向量,最后,在连接好的表示上添加一个softmax分类器。

#多输入模型
from keras.models import Model
from keras import layers
from keras import Input

text_vocabulary_size=10000
question_vocabulary_size=10000
answer_vocabulary_size=500

text_input=Input(shape=(None,),dtype='int32',name='text')#文本输入是一个长度可变的整数序列。注意,你可以选择对输入进行命名

embedded_text=layers.Embedding(text_vocabulary_size,64)(text_input)#将输入嵌入长度为64的向量
encoded_text=layers.LSTM(32)(embedded_text)#利用LSTM将向量编码为单个向量
question_input=Input(shape=(None,),dtype='int32',name='question')#对问题进行相同的处理
embedded_question=layers.Embedding(question_vocabulary_size,32)(question_input)
encoded_question=layers.LSTM(16)(embedded_question)
concatenated=layers.concatenate([encoded_text,encoded_question],axis=-1)#将编码后的问题和文本联系起来
answer=layers.Dense(answer_vocabulary_size,activation='softmax')(concatenated)#在上面添加一个softmax分类器

model=Model([text_input,question_input],answer)#在模型实例化时,指定两个输入和输出
model.compile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['acc'])

如何训练?有两个可用的 API:我们可以向模型输入一个由Numpy数组组成的列表,或者也可以输入一个将输入名称映射为Numpy数组的字典。当然,只有输入具有名称时才能使用后一种方法。

输入数据查看结果:

import numpy as np
import keras
from keras.utils import to_categorical
num_samples=1000
max_length=100
text=np.random.randint(1,text_vocabulary_size,size=(num_samples,max_length))#生成虚构的Numpy数据
#这段代码利用NumPy库生成一个随机数组,这个数组的大小是(num_samples,max_length),其中num_samples表示生成的样本数量,max_length则表示每个样本的长度。这个数组中的每个元素的取值是在1到text_vocabulary_size之间的随机数,text_vocabulary_size表示文本的词汇表大小。
question=np.random.randint(1,question_vocabulary_size,size=(num_samples,max_length))
answer=np.random.randint(answer_vocabulary_size,size=(num_samples))
answer = keras.utils.to_categorical(answer,answer_vocabulary_size)#回答是onehot编码
model.fit([text,question],answer,epochs=10,batch_size=128)#使用输入组成的列表来拟合
model.fit({'text':text,'question':question},answer,epochs=10,batch_size=128)#使用输入组成的字典来拟合

三:多输出模型

利用相同的方法,可以使用函数式API来构建多个输出的模型。一个简单的例子就是一个网络试图同时预测数据的不同性质,比如一个网络,输入某个匿名人士的一系列社交媒体发帖,然后尝试预测那个人的属性,比如年龄、性别和收入水平,是一个三输出的模型。

#多输出模型
from keras import layers
from keras import Input
from keras.models import Model

vocabulary_size=50000
num_income_groups=10
posts_input=Input(shape=(None,),dtype='int32',name='posts')
embedded_posts=layers.Embedding(256,vocabulary_size)(posts_input)
x=layers.Conv1D(128,5,activation='relu')(embedded_posts)
x=layers.MaxPool1D(5)(x)
x=layers.Conv1D(256,5,activation='relu')(x)
x=layers.Conv1D(256,5,activation='relu')(x)
x=layers.MaxPool1D(5)(x)
x=layers.Conv1D(256,5,activation='relu')(x)
x=layers.Conv1D(256,5,activation='relu')(x)
x=layers.GlobalMaxPool1D()(x)
x=layers.Dense(128,activation='relu')(x)

age_prediction=layers.Dense(1,name='age')(x)
income_prediction=layers.Dense(num_income_groups,activation='softmax',name='income')(x)
gender_prediction=layers.Dense(1,activation='sigmoid',name='gender')(x)

model=Model(posts_input,[age_prediction,income_prediction,gender_prediction])

训练这种模型需要能够对网络的各个头指定不同的损失函数,例如,年龄预测是标量回归任务,而性别预测是二分类,二者需要不同的训练过程。但是,梯度下降要求将一个标量最小化,所以为了能训练模型,我们必须将这些损失合并为单个标量。合并不同损失最简单的方法就是对所有损失求和。在Keras中,你可以在编译时使用损失组成的列表或字典来为不同输出指定不同损失,然后将得到的损失值相加得到一个全局损失,并在训练过程中将其最小化。

model.compile(optimizer='rmsprop',loss=['mse','categorical_crossentropy','binary_crossentropy'])
#model.compile(optimizer='rmsprop',loss={'age':'mse','income':'categorical_crossentropy','gender':'binary_crossentropy'})#与上述等价

严重不平衡的损失贡献会导致模型表示针对单个损失值最大的任务优先进行优化,而不考虑其他任务的优化。为了解决这个问题,我们可以为每个损失值对最终损失的贡献分配不同大小的重要性。如果不同的损失值具有不同的取值范围,那么这一方法尤其有用。比如,用于年龄回归任务的均方误差损失值通常在3-5左右,而用于性别分类任务的交叉熵损失值可能低至0.1。为了平衡不同损失的贡献,可以让交叉熵损失的权重取10,而MSE损失的权重取0.5。

四:层组成的有向无环图

 1.Inception模块

Inception是一种流行的卷积神经网络的架构类型,是模块的堆叠,这些模块本身看起来像小型的独立网格,被分为多个并行分支。Inception模块最基本的形式包含3-4个分支,首先是1*1的卷积,然后是一个3*3的卷积,最后将所得到的特征连接在一起。这种设置有助于网络分别学习空间特征和逐通道的特征,比联合学习这两种特征更加有效。Inception也可能具有更复杂的形式,通常会包含池化运算、不同尺寸的空间卷积和不包含空间卷积的分支等。

from  keras import layers
#这个例子假设我们有一个四维输入张量
branch_a=layers.Conv2D(128,1,activation='relu',strides=2)(x)
branch_b=layers.Conv2D(128,1,activation='relu')(x)
branch_b=layers.Conv2D(128,3,activation='relu',strides=2)(branch_b)
branch_c=layers.AveragePooling2D(3,strides=2)(x)
branch_c=layers.Conv2D(128,3,activation='relu')(branch_c)
branch_d=layers.Conv2D(128,1,activation='relu')(x)
branch_d=layers.Conv2D(128,3,activation='relu')(branch_d)
branch_d=layers.Conv2D(128,3,activation='relu',strides=2)(branch_d)

完整的Inception V3架构内置于Keras中,,其中包括在ImageNet数据集上预训练得到的权重。与其密切相关的另一个模型是Xception,也是Keras的applications模块的一部分,代表极端Inception,它是一种卷积神经网络架构。Xception将分别进行通道特征学习与空间特征学习的想法推向逻辑上的极端,并将Inception模块替换为深度可分离卷积,其中包括一个逐深度卷积和后面的一个逐点卷积。这个深度可分离卷积实际上是Inception模块的一种极端形式,空间特征和通道特征被完全分离。Xception比Inception对模型参数的使用更加高效,所以在ImageNet以及其他大规模数据集上的运行性能更好,精度更高

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值