![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAjM2EzLcd3LcJzLcJzdllmVldWYtl2Pn5GcucTOjZzMlV2NlF2NwgTOmFWOiFjM5cjNyEzMwEjNzkDNvwFMwUTNwYzMtUGall3LcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.png)
本文提出了Squareplus激活函數,這是一個類似softplus的激活函數,但隻需要通過簡單的代數運算來實作:加法、乘法和平方根。由于Squareplus在CPU上的計算速度比softplus快約6倍。
11 Squareplus
激活函數是深度學習體系結構的核心組成部分。特定的非線性應用于神經網絡的每一層,影響訓練的動态和測試時間的準确性,是一個關鍵的工具,當設計體系結構的輸出必須在一定範圍内。當限制一個層的輸出為非負時,一個普遍的做法是應用ReLU激活:
雖然ReLU保證了非負輸出,但它有兩個潛在的缺點:
- 當x≤0時,它的梯度為零
- 在x = 0時,它是不連續的
如果需要平滑或非零梯度,通常使用Softplus代替ReLU:
Softplus是ReLU的上界,當|x|較大時接近ReLU,但與ReLU不同的是,它是連續的。
雖然Softplus是一個有效的工具,但它也有一些潛在的缺點:
- 高效計算并不簡單,因為它需要求兩個transcendental 函數的值
- 當x很大時,Softplus的簡單實作在數值上是不穩定的(當x遠大于0時,傳回x作為Softplus(x)的輸出,可以直接改善這個問題)
在這裡,提供了一個Softplus的替代方案,它沒有上訴的缺點,這裡稱之為“Squareplus”:
Squareplus由超參數b>0定義,它決定了x=0附近彎曲區域的大小。
圖1顯示了不同b值的Squareplus(以及它的一階和二階導數),以及Softplus。Squareplus與Softplus有很多相同的特性:
- 它的輸出是非負的
- 它是ReLU的一個上界函數,會随着|x|的增長而接近ReLU
- 它是連續的
然而,Squareplus隻使用代數運算進行計算,這使得它非常适合計算資源或指令集有限的情況。此外,當x較大時,Squareplus無需特别考慮確定數值穩定性。Squareplus的一階導數和二階導數為:
就像Squareplus本身一樣,這些導數是也是代數形式的,計算起來很簡單。類似地,Softplus的導數是經典的logistic s型函數,Squareplus的導數是“Sigmoid”函數x/\sqrt{x^2+1} (相應縮放和移動)。類似地,Softplus的二階導數是Logistic分布的PDF,平方加号的二階導數(b=2)是學生t分布 (ν = 2)。
超參數b的特定值産生某些性質。當b=0時,Squareplus簡化為ReLU:
通過設定b = 4ln^2 2 ,可以在原點附近近似Softplus的形狀:
這也是b的最小值,在這裡Squareplus的輸出總是保證大于Softplus的輸出:
設定b = 4使Squareplus的二階導數近似于Softplus的原點附近,并給出的輸出為1在原點(使用者可能會覺得很直覺):
對于b的所有有效值,Squareplus的一階導數在原點處為0.5,就像Softplus一樣:
b超參數可以被認為是一個尺度參數,類似于Charbonnier/pseudoHuber損失中的偏移如何被參數化為一個尺度參數。同樣,縮放x(不縮放激活輸出)或改變b也可以産生相同的激活:
雖然Squareplus表面上類似于Softplus,但當|x|增長較大時,Squareplus接近ReLU的速度明顯慢于Softplus。
如圖2所示繪制了Squareplus/Softplus和ReLU之間的差別。這張圖也顯示了在大輸入上Softplus的數值不穩定性,這就是為什麼大多數Softplus實作在x >0。類似于函數本身的緩慢漸近行為,當x<0時,Squareplus的梯度接近零比Softplus的梯度更慢。這個屬性在實踐中可能是有用的,因為“死亡”梯度通常是不受歡迎的,但這可能是依賴于任務的。
如表1所示,在CPU上Squareplus要比Softplus快約6倍,與ReLU相當。在GPU上,Squareplus隻比Softplus快10%,可能是因為所有整流器都受到記憶體帶寬的限制,而不是在這種設定下的計算能力。這表明Squareplus可能隻是在計算資源有限或無法使用Softplus的情況下(可能是因為硬體平台不支援exp和log)的理想替代方案。
Pytorch實作如下:
class Squareplus(nn.Module):
def __init__(self, b=0.2):
super(Squareplus, self).__init__()
self.b = b
def forward(self, x):
x = 0.5 * (x + torch.sqrt(x+self.b))
return x
複制
這裡也提供了自适應參數版本,已經上傳【集智書童】知識星球。