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!
--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
D'abord de la fonction étape. Probablement la fonction d'activation la plus ancienne. À 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.
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. 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!
C'est une fonction similaire à [Identity function](# constant function identity). Cependant, il n'est pas droit mais légèrement incurvé.
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.
De Pytorch, juste une introduction pour le moment. ** Consultez les informations supplémentaires TODO ** 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 $.
Ceci est également juste une introduction de Pytorch. ** Consultez les informations supplémentaires TODO *** 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 $.
Ceci est juste une introduction de Pytorch. ** Consultez les informations supplémentaires TODO ** 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.
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. 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).
La fonction hardSigmoid est une approximation linéaire de la fonction sigmoïde, telle qu'une fonction linéaire. 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 ~~
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 ** 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 $.
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 $. 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.
C'est aussi de Pytorch. C'est juste une introduction. ** Consultez les informations supplémentaires TODO ** 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.
C'est aussi Pytorch. Introduction seulement ... ** Consultez les informations supplémentaires TODO ** 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.
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. 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.
Seulement une introduction de Pytorch. ** Consultez les informations supplémentaires TODO ** 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.
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. 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 ...
Un graphe de forme similaire à la [fonction ReLU](fonction #relu), l'une des fonctions les plus lisses lorsque $ x = 0 $ est la fonction ELU. 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 ...
La fonction SELU est la sortie de la [fonction ELU](fonction #elu) multipliée par $ \ lambda $. 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.
Ceci est également une introduction uniquement de Pytorch. ** Consultez les informations supplémentaires TODO ** 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.
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é. 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.
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 ** 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.
De Pytorch, c'est la logarithmique de [fonction softmax](fonction #softmax softmax). ** Consultez les informations supplémentaires TODO ** Ç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.
La fonction softplus a un nom similaire à [fonction softmax](fonction #softmax softmax), mais est essentiellement similaire à [fonction ReLU](fonction #relu).
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.
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).
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.
Il s'agit de la fonction Swish qui devrait succéder à la [fonction ReLU](fonction #relu) apparue en 2017. 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).
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) Cela ressemble presque à la fonction Swish, mais c'est légèrement différent. 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.
C'est la fonction tanhExp fournie par @ reppy4620! Selon Paper, c'est de mars 2020 ~ C'est terriblement récent. 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) 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). 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 ~
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
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
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 ...
--- @ reppy4620 nous a donné des informations sur la fonction tanhExp! Merci de poster poliment le lien du papier!
Recommended Posts