提交 f005cc21 authored 作者: Arnaud Bergeron's avatar Arnaud Bergeron

Add a bunch of documentation to gpuarray/type.py

上级 418967de
......@@ -67,6 +67,7 @@ def get_context(name):
def list_contexts():
"""
Return an iterable of all the registered context names.
"""
return _context_reg.keys()
......@@ -85,6 +86,50 @@ def _unreg_context(name):
class GpuArrayType(Type):
"""
The type that represents an array on a gpu.
The `dtype` indicates what scalar data type the elements of
variables of this type will be.
`broadcastable` indicates whether each dimension is broadcastable
or not (to be broadcastable a dimension must always be of length
1).
The `context_name` is the name of the context on will values of
variables of this type will be stored.
Parameters
----------
dtype : str
The name of a numpy dtype
broadcastable : tuple of bools
A tuple that indicates both the number of dimensions (by its
length) and whether those dimensions are broadcastable or not
(by the boolean values).
context_name : str
The name of the context the that this type is attached to
(default: None, which is the context specified by
config.device).
name : string, optional
A name for the type that will be used in printouts.
Attributes
----------
dtype : str
Data type used for scalar elements of variables.
broadcastable : tuple of bools
Indicates whether the dimensions are broadcastable or not.
ndim : int
The number of dimensions
context_name : str
The name of a gpu context on which variables will have their values.
name : str
A string used to print the type if given.
typecode : int
The gpuarray typecode for `dtype`
"""
def __init__(self, dtype, broadcastable, context_name=None, name=None):
# In case this was not provided and no global value is available
self.dtype = str(dtype)
......@@ -101,6 +146,21 @@ class GpuArrayType(Type):
(self.__class__.__name__, self.dtype))
def clone(self, dtype=None, broadcastable=None):
"""
Returns a copy of this type, possibly with some changed attributes.
The returned type will have all the same attributes as this
one with the possible exception of `dtype` and `broadcastable`
which will respect the passed-in values if given.
Parameters
----------
dtype : str, optional
scalar data type for the returned type.
broadcastable : tuple of bools
broadcastable pattern for the returned type.
"""
if dtype is None:
dtype = self.dtype
if broadcastable is None:
......@@ -111,6 +171,11 @@ class GpuArrayType(Type):
# This is a property to keep the type pickleable
@property
def context(self):
"""
The context object mapped to the type's :attr:`context_name`.
This is a property.
"""
return get_context(self.context_name)
def __repr__(self):
......@@ -118,6 +183,31 @@ class GpuArrayType(Type):
self.broadcastable)
def filter(self, data, strict=False, allow_downcast=None):
"""
Return a GpuArray compatible with this type or raise a TypeError.
When `strict` is `True` the data must exactly match the
specifications of this type and no conversions will be
performed.
If `strict` is `False` the data will be transferred or
converted as neede so long as it does not cause a downcast of
the values.
To allow a downcast (which may lose precision),
`allow_downcast` should be set to `True`.
Parameters
----------
data
Some data to be converted.
strict : bool, optional
Whether to check in strict mode or not. (default: False)
allow_downcast : bool, optional
Allow the downcasting of `data`, which may lose
precision. (default: False)
"""
if (isinstance(data, gpuarray.GpuArray) and
data.typecode == self.typecode):
# This is just to make this condition not enter the
......@@ -171,6 +261,31 @@ class GpuArrayType(Type):
return data
def filter_variable(self, other, allow_convert=True):
"""
Make a variable of this type out of `other` or raise TypeError.
Make a series of checks to make sure that the passed-in
variable is compatible with this type.
Will attempt some limited conversions (like from CPU to GPU) as
long as no major changes (ndim, dtype, ...) are required.
If present, a method nameed :meth:`_as_GpuArrayVariable` will
be called with the target context name to produce a variable
in the appropriate context. The rest of the checks will
proceed with the returned object.
If passed numerical data it will create a theano `Constant`
object out of it assuming that other paramters match.
Parameters
----------
other : object
Usually a theano variable, but can be some data also.
allow_convert : bool
Allows (safe) conversion of broadcastable pattern (default: True)
"""
from theano.sandbox.gpuarray import GpuFromHost
if hasattr(other, '_as_GpuArrayVariable'):
......@@ -207,6 +322,13 @@ class GpuArrayType(Type):
@staticmethod
def values_eq(a, b):
"""
Returns `True` if `a` and `b` are equal.
This will only work correctly for values which would pass
:meth:`filter` for any instance of this type.
"""
if a.shape != b.shape:
return False
if a.typecode != b.typecode:
......@@ -230,6 +352,35 @@ class GpuArrayType(Type):
def values_eq_approx(a, b,
allow_remove_inf=False, allow_remove_nan=False,
rtol=None, atol=None):
"""
Return `True` if `a` and `b` are approximately equal.
Parameters
----------
a : object
b : object
allow_remove_inf : bool
If `True` an inf (or -inf) in `a` will be considered equal
to any value in `b`.
allow_remove_nan : bool
If `True` an nan in `a` will be considered equal to any
value in `b`.
rtol : float
Relative tolerance for the comparison (see Notes)
atol : float
Absolute tolerance for the comparison (see Notes)
Notes
-----
This is the element-wise operation used to verify approximate
equality::
absolute(a - b) <= (atol + rtol * absolute(b))
If it returns all Trues, then the result is True.
"""
if a.shape != b.shape or a.dtype != b.dtype:
return False
if 'int' in str(a.dtype):
......@@ -266,16 +417,53 @@ class GpuArrayType(Type):
@staticmethod
def may_share_memory(a, b):
"""
Returns `True` if `a` and `b` might have some memory areas in common.
Parameters
----------
a
A value
b
A value
Notes
-----
This is not 100% accurate and may give some false positve, but
is still a good indicator.
"""
if (not isinstance(a, gpuarray.GpuArray) or
not isinstance(b, gpuarray.GpuArray)):
return False
return pygpu.gpuarray.may_share_memory(a, b)
def value_zeros(self, shape):
"""
Return a value of `shape` filled with zeros.
The returned value will have the dtype and context of this
type. This does not check that the shape is consistent with
:attr:`broadcastable` or :attr:`ndim`.
Parameters
----------
shape : tuple of ints
The shape of the return value
"""
return pygpu.gpuarray.zeros(shape, dtype=self.typecode,
context=self.context)
def make_variable(self, name=None):
"""
Create a variable with this type.
Parameters
----------
name : str, optional
The name of the returned variable.
"""
return self.Variable(self, name=name)
def __eq__(self, other):
......@@ -285,6 +473,21 @@ class GpuArrayType(Type):
self.context_name == other.context_name)
def convert_variable(self, var):
"""
Convert a variable to this type if the conditions match.
This will return a new variable with this type if the
following implication holds true for all `val`::
self.is_valid_valud(val) => var.type.is_valid_value(val)
If that can't be satisfied, it returns None.
Parameters
----------
var
Variable to convert.
"""
vt = var.type
if (type(self) == type(vt) and
self.typecode == vt.typecode and
......@@ -306,8 +509,6 @@ class GpuArrayType(Type):
This function is used internally as part of C code generation.
"""
# TODO: add more type correspondances for e.g. int32, int64, float32,
# complex64, etc.
try:
return {
'float16': (float, 'npy_float16', 'NPY_FLOAT16'),
......@@ -321,17 +522,33 @@ class GpuArrayType(Type):
'int32': (int, 'npy_int32', 'NPY_INT32'),
'uint64': (int, 'npy_uint64', 'NPY_UINT64'),
'int64': (int, 'npy_int64', 'NPY_INT64'),
'complex128': (complex, 'theano_complex128', 'NPY_COMPLEX128'),
'complex64': (complex, 'theano_complex64', 'NPY_COMPLEX64')
#'complex128': (complex, 'theano_complex128', 'NPY_COMPLEX128'),
#'complex64': (complex, 'theano_complex64', 'NPY_COMPLEX64')
}[self.dtype]
except KeyError:
raise TypeError("Unsupported dtype for %s: %s" %
(self.__class__.__name__, self.dtype))
def get_shape_info(self, obj):
"""
Return the shape of a value for this type.
Parameters
----------
obj : object
Something that would pass :meth:`is_valid_value`.
"""
return obj.shape
def get_size(self, shape_info):
"""
Return the size (in bytes) of an object of the given shape.
Parameters
----------
shape_info : tuple of ints
The shape to get the size for.
"""
if shape_info:
return numpy.prod(shape_info) * numpy.dtype(self.dtype).itemsize
else:
......@@ -420,10 +637,21 @@ class _operators(_tensor_py_operators):
class GpuArrayVariable(_operators, Variable):
"""
A variable representing a computation on a certain GPU.
This supports all the operations that :class:`TensorType`
supports.
See Also
--------
Variable
"""
# override the default
def __repr_test_value__(self):
return repr(numpy.array(theano.gof.op.get_test_value(self)))
pass
GpuArrayType.Variable = GpuArrayVariable
......@@ -436,6 +664,17 @@ class GpuArraySignature(tensor.TensorConstantSignature):
class GpuArrayConstant(_operators, Constant):
"""
A constant representing a value on a certain GPU.
This supports all the operations that :class:`TensorType`
supports.
See Also
--------
Constant
"""
def signature(self):
return GpuArraySignature((self.type, numpy.asarray(self.data)))
......@@ -453,6 +692,17 @@ GpuArrayType.Constant = GpuArrayConstant
class GpuArraySharedVariable(_operators, SharedVariable):
"""
A variable representing a shared value on a certain GPU.
This supports all the operations that :class:`TensorType`
supports.
See Also
--------
SharedVariable
"""
def get_value(self, borrow=False, return_internal_type=False):
if return_internal_type:
if borrow:
......@@ -481,6 +731,8 @@ def gpuarray_shared_constructor(value, name=None, strict=False,
"""
SharedVariable constructor for GpuArrayType.
See :func:`theano.shared`.
"""
if target == 'gpu' or target == 'cpu':
raise TypeError('not for me')
......@@ -596,6 +848,13 @@ theano.compile.register_specify_shape_c_code(
class GpuContextType(Type):
"""
Minimal type used for passing contexts to nodes.
This Type is not a complete type and should never be used for
regular graph operations.
"""
def filter(self, data, strict=False, allow_downcast=None):
if not isinstance(data, gpuarray.GpuContext):
raise TypeError('context is not a GpuContext')
......@@ -652,4 +911,8 @@ Py_INCREF(%(name)s);
# Variable, Contstant, ... not declared
"""
Instance of :class:`GpuContextType` to use for the context_type
declaration of an operation.
"""
gpu_context_type = GpuContextType()
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论