简介

MobileNetV2 是由谷歌团队于 2018 年提出的一种轻量级卷积神经网络模型,是 MobileNetV1 的改进版本,旨在在保持准确性的前提下,极大地减少模型的参数数量和计算复杂度,从而适用于移动设备和嵌入式系统等资源受限的场景。

为什么使用MobileNetV2模型?

  • 轻量级模型,运行速度快

  • 在ImageNet数据集上预训练,识别准确度高

  • 适合移动设备和普通电脑使用

目标

使用 python 和深度学习框架,利用 MobileNetV2 模型,完成猫图像的识别;最后完成网页端部署。

实现

环境配置

推荐虚拟环境

1
2
virtualenv venv
.\venv\Scripts\activate

创建 requirements.txt, pip install -r requirements.txt 安装相关依赖

1
2
3
4
tensorflow>=2.8.0
opencv-python>=4.5.5
numpy>=1.21.0
pillow>=8.3.0

主程序编写

调包

1
2
3
4
5
import tensorflow as tf
import cv2
import numpy as np
from PIL import Image
import os
  • tensorflow: 用于加载和使用预训练模型

  • cv2: 用于图像处理

  • numpy: 用于数组操作

  • PIL: 用于图像加载和预处理

创建加载模型函数

1
2
3
4
5
6
7
8
9
10
11
12
def load_model():
"""
加载预训练的MobileNetV2模型

Returns:
model: 加载好的MobileNetV2模型
"""
print("开始加载模型...")
# 使用ImageNet预训练的MobileNetV2模型
model = tf.keras.applications.MobileNetV2(weights='imagenet')
#虽然ImageNet数据集本身不专门针对猫的识别,但其预训练的特征可以很好地迁移到猫狗分类等任务中
return model

创建图像预处理函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def  preprocess_image(image_path):
"""
预处理图片,使其符合模型输入要求

Args:
image_path: 图片文件路径

Returns:
processed_image: 预处理后的图片数组,形状为(1, 224, 224, 3)
"""
print("开始预处理图片...")
# 打开图片
img = Image.open(image_path)
print("图片打开成功")

# 调整图片大小为224x224,这是MobileNetV2的标准输入大小
img = img.resize((224, 224))
print("图片调整大小完成")

# 转换为numpy数组
img_array = np.array(img)
print("转换为numpy数组完成")

# 应用MobileNetV2的预处理,包括归一化和通道调整
img_array = tf.keras.applications.mobilenet_v2.preprocess_input(img_array)
print("预处理完成")

# 添加批次维度,因为模型需要批量输入
return np.expand_dims(img_array, axis=0)

创建猫检测函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def detect_cat(image_path, model, confidence_threshold=0.5):
"""
检测图片中是否有猫

Args:
image_path: 图片文件路径
model: 预训练的MobileNetV2模型
confidence_threshold: 置信度阈值,默认0.5

Returns:
tuple: (是否检测到猫, 检测结果描述)
"""
print(f"开始检测 {image_path}")
# 预处理图片
processed_image = preprocess_image(image_path)

# 使用模型进行预测
predictions = model.predict(processed_image)

# 解码预测结果,获取top5的预测类别
decoded_predictions = tf.keras.applications.mobilenet_v2.decode_predictions(predictions, top=5)[0]
print("解码预测结果完成\n\n")

# 定义猫的标签,这些是ImageNet数据集中猫的类别
cat_labels = ['tabby', 'tiger_cat', 'Persian_cat', 'Siamese_cat', 'Egyptian_cat']

# 检查预测结果中是否包含猫,并且置信度超过阈值
for _, label, prob in decoded_predictions:
if any(cat in label for cat in cat_labels) and prob >= confidence_threshold:
return True, f"检测到猫 ({label}, 置信度: {prob:.2f}) \n\n"

return False, "未检测到猫\n\n"

实现主函数

在实现主函数前,我创建了两个函数来分别处理单个文件和多个文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def detect_file(model, confidence=0.5):
image_path = input("请输入图片路径:")
print("\n\n")
try:
is_cat, result = detect_cat(image_path, model)
print(result)
except Exception as e:
print(f"错误: {str(e)}")

