Theano градиенты терпят неудачу по операции сканирования - PullRequest
1 голос
/ 15 марта 2020

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

У меня есть следующая внутренняя функция (часть шага внутренней итерации RNN, я могу предоставить, если ne c.):

    def iter_step(x_step, h):
        ...

        return hidden, obj, est

У меня есть набор параметров h_params, o_params, e_params, которые я использую для вычисления градиентов:

h, o, e = iter_step(x_step, h)
hidden_grads = T.grad(T.sum(h), h_params)
obj_grads = T.grad(T.sum(o), o_params)
est_grads = T.grad(T.sum(est), e_params)

все в порядке. Я добавляю операцию сканирования

[h_n, obj_n, x_n], _ = theano.scan(
    fn=iter_step,
    sequences=[x],
    outputs_info=[T.as_tensor_variable(np.zeros(model.h_shape), model.h.dtype),
                  None,
                  None],
    )

Оценка в порядке, но вычисление градиентов по тем же параметрам теперь является проблемой:

# Works
h_n0 = theano.function([], h_n)()
# Fails
h_n_grads = T.grad(T.sum(h_n), h_params)

---------------------------------------------------------------------------
NullTypeGradError                         Traceback (most recent call last)
<ipython-input-32-0d7c8a65d265> in <module>
----> 1 h_n_grads = T.grad(T.sum(h_n), h_params)

/usr/local/lib/python3.6/dist-packages/theano/gradient.py in grad(cost, wrt, consider_constant, disconnected_inputs, add_names, known_grads, return_disconnected, null_gradients)
    609             if null_gradients == 'raise':
    610                 raise NullTypeGradError("tensor.grad encountered a NaN. " +
--> 611                                         rval[i].type.why_null)
    612             else:
    613                 assert null_gradients == 'return'

NullTypeGradError: tensor.grad encountered a NaN. This variable is Null because the grad method for input 4 (Subtensor{int64}.0) of the for{cpu,scan_fn} op is mathematically undefined. Depends on a shared variable

Почему это так? Я еще не смог отладить - график не отключен, развертка сканирования вручную дает хорошие градиенты. Расчеты градиента должны выполняться через операцию сканирования. Если можно рассчитать градиенты по h (1-й выход iter_step), то почему не по аналогичному выходу сканирования?

1 Ответ

0 голосов
/ 17 марта 2020

Проблема была решена. iter_step выше содержал шаг выборки по линиям

def sample(self, mu, logSigma):
    global SEED
    srng = T.shared_randomstreams.RandomStreams(seed=SEED)
    dev = srng.normal((self.batch_size, self.n_latent[-1]))
    z = mu + T.exp(0.5 * logSigma) * dev
    return z

Градиенты в этом расчете не сохраняются в операции scan. Разделение всех параметрических c зависимостей в образце по-прежнему не работает. В итоге получилось создать отклонения в dev и передать их как один из non_sequences при сканировании, как в

    [h_n, obj, x],inner_updates = theano.scan(
        fn=iter_step,
        sequences=[x_in],
        outputs_info=[T.as_tensor_variable(np.zeros(self.h_shape), self.h.dtype),
                      None,
                      None],
        non_sequences=[T.as_tensor_variable(self.srng.normal((self.batch_size, self.n_latent[-1])), self.h.dtype)],
        )

. У меня есть идея, почему этот градиент над этим scan не работает, в то время как простые операции сканирования даже с randomstreams.RandomStreams объектами работают. Я расскажу более подробно.

Резюме: используйте трюк репарамеризации, если ваш дистрибутив позволяет это, передайте отбеленные отклонения, предварительно параметризованные как non_sequences. Кажется, это работает во всех случаях.

...