深度学习笔记34_函数式API之多输出模型构建
多输出模型
社交模型的构建
这里我们先来看个例子,通过一个网络来试图预测数据的不同性质,一个网络中:
输入:某个匿名人士在社交媒体发帖一系列文章
预测个人属性:
年龄
性别
收入水平
这个就是一个典型的一个输入,多个输出的模型,具体的coding如下。
from keras import layers
from keras import Input
from keras.models import Model
# 最常用的前50000词语
vocabulary_size = 50000
# 收入为10个等级
num_income_groups = 10
# shape = (None,) 表示输入的长度是可变的
# 输入的格式类型是:整数序列
# name='posts' 对输入进行命名
posts_input = Input(shape=(None,),dtype='int32',name='posts')
# # 将输入嵌入维度为256的向量
embedded_posts = layers.Embedding(256,vocabulary_size)(posts_input)
x = layers.Conv1D(128,5,activation='relu')(embedded_posts)
x = layers.MaxPooling1D(5)(x)
x = layers.Conv1D(256,5,activation = 'relu')(x)
x = layers.Conv1D(256,5,activation='relu')(x)
x = layers.MaxPooling1D(5)(x)
x = layers.Conv1D(256,5,activation='relu')(x)
x = layers.Conv1D(256,5,activation='relu')(x)
# 求全局的MAX池化,这里全局指的是整个steps
x = layers.GlobalMaxPooling1D()(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中我们可以这样处理:
在编译函数
compile
中,使用列表或者使用字典将不同的输出指定不同的损失,然后将得到的损失值相加得到一个全局损失值,然后在训练过程中将相加的那个损失进行最小化.
具体的coding如下
# 使用列表的形式,要与模型建立的是输出要对应model.compile(optimizer='rmsprop', loss = ['mse', 'categorical_crossentropy', 'binary_crossentropy'])# 使用字典的形式# 这里也是需要输出层具有名称时model.compile(optimizer='rmsprop', loss= {'age':'mse', 'income': 'categorical_crossentropy', 'gender': 'binary_crossentropy'
})
损失值权重的分配
上面的相加是比较粗暴的直接相加,这里需要考虑两个问题:
每个损失值的度量不一样,各个损失值的范围不一样
比如age:得出的结果可能在3-5左右
gender:交叉熵损失值可能在0.1左右
每个损失值贡献不一样,需要分配不同的权重
为了平衡这些损失值的贡献,我们这里需要对损失值进行权重的赋值.比如:交叉熵que
具体coding如下:
# 使用列表的形式,要与模型建立的是输出要对应
model.compile(optimizer='rmsprop',
loss = ['mse',
'categorical_crossentropy',
'binary_crossentropy'],
loss_weights=[0.25,1.0,10.])
# 使用字典的形式
# 这里也是需要输出层具有名称时
model.compile(optimizer='rmsprop',
loss= {'age':'mse',
'income': 'categorical_crossentropy',
'gender': 'binary_crossentropy'
},
loss_weights={
'age':0.25,
'imcome':1.,
'gender':10.
}
)
多输出模型的训练
对于多输出模型,要将标签数据对应与模型中的目标数据.我们可以使用Numpy数据组成的列表或者字典.
# 训练函数中,多输出模型的列表数据model.fit(posts, [age_targets,income_targets,gender_targets], epochs=10, batch_size=64)
# 训练函数中,多输出模型的字典数据# 这里也是需要输出层具有名称时model.fit(posts, {'age':age_targets, 'income':income_targets, 'gender':gender_targets}, epochs=10, batch_size=64)
多输入多输出模型
本例子参考Keras 文档的关于试图预测Twitter上的一条新闻有多少转发和点赞数,来说明多输入多输出模型,利用函数API里处理大量交织的数据流.
输入的数据:
新闻标题本身
辅助输入来接收额外的数据: 新闻标题的发布的时间等
输出的数据:
辅助输出
较早地在模型中使用主损失函数,是深度学习模型的一个良好正则方法
插入辅助损失,使得即使在模型主损失很高的情况下,LSTM 层和 Embedding 层都能被平稳地训练
主输出
具体的模型结构如下图:
具体的coding如下:
from keras.layers import Input,Embedding,LSTM,Dense
from keras.models import Model
# 最常用的前10000词语
vocabulary_size = 10000
# shape = (100,) 表示输入是一个含有100个整数序列,
# 每个整数在1到10000之间的
# 输入的格式类型是:整数序列
# name='main_input' 对输入进行命名
main_input = Input(shape=(100,),
dtype='int32',
name='main_input')
# Embedding 层将输入序列编码为一个稠密向量的序列,
# 每个向量维度为 512。
# 使用最常用的前10000词语
# 输入的长度100,同上面main_input
x = Embedding(output_dim=512,
input_dim=10000,
input_length=100)(main_input)
# LSTM 层把向量序列转换成单个向量,
# 它包含整个序列的上下文信息
lstm_out = LSTM(32)(x)
# 这里直接来一个辅助输出# 作用是:# 1.使得即使在模型主损失很高的情况下,#LSTM 层和 Embedding 层都能被平稳地训练# 2. 较早地在模型中使用主损失函数,是一个良好正则方法 auxiliary_output = Dense(1, activation='sigmoid', name='aux_output')(lstm_out)
# 引入辅助输入数据auxiliary_input = Input(shape=(5,),name = 'aux_input')# 结合辅助数据x = keras.layers.concatenate([lstm_out,auxiliary_input])
# 堆叠多个全连接网络层x = Dense(64, activation='relu')(x)x = Dense(64, activation='relu')(x)x = Dense(64, activation='relu')(x)
# 最后添加主要的逻辑回归层main_output = Dense(1, a ctivation='sigmoid', name='main_output')(x)
# 定义一个多输入多输出模型model = Model(inputs=[main_input,auxiliary_input], outputs=[main_output,auxiliary_output] )
# 这里做了一个简写,因为这里的两个损失函数选的是一样,
# 这里对于辅助损失值分配一个0.2的权重
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
loss_weights=[1.,0.2])
# 另外一种列表的写法
model.compile(optimizer='rmsprop',
loss=['binary_crossentropy',
'binary_crossentropy'],
loss_weights=[1.,0.2])
# 传入的数据也是两个,和两个标签数据
model.fit([headline_data,additional_data],
[labels,labels],
epochs=50,
batch_size=32)
# 使用字典的写法
model.compile(optimizer='rmsprop', losss = {'main_output':'binary_crossentropy', 'aux_output':'binary_crossentropy'}, loss_weight=[1.,0.2] )# 要跟前面的name对应model.fit( {'main_input':headline_data, 'aux_input': additional_data}, {'main_output':labels, 'aux_output':labels}, epochs=50, batch_size=32)