Keras预测方法结果不一致:GPU与CPU运行差异问询
Keras预测方法在GPU与CPU上的结果差异问题
问题说明
原本认为Keras的predict()、predict_on_batch()、predict_step()以及直接调用模型(model(x, training=False)即__call__())这四种方法输出结果应该完全一致,仅批量处理效率有区别。但在图像超分辨率任务中,P100 GPU上predict()/predict_on_batch()与predict_step()/__call__()结果差异明显,CPU上四种方法结果则完全一致。
测试代码
for lowres, _ in val.take(1): # 随机裁剪低分辨率图像用于超分 lowres = tf.image.random_crop(lowres, (150, 150, 3)) # uint8 # 添加批量维度 model_inputs = tf.expand_dims(lowres, axis=0) # (1, 150, 150, 3), uint8 # 转换为float32类型输入模型 model_inputs = tf.cast(model_inputs, tf.float32) # float32 preds = model.predict_on_batch(model_inputs) min_val = tf.reduce_min(preds).numpy() max_val = tf.reduce_max(preds).numpy() print("Min value: ", min_val) print("Max value: ", max_val) preds = model.predict(model_inputs) min_val = tf.reduce_min(preds).numpy() max_val = tf.reduce_max(preds).numpy() print("Min value: ", min_val) print("Max value: ", max_val) preds = model.predict_step(model_inputs) min_val = tf.reduce_min(preds).numpy() max_val = tf.reduce_max(preds).numpy() print("Min value: ", min_val) print("Max value: ", max_val) preds = model(model_inputs, training=False) # __call__() min_val = tf.reduce_min(preds).numpy() max_val = tf.reduce_max(preds).numpy() print("Min value: ", min_val) print("Max value: ", max_val)
输出结果
Min value: -6003.622 Max value: 5802.6826 Min value: -6003.622 Max value: 5802.6826 Min value: -53.7696 Max value: 315.1499 Min value: -53.7696 Max value: 315.1499
模型详情
模型仅包含Conv2D、Add、tf.nn.depth_to_space(像素洗牌)和Rescaling层,无BatchNorm或Dropout这类依赖训练模式的层,未使用子类化或重写方法,仅通过keras.Model(inputs, outputs)构建。其中predict_step()和__call__()的输出符合预期。
差异原因
- 执行模式与图优化差异
predict()和predict_on_batch()默认触发TensorFlow的静态图执行模式,GPU上会进行算子融合、精度优化等图转换操作;而predict_step()和直接调用__call__()默认使用动态图(Eager Execution)模式。两种模式下,部分算子的计算路径或精度处理可能不同,比如Rescaling层在静态图中可能被融合到卷积算子里,动态图中则单独执行,累积浮点误差被放大后导致结果偏差。
- GPU并行计算的异步特性
- GPU的并行调度机制会让算子异步执行,
predict()系列方法的内存分配、任务调度策略与动态图模式不同,硬件层面的浮点运算精度限制会进一步放大这种差异,而CPU的计算并行度低,误差不容易显现。
- GPU的并行调度机制会让算子异步执行,
- 参数读取与张量存储差异
- 静态图模式下会对模型参数的读取方式做优化,动态图则实时读取参数,虽然参数值本身一致,但GPU张量的存储和读取过程中可能存在细微的精度损失,累积后导致结果不同。
解决建议
- 统一执行模式:用
tf.function装饰predict_step或直接调用的逻辑,将动态图转为静态图;或者关闭predict()的图优化(通过设置相关配置),确保所有方法使用相同的执行路径。 - 检查
Rescaling层逻辑:确认归一化/缩放操作在所有模式下的计算逻辑完全一致,避免图优化改变计算顺序。 - 提升浮点精度:尝试将模型计算切换为
tf.float64类型,看差异是否缩小,验证是否由浮点精度累积导致。
内容的提问来源于stack exchange,提问作者while1
相关产品推荐
相关产品推荐

