栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Yolov3在libtorch上模型加载及预测(c++、yolov3、libtorch)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Yolov3在libtorch上模型加载及预测(c++、yolov3、libtorch)

写在前面:

黄宁然,你们甲方的项目不好做啊。

问题来源:

之前已经基于WIN10+VS2015+opencv3.4.12,实现Yolov3。
(https://download.csdn.net/download/xiaohuolong1827/34664248)
用于项目时,才发现,该实现不支持cuda,需要opencv4以上版本才支持,这在dnn.hpp有提及://OpenCV 4.x: DNN_BACKEND_CUDA,
无奈黄甲方所有工程一直使用opencv3.4.12版本。
为此,解决方案之一,便是基于libtorch实现yolov3。

参考文献:

[1] 罗彬,Yolov3模型在pytorch上训练,在C++中利用Libtorch上进行模型的加载、推理,
https://zhuanlan.zhihu.com/p/246156517?utm_source=qq
[2] L2_Zhang, c++调用pytorch libtorch(YoloV3实战篇),
https://blog.csdn.net/WANGWUSHAN/article/details/118968060

1. 下载yolov3 pytorch版本

下载网址: https://github.com/eriklindernoren/PyTorch-YOLOv3

2. 在python中制作pt文件 2.1 pt文件制作

打开工程中的detect.py文件,指定模型的各参数文件路径(事先已训练好)。例如:

args.model = '../lxxz_yolo_test/yolov3_1classes.cfg'
args.weights = '../lxxz_yolo_test/trained_weights_final_202204252156.weights'
args.classes = '../lxxz_yolo_test/lxxz_classes.txt'
args.n_cpu = 1
args.conf_thres = 0.5
args.nms_thres = 0.5
args.images = '../lxxz_image/'

这里,重写detect_directory函数:

def detect_directory2(model_path, weights_path, img_path, classes, output_path,
                     batch_size=8, img_size=416, n_cpu=8, conf_thres=0.5, nms_thres=0.5):
    files_list = os.listdir(img_path)
    model = load_model(model_path, weights_path)
    for f in files_list:
        img = cv2.imread(img_path+f,cv2.IMREAD_COLOR)
        boxes = detect_image(model,img,img_size=img_size,conf_thres=conf_thres,nms_thres=nms_thres)
        draw_img = draw_boxes(img, boxes)
        print(boxes)
    print(f"---- Detections were saved to: '{output_path}' ----")

主程序中,原来调用detect_directory改为调用detect_directory2。主要是想调用detect_image这个子函数。在detect_image函数中,在网络预测之后,根据需要添加生成pt文件或调用pt文件的语句

with torch.no_grad():
        detections = model(input_img)
        detections = non_max_suppression(detections, conf_thres, nms_thres)
        detections = rescale_boxes(detections[0], img_size, image.shape[:2])
    ##根据需要将网络保存为pt格式文件
    traced_model = torch.jit.trace(model, input_img, check_trace=False)
    traced_model.save("yolo_temp.pt")
    test_out = traced_model(input_img)
    ##根据需要,导入pt文件,进行预测
    model2 = torch.jit.load("yolo_temp.pt")
    output2 = model2.forward(input_img)
    output2 = non_max_suppression(output2, conf_thres, nms_thres)
    output2 = rescale_boxes(output2[0], img_size, image.shape[:2])
    print(output2[0].equal(detections[0]))
2.2 几点注意的地方 (1)若运行出错

若在torch.jit.trace时出错,需要设置参数 check_trace=False
在models.py文件中的_make_grid函数,若调用torch.meshgrid函数:
yv, xv = torch.meshgrid([torch.arange(ny), torch.arange(nx)], indexing=‘ij’)
出现indexing参数错误,则将indexing参数删除。

(2)gpu或cpu

在trace生成pt文件时,若model、input_img位于‘cuda’,则生成的pt为GPU版,否则生成的pt为cpu版。

(3)生成pt文件时不可随意在模型中添加非固定代码

在python中,使用torch.jit.trace生成pt文件:

traced_model = torch.jit.trace(model, input_img, check_trace=False)
traced_model.save("yolo_temp.pt")

这里,不可为了在c++预测中图省事,而将非极大值抑制代码加入到model中。原因是:在使用torch.jit.trace生成pt文件时,应保证model的输出是一固定的维度,例如,yolov3的输出是10647*(4+1+类别数)维度;倘若在model中加入非极大值抑制,网络的输出将变得不确定(例如,经非极大值抑制后,对于某张图,可能预测出2个框,对于另一张图可能预测4个框,这就是不确定)。直接导致的出错现象:使用图片A进行trace、save成pt文件;然后load该pt模型,使用图片A进行预测,结果正常,但若使用其它图片进行预测,失败。

3. 在libtorch中进行预测 3.1 导入模型

主程序中导入模型

torch::jit::script::Module module = torch::jit::load(“D:\xxx_gpu.pt”);
3.2 读取图片

主程序中读取图片,并进行格式处理

	Mat imgSrc = imread("D: \60_1.265_89.74.tif", -1);
	Mat img = imgSrc.clone();
	if (img.depth() == CV_16U)
	{
		img.convertTo(img, CV_32F, 1.0 / 65535);
	}
	else
	{
		img.convertTo(img, CV_32F, 1.0 / 255);
	}
	cv::resize(img, img, Size(416, 416));
	if (img.channels() == 1)
	{
		cv::cvtColor(img, img, cv::COLOR_GRAY2BGR);
	}
3.3 进行网络预测

编写预测函数

int torch_model_predict(void*pmodule, Mat img_input, Mat *img_output, int cuda_flag)
{
	Mat img = img_input.clone();
	if (pmodule == 0)
	{
		return 1;
	}
	try
	{
		torch::DeviceType device_type = (cuda_flag) ? at::kCUDA : at::kCPU;
		torch::jit::script::Module *module = (torch::jit::script::Module *)pmodule;
		module->to(device_type);
		module->eval();
		//制作tensor
		Mat data_src;
		img.convertTo(data_src, CV_32F, 1.0);//无论img什么类型,先转为float类型
		torch::Tensor tensor_image = torch::from_blob(data_src.data, { 1,img.rows, img.cols,img.channels() }, torch::kFloat);// torch::kFloat//torch::kByte
		tensor_image = tensor_image.permute({ 0,3,1,2 });//将第3维度提前
		tensor_image = tensor_image.to(device_type);
		//网络预测
		at::Tensor outputs = module->forward({ tensor_image }).toTensor();
		//提取预测结果//
		int size_arr[10] = { 0 };//最多接受10维
		int n = outputs.dim();
		if (n > 10)
		{
			return 2;
		}
		for (int i = 0; i < n; i++)
		{
			size_arr[i] = outputs.size(i);
		}
		outputs = outputs.to(at::kCPU);
		Mat outimg(n, size_arr, CV_32F, outputs.data_ptr());
		*img_output = outimg.clone();
	}
	catch (...)
	{
		return 3;
	}
	return 0;
}

在主程序中调用:

	Mat img_predict2;
	int reu = 0;
	reu = torch_model_predict((void*)module, img, &img_predict2, 1);	
3.4 网络输出的后处理

在Python中,我们已知道网络的输出维度是:1*10647*n,n=(5+类别数)

	int size_arr[10];
	for (int i = 0; i < img_predict2.dims; i++)
	{
		cout << img_predict2.size[i]<< " ";
		size_arr[i] = img_predict2.size[i];
	}	
	Mat boxes (Size(size_arr[2], size_arr[1]), CV_32F, img_predict2.data);

这样便得到预测的框了。

3.5 阈值处理、非极大值抑制

对框进行阈值处理、nms抑制处理。这部分程序可使用基于opencv实现YOLOv3相应部分的程序。但要先对boxes的格式进行处理,每个box格式为(cx,cy,w,h,s,c0~cn)

	for (int i = 0; i < boxes.rows; i++)
	{
		boxes.at(i, 0) /= img_size;
		boxes.at(i, 1) /= img_size;
		boxes.at(i, 2) /= img_size;
		boxes.at(i, 3) /= img_size;
	}

img_size为416。
然后将boxes转为vector,便可调用postprocess函数了。
(https://download.csdn.net/download/xiaohuolong1827/34664248)

3.6 几点注意的地方 (1)维度顺序

在制作网络的输入tensor时,使用torch::from_blob要注意维度顺序:
{ 1,img.rows, img.cols,img.channels() },即batch、行、列、通道数。

(2)GPU或CPU需要严格对应

Yolov3在libtroch上进行预测时,是否使用GPU需要与保存为pt文件时保持一致,即:在python上保存pt文件时,若模型是在CPU中,则在libtorch进行预测时,也需要将模型放在cpu中;如果在保存为pt文件时,模型是放在GPU中,则在libtorch中进行预测时,需要将模型放在GPU中。
将模型放在GPU或CPU的方法是:model.to(‘cpu’)、model.to(‘cuda’),图像tensor也要做同样的处理。
这一点,与unet不同,unet在libtorch上进行预测时,只需要保证model和图像tensor位于同样的device中(CPU或cuda)即可,无需关注在生成pt文件时,模型处于GPU或CPU中。原因未探究。

4. 其它

该工程基于VS2017实现,可形成dll工程,形成dll文件,便可在vs2013、vs2015中调用了。
真是又水了一篇水文。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/917190.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号