基于Pytorch Mobile在安卓手机端部署深度估计模型
1.选取torch版本的深度估计模型
深度估计模型这里选择torch版本的Monodepth,代码地址:https://github.com/OniroAI/MonoDepth-PyTorch,文章链接:https://arxiv.org/abs/1609.03677。
建议在实现本文之前,先跑通torch的官方教程,https://github.com/pytorch/android-demo-app,本文建立在能跑通示例中语义分割模型的基础上。
Monodepth代码中需要使用的部分:
2.修改模型实现代码
整个网络设计中只使用pytorch定义的方法或python原生的语法,不能使用其他第三方框架如Numpy,Opencv。该例中,模型定义在models_resnet.py中,以Resnet18_md为例,需要修改的部分为:
1.代码中使用numpy实现的操作用原生的python库进行代替:
class conv(nn.Module):
def __init__(self, num_in_layers, num_out_layers, kernel_size, stride):
super(conv, self).__init__()
self.kernel_size = kernel_size
self.conv_base = nn.Conv2d(num_in_layers, num_out_layers, kernel_size=kernel_size, stride=stride)
self.normalize = nn.BatchNorm2d(num_out_layers)
def forward(self, x):
p = int(np.floor((self.kernel_size-1)/2)) #使用Numpy实现需要修改 np.floor ==》 math.floor ,即int(math.floor((self.kernel_size-1)/2))
p2d = (p, p, p, p)
x = self.conv_base(F.pad(x, p2d))
x = self.normalize(x)
return F.elu(x, inplace=True)
class maxpool(nn.Module):
def __init__(self, kernel_size):
super(maxpool, self).__init__()
self.kernel_size = kernel_size
def forward(self, x):
p = int(np.floor((self.kernel_size-1) / 2)) #使用Numpy实现需要修改 np.floor ==》 math.floor
p2d = (p, p, p, p)
return F.max_pool2d(F.pad(x, p2d), self.kernel_size, stride=2)
2.代码中过期的pytorch函数重新实现,因为Pytorch Mobile需要的pytorch版本很新,因此有些旧的实现已经在新版本中被修改:
self.udisp4 = nn.functional.interpolate(self.disp4, scale_factor=2, mode='bilinear', align_corners=True)
修改为:
udisp4 = nn.functional.interpolate(disp4, scale_factor=2., mode='bilinear', align_corners=True)
scale_factor在新版本中只能是浮点数,并且udisp4和disp4并没有在__init__()中定义为属性,因此在这里去掉self,否则Pytorch Mobile编译会报错。
3.修改输出:
return self.disp1, self.disp2, self.disp3, self.disp4
修改为
return disp1
这里输出四个视差是为了在多尺度下做Loss,在迁移到手机上时我们只用选择最大的尺度输出即可。
3.Pytorch生成ptl模型
import torch
from PIL import Image
from torchvision import transforms
from torch.utils.mobile_optimizer import optimize_for_mobile
from utils import get_model
image = Image.open("O:\\xxx\\0.jpg") #读取一张图片用来测试输出尺寸是否满足预期
preprocess = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
input = preprocess(image) #转换成Tensor
model = get_model('resnet18_md', 3, True) #获取模型,模型的定义代码为models_resnet.py。
model.load_state_dict(torch.load("O:\\xxx\\monodepth_resnet18_001.pth")) #读取模型的预训练参数,预训练文件下载地址https://github.com/OniroAI/MonoDepth-PyTorch
input = input.unsqueeze(0)
output = model(input) #使用模型处理一张图片
print(output.shape) #测试尺度是否正常
model.eval()
scripted_module = torch.jit.script(model