TensorFlow训练CNN模型保存后加载失效问题求助
嘿,我之前也踩过类似的坑,咱们一步步来排查和解决这个问题:
1. 最常见的原因:图像预处理不一致
训练模型时你肯定对输入图像做了标准化、尺寸调整这类预处理操作,但预测时如果没严格复刻这些步骤,输入数据的分布和训练时完全不同,模型自然会像“没训练过”一样输出乱结果。
比如训练时你可能写了这样的预处理代码:
def train_preprocess(img): # 调整到训练时的输入尺寸 img = tf.image.resize(img, (224, 224)) # 归一化到0-1区间 img = img / 255.0 # 可能还有其他操作,比如通道转换(注意:不要在预测时用随机数据增强!) return img
那预测时必须完全复用同样的逻辑,只保留确定性的预处理(去掉训练时的随机翻转、裁剪等增强操作):
def predict_preprocess(img_path): img = tf.keras.preprocessing.image.load_img(img_path, target_size=(224, 224)) img_array = tf.keras.preprocessing.image.img_to_array(img) # 增加批量维度(模型默认接受批量输入) img_array = tf.expand_dims(img_array, axis=0) # 和训练时一致的归一化 img_array = img_array / 255.0 return img_array
重点要确认:尺寸、归一化方式、通道顺序(比如是RGB还是BGR)是否和训练时完全匹配。
2. 模型加载时遗漏自定义组件
如果你的CNN模型里用到了自定义层、自定义损失函数或者自定义指标,直接用tf.keras.models.load_model('example.h5')加载时,TensorFlow找不到这些自定义代码的定义,会导致模型加载不完整(相当于初始化了一个新的空模型)。
解决办法是加载时通过custom_objects参数指定这些自定义组件:
# 先导入你的自定义层/损失函数 from my_custom_modules import MyCustomConvLayer, my_focal_loss # 加载时传入custom_objects model = tf.keras.models.load_model( 'example.h5', custom_objects={'MyCustomConvLayer': MyCustomConvLayer, 'my_focal_loss': my_focal_loss} )
你可以检查一下训练代码里有没有自定义的组件,有的话一定要在加载时传入。
3. 模型文件损坏
下载example.h5文件时可能因为网络中断、存储问题导致文件不完整,加载后的模型权重和训练完成时的完全不一致。
你可以做两个验证:
- 对比云端(比如Colab)和本地的
example.h5文件大小,如果差距很大,说明下载出错,重新下载; - 训练完成后,打印某一层的权重均值(比如
print(model.layers[0].get_weights()[0].mean())),加载本地模型后再打印同一层的权重均值,如果数值完全不同,说明文件损坏,重新保存并下载。
4. TensorFlow版本不兼容
训练模型用的TensorFlow版本和Flask后端的版本差异过大(比如一个是2.10,一个是2.20),可能会导致h5模型的权重加载异常。
解决办法是确保两边使用完全相同的TensorFlow版本,比如训练时用pip install tensorflow==2.15.0,Flask后端也安装同一个版本:
pip install tensorflow==2.15.0
5. 预测输入形状不匹配
训练时模型的输入形状比如是(224, 224, 3),但预测时传入的图像形状不对(比如尺寸是(100,100,3),或者没有批量维度),模型可能自动调整但输出错误结果。
确保预测时的输入形状和训练时一致:
- 用
tf.image.resize把图像调整到训练时的目标尺寸; - 用
tf.expand_dims增加批量维度(因为模型默认接受批量输入,形状为(batch_size, height, width, channels))。
内容的提问来源于stack exchange,提问作者user12498862

