TensorFlow中创建多Conv3DLSTMCell层报错的技术求助
我尝试搭建一个包含多个Conv3DLSTMCell层的模型,运行了以下代码:
conv1, state1 = conv3d('conv1', _X, [8,112,112,1], [3,3,3], 64) pool1 = max_pool('pool1', conv1, k=1) conv2, state2 = conv3d('conv2', pool1, [8, 56, 56, 64], [3, 3, 3], 128) pool2 = max_pool('pool2', conv2, k=2)
我的conv3d函数定义如下:
def conv3d(myname, l_input, shape, kernel, outchan): cell = contrib_rnn_cell.Conv3DLSTMCell(input_shape=shape, output_channels=outchan) hidden = cell.zero_state(array_ops.shape(l_input)[0], dtypes.float32) output, state = cell(l_input, hidden) print(output.shape) return output, state
代码里conv1和pool1运行正常,但到conv2层就报错了,报错信息如下:
Traceback (most recent call last):
File "conv3dlstm.py", line 272, in
run(16)
File "conv3dlstm.py", line 199, in run
biases)
File "/home/user/projects/model_conv3dlstm.py", line 47, in inference_c3d
conv2, state2 = conv3d('conv2', pool1, [8, 56, 56, 64], [3, 3, 3], 128)
File "/home/user/projects/model_conv3dlstm.py", line 32, in conv3d
output, state = cell(l_input, hidden)
File "/usr/local/lib/python2.7/dist-packages/tensorflow/python/ops/rnn_cell_impl.py", line 190, in call
return super(RNNCell, self).call(inputs, state)
File "/usr/local/lib/python2.7/dist-packages/tensorflow/python/layers/base.py", line 696, in call
outputs = self.call(inputs, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/tensorflow/contrib/rnn/python/ops/rnn_cell.py", line 2110, in call
4 * s...
问题分析与解决思路
嘿,我帮你梳理了下这个问题,核心问题出在Conv3DLSTMCell的状态传递和维度匹配上——毕竟Conv3DLSTM是循环结构,和普通Conv3D不一样,不能每次都从头初始化状态。
具体问题点:
- 错误的状态初始化:你在每个
conv3d函数里都重新创建了零状态hidden = cell.zero_state(...),但第二层的输入是第一层池化后的结果(通道数64),而你初始化的第二层状态是对应输出通道128的,这直接导致输入和状态的维度不兼容,触发报错。 - 手动传参的shape可能不准:你手动传入的
shape参数可能和pool1实际的张量维度不匹配,池化后的维度最好从张量本身自动获取,避免手动写错。
修正方案:
首先修改你的conv3d函数,让它支持传递上一层的状态,而不是每次都初始化零状态:
def conv3d(myname, l_input, prev_state, kernel, outchan): # 从输入张量自动获取shape,不用手动传,避免出错 input_shape = l_input.get_shape().as_list()[1:] # 格式是[time_steps, height, width, channels] # 初始化Conv3DLSTMCell时,input_shape要对应输入的空间维度+输出通道数 cell = contrib_rnn_cell.Conv3DLSTMCell(input_shape=input_shape[:-1] + [outchan], output_channels=outchan) # 如果是第一层,没有前序状态就初始化零状态;否则直接用传入的前序状态 if prev_state is None: hidden = cell.zero_state(array_ops.shape(l_input)[0], dtypes.float32) else: hidden = prev_state output, state = cell(l_input, hidden) print(output.shape) return output, state
然后修改调用代码,把上一层的状态传递给下一层:
# 第一层没有前序状态,传None conv1, state1 = conv3d('conv1', _X, None, [3,3,3], 64) pool1 = max_pool('pool1', conv1, k=1) # 第二层传入第一层的状态state1 conv2, state2 = conv3d('conv2', pool1, state1, [3, 3, 3], 128) pool2 = max_pool('pool2', conv2, k=2)
另外,你可以先打印pool1.get_shape().as_list()确认一下池化后的维度是不是[batch_size, 8, 56, 56, 64],确保和你预期的一致。如果报错信息没显示完整,修正后还有问题的话,可以把完整的报错内容贴出来,不过按这个思路改应该能解决大部分问题。
内容的提问来源于stack exchange,提问作者maximus

