文章目录
一、预训练模型的概念与目的
预训练模型是指在大规模数据上训练好的模型,通常采用无监督学习方法进行训练。
预训练模型的目的是:利用大规模数据训练得到的特征来初始化模型参数,从而加快模型的收敛速度和提高模型的泛化能力。预训练模型通常可以分为两类:
- 基于无监督学习的预训练模型,如自编码器、生成对抗网络等。这些模型在大规模无标注数据上进行训练,学习数据的高层次特征表示,如图像的纹理、形状等。
- 基于监督学习的预训练模型,如在ImageNet等大规模标注数据集上训练的模型。这些模型通常采用卷积神经网络(CNN)结构,在大规模数据上进行训练,学习到数据的高层次特征表示,如图像的纹理、形状等。
在图像分类等任务中,预训练模型可以用作特征提取器或者迁移学习的基础模型,通过微调等方式进行优化,从而得到更好的性能和泛化能力。
二、安装配置环境
1.下载工具包
!pip install numpy pandas matplotlib requests tqdm opencv-python pillow gc -i https://pypi.tuna.tsinghua.edu.cn/simple
库介绍:
pillow
:Pillow 是 Python 中一个流行的图像处理库,它基于 PIL (Python Imaging Library) 库的基础上进行了更新和优化。Pillow 提供了大量的图像处理函数和方法,可以方便地进行图像的加载、处理和保存。它支持的图像格式包括 JPEG、PNG、BMP、GIF、TIFF 等多种格式,并且可以对图像进行缩放、裁剪、旋转、滤镜等各种操作。
Pillow 提供了 Image 类来表示图像,可以使用 Image.open() 方法来加载图像,使用 Image.save() 方法保存图像,还可以使用 Image.show() 方法来显示图像。除此之外,Pillow 还提供了丰富的图像处理方法,包括调整图像大小、调整图像颜色、应用图像滤镜等。
总的来说,Pillow 是一个非常方便实用的图像处理库,特别适用于图像处理和数据预处理等任务,能够帮助用户更快速、更方便地进行图像处理任务。
gc
gc(Garbage Collection)是 Python 内置的垃圾回收机制,负责回收不再使用的内存空间。
问题:
不知道为什么gc这个包装不了,网上也没找到解决方案,后面将这个问题忽略了(因为没有这个包对程序并没什么影响)即:
!pip install numpy pandas matplotlib requests tqdm opencv-python pillow -i https://pypi.tuna.tsinghua.edu.cn/simple
2.下载安装Pytorch
!pip3 install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113
PyTorch 是一个非常灵活、易用、高效和功能强大的机器学习框架,特别适合用于深度学习模型的开发和训练。同时,PyTorch 的社区也非常活跃,提供了大量的资源和支持,使得用户可以更快地掌握 PyTorch 并开发出更加优秀的深度学习模型。
3.下载安装 mmcv-full
# 安装mmcv -full
!pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.10.0/index.html
mmcv-full
是一个开源的计算机视觉工具箱,提供了丰富的图像和视频处理模块、模型和优化器等。它是基于 PyTorch 框架的高级计算机视觉库,可以用来开发和训练各种视觉模型,如目标检测、实例分割、姿态估计、图像分类、视频理解等。
mmcv-full
的主要特点包括:
- 提供了丰富的图像和视频处理模块,如图像增强、数据集预处理、视频流处理等。
- 提供了多个流行的目标检测、实例分割、姿态估计等算法的实现,如 Faster R-CNN、Mask R-CNN、YOLO、OpenPose 等。
- 提供了各种优化器和学习率调度器,如 Adam、SGD、Cosine Annealing 等,方便用户进行模型优化。
- 支持分布式训练,可以通过多个 GPU 或多个机器并行训练模型,提高训练速度和效率。
- 提供了丰富的模型评估和可视化工具,可以帮助用户对模型的性能进行评估和分析。
使用
mmcv-full
库可以大大简化计算机视觉任务的开发和训练过程,提高开发效率和模型性能。
4.下载中文字体文件
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/dataset/SimHei.ttf
5.下载 ImageNet 1000类别信息
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/dataset/meta_data/imagenet_class_index.csv
下面为部分类别信息:
6. 创建test_img和output目录
import os
# 存放测试图片
os.mkdir('test_img')
# 存放结果文件
os.mkdir('output')
# 下载测试图像文件至 test_img 文件夹
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/test/watermelon1.jpg -O test_img/watermelon1.jpg
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/test/banana1.jpg -O test_img/banana1.jpg
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/test/cat1.jpg -O test_img/cat1.jpg
# 哈士奇,来源:https://www.pexels.com/zh-cn/photo/2853130/
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/test/husky1.jpeg -O test_img/husky1.jpeg
# 猫狗,来源:https://unsplash.com/photos/ouo1hbizWwo
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/test/cat_dog.jpg -O test_img/cat_dog.jpg
!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/test/video_2.mp4 -O test_img/video_2.mp4
三、预测单张图片
1. 导入基础工具包
import os # 操作系统库
import cv2 # 开源cv库
import pandas as pd # 数据分析库
import numpy as np # 科学计算库
import torch # pytorch
import matplotlib.pyplot as plt # 数据可视化库
%matplotlib inline
2. 获取计算设备
# 有 GPU 就用 GPU,没有就用 CPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
print('device', device)
3. 载入预训练图像分类模型
from torchvision import models
# 载入预训练图像分类模型(resnet18为已经训练好的模型,我们直接调包用就好)
model = models.resnet18(pretrained=True)
model = model.eval()
model = model.to(device)
4. 定义图像(模型输入)预处理方法
from torchvision import transforms
# 测试集图像预处理-RCTN:缩放、裁剪、转 Tensor、归一化
test_transform = transforms.Compose([transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
PyTorch 中用于测试数据集预处理的
transforms.Compose
组合。具体解释如下:
缩放
transforms.Resize(256)
:将图像大小调整为 256x256 像素,保持原始图像的纵横比。裁剪
transforms.CenterCrop(224)
:将图像中心区域裁剪为 224x224 像素,这是许多预训练模型接受的输入图像尺寸。转tensor
transforms.ToTensor()
:将 PIL 图像或 numpy 数组转换为 PyTorch 张量,并将像素值缩放到 0 到 1 之间。
张量(tensor):是一种数学概念,它是一种多维数组,可以看作是标量、向量和矩阵的推广。在 PyTorch 中,张量是一种特殊的数据结构,它与 NumPy 数组类似,但是能够在 GPU 上运行,从而加速运算。与 NumPy 数组不同的是,PyTorch 张量可以自动求导,支持动态图,方便构建深度学习模型。
import torch # 创建一个标量 x = torch.tensor(3.14) # 创建一个向量 y = torch.tensor([1, 2, 3]) # 创建一个矩阵 z = torch.tensor([[1, 2], [3, 4]]) # 这些张量的形状可以通过 shape 属性获取,数据类型可以通过 dtype 属性获取。我们还可以使用张量进行数学运算。
归一化
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
:对张量进行标准化处理,以便每个像素都以预定义的平均值和标准差为中心。这是为了减少数据之间的差异并帮助模型更好地进行训练。通过使用这些测试数据集预处理步骤,可以将测试数据集中的每个图像转换为张量,并进行与训练数据集相同的标准化处理,从而使测试数据集的预处理与训练数据集一致。这有助于确保测试数据集的输入具有相同的尺寸和像素值范围,从而更好地适应深度学习模型的要求。
5. 载入一张测试图像
img_path = 'test_img/cat_dog.jpg'
# 用 pillow 载入
from PIL import Image
img_pil = Image.open(img_path)
使用Pillow的Image类来读取一张图片,实例化一个Image对象img_pil,并将图片读取到内存中。
np.array(img_pil).shape
将
PIL.Image
对象转换为numpy.ndarray
数组,并查看该数组的形状。通常情况下,我们可以通过np.array()
函数将 PIL.Image 对象转换为 numpy 数组,从而方便地对图像进行进一步的处理和分析。对于三通道的 RGB 彩色图像,其数组形状为 (height, width, 3),即高度、宽度和 3 个通道(红、绿、蓝)。
6. 执行图像分类预测
input_img = test_transform(img_pil) # 图像预处理(转换为张量)
input_img = input_img.unsqueeze(0).to(device)
input_img.unsqueeze(0)
是将input_img
张量的维度从[C, H, W]
变为[1, C, H, W]
,即在第 0 个维度(即 batch 维度)增加一个维度,表示这是一个 batch 大小为 1 的数据。这是因为 PyTorch 中大多数模型都是设计为可以同时处理多个样本(即 batch),因此输入张量的第一个维度通常表示 batch 的大小。
.to(device)
表示将数据转移到指定设备上,其中device
可以是 CPU 或 GPU。对于大规模的深度学习模型,通常需要使用 GPU 加速,因此需要将输入张量放到 GPU 上。
# 执行前向预测,得到所有类别的 logit 预测分数
pred_logits = model(input_img)
import torch.nn.functional as F
pred_softmax = F.softmax(pred_logits, dim=1) # 对 logit 分数做 softmax 运算(因为我们要的是置信度)
7. 预测结果分析
- 各类别置信度柱状图
plt.figure(figsize=(8,4))
x = range(1000)
y = pred_softmax.cpu().detach().numpy()[0]
ax = plt.bar(x, y, alpha=0.5, width=0.3, color='yellow', edgecolor='red', lw=3)
plt.ylim([0, 1.0]) # y轴取值范围
# plt.bar_label(ax, fmt='%.2f', fontsize=15) # 置信度数值
plt.xlabel('Class', fontsize=20)
plt.ylabel('Confidence', fontsize=20)
plt.tick_params(labelsize=16) # 坐标文字大小
plt.title(img_path, fontsize=25)
plt.show()
- 取置信度最大的 n 个结果
n = 10
top_n = torch.topk(pred_softmax, n)
# 解析出类别
pred_ids = top_n[1].cpu().detach().numpy().squeeze()
# 解析出置信度
confs = top_n[0].cpu().detach().numpy().squeeze()
-
载入ImageNet 1000图像分类标签
df = pd.read_csv('imagenet_class_index.csv')
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u7bysEB4-1676878703009)(https://gitee.com/i-dont-have-him/cloudimage/raw/master/img/202302191632909.png)]
# 将数据转换成键值对形式,键是id,值是[wordnet编号,英文名称] idx_to_labels = {} for idx, row in df.iterrows(): idx_to_labels[row['ID']] = [row['wordnet'], row['class']]
下面是部分数据:
-
图像分类结果写在原图上
# 用 opencv 载入原图
img_bgr = cv2.imread(img_path)
for i in range(n):
class_name = idx_to_labels[pred_ids[i]][1] # 获取类别名称
confidence = confs[i] * 100 # 获取置信度
text = '{:<15} {:>.4f}'.format(class_name, confidence)
print(text)
# !图片,添加的文字,左上角坐标,字体,字号,bgr颜色,线宽
img_bgr = cv2.putText(img_bgr, text, (25, 50 + 40 * i), cv2.FONT_HERSHEY_SIMPLEX, 1.25, (0, 0, 255), 3)
# 保存图像
cv2.imwrite('output/img_pred.jpg', img_bgr)
# 载入预测结果图像
img_pred = Image.open('output/img_pred.jpg')
img_pred
- 图像和柱状图一起显示
fig = plt.figure(figsize=(18,6))
# 绘制左图-预测图
ax1 = plt.subplot(1,2,1)
ax1.imshow(img_pred)
ax1.axis('off')
# 绘制右图-柱状图
ax2 = plt.subplot(1,2,2)
x = df['ID']
y = pred_softmax.cpu().detach().numpy()[0]
ax2.bar(x, y, alpha=0.5, width=0.3, color='yellow', edgecolor='red', lw=3)
plt.ylim([0, 1.0]) # y轴取值范围
plt.title('{} Classification'.format(img_path), fontsize=30)
plt.xlabel('Class', fontsize=20)
plt.ylabel('Confidence', fontsize=20)
ax2.tick_params(labelsize=16) # 坐标文字大小
plt.tight_layout()
fig.savefig('output/预测图+柱状图.jpg')
-
预测结果表格输出
pred_df = pd.DataFrame() # 预测结果表格 for i in range(n): class_name = idx_to_labels[pred_ids[i]][1] # 获取类别名称 label_idx = int(pred_ids[i]) # 获取类别号 wordnet = idx_to_labels[pred_ids[i]][0] # 获取 WordNet confidence = confs[i] * 100 # 获取置信度 pred_df = pred_df.append({'Class':class_name, 'Class_ID':label_idx, 'Confidence(%)':confidence, 'WordNet':wordnet}, ignore_index=True) # 预测结果表格添加一行 display(pred_df) # 展示预测结果表格
标签的中文显示
整体流程基本上与上面一致,只是改成了中文标签。
设置matplotlib中文字体
import matplotlib.pyplot as plt
# windows操作系统
plt.rcParams['font.sans-serif']=['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False # 用来正常显示负号
导入pillow中文字体
from PIL import ImageFont, ImageDraw
# 导入中文字体,指定字号
font = ImageFont.truetype('SimHei.ttf', 32)
四、预测视频文件
处理逻辑:
-
载入预训练图像分类模型(resnet18)
-
载入ImageNet 1000图像分类标签
-
编写测试集图像预处理规则(缩放、剪裁、转tensor、归一化)
-
图像分类预测函数(输入摄像头画面bgr-array,输出前n个图像分类预测结果的图像bgr-array)
跟之前预测单张图片逻辑大致是一样的:
-
BGR 转 RGB:
在计算机视觉领域中,常用的图像颜色空间有 RGB 和 BGR 两种。RGB 颜色空间指的是红绿蓝三原色,而 BGR 颜色空间则是指蓝绿红三原色,通常在使用 OpenCV 库进行图像处理时,图像数据存储的是 BGR 格式。而在 PyTorch 中,使用 PIL 库读入的图像数据格式为 RGB 格式,所以需要在读入图像后通过 cv2.cvtColor 函数进行颜色空间转换,将 BGR 格式转换为 RGB 格式,才能与使用 PIL 库处理的图像数据保持一致。
-
array 转 pil
-
对图片进行预处理;执行前向预测,得到所有类别的 logit 预测分数;对 logit 分数做 softmax 运算;取置信度最大的 n 个结果;解析出类别、置信度;在图像上写字。
-
RGB转BGR
-
返回前n个图像分类预测结果的图像bgr-array和所有类别的 logit 预测分数做softmax运算后的结果
-
-
视频预测:
- 输入待预测视频路径
- 创建一个临时文件夹存放每帧(用存入时间命名)的结果
- 通过路径读入待预测视频
- 对视频进行逐帧处理(每一帧都进行图像分类预测,即调用上一步编写的分类预测函数),将处理后的当前帧图像保存至临时文件夹
- 将处理后的每一帧图像串成视频文件
五、预测摄像头实时画面
处理逻辑:
-
载入预训练图像分类模型
-
载入ImageNet 1000图像分类标签
-
编写测试集图像预处理规则(缩放、剪裁、转tensor、归一化)
-
获取摄像头的一帧画面
-
对该帧画面进行图像分类预测(与前面预测单张图片是一样的)
-
编写处理单帧画面的函数(同上)
-
调用摄像头获取每帧,设置一个死循环,不断重复做以下操作(直至break触发:按q或者esc):
-
获取画面
-
调用处理帧函数处理画面
-
展示处理后的三通道图像
-