我正在尝试更好地理解 theano
中的 scan
功能,根据文档,我的理解是它类似于 for
循环。我创建了一个非常简单的可运行示例,用于在执行线性回归时查找权重和偏置。
#### 库# 第三方库import numpy as npimport theanoimport theano.tensor as T# 非迷你批量使用def gen_data(num_points=50, slope=1, bias=10, x_max=50): f = lambda z: slope * z + bias x = np.zeros(shape=(num_points), dtype=theano.config.floatX) y = np.zeros(shape=(num_points), dtype=theano.config.floatX) for i in range(num_points): x_temp = np.random.uniform()*x_max x[i] = x_temp y[i] = f(x_temp) + np.random.normal(scale=3.0) return (x, y)##########################################################################################################################train_x, train_y = gen_data(num_points=50, slope=2, bias=5)epochs = 50# 声明变量learn_rate = T.scalar(name='learn_rate', dtype=theano.config.floatX)x = T.vector(name='x', dtype=theano.config.floatX)y = T.vector(name='y', dtype=theano.config.floatX)# 将被更新的变量theta = theano.shared(np.random.rand(), name='theta')bias = theano.shared(np.random.rand(), name='bias')hyp = T.dot(theta, x) + biascost = T.mean((hyp - y)**2)/2f_cost = theano.function(inputs=[x, y], outputs=cost)grad_t, grad_b = T.grad(cost, [theta, bias])train = theano.function(inputs=[x, y, learn_rate], outputs=cost, updates=((theta, theta-learn_rate*grad_t), (bias, bias-learn_rate*grad_b)))print('weight: {}, bias: {}'.format(theta.get_value(), bias.get_value()))for i in range(epochs): # 尝试将此处改为 `scan` train(train_x, train_y, 0.001)print('------------------------------')print('weight: {}, bias: {}'.format(theta.get_value(), bias.get_value()))
我想将那个 for
循环改为 theano.scan
函数,但我每次尝试都遇到一个接一个的错误消息。
回答:
为了使用 theano.scan
,我从 collection
中导入了 OrderedDict
以便用于共享变量。使用 dict
会导致以下错误消息:
Expected OrderedDict or OrderedUpdates, got <class 'dict'>. This can make your script non-deterministic.
其次,我定义了一个函数来计算损失和梯度。该函数返回 loss
和一个 OrderedDict()
。函数如下:
def cost(inputs, outputs, learn_rate, theta, bias): hyp = T.dot(theta, inputs) + bias loss = T.mean((hyp - outputs)**2)/2 grad_t, grad_b = T.grad(loss, [theta, bias]) return loss, OrderedDict([(theta, theta-learn_rate*grad_t), (bias, bias-learn_rate*grad_b)])
接着,我定义了 theano.scan()
如下:
results, updates = theano.scan(fn=cost, non_sequences=[x, y, learn_rate, theta, bias], n_steps=epochs)
我选择将 x
和 y
作为 non_sequences
包含进来,因为这个玩具示例相对较小,并且与将其作为 sequences
传递相比速度提高了大约两倍。
最后,使用 theano.scan()
的 results, updates
定义了 theano.function()
train = theano.function(inputs=[x, y, learn_rate, epochs], outputs=results, updates=updates)
将所有内容整合在一起,我们有:
#### 库# 标准库from collections import OrderedDict# 第三方库# import matplotlib.pyplot as pltimport numpy as np# from sklearn import linear_modelimport theanoimport theano.tensor as T# def gen_data(num_points=50, slope=1, bias=10, x_max=50):# pass # 使用上文中的代码生成样本点######################################################################### 生成数据train_x, train_y = gen_data(num_points=50, slope=2)# 声明变量x = T.vector(name='x', dtype=theano.config.floatX)y = T.vector(name='y', dtype=theano.config.floatX)learn_rate = T.scalar(name='learn_rate', dtype=theano.config.floatX)epochs = T.iscalar(name='epochs')# 将被更新的变量,因此声明为 `theano.share`theta = theano.shared(np.random.rand(), name='theta')bias = theano.shared(np.random.rand(), name='bias')def cost(inputs, outputs, learn_rate, theta, bias): hyp = T.dot(theta, inputs) + bias loss = T.mean((hyp - outputs)**2)/2 grad_t, grad_b = T.grad(loss, [theta, bias]) return loss, OrderedDict([(theta, theta-learn_rate*grad_t), (bias, bias-learn_rate*grad_b)])results, updates = theano.scan(fn=cost, non_sequences=[x, y, learn_rate, theta, bias], n_steps=epochs)# results, updates = theano.scan(fn=cost,# sequences=[x, y],# non_sequences = [learn_rate, theta, bias],# n_steps=epochs)train = theano.function(inputs=[x, y, learn_rate, epochs], outputs=results, updates=updates)print('weight: {}, bias: {}'.format(theta.get_value(), bias.get_value()))train(train_x, train_y, 0.001, 30)print('------------------------------')print('weight: {}, bias: {}'.format(theta.get_value(), bias.get_value()))
为了完整性,我包含了将 x
和 y
作为 sequences
传递的代码。只需取消注释该部分代码,并并且注释掉另一个 theano.scan()
实例。