提交 5dfeaf73 authored 作者: Pascal Lamblin's avatar Pascal Lamblin

Add test with an Op with c_code that assumes c-contiguous memory.

That test passes now, but will fail in the future when the CLinker is modified so the C code is able to access memory in the storage_map.
上级 398d2e8a
...@@ -7,6 +7,7 @@ import theano ...@@ -7,6 +7,7 @@ import theano
import theano.tensor import theano.tensor
from theano.compile import debugmode from theano.compile import debugmode
import theano.compile import theano.compile
from theano.tests import unittest_tools as utt
import unittest import unittest
def test0(): def test0():
...@@ -505,3 +506,127 @@ class Test_check_isfinite(unittest.TestCase): ...@@ -505,3 +506,127 @@ class Test_check_isfinite(unittest.TestCase):
print infs print infs
f(infs) f(infs)
return return
class Test_preallocated_output(unittest.TestCase):
class BrokenCImplementationAdd(gof.Op):
def __eq__(self, other):
return type(self) == type(other)
def __hash__(self):
return hash(type(self))
def make_node(self, a, b):
a = theano.tensor.as_tensor_variable(a)
b = theano.tensor.as_tensor_variable(b)
assert a.type.dtype == 'float32'
assert a.type.dtype == b.type.dtype
assert a.type.ndim==2
r = gof.Apply(self, [a, b], [a.type()])
return r
def perform(self, node, inp, out_):
print 'executing python perform'
a, b = inp
out, = out_
z = a + b
print 'out[0] was:', out[0]
out[0] = z
def c_code(self, node, name, inp, out, sub):
a, b = inp
z, = out
debug = 0
return """
printf("executing c_code\\n");
if (%(a)s->nd != 2) {PyErr_SetString(PyExc_NotImplementedError, "rank(a) != 2"); %(fail)s;}
if (%(b)s->nd != 2) {PyErr_SetString(PyExc_NotImplementedError, "rank(b) != 2"); %(fail)s;}
if (%(a)s->descr->type_num != PyArray_FLOAT)
{PyErr_SetString(PyExc_NotImplementedError, "a dtype not NPY_FLOAT"); %(fail)s;}
if (%(b)s->descr->type_num != PyArray_FLOAT)
{PyErr_SetString(PyExc_NotImplementedError, "b's dtype not NPY_FLOAT"); %(fail)s;}
if (%(a)s->dimensions[0] != %(a)s->dimensions[1])
{PyErr_SetString(PyExc_NotImplementedError, "a is not square"); %(fail)s;}
if (%(b)s->dimensions[0] != %(b)s->dimensions[1])
{PyErr_SetString(PyExc_NotImplementedError, "b is not square"); %(fail)s;}
if (%(a)s->dimensions[0] != %(b)s->dimensions[0])
{PyErr_SetString(PyExc_NotImplementedError, "a and b have different dimensions"); %(fail)s;}
// We do not check for c_contiguous property here
if (%(debug)s)
{
if (!%(z)s)
printf("%(z)s is not there, %%p \\n", %(z)s);
else if (%(z)s->dimensions[0] != %(b)s->dimensions[0])
printf("Dimension 0 mismatch for %(z)s and %(b)s\\n");
else if (%(z)s->dimensions[1] != %(b)s->dimensions[1])
printf("Dimension 1 mismatch for %(z)s and %(b)s\\n");
else
printf("Reusing %(z)s\\n");
}
if ((!%(z)s)
|| (%(z)s->dimensions[0] != %(b)s->dimensions[0])
|| (%(z)s->dimensions[1] != %(b)s->dimensions[1])
)
{
Py_XDECREF(%(z)s);
npy_intp dims[] = {0, 0};
dims[0] = %(b)s->dimensions[0];
dims[1] = %(b)s->dimensions[1];
%(z)s = (PyArrayObject*) PyArray_SimpleNew(2, dims, %(b)s->descr->type_num);
}
// Let us assume that %(z)s is c_contiguous
{
dtype_%(z)s * z = ((dtype_%(z)s*)(PyArray_GETPTR2(%(z)s,0,0)));
for (int i=0; i<%(b)s->dimensions[0]; i++)
{
for (int j=0; j<%(b)s->dimensions[1]; j++)
{
*z = ((float*)PyArray_GETPTR2(%(a)s, i, j))[0] +
((float*)PyArray_GETPTR2(%(b)s, i, j))[0] ;
z++;
}
}
}
"""% dict(locals(), **sub)
def test_f_contiguous(self):
a = theano.tensor.fmatrix('a')
b = theano.tensor.fmatrix('b')
z = self.BrokenCImplementationAdd()(a, b)
out = theano.tensor.dot(z, numpy.eye(7)) # Needed so that z is not the output of the graph
rng = numpy.random.RandomState(seed=utt.fetch_seed())
a_val = rng.randn(7,7).astype('float32')
b_val = rng.randn(7,7).astype('float32')
init_conf_val = config.DebugMode.check_preallocated_output
try:
# Should work
config.DebugMode.check_preallocated_output = 'c_contiguous'
f = theano.function([a, b], out, mode='DEBUG_MODE')
out_val = f(a_val, b_val)
print 'out_val =', out_val
print out_val.strides
# Should work for now (0.4.0), because the C thunk does not care
# at all of what is in storage_map initially.
# When it changes, the call to f should raise an Exception,
# since the output buffer is used incorrectly.
config.DebugMode.check_preallocated_output = 'f_contiguous'
f = theano.function([a, b], out, mode='DEBUG_MODE')
out_val = f(a_val, b_val)
print 'out_val =', out_val
print out_val.strides
finally:
config.DebugMode.check_preallocated_output = init_conf_val
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论