[pytorch、学習] -4.2モデルパラメータへのアクセス、初期化、共有

参照

4.2モデルパラメータへのアクセス、初期化、共有

セクション3.3(線形回帰の簡潔な実現)では、initモジュールを介してモデルのパラメーター初期化ます。また、モデルパラメータにアクセスする簡単な方法も紹介しました。このセクションでは、モデルパラメータにアクセスして初期化する方法、および複数のレイヤー間で同じモデルパラメータを共有する方法について詳しく説明します。

import torch
from torch import nn
from torch.nn import init

net = nn.Sequential(nn.Linear(4,3), nn.ReLU(), nn.Linear(3, 1))

print(net)
X = torch.rand(2, 4)
Y = net(X).sum()

ここに画像の説明を挿入

4.2.1モデルパラメータへのアクセス

前のセクションで説明したSequentialクラスModule間の継承関係を思い出してくださいためのSequentialインスタンスにおけるモデルパラメータを含む層、我々はでき(イテレータの形で返される)全てのパラメータへのアクセスを介してModuleクラスparameters()またはnamed_parametersメソッド、後者はTensorでその名前が返されるリターン・パラメータに加え

print(type(net.named_parameters()))
for name, param in net.named_parameters():
    print(name, param.size())

ここに画像の説明を挿入
返された名前の前に、レイヤー番号のインデックスが自動的に付けられていることがわかります。net単層のパラメータを見てみましょうSequentialクラスを使用して構築されたニューラルネットワークの場合、角括弧を介し[]てネットワークの任意の層にアクセスできます。インデックス0は、非表示レイヤーがSequentialインスタンスによって追加された最初のレイヤーであることを示します。

for name, param in net[0].named_parameters():
    print(name, param.size(), type(param))

ここに画像の説明を挿入

# 如果一个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在参数列表中,但是weight2却没在参数列表中
# 因为Parameters是Tensor,即Tensor拥有的属性它都有,比如可以根据data来访问参数数值,用grad来访问参数梯度
weight_0 = list(net[0].parameters())[0]  # 将第0层的W取出
print(net)
print(weight_0)
print(weight_0.grad)   # 此时并未对Y做梯度下降,因此会显示None
Y.backward()
print(weight_0.grad)

ここに画像の説明を挿入

4.2.2モデルパラメータの初期化

次の例では、重みパラメーターを、平均値が0、標準偏差が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)

ここに画像の説明を挿入

# 使用常数来初始化权重参数
for name, param in net.named_parameters():
    if 'bias' in name:
        init.constant_(param, val=0)
        print(name, param.data)

ここに画像の説明を挿入

4.2.3カスタム初期化方法

必要な初期化メソッドがinitモジュールで提供されていない場合があります。このとき、初期化メソッドを実装して、他のメソッドと同じように使用できるようにすることができます。

# 我们先看看pytorch如何实现的
def normal_(tensor, mean=0, std= 1):
    with torch.no_grad:
        return tensor.normal_(mean, std)

これは、インプレースでTensorの値を変更する関数であり、このプロセスでは勾配が記録されないことがわかります。同様に、カスタム初期化メソッドを実装しましょう。次の例では、重みの確率の半分を0に初期化し、残りの半分を[-10、-5]と[5,10]の2つの区間で一様分布の乱数に初期化します。

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)

ここに画像の説明を挿入

4.2.4モデルパラメータの共有

場合によっては、モデルパラメータを複数のレイヤー間で共有したいことがあります。例を見てみましょう

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)

ここに画像の説明を挿入

# 在内存中,这两个线性层其实是一个对象
print(id(net[0]) == id(net[1]))
print(id(net[0].weight) == id(net[1].weight))

ここに画像の説明を挿入

# 因为模型参数里包含了梯度,所以在反向传播时,这些共享的参数的梯度是累加的
x = torch.ones(1, 1)
y = net(x).sum()
print(y)
y.backward()
print(net[0].weight.grad)

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/piano9425/article/details/107175877