我创建了以下模型:
import tensorflow as tfimport numpy as npfrom tensorflow.keras.layers import Input, Embedding, Concatenate, Dense, LSTMfrom tensorflow.keras.models import Modelimport kerasdef get_model(): inputs = Input( shape =(None,2), name='timeseries_input',ragged=True ) lstm = LSTM(100, activation='tanh')(inputs.to_tensor(), mask=tf.sequence_mask(inputs.row_lengths())) dense1 = Dense(10, name='dense1')(lstm) out1 = Dense(1)(dense1) dense2 = Dense(10, name='dense2')(lstm) out2 = Dense(1)(dense2) dense3 = Dense(10, name='dense3')(lstm) out3 = Dense(1)(dense3) model = Model(inputs=inputs, outputs=[out1,out2,out3]) model.summary() return modelm = get_model()m.compile(loss=['mse','mse','mse'], optimizer='adam', metrics=['mse'])tf.keras.utils.plot_model( m, show_shapes=True, show_dtype=True, show_layer_names=True, rankdir="TB",)
以及以下虚拟数据:
import pandas as pddef get_ragged_constants(data): return tf.RaggedTensor.from_row_lengths( values=data[['f1','f2']].values, row_lengths=data.groupby('grp').size()) data = pd.DataFrame({'f1':[1,2,3,4,11,22,33,6,7,8,9,8,66,55,88,99],'f2':[4,3,2,1,44,33,22,66,55,44,33,22,1,2,3,4],'grp':[1,1,1,1,2,2,2,3,3,3,3,3,4,4,4,4]})targets = pd.DataFrame({'t1':[1,2,1,2],'t2':[1,2,1,2],'t3':[1,2,1,2]})x = get_ragged_constants(data)y = targets.values
它们的形状分别为 (4, None, 2)
和 (4, 3)
。
从模型结构来看,可以看出模型有三个输出,形状为 (None, 1)
。
我想知道为什么拟合能工作,我预期它们应该形状为 (4, 3, 1)
而不是 (4, 3)
。
m.fit(x,y,epochs=3)Epoch 1/31/1 [==============================] - 4s 4s/step - loss: 7.0158 - dense_21_loss: 1.8125 - dense_22_loss: 2.3360 - dense_23_loss: 2.8673 - dense_21_mse: 1.8125 - dense_22_mse: 2.3360 - dense_23_mse: 2.8673Epoch 2/31/1 [==============================] - 0s 11ms/step - loss: 5.6303 - dense_21_loss: 1.2898 - dense_22_loss: 2.0406 - dense_23_loss: 2.2999 - dense_21_mse: 1.2898 - dense_22_mse: 2.0406 - dense_23_mse: 2.2999Epoch 3/31/1 [==============================] - 0s 8ms/step - loss: 4.4403 - dense_21_loss: 0.8691 - dense_22_loss: 1.7483 - dense_23_loss: 1.8228 - dense_21_mse: 0.8691 - dense_22_mse: 1.7483 - dense_23_mse: 1.8228<tensorflow.python.keras.callbacks.History at 0x7fda43d41b90>
所以我给目标增加了一个输出,并用形状为 (4, 4)
的 y 测试了同一个模型,结果拟合仍然工作……我迷失了。
问题: 我应该如何调整 y 的形状以适应模型?当我提供错误的 y 形状时,实际发生了什么?
回答:
两种方式都是正确的。请看这里和这里。如你所见,这里提到“如果需要,压缩或扩展最后一维”,所以在进行这些操作后,如果维度匹配,那么一切正常。
首先要记住,一切都取决于你的损失函数。下面我将展示一个例子:
# 我从模型的输出 x 中获取预测值。preds = m(x)# 让我们打印形状preds = np.array(preds)x.shape, y.shape, y2.shape, preds.shape# 结果 -> (TensorShape([4, None, 2]), (4, 3), (4, 5), (3, 4, 1))# 让我们分别看一下 y2[0] 和 preds[0]y2[0], preds[0]'''(array([1, 1, 1, 1, 1]), array([[-0.1815457 ], [-1.0390669 ], [ 0.27160883], [-0.3232715 ]], dtype=float32))所以,现在要注意的是,如果我们做 y2[0] - preds[0] 会发生什么?由于形状不同,数组将首先被广播,y2[0] 将变为 :[[1,1,1,1,1][1,1,1,1,1][1,1,1,1,1][1,1,1,1,1]]而 preds[0] 将变为:array([[-0.1815457 , -0.1815457 , -0.1815457 , -0.1815457 , -0.1815457 ], [-1.03906691, -1.03906691, -1.03906691, -1.03906691, -1.03906691], [ 0.27160883, 0.27160883, 0.27160883, 0.27160883, 0.27160883], [-0.32327151, -0.32327151, -0.32327151, -0.32327151, -0.32327151]])'''# 执行 y2[0] - preds[0]y2[0] - preds[0]'''由于上述提到的广播,这些操作的结果将是array([[1.1815457 , 1.1815457 , 1.1815457 , 1.1815457 , 1.1815457 ], [2.03906691, 2.03906691, 2.03906691, 2.03906691, 2.03906691], [0.72839117, 0.72839117, 0.72839117, 0.72839117, 0.72839117], [1.32327151, 1.32327151, 1.32327151, 1.32327151, 1.32327151]])'''# 现在我们取平均值np.mean(y2[0] - preds[0])# 结果 -> 1.3180688247084618# 在对整个 y2 和 preds 执行整个过程后temp = y2 - predsnp.mean(temp)# 结果 -> 1.9192037958030899# 所以这就是 y2 的情况。现在让我们看看 y1 的情况# 加快速度,如果我执行 y[0] - preds[0]y[0]-preds[0]'''结果将是:array([[1.1815457 , 1.1815457 , 1.1815457 ], [2.03906691, 2.03906691, 2.03906691], [0.72839117, 0.72839117, 0.72839117], [1.32327151, 1.32327151, 1.32327151]])你能看到答案吗?一旦我们取平均值,结果将与 y2 相同。'''np.mean(y[0] - preds[0])# 结果 -> 1.3180688247084618
因此,在这种情况下,两种方法都能正常工作。