《Pytorch模型推理及多任务通用范式》第三节作业

课程学习

本节课主要对于大白AI课程:https://mp.weixin.qq.com/s/STbdSoI7xLeHrNyLlw9GOg

《Pytorch模型推理及多任务通用范式》课程中的第三节课进行学习。

作业题目

包含以下必做题思考题

1、必做题:

1.1 把模型改为 resnet18,加载相应的模型权重( Lesson2 的物料包中有),跑一下 0.jpg和 1.jpg,看一下输出结果。官方 torchvision 训练 mobilenet 和训练 resnet 的方式是一样的,所以数据预处理和数据后处理部分完全相同。
1.2 自己找 2 张其他图,用 resnet18 做下推理。

2、思考题:

2.1 以 ResNet18 为例,用 time 模块和 for 循环,对”./images/0.jpg” 连续推理 100
次,统计时间开销,比如:

model_classify=ModelPipline()
import time
image=cv2.imread("./images/0.jpg")
t_all=0
for i in range(100):
t_start=time.time()
result=model_classify.predict(image)
t_end=time.time()
t_all+=t_end-t_start
print(t_all)

有 CUDA 的同学,改下代码: self.device=torch.device(‘cuda’)。用上述相同方法测试时间开销。
2.2 在数据预处理和数据后处理的代码实现中,到处在用 numpy, opencv, torch 对数组做相应变换,大家至少要把课程中出现的函数们给理解。

3、总结


作业答案

1、必做题:

1.1 resnet18输出结果

修改get_model()代码如下:

def get_model():
	# 修改模型为resnet18
    model = models.resnet18(num_classes=1000)
    # 加载resnet18的预训练模型
    pretrained_state_dict = torch.load('./weights/resnet18-5c106cde.pth', map_location=lambda storage, loc: storage)
    model.load_state_dict(pretrained_state_dict, strict=True)
    model.to(device=device)
    model.eval()
    return model

输出结果如下:

(‘umbrella’, 0.9995712637901306)
(‘peacock’, 0.9999839067459106)

1.2 使用自己找的图片进行resnet18分类

图片如下,图片为百度的图片,图1为柯基狗,图2为暹罗猫:

dog

cat

输出结果如下:

(‘Pomeranian’, 0.5854851603507996)
(‘Siamese cat’, 0.9999914169311523)

结论
resnet的模型参数量很小,预测准确率不是很高,同样的图片,使用mobilenet_v2模型进行预测的结果如下,预测正确。

(‘Pembroke’, 0.5984793901443481)
(‘Siamese cat’, 0.999940037727356)

2、思考题:

2.1 以 ResNet18 为例,计算推理时间开销,分别使用gpu和cpu进行测试

首先测试cpu的结果,修改__main__函数为以下代码:

if __name__=='__main__':
    model_classify = ModelPipline()

    import time
    image=cv2.imread('./images/2.jpg')

    t_all = 0
    for i in range(100):
        t_start = time.time()
        result = model_classify.predict(image)
        t_end = time.time()
        t_inter = t_end - t_start
        # print(t_inter)
        t_all += t_inter
    print("推理一百次运行时间:{}".format(t_all))

运行结果如下:

推理一百次运行时间:6.4180748462677

接下来在ModelPipline中的__init__函数中修改self.device为gpu:

self.device=torch.device('cuda')

运行结果:

推理一百次运行时间:1.042039155960083

结论
相比较于使用cpu的推理时间,我的gpu(1050ti)推理时间是cpu的6倍,正如大潘老师在第二节中讲到的,算力是决定模型推理速度的重要因素,cpu的算力相较于gpu的算力要小很多,然而对于不同的设备拥有不同的算力来说,同样的代码在不同的设备的测试结果是不同的,如嵌入式端的设备的算力通常因为体积和成本等问题,会非常小。在部署的过程中,如何在不降低模型过多精度的同时,尽可能地提升算法的推理速度,这是一个很重要的问题。

