2010-05-22 3 views
9

j'ai un réseau de neurones écrit en Java qui utilise une fonction de transfert sigmoïde défini comme suit:Accélération des calculs mathématiques en Java

private static double sigmoid(double x) 
{ 
    return 1/(1 + Math.exp(-x)); 
} 

et cela est appelé beaucoup fois au cours de la formation et de calcul en utilisant le réseau. Y a-t-il un moyen d'accélérer cela? Ce n'est pas que c'est lent, c'est juste que c'est beaucoup utilisé, donc une petite optimisation ici serait un gros gain global.

+3

Les valeurs de x sont-elles répétées ou est-il plus probable qu'elles seront toujours différentes chaque fois que la méthode est appelée? – DaveJohnston

+0

En outre, à quel point le résultat doit-il être précis? –

+0

@Dave - dépend de la précision désirée, mais ils sont tous des nombres à virgule flottante, donc à peu près unique – Simon

Répondre

20

Pour les réseaux de neurones, vous n'avez pas besoin de la valeur exacte de la fonction sigmoïde. Vous pouvez donc précalculer 100 valeurs et réutiliser la valeur la plus proche de votre entrée, ou mieux (comme indiqué dans un commentaire) faire une interpolation à partir des valeurs voisines.

Comment vous pouvez faire ceci est décrit dans ce article (lien volé du answer of s-lott).

C'est la fonction sigmoïde: Sigmoid function graph

Comme vous pouvez le voir, seules les valeurs de -10 < x < 10 sont intéressants du tout. Et, comme un autre commentaire l'a indiqué, la fonction est symétrique. Vous devez seulement stocker la moitié des valeurs.


Edit: Je suis désolé que j'ai montré le mauvais graphique ici. Je l'ai corrigé.

+1

Peut-être quelque chose de plus de 100 si vous voulez un peu plus de précision. Une table de consultation de 5000 (mais probablement même 1000) valeurs sera absolument suffisante à mon humble avis. – nico

+2

Pour plus de précision, il est probablement préférable d'effectuer une interpolation linéaire entre les deux valeurs les plus proches. –

+2

Le problème est symétrique, vous n'avez donc besoin que de la moitié des valeurs. Le calcul de l'autre côté est trivial. –

0

D'un point de vue mathématique, je ne vois aucune possibilité de l'optimiser.

1

C'est une fonction assez fluide, donc un schéma de recherche et d'interpolation est susceptible d'être plus que suffisant.

Lorsque je trace la fonction sur une plage de -10 <= x <= 10, j'obtiens une précision de cinq positions aux extrêmes. Est-ce suffisant pour votre application?

5

Si vous avez beaucoup de noeuds où la valeur de x est en dehors de -10 .. + 10 boîte, vous pouvez simplement omettre de calculer ces valeurs à tous, par exemple, comme si ..

if(x < -10) 
    y = 0; 
else if(x > 10) 
    y = 1; 
else 
    y = 1/(1 + Math.exp(-x)); 
return y; 

Bien sûr, cela entraîne la surcharge des contrôles conditionnels pour CHAQUE calcul, donc cela ne vaut que si vous avez beaucoup de nœuds saturés. Une autre chose qui vaut la peine d'être mentionnée est que, si vous utilisez la rétropropagation, et que vous devez gérer la pente de la fonction, il est préférable de la calculer en morceaux plutôt que «tel qu'écrit».

Je ne me souviens pas de la pente pour l'instant, mais voici ce dont je parle en utilisant un sigmoïde bipolaire comme exemple. Plutôt que de calculer cette façon

y = (1 - exp(-x))/(1 + exp(-x)); 

qui frappe exp() deux fois, vous pouvez mettre en cache les calculs coûteux dans les variables temporaires, comme si

temp = exp(-x); 
y = (1 - temp)/(1 + temp); 

Il y a beaucoup d'endroits pour mettre ce genre de chose à utiliser dans les moustiquaires BP.

Questions connexes