auto_gradient_check.html 19.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10


<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
11
  <title>Auto Gradient Check Design &mdash; PaddlePaddle  文档</title>
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
  

  
  

  

  
  
    

  

  
  
    <link rel="stylesheet" href="../_static/css/theme.css" type="text/css" />
  

  
31

32 33 34 35 36 37 38 39 40 41 42 43 44
  
        <link rel="index" title="索引"
              href="../genindex.html"/>
        <link rel="search" title="搜索" href="../search.html"/>
    <link rel="top" title="PaddlePaddle  文档" href="../index.html"/> 

  
  <script src="../_static/js/modernizr.min.js"></script>

</head>

<body class="wy-body-for-nav" role="document">

45 46 47 48 49 50 51 52 53 54 55 56 57
  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-scroll">
        <div class="wy-side-nav-search">
          

          
            <a href="../index_cn.html" class="icon icon-home"> PaddlePaddle
          

          
58 59
          </a>

60 61 62 63 64 65
          
            
            
          

          
66 67 68 69 70 71
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
72
</div>
73 74

          
75 76 77 78 79 80 81 82 83 84 85 86
        </div>

        <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
          
            
            
                <ul>
<li class="toctree-l1"><a class="reference internal" href="../getstarted/index_cn.html">新手入门</a></li>
<li class="toctree-l1"><a class="reference internal" href="../build_and_install/index_cn.html">安装与编译</a></li>
<li class="toctree-l1"><a class="reference internal" href="../howto/index_cn.html">进阶使用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../dev/index_cn.html">开发标准</a></li>
<li class="toctree-l1"><a class="reference internal" href="../faq/index_cn.html">FAQ</a></li>
87 88
</ul>

89 90 91 92
            
          
        </div>
      </div>
93 94
    </nav>

95
    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
96

97 98 99 100 101
      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="../index_cn.html">PaddlePaddle</a>
      </nav>
102 103


104 105 106 107
      
      <div class="wy-nav-content">
        <div class="rst-content">
          
108

109
 
110 111 112 113 114



<div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
115
    <li><a href="../index_cn.html">Docs</a> &raquo;</li>
116
      
117
    <li>Auto Gradient Check Design</li>
118 119 120 121 122 123 124
      <li class="wy-breadcrumbs-aside">
        
          
            <a href="../_sources/design/auto_gradient_check.md.txt" rel="nofollow"> View page source</a>
          
        
      </li>
125
  </ul>
126
  <hr/>
127 128 129 130
</div>
          <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
           <div itemprop="articleBody">
            
131 132
  <div class="section" id="auto-gradient-check-design">
<span id="auto-gradient-check-design"></span><h1>Auto Gradient Check Design<a class="headerlink" href="#auto-gradient-check-design" title="永久链接至标题"></a></h1>
133
</div>
134 135
<div class="section" id="background">
<span id="background"></span><h1>Background:<a class="headerlink" href="#background" title="永久链接至标题"></a></h1>
136
<ul class="simple">
137 138 139 140
<li>Generally, it is easy to check whether the forward computation of an Operator is correct or not. However, backpropagation is a notoriously difficult algorithm to debug and get right because of the following challenges:<ol>
<li>The formula for backpropagation formula should be correct according to the forward computation.</li>
<li>The Implementation of the above shoule be correct in CPP.</li>
<li>It is difficult to prepare an unbiased test data.</li>
141 142
</ol>
</li>
143 144 145
<li>Auto gradient checking gets a numerical gradient using forward Operator and uses it as a reference for the backward Operator&#8217;s result. It has several advantages:<ol>
<li>Numerical gradient checker only needs the forward operator.</li>
<li>The user only needs to prepare the input data for forward Operator and not worry about the backward Operator.</li>
146 147 148 149 150 151
</ol>
</li>
</ul>
</div>
<div class="section" id="mathematical-theory">
<span id="mathematical-theory"></span><h1>Mathematical Theory<a class="headerlink" href="#mathematical-theory" title="永久链接至标题"></a></h1>
152
<p>The following documents from Stanford have a detailed explanation of how to compute the numerical gradient and why it is useful.</p>
153 154 155 156 157 158 159
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference external" href="http://deeplearning.stanford.edu/wiki/index.php/Gradient_checking_and_advanced_optimization">Gradient checking and advanced optimization(en)</a></li>
<li class="toctree-l1"><a class="reference external" href="http://ufldl.stanford.edu/wiki/index.php/%E6%A2%AF%E5%BA%A6%E6%A3%80%E9%AA%8C%E4%B8%8E%E9%AB%98%E7%BA%A7%E4%BC%98%E5%8C%96">Gradient checking and advanced optimization(cn)</a></li>
</ul>
</div>
</div>
160 161
<div class="section" id="numerical-gradient-implementation">
<span id="numerical-gradient-implementation"></span><h1>Numerical Gradient Implementation<a class="headerlink" href="#numerical-gradient-implementation" title="永久链接至标题"></a></h1>
162 163
<div class="section" id="python-interface">
<span id="python-interface"></span><h2>Python Interface<a class="headerlink" href="#python-interface" title="永久链接至标题"></a></h2>
164
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">get_numerical_gradient</span><span class="p">(</span><span class="n">op</span><span class="p">,</span>
165 166 167 168 169 170
                         <span class="n">input_values</span><span class="p">,</span>
                         <span class="n">output_name</span><span class="p">,</span>
                         <span class="n">input_to_check</span><span class="p">,</span>
                         <span class="n">delta</span><span class="o">=</span><span class="mf">0.005</span><span class="p">,</span>
                         <span class="n">local_scope</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
