Использование Theano.scan с многомерными массивами

Чтобы ускорить мой код, я конвертирую многомерную функцию суммарного произведения из Python в Theano. Мой код Theano дает тот же результат, но вычисляет результат только для одного измерения за раз, так что мне приходится использовать цикл Python for для получения конечного результата. Я предполагаю, что это сделает код медленным, потому что Theano не может оптимизировать использование памяти и передачу (для графического процессора) между несколькими вызовами функций. Или это неверное предположение?

Итак, как мне изменить код Theano, чтобы sumprod вычислялся за один вызов функции?

Оригинальная функция Python:

def sumprod(a1, a2):
    """Sum the element-wise products of the `a1` and `a2`."""
    result = numpy.zeros_like(a1[0])
    for i, j in zip(a1, a2):
        result += i*j
    return result

Для следующего ввода

a1 = ([1, 2, 4], [5, 6, 7])
a2 = ([1, 2, 4], [5, 6, 7])

вывод будет: [ 26. 40. 65.], то есть 1*1 + 5*5, 2*2 + 6*6 и 4*4 + 7*7

Theano-версия кода:

import theano
import theano.tensor as T
import numpy

a1 = ([1, 2, 4], [5, 6, 7])
a2 = ([1, 2, 4], [5, 6, 7])

# wanted result:  [ 26.  40.  65.]
# that is 1*1 + 5*5, 2*2 + 6*6 and 4*4 + 7*7

Tk = T.iscalar('Tk')
Ta1_shared = theano.shared(numpy.array(a1).T)
Ta2_shared = theano.shared(numpy.array(a2).T)

outputs_info = T.as_tensor_variable(numpy.asarray(0, 'float64'))

Tsumprod_result, updates = theano.scan(fn=lambda Ta1_shared, Ta2_shared, prior_value: 
                                       prior_value + Ta1_shared * Ta2_shared,
                                       outputs_info=outputs_info,
                                       sequences=[Ta1_shared[Tk], Ta2_shared[Tk]])
Tsumprod_result = Tsumprod_result[-1]

Tsumprod = theano.function([Tk], outputs=Tsumprod_result)

result = numpy.zeros_like(a1[0])
for i in range(len(a1[0])):
    result[i] = Tsumprod(i)
print result

person Framester    schedule 29.05.2013    source источник


Ответы (1)


Во-первых, в списке рассылки theano больше людей ответят на ваши вопросы, чем в stackoverflow. Но я здесь :)

Во-первых, ваша функция не подходит для GPU. Даже если все было хорошо оптимизировано, передача ввода в gpu только для сложения и суммирования результата займет больше времени, чем версия python.

Ваш код Python медленный, вот версия, которая должна быть быстрее:

def sumprod(a1, a2):
    """Sum the element-wise products of the `a1` and `a2`."""
    a1 = numpy.asarray(a1)
    a2 = numpy.asarray(a2)
    result (a1 * a2).sum(axis=0)
    return result

Для кода theano вот эквивалент этой более быстрой версии python (сканирование не требуется)

m1 = theano.tensor.matrix()
m2 = theano.tensor.matrix()
f = theano.function([m1, m2], (m1 * m2).sum(axis=0))

Из этого следует помнить, что вам нужно «векторизировать» свой код. «Векторизация» используется в контексте NumPy, и это означает использование numpy.ndarray и использование функции, которая одновременно работает с полным тензором. Это всегда быстрее, чем делать это с помощью цикла (петля python или сканирование theano). Кроме того, Theano оптимизирует некоторые из этих случаев, перемещая вычисления за пределы сканирования, но не всегда это происходит.

person nouiz    schedule 29.05.2013
comment
В очередной раз благодарим за помощь. Я предпочитаю SO, потому что я думаю, что уже отвеченные вопросы легче найти на SO, чем в архиве списка рассылки. А также спасибо за ваш отзыв о коде. Sumprod является частью более крупного алгоритма, и я предполагаю, что выполнение этого неподходящего вычисления также на графическом процессоре лучше, чем загрузка и загрузка данных. - person Framester; 03.06.2013