1.1はじめに
エンドツーエンドのディープラーニングフレームワークとして、PyTorchはバージョン1.0以降の本番環境の展開条件が良好です。Web側にデプロイするためのRESTAPIを作成することに加えて(リファレンス)、ソフトウェア側のデプロイメントにも広範な要件があります。特に最近リリースされたバージョン1.5は、より安定したC ++フロントエンドAPIを提供します。
産業界と学界の最大の違いは、産業界は地上に展開する必要があるということです。学界はモデルの精度要件に関心があり、モデルの展開パフォーマンスにはあまり関心がありません。一般的に、ディープラーニングフレームワークを使用してモデルをトレーニングした後は、Pythonで簡単な推論のデモンストレーションを実装できます。しかし、実稼働環境では、Pythonの移植性と速度パフォーマンスはC ++よりはるかに劣っています。したがって、深層学習アルゴリズムエンジニアの場合、Pythonは通常、アイデアの迅速な実装とモデルトレーニングに使用され、C ++はモデルの作成ツールとして使用されます。現在、PyTorchはこの2つを完全に組み合わせることができます。PyTorchモデルのデプロイを実装するコアテクノロジーコンポーネントは、TorchScriptとlibtorchです。
したがって、PyTorchベースの深層学習アルゴリズムのエンジニアリングプロセスは、おおよそ次の図に示すようになります。
1.2 TorchScript
TorchScriptはPyTorchモデルの中間表現と見なすことができ、TorchScriptで表されるPyTorchモデルはC ++で直接読み取ることができます。PyTorchは、TorchScriptを使用して、バージョン1.0以降のシリアル化されたモデルを構築できます。TorchScriptには、トレースとスクリプトの2つのアプリケーションメソッドがあります。
トレースアプリケーションの例は次のとおりです。
class MyModel(torch.nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.linear = torch.nn.Linear(4, 4)
def forward(self, x, h):
new_h = torch.tanh(self.linear(x) + h)
return new_h, new_h
# 创建模型实例
my_model = MyModel()
# 输入示例
x, h = torch.rand(3, 4), torch.rand(3, 4)
# torch.jit.trace方法对模型构建TorchScript
traced_model = torch.jit.trace(my_model, (x, h))
# 保存转换后的模型
traced_model.save('model.pt')
このコードでは、最初に単純なモデルを定義してモデルインスタンスを作成し、次に入力例を示します。Tracingメソッドの最も重要なステップは、torch.jit.traceメソッドを使用してモデルをTorchScriptに変換することです。変換されたtraced_modelオブジェクトを取得して、その計算グラフ属性とコード属性を取得できます。計算グラフのプロパティ:
print(traced_model.graph)
graph(%self.1 : __torch__.torch.nn.modules.module.___torch_mangle_1.Module,
%input : Float(3, 4),
%h : Float(3, 4)):
%19 : __torch__.torch.nn.modules.module.Module = prim::GetAttr[name="linear"](%self.1)
%21 : Tensor = prim::CallMethod[name="forward"](%19, %input)
%12 : int = prim::Constant[value=1]() # /var/lib/jenkins/workspace/beginner_source/Intro_to_TorchScript_tutorial.py:188:0
%13 : Float(3, 4) = aten::add(%21, %h, %12) # /var/lib/jenkins/workspace/beginner_source/Intro_to_TorchScript_tutorial.py:188:0
%14 : Float(3, 4) = aten::tanh(%13) # /var/lib/jenkins/workspace/beginner_source/Intro_to_TorchScript_tutorial.py:188:0
%15 : (Float(3, 4), Float(3, 4)) = prim::TupleConstruct(%14, %14)
return (%15)
コード属性:
print(traced_cell.code)
def forward(self,
input: Tensor,
h: Tensor) -> Tuple[Tensor, Tensor]:
_0 = torch.add((self.linear).forward(input, ), h, alpha=1)
_1 = torch.tanh(_0)
return (_1, _1)
このようにして、モデル全体をハードディスクに保存でき、この方法で保存されたモデルを他の言語環境にロードできます。
TorchScriptの別の実装はScriptメソッドであり、これはTracingメソッドの補足と見なすことができます。モデルコードにifやforループなどの制御フロープログラムが含まれている場合、Tracingメソッドは無効です。現時点では、Scriptメソッドを使用してTorchScriptを実装できます。実装方法はトレーシングと大差ありません。重要なのは、jit.tracingをjit.scriptメソッドに置き換えることです。例は次のとおりです。
scripted_model = torch.jit.script(MyModel)
scripted_model.save('model.pt')
トレースとスクリプトに加えて、2つの方法を混在させることもできますが、ここでは詳しく説明しません。つまり、TorchScriptは、コンパイラーが最適化してより効率的な実行を提供できる表現形式を提供します。
1.3 libtorch
トレーニングされたモデルをPython環境で変換した後、モデルを読み取り、コンパイルしてデプロイするには、C ++環境でPyTorchが必要です。このC ++環境のPyTorchはlibtorchです。libtorchは通常PyTorchモデルのC ++インターフェイスとして使用されるため、libtorchはPyTorchのC ++フロントエンドとも呼ばれます。
コンパイルされたlibtorchインストールパッケージは、PyTorchの公式Webサイトから直接ダウンロードできます。もちろん、ソースコードをダウンロードして自分でコンパイルすることもできます。ここで、インストールされているlibtorchのバージョンは、Python環境のPyTorchのバージョンと一致している必要があることに注意してください。
libtorchをインストールした後、それが正常であるかどうかを簡単にテストできます。たとえば、TorchScriptを使用して、事前にトレーニングされたモデルを変換します。例は次のとおりです。
import torch
import torchvision.models as models
vgg16 = models.vgg16()
example = torch.rand(1, 3, 224, 224).cuda()
model = model.eval()
traced_script_module = torch.jit.trace(model, example)
output = traced_script_module(torch.ones(1,3,224,224).cuda())
traced_script_module.save('vgg16-trace.pt')
print(output)
出力は次のとおりです。
tensor([[ -0.8301, -35.6095, 12.4716]], device='cuda:0',
grad_fn=<AddBackward0>)
次に、C ++環境に切り替えて、CmakeListsファイルを次のように記述します。
cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
project(libtorch_test)
find_package(Torch REQUIRED)
message(STATUS "Pytorch status:")
message(STATUS "libraries: ${TORCH_LIBRARIES}")
add_executable(libtorch_test test.cpp)
target_link_libraries(libtorch_test "${TORCH_LIBRARIES}")
set_property(TARGET libtorch_test PROPERTY CXX_STANDARD 11)
次のようにtest.cppコードを記述し続けます。
#include "torch/script.h"
#include "torch/torch.h"
#include <iostream>
#include <memory>
using namespace std;
int main(int argc, const char* argv[]){
if (argc != 2) {
std::cerr << "usage: example-app <path-to-exported-script-module>\n";
return -1;
}
// 读取TorchScript转化后的模型
torch::jit::script::Module module;
try {
module = torch::jit::load(argv[1]);
}
catch (const c10::Error& e) {
std::cerr << "error loading the model\n";
return -1;
}
module->to(at::kCUDA);
assert(module != nullptr);
std::cout << "ok\n";
// 构建示例输入
std::vector<torch::jit::IValue> inputs;
inputs.push_back(torch::ones({1, 3, 224, 224}).to(at::kCUDA));
// 执行模型推理并输出tensor
at::Tensor output = module->forward(inputs).toTensor();
std::cout << output.slice(/*dim=*/1, /*start=*/0, /*end=*/5) << '\n';}
test.cppをコンパイルして実行すると、出力は次のようになります。Python環境での実行結果を比較すると、基本的に同じであることがわかります。これは、現在の環境でのlibtorchのインストールに問題がないことも示しています。
ok
-0.8297, -35.6048, 12.4823
[Variable[CUDAFloatType]{1,3}]
1.4完全な展開プロセス
TorchScriptとlibtorchのこれまでの説明を通じて、実際、基本的にPyTorchのC ++デプロイメントについて説明しました。ここでは、プロセス全体を完全に見ていきます。C ++に基づくPyTorchモデルの展開プロセスは次のとおりです。
最初の一歩:
torch.jit.traceメソッドを使用して、PyTorchモデルをTorchScriptに変換します。例は次のとおりです。
import torch
from torchvision.models import resnet18
model =resnet18()
example = torch.rand(1, 3, 224, 224)
tracing.traced_script_module = torch.jit.trace(model, example)
2番目のステップ:
TorchScriptを.ptモデルファイルにシリアル化します。
traced_script_module.save("traced_resnet_model.pt")
3番目のステップ:
シリアル化されたTorchScriptモデルをC ++でインポートします。このために、呼び出し側プログラムを含むcppファイル、構成およびコンパイル用のCMakeLists.txtファイルを作成する必要があります。CMakeLists.txtファイルのサンプルコンテンツは次のとおりです。
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(custom_ops)
find_package(Torch REQUIRED)
add_executable(example-app example-app.cpp)
target_link_libraries(example-app "${TORCH_LIBRARIES}")
set_property(TARGET example-app PROPERTY CXX_STANDARD 14)
モデル呼び出しプログラムを含むexample-app.cppのサンプルコードは次のとおりです。
#include <torch/script.h> // torch头文件.
#include <iostream>#include <memory>
int main(int argc, const char* argv[]) {
if (argc != 2) {
std::cerr << "usage: example-app <path-to-exported-script-module>\n";
return -1;
}
torch::jit::script::Module module;
try {
// 反序列化:导入TorchScript模型
module = torch::jit::load(argv[1]);
}
catch (const c10::Error& e) {
std::cerr << "error loading the model\n";
return -1;
}
std::cout << "ok\n";}
2つのファイルが書き込まれた後、それらをコンパイルできます。
mkdir example_test
cd example_test
cmake -DCMAKE_PREFIX_PATH=/path/to/libtorch ..
cmake --example_test . --config Release
4番目のステップ:
モデル推論コードをexample-app.cppに追加し、以下を実行します。
std::vector<torch::jit::IValue> inputs;inputs.push_back(torch::ones({1, 3, 224, 224}));
// 执行推理并将模型转化为Tensor
output = module.forward(inputs).toTensor();std::cout << output.slice(/*dim=*/1, /*start=*/0, /*end=*/5) << '\n';
上記は、C ++でPyTorchモデルをデプロイするプロセス全体です。関連するチュートリアルについては、公式のPyTorchを参照してください:https://pytorch.org/tutorials/
総括する
モデルの展開はアルゴリズムエンジニアにとって非常に重要であり、それはあなたの仕事が実際の価値を生み出すことができるかどうかに関係しています。同様に、MySQL、Redis、C ++などの十分なエンジニアリング機能、フロントエンドとバックエンドの知識と開発技術も必要です。すべてのアルゴリズムエンジニアは、それを理解して使用できる必要があります。