提交 cc3b43d9 authored 作者: bergstrj@lgcm's avatar bergstrj@lgcm

added docs, gen_op_list

上级 a8242ddf
import gof
import tensor
def isOp(thing):
return hasattr(thing, 'perform')
for module in [tensor]:
title = 'Ops in module: `%s`' % module.__name__
print title
print '-' * len(title)
for symbol_name in dir(module):
symbol = getattr(module, symbol_name)
if isOp(symbol):
print ""
print "- `%s.%s`" % (module.__name__, symbol_name)
"""A L{Result} to store L{numpy.ndarray} with basic accompanying L{Op}s""" """A `Type` and `Op` classes to work with numpy.ndarrays symbolically."""
__docformat__ = "restructuredtext en"
import sys # for sys.maxint import sys # for sys.maxint
import inspect import inspect
import functools import functools
...@@ -24,7 +27,27 @@ import tensor_random as random ...@@ -24,7 +27,27 @@ import tensor_random as random
def as_tensor(x, name = None): def as_tensor(x, name = None):
"""Return `x`, transformed into a `Tensor`
This function is often used by `make_node` methods of `Op` subclasses to
turn ndarrays, numbers, `Scalar` instances, `Apply` instances and `Tensor`
instances into valid input list elemnts.
:Parameters:
- `x`: Apply instance, Result instance, numpy.ndarray, or number
This thing will be transformed into a `Result` in a sensible way. An
ndarray argument will not be copied, but a list of numbers will be copied
to make an ndarray.
- `name`: str or None
If a new `Result` instance is created, it will be named with this string.
:Exceptions:
- `ValueError`: raised if an `Apply` with no default output is fetched
- `TypeError`: raised if `x` cannot be converted to a Tensor Result
"""
if isinstance(x, gof.Apply): if isinstance(x, gof.Apply):
#TODO: use Apply's default output mechanism
if len(x.outputs) != 1: if len(x.outputs) != 1:
raise ValueError("It is ambiguous which output of a multi-output Op has to be fetched.", x) raise ValueError("It is ambiguous which output of a multi-output Op has to be fetched.", x)
else: else:
...@@ -39,56 +62,74 @@ def as_tensor(x, name = None): ...@@ -39,56 +62,74 @@ def as_tensor(x, name = None):
return constant(x) return constant(x)
except TypeError: except TypeError:
raise TypeError("Cannot convert %s to Tensor" % x, type(x)) raise TypeError("Cannot convert %s to Tensor" % x, type(x))
# this has a different name, because _as_tensor is the function which ops use # this has a different name, because _as_tensor is the function which ops use
# to upcast their arguments... this internal-use function is a good place to put debugging stuff, better than the global astensor. # to upcast their arguments... this internal-use function is a good place to put debugging stuff, better than the global astensor.
_as_tensor = as_tensor _as_tensor = as_tensor
def constant(_x): def constant(x):
if not isinstance(_x, numpy.ndarray): """Return a symbolic `Constant` with value `x`
x = numpy.asarray(_x)
:Exceptions:
- `TypeError`: `x` could not be converted to a numpy.ndarray
"""
if isinstance(x, numpy.ndarray):
x_ = x
else: else:
x = _x x_ = numpy.asarray(x)
try: try:
return TensorConstant(Tensor(dtype = x.dtype, return TensorConstant(Tensor(dtype = x_.dtype,
broadcastable = [d == 1 for d in x.shape]), x) broadcastable = [d == 1 for d in x_.shape]), x_)
except: except:
raise TypeError("Could not convert %s to Tensor" % _x, type(_x)) raise TypeError("Could not convert %s to Tensor" % x, type(x))
def value(x): def value(x):
if not isinstance(x, numpy.ndarray): """Return a symbolic `Value` with default value `x`
x = numpy.asarray(x)
:Exceptions:
- `TypeError`: `x` could not be converted to a numpy.ndarray
"""
if isinstance(x, numpy.ndarray):
x_ = x
else:
x_ = numpy.asarray(x)
try: try:
return TensorValue(Tensor(dtype = x.dtype, return TensorValue(Tensor(dtype = x_.dtype,
broadcastable = [d == 1 for d in x.shape]), x) broadcastable = [d == 1 for d in x_.shape]), x_)
except: except:
raise TypeError("Could not convert %s to Tensor" % _x, type(_x)) raise TypeError("Could not convert %s to Tensor" % x, type(x))
class Tensor(Type): class Tensor(Type):
""" """Symbolic `Type` representing a numpy.ndarray value."""
L{Type} representing L{numpy.ndarray} in Theano.
@todo: At some point we should document a glossary, such as terms like
broadcasting and shape.
@type dtype: numpy dtype string such as 'int64' or 'float64' (among others)
@type broadcastable: tuple or list or array of boolean values, whose length
is the number of dimensions of the L{ndarray} represented by this Type.
@ivar broadcastable: Each element of the broadcastable vector tells us
something about the corresponding dimension:
- False means the dimension can be anything.
- True means the dimension must be 1. Also, this dimension will be considered
for L{broadcasting}, as described and implemented in Numpy.
"""
def __init__(self, dtype, broadcastable): def __init__(self, dtype, broadcastable):
"""Initialize self.dtype and self.broadcastable.
:Parameters:
- `dtype`: str corresponding to numpy dtype (e.g., 'int64')
The value (ndarray) associated to a `Result` of this `Type` will have
this dtype.
- `broadcastable`: tuple, list, or array of boolean values
This argument serves two purposes. First, the True elements of this
list indicate the dimensions where the shape of an associated value
must be 1. Secondly, the length of this list is the number of
dimensions that an associated value must have. See
:doc:`broadcasting` for an explanation of how this list is used.
"""
self.dtype = str(dtype) self.dtype = str(dtype)
self.broadcastable = tuple(broadcastable) self.broadcastable = tuple(broadcastable)
self.dtype_specs() # error checking is done there self.dtype_specs() # error checking is done there
def filter(self, data, strict = False): def filter(self, data, strict = False):
"""Convert `data` to something which can be associated to a `TensorResult`.
This function is not meant to be called in user code. It is for
`Linker` instances to use when running a compiled graph.
"""
_data = data _data = data
if strict: if strict:
if not isinstance(data, numpy.ndarray): if not isinstance(data, numpy.ndarray):
...@@ -107,10 +148,10 @@ class Tensor(Type): ...@@ -107,10 +148,10 @@ class Tensor(Type):
return data return data
def dtype_specs(self): def dtype_specs(self):
"""Return python - C type correspondance tuple for self.data """Return a tuple (python type, c type, numpy typenum) that corresponds to
self.dtype.
Return a tuple (python type, c type, numpy typenum) that corresponds to This function is used internally as part of C code generation.
L{self.dtype}. It is for use in C code generation.
""" """
#TODO: add more type correspondances for e.g. int32, int64, float32, #TODO: add more type correspondances for e.g. int32, int64, float32,
#complex64, etc. #complex64, etc.
...@@ -131,14 +172,23 @@ class Tensor(Type): ...@@ -131,14 +172,23 @@ class Tensor(Type):
raise TypeError("Unsupported dtype for %s: %s" % (self.__class__.__name__, self.dtype)) raise TypeError("Unsupported dtype for %s: %s" % (self.__class__.__name__, self.dtype))
def __eq__(self, other): def __eq__(self, other):
"""Compare True iff other is the same kind of Tensor"""
return type(self) == type(other) and other.dtype == self.dtype and other.broadcastable == self.broadcastable return type(self) == type(other) and other.dtype == self.dtype and other.broadcastable == self.broadcastable
def __hash__(self): def __hash__(self):
"""Hash equal for same kinds of Tensor"""
return hash(self.dtype) ^ hash(self.broadcastable) return hash(self.dtype) ^ hash(self.broadcastable)
ndim = property(lambda self: len(self.broadcastable), doc = "read-only access to the number of dimensions") # this read-only property is the preferred way to get the number of
# dimensions
ndim = property(lambda self: len(self.broadcastable), doc = "number of dimensions")
def make_result(self, name = None): def make_result(self, name = None):
"""Return a `TensorResult` of this type
:Parameters:
- `name`: str
A pretty name to identify this `Result` when printing and debugging
"""
return TensorResult(self, name = name) return TensorResult(self, name = name)
def __str__(self): def __str__(self):
...@@ -148,6 +198,7 @@ class Tensor(Type): ...@@ -148,6 +198,7 @@ class Tensor(Type):
return "Tensor{%s, %s}" % (str(self.dtype), str(self.broadcastable)) return "Tensor{%s, %s}" % (str(self.dtype), str(self.broadcastable))
def c_declare(self, name, sub): def c_declare(self, name, sub):
"""Override `CLinkerOp.c_declare` """
return """ return """
PyArrayObject* %(name)s; PyArrayObject* %(name)s;
int type_num_%(name)s; int type_num_%(name)s;
...@@ -155,12 +206,14 @@ class Tensor(Type): ...@@ -155,12 +206,14 @@ class Tensor(Type):
""" % dict(sub, name = name, dtype = self.dtype_specs()[1]) """ % dict(sub, name = name, dtype = self.dtype_specs()[1])
def c_init(self, name, sub): def c_init(self, name, sub):
"""Override `CLinkerOp.c_init` """
return """ return """
%(name)s = NULL; %(name)s = NULL;
type_num_%(name)s = %(type_num)s; type_num_%(name)s = %(type_num)s;
""" % dict(sub, name = name, type_num = self.dtype_specs()[2]) """ % dict(sub, name = name, type_num = self.dtype_specs()[2])
def c_extract(self, name, sub): def c_extract(self, name, sub):
"""Override `CLinkerOp.c_extract` """
return """ return """
%(name)s = NULL; %(name)s = NULL;
type_num_%(name)s = %(type_num)s; type_num_%(name)s = %(type_num)s;
...@@ -186,6 +239,7 @@ class Tensor(Type): ...@@ -186,6 +239,7 @@ class Tensor(Type):
""" % dict(sub, name = name, type_num = self.dtype_specs()[2]) """ % dict(sub, name = name, type_num = self.dtype_specs()[2])
def c_cleanup(self, name, sub): def c_cleanup(self, name, sub):
"""Override `CLinkerOp.c_cleanup` """
return """ return """
if (%(name)s) { if (%(name)s) {
Py_XDECREF(%(name)s); Py_XDECREF(%(name)s);
...@@ -193,6 +247,7 @@ class Tensor(Type): ...@@ -193,6 +247,7 @@ class Tensor(Type):
""" % locals() """ % locals()
def c_sync(self, name, sub): def c_sync(self, name, sub):
"""Override `CLinkerOp.c_sync` """
return """ return """
Py_XDECREF(py_%(name)s); Py_XDECREF(py_%(name)s);
if (!%(name)s) { if (!%(name)s) {
...@@ -205,12 +260,14 @@ class Tensor(Type): ...@@ -205,12 +260,14 @@ class Tensor(Type):
""" % locals() """ % locals()
def c_headers(self): def c_headers(self):
"""Override `CLinkerOp.c_headers` """
return [] return []
def c_libraries(self): def c_libraries(self):
return [] return []
def c_support_code(cls): def c_support_code(cls):
"""Override `CLinkerOp.c_support_code` """
template = """ template = """
struct theano_complex%(nbits)s : public npy_complex%(nbits)s struct theano_complex%(nbits)s : public npy_complex%(nbits)s
{ {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论