Теано средно на квадрат градиенти

В theano, при дадена партидна цена cost с форма (batch_size,), е лесно да се изчисли градиентът на средната цена, както в 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