I have the following draft for a neural network class. This neural network should learn with TD-lambda. It is started by calling the getRating() function.
But unfortunately, there is an EInvalidOp (invalid floading point operation) error after about 1000 iterations in the following lines:
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
Why is this error? I can't find the mistake in my code :( Can you help me? Thank you very much in advance!
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;
[...]
The most likely reason for you error is that you are overflowing the accumulators
neuronsHidden
orweightsHidden
. I know nothing about neural networks so I can't offer any explanation as to why this is so.As a side issue, I question the use of
Extended
floating point variables. Normally this simply results in extremely slow performance, much slower than when usingDouble
. You may think it gives you more headroom for large numbers, but in reality, if this is a run-away overflow of the nature that I suspect, then usingExtended
would never save you.UPDATE OP points out that overflow results in a different exception class. So for
EInvalidOp
I suspect some square root or trig failure or something like that. Or perhaps a signaling NaN, but since you don't obviously use uninitialised data I'll not persue that.I can see now that you have been affected by Embarcadero's bizarre decision to break their implementation of
Tanh
. This used to work perfectly on older versions of Delphi (e.g. D6), but was broken recently. The version you use isn't quite right for large negative input, and uses two calls toExp
when one suffices. I use this version: