[PYTHON] Liste des fonctions d'activation (2020)

Personne cible

J'ai résumé le type de fonction d'activation. ** Les derniers Swish et Mish, ainsi que tanhExp! ** ** Je cible le calque que je ne trouve pas de bon même si je recherche dans la liste. De nouveaux seront ajoutés dès qu'ils seront trouvés. Si vous avez des informations sur de nouvelles fonctions ou fonctions dans la liste TODO ci-dessous, veuillez nous en informer!

Liste de choses à faire

--Vérifiez les informations supplémentaires de la fonction hardShrink --Vérifiez les informations supplémentaires de la fonction softShrink --Vérifiez les informations supplémentaires de la fonction Seuil --Vérifiez les informations supplémentaires de la fonction logSigmoid --Vérifiez les informations supplémentaires de la fonction tanhShrink --Vérifiez les informations supplémentaires de la fonction hardtanh --Vérifiez les informations supplémentaires de la fonction ReLU6 --Vérifiez les informations supplémentaires de la fonction CELU --Vérifiez les informations supplémentaires de la fonction softmin --Vérifiez les informations supplémentaires de la fonction logSoftmax

table des matières

Fonction étape (étape)

D'abord de la fonction étape. Probablement la fonction d'activation la plus ancienne. step.png À cette époque, il était utilisé pour implémenter Perceptron, mais il est rarement vu dans l'apprentissage en profondeur de nos jours. La raison est que le différentiel est $ 0 $ pour tous les nombres réels ($ x \ ne 0 $), donc les paramètres ne peuvent pas être optimisés par rétropropagation.

La formule de propagation vers l'avant est

