Skip to content

Commit 1ed4e69

Browse files
Lukasz Kaisertensorflower-gardener
authored andcommitted
Default reuse should be None, never False. Correct it in layers and add tests.
Change: 144903238
1 parent f0a1af4 commit 1ed4e69

6 files changed

Lines changed: 135 additions & 31 deletions

File tree

tensorflow/python/layers/convolutional.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ def conv1d(inputs,
268268
activity_regularizer=None,
269269
trainable=True,
270270
name=None,
271-
reuse=False):
271+
reuse=None):
272272
"""Functional interface for 1D convolution layer (e.g. temporal convolution).
273273
274274
This layer creates a convolution kernel that is convolved
@@ -435,7 +435,7 @@ def conv2d(inputs,
435435
activity_regularizer=None,
436436
trainable=True,
437437
name=None,
438-
reuse=False):
438+
reuse=None):
439439
"""Functional interface for the 2D convolution layer.
440440
441441
This layer creates a convolution kernel that is convolved
@@ -608,7 +608,7 @@ def conv3d(inputs,
608608
activity_regularizer=None,
609609
trainable=True,
610610
name=None,
611-
reuse=False):
611+
reuse=None):
612612
"""Functional interface for the 3D convolution layer.
613613
614614
This layer creates a convolution kernel that is convolved
@@ -867,7 +867,7 @@ def separable_conv2d(inputs,
867867
activity_regularizer=None,
868868
trainable=True,
869869
name=None,
870-
reuse=False):
870+
reuse=None):
871871
"""Functional interface for the depthwise separable 2D convolution layer.
872872
873873
This layer performs a depthwise convolution that acts separately on
@@ -1128,7 +1128,7 @@ def conv2d_transpose(inputs,
11281128
activity_regularizer=None,
11291129
trainable=True,
11301130
name=None,
1131-
reuse=False):
1131+
reuse=None):
11321132
"""Transposed convolution layer (sometimes called Deconvolution).
11331133
11341134
The need for transposed convolutions generally arises

tensorflow/python/layers/convolutional_test.py

Lines changed: 103 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,16 @@
1818
from __future__ import division
1919
from __future__ import print_function
2020

21+
import numpy as np
22+
2123
from tensorflow.python.framework import ops
2224
from tensorflow.python.layers import convolutional as conv_layers
25+
from tensorflow.python.ops import init_ops
2326
from tensorflow.python.ops import math_ops
2427
from tensorflow.python.ops import nn_ops
2528
from tensorflow.python.ops import random_ops
29+
from tensorflow.python.ops import variable_scope
30+
from tensorflow.python.ops import variables
2631
from tensorflow.python.platform import test
2732

2833

@@ -191,21 +196,45 @@ def testFunctionalConv2DReuse(self):
191196
height, width = 7, 9
192197
images = random_ops.random_uniform((5, height, width, 3), seed=1)
193198
conv_layers.conv2d(images, 32, [3, 3], name='conv1')
194-
self.assertEqual(
195-
len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 2)
199+
self.assertEqual(len(variables.trainable_variables()), 2)
196200
conv_layers.conv2d(images, 32, [3, 3], name='conv1', reuse=True)
197-
self.assertEqual(
198-
len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 2)
201+
self.assertEqual(len(variables.trainable_variables()), 2)
202+
203+
def testFunctionalConv2DReuseFromScope(self):
204+
with variable_scope.variable_scope('scope'):
205+
height, width = 7, 9
206+
images = random_ops.random_uniform((5, height, width, 3), seed=1)
207+
conv_layers.conv2d(images, 32, [3, 3], name='conv1')
208+
self.assertEqual(len(variables.trainable_variables()), 2)
209+
with variable_scope.variable_scope('scope', reuse=True):
210+
conv_layers.conv2d(images, 32, [3, 3], name='conv1')
211+
self.assertEqual(len(variables.trainable_variables()), 2)
212+
213+
def testFunctionalConv2DInitializerFromScope(self):
214+
with self.test_session() as sess:
215+
with variable_scope.variable_scope(
216+
'scope', initializer=init_ops.ones_initializer()):
217+
height, width = 7, 9
218+
images = random_ops.random_uniform((5, height, width, 3), seed=1)
219+
conv_layers.conv2d(images, 32, [3, 3], name='conv1')
220+
weights = variables.trainable_variables()
221+
# Check the names of weights in order.
222+
self.assertTrue('kernel' in weights[0].name)
223+
self.assertTrue('bias' in weights[1].name)
224+
sess.run(variables.global_variables_initializer())
225+
weights = sess.run(weights)
226+
# Check that the kernel weights got initialized to ones (from scope)
227+
self.assertAllClose(weights[0], np.ones((3, 3, 3, 32)))
228+
# Check that the bias still got initialized to zeros.
229+
self.assertAllClose(weights[1], np.zeros((32)))
199230

200231
def testFunctionalConv2DNoReuse(self):
201232
height, width = 7, 9
202233
images = random_ops.random_uniform((5, height, width, 3), seed=1)
203234
conv_layers.conv2d(images, 32, [3, 3])
204-
self.assertEqual(
205-
len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 2)
235+
self.assertEqual(len(variables.trainable_variables()), 2)
206236
conv_layers.conv2d(images, 32, [3, 3])
207-
self.assertEqual(
208-
len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 4)
237+
self.assertEqual(len(variables.trainable_variables()), 4)
209238

210239

211240
class SeparableConv2DTest(test.TestCase):
@@ -323,22 +352,48 @@ def testFunctionalConv2DReuse(self):
323352
height, width = 7, 9
324353
images = random_ops.random_uniform((5, height, width, 3), seed=1)
325354
conv_layers.separable_conv2d(images, 32, [3, 3], name='sepconv1')
326-
self.assertEqual(
327-
len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 3)
355+
self.assertEqual(len(variables.trainable_variables()), 3)
328356
conv_layers.separable_conv2d(
329357
images, 32, [3, 3], name='sepconv1', reuse=True)
330-
self.assertEqual(
331-
len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 3)
358+
self.assertEqual(len(variables.trainable_variables()), 3)
359+
360+
def testFunctionalConv2DReuseFromScope(self):
361+
with variable_scope.variable_scope('scope'):
362+
height, width = 7, 9
363+
images = random_ops.random_uniform((5, height, width, 3), seed=1)
364+
conv_layers.separable_conv2d(images, 32, [3, 3], name='sepconv1')
365+
self.assertEqual(len(variables.trainable_variables()), 3)
366+
with variable_scope.variable_scope('scope', reuse=True):
367+
conv_layers.separable_conv2d(images, 32, [3, 3], name='sepconv1')
368+
self.assertEqual(len(variables.trainable_variables()), 3)
369+
370+
def testFunctionalConv2DInitializerFromScope(self):
371+
with self.test_session() as sess:
372+
with variable_scope.variable_scope(
373+
'scope', initializer=init_ops.ones_initializer()):
374+
height, width = 7, 9
375+
images = random_ops.random_uniform((5, height, width, 3), seed=1)
376+
conv_layers.separable_conv2d(images, 32, [3, 3], name='sepconv1')
377+
weights = variables.trainable_variables()
378+
# Check the names of weights in order.
379+
self.assertTrue('depthwise_kernel' in weights[0].name)
380+
self.assertTrue('pointwise_kernel' in weights[1].name)
381+
self.assertTrue('bias' in weights[2].name)
382+
sess.run(variables.global_variables_initializer())
383+
weights = sess.run(weights)
384+
# Check that the kernel weights got initialized to ones (from scope)
385+
self.assertAllClose(weights[0], np.ones((3, 3, 3, 1)))
386+
self.assertAllClose(weights[1], np.ones((1, 1, 3, 32)))
387+
# Check that the bias still got initialized to zeros.
388+
self.assertAllClose(weights[2], np.zeros((32)))
332389

333390
def testFunctionalConv2DNoReuse(self):
334391
height, width = 7, 9
335392
images = random_ops.random_uniform((5, height, width, 3), seed=1)
336393
conv_layers.separable_conv2d(images, 32, [3, 3])
337-
self.assertEqual(
338-
len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 3)
394+
self.assertEqual(len(variables.trainable_variables()), 3)
339395
conv_layers.separable_conv2d(images, 32, [3, 3])
340-
self.assertEqual(
341-
len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 6)
396+
self.assertEqual(len(variables.trainable_variables()), 6)
342397

343398
def testSeparableConv2DDepthwiseRegularizer(self):
344399
height, width = 7, 9
@@ -511,21 +566,45 @@ def testFunctionalConv2DTransposeReuse(self):
511566
height, width = 7, 9
512567
images = random_ops.random_uniform((5, height, width, 3), seed=1)
513568
conv_layers.conv2d_transpose(images, 32, [3, 3], name='deconv1')
514-
self.assertEqual(
515-
len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 2)
569+
self.assertEqual(len(variables.trainable_variables()), 2)
516570
conv_layers.conv2d_transpose(images, 32, [3, 3], name='deconv1', reuse=True)
517-
self.assertEqual(
518-
len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 2)
571+
self.assertEqual(len(variables.trainable_variables()), 2)
572+
573+
def testFunctionalConv2DTransposeReuseFromScope(self):
574+
with variable_scope.variable_scope('scope'):
575+
height, width = 7, 9
576+
images = random_ops.random_uniform((5, height, width, 3), seed=1)
577+
conv_layers.conv2d_transpose(images, 32, [3, 3], name='deconv1')
578+
self.assertEqual(len(variables.trainable_variables()), 2)
579+
with variable_scope.variable_scope('scope', reuse=True):
580+
conv_layers.conv2d_transpose(images, 32, [3, 3], name='deconv1')
581+
self.assertEqual(len(variables.trainable_variables()), 2)
582+
583+
def testFunctionalConv2DTransposeInitializerFromScope(self):
584+
with self.test_session() as sess:
585+
with variable_scope.variable_scope(
586+
'scope', initializer=init_ops.ones_initializer()):
587+
height, width = 7, 9
588+
images = random_ops.random_uniform((5, height, width, 3), seed=1)
589+
conv_layers.conv2d_transpose(images, 32, [3, 3], name='deconv1')
590+
weights = variables.trainable_variables()
591+
# Check the names of weights in order.
592+
self.assertTrue('kernel' in weights[0].name)
593+
self.assertTrue('bias' in weights[1].name)
594+
sess.run(variables.global_variables_initializer())
595+
weights = sess.run(weights)
596+
# Check that the kernel weights got initialized to ones (from scope)
597+
self.assertAllClose(weights[0], np.ones((3, 3, 32, 3)))
598+
# Check that the bias still got initialized to zeros.
599+
self.assertAllClose(weights[1], np.zeros((32)))
519600

520601
def testFunctionalConv2DTransposeNoReuse(self):
521602
height, width = 7, 9
522603
images = random_ops.random_uniform((5, height, width, 3), seed=1)
523604
conv_layers.conv2d_transpose(images, 32, [3, 3])
524-
self.assertEqual(
525-
len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 2)
605+
self.assertEqual(len(variables.trainable_variables()), 2)
526606
conv_layers.conv2d_transpose(images, 32, [3, 3])
527-
self.assertEqual(
528-
len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 4)
607+
self.assertEqual(len(variables.trainable_variables()), 4)
529608

530609

531610
if __name__ == '__main__':

tensorflow/python/layers/core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ def dense(
167167
activity_regularizer=None,
168168
trainable=True,
169169
name=None,
170-
reuse=False):
170+
reuse=None):
171171
"""Functional interface for the densely-connected layer.
172172
173173
This layer implements the operation:

