TorchScriptでScriptModuleに子モジュールを追加:add_module()徹底解説
torch.jit.ScriptModule.add_module()
は、TorchScript における ScriptModule
クラスのメソッドで、子モジュールを親モジュールに追加するためのものです。子モジュールは、nn.Module
クラスのインスタンスである必要があります。
使用方法
torch.jit.ScriptModule.add_module(name, module)
module
: 追加する子モジュール (nn.Module
クラスのインスタンス)name
: 子モジュールに割り当てる名前 (文字列)
例
import torch
import torch.nn as nn
import torch.jit
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.linear1 = nn.Linear(10, 20)
self.linear2 = nn.Linear(20, 5)
def forward(self, x):
x = self.linear1(x)
x = self.linear2(x)
return x
# ScriptModule に変換
scripted_model = torch.jit.script(MyModel())
# 子モジュールを追加
scripted_model.add_module('my_conv', nn.Conv2d(3, 16, 3))
# 子モジュールにアクセス
print(scripted_model.my_conv) # nn.Conv2d(3, 16, 3)
- 子モジュールを追加しても、
ScriptModule
クラス自体は自動的に再コンパイルされません。再コンパイルが必要な場合は、torch.jit.script()
メソッドを再度呼び出す必要があります。 add_module()
メソッドは、再帰的に呼び出すことができます。- 子モジュールは、
forward()
メソッド内で使用できます。 add_module()
メソッドは、ScriptModule
クラスの属性として子モジュールを追加します。
利点
- モデルを動的に構成することで、コードの再利用性を向上させることができます。
- モデルを動的に構成することで、異なる入力データやタスクに応じてモデルを調整することができます。
torch.jit.ScriptModule.add_module()
メソッドを使用すると、モデルを動的に構成することができます。
- 子モジュールを追加する前に、
ScriptModule
クラスが ScriptMode に設定されていることを確認する必要があります。 torch.jit.ScriptModule.add_module()
メソッドは、訓練済みのモデルには使用できません。
モデルの動的構成
import torch
import torch.nn as nn
import torch.jit
class MyModel(nn.Module):
def __init__(self, input_dim):
super().__init__()
if input_dim == 1:
self.linear = nn.Linear(1, 10)
elif input_dim == 2:
self.conv = nn.Conv2d(1, 16, 3)
self.pool = nn.MaxPool2d(2)
self.linear = nn.Linear(16 * 9, 10)
else:
raise ValueError(f"Unsupported input dimension: {input_dim}")
def forward(self, x):
if input_dim == 1:
x = self.linear(x)
elif input_dim == 2:
x = self.conv(x)
x = self.pool(x)
x = x.view(-1, 16 * 9)
x = self.linear(x)
else:
raise ValueError(f"Unsupported input dimension: {input_dim}")
return x
# ScriptModule に変換
input_dim = 2
scripted_model = torch.jit.script(MyModel(input_dim))
# 子モジュールを追加
print(scripted_model) # MyModel(linear=Linear(in_features=1, out_features=10))
# 入力データに応じてモデルを動的に構成
if input_dim == 2:
scripted_model.add_module('my_conv', nn.Conv2d(3, 16, 3))
print(scripted_model) # MyModel(linear=Linear(in_features=10, out_features=10), my_conv=Conv2d(3, 16, 3))
この例では、torch.jit.ScriptModule.add_module()
メソッドを使用して、共通のサブモジュールを再利用する方法を示します。
import torch
import torch.nn as nn
import torch.jit
class CommonSubmodule(nn.Module):
def __init__(self):
super().__init__()
self.linear1 = nn.Linear(10, 20)
self.relu = nn.ReLU()
class MyModel1(nn.Module):
def __init__(self):
super().__init__()
self.common = CommonSubmodule()
self.linear2 = nn.Linear(20, 5)
def forward(self, x):
x = self.common(x)
x = self.linear2(x)
return x
class MyModel2(nn.Module):
def __init__(self):
super().__init__()
self.common = CommonSubmodule()
self.linear3 = nn.Linear(20, 1)
def forward(self, x):
x = self.common(x)
x = self.linear3(x)
return x
# ScriptModule に変換
scripted_model1 = torch.jit.script(MyModel1())
scripted_model2 = torch.jit.script(MyModel2())
# 共通サブモジュールにアクセス
print(scripted_model1.common) # CommonSubmodule(linear1=Linear(in_features=10, out_features=20), relu=ReLU())
print(scripted_model2.common) # CommonSubmodule(linear1=Linear(in_features=10, out_features=20), relu=ReLU())
状況に応じて、以下の代替方法を検討してください。
直接子モジュールを割り当てる
最も単純な代替方法は、add_module()
メソッドを使用せずに、子モジュールを直接 ScriptModule の属性として割り当てることです。
import torch
import torch.nn as nn
import torch.jit
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.linear1 = nn.Linear(10, 20)
self.linear2 = nn.Linear(20, 5)
def forward(self, x):
x = self.linear1(x)
x = self.linear2(x)
return x
# ScriptModule に変換
scripted_model = torch.jit.script(MyModel())
# 子モジュールを直接割り当てる
scripted_model.my_conv = nn.Conv2d(3, 16, 3)
# 子モジュールにアクセス
print(scripted_model.my_conv) # nn.Conv2d(3, 16, 3)
torch.nn.ModuleDict を使用する
より柔軟な方法として、torch.nn.ModuleDict
を使用して子モジュールを管理することができます。ModuleDict
は、名前とモジュールのペアの辞書として機能します。
import torch
import torch.nn as nn
import torch.jit
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.modules = nn.ModuleDict({
'linear1': nn.Linear(10, 20),
'linear2': nn.Linear(20, 5)
})
def forward(self, x):
x = self.modules['linear1'](x)
x = self.modules['linear2'](x)
return x
# ScriptModule に変換
scripted_model = torch.jit.script(MyModel())
# 子モジュールを追加
scripted_model.modules['my_conv'] = nn.Conv2d(3, 16, 3)
# 子モジュールにアクセス
print(scripted_model.modules['my_conv']) # nn.Conv2d(3, 16, 3)
カスタムコンテナクラスを作成する
高度な制御が必要な場合は、独自のカスタムコンテナクラスを作成することができます。このクラスは、子モジュールの追加、削除、アクセスを制御する独自のロジックを実装できます。
add_module() を拡張する
add_module()
メソッドを拡張して、独自の機能を追加することもできます。これにより、子モジュールの追加方法をより細かく制御することができます。
選択の指針
上記で紹介した代替方法はそれぞれ、異なる利点と欠点があります。
add_module()
を拡張する:** 既存のadd_module()
メソッドの機能を拡張できますが、複雑でエラーが発生しやすい可能性があります。- カスタムコンテナクラスを作成する
高度な制御が可能ですが、実装が複雑になります。 torch.nn.ModuleDict
を使用する:** より柔軟な方法ですが、コードが冗長になる可能性があります。- 直接子モジュールを割り当てる
最もシンプルでわかりやすい方法ですが、柔軟性に欠けます。
状況に応じて、適切な代替方法を選択してください。
- 子モジュールを追加しても、
ScriptModule
クラス自体は自動的に再コンパイルされません。再コンパイルが必要な場合は、torch.jit.script()
メソッドを再度呼び出す必要があります。 - いずれの代替方法を使用する場合でも、
ScriptModule
クラスが ScriptMode に設定されていることを確認する必要があります。