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

Keras模型访问Input层元素创建序列掩码报错解决方案

问题背景

我基于Keras TensorFlow编译训练用于回归任务的RNN模型,采用函数式API完成模型定义。
模型共设置2个不同输入:

  • 第一个输入原代码命名为input,为训练数据,数组形状为(TOTAL_TRAIN_DATA, SEQUENCE_LENGTH, NUM_OF_FEATURES) = (15000,1564,2),对应15000个视频每帧的2项特征;由于原始视频帧长不统一,所有视频通过重复最后一行的方式填充至SEQUENCE_LENGTH=1564帧。
  • 第二个输入lengths为形状(15000,)的向量,存储每个视频的原始有效帧长,示例为:lengths = [317 215 576 ... 1245 213 654]。

原实现逻辑为:拼接GRU层输出的所有特征,再乘以对应掩码,仅保留原始视频有效长度对应的特征值。具体来说,GRU层输出形状为(batch_size, SEQUENCE_LENGTH, GRU_UNITS) = (50,1564,256),经Flatten()层重塑为(50, 1564*256),需要创建形状为(50,1564*256)的掩码数组,数组每一行对应当前batch内一个样本的掩码规则。

原实现的掩码函数代码:

def mask_creator(lengths,number_of_GRU_features=256,max_pad_len=1564):
  
    masks = np.zeros((lengths.shape[0],number_of_GRU_features*max_pad_len))

    for i, length in enumerate(lengths):   
      masks[i,:] = np.concatenate((np.ones([length * number_of_GRU_features, ]),
                                  np.zeros([(max_pad_len - length) * number_of_GRU_features, ])), axis=0)          
    return masks

原模型搭建代码:

#tf.compat.v1.enable_eager_execution()
#tf.data.experimental.enable_debug_mode()
#tf.config.run_functions_eagerly(True)

GRU_UNITS = 256
SEQUENCE_LENGTH = 1564
NUM_OF_FEATURES = 2

input = tf.keras.layers.Input(shape=(SEQUENCE_LENGTH,NUM_OF_FEATURES))
lengths = tf.keras.layers.Input(shape=())  
masks = tf.keras.layers.Lambda(mask_creator, name="mask_function")(lengths)
gru = tf.keras.layers.GRU(GRU_UNITS , return_sequences=True)(input)
flat = tf.keras.layers.Flatten()(gru)
multiplied = tf.keras.layers.Multiply()([flat, masks])
outputs = tf.keras.layers.Dense(7, name="pred")(multiplied )

# Compile
model = tf.keras.Model([input, lengths], outputs, name="RNN")
# optimizer = tf.keras.optimizers.Adam(learning_rate=1e-2)


#Compile keras model
model.compile(optimizer='adam',
              loss='mean_squared_error',
              metrics=['MeanSquaredError', 'MeanAbsoluteError']),
              #run_eagerly=True)

model.summary()
报错现象

为生成掩码,需要访问作为模型输入传入的lengths向量(定义语句为lengths = tf.keras.layers.Input(shape=())),因此定义Lambda层(masks=tf.keras.layers.Lambda(mask_creator, name="mask_function")(lengths))调用mask_creator函数生成掩码。按照预期,lengths应为形状(batch_size,)=(50,)的张量,但始终无法正常访问lengths的元素,抛出如下类型错误:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-30-8e31522694ee> in <module>()
      9 input = tf.keras.layers.Input(shape=(SEQUENCE_LENGTH,FEATURES))
     10 lengths = tf.keras.layers.Input(shape=())
---> 11 masks = tf.keras.layers.Lambda(mask_creator, name="mask_function")(lengths)
     12 gru = tf.keras.layers.GRU(GRU_UNITS , return_sequences=True)(input)
     13 flat = tf.keras.layers.Flatten()(gru)

1 frames
<ipython-input-19-9490084e8336> in mask_creator(lengths, number_of_GRU_features, max_pad_len)
      1 def mask_creator(lengths,number_of_GRU_features=256,max_pad_len=1564):
      2 
----> 3     masks = np.zeros((lengths.shape[0],number_of_GRU_features*max_pad_len))
      4 
      5     for i, length in enumerate(lengths):

TypeError: Exception encountered when calling layer "mask_function" (type Lambda).

'NoneType' object cannot be interpreted as an integer

Call arguments received:
  • inputs=tf.Tensor(shape=(None,), dtype=float32)
  • mask=None
  • training=None
报错原因
  • 模型构建阶段,Keras所有输入张量的batch维度都是动态值None,代表batch大小不固定,不会提前绑定固定值。原代码直接取lengths.shape[0]传给np.zeros作为维度参数,拿到的是None,自然无法被识别为整数维度,触发类型错误。
  • Lambda层内混用numpy操作与TensorFlow张量:传入Lambda层的lengths是TensorFlow张量,不是numpy数组,直接用enumerate遍历、调用numpy的数组初始化/拼接接口,即便解决batch维度问题,在TensorFlow默认的图执行模式下也无法正常运行。
    补充:原代码将输入层命名为input,会和Python内置的input()函数重名,存在潜在冲突风险。
修复方案

将掩码生成逻辑全部替换为TensorFlow原生操作,支持动态batch维度,可正常在图模式下运行,无需开启eager执行模式。

修复后的掩码函数:

import tensorflow as tf
import numpy as np

def mask_creator(lengths, number_of_GRU_features=256, max_pad_len=1564):
    # 读取动态batch大小
    batch_size = tf.shape(lengths)[0]
    # 生成帧位置索引,形状为(1, max_pad_len)
    frame_pos = tf.range(max_pad_len, dtype=tf.float32)[None, :]
    # 生成帧级掩码:位置索引小于有效帧长的位置为1,否则为0,形状(batch_size, max_pad_len)
    frame_mask = tf.cast(frame_pos < lengths[:, None], dtype=tf.float32)
    # 将掩码扩展到GRU输出的特征维度,再展平为与Flatten层输出一致的形状
    feature_mask = tf.tile(frame_mask[:, :, None], [1, 1, number_of_GRU_features])
    flat_mask = tf.reshape(feature_mask, [batch_size, max_pad_len * number_of_GRU_features])
    return flat_mask

修复后的模型构建代码(修正输入层命名问题,指定帧长输入的类型为整数):

GRU_UNITS = 256
SEQUENCE_LENGTH = 1564
NUM_OF_FEATURES = 2

# 修改输入层命名,避免与内置函数冲突
seq_input = tf.keras.layers.Input(shape=(SEQUENCE_LENGTH,NUM_OF_FEATURES))
len_input = tf.keras.layers.Input(shape=(), dtype=tf.int32)  

masks = tf.keras.layers.Lambda(mask_creator, name="mask_function")(len_input)
gru = tf.keras.layers.GRU(GRU_UNITS , return_sequences=True)(seq_input)
flat = tf.keras.layers.Flatten()(gru)
multiplied = tf.keras.layers.Multiply()([flat, masks])
outputs = tf.keras.layers.Dense(7, name="pred")(multiplied )

# 编译模型
model = tf.keras.Model([seq_input, len_input], outputs, name="RNN")
model.compile(optimizer='adam',
              loss='mean_squared_error',
              metrics=['MeanSquaredError', 'MeanAbsoluteError'])

model.summary()

优化提示:GRU层原生支持mask输入,可直接传入帧级掩码让GRU自动跳过填充帧的计算,相比当前先计算所有填充帧输出再乘0清零的写法,能大幅降低计算量和内存占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 21:33:29