Skip to content

Commit fc8f7e9

Browse files
committed
updating batch norm
1 parent 26e3b48 commit fc8f7e9

2 files changed

Lines changed: 74 additions & 86 deletions

File tree

python/06_modern_convnet.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,27 @@
1616
mnist = MNIST()
1717
x = tf.placeholder(tf.float32, [None, 784])
1818
y = tf.placeholder(tf.float32, [None, 10])
19+
20+
# %% We add a new type of placeholder to denote when we are training.
21+
# This will be used to change the way we compute the network during
22+
# training/testing.
23+
is_training = tf.placeholder(tf.bool, name='is_training')
24+
25+
# %% We'll convert our MNIST vector data to a 4-D tensor:
26+
# N x W x H x C
1927
x_tensor = tf.reshape(x, [-1, 28, 28, 1])
2028

21-
# %% Define the network:
22-
bn1 = batch_norm(-1, name='bn1')
23-
bn2 = batch_norm(-1, name='bn2')
24-
bn3 = batch_norm(-1, name='bn3')
25-
h_1 = lrelu(bn1(conv2d(x_tensor, 32, name='conv1')), name='lrelu1')
26-
h_2 = lrelu(bn2(conv2d(h_1, 64, name='conv2')), name='lrelu2')
27-
h_3 = lrelu(bn3(conv2d(h_2, 64, name='conv3')), name='lrelu3')
29+
# %% We'll use a new method called batch normalization.
30+
# This process attempts to "reduce internal covariate shift"
31+
# which is a fancy way of saying that it will normalize updates for each
32+
# batch using a smoothed version of the batch mean and variance
33+
# The original paper proposes using this before any nonlinearities
34+
h_1 = lrelu(batch_norm(conv2d(x_tensor, 32, name='conv1'),
35+
is_training, scope='bn1'), name='lrelu1')
36+
h_2 = lrelu(batch_norm(conv2d(h_1, 64, name='conv2'),
37+
is_training, scope='bn2'), name='lrelu2')
38+
h_3 = lrelu(batch_norm(conv2d(h_2, 64, name='conv3'),
39+
is_training, scope='bn3'), name='lrelu3')
2840
h_3_flat = tf.reshape(h_3, [-1, 64 * 4 * 4])
2941
h_4 = linear(h_3_flat, 10)
3042
y_pred = tf.nn.softmax(h_4)
@@ -48,9 +60,10 @@
4860
for batch_i in range(mnist.train.num_examples // batch_size):
4961
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
5062
sess.run(train_step, feed_dict={
51-
x: batch_xs, y: batch_ys})
63+
x: batch_xs, y: batch_ys, is_training: True})
5264
print(sess.run(accuracy,
5365
feed_dict={
5466
x: mnist.validation.images,
55-
y: mnist.validation.labels
67+
y: mnist.validation.labels,
68+
is_training: False
5669
}))

python/libs/batch_norm.py

