Насколько эффективен / интеллектуален Theano в вычислении градиентов?

Предположим, у меня есть искусственная нейронная сеть с 5 скрытыми слоями. На данный момент забудьте о деталях модели нейронной сети, таких как смещения, используемые функции активации, тип данных и так далее ... Конечно, функции активации дифференцируемы.

С помощью символического дифференцирования следующее вычисляет градиенты целевой функции относительно весов слоев:

w1_grad = T.grad(lost, [w1])
w2_grad = T.grad(lost, [w2])
w3_grad = T.grad(lost, [w3])
w4_grad = T.grad(lost, [w4])
w5_grad = T.grad(lost, [w5])
w_output_grad = T.grad(lost, [w_output])

Таким образом, чтобы вычислить градиенты w.r.t w1, сначала должны быть вычислены градиенты w.r.t w2, w3, w4 и w5. Аналогично, чтобы вычислить градиенты по w.r.t w2, сначала должны быть вычислены градиенты по w3, w4 и w5.

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

w1_grad, w2_grad, w3_grad, w4_grad, w5_grad, w_output_grad = T.grad(lost, [w1, w2, w3, w4, w5, w_output])

Мне было интересно, есть ли разница между этими двумя методами с точки зрения производительности? Достаточно ли умен Теано, чтобы не пересчитывать градиенты вторым методом? Под интеллектуальным я подразумеваю вычисление w3_grad, Theano следует [предпочтительно] использовать предварительно вычисленные градиенты w_output_grad, w5_grad и w4_grad вместо их повторного вычисления.


person Amir    schedule 22.12.2015    source источник
comment
Интересный вопрос. Вы просто опробовали и измерили время выполнения обоих методов?   -  person hbaderts    schedule 24.12.2015
comment
@hbaderts Пока нет, я проведу несколько экспериментов и опубликую здесь результаты производительности.   -  person Amir    schedule 24.12.2015
comment
@hbaderts Решение размещено сейчас.   -  person Amir    schedule 28.12.2015
comment
спасибо за понимание, хороший вопрос и ответ.   -  person hbaderts    schedule 28.12.2015
comment
Амир, вы редактировали новые теги (jacobean, hessian) в кучу старых вопросов, но я не уверен, что теги необходимы - я думаю, это метатеги, так как они не могут работать сами по себе. Они определенно недостаточно важны, чтобы оправдать редактирование только с помощью тегов в старых сообщениях, в которых есть много других проблем. Я предлагаю вам сделать мета-сообщение, чтобы начать обсуждение того, приветствуются ли теги; если сообщество поддержит их добавление, это не обязательно будет делом одного человека.   -  person Mogsdad    schedule 18.01.2016
comment
@Mogsdad Для Hessian это было определенно необходимо, поскольку есть программа под названием hessian, которая имеет какое-то отношение к сети / Интернету. Итак, большинство вопросов были перепутаны, и я разделил их, создав тег hessian-matrix. Для матрицы Якоби, безусловно, нужен новый тег. Якобиан - очень важный математический термин, и вопросы, которые имеют какое-то отношение к математической оптимизации и задают что-то, связанное с матрицей Якоби, встречаются повсюду.   -  person Amir    schedule 18.01.2016
comment
Математические термины могут быть достаточно важными, чтобы иметь собственные теги на математическом сайте, но это сайт программирования. Я также рекомендую задать вопрос meta.SO, особенно учитывая, что теги не имеют инструкций по использованию или описаний.   -  person TylerH    schedule 18.01.2016
comment
@TylerH Возможно, ты прав, но только до некоторой степени. Возможно, вы не занимаетесь математикой и поэтому жалуетесь на то, что я сделал. Я много занимаюсь программированием, и мои программы связаны с такой математикой, как и многие другие, которые задали много вопросов, связанных с математической оптимизацией. Эти вопросы должны быть правильно распределены по категориям, чтобы людям было легче их находить, и они всплывали в поисковых системах, когда кто-то ищет эти термины.   -  person Amir    schedule 18.01.2016
comment
@Amir И мы категорически не утверждаем, что они не должны здесь существовать, просто вы начинаете обсуждение мета, потому что мы не решаемся согласовать с вами мета-статус таких тегов, как было. Если вы можете предоставить здесь убедительный аргумент вместе с хорошим описанием тега, которое предлагает точное руководство по использованию (там, где в настоящее время его нет), то, как сказал Могсдад, другие могут даже помочь вам добавить эти теги в соответствующие вопросы.   -  person TylerH    schedule 18.01.2016


