[阿里DIN] 從論文源碼梳理深度學習幾個概念
0x00 摘要
本文基於阿里推薦 DIN 和 DIEN 代碼,梳理了下深度學習一些概念,以及TensorFlow中的相關實現。
因為篇幅所限,所以之前的整體代碼講解中,很多細節沒有深入,所以本文會就這些細節進行探討,旨在幫助小伙伴們詳細了解每一的步驟以及為什么要這樣做。
涉及概念有:全連接層,prelu,batch normalization等。
0x01 全連接層
1.1 全連接層作用
全連接層則起到將學到的 “分布式特征表示” 映射到 ”樣本標簽空間” 的作用。
全連接的核心操作就是矩陣向量乘積 y = Wx。本質就是由一個特征空間線性變換到另一個特征空間。目標空間的任一維——也就是隱層的一個 cell——都認為會受到源空間的每一維的影響。可以說,目標向量是源向量的加權和。
泰勒公式就是用多項式函數去擬合光滑函數。全連接層中一層的一個神經元就可以看成一個多項式,我們用許多神經元去擬合數據分布,但是只用一層 fully-connected layer 有時候沒法解決非線性問題,而如果有兩層或以上 fully-connected layer 就可以很好地解決非線性問題了。
1.2 CNN
全連接層之前的作用是提取特征,全連接層的作用是分類。
卷積取的是局部特征,全連接就是把以前的局部特征重新通過權值矩陣組裝成完整的圖。因為用到了所有的局部特征,所以叫全連接。
我們現在的任務是去區別一圖片是不是貓:
在CNN中,全連接層把特征representation整合到一起,輸出為一個值。這樣做可以大大減少特征位置對分類帶來的影響。
比如識別一個圖片中的貓,貓在不同的位置,輸出的 feature 值相同,但是位置不同。對於電腦來說,特征值相同,但是特征值位置不同,那分類結果也可能不一樣,而這時全連接層 filter 的作用就相當於
喵在哪我不管
我只要喵於是我讓filter去把這個喵找到,實際就是把 feature map 整合成一個值:這個值大,哦,有喵;這個值小,那就可能沒喵,和這個喵在哪關系不大了有沒有,魯棒性有大大增強了有沒有
最后總結就是,卷積神經網絡中全連接層的設計,屬於人們在傳統特征提取+分類思維下的一種"遷移學習"思想,但在這種end-to-end的模型中,其用於分類的功能其實是被弱化了,而全連接層參數過多的缺點也激勵着人們設計出更好的模型替代之達到更好的效果。同時,也將促進我們更深入地探討其中的奧秘。
1.3 RNN
為什么模型最后需要加入全連接層?
從模型擬合能力上說,不是必須的;從模型設計角度上說,是常見的。因為假如用RNN做一維時序數據的回歸任務,RNN的隱元包含的是一些時序狀態的信息,主要是在time上的擬合能力,與問題定義的輸出之間通常具有比較明顯的gap,和任務想要獲得的輸出之間還存在一個映射,最后的fc就是用來完成這道任務的。
1.4 DIN使用
DIN中,大量使用了FCN,比如:
query = tf.layers.dense(query, facts_size, activation=None, name='f1' + stag)
query = prelu(query)
0x02 prelu
2.1 激活函數作用
首先我們要明白激活函數的作用是:增加模型的非線性表達能力。
深度學習的目的是用一堆神經元堆出一個函數大致的樣子,然后通過大量的數據去反向擬合出這個函數的各個參數,最終勾勒出函數的完整形狀。
那如果激活函數只是線性函數,那一層層的線性函數堆起來還是線性的,這年頭線性函數能干啥呀?
肯定不行,這樣整個網絡表現能力有限,所以要引入非線性的激活函數進來。
就是鉛筆不夠畫的,咱得上帶顏色、筆觸更豐富的油畫筆。
2.2 prelu 和 sigmoid 之間對比
具體 prelu 和 sigmoid 之間對比如下。
- 首先,sigmoid 有一個“梯度消失”的問題。
- 梯度消失什么意思呢?就是我們希望對每個神經元,激勵函數都能盡量區分出z值變化,這樣每個神經元的表達能力更強,但sigmoid明顯在|z|>4的區間的梯度就不夠看了,即它的梯度消失了。
- 相比之下,ReLU輸出就很穩定,因為他z>0區間就是一個線性函數!不存在sigmoid的梯度消失的問題。
- 其次,另一個ReLU給力的地方就是稀疏度問題。
- 我們希望每個神經元都能最大化的發揮它篩選的作用,符合某一個特征的中間值,使勁兒放大;不符合的,一刀切掉。
- 反觀sigmoid就要黏糊的多。這個函數是很對稱很美,但它面對負的z值仍然剪不斷理還亂,會輸出一個小的激勵值(tanh會好一些但仍不能避免),形成所謂的“稠密表示”。
- 最后,ReLU運算速度快,max肯定比冪指數快的多。
2.3 DIN使用
DIN中使用如下,可以看到,在全連接函數中,Batch Normalization 之后就接入了激活函數:
def prelu(_x, scope=''):
"""parametric ReLU activation"""
with tf.variable_scope(name_or_scope=scope, default_name="prelu"):
_alpha = tf.get_variable("prelu_"+scope, shape=_x.get_shape()[-1],
dtype=_x.dtype,
initializer=tf.constant_initializer(0.1))
return tf.maximum(0.0, _x) + _alpha * tf.minimum(0.0, _x)
def build_fcn_net(self, inp, use_dice = False):
bn1 = tf.layers.batch_normalization(inputs=inp, name='bn1')
dnn1 = tf.layers.dense(bn1, 200, activation=None, name='f1')
if use_dice:
dnn1 = dice(dnn1, name='dice_1')
else:
dnn1 = prelu(dnn1, 'prelu1')
0x03 Batch Normalization
3.1 DIN使用
在DIN中,全連接層構建中,上來就進行了Batch Normalization。
def build_fcn_net(self, inp, use_dice = False):
bn1 = tf.layers.batch_normalization(inputs=inp, name='bn1')
dnn1 = tf.layers.dense(bn1, 200, activation=None, name='f1')
if use_dice:
dnn1 = dice(dnn1, name='dice_1')
else:
dnn1 = prelu(dnn1, 'prelu1')
所以我們要看看 Batch Normalization 究竟起到什么作用。
3.2 BN層作用
BN層的作用主要有三個:
- 加快網絡的訓練和收斂的速度;
- 控制梯度爆炸防止梯度消失;
- 防止過擬合;
3.3 BN思想
機器學習領域有個很重要的假設:IID獨立同分布假設,就是假設訓練數據和測試數據是滿足相同分布的,這是通過訓練數據獲得的模型能夠在測試集獲得好的效果的一個基本保障。BatchNorm就是在深度神經網絡訓練過程中使得每一層神經網絡的輸入保持相同分布的。
3.3.1 Internal Covariate Shift
“Internal Covariate Shift”問題是指:對於深度學習這種包含很多隱層的網絡結構,在訓練過程中,因為各層參數老在變,所以每個隱層都會面臨covariate shift的問題。Internal指的是深層網絡的隱層,是發生在網絡內部的事情,而不是covariate shift問題只發生在輸入層。
因此,就有了Batch Normalization的基本思想:能不能讓每個隱層節點的激活輸入分布固定下來呢?這樣就避免了“Internal Covariate Shift”問題了。
BN不是憑空拍腦袋拍出來的好點子,它是有啟發來源的:之前的研究表明如果在圖像處理中對輸入圖像進行白化(Whiten)操作的話——所謂白化,就是對輸入數據分布變換到0均值,單位方差的正態分布——那么神經網絡會較快收斂,那么BN作者就開始推論了:圖像是深度神經網絡的輸入層,做白化能加快收斂,那么其實對於深度網絡來說,其中某個隱層的神經元是下一層的輸入,意思是其實深度神經網絡的每一個隱層都是輸入層,不過是相對下一層來說而已,那么能不能對每個隱層都做白化呢?這就是啟發BN產生的原初想法,而BN也確實就是這么做的,可以理解為對深層神經網絡每個隱層神經元的激活值做簡化版本的白化操作。
3.3.2 基本思想
詳細解釋Batch Normalization的基本思想:對於每個隱層神經元,把逐漸向非線性函數映射后向取值區間極限飽和區靠攏的輸入分布強制拉回到均值為0方差為1的比較標准的正態分布,使得非線性變換函數的輸入值落入對輸入比較敏感的區域,以此避免梯度消失問題。因為梯度一直都能保持比較大的狀態,所以很明顯對神經網絡的參數調整效率比較高,就是變動大,就是說向損失函數最優值邁動的步子大,也就是說收斂地快。
有的讀者一般會提出一個疑問:如果都通過BN,那么不就跟把非線性函數替換成線性函數效果相同了?這意味着什么?我們知道,如果是多層的線性函數變換其實這個深層是沒有意義的,因為多層線性網絡跟一層線性網絡是等價的。這意味着網絡的表達能力下降了,這也意味着深度的意義就沒有了。
所以BN為了保證非線性的獲得,對變換后的滿足均值為0方差為1的x又進行了scale加上shift操作(y=scale*x+shift),每個神經元增加了兩個參數scale和shift參數,這兩個參數是通過訓練學習到的,意思是通過scale和shift把這個值從標准正態分布左移或者由移一點並長胖一點或者變瘦一點,每個實例挪動的程度不一樣,這樣等價於非線性函數的值從正中心周圍的線性區往非線性區動了動。
核心思想是想找到一個線性和非線性的較好平衡點,既能享受非線性的較強表達能力的好處,又避免太靠非線性區兩頭使得網絡收斂速度太慢。
0xFF 參考s
對全連接層(fully connected layer)的通俗理解
斯坦福cs231n學習筆記(9)------神經網絡訓練細節(Batch Normalization)
https://blog.csdn.net/zongza/article/details/89682862
Tensorflow 的reduce_sum()函數到底是什么意思