Отладка RNN

#debugging #machine-learning #neural-network #deep-learning #recurrent-neural-network

#отладка #машинное обучение #нейронная сеть #глубокое обучение #рекуррентная нейронная сеть

Вопрос:

В настоящее время я пишу свой собственный RNN с нуля, используя практически только numpy. Я в основном застрял, потому что я проверил все градиенты с каждого отдельного слоя, и у меня есть все модульные тесты здесь:https://github.com/OneRaynyDay/BibleNet/blob/master/Unit tests.ipynb
https://github.com/OneRaynyDay/BibleNet/blob/master/Gradient Solver Unit Test.ipynb

Однако, когда я выполняю обратное распространение в своей сети с относительно разумной инициализацией весов и модульными оптимизаторами градиента (), я вижу, что график ОПРЕДЕЛЕННО не то, что я хочу. Я перешел к относительно простому корпусу, который в основном представляет собой эту статью отсюда:http://www.dailycal.org/2016/10/18/students-gather-hear-faculty-speak-trump-teach / который составляет менее 1000 слов, его должно быть очень легко переопределить. Однако функция затрат выглядит примерно так: введите описание изображения здесь Это определенно не то, что сходится. Он прыгает вверх и вниз, как будто на самом деле ничему не учится. Что я должен делать с точки зрения отладки?

Я не могу предоставить MVCE для этого примера просто потому, что это ошибка функционального теста, которая объединяет все части библиотеки, которую я создал. Следовательно, MVCE — это весь проект. Не стесняйтесь клонировать его с github.

Подозрительные места

Я чувствую, что ошибка возникает из-за моей архитектуры нейронной сети. Возможно, способ, которым я обрабатываю продолжающиеся итерации, неверен. Вот увеличенный код:

         # Save typing 
        c = lambda arg: self.constants[arg]
        p = lambda arg: self.params[arg]

        # Step 1: Word embedding forward:
        words_chosen = word_embedding_forward(p("words"), x)

        # Step 2: rnn forward:
        h = rnn_forward(words_chosen, p("W_xh"), p("W_hh"), p("b_rnn"), h0)

        # Step 3: affine forward:
        affine = rnn_affine_forward(h, p("W_hy"), p("b_affine"))

        # step 4: softmax forward and backward:
        loss, dout = rnn_softmax(affine, y) 

        # step 3: affine backward:
        dh, dW_hy, db_affine = rnn_affine_backward(h, p("W_hy"), p("b_affine"), dout)

        # step 2: rnn backward:
        dW_hh, dW_xh, dx, db_rnn, dh0 = rnn_backward(words_chosen, p("W_xh"), p("W_hh"), p("b_rnn"), h0, h, dh)

        # step 1: Word embedding backward:
        dwords = word_embedding_backward(dx, p("words"), x)

        # Returns the loss and all the derivatives along with the fields.
        return (loss, [[p("words"), dwords], 
               [p("W_xh"), dW_xh], 
               [p("W_hh"), dW_hh],
               [p("W_hy"), dW_hy],
               [p("b_affine"), db_affine],
               [p("b_rnn"), db_rnn],
               [h0, dh0]], h[:,-1,:])
  

Другое подозрение заключается в том, что я неправильно обрабатываю скрытые состояния. Я беру скрытое состояние из предыдущего образца и подключаю это состояние скрытого слоя прямо к следующему образцу.

Вот иллюстрация: [a,b,c,d,e,f,g] is the sequence

input (a,b,c) -> (b,c,d) output (uses zeros as initial hidden layer)

We skip over to d: input (d,e,f) -> (e,f,g) output (uses previous hidden state of c)

Комментарии:

1. Проверяли ли вы свои нормы градиента с течением времени? С помощью Vanilla RNN вы легко переходите к появлению / исчезновению градиентов.

2. Привет — нет, у меня нет, но проблема в том, что это происходит даже при размере временной последовательности 2, где градиент взрыва / исчезновения не так очевиден. (На самом деле, приведенный здесь график имеет размер временного шага 2)