<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Dishank Bansal on Medium]]></title>
        <description><![CDATA[Stories by Dishank Bansal on Medium]]></description>
        <link>https://medium.com/@theshank?source=rss-c38f52524a15------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*wNd--XF8l3dxbM_o.</url>
            <title>Stories by Dishank Bansal on Medium</title>
            <link>https://medium.com/@theshank?source=rss-c38f52524a15------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 04:54:25 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@theshank/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Pitfalls of Batch Norm in TensorFlow and Sanity Checks for Training Networks]]></title>
            <link>https://medium.com/data-science/pitfalls-of-batch-norm-in-tensorflow-and-sanity-checks-for-training-networks-e86c207548c8?source=rss-c38f52524a15------2</link>
            <guid isPermaLink="false">https://medium.com/p/e86c207548c8</guid>
            <category><![CDATA[machine-learning-tutorial]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[tensorflow]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Dishank Bansal]]></dc:creator>
            <pubDate>Tue, 26 Jun 2018 07:33:45 GMT</pubDate>
            <atom:updated>2018-12-02T23:46:54.319Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uu5uU4EPi86Uzb37DzogmA.png" /></figure><h4>In this post I will write about mistakes we make when writing our deep learning model and some sanity checks, which will help you to narrow down the little daemons and save your nights’ sleep.</h4><h3>I. Let’s get done with Batch Norm in TensorFlow, once and for all</h3><h4>Brief Theory of Batch Normalization</h4><p>This revolutionary technique is introduced by Sergey Ioffe, Christian Szegedy in the <a href="https://arxiv.org/pdf/1502.03167.pdf">paper</a><a href="https://arxiv.org/abs/1502.03167">,</a> and this is cited for 4994 times as of now. According to the paper, batch normalization reduces the internal covariance shift i.e. it makes the learning of layers in the network more independent of each other. The objective of batch norm layer is to make input to the activation layer, unit Gaussian, so that neuron does not get saturate in case of sigmoid and tanh. It helps in fast convergence of network, allows you to be care free about weight initialization, works as regularization in place of dropout and other regularization techniques. Now I won’t be discussing much of theoretical details but more on implementation. I will take you through implementation of batch norm in TensorFlow and its mathematics. <br>At Training Time -</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/386/1*U0ZFNnQZnuldcHFN14Dy-Q.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/350/1*Ki4E1TnC-0ZtkFhFuLGrOg.png" /><figcaption>At training time. Images taken from Batch Normalization paper.</figcaption></figure><p>Now suppose that batch norm layer is used between convolution layer and activation, then <strong><em>x</em></strong> is the output of convolution layer, and <strong><em>y</em></strong> is output of batch norm layer and input to activation layer, which may be ReLU, sigmoid, etc. Batch Norm layer learns the parameter <strong><em>γ</em></strong> and <strong><em>β</em></strong>, and <strong><em>y</em></strong> depends on their values. Hence, it is shown that best representation of <strong><em>x</em></strong> is learnt using <strong><em>γ</em></strong> and <strong><em>β</em></strong>. Please, note other two statistics which are <strong><em>E[x]</em></strong> and <strong><em>Var[x]</em></strong>, population mean and variance. They are estimated through moving mean and moving variance during training.</p><p>At Inference Time -</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/247/1*2wEyEM8-6XEXbmVWiK88Xw.png" /><figcaption>At inference time</figcaption></figure><p>Forward pass through batch norm layer at inference is different than at training. At inference, instead of batch mean(<strong><em>μ</em></strong>) and variance(<strong><em>σ2</em></strong>) we use population mean(<strong><em>E[x]</em></strong>) and variance(<strong><em>Var[x]</em></strong>) to calculate <strong><em>x^</em></strong>. Suppose you give batch of size one during inference and normalize using batch mean and batch variance, in that case <strong><em>x^=0</em></strong> as <strong><em>μ=x </em></strong>then <strong><em>y=β</em></strong>, which shows that layer output<em>(</em><strong><em>y</em></strong><em>)</em> will be same for any input<em>(</em><strong><em>x</em></strong><em>)</em> which is wrong. Hence to normalize at inference time we use population mean and variance which we were calculating during training using moving mean and variance. In the next section, we will go through the implementation of Batch Norm in TensorFlow.</p><h4>Caveats of Batch Norm in TF</h4><ul><li><strong>Moving mean and variance not updating:<br></strong>TensorFlow is graph based, calculations is performed in order of dependencies.</li></ul><pre>import tensorflow as tf</pre><pre>a = tf.placeholder(tf.float32, shape=[1,3])<br>b = tf.placeholder(tf.float32, shape=[1,3])<br>c = tf.Variable(tf.zeros([1, 3]), dtype=tf.float32)</pre><pre><br>def train(a,b):<br>    c = tf.add(c,a)<br>    e = some_train_op(a,b)<br>    return e</pre><pre>output = train(a,b)<br>loss = tf.log(output)</pre><pre>sess = tf.Session()<br>saver = tf.train.Saver()<br>sess.run(tf.global_variables_initializer())</pre><pre>for itr in range(1000):<br>    ls = sess.run(loss, {a:x, b:y})</pre><pre>saver.save(sess, some_path)</pre><pre>#Note that this code is for reference only. </pre><p>Now, in this we run the <strong><em>loss</em></strong> tensor in each iteration, for every iteration <strong><em>train </em></strong>function will be called. <strong><em>c</em></strong> is a variable to sum the value of <strong><em>a</em></strong> for all iteration. So, when we save the model, we expect variable <strong><em>c</em></strong> to be equal to summation of all values passed to placeholder <strong><em>a</em></strong> in each iteration.</p><p>Let’s analyze in detail, the dependencies in graph of this model. When we run <strong><em>loss</em></strong> tensor, <strong><em>output</em></strong> will be computed then <strong><em>output</em></strong> will call the<strong> <em>train</em></strong> from which value of <strong><em>e</em></strong> will be needed which will be calculated using <strong><em>a</em></strong> and <strong><em>b</em></strong>. In all this computation <strong><em>c</em></strong> won’t be evaluated at all as value of <strong><em>loss</em></strong> tensor does not depend on <strong><em>c</em></strong>. Solution is to add <strong><em>c</em> </strong>as dependency before computing <strong><em>e</em></strong>. Therefore, solution</p><pre>def train(a,b):<br>    c = tf.add(c,a)<br>    with tf.control_dependencies([c]):<br>        e = some_train_op(a,b)<br>    return e</pre><p>When training the network we call the optimizer op which does all the computations and updates all the weights, but optimizer op never depends upon computation of moving mean or variance. Hence, moving mean and variance never get updates and remain at their initialized value.</p><p>Solution: TensorFlow provide major three functions for batch normalization</p><pre><strong>tf.nn.batch_normalization()</strong> - Never use this for training, it just compute the y = gamma*x^hat + beta where x^hat = (x-mean)/std_dev.<br>It doesn&#39;t account for keeping moving mean and variance. </pre><pre><strong>tf.layers.batch_normalization() </strong>-<strong> </strong>This function can be used for your model. Note: Always add batch norm dependency when using this, either on optimizer op or any other op which you sure that will execute when optimizer op is run. ex:-</pre><pre>update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)                            with tf.control_dependencies(update_ops):                                                            <br>    self.solver = tf.train.AdamOptimizer(learning_rate=1e-04) <br>                  .minimize(self.loss)</pre><pre>Here tf.GraphKeys.UPDATE_OPS is the collections which have moving mean and variance op. </pre><pre><strong>tf.contrib.layers.batch_norm()</strong> - This function is in contrib module of TensorFlow. This function gives two ways to add dependencies as follows:<br>1.It has &#39;<em>update</em>&#39; parameter, set <em>update=None</em> while calling the function and dependency will be added inside the function itself and you don&#39;t have to anything else.<br><strong>Note:This is believed to be slow in comparison to the next method.</strong></pre><pre>2. Let the <em>update</em> parameter have it&#39;s default value which is &quot;<em>tf.GraphKeys.UPDATE_OPS</em>&quot;. Now here also you have to manually add dependency as above with tf.layers.batch_normalization().</pre><p>Hence, you can use either <strong>tf.layers.batch_normalization() or tf.contrib.layers.batch_norm() </strong>with proper update dependency handling.</p><ul><li><strong>Different usage at train and test time:</strong><br>From train to test time, we have to switch between batch mean and variance or population mean and variance. We have parameters is_trainingand training in tf.contrib.layers.batch_norm() and tf.nn.batch_normalization() respectively. When its value is True, batch mean &amp; variance is used and moving mean and variance is updated for estimating population mean and variance. On False, population mean and variance is used. Hence you should use a placeholder train_phase for this. So, solution looks like the following</li></ul><pre>def Bn(x, <strong>is_train</strong>):<br>        return tf.contrib.layers.batch_norm(x, decay= 0.99,                                                                                                               <br>          <strong><em>is_training=is_train</em></strong>,center= True, scale=True, <br>          reuse= False)</pre><pre><em>train_phase = tf.placeholder(tf.bool, name=&quot;is_training&quot;)</em><br>data = tf.placeholder(tf.float32, shape=[None,240,240,3],                                                                                                        name=&quot;Image&quot;)                                         </pre><pre>bn_layer = Bn(data, train_phase)</pre><pre>loss = some_loss_op()</pre><pre>solver = tf.train.AdamOptimizer().minimize(loss)</pre><pre># Training iteration<br>sess.run(solver, {data: input_data, <em>train_phase:True</em>})</pre><pre>#Validation iteration<br>sess.run(loss, {data: input_data, <em>train_phase:False</em>})</pre><ul><li><strong>Sharing Batch Norm parameters:<br></strong>Often you share weights in two parallel networks such as siamese or in discriminators of GANs. When you share your weights, batch norm parameters also get shared. Sometimes, sharing batch norm parameters across two networks can not be healthy, I will tell you exactly when. <br>Let’s say we are training a GAN, it will have two discriminator instance with share parameters, when the training starts, distributions of fake and real images are different. Now here we are updating the moving mean and variance with two different distributions, one is of fake images and the other real one. But as the training continues and generator learns the distribution of real data, then distribution of both fake and real data eventually becomes approximately same. Then we are updating the mean and variance with same distribution, so our population mean and variance should be estimated statistics of real data after complete training. Hence, theoretically, sharing batch norm parameter may not be such a big problem in case of GANs. But I will do some experiments in both the conditions and update about the empirical results with new blog. <br>Now <a href="https://www.alexirpan.com/2017/04/26/perils-batch-norm.html"><strong>this blog post</strong></a> can be good explanation with better visualization for cases where sharing batch norm parameters can adversely affect the accuracy of the model. <br>In a nutshell, sharing batch norm parameters is okay until input distributions to both shared batch norm layers are same, if this is not the case try to use reuse=False in above mentioned batch norm functions, which will allow you to have independent batch norm parameters for both of your networks in which you wanted to share weights.</li></ul><h4>II. Sanity Checks and Debugging -</h4><ul><li><strong>End to End Image Models:</strong><br>In tasks like image segmentation or depth prediction that have image as an input, we expect a equally sized image as an output. Train your model to learn identity function i.e. give input image as the target image. In this case the network will represent a identity function. If this is trained perfectly but still you are unable to learn segmentation or depth, may be your model doesn’t have enough capacity. You can try to add some more layers or may be better loss function for your task.</li><li><strong>Target and output range:</strong><br>If you have normalized your target image in 0 to 1, then make sure in the image generating layer to have sigmoid as activation function and not tanh, as tanh will have range -1 to 1 which will make learning difficult. If normalized between -1 to 1, then use tanh.</li><li><strong>Fluctuating Loss:</strong><br>Most probable reason can be that your model doesn’t have enough capacity. Hence weights changes rapidly to learn the model but due to limited capacity they keep changing their weights rapidly but never getting to close to optimum. You should also try decreasing the learning rate.</li><li><strong>Hyper-parameters:</strong><br>Never ignore hyper-parameters. They may not be very crucial for accuracy and performance of your network in general, but are definitely very important for convergence and stability of training. Negligent weight initialization may cause exploiting/vanishing gradients or NaNs in your network. Check the std_dev of your weight initialization in case you are using normal distribution, range [0.2, 0.01] is okay. Learning rate and batch size are first thing to experiment with if loss is behaving abnormally.</li><li><strong>Shuffling of sequential data:</strong><br>When your input data is sequential which most often happen with videos such as in autonomous driving like segmentation, depth prediction, etc. You should consider shuffling the data, training with sequential data can adversely affect model accuracy at testing. <br><strong>Note: You should have sequential data whenever task requires temporal consistency like optical flow, visual odometry, etc.</strong></li><li><strong>Scaling the losses:</strong><br>In case you are using more than one type of loss in your network such as MSE, adversarial, L1, <a href="https://arxiv.org/pdf/1603.08155.pdf">feature loss</a>, <a href="https://www.tensorflow.org/api_docs/python/tf/image/ssim">SSIM</a> then make sure all losses are scaled properly to be of same order i.e. of mse is in order of 1e-01 and feature loss is of order of 1e03, then scale the feature loss to be of same order.</li><li><strong>Graph Visualization, Greatest weapon in this war:</strong><br>If you re using TF and other framework having visualization tool. You should use visualization to check for connections, they will help you to find out missed connection, dimension error or weight sharing error.</li><li><strong>Sharing Batch Norm parameter:</strong><br>As mentioned above, if you are sharing batch norm parameters in two networks then make sure that input data distribution of both network is same.</li></ul><p>This <a href="https://blog.slavv.com/37-reasons-why-your-neural-network-is-not-working-4020854bd607">blog post</a> also have exhaustive list of other reasons for failure of your network.</p><p>Thank you all for reading this blog, I hope that it will save your struggle with batch norm and training networks. I welcome all your comments and do let me know if want to add anything or feel any content to be misleading. You can reach me at dishank.bansal@iitkgp.ac.in for your queries.</p><h4>References:</h4><ul><li><a href="https://arxiv.org/abs/1502.03167">https://arxiv.org/abs/1502.03167</a> — Batch norm paper</li><li><a href="https://r2rt.com/implementing-batch-normalization-in-tensorflow.html">https://r2rt.com/implementing-batch-normalization-in-tensorflow.html</a></li><li><a href="https://medium.com/machine-learning-world/how-to-debug-neural-networks-manual-dc2a200f10f2">https://medium.com/machine-learning-world/how-to-debug-neural-networks-manual-dc2a200f10f2</a></li><li><a href="https://github.com/tensorflow/tensorflow/blob/r1.8/tensorflow/python/layers/normalization.py">https://github.com/tensorflow/tensorflow/blob/r1.8/tensorflow/python/layers/normalization.py</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e86c207548c8" width="1" height="1" alt=""><hr><p><a href="https://medium.com/data-science/pitfalls-of-batch-norm-in-tensorflow-and-sanity-checks-for-training-networks-e86c207548c8">Pitfalls of Batch Norm in TensorFlow and Sanity Checks for Training Networks</a> was originally published in <a href="https://medium.com/data-science">TDS Archive</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>