当我将一个 numpy 数组发送到 theano 函数中的一个 givens 参数时,为什么我会得到这个 Theano TypeError

When I send a numpy array to a givens parameter in a theano function, why do I get this Theano TypeError

我是 theano 的新手,一方面还在为 theano 的 "pseudo code" 风格和另一方面的严格类型检查而苦苦挣扎。我更像是一名 C 程序员和一名 python 程序员。有人可以指出我在这个示例代码中出错的地方吗,它使用预测的 y 点和 x 值的训练 y 点之间的均方误差,以获得线性拟合的最佳斜率和截距?

代码如下:

import numpy as np
import theano
import theano.tensor as T
from collections import OrderedDict

class LinearModel:
    def __init__(self,num_points):
        self.m = theano.shared(value=0.1,name='m')
        self.b = theano.shared(value=1, name='b')
        self.params = [self.m, self.b]

        def step(x_t):
            y_t = self.m * x_t + self.b
            return y_t

        self.x = T.matrix('x',dtype=theano.config.floatX)
        self.y, _ = theano.scan(
                        fn=step,
                        sequences=self.x,
                    ) 

        self.loss = lambda y_train: self.mse(y_train)

    def mse(self, y_train):
        return T.mean((self.y - y_train) ** 2)

    def fit(self,x, y, learning_rate=0.01, num_iter=100):
        trainset_x = theano.tensor._shared(x.astype(np.dtype(np.float32)),borrow=True)
        trainset_y = theano.tensor._shared(y.astype(np.dtype(np.float32)),borrow=True)
        n_train = trainset_x.get_value(borrow=True).shape[0]

        cost = self.loss(trainset_y)
        gparams = T.grad(cost,self.params)

        l_r = T.scalar('l_r', dtype=theano.config.floatX)

        updates = OrderedDict()
        for param,gparam in zip(self.params,gparams):
            updates[param] = param - l_r * gparam

        self.train_model = theano.function(  inputs=[l_r],
                                        outputs=[cost,self.y],
                                        updates=updates,
                                        givens={
                                              self.x: trainset_x,
                                            }
                                        )

        epoch = 0
        while epoch < num_iter:
            cost, _ = self.train_model(learning_rate)
            m = self.m.get_value()
            b = self.b.get_value()
            print "epoch: ",epoch," cost: ",cost," m: ",m," b: ",b


if __name__ == '__main__':
    lin = LinearModel(10)
    x = np.arange(10)
    y = np.random.rand(10)
    lin.fit(x,y,learning_rate=0.01,num_iter=100)

错误是:

Traceback (most recent call last): File "~/EclipseWorkspace/MemoryNetworkQA.Theano/linear_regression.py", line 70, in lin.fit(x,y,learning_rate=0.01,num_iter=100) File "~/EclipseWorkspace/MemoryNetworkQA.Theano/linear_regression.py", line 54, in fit self.x: trainset_x, File "/usr/local/lib/python2.7/dist-packages/theano/compile/function.py", line 266, in function profile=profile) File "/usr/local/lib/python2.7/dist-packages/theano/compile/pfunc.py", line 489, in pfunc no_default_updates=no_default_updates) File "/usr/local/lib/python2.7/dist-packages/theano/compile/pfunc.py", line 217, in rebuild_collect_shared raise TypeError(err_msg, err_sug)

TypeError: ('An update must have the same type as the original shared variable (shared_var=b, shared_var.type=TensorType(int64, scalar), update_val=Elemwise{sub,no_inplace}.0, update_val.type=TensorType(float64, scalar)).', 'If the difference is related to the broadcast pattern, you can call the tensor.unbroadcast(var, axis_to_unbroadcast[, ...]) function to remove broadcastable dimensions.')

