赞
踩
根据项目组要求,最近用Pytorch完成了U-net训练BraTS2019数据的任务,输出模型并在C++上重现部署,简单说说我遇到的坑,可按目录浏览:
步骤1:先在pytorch验证你的模型(.pth)是否能够重现结果,一般来讲都可以成功复原的,这一步很重要,在C++上重现时最好有对照,以免思路混乱,这里贴出我的测试一张图片的部分代码:
def load_model(): net = UNet2D(1, 5, 64 ).to(torch.device('cpu')) #cpu测试 state_dict = torch.load(saved_model_path,map_location='cpu') net.load_state_dict(state_dict,strict=True) #记得加True return net if __name__ == "__main__": np.set_printoptions(threshold=np.inf) #为了看完整的结果 net = load_model() img = sitk.ReadImage('BraTS19_2013_2_1_flair.nii.gz')#需要安装SimpleITK这个包来读nii nda = sitk.GetArrayFromImage(img) test_data = np.asarray(nda[110]) test_data = norm_vol(test_data)#这里的归一化自己写的,按照自己需求来确定是否要做归一化 #转成tensor test_data = torch.from_numpy(test_data) test_data = torch.tensor(test_data,dtype=torch.float32) #按照网络输入需求拓展维度 test_data=torch.unsqueeze(test_data,0) test_data=torch.unsqueeze(test_data,1) #预测阶段 with torch.no_grad(): net.eval() predict = net(test_data) predict = F.softmax(predict,dim=1) predict = torch.max(predict,dim=1)[1] predict = predict.squeeze().long().data io.imwrite('result.jpg', predict)#imageio工具包
步骤2:将pth模型转至pt文件,后续用于C++预测,这个过程官方的例子里也有,这是我按照自己需求来改的代码:
import torch
import torch.nn as nn
from unet2d import UNet2D
saved_model_path = 'best.pth'
net = UNet2D(1, 5, 64 ).to(torch.device('cpu'))
state_dict = torch.load(saved_model_path,map_location='cpu')
net.load_state_dict(state_dict,strict=True)#同样记得TRUE
net.eval()#重要!
example = torch.rand(1, 1, 240, 240).float()
traced = torch.jit.trace(net, example)
traced.save('best.pt')
其他:可以按压缩包的打开方式来打开pt文件来查看模型追踪是否正确:
其中这个文件可以查看整体的追踪结果。
libtorch的安装以及cmake运行在我之前的博客里有提到,可以翻一下对号入座来安装,网上教程也很多,这里不加赘述,我pytorch和libtorch都是1.4.0。
部分C++部署代码如下:
int main() { auto tensor1 = torch::empty(1 * 1 * 240 * 240); float* data1 = tensor1.data<float>(); for (int i = 0; i < 1; i++) { for (int j = 0; j < 1; j++) { for (int x = 0; x < 240; x++) { for (int y = 0; y < 240; y++) { *data1++ = (itk[110][x][y]-min*1.0)/(max.0-1.0); } } } } auto t = tensor1.resize_({ 1,1,240,240 }); t=t.div(255); torch::jit::script::Module module = torch::jit::load(model_path,torch::kCPU); //load model // init model module.eval(); cout << "model input is ok\n"; vector<torch::jit::IValue> inputs; //def an input inputs.emplace_back(t.toType(torch::kFloat32)); float start = getTickCount(); auto result = module.forward( inputs ).toTensor(); //前向传播获取结果 = net(image) float end = getTickCount(); float last = end - start; cout << "time consume: " << (last / getTickFrequency()) << endl; //rescalling input element into range(0,1) and sum to 1; output size is same to input auto prob = result.softmax(1);//torch::nn::functional::softmax(result, 1); auto prediction = prob.max(1);//tuple类型 inputs.pop_back(); std::tuple_element<1, decltype(prediction)>::type cnt = std::get<1>(prediction); std::cout << "cnt = " << cnt.sizes() << std::endl;// 1 240 240 cnt=cnt.squeeze().data;//这句代码有问题,最好按照需求来确认要不要写 cout << "result sizes:" << cnt.sizes() << endl; //240 240 Mat m(cnt.size(0), cnt.size(1), CV_32FC1, cnt.data()); imwrite("res.jpg", m); return 0; }
从上述代码可以看出流程:
读入数据->载入模型->将数据整理成tensor(这里我没用torch::from_blob)->预测->结果整理->输出
大体流程与上面的pytorch流程一致。
但在前向传播这一步的时候,结果输出nan值:
很明显是不正确的,问题是出在我加了一句t=t.div(255);,导致我数据类型出错,问题发生点可以看我在pytorch论坛里的提问:
Pytorch Forums–Having problems in segmenting image when using libtorch
结果输出有很多情况,就我而言,遇到的问题是输出全黑的图片和只有部分分割结果的图片:
这种情况最好检查输入tensor的值,是否与pytorch上输出的一致
这种情况最好确认是否需要加==cnt.squeeze.data();==这一句代码,我删除以后就没问题了。
因为我只训练了50个epoch,所以结果很差,将就着先用。
先写到这,想到再补充。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。