1

J'ai le brouillon suivant pour une classe de réseau de neurones. Ce réseau de neurones devrait apprendre avec TD-lambda. Il est démarré en appelant la fonction getRating().Delphi: EInvalidOp dans la classe de réseau neuronal (TD-lambda)

Mais malheureusement, il y a une EInvalidOp (opération de point de floading non valide) erreur après environ 1000 itérations dans les lignes suivantes:

neuronsHidden[j] := neuronsHidden[j]+neuronsInput[t][i]*weightsInput[i][j]; // input -> hidden 

weightsHidden[j][k] := weightsHidden[j][k]+LEARNING_RATE_HIDDEN*tdError[k]*eligibilityTraceOutput[j][k]; // adjust hidden->output weights according to TD-lambda 

Pourquoi cette erreur? Je ne peux pas trouver l'erreur dans mon code :(Pouvez-vous me aider? Merci beaucoup à l'avance!

learningMode: Boolean; // does the network learn and change its weights? 
neuronsInput: Array[1..MAX_TIMESTEPS] of Array[1..NEURONS_INPUT] of Extended; 
neuronsHidden: Array[1..NEURONS_HIDDEN] of Extended; 
neuronsOutput: Array[1..NEURONS_OUTPUT] of Extended; 
weightsInput: Array[1..NEURONS_INPUT] of Array[1..NEURONS_HIDDEN] of Extended; 
weightsHidden: Array[1..NEURONS_HIDDEN] of Array[1..NEURONS_OUTPUT] of Extended; 

[...] 

function HyperbolicTangent; 
begin 
    if x > 5500 then // prevent overflow 
    result := 1 
    else 
    result := (Exp(2*x)-1)/(Exp(2*x)+1); 
end; 
[...] 
+0

Êtes-vous toujours intéressé par une réponse à cette question? –

+0

Oui, je le suis, définitivement. Mais depuis que j'ai remplacé les variables étendues par des variables réelles, il n'y a plus d'erreur. Je ne sais pas si c'est juste une coïncidence. Pourquoi cela devrait-il résoudre le problème? – caw

Répondre

1

La raison la plus probable pour vous erreur est que vous les accumulateurs débordait neuronsHidden ou weightsHidden. I En tant que problème secondaire, je doute de l'utilisation de variables à virgule flottante Extended, ce qui se traduit tout simplement par des performances extrêmement lentes, beaucoup plus lentes, et je ne peux rien expliquer sur les réseaux de neurones. que lorsque vous utilisez Double Vous pensez peut-être que cela vous donne plus d'espace pour les grands nombres, mais en réalité, si c'est un débordement de la nature t Je suppose que l'utilisation de Extended ne vous sauverait jamais.

MISE À JOUR OP signale que le dépassement entraîne une classe d'exception différente. Donc, pour EInvalidOp, je soupçonne une racine carrée ou une défaillance trigonométrique ou quelque chose comme ça. Ou peut-être un NaN de signalisation, mais puisque vous n'utilisez évidemment pas de données non initialisées, je ne persisterai pas.

Je peux voir maintenant que vous avez été affecté par la décision bizarre d'Embarcadero de casser leur implémentation de Tanh. Cela fonctionnait parfaitement sur les anciennes versions de Delphi (par exemple D6), mais a été cassé récemment. La version que vous utilisez n'est pas tout à fait appropriée pour une entrée négative importante et utilise deux appels à Exp quand cela est suffisant. J'utilise cette version:

const 
    MaxTanhDomain = 5678.22249441322; // Ln(MaxExtended)/2 

function Tanh(const X: Extended): Extended; 
begin 
    if X>MaxTanhDomain then begin 
    Result := 1.0 
    end else if X<-MaxTanhDomain then begin 
    Result := -1.0 
    end else begin 
    Result := Exp(X); 
    Result := Result*Result; 
    Result := (Result-1.0)/(Result+1.0); 
    end; 
end; 
+0

Si je débordais les accumulateurs neuronsHidden ou weightsHidden, il y aurait une erreur EOverflow, n'est-ce pas?Mais maintenant j'ai remplacé toutes les variables étendues par des variables réelles (= double) dans mon code. – caw

+1

Désolé, oui ce serait un EOverflow. Si vous faisiez 'Sqrt' ou trig, vous pourriez voir' EInvalidOp', mais vous n'êtes pas vous. Vous obtenez également 'EInvalidOp' pour signaler les NaN. Ce que vous devez faire est de casser au point de l'erreur et voir quelles valeurs sont utilisées. Trouver une reproduction de la faute et un moyen de casser au point où il échoue. Ou juste spew les valeurs sur la fenêtre de débogage avec 'OutputDebugString'. –

+0

Merci beaucoup pour l'amélioration de ma fonction tanh(). Cela fonctionne parfaitement :) Êtes-vous sûr que la fonction intégrée de Delphi tanh() est cassée? – caw

0

Vous pouvez obtenir EInvalidOp lorsque vous calculez des nombres très grands ou très petits.

Lorsque vous obtenez cette erreur, vous pouvez peut-être déboguer/afficher les valeurs dans le tableau et effectuer un calcul partiel dans la liste de surveillance?

+0

Mais pour les nombres trop grands ou trop petits, il y a un type d'erreur spécial, à savoir EOverflow, n'est-ce pas? – caw

2

Pas une réponse, juste une suggestion; Les deux lignes de code que vous montrez incluent seulement la multiplication et l'addition, des opérations très simples. Que diriez-vous de consigner les valeurs sur l'échec, peut-être voir les valeurs que vous pouvez comprendre quelque chose.

Le problème le plus ennuyeux avec l'arrêt sur exception est que vous ne pouvez pas inspecter les variables impliquées dans cette exception. Pour contourner cette limitation, j'emballe parfois l'opération problématique dans un bloc try-except et placez un point d'arrêt dans le gestionnaire except; Delphi s'arrêtera d'abord à l'exception, j'appuierai, puis s'arrêtera sur mon point d'arrêt. Au point d'arrêt, je peux librement inspecter toutes les variables utilisées dans l'instruction générant des erreurs, afin que je puisse comprendre ce qui ne va pas.

// In place of: 
neuronsHidden[j] := neuronsHidden[j]+neuronsInput[t][i]*weightsInput[i][j]; 

var saveNerusonsHidden: Double; 
try 
    saveNeuronsHidden := neuronsHidden[j]; // saved, to be sure I can inspect the original value 
    neuronsHidden[j] := neuronsHidden[j]+neuronsInput[t][i]*weightsInput[i][j]; 
except on E:EInvalidOp do 
    begin 
    // Breakpoint here, so you can inspect the values of neuronsInput[t][i], wightsInput[i][j] and saveNeuronsHidden 
    raise; 
    end; 
end; 
+0

Merci beaucoup pour cette suggestion :) Que fait exactement le "raise"? Pourquoi en ai-je besoin? – caw