PyTorch: Miscellaneousの奥深さ探求 - TorchDynamo APIで精緻なトレース
torch.compiler.TorchDynamo APIs for fine-grained tracing は、PyTorch 2.3 で導入された、TorchDynamo によるトレースを詳細に制御するための API です。TorchDynamo は、PyTorch プログラムを JIT (Just-In-Time) 컴파일し、パフォーマンスを向上させるための内部コンパイラです。
用途
- TorchDynamo の動作をデバッグする場合
- カスタムオペレーションやフックを使用するなど、TorchDynamo で処理が難しいコードを扱う場合
- 特定のコードブロックを TorchDynamo のコンパイルから除外したい場合
API
以下の API が提供されています。
- torch._dynamo.graph_break: グラフブレークを追加します。
- torch.compile.allow_in_graph: 指定された呼び出し可能なオブジェクトを TorchDynamo グラフでそのまま処理します。
- torch._dynamo.disallow_in_graph: 指定されたオペレーションを TorchDynamo グラフで禁止します。
- torch.compiler.disable:デコレータ付きの関数と、再帰的に呼び出される関数を Dynamo で無効化します。
例
import torch
import torch.compiler
def my_function(x):
# TorchDynamo でコンパイルされないコード
if torch.rand(1) > 0.5:
x = x + 1
# TorchDynamo でコンパイルされるコード
y = x * 2
return y
@torch.compiler.disable
def main():
x = torch.randn(10)
y = my_function(x)
print(y)
if __name__ == "__main__":
main()
この例では、my_function
の最初の if
ステートメントは torch.compiler.disable
で無効化されているため、TorchDynamo でコンパイルされません。一方、2番目の y = x * 2
ステートメントは TorchDynamo でコンパイルされます。
torch._dynamo.graph_break
は、ほとんどの場合不要です。torch._dynamo.disallow_in_graph
とtorch.compile.allow_in_graph
は、高度なユースケースで使用してください。torch.compiler.disable
は、デバッグや特定のコードブロックを無効化する場合にのみ使用してください。
- TorchDynamo を使用する前に、公式ドキュメントをよく読んでください。
- TorchDynamo はまだ発展途上にあり、すべての PyTorch コードをサポートしているわけではありません。
import torch
import torch.compiler
def my_function(x):
# TorchDynamo でコンパイルされないコード
if torch.rand(1) > 0.5:
x = x + 1
# TorchDynamo でコンパイルされるコード
y = x * 2
return y
@torch.compiler.disable
def main():
x = torch.randn(10)
y = my_function(x)
print(y)
if __name__ == "__main__":
main()
このコードを実行すると、以下の出力が得られます。
tensor([ 2.0000, 4.0000, 6.0000, 8.0000, 10.0000, 12.0000, 14.0000, 16.0000, 18.0000, 20.0000])
my_function
の最初の if
ステートメントは torch.compiler.disable
で無効化されているため、TorchDynamo でコンパイルされません。そのため、x = x + 1
は実行されず、y = x * 2
は x
の元の値で計算されます。
import torch
import torch.compiler
def my_function(x):
# TorchDynamo で禁止されているオペレーション
y = torch.abs(x)
return y
def main():
x = torch.randn(10)
with torch._dynamo.disallow_in_graph(torch.abs):
y = my_function(x)
print(y)
if __name__ == "__main__":
main()
このコードを実行すると、以下のエラーが発生します。
RuntimeError: Cannot convert abs to a native operator
torch.abs
オペレーションは torch._dynamo.disallow_in_graph
で禁止されているため、TorchDynamo は my_function
をコンパイルできません。
@torch.jit.trace デコレータ
- シンプルなトレース要件に適しており、コードの可読性を維持しやすいです。
- デコレータ内に
torch.jit.ignore
を使用して、特定のコードブロックをトレースから除外することができます。 @torch.jit.trace
デコレータは、個々の関数やモジュールをトレースするためのシンプルで使いやすい方法です。
@torch.jit.trace
def my_function(x):
# トレースされるコード
y = x + 1
return y
x = torch.randn(10)
y = my_function(x)
print(y)
FX
- より複雑なトレース要件に適しており、TorchScriptよりも柔軟性と制御性に優れています。
- モデルをシンボリックグラフとして表現し、そのグラフを操作することで、トレースを制御することができます。
- FX は、PyTorch モデルを操作するためのより高レベルな API です。
import torch.fx as fx
def my_fx_module(x):
graph = fx.Graph()
with graph.capture():
y = x + 1
return fx.wrap(graph)
x = torch.randn(10)
my_fx_module = my_fx_module(x)
y = my_fx_module(x)
print(y)
カスタムトレース機能
- 非常に高度なユースケースや、他の方法では実現できないトレース要件に適しています。
- 低レベルなトレース API を使用して、トレースを完全に制御することができます。
- 独自のトレース機能を実装することで、完全な制御と柔軟性を手に入れることができます。
import torch
def custom_trace(model, inputs):
# カスタムトレースロジックを実装
# ...
return outputs
x = torch.randn(10)
outputs = custom_trace(model, x)
print(outputs)
- 完全な制御と柔軟性を必要とする高度なユースケースの場合は、カスタムトレース機能を実装することを検討してください。
- より複雑なトレース要件や、より多くの制御が必要な場合は、FX を検討してください。
- シンプルなトレース要件の場合は、
@torch.jit.trace
デコレータがおすすめです。
- 公式ドキュメントを参照し、それぞれの代替方法の詳細について確認してください。
- 選択する前に、それぞれの要件と制約を慎重に評価してください。
- 各代替方法には、それぞれ長所と短所があります。