介绍
这篇文章是《【Pytorch】计算机视觉项目——卷积神经网络TinyVGG模型图像分类(如何使用自定义数据集)》的最后一部分内容:模型预测。
在本文中,我们将介绍如何测试模型的预测效果——让已训练好模型对一张新的图片进行分类;最后将整个流程打包,写成一个可以被直接调用的函数。
整个预测流程包括:
- 图片下载
- 图像转张量、图像数据变换
- 使用训练好的模型进行预测
- 预测结果输出
通过这些步骤,读者将能够进一步了解如何对已经训练好模型进行测试,以及了解模型是如何完成对图像的分类工作。
其他相关文章:
- 深度学习入门笔记:总结了一些神经网络的基础概念。
- TensorFlow专栏:《计算机视觉入门系列》介绍如何用TensorFlow框架实现卷积分类器。
- 【Pytorch】整体工作流程代码详解(新手入门)
图像处理和预测分步骤详解
1. 图片下载&路径设置
import requests# 设置文件路径
custom_image_path = data_path / "04-pizza-dad.jpeg"# 文件下载
if not custom_image_path.is_file():with open(custom_image_path, "wb") as f:request = requests.get("https://raw.githubusercontent.com/mrdbourke/pytorch-deep-learning/main/images/04-pizza-dad.jpeg")print(f"Downloading {custom_image_path}...")f.write(request.content)
else:print(f"{custom_image_path} already exists, skipping download.")
2. 将图像转换成张量
import torchvision# 将图像转换成张量(未指定格式)
custom_image_uint8 = torchvision.io.read_image(str(custom_image_path))# 打印结果
print(f"Custom image tensor:\n{custom_image_uint8}\n")
print(f"Custom image shape: {custom_image_uint8.shape}\n")
print(f"Custom image dtype: {custom_image_uint8.dtype}")
图像数据的格式是torch.uint8, 表示范围在(0,255),通常用于表示图像的像素值。
而在深度学习模型中,通常使用 torch.float32
格式的输入,因为模型训练和推理时需要更高的数值精度和更广泛的表示范围。
因此,需要把格式转成精度更高的float32,这是模型所需要的格式。
# 载入图像,并将张量值转换为float32
custom_image = torchvision.io.read_image(str(custom_image_path)).type(torch.float32)# 将torch.uint8张量转换为torch.float32,并归一化到[0, 1]
custom_image = custom_image / 255. # 检查转换后的张量的数据
print(f"Custom image tensor:\n{custom_image}\n")
print(f"Custom image shape: {custom_image.shape}\n")
print(f"Custom image dtype: {custom_image.dtype}")
![[04.1 8. 模型预测-20240606124914487.webp]]
# 图片展示
plt.imshow(custom_image.permute(1, 2, 0))
plt.title(f"Image shape: {custom_image.shape}")
plt.axis(False);
![[04.1 8. 模型预测-20240605181832312.webp]]
数据形状现在是[3,4032,4032], 我们还需要对它进行进一步的处理,使其能够匹配模型训练时使用的数据形状。
3. 图像变换
# 设置图像变换过程
custom_image_transform = transforms.Compose([transforms.Resize((64, 64)),
])# 图片转换
custom_image_transformed = custom_image_transform(custom_image)# 打印图片形状
print(f"Original shape: {custom_image.shape}")
print(f"New shape: {custom_image_transformed.shape}")
经过Transform过程,图片形状变成[3,64,64]。
原始形状为torch.Size([3, 4032, 3024])
,这表示图像的高度为4032像素,宽度为3024像素,并且有3个通道(通常表示RGB通道)。
新的形状为torch.Size([3, 64, 64])
,这表示经过调整后,图像的高度和宽度都变成了64像素,依然保持3个通道。
transforms.ToTensor()
:
- 输入格式:对于彩色图像(RGB),输入通常是形状为
(H, W, 3)
的 numpy 数组或 PIL 图像,其中H
是高度,W
是宽度,3
表示颜色通道(红、绿、蓝)。- 输出格式:形状为
(C, H, W)
的PyTorch 张量,其中C
是颜色通道数(通常为 3),H
是高度,W
是宽度。- 示例:假设有一张 RGB 图像,原始大小为 256x256,转换后为形状为
(3, 256, 256)
的张量,其中 3 表示 RGB 通道。如果是灰度图像,转换为(1, H, W)
,因为灰度图像只有一个通道。
4. 模型预测
model_0.eval()with torch.inference_mode():# 给图像增加一个维度:batch sizecustom_image_transformed_with_batch_size = custom_image_transformed.unsqueeze(dim=0) # 打印结果print(f"Custom image transformed shape: {custom_image_transformed.shape}")print(f"Unsqueezed custom image shape: {custom_image_transformed_with_batch_size.shape}")# 使用模型对图像进行分类预测custom_image_pred = model_0(custom_image_transformed.unsqueeze(dim=0).to(device))
custom_image_transformed.unsqueeze(dim=0)
因为在模型训练过程中,图像张量数据是按照批次导入模型训练的,模型适应的维度/形状是(N, C, H, W)
, 这里的N是批次的意思。因此,torch.unsqueeze(dim=0)
给图像价
5. 预测结果输出
# 打印原始预测值logits
print(f"Prediction logits: {custom_image_pred}")# 将logits转换为预测概率-->模型预测的概率
custom_image_pred_probs = torch.softmax(custom_image_pred, dim=1)
print(f"Prediction probabilities: {custom_image_pred_probs}")# 将预测概率转换为预测标签
custom_image_pred_label = torch.argmax(custom_image_pred_probs, dim=1)
print(f"Prediction label: {custom_image_pred_label}")
torch.softmax(custom_image_pred, dim=1)
: 使用Softmax函数将logits转换为概率。Softmax函数将logits转换为0到1之间的概率值,并且所有概率值的总和为1。dim=1
表示在类别维度上进行计算。torch.argmax(custom_image_pred_probs, dim=1)
: 在概率最大的类别索引上取最大值,这个索引对应于模型预测的类别标签。
# 找出预测标签
custom_image_pred_class = class_names[custom_image_pred_label.cpu()] # put pred label to CPU, otherwise will errorcustom_image_pred_class
.cpu()
这里代码是在GPU上运行的,所以需要把预测标签移回CPU上。
创建预测函数(打包整个预测过程)
我们复习一下上面的步骤:
- 设置目标图像路径,并将其转换为适合我们模型的数据类型(torch.float32)。
- 确保目标图像的像素值在范围 [0, 1] 之内。
- 如有必要,对目标图像进行变换。
- 确保模型在指定的设备上。
- 使用训练好的模型对目标图像进行预测(确保图像尺寸正确,并与模型在同一设备上)。
- 将模型的输出logits转换为预测概率。
- 将预测概率转换为预测标签。
- 绘制目标图像,并显示模型的预测结果和预测概率。
接下来我们需要把这些步骤都打包到一个函数中,这样就能通过函数实现模型的预测功能。
def pred_and_plot_image(model: torch.nn.Module,image_path: str,class_names: List[str] = None,transform=None,device: torch.device = device):# 1. 载入图像,并将张量值转换为float32target_image = torchvision.io.read_image(str(image_path)).type(torch.float32)# 2. 将图像像素值除以255,使其在[0, 1]之间target_image = target_image / 255.# 3. 如有必要,进行图像变换if transform:target_image = transform(target_image)# 4. 确保模型在指定设备上model.to(device)# 5. 启用模型评估模式和推理模式model.eval()with torch.inference_mode():# 为图像添加一个维度target_image = target_image.unsqueeze(dim=0)# 对图像进行预测,并将其发送到指定设备target_image_pred = model(target_image.to(device))# 6. 将logits转换为预测概率(使用softmax进行多分类)target_image_pred_probs = torch.softmax(target_image_pred, dim=1)# 7. 将预测概率转换为预测标签target_image_pred_label = torch.argmax(target_image_pred_probs, dim=1)# 8. 绘制图像,并显示预测结果和预测概率plt.imshow(target_image.squeeze().permute(1, 2, 0)) # 调整图像以适应matplotlibif class_names:title = f"预测: {class_names[target_image_pred_label.cpu()]} | 概率: {target_image_pred_probs.max().cpu():.3f}"else:title = f"预测: {target_image_pred_label} | 概率: {target_image_pred_probs.max().cpu():.3f}"plt.title(title)plt.axis(False);
pred_and_plot_image(model=model_0,image_path=custom_image_path,class_names=class_names,transform=custom_image_transform,device=device)
最后结果展示了分类的标签,概率,以及经过处理后的图片。