3DCNN转LSTM实现唇读模型:报错解决后仍存结构转换疑惑
3DCNN+LSTM唇读模型:报错解决与跨层数据传递原理
问题场景与报错
学习循环神经网络时,尝试搭建3DCNN+LSTM的自动唇读模型,采用Kaggle上的代码:
model = Sequential() # 1st layer group model.add(Conv3D(32, (3, 3, 3), strides = 1, input_shape=(22, 100, 100, 1), activation='relu', padding='valid')) model.add(MaxPooling3D(pool_size=(2, 2, 2), strides=2)) model.add(Conv3D(64, (3, 3, 3), activation='relu', strides=1)) model.add(MaxPooling3D(pool_size=(2, 2, 2), strides=2)) model.add(Conv3D(128, (3, 3, 3), activation='relu', strides=1)) model.add(MaxPooling3D(pool_size=(2, 2, 2), strides=2)) shape = model.get_output_shape_at(0) model.add(Reshape((shape[-1],shape[1]*shape[2]*shape[3]))) # LSTMS - Recurrent Network Layer model.add(LSTM(32, return_sequences=True)) model.add(Dropout(.5)) model.add((Flatten())) # # FC layers group model.add(Dense(2048, activation='relu')) model.add(Dropout(.5)) model.add(Dense(1024, activation='relu')) model.add(Dropout(.5)) model.add(Dense(10, activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer='Adam', metrics=['accuracy']) model.summary()
运行时出现报错:
11 model.add(MaxPooling3D(pool_size=(2, 2, 2), strides=2)) 12 ---> 13 shape = model.get_output_shape_at(0) 14 model.add(Reshape((shape[-1],shape[1]*shape[2]*shape[3]))) 15 RuntimeError: The layer sequential_2 has never been called and thus has no defined output shape.
将代码修改为以下内容后,错误解决:
shape = model.layers[-1].output_shape # shape = model.get_output_shape_at(0)
错误原因解析
model.get_output_shape_at(0)需要模型已经接收过输入数据(即被调用过),才能生成实际的输出形状。在模型构建阶段还未传入数据,因此无法获取形状,触发报错。model.layers[-1].output_shape是通过层的定义(如卷积核大小、步长、池化规则)推导出来的理论输出形状,不需要模型实际运行,因此在构建阶段即可正常获取。
3DCNN输出转LSTM输入的核心逻辑
唇读模型中,3DCNN负责提取视频序列的时空特征,LSTM负责处理序列的时间依赖关系,两者的输入输出格式不同,需要通过Reshape层完成适配:
1. 3DCNN的输出格式
3DCNN处理的是视频数据,输入形状为(帧数, 图像高度, 图像宽度, 通道数)(对应代码中的input_shape=(22,100,100,1),22是视频帧数)。经过多轮卷积+池化后,最后一层输出是5维张量:(批量大小, 处理后的帧数, 特征图高度, 特征图宽度, 通道数)
2. LSTM的输入要求
LSTM需要3维张量作为输入:(批量大小, 时间步长, 特征向量维度)
其中时间步长对应序列的连续单元(唇读场景下通常是视频帧数),每个时间步需要传入一个一维的特征向量。
3. Reshape层的作用
通过model.layers[-1].output_shape获取3DCNN最后一层的输出形状后,代码做了两个计算:
shape[-1]:取3DCNN输出的通道数shape[1]*shape[2]*shape[3]:计算每个通道对应的空间特征总维度(处理后的帧数×特征图高度×特征图宽度)
Reshape层将5维的时空特征张量转换为3维张量,让LSTM可以按通道维度作为"时间步长",每个时间步对应一组展平后的空间特征,从而完成3DCNN到LSTM的数据传递。
注:从唇读的逻辑来看,更合理的转换应该是将帧数作为时间步长,此时Reshape参数应为
(shape[1], shape[2]*shape[3]*shape[4]),原代码的参数可能存在维度顺序的笔误,但核心适配逻辑是一致的——将空间特征展平为一维向量,匹配LSTM的输入格式。
内容的提问来源于stack exchange,提问作者Deepak Pawade
相关产品推荐
相关产品推荐