def detect_folder(model, confidence=0.5):
folder_path = input("请输入测试文件夹路径: ")
print("\n\n")
all_items = os.listdir(folder_path)

files = [folder_path+"\\"+ f for f in all_items if os.path.isfile(os.path.join(folder_path, f))]

for image_path in files:
try:
# 检测图片
is_cat, result = detect_cat(image_path, model)
print(result)
except Exception as e:
print(f"发生错误: {str(e)}")

def set_confidence():

#获取置信度阈值
try:
confidence = float(input("请输入置信度阈值(0-1之间,默认0.5): ") or 0.5)
if confidence < 0 or confidence > 1:
print("置信度必须在0-1之间,使用默认值0.5")
confidence = 0.5
except ValueError:
print("输入无效,使用默认值0.5")
confidence = 0.5
return confidence

注:置信度阈值决定了模型预测结果的可接受最低置信水平,即判断模型是否可靠。

串起来上面的函数,实现主函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def main():
"""
主函数,程序的入口点
"""
try:
# 加载模型
model = load_model()
print("模型加载完成")
except Exception as e:
print("模型加载失败\n",e)


confidence = set_confidence()

# detect_file(model)
detect_folder(model, confidence)

测试

先拿一张猫猫的图片来测试

image-20250412160307745

==》

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
开始加载模型...
2025-04-12 16:03:42.296507: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.
To enable the following instructions: SSE3 SSE4.1 SSE4.2 AVX AVX2 AVX512F AVX512_VNNI AVX512_BF16 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.
模型加载完成
请输入置信度阈值(0-1之间,默认0.5):
请输入图片路径:test\cat2.png



开始检测 test\cat2.png
开始预处理图片...
图片打开成功
图片调整大小完成
转换为numpy数组完成
预处理完成
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 448ms/step
解码预测结果完成


检测到猫 (Egyptian_cat, 置信度: 0.74)

image-20250412160604206

虽然检测出了猫,但是类别上非常错。

再检测一下人。

image-20250412160658029

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
模型加载完成
请输入置信度阈值(0-1之间,默认0.5):
请输入图片路径:test\human.png



开始检测 test\human.png
开始预处理图片...
图片打开成功
图片调整大小完成
转换为numpy数组完成
预处理完成
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 436ms/step
解码预测结果完成


未检测到猫

可以看出他基本特征还是能够提取的,再测试一组数据。

image-20250412163806643

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
模型加载完成
请输入置信度阈值(0-1之间,默认0.5): 0.3
请输入测试文件夹路径: test



开始检测 test\cat1.png
开始预处理图片...
图片打开成功
图片调整大小完成
转换为numpy数组完成
预处理完成
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 447ms/step
解码预测结果完成


未检测到猫


开始检测 test\cat2.png
开始预处理图片...
图片打开成功
图片调整大小完成
转换为numpy数组完成
预处理完成
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step
解码预测结果完成


检测到猫 (Egyptian_cat, 置信度: 0.74)


开始检测 test\cat3.png
开始预处理图片...
图片打开成功
图片调整大小完成
转换为numpy数组完成
预处理完成
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step
解码预测结果完成


未检测到猫


开始检测 test\cat4.png
开始预处理图片...
图片打开成功
图片调整大小完成
转换为numpy数组完成
预处理完成
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step
解码预测结果完成


检测到猫 (tabby, 置信度: 0.58)


开始检测 test\cat5.png
开始预处理图片...
图片打开成功
图片调整大小完成
转换为numpy数组完成
预处理完成
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 33ms/step
解码预测结果完成


检测到猫 (Egyptian_cat, 置信度: 0.33)


开始检测 test\human1.png
开始预处理图片...
图片打开成功
图片调整大小完成
转换为numpy数组完成
预处理完成
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 33ms/step
解码预测结果完成


未检测到猫


开始检测 test\human2.png
开始预处理图片...
图片打开成功
图片调整大小完成
转换为numpy数组完成
预处理完成
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step
解码预测结果完成


未检测到猫


开始检测 test\nono.png
开始预处理图片...
图片打开成功
图片调整大小完成
转换为numpy数组完成
预处理完成
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 33ms/step
解码预测结果完成


