Theano Среднее квадратов градиентов

В теано, учитывая стоимость пакета cost с формой (размер_пакета), легко вычислить градиент средней стоимости, как в случае T.grad(T.mean(cost,axis=0),p), где p является параметром, используемым при вычислении cost. Это делается эффективно путем обратного распространения градиента по вычислительному графу. Что я хотел бы сейчас сделать, так это вычислить среднее значение квадратов градиентов по пакету. Это можно сделать с помощью следующего фрагмента кода:

import theano.tensor as T

g_square = T.mean(theano.scan(lambda i:T.grad(cost[i],p)**2,sequences=T.arange(cost.shape[0]))[0],axis=0)

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

Кто-нибудь знает решение, позволяющее сделать вычисления более эффективными, либо путем принудительной оптимизации, выражая вычисления по-другому, либо даже используя процесс обратного распространения?

Заранее спасибо.


person c_tallec    schedule 23.03.2016    source источник
comment
знаем ли мы batch_size заранее (до вызова функции)?   -  person dontloo    schedule 24.03.2016
comment
@dontloo Действительно, batch_size доступен до вызовов функций.   -  person c_tallec    schedule 25.03.2016


Ответы (2)


Ваша функция g_square имеет сложность O(batch_size**2) вместо O(batch_size), как и ожидалось. Это позволяет ему казаться невероятно медленным для больших размеров пакетов.

Причина в том, что на каждой итерации прямой и обратный проходы вычисляются для всего пакета, хотя требуется всего cost[i] для одной точки данных. Я предполагаю, что ввод графа вычислений cost, x, представляет собой тензор с первым измерением размера batch_size. Theano не имеет возможности автоматически разрезать этот тензор по этому измерению. Поэтому расчет всегда выполняется для всей партии.

К сожалению, я не вижу лучшего решения, чем нарезать ваш ввод и выполнять цикл вне Theano:

# x: input data batch
batch_size = x.shape[0]
g_square_fun = theano.function( [p], T.grad(cost[0],p)**2) 

g_square_value = 0
for i in batch_size:
    g_square_value += g_square_fun( x[i:i+1])

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

person rvolli    schedule 04.11.2016

Покопавшись в документации Theano, я нашел решение, которое работает в графе вычислений. Основная идея заключается в том, что вы клонируете граф своей сети внутри функции сканирования, тем самым явно разрезая входной тензор. Я попробовал следующий код, и эмпирически он показывает O (batch_size), как и ожидалось:

 # x: input data batch
 # assuming cost = network(x,p)

 from theano.gof.graph import clone_get_equiv

 def g_square(cost,p):

    g = T.zeros_like(p)

    def scan_fn( i, g, cost, p):
        # clone the graph computing cost, but slice it's input 
        cloned = clone_get_equiv([],[cost], 
                                 copy_inputs_and_orphans=False,
                                 memo={x: x[i:i+1]})
        cost_slice = cloned[cost].reshape([])
        return  g+T.grad(cost_slice,p)**2 

    result,updates = theano.reduce( scan_fn,
                                    outputs_info=g,
                                    sequences=[T.arange(cost.size)],
                                    non_sequences=[cost.flatten(),p])

    return result
person rvolli    schedule 08.11.2016
comment
Пожалуйста, не добавляйте еще один ответ, вы должны отредактировать свой старый ответ и добавить новые выводы. пометка для закрытия этого - person Marcs; 08.11.2016