提交 d0d64720 authored 作者: Reyhane Askari's avatar Reyhane Askari

removed centralized caching with metaclass (to keep it as history)

上级 63306840
from __future__ import absolute_import, print_function, division from __future__ import absolute_import, print_function, division
import theano import theano
from theano.gof.utils import CacheClass
from theano.gof.utils import ( from theano.gof.utils import (
give_variables_names, remove, unique) give_variables_names, remove, unique)
...@@ -62,17 +61,3 @@ def test_stack_trace(): ...@@ -62,17 +61,3 @@ def test_stack_trace():
assert len(v.tag.trace[0]) == 2 assert len(v.tag.trace[0]) == 2
finally: finally:
theano.config.traceback.limit = orig theano.config.traceback.limit = orig
class CachingClassExample(CacheClass, theano.Op):
__props__ = ('value',)
__cache_instance__ = True
def __init__(self, value):
self.value = value
def test_caching():
obj_1 = CachingClassExample(3)
obj_2 = CachingClassExample(3)
assert obj_1 is obj_2
...@@ -386,6 +386,9 @@ if run_memory_usage_tests: ...@@ -386,6 +386,9 @@ if run_memory_usage_tests:
class RunOnce(theano.Op): class RunOnce(theano.Op):
__props__ = ("nb_run",)
def __init__(self): def __init__(self):
self.nb_run = 0 self.nb_run = 0
......
...@@ -9,7 +9,6 @@ from six.moves import StringIO ...@@ -9,7 +9,6 @@ from six.moves import StringIO
from theano import config from theano import config
from theano.compat import PY3 from theano.compat import PY3
from theano.misc.frozendict import frozendict
def simple_extract_stack(f=None, limit=None, skips=[]): def simple_extract_stack(f=None, limit=None, skips=[]):
...@@ -212,49 +211,6 @@ class MetaObject(type): ...@@ -212,49 +211,6 @@ class MetaObject(type):
return type.__new__(cls, name, bases, dct) return type.__new__(cls, name, bases, dct)
class MetaObject_caching(MetaObject):
_cache = {}
def __call__(cls, *args, **kwargs):
key = [cls]
for arg in args:
arg = make_hashable(arg)
key.append(arg)
for k, v in sorted(kwargs.items()):
key.append(k)
v = make_hashable(v)
key.append(v)
key = tuple(key)
if key not in cls._cache:
cls._cache[key] = super(MetaObject_caching, cls).__call__(*args, **kwargs)
return cls._cache[key]
class CacheClass(with_metaclass(MetaObject_caching, object)):
pass
def make_hashable(argument):
try:
hash(argument)
return argument
except:
if isinstance(argument, (list, tuple)):
argument = list(argument)
for index, instance in enumerate(argument):
argument[index] = make_hashable(instance)
argument = tuple(argument)
elif isinstance(argument, dict):
for k, v in argument.items():
argument[k] = make_hashable(v)
argument = frozendict(argument)
elif isinstance(argument, slice):
argument = argument.__reduce__()
elif isinstance(argument, np.ndarray):
argument = hash_from_ndarray(argument)
return argument
class object2(with_metaclass(MetaObject, object)): class object2(with_metaclass(MetaObject, object)):
__slots__ = [] __slots__ = []
...@@ -609,30 +565,6 @@ else: ...@@ -609,30 +565,6 @@ else:
return hashlib.md5(np.getbuffer(msg)).hexdigest() return hashlib.md5(np.getbuffer(msg)).hexdigest()
def hash_from_ndarray(data):
"""
Return a hash from an ndarray.
It takes care of the data, shapes, strides and dtype.
"""
# We need to hash the shapes and strides as hash_from_code only hashes
# the data buffer. Otherwise, this will cause problem with shapes like:
# (1, 0) and (2, 0) and problem with inplace transpose.
# We also need to add the dtype to make the distinction between
# uint32 and int32 of zeros with the same shape and strides.
# python hash are not strong, so I always use md5 in order not to have a
# too long hash, I call it again on the concatenation of all parts.
if not data.flags["C_CONTIGUOUS"]:
# hash_from_code needs a C-contiguous array.
data = np.ascontiguousarray(data)
return hash_from_code(hash_from_code(data) +
hash_from_code(str(data.shape)) +
hash_from_code(str(data.strides)) +
hash_from_code(str(data.dtype)))
def hash_from_file(file_path): def hash_from_file(file_path):
""" """
Return the MD5 hash of a file. Return the MD5 hash of a file.
......
...@@ -12,7 +12,7 @@ from theano.tensor.basic import ( ...@@ -12,7 +12,7 @@ from theano.tensor.basic import (
Alloc, AllocEmpty, alloc_validate_shape, Join, Split) Alloc, AllocEmpty, alloc_validate_shape, Join, Split)
from theano.gof import HideC, COp from theano.gof import HideC, COp
from theano.gof.utils import MethodNotDefined, CacheClass from theano.gof.utils import MethodNotDefined
from collections import deque from collections import deque
...@@ -629,7 +629,7 @@ class HostFromGpu(Op): ...@@ -629,7 +629,7 @@ class HostFromGpu(Op):
host_from_gpu = HostFromGpu() host_from_gpu = HostFromGpu()
class GpuFromHost(CacheClass, Op): class GpuFromHost(Op):
""" """
Transfer data to GPU. Transfer data to GPU.
...@@ -783,7 +783,7 @@ class GpuToGpu(Op): ...@@ -783,7 +783,7 @@ class GpuToGpu(Op):
return (1,) return (1,)
class GpuAlloc(CacheClass, HideC, Alloc): class GpuAlloc(HideC, Alloc):
""" """
Allocate initialized memory on the GPU. Allocate initialized memory on the GPU.
...@@ -945,7 +945,7 @@ class GpuAlloc(CacheClass, HideC, Alloc): ...@@ -945,7 +945,7 @@ class GpuAlloc(CacheClass, HideC, Alloc):
return True return True
class GpuAllocEmpty(CacheClass, HideC, AllocEmpty): class GpuAllocEmpty(HideC, AllocEmpty):
""" """
Allocate uninitialized memory on the GPU. Allocate uninitialized memory on the GPU.
......
...@@ -13,7 +13,6 @@ from theano.scalar import as_scalar, constant, Log, get_scalar_type ...@@ -13,7 +13,6 @@ from theano.scalar import as_scalar, constant, Log, get_scalar_type
from theano.tensor import as_tensor_variable from theano.tensor import as_tensor_variable
from theano.gradient import DisconnectedType, grad_not_implemented from theano.gradient import DisconnectedType, grad_not_implemented
from theano.gof import Optimizer, local_optimizer, COp from theano.gof import Optimizer, local_optimizer, COp
from theano.gof.utils import CacheClass
from theano.gof.cmodule import GCC_compiler from theano.gof.cmodule import GCC_compiler
from theano.gof.type import CDataType, Generic from theano.gof.type import CDataType, Generic
from theano.compile import optdb from theano.compile import optdb
...@@ -349,7 +348,7 @@ def version(raises=True): ...@@ -349,7 +348,7 @@ def version(raises=True):
version.v = None version.v = None
class GpuDnnConvDesc(CacheClass, COp): class GpuDnnConvDesc(COp):
""" """
This Op builds a convolution descriptor for use in the other convolution This Op builds a convolution descriptor for use in the other convolution
...@@ -640,7 +639,7 @@ class GpuDnnConv(DnnBase): ...@@ -640,7 +639,7 @@ class GpuDnnConv(DnnBase):
return [shape[2]] return [shape[2]]
class GpuDnnConvGradW(CacheClass, DnnBase): class GpuDnnConvGradW(DnnBase):
""" """
The convolution gradient with respect to the weights. The convolution gradient with respect to the weights.
...@@ -771,7 +770,7 @@ class GpuDnnConvGradW(CacheClass, DnnBase): ...@@ -771,7 +770,7 @@ class GpuDnnConvGradW(CacheClass, DnnBase):
return [shape[2]] return [shape[2]]
class GpuDnnConvGradI(CacheClass, DnnBase): class GpuDnnConvGradI(DnnBase):
""" """
The convolution gradient with respect to the inputs. The convolution gradient with respect to the inputs.
...@@ -1138,8 +1137,9 @@ def dnn_gradweight(img, topgrad, kerns_shp, border_mode='valid', ...@@ -1138,8 +1137,9 @@ def dnn_gradweight(img, topgrad, kerns_shp, border_mode='valid',
precision = get_precision(precision, [img, topgrad]) precision = get_precision(precision, [img, topgrad])
desc = GpuDnnConvDesc(border_mode=border_mode, subsample=subsample, desc = GpuDnnConvDesc(border_mode=border_mode, subsample=subsample,
conv_mode=conv_mode, precision=precision)(kerns_shp) conv_mode=conv_mode, precision=precision)(
out = GpuAllocEmpty(dtype=img.dtype, context_name=ctx_name)(*kerns_shp) kerns_shp)
out = GpuAllocEmpty(ctx_name, dtype=img.dtype)(*kerns_shp)
return GpuDnnConvGradW()(img, topgrad, out, desc) return GpuDnnConvGradW()(img, topgrad, out, desc)
...@@ -1151,7 +1151,6 @@ def dnn_gradweight3d(img, topgrad, kerns_shp, border_mode='valid', ...@@ -1151,7 +1151,6 @@ def dnn_gradweight3d(img, topgrad, kerns_shp, border_mode='valid',
return dnn_gradweight(img, topgrad, kerns_shp, border_mode, return dnn_gradweight(img, topgrad, kerns_shp, border_mode,
subsample, conv_mode, precision) subsample, conv_mode, precision)
def dnn_gradinput(kerns, topgrad, img_shp, border_mode='valid', def dnn_gradinput(kerns, topgrad, img_shp, border_mode='valid',
subsample=(1, 1), conv_mode='conv', precision=None): subsample=(1, 1), conv_mode='conv', precision=None):
""" """
...@@ -1166,8 +1165,9 @@ def dnn_gradinput(kerns, topgrad, img_shp, border_mode='valid', ...@@ -1166,8 +1165,9 @@ def dnn_gradinput(kerns, topgrad, img_shp, border_mode='valid',
precision = get_precision(precision, [kerns, topgrad]) precision = get_precision(precision, [kerns, topgrad])
desc = GpuDnnConvDesc(border_mode=border_mode, subsample=subsample, desc = GpuDnnConvDesc(border_mode=border_mode, subsample=subsample,
conv_mode=conv_mode, precision=precision)(kerns.shape) conv_mode=conv_mode, precision=precision)(
out = GpuAllocEmpty(dtype=kerns.dtype, context_name=ctx_name)(*img_shp) kerns.shape)
out = GpuAllocEmpty(ctx_name, kerns.dtype)(*img_shp)
return GpuDnnConvGradI()(kerns, topgrad, out, desc) return GpuDnnConvGradI()(kerns, topgrad, out, desc)
...@@ -1179,7 +1179,6 @@ def dnn_gradinput3d(kerns, topgrad, img_shp, border_mode='valid', ...@@ -1179,7 +1179,6 @@ def dnn_gradinput3d(kerns, topgrad, img_shp, border_mode='valid',
return dnn_gradinput(kerns, topgrad, img_shp, border_mode, subsample, return dnn_gradinput(kerns, topgrad, img_shp, border_mode, subsample,
conv_mode, precision) conv_mode, precision)
class GpuDnnPoolDesc(Op): class GpuDnnPoolDesc(Op):
""" """
......
...@@ -346,7 +346,6 @@ class InplaceElemwiseOptimizer(Optimizer): ...@@ -346,7 +346,6 @@ class InplaceElemwiseOptimizer(Optimizer):
inplace_pattern = dict(baseline) inplace_pattern = dict(baseline)
inplace_pattern[candidate_output] = candidate_input inplace_pattern[candidate_output] = candidate_input
inplace_pattern = theano.misc.frozendict.frozendict(inplace_pattern)
try: try:
if hasattr(op.scalar_op, "make_new_inplace"): if hasattr(op.scalar_op, "make_new_inplace"):
new_scal = op.scalar_op.make_new_inplace( new_scal = op.scalar_op.make_new_inplace(
...@@ -7271,14 +7270,7 @@ your code will run correctly, but may be slower.""") ...@@ -7271,14 +7270,7 @@ your code will run correctly, but may be slower.""")
# Do not call make_node to have test_value # Do not call make_node to have test_value
n = maker(node, C)(*inputs).owner n = maker(node, C)(*inputs).owner
assert len(n.outputs) == 1 assert len(n.outputs) == 1
assert node.outputs[0].dtype == n.outputs[0].dtype, ( assert node.outputs[0].dtype == n.outputs[0].dtype
"node.outputs[0].dtype: %r" % node.outputs[0].dtype,
"n.outputs[0].dtype: %r" % n.outputs[0].dtype,
"n.op: %r" % n.op, "node.op: %r" % node.op,
"n.outputs %r" % n.outputs, "n: %r" % n,
"node.outputs %r" % node.outputs, "node %r" % node,
"inputs: %r" % n.inputs, "s_inputs: %r" % s_inputs,
"s_new_out: %r" % s_new_out, "OP: %r" % OP)
if len(n.inputs) > max_nb_input: if len(n.inputs) > max_nb_input:
_logger.info('loop fusion failed because Op would exceed' _logger.info('loop fusion failed because Op would exceed'
......
...@@ -4,8 +4,8 @@ import unittest ...@@ -4,8 +4,8 @@ import unittest
import numpy import numpy
import theano import theano
from theano.tensor.utils import shape_of_variables from theano.tensor.utils import (hash_from_ndarray, shape_of_variables)
from theano.gof.utils import hash_from_ndarray
def test_hash_from_ndarray(): def test_hash_from_ndarray():
hashs = [] hashs = []
......
from __future__ import absolute_import, print_function, division from __future__ import absolute_import, print_function, division
import numpy
import theano import theano
from theano.compat import izip from theano.compat import izip
from theano.gof.utils import hash_from_code
def hash_from_ndarray(data):
"""
Return a hash from an ndarray.
It takes care of the data, shapes, strides and dtype.
"""
# We need to hash the shapes and strides as hash_from_code only hashes
# the data buffer. Otherwise, this will cause problem with shapes like:
# (1, 0) and (2, 0) and problem with inplace transpose.
# We also need to add the dtype to make the distinction between
# uint32 and int32 of zeros with the same shape and strides.
# python hash are not strong, so I always use md5 in order not to have a
# too long hash, I call it again on the concatenation of all parts.
if not data.flags["C_CONTIGUOUS"]:
# hash_from_code needs a C-contiguous array.
data = numpy.ascontiguousarray(data)
return hash_from_code(hash_from_code(data) +
hash_from_code(str(data.shape)) +
hash_from_code(str(data.strides)) +
hash_from_code(str(data.dtype)))
def shape_of_variables(fgraph, input_shapes): def shape_of_variables(fgraph, input_shapes):
......
...@@ -12,7 +12,8 @@ import theano ...@@ -12,7 +12,8 @@ import theano
from theano.compat import PY3 from theano.compat import PY3
from theano.scalar import ComplexError, IntegerDivisionError from theano.scalar import ComplexError, IntegerDivisionError
from theano.gof import Constant, Variable from theano.gof import Constant, Variable
from theano.gof.utils import hashtype, hash_from_ndarray from theano.gof.utils import hashtype
from theano.tensor.utils import hash_from_ndarray
from theano.tensor.type import TensorType from theano.tensor.type import TensorType
from theano.configparser import config from theano.configparser import config
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论