Swish函数先对来说是比较新的一些激活函数,算是由之前的激活函数复合而成出来的。也是由Google提出的,毕竟资力雄厚,承担的起搜索的任务。而且这个算法感觉曝光率还算比较高,就在这里整理一下,同时后面的文章也会再次提到这个函数。
对前面的激活函数有了一定的基础之后,理解Swish激活就容易很多了,Swish函数的表达式是
,
就是sigmoid函数。因为sigmoid函数的饱和性容易导致梯度消失,借鉴ReLU的效果,当
非常大的时候,这个时候有
趋近于
,但是当
,函数的大致走势和ReLU比较相似,但是又比ReLU复杂。
但是呢,为了让自己理论看起来更厉害一些,所以通常就把自己的想法抽象成一个框架,以囊括更多的东西进去。通常在函数上体现就是加几个超参数进去,然后呈现出更多的特性。在Swish中,加了一个超参数使得函数表达式变成了
,然后说这个
可以是常量,或者是可训练参数。函数的图像如下。
接下来就是考虑这个激活函数的反向传播了,核心步骤就是求导。显然这里就是复合求导。
则有
上面已经提到过
的情况,容易明白在
的时候,同样是不存在梯度消失的情况。而在
的时候,神经元也不会像ReLU一样出现死亡的情况。同时Swish相比于ReLU导数不是一成不变的,这也是一种优势。而且Swish处处可导,连续光滑。另外还有一个特点就是Swish并非一个单调的函数。但是swish也并非没有任何缺点,最大的缺点就是计算量大,本来sigmoid函数就不容易计算。
在Swish之上,后面有人提出了一种激活函数叫h-swish,这个h代表hard(硬)的意思。大概是想让激活函数硬起来。我说的是边界,sigmoid函数取值位于[0,1]之间,两侧边界都是趋近于0或者1,这个趋近于就是soft的意思,如果直接就是常量,这就是hard。
找到一个sigmoid函数的近似,但是两边边界是hard的。这个函数就是
,relu6代表着什么,因为relu函数无上界,给relu函数加一个上界,如果大于6,就让relu函数的值等于6,就是relu6。图像如下。
显然如果对relu6再除6再向左平移三个单位,就会得到一条类似于sigmoid函数的图像。对比图如下。
可以看到swish中使用到了sigmoid函数,如果我们使用h-sigmoid来构造swish函数,就得到了h-swish函数。这样一近似,计算量也变小了。
这个激活后函数基本就是这样了,不知道以后是否会变成一种范式,彻底撼动ReLU的地位。
pytorch实现
class SwishImplementation(torch.autograd.Function):
@staticmethod
def forward(ctx, i):
ctx.save_for_backward(i)
return i * torch.sigmoid(i)
@staticmethod
def backward(ctx, grad_output):
sigmoid_i = torch.sigmoid(ctx.saved_variables[0])
return grad_output * (sigmoid_i * (1 + ctx.saved_variables[0] * (1 - sigmoid_i)))
class Swish(nn.Module):
def forward(self, x):
return SwishImplementation.apply(x)
系列文章:
神经网络中的激活函数总述
sigmoid激活函数
tanh激活函数
ReLU系列激活函数
maxout激活函数
Swish激活函数
激活函数发展的新里程——EvoNorms