如何构建具有多个输入的 Tensorflow 模型?

Luc*_*ari 6 python deep-learning keras tensorflow

我想使用 Functional API 创建一个 Tensorflow 神经网络模型,但我不确定如何将输入分成两个。我想做这样的事情:给定一个输入,它的前半部分进入神经网络的第一部分,它的后半部分进入第二部分,每个输入都通过层,直到它们连接起来,再通过另一层,然后最终到达输出。我想到了类似下面的代码片段,以及一个快速草图。

from tensorflow.keras.layers import Dense

def define_model(self):
    input1 = tf.keras.Input(shape=(4,)) #input is a 1D vector containing 7 elements, split as 4 and 3
    input2 = tf.keras.Input(shape=(3,))

    layer1_1 = Dense(4, activation=tf.nn.leaky_relu)(input1)
    layer2_1 = Dense(4, activation=tf.nn.leaky_relu)(layer1_1)

    layer1_2 = Dense(4, activation=tf.nn.leaky_relu)(input2)
    layer2_2 = Dense(3, activation=tf.nn.leaky_relu)(layer1_2)

    concat_layer = tf.keras.concatenate([layer2_1,layer2_2], axis = 0)
    layer3 = Dense(6, activation=tf.nn.leaky_relu)(concat_layer)

    output = Dense(4)(layer3) #no activation

    self.model = tf.keras.Model(inputs = [input1,input2],outputs = output)
    self.model.compile(loss = 'mean_squared_error', optimizer = 'rmsprop')
    return self.model
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

首先,我应该在这个模型中添加任何 Dropout 或 BatchNormalization 层吗?

此外,输入数组的前 4 个元素是二进制的(如 [1,0,0,1] 或 [0,1,1,1]),而其他 3 个元素可以是任何实数。考虑到第一个在 0<x<1 范围内使用输入操作,而第二个没有,我是否应该将神经网络的第一个“列”与第二个“列”区别对待?

听起来不错,但我无法真正测试它是否应该工作,因为我必须重新编写大量代码以生成足够的数据来训练它。我是朝着正确的方向前进还是应该做一些不同的事情?这段代码会起作用吗?

编辑:我在训练期间遇到问题。假设我想像这样训练模型(值并不重要,重要的是数据类型):

#this snippet generates training data - nothing real, just test examples. Also, I changed the output layer from 4 elements to just 1 to test it.
A1=[np.array([[1.,0,0,1]]),np.array([[0,1.,0]])]
B1=np.array([7])

c=np.array([[5,-4,1,-1],[2,3,-1]], dtype = object)
A2 = [[np.random.randint(2, size= [1,4]),np.random.randint(2, size= [1,3])] for i in range(1000)]
B2 = np.array([np.sum(A[i][0]*c[0])+np.sum(A[i][1]*c[1]) for i in range(1000)]) 

model.fit(A1,B1, epochs = 50, verbose=False) #this works!
model.fit(A2,B2, epochs = 50, verbose=False) #but this doesn't.


Run Code Online (Sandbox Code Playgroud)

最终编辑:这里是 predict() 和 predict_on_batch() 函数。

def predict(a,b):
    pred = m.predict([a,b])
    return pred

def predict_b(c,d):
    preds = m.predict_on_batch([c,d])
    return preds

#a, b, c and d must look like this:
a = [np.array([0,1,0,1])]
b = [np.array([0,0,1])]

c =        [np.array([1, 0, 0, 1]), 
            np.array([0, 1, 1, 1]), 
            np.array([0, 1, 0, 0]), 
            np.array([1, 0, 0, 0]), 
            np.array([0, 0, 1, 0])] 

d =        [np.array([1, 0, 1]),
            np.array([0, 0, 1]),
            np.array([0, 1, 1]),
            np.array([1, 1, 1]),
            np.array([0, 0, 0])]
#notice that all of those should follow the same pattern, which is a list of arrays.
Run Code Online (Sandbox Code Playgroud)

其余代码在 M. Innat 的回答下。

M.I*_*nat 2

您的代码存在一些问题。我将尝试在这里回答主要问题,并放弃一些附带问题,例如您是否应该在模型中使用Dropoutor层,因为这完全超出了您的主要问题的范围,而且也不相关。BatchNormalization


如果您尝试使用 构建模型m = define_model(),我很确定您会遇到以下错误:

