YOLOv 4によくある非線形活性化関数の詳細解


YOLOv 4で使用されるアクティブ関数はMish活性化関数です。
YOLOv 4で言及されている活性化関数は、ReLU、Leaky ReLU、PReLU、ReLU 6、SELU、Swish、Mishである。
このうち、Leaky ReLUは、PReLUのトレーニングが困難であり、ReLU 6は量子化ネットワーク設計に移行する。
アクティブ関数使用プロセス図:
在这里插入图片描述
一、飽和活性化関数
 1.1、Sigmoid
関数式:

Sigmoid関数画像とその微分画像:
在这里插入图片描述
利点:
  • 案内しやすい平滑関数です。
  • データを圧縮し、出力を[0,1][0,1][0,1]の間に確保し(出力を正規化したに相当)、データの幅に問題がないことを保証する。
  • (上下界がある)順方向伝播には適していますが、逆方向伝播には不利です。
  • 短所:
  • 勾配が消えやすく、重みの更新に不利である。
  • 0平均ではないので、後層のニューロンの入力は0平均でない信号となり、勾配に影響を与えます。f=sigmoid(wx+b)を例にとって、入力が正(または負)であると仮定すると、wに対する導関数は常に正(または負)であり、このように逆伝搬過程でいずれも正の方向に更新されるか、または負の方向に更新されるので、収束が遅いようなバンドル効果が生じる。
  • 指数演算は、相対的に時間がかかります。
  • 1.2、hard-Sigmoid関数
    hard-Sigmoid関数のときのSigmoid活性化関数の区分的線形近似。
    関数式:

    hard-Sigmoid関数画像とSigmoid関数画像のコントラスト:
    在这里插入图片描述
    hard-Sigmoid関数画像とその微分画像:
    在这里插入图片描述
    利点:
  • 公示や曲線から見て、より計算しやすく、指数演算がないため、訓練の効率が向上します。
  • 短所:
  • 最初の派生値がゼロになると、ニューロンdiedや学習が遅くなる可能性があります。
  • 1.3、Tanh双曲線タンジェント
    関数式:

    Tanh関数画像とそのガイド関数画像:
    在这里插入图片描述
    利点:
  • Sigmoid関数の非ZERO-centred問題を解決した
  • データを圧縮して、出力を[0,1][0,1][0,1]の間(出力を正規化したに相当)に保証し、データの幅に問題がないようにする。上下界がある)
  • 短所:
  • 勾配が消えやすいので、重みの更新には不利です。
  • 指数演算は、相対的に時間がかかります。
  • 二、非飽和活性化関数
     2.1、ReLU(修正リニアユニット)
    関数式:
    f(z)=m a x(0,x)f(z)=max(0,x)f(z)=max(0,x)
    ReLU関数画像とその微分画像:
    在这里插入图片描述
    利点:
  • ReLuの収束速度はsigmoidとtanhより速い;
  • 入力が正の場合、勾配が消えてしまう問題を解決し、逆伝搬に適しています。
  • 計算の複雑さが低いので、指数演算は不要です。
  • 短所:
  • ReLUの出力はゼロ・センターredではない。
  • ReLUはデータの幅を圧縮しないので、データの幅はモデル層数の増加とともに拡大していきます。下界あり、上界なし)
  • Dead ReLU Proble:xが負の場合、勾配は0であり、これらのニューロンは永遠に活性化されない可能性があり、該当パラメータは更新されない(入力がマイナスの場合、関数に勾配が消える現象があります。
  •  2.2、ReLU 6(その最大値を抑制する)
    関数式:

    ReLU関数画像とReLU 6関数画像の比較:
    在这里插入图片描述
    ReLU 6関数画像とその微分画像:
    在这里插入图片描述
    2.3、Leakly ReLU
    関数式:

    ReLU関数画像とLeakly ReLU関数画像の比較:
    在这里插入图片描述
    Leakly ReLU関数画像とその微分画像:
    在这里插入图片描述
    利点:
  • 上記のdead ReLU現象を解決し、負の領域も勾配が消える;
  • 理論的にはLeaky ReLUはReLUより優れていますが、実際の操作では必ずしもそうではありません。
    2.4、PReLU(parametric ReLU)
    関数式:

    注意:

    関数画像:
    在这里插入图片描述
    利点:
  • dead ReLU現象を避けることができます。
  • ELUに比べて負の値を入力すると勾配が消えない。
  • 2.5、ELU(指数線形関数)
    関数式:

    ELU関数画像とその微分画像(α = 1.5\アルファ=1.5α=1.5):
    在这里插入图片描述
    利点:
  • ReLUのすべての長所があり、Dead ReLU Problem(ニューロン壊死現象)がない;
  • 出力はゼロ・センターredで、出力平均は0に近い。
  • バイアスオフセットの影響を低減することにより、正常勾配を自然勾配に近づけ、平均値を0に加速させる。
  • 短所:
  • 計算量がより高い。
  • 理論的にはELUはReLUより優れていますが、実際のデータでは必ずしもそうではありません。
    2.6、SELU
    SELUはELUの上にもう一つ追加しました。λ \lambanλパラメータλ > 1\lamban>1λ>1
    関数式:

    ELU関数画像とSELU関数画像の比較(α = 1.5,λ = 2\alpha=1.5、\lamban=2α=1.5,λ=2)
    在这里插入图片描述
    SELU関数画像とその導関数画像(α = 1.5,λ = 2\alpha=1.5、\lamban=2α=1.5,λ=2)
    在这里插入图片描述
    利点:
  • 従来のReLU、P-RELU、ELUなどの活性化関数はすべて負の半軸勾配が緩やかで、アクティブな分散が大きすぎると勾配を減少させて勾配爆発を防止しましたが、正の半軸では勾配がシンプルに設定されています。一方、SELUの正半軸は1より大きく、分散が小さいときは増大させることができますが、勾配の消失を防ぐことができます。このように、アクティブ関数は、ネットワークが深いと、各階層の出力は平均値0で、分散は1.2.7、Swish
  • 関数式:

    Swish関数画像(β = 0.1,β = 1,β = 10\beta=0.1、\beta=1、\beta=10β=0.1,β=1,β=10):
    在这里插入图片描述
    Swish関数勾配画像(β = 0.1,β = 1,β = 10\beta=0.1、\beta=1、\beta=10β=0.1,β=1,β=10):
    在这里插入图片描述
    利点:
  • x>0の時も同様に勾配がなくなった場合。x<0の時、ニューロンもReLUのように死亡することはありません。
  • 同時にSwishはReLU導関数に比べて一定不変ではないのも利点です。
  • しかもSwishは至るところにガイドされ、連続的に滑らかである。
  • 短所:
  • 計算量が多く、本来はsigmoid関数は計算しにくいので、sigmoidよりも難しいです。2.8、hard-Swish
  • ハードとは、画像を全体的に滑らかにしないことです。
    関数式:

    hard-Swish関数画像とSwish(β = 1\beta=1β=1)関数画像のコントラスト:
    在这里插入图片描述
    hard-Swish関数画像とSwish(β = 1\beta=1β=1)関数勾配画像のコントラスト:
    在这里插入图片描述
    利点:
  • hard-Swish近似はSwishの効果を達成しました。
  • Swishの計算量が大きすぎる問題を改善し、量子化モードでは、ReLU関数はSigmoidに比べて多すぎます。
  •  2.9、Mish
    論文の住所:
    https://arxiv.org/pdf/1908.08681.pdf
    活性化関数についての最新の文章は、広くYOLO 4に使われています。Swishより0.494%アップしています。ReLUより1.671%アップしています。
    Mish関数の数式:

    Mish関数画像とSwish(β = 1\beta=1β=1)関数画像のコントラスト:
    在这里插入图片描述
    Mish関数画像とSwish(β = 1\beta=1β=1)関数の微分画像の比較:
    在这里插入图片描述
    なぜMishの方がいいですか?
    上の無境界(すなわち正の値は任意の高さに達することができる)は,キャップによる飽和を回避した。理論的に負の値に対するわずかな許容度は,ReLUにおけるような硬零境界ではなく,より良い勾配流を可能にする。
    最後に、最も重要かもしれませんが、現在の考えは、平滑化された活性化関数によって、より良い情報が神経ネットワークに深く入ることができ、より良い精度と一般化が得られます。Mish関数は曲線上のほとんどの点で極めて滑らかである。
    三、PyTorch実現
    
    import matplotlib.pyplot as plt
    import numpy as np
    
    class ActivateFunc():
        def __init__(self, x, b=None, lamb=None, alpha=None, a=None):
            super(ActivateFunc, self).__init__()
            self.x = x
            self.b = b
            self.lamb = lamb
            self.alpha = alpha
            self.a = a
    
        def Sigmoid(self):
            y = np.exp(self.x) / (np.exp(self.x) + 1)
            y_grad = y*(1-y)
            return [y, y_grad]
    
        def Hard_Sigmoid(self):
            f = (2 * self.x + 5) / 10
            y = np.where(np.where(f > 1, 1, f) < 0, 0, np.where(f > 1, 1, f))
            y_grad = np.where(f > 0, np.where(f >= 1, 0, 1 / 5), 0)
            return [y, y_grad]
    
        def Tanh(self):
            y = np.tanh(self.x)
            y_grad = 1 - y * y
            return [y, y_grad]
    
        def ReLU(self):
            y = np.where(self.x < 0, 0, self.x)
            y_grad = np.where(self.x < 0, 0, 1)
            return [y, y_grad]
    
        def ReLU6(self):
            y = np.where(np.where(self.x < 0, 0, self.x) > 6, 6, np.where(self.x < 0, 0, self.x))
            y_grad = np.where(self.x > 6, 0, np.where(self.x < 0, 0, 1))
            return [y, y_grad]
    
        def LeakyReLU(self):   # a  1,  a
            y = np.where(self.x < 0, self.x / self.a, self.x)
            y_grad = np.where(self.x < 0, 1 / self.a, 1)
            return [y, y_grad]
    
        def PReLU(self):    # a  1,  a
            y = np.where(self.x < 0, self.x / self.a, self.x)
            y_grad = np.where(self.x < 0, 1 / self.a, 1)
            return [y, y_grad]
    
        def ELU(self): # alpha    ,  alpha
            y = np.where(self.x > 0, self.x, self.alpha * (np.exp(self.x) - 1))
            y_grad = np.where(self.x > 0, 1, self.alpha * np.exp(self.x))
            return [y, y_grad]
    
        def SELU(self):  # lamb  1,  lamb alpha
            y = np.where(self.x > 0, self.lamb * self.x, self.lamb * self.alpha * (np.exp(self.x) - 1))
            y_grad = np.where(self.x > 0, self.lamb * 1, self.lamb * self.alpha * np.exp(self.x))
            return [y, y_grad]
    
        def Swish(self): # b     ,  b
            y = self.x * (np.exp(self.b*self.x) / (np.exp(self.b*self.x) + 1))
            y_grad = np.exp(self.b*self.x)/(1+np.exp(self.b*self.x)) + self.x * (self.b*np.exp(self.b*self.x) / ((1+np.exp(self.b*self.x))*(1+np.exp(self.b*self.x))))
            return [y, y_grad]
    
        def Hard_Swish(self):
            f = self.x + 3
            relu6 = np.where(np.where(f < 0, 0, f) > 6, 6, np.where(f < 0, 0, f))
            relu6_grad = np.where(f > 6, 0, np.where(f < 0, 0, 1))
            y = self.x * relu6 / 6
            y_grad = relu6 / 6 + self.x * relu6_grad / 6
            return [y, y_grad]
    
        def Mish(self):
            f = 1 + np.exp(x)
            y = self.x * ((f*f-1) / (f*f+1))
            y_grad = (f*f-1) / (f*f+1) + self.x*(4*f*(f-1)) / ((f*f+1)*(f*f+1))
            return [y, y_grad]
    
    def PlotActiFunc(x, y, title):
        plt.grid(which='minor', alpha=0.2)
        plt.grid(which='major', alpha=0.5)
        plt.plot(x, y)
        plt.title(title)
        plt.show()
    
    def PlotMultiFunc(x, y):
        plt.grid(which='minor', alpha=0.2)
        plt.grid(which='major', alpha=0.5)
        plt.plot(x, y)
    
    if __name__ == '__main__':
        x = np.arange(-10, 10, 0.01)
        activateFunc = ActivateFunc(x)
        activateFunc.a = 100
        activateFunc.b= 1
        activateFunc.alpha = 1.5
        activateFunc.lamb = 2
    
        plt.figure(1)
        PlotMultiFunc(x, activateFunc.Sigmoid()[0])
        PlotMultiFunc(x, activateFunc.Hard_Sigmoid()[0])
        PlotMultiFunc(x, activateFunc.Tanh()[0])
        PlotMultiFunc(x, activateFunc.ReLU()[0])
        PlotMultiFunc(x, activateFunc.ReLU6()[0])
        PlotMultiFunc(x, activateFunc.LeakyReLU()[0])
        PlotMultiFunc(x, activateFunc.ELU()[0])
        PlotMultiFunc(x, activateFunc.SELU()[0])
        PlotMultiFunc(x, activateFunc.Swish()[0])
        PlotMultiFunc(x, activateFunc.Hard_Swish()[0])
        PlotMultiFunc(x, activateFunc.Mish()[0])
    
        plt.legend(['Sigmoid', 'Hard_Sigmoid', 'Tanh', 'ReLU', 'ReLU6', 'LeakyReLU',
                    'ELU', 'SELU', 'Swish', 'Hard_Swish', 'Mish'])
        plt.show()
    四、結果表示
    在这里插入图片描述
    Reference
    リンク1:link.
    リンク2:link.
    https://arxiv.org/pdf/1908.08681.pdf
    ここでYOLOv 4によくある非線形活性化関数について詳しく説明した文章を紹介します。もっと関連するYOLOv 4活性化関数の内容は以前の文章を検索してください。または下記の関連記事を引き続き閲覧してください。これからもよろしくお願いします。