Ответы (1)


Что ж, оказывается, Theano не использует ранее вычисленные градиенты для вычисления градиентов на нижних уровнях вычислительного графа. Вот фиктивный пример нейронной сети с 3 скрытыми слоями и выходным слоем. Однако это не будет большим делом, поскольку вычисление градиентов выполняется один раз в жизни, если только вам не нужно вычислять градиент на каждой итерации. Theano возвращает символическое выражение для производных в виде вычислительного графа и с этого момента вы можете просто использовать его как функцию. С этого момента мы просто используем функцию, полученную Theano, для вычисления числовых значений и обновления весов с их помощью.

import theano.tensor as T
import time
import numpy as np
class neuralNet(object):
    def __init__(self, examples, num_features, num_classes):
        self.w = shared(np.random.random((16384, 5000)).astype(T.config.floatX), borrow = True, name = 'w')
        self.w2 = shared(np.random.random((5000, 3000)).astype(T.config.floatX), borrow = True, name = 'w2')
        self.w3 = shared(np.random.random((3000, 512)).astype(T.config.floatX), borrow = True, name = 'w3')
        self.w4 = shared(np.random.random((512, 40)).astype(T.config.floatX), borrow = True, name = 'w4')
        self.b = shared(np.ones(5000, dtype=T.config.floatX), borrow = True, name = 'b')
        self.b2 = shared(np.ones(3000, dtype=T.config.floatX), borrow = True, name = 'b2')
        self.b3 = shared(np.ones(512, dtype=T.config.floatX), borrow = True, name = 'b3')
        self.b4 = shared(np.ones(40, dtype=T.config.floatX), borrow = True, name = 'b4')
        self.x = examples

        L1 = T.nnet.sigmoid(T.dot(self.x, self.w) + self.b)
        L2 = T.nnet.sigmoid(T.dot(L1, self.w2) + self.b2)
        L3 = T.nnet.sigmoid(T.dot(L2, self.w3) + self.b3)
        L4 = T.dot(L3, self.w4) + self.b4
        self.forwardProp = T.nnet.softmax(L4)
        self.predict = T.argmax(self.forwardProp, axis = 1)

    def loss(self, y):
        return -T.mean(T.log(self.forwardProp)[T.arange(y.shape[0]), y])

x = T.matrix('x')
y = T.ivector('y')

nnet = neuralNet(x)
loss = nnet.loss(y)

diffrentiationTime = []
for i in range(100):
    t1 = time.time()
    gw, gw2, gw3, gw4, gb, gb2, gb3, gb4 = T.grad(loss, [nnet.w, nnet.w2, logReg.w3, nnet.w4, nnet.b, nnet.b2, nnet.b3, nnet.b4])
    diffrentiationTime.append(time.time() - t1)
print 'Efficient Method: Took %f seconds with std %f' % (np.mean(diffrentiationTime), np.std(diffrentiationTime))

diffrentiationTime = []
for i in range(100):
    t1 = time.time()
    gw = T.grad(loss, [nnet.w])
    gw2 = T.grad(loss, [nnet.w2])
    gw3 = T.grad(loss, [nnet.w3])
    gw4 = T.grad(loss, [nnet.w4])
    gb = T.grad(loss, [nnet.b])
    gb2 = T.grad(loss, [nnet.b2])
    gb3 = T.grad(loss, [nnet.b3])
    gb4 = T.grad(loss, [nnet.b4])
    diffrentiationTime.append(time.time() - t1)
print 'Inefficient Method: Took %f seconds with std %f' % (np.mean(diffrentiationTime), np.std(diffrentiationTime))

Это распечатает следующее:

Efficient Method: Took 0.061056 seconds with std 0.013217
Inefficient Method: Took 0.305081 seconds with std 0.026024

Это показывает, что Theano использует подход динамического программирования для вычисления градиентов для эффективного метода.

person Amir    schedule 27.12.2015