提交 f98e8f99 authored 作者: notoraptor's avatar notoraptor

Fix typo.

Convert CPU DimShuffle to a COp and add a __setstate__(). And add a placeholder in GPU verion to prevent COp errors.
上级 3f3cdb9a
#section support_code_apply
int cpu_dimshuffle(PyArrayObject* input, PyArrayObject** res, PARAMS_TYPE* params) {
npy_bool* input_broadcastable;
npy_int64* new_order;
npy_intp nd_in;
npy_intp nd_out;
PyArrayObject* basename;
npy_intp* dimensions;
npy_intp* strides;
if (!PyArray_IS_C_CONTIGUOUS(params->input_broadcastable)) {
PyErr_SetString(PyExc_RuntimeError, "DimShuffle: param input_broadcastable must be C-contiguous.");
return 1;
}
if (!PyArray_IS_C_CONTIGUOUS(params->_new_order)) {
PyErr_SetString(PyExc_RuntimeError, "DimShuffle: param _new_order must be C-contiguous.");
return 1;
}
input_broadcastable = (npy_bool*) PyArray_DATA(params->input_broadcastable);
new_order = (npy_int64*) PyArray_DATA(params->_new_order);
nd_in = PyArray_SIZE(params->input_broadcastable);
nd_out = PyArray_SIZE(params->_new_order);
/* check_input_nd */
if (PyArray_NDIM(input) != nd_in) {
PyErr_SetString(PyExc_NotImplementedError, "input nd");
return 1;
}
/* clear_output */
if (*res)
Py_XDECREF(*res);
/* get_base */
if (params->inplace) {
basename = input;
Py_INCREF((PyObject*)basename);
} else {
basename =
(PyArrayObject*)PyArray_FromAny((PyObject*)input,
NULL, 0, 0, NPY_ARRAY_ALIGNED|NPY_ARRAY_ENSURECOPY, NULL);
}
/* shape_statements and strides_statements */
dimensions = (npy_intp*) malloc(nd_out * sizeof(npy_intp));
strides = (npy_intp*) malloc(nd_out * sizeof(npy_intp));
if (dimensions == NULL || strides == NULL) {
PyErr_NoMemory();
free(dimensions);
free(strides);
return 1;
};
for (npy_intp i = 0; i < nd_out; ++i) {
if (new_order[i] != -1) {
dimensions[i] = PyArray_DIMS(basename)[new_order[i]];
strides[i] = PyArray_DIMS(basename)[new_order[i]] == 1 ?
0 : PyArray_STRIDES(basename)[new_order[i]];
} else {
dimensions[i] = 1;
strides[i] = 0;
}
}
/* set the strides of the broadcasted dimensions.
* This algorithm is from numpy: PyArray_Newshape() in
* cvs/numpy/numpy/core/src/multiarraymodule.c */
if (nd_out > 0) {
if (strides[nd_out - 1] == 0)
strides[nd_out - 1] = PyArray_DESCR(basename)->elsize;
for (npy_intp i = nd_out - 2; i > -1; --i) {
if (strides[i] == 0)
strides[i] = strides[i + 1] * dimensions[i + 1];
}
}
/* close_bracket */
// create a new array.
*res = (PyArrayObject*)PyArray_New(&PyArray_Type, nd_out, dimensions,
PyArray_TYPE(basename), strides,
PyArray_DATA(basename), PyArray_ITEMSIZE(basename),
// borrow only the writable flag from the base
// the NPY_OWNDATA flag will default to 0.
(NPY_ARRAY_WRITEABLE * PyArray_ISWRITEABLE(basename)),
NULL);
if (*res == NULL) {
free(dimensions);
free(strides);
return 1;
}
// recalculate flags: CONTIGUOUS, FORTRAN, ALIGNED
PyArray_UpdateFlags(*res, NPY_ARRAY_UPDATE_ALL);
// we are making a view in both inplace and non-inplace cases
PyArray_SetBaseObject(*res, (PyObject*)basename);
free(strides);
free(dimensions);
return 0;
}
......@@ -9,7 +9,7 @@ import theano
from theano import gof
from theano.compat import izip
from theano.configparser import change_flags
from theano.gof import Apply, Op, OpenMPOp, ParamsType
from theano.gof import Apply, Op, COp, OpenMPOp, ParamsType
from theano import scalar
from theano.scalar import get_scalar_type
from theano.printing import pprint
......@@ -50,7 +50,7 @@ def TensorConstant(*inputs, **kwargs):
# DimShuffle #
##################
class DimShuffle(Op):
class DimShuffle(COp):
"""
Allows to reorder the dimensions of a tensor or insert or remove
broadcastable dimensions.
......@@ -130,6 +130,8 @@ class DimShuffle(Op):
_f16_ok = True
check_input = False
__props__ = ("input_broadcastable", "new_order", "inplace")
c_func_file = 'c_code/dimshuffle.c'
c_func_name = 'cpu_dimshuffle'
@property
def params_type(self):
......@@ -147,6 +149,7 @@ class DimShuffle(Op):
return [(-1 if x == 'x' else x) for x in self.new_order]
def __init__(self, input_broadcastable, new_order, inplace=True):
COp.__init__(self, [self.c_func_file], self.c_func_name)
self.input_broadcastable = tuple(input_broadcastable)
self.new_order = tuple(new_order)
if inplace is True:
......@@ -198,6 +201,15 @@ class DimShuffle(Op):
if self.inplace:
self.view_map = {0: [0]}
def __setstate__(self, state):
self.__dict__.update(state)
if not hasattr(self, 'func_files'):
# Perhaps we are loading an old `Op` version of DimShuffle.
# Let's just build the COp.
self.c_func_file = 'c_code/dimshuffle.c'
self.c_func_name = 'cpu_dimshuffle'
COp.__init__(self, [self.c_func_file], self.c_func_name)
def make_node(self, _input):
input = as_tensor_variable(_input)
ib = tuple(input.type.broadcastable)
......@@ -273,119 +285,6 @@ class DimShuffle(Op):
return [None]
return self(*eval_points, **dict(return_list=True))
def c_code(self, node, name, inp, out, sub):
input, = inp
res, = out
basename = input + '__view_or_copy'
return """{
npy_bool* input_broadcastable;
npy_int64* new_order;
npy_intp nd_in;
npy_intp nd_out;
PyArrayObject* %(basename)s;
npy_intp* dimensions;
npy_intp* strides;
if (!PyArray_IS_C_CONTIGUOUS(%(params)s->input_broadcastable)) {
PyErr_SetString(PyExc_RuntimeError, "DimShuffle: param input_broadcastable must be C-contiguous.");
%(just_fail)s
}
if (!PyArray_IS_F_CONTIGUOUS(%(params)s->_new_order)) {
PyErr_SetString(PyExc_RuntimeError, "DimShuffle: param _new_order must be C-contiguous.");
%(just_fail)s
}
input_broadcastable = (npy_bool*) PyArray_DATA(%(params)s->input_broadcastable);
new_order = (npy_int64*) PyArray_DATA(%(params)s->_new_order);
nd_in = PyArray_SIZE(%(params)s->input_broadcastable);
nd_out = PyArray_SIZE(%(params)s->_new_order);
/* check_input_nd */
if (PyArray_NDIM(%(input)s) != nd_in) {
PyErr_SetString(PyExc_NotImplementedError, "input nd");
%(just_fail)s
}
/* clear_output */
if (%(res)s)
Py_XDECREF(%(res)s);
/* get_base */
if (%(params)s->inplace) {
%(basename)s = %(input)s;
Py_INCREF((PyObject*)%(basename)s);
} else {
%(basename)s =
(PyArrayObject*)PyArray_FromAny((PyObject*)%(input)s,
NULL, 0, 0, NPY_ARRAY_ALIGNED|NPY_ARRAY_ENSURECOPY, NULL);
}
/* shape_statements and strides_statements */
dimensions = (npy_intp*) malloc(nd_out * sizeof(npy_intp));
strides = (npy_intp*) malloc(nd_out * sizeof(npy_intp));
if (dimensions == NULL || strides == NULL) {
PyErr_NoMemory();
%(fail)s
};
for (npy_intp i = 0; i < nd_out; ++i) {
if (new_order[i] != -1) {
dimensions[i] = PyArray_DIMS(%(basename)s)[new_order[i]];
strides[i] = PyArray_DIMS(%(basename)s)[new_order[i]] == 1 ?
0 : PyArray_STRIDES(%(basename)s)[new_order[i]];
} else {
dimensions[i] = 1;
strides[i] = 0;
}
}
/* set the strides of the broadcasted dimensions.
* This algorithm is from numpy: PyArray_Newshape() in
* cvs/numpy/numpy/core/src/multiarraymodule.c */
if (nd_out > 0) {
if (strides[nd_out - 1] == 0)
strides[nd_out - 1] = PyArray_DESCR(%(basename)s)->elsize;
for (npy_intp i = nd_out - 2; i > -1; --i) {
if (strides[i] == 0)
strides[i] = strides[i + 1] * dimensions[i + 1];
}
}
/* close_bracket */
// create a new array.
%(res)s = (PyArrayObject*)PyArray_New(&PyArray_Type, nd_out, dimensions,
PyArray_TYPE(%(basename)s), strides,
PyArray_DATA(%(basename)s), PyArray_ITEMSIZE(%(basename)s),
// borrow only the writable flag from the base
// the NPY_OWNDATA flag will default to 0.
(NPY_ARRAY_WRITEABLE * PyArray_ISWRITEABLE(%(basename)s)),
NULL);
if (%(res)s == NULL) {
%(fail)s
}
// recalculate flags: CONTIGUOUS, FORTRAN, ALIGNED
PyArray_UpdateFlags(%(res)s, NPY_ARRAY_UPDATE_ALL);
// we are making a view in both inplace and non-inplace cases
PyArray_SetBaseObject(%(res)s, (PyObject*)%(basename)s);
free(strides);
free(dimensions);
}""" % dict(input=input, res=res,
basename=basename,
params=sub['params'],
just_fail=sub['fail'],
fail="""
free(strides);
free(dimensions);
%(fail)s
""" % dict(fail=sub['fail']))
def c_code_cache_version(self):
return (4,)
def grad(self, inp, grads):
x, = inp
gz, = grads
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论