Функция Theano: неиспользуемый вход

Я пытаюсь реализовать мини-пакет Kmeans. Часть, которая, кажется, доставляет мне очень трудные времена, — это указание мини-пакетов в качестве входных данных для theano. У меня есть класс KmeansMiniBatch с функцией __init__(self, batch_size, data=None), где data в данном случае — это мини-пакет, а batch_size — размер пакета. У меня также есть функция fit_once, которая не принимает аргументов, а вместо этого использует данные, переданные в __init__.

Мой основной скрипт состоит из следующего:

X = T.matrix('X', dtype='float64')
mini_batch = T.matrix('X', dtype='float64')

kmeans = KmeansMiniBatch(
    batch_size=10000,
    data=X
)

func = theano.function(
    inputs=[mini_batch],
    outputs=kmeans.fit_once(),
    givens={
        kmeans.X: mini_batch,
    }
)

data = load_data()
for i in xrange(30):
    func(get_batch(data))

image = Image.fromarray(
tile_raster_images(X=np.transpose(kmeans.D.eval()),
                       img_shape=(12, 12), tile_shape=(10, 30),
                       tile_spacing=(1, 1)))

Я намеревался инициализировать объект KmeansMiniBatch символической переменной X, которая заменяется на a mini_batch на каждой итерации. Каждый из мини-пакетов генерируется функцией get_batch, которая в основном принимает в качестве входных данных весь набор данных, а использование numpy.random.choice возвращает только подмножество этого набора данных, которое представляет собой массив numpy. К сожалению, мне не удается выполнить то, что я намеревался достичь, поскольку приведенный выше код приводит к следующему сообщению об ошибке:

theano.compile.function_module.UnusedInputError: theano.function попросили создать функцию, вычисляющую выходные данные с учетом определенных входных данных, но предоставленная входная переменная с индексом 0 не является частью вычислительного графа, необходимого для вычисления выходных данных: X. Чтобы сделать эту ошибку в предупреждение вы можете передать параметр on_unused_input='warn' в theano.function. Чтобы полностью отключить его, используйте on_unused_input='ignore'.

Я не уверен, почему именно я получаю эту ошибку, поскольку я заменяю символическую переменную X входом функции mini_batch. Кроме того, если я устанавливаю on_unused_input='ignore', я получаю следующее сообщение об ошибке во время оценки kmeans.D.eval():

theano.gof.fg.MissingInputError: ("Ввод графика, используемый для вычисления Shape(X), не был предоставлен и ему не было присвоено значение. Используйте флаг Theano exception_verbosity='high', для получения дополнительной информации об этой ошибке. ", ИКС)

Любая помощь будет очень высоко ценится !


Редактировать:

Итак, я наконец-то заработал! Моя функция fit_once использовалась для обновления матрицы D, которая является атрибутом класса KmeanMiniBatch, но не вернула ее, что, по-видимому, вызвало жалобу theano, поскольку ввод действительно не использовался в выводе. Что я сделал, так это изменил fit_once, чтобы вернуть D, и это в основном решило проблему. Вот мой модифицированный main

X = T.matrix('X', dtype='float64')
mini_batch = T.matrix('mini_batch', dtype='float64')

kmeans = KmeansMiniBatch(
    batch_size=1000,
    data=X
)

func = theano.function(
    inputs=[mini_batch],
    outputs=kmeans.fit_once(),
    givens={
        X: mini_batch
    },
)

data = load_data()
D= None
for i in xrange(30):
    D = func(get_batch(data))

image = Image.fromarray(
tile_raster_images(X=np.transpose(D),
                       img_shape=(12, 12), tile_shape=(10, 30),
                       tile_spacing=(1, 1)))
image.save('repflds7.png')

По-видимому, функции theano плохо работают с функциями void python.


Редактировать 2:

Просто чтобы пролить больше света на проблему, которую я хотел бы решить. Итак, версия Kmeans, которую я реализую, также известна как Vector Quantization, в которой словарь D в основном обеспечивает сжатие набора данных X в S. Первоначально часть fit_once, касающаяся D, была следующей:

self.D = T.dot(self.X, T.transpose(S))
self.D = self.D / T.sqrt(T.sum(T.sqr(self.D), axis=0))

Таким образом, на каждой итерации словарь D будет обновляться, и поэтому нет смысла возвращать D, что мне пришлось сделать, чтобы theano перестал жаловаться:

self.D = T.dot(self.X, T.transpose(S))
self.D = self.D / T.sqrt(T.sum(T.sqr(self.D), axis=0))
return self.D

D инициализируется следующим образом в __init__:

self.D = self.srng.normal(size=(self.dimensions, self.K))
self.D = self.D / T.sqrt(T.sum(T.sqr(self.D), axis=0))

Чего я хотел бы добиться, так это: 1. Не нужно возвращать D, а вместо этого обновлять и оценивать D на месте, которое я затем могу получить через kmeans.D 2. Я не о своем выборе иметь D в качестве символической переменной? Возможно, общая переменная была бы лучшим выбором? 3. Самое главное, на каждой из 30 итераций я хотел бы заменить данные X на модель KmeansMiniBatch мини-пакетом, и, следовательно, мое использование заданного параметра. Есть ли лучший способ добиться этого?