2.2 理解numpy, opencv, torch 数组的相应变换

我们来重头捋一遍整个数组的变换。

0) 经过opencv读取的图片,会直接转化为numpy数组:

image=cv2.imread('./images/2.jpg')
print(type(image))

输出结果为numpy数组:

<class ‘numpy.ndarray’>

1)numpy数组经过前处理阶段中的数据变换:

首先使用opencv中的函数将读取到的图片数组转换成推理阶段的通道对齐(cv2.cvtColor)和模型推理尺寸(cv2.resize)。

# opencv默认读入是BGR,需要转为RGB,和训练时保持一致
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# resize成模型输入的大小,和训练时保持一致
image = cv2.resize(image, dsize=inputs_size)
print(type(image))

输出结果是numpy数组,但是操作使用的为opencv的函数:

<class ‘numpy.ndarray’>

接着对数组进行归一化和标准化操作,并将数组维度调整到与模型输入维度对齐。

# 归一化和标准化处理,和训练时保持一致
inputs = image / 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),transpose修改维度顺序
inputs = inputs.transpose(2, 0, 1)
# (C, H, W) -> (1, C, H, W), 1为新增batch_size,默认为1即可
inputs = inputs[np.newaxis, :, :, :]
print(type(inputs))

输出结果是numpy数组,但是此时的操作使用的为numpy的函数:

<class ‘numpy.ndarray’>

最后将numpy通过torch.from_numpy函数将numpy数组转换为torch的Tensor,并设置其数据类型和推理设备,与模型加载保持一致。

# NumpyArray -> Tensor
inputs = torch.from_numpy(inputs)
# dtype float32
inputs = inputs.type(torch.float32)
# 与model放在相同设备上
inputs = inputs.to(device=device)
print(type(inputs))

输出结果为Tensor,此时的输出即为模型推理的输入,前处理结束。

<class ‘torch.Tensor’>

2)模型推理过程中的数据变换:

模型推理过程中的数据变换很简单,经过了网络输出的推理结果,维度发生了很大的变化,但是数据类型没有改变。

outputs = model(inputs)
print(type(outputs), outputs.size())

输出结果为1*1000维度的Tensor张量:

<class ‘torch.Tensor’> torch.Size([1, 1000])

3)模型后处理过程中的数据变换:

后处理的过程,主要是将模型推理的结果,解码为我们需要得到的输出结果,即网络推理得到的图片的类别和置信度。

输出结果首先通过softmax函数得到1000类中每个类的置信度,并通过max函数选择置信度最高的类别的作为推理的结果,即将维度从1000 -> 1,此时的数据类型还是Tensor。

# 取softmax得到每个类别的置信度
outputs = torch.softmax(outputs, dim=1)
# 取最高置信度的类别和分数
score, label_id = torch.max(outputs, dim=1)
print(type(score), score.size())
print(type(label_id), label_id.size())

输出结果为1维的Tensor张量:

<class ‘torch.Tensor’> torch.Size([1])
<class ‘torch.Tensor’> torch.Size([1])

最后一步,从score和label_id的Tensor中提取出真正的置信度分数和标签id,并使用标签id从label_names中提取出真正的标签名字。

# Tensor -> Float
score, label_id = score.item(), label_id.item()
# 查找标签名字
label_name = label_names[label_id]
print(type(score), type(label_id), type(label_name))

输出结果分别为置信度分数、标签id和标签名字的数据类型:

<class ‘float’> <class ‘int’> <class ‘str’>

到此,一次完整的推理过程结束。

3、总结

非常感谢大潘老师的课程!!上课的时候因为有事没有时间听,但是后面按照笔记自己完整的实现了一遍pytorch模型推理的完整过程,从最基础的数据读取,到数据转换到最后的数据处理,都有一定的清晰思路。之前在看源码的过程中,分开看每个模块,却缺少了整体模块的完整性结构,(加载模型)前处理、模型推理、后处理,完整的模型推理结构,是后续我学习不同算法的基本框架,受益匪浅。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值