【保存版】PyTorchでモデルをトレースする3つの方法:torch.export.FakeTensorを超えた手法も紹介


PyTorch の torch.export 関数は、Tensor 計算グラフを事前コンパイル (AOT) してトレースし、そのグラフを ExportedProgram オブジェクトとしてカプセル化します。この ExportedProgram は、シリアル化して保存したり、異なる入力で後から実行したりすることができます。

torch.export.FakeTensor の役割

torch.export 関数でトレースを行う際、torch.export.FakeTensor を使用すると、計算を実際に行わずに、Tensor のサイズやデータ型などの情報を取得することができます。これは、特に大規模なモデルをトレースする場合に有効です。

FakeTensor は、実際の Tensor と同様に動作しますが、実際にはデータを持っていません。これは、計算を実行せずに、Tensor の形状やデータ型などの情報を取得する必要がある場合に役立ちます。

torch.export.FakeTensor の使用方法

torch.export.FakeTensor を使用するには、まず FakeTensorMode オブジェクトを作成する必要があります。このオブジェクトは、トレース対象のコードを実行するコンテキストを設定します。

from torch._subclasses.fake_tensor import FakeTensorMode

fake_mode = FakeTensorMode()

次に、fake_mode オブジェクトを使用して、実際の Tensor を FakeTensor に変換します。

x = torch.randn(10, 20)
fake_x = fake_mode.from_real_tensor(x)

FakeTensortorch.export 関数に渡すことで、計算を実行せずに Tensor の形状やデータ型などの情報を取得することができます。

def my_function(x):
    # 計算を実行する

@torch.export(my_function, fake_args=(fake_x,))
def my_exported_function(x):
    # 計算を実行しない

torch.export.FakeTensor の利点

  • モデルのシリアル化と保存を容易化
  • 計算を実行せずに Tensor の形状やデータ型などの情報を取得
  • 大規模なモデルのトレース時間を短縮
  • FakeTensor を使用してトレースを行った場合、モデルをデバッグするのが難しくなる場合があります。
  • FakeTensor は実際の Tensor とは異なる動作をする場合があります。


import torch
from torch._subclasses.fake_tensor import FakeTensorMode

# モデル定義
class LinearRegression(torch.nn.Module):
    def __init__(self, in_features, out_features):
        super().__init__()
        self.linear = torch.nn.Linear(in_features, out_features)

    def forward(self, x):
        return self.linear(x)

# モデルを作成
model = LinearRegression(2, 1)

# FakeTensorMode を作成
fake_mode = FakeTensorMode()

# 入力データを FakeTensor に変換
x = torch.randn(10, 2)
fake_x = fake_mode.from_real_tensor(x)

# モデルをトレースして ExportedProgram を取得
traced_model = torch.jit.trace(model, fake_x)

# ExportedProgram をシリアル化して保存
torch.jit.save(traced_model, "model.pt")

# モデルをロードして実行
loaded_model = torch.jit.load("model.pt")
y = loaded_model(x)
print(y)

このコードでは、まず LinearRegression クラスというシンプルな線形回帰モデルを定義します。次に、FakeTensorMode オブジェクトを作成して、トレース対象のコードを実行するコンテキストを設定します。

その後、入力データ (x) を FakeTensor に変換し、torch.jit.trace 関数を使用してモデルをトレースします。トレースされたモデルは ExportedProgram オブジェクトとしてカプセル化され、torch.jit.save 関数を使用してシリアル化して保存されます。

最後に、シリアル化されたモデルを torch.jit.load 関数を使用してロードし、実際の入力データ (x) で実行します。

  • torch.jit.save 関数を使用して保存されたモデルは、PyTorch でのみ実行できます。
  • モデルをトレースする前に、モデルのトレーニングを完了しておく必要があります。
  • このコードは、PyTorch 1.10 以降で使用できます。


ランダムな入力を使用する

最も簡単な代替方法は、トレース対象の関数にランダムな入力を使用することです。これは、torch.randntorch.rand などの関数を使用して行うことができます。

import torch

def my_function(x):
    # 計算を実行する

@torch.export(my_function, args=(torch.randn(10, 20),))
def my_exported_function(x):
    # 計算を実行しない

この方法は、単純ですが、入力データの分布が実際のデータと異なる場合、トレースされたモデルの精度が低下する可能性があります。

動的な形状を使用する

torch.export.FakeTensor の代わりに、動的な形状を使用することができます。動的な形状は、Tensor の形状をシンボリックな表現で表すことができます。

import torch
from torch.jit.annotations import shape

def my_function(x: torch.Tensor) -> torch.Tensor:
    # 計算を実行する

@torch.export(my_function, shape_dict={"x": [shape(None, 20)]})
def my_exported_function(x):
    # 計算を実行しない

この方法は、torch.export.FakeTensor よりも柔軟性が高く、入力データの分布が実際のデータと異なる場合でも、トレースされたモデルの精度を維持することができます。

TorchScript のトレースツールを使用する

TorchScript には、torch.jit.trace_moduletorch.jit.trace などのトレースツールが用意されています。これらのツールは、torch.export.FakeTensor を使用せずにモデルをトレースすることができます。

import torch
import torch.jit

model = LinearRegression(2, 1)

traced_model = torch.jit.trace(model, torch.randn(10, 2))

この方法は、最も汎用性が高く、複雑なモデルをトレースするのに適しています。

ONNX を使用する

ONNX は、機械学習モデルを表現するためのオープンフォーマットです。PyTorch には、ONNX 形式にモデルをエクスポートするための torch.onnx.export 関数が用意されています。

import torch
import torch.onnx

model = LinearRegression(2, 1)

torch.onnx.export(model, torch.randn(10, 2), "model.onnx")

この方法は、PyTorch 以外のフレームワークでモデルを実行したい場合に役立ちます。

torch.export.FakeTensor は、PyTorch の torch.export 関数でトレースを行う際に役立つツールですが、いくつかの代替方法があります。

  • ONNX を使用する
  • TorchScript のトレースツールを使用する
  • 動的な形状を使用する
  • ランダムな入力を使用する