提交 7071ddef authored 作者: lamblin's avatar lamblin

Merge pull request #430 from delallea/minor

Some more typo fixes & co
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
Since 0.5rc2 Since 0.5rc2
* Fix a memory leak with shared variable(we kept a pointor to the original value) * Fixed a memory leak with shared variable (we kept a pointer to the original value)
* The key in our cache now store the hash of constant and not the constant value itself. This is significat for big constant. * The keys in our cache now store the hash of constants and not the constant values themselves. This is significantly more efficient for big constant arrays.
* theano-cache list list key file bigger then 1M * 'theano-cache list' lists key files bigger than 1M
* theano-cache list print an histograme of the number of key per compiled module * 'theano-cache list' prints an histogram of the number of keys per compiled module
* theano-cache list print the number of compiled module per op class * 'theano-cache list' prints the number of compiled modules per op class
============= =============
Release Notes Release Notes
......
...@@ -39,6 +39,6 @@ else: ...@@ -39,6 +39,6 @@ else:
print 'Type "theano-cache clear" to erase the cache' print 'Type "theano-cache clear" to erase the cache'
print 'Type "theano-cache list" to print the cache content' print 'Type "theano-cache list" to print the cache content'
print 'Type "theano-cache unlock" to unlock the cache directory' print 'Type "theano-cache unlock" to unlock the cache directory'
print 'Type "theano-cache cleanup" to delete old key format' print 'Type "theano-cache cleanup" to delete keys in the old format'
sys.exit(1) sys.exit(1)
.. _NEWS: .. _NEWS:
Since 0.5rc2
* Fixed a memory leak with shared variable (we kept a pointer to the original value)
* The keys in our cache now store the hash of constants and not the constant values themselves. This is significantly more efficient for big constant arrays.
* 'theano-cache list' lists key files bigger than 1M
* 'theano-cache list' prints an histogram of the number of keys per compiled module
* 'theano-cache list' prints the number of compiled modules per op class
============= =============
Release Notes Release Notes
============= =============
......
...@@ -84,7 +84,7 @@ Benjamin J. McCann provides `installation documentation <http://www.benmccann.co ...@@ -84,7 +84,7 @@ Benjamin J. McCann provides `installation documentation <http://www.benmccann.co
Gentoo Gentoo
~~~~~~ ~~~~~~
Brian Vandenberg emailed `installation instruction on Gentoo <https://groups.google.com/d/msg/theano-dev/-8WCMn2FMR0/bJPasoZXaqoJ>`. Brian Vandenberg emailed `installation instructions on Gentoo <http://groups.google.com/d/msg/theano-dev/-8WCMn2FMR0/bJPasoZXaqoJ>`.
.. _linux_basic: .. _linux_basic:
......
...@@ -6,6 +6,7 @@ Defines Linkers that deal with C implementations. ...@@ -6,6 +6,7 @@ Defines Linkers that deal with C implementations.
from copy import copy from copy import copy
import re #for set_compiledir import re #for set_compiledir
import os, sys, StringIO import os, sys, StringIO
from itertools import izip
if sys.version_info[:2] >= (2,5): if sys.version_info[:2] >= (2,5):
...@@ -733,8 +734,8 @@ class CLinker(link.Linker): ...@@ -733,8 +734,8 @@ class CLinker(link.Linker):
output_storage, output_storage,
keep_lock=keep_lock) keep_lock=keep_lock)
return thunk, \ return thunk, \
[link.Container(input, storage) for input, storage in zip(self.env.inputs, input_storage)], \ [link.Container(input, storage) for input, storage in izip(self.env.inputs, input_storage)], \
[link.Container(output, storage, True) for output, storage in zip(self.env.outputs, output_storage)], \ [link.Container(output, storage, True) for output, storage in izip(self.env.outputs, output_storage)], \
error_storage error_storage
def get_init_tasks(self): def get_init_tasks(self):
...@@ -906,11 +907,12 @@ class CLinker(link.Linker): ...@@ -906,11 +907,12 @@ class CLinker(link.Linker):
if isinstance(i, graph.Constant): #orphans if isinstance(i, graph.Constant): #orphans
if id(i) not in constant_ids: if id(i) not in constant_ids:
isig = (i.signature(), topological_pos, i_idx) isig = (i.signature(), topological_pos, i_idx)
# If the Theano constant provide a strong hash # If the Theano constant provides a strong hash
# (no collision for transpose, 2, 1, 0, -1, -2, # (no collision for transpose, 2, 1, 0, -1, -2,
# 2 element swapped...) we put this hash in the signature # 2 element swapped...) we put this hash in the signature
# instead of the value. This make the key file much smaller # instead of the value. This makes the key file much
# for big constant. Before this, we saw key file up to 80M. # smaller for big constant arrays. Before this, we saw key
# files up to 80M.
if hasattr(isig[0], "theano_hash"): if hasattr(isig[0], "theano_hash"):
isig = (isig[0].theano_hash(), topological_pos, i_idx) isig = (isig[0].theano_hash(), topological_pos, i_idx)
try: try:
...@@ -1234,20 +1236,21 @@ class OpWiseCLinker(link.LocalLinker): ...@@ -1234,20 +1236,21 @@ class OpWiseCLinker(link.LocalLinker):
self.no_recycling = no_recycling self.no_recycling = no_recycling
return self return self
def make_all(self, profiler = None, input_storage = None, output_storage = None): def make_all(self, profiler=None, input_storage=None, output_storage=None):
# The lock will be acquired when we compile the first # The lock will be acquired when we compile the first
# C code. We will keep the lock untill all the function # C code. We will keep the lock untill all the function
# compilation will be finished. This allow to don't # compilation will be finished. This allow to don't
# require the lock when all c code are already compiled! # require the lock when all c code are already compiled!
orig_n_lock = getattr(get_lock,"n_lock",0) orig_n_lock = getattr(get_lock, "n_lock", 0)
try: try:
env = self.env env = self.env
order = env.toposort() order = env.toposort()
no_recycling = self.no_recycling no_recycling = self.no_recycling
input_storage, output_storage, storage_map = link.map_storage(env, order, input_storage, output_storage) input_storage, output_storage, storage_map = link.map_storage(
env, order, input_storage, output_storage)
if self.allow_gc: if self.allow_gc:
computed, last_user = link.gc_helper(order) computed, last_user = link.gc_helper(order)
post_thunk_old_storage = [] post_thunk_old_storage = []
...@@ -1265,7 +1268,7 @@ class OpWiseCLinker(link.LocalLinker): ...@@ -1265,7 +1268,7 @@ class OpWiseCLinker(link.LocalLinker):
# There are ops that don't have _op_use_c_code property # There are ops that don't have _op_use_c_code property
# for example ifelse (or any ops that come with their own # for example ifelse (or any ops that come with their own
# make_thunk # make_thunk
old_value = getattr(node.op,'_op_use_c_code', False) old_value = getattr(node.op, '_op_use_c_code', False)
try: try:
node.op._op_use_c_code = True node.op._op_use_c_code = True
thunks += [node.op.make_thunk(node, thunks += [node.op.make_thunk(node,
...@@ -1280,31 +1283,37 @@ class OpWiseCLinker(link.LocalLinker): ...@@ -1280,31 +1283,37 @@ class OpWiseCLinker(link.LocalLinker):
if self.allow_gc: if self.allow_gc:
post_thunk_old_storage.append([storage_map[input] post_thunk_old_storage.append([storage_map[input]
for input in node.inputs for input in node.inputs
if (input in computed) and (input not in env.outputs) and node == last_user[input]]) if ((input in computed) and
(input not in env.outputs) and
node == last_user[input])])
if no_recycling is True: if no_recycling is True:
no_recycling = storage_map.values() no_recycling = storage_map.values()
no_recycling = utils.difference(no_recycling, input_storage) no_recycling = utils.difference(no_recycling, input_storage)
else: else:
no_recycling = [storage_map[r] for r in no_recycling if r not in env.inputs] no_recycling = [storage_map[r]
for r in no_recycling if r not in env.inputs]
f = link.streamline(env, thunks, order, f = link.streamline(env, thunks, order,
post_thunk_old_storage, post_thunk_old_storage,
no_recycling = no_recycling, no_recycling=no_recycling,
nice_errors = self.nice_errors) nice_errors=self.nice_errors)
f.allow_gc = self.allow_gc f.allow_gc = self.allow_gc
finally: finally:
# Release lock on compilation directory. # Release lock on compilation directory.
if getattr(get_lock,"n_lock",0) > orig_n_lock: if getattr(get_lock, "n_lock", 0) > orig_n_lock:
release_lock() release_lock()
assert get_lock.n_lock == orig_n_lock assert get_lock.n_lock == orig_n_lock
return f, [link.Container(input, storage) for input, storage in zip(env.inputs, input_storage)], \ return (f,
[link.Container(output, storage, True) for output, storage in zip(env.outputs, output_storage)], \ [link.Container(input, storage)
thunks, order for input, storage in izip(env.inputs, input_storage)],
[link.Container(output, storage, True)
for output, storage in izip(env.outputs, output_storage)],
thunks,
order)
def _default_checker(x, y): def _default_checker(x, y):
...@@ -1313,7 +1322,9 @@ def _default_checker(x, y): ...@@ -1313,7 +1322,9 @@ def _default_checker(x, y):
variables contain the same data using ==. variables contain the same data using ==.
""" """
if x[0] != y[0]: if x[0] != y[0]:
raise Exception("Output mismatch.", {'performlinker': x[0], 'clinker': y[0]}) raise Exception("Output mismatch.",
{'performlinker': x[0], 'clinker': y[0]})
class DualLinker(link.Linker): class DualLinker(link.Linker):
"""WRITEME """WRITEME
...@@ -1327,7 +1338,7 @@ class DualLinker(link.Linker): ...@@ -1327,7 +1338,7 @@ class DualLinker(link.Linker):
function. function.
""" """
def __init__(self, checker = _default_checker): def __init__(self, checker=_default_checker):
""" """
Initialize a DualLinker. Initialize a DualLinker.
...@@ -1353,10 +1364,11 @@ class DualLinker(link.Linker): ...@@ -1353,10 +1364,11 @@ class DualLinker(link.Linker):
self.env = None self.env = None
self.checker = checker self.checker = checker
def accept(self, env, no_recycling = []): def accept(self, env, no_recycling=[]):
if self.env is not None and self.env is not env: if self.env is not None and self.env is not env:
return type(self)(self.checker).accept(env, no_recycling) return type(self)(self.checker).accept(env, no_recycling)
#raise Exception("Cannot accept from a Linker that is already tied to another Env.") # raise Exception("Cannot accept from a Linker that is already "
# "tied to another Env.")
self.env = env self.env = env
self.no_recycling = no_recycling self.no_recycling = no_recycling
return self return self
...@@ -1366,26 +1378,31 @@ class DualLinker(link.Linker): ...@@ -1366,26 +1378,31 @@ class DualLinker(link.Linker):
env = self.env env = self.env
no_recycling = self.no_recycling no_recycling = self.no_recycling
_f, i1, o1, thunks1, order1 = link.PerformLinker().accept(env, no_recycling = no_recycling).make_all(**kwargs) _f, i1, o1, thunks1, order1 = link.PerformLinker().accept(env,
no_recycling=no_recycling).make_all(**kwargs)
kwargs.pop('input_storage', None) kwargs.pop('input_storage', None)
_f, i2, o2, thunks2, order2 = OpWiseCLinker().accept(env, no_recycling = no_recycling).make_all(**kwargs) _f, i2, o2, thunks2, order2 = OpWiseCLinker().accept(env,
no_recycling=no_recycling).make_all(**kwargs)
def f(): def f():
for input1, input2 in zip(i1, i2): for input1, input2 in izip(i1, i2):
# set the inputs to be the same in both branches # Set the inputs to be the same in both branches.
# the copy is necessary in order for inplace ops not to interfere # The copy is necessary in order for inplace ops not to
# interfere.
input2.storage[0] = copy(input1.storage[0]) input2.storage[0] = copy(input1.storage[0])
for thunk1, thunk2, node1, node2 in zip(thunks1, thunks2, order1, order2): for thunk1, thunk2, node1, node2 in izip(thunks1, thunks2,
for output, storage in zip(node1.outputs, thunk1.outputs): order1, order2):
for output, storage in izip(node1.outputs, thunk1.outputs):
if output in no_recycling: if output in no_recycling:
storage[0] = None storage[0] = None
for output, storage in zip(node2.outputs, thunk2.outputs): for output, storage in izip(node2.outputs, thunk2.outputs):
if output in no_recycling: if output in no_recycling:
storage[0] = None storage[0] = None
try: try:
thunk1() thunk1()
thunk2() thunk2()
for output1, output2 in zip(thunk1.outputs, thunk2.outputs): for output1, output2 in izip(thunk1.outputs,
thunk2.outputs):
self.checker(output1, output2) self.checker(output1, output2)
except Exception: except Exception:
link.raise_with_op(node1) link.raise_with_op(node1)
......
...@@ -120,10 +120,11 @@ def flatten(a): ...@@ -120,10 +120,11 @@ def flatten(a):
def cleanup(): def cleanup():
""" Delete old keys from the compiledir """
Delete keys in old format from the compiledir.
We define old key as key that have an ndarray in them. We define keys in old format as keys that have an ndarray in them.
Now we use an hash in the keys of the constant data. Now we use a hash in the keys of the constant data.
If there is no key left for a compiled module, we delete the module. If there is no key left for a compiled module, we delete the module.
""" """
...@@ -144,7 +145,6 @@ def cleanup(): ...@@ -144,7 +145,6 @@ def cleanup():
break break
if len(keydata.keys) == 0: if len(keydata.keys) == 0:
shutil.rmtree(os.path.join(compiledir, directory)) shutil.rmtree(os.path.join(compiledir, directory))
pass
except EOFError: except EOFError:
print ("ERROR while reading this key file '%s'." print ("ERROR while reading this key file '%s'."
......
...@@ -2,17 +2,17 @@ from theano.gof.cc import hash_from_code ...@@ -2,17 +2,17 @@ from theano.gof.cc import hash_from_code
def hash_from_sparse(data): def hash_from_sparse(data):
# We need to hash the shapes as hash_from_code only hash # We need to hash the shapes as hash_from_code only hashes
# the data buffer. Otherwise, this will cause problem with shapes like: # the data buffer. Otherwise, this will cause problem with shapes like:
# (1, 0) and (2, 0) # (1, 0) and (2, 0)
# We also need to add the dtype to make the distinction between # We also need to add the dtype to make the distinction between
# uint32 and int32 of zeros with the same shape. # uint32 and int32 of zeros with the same shape.
# python hash are not strong, so I always use md5. To don't have a too long # Python hash is not strong, so I always use md5. To avoid having a too
# hash, I call it again on the contatenation of all part. # long hash, I call it again on the contatenation of all parts.
return (hash_from_code(hash_from_code(data.data) + return hash_from_code(hash_from_code(data.data) +
hash_from_code(data.indices) + hash_from_code(data.indices) +
hash_from_code(data.indptr) + hash_from_code(data.indptr) +
hash_from_code(str(data.shape)) + hash_from_code(str(data.shape)) +
hash_from_code(str(data.dtype)) + hash_from_code(str(data.dtype)) +
hash_from_code(data.format))) hash_from_code(data.format))
...@@ -4,7 +4,7 @@ from theano.gof.cc import hash_from_code ...@@ -4,7 +4,7 @@ from theano.gof.cc import hash_from_code
def hash_from_ndarray(data): def hash_from_ndarray(data):
# We need to hash the shapes and strides as hash_from_code only hash # 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: # the data buffer. Otherwise, this will cause problem with shapes like:
# (1, 0) and (2, 0) and problem with inplace transpose. # (1, 0) and (2, 0) and problem with inplace transpose.
# We also need to add the dtype to make the distinction between # We also need to add the dtype to make the distinction between
...@@ -14,7 +14,7 @@ def hash_from_ndarray(data): ...@@ -14,7 +14,7 @@ def hash_from_ndarray(data):
# too long hash, I call it again on the concatenation of all parts. # too long hash, I call it again on the concatenation of all parts.
if not data.flags["C_CONTIGUOUS"] and not data.flags["F_CONTIGUOUS"]: if not data.flags["C_CONTIGUOUS"] and not data.flags["F_CONTIGUOUS"]:
data = numpy.ascontiguousarray(data) data = numpy.ascontiguousarray(data)
return (hash_from_code(hash_from_code(data) + return hash_from_code(hash_from_code(data) +
hash_from_code(str(data.shape)) + hash_from_code(str(data.shape)) +
hash_from_code(str(data.strides)) + hash_from_code(str(data.strides)) +
hash_from_code(str(data.dtype)))) hash_from_code(str(data.dtype)))
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论