為什么要權值初始化?
權重初始化的目的是:防止在深度神經網絡的正向(前向)傳播過程中層激活函數的輸出損失梯度爆炸或消失。如果發生任何一種情況,損失梯度太大或太小,就無法有效地反向傳播,並且即便可以反向傳播,網絡也需要花更長時間來達到收斂。
網絡初始化的一般做法:讓輸入值落入類似一個均值為0,標准差為1的正態分布中,確保被歸一化,
即torch.randn
函數的做法
因為CNN的做法類似於累積矩陣乘法,所以正態分布的初始化不當會造成以下問題:
- 初始化太大會造成梯度爆炸
- 初始化太小會造成梯度消失
Xavier初始化
基於激活函數為基於給定點對稱的,如
tanh
、softsign
這樣的激活函數,提出了Xavier初始化
以往標准權重初始化是根據[-1,1]
中的均勻分布來初始化權重,然后按1 /√n
的比例縮放。但是這種方法實際上並不能很好地發揮作用,如下:
x = torch.randn(512)
for i in range(100):
a = torch.Tensor(512, 512).uniform_(-1, 1) * math.sqrt(1. / 512)
x = tanh(a @ x)
print(x.mean()) # tensor(3.7062e-26)
print(x.std()) # tensor(9.9671e-25)
使用該權重初始化方法運行100層tanh
網絡[服從上述分布]會導致激活梯度變得無限小就像消失了一樣。
所以提出了Xavier初始化:將每層權重設置為在有界的隨機均勻分布中選擇的值
其中
Xavier權重初始化
將保持激活函數和反向傳播梯度的方差,一直向上或向下傳播到神經網絡的每一層
def xavier(m, h):
return torch.Tensor(m, h).uniform_(-1, 1) * math.sqrt(6. / (m + h))
Kaiming
初始化
基於非對稱的激活函數,如
relu
等提出的Kaiming
初始化
-
使用適合給定圖層的權重矩陣創建張量,並使用從標准正態分布中隨機選擇的數字填充它。
-
將每個隨機選擇的數字乘以
√2/√n
,其中n
是從前一層輸出到指定層的連接數(也稱為fan-in
) -
偏差張量初始化為零
def kaiming(m, h):
return torch.randn(m, h) * math.sqrt(2. / m)
在relu
為激活函數的網絡中,如果使用Xavier
初始化會導致梯度消失,Kaiming初始化
應該是我們的首選權重初始化策略。
pytorch
中的初始化
pytorch
中已經集成了多種的初始化方式,上述的Xavier
和kaiming
初始化都可以直接調用
- 初始化為均勻分布
torch.nn.init.xavier_uniform(tensor, gain=1)
torch.nn.init.kaiming_uniform(tensor, a=0, mode='fan_in')
- 初始化為高斯分布(正態分布)
torch.nn.init.xavier_normal(tensor, gain=1)
torch.nn.init.kaiming_normal(tensor, a=0, mode='fan_in')
- 更多初始化方法👉官方文檔
pytorch
搭建網絡自動初始化
通過閱讀一些代碼我們會發現,有些網絡只搭建了框架而沒有進行上述的各種初始化,那網絡的初始參數怎么樣呢?
通過TORCH.NN.MODULES.CONV
文檔可以看出,在pytorch
框架會自動使用kaiming
均勻分布初始化網絡參數
def reset_parameters(self) -> None:
init.kaiming_uniform_(self.weight, a=math.sqrt(5))
if self.bias is not None:
fan_in, _ = init._calculate_fan_in_and_fan_out(self.weight)
bound = 1 / math.sqrt(fan_in)
init.uniform_(self.bias, -bound, bound)
Write by Gqq