激活函數maxout

激活函數maxout


  maxout函數相對於其他的激活函數有很大的區別,可以看做是在神經網絡中激活函數的地方加入一個激活函數層。maxout可以看做是一個可學習的分段線性函數,因爲可學習所以是需要參數的,而且參數是可以通過反向傳播來學習的。因爲參數量的增大,勢必導致計算量的增大。
  傳統的神經網絡從第i層輸入到第i+1層,只需要訓練一組權重參數,這些參數決定了上一層輸入到到達這一層之後進行的變換。但是maxout做的事情就是第i層到第i+1層之前我們多訓練一些參數,對第i層的輸出,我們將每個輸出連接k個隱藏層,通過k個隱藏層的參數進行計算之後,然後把這k個隱藏層求最大值,作爲最終的輸出。

  這裏我們給出maxout的計算公式。
在這裏插入圖片描述
  ,使用maxout需要人爲的設定一個參數k,這個參數k就是每個神經元輸出之後接的虛擬隱藏層的個數。而權重參數W的維度是(d,m,k)(d,m,k)的,d代表的是輸入節點的個數,m代表的則是輸出層節點的個數。這也是之前神經網絡第i+1層的參數設置。但是現在多出來一個維度k,就是爲了產生中間的k個輸出,然後將這k個輸出再取一個最大值。
maxout原理示意圖
  如上圖,原本的神經網絡只有輸入的兩個神經元x,輸出的只有一個神經元hi(x)h_i(x),普通的神經元則是直接把x和hi(x)h_i(x)連接,現在相當於在兩層之間又增加了k=5k=5個參數,然後輸入先經過這個maxout的隱藏層得到輸出,然後對輸出取最大值,再輸入到下一層當中。其中虛擬隱藏層的WWbb就是所需要學習的參數。可以看到,參數量的增大是針對每一個輸出神經元增加k個的。
  普通的神經元配合激活函數得到一組輸出,經過了maxout將會得到k組輸出,然後在k組之中取最大值。可見maxout非線性的擬合能力是更強的,因爲參數更多,而且可學習。我們能想到relu(z)=max(0,z)relu(z)=max(0,z),而maxout也是取最大,如果我們能讓一個虛擬神經元學習m(x)=xm(x)=x,一個虛擬神經元學習m(x)=0m(x)=0,然後兩個神經元求最大就得到了relu激活函數。可見這是k=2的情況,如果我們有更多的k,就可以學習更加負責的激活函數,這就是maxout擬合能力更強的原因。事實上maxout可以擬合任意的凸函數。
  相比於ReLU,ReLU有的優點maxout有,是分段線性的,不容易梯度消失。同時ReLU沒有的優點,maxout可能也有,比如神經元不會死亡。但是這些優點是通過計算量換來的,maxout的計算量非常大,我們已經解釋過。
  這個激活函數的實現沒什麼難的,就是在指定的維度上取最大值即可,但是爲了得到能夠得到這個要取最大值的維度的變量,往往需要在上一層的神經元上做手腳,需要增加參數量。原本是m維的輸出通道數,現在需要變成k×m的數出通道。給出tensorflow代碼示例。

x=tf.random_normal([1,3])
m=4  # out_channel
k=3  # maxout_chanenl
d=x.get_shape().as_list()[-1]
W=tf.Variable(tf.random_normal(shape=[d,m,k]))
b=tf.Variable(tf.random_normal(shape=[m,k]))
# 從W和b的維度看出參數量是增大了
dot_z=tf.tensordot(x,W,axes=1)+b
z=tf.reduce_max(dot_z,axis=2)  # 這裏再把maxout的通道給取最大降維下去

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run([x,dot_z,z]))

  事實上這裏還有一種方式就是爲maxout特殊定義一個方法或者類,然後就可以像其他普通的激活函數一樣使用。以下給出tensorflow代碼示例。

def maxout(inputs, num_units, axis=None):
    '''
    inputs: 上一層的輸出的結果,這裏需要上一層的輸出結果的維度是k*m
    num_units:激活後的最終的輸出結果數m
    '''
    shape = inputs.get_shape().as_list()
    if axis is None:
        # Assume that channel is the last dimension
        axis = -1
    num_channels = shape[axis]
    if num_channels % num_units:
        raise ValueError('number of features({}) is not a multiple of num_units({})'
             .format(num_channels, num_units))
    shape[axis] = num_units
    shape += [num_channels // num_units]
    for i in range(len(shape)):
        if shape[i] is None:
            shape[i] = -1
    outputs = tf.reduce_max(tf.reshape(inputs, shape), -1, keepdims=False)
    return outputs

# X.shape = (..., d)
X = tf.layers.conv2d(inputs=X, filters=k * m, kernel_size, strides, padding)
# X.shape = (..., m*k)
X = maxout(inputs=X, num_units=m)
# X.shape = (..., m)

系列文章:

神經網絡中的激活函數總述
sigmoid激活函數
tanh激活函數
ReLU系列激活函數
maxout激活函數
Swish激活函數
激活函數發展的新里程——EvoNorms

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章