PyTorch TorchScript

TorchScript converts a PyTorch model from Python into an intermediate representation that runs without a Python interpreter. This lets you deploy models in production environments where Python is unavailable — C++ applications, mobile devices, embedded systems — while keeping full PyTorch compatibility during development.

Why TorchScript Exists

Python PyTorch model:
  ✓ Flexible, easy to debug, great for research
  ✗ Requires Python runtime to execute
  ✗ Python's Global Interpreter Lock limits multi-threading
  ✗ Cannot run on mobile apps or C++ servers

TorchScript model:
  ✓ Runs without Python
  ✓ Portable to C++, mobile, edge devices
  ✓ Can be optimized and serialized to a single file
  ✓ Thread-safe for concurrent inference

Two Ways to Create TorchScript

Method 1: torch.jit.script
  → Analyzes your Python code and converts it
  → Works with control flow (if/else, loops)
  → Requires type annotations in some cases

Method 2: torch.jit.trace
  → Runs the model with example input, records operations
  → Simpler but misses data-dependent control flow
  → Best for straightforward feed-forward models

Method 1: torch.jit.script

import torch
import torch.nn as nn

class SimpleNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(4, 16)
        self.fc2 = nn.Linear(16, 2)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x

model = SimpleNet()

# Convert to TorchScript via scripting
scripted_model = torch.jit.script(model)

x   = torch.rand(8, 4)
out = scripted_model(x)
print(out.shape)   # torch.Size([8, 2])

# Save to disk
scripted_model.save('simple_net_scripted.pt')

# Load it back (no class definition needed)
loaded = torch.jit.load('simple_net_scripted.pt')
print(loaded(x).shape)   # torch.Size([8, 2])

Method 2: torch.jit.trace

model = SimpleNet()

# Provide an example input — tracing records the operations
example_input  = torch.rand(1, 4)
traced_model   = torch.jit.trace(model, example_input)

print(traced_model(torch.rand(8, 4)).shape)   # torch.Size([8, 2])

# Save
traced_model.save('simple_net_traced.pt')

Script vs Trace — When Each Breaks

Model with data-dependent control flow:

  def forward(self, x):
      if x.sum() > 0:     ← depends on actual data value
          return self.fc1(x)
      else:
          return self.fc2(x)

  → torch.jit.trace records only ONE branch (the one taken by example input)
    Any input that goes down the other branch gives WRONG results silently.
  → torch.jit.script handles both branches correctly.

Rule:
  Use script for models with if/else or loops that depend on input values.
  Use trace for simple sequential models with no conditional logic.

Inspecting TorchScript Code

scripted = torch.jit.script(SimpleNet())
print(scripted.code)
# Shows the TorchScript IR (intermediate representation):
# def forward(self, x: Tensor) -> Tensor:
#   x = torch.relu(self.fc1.forward(x))
#   return self.fc2.forward(x)

TorchScript with Control Flow

class BranchNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc_pos = nn.Linear(4, 2)
        self.fc_neg = nn.Linear(4, 2)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        if x.mean() > 0:
            return self.fc_pos(x)
        else:
            return self.fc_neg(x)

scripted = torch.jit.script(BranchNet())   # handles both branches

x_pos = torch.rand(3, 4)     # mean > 0 → uses fc_pos
x_neg = -torch.rand(3, 4)    # mean < 0 → uses fc_neg

print(scripted(x_pos).shape)
print(scripted(x_neg).shape)

Running TorchScript Models from C++

After saving a scripted model, load it from a C++ application using LibTorch. This is how PyTorch models are deployed in high-performance servers, games, and robotics.

C++ code (conceptual):
  #include <torch/script.h>

  torch::jit::script::Module model;
  model = torch::jit::load("simple_net_scripted.pt");
  model.eval();

  auto input  = torch::rand({8, 4});
  auto output = model.forward({input}).toTensor();

Optimizing for Inference

scripted = torch.jit.script(model)

# Optimize for mobile or CPU inference
optimized = torch.jit.optimize_for_inference(scripted)

x   = torch.rand(1, 4)
out = optimized(x)
print(out)

TorchScript on Mobile

TorchScript is the bridge to PyTorch Mobile (iOS and Android). After scripting and optimizing, serialize the model and bundle it with your app. The model runs fully on-device — no server call required.

from torch.utils.mobile_optimizer import optimize_for_mobile

scripted    = torch.jit.script(model)
mobile_opt  = optimize_for_mobile(scripted)
mobile_opt._save_for_lite_interpreter('model_mobile.ptl')

Summary

TorchScript converts PyTorch models to a Python-independent format that runs anywhere — C++ servers, mobile apps, and edge hardware. Use torch.jit.script for models with conditional logic or loops; use torch.jit.trace for simple sequential models. Save with .save() and load with torch.jit.load() — no class definition needed at load time. Inspect the generated code with scripted.code. Use optimize_for_mobile before deploying to iOS or Android. TorchScript is the recommended path for all PyTorch production deployments that need to operate outside a Python environment.

Leave a Comment

Your email address will not be published. Required fields are marked *