具有两种不同输入样本量的Keras多任务学习

Abd*_*han 8 python nlp machine-learning keras tensorflow

我正在使用共享层部分下的Keras API中的代码实现多任务回归模型。

有两组数据,让我们称他们data_1data_2如下。

data_1 : shape(1434, 185, 37)
data_2 : shape(283, 185, 37)
Run Code Online (Sandbox Code Playgroud)

data_1是由1434个样本组成,每个样本的长度为185个字符,并且37显示的唯一字符总数为37或换句话说,vocab_size。比较而言,它data_2由283个字符组成。

我先将data_1data_2转换为二维numpy数组,然后将其提供给Embedding层。

data_1=np.argmax(data_1, axis=2)
data_2=np.argmax(data_2, axis=2)
Run Code Online (Sandbox Code Playgroud)

这使得数据的形状如下。

print(np.shape(data_1)) 
(1434, 185)

print(np.shape(data_2)) 
(283, 185)
Run Code Online (Sandbox Code Playgroud)

矩阵中的每个数字代表索引整数。

多任务模型如下。

user_input = keras.layers.Input(shape=((185, )), name='Input_1')
products_input =  keras.layers.Input(shape=((185, )), name='Input_2')

shared_embed=(keras.layers.Embedding(vocab_size, 50, input_length=185))

user_vec_1 = shared_embed(user_input )
user_vec_2 = shared_embed(products_input )


input_vecs = keras.layers.concatenate([user_vec_1, user_vec_2], name='concat')

input_vecs_1=keras.layers.Flatten()(input_vecs)
input_vecs_2=keras.layers.Flatten()(input_vecs)

# Task 1 FC layers
nn = keras.layers.Dense(90, activation='relu',name='layer_1')(input_vecs_1)
result_a = keras.layers.Dense(1, activation='linear', name='output_1')(nn)



# Task 2 FC layers
nn1 = keras.layers.Dense(90, activation='relu', name='layer_2')(input_vecs_2)
result_b = keras.layers.Dense(1, activation='linear',name='output_2')(nn1) 

model = Model(inputs=[user_input , products_input], outputs=[result_a, result_b])

model.compile(optimizer='rmsprop',
              loss='mse',
              metrics=['accuracy'])
Run Code Online (Sandbox Code Playgroud)

该模型如下所示。 在此处输入图片说明

然后我按以下方式拟合模型。

model.fit([data_1, data_2], [Y_1,Y_2], epochs=10)
Run Code Online (Sandbox Code Playgroud)

错误:

ValueError: All input arrays (x) should have the same number of samples. Got array shapes: [(1434, 185), (283, 185)]
Run Code Online (Sandbox Code Playgroud)

在Keras中,有什么方法可以使用两个不同的样本量输入,或者可以使用一些技巧来避免此错误,从而实现我的多任务回归目标。

这是用于测试的最低工作代码

data_1=np.array([[25,  5, 11, 24,  6],
       [25,  5, 11, 24,  6],
       [25,  0, 11, 24,  6],
       [25, 11, 28, 11, 24],
       [25, 11,  6, 11, 11]])

data_2=np.array([[25, 11, 31,  6, 11],
       [25, 11, 28, 11, 31],
       [25, 11, 11, 11, 31]])

Y_1=np.array([[2.33],
       [2.59],
       [2.59],
       [2.54],
       [4.06]])


Y_2=np.array([[2.9],
       [2.54],
       [4.06]])



user_input = keras.layers.Input(shape=((5, )), name='Input_1')
products_input =  keras.layers.Input(shape=((5, )), name='Input_2')

shared_embed=(keras.layers.Embedding(37, 3, input_length=5))
user_vec_1 = shared_embed(user_input )
user_vec_2 = shared_embed(products_input )

input_vecs = keras.layers.concatenate([user_vec_1, user_vec_2], name='concat')


