blob: 931aed7ab7a92f5c64fe047746053afe2975741a [file] [log] [blame]
torch::deploy
=============
``torch::deploy`` is a system that allows you to run multiple embedded Python
interpreters in a C++ process without a shared global interpreter lock. For more
information on how ``torch::deploy`` works internally, please see the related
`arXiv paper <https://arxiv.org/pdf/2104.00254.pdf>`_.
.. warning::
This is a prototype feature. Only Linux x86 is supported, and the API may
change without warning.
Getting Started
---------------
Installing ``torch::deploy``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``torch::deploy`` is not yet built by default in our binary releases, so to get
a copy of libtorch with ``torch::deploy`` enabled, follow the instructions for
`building PyTorch from source <https://github.com/pytorch/pytorch/#from-source>`_.
When running ``setup.py``, you will need to specify ``USE_DEPLOY=1``, like:
.. code-block:: bash
export CMAKE_PREFIX_PATH=${CONDA_PREFIX:-"$(dirname $(which conda))/../"}
export USE_DEPLOY=1
python setup.py bdist_wheel
python -mpip install dist/*.whl
Creating a model package in Python
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``torch::deploy`` can load and run Python models that are packaged with
``torch.package``. You can learn more about ``torch.package`` in the
``torch.package`` `documentation <https://pytorch.org/docs/stable/package.html#tutorials>`_.
For now, let's create a simple model that we can load and run in ``torch::deploy``.
.. code-block:: py
from torch.package import PackageExporter
import torchvision
# Instantiate some model
model = torchvision.models.resnet.resnet18()
# Package and export it.
with PackageExporter("my_package.pt") as e:
e.intern("torchvision.**")
e.extern("sys")
e.save_pickle("model", "model.pkl", model)
Now, there should be a file named ``my_package.pt`` in your working directory.
.. note::
Currently, ``torch::deploy`` supports only the Python standard library and
``torch`` as ``extern`` modules in ``torch.package``. In the future we plan
to transparently support any Conda environment you point us to.
Loading and running the model in C++
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Let's create a minimal C++ program to that loads the model.
.. code-block:: cpp
#include <torch/deploy.h>
#include <torch/script.h>
#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;
}
// Start an interpreter manager governing 4 embedded interpreters.
torch::deploy::InterpreterManager manager(4);
try {
// Load the model from the torch.package.
torch::deploy::Package package = manager.loadPackage(argv[1]);
torch::deploy::ReplicatedObj model = package.loadPickle("model", "model.pkl");
} catch (const c10::Error& e) {
std::cerr << "error loading the model\n";
return -1;
}
std::cout << "ok\n";
}
This small program introduces many of the core concepts of ``torch::deploy``.
An ``InterpreterManager`` abstracts over a collection of independent Python
interpreters, allowing you to load balance across them when running your code.
Using the ``InterpreterManager::loadPackage`` method, you can load a
``torch.package`` from disk and make it available to all interpreters.
``Package::loadPickle`` allows you to retrieve specific Python objects
from the package, like the ResNet model we saved earlier.
Finally, the model itself is a ``ReplicatedObj``. This is an abstract handle to
an object that is replicated across multiple interpreters. When you interact
with a ``ReplicatedObj`` (for example, by calling ``forward``), it will select
an free interpreter to execute that interaction.
Building and running the application
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Assuming the above C++ program was stored in a file called, `example-app.cpp`, a
minimal CMakeLists.txt file would look like:
.. code-block:: cmake
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(deploy_tutorial)
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)
The last step is configuring and building the project. Assuming that our code
directory is laid out like this:
.. code-block:: none
example-app/
CMakeLists.txt
example-app.cpp
We can now run the following commands to build the application from within the
``example-app/`` folder:
.. code-block:: bash
mkdir build
cd build
# Point CMake at the built version of PyTorch we just installed.
SITE_PACKAGES="$(python -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())')"
cmake -DCMAKE_PREFIX_PATH="$SITE_PACKAGES/torch" ..
cmake --build . --config Release
Now we can run our app:
.. code-block:: bash
./example-app /path/to/my_package.pt
Executing ``forward`` in C++
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
One you have your model loaded in C++, it is easy to execute it:
.. code-block:: cpp
// Create a vector of inputs.
std::vector<torch::jit::IValue> inputs;
inputs.push_back(torch::ones({1, 3, 224, 224}));
// Execute the model and turn its output into a tensor.
at::Tensor output = model(inputs).toTensor();
std::cout << output.slice(/*dim=*/1, /*start=*/0, /*end=*/5) << '\n';
Notably, the model's forward function is executing in Python, in an embedded
CPython interpreter. Note that the model is a ``ReplicatedObj``, which means
that you can call ``model()`` from multiple threads and the forward method will
be executed on multiple independent interpreters, with no global interpreter
lock.