171
<span class="sd">    Get Numerical Gradient for the input of an operator.</span>
172

173
<span class="sd">    :param op: C++ operator instance, could be an network.</span>
174
<span class="sd">    :param input_values: The input variables. Should be an dictionary, whose key is</span>
175
<span class="sd">    variable name, and value is a numpy array.</span>
176
<span class="sd">    :param output_name: The final output variable name.</span>
177 178 179 180
<span class="sd">    :param input_to_check: The input variable with respect to which the gradient has to be computed.</span>
<span class="sd">    :param delta: The perturbation value for numerical gradient method. The</span>
<span class="sd">    smaller the delta, the more accurate the result. But if the delta is too</span>
<span class="sd">    small, it will suffer from the numerical stability problem.</span>
181 182 183 184 185 186
<span class="sd">    :param local_scope: The local scope used for get_numeric_gradient.</span>
<span class="sd">    :return: The gradient array in numpy format.</span>
<span class="sd">    &quot;&quot;&quot;</span>
</pre></div>
</div>
</div>
187 188
<div class="section" id="explanation">
<span id="explanation"></span><h2>Explanation:<a class="headerlink" href="#explanation" title="永久链接至标题"></a></h2>
189
<ul class="simple">
190 191
<li>Why do we need an <code class="docutils literal"><span class="pre">output_name</span></code><ul>
<li>An Operator may have multiple Outputs, one can compute an independent gradient from each Output. So the caller should specify the name of the output variable.</li>
192 193
</ul>
</li>
194 195
<li>Why do we need <code class="docutils literal"><span class="pre">input_to_check</span></code><ul>
<li>One operator can have multiple inputs. Gradient Op can calculate the gradient of these inputs at the same time. But Numerical Gradient needs to calculate them one by one. So <code class="docutils literal"><span class="pre">get_numeric_gradient</span></code> is designed to calculate the gradient for one input. If you need to compute multiple inputs, you can call <code class="docutils literal"><span class="pre">get_numeric_gradient</span></code> multiple times each with a different input.</li>
196 197 198 199 200 201
</ul>
</li>
</ul>
</div>
<div class="section" id="core-algorithm-implementation">
<span id="core-algorithm-implementation"></span><h2>Core Algorithm Implementation<a class="headerlink" href="#core-algorithm-implementation" title="永久链接至标题"></a></h2>
202
<div class="highlight-python"><div class="highlight"><pre><span></span>    <span class="c1"># we only compute the gradient of one element a time.</span>
203
    <span class="c1"># we use a for loop to compute the gradient of each element.</span>
204
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="n">tensor_size</span><span class="p">):</span>
205 206
        <span class="c1"># get one input element using the index i.</span>
        <span class="n">original</span> <span class="o">=</span> <span class="n">tensor_to_check</span><span class="o">.</span><span class="n">get_float_element</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
207

208 209 210
        <span class="c1"># add delta to it, run the forward op and then</span>
        <span class="c1"># get the new value of the result tensor.</span>
        <span class="n">x_pos</span> <span class="o">=</span> <span class="n">original</span> <span class="o">+</span> <span class="n">delta</span>