input_vecs_1=keras.layers.Flatten()(input_vecs) 
input_vecs_2=keras.layers.Flatten()(input_vecs)

    nn = keras.layers.Dense(90, activation='relu',name='layer_1')(input_vecs_1)
    result_a = keras.layers.Dense(1, activation='linear', name='output_1')(nn)

    # Task 2 FC layers
    nn1 = keras.layers.Dense(90, activation='relu', name='layer_2')(input_vecs_2)

    result_b = keras.layers.Dense(1, activation='linear',name='output_2')(nn1)

model = Model(inputs=[user_input , products_input], outputs=[result_a, result_b])

model.compile(optimizer='rmsprop',
              loss='mse',
              metrics=['accuracy'])

model.fit([data_1, data_2], [Y_1,Y_2], epochs=10)
Run Code Online (Sandbox Code Playgroud)

moh*_*moh 6

新答案

在这里,我正在使用 TensorFlow 2 编写解决方案。因此,您需要的是:

  1. 定义从数据中获取形状的动态输入

  2. 使用平均池化,以便您的 dens 层维度独立于输入维度。

  3. 分别计算损失

这是您修改后的示例:

## Do this
#pip install tensorflow==2.0.0

import tensorflow.keras as keras
import numpy as np
from tensorflow.keras.models import Model


data_1=np.array([[25,  5, 11, 24,  6],
       [25,  5, 11, 24,  6],
       [25,  0, 11, 24,  6],
       [25, 11, 28, 11, 24],
       [25, 11,  6, 11, 11]])

data_2=np.array([[25, 11, 31,  6, 11],
       [25, 11, 28, 11, 31],
       [25, 11, 11, 11, 31]])

Y_1=np.array([[2.33],
       [2.59],
       [2.59],
       [2.54],
       [4.06]])


Y_2=np.array([[2.9],
       [2.54],
       [4.06]])



user_input = keras.layers.Input(shape=((None,)), name='Input_1')
products_input =  keras.layers.Input(shape=((None,)), name='Input_2')

shared_embed=(keras.layers.Embedding(37, 3, input_length=5))
user_vec_1 = shared_embed(user_input )
user_vec_2 = shared_embed(products_input )

x = keras.layers.GlobalAveragePooling1D()(user_vec_1)
nn = keras.layers.Dense(90, activation='relu',name='layer_1')(x)
result_a = keras.layers.Dense(1, activation='linear', name='output_1')(nn)

# Task 2 FC layers
x = keras.layers.GlobalAveragePooling1D()(user_vec_2)
nn1 = keras.layers.Dense(90, activation='relu', name='layer_2')(x)

result_b = keras.layers.Dense(1, activation='linear',name='output_2')(nn1)

model = Model(inputs=[user_input , products_input], outputs=[result_a, result_b])


loss = tf.keras.losses.MeanSquaredError()
optimizer = tf.keras.optimizers.Adam()

loss_values = []
num_iter = 300
for i in range(num_iter):
    with tf.GradientTape() as tape:
        # Forward pass.
        logits = model([data_1, data_2])          
        loss_value = loss(Y_1, logits[0]) + loss(Y_2, logits[1]) 
        loss_values.append(loss_value)
    gradients = tape.gradient(loss_value, model.trainable_weights)          
    optimizer.apply_gradients(zip(gradients, model.trainable_weights))

import matplotlib.pyplot as plt
plt.plot(range(num_iter), loss_values)
plt.xlabel("iterations")
plt.ylabel('loss value')
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

旧答案

看来您的问题不是编码问题,而是机器学习问题!你必须配对你的数据集:这意味着你必须在每一轮的两个输入层上输入你的 Keras 模型。

解决方案是以两个数据集大小相同的方式对较小的数据集进行上采样。你这样做的方式取决于你的数据集的语义。另一种选择是对较大的数据集进行下采样,这是不推荐的。

在一个非常基本的情况下,如果我们假设样本跨数据集是 iid,则可以使用以下代码:

random_indices = np.random.choice(data_2.shape[0],
data_1.shape[0], replace=True) 

upsampled_data_2 = data_2[random_indices]
Run Code Online (Sandbox Code Playgroud)

因此,您将获得较小数据集的新版本upsampled_data_2,其中包含一些重复样本,但与较大数据集的大小相同。