Keras 模型如何成功训练,但之后又抱怨层不兼容?
How can a Keras model train successfully, but then complain about incompatible layers afterwards?
我正在使用一个简单的三层模型:
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=(6,), name="flatten"),
tf.keras.layers.Dense(128, activation="relu", name="dense1"),
tf.keras.layers.Dense(1, name="dense2")
])
model.compile(
optimizer=tf.keras.optimizers.Adam(0.001),
loss=tf.keras.losses.MeanAbsoluteError()
)
好的,编译成功。我已经为它准备了一些数据,让我们检查一下:
print(features)
print(labels)
这将打印两个列表:
[[1.0, 0.6747252747252748, 0.5652173913043478, 0.6817120622568094, 0.48387096774193544, 0.8536585365853658], [1.0, 0.7692307692307693, 0.717391304347826, 0.7184824902723735, 0.4637096774193548, 0.8536585365853658], (many more features...)]
[18.0, 15.0, (many more labels, same amount as features...)]
太棒了。现在我将训练模型并打印损失历史:
print(
model.fit(
features,
labels,
verbose=0,
epochs=100,
validation_data=(features, labels)
).history["val_loss"]
)
这会打印:
[22.92747688293457, 22.328025817871094, (many more epochs...), 3.36980938911438, 3.3660128116607666]
太好了,训练成功了,随着时间的推移,损失已经下降了。现在我想手动调用模型:
print(
model(
features[0]
)
)
但这抱怨:
ValueError: Layer "sequential" expects 1 input(s), but it received 6 input tensors. Inputs received: [<tf.Tensor: shape=(), dtype=float32, numpy=1.0>, <tf.Tensor: shape=(), dtype=float32, numpy=0.6747253>, <tf.Tensor: shape=(), dtype=float32, numpy=0.5652174>, <tf.Tensor: shape=(), dtype=float32, numpy=0.6817121>, <tf.Tensor: shape=(), dtype=float32, numpy=0.48387095>, <tf.Tensor: shape=(), dtype=float32, numpy=0.85365856>]
我不明白为什么我不能将它作为列表传递,因为在 .fit
调用中没问题,但通过一些阅读和反复试验,我找到了解决方案为此使用 tf.constant
:
print(
model(
tf.constant(features[0])
)
)
但是现在又报错了!
ValueError: Exception encountered when calling layer "sequential" (type Sequential).
Input 0 of layer "dense1" is incompatible with the layer: expected axis -1 of input shape to have value 6, but received input with shape (6, 1)
Call arguments received:
• inputs=tf.Tensor(shape=(6,), dtype=float32)
• training=None
• mask=None
似乎第二层与第一层不兼容!那是什么意思?我绝对不明白的是,如果图层不兼容,那么这个编译是如何开始的?更糟糕的是,为什么训练成功了?显然,如果模型没有报错地编译,并且我将输入很好地传递到第一层,那么第二层就不可能有问题吗?
这里出了什么问题?在我看来,这似乎不合逻辑。一定有什么我错过了。
首先为什么要使用 Flatten 层?您可以将展平层取出并仅使用
model = tf.keras.Sequential([
tf.keras.layers.Dense(128, activation="relu", name="dense1", input_shape=(6,)),
tf.keras.layers.Dense(1, name="dense2")
])
并且看起来我们已经作为 input_shape 传递了一个与 (6, None)
相同的元组 (6,)
。如果我们 运行 model.summary()
我们会得到
Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense1 (Dense) (None, 128) 896
dense2 (Dense) (None, 1) 129
=================================================================
Total params: 1,025
Trainable params: 1,025
Non-trainable params: 0
_________________________________________________________________
现在我们可以正常配合了
features = [[1.0, 0.6747252747252748, 0.5652173913043478, 0.6817120622568094, 0.48387096774193544, 0.8536585365853658], [1.0, 0.7692307692307693, 0.717391304347826, 0.7184824902723735, 0.4637096774193548, 0.8536585365853658]]
labels = [18.0, 15.0]
history = model.fit(
features,
labels,
verbose=0,
epochs=100,
validation_data=(features, labels)
)
现在如果你想做预测你可以做
# Using .predict
model.predict(features)
>>> array([[15.692635], [16.437447]], dtype=float32)
model.predict([features[0]])
>>> array([[15.692635]], dtype=float32)
# Using functional way
model(np.array(features))
>>><tf.Tensor: shape=(2, 1), dtype=float32, numpy=array([[15.692635],[16.437447]],dtype=float32)>
model(np.array(features[0]).reshape(1,-1))
>>> <tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[15.692635]], dtype=float32)>
.predict 和将模型本身用作函数之间的这种差异一定是由于 predict
方法和来自模型 class 的 __call__
的不同实现。
似乎预测方法更灵活,可能会对输入进行一些修改以使用它进行预测,而功能方法可能会尝试按原样使用输入,因此我们需要将其传递为二维数组
我正在使用一个简单的三层模型:
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=(6,), name="flatten"),
tf.keras.layers.Dense(128, activation="relu", name="dense1"),
tf.keras.layers.Dense(1, name="dense2")
])
model.compile(
optimizer=tf.keras.optimizers.Adam(0.001),
loss=tf.keras.losses.MeanAbsoluteError()
)
好的,编译成功。我已经为它准备了一些数据,让我们检查一下:
print(features)
print(labels)
这将打印两个列表:
[[1.0, 0.6747252747252748, 0.5652173913043478, 0.6817120622568094, 0.48387096774193544, 0.8536585365853658], [1.0, 0.7692307692307693, 0.717391304347826, 0.7184824902723735, 0.4637096774193548, 0.8536585365853658], (many more features...)]
[18.0, 15.0, (many more labels, same amount as features...)]
太棒了。现在我将训练模型并打印损失历史:
print(
model.fit(
features,
labels,
verbose=0,
epochs=100,
validation_data=(features, labels)
).history["val_loss"]
)
这会打印:
[22.92747688293457, 22.328025817871094, (many more epochs...), 3.36980938911438, 3.3660128116607666]
太好了,训练成功了,随着时间的推移,损失已经下降了。现在我想手动调用模型:
print(
model(
features[0]
)
)
但这抱怨:
ValueError: Layer "sequential" expects 1 input(s), but it received 6 input tensors. Inputs received: [<tf.Tensor: shape=(), dtype=float32, numpy=1.0>, <tf.Tensor: shape=(), dtype=float32, numpy=0.6747253>, <tf.Tensor: shape=(), dtype=float32, numpy=0.5652174>, <tf.Tensor: shape=(), dtype=float32, numpy=0.6817121>, <tf.Tensor: shape=(), dtype=float32, numpy=0.48387095>, <tf.Tensor: shape=(), dtype=float32, numpy=0.85365856>]
我不明白为什么我不能将它作为列表传递,因为在 .fit
调用中没问题,但通过一些阅读和反复试验,我找到了解决方案为此使用 tf.constant
:
print(
model(
tf.constant(features[0])
)
)
但是现在又报错了!
ValueError: Exception encountered when calling layer "sequential" (type Sequential).
Input 0 of layer "dense1" is incompatible with the layer: expected axis -1 of input shape to have value 6, but received input with shape (6, 1)
Call arguments received:
• inputs=tf.Tensor(shape=(6,), dtype=float32)
• training=None
• mask=None
似乎第二层与第一层不兼容!那是什么意思?我绝对不明白的是,如果图层不兼容,那么这个编译是如何开始的?更糟糕的是,为什么训练成功了?显然,如果模型没有报错地编译,并且我将输入很好地传递到第一层,那么第二层就不可能有问题吗?
这里出了什么问题?在我看来,这似乎不合逻辑。一定有什么我错过了。
首先为什么要使用 Flatten 层?您可以将展平层取出并仅使用
model = tf.keras.Sequential([
tf.keras.layers.Dense(128, activation="relu", name="dense1", input_shape=(6,)),
tf.keras.layers.Dense(1, name="dense2")
])
并且看起来我们已经作为 input_shape 传递了一个与 (6, None)
相同的元组 (6,)
。如果我们 运行 model.summary()
我们会得到
Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense1 (Dense) (None, 128) 896
dense2 (Dense) (None, 1) 129
=================================================================
Total params: 1,025
Trainable params: 1,025
Non-trainable params: 0
_________________________________________________________________
现在我们可以正常配合了
features = [[1.0, 0.6747252747252748, 0.5652173913043478, 0.6817120622568094, 0.48387096774193544, 0.8536585365853658], [1.0, 0.7692307692307693, 0.717391304347826, 0.7184824902723735, 0.4637096774193548, 0.8536585365853658]]
labels = [18.0, 15.0]
history = model.fit(
features,
labels,
verbose=0,
epochs=100,
validation_data=(features, labels)
)
现在如果你想做预测你可以做
# Using .predict
model.predict(features)
>>> array([[15.692635], [16.437447]], dtype=float32)
model.predict([features[0]])
>>> array([[15.692635]], dtype=float32)
# Using functional way
model(np.array(features))
>>><tf.Tensor: shape=(2, 1), dtype=float32, numpy=array([[15.692635],[16.437447]],dtype=float32)>
model(np.array(features[0]).reshape(1,-1))
>>> <tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[15.692635]], dtype=float32)>
.predict 和将模型本身用作函数之间的这种差异一定是由于 predict
方法和来自模型 class 的 __call__
的不同实现。
似乎预测方法更灵活,可能会对输入进行一些修改以使用它进行预测,而功能方法可能会尝试按原样使用输入,因此我们需要将其传递为二维数组