目次
序文
ディープ ラーニング モデルを作成するとき、特に転移学習のトレーニング中にこれら 3 つのことによく遭遇します。これらは何ですか、どのように使用され、使用時にどのような注意が必要ですか? このブログ投稿をご覧nn.Sequential
くださいnn.ModuleList
。nn.ModuleDict
1.nn.モジュール
これら 3 つのコンテナーを紹介する前に、 とは何かを知る必要がありますModule
。モデルを作成するとき、ほとんどすべてのモデルがこのクラスを継承します。彼はすべてのネットワークの基本クラスであり、ネットワークのプロパティを管理するために使用されます。nn.Parameter
これには とという 2 つのモジュールが関連付けられていますnn.functional
。これらすべてのモジュールは から来ていますtorch.nn
。以下にこれらのモジュールを簡単に紹介します。
1.1. nn.パラメータ
の最初のnn.Parameter
はPytorch
、nn.Parameter
モデル パラメーターを作成するための特別なクラスです。モデルには多くのパラメーターが存在することが多く、これらのパラメーターを手動で管理するのは簡単な作業ではありません。Pytorch
一般に、パラメータは、その構造の下にあるすべてのパラメータを表し、管理するnn.Parameter
ために使用されますnn.Module
。
## nn.Parameter 具有 requires_grad = True 属性
w = nn.Parameter(torch.randn(2,2))
print(w) # tensor([[ 0.3544, -1.1643],[ 1.2302, 1.3952]], requires_grad=True)
print(w.requires_grad) # True
## nn.ParameterList 可以将多个nn.Parameter组成一个列表
params_list = nn.ParameterList([nn.Parameter(torch.rand(8,i)) for i in range(1,3)])
print(params_list)
print(params_list[0].requires_grad)
## nn.ParameterDict 可以将多个nn.Parameter组成一个字典
params_dict = nn.ParameterDict({
"a":nn.Parameter(torch.rand(2,2)),
"b":nn.Parameter(torch.zeros(2))})
print(params_dict)
print(params_dict["a"].requires_grad)
上記で定義されたパラメータは、モジュールを通じて管理できます。
# module.parameters()返回一个生成器,包括其结构下的所有parameters
module = nn.Module()
module.w = w
module.params_list = params_list
module.params_dict = params_dict
num_param = 0
for param in module.parameters():
print(param,"\n")
num_param = num_param + 1
print("number of Parameters =",num_param)
実際の使用では、nn.Module
モジュールクラスは継承によって構築されるのが一般的で、学習が必要なパラメータを含む部分はすべてコンストラクタ内に配置されます。
#以下范例为Pytorch中nn.Linear的源码的简化版本
#可以看到它将需要学习的参数放在了__init__构造函数中,并在forward中调用F.linear函数来实现计算逻辑。
class Linear(nn.Module):
__constants__ = ['in_features', 'out_features']
def __init__(self, in_features, out_features, bias=True):
super(Linear, self).__init__()
self.in_features = in_features
self.out_features = out_features
self.weight = nn.Parameter(torch.Tensor(out_features, in_features))
if bias:
self.bias = nn.Parameter(torch.Tensor(out_features))
else:
self.register_parameter('bias', None)
def forward(self, input):
return F.linear(input, self.weight, self.bias)
1.2. nn.機能的
nn.functional
(導入後は一般に F に名前変更されました) さまざまな機能コンポーネントの機能実装があります。例えば:
- 活性化関数シリーズ (
F.relu, F.sigmoid, F.tanh, F.softmax
)- モデル レイヤー シリーズ (
F.linear, F.conv2d, F.max_pool2d, F.dropout2d, F.embedding
)- 損失関数シリーズ (
F.binary_cross_entropy, F.mse_loss, F.cross_entropy
)
パラメータの管理を容易にするために、パラメータは通常、nn.Module
継承を通じてクラス実装形式に変換され、nn
モジュールの下に直接カプセル化されます。
- 活性化関数は (
nn.ReLu, nn.Sigmoid, nn.Tanh, nn.Softmax
)になります。- モデルレイヤー (
nn.Linear, nn.Conv2d, nn.MaxPool2d, nn.Embedding
)- 損失関数 (
nn.BCELoss, nn.MSELoss, nn.CrossEntorpyLoss
)
したがって、表面上に確立したnn
活性化関数、層、損失関数はすべてfunctional
舞台裏で実装されます。nn.Module
さらに下を見ていくと、このモジュールが非常に強力であることがわかります。このモジュールが参照するさまざまなパラメータを管理することに加えて、このモジュールが参照するサブモジュールも管理できます。
1.3. nn.モジュール
私たちの焦点は、このnn.Module
モジュールを導入することです。nn.Module
以下には重要な辞書属性が多数あります。
self.training = True
self._parameters: Dict[str, Optional[Parameter]] = OrderedDict()
self._buffers: Dict[str, Optional[Tensor]] = OrderedDict()
self._non_persistent_buffers_set: Set[str] = set()
self._backward_hooks: Dict[int, Callable] = OrderedDict()
self._is_full_backward_hook = None
self._forward_hooks: Dict[int, Callable] = OrderedDict()
self._forward_pre_hooks: Dict[int, Callable] = OrderedDict()
self._state_dict_hooks: Dict[int, Callable] = OrderedDict()
self._load_state_dict_pre_hooks: Dict[int, Callable] = OrderedDict()
self._modules: Dict[str, Optional['Module']] = OrderedDict()
_parameters
そのうちの 2 つにのみ注目する必要があります。_modules
_parameters
:nn.Parameter
クラスに属する属性 (重みなど) を保存および管理し、これらのパラメータにバイアスをかけます_modules
: クラシック ネットワークなどのストレージ管理nn.Module
クラスはLeNet
、サブモジュール、畳み込み層、プーリング層を構築し、_modules に保存されます。
ここで質問があります:nn.Parameter
とnn.Module
の違いは何ですか_parameters
?
nn.Parameter
: これはtorch.Tensor
のサブクラスであり、テンソルをモデルの学習可能なパラメーターとしてマークするために使用されます。モデルを定義するプロセスでは、通常、nn.Parameter
モデルの属性として学習可能なパラメーターを作成するために使用します。この利点は、nn.Parameter
オブジェクトがモデルのパラメーターとして自動的に登録され、勾配の計算とパラメーターの更新に参加することです。_parameters
: これはnn.Module
クラス内の属性であり、モデルの学習可能なパラメーターを格納するために使用される辞書です。辞書のキーはパラメータの名前であり、値は対応するパラメータ テンソル (nn.Parameter
タイプ) です。_parameters
属性の値により、モデルの属性から学習可能なパラメーターが自動的に抽出され、辞書に追加されます。
_parameters
は、モデルの学習可能なパラメータを格納するためのコンテナと考えることが でき、nn.Parameter
これらのパラメータを作成してラベルを付けるための特別なクラスです。を使用してパラメータを作成し、モデルの属性として使用すると、これらのパラメータは辞書nn.Parameter
に自動的に追加され、一元的な管理と操作が容易になります。_parameters
つまり、nn.Parameter
モデルパラメータを作成するための特別なクラスであり、_parameters
モデルパラメータを格納する辞書属性です。でnn.Parameter
作成されたパラメータは自動的に_parameters
ディクショナリに追加されるため、モデルのパラメータの管理とアクセスが容易になります。
nn.Module
ファブリック ネットワークを構築するプロセスはどのようなものですか? 次のネットワークを例に挙げます。
import torch
from torch import nn
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 1, 1, 1)
self.bn = nn.BatchNorm2d(1)
self.relu = nn.ReLU()
self.conv2 = nn.Conv2d(1, 1, 1, 1)
def forward(self, x):
x = self.conv1(x)
x = self.bn(x)
x = self.relu(x)
x = self.conv2(x)
return x
if __name__ == "__main__":
dat = torch.rand(1, 1, 10, 10)
net = Net().cuda()
ビルドプロセスは次のとおりです。
Module
まず、この基本クラス(上記のクラスなど) を継承する 大きな(上で作成したNet
) を用意し、次にその中に多くのサブモジュールを含めることができ、これらのサブモジュールも から継承されます。これらのメソッドでは、それらは呼び出されます。親クラスの初期化メソッドは、親クラスのプロパティの初期化を実行します。そして、各サブモジュールを構築する際には、実際には初期化を行い、このメソッドで判定した型を対応する属性辞書に保存し、対応するメンバに割り当てるという2つのステップに分かれています。このようなサブモジュールを一つ一つ構築していき、最終的に全体の構築が完了します。特定のプロセスを自分でデバッグできます。nn.Module
Net
Net
nn.Module
Module
__init__
__setattr__
value
Net
要約:
- 1 つに
module
複数のサブクラスを含めることができますmodule
(Net
畳み込み層、BN
層、活性化関数を含む)- 1 つ
module
は 1 つの操作に相当し、forward()
その関数を実装する必要があります (一部のモジュールの前方は自分で書き直す必要があります。下読みするとわかります)- それぞれには
module
、その属性を管理するための多くの辞書があります (最も一般的に使用されるのは_parameters
、_modules
)
二.nn.シーケンシャル
nn.Module
上記のモジュール を導入したら、コンテナの導入を始めましょう。まず、 のモジュールコンテナであるitを見てみましょうnn.Sequential
。これは、複数のモジュールを順番に組み合わせるために使用されます。一連のモジュールを接続してシリアルモデル構造を形成できます。でどのように実装されているかを見てみましょう。ここではコンストラクターと順伝播部分のみを見て、他の部分のコードは省略しています。nn.Sequential
PyTorch
pytorch
class Sequential(Module):
...
def __init__(self, *args):
super(Sequential, self).__init__()
if len(args) == 1 and isinstance(args[0], OrderedDict):
for key, module in args[0].items():
self.add_module(key, module)
else:
for idx, module in enumerate(args):
self.add_module(str(idx), module)
...
def forward(self, input):
for module in self:
input = module(input)
return input
上記のコードからわかるように、nn.Sequential
これは から継承されておりModule
、説明Sequential
自体も 1 であるModule
ため、これらの辞書パラメータも持ちます。メソッドnn.Sequential
が実装されていることがわかります。最も一般的に使用される方法は次のとおりです。forward
nn.Sequential
forward(input)
: モデルの順伝播プロセスを定義します。ではnn.Sequential
、このメソッドは各モジュールのメソッドをモジュールの順序で順番に呼び出しforward
、前のモジュールの出力を入力として次のモジュールに渡して最終出力を計算します。add_module(name, module)
:nn.Sequential
にサブモジュールを追加します。name
はサブモジュールの名前で、module
追加するサブモジュール オブジェクトです。モジュールは、追加された順序で順に順伝播されます。parameters()
:nn.Sequential
のすべての学習可能なパラメータに対する反復子を返します。モデルの学習可能なパラメーターは、反復子を介してアクセスし、操作できます。zero_grad()
:nn.Sequential
すべてのモジュールのパラメータ勾配をゼロに設定します。このメソッドは通常、各グラデーション更新の前に呼び出されます。
add_module(name, module)
上記のメソッドを列挙してみますが、これらは実際にはまったく正しく、通常、このメソッドはモジュールを追加するために 最もよく使用されます。nn.Sequential
使い方を見てみましょう?
class Net(nn.Module):
def __init__(self, classes):
super(Net, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 6, 5),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(6, 16, 5),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),)
self.classifier = nn.Sequential(
nn.Linear(16*5*5, 120),
nn.ReLU(),
nn.Linear(120, 84),
nn.ReLU(),
nn.Linear(84, classes),)
def forward(self, x):
x = self.features(x)
x = x.view(x.size()[0], -1)
x = self.classifier(x)
return x
add_module メソッドを使用して作成することもできます。
import torch
import torch.nn as nn
class Net(nn.Module):
def __init__(self, classes):
super(Net, self).__init__()
self.features = nn.Sequential()
self.features.add_module('conv1', nn.Conv2d(3, 6, 5))
self.features.add_module('relu1', nn.ReLU())
self.features.add_module('pool1', nn.MaxPool2d(kernel_size=2, stride=2))
self.features.add_module('conv2', nn.Conv2d(6, 16, 5))
self.features.add_module('relu2', nn.ReLU())
self.features.add_module('pool2', nn.MaxPool2d(kernel_size=2, stride=2))
self.classifier = nn.Sequential()
self.classifier.add_module('fc1', nn.Linear(16*5*5, 120))
self.classifier.add_module('relu3', nn.ReLU())
self.classifier.add_module('fc2', nn.Linear(120, 84))
self.classifier.add_module('relu4', nn.ReLU())
self.classifier.add_module('fc3', nn.Linear(84, classes))
def forward(self, x):
x = self.features(x)
x = x.view(x.size()[0], -1)
x = self.classifier(x)
return x
forward
上記のネットワーク構築により、関数内で 1 つの文だけを使用してself.features(x)
6 つの文の実行が完了すること がわかります。この操作を完了できるのは、プログラムnn.Sequential
内の関数によるものですforward
。プログラムの実行中に、分析のためにパラメーターが渡されますnn.Sequential
。特定の実装プロセスはデバッグおよび観察できます。
概要:
nn.Sequential
これはnn.module
、一連のネットワーク層を順番にパッケージ化するために使用されるコンテナであり、次の 2 つの特徴があります。
- 順序性: 各ネットワーク層は厳密に順序どおりに構築されますが、このとき、前層と後層のデータの関係に注意する必要があります。
- 自己完結型
forward()
:forward
自己完結型では、for
順伝播操作がループを通じて順次実行されます。
3.nn.ModuleList
nn.ModuleList
これはnn.module
、ネットワーク層のグループをラップし、ネットワーク層を繰り返し呼び出すために使用されるコンテナでもあります。一般的に使用されるメソッドは次のとおりで、リストの使用とよく似ています。
append()
:ModuleList
後にネットワーク層を追加しますextend()
: 2 つのスプライスModuleList
insert()
:ModuleList
ネットワーク層を中間位置に挿入することを指定します
nn.ModuleList
ネットワークを構築するために使用する方法の例を見てみましょう。
class ModuleListNet(nn.Module):
def __init__(self):
super(ModuleListNet, self).__init__()
self.linears = nn.ModuleList([nn.Linear(10, 10) for i in range(10)])
def forward(self, x):
for i, linear in enumerate(self.linears):
x = linear(x)
return x
上の例では、nn.Linear
リスト内包表記を使用して 10 個のモジュールを作成します。全体的に見て、使い方はまだ非常に簡単で、特定の実装プロセスに興味のある友人は、コードをデバッグすることでそれを見ることができます。
3.nn.ModuleDict
このモジュールをもう一度見てみましょうnn.ModuleDict
。nn.ModuleDict
これは、ネットワーク層のセットをパッケージ化し、インデックスnn.module
によってネットワーク層を呼び出すために使用されるコンテナでもあります。一般的に使用されるメソッドは次のとおりで、辞書の操作に似ています。
clear()
: 空ModuleDict
items()
: キーと値のペアの反復可能値を返します (key-value pairs
)keys()
: 辞書のキーを返します (key
)values()
: 辞書の値を返します (value)
pop()
: キーと値のペアを返し、辞書から削除します。
例を見てみましょう:
import torch
import torch.nn as nn
class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.module_dict = nn.ModuleDict({
'conv1': nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1),
'relu1': nn.ReLU(),
'conv2': nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
'relu2': nn.ReLU(),
'flatten': nn.Flatten(),
'linear': nn.Linear(128 * 32 * 32, 10)
})
def forward(self, x):
for module in self.module_dict.values():
x = module(x)
return x
# 创建模型实例
model = MyModel()
# 随机生成输入
x = torch.randn(1, 3, 32, 32)
# 进行前向传播
output = model(x)
print(output.shape)
nn.ModuleDict
上記のネットワークを作成しても、全体としては辞書操作と同様に非常に単純です。
、 、の基本的な使い方は基本的にワインの紹介です、間違いがあれば修正してnn.Sequential
くださいnn.ModuleList
!nn.ModuleDict