instance_reuse

tfsnippet.instance_reuse(method_or_scope=None, _sentinel=None, scope=None)

Decorate an instance method to reuse a variable scope automatically.

This decorator should be applied to unbound instance methods, and the instance that owns the methods should have variable_scope attribute. The first time to enter a decorated method will open a new variable scope under the variable_scope of the instance. This variable scope will be reused the next time to enter this method. For example:

class Foo(object):

    def __init__(self, name):
        with tf.variable_scope(name) as vs:
            self.variable_scope = vs

    @instance_reuse
    def bar(self):
        return tf.get_variable('bar', ...)

foo = Foo()
bar = foo.bar()
bar_2 = foo.bar()
assert(bar is bar_2)  # should be True

By default the name of the variable scope should be chosen according to the name of the decorated method. You can change this behavior by specifying an alternative name, for example:

class Foo(object):

    @instance_reuse('scope_name')
    def foo(self):
        # name will be self.variable_scope.name + '/foo/bar'
        return tf.get_variable('bar', ...)

Unlike the behavior of global_reuse(), if you have two methods sharing the same scope name, they will indeed use the same variable scope. For example:

class Foo(object):

    @instance_reuse('foo')
    def foo_1(self):
        return tf.get_variable('bar', ...)

    @instance_reuse('foo')
    def foo_2(self):
        return tf.get_variable('bar', ...)


    @instance_reuse('foo')
    def foo_2(self):
        return tf.get_variable('bar2', ...)

foo = Foo()
foo.foo_1()  # its name should be variable_scope.name + '/foo/bar'
foo.foo_2()  # should raise an error, because 'bar' variable has
             # been created, but the decorator of `foo_2` does not
             # aware of this, so has not set ``reused = True``.
foo.foo_3()  # its name should be variable_scope.name + '/foo/bar2'

The reason to take this behavior is because the TensorFlow seems to have some absurd behavior when using tf.variable_scope(..., default_name=?) to uniquify the variable scope name. In some cases we the following absurd behavior would appear:

@global_reuse
def foo():
    with tf.variable_scope(None, default_name='bar') as vs:
        return vs

vs1 = foo()  # vs.name == 'foo/bar'
vs2 = foo()  # still expected to be 'foo/bar', but sometimes would be
             # 'foo/bar_1'. this absurd behavior is related to the
             # entering and exiting of variable scopes, which is very
             # hard to diagnose.

In order to compensate such behavior, if you have specified the scope argument of a VarScopeObject, then it will always take the desired variable scope. Also, constructing a VarScopeObject within a method or a function decorated by global_reuse or instance_reuse has been totally disallowed.