tensorflow/python/layers/core_test.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,16 @@ def testFunctionalDenseTwiceReuse(self):
207207
vars2 = variables.trainable_variables()
208208
self.assertEqual(vars1, vars2)
209209

210+
def testFunctionalDenseTwiceReuseFromScope(self):
211+
with variable_scope.variable_scope('scope'):
212+
inputs = random_ops.random_uniform((5, 3), seed=1)
213+
core_layers.dense(inputs, 2, name='my_dense')
214+
vars1 = variables.trainable_variables()
215+
with variable_scope.variable_scope('scope', reuse=True):
216+
core_layers.dense(inputs, 2, name='my_dense')
217+
vars2 = variables.trainable_variables()
218+
self.assertEqual(vars1, vars2)
219+
210220
def testFunctionalDenseInitializerFromScope(self):
211221
with self.test_session() as sess:
212222
with variable_scope.variable_scope(

tensorflow/python/layers/normalization.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ def batch_normalization(inputs,
257257
training=False,
258258
trainable=True,
259259
name=None,
260-
reuse=False):
260+
reuse=None):
261261
"""Functional interface for the batch normalization layer.
262262
263263
Reference: http://arxiv.org/abs/1502.03167

tensorflow/python/layers/normalization_test.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from tensorflow.python.ops import array_ops
2727
from tensorflow.python.ops import math_ops
2828
from tensorflow.python.ops import random_ops
29+
from tensorflow.python.ops import variable_scope
2930
from tensorflow.python.ops import variables
3031
from tensorflow.python.platform import test
3132

@@ -454,6 +455,20 @@ def testFunctionalReuse(self):
454455
self.assertAlmostEqual(np.mean(normed_np_output), 0., places=2)
455456
self.assertAlmostEqual(np.std(normed_np_output), 1., places=1)
456457

458+
def testFunctionalReuseFromScope(self):
459+
inputs = variables.Variable(
460+
np.random.random((5, 4, 3, 6)), dtype=dtypes.float32)
461+
epsilon = 1e-3
462+
training = array_ops.placeholder(dtype='bool')
463+
with variable_scope.variable_scope('scope'):
464+
_ = normalization_layers.batch_norm(
465+
inputs, axis=-1, momentum=0.9, epsilon=epsilon, training=training)
466+
self.assertEqual(len(variables.global_variables()), 5)
467+
with variable_scope.variable_scope('scope', reuse=True):
468+
_ = normalization_layers.batch_norm(
469+
inputs, axis=-1, momentum=0.9, epsilon=epsilon, training=training)
470+
self.assertEqual(len(variables.global_variables()), 5)
471+
457472
def testNoCenter(self):
458473
bn = normalization_layers.BatchNormalization(axis=1, center=False)
459474
inputs = random_ops.random_uniform((5, 4, 3), seed=1)

0 commit comments

Comments
 (0)