Lines changed: 52 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,63 @@
11
"""Batch Normalization for TensorFlow.
2-
Parag K. Mital, Jan 2016."""
2+
Parag K. Mital, Jan 2016.
3+
"""
34

45
import tensorflow as tf
6+
from tensorflow.python import control_flow_ops
57

68

7-
class batch_norm(object):
8-
"""Basic usage from: http://stackoverflow.com/a/33950177
9-
10-
Parag K. Mital, Jan 2016
11-
12-
Attributes
13-
----------
14-
batch_size : int
15-
Size of the batch. Set to -1 to fit to current net.
16-
beta : Tensor
17-
A 1D beta Tensor with size matching the last dimension of t.
18-
An offset to be added to the normalized tensor.
19-
ema : tf.train.ExponentialMovingAverage
20-
For computing the moving average.
21-
epsilon : float
22-
A small float number to avoid dividing by 0.
23-
gamma : Tensor
24-
If "scale_after_normalization" is true, this tensor will be multiplied
25-
with the normalized tensor.
26-
momentum : float
27-
The decay to use for the moving average.
28-
name : str
29-
The variable scope for all variables under batch normalization.
9+
def batch_norm(x, phase_train, scope='bn', affine=True):
3010
"""
11+
Batch normalization on convolutional maps.
3112
32-
def __init__(self, batch_size, epsilon=1e-5,
33-
momentum=0.1, name="batch_norm"):
34-
"""Summary
35-
36-
Parameters
37-
----------
38-
batch_size : int
39-
Size of the batch, or -1 for size to fit.
40-
epsilon : float, optional
41-
A small float number to avoid dividing by 0.
42-
momentum : float, optional
43-
Decay to use for the moving average.
44-
name : str, optional
45-
Variable scope will be under this prefix.
46-
"""
47-
with tf.variable_scope(name) as scope:
48-
self.epsilon = epsilon
49-
self.momentum = momentum
50-
self.batch_size = batch_size
51-
self.ema = tf.train.ExponentialMovingAverage(decay=self.momentum)
52-
self.name = name
53-
54-
def __call__(self, x, train=True):
55-
"""Applies/updates the BN to the input Tensor.
13+
from: https://stackoverflow.com/questions/33949786/how-could-i-
14+
use-batch-normalization-in-tensorflow
5615
57-
Parameters
58-
----------
59-
x : Tensor
60-
The input tensor to normalize.
61-
train : bool, optional
62-
Whether or not to train parameters.
16+
Only modified to infer shape from input tensor x.
6317
64-
Returns
65-
-------
66-
x_normed : Tensor
67-
The normalized Tensor.
68-
"""
18+
Parameters
19+
----------
20+
x
21+
Tensor, 4D BHWD input maps
22+
phase_train
23+
boolean tf.Variable, true indicates training phase
24+
scope
25+
string, variable scope
26+
affine
27+
whether to affine-transform outputs
28+
29+
Return
30+
------
31+
normed
32+
batch-normalized maps
33+
"""
34+
with tf.variable_scope(scope):
6935
shape = x.get_shape().as_list()
7036

71-
# Using a variable scope means any new variables
72-
# will be prefixed with "variable_scope/", e.g.:
73-
# "variable_scope/new_variable". Also, using
74-
# TensorBoard, this will make everything very
75-
# nicely grouped.
76-
with tf.variable_scope(self.name) as scope:
77-
self.gamma = tf.get_variable(
78-
"gamma", [shape[-1]],
79-
initializer=tf.random_normal_initializer(1., 0.02))
80-
self.beta = tf.get_variable(
81-
"beta", [shape[-1]],
82-
initializer=tf.constant_initializer(0.))
83-
84-
mean, variance = tf.nn.moments(x, [0, 1, 2])
85-
86-
return tf.nn.batch_norm_with_global_normalization(
87-
x, mean, variance, self.beta, self.gamma, self.epsilon,
88-
scale_after_normalization=True)
37+
beta = tf.Variable(tf.constant(0.0, shape=[shape[-1]]),
38+
name='beta', trainable=True)
39+
gamma = tf.Variable(tf.constant(1.0, shape=[shape[-1]]),
40+
name='gamma', trainable=affine)
41+
42+
batch_mean, batch_var = tf.nn.moments(x, [0, 1, 2], name='moments')
43+
ema = tf.train.ExponentialMovingAverage(decay=0.9)
44+
ema_apply_op = ema.apply([batch_mean, batch_var])
45+
ema_mean, ema_var = ema.average(batch_mean), ema.average(batch_var)
46+
47+
def mean_var_with_update():
48+
"""Summary
49+
50+
Returns
51+
-------
52+
name : TYPE
53+
Description
54+
"""
55+
with tf.control_dependencies([ema_apply_op]):
56+
return tf.identity(batch_mean), tf.identity(batch_var)
57+
mean, var = control_flow_ops.cond(phase_train,
58+
mean_var_with_update,
59+
lambda: (ema_mean, ema_var))
60+
61+
normed = tf.nn.batch_norm_with_global_normalization(
62+
x, mean, var, beta, gamma, 1e-3, affine)
63+
return normed

0 commit comments

Comments
 (0)