初期化と共有アクセスモデルパラメータ
パラメータアクセス
アクセスパラメータ:下記の二つの方法。これらの2つの方法は、クラスnn.Moduleに実装されている。サブクラスこのクラスから継承するが、同じメソッドを持っていること。
- 。パラメーター()
- .named_parameters()
import torch
from torch import nn
from torch.nn import init
net = nn.Sequential(nn.Linear(4, 3), nn.ReLU(), nn.Linear(3, 1)) # pytorch已进行默认初始化
print(type(net.named_parameters()))
for name, param in net.named_parameters():
print(name, param.size())
輸出
<class 'generator'>
0.weight torch.Size([3, 4])
0.bias torch.Size([3])
2.weight torch.Size([1, 3])
2.bias torch.Size([1])
目に見えるリターンは自動的にインデックスの層数に接頭辞として名前を追加します。
私たちがアクセスしてみましょうnet
単一層のパラメータを。使用するSequential
ニューラルネットワークベースの構成を、我々はブラケットができる[]
任意のネットワーク層にアクセスすることができます。インデックス0は、中間層があることを示すSequential
第一実施例に追加層。
for name, param in net[0].named_parameters():
print(name, param.size(), type(param))
出力:
weight torch.Size([3, 4]) <class 'torch.nn.parameter.Parameter'>
bias torch.Size([3]) <class 'torch.nn.parameter.Parameter'>
層の単層があるのでその接頭辞インデックスはありません。リターンのほかにparam
タイプされtorch.nn.parameter.Parameter
、実際には、これはTensor
サブクラス、およびTensor
相違点は1つがあればということでTensor
あるParameter
次の例を見て、それが自動的にモデルのパラメータのリストに追加されます。
class MyModel(nn.Module):
def __init__(self, **kwargs):
super(MyModel, self).__init__(**kwargs)
self.weight1 = nn.Parameter(torch.rand(20, 20))
self.weight2 = torch.rand(20, 20)
def forward(self, x):
pass
n = MyModel()
for name, param in n.named_parameters():
print(name)
出力:
weight1
上記のコードweight1
パラメータリストではなく、weight2
パラメータリストではありません1。
ASがParameter
あるTensor
、すなわち、Tensor
そのようなことができるように、それが有する特性を有しているdata
と、値パラメータにアクセスするgrad
勾配パラメータにアクセスします。
weight_0 = list(net[0].parameters())[0]
print(weight_0.data)
print(weight_0.grad) # 反向传播前梯度为None
Y.backward()
print(weight_0.grad)
出力:
tensor([[ 0.2719, -0.0898, -0.2462, 0.0655],
[-0.4669, -0.2703, 0.3230, 0.2067],
[-0.2708, 0.1171, -0.0995, 0.3913]])
None
tensor([[-0.2281, -0.0653, -0.1646, -0.2569],
[-0.1916, -0.0549, -0.1382, -0.2158],
[ 0.0000, 0.0000, 0.0000, 0.0000]])
初期化パラメータ
一般的に、様々な層、pytorchが初期化さ良い、合理的なデフォルト値を達成している、我々は心配する必要はありません。(サンプルの異なる種類が層の具体的な参照することができ、初期化メソッドのソースコード)。
あなたはネットの全てのパラメータによって、その後、自重を初期化したい場合は、。、初期化戦略を実行するたとえば、次の例では、我々は正規分布乱数0.01のゼロ平均と標準偏差に重みパラメータを初期化し、まだクリアされているパラメータオフセットします。
for name, param in net.named_parameters():
if 'weight' in name:
init.normal_(param, mean=0, std=0.01)
print(name, param.data)
elif 'bias' in name:
init.constant_(param,0)
print(name, param.data)
。初期化メソッドが付属して、あなたは満足彼らのニーズを達成するための初期化メソッドを所有することができtorch.nn.initを使用して上記
のような、レッツはPyTorchを見てこれらの初期化方法を実現する方法ですtorch.nn.init.normal_
。
def normal_(tensor, mean=0, std=1):
with torch.no_grad():
return tensor.normal_(mean, std)
それことが分かるこれはインプレース変化であるTensor
関数の値は、このプロセスは、勾配が記録されていません。
私たちは、カスタムの初期化メソッドを実装したいです。次の例では、我々は、他の半分は、初期化確率を有する重みの確率が0の半分に初期化させて\([ - 10-5] \)と\([5,10] \)両者が均一間隔に分布乱数。
def init_weight_(tensor):
with torch.no_grad():
tensor.uniform_(-10, 10)
tensor *= (tensor.abs() >= 5).float()
for name, param in net.named_parameters():
if 'weight' in name:
init_weight_(param)
print(name, param.data)
init_weight_()ので、これらのparamを変更し、宣言してtorch.no_grad()
私たちは、これらのパラメータを変更することができるように、data
勾配を損なうことなく、モデルパラメータ値を書き換えます。
for name, param in net.named_parameters():
if 'bias' in name:
param.data += 1
print(name, param.data)
出力:
0.bias tensor([1., 1., 1.])
2.bias tensor([1.])
パラメータ共有
いくつかのケースでは、我々は、複数の層の間のモデルパラメータを共有したいです。ボーエンは、モデルパラメータを共有する方法前に述べた:Module
のクラスforward
と同じ倍数で関数呼び出しを。私たちが合格した場合に加えて、Sequential
モジュールを同じであるModule
パラメータの、そしてまた、共有例の例で見てみましょう:
linear = nn.Linear(1, 1, bias=False)
net = nn.Sequential(linear, linear)
print(net)
for name, param in net.named_parameters():
init.constant_(param, val=3)
print(name, param.data)
出力:
Sequential(
(0): Linear(in_features=1, out_features=1, bias=False)
(1): Linear(in_features=1, out_features=1, bias=False)
)
0.weight tensor([[3.]])
メモリ、線形二層の事実オブジェクトに導入されたバージョン:
print(id(net[0]) == id(net[1]))
print(id(net[0].weight) == id(net[1].weight))
出力:
True
True
勾配は、モデルパラメータを含んでいるので、これ逆伝播計算で、共有勾配パラメータが蓄積されます。
x = torch.ones(1, 1)
y = net(x).sum()
print(y)
y.backward()
print(net[0].weight.grad) # 单次梯度是3,两次所以就是6
出力:
tensor(9., grad_fn=<SumBackward0>)
tensor([[6.]])
比較があることにより、
linear1 = nn.Linear(1, 1, bias=False)
linear2 = nn.Linear(1, 1, bias=False)
net = nn.Sequential(linear1, linear2)
print(net)
for name, param in net.named_parameters():
init.constant_(param, val=3)
print(name, param.data)
x = torch.ones(1, 1)
y = net(x).sum()
print(y)
y.backward()
print(net[0].weight.grad)
輸出
Sequential(
(0): Linear(in_features=1, out_features=1, bias=False)
(1): Linear(in_features=1, out_features=1, bias=False)
)
0.weight tensor([[3.]])
1.weight tensor([[3.]])
tensor(9., grad_fn=<SumBackward0>)
tensor([[3.]])
.weight.grad [0]ネット、それはlinear1 linear2ない同じ物体ここで見ることができ、そのためバックプロパゲーション後の正味の2つのパラメータがありテンソル([[3]])であります