在要求低延迟、脚本部署的生存环境,C++是更被青睐的语言。在之前版本的PyTorch提供的都是Python语言的接口,PyTorch1.0版本的发布带来了C++的前端,为生产环境的部署带来了极大的方便。目前PyTorch1.3.0的稳定版本已经可以在官网下载了,本文的所有代码均运行在 cuda 10.1, cudnn 7 LibTorch1.3.0环境下。

1. 将Pytorch Model转换为Torch Script

首先,C++能够理解的模型不是原生的Python版本的模型,而是需要通过Torch Script编译和序列化Python模型,C++调用序列化后的模型进行预测。

官方给出了两种将PyTorch模型转换为Torch Script的方法,第一种是通过torch.jit.trace方法,该方法缺点是在forward()中不能有复杂的条件控制,优点是操作比较方便;第二种是通过torch.jit.script方法进行转换,该方法允许forward()中有条件控制。

1.1 通过torch.jit.trace方法转换

我们先新建一个简单的线性模型

class MyModel(nn.Module):
    def __init__(self, N, M):
        super(MyModel, self).__init__()
        self.linear = nn.Linear(N, M)

    def forward(self, inputs):
        output = self.linear(inputs)
        return output

接下来我们仅需一行代码即可完成转换

B, N, M = 64, 32, 8
model = MyModel(N, M)
data = torch.rand(B, N)
# Use torch.jit.trace to generate a torch.jit.ScriptModule via tracing.
traced_script_module = torch.jit.trace(model, data)

traced_script_module即为转换好的C++需要的模型。可以调用save()函数保存模型。

traced_script_module.save("[model.pt](<http://model.pt/>)")

1.2 使用torch.jit.script方法

1.0.0的版本中,该方法需要重新写一个类,这个类继承torch.jit.ScriptModule,同时对需要使用的方法添加@torch.jit.script_method装饰器,较为麻烦。在最新的1.3.0版本中已经简化模型仍然继承的是torch.nn.Module,且不需要使用装饰器,直接使用torch.jit.script方法即可,非常方便。

模型代码不变:

class MyModel(nn.Module):
    def __init__(self, N, M):
        super(MyModel, self).__init__()
        self.linear = nn.Linear(N, M)

    def forward(self, inputs):
        output = self.linear(inputs)
        return output

保存模型之前需要调用torch.jit.script将模型转换为ScriptModule:

B, N, M = 64, 32, 8
model = MyModel(N, M)
traced_script_module = torch.jit.script(model)
traced_script_module.save("model.pt")

2. C++模型加载和预测

PyTorch的C++接口官方包名为LibTorch,可以在官网下载,无需编译即可使用。

2.1 模型加载