y = \left\{
  \begin{array}{cc}
    1 & (x \gt 0) \\
    0 & (x \le 0)
  \end{array}
\right.

Comme ça, la formule de la propagation arrière est naturelle

\cfrac{\partial y}{\partial x} = 0

Et multipliez cela par l'erreur coulée. En d'autres termes, rien n'est jeté. Pour cette raison, la méthode de propagation des erreurs de retour n'a pas pu être appliquée, et elle a été forcée à l'ombre dans l'apprentissage en profondeur.

Fonction d'identité

La fonction d'égalité sort l'entrée telle quelle. Il est utilisé pour la fonction d'activation de la couche de sortie de l'analyse de régression. Il n'y a pas de tour dans la couche intermédiaire. Le but de l'utilisation d'une telle fonction d'activation est ** de l'implémenter de manière unique **. La mise en œuvre unique vise ici à ne pas diviser le traitement par branchement conditionnel ou autre. identity.png Comme la valeur différentielle est de 1 $, l'erreur se propage à la couche précédente telle quelle. Puisque le calcul d'erreur utilise l'erreur quadratique, la propagation vers la couche suivante sera $ y --t $ ~

La formule de propagation vers l'avant est

y = x

Et la propagation arrière est

\cfrac{\partial y}{\partial x} = 1

Ce sera. Vous pouvez voir que la valeur qui vient de s'écouler s'écoulera!

Fonction Bent Identity

C'est une fonction similaire à [Identity function](# constant function identity). Cependant, il n'est pas droit mais légèrement incurvé. bent-identity.png

La formule de propagation vers l'avant est

y = \cfrac{1}{2}(\sqrt{x^2 + 1} - 1) + x

Comme ça, propagation arrière

\cfrac{\partial y}{\partial x} = \cfrac{x}{2 \sqrt{x^2 + 1}} + 1

Ce sera. D'une manière ou d'une autre, cela ressemble à [fonction ReLU](fonction #relu) (impression personnelle). Je n'ai pas pu trouver l'article introduit en japonais en un coup d'œil, donc je pense que c'est une fonction d'activation mineure.

Fonction hardShrink

De Pytorch, juste une introduction pour le moment. ** Consultez les informations supplémentaires TODO ** hard-shrink.png La formule de propagation vers l'avant est

y = \left\{
  \begin{array}{cc}
    x & (x \lt -\lambda \quad \textrm{or} \quad \lambda \lt x) \\
    0 & (\textrm{otherwise})
  \end{array}
\right.

Et la propagation arrière est

\cfrac{\partial y}{\partial x} = \left\{
  \begin{array}{cc}
    1 & (x \lt -\lambda \quad \textrm{or} \quad \lambda \lt x) \\
    0 & (\textrm{otherwise})
  \end{array}
\right.

Ce sera. La valeur par défaut de $ \ lambda $ est de 0,5 $.

fonction softShrink

Ceci est également juste une introduction de Pytorch. ** Consultez les informations supplémentaires TODO *** soft-shrink.png La formule de propagation vers l'avant est

y = \left\{
  \begin{array}{cc}
    x + \lambda & (x \lt -\lambda) \\
    x - \lambda & (x \gt \lambda) \\
    0 & (\textrm{otherwise})
  \end{array}
\right.

Et la propagation arrière est

\cfrac{\partial y}{\partial x} = \left\{
  \begin{array}{cc}
    1 & (x \lt -\lambda \quad \textrm{or} \quad \lambda \lt x) \\
    0 & (\textrm{otherwise})
  \end{array}
\right.

Ce sera. La valeur initiale de $ \ lambda $ ici est également de 0,5 $.

Fonction de seuil

Ceci est juste une introduction de Pytorch. ** Consultez les informations supplémentaires TODO ** threshold.png La formule de propagation vers l'avant est

y = \left\{
  \begin{array}{cc}
    x & (x \gt threshold) \\
    value & (\textrm{otherwise})
  \end{array}
\right.

Et la propagation arrière est

y = \left\{
  \begin{array}{cc}
    1 & (x \gt threshold) \\
    0 & (\textrm{otherwise})
  \end{array}
\right.

Ce sera. Où le seuil et la valeur des variables sont des valeurs qui doivent être données à l'avance. De manière appropriée pour le moment dans le graphique

threshold = -1 \\
value = -2

C'est dit.

Fonction sigmoïde (sigmoïde)

La fonction sigmoïde est une fonction d'activation souvent utilisée lors de l'introduction de la méthode de rétropropagation. Cependant, il est rarement utilisé dans la couche intermédiaire maintenant, et il est souvent utilisé dans la couche de sortie des problèmes de classification binaire. La raison en est l'inconvénient décrit plus loin. sigmoid.png Propagation vers l'avant

y = \cfrac{1}{1 + e^{-x}}

Rétropropagation

\cfrac{\partial y}{\partial x} = y(1 - y)

Peut être écrit comme La plus grande caractéristique est que la différenciation peut être facilement obtenue à partir de la sortie, mais la réponse aux entrées extrêmement grandes et petites est médiocre, et la valeur maximale de la différenciation est de 0,25 $, donc si vous empilez des couches ** gradient Il existe également des inconvénients tels que le problème de la disparition **. De plus, comme il existe un calcul et une division exponentiels, la charge de calcul est inévitablement plus élevée que celle des fonctions simples telles que [fonction ReLU](fonction #relu).

Fonction hardSigmoid

La fonction hardSigmoid est une approximation linéaire de la fonction sigmoïde, telle qu'une fonction linéaire. hard-sigmoid.png Mathématiquement, propagation vers l'avant

y = \left\{
  \begin{array}{cc}
    1 & (x \gt 2.5) \\
    0.2x + 0.5 & (-2.5 \le x \le 2.5) \\
    0 & (x \lt -2.5)
  \end{array}
\right.

Rétropropagation

\cfrac{\partial y}{\partial x} = \left\{
  \begin{array}{cc}
    0.2 & (-2.5 \le x \le 2.5) \\
    0 & (\textrm{otherwise})
  \end{array}
\right.

On dirait. Il existe un Article vérifié en détail, donc si vous voulez en savoir plus, allez-y! Il y a une raison théorique tellement compliquée que le coefficient de la fonction linéaire est de 0,2 $ ... ~~ Je l'ai lu mais je n'ai pas compris du tout ~~

fonction logSigmoid

Ceci est également juste une introduction de Pytorch. Prend le logarithme de [fonction sigmoïde](# fonction sigmoïde sigmoïde). ** Consultez les informations supplémentaires TODO ** log-sigmoid.png La formule de propagation vers l'avant est

y = \log \left( \cfrac{1}{1 + e^{-x}} \right)

Et rétropropagation

\cfrac{\partial y}{\partial x} = \cfrac{1}{1 + e^x}

Ce sera. Notez que le dénominateur de la rétropropagation n'est pas la puissance $ -x $.

fonction tanh

La fonction tanh, qui est l'une des fonctions à deux courbes, a été proposée comme l'une des fonctions pour résoudre le problème que la valeur maximale de la différenciation de [fonction sigmoïde](# fonction sigmoïde sigmoïde) est de 0,25 $. tanh.png Comme vous pouvez le voir sur la figure, la valeur maximale du différentiel est de 1 $ et la cause de la disparition du gradient peut être éliminée. Cependant, il y a toujours le problème que la différenciation entre les intrants extrêmement grands et petits est de 0 $.

y = \tanh x = \cfrac{e^x - e^{-x}}{e^x + e^{-x}}

Rétropropagation

\cfrac{\partial y}{\partial x} = \textrm{sech}^2 x = \cfrac{1}{\cosh^2 x} = \cfrac{4}{(e^x + e^{-x})^2}

Ce sera. Récemment, il a été partiellement utilisé pour les nouvelles étoiles attendues telles que [fonction Mish](fonction #mish) et [fonction tanhExp](fonction #tanhexp) .Il semble être une fonction avec une grande attention.

Fonction tanhShrink

C'est aussi de Pytorch. C'est juste une introduction. ** Consultez les informations supplémentaires TODO ** tanh-shrink.png La formule de propagation vers l'avant est

y = x - \tanh x

Et la propagation arrière est

\cfrac{\partial y}{\partial x} = \tanh^2 x

Ce sera.

fonction hardtanh

C'est aussi Pytorch. Introduction seulement ... ** Consultez les informations supplémentaires TODO ** hard-tanh.png La formule de propagation vers l'avant est

y = \left\{
  \begin{array}{cc}
    1 & (x \gt 1) \\
    -1 & (x \lt -1) \\
    x & (\textrm{otherwise})
  \end{array}
\right.

Et la propagation arrière est

\cfrac{\partial y}{\partial x} = \left\{
  \begin{array}{cc}
    0 & (x \lt -1 \quad \textrm{or} \quad 1 \le x) \\
    1 & (\textrm{otherwise})
  \end{array}
\right.

Ce sera.

Fonction ReLU

La fonction ReLU (généralement appelée fonction de rampe) est une fonction d'activation proposée assez récemment qui détient la suprématie. La caractéristique est ce calcul simple et rapide. ReLU.png La formule de propagation vers l'avant est

y = \left\{
  \begin{array}{cc}
    x & (x \gt 0) \\
    0 & (x \le 0)
  \end{array}
\right.

Rétropropagation

\cfrac{\partial y}{\partial x} = \left\{
  \begin{array}{cc}
    1 & (x \gt 0) \\
    0 & (x \le 0)
  \end{array}
\right.

Ce sera. Si l'entrée est une valeur positive, le gradient sera toujours $ 1 $, donc le gradient disparaît moins facilement et il est facile d'empiler les couches, mais il y a aussi l'inconvénient que l'apprentissage ne se déroule pas du tout pour les entrées négatives. En outre, il ignore fondamentalement la discontinuité à $ x = 0 $. Dans la méthode de propagation d'erreur en retour, l'apprentissage est avancé en fonction de la propagation du gradient en utilisant la loi des chaînes, de sorte que la fonction d'activation doit être différentiable avec tous les nombres réels, mais en réalité, elle est parfaite $ x = 0 $ Il y a moins de cas où cela devient & $ 0 $ de toute façon, donc ce n'est pas grave.

Fonction ReLU6

Seulement une introduction de Pytorch. ** Consultez les informations supplémentaires TODO ** ReLU6.png La formule de propagation vers l'avant est

y = \left\{
  \begin{array}{cc}
    0 & (x \le 0) \\
    6 & (x \ge 6) \\
    x & (\textrm{otherwise})
  \end{array}
\right.

Et rétropropagation

\cfrac{\partial y}{\partial x} = \left\{
  \begin{array}{cc}
    0 & (x \le 0 \quad \textrm{or} \quad 6 \le x) \\
    1 & (\textrm{otherwise})
  \end{array}
\right.

Ce sera.

Fonction leaky-ReLU

La fonction leaky-ReLU sort une fonction linéaire avec un très petit gradient lorsqu'il y a une entrée négative, afin de compenser l'inconvénient de la [fonction ReLU](fonction #relu) que "l'apprentissage ne se déroule pas pour les entrées négatives". C'est quelque chose comme ça. leaky-ReLU.png On ne voit pas grand-chose dans le graphique, mais dans la formule

y = \left\{
  \begin{array}{cc}
    x & (x \gt 0) \\
    0.01x & (x \le 0)
  \end{array}
\right.

La sortie est différente lorsque l'entrée est négative. Par conséquent, la rétropropagation

\cfrac{\partial y}{\partial x} = \left\{
  \begin{array}{cc}
    1 & (x \gt 0) \\
    0.01 & (x \le 0)
  \end{array}
\right.

Ce sera. Ceci est également discontinu à $ x = 0 $. Aussi, je l'ai vu à divers endroits au cours de mes recherches, mais il semble que le nom de cette fonction dise: "Il n'y avait aucun intérêt particulier à l'utiliser." C'est un peu surprenant. On dirait que ça va s'améliorer un peu ...

Fonction ELU

Un graphe de forme similaire à la [fonction ReLU](fonction #relu), l'une des fonctions les plus lisses lorsque $ x = 0 $ est la fonction ELU. ELU.png Comme vous pouvez le voir sur le graphique, les entrées négatives n'entraînent pas un gradient de $ 0 $ ($ 0 $ pour $ x \ to- \ infty $). Dans la formule

y = \left\{
  \begin{array}{cc}
    x & (x \ge 0) \\
    \alpha (e^x - 1) & (x \lt 0)
  \end{array}
\right.

Et rétropropagation

\cfrac{\partial y}{\partial x} = \left\{
  \begin{array}{cc}
    1 & (x \ge 0) \\
    \alpha e^x & (x \lt 0)
  \end{array}
\right.

Ce sera. Il semble que la valeur de ~~ $ \ alpha $ prend souvent une valeur théoriquement appropriée dans la prochaine [fonction SELU](fonction #selu) (probablement). ~~ ** Révisé le 02/06/2020 ** La valeur par défaut de $ \ alpha $ semble généralement être $ 1 $. Je vais le remplacer par un graphique de $ \ alpha = 1 $. Je suis désolé d'avoir envoyé les mauvaises informations ...

Fonction SELU

La fonction SELU est la sortie de la [fonction ELU](fonction #elu) multipliée par $ \ lambda $. SeLU.png Dans la formule

y = \left\{
  \begin{array}{cc}
    \lambda x & (x \ge 0) \\
    \lambda \alpha (e^x - 1) & (x \lt 0)
  \end{array}
\right.

Et rétropropagation

\cfrac{\partial y}{\partial x} = \left\{
  \begin{array}{cc}
    \lambda & (x \ge 0) \\
    \lambda \alpha e^x & (x \lt 0)
  \end{array}
\right.

Il est multiplié par $ \ lambda $ comme dans. Il semble que la valeur du paramètre théoriquement optimale puisse être obtenue, et cette valeur est

\alpha = 1.67326\ldots, \quad \lambda = 1.0507\ldots

Il semble que. Je vais peut-être lire le journal bientôt ... Je le compléterai quand je le lirai.

Fonction CELU

Ceci est également une introduction uniquement de Pytorch. ** Consultez les informations supplémentaires TODO ** CeLU.png La formule de propagation vers l'avant est

y = \left\{
  \begin{array}{cc}
    x & (x \ge 0) \\
    \alpha \left( e^{\frac{x}{\alpha}} - 1 \right) & (\textrm{otherwise})
  \end{array}
\right.

Et la formule de rétropropagation est

y = \left\{
  \begin{array}{cc}
    1 & (x \ge 0) \\
    e^{\frac{x}{\alpha}} & (\textrm{otherwise})
  \end{array}
\right.

Ce sera.

Fonction Softmax (softmax)

La fonction softmax est utilisée comme fonction d'activation pour la couche de sortie des problèmes de classification à valeurs multiples. En raison des caractéristiques du calcul, la sortie peut être considérée comme une probabilité. softmax.png Ne vous inquiétez pas trop de l'axe vertical du graphique. Tout ce qui compte, c'est que lorsque vous intégrez (l'ordinateur est discret, alors résumez-le), vous obtenez 1 $. Mathématiquement

y_i = \cfrac{e^{x_i}}{\displaystyle\sum_{k=1}^{n}{e^{x_k}}} \quad (i = 1, 2, \ldots, n)

C'est comme ça. La propagation arrière est provisoire

\left( \cfrac{\partial y}{\partial x} \right)_i = e^{x_i} \cfrac{\displaystyle\sum_{k=1}^{n}{e^{x_k}} - e^{x_i}}{\left( \displaystyle\sum_{k=1}^{n}{e^{x_k}} \right)^2}

Cependant, ** erreur d'entropie croisée **

Error = t \log y

En prenant, la rétro-propagation de la couche de sortie à la couche intermédiaire

y - t

Ce sera très simple. Au fait, ce n'est pas une coïncidence, l'erreur d'entropie croisée est une fonction conçue pour s'adapter à la fonction softmax de sorte que le gradient soit $ y-t $. Je peux l'introduire un jour dans un graphique de calcul.

fonction softmin

C'est aussi de Pytorch. À l'opposé de [fonction softmax](fonction #softmax softmax), la probabilité de petites valeurs augmente. ** Consultez les informations supplémentaires TODO ** softmin.png La formule de propagation vers l'avant est

y_i = \cfrac{e^{-x_i}}{\displaystyle\sum_{k=1}^{n}{e^{-x_k}}} \quad (i = 1, 2, \ldots, n)

Et la formule de rétropropagation est

\left( \cfrac{\partial y}{\partial x} \right)_i = e^{-x_i} \cfrac{\displaystyle\sum_{k=1}^{n}{e^{-x_k}} - e^{-x_i}}{\left( \displaystyle\sum_{k=1}^{n}{e^{-x_k}} \right)^2}

Ce sera. Si l'erreur d'entropie croisée est également utilisée ici, l'erreur se propagera-t-elle proprement ... Je l'étudierai la prochaine fois.

Fonction logSoftmax

De Pytorch, c'est la logarithmique de [fonction softmax](fonction #softmax softmax). ** Consultez les informations supplémentaires TODO ** log-softmax.png Ça a l'air presque droit. Je me demande si cela correspond ... Je pense que le code est correct. La formule de propagation vers l'avant est

y_i = \log \left( \cfrac{e^{x_i}}{\displaystyle\sum_{k=1}^{n}{e^{x_k}}} \right)

Et la propagation arrière est

\left( \cfrac{\partial y}{\partial x} \right)_i = \cfrac{\displaystyle\sum_{k=1}^{n}{e^{x_k}} - e^{x_i}}{\displaystyle\sum_{k=1}^{n}{e^{x_k}}}

Ce sera.

fonction softplus

La fonction softplus a un nom similaire à [fonction softmax](fonction #softmax softmax), mais est essentiellement similaire à [fonction ReLU](fonction #relu). softplus.png

Dans la formule

y = \log{(1 + e^x)} = \ln{(1 + e^x)}

Exprimé comme, rétropropagation

\cfrac{\partial y}{\partial x} = \cfrac{e^x}{1 + e^x} = \cfrac{1}{1 + e^{-x}}

On dirait. Cela ressemble exactement à la [fonction ReLU](fonction #relu) et à la différenciation.

Soit dit en passant, $ \ ln x $ sert à préciser que la base est une fonction logarithmique des nombres de Napier. En d'autres termes

\ln x = \log_ex

C'est ça.

fonction softsign

Encore une fois, le nom est similaire à [fonction softmax](fonction #softmax softmax), mais en réalité, il est similaire à [fonction tanh](fonction #tanh) (propagation directe). softsign.png

La propagation vers l'avant ressemble exactement à la fonction tanh, mais la propagation arrière est complètement différente. C'est très net. Regarder la propagation vers l'avant avec une formule mathématique

y = \cfrac{x}{1 + |x|}

Et rétropropagation

\cfrac{\partial y}{\partial x} = \cfrac{1}{(1 + |x|)^2}

Il est devenu. A ~~ $ x = 0 $, la différenciation est devenue une fonction discontinue. ~~ ** Révisé le 02/06/2020 ** J'ai mal compris la continuité de la fonction. Ce n'est pas correctement discontinu. Il ne peut pas être différencié.

\lim_{x \to \pm 0}{\cfrac{1}{(1 + |x|)^2}} = 1
\Leftrightarrow
\lim_{x \to 0}{\cfrac{1}{(1 + |x|)^2}} = 1 

Et

\cfrac{\partial y}{\partial x} = \cfrac{1}{(1 + |0|)^2} = 1 \quad (\because x = 0)

Alors

\lim_{x \to 0}{\cfrac{1}{(1 + |x|)^2}} = \cfrac{1}{(1 + |0|)^2}

Se montre continue.

Fonction Swish

Il s'agit de la fonction Swish qui devrait succéder à la [fonction ReLU](fonction #relu) apparue en 2017. Swish.png Cela ressemble exactement à la [fonction ReLU](fonction #relu), mais contrairement à la [fonction ELU](fonction #elu) et à la [fonction SELU](fonction #selu), c'est une fonction continue même à $ x = 0 $. Je suis. Une autre caractéristique est qu'il s'agit d'une fonction de classe $ C ^ {\ infty} $. En outre, vous pouvez également voir qu'il faut une petite quantité de valeurs négatives pour les entrées négatives. Le bon point est qu'il y a une valeur minimale et il n'y a pas de valeur maximale. Lorsque la propagation vers l'avant est exprimée par une formule mathématique

y = x \sigma_{sigmoid}(\beta x) = \cfrac{x}{1 + e^{-\beta x}}

C'est comme ça. Dans le graphique ci-dessus, $ \ beta = 1 $ est défini. Au fait, il semble que $ \ beta $ puisse être optimisé par la méthode de propagation de retour d'erreur (non implémentée). Rétropropagation

\cfrac{\partial y}{\partial x} = \beta y + \sigma_{sigmoid}(\beta x)(1 - \beta y) = \beta y + \cfrac{1 - \beta y}{1 + e^{-\beta x}}

Vous pouvez écrire comme ça. Cela ressemble à un aperçu de la [fonction sigmoïde](# fonction sigmoïde sigmoïde).

Fonction Mish

La fonction Mish est le successeur de la [fonction ReLU](fonction #relu) proposée en 2019, qui est encore plus récente que la [fonction Swish](fonction #swish). Des articles ont montré qu'il surpasse souvent la fonction Swish. (Je n'ai pas encore lu correctement le journal, mais il l'a écrit) Mish.png Cela ressemble presque à la fonction Swish, mais c'est légèrement différent. swish_vs_mish.png Le graphique à l'extrême droite montre le plus de différence. Ce graphique est le calcul de chaque double différenciation. En d'autres termes, il représente le degré de changement du dégradé. Ce que l'on peut lire sur le graphique, c'est que la fonction Mish transmet l'erreur de manière plus significative, en particulier dans le calcul du gradient $ \ Rightarrow $, qui change dynamiquement autour de $ x = 0 $. En tant que formule de propagation directe

y = x \tanh{(\varsigma(x))} = x \tanh{(\ln{(1 + e^x)})}

La propagation arrière est un peu compliquée

\cfrac{\partial y}{\partial x} = \cfrac{e^x \omega}{\delta^2}\\
\omega = 4(x + 1) + 4e^{2x} + e^{3x} + (4x + 6)e^x \\
\delta = 2e^x + e^{2x} + 2

Il est calculé comme suit. Par conséquent, son apprentissage prend plus de temps que la fonction ReLU. Cependant, il est souvent préférable d'utiliser la fonction ReLU en termes de précision, alors considérez le compromis entre le temps d'apprentissage et la précision lors du choix d'une fonction d'activation.

Fonction tanhExp

C'est la fonction tanhExp fournie par @ reppy4620! Selon Paper, c'est de mars 2020 ~ C'est terriblement récent. tanhExp.png Comme vous pouvez le voir dans l'article, c'est un membre de la [fonction ReLU](fonction #relu) (s'appelle-t-elle la famille ReLU?). Apparemment, il surpasse la [fonction Mish](fonction #mish) dans des ensembles de données célèbres tels que MNIST, CIFER-10 et CIFER-100 (je ne l'ai pas encore lu). Comparer avec [fonction Swish](fonction #swish) Swish_vs_tanhExp.png La sortie de la propagation directe semble presque la même, mais la fonction tanhExp a une pente plus raide et une plage plus petite sur la valeur différentielle de $ 1 $ en propagation arrière. Le dégradé est très délicat, et si la valeur absolue du différentiel est inférieure à 1 $, le dégradé disparaît immédiatement, et inversement, s'il est supérieur à 1 $, une explosion de gradient se produit. La fonction tanhExp est également excellente à cet égard. Puis comparez avec [fonction Mish](fonction #mish). Mish_vs_tanhExp.png La fonction Mish suit la fonction tanhExp plutôt que la fonction Swish. Cependant, la fonction tanhExp est toujours meilleure dans les pentes raides autour de 0 $. Regardons la propagation vers l'avant avec une formule mathématique.

y = x \tanh(e^x)

Vous utilisez la fonction tanh ainsi que la fonction Mish. La fonction tanh ne retient-elle pas plus l'attention maintenant? Rétropropagation

\begin{align}
  \cfrac{\partial y}{\partial x} &= \tanh(e^x) + xe^x\textrm{sech}^2(e^x) \\
  &= \tanh(e^x) - xe^x(\tanh^2(e^x) - 1)
\end{align}

Ce sera. C'est bien de pouvoir calculer beaucoup plus simple que la fonction Mish ~

Exemple de code

Voici un exemple du code utilisé lors du dessin du graphique. Veuillez l'utiliser comme référence lors de la mise en œuvre. J'utilise un bloc-notes Jupyter.

activators.py

activators.py


import numpy as np


class Activator():
    def __init__(self, *args,**kwds):
        pass
    

    def forward(self, *args,**kwds):
        raise Exception("Not Implemented")
    
    
    def backward(self, *args,**kwds):
        raise Exception("Not Implemented")
    
    
    def update(self, *args,**kwds):
        pass


class step(Activator):
    def forward(self, x, *args,**kwds):
        return np.where(x > 0, 1, 0)
    
    
    def backward(self, x, *args,**kwds):
        return np.zeros_like(x)


class identity(Activator):
    def forward(self, x, *args,**kwds):
        return x
    
    
    def backward(self, x, *args,**kwds):
        return np.ones_like(x)


class bentIdentity(Activator):
    def forward(self, x, *args,**kwds):
        return 0.5*(np.sqrt(x**2 + 1) - 1) + x
    
    
    def backward(self, x, *args,**kwds):
        return 0.5*x/np.sqrt(x**2 + 1) + 1


class hardShrink(Activator):
    def __init__(self, lambda_=0.5, *args,**kwds):
        self.lambda_ = lambda_
        super().__init__(*args,**kwds)
    
    
    def forward(self, x, *args,**kwds):
        return np.where((-self.lambda_ <= x) & (x <= self.lambda_),
                        0, x)
    
    
    def backward(self, x, *args,**kwds):
        return np.where((-self.lambda_ <= x) & (x <= self.lambda_),
                        0, 1)


class softShrink(Activator):
    def __init__(self, lambda_=0.5, *args,**kwds):
        self.lambda_ = lambda_
        super().__init__(*args,**kwds)
    
    
    def forward(self, x, *args,**kwds):
        return np.where(x < -self.lambda_, x + self.lambda_,
                        np.where(x > self.lambda_, x - self.lambda_, 0))
    
    
    def backward(self, x, *args,**kwds):
        return np.where((-self.lambda_ <= x) & (x <= self.lambda_),
                        0, 1)


class threshold(Activator):
    def __init__(self, threshold, value, *args,**kwds):
        self.threshold = threshold
        self.value = value
        super().__init__(*args,**kwds)
    
    
    def forward(self, x, *args,**kwds):
        return np.where(x > self.threshold, x, self.value)
    
    
    def backward(self, x, *args,**kwds):
        return np.where(x > self.threshold, 1, 0)


class sigmoid(Activator):
    def forward(self, x, *args,**kwds):
        return 1/(1 + np.exp(-x))
    
    
    def backward(self, x, y, *args,**kwds):
        return y*(1 - y)


class hardSigmoid(Activator):
    def forward(self, x, *args,**kwds):
        return np.clip(0.2*x + 0.5, 0, 1)
    
    
    def backward(self, x, *args,**kwds):
        return np.where((x > 2.5) | (x < -2.5), 0, 0.2)


class logSigmoid(Activator):
    def forward(self, x, *args,**kwds):
        return -np.log(1 + np.exp(-x))
    
    
    def backward(self, x, *args,**kwds):
        return 1/(1 + np.exp(x))


class act_tanh(Activator):
    def forward(self, x, *args,**kwds):
        return np.tanh(x)
    
    
    def backward(self, x, *args,**kwds):
        return 1 - np.tanh(x)**2


class hardtanh(Activator):
    def forward(self, x, *args,**kwds):
        return np.clip(x, -1, 1)
    
    
    def backward(self, x, *args,**kwds):
        return np.where((-1 <= x) & (x <= 1), 1, 0)


class tanhShrink(Activator):
    def forward(self, x, *args,**kwds):
        return x - np.tanh(x)
    
    
    def backward(self, x, *args,**kwds):
        return np.tanh(x)**2


class ReLU(Activator):
    def forward(self, x, *args,**kwds):
        return np.maximum(0, x)
    
    
    def backward(self, x, *args,**kwds):
        return np.where(x > 0, 1, 0)


class ReLU6(Activator):
    def forward(self, x, *args,**kwds):
        return np.clip(x, 0, 6)
    
    
    def backward(self, x, *args,**kwds):
        return np.where((0 < x) & (x < 6), 1, 0)


class leakyReLU(Activator):
    def __init__(self, alpha=1e-2, *args,**kwds):
        self.alpha = alpha
        super().__init__(*args,**kwds)
    
    
    def forward(self, x, *args,**kwds):
        return np.maximum(self.alpha * x, x)
    
    
    def backward(self, x, *args,**kwds):
        return np.where(x < 0, self.alpha, 1)


class ELU(Activator):
    def __init__(self, alpha=1., *args,**kwds):
        self.alpha = alpha
        super().__init__(*args,**kwds)
    
    
    def forward(self, x, *args,**kwds):
        return np.where(x >= 0, x, self.alpha*(np.exp(x) - 1))
    
    
    def backward(self, x, *args,**kwds):
        return np.where(x >= 0, 1, self.alpha*np.exp(x))


class SELU(Activator):
    def __init__(self, lambda_=1.0507, alpha=1.67326, *args,**kwds):
        self.lambda_ = lambda_
        self.alpha = alpha
        super().__init__(*args,**kwds)
    
    
    def forward(self, x, *args,**kwds):
        return np.where(x >= 0,
                        self.lambda_*x,
                        self.lambda_*self.alpha*(np.exp(x) - 1))
    
    
    def backward(self, x, *args,**kwds):
        return np.where(x >= 0, 
                        self.lambda_,
                        self.lambda_*self.alpha*np.exp(x))


class CELU(Activator):
    def __init__(self, alpha=1., *args,**kwds):
        self.alpha = alpha
        super().__init__(*args,**kwds)
    
    
    def forward(self, x, *args,**kwds):
        return np.where(x >= 0,
                        x,
                        self.alpha*(np.exp(x/self.alpha) - 1))
    
    
    def backward(self, x, *args,**kwds):
        return np.where(x >= 0, 1, np.exp(x/self.alpha))


class softmax(Activator):
    def forward(self, x, *args,**kwds):
        return np.exp(x)/np.sum(np.exp(x))
    
    
    def backward(self, x, *args,**kwds):
        return np.exp(x)*(np.sum(np.exp(x)) 
                          - np.exp(x))/np.sum(np.exp(x))**2


class softmin(Activator):
    def forward(self, x, *args,**kwds):
        return np.exp(-x)/np.sum(np.exp(-x))
    
    
    def backward(self, x, *args,**kwds):
        return -(np.exp(x)*(np.sum(np.exp(-x)) - np.exp(x))
                 /np.sum(np.exp(-x))**2)


class logSoftmax(Activator):
    def forward(self, x, *args,**kwds):
        return np.log(np.exp(x)/np.sum(np.exp(x)))
    
    
    def backward(self, x, *args,**kwds):
        y = np.sum(np.exp(x))
        return (y - np.exp(x))/y


class softplus(Activator):
    def forward(self, x, *args,**kwds):
        return np.logaddexp(x, 0)
    
    
    def backward(self, x, *args,**kwds):
        return 1/(1 + np.exp(-x))


class softsign(Activator):
    def forward(self, x, *args,**kwds):
        return x/(1 + np.abs(x))
    
    
    def backward(self, x, *args,**kwds):
        return 1/(1 + np.abs(x)) ** 2


class Swish(Activator):
    def __init__(self, beta=1, *args,**kwds):
        self.beta = beta
        super().__init__(*args,**kwds)
    
    
    def forward(self, x, *args,**kwds):
        return x/(1 + np.exp(-self.beta*x))
    
    
    def backward(self, x, y, *args,**kwds):
        return self.beta*y + (1 - self.beta*y)/(1 + np.exp(-self.beta*x))
    
    
    def d2y(self, x, *args,**kwds):
        return (-0.25*self.beta*(self.beta*x*np.tanh(0.5*self.beta*x) - 2)
                               *(1 - np.tanh(0.5*self.beta*x)**2))


class Mish(Activator):
    def forward(self, x, *args,**kwds):
        return x*np.tanh(np.logaddexp(x, 0))
    
    
    def backward(self, x, *args,**kwds):
        omega = (4*(x + 1) + 4*np.exp(2*x) 
                 + np.exp(3*x) + (4*x + 6)*np.exp(x))
        delta = 2*np.exp(x) + np.exp(2*x) + 2
        return np.exp(x)*omega/delta**2
    
    
    def d2y(self, x, *args,**kwds):
        omega = (2*(x + 2) 
                 + np.exp(x)*(np.exp(x)*(-2*np.exp(x)*(x - 1) - 3*x + 6)
                              + 2*(x + 4)))
        delta = np.exp(x)*(np.exp(x) + 2) + 2
        return 4*np.exp(x)*omega/delta**3


class tanhExp(Activator):
    def forward(self, x, *args,**kwds):
        return x*np.tanh(np.exp(x))
    
    
    def backward(self, x, *args,**kwds):
        tanh_exp = np.tanh(np.exp(x))
        return tanh_exp - x*np.exp(x)*(tanh_exp**2 - 1)
    
    
    def d2y(self, x, *args,**kwds):
        tanh_exp = np.tanh(np.exp(x))
        return (np.exp(x)*(-x + 2*np.exp(x)*x*tanh_exp - 2)
                         *(tanh_exp**2 - 1))


class maxout(Activator):
    def __init__(self, n_prev, n, k, wb_width=5e-2, *args,**kwds):
        self.n_prev = n_prev
        self.n = n
        self.k = k
        self.w = wb_width*np.random.rand((n_prev, n*k))
        self.b = wb_width*np.random.rand(n*k)
        
        super().__init__(*args,**kwds)
    
    
    def forward(self, x, *args,**kwds):
        self.x = x.copy()
        self.z = np.dot(self.w.T, x) + self.b
        self.z = self.z.reshape(self.n, self.k)
        self.y = np.max(self.z, axis=1)
        return self.y
    
    def backward(self, g, *args,**kwds):
        self.dw = np.sum(np.dot(self.w, self.x))
test_activators.py

test_activators.py


import numpy as np
import matplotlib.pyplot as plt


_act_dic = {"step": step,
            "identity": identity,
            "bent-identity": bentIdentity,
            "hard-shrink": hardShrink,
            "soft-shrink": softShrink,
            "threshold": threshold,
            "sigmoid": sigmoid,
            "hard-sigmoid": hardSigmoid,
            "log-sigmoid": logSigmoid,
            "tanh": act_tanh,
            "tanh-shrink": tanhShrink,
            "hard-tanh":hardtanh,
            "ReLU": ReLU,
            "ReLU6": ReLU6,
            "leaky-ReLU": leakyReLU,
            "ELU": ELU,
            "SELU": SELU,
            "CELU": CELU,
            "softmax": softmax,
            "softmin": softmin,
            "log-softmax": logSoftmax,
            "softplus": softplus,
            "softsign": softsign,
            "Swish": Swish,
            "Mish": Mish,
            "tanhExp": tanhExp,
           }


def get_act(name, *args,**kwds):
    for act in _act_dic:
        if name == act:
            activator = _act_dic[name](*args,**kwds)
            break
    else:
        raise ValueError(name, ": Unknown activator")
    
    return activator


def plot_graph(x, name, *args,**kwds):
    activator = get_act(name, *args,**kwds)
    
    y = activator.forward(x, *args,**kwds)
    dx = activator.backward(x, y, *args,**kwds)
    
    plt.plot(x, y, label="forward")
    plt.plot(x, dx, label="backward")
    plt.title(name)
    plt.xlabel("x")
    plt.ylabel("y")
    plt.grid()
    plt.legend(loc="best")
    plt.savefig("{}.png ".format(name))
    plt.show()


def vs_plot(x, A, B):
    A_activator = get_act(A)
    B_activator = get_act(B)
    
    y_A = {}
    y_B = {}
    
    y_A["{} y".format(A)] = A_activator.forward(x)
    y_B["{} y".format(B)] = B_activator.forward(x)
    y_A["{} dy".format(A)] = A_activator.backward(x, 
                                                  y_A["{} y".format(A)])
    y_B["{} dy".format(B)] = B_activator.backward(x,
                                                  y_B["{} y".format(B)])
    y_A["{} d2y".format(A)] = A_activator.d2y(x, y_A["{} y".format(A)])
    y_B["{} d2y".format(B)] = B_activator.d2y(x, y_B["{} y".format(B)])
    
    fig, ax = plt.subplots(1, 3, figsize=(18, 6))
    for i, key in enumerate(y_A):
        ax[i].plot(x, y_A[key], label=key)
        ax[i].set_xlabel("x")
        ax[i].set_ylabel("y")
        ax[i].grid()
    for i, key in enumerate(y_B):
        ax[i].plot(x, y_B[key], label=key)
        ax[i].legend(loc="best")
    ax[0].set_title("forward")
    ax[1].set_title("backward")
    ax[2].set_title("second-order derivative")
    fig.tight_layout()
    fig.savefig("{}_vs_{}.png ".format(A, B))
    plt.show()


x = np.arange(-5, 5, 5e-2)

plot_graph(x, "step")
plot_graph(x, "identity")
plot_graph(x, "bent-identity")
plot_graph(x, "hard-shrink")
plot_graph(x, "soft-shrink")
plot_graph(x, "threshold", -1, -2)
plot_graph(x, "sigmoid")
plot_graph(x, "hard-sigmoid")
plot_graph(x, "log-sigmoid")
plot_graph(x, "tanh")
plot_graph(x, "tanh-shrink")
plot_graph(x, "hard-tanh")
plot_graph(x, "ReLU")
plot_graph(x + 2, "ReLU6")
plot_graph(x, "leaky-ReLU")
plot_graph(x, "ELU")
plot_graph(x, "SELU")
plot_graph(x, "CELU")
plot_graph(x, "softmax")
plot_graph(x, "softmin")
plot_graph(x, "log-softmax")
plot_graph(x, "softplus")
plot_graph(x, "softsign")
plot_graph(x, "Swish")
plot_graph(x, "Mish")
plot_graph(x, "tanhExp")

vs_plot(x, "Swish", "Mish")
vs_plot(x, "Swish", "tanhExp")
vs_plot(x, "Mish", "tanhExp")

Il y en a d'autres qui sont en cours de mise en œuvre. Je pense que je vais l'ajouter bientôt ...

référence

Liste des addenda et merci

--- @ reppy4620 nous a donné des informations sur la fonction tanhExp! Merci de poster poliment le lien du papier!

Série d'apprentissage en profondeur

Recommended Posts

Liste des fonctions d'activation (2020)
Liste des modules python
Fonctions d'apprentissage en profondeur / d'activation
Copie de plusieurs listes
Liste des fonctions et méthodes intégrées fréquemment utilisées
# 4 [python] Bases des fonctions
Profondeur de la liste imbriquée
Affichage des fractions (liste)
Ajouter une liste de fonctions de bibliothèque numpy petit à petit --a
Résumé des opérations de liste Python3
Visualisez les fonctions d'activation côte à côte
Compréhension complète de la fonction numpy.pad
Fonctionnement du filtre (Aucun, liste)
Liste des nœuds dans les diagrammes
Liste des images Docker personnalisées
Initialisation de tableau multidimensionnel de la liste
[Python] Copie d'une liste multidimensionnelle
Liste des styles de codage utiles
Ajouter une liste de fonctions de la bibliothèque numpy petit à petit --- b
Ajouter une liste de fonctions de bibliothèque numpy petit à petit --c
Résumé des fonctions d'activation (step, sigmoïde, ReLU, softmax, fonction constante)
[python] Gérer les fonctions dans une liste
Introduction et mise en œuvre de la fonction d'activation
Jugement du if par la notation d'inclusion de liste
Liste des vecteurs d'incorporation de mots prêts à l'emploi
Liste des packages installés par conda
10 fonctions du "langage avec batterie" python
Liste des commandes Linux fréquemment utilisées
Générer une liste de caractères consécutifs
À propos de la liste de base des bases de Python
Appliquez la fonction à la ligne ou à la colonne de numpy.array sans utiliser la notation d'inclusion de liste
[Linux] Liste des commandes Linux utilisées dans la pratique
Afficher une liste d'alphabets en Python 3
Gymnastique algorithmique 24 Milieu de la liste liée
Obtenez la liste des colonnes et la liste des données de CASTable
Résumé des fonctions numpy que je ne connaissais pas
[python] Obtenir une liste de variables d'instance
Conversion de chaîne d'une liste contenant des nombres
Grammaire de base de la série Python3 (liste, tapple)
Liste des packages Atom que j'utilise vraiment
Résumé des méthodes intégrées, etc. de la liste Python
[Apprentissage automatique] Liste des packages fréquemment utilisés
Résumé de l'utilisation de la liste Python
[Python] Obtenir une liste de dossiers uniquement
[Pour les débutants] Exemple simple de fonctions d'opération de liste mapper, réduire, filtrer