person BitRiver    schedule 30.05.2015    source источник
comment
В этом коде происходит много странного. У вас есть две переменные Theano с именем «X». Вы используете mini_batch в качестве входных данных, но затем вы также впихиваете его в givens (я почти уверен, что вы неправильно используете givens). Вы говорите, что fit_once обновляет D, но ваш вызов theano.function не имеет параметра updates. Вы не показали нам код для fit_once, но что он возвращал раньше? Если он раньше ничего не возвращал, то нет смысла указывать его как outputs. И так далее.   -  person cfh    schedule 31.05.2015
comment
@cfh Я обновил свой ответ подробностями. Я почти уверен, что в своем коде я в некотором смысле злоупотребляю theano, поэтому я надеюсь улучшить его. Если вам нужна дополнительная информация, пожалуйста, дайте мне знать. Я также отредактировал ошибку повторяющихся переменных.   -  person BitRiver    schedule 31.05.2015
comment
У вас могут быть некоторые опасения по поводу того, как работает Theano. fit_once должен что-то возвращать, потому что он будет выполнен только один раз, а именно, когда вы создаете объект function, и то, что он возвращает, должен быть графом символических вычислений, который сообщает Theano, что вычислять всякий раз, когда вызывается func. Если fit_once ничего не возвращает, ваша функция имеет outputs=None, а это означает, что func на самом деле ничего не вычислит (поскольку в ней также нет предложения updates=). Может быть, пересмотреть некоторые учебники, чтобы увидеть, как все это сочетается друг с другом.   -  person cfh    schedule 31.05.2015


Ответы (1)


Что касается вас, как пользователя Theano, символические переменные не поддерживают понятие «текущее значение» или «обновление». Для этого вам понадобится общая переменная.

Вы должны четко представлять себе, как вы хотите использовать свой KmeansMiniBatch класс. На данный момент он не инкапсулирует поведение D-обновления, поскольку функция Theano компилируется и выполняется вне KmeansMiniBatch. Вы можете предпочесть такое использование:

kmeans = KmeansMiniBatch()

data = load_data()
for i in xrange(30):
    kmeans.update(get_batch(data, batch_size=10000))

image = Image.fromarray(
tile_raster_images(X=np.transpose(kmeans.get_D()),
                       img_shape=(12, 12), tile_shape=(10, 30),
                       tile_spacing=(1, 1)))

Обратите внимание, что здесь не видны функциональные возможности Theano, все они инкапсулированы в класс KmeansMiniBatch. Нам также не нужно сообщать KmeansMiniBatch размер пакета, потому что это не меняет символьного выражения; вместо этого мы сообщаем get_batch, какого размера партия должна быть получена.

Внутри KmeansMiniBatch у вас есть два возможных подхода.

  1. Сделайте D общей переменной и используйте updates=... в своей функции Theano для изменения ее содержимого в каждом update.

    class KmeansMiniBatch:
        def __init__(dimensions, K):
            # ... init srng ...
            D = srng.normal(size=(dimensions, K))
            D = D / numpy.sqrt(numpy.sum(numpy.sqr(D), axis=0)))
            self.D = theano.shared(D, 'D')
            mini_batch = T.matrix('mini_batch', dtype='float64')
            self.func = theano.function(inputs=[mini_batch], updates=fit_once(mini_batch))
    
        def update(batch):
            self.func(batch)
    
        def fit_once(mini_batch):
            # ... do work to create S symbolically ...
            D_update = T.dot(mini_batch, T.transpose(S))
            D_update = D_update / T.sqrt(T.sum(T.sqr(D_update), axis=0))
            return [(self.D, D_update)]
    
        def get_D():
            return self.D.get_value()
    

    Обратите внимание, что инициализация D изменилась с операции Theano на операцию numpy.

  2. Сделайте D обычным массивом numpy, передайте его в качестве входных данных для вашей функции Theano и измените значение на вывод вашей функции Theano для каждого update.

    class KmeansMiniBatch:
        def __init__(dimensions, K):
            # ... init srng ...
            self.D = srng.normal(size=(dimensions, K))
            self.D = self.D / numpy.sqrt(numpy.sum(numpy.sqr(self.D), axis=0)))
            mini_batch = T.matrix('mini_batch', dtype='float64')
            self.func = theano.function(inputs=[mini_batch], outputs=fit_once())
    
        def update(batch):
            self.D = self.func(batch)
    
        def fit_once(mini_batch):
            # ... do work to create S symbolically ...
            D_update = T.dot(mini_batch, T.transpose(S))
            D_update = D_update / T.sqrt(T.sum(T.sqr(D_update), axis=0))
            return D_update
    
        def get_D():
            return self.D
    

Насколько я вижу, нет необходимости использовать givens=... вообще.

person Daniel Renshaw    schedule 01.06.2015