江大白共学计划_Pytorch推理及范式_Lesson5

本篇博客记录了学习大白AI关于PyTorch中YOLOx模型推理的课程内容,包括使用Yolox_s进行目标检测,设置输入尺寸和阈值,以及在CPU和GPU上的性能对比。通过实操,作者了解到模型推理的通用流程,即数据预处理、模型推断和后处理。同时,作者建议课程增加更多挑战性的作业,并希望能深入理解算法原理。此外,文中提供了不同规模的YOLOx模型在GPU上的推理时间开销数据。
摘要由CSDN通过智能技术生成

1.课程学习

本节课主要对于大白AI课程:https://mp.weixin.qq.com/s/STbdSoI7xLeHrNyLlw9GOg
《Pytorch推理及范式》课程中的第五节课进行学习。

2.作业题目

必做题:

(1) 自己找 2 张其他图,用 Yolox_s 进行目标检测,并注明输入尺寸和两个阈值。
两张图片的输入尺寸都是640*640,两个阈值分别是: conf_threshold = 0.6 nms_threshold = 0.45
在这里插入图片描述
在这里插入图片描述

思考题:

(1) Yolox_s:用 time 模块和 for 循环,对”./images/1.jpg”连续推理 100 次,统计时
间开销。有 CUDA 的同学,改下代码:self.device=torch.device(‘cuda’),统计时间
开销。
CPU:

图片运行100次耗时: 84.00596022605896
推理一次平均耗时: 0.8400596022605896

GPU:

图片运行100次耗时: 48.27049493789673
推理一次平均耗时: 0.4827049493789673

(2) 有 CUDA 的同学,分别用 Yolox_tiny、Yolox_s、Yolox_m、Yolox_l、Yolox_x
对”./images/1.jpg”连续推理 100 次,统计时间开销。
Yolo_tiny:
Yolox_s:

图片运行100次耗时: 48.27049493789673
推理一次平均耗时: 0.4827049493789673

Yolox_m:

图片运行100次耗时: 126.11759567260742
推理一次平均耗时: 1.2611759567260743

Yolox_l:
Yolox_x:
最后两个模型用公司的笔记本跑不起来了。。。。

3.课程总结:

本次课程到这就结束了,下面谈谈我对此次课程的心得体会:
收获:
通过这次课程,我学会了一种通用的推理流程,通过这个流程理解了模型推理的核心内容,即数据预处理,数据进网络,数据后处理,这三步到底在干些什么。后面就是靠这个流程慢慢体会模型推理的本质和乐趣,以后c++推理也可以用这个流程。逐步地入门、熟悉模型推理。
建议:
对于课程的形式,我觉得非常合适,这课后作业有点太单调了,每次的作业基本上都一样,我觉得可以适当加点难度。
有的时候知道怎么推理了,却对算法原理不是很清楚,之前看过大白老师的yolo系列文章,让我对yolo算法有了进一步的理解,对于别的算法,很难找到写的这么透彻的文章,希望老师讲课的时候能推荐一下对算法讲的比较好的文章,或者讲一下如何学习一个新的算法,感觉这个也很重要。
阶段:
在职,入职4个月。

4.完整代码:

import torch
import cv2
import numpy as np
import torchvision.models as models
import time
from lesson5.models_yolox.visualize import vis

import torchvision.ops

from lesson5.models_yolox.yolox_s import YOLOX


