Keras 2.10.0如何仅保存模型用于推理并隐藏细节?
Keras 2.10.0 + TensorFlow 2.10.1 推理模型保存与部署方案
一、隐藏模型细节的保存方法
由于Keras 3的export()方法不可用,在2.10版本中可以通过以下两种方式保存仅用于推理的模型,避免暴露架构和训练超参数:
1. 导出为冻结计算图(.pb格式)
SavedModel格式配合冻结图转换,能彻底隐藏模型架构细节,仅保留推理所需的计算逻辑和权重:
- 训练完成后,先保存为SavedModel格式:
model.save("temp_saved_model") - 转换为冻结图,代码示例:
冻结后的import tensorflow as tf def freeze_saved_model(saved_model_dir, output_pb_path="frozen_inference_model.pb"): # 兼容TF1.x的API加载SavedModel with tf.compat.v1.Session(graph=tf.Graph()) as sess: tf.compat.v1.saved_model.loader.load(sess, [tf.saved_model.SERVING], saved_model_dir) # 替换为你的模型输出层节点名(可通过TensorBoard查看) output_node_names = ["dense_1/Softmax"] # 将变量转换为常量,生成冻结图 frozen_graph = tf.compat.v1.graph_util.convert_variables_to_constants( sess, sess.graph.as_graph_def(), output_node_names ) # 保存冻结图 with tf.io.gfile.GFile(output_pb_path, "wb") as f: f.write(frozen_graph.SerializeToString()) freeze_saved_model("temp_saved_model").pb文件无法通过summary()查看架构,也不会包含训练超参数,仅支持推理。
2. 仅保存权重,自定义推理逻辑
只保存模型权重,部署时手动编写和原模型一致的推理前向传播代码,不暴露完整模型结构:
- 训练后仅保存权重:
model.save_weights("inference_weights.h5") - 部署时,编写不含训练细节的推理代码(需和原模型的层结构、顺序完全匹配):
部署时可以只封装推理函数,不对外暴露模型对象,避免用户查看架构。import tensorflow as tf # 仅构建推理所需的层结构,去掉训练相关配置(如Dropout的training参数) def build_inference_model(input_shape=(224,224,3), num_classes=2): inputs = tf.keras.Input(shape=input_shape) x = tf.keras.layers.Conv2D(32, (3,3), activation="relu")(inputs) x = tf.keras.layers.MaxPooling2D()(x) x = tf.keras.layers.Flatten()(x) outputs = tf.keras.layers.Dense(num_classes, activation="softmax")(x) model = tf.keras.Model(inputs=inputs, outputs=outputs) return model # 加载权重 inference_model = build_inference_model() inference_model.load_weights("inference_weights.h5")
二、推理时的数据传入流程
推理数据的处理必须和训练阶段完全一致,否则会导致预测结果偏差:
- 预处理数据:按照训练时的规则处理输入,比如图像的尺寸、归一化方式:
import numpy as np
def preprocess_image(image_path, target_size=(224,224)):
img = tf.keras.preprocessing.image.load_img(image_path, target_size=target_size)
img_array = tf.keras.preprocessing.image.img_to_array(img)
img_array = np.expand_dims(img_array, axis=0) # 增加batch维度
img_array /= 255.0 # 和训练时的归一化逻辑一致
return img_array
2. **执行推理**: - 冻结图加载与推理: ```python def load_frozen_graph(pb_path): with tf.io.gfile.GFile(pb_path, "rb") as f: graph_def = tf.compat.v1.GraphDef() graph_def.ParseFromString(f.read()) with tf.Graph().as_default() as graph: tf.import_graph_def(graph_def, name="") sess = tf.compat.v1.Session(graph=graph) input_tensor = graph.get_tensor_by_name("input_1:0") # 替换为你的输入节点名 output_tensor = graph.get_tensor_by_name("dense_1/Softmax:0") # 替换为输出节点名 return sess, input_tensor, output_tensor sess, input_tensor, output_tensor = load_frozen_graph("frozen_inference_model.pb") input_data = preprocess_image("test.jpg") prediction = sess.run(output_tensor, feed_dict={input_tensor: input_data}) ``` - 权重加载后的推理: ```python input_data = preprocess_image("test.jpg") prediction = inference_model.predict(input_data) ``` 3. **后处理结果**:根据模型输出解析结果,比如分类模型取概率最高的类别: ```python class_names = ["猫", "狗"] # 对应训练时的类别顺序 predicted_class = class_names[np.argmax(prediction)]
内容的提问来源于stack exchange,提问作者CuriousRabbit
相关产品推荐
相关产品推荐

