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 )