【问题标题】:Theano function: Unused inputTheano 函数:未使用的输入
【发布时间】:2015-08-13 10:46:13
【问题描述】:

我正在尝试实现小批量 Kmeans。似乎让我很难过的部分是将小批量指定为 theano 的输入。我有一个带有__init__(self, batch_size, data=None) 函数的KmeansMiniBatch 类,其中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)))

我打算用符号变量 X 初始化一个 KmeansMiniBatch 对象,在每次迭代时它都会被 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',有关更多信息这个错误。”, X)

任何帮助将不胜感激!


编辑:

所以我终于让它工作了!我的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_onceD 相关的部分如下:

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 模型,因此我使用了给定参数。有没有更好的方法来实现这一目标?

【问题讨论】:

  • 该代码中有很多奇怪的东西。您有两个名为“X”的 Theano 变量。您使用mini_batch 作为输入,但随后您也将它硬塞进givens(我很确定您在滥用givens)。你说fit_once 更新D,但你的theano.function 调用没有updates 参数。您没有向我们展示fit_once 的代码,但它之前返回了什么?如果它之前没有返回任何东西,那么将其指定为outputs 是没有意义的。以此类推。
  • @cfh 我用详细信息更新了我的答案。我很确定在我的代码中我确实在某种意义上滥用了theano,这就是我希望改进它的原因。如果您需要更多详细信息,请告诉我。我还编辑了重复变量错误。
  • 您可能对 Theano 的工作方式有一些基本的疑虑。 fit_once 必须返回一些东西,因为它只会执行一次,即当您构造 function 对象时,它返回的应该是一个符号计算图,它告诉 Theano 每当调用 func 时要计算什么。如果fit_once 没有返回任何内容,则您的函数具有outputs=None,这意味着func 实际上不会计算任何内容(因为它也没有updates= 子句)。也许重温一些教程,看看这一切是如何结合在一起的。

标签: python numpy k-means theano


【解决方案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 设为共享变量,并在您的Theano 函数中使用updates=... 来更改每个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 的 init 已从 Theano 操作变为 numpy 操作。

  2. D 设为常规的 numpy 数组,将其作为 Theano 函数的输入传递,然后在每个 update 上将值更改为 Theano 函数的输出。

    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=...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-10
    • 2015-11-06
    • 2017-06-19
    • 1970-01-01
    • 2015-10-29
    • 2016-06-07
    相关资源
    最近更新 更多