天天看點

初始化網絡參數

為什麼要給網絡參數賦初值

既然網絡參數通過訓練得到,那麼其初值是否重要?設定初值不佳是否隻影響收斂速度而不影響模型結果?網絡參數是否可以設定為全0或者全1?

假設網絡的參數W初值都是0,如下圖所示,無論輸入任何X,第一層的輸出A将都為0,再向前傳遞到y也是0,使用誤差函數調參時,每一層的梯度隻與該層的輸入和輸出有關,由于a1,a2值相等,計算出的梯度調整的值,以及調整後的梯度也相等;第二次疊代也同理,由于a1,a2相等,w[2]中各單元的值也相等。是以該層有100個單元與1個單元沒有差異,該問題被稱為“對稱性”問題。

初始化網絡參數

試想将w設定成全1,則有a1=x1+x2,a2=x1+x2,a1與a2值仍然相同,對稱性問題依然存在。由此,一般将參數設定為随機值。

設定成随機值還不夠,還需要設定成較小的随機值,試想如果w的均值在0.5附近,某一層的輸入輸出都為500個元素,那麼經過該層乘和加的運算,輸出約是輸入值的250倍;如果存在多層,250x250x…,很快就爆炸了。如果在層後使用Sigmoid函數,将值映射到較小的空間,又會發生非線性激活函數的飽和問題,使收斂變慢。

是以,簡單的方法是:

W = np.random.randn(o_dim, i_dim) * 0.01   
np.zeros((o_dim, 1))      

bias不導緻對稱性,一般設定為0。

常用的初值化方法

全0或全1的初始化方法不能使用,而随機初始化也存在一些問題,由于各層的輸入和輸出元素個數不同,這使得每一層輸出資料的方差也不同,比如層輸入500個元素和5個元素,同等大小的w,輸出的大小可能差出百倍。不同層的調參将受到影響。

Xavier初始化

假設層的輸入有三個元素x1,x2,x3,輸入為y,權重分别是w1,w2,w3,

初始化網絡參數

則y值為:

y=w1x1+w2x2+w3x3,在計算參數w的初值時考慮到輸入該層元素的個數n:于是出現了Xavier方法。

初始化網絡參數

Kaiming初始化

Xavier的問題是,它沒有考慮到激活函數對輸出資料分布的影響,它會帶偏目前廣泛使用的ReLU激活函數的結果,于是He Kaiming提取了針對ReLU激活函數的Kaiming初始化(有時也叫作He初始化)。

其原理是:由于ReLU過濾掉了0以下的輸入值,是以,激活函數輸出的均值将大于0,為解決這和問題,Kaiming方法修改了生成随機數時的标準差。

初始化網絡參數

ReLU過濾掉了一半資料,是以分子乘2,分母是上一層的輸出元素個數,即本層的輸入元素個數。推導過程請見論文:《Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification》的Section 2.2。

盡管Kaiming初始化一開始主要針對ReLU激活函數優化,但是目前主流庫中的Kaiming函數已經支援sigmoid等多種激活函數,可放心調用。

歸一化層

Kaiming的目标也是保證各個層輸入和輸出資料的方差不變。由于後來歸一化層被廣泛使用,有效地緩解了均值和方差穩定的問題。是以,在使用歸一化層的情況下,使用随機數始初化參數即可。

另外,在有些情況下無法使用歸一化層,比如最常用的BN(Batch Normalization)在Batch中資料較少時效果不好,這種情況下就需要選用參數初始化。

Python參數初始化

def init_network_params(model, method='xavier', keywords, seed=123, debug=False):  
    for name, w in model.named_parameters():  
        init = False  
        for key in keywords:  
            if key in name:  
                init = True  
        if init:  
            if debug:  
                print('init layer params', name)  
            if 'weight' in name:  
                if method == 'xavier':  
                    nn.init.xavier_normal_(w)  
                elif method == 'kaiming':  
                    nn.init.kaiming_normal_(w)  
                else:  
                    nn.init.normal_(w)  
            elif 'bias' in name:  
                nn.init.constant_(w, 0)  
            else:  
                pass      
kaiming_uniform_(self.weight, a=math.sqrt(5))      

繼續閱讀