TorchScript: ScriptModule.modules() 関数の詳細解説と代替方法
torch.jit.ScriptModule.modules()
は、TorchScript ScriptModule 内のすべてのサブモジュールを階層的に返すジェネレータ関数です。サブモジュールは、nn.Module
のサブクラスである任意のオブジェクトです。
使用方法
for name, module in model.modules():
print(f"{name}: {module}")
このコードは、model
という名前の ScriptModule 内のすべてのサブモジュールをループし、各サブモジュールの名前とオブジェクトを出力します。
例
import torch
import torch.nn as nn
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 32, 3, 1)
self.conv2 = nn.Conv2d(32, 64, 3, 1)
self.fc = nn.Linear(9600, 10)
model = MyModel()
script_model = torch.jit.script(model)
for name, module in script_model.modules():
print(f"{name}: {module}")
このコードは、以下の出力を生成します。
conv1: Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=True)
conv2: Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=True)
fc: Linear(in_features=9600, out_features=10, bias=True)
torch.jit.ScriptModule.modules()
は、TorchScript でトレースされたモデルをデバッグする際に役立ちます。- モジュール名とオブジェクトに加えて、
torch.jit.ScriptModule.modules()
は、各サブモジュールの属性とパラメータにもアクセスできます。 torch.jit.ScriptModule.modules()
は、再帰的にサブモジュールを探索するため、ネストされたサブモジュールもすべて返されます。
サブモジュールの属性とパラメータへのアクセス
import torch
import torch.nn as nn
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 32, 3, 1)
self.conv2 = nn.Conv2d(32, 64, 3, 1)
self.fc = nn.Linear(9600, 10)
model = MyModel()
script_model = torch.jit.script(model)
for name, module in script_model.modules():
print(f"{name}:")
print(f" attributes: {module.__dict__}")
print(f" parameters: {module.parameters()}")
conv1:
attributes: {'weight': Parameter containing: [32, 1, 3, 3], 'bias': Parameter containing: [32]}
parameters: [Parameter containing: [32, 1, 3, 3], Parameter containing: [32]]
conv2:
attributes: {'weight': Parameter containing: [64, 32, 3, 3], 'bias': Parameter containing: [64]}
parameters: [Parameter containing: [64, 32, 3, 3], Parameter containing: [64]]
fc:
attributes: {'weight': Parameter containing: [10, 9600], 'bias': Parameter containing: [10]}
parameters: [Parameter containing: [10, 9600], Parameter containing: [10]]
特定の条件に一致するサブモジュールのフィルタリング
import torch
import torch.nn as nn
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 32, 3, 1)
self.conv2 = nn.Conv2d(32, 64, 3, 1)
self.fc = nn.Linear(9600, 10)
model = MyModel()
script_model = torch.jit.script(model)
for name, module in script_model.modules() if isinstance(module, nn.Conv2d):
print(f"{name}: {module}")
conv1: Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=True)
conv2: Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=True)
import torch
import torch.nn as nn
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 32, 3, 1)
self.conv2 = nn.Sequential(
nn.Conv2d(32, 64, 3, 1),
nn.ReLU(),
nn.MaxPool2d(2, 2)
)
self.fc = nn.Linear(9600, 10)
model = MyModel()
script_model = torch.jit.script(model)
def print_submodule_tree(module, indent=0):
print(f"{' ' * indent}{module.__class__.__name__}: {module}")
for name, child in module.named_children():
print_submodule_tree(child, indent + 4)
print_submodule_tree(script_model)
MyModel: MyModel
conv1: Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=True)
conv2: Sequential
手動の再帰処理
最も基本的な代替方法は、手動で再帰処理を行うことです。これは、サブモジュールの探索方法を完全に制御したい場合に役立ちます。
def traverse_modules(module, indent=0):
print(f"{' ' * indent}{module.__class__.__name__}: {module}")
for name, child in module.named_children():
traverse_modules(child, indent + 4)
model = MyModel()
script_model = torch.jit.script(model)
traverse_modules(script_model)
利点
- コードが簡潔になる場合がある
- サブモジュールの探索方法を完全に制御できる
欠点
- 再帰処理のロジックを実装する必要がある
- 煩雑でエラーが発生しやすい
inspect モジュール
inspect
モジュールを使用して、ScriptModule 内のサブモジュールを反復処理することもできます。 これは、より簡潔で、エラーが発生しにくい方法です。
import inspect
def traverse_modules(module):
for name, obj in inspect.getmembers(module):
if inspect.ismodule(obj):
print(f"{name}: {obj}")
traverse_modules(obj)
model = MyModel()
script_model = torch.jit.script(model)
traverse_modules(script_model)
利点
- エラーが発生しにくい
- コードが簡潔で読みやすい
欠点
inspect
モジュールのインポートが必要- サブモジュールの探索方法を完全に制御できない
カスタムジェネレータ
ScriptModule クラスのサブクラスを作成し、modules()
メソッドをオーバーライドしてカスタム ジェネレータを実装することもできます。 これは、複雑なサブモジュール階層を持つ場合や、サブモジュールに対して特別な処理を実行する必要がある場合に役立ちます。
class MyScriptModule(torch.jit.ScriptModule):
def __init__(self, model):
super().__init__(model)
def modules(self, recurse=True):
yield self
for name, module in self.named_children():
yield from module.modules(recurse=recurse)
model = MyModel()
script_model = MyScriptModule(model)
for module in script_model.modules():
print(module)
利点
- サブモジュールに対して特別な処理を実行できる
- サブモジュールの探索方法を完全に制御できる
欠点
- ScriptModule クラスのサブクラスを作成する必要がある
- コードが煩雑でエラーが発生しやすい
最適な代替方法の選択
最適な代替方法は、ニーズと要件によって異なります。
- 複雑なサブモジュール階層を持つ場合や、サブモジュールに対して特別な処理を実行する必要がある場合は、カスタム ジェネレータを実装します。
- コードを簡潔で読みやすくしたい場合は、
inspect
モジュールを使用します。 - サブモジュールの探索方法を完全に制御したい場合は、手動の再帰処理が最適です。
- TorchScript には、サブモジュールを操作するための他にもさまざまなメソッドがあります。 詳細については、TorchScript ドキュメントを参照してください。
- 上記に記載されている代替方法は、すべて ScriptModule 内のサブモジュールのみを反復処理します。 サブモジュールの属性やパラメータにアクセスするには、
module.__dict__
やmodule.parameters()
などの属性を使用する必要があります。