提交 3bed4bb1 authored 作者: Joseph Turian's avatar Joseph Turian

merge

......@@ -31,12 +31,15 @@ Op's contract
An Op is any object which defines the following methods:
- **make_node(*inputs)**
- This method is responsible for creating output Results of a suitable Type
to serve as the outputs of this Op's application. It should put these
outputs into an Apply instance, and return the Apply instance.
- This important function creates an Apply node representing the
application of the Op on the inputs provided. If the Op cannot be
applied on these inputs, it must raise an appropriate
exception. This method is also responsible for creating Results of
the suitable Type to serve as the outputs of the Op's application.
exception.
- **__call__(*inputs)**
......@@ -52,20 +55,54 @@ An Op is any object which defines the following methods:
method, the inputs are a list of references to data to operate on
and output_storage is a list of storage cells where the results of
the computation must be put.
- This function must be determined by the inputs. That is to say, if it is
evaluated once on inputs A and returned B, then if ever inputs C, equal to
A, are presented again, then outputs equal to B must be returned again.
- **__eq__(self, other)**
- Returning True here is a promise to the optimization system that the other
Op will produce exactly the same graph effects (from perform) as this one,
given identical inputs. This means it will produce the same output values,
it will destroy the same inputs (same destroy_map), and will alias outputs
to the same inputs (same view_map).
- **__hash__(self)**
- If two Op instances compare equal, then they MUST return the same hash
value.
- Equally important, this hash value must not change during the lifetime of
self.
- **__ne__(self, other)**
- Recommended, and default: define as (not (self==other))
- **grad(inputs, output_gradients)** *Optional*
- If the Op you are defining is differentiable, you can define its
gradient symbolically in this method. Both the inputs and
output_gradients are Results and you must return one Result for
each input representing the gradient wrt these inputs provided
that the gradients wrt the outputs are computed by
output_gradients.
gradient symbolically in this method.
- Both the inputs and output_gradients will be Results. This function must
return a list containg one Result (or None) for each input.
Each returned Result represents the gradient wrt that input given the
symbolic gradients wrt each output.
- If the output is not differentiable with respect to any inputs, then this
function should be defined to return [None for i in inputs].
- If this method is not defined, then theano assumes it hsa been forgotten.
Symbolic differentiation will fail on a graph that includes this Op.
- For more information on the use of this method, see ``grad``.
For each method, the *default* is what the Op class defines for you.
For more details you can go see the documentation for :ref:`op`.
For more details, including the interface for providing a C implementation of
perform(), refer to the documentation for :ref:`op`.
......
......@@ -43,7 +43,7 @@ from compile import \
Mode, \
predefined_modes, predefined_linkers, predefined_optimizers, \
FunctionMaker, function, OpFromGraph, \
Component, External, Member, KitComponent, Method, \
Component, External, Member, Method, \
Composite, ComponentList, ComponentDict, Module, \
ProfileMode
......
......@@ -998,32 +998,6 @@ FancyModule = Module
FancyModuleInstance = ModuleInstance
class KitComponent(Component):
"""
Represents a SymbolicInputKit (see io.py).
"""
def __init__(self, kit):
super(KitComponent, self).__init__()
self.kit = kit
def allocate(self, memo):
"""
Allocates a Container for each input in the kit. Sets a key in
the memo that maps the SymbolicInputKit to the list of
Containers.
"""
for input in self.kit.sinputs:
r = input.result
if r not in memo:
input = copy(input)
input.value = gof.Container(r, storage = [None])
memo[r] = input
def build(self, mode, memo):
return [memo[i.result].value for i in self.kit.sinputs]
def func_to_mod(f):
"""
Creates a dummy module, with external member variables for the input
......
......@@ -159,6 +159,9 @@ class PureOp(object):
To see how `Op`, `Type`, `Result`, and `Apply` fit together see the page on :doc:`graph`.
For more specifications on how these methods should behave: see the `Op Contract` in the
sphinx docs (advanced tutorial on Op-making).
"""
default_output = None
......
......@@ -6,11 +6,11 @@ from basic import *
import opt
import blas
import raw_random, rmodule
from rmodule import \
RandomKit, RModule
import raw_random, randomstreams
from randomstreams import \
RandomStreams
random = RandomKit('random')
random = RandomStreams(seed=0xBAD5EED)
"""Imitate the numpy.random symbol with a tensor.random one"""
from elemwise import \
......
"""Define RModule, a Module providing random number streams in Theano graphs."""
__docformat__ = "restructuredtext en"
import sys
import functools
from functools import partial
from collections import deque
import numpy
from ...compile import (SymbolicInputKit, SymbolicInput,
Module, module, Method, Member, In, Component)
from ...gof import Container
from ...tensor import raw_random
class KitComponent(Component):
"""
Represents a SymbolicInputKit (see io.py).
"""
def __init__(self, kit):
super(KitComponent, self).__init__()
self.kit = kit
def allocate(self, memo):
"""
Allocates a Container for each input in the kit. Sets a key in
the memo that maps the SymbolicInputKit to the list of
Containers.
"""
for input in self.kit.sinputs:
r = input.result
if r not in memo:
input = copy(input)
input.value = gof.Container(r, storage = [None])
memo[r] = input
def build(self, mode, memo):
return [memo[i.result].value for i in self.kit.sinputs]
class RandomKit(SymbolicInputKit):
def __init__(self, name, value = None):
super(RandomKit, self).__init__(name)
self.value = value
def gen(self, op, *args, **kwargs):
random_state_result = raw_random.random_state_type()
new_r, out = op(random_state_result, *args, **kwargs)
self.add_input(SymbolicInput(random_state_result, update = new_r))
out.rng = new_r
out.auto = self
return out
def distribute(self, value, indices, containers):
rg = partial(numpy.random.RandomState(int(value)).randint, 2**30)
elems = deque(zip(indices, containers))
i = 0
while elems:
index, container = elems.popleft()
while i <= index:
curr = rg()
i += 1
rs = numpy.random.RandomState(int(curr))
container.data = rs
def binomial(self, *args, **kwargs):
return self.gen(raw_random.binomial, *args, **kwargs)
def uniform(self, *args, **kwargs):
return self.gen(raw_random.uniform, *args, **kwargs)
def normal(self, *args, **kwargs):
return self.gen(raw_random.normal, *args, **kwargs)
def random_integers(self, *args, **kwargs):
return self.gen(raw_random.random_integers, *args, **kwargs)
rk = RandomKit('rk', 0xBAD5EED)
class RModule(Module):
"""Module providing random number streams in Theano graphs."""
def __init__(self, components = {}, **kwcomponents):
super(RModule, self).__init__(components, **kwcomponents)
self.random = RandomKit('rkit')
self._rkit = KitComponent(self.random)
def __wrapper__(self, x):
x = module.wrap(x)
if isinstance(x, Method):
x.kits += [self.random]
return x
def _instance_seed(self, inst, seed, recursive = True):
seedgen = numpy.random.RandomState(seed)
if recursive:
#Here, we recurse through all the components (inst2) contained in (inst)
#and seeds each subcomponent that is an RModule
for path, c in self.flat_components_map(True):
if isinstance(c, RModule):
inst2 = inst
for name in path:
inst2 = inst2[name]
# A Kit (c._rkit.kit) contains a list of io.SymbolicIn instances
# and the distribute method takes a value (seed), a list of indices
# and a list of corresponding Container instances. In this
# situation it will reseed all the rngs using the containers
# associated to them.
c._rkit.kit.distribute(seedgen.random_integers(2**30),
xrange(len(inst2._rkit)), inst2._rkit)
else:
self._rkit.kit.distribute(seedgen.random_integers(2**30), xrange(len(inst._rkit)), inst._rkit)
__docformat__ = "restructuredtext en"
import sys
import unittest
import numpy as N
from theano.tensor.deprecated.rmodule import *
from theano import tensor
from theano import compile, gof
if 0:
class T_test_module(unittest.TestCase):
def test_state_propagation(self):
if 1:
print >> sys.stderr, "RModule deprecated"
else:
x = tensor.vector()
rk = RandomKit('rk', 1000)
f = compile.function([x, (rk, [gof.Container(r = gof.generic, storage = [123], name='bla')])], rk.binomial(tensor.shape(x)))
print "RK", rk.value
f['rk'] = 9873456
print "RK", rk.value
rvals = [f([1,2,3,4,6, 7, 8]) for i in xrange(5)]
print rvals
for i in xrange(5-1):
for j in xrange(i+1, 5):
assert not N.all(rvals[i] == rvals[j])
def test_B(self):
"""Test that random numbers change from call to call!
Also, make sure that the seeding strategy doesn't change without failing a test.
Random numbers can't be too random or experiments aren't repeatable. Email theano-dev
before updating the `rvals` in this test.
"""
class B(RModule):
def __init__(self):
super(B, self).__init__()
self.x = compile.Member(tensor.dvector())
self.r = self.random.uniform(tensor.shape(self.x))
self.f = compile.Method([self.x], self.r)
class E(RModule):
def __init__(self):
super(E, self).__init__()
self.b = B()
self.f = compile.Method([self.b.x], self.b.r)
b = E()
m = b.make()
m.seed(1000)
#print m.f(N.ones(5))
#print m.f(N.ones(5))
#print m.f(N.ones(5))
rvals = ["0.74802375876 0.872308123517 0.294830748897 0.803123780003 0.6321109955",
"0.00168744844365 0.278638315678 0.725436793755 0.7788480779 0.629885140994",
"0.545561221664 0.0992011009108 0.847112593242 0.188015424144 0.158046201298",
"0.054382248842 0.563459168529 0.192757276954 0.360455221883 0.174805216702",
"0.961942907777 0.49657319422 0.0316111492826 0.0915054717012 0.195877184515"]
for i in xrange(5):
s = " ".join([str(n) for n in m.f(N.ones(5))])
print s
assert s == rvals[i]
if __name__ == '__main__':
from theano.tests import main
main("test_rmodule")
"""Define RModule, a Module providing random number streams in Theano graphs."""
"""Define RandomStreams, providing random number variables for Theano graphs."""
__docformat__ = "restructuredtext en"
import sys
import functools
from functools import partial
from collections import deque
import sys
import numpy
from ..compile import (SymbolicInputKit, SymbolicInput,
Module, KitComponent, module, Method, Member, In, Component)
from ..compile import module, In, Component
from ..gof import Container
from ..tensor import raw_random
class RandomKit(SymbolicInputKit):
def __init__(self, name, value = None):
super(RandomKit, self).__init__(name)
self.value = value
def gen(self, op, *args, **kwargs):
random_state_result = raw_random.random_state_type()
new_r, out = op(random_state_result, *args, **kwargs)
self.add_input(SymbolicInput(random_state_result, update = new_r))
out.rng = new_r
out.auto = self
return out
def distribute(self, value, indices, containers):
rg = partial(numpy.random.RandomState(int(value)).randint, 2**30)
elems = deque(zip(indices, containers))
i = 0
while elems:
index, container = elems.popleft()
while i <= index:
curr = rg()
i += 1
rs = numpy.random.RandomState(int(curr))
container.data = rs
def binomial(self, *args, **kwargs):
return self.gen(raw_random.binomial, *args, **kwargs)
def uniform(self, *args, **kwargs):
return self.gen(raw_random.uniform, *args, **kwargs)
def normal(self, *args, **kwargs):
return self.gen(raw_random.normal, *args, **kwargs)
def random_integers(self, *args, **kwargs):
return self.gen(raw_random.random_integers, *args, **kwargs)
rk = RandomKit('rk', 0xBAD5EED)
class RModule(Module):
"""Module providing random number streams in Theano graphs."""
def __init__(self, components = {}, **kwcomponents):
super(RModule, self).__init__(components, **kwcomponents)
self.random = RandomKit('rkit')
self._rkit = KitComponent(self.random)
def __wrapper__(self, x):
x = module.wrap(x)
if isinstance(x, Method):
x.kits += [self.random]
return x
def _instance_seed(self, inst, seed, recursive = True):
seedgen = numpy.random.RandomState(seed)
if recursive:
#Here, we recurse through all the components (inst2) contained in (inst)
#and seeds each subcomponent that is an RModule
for path, c in self.flat_components_map(True):
if isinstance(c, RModule):
inst2 = inst
for name in path:
inst2 = inst2[name]
# A Kit (c._rkit.kit) contains a list of io.SymbolicIn instances
# and the distribute method takes a value (seed), a list of indices
# and a list of corresponding Container instances. In this
# situation it will reseed all the rngs using the containers
# associated to them.
c._rkit.kit.distribute(seedgen.random_integers(2**30),
xrange(len(inst2._rkit)), inst2._rkit)
else:
self._rkit.kit.distribute(seedgen.random_integers(2**30), xrange(len(inst._rkit)), inst._rkit)
class RandomStreamsInstance(object):
"""RandomStreamsInstance"""
def __init__(self, random_streams, memo, default_seed):
......@@ -168,10 +83,8 @@ class RandomStreamsInstance(object):
return
raise KeyError(item)
class RandomStreams(Component):
"""Module with similar interface to numpy.random (numpy.random.RandomState)"""
"""Module component with similar interface to numpy.random (numpy.random.RandomState)"""
random_state_results = []
"""A list of pairs of the form (input_r, output_r). This will be over-ridden by the module
......@@ -183,11 +96,18 @@ class RandomStreams(Component):
generator that provides seeds for member streams"""
def __init__(self, seed=None):
"""
:type seed: None or int
:param seed: a default seed to initialize the RandomState instances after build. See
`RandomStreamsInstance.__init__` for more details.
"""
super(RandomStreams, self).__init__()
self.random_state_results = []
self.default_instance_seed = seed
def allocate(self, memo):
"""override `Component.allocate` """
for old_r, new_r in self.random_state_results:
assert old_r not in memo
memo[old_r] = In(old_r,
......@@ -196,11 +116,23 @@ class RandomStreams(Component):
mutable=True)
def build(self, mode, memo):
#print 'MODE', mode
#returns a list of containers
"""override `Component.build` """
return RandomStreamsInstance(self, memo, self.default_instance_seed)
def gen(self, op, *args, **kwargs):
"""Create a new random stream in this container.
:param op: a RandomFunction instance to
:param args: interpreted by `op`
:param kwargs: interpreted by `op`
:returns: The symbolic random draw part of op()'s return value. This function stores
the updated RandomStateType Result for use at `build` time.
:rtype: TensorResult
"""
random_state_result = raw_random.random_state_type()
new_r, out = op(random_state_result, *args, **kwargs)
out.rng = random_state_result
......@@ -210,15 +142,28 @@ class RandomStreams(Component):
def binomial(self, *args, **kwargs):
"""Return a symbolic binomial sample
This is a shortcut for a call to `self.gen`
"""
return self.gen(raw_random.binomial, *args, **kwargs)
def uniform(self, *args, **kwargs):
"""Return a symbolic uniform sample
This is a shortcut for a call to `self.gen`
"""
return self.gen(raw_random.uniform, *args, **kwargs)
def normal(self, *args, **kwargs):
"""Return a symbolic normal sample
This is a shortcut for a call to `self.gen`
"""
return self.gen(raw_random.normal, *args, **kwargs)
def random_integers(self, *args, **kwargs):
"""Return a symbolic random integer sample
This is a shortcut for a call to `self.gen`
"""
return self.gen(raw_random.random_integers, *args, **kwargs)
......@@ -18,7 +18,7 @@ def cross_entropy(target, output, axis=1):
"""
return -T.mean(target * T.log(output) + (1 - target) * T.log(1 - output), axis=axis)
class QuadraticDenoisingAA(T.RModule):
class QuadraticDenoisingAA(module.Module):
"""Quadratic de-noising Auto-encoder
WRITEME
......@@ -59,6 +59,8 @@ class QuadraticDenoisingAA(T.RModule):
"""
super(QuadraticDenoisingAA, self).__init__()
self.random = T.RandomStreams()
# MODEL CONFIGURATION
# self.regularize = regularize
self.tie_weights = tie_weights
......@@ -75,11 +77,11 @@ class QuadraticDenoisingAA(T.RModule):
# PARAMETERS
if _qfilters is None:
self.qfilters = [theano.Member(T.dmatrix()) for i in xrange(n_quadratic_filters)]
self.qfilters = [theano.Member(T.dmatrix('q%i'%i)) for i in xrange(n_quadratic_filters)]
else:
self.qfilters = [theano.Member(q) for q in _qfilters]
self.w1 = theano.Member(T.matrix()) if _w1 is None else theano.Member(_w1)
self.w1 = theano.Member(T.matrix('w1')) if _w1 is None else theano.Member(_w1)
if _w2 is None:
if not tie_weights:
self.w2 = theano.Member(T.matrix())
......@@ -87,8 +89,8 @@ class QuadraticDenoisingAA(T.RModule):
self.w2 = self.w1.T
else:
self.w2 = theano.Member(_w2)
self.b1 = theano.Member(T.vector()) if _b1 is None else theano.Member(_b1)
self.b2 = theano.Member(T.vector()) if _b2 is None else theano.Member(_b2)
self.b1 = theano.Member(T.vector('b1')) if _b1 is None else theano.Member(_b1)
self.b2 = theano.Member(T.vector('b2')) if _b2 is None else theano.Member(_b2)
# # REGULARIZATION COST
# self.regularization = self.build_regularization()
......@@ -173,6 +175,7 @@ class QuadraticDenoisingAA(T.RModule):
if (input_size is None) ^ (hidden_size is None):
raise ValueError("Must specify input_size and hidden_size or neither.")
super(QuadraticDenoisingAA, self)._instance_initialize(obj, {})
obj.random.initialize()
if seed is not None:
R = N.random.RandomState(seed)
else:
......@@ -189,7 +192,7 @@ class QuadraticDenoisingAA(T.RModule):
obj.qfilters = [R.uniform(size = sz, low = -inf, high = inf) * qfilter_relscale \
for qf in self.qfilters]
if seed is not None:
obj.seed(seed, recursive=True)
obj.random.seed(seed)
obj.lr = lr
......
......@@ -2,9 +2,10 @@ __docformat__ = "restructuredtext en"
import sys
import unittest
import numpy as N
import numpy
from theano.tensor.rmodule import *
from theano.tensor.randomstreams import RandomStreams, raw_random
from theano.compile import Module, Method, Member
from theano import tensor
from theano import compile, gof
......@@ -122,66 +123,6 @@ class T_RandomStreams(unittest.TestCase):
assert numpy.all(fn_val1 == numpy_val1)
class T_test_module(unittest.TestCase):
def test_state_propagation(self):
if 1:
print >> sys.stderr, "RModule deprecated"
else:
x = tensor.vector()
rk = RandomKit('rk', 1000)
f = compile.function([x, (rk, [gof.Container(r = gof.generic, storage = [123], name='bla')])], rk.binomial(tensor.shape(x)))
print "RK", rk.value
f['rk'] = 9873456
print "RK", rk.value
rvals = [f([1,2,3,4,6, 7, 8]) for i in xrange(5)]
print rvals
for i in xrange(5-1):
for j in xrange(i+1, 5):
assert not N.all(rvals[i] == rvals[j])
def test_B(self):
"""Test that random numbers change from call to call!
Also, make sure that the seeding strategy doesn't change without failing a test.
Random numbers can't be too random or experiments aren't repeatable. Email theano-dev
before updating the `rvals` in this test.
"""
class B(RModule):
def __init__(self):
super(B, self).__init__()
self.x = compile.Member(tensor.dvector())
self.r = self.random.uniform(tensor.shape(self.x))
self.f = compile.Method([self.x], self.r)
class E(RModule):
def __init__(self):
super(E, self).__init__()
self.b = B()
self.f = compile.Method([self.b.x], self.b.r)
b = E()
m = b.make()
m.seed(1000)
#print m.f(N.ones(5))
#print m.f(N.ones(5))
#print m.f(N.ones(5))
rvals = ["0.74802375876 0.872308123517 0.294830748897 0.803123780003 0.6321109955",
"0.00168744844365 0.278638315678 0.725436793755 0.7788480779 0.629885140994",
"0.545561221664 0.0992011009108 0.847112593242 0.188015424144 0.158046201298",
"0.054382248842 0.563459168529 0.192757276954 0.360455221883 0.174805216702",
"0.961942907777 0.49657319422 0.0316111492826 0.0915054717012 0.195877184515"]
for i in xrange(5):
s = " ".join([str(n) for n in m.f(N.ones(5))])
print s
assert s == rvals[i]
if __name__ == '__main__':
from theano.tests import main
main("test_rmodule")
main("test_randomstreams")
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论