【问题标题】:Keras LSTM return_sequences: INVALID_ARGUMENT: Cannot update variable with shape [16,1] using a Tensor with shape [2,1], shapes must be equalKeras LSTM return_sequences:INVALID_ARGUMENT:无法使用形状为 [2,1] 的张量更新形状为 [16,1] 的变量,形状必须相等
【发布时间】:2023-02-26 09:57:35
【问题描述】:

我正在尝试使用 Keras 训练 LSTM;这是我的模型:

def generate_model() -> keras.Model:
    model = keras.Sequential()
    model.add(keras.layers.LSTM(64, return_sequences=True, name='lstm_64'))
    model.add(keras.layers.LSTM(32, return_sequences=True, name='lstm_32'))
    model.add(keras.layers.Dense(32, activation='relu', name='dense_32'))
    model.add(keras.layers.Dense(1, activation='linear', name='dense_1'))
    return model
Model: "sequential_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 lstm_64 (LSTM)              (1, None, 64)             18176     
                                                                 
 lstm_32 (LSTM)              (1, None, 32)             12416     
                                                                 
 dense_32 (Dense)            (1, None, 32)             1056      
                                                                 
 dense_1 (Dense)             (1, None, 1)              33        
                                                                 
=================================================================
Total params: 31,681
Trainable params: 31,681
Non-trainable params: 0
_________________________________________________________________

我的数据形式为 (X_我,_i) 每个X_i 是 R^6 x_1, x_2, x_3, ..., x_T_i 和_i 是 R 中每个 x_i 对应的目标变量序列。
请注意,序列长度取决于 i(每个数据点都是不同长度的序列)。

为了对这些序列进行批处理,我尝试将具有相同长度的数据点分组在一起并将它们作为张量传递:

def hashData(X, y):
    XDict = {}
    yDict = {}

    # X is a list of tensors and X[i] has shape(1, T\_i, 6)
    # y is a list of tensors and y[i] has shape(1, T\_i, 1)
    for i in range(len(X)):
        if X[i].shape[1] not in XDict:
            XDict[X[i].shape[1]] = [X[i]]
            yDict[X[i].shape[1]] = [y[i]]
        else:
            XDict[X[i].shape[1]].append(X[i])
            yDict[X[i].shape[1]].append(y[i])

    for key in XDict:
        XDict[key] = tf.concat(XDict[key], axis=0)
        yDict[key] = tf.concat(yDict[key], axis=0)

    return XDict, Ydict

所以生成的散列数据看起来像这样:

XDict, yDict = hashData(X,y)
for key in XDict:
    print(f"{key}:", XDict[key].shape, yDict[key].shape)
16: (62, 16, 6) (62, 16, 1)
2: (36, 2, 6) (36, 2, 1)
12: (45, 12, 6) (45, 12, 1)
17: (56, 17, 6) (56, 17, 1)
86: (1, 86, 6) (1, 86, 1)
...
3: (42, 3, 6) (42, 3, 1)

IE。有 62 个长度为 T_i = 16 的数据点,依此类推。

然后我尝试按如下方式在每个批次上训练模型:

N_EPOCHS = 10

cv = KFold(n_splits=10, shuffle=True, random_state=SEED)
results = []
for fold, (train_idx, test_idx) in enumerate(cv.split(X)):
    print(f'=============== Training Fold {fold} ===============')

    # Slice is my function to mimic numpy multi-index slicing because X and y are python lists of tensors (and Tensors of varying lengths don't like being concatenated)
    X_train, y_train = hashData(slice(X, train_idx), slice(y, train_idx)) 
    X_test, y_test = slice(X, test_idx), slice(y, test_idx)
    model = generate_model()

    model.compile(loss='mse', optimizer='adam', metrics=[r2.RSquare()])
    model.build(input_shape=(1, None, len(factors)))

    model.summary()


    for _ in range(N_EPOCHS):
        for key in X_train:
            model.fit(X_train[key], y_train[key], epochs=1, batch_size=min(key, 32), verbose=0)

    model.evaluate(X_test, y_test, verbose=0)

    results.append(model.evaluate(X_test, y_test, verbose=0))
    print(f'Fold {fold} results: {results[-1]}', end='\n\n')

运行它会给我以下错误,我不知道如何修复它:

Output exceeds the size limit. Open the full output data in a text editor
---------------------------------------------------------------------------
InvalidArgumentError                      Traceback (most recent call last)
Cell In[28], line 19
     17 for _ in range(N_EPOCHS):
     18     for key in X_train:
---> 19         model.fit(X_train[key], y_train[key], epochs=1, batch_size=min(key, 32), verbose=0)
     21 model.evaluate(X_test, y_test, verbose=0)
     23 results.append(model.evaluate(X_test, y_test, verbose=0))