未检测到猫

预测效果,其实很差,但可以调整置信度。

微调和优化

概念介绍

  1. 模型微调(Fine-tuning):
  • 定义: 在预训练模型的基础上,使用特定任务的数据进行再训练。

  • 目的: 适应特定任务,提高模型在该任务上的表现。

  • 方法: 冻结部分层,只训练特定层,或者在整个模型上进行微调。

  1. 模型优化:
  • 定义: 通过调整模型结构、超参数等方式提高模型性能。

  • 目的: 提高模型的准确性、速度和效率。

  • 方法: 调整学习率、批次大小、使用正则化等。


实施:

  1. 数据准备
  • 收集更多数据: 获取更多与任务相关的数据。

  • 数据增强: 使用数据增强技术(如旋转、翻转、缩放)来增加数据多样性。

  1. 模型微调
  • 冻结层: 冻结预训练模型的前几层,只训练后面的全连接层。

  • 解冻层: 在初步训练后,解冻更多层进行微调。


这部分暂时不会,先留着。

网页开发

测试

image-20250412170318703

image-20250412170325684

用 cat2.png

image-20250412170430872

识别效果不好,只能调低置信度,测试 cat5.png

image-20250412170603565

只能先这样了。

最后简单美化一下前端。

image-20250412171941214

image-20250412171921724

主要代码如下

cat_detector.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
"""
猫识别程序
使用预训练的 模型来识别图片中是否包含猫
"""

import tensorflow as tf # 深度学习框架
import cv2 # 图像处理库
import numpy as np # 科学计算库
from PIL import Image # Python图像处理库
import os

#加载函数
def load_model():
"""
加载预训练的MobileNetV2模型

Returns:
model: 加载好的MobileNetV2模型
"""
print("开始加载模型...")
# 使用ImageNet预训练的MobileNetV2模型
model = tf.keras.applications.MobileNetV2(weights='imagenet')
return model

#图像预处理
def preprocess_image(image_path):
"""
预处理图片,使其符合模型输入要求

Args:
image_path: 图片文件路径

Returns:
processed_image: 预处理后的图片数组,形状为(1, 224, 224, 3)
"""
print("开始预处理图片...")
# 打开图片
img = Image.open(image_path)
print("图片打开成功")

# 调整图片大小为224x224,这是MobileNetV2的标准输入大小
img = img.resize((224, 224))
print("图片调整大小完成")

# 转换为numpy数组
img_array = np.array(img)
print("转换为numpy数组完成")

# 应用MobileNetV2的预处理,包括归一化和通道调整
img_array = tf.keras.applications.mobilenet_v2.preprocess_input(img_array)
print("预处理完成")

# 添加批次维度,因为模型需要批量输入
return np.expand_dims(img_array, axis=0)

#实现猫检测函数
def detect_cat(image, confidence_threshold=0.3):
model = tf.keras.applications.MobileNetV2(weights='imagenet')
processed_image = preprocess_image(image)
predictions = model.predict(processed_image)
decoded_predictions = tf.keras.applications.mobilenet_v2.decode_predictions(predictions, top=5)[0]
# 定义猫的标签
cat_labels = ['tabby', 'tiger_cat', 'Persian_cat', 'Siamese_cat', 'Egyptian_cat']
for _, label, prob in decoded_predictions:
if any(cat in label for cat in cat_labels) and prob >= confidence_threshold:
return f"检测到猫 ({label}, 置信度: {prob:.2f})"
return "未检测到猫"

app.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

from flask import Flask, request, render_template
import cat_detector

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == "POST":
file = request.files['file']
if file:
result = cat_detector.detect_cat(file)
return render_template('result.html', result=result)
return render_template('upload.html')


if __name__ == "__main__":
app.run(debug=True)

前端就不说了。

最后修改一下关键信息,部署在 sealos 上即可。

image-20250412183927149

后记

使用预训练其实比较简单,调库,然后塞测试数据就行了。后续可能需要做进一步的数据收集、模型优化和训练。后面的后面或许可以根据别人上传的图片来进行动态训练。

菜啊,有待提升。