x.1 レイヤーとブロック
ネットワーク モデルはレイヤーとモジュールで構成されます。複数のレイヤーがレイヤー グループを形成し、レイヤー グループがブロック ブロックになります。レイヤーとブロックはどちらも module のサブクラスから構築され、net(x)
実際に呼び出されるのは ですnet.__call__(x)
。
カスタム ブロックとカスタム レイヤーの両方に定義__init__
と__forward__
メソッドが必要です。このうち、nn.Sequential メソッドは、複数のレイヤーを重ね合わせるために使用されます。たとえばhttps://blog.csdn.net/qq_43369406/article/details/129998217
、torch.nn.Module.add_module()
サブクラスの追加にはこのメソッドが使用され、torch.nn.Module.children()
すべてのサブクラスの表示には メソッドが使用されます。クラスで。
class MySequential(nn.Module):
def __init__(self, *args):
super().__init__()
for idx, module in enumerate(args):
self.add_module(str(idx), module) # layer_name be not the same, like parameters str.
def forward(self, X):
for module in self.children():
X = module(X)
return X
nn.Parameter() や nn.Linear() などの nn モジュールのメソッドを使用してレイヤーを定義しない場合、その required_grad 属性はデフォルトで False になります。つまり、**weight はモデル パラメーターではないことに注意してください。逆伝播更新には使用されません。つまり、偏微分を求めるとき、彼は変数として現れず、連鎖導出規則では常に定数とみなされます。** torch.tensor と torch.nn.Parameterを参照できます。https://blog.csdn.net/qq_43369406/article/details/131234557
self.rand_weight = torch.rand((20, 20)) # required_grad == False
self.linear = nn.LazyLinear(20) # True
nn.Linear
事前に作成されたレイヤーの代わりにカスタムレイヤーを使用することもできます。torch.tensor と torch.nn.Parameterを参照してください。https://blog.csdn.net/qq_43369406/article/details/131234557
class MyLinear(nn.Module):
def __init__(self, in_units, units):
super().__init__()
self.weight = nn.Parameter(torch.randn(in_units, units))
self.bias = nn.Parameter(torch.randn(units,))
def forward(self, X):
linear = torch.matmul(X, self.weight.data) + self.bias.data
return F.relu(linear)
x.2 パラメータ
まず、パラメーター モデル パラメーターは重み重みとバイアス バイアスに分けられることが多く、モデル パラメーターの種類はすべてのtorch.nn.parameter.Parameter
種類であることを知る必要があります。
net[0].weight
パラメータ内の重みパラメータ (パラメータは値、勾配、追加情報を含む複合オブジェクトであることが多い)、net[0].weight.data
値にアクセスすること、net[0].weight.grad
勾配にアクセスすることによってアクセスできます(ただし、逆伝播しない場合loss.backward()
、勾配行列は多くの場合 None です)。 。
net[0].state_dict()
また、キーと値のペアの形式でparam にアクセスすることもできます。キーと値のペアにアクセスするnet.named_parameters()
には、param ジェネレーター (値、勾配などを含む) を生成することで、 torch.save(model.state_dict() )next(net.named_parameters())
に注意してください。勾配情報は保存されません。この関数はモデルのパラメータ (重みとバイアス) のみを保存し、勾配情報は保存しません。モデルの勾配情報を保存したい場合は、 torch.save(model) などの完全なモデル保存メソッドを使用できます。例は次のとおりです。
net = nn.Sequential(nn.LazyLinear(8),
nn.ReLU(),
nn.LazyLinear(1))
X = torch.rand(size=(2, 4)) # 2 means the number of sample. Linear() just chage the last dimension's data.
Y = net(X)
# type
print(type(net.state_dict()))
print(type(next(net.named_parameters())))
print(type(net.named_parameters()))
# value
print(net.state_dict())
print([(name, param.shape) for name, param in net.named_parameters()])
print(net.state_dict()['2.bias'].data)
'''
output is ::
<class 'collections.OrderedDict'>
<class 'tuple'>
<class 'generator'>
OrderedDict([('0.weight', tensor([[ 0.0387, 0.0717, 0.0398, 0.3735],
[ 0.1486, -0.3150, -0.3813, 0.3046],
[ 0.3214, -0.0327, 0.3165, -0.3807],
[-0.4867, -0.4954, 0.3559, 0.1104],
[ 0.0462, -0.2147, 0.3825, 0.1375],
[ 0.3976, -0.2493, 0.1906, -0.4750],
[ 0.1445, 0.0632, -0.1869, -0.0446],
[-0.2179, 0.1317, -0.4357, 0.1538]])), ('0.bias', tensor([ 0.4576, -0.0437, -0.0475, 0.0576, -0.1058, 0.4215, -0.1188, 0.1157])), ('2.weight', tensor([[ 0.2158, 0.0116, 0.0566, 0.3138, -0.0825, -0.1470, -0.1105, -0.2869]])), ('2.bias', tensor([-0.2899]))])
[('0.weight', torch.Size([8, 4])), ('0.bias', torch.Size([8])), ('2.weight', torch.Size([1, 8])), ('2.bias', torch.Size([1]))]
tensor([-0.2899])
'''
知っておく必要があるのは、param は値、勾配、および追加情報を含む複合オブジェクトであるタプルであるということです。param の値については、重みまたはバイアスであっても、次のようなタプルで構成されています(参数名称, tensor())
。パラメータ名は一意です。これは、レイヤ名も一意であるのと同じですnn.Module.add_module(层名称, 对象)
。これは、タプル内のテンソルの存在によるものでもあり、モデルがどのデバイス上にあるかを後で確認できる理由でもあり、これも Tensor.device メソッドを取得することによって取得されます。
[(参数名称, tensor())]
[('weight', tensor([[ 0.2336, -0.2090, 0.0561, 0.1469, 0.1116, -0.0786, 0.1960, 0.0033]])), ('bias', tensor([-0.3357]))]
x.2 初期パラメータ
重みの初期化については、pytorch の重みの初期化/パラメータの初期化を参照してください。https://blog.csdn.net/qq_43369406/article/details/131342983
x.2.1 組み込みメソッドの初期化
モデルの初期化とは、トレーニング前のモデルへのパラメーターの割り当てを指します。これは、 initmodel.apply(func)
と同様のメソッドで実装する必要があります。nn.init.normal_
ネットワーク全体に適用する場合、すべての子は同じメソッドで再帰的に初期化されます (子は nn.Module から継承されたサブクラスを参照することに注意してください)。単一のレイヤーに適用する場合は、単一のレイヤーのみが初期化されます。以下は、システムの組み込みの初期化重み付けメソッドです。
"""
6.3.1. Built-in Initialization
using built-in func to init.
- `nn.init.normal_(module.weight, mean=0, std=0.01)`
- `nn.init.zeros_(module.bias)`
- `nn.init.constant_(module.weight, 1)`
- `nn.init.zeros_(module.bias)`
- `nn.init.xavier_uniform_(module.weight)`
- `nn.init.kaiming_uniform_(module.weight)` # default one for Linear, and the type is Leaky_ReLU
- `nn.init.uniform_(module.weight, -10, 10)`
"""
def init_normal(module):
if type(module) == nn.Linear:
nn.init.normal_(module.weight, mean=0, std=0.01)
nn.init.zeros_(module.bias)
net.apply(init_normal)
print(net[0].weight.data[0])
print(net[0].bias.data[0])
def init_constant(module):
if type(module) == nn.Linear:
nn.init.constant_(module.weight, 1)
nn.init.zeros_(module.bias)
net.apply(init_constant)
print(net[0].weight.data[0]); print(net[0].bias.data[0])
def init_xavier(module):
if type(module) == nn.Linear:
nn.init.xavier_uniform_(module.weight)
def init_42(module):
if type(module) == nn.Linear:
nn.init.constant_(module.weight, 42)
net[0].apply(init_xavier); net[2].apply(init_42)
print(net[0].weight.data[0]); print(net[2].weight.data)
x.2.2 カスタム メソッドの初期化
def _weights_init(m):
"""
intro:
weights init.
finish these:
- torch.nn.Linear
>>> version 1.0.0
if type(m) == nn.Linear:
print("Init", *[(name, param.shape) for name, param in m.named_parameters()][0]) # linear - param - weight
nn.init.trunc_normal_(m.weight, std=.01)
if m.bias is not None:
print("Init", *[(name, param.shape) for name, param in m.named_parameters()][1]) # linear - param - bias
nn.init.zeros_(m.bias)
args:
:param torch.parameters m: nn.Module
"""
classname = m.__class__.__name__
if type(m) == nn.Linear:
print("Init", *[(name, param.shape) for name, param in m.named_parameters()][0]) # linear - param - weight
nn.init.trunc_normal_(m.weight, std=.01)
if m.bias is not None:
print("Init", *[(name, param.shape) for name, param in m.named_parameters()][1]) # linear - param - bias
nn.init.zeros_(m.bias)
elif isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode="fan_out")
if m.bias is not None:
nn.init.zeros_(m.bias)
elif isinstance(m, nn.LayerNorm):
nn.init.zeros_(m.bias)
nn.init.ones_(m.weight)
elif classname.startswith('Conv'):
m.weight.data.normal_(0.0, 0.02)
elif classname.find('BatchNorm') != -1:
m.weight.data.normal_(1.0, 0.02)
m.bias.data.fill_(0)
net = nn.Sequential(nn.LazyLinear(8), nn.ReLU(), nn.LazyLinear(1))
X = torch.rand(size=(2, 4))
net.apply(_weights_init)
x.3 遅延初期化
Lazy を含むすべてのレイヤーがnn.LazyLinear
Lazy init で初期化される場合、モデルが決定される前に Tensor を渡す必要があります。
x.4 周辺機器との対話/読み込みと保存
モデル ネットワーク モデルとテンソル データ テンソルが CPU 上にある場合、実際には CPU とメモリが連携して動作します。また、モデル ネットワーク モデルとテンソル データ テンソルが GPU 上にある場合、実際には対応する GPU と対応する GPU です。ビデオメモリが作業に協力します。ただし、メモリは電源オフ後に停止するため、永続的に保存するために外部メモリに保存されている場合、Pytorch はこれら 2 つのメソッドを と にカプセル化しtorch.save
ますtorch.load
。
x.4.1 テンソルとの相互作用
x = torch.arange(4)
torch.save(x, 'x-file')
x2 = torch.load('x-file')
x.4.2 モデルとの対話
torch.nn.state_dict()
方法と方法を一致させる必要がありますtorch.nn.load_state_dict()
。また、モデルの外観ではなく、モデルのパラメーターのみを保存するため、最初にモデルをインスタンス化してから、パラメーターをロードする必要があります。
torch.save(net.state_dict(), 'mlp.params')
net_clone = MLP()
net_clone.load_state_dict(torch.load('mlp.params'))
ロードするときに、ロードするデバイスを指定できます。たとえば、
checkpoint = torch.load(load_path, map_location="cpu")
x.5 デバイス
デバイスをGPUとCPU、テンソルとモデルの指定デバイスに分け、どのデバイスであるかを確認するためのデバイスの転送方法は以下の通りです デバイス指定_GPUデバイス指定/CUDAデバイス指定/どこで確認するかの共通操作も参照できますモデルはhttps://blog.csdn.net/qq_43369406/article/details/129816988
# tensor
X = torch.zeros((2, 3), device=torch.device("cuda:1"))
X = X.to(device=torch.device("cuda:0"))
print(X.device)
# model
net = nn.Sequential(nn.LazyLinear(1))
net = net.to(device=torch.device("cuda:0"))
print(net[0].weight.data.device)
利用可能なデバイスを確認する
print(torch.device("cpu"))
print(torch.device("cuda:1"))
print(torch.cuda.is_available())
print(torch.cuda.device_count())