在解决以下问题之前,此代码不会执行。

  1. 问题中报告的错误是由于 self.b 的类型与 self.b 的更新类型不匹配。 self.b 没有指定类型,因此已推断出一个。初始值为 Python 整数,因此推断类型为 int64。更新是 floatX 因为学习率是 floatX。您不能用 floatX 更新 int64。解决方案是使初始值成为 Python 浮点数,从而推断出 floatX 类型。将self.b = theano.shared(value=1, name='b')改为self.b = theano.shared(value=1., name='b')(注意1后面的小数点)。

  2. 接下来的问题是self.x定义为矩阵但是最后一行函数调用中传递的值是向量。一种解决方案是将 x 重塑为矩阵,例如将 x = np.arange(10) 更改为 x = np.arange(10).reshape(1,10).

  3. 训练集共享变量的类型为 float32 但这与使用 floatX 的代码的其他区域冲突。如果你的 floatX=float32 那么应该没有问题,但是简单地使用 floatX 来保持相同的 float 类型会更安全。将 trainset_x = theano.tensor._shared(x.astype(np.dtype(np.float32)),borrow=True) 更改为 trainset_x = theano.tensor._shared(x.astype(theano.config.floatX),borrow=True) 并类似地更改 trainset_y.

  4. 纪元数目前没有任何影响,因为 epoch 没有增加。将 while epoch < num_iter: 更改为 for epoch in xrange(num_iter): 并删除 epoch = 0.

此外,

  • 参数看起来没有更新,但这是错误的看法。由于上面的问题 4,迭代很快通过并且永不停止,并且学习率足够大以使模型收敛得非常快。尝试将学习率更改为更小的值,例如0.0001,只查看前 100 个时期的输出。

  • 我建议避免使用 theano.tensor._shared,除非你确实需要在 device=gpu 时强制在 CPU 上分配共享变量。首选方法是 theano.shared.

  • n_train 变量未在任何地方使用。

  • 您使用 givens 不一致。我建议将它用于 xy,或者两者都不用。查看 logistic regression tutorial 以获取更多关于此的指示。

  • 每次调用 fit 时都会重新编译 Theano 函数,但最好只编译一次并在每次 fit.[=58 时重新使用它=]

  • 无需使用scan即可实现此模型。通常,scan 通常仅在步骤的输出是先前步骤的输出的函数时才需要。 scan 通常也比替代方案慢得多,应尽可能避免使用。您可以使用 self.y = self.m * self.x + self.b 来删除 scan

  • 如果您使用扫描,最好在 scan 调用中通过 strict=True 启用严格模式。

  • 为所有共享变量显式提供类型是一种很好的做法。你这样做是为了 trainset_xtrainset_y 但不是为了 self.mself.b.

好吧,我发现问题真的出在self.b。用显式浮点数初始化后,类型错误消失。

但是斜率和截距(self.m 和 self.b)仍然是 theano 共享变量并且通过更新传入,并没有真正得到更新。如果有人能告诉我原因,那将是一个很大的帮助。谢谢

import numpy as np
import theano
import theano.tensor as T
from collections import OrderedDict

class LinearModel:
    def __init__(self,num_points):
        self.m = theano.shared(value=0.1,name='m')
        self.b = theano.shared(value=1.0, name='b')
        self.params = [self.m, self.b]

        def step(x_t):
            y_t = self.m * x_t + self.b
            return y_t

        #self.x = T.matrix('x',dtype=theano.config.floatX)
        #self.x = T.dmatrix('x')
        self.x = T.vector('x',dtype=theano.config.floatX)
        self.y, _ = theano.scan(
                        fn=step,
                        sequences=self.x,
                    ) 

        self.loss = lambda y_train: self.mse(y_train)

    def mse(self, y_train):
        return T.mean((self.y - y_train) ** 2)

    def fit(self,x, y, learning_rate=0.01, num_iter=100):
        trainset_x = theano.tensor._shared(x.astype(np.dtype(np.float32)),borrow=True)
        trainset_y = theano.tensor._shared(y.astype(np.dtype(np.float32)),borrow=True)
        n_train = trainset_x.get_value(borrow=True).shape[0]

        cost = self.loss(trainset_y)
        gparams = T.grad(cost,self.params)

        l_r = T.scalar('l_r', dtype=theano.config.floatX)

        updates = OrderedDict()
        for param,gparam in zip(self.params,gparams):
            updates[param] = param - l_r * gparam

        self.train_model = theano.function(  inputs=[l_r],
                                        outputs=[cost,self.y],
                                        updates=updates,
                                        givens={
                                              self.x: trainset_x,
                                            }
                                        )


        epoch = 0
        while epoch < num_iter:
            cost, _ = self.train_model(learning_rate)
            m = self.m.get_value()
            b = self.b.get_value()
            print "epoch: ",epoch," cost: ",cost," m: ",m," b: ",b
            epoch += 1


if __name__ == '__main__':
    lin = LinearModel(10)
    x = np.array([1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0])
    y = np.random.rand(10)
    lin.fit(x,y,learning_rate=0.01,num_iter=100)