layer2_1 = Dense(4, activation=tf.nn.leaky_relu)(layer1_1)
layer2_2 = Dense(3, activation=tf.nn.leaky_relu)(layer1_2)
concat_layer = tf.keras.layers.concatenate([layer2_1, layer2_2], axis = 0)

ValueError: A `Concatenate` layer requires inputs with matching shapes 
except for the concat axis. Got inputs shapes: [(None, 4), (None, 3)]
Run Code Online (Sandbox Code Playgroud)

正确的axis应该是默认的-1,但在连接不同的形状时(例如, )1则不正确。您可以设置与相同的输出形状或设置。让我们选择一个(根据您的抽签):0Dense(4)Dense(3)Dense(3)Dense(4)axis = 1

from tensorflow.keras import Input
from tensorflow.keras import layers

def define_model():
    input1 = Input(shape=(4,)) 
    input2 = Input(shape=(3,))

    layer1_1 = layers.Dense(4, activation=tf.nn.leaky_relu)(input1)
    layer2_1 = layers.Dense(4, activation=tf.nn.leaky_relu)(layer1_1)

    layer1_2 = layers.Dense(4, activation=tf.nn.leaky_relu)(input2)
    layer2_2 = layers.Dense(3, activation=tf.nn.leaky_relu)(layer1_2)

    concat_layer = layers.concatenate([layer2_1, layer2_2], axis = 1) 
    layer3 = layers.Dense(6, activation=tf.nn.leaky_relu)(concat_layer)

    output = layers.Dense(4)(layer3) 
    model = tf.keras.Model(inputs = [input1,input2],outputs = output)
    model.compile(loss = 'mean_squared_error', optimizer = 'rmsprop')
    return model

m = define_model()
Run Code Online (Sandbox Code Playgroud)

更多详细信息,请参阅选择参数的输出形状axis

x1 = tf.keras.layers.Dense(8)(np.arange(10).reshape(5, 2))
x2 = tf.keras.layers.Dense(8)(np.arange(10, 20).reshape(5, 2))
print(x1.shape, x2.shape)
# (5, 8) (5, 8)

# using axis = 0
concatted = tf.keras.layers.Concatenate(axis=0)([x1, x2])
concatted.shape
# TensorShape([10, 8])

# using axis = 1
concatted = tf.keras.layers.Concatenate(axis=1)([x1, x2])
concatted.shape
# TensorShape([5, 16])
Run Code Online (Sandbox Code Playgroud)

测试模型

适合您的输入:

A1_i = np.array([[1.,0, 0,1]])
A1_j = np.array([[0, 1., 0]])
B1   = np.array([4])

print(type(A1_i), type(A1_j), type(B1))
print(A1_i.shape, A1_j.shape, B1.shape)
m.fit([A1_i, A1_j], B1, epochs = 2, verbose=2) 
Run Code Online (Sandbox Code Playgroud)
<class 'numpy.ndarray'> <class 'numpy.ndarray'> <class 'numpy.ndarray'>
(1, 4) (1, 3) (1,)
Epoch 1/2
584ms/step - loss: 15.9902
Epoch 2/2
4ms/step - loss: 15.8900
<tensorflow.python.keras.callbacks.History at 0x7fb1b484b890>
Run Code Online (Sandbox Code Playgroud)

不适合您的其他部分有几个问题,第一个模型输入应该是数组numpy,而不是list. 第二个问题来自连接的建模部分。但正确的做法应该是这样的:

c = np.array([[5,-4,1,-1],[2,3,-1]], dtype = object)

A2_i = np.random.randint(10, size = [100,4])
A2_j = np.random.randint(10, size = [100,3])
B2   = np.array( [np.sum(A2_i[i][0]*c[0]) + 
                  np.sum(A2_j[i][1]*c[1]) for i in range(100)]) 

print(type(A2_i), type(A2_j), type(B2))
print(A2_i.shape, A2_j.shape, B2.shape)
m.fit([A2_i, A2_j], B2, epochs = 2, verbose=2) 
Run Code Online (Sandbox Code Playgroud)
<class 'numpy.ndarray'> <class 'numpy.ndarray'> <class 'numpy.ndarray'>
(100, 4) (100, 3) (100,)
Epoch 1/2
4ms/step - loss: 683.9537
Epoch 2/2
4ms/step - loss: 681.0673
<tensorflow.python.keras.callbacks.History at 0x7fb1600a8d50>
Run Code Online (Sandbox Code Playgroud)