激活函數maxout
maxout函數相對於其他的激活函數有很大的區別,可以看做是在神經網絡中激活函數的地方加入一個激活函數層。maxout可以看做是一個可學習的分段線性函數,因爲可學習所以是需要參數的,而且參數是可以通過反向傳播來學習的。因爲參數量的增大,勢必導致計算量的增大。
傳統的神經網絡從第i層輸入到第i+1層,只需要訓練一組權重參數,這些參數決定了上一層輸入到到達這一層之後進行的變換。但是maxout做的事情就是第i層到第i+1層之前我們多訓練一些參數,對第i層的輸出,我們將每個輸出連接k個隱藏層,通過k個隱藏層的參數進行計算之後,然後把這k個隱藏層求最大值,作爲最終的輸出。
這裏我們給出maxout的計算公式。
,使用maxout需要人爲的設定一個參數k,這個參數k就是每個神經元輸出之後接的虛擬隱藏層的個數。而權重參數W的維度是的,d代表的是輸入節點的個數,m代表的則是輸出層節點的個數。這也是之前神經網絡第i+1層的參數設置。但是現在多出來一個維度k,就是爲了產生中間的k個輸出,然後將這k個輸出再取一個最大值。
如上圖,原本的神經網絡只有輸入的兩個神經元x,輸出的只有一個神經元,普通的神經元則是直接把x和連接,現在相當於在兩層之間又增加了個參數,然後輸入先經過這個maxout的隱藏層得到輸出,然後對輸出取最大值,再輸入到下一層當中。其中虛擬隱藏層的和就是所需要學習的參數。可以看到,參數量的增大是針對每一個輸出神經元增加k個的。
普通的神經元配合激活函數得到一組輸出,經過了maxout將會得到k組輸出,然後在k組之中取最大值。可見maxout非線性的擬合能力是更強的,因爲參數更多,而且可學習。我們能想到,而maxout也是取最大,如果我們能讓一個虛擬神經元學習,一個虛擬神經元學習,然後兩個神經元求最大就得到了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