Delphi: EInvalidOp в классе нейронных сетей (TD-лямбда) - PullRequest
1 голос
/ 16 февраля 2011

У меня есть следующий проект для класса нейронной сети.Эту нейронную сеть следует учить с помощью TD-лямбды.Он запускается путем вызова функции getRating ().

Но, к сожалению, возникает ошибка EInvalidOp (недопустимая операция с точкой загрузки) после примерно 1000 итераций в следующих строках:

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

Почемуэто ошибка?Я не могу найти ошибку в своем коде :( Вы можете мне помочь? Большое спасибо заранее!

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;
[...]

Ответы [ 3 ]

2 голосов
/ 17 февраля 2011

Не ответ, а предложение; Две строки кода, которые вы показываете, включают только умножение и сложение, очень простые операции. Как насчет регистрации значений при сбое, возможно, увидев значения, вы можете что-то выяснить.

Самая досадная проблема с остановкой на исключение состоит в том, что вы не можете проверить переменные, включенные в это исключение. Чтобы обойти это ограничение, я иногда оборачиваю хлопотную операцию в блок try-except и помещаю точку останова в обработчик except; Delphi сначала остановится на исключении, я нажму на run, а затем остановлюсь на моей точке останова. В точке останова я могу свободно проверять все переменные, используемые в операторе, генерирующем ошибки, чтобы я мог выяснить, в чем дело.

// 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;
1 голос
/ 16 февраля 2011

Наиболее вероятной причиной вашей ошибки является переполнение аккумуляторов neuronsHidden или weightsHidden.Я ничего не знаю о нейронных сетях, поэтому не могу дать никакого объяснения, почему это так.

В качестве дополнительной проблемы я ставлю под сомнение использование Extended переменных с плавающей запятой.Обычно это просто приводит к крайне низкой производительности, намного медленнее, чем при использовании Double.Вы можете подумать, что это дает вам больше возможностей для больших чисел, но на самом деле, если это чрезмерное переполнение той природы, которую я подозреваю, то использование Extended никогда не спасет вас.

UPDATE OP указывает, что переполнение приводит к другому классу исключений.Так что для EInvalidOp я подозреваю какой-то сбой квадратного корня или триггера или что-то в этом роде.Или, возможно, сигнальный NaN, но, поскольку вы, очевидно, не используете неинициализированные данные, я этого не продолжу.

Теперь я вижу, что вы были затронуты странным решением Embarcadero прервать реализацию Tanh,Раньше он отлично работал на старых версиях Delphi (например, D6), но недавно был сломан.Используемая версия не совсем подходит для большого отрицательного ввода и использует два вызова Exp, когда достаточно одного.Я использую эту версию:

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 голосов
/ 16 февраля 2011

Вы можете получить EInvalidOp при вычислении очень больших или очень маленьких чисел.

При получении этой ошибки, возможно, вы можете отладить / просмотреть значения в массиве и выполнить частичный расчет в списке наблюдения?

...