提交 348e14dc authored 作者: lamblin's avatar lamblin

Merge pull request #1279 from jsalvatier/advinc_rebase3

Advinc rebase3
import os, sys import os
import sys
from theano.compat import PY3 from theano.compat import PY3
from theano.gof.compilelock import get_lock, release_lock from theano.gof.compilelock import get_lock, release_lock
from theano import config from theano import config
import cmodule
# TODO These two lines may be removed in the future, when we are 100% sure # TODO These two lines may be removed in the future, when we are 100% sure
# noone has an old cutils_ext.so lying around anymore. # noone has an old cutils_ext.so lying around anymore.
...@@ -12,8 +14,66 @@ if os.path.exists(os.path.join(config.compiledir, 'cutils_ext.so')): ...@@ -12,8 +14,66 @@ if os.path.exists(os.path.join(config.compiledir, 'cutils_ext.so')):
def compile_cutils(): def compile_cutils():
"""Do just the compilation of cutils_ext""" """Do just the compilation of cutils_ext"""
code = """
types = ['npy_' + t for t in ['int8', 'int16', 'int32', 'int64', 'int128',
'int256', 'uint8', 'uint16', 'uint32', 'uint64', 'uint128', 'uint256',
'float16', 'float32', 'float64', 'float80', 'float96', 'float128',
'float256']]
complex_types = ['npy_' + t for t in ['complex32', 'complex64',
'complex128', 'complex160', 'complex192', 'complex512']]
inplace_map_template = """
#if defined(%(typen)s)
static void %(type)s_inplace_add(PyArrayMapIterObject *mit, PyArrayIterObject *it)
{
int index = mit->size;
while (index--) {
%(op)s
PyArray_MapIterNext(mit);
PyArray_ITER_NEXT(it);
}
}
#endif
"""
floatadd = "((%(type)s*)mit->dataptr)[0] = ((%(type)s*)mit->dataptr)[0] + ((%(type)s*)it->dataptr)[0];"
complexadd = """
((%(type)s*)mit->dataptr)[0].real = ((%(type)s*)mit->dataptr)[0].real + ((%(type)s*)it->dataptr)[0].real;
((%(type)s*)mit->dataptr)[0].imag = ((%(type)s*)mit->dataptr)[0].imag + ((%(type)s*)it->dataptr)[0].imag;
"""
fns = ''.join([inplace_map_template % {'type': t, 'typen': t.upper(),
'op': floatadd % {'type': t}}
for t in types] +
[inplace_map_template % {'type': t, 'typen': t.upper(),
'op': complexadd % {'type': t}}
for t in complex_types])
fn_array = ("inplace_map_binop addition_funcs[] = {" +
''.join(["""
#if defined(%(typen)s)
%(type)s_inplace_add,
#endif
""" % {'type': t, 'typen': t.upper()}
for t in types + complex_types]) +
"""NULL};
""")
type_number_array = ("int type_numbers[] = {" +
''.join(["""
#if defined(%(typen)s)
%(typen)s,
#endif
""" % {'type': t, 'typen': t.upper()}
for t in types + complex_types]) +
"-1000};")
code = ("""
#include <Python.h> #include <Python.h>
#include "numpy/arrayobject.h"
extern "C"{ extern "C"{
static PyObject * static PyObject *
run_cthunk(PyObject *self, PyObject *args) run_cthunk(PyObject *self, PyObject *args)
...@@ -35,14 +95,130 @@ def compile_cutils(): ...@@ -35,14 +95,130 @@ def compile_cutils():
return Py_BuildValue("i", failure); return Py_BuildValue("i", failure);
} }
#if NPY_API_VERSION >= 0x00000008
typedef void (*inplace_map_binop)(PyArrayMapIterObject *, PyArrayIterObject *);
""" + fns + fn_array + type_number_array +
"""
static int
map_increment(PyArrayMapIterObject *mit, PyObject *op, inplace_map_binop add_inplace)
{
PyArrayObject *arr = NULL;
PyArrayIterObject *it;
PyArray_Descr *descr;
if (mit->ait == NULL) {
return -1;
}
descr = PyArray_DESCR(mit->ait->ao);
Py_INCREF(descr);
arr = (PyArrayObject *)PyArray_FromAny(op, descr,
0, 0, NPY_ARRAY_FORCECAST, NULL);
if (arr == NULL) {
return -1;
}
if ((mit->subspace != NULL) && (mit->consec)) {
if (mit->iteraxes[0] > 0) {
PyArray_MapIterSwapAxes(mit, (PyArrayObject **)&arr, 0);
if (arr == NULL) {
return -1;
}
}
}
it = (PyArrayIterObject*)
PyArray_BroadcastToShape((PyObject*)arr, mit->dimensions, mit->nd);
if (it == NULL) {
Py_DECREF(arr);
return -1;
}
(*add_inplace)(mit, it);
Py_DECREF(arr);
Py_DECREF(it);
return 0;
}
static PyObject *
inplace_increment(PyObject *dummy, PyObject *args)
{
PyObject *arg_a = NULL, *index=NULL, *inc=NULL;
PyArrayObject *a;
inplace_map_binop add_inplace = NULL;
int type_number = -1;
int i =0;
PyArrayMapIterObject * mit;
if (!PyArg_ParseTuple(args, "OOO", &arg_a, &index,
&inc)) {
return NULL;
}
if (!PyArray_Check(arg_a)) {
PyErr_SetString(PyExc_ValueError, "needs an ndarray as first argument");
return NULL;
}
a = (PyArrayObject *) arg_a;
if (PyArray_FailUnlessWriteable(a, "input/output array") < 0) {
return NULL;
}
if (PyArray_NDIM(a) == 0) {
PyErr_SetString(PyExc_IndexError, "0-d arrays can't be indexed.");
return NULL;
}
type_number = PyArray_TYPE(a);
while (type_numbers[i] >= 0 && addition_funcs[i] != NULL){
if (type_number == type_numbers[i]) {
add_inplace = addition_funcs[i];
break;
}
i++ ;
}
if (add_inplace == NULL) {
PyErr_SetString(PyExc_TypeError, "unsupported type for a");
return NULL;
}
mit = (PyArrayMapIterObject *) PyArray_MapIterArray(a, index);
if (mit == NULL) {
goto fail;
}
if (map_increment(mit, inc, add_inplace) != 0) {
goto fail;
}
Py_DECREF(mit);
Py_INCREF(Py_None);
return Py_None;
fail:
Py_XDECREF(mit);
return NULL;
}
#endif
static PyMethodDef CutilsExtMethods[] = { static PyMethodDef CutilsExtMethods[] = {
{"run_cthunk", run_cthunk, METH_VARARGS|METH_KEYWORDS, {"run_cthunk", run_cthunk, METH_VARARGS|METH_KEYWORDS,
"Run a theano cthunk."}, "Run a theano cthunk."},
#if NPY_API_VERSION >= 0x00000008
{"inplace_increment", inplace_increment,
METH_VARARGS,
"increments a numpy array inplace at the passed indexes."},
#endif
{NULL, NULL, 0, NULL} /* Sentinel */ {NULL, NULL, 0, NULL} /* Sentinel */
};""" };""")
if PY3: if PY3:
# This is not the most efficient code, but it is written this way to highlight # This is not the most efficient code, but it is written this way to
# the changes needed to make 2.x code compile under python 3. # highlight the changes needed to make 2.x code compile under python 3.
code = code.replace("<Python.h>", '"numpy/npy_3kcompat.h"', 1) code = code.replace("<Python.h>", '"numpy/npy_3kcompat.h"', 1)
code = code.replace("PyCObject", "NpyCapsule") code = code.replace("PyCObject", "NpyCapsule")
code += """ code += """
...@@ -59,15 +235,16 @@ def compile_cutils(): ...@@ -59,15 +235,16 @@ def compile_cutils():
return PyModule_Create(&moduledef); return PyModule_Create(&moduledef);
} }
} }
""" """
else: else:
code += """ code += """
PyMODINIT_FUNC PyMODINIT_FUNC
initcutils_ext(void) initcutils_ext(void)
{ {
import_array();
(void) Py_InitModule("cutils_ext", CutilsExtMethods); (void) Py_InitModule("cutils_ext", CutilsExtMethods);
} }
} } //extern C
""" """
loc = os.path.join(config.compiledir, 'cutils_ext') loc = os.path.join(config.compiledir, 'cutils_ext')
...@@ -95,8 +272,6 @@ try: ...@@ -95,8 +272,6 @@ try:
try: try:
from cutils_ext.cutils_ext import * from cutils_ext.cutils_ext import *
except ImportError: except ImportError:
import cmodule
get_lock() get_lock()
# Ensure no-one else is currently modifying the content of the compilation # Ensure no-one else is currently modifying the content of the compilation
# directory. This is important to prevent multiple processes from trying to # directory. This is important to prevent multiple processes from trying to
...@@ -108,7 +283,6 @@ try: ...@@ -108,7 +283,6 @@ try:
# and when we receive the lock # and when we receive the lock
from cutils_ext.cutils_ext import * from cutils_ext.cutils_ext import *
except ImportError: except ImportError:
import cmodule
compile_cutils() compile_cutils()
from cutils_ext.cutils_ext import * from cutils_ext.cutils_ext import *
......
...@@ -23,7 +23,8 @@ import numpy ...@@ -23,7 +23,8 @@ import numpy
import theano import theano
from theano.compat import PY3 from theano.compat import PY3
from theano import gof from theano import gof
from theano.gof import Op, utils, Variable, Constant, Type, Apply, FunctionGraph from theano.gof import (Op, utils, Variable, Constant, Type, Apply,
FunctionGraph)
from theano.gof.python25 import partial, all, any from theano.gof.python25 import partial, all, any
from theano.configparser import config from theano.configparser import config
...@@ -1090,7 +1091,7 @@ class UnaryBitOp(UnaryScalarOp): ...@@ -1090,7 +1091,7 @@ class UnaryBitOp(UnaryScalarOp):
return upcast_out(*input_types[0]) return upcast_out(*input_types[0])
def grad(self, inputs, output_gradients): def grad(self, inputs, output_gradients):
return [None] return [inputs[0].zeros_like().astype(theano.config.floatX)]
class BinaryBitOp(BinaryScalarOp): class BinaryBitOp(BinaryScalarOp):
...@@ -1103,7 +1104,8 @@ class BinaryBitOp(BinaryScalarOp): ...@@ -1103,7 +1104,8 @@ class BinaryBitOp(BinaryScalarOp):
return upcast_out(*input_types[0]) return upcast_out(*input_types[0])
def grad(self, inputs, output_gradients): def grad(self, inputs, output_gradients):
return [None, None] a,b = inputs
return [a.zeros_like().astype(theano.config.floatX), b.zeros_like().astype(theano.config.floatX)]
class OR(BinaryBitOp): class OR(BinaryBitOp):
...@@ -2679,7 +2681,7 @@ class Composite(ScalarOp): ...@@ -2679,7 +2681,7 @@ class Composite(ScalarOp):
except AttributeError: except AttributeError:
if 0: if 0:
l = [] l = []
for n in fgraph.toposort(): for n in self.fgraph.toposort():
if hasattr(n.op, "name") and n.op.name is not None: if hasattr(n.op, "name") and n.op.name is not None:
v = n.op.name v = n.op.name
if v.startswith("Composite"): if v.startswith("Composite"):
......
差异被折叠。
...@@ -37,13 +37,13 @@ from theano.tensor import (_shared, wvector, bvector, autocast_float_as, ...@@ -37,13 +37,13 @@ from theano.tensor import (_shared, wvector, bvector, autocast_float_as,
tensor_copy, tensordot, TensorType, Tri, tri, tril, triu, unbroadcast, tensor_copy, tensordot, TensorType, Tri, tri, tril, triu, unbroadcast,
var, Join, shape, MaxAndArgmax, lscalar, zvector, exp, var, Join, shape, MaxAndArgmax, lscalar, zvector, exp,
get_scalar_constant_value, ivector, reshape, scalar_from_tensor, scal, get_scalar_constant_value, ivector, reshape, scalar_from_tensor, scal,
iscalars, arange, dscalars, fvector, imatrix, numeric_grad, iscalars, arange, dscalars, fvector, imatrix, numeric_grad,
opt, ComplexError, lvector, lmatrix, true_div, max, min, Split, roll, opt, ComplexError, lvector, lmatrix, true_div, max, min, Split, roll,
tile, patternbroadcast, Eye, Shape, Dot, PermuteRowElements, tile, patternbroadcast, Eye, Shape, Dot, PermuteRowElements,
ScalarFromTensor, TensorFromScalar, dtensor4, Rebroadcast, Alloc, ScalarFromTensor, TensorFromScalar, dtensor4, Rebroadcast, Alloc,
dtensor3, SpecifyShape, Mean, IncSubtensor, AdvancedIncSubtensor1, dtensor3, SpecifyShape, Mean, IncSubtensor, AdvancedIncSubtensor1,
itensor3, Tile, AdvancedIncSubtensor, switch, Diagonal, Diag, itensor3, Tile, AdvancedIncSubtensor, switch, Diagonal, Diag,
nonzero, flatnonzero, nonzero_values) nonzero, flatnonzero, nonzero_values, inplace_increment)
from theano.tests import unittest_tools as utt from theano.tests import unittest_tools as utt
...@@ -3131,10 +3131,6 @@ class T_subtensor(unittest.TestCase, utt.TestOptimizationMixin): ...@@ -3131,10 +3131,6 @@ class T_subtensor(unittest.TestCase, utt.TestOptimizationMixin):
n = self.shared(numpy.asarray(5, dtype=self.dtype)) n = self.shared(numpy.asarray(5, dtype=self.dtype))
self.assertRaises(TypeError, n.__getitem__, [0, 0]) self.assertRaises(TypeError, n.__getitem__, [0, 0])
def test_err_invalid_not_2d(self):
n = self.shared(numpy.ones((3, 3, 3), dtype=self.dtype) * 5)
self.assertRaises(NotImplementedError, n.__getitem__,
([0, 0, 0], [1, 1, 1], [2, 2, 2]))
def test_err_invalid_2list_dtype(self): def test_err_invalid_2list_dtype(self):
n = self.shared(numpy.ones((3, 3), dtype=self.dtype) * 5) n = self.shared(numpy.ones((3, 3), dtype=self.dtype) * 5)
...@@ -3725,6 +3721,109 @@ class TestIncSubtensor1(unittest.TestCase): ...@@ -3725,6 +3721,109 @@ class TestIncSubtensor1(unittest.TestCase):
self.assertRaises(TypeError, self.assertRaises(TypeError,
lambda: inc_subtensor(self.v[self.adv1q], fmatrix())) lambda: inc_subtensor(self.v[self.adv1q], fmatrix()))
inplace_increment_missing = SkipTest("inc_subtensor with advanced indexing not enabled. "
"Installing NumPy 1.8 or the latest development version "
"should make that feature available.")
class TestAdvancedSubtensor(unittest.TestCase):
# test inc_subtensor
# also tests set_subtensor
def setUp(self):
self.s = iscalar()
self.v = fvector()
self.m = dmatrix()
self.t = ctensor3()
self.ix1 = lvector() # advanced 1d query
self.ix12 = lvector()
self.ix2 = lmatrix()
def test_cant_adv_idx_into_scalar(self):
self.assertRaises(TypeError, lambda: self.s[self.ix1])
def test_index_into_vec_w_vec(self):
a = self.v[self.ix1]
assert a.type == self.v.type, (a.type, self.v.type)
def test_index_into_vec_w_matrix(self):
a = self.v[self.ix2]
assert a.dtype == self.v.dtype, (a.dtype, self.v.dtype)
assert a.broadcastable == self.ix2.broadcastable, (
a.broadcastable, self.ix2.broadcastable)
def test_inc_adv_subtensor_w_matrix(self):
if inplace_increment is None:
raise inplace_increment_missing
subt = self.v[self.ix2]
a = inc_subtensor(subt,subt)
assert a.type == self.v.type, (a.type, self.v.type)
f = theano.function([self.v, self.ix2], a, allow_input_downcast=True)
aval = f([.4, .9, .1], [[1, 2],
[1, 2]])
assert numpy.allclose(aval, [.4, .9 * 3, .1 * 3])
def test_inc_adv_subtensor_w_2vec(self):
if inplace_increment is None:
raise inplace_increment_missing
subt = self.m[self.ix1, self.ix12]
a = inc_subtensor(subt, subt)
typ = TensorType(self.m.type.dtype, self.ix2.type.broadcastable)
assert a.type == typ, (a.type, typ)
f = theano.function([self.m, self.ix1, self.ix12], a,
allow_input_downcast=True)
aval = f([[.4, .9, .1],
[5, 6, 7],
[.5, .3, .15]],
[1, 2, 1],
[0, 1, 0])
assert numpy.allclose(aval,
[[.4, .9, .1],
[5 * 3, 6, 7],
[.5, .3 * 2, .15]]), aval
def test_inc_adv_subtensor_with_broadcasting(self):
if inplace_increment is None:
raise inplace_increment_missing
a = inc_subtensor(self.m[self.ix1, self.ix12], 2.1)
assert a.type == self.m.type, (a.type, self.m.type)
f = theano.function([self.m, self.ix1, self.ix12], a,
allow_input_downcast=True)
aval = f([[.4, .9, .1],
[5, 6, 7],
[.5, .3, .15]],
[1, 2, 1],
[0, 1, 0])
assert numpy.allclose(aval,
[[.4, .9, .1],
[5 + 2.1 * 2, 6, 7],
[.5, .3 + 2.1, .15]]), aval
def test_inc_adv_subtensor_with_index_broadcasting(self):
if inplace_increment is None:
raise inplace_increment_missing
a = inc_subtensor(self.m[self.ix1, self.ix2], 2.1)
assert a.type == self.m.type, (a.type, self.m.type)
f = theano.function([self.m, self.ix1, self.ix2], a,
allow_input_downcast=True)
aval = f([[.4, .9, .1],
[5, 6, 7],
[.5, .3, .15]],
[0, 2, 0],
[[0, 1, 0],
[2, 2, 2]])
assert numpy.allclose(aval,
[[.4 + 2*2.1, .9, .1 + 2*2.1],
[5 , 6, 7 ],
[.5, .3 + 2.1, .15 + 2.1]]), aval
class T_Join_and_Split(unittest.TestCase): class T_Join_and_Split(unittest.TestCase):
""" """
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论