TensorFlow实现多输入多输出模型
有时我们的输入数据不只一个,会存在多个输入源,多个输出源,对于这种情况我们使用Sequential
显然是不行的,因为Sequential
只能够搭建线性拓扑模型,对于那种流水线型的模型较为适合,如果是非线性拓扑,复杂的拓扑使用Sequential
是不能够实现的,这是我们就需要使用Function API
,它会使我们处理多输入多输出变得简单。
例如,如果您要构建一个系统,该系统按照优先级对自定义问题工单进行排序,然后将工单传送到正确的部门,则此模型将具有三个输入:
- 工单标题(文本输入),
- 工单的文本正文(文本输入),以及
- 用户添加的任何标签(分类输入)
此模型将具有两个输出:
- 介于 0 和 1 之间的优先级分数(标量 Sigmoid 输出),以及
- 应该处理工单的部门(部门范围内的 Softmax 输出)。
您可以使用函数式 API 通过几行代码构建此模型:
定义输入源
模型的数据输入源有三个:标题输入、正文输入、标签输入
# 输入源
title_input = keras.Input(shape=(None,), name='title')
body_input = keras.Input(shape=(None,), name='body')
tags_input = keras.Input(shape=(num_tags,), name='tags')
定义层之间关系
首先需要将标题和正文的文本进行Embedding处理,然后使用长短期网络LSTM进行处理,然后将处理后的特征向量进行维度拼接,将三个输入源的特征向量进行拼接
title_features = Embedding(num_words, 64)(title_input)
body_features = Embedding(num_words, 64)(body_input)
title_features = LSTM(128)(title_features)
body_features = LSTM(128)(body_features)
x = Concatenate(axis=1)([title_features, body_features, tags_input])
定义输出源
定义两个输出源,第一个是预测优先级,所以Dense为1,另外一个是预测部分,需要使用softmax,所以维度是部门的数量
# 输出源
priority_pred = Dense(1, name='priority')(x)
department_pred = Dense(num_departments, name='department')(x)
构建模型
只需要指定模型的输入和输出,然后keras.Model
会自动根据输入和输出之间的关系搭建出计算图拓扑
model = keras.Model(
inputs=[title_input, body_input, tags_input],
outputs=[priority_pred, department_pred]
)
编译模型
为不同的输出指定不同的损失函数,并且赋值不同的损失权重
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss={
'priority': keras.losses.BinaryCrossentropy(from_logits=True),
'department': keras.losses.CategoricalCrossentropy(from_logits=True)
},
loss_weights=[1.0, 0.2]
)
定义数据集
title_data = np.random.randint(num_words, size=(1280, 10))
body_data = np.random.randint(num_words, size=(1280, 100))
tags_data = np.random.randint(2, size=(1280, num_tags)).astype('float32')
priority_targets = np.random.random(size=(1280, 1))
department_targets = np.random.randint(2, size=(1280, num_departments))
训练模型
model.fit(
{'title': title_data, 'body': body_data, 'tags': tags_data},
{'priority': priority_targets, 'department': department_targets},
epochs=2,
batch_size=32
)
完整代码
"""
* Created with PyCharm
* 作者: 阿光
* 日期: 2022/1/1
* 时间: 19:32
* 描述:
"""
import numpy as np
from tensorflow import keras
from tensorflow.keras.layers import *
num_tags = 12
num_words = 10000
num_departments = 4
# 输入源
title_input = keras.Input(shape=(None,), name='title')
body_input = keras.Input(shape=(None,), name='body')
tags_input = keras.Input(shape=(num_tags,), name='tags')
title_features = Embedding(num_words, 64)(title_input)
body_features = Embedding(num_words, 64)(body_input)
title_features = LSTM(128)(title_features)
body_features = LSTM(128)(body_features)
x = Concatenate(axis=1)([title_features, body_features, tags_input])
# 输出源
priority_pred = Dense(1, name='priority')(x)
department_pred = Dense(num_departments, name='department')(x)
model = keras.Model(
inputs=[title_input, body_input, tags_input],
outputs=[priority_pred, department_pred]
)
keras.utils.plot_model(model, "multi_input_and_output_model.png", show_shapes=True)
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss={
'priority': keras.losses.BinaryCrossentropy(from_logits=True),
'department': keras.losses.CategoricalCrossentropy(from_logits=True)
},
loss_weights=[1.0, 0.2]
)
title_data = np.random.randint(num_words, size=(1280, 10))
body_data = np.random.randint(num_words, size=(1280, 100))
tags_data = np.random.randint(2, size=(1280, num_tags)).astype('float32')
priority_targets = np.random.random(size=(1280, 1))
department_targets = np.random.randint(2, size=(1280, num_departments))
model.fit(
{'title': title_data, 'body': body_data, 'tags': tags_data},
{'priority': priority_targets, 'department': department_targets},
epochs=2,
batch_size=32
)