LSTMBlockFusedCell测试误差比LSTMCell高6%?是特性还是Dropout实现错误?
先直接回应你的问题:LSTMBlockFusedCell和LSTMCell之间出现一定的精度差异是可能的,但你遇到的6%误差升高主要是代码实现中的Dropout应用不一致导致的,而非Fused Cell本身的固有问题。下面我们一步步拆解分析:
一、Fused Cell与标准LSTMCell的性能差异是否正常?
- 速度差异完全正常:
LSTMBlockFusedCell是TensorFlow针对LSTM的融合优化实现(尤其是在GPU上,会使用专门的CUDA核),它把LSTM的多个运算步骤合并成单个操作,大幅减少了显存IO和运算开销,所以训练时长从14.5小时降到3.6小时是符合预期的优化效果。 - 精度差异的合理范围:理论上,只要实现细节对齐,两者的精度应该非常接近。但由于Fused Cell在数值计算、权重初始化的细微实现差异,可能会出现小幅度的精度波动(比如1-2%),但你遇到的6%差异明显超出了正常波动范围,大概率是代码实现有误。
二、你的Model_blockfused代码中的关键问题
最核心的问题是Dropout的应用逻辑和原模型不一致:
原模型(Model_Orig)的Dropout逻辑
原模型使用DropoutWrapper包裹每个LSTMCell,这意味着每一层LSTM的输出都会经过Dropout:
for iiLyr in list(range(3)): cell_iiLyr = tf.nn.rnn_cell.LSTMCell(...) # 每个LSTM层的输出都会应用Dropout dropcells.append(tf.nn.rnn_cell.DropoutWrapper(cell=cell_iiLyr, output_keep_prob=keep_prob))
新模型(Model_blockfused)的Dropout逻辑
你只在输入层做了一次Dropout,后续的2个堆叠LSTM层之间完全没有Dropout:
# 仅输入层做了Dropout dropout_input_TSs_TimeMajor = tf.layers.dropout(...) # 后续堆叠层的输出没有任何Dropout处理 for iiLyr in list(range(3)): cur_fw_BFcell_obj = tf.contrib.rnn.LSTMBlockFusedCell(...) fw_out_TM, fw_state = cur_fw_BFcell_obj(...) # 这里没有对fw_out_TM应用Dropout!
这种差异会导致新模型的模型容量更大,更容易过拟合,最终表现为测试误差升高。
其他需要检查的细节
Sequence Length的形状:原模型中
sequence_length=length的shape是[#batches, 1],但TensorFlow的RNN API要求sequence_length是一维张量(shape=[#batches])。虽然原模型可能自动做了降维,但新模型中需要确保length是一维的,否则可能导致反向序列的处理出错。并行迭代数(parallel_iterations):原模型设置了
parallel_iterations=512,而LSTMBlockFusedCell的__call__方法也支持这个参数,建议在调用时添加该参数,确保并行计算逻辑一致:
fw_out_TM, fw_state = cur_fw_BFcell_obj( dropout_input_TSs_TimeMajor, dtype=tf.float32, sequence_length=length, parallel_iterations=512 # 和原模型对齐 )
- Dropout的training参数:确保
Flg_training在测试阶段被正确设置为False,否则测试时还会应用Dropout,导致结果偏差。
三、修正后的Model_blockfused代码示例
针对Dropout的问题,你需要在每一层LSTM的输出后添加Dropout,对齐原模型的逻辑:
LSTM_CELL_SIZE = 200 keep_prob = 0.90 Flg_training = True input_TSs_TimeMajor = tf.transpose(Orig_input_TSs, perm=[1,0,2]) # 输入层Dropout dropout_input_TSs_TimeMajor = tf.layers.dropout( input_TSs_TimeMajor, rate=1.0 - keep_prob, training=Flg_training ) for iiLyr in list(range(3)): cur_fw_BFcell_obj = tf.contrib.rnn.LSTMBlockFusedCell(num_units=LSTM_CELL_SIZE) cur_bw_BFcell_obj = tf.contrib.rnn.TimeReversedFusedRNN(cur_fw_BFcell_obj) if (iiLyr == 0): fw_out_TM, fw_state = cur_fw_BFcell_obj( dropout_input_TSs_TimeMajor, dtype=tf.float32, sequence_length=length, parallel_iterations=512 ) bw_out_TM, bw_state = cur_bw_BFcell_obj( dropout_input_TSs_TimeMajor, dtype=tf.float32, sequence_length=length, parallel_iterations=512 ) else: fw_out_TM, fw_state = cur_fw_BFcell_obj( fw_out_TM, dtype=tf.float32, sequence_length=length, parallel_iterations=512 ) bw_out_TM, bw_state = cur_bw_BFcell_obj( bw_out_TM, dtype=tf.float32, sequence_length=length, parallel_iterations=512 ) # 每一层LSTM输出后添加Dropout,和原模型对齐 fw_out_TM = tf.layers.dropout(fw_out_TM, rate=1.0 - keep_prob, training=Flg_training) bw_out_TM = tf.layers.dropout(bw_out_TM, rate=1.0 - keep_prob, training=Flg_training) # 获取最后一层状态 c_fw_lstLyr, h_fw_lstLyr = fw_state c_bw_lstLyr, h_bw_lstLyr = bw_state
四、预期结果
修正Dropout逻辑后,新模型的测试误差应该会接近原模型的2.89,同时保持3.6小时的训练速度优势。如果还有微小差异,可能是Fused Cell和标准LSTMCell在数值计算上的细微差别,这属于正常现象。
内容的提问来源于stack exchange,提问作者Maosi Chen

