Базовый случай в рекурсивной функции не останавливает рекурсивный набор текста - PullRequest
1 голос
/ 07 июня 2019

Я работаю над алгоритмом машинного обучения в TypeScript, и у меня есть метод частичной производной, предназначенный для воспроизведения этого: enter image description here Вот мой рекурсивный метод для этого:

private pd(a : Activation, w : Weight, t : number) : number { //Takes partial derivative of activation with respect to weight
        return sigDeriv(this.sums[t][a.l][a.j].val)*(a.l == w.l && a.j == w.j ?
            this.activations[t][a.l - 1][w.k].val
            : sumFunc(this.activations[t][a.l - 1].length, 1,
                async k => await this.weights[a.l][a.j][k].val*this.pd(this.activations[t][a.l - 1][k], w, t)
            )
        );
    }

Проблема в том, что даже после достижения базового условия (a.l == w.l && a.j == w.j) функция продолжает выполняться и в конечном итоге достигает входного слоя (где нет весов), что приводит к ошибке.Почему это происходит и как я могу это исправить? Когда я запустил функцию и зарегистрировал значение базового случая, он вернет true, когда это будет необходимо, но функция продолжит выполнение, что приведет к ошибке.

Ответы [ 2 ]

1 голос
/ 07 июня 2019

Прежде всего, существует проблема с круглыми скобками. Попробуйте:

((a.l == w.l && a.j == w.j) ? … : … )

Потому что здесь тест проводится только на a.j == w.j

(оператор?: Имеет больший приоритет, чем &&)

Но, как заметил Скотт, это не исправит вашу проблему. Мы не видим полный код, поэтому не можем быть уверены, но это может быть проблемой синхронности (я вижу, вы используете async / await). Если w может быть асинхронно изменен, тогда ваш тест может быть ложным, если он не должен ...

0 голосов
/ 07 июня 2019

Я понял, что мне нужно изменить свое базовое состояние, чтобы оно было более общим.В то время как первое условие остановило функцию, когда была найдена активация, умноженная на дифференцируемый вес, функция продолжала пытаться дифференцировать остальную часть активаций, после которой вес оказывал влияние на функцию.По сути, я оказался на ∂/∂w(aw + a2w2 + ...), и pd вернул бы активацию, умноженную на w, когда этот термин был дифференцирован, но продолжил с рекурсией для других терминов, на которые больше не влияло w и, следовательно,никогда не достигнет базового состояния.Таким образом, решение состояло в том, чтобы возвращать значение a всякий раз, когда функция достигла слоя веса, поскольку вышеупомянутая производная оценивается как (a + 0 + ...).

private pd(a : Activation, w : Weight, t : number) : number { //Takes partial derivative of activation with respect to weight
    return sigDeriv(this.sums[t][a.l][a.j].val)*this.pdSum(a, w, t);
}

private pdSum(a : Activation, w : Weight, t : number) : number { //Handles sum statement in recursive derivative definition
    if(a.l == w.l) return this.activations[t][a.l - 1][w.k].val; //This line solves the problem

    return sumFunc(this.activations[t][a.l - 1].length, 1,
        async k => await this.weights[a.l][a.j][k].val*this.pd(this.activations[t][a.l - 1][k], w, t)
    );
}
...