class ModelPipline(object):
    def __init__(self):
        # 进去模型的图片大小:为数据预处理和后处理做准备
        self.inputs_size = (640, 640)
        # CPU or CUDA:为数据预处理和模型加载做准备
        self.device = torch.device('cuda')
        # 载入模型结构和模型权重
        self.num_classes = 80
        self.model = self.get_model()
        # 后处理的阈值
        self.conf_threshold = 0.6
        self.nms_threshold = 0.45
        # 标签载入
        label_name = open(r'D:\Pycharm Projcets\Pytorch_test\torch_inference\lesson5\labels\coco_label.txt')
        self.label_names = [line.strip('n') for line in label_name]

    def predict(self, image):
        # 数据预处理
        inputs, r = self.preprocess(image)
        # 数据进网络
        outputs = self.model(inputs)
        # 数据后处理
        results = self.postprocess(outputs, r)
        return results

    def get_model(self):
        model = YOLOX(num_classes=self.num_classes)
        pretrained_state_dict = torch.load(r"D:\Pycharm Projcets\Pytorch_test\torch_inference\lesson5\weights\yolox_m.pth",
                                           map_location=lambda storage, loc: storage)["model"]
        model.load_state_dict(pretrained_state_dict)
        model.to(self.device)
        model.eval()
        return model

    def preprocess(self, image):
        # 原图尺寸
        h, w = image.shape[:2]
        # 生成一张 w=h=640的mask,数值全是114
        padded_img = np.ones((self.inputs_size[0], self.inputs_size[1], 3)) * 114.0
        # 计算原图的长边缩放到640所需要的比例
        r = min(self.inputs_size[0] / h, self.inputs_size[1] / w)
        # 对原图做等比例缩放, 使得长边=640
        resize_img = cv2.resize(image, (int(w * r), int(h * r)), interpolation=cv2.INTER_LINEAR).astype(np.float32)
        # 将缩放后的原图填充到 640*640的mask的左上方
        padded_img[: int(h * r), :int(w * r)] = resize_img
        # BGR ————> RGB
        padded_img = padded_img[:, :, ::-1]
        # 归一化和标准化, 和训练时保持一致
        inputs = padded_img / 255
        inputs = (inputs - np.array([0.485, 0.456, 0.406])) / np.array([0.229, 0.224, 0.225])
        # # 以下是图像任务的通用处理
        # (H, W, C) ——> (C, H, W)
        inputs = inputs.transpose(2, 0, 1)
        # (C, H, W) ——> (1, C, H, W)
        inputs = inputs[np.newaxis, :, :, :]
        # NumpyArray ——> Tensor
        inputs = torch.from_numpy(inputs)
        # dtype float32
        inputs = inputs.type(torch.float32)
        # 与self.model放在相同硬件上
        inputs = inputs.to(self.device)
        return inputs, r

    def postprocess(self, prediction, r):
        # prediction.shape = [1, 8400, 85],下面先将85中的前4列进行转换,从xc,yc,w,h变为x0,y0,x1,y1
        # 将每个anchor的“中心点横坐标”、“中心点纵坐标”、“框的宽”、“框的高”转换为
        # anchor的“左上角横坐标”、“左上角纵坐标”、“右下角横坐标”、“右下角纵坐标”。
        box_corner = prediction.new(prediction.shape)
        box_corner[:, :, 0] = prediction[:, :, 0] - prediction[:, :, 2] / 2
        box_corner[:, :, 1] = prediction[:, :, 1] - prediction[:, :, 3] / 2
        box_corner[:, :, 2] = prediction[:, :, 0] + prediction[:, :, 2] / 2
        box_corner[:, :, 3] = prediction[:, :, 1] + prediction[:, :, 3] / 2
        prediction[:, :, :4] = box_corner[:, :, :4]
        # 只处理单张图片 由于只处理单张图片,所以减少一个维度,从(1, 8400, 85) 变为(8400, 85) 。
        image_pred = prediction[0]
        # class_conf.shape = [8400,1],求每个anchor在80个类别中的最高分。class_pred.shape=[8400, 1],每个anchor的label index。
        # 求出每个 anchor 分数最高的类别,将该最高分和前景分相乘,作为该 anchor 最终的
        # 置信度,和人为设置的阈值 self.conf_threshold 作比较,判断该 anchor 之后是否要保留
        class_conf, class_pred = torch.max(image_pred[:, 5: 5 + self.num_classes], 1, keepdim=True)
        conf_score = image_pred[:, 4].unsqueeze(dim=1) * class_conf  # image_pred[:, :4]是框的坐标信息,image_pred[:, 4]是前景得分,image_pred[:, 5:]是类别得分
        conf_mask = (conf_score >= self.conf_threshold).squeeze()
        # detection.shape=[8400, 6],分别是x0, y0, x1, y1, obj_score*class_score, class_label
        # 求出的 anchor 框的位置信息、置信度信息、类别信息整合到一起
        detections = torch.cat((image_pred[:, :4], conf_score, class_pred.float()), 1)
        # 将obj_score*class_score > conf_thre 筛选出来
        # 剔除置信度小于 self.conf_threshold 的anchor框
        detections = detections[conf_mask]
        # 通过阈值筛选后, 如果没有剩余目标则结束
        # 如把所有 anchor 都剔除了,即图中没有有效检测框,则返回 None。
        if not detections.size(0):
            return None
        # NMS
        # NMS(非极大抑制),如果两个相同类别的 anchor 框的 IOU>self.nms_threshold,
        # 则会剔除置信度较低的 anchor。因此人为设置的阈值 self.nms_threshold 越大,图中保留的框越多
        nms_out_index = torchvision.ops.batched_nms(detections[:, :4], detections[:, 4], detections[:, 5], self.nms_threshold)
        detections = detections[nms_out_index]
        # 把坐标映射回原图
        detections = detections.data.cpu().numpy()
        bboxes = (detections[:, :4] / r).astype(np.int64)
        scores = detections[:, 4]
        labels = detections[:, 5].astype(np.int64)

        return bboxes, scores, labels


# 实例化
model_detect = ModelPipline()
# 获取标签名称
label_name = model_detect.label_names
# 读取图片
image = cv2.imread(r'D:\Pycharm Projcets\Pytorch_test\torch_inference\lesson5\images\1.jpg')
# 模型推理
result = model_detect.predict(image)

start = time.time()
for i in range(100):
    result = model_detect.predict(image)
end = time.time()
print("图片运行100次耗时:", end - start)
print("推理一次平均耗时:", (end - start) / 100)

# 可视化结果
if result is not None:
    bboxes, scores, labels = result
    image = vis(image, bboxes, scores, labels, label_name)
cv2.imwrite('01.jpg', image)
cv2.imshow("result", image)
cv2.waitKey(0)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值