我有一个模型,像这样:
inputA = tf.keras.layers.Input(shape=(40,40))inputB = tf.keras.layers.Input(shape=6)a = tf.keras.layers.Conv2D(...)(inputA)...b = tf.keras.layers.Dense(...)(inputB)combined = tf.keras.layers.concatenate([a, b])....
它有两个输入,一个是预处理过的图像,还有一些额外的信息。
我的问题是如何一次训练多个实例。我有这个训练函数:
def train_step(observations, actions, rewards): with tf.GradientTape() as tape: logits = my_model(observations) loss = self.compute_loss(logits, actions, rewards) ....
在logits = my_model(observations)
这行,如果我只提供一个样本,它能工作,但如果我发送一个列表,它会报错“Layer model expects 2 input(s), but it received 34 input tensors”。
我怀疑我传递参数的方式不对(当我只有一个输入模型时它曾经工作过)。
我应该如何将一批观察数据传递给这个模型?
为了澄清:
observations
是一个numpy数组的列表。my_model(observations)
会抛出错误“Layer model expects…”。my_model([observations[0][0], observations[0][1]])
可以工作。my_model([[observations[0][0], observations[0][1]],[observations[1][0], observations[1][1]]])
会抛出错误Layer model expects 2 input(s), but it received 4 input tensors
。
我可以使用my_model([observations[i][0], observations[i][1]])
在一个循环中进行训练(其中i
是我在这个批次中的第n个观察)。但我想如果这样做与一次性发送所有训练批次相比,可能会有性能问题。
编辑
为了更清楚。我可以这样做:
input_a = np.random.randint(0, 255, size=(1, 40, 40, 3)).astype("int8")input_b = np.random.randint(0, 1, size=(1, 6)).astype("int8")logits = my_model([input_a, input_b])
这可以完美工作。
但如果我有一个批次中的多个观察,我不知道如何传递参数:
input_a0 = np.random.randint(0, 255, size=(1, 40, 40, 3)).astype("int8")input_b0 = np.random.randint(0, 1, size=(1, 6)).astype("int8")input_a1 = np.random.randint(0, 255, size=(1, 40, 40, 3)).astype("int8")input_b1 = np.random.randint(0, 1, size=(1, 6)).astype("int8")logits = my_model([[input_a0, input_a0], [input_a1, input_a1]])
会抛出:
ValueError: Layer model expects 2 input(s), but it received 4 input tensors. Inputs received: ...
回答:
如果我理解正确的话,你遇到的问题主要是如何为多输入模型正确传递输入数据。如你所述,observations
是一个numpy
数组的列表,你将数据传递给多输入模型的方式是my_model(observations)
– 这似乎有问题。你可能需要做的是解包observations
并将数据作为list
传递,例如my_model([input1, input2])
。这是一个可能的解决方案。
自定义训练
from tensorflow import kerasimport tensorflow as tf class CustomModel(keras.Model): def train_step(self, data): # 解包数据。其结构取决于你的模型和 # 你传递给`fit()`的内容。 (x, z), y = data with tf.GradientTape() as tape: y_pred = self([x, z], training=True) # 前向传播 # 计算损失值 #(损失函数在`compile()`中配置) loss = self.compiled_loss(y, y_pred, regularization_losses=self.losses) # 计算梯度 trainable_vars = self.trainable_variables gradients = tape.gradient(loss, trainable_vars) # 更新权重 self.optimizer.apply_gradients(zip(gradients, trainable_vars)) # 更新指标(包括跟踪损失的指标) self.compiled_metrics.update_state(y, y_pred) # 返回一个将指标名称映射到当前值的字典 return {m.name: m.result() for m in self.metrics}
基础模型
训练
x = np.random.randint(0, 256, size=(50, 28, 28)).astype("float32")z = np.random.random((50, 32))y = np.random.random((50, 1))print(x.shape, z.shape, y.shape)model.fit([x, z], y, epochs=3, verbose=2)
(50, 28, 28) (50, 32) (50, 1)Epoch 1/37ms/step - loss: 19227.8789 - mae: 112.9769Epoch 2/38ms/step - loss: 16268.3952 - mae: 98.0642Epoch 3/310ms/step - loss: 14247.0742 - mae: 95.9225