File ~/miniconda3/envs/ml/lib/python3.10/site-packages/keras/utils/traceback_utils.py:70, in filter_traceback.<locals>.error_handler(*args, **kwargs)
     67     filtered_tb = _process_traceback_frames(e.__traceback__)
     68     # To get the full stack trace, call:
     69     # `tf.debugging.disable_traceback_filtering()`
---> 70     raise e.with_traceback(filtered_tb) from None
     71 finally:
     72     del filtered_tb

File ~/miniconda3/envs/ml/lib/python3.10/site-packages/tensorflow/python/eager/execute.py:52, in quick_execute(op_name, num_outputs, inputs, attrs, ctx, name)
     50 try:
     51   ctx.ensure_initialized()
---> 52   tensors = pywrap_tfe.TFE_Py_Execute(ctx._handle, device_name, op_name,
     53                                       inputs, attrs, num_outputs)
     54 except core._NotOkStatusException as e:
     55   if name is not None:

InvalidArgumentError: Graph execution error:

Detected at node 'AssignAddVariableOp_6' defined at (most recent call last):
    File "~/miniconda3/envs/ml/lib/python3.10/runpy.py", line 196, in _run_module_as_main
      return _run_code(code, main_globals, None,
    File "~/miniconda3/envs/ml/lib/python3.10/runpy.py", line 86, in _run_code
      exec(code, run_globals)
    File "~/miniconda3/envs/ml/lib/python3.10/site-packages/ipykernel_launcher.py", line 17, in <module>
      app.launch_new_instance()
    File "~/miniconda3/envs/ml/lib/python3.10/site-packages/traitlets/config/application.py", line 992, in launch_instance
      app.start()
    File "~/miniconda3/envs/ml/lib/python3.10/site-packages/ipykernel/kernelapp.py", line 711, in start
      self.io_loop.start()
    File "~/miniconda3/envs/ml/lib/python3.10/site-packages/tornado/platform/asyncio.py", line 199, in start
      self.asyncio_loop.run_forever()
    File "~/miniconda3/envs/ml/lib/python3.10/asyncio/base_events.py", line 603, in run_forever
      self._run_once()
    File "~/miniconda3/envs/ml/lib/python3.10/asyncio/base_events.py", line 1906, in _run_once
      handle._run()
    File "~/miniconda3/envs/ml/lib/python3.10/asyncio/events.py", line 80, in _run
...
    File "~/miniconda3/envs/ml/lib/python3.10/site-packages/tensorflow_addons/metrics/r_square.py", line 157, in update_state
      self.count.assign_add(tf.reduce_sum(sample_weight, axis=0))
Node: 'AssignAddVariableOp_6'
Cannot update variable with shape [16,1] using a Tensor with shape [2,1], shapes must be equal.
     [[{{node AssignAddVariableOp_6}}]] [Op:__inference_train_function_45490]

我已经尝试以各种方式解决这个问题,包括在数据集中一次跳过一个数据点的散列和训练(并且 batch_size = 1),并在每一层尝试不同数量的节点,但我不断得到相同的结果,使用形状为 [2,1] 的张量更新形状为 [16,1] 的张量。

笔记:当我在“lstm_2”层中设置 return_sequences=False 并仅在每个序列的最终 y 值 (y_T_i) 上训练模型时,该过程工作正常,但训练以获取整个 y 值序列会导致上述错误。

【问题讨论】:

  • 当我发布问题时,LaTeX 格式(对于序列)似乎不起作用,不知道为什么......

标签: tensorflow machine-learning keras time-series lstm


【解决方案1】:

问题似乎是您将不同长度的序列作为输入传递给 LSTM 层,这导致 LSTM 层和后续层的输出形状不匹配。具体来说,LSTM 层返回形状为 (batch_size, sequence_length, num_units) 的张量,其中 sequence_length 是批次中最长序列的长度,但后续层期望每个时间步的形状为 (batch_size, num_units) 的张量。

解决此问题的一种方法是使用 Keras 的 pad_sequences 函数将序列填充到固定长度。此函数可以获取不同长度的序列列表,并用零填充它们到固定长度,可以将其设置为数据中最长序列的长度。

以下是如何将 pad_sequences 与您的数据一起使用的示例:

from tensorflow.keras.preprocessing.sequence import pad_sequences

# Assume X and y are lists of sequences of different lengths

# Pad the sequences with zeros to a fixed length
X_padded = pad_sequences(X, padding='post')
y_padded = pad_sequences(y, padding='post')

# Create a mask to ignore the padded values during training
mask = (X_padded != 0)

# Train the model using the padded sequences and the mask
model.fit(X_padded, y_padded, sample_weight=mask, ...)

在这个例子中,X_paddedy_padded是填充序列,mask是一个布尔数组,True代表实际值,False代表填充值。 sample_weight 参数用于在训练期间根据掩码对损失函数进行加权,以便填充值不会对损失产生影响。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 2019-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-01
    相关资源
    最近更新 更多