提交 46305ee5 authored 作者: James Bergstra's avatar James Bergstra

Removed pointless dependence of test_debugmode on sparse stuff

上级 570d61d4
import sys import sys
import numpy import numpy
import scipy.sparse
from theano import gof from theano import gof
import theano.sparse
import theano import theano
import theano.tensor import theano.tensor
from theano.compile import debugmode from theano.compile import debugmode
...@@ -15,7 +13,7 @@ def test0(): ...@@ -15,7 +13,7 @@ def test0():
f = theano.function([x], (2.*x + 7) / 2., mode=debugmode.DebugMode()) f = theano.function([x], (2.*x + 7) / 2., mode=debugmode.DebugMode())
print f([1,2]) print f([1,2])
class BROKEN_ON_PURPOSE_StructuredDotCSC(gof.Op): class BROKEN_ON_PURPOSE_Add(gof.Op):
def __init__(self, py_offset): def __init__(self, py_offset):
gof.Op.__init__(self) gof.Op.__init__(self)
self.py_offset = py_offset self.py_offset = py_offset
...@@ -23,140 +21,65 @@ class BROKEN_ON_PURPOSE_StructuredDotCSC(gof.Op): ...@@ -23,140 +21,65 @@ class BROKEN_ON_PURPOSE_StructuredDotCSC(gof.Op):
return type(self) == type(other) and (self.py_offset == other.py_offset) return type(self) == type(other) and (self.py_offset == other.py_offset)
def __hash__(self): def __hash__(self):
return 29834 ^ hash(type(self)) ^ hash(self.py_offset) return 29834 ^ hash(type(self)) ^ hash(self.py_offset)
def make_node(self, a_val, a_ind, a_ptr, a_nrows, b): def make_node(self, a, b):
a_nrows = theano.tensor.as_tensor_variable(a_nrows) a = theano.tensor.as_tensor_variable(a)
assert a_val.type.dtype == b.type.dtype b = theano.tensor.as_tensor_variable(b)
r = gof.Apply(self, [a_val, a_ind, a_ptr, a_nrows, b], assert a.type.dtype == 'float64'
[theano.tensor.tensor(a_val.type.dtype, (False, False))]) assert a.type.dtype == b.type.dtype
assert a.type.ndim==1
r = gof.Apply(self, [a, b], [a.type()])
return r return r
def perform(self, node, (a_val, a_ind, a_ptr, a_nrows, b), (out,)): def perform(self, node, (a, b), (out,)):
a = scipy.sparse.csc_matrix((a_val, a_ind, a_ptr), z = a+b
(a_nrows, b.shape[0]),
copy = False)
# TODO: todense() is automatic in 0.7.0, just remove the following line:
z = a * b
#ERROR TO ADD THIS CRAPPY OFFSET #ERROR TO ADD THIS CRAPPY OFFSET
if self.py_offset: if self.py_offset:
out[0] = z+0.5 out[0] = z+0.5
else: out[0] = z else: out[0] = z
def c_code(self, node, name, (a_val, a_ind, a_ptr, a_nrows, b), (z,), sub): def c_code(self, node, name, (a, b), (z,), sub):
return """ return """
if (%(a_val)s->nd != 1) {PyErr_SetString(PyExc_NotImplementedError, "rank(a_val) != 1"); %(fail)s;} if (%(a)s->nd != 1) {PyErr_SetString(PyExc_NotImplementedError, "rank(a) != 1"); %(fail)s;}
if (%(a_ind)s->nd != 1) {PyErr_SetString(PyExc_NotImplementedError, "rank(a_ind) != 1"); %(fail)s;} if (%(b)s->nd != 1) {PyErr_SetString(PyExc_NotImplementedError, "rank(b) != 1"); %(fail)s;}
if (%(a_ptr)s->nd != 1) {PyErr_SetString(PyExc_NotImplementedError, "rank(a_ptr) != 1"); %(fail)s;}
if (%(a_nrows)s->nd != 0) {PyErr_SetString(PyExc_NotImplementedError, "rank(nrows) != 0"); %(fail)s;}
if (%(b)s->nd != 2) {PyErr_SetString(PyExc_NotImplementedError, "rank(b) != 2"); %(fail)s;}
if (%(a_val)s->descr->type_num != PyArray_DOUBLE) if (%(a)s->descr->type_num != PyArray_DOUBLE)
{PyErr_SetString(PyExc_NotImplementedError, "a_val dtype not NPY_DOUBLE"); %(fail)s;} {PyErr_SetString(PyExc_NotImplementedError, "a dtype not NPY_DOUBLE"); %(fail)s;}
if (%(a_ind)s->descr->type_num != PyArray_INT32) {
PyErr_SetString(PyExc_NotImplementedError, "a_ind dtype not INT32"); %(fail)s;}
if (%(a_ptr)s->descr->type_num != PyArray_INT32)
{PyErr_SetString(PyExc_NotImplementedError, "a_ptr dtype not INT32"); %(fail)s;}
if (%(a_nrows)s->descr->type_num != PyArray_INT32)
{PyErr_SetString(PyExc_NotImplementedError, "a_nrows dtype not INT32"); %(fail)s;}
if (%(b)s->descr->type_num != PyArray_DOUBLE) if (%(b)s->descr->type_num != PyArray_DOUBLE)
{PyErr_SetString(PyExc_NotImplementedError, "b's dtype not NPY_DOUBLE"); %(fail)s;} {PyErr_SetString(PyExc_NotImplementedError, "b's dtype not NPY_DOUBLE"); %(fail)s;}
if (%(a_val)s->dimensions[0] != %(a_ind)s->dimensions[0]) if (%(a)s->dimensions[0] != %(b)s->dimensions[0])
{PyErr_SetString(PyExc_NotImplementedError, "a_val and a_ind have different lengths"); %(fail)s;} {PyErr_SetString(PyExc_NotImplementedError, "a and b have different lengths"); %(fail)s;}
if (%(a_ptr)s->dimensions[0] != %(b)s->dimensions[0]+1)
{PyErr_SetString(PyExc_NotImplementedError, "a's number of columns doesn't match b's rows"); %(fail)s;}
if ((!%(z)s) if ((!%(z)s)
|| (%(z)s->dimensions[0] != ((npy_int32 *)%(a_nrows)s->data)[0]) || (%(z)s->dimensions[0] != %(b)s->dimensions[0])
|| (%(z)s->dimensions[1] != %(b)s->dimensions[1])
) )
{ {
{Py_XDECREF(%(z)s);} {Py_XDECREF(%(z)s);}
npy_intp dims[] = {0,0}; npy_intp dims[] = {0};
dims[0] = ((npy_int32 *)%(a_nrows)s->data)[0]; dims[0] = %(b)s->dimensions[0];
dims[1] = %(b)s->dimensions[1]; %(z)s = (PyArrayObject*) PyArray_SimpleNew(1, dims, %(b)s->descr->type_num);
%(z)s = (PyArrayObject*) PyArray_SimpleNew(2, dims, %(b)s->descr->type_num);
} }
{ {
//the output array has size M x N for (npy_intp m = 0; m < %(z)s->dimensions[0]; ++m)
npy_intp M = %(z)s->dimensions[0];
npy_intp N = %(z)s->dimensions[1];
npy_intp K = %(b)s->dimensions[0];
npy_intp Szm = %(z)s->strides[0] / %(z)s->descr->elsize;
npy_intp Szn = %(z)s->strides[1] / %(z)s->descr->elsize;
//npy_intp Sbm = %(b)s->strides[0] / %(b)s->descr->elsize;
npy_intp Sbn = %(b)s->strides[1] / %(b)s->descr->elsize;
npy_intp Sval = %(a_val)s->strides[0] / %(a_val)s->descr->elsize;
npy_intp Sind = %(a_ind)s->strides[0] / %(a_ind)s->descr->elsize;
npy_intp Sptr = %(a_ptr)s->strides[0] / %(a_ptr)s->descr->elsize;
npy_double * __restrict__ Dz = (npy_double*)%(z)s->data;
//const npy_double * __restrict__ Db = (npy_double*)%(b)s->data;
const npy_double * __restrict__ Dval = (npy_double*)%(a_val)s->data;
const npy_int32 * __restrict__ Dind = (npy_int32*)%(a_ind)s->data;
const npy_int32 * __restrict__ Dptr = (npy_int32*)%(a_ptr)s->data;
//npy_intp nnz = %(a_ind)s->dimensions[0];
//clear the output array
for (npy_intp m = 0; m < M; ++m)
{
for (npy_intp n = 0; n < N; ++n)
{
//Dz[m*Szm + n*Szn] = 0.0;
Dz[m*Szm + n*Szn] = 0.5; //here is the py_offset amount
}
}
//iterate over the sparse array, making the most of an entry wherever we find it.
//
// Normal matrix matrix multiply:
// for m
// for n
// for k
// z[m,n] += a[m,k] * b[k,n]
// Here instead:
// for k
// for m (sparse)
// for n
// z[m,n] += a[m,k] * b[k,n]
for (npy_int32 k = 0; k < K; ++k)
{ {
const npy_double * __restrict__ bk = (double *)(%(b)s->data + %(b)s->strides[0] * k); ((double*)PyArray_GETPTR1(%(z)s, m))[0]
= 0.5
for (npy_int32 m_idx = Dptr[k * Sptr]; m_idx < Dptr[(k+1) * Sptr]; ++m_idx) + ((double*)PyArray_GETPTR1(%(a)s, m))[0]
{ + ((double*)PyArray_GETPTR1(%(b)s, m))[0] ;
npy_int32 m = Dind[m_idx * Sind];
const double Amk = Dval[m_idx * Sval];
npy_double * __restrict__ zm = (npy_double *)(%(z)s->data + %(z)s->strides[0] * m);
if (m >= %(z)s->dimensions[0])
{PyErr_SetString(PyExc_NotImplementedError, "illegal row index in a"); %(fail)s;}
for(npy_int32 n = 0; n < N; ++n)
{
zm[n*Szn] += Amk * bk[n*Sbn];
}
}
} }
} }
"""% dict(locals(), **sub) """% dict(locals(), **sub)
# inconsistent is a invalid op, whose perform and c_code do not match # inconsistent is a invalid op, whose perform and c_code do not match
inconsistent = BROKEN_ON_PURPOSE_StructuredDotCSC(False) inconsistent = BROKEN_ON_PURPOSE_Add(False)
# off_by_half is a good op, that is different from theano.sparse.sd_csc # off_by_half is a good op, that is different from theano.sparse.sd_csc
off_by_half = BROKEN_ON_PURPOSE_StructuredDotCSC(True) off_by_half = BROKEN_ON_PURPOSE_Add(True)
class WeirdBrokenOp(gof.Op): class WeirdBrokenOp(gof.Op):
""" """
This op can be inplace if behaviour is times1_inplace This op can be inplace if behaviour is 'times1_inplace'
This op can be destructive if behaviour is times2_inplace This op can be destructive if behaviour is 'times2_inplace'
In both cases, it does not set the destroy_map or view_map correctly so it should raise an In both cases, it does not set the destroy_map or view_map correctly so it should raise an
error in DebugMode. error in DebugMode.
...@@ -245,32 +168,20 @@ wb1 = WeirdBrokenOp('times1') ...@@ -245,32 +168,20 @@ wb1 = WeirdBrokenOp('times1')
def test_badclinkeroutput(): def test_badclinkeroutput():
vals = theano.tensor.dvector() a = theano.tensor.dvector()
inds = theano.tensor.ivector() b = theano.tensor.dvector()
ptrs = theano.tensor.ivector()
nrows = theano.tensor.iscalar()
b = theano.tensor.dmatrix()
f_good = theano.function([vals, inds, ptrs, nrows, b], f_good = theano.function([a, b],
theano.sparse.StructuredDotCSC()(vals, inds, ptrs, nrows, b), off_by_half(a, b),
mode=debugmode.DebugMode(check_c_code=True)) mode=debugmode.DebugMode(check_c_code=True))
f_inconsistent = theano.function([vals, inds, ptrs, nrows, b], f_inconsistent = theano.function([a,b],
inconsistent(vals, inds, ptrs, nrows, b), inconsistent(a, b),
mode=debugmode.DebugMode(check_c_code=True)) mode=debugmode.DebugMode(check_c_code=True))
#this should evaluate with no error #this should evaluate with no error
rval_good = f_good([1.0, 2.0, 3.0], f_good([1.0, 2.0, 3.0], [2,3,4])
[0,1,2],
[0,1,2,3],
3,
numpy.asarray([[0.,1.,2.],[3.,4.,5.],[6.,7.,8.]]))
try: try:
rval = f_inconsistent([1.0, 2.0, 3.0], f_inconsistent([1.0, 2.0, 3.0], [2,3,4])
[0,1,2],
[0,1,2,3],
3,
numpy.asarray([[0.,1.,2.],[3.,4.,5.],[6.,7.,8.]]))
except debugmode.BadCLinkerOutput, e: except debugmode.BadCLinkerOutput, e:
print repr(e) print repr(e)
assert e.r.owner.op is inconsistent assert e.r.owner.op is inconsistent
...@@ -280,34 +191,25 @@ def test_badclinkeroutput(): ...@@ -280,34 +191,25 @@ def test_badclinkeroutput():
def test_badoptimization(): def test_badoptimization():
@gof.local_optimizer([theano.sparse.sd_csc]) @gof.local_optimizer([theano.tensor.add])
def insert_broken_csc(node): def insert_broken_add(node):
if node.op == theano.sparse.sd_csc: if node.op == theano.tensor.add:
return [off_by_half(*node.inputs)] return [off_by_half(*node.inputs)]
return False return False
edb = gof.EquilibriumDB() edb = gof.EquilibriumDB()
edb.register('insert_broken_csc', insert_broken_csc, 'all') edb.register('insert_broken_add', insert_broken_add, 'all')
opt = edb.query('+all') opt = edb.query('+all')
vals = theano.tensor.dvector() a = theano.tensor.dvector()
inds = theano.tensor.ivector() b = theano.tensor.dvector()
ptrs = theano.tensor.ivector()
nrows = theano.tensor.iscalar()
b = theano.tensor.dmatrix() f = theano.function([a, b], a+b,
f = theano.function([vals, inds, ptrs, nrows, b],
theano.sparse.sd_csc(vals, inds, ptrs, nrows, b),
mode=debugmode.DebugMode(optimizer=opt, check_c_code=True)) mode=debugmode.DebugMode(optimizer=opt, check_c_code=True))
try: try:
rval = f([1.0, 2.0, 3.0], rval = f([1.0, 2.0, 3.0], [2,3,4],)
[0,1,2],
[0,1,2,3],
3,
numpy.asarray([[0.,1.,2.],[3.,4.,5.],[6.,7.,8.]]))
except debugmode.BadOptimization, e: except debugmode.BadOptimization, e:
assert str(e.reason) == 'insert_broken_csc' assert str(e.reason) == 'insert_broken_add'
return #TEST PASS return #TEST PASS
assert False assert False
...@@ -317,27 +219,23 @@ def test_stochasticoptimization(): ...@@ -317,27 +219,23 @@ def test_stochasticoptimization():
# this optimization alternates between triggering and not triggering. # this optimization alternates between triggering and not triggering.
last_time_replaced=[False] last_time_replaced=[False]
@gof.local_optimizer([theano.sparse.sd_csc]) @gof.local_optimizer([theano.tensor.add])
def insert_broken_csc_sometimes(node): def insert_broken_add_sometimes(node):
if node.op == theano.sparse.sd_csc: if node.op == theano.tensor.add:
last_time_replaced[0] = not last_time_replaced[0] last_time_replaced[0] = not last_time_replaced[0]
if last_time_replaced[0]: if last_time_replaced[0]:
return [off_by_half(*node.inputs)] return [off_by_half(*node.inputs)]
return False return False
edb = gof.EquilibriumDB() edb = gof.EquilibriumDB()
edb.register('insert_broken_csc_sometimes', insert_broken_csc_sometimes, 'all') edb.register('insert_broken_add_sometimes', insert_broken_add_sometimes, 'all')
opt = edb.query('+all') opt = edb.query('+all')
vals = theano.tensor.dvector() a = theano.tensor.dvector()
inds = theano.tensor.ivector() b = theano.tensor.dvector()
ptrs = theano.tensor.ivector()
nrows = theano.tensor.iscalar()
b = theano.tensor.dmatrix()
try: try:
f = theano.function([vals, inds, ptrs, nrows, b], f = theano.function([a, b],
theano.sparse.sd_csc(vals, inds, ptrs, nrows, b), theano.tensor.add(a, b),
mode=debugmode.DebugMode(optimizer=opt, check_c_code=True)) mode=debugmode.DebugMode(optimizer=opt, check_c_code=True))
except debugmode.StochasticOrder: except debugmode.StochasticOrder:
return #TEST PASS return #TEST PASS
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论