3. 图像分类模型部署

图像分类模型部署 学习卡片

任务目标

本案例将完成MobileNetV2图像分类模型的端侧部署闭环:将Keras预训练模型转换为TensorFlow Lite格式,并在Python环境中模拟端侧推理,对单张输入图片输出Top-1类别标签与置信度。转换后的.tflite文件可直接用于Android/iOS等端侧集成。

环境依赖

  • TensorFlow ≥ 2.6(含TFLite Converter与Interpreter)
  • NumPy、Pillow(图片预处理)
  • ImageNet类别标签文件(imagenet_labels.txt,1000行,每行一个类别名)

完整实现代码

import numpy as np
from PIL import Image
import tensorflow as tf

# ========== 1. 转换模型 ==========
def convert_mobilenetv2_to_tflite(save_path="mobilenet_v2.tflite"):
    # 加载Keras预训练模型(含ImageNet权重)
    model = tf.keras.applications.MobileNetV2(
        weights="imagenet", input_shape=(224, 224, 3))
    
    # 转换为TFLite(使用默认float32精度)
    converter = tf.lite.TFLiteConverter.from_keras_model(model)
    tflite_model = converter.convert()
    
    with open(save_path, "wb") as f:
        f.write(tflite_model)
    print(f"模型已保存: {save_path}")
    return save_path

# ========== 2. 图片预处理 ==========
def preprocess_image(image_path, target_size=(224, 224)):
    img = Image.open(image_path).convert("RGB")
    img = img.resize(target_size)
    # MobileNetV2的预处理:像素归一化到[-1, 1]
    img_array = np.array(img, dtype=np.float32)
    img_array = (img_array / 127.5) - 1.0
    # 增加batch维度: (1, 224, 224, 3)
    return np.expand_dims(img_array, axis=0)

# ========== 3. TFLite推理 ==========
def tflite_inference(tflite_path, image_path, label_path):
    # 加载标签
    with open(label_path, "r") as f:
        labels = [line.strip() for line in f.readlines()]
    
    # 初始化解释器
    interpreter = tf.lite.Interpreter(model_path=tflite_path)
    interpreter.allocate_tensors()
    
    input_details = interpreter.get_input_details()
    output_details = interpreter.get_output_details()
    
    # 输入数据
    input_data = preprocess_image(image_path)
    interpreter.set_tensor(input_details[0]["index"], input_data)
    interpreter.invoke()
    
    # 输出处理
    output_data = interpreter.get_tensor(output_details[0]["index"])
    scores = np.squeeze(output_data)  # 去掉batch维度
    top_idx = np.argmax(scores)
    confidence = float(scores[top_idx])
    
    # softmax归一化到0~1(TFLite输出为logits)
    exp_scores = np.exp(scores - np.max(scores))
    probs = exp_scores / np.sum(exp_scores)
    confidence = float(probs[top_idx])
    
    return labels[top_idx], confidence

# ========== 4. 执行入口 ==========
if __name__ == "__main__":
    # 转换模型(首次运行需下载权重,约14MB)
    tflite_path = convert_mobilenetv2_to_tflite()
    
    # 推理示例(请替换为实际图片路径)
    result = tflite_inference(
        tflite_path=tflite_path,
        image_path="test_cat.jpg",
        label_path="imagenet_labels.txt"
    )
    print(f"Top-1类别: {result[0]}, 置信度: {result[1]:.4f}")

运行与验证

  1. 准备标签文件:下载ImageNet1000类标签,保存为imagenet_labels.txt(每行一个类别名,顺序与模型输出层对应)。
  2. 准备测试图片:任选一张包含明确物体的图片(如猫、狗、汽车),命名为test_cat.jpg放入脚本同目录。
  3. 执行脚本:python tflite_deploy.py。首次运行会自动下载MobileNetV2权重,转换过程约需10~30秒。
  4. 通过标准:控制台输出模型已保存: mobilenet_v2.tflite,且推理结果中Top-1类别与图片内容一致、置信度大于0.5。例如输入猫图片预期输出Top-1类别: tabby cat或Egyptian cat等猫科类别。

关键说明

  • 转换得到的mobilenet_v2.tflite约14MB,可直接集成到Android(Java/Kotlin)或iOS(Swift)项目,使用TFLite Runtime API加载推理。
  • 本案例使用float32精度模型,如需进一步压缩可设置converter.optimizations = [tf.lite.Optimize.DEFAULT]启用动态范围量化,模型可缩减至约4MB,但精度略有下降。
  • 端侧部署时图片预处理(缩放、归一化)需在应用层完成,与preprocess_image()逻辑保持一致。