Theano是怎么处理形状信息(Shape Information)
在构建图的时候,不可能严格执行Theano变量的形状。因为在运行的时候,传递给Theano函数的某一参数的值可能影响Thenao变量的形状。目前,关于形状信息的使用在Theano中有以下两种方式:
在输出形状已知的情况下,生成在CPU和GPU上进行2d卷积的更高效的C代码
当我们只关心变量的形状,而不是实际值的时候,将移除图的计算。这通过Op.infer_shape完成。
例子:
import theano
import theano.tensor as T
x = T.matrix('x')
f = theano.function([x], (x ** 2).shape)
theano.printing.debugprint(f)
# MakeVector{dtype='int64'} [id A] '' 2
# |Shape_i{0} [id B] '' 1
# | |x [id C]
# |Shape_i{1} [id D] '' 0
# |x [id C]
输出结果不包含任何乘法以及幂运算。Theano已经移除了它们直接去计算输出的形状。
形状推断问题(Shape Inference Problem)
在图中,Theano将会传播形状的信息。有时,这将会导致一些错误。考虑下面的例子:
import numpy
import theano
x = theano.tensor.matrix('x')
y = theano.tensor.matrix('y')
z = theano.tensor.join(0, x, y) # 将x,y按行拼接起来,要求x,y的列数一致
xv = numpy.random.rand(5, 4)
yv = numpy.random.rand(3, 3)
f = theano.function([x, y], z.shape)
theano.printing.debugprint(f)
# MakeVector{dtype='int64'} [id A] '' 4
# |Elemwise{Add}[(0, 0)] [id B] '' 3
# | |Shape_i{0} [id C] '' 1
# | | |x [id D]
# | |Shape_i{0} [id E] '' 2
# | |y [id F]
# |Shape_i{1} [id G] '' 0
# |x [id D]
f(xv, yv) # 并没有报错
# array([8, 4])
f = theano.function([x,y], z) # 直接返回z
theano.printing.debugprint(f)
# Join [id A] '' 0
# |TensorConstant{0} [id B]
# |x [id C]
# |y [id D]
f(xv, yv) # 报错
# Traceback (most recent call last):
# ...
# ValueError: ...
正如你看到的,当仅仅访问计算结果的形状信息(z.shape)时,将会直接推断结果的形状,并不会执行计算过程(即z的具体数值)。
这使得形状的计算速度很快,但是它可能会隐藏一些错误。在这个例子中,输出结果形状的计算仅仅基于输入的第一个Theano变量,这导致返回形状信息的错误。
这种现象也可能出现在其他运算上,比如elemwise和dot。事实上,为了执行一些优化(例如,速度和稳定性),Theano从一开始就假定计算是正确的,并且是一致的。就像上述例子中一样。
你可以通过使用Theano标志optimizer_excluding=local_shape_to_shape_i运行代码(将不会执行上述提及的优化)来检测这种错误。你也可以通过在FAST_COMPILE或者DebugMode模式下执行代码,得到同样的效果。
FAST_COMPILE模式将不会执行这种优化,以及大部分其它的优化。
DebugMode模式将会在优化前以及优化后进行测试,导致运行速率更慢。
指定确切的形状
目前,指定一个形状并不像我们计划一些更新和期望的那么容易和灵活。以下情形是目前我们可以做到的:
当调用conv2d时,你可以直接把形状信息传递给ConvOp。你只需要在调用时简单地设置一下image_shape和filter_shape参数就可以了。他们必须是包含4个元素的元组。例如:
theano.tensor.nnet.conv2d(..., image_shape=(7,3,5,5), filter_shape=(2,3,4,4))
你可以在图的任何位置使用SpecifyShape添加位置信息。这允许执行一些优化。在接下来的例子中,这使得预先计算Theano函数为常数成为可能。
import theano
x = theano.tensor.matrix()
x_specify_shape = theano.tensor.specify_shape(x, (2,2))
f = theano.function([x], (x_specify_shape ** 2).shape)
theano.printing.debugprint(f)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。