博主曾经在试过用C++调用tensorflow模型失败后弃坑,选择了C++调用Pytorch模型,虽然也是一路踩坑,但是最终结果还是成功了,固在此记录一下。
step1:
下载pytorch:可以根据官网自行选择符合自己电脑和环境的pytorch版本
下载libtorch(一个让pytorch模型能被C++调用的库):最好选择和pytorch版本一样的libtorch,否则好像也会也版本兼容问题(但是博主torch版本1.0.0,libtorch1.7.1也能用= = )
step2:
训练pytorch模型,博主这儿训练了一个简单的二分类模型,输入是一个float类型的一维数据,输出是一个二维的tensor张量,分别代表该数据为类型0/1的概率
导出对应的torch script:
traced_script_module = torch.jit.trace(net, text) # 保存模型 traced_script_module.save("D:/***/torch_script_eval.pt")
step3:
在clion中,调用torch_script_eval.pt,这儿来了第一个坑
在使用如下语句调用模型时报错找不到路径:
string path ="D:/***/torch_script_eval.pt"; torch::jit::Module module = torch::jit::load(path);
博主的代码和模型都是放在D盘中,但是我通过Clion的wsl功能,链接到了windows的Ubuntu子系统下,用了子系统的环境,包括libtorch都是放在子系统中的,
所以这里的访问路径并不能直接从D盘访问,而是应该站在子系统的角度去访问,改为如下就能成功找到模型了:
string path ="/mnt/d/***/torch_script_eval.pt"; torch::jit::Module module = torch::jit::load(path);
step4:
博主想使用我训练时候的数据,进行测试,看看在c++中调用和python调用结果是否一样,于是我从csv文件中访问我的数据,并且进行测试
// 加载数据 string pos_path="/mnt/d/***/data/pos_test1.csv"; string neg_path="/mnt/d/***/data/neg_test1.csv"; ifstream fin(neg_path); //打开文件流操作 string line = ""; vector<torch::jit::IValue> inputs; while (getline(fin, line)) //整行读取,换行符“\n”区分,遇到文件尾标志eof终止读取 { // line 中格式为string,且末尾带一个‘\r‘ istringstream sin(line); //将整行字符串line读入到字符串流istringstream中 getline(sin,line,‘\r‘); //第一行是id,跳过 if( strcmp(line.c_str(),"id") == 0) continue; float tmp; tmp = atof(line.c_str()); torch::Tensor test = torch::ones({1, 1}); at::Tensor t = test.variable_data(); t[0][0] = tmp; //将一个数字改为一个1*1的tensor矩阵 inputs.clear(); inputs.push_back(test); at::Tensor output = module.forward(inputs).toTensor();//输出两个数字,分别对应类别0/1的分数 cout << output<<endl; }
这是最终成功的代码,其中的重点在于,我需要向module.forward()方法中输入一个vector,且vector中的数据结构应该是一个1*1的tensor张量(没错,坑在这儿,要如何将自己的一个一维float数据转换为1*1的tensor张量,博主在坑里躺了很久)
最终采用的方法如下:
float tmp; tmp = atof(line.c_str()); torch::Tensor test = torch::ones({1, 1}); at::Tensor t = test.variable_data(); t[0][0] = tmp; //将一个数字改为一个1*1的tensor矩阵
这个方法可能不是最优的,但是确实是有效地
先用torch::ones({1,1})方法,生成一个1*1的tensor张量,当然,里面的数据是1
然后将test.variable_data()赋值给一个at::Tensor类,据说at::Tensor类才可以修改里面的数据,torch::Tensor不可以
然后at::Tensor支持随机访问,此时用t[0][0]=tmp,就成功构造了一个1*1的一维张量,且里面包含的数据是自己定义的数据啦
原文:https://www.cnblogs.com/massami1999/p/14379854.html