1. 程式人生 > >Pytorch基礎(6)----引數初始化

Pytorch基礎(6)----引數初始化

一、使用Numpy初始化:【直接對Tensor操作】

 

  • 對Sequential模型的引數進行修改:

 

 1 import numpy as np
 2 import torch
 3 from torch import nn
 4 
 5 # 定義一個 Sequential 模型
 6 net1 = nn.Sequential(
 7     nn.Linear(30, 40),
 8     nn.ReLU(),
 9     nn.Linear(40, 50),
10     nn.ReLU(),
11     nn.Linear(50, 10)
12 ) 13 14 # 訪問第一層的引數 15 w1 = net1[0].weight 16 b1 = net1[0].bias 17 print(w1) 18 19 #對第一層Linear的引數進行修改: 20 # 定義第一層的引數 Tensor 直接對其進行替換 21 net1[0].weight.data = torch.from_numpy(np.random.uniform(3, 5, size=(40, 30))) 22 print(net1[0].weight)
23
24 #若模型中相同型別的層都需要初始化成相同的方式,一種更高效的方式:使用迴圈去訪問:
25 for layer in net1:
26     if isinstance(layer, nn.Linear): #
判斷是否是線性層
27         param_shape = layer.weight.shape
28         layer.weight.data = torch.from_numpy(np.random.normal(0, 0.5, size=param_shape))
29         # 定義為均值為 0,方差為 0.5 的正態分佈
  • 對Module模型 的引數初始化:

對於 Module 的引數初始化,其實也非常簡單,如果想對其中的某層進行初始化,可以直接像 Sequential 一樣對其 Tensor 進行重新定義,其唯一不同的地方在於,如果要用迴圈的方式訪問,需要介紹兩個屬性,children 和 modules,下面我們舉例來說明:

1、建立Module模型類:

 1 class sim_net(nn.Module):
 2     def __init__(self):
 3         super(sim_net, self).__init__()
 4         self.l1 = nn.Sequential(
 5             nn.Linear(30, 40),
 6             nn.ReLU()
 7         )
 8         
 9         self.l1[0].weight.data = torch.randn(40, 30) # 直接對某一層初始化
10         
11         self.l2 = nn.Sequential(
12             nn.Linear(40, 50),
13             nn.ReLU()
14         )
15         
16         self.l3 = nn.Sequential(
17             nn.Linear(50, 10),
18             nn.ReLU()
19         )
20     
21     def forward(self, x):
22         x = self.l1(x)
23         x =self.l2(x)
24         x = self.l3(x)
25         return x
View Code

2、建立模型物件:

net2 = sim_net()

3、訪問children:

# 訪問 children
for i in net2.children():
    print(i)
     #列印的結果:
Sequential(
  (0): Linear(in_features=30, out_features=40)
  (1): ReLU()
)
Sequential(
  (0): Linear(in_features=40, out_features=50)
  (1): ReLU()
)
Sequential(
  (0): Linear(in_features=50, out_features=10)
  (1): ReLU()
)

4、訪問modules:

# 訪問 modules
for i in net2.modules():
    print(i)


#列印的結果
sim_net(
  (l1): Sequential(
    (0): Linear(in_features=30, out_features=40)
    (1): ReLU()
  )
  (l2): Sequential(
    (0): Linear(in_features=40, out_features=50)
    (1): ReLU()
  )
  (l3): Sequential(
    (0): Linear(in_features=50, out_features=10)
    (1): ReLU()
  )
)
Sequential(
  (0): Linear(in_features=30, out_features=40)
  (1): ReLU()
)
Linear(in_features=30, out_features=40)
ReLU()
Sequential(
  (0): Linear(in_features=40, out_features=50)
  (1): ReLU()
)
Linear(in_features=40, out_features=50)
ReLU()
Sequential(
  (0): Linear(in_features=50, out_features=10)
  (1): ReLU()
)
Linear(in_features=50, out_features=10)
ReLU()

通過上面的例子,可以看到:

children 只會訪問到模型定義中的第一層,因為上面的模型中定義了三個 Sequential,所以只會訪問到三個 Sequential,而 modules 會訪問到最後的結構,比如上面的例子,modules 不僅訪問到了 Sequential,也訪問到了 Sequential 裡面,這就對我們做初始化非常方便。

5、採用迴圈初始化:

for layer in net2.modules():
    if isinstance(layer, nn.Linear):
        param_shape = layer.weight.shape
        layer.weight.data = torch.from_numpy(np.random.normal(0, 0.5, size=param_shape))

 

二、torch.nn.init初始化

PyTorch 還提供了初始化的函式幫助我們快速初始化,就是 torch.nn.init,其操作層面仍然在 Tensor 上。先介紹一種初始化方法:

Xavier 初始化方法:

其中 $n_j$$n_{j+1}$ 表示該層的輸入和輸出數目。

 這種非常流行的初始化方式叫 Xavier,方法來源於 2010 年的一篇論文 Understanding the difficulty of training deep feedforward neural networks,其通過數學的推到,證明了這種初始化方式可以使得每一層的輸出方差是儘可能相等的。

torch.nn.init:

from torch.nn import init

init.xavier_uniform(net1[0].weight) # 這就是上面我們講過的 Xavier 初始化方法,PyTorch 直接內建了其實現

#這就直接修改了net1[0].weight的值