You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LSTM自定义损失函数报错:ValueError: too many values to unpack (expected 4)

问题:LSTM模型自定义损失函数报错:too many values to unpack (expected 4)

我尝试用以下代码实现带有自定义损失函数的LSTM模型:

tf.random.set_seed(7)

model = Sequential()
model.add(LSTM(100, input_shape=(18,1 ), return_sequences=True))
model.add(Dropout(0.2))
#model.add(LSTM(100))
#model.add(Dropout(0.2))
model.add(Dense(4, activation='tanh'))

def LossQuat(y_true, y_pred):
        a, b = y_true.get_shape()
        error = []
        for i in range(a):
            w0,x0,y0,z0 = y_true[i,:]
            w1,x1,y1,z1 = y_pred[i,:]/tf.norm(y_pred[i,:], ord='euclidean', axis=None, keepdims=None, name=None)
            w = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1
            error.append(tf.square(2*tf.math.acos(w)))
        err = tf.reduce_sum(error)
        return tf.reduce_mean(err) 

model.compile(loss=LossQuat, optimizer = tf.keras.optimizers.Adam(learning_rate=1e-5),run_eagerly=True)

model.summary()

但训练时出现如下错误:

Epoch 1/150

---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

<ipython-input-17-8e2657a2f86a> in <module>()
----> 1 history=model.fit(X,Y, verbose=1,epochs=150, batch_size=32)

1 frames

/usr/local/lib/python3.7/dist-packages/keras/utils/traceback_utils.py in error_handler(*args, **kwargs)
     65     except Exception as e:  # pylint: disable=broad-except
     66       filtered_tb = _process_traceback_frames(e.__traceback__)
---> 67       raise e.with_traceback(filtered_tb) from None
     68     finally:
     69       del filtered_tb

/usr/local/lib/python3.7/dist-packages/tensorflow/python/autograph/impl/api.py in wrapper(*args, **kwargs)
    690       except Exception as e:  # pylint:disable=broad-except
    691         if hasattr(e, 'ag_error_metadata'):
---> 692           raise e.ag_error_metadata.to_exception(e)
    693         else:
    694           raise

ValueError: in user code:

    File "<ipython-input-16-820055073eb4>", line 15, in LossQuat  *
        w1,x1,y1,z1 = y_pred[i,:]/tf.norm(y_pred, ord='euclidean', axis=None, keepdims=None, name=None)

    ValueError: too many values to unpack (expected 4)

该自定义损失函数训练FFN时可正常运行,我知道错误和LSTM层相关,但不清楚具体原因。


问题原因与解决方法

问题根源

你给LSTM层设置了return_sequences=True,这会让LSTM输出三维张量:(batch_size, timesteps, features),而FFN模型的输出是二维张量:(batch_size, features)。你的损失函数是按二维张量写的,遍历batch维度时,y_pred[i,:]实际是形状为(timesteps, 4)的张量,不是4个单独的值,所以尝试解包成w1,x1,y1,z1就会触发"too many values to unpack"错误。

两种解决方式

方式1:关闭序列输出(推荐,若不需要后续序列输入)

如果你的模型不需要LSTM返回完整序列,把return_sequences=True改成return_sequences=False,这样LSTM输出和FFN一致是二维张量,原损失函数可以直接使用:

model.add(LSTM(100, input_shape=(18,1 ), return_sequences=False))

方式2:修改损失函数适配三维张量(需保留序列输出时)

如果必须保留LSTM的序列输出(比如后续还有LSTM层需要序列输入),需要修改损失函数,用张量操作替代循环,适配三维输入:

def LossQuat(y_true, y_pred):
    # y_true: (batch_size, timesteps, 4),y_pred: (batch_size, timesteps, 4)
    # 对每个样本的每个时间步的四元数做归一化
    y_pred_normalized = y_pred / tf.norm(y_pred, ord='euclidean', axis=-1, keepdims=True)
    # 计算四元数的点积
    dot_product = tf.reduce_sum(y_true * y_pred_normalized, axis=-1)
    # 限制点积范围在[-1,1],避免acos出现数值错误
    clip_dot = tf.clip_by_value(dot_product, -1.0, 1.0)
    # 计算每个时间步的损失
    loss_per_step = tf.square(2 * tf.math.acos(clip_dot))
    # 先对时间步求平均,再对batch求平均得到最终损失
    return tf.reduce_mean(loss_per_step)

这里的关键改进:

  • 用axis=-1指定对四元数维度求范数,keepdims=True保证形状匹配,能直接做除法
  • 用tf.clip_by_value避免acos输入超出有效范围,防止NaN
  • 去掉Python循环,改用TensorFlow原生张量操作,效率更高且符合计算图模式要求

内容的提问来源于stack exchange,提问作者Arman Asgharpoor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 21:15:06