211 212 213
        <span class="n">tensor_to_check</span><span class="o">.</span><span class="n">set_float_element</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">x_pos</span><span class="p">)</span>
        <span class="n">y_pos</span> <span class="o">=</span> <span class="n">get_output</span><span class="p">()</span>

214 215 216
        <span class="c1"># Subtract delta from this element, run the op again</span>
        <span class="c1"># and get the new value of the result tensor.</span>
        <span class="n">x_neg</span> <span class="o">=</span> <span class="n">original</span> <span class="o">-</span> <span class="n">delta</span>
217 218 219 220
        <span class="n">tensor_to_check</span><span class="o">.</span><span class="n">set_float_element</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">x_neg</span><span class="p">)</span>
        <span class="n">y_neg</span> <span class="o">=</span> <span class="n">get_output</span><span class="p">()</span>

        <span class="c1"># restore old value</span>
221
        <span class="n">tensor_to_check</span><span class="o">.</span><span class="n">set_float_element</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">original</span><span class="p">)</span>
222

223 224
        <span class="c1"># compute the gradient of this element and store</span>
        <span class="c1"># it into a numpy array.</span>
225 226 227 228 229 230 231 232
        <span class="n">gradient_flat</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">y_pos</span> <span class="o">-</span> <span class="n">y_neg</span><span class="p">)</span> <span class="o">/</span> <span class="n">delta</span> <span class="o">/</span> <span class="mi">2</span>

    <span class="c1"># reshape the gradient result to the shape of the source tensor.</span>
    <span class="k">return</span> <span class="n">gradient_flat</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="n">tensor_to_check</span><span class="o">.</span><span class="n">get_dims</span><span class="p">())</span>
</pre></div>
</div>
</div>
</div>
233 234
<div class="section" id="auto-gradient-check-framework">
<span id="auto-gradient-check-framework"></span><h1>Auto Gradient Check Framework<a class="headerlink" href="#auto-gradient-check-framework" title="永久链接至标题"></a></h1>
235
<p>Each Operator Kernel has three kinds of Gradient:</p>
236 237 238
<ol class="simple">
<li>Numerical gradient</li>
<li>CPU kernel gradient</li>
239
<li>GPU kernel gradient (if supported by the device)</li>
240
</ol>
241
<p>The numerical gradient only relies on the forward Operator, so we use the numerical gradient as the reference value. The gradient checking is performed in the following three steps:</p>
242
<ol class="simple">
243 244 245
<li>Calculate the numerical gradient</li>
<li>Calculate CPU kernel gradient with the backward Operator and compare it with the numerical gradient.</li>
<li>Calculate GPU kernel gradient with the backward Operator and compare it with the numeric gradient. (if supported)</li>
246 247 248 249 250 251 252 253 254 255 256 257 258 259
</ol>
<div class="section" id="python-interface">
<span id="id1"></span><h2>Python Interface<a class="headerlink" href="#python-interface" title="永久链接至标题"></a></h2>
<div class="highlight-python"><div class="highlight"><pre><span></span>    <span class="k">def</span> <span class="nf">check_grad</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
                   <span class="n">forward_op</span><span class="p">,</span>
                   <span class="n">input_vars</span><span class="p">,</span>
                   <span class="n">inputs_to_check</span><span class="p">,</span>
                   <span class="n">output_name</span><span class="p">,</span>
                   <span class="n">no_grad_set</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
                   <span class="n">only_cpu</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span>
                   <span class="n">max_relative_error</span><span class="o">=</span><span class="mf">0.005</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        :param forward_op: used to create backward_op</span>
<span class="sd">        :param input_vars: numpy value of input variable. The following</span>
260 261 262
<span class="sd">          computation will use these variables.</span>
<span class="sd">        :param inputs_to_check: the input variable with respect to which the</span>
<span class="sd">          gradient will be computed.</span>
263
<span class="sd">        :param output_name: The final output variable name.</span>
264
<span class="sd">        :param max_relative_error: The relative tolerance parameter.</span>
265
<span class="sd">        :param no_grad_set: used to create backward ops</span>
266 267 268 269 270 271
<span class="sd">        :param only_cpu: only compute and check gradient on cpu kernel.</span>
<span class="sd">        :return:</span>
<span class="sd">        &quot;&quot;&quot;</span>
</pre></div>
</div>
</div>
272 273 274
<div class="section" id="how-to-check-if-two-numpy-arrays-are-close-enough">
<span id="how-to-check-if-two-numpy-arrays-are-close-enough"></span><h2>How to check if two numpy arrays are close enough?<a class="headerlink" href="#how-to-check-if-two-numpy-arrays-are-close-enough" title="永久链接至标题"></a></h2>
<p>if <code class="docutils literal"><span class="pre">abs_numerical_grad</span></code> is nearly zero, then use absolute error for numerical_grad.</p>
275
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">numerical_grad</span> <span class="o">=</span> <span class="o">...</span>
276 277
<span class="n">operator_grad</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">scope</span><span class="o">.</span><span class="n">find_var</span><span class="p">(</span><span class="n">grad_var_name</span><span class="p">(</span><span class="n">name</span><span class="p">))</span><span class="o">.</span><span class="n">get_tensor</span><span class="p">())</span>

278
<span class="n">abs_numerical_grad</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">abs</span><span class="p">(</span><span class="n">numerical_grad</span><span class="p">)</span>
279 280
<span class="c1"># if abs_numerical_grad is nearly zero, then use abs error for</span>
<span class="c1"># numeric_grad, instead of relative error.</span>
281
<span class="n">abs_numerical_grad</span><span class="p">[</span><span class="n">abs_numerical_grad</span> <span class="o">&lt;</span> <span class="mf">1e-3</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
282

283
<span class="n">diff_mat</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">abs</span><span class="p">(</span><span class="n">abs_numerical_grad</span> <span class="o">-</span> <span class="n">operator_grad</span><span class="p">)</span> <span class="o">/</span> <span class="n">abs_numerical_grad</span>
284 285 286 287 288
<span class="n">max_diff</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">diff_mat</span><span class="p">)</span>
</pre></div>
</div>
<div class="section" id="notes">
<span id="notes"></span><h3>Notes:<a class="headerlink" href="#notes" title="永久链接至标题"></a></h3>
289
<p>The Input data for auto gradient checker should be reasonable to avoid numerical stability problem.</p>
290
</div>
291 292
<div class="section" id="references">
<span id="references"></span><h3>References:<a class="headerlink" href="#references" title="永久链接至标题"></a></h3>
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference external" href="http://deeplearning.stanford.edu/wiki/index.php/Gradient_checking_and_advanced_optimization">Gradient checking and advanced optimization(en)</a></li>
<li class="toctree-l1"><a class="reference external" href="http://ufldl.stanford.edu/wiki/index.php/%E6%A2%AF%E5%BA%A6%E6%A3%80%E9%AA%8C%E4%B8%8E%E9%AB%98%E7%BA%A7%E4%BC%98%E5%8C%96">Gradient checking and advanced optimization(cn)</a></li>
</ul>
</div>
</div>
</div>
</div>


           </div>
          </div>
          <footer>
  

  <hr/>

  <div role="contentinfo">
    <p>
        &copy; Copyright 2016, PaddlePaddle developers.

    </p>
  </div>
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. 

</footer>

        </div>
      </div>

    </section>

  </div>
  


  

    <script type="text/javascript">
        var DOCUMENTATION_OPTIONS = {
            URL_ROOT:'../',
            VERSION:'',
            COLLAPSE_INDEX:false,
            FILE_SUFFIX:'.html',
338
            HAS_SOURCE:  true
339 340 341 342 343 344 345
        };
    </script>
      <script type="text/javascript" src="../_static/jquery.js"></script>
      <script type="text/javascript" src="../_static/underscore.js"></script>
      <script type="text/javascript" src="../_static/doctools.js"></script>
      <script type="text/javascript" src="../_static/translations.js"></script>
      <script type="text/javascript" src="https://cdn.bootcss.com/mathjax/2.7.0/MathJax.js"></script>
346

347 348 349 350 351 352
  

  
  
    <script type="text/javascript" src="../_static/js/theme.js"></script>
  
353

354
  
355 356 357 358 359 360 361
  
  <script type="text/javascript">
      jQuery(function () {
          SphinxRtdTheme.StickyNav.enable();
      });
  </script>
   
362 363 364

</body>
</html>