<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>MNIST &#8211; 编码无悔 /  Intent &amp; Focused</title>
	<atom:link href="https://www.codelast.com/tag/mnist/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.codelast.com</link>
	<description>最优化之路</description>
	<lastBuildDate>Mon, 27 Apr 2020 17:09:23 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>[原创] 《Neural Networks and Deep Learning》读书笔记：最简单的识别MNIST的神经网络程序(2)</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e3%80%8aneural-networks-and-deep-learning%e3%80%8b%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0%ef%bc%9a%e6%9c%80%e7%ae%80%e5%8d%95%e7%9a%84%e8%af%86%e5%88%abmnist%e7%9a%84%e7%a5%9e-2/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e3%80%8aneural-networks-and-deep-learning%e3%80%8b%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0%ef%bc%9a%e6%9c%80%e7%ae%80%e5%8d%95%e7%9a%84%e8%af%86%e5%88%abmnist%e7%9a%84%e7%a5%9e-2/#comments</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Thu, 31 Aug 2017 16:52:30 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[deep learning]]></category>
		<category><![CDATA[MNIST]]></category>
		<category><![CDATA[Neural Networks]]></category>
		<category><![CDATA[深度学习]]></category>
		<category><![CDATA[神经网络]]></category>
		<guid isPermaLink="false">http://www.codelast.com/?p=9083</guid>

					<description><![CDATA[<p>
本文是<a href="https://www.codelast.com/?p=9040" target="_blank" rel="noopener noreferrer"><span style="background-color: rgb(255, 160, 122);">上一篇文章</span></a>的续文。<br />
《<a href="http://neuralnetworksanddeeplearning.com/" target="_blank" rel="noopener noreferrer">Neural Networks and Deep Learning</a>》一书的中文译名是《神经网络与深度学习》，书如其名，不需要解释也知道它是讲什么的，这是本入门级的好书。<br />
在第一章中，作者展示了如何编写一个简单的、用于识别MNIST数据的Python神经网络程序。<br />
本文接着上一篇文章对程序代码进行解析。<br />
<span id="more-9083"></span><br />
下面来看看 SGD() 方法的实现。先把它的完整代码贴上来：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &#34;Lucida Console&#34;, &#34;DejaVu Sans Mono&#34;, Monaco, &#34;Courier New&#34;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 238, 128);">def</span> <span style="color: rgb(255, 221, 0);">SGD</span><span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(204, 204, 204);">self</span>, <span style="color: rgb(204, 204, 204);">training_data</span>, <span style="color: rgb(204, 204, 204);">epochs</span>, <span style="color: rgb(204, 204, 204);">mini_batch_size</span>, <span style="color: rgb(204, 204, 204);">eta</span>,
        <span style="color: rgb(204, 204, 204);">test_data</span><span style="color: rgb(255, 157, 0);">=</span><span style="color: rgb(255, 98, 140);">None</span><span style="color: rgb(225, 239, 255);">)</span><span style="color: rgb(225, 239, 255);">:</span>
    <span style="color: rgb(58, 217, 0);">&#34;&#34;&#34;</span>Train the neural network using mini-batch stochastic
    gradient descent.</pre>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e3%80%8aneural-networks-and-deep-learning%e3%80%8b%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0%ef%bc%9a%e6%9c%80%e7%ae%80%e5%8d%95%e7%9a%84%e8%af%86%e5%88%abmnist%e7%9a%84%e7%a5%9e-2/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p>
本文是<a href="https://www.codelast.com/?p=9040" target="_blank" rel="noopener noreferrer"><span style="background-color: rgb(255, 160, 122);">上一篇文章</span></a>的续文。<br />
《<a href="http://neuralnetworksanddeeplearning.com/" target="_blank" rel="noopener noreferrer">Neural Networks and Deep Learning</a>》一书的中文译名是《神经网络与深度学习》，书如其名，不需要解释也知道它是讲什么的，这是本入门级的好书。<br />
在第一章中，作者展示了如何编写一个简单的、用于识别MNIST数据的Python神经网络程序。<br />
本文接着上一篇文章对程序代码进行解析。<br />
<span id="more-9083"></span><br />
下面来看看 SGD() 方法的实现。先把它的完整代码贴上来：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 238, 128);">def</span> <span style="color: rgb(255, 221, 0);">SGD</span><span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(204, 204, 204);">self</span>, <span style="color: rgb(204, 204, 204);">training_data</span>, <span style="color: rgb(204, 204, 204);">epochs</span>, <span style="color: rgb(204, 204, 204);">mini_batch_size</span>, <span style="color: rgb(204, 204, 204);">eta</span>,
        <span style="color: rgb(204, 204, 204);">test_data</span><span style="color: rgb(255, 157, 0);">=</span><span style="color: rgb(255, 98, 140);">None</span><span style="color: rgb(225, 239, 255);">)</span><span style="color: rgb(225, 239, 255);">:</span>
    <span style="color: rgb(58, 217, 0);">&quot;&quot;&quot;</span>Train the neural network using mini-batch stochastic
    gradient descent.  The ``training_data`` is a list of tuples
    ``(x, y)`` representing the training inputs and the desired
    outputs.  The other non-optional parameters are
    self-explanatory.  If ``test_data`` is provided then the
    network will be evaluated against the test data after each
    epoch, and partial progress printed out.  This is useful for
    tracking progress, but slows things down substantially.<span style="color: rgb(58, 217, 0);">&quot;&quot;&quot;</span>
    <span style="color: rgb(255, 157, 0);">if</span> test_data: n_test <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(255, 176, 84);">len</span><span style="color: rgb(225, 239, 255);">(</span>test_data<span style="color: rgb(225, 239, 255);">)</span></span>
    n <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(255, 176, 84);">len</span><span style="color: rgb(225, 239, 255);">(</span>training_data<span style="color: rgb(225, 239, 255);">)</span></span>
    <span style="color: rgb(255, 157, 0);">for</span> j <span style="color: rgb(255, 157, 0);">in</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(128, 255, 187);">xrange</span><span style="color: rgb(225, 239, 255);">(</span>epochs<span style="color: rgb(225, 239, 255);">)</span></span>:
        <span style="color: rgb(255, 238, 128);">random.shuffle<span style="color: rgb(225, 239, 255);">(</span>training_data<span style="color: rgb(225, 239, 255);">)</span></span>
        mini_batches <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(225, 239, 255);">[</span>
            training_data<span style="color: rgb(225, 239, 255);">[</span>k:k <span style="color: rgb(255, 157, 0);">+</span> mini_batch_size<span style="color: rgb(225, 239, 255);">]</span>
            <span style="color: rgb(255, 157, 0);">for</span> k <span style="color: rgb(255, 157, 0);">in</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(128, 255, 187);">xrange</span><span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(255, 98, 140);">0</span>, n, mini_batch_size<span style="color: rgb(225, 239, 255);">)</span></span><span style="color: rgb(225, 239, 255);">]</span>
        <span style="color: rgb(255, 157, 0);">for</span> mini_batch <span style="color: rgb(255, 157, 0);">in</span> mini_batches:
            <span style="color: rgb(255, 238, 128);"><span style="color: rgb(255, 128, 225);">self</span>.update_mini_batch<span style="color: rgb(225, 239, 255);">(</span>mini_batch, eta<span style="color: rgb(225, 239, 255);">)</span></span>
        <span style="color: rgb(255, 157, 0);">if</span> test_data:
            <span style="color: rgb(255, 157, 0);">print</span> <span style="color: rgb(58, 217, 0);">&quot;</span>Epoch {0}: {1} / {2}<span style="color: rgb(58, 217, 0);">&quot;</span>.<span style="color: rgb(255, 238, 128);">format<span style="color: rgb(225, 239, 255);">(</span>
                j, <span style="color: rgb(255, 128, 225);">self</span>.evaluate<span style="color: rgb(225, 239, 255);">(</span>test_data<span style="color: rgb(225, 239, 255);">)</span>, n_test<span style="color: rgb(225, 239, 255);">)</span></span>
        <span style="color: rgb(255, 157, 0);">else</span>:
            <span style="color: rgb(255, 157, 0);">print</span> <span style="color: rgb(58, 217, 0);">&quot;</span>Epoch {0} complete<span style="color: rgb(58, 217, 0);">&quot;</span>.<span style="color: rgb(255, 238, 128);">format<span style="color: rgb(225, 239, 255);">(</span>j<span style="color: rgb(225, 239, 255);">)</span></span></pre>
<p>代码自带详细注释，而且很容易看懂。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(0, 0, 255);">for j in xrange(epochs)</span>&nbsp;这句代码使得训练会进行epoch轮。<br />
xrang()是Python自带函数，随便试验一下就知道它的作用了，例如：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 157, 0);">for</span> j <span style="color: rgb(255, 157, 0);">in</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(128, 255, 187);">xrange</span><span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(255, 98, 140);">4</span><span style="color: rgb(225, 239, 255);">)</span></span>:
    <span style="color: rgb(255, 157, 0);">print</span>(j)</pre>
<p>这段代码输出的结果是：</p>
<blockquote>
<div>
		0</div>
<div>
		1</div>
<div>
		2</div>
<div>
		3</div>
</blockquote>
<p>所以，如果我们把epoch定义成4，那么循环就会进行4次，也就是说训练会进行4轮。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
显然，<span style="color: rgb(0, 0, 255);">for j in xrange(epochs)</span>&nbsp;下面的循环体里的代码，就是每一轮训练要执行的代码。<br />
首先，<span style="color: rgb(0, 0, 255);">random.shuffle(training_data)</span>这一句的作用是什么呢？答：随机打乱training_data这个list。<br />
为了说明它，我们打开ipython，来做一个相当简单的试验：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 157, 0);">import</span> numpy <span style="color: rgb(255, 157, 0);">as</span> np
<span style="color: rgb(255, 157, 0);">import</span> random
a <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(225, 239, 255);">[</span>(<span style="color: rgb(255, 98, 140);">1</span>, <span style="color: rgb(255, 98, 140);">2</span>)<span style="color: rgb(225, 239, 255);">,</span> (<span style="color: rgb(255, 98, 140);">3</span>, <span style="color: rgb(255, 98, 140);">4</span>)<span style="color: rgb(225, 239, 255);">,</span> (<span style="color: rgb(255, 98, 140);">5</span>, <span style="color: rgb(255, 98, 140);">6</span>)<span style="color: rgb(225, 239, 255);">,</span> (<span style="color: rgb(255, 98, 140);">7</span>, <span style="color: rgb(255, 98, 140);">8</span>)<span style="color: rgb(225, 239, 255);">,</span> (<span style="color: rgb(255, 98, 140);">0</span>, <span style="color: rgb(255, 98, 140);">9</span>)<span style="color: rgb(225, 239, 255);">]</span>
<span style="color: rgb(255, 238, 128);">random.shuffle<span style="color: rgb(225, 239, 255);">(</span>a<span style="color: rgb(225, 239, 255);">)</span></span>
<span style="color: rgb(255, 157, 0);">print</span>(a)
<span style="color: rgb(255, 238, 128);">random.shuffle<span style="color: rgb(225, 239, 255);">(</span>a<span style="color: rgb(225, 239, 255);">)</span></span>
<span style="color: rgb(255, 157, 0);">print</span>(a)
<span style="color: rgb(255, 238, 128);">random.shuffle<span style="color: rgb(225, 239, 255);">(</span>a<span style="color: rgb(225, 239, 255);">)</span></span>
<span style="color: rgb(255, 157, 0);">print</span>(a)</pre>
<p>在上面的代码中，打印了3次 a 的内容，在我的PC上，3次print的输出分别如下：</p>
<blockquote>
<p>
		[(7, 8), (0, 9), (1, 2), (3, 4), (5, 6)]<br />
		[(3, 4), (5, 6), (0, 9), (7, 8), (1, 2)]<br />
		[(1, 2), (0, 9), (5, 6), (3, 4), (7, 8)]</p>
</blockquote>
<p>可见，<span style="color: rgb(0, 0, 255);">random.shuffle()</span>把list里的元素进行了随机打乱。由于是随机的，所以，你的测试结果可能和我的不一样。<br />
随机打乱数据是为了防止某些pattern相似的输入数据集中在一个batch中，导致对训练结果产生负面影响。SGD不就是&ldquo;<span style="color: rgb(0, 0, 255);">随机</span>梯度下降&rdquo;嘛。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
在打乱数据之后，程序就把所有输入数据拆分成了若干个批量（mini batch），每一个batch的大小是由mini_batch_size定义的：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
mini_batches <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(225, 239, 255);">[</span>
    training_data<span style="color: rgb(225, 239, 255);">[</span>k:k<span style="color: rgb(255, 157, 0);">+</span>mini_batch_size<span style="color: rgb(225, 239, 255);">]</span>
    <span style="color: rgb(255, 157, 0);">for</span> k <span style="color: rgb(255, 157, 0);">in</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(128, 255, 187);">xrange</span><span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(255, 98, 140);">0</span>, n, mini_batch_size<span style="color: rgb(225, 239, 255);">)</span></span><span style="color: rgb(225, 239, 255);">]</span></pre>
<p>这里的xrange用法和上面的xrange稍有不同，我们还是用一个实例来表明它的作用：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 157, 0);">for</span> k <span style="color: rgb(255, 157, 0);">in</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(128, 255, 187);">xrange</span><span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(255, 98, 140);">0</span>, <span style="color: rgb(255, 98, 140);">10</span>, <span style="color: rgb(255, 98, 140);">3</span><span style="color: rgb(225, 239, 255);">)</span></span>:
    <span style="color: rgb(255, 157, 0);">print</span>(k)</pre>
<p>这段代码把mini_batch_size设置成了3，它的输出结果是：</p>
<blockquote>
<div>
		0</div>
<div>
		3</div>
<div>
		6</div>
<div>
		9</div>
</blockquote>
<div>
	可见，它会使k从0开始，按mini_batch_size的大小为步长递增，但最大值不超过第二个参数。<br />
	所以，training_data也是按这个套路实现了分割。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	在training_data分割得到了若干个mini batch之后，下面就是对每一个mini batch分别进行训练，从而求得参数向量 <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f1290186a5d0b1ceab27f4e77c0c5d68.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="w" /></span><script type='math/tex'>w</script> 和 <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_92eb5ffee6ae2fec3ad71c777531578f.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="b" /></span><script type='math/tex'>b</script> 的值。但这里是一个串行的计算，也就是说第一个mini batch计算完了，才轮到第二个mini batch计算，依此类推。<br />
	对每一个mini batch求解参数向量，其实就是这一句代码调用（eta即  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_7174cbd6aeaaa56e37102b72386bb2b9.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\eta " /></span><script type='math/tex'>\eta </script> ，学习率，这是一个人为设定其值的超参数）：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 238, 128);"><span style="color: rgb(255, 128, 225);">self</span>.update_mini_batch<span style="color: rgb(225, 239, 255);">(</span>mini_batch, eta<span style="color: rgb(225, 239, 255);">)</span></span></pre>
<p>	有人可能会说，这跟待求的参数向量 <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f1290186a5d0b1ceab27f4e77c0c5d68.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="w" /></span><script type='math/tex'>w</script> 和 <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_92eb5ffee6ae2fec3ad71c777531578f.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="b" /></span><script type='math/tex'>b</script> 没什么关系啊？在上一篇文章中我们看到， <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f1290186a5d0b1ceab27f4e77c0c5d68.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="w" /></span><script type='math/tex'>w</script> 和 <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_92eb5ffee6ae2fec3ad71c777531578f.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="b" /></span><script type='math/tex'>b</script> 被定义成了Network类的成员变量，update_mini_batch()其实是在函数体内计算出、并更新了它们的值，所以只是表面上看起来&ldquo;没关系&rdquo;，实际上完全有关系。</p>
<p>	在循环迭代完所有的mini batch之后， <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f1290186a5d0b1ceab27f4e77c0c5d68.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="w" /></span><script type='math/tex'>w</script> 和 <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_92eb5ffee6ae2fec3ad71c777531578f.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="b" /></span><script type='math/tex'>b</script> 的值也就被更新完了，即&ldquo;学习&rdquo;的过程也就结束了。所以，随着迭代的进行， <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f1290186a5d0b1ceab27f4e77c0c5d68.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="w" /></span><script type='math/tex'>w</script> 和 <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_92eb5ffee6ae2fec3ad71c777531578f.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="b" /></span><script type='math/tex'>b</script> 的值越来越接近理想值，所有迭代结束之后，我们就认为 <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f1290186a5d0b1ceab27f4e77c0c5d68.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="w" /></span><script type='math/tex'>w</script> 和 <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_92eb5ffee6ae2fec3ad71c777531578f.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="b" /></span><script type='math/tex'>b</script> 的值已经达到了理想值。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	在每一轮迭代的最后，有下面这段代码：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 157, 0);">if</span> test_data:
    <span style="color: rgb(255, 157, 0);">print</span> <span style="color: rgb(58, 217, 0);">&quot;</span>Epoch {0}: {1} / {2}<span style="color: rgb(58, 217, 0);">&quot;</span>.<span style="color: rgb(255, 238, 128);">format<span style="color: rgb(225, 239, 255);">(</span>j, <span style="color: rgb(255, 128, 225);">self</span>.evaluate<span style="color: rgb(225, 239, 255);">(</span>test_data<span style="color: rgb(225, 239, 255);">)</span>, n_test<span style="color: rgb(225, 239, 255);">)</span></span>
<span style="color: rgb(255, 157, 0);">else</span>:
    <span style="color: rgb(255, 157, 0);">print</span> <span style="color: rgb(58, 217, 0);">&quot;</span>Epoch {0} complete<span style="color: rgb(58, 217, 0);">&quot;</span>.<span style="color: rgb(255, 238, 128);">format<span style="color: rgb(225, 239, 255);">(</span>j<span style="color: rgb(225, 239, 255);">)</span></span></pre>
<p>	在每一轮迭代更新完 <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f1290186a5d0b1ceab27f4e77c0c5d68.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="w" /></span><script type='math/tex'>w</script> 和 <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_92eb5ffee6ae2fec3ad71c777531578f.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="b" /></span><script type='math/tex'>b</script> 的值之后，如果test_data不为空的话，那么就会用evaluate()方法对本轮的计算结果进行评估。理论上，随着迭代一轮一轮的进行，评估结果应该越来越好。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	所以，现在最关键的代码就封装在了<span style="color: rgb(255, 238, 128); background-color: rgb(0, 34, 64); font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; font-size: 0.9333em;">update_mini_batch</span><span style="background-color: rgb(0, 34, 64); font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; font-size: 0.9333em; color: rgb(225, 239, 255);">(</span><span style="background-color: rgb(0, 34, 64); font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; font-size: 0.9333em; color: rgb(225, 239, 255);">)</span>方法中。这个方法是怎么对 <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f1290186a5d0b1ceab27f4e77c0c5d68.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="w" /></span><script type='math/tex'>w</script> 和 <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_92eb5ffee6ae2fec3ad71c777531578f.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="b" /></span><script type='math/tex'>b</script> 进行计算的呢？且听下回分解。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
	转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
	感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
		<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e3%80%8aneural-networks-and-deep-learning%e3%80%8b%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0%ef%bc%9a%e6%9c%80%e7%ae%80%e5%8d%95%e7%9a%84%e8%af%86%e5%88%abmnist%e7%9a%84%e7%a5%9e-2/feed/</wfw:commentRss>
			<slash:comments>8</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 《Neural Networks and Deep Learning》读书笔记：反向传播的4个基本方程(1)</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e3%80%8aneural-networks-and-deep-learning%e3%80%8b%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0%ef%bc%9a%e5%8f%8d%e5%90%91%e4%bc%a0%e6%92%ad%e7%9a%844%e4%b8%aa%e5%9f%ba%e6%9c%ac%e6%96%b9/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e3%80%8aneural-networks-and-deep-learning%e3%80%8b%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0%ef%bc%9a%e5%8f%8d%e5%90%91%e4%bc%a0%e6%92%ad%e7%9a%844%e4%b8%aa%e5%9f%ba%e6%9c%ac%e6%96%b9/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Sat, 21 Jan 2017 09:40:11 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[deep learning]]></category>
		<category><![CDATA[MNIST]]></category>
		<category><![CDATA[Neural Networks]]></category>
		<category><![CDATA[深度学习]]></category>
		<category><![CDATA[神经网络]]></category>
		<guid isPermaLink="false">http://www.codelast.com/?p=9085</guid>

					<description><![CDATA[<p>
从<span style="color:#0000ff;">反向传播的4个基本方程</span>这部分内容开始，《Neural Networks and Deep Learning》一书基本上是满屏的数学公式了，然而，得益于作者强大的、深入浅出的表述能力，理解起来并不会让人感觉那么难。<br />
本文将描述<span style="color:#b22222;">反向传播</span>的4个基本方程中的第一个&#8212;&#8212;<span style="color:#ff0000;">输出层误差的方程</span>：<br />
<span id="more-9085"></span><br />
<span style="color:#ff0000;"> <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f7724be9538063b9d5c68ffb82ddd15b.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\delta _j^L = \frac{{\partial C}}{{\partial a_j^L}}\sigma '\left( {z_j^L} \right)" /></span><script type='math/tex'>\delta _j^L = \frac{{\partial C}}{{\partial a_j^L}}\sigma '\left( {z_j^L} \right)</script> </span><br />
就算完全看不懂这个公式的含义，也千万不要被吓到，毕竟它才如此之短。<br />
本文将解释一下这个公式的含义。但我必须得说，如果没有上下文的话，再怎么看解释也是没用的，毕竟这些符号是什么意思都是作者定义的，所以，必须结合原书来理解。<br />
其中：<br />
<span style="color:#800080;">（1）</span> <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_4ae590f679b31f133939d1df256ac831.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\delta _j^L" /></span><script type='math/tex'>\delta _j^L</script> &#160;代表神经网络的第 L 层、第 j 个神经元产生的误差。<br />
<span style="color:#800080;">（2）</span>C 代表代价函数（cost function），a 代表神经网络的输出激活（activation）值，由于每一个神经元都有一个输出激活值，所以 a 是一个向量。把 a 看成一个变量， <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_67c812b472c1a6cf2a58e6abd6a802f0.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\frac{{\partial C}}{{\partial a}}" /></span><script type='math/tex'>\frac{{\partial C}}{{\partial a}}</script>  就表示用代价函数对输出激活值求导。<br />
<span style="color:#800080;">（3）</span> <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_9d43cb8bbcb702e9d5943de477f099e2.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\sigma " /></span><script type='math/tex'>\sigma </script>  是作者书中所说的&#8220;<span style="color:#0000ff;">向量化函数</span>&#8221;，其实就是激活函数，因为作者在书的前面章节中已经定义过&#160; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_ad7cca5ff8e6f6f28cce41a3441d7f6e.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="{a^l} = \sigma ({w^l}{a^{l - 1}} + {b^l})" /></span><script type='math/tex'>{a^l} = \sigma ({w^l}{a^{l - 1}} + {b^l})</script> ，所以输出激活值就是把<span style="color:#b22222;">带权输入</span>再应用一个&#160; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_9d43cb8bbcb702e9d5943de477f099e2.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\sigma " /></span><script type='math/tex'>\sigma </script> ，这就是激活函数。<br />
<span style="color:#800080;">（4）</span>z 代表的是<span style="color: rgb(178, 34, 34);">带权输入</span>，即&#160; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_7aff64f9c576b307da59f0d9c46f72fa.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="{z^l} = {w^l}{a^{l - 1}} + {b^l}" /></span><script type='math/tex'>{z^l} = {w^l}{a^{l - 1}} + {b^l}</script> ，把 z 看作变量，所以&#160; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_665290b678082738b67e8866ad3f6a80.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\sigma '\left( {z_j^L} \right)" /></span><script type='math/tex'>\sigma '\left( {z_j^L} \right)</script>  表示的就是激活函数对带权输入求导。数学公式已经忘得差不多的话，一定要注意这里不是表示两个式子相乘，而是一个表示求导的式子。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">http://www.codelast.com/</span></a>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e3%80%8aneural-networks-and-deep-learning%e3%80%8b%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0%ef%bc%9a%e5%8f%8d%e5%90%91%e4%bc%a0%e6%92%ad%e7%9a%844%e4%b8%aa%e5%9f%ba%e6%9c%ac%e6%96%b9/" class="read-more">Read More </a></p>]]></description>
										<content:encoded><![CDATA[<p>
从<span style="color:#0000ff;">反向传播的4个基本方程</span>这部分内容开始，《Neural Networks and Deep Learning》一书基本上是满屏的数学公式了，然而，得益于作者强大的、深入浅出的表述能力，理解起来并不会让人感觉那么难。<br />
本文将描述<span style="color:#b22222;">反向传播</span>的4个基本方程中的第一个&mdash;&mdash;<span style="color:#ff0000;">输出层误差的方程</span>：<br />
<span id="more-9085"></span><br />
<span style="color:#ff0000;"> <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f7724be9538063b9d5c68ffb82ddd15b.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\delta _j^L = \frac{{\partial C}}{{\partial a_j^L}}\sigma '\left( {z_j^L} \right)" /></span><script type='math/tex'>\delta _j^L = \frac{{\partial C}}{{\partial a_j^L}}\sigma '\left( {z_j^L} \right)</script> </span><br />
就算完全看不懂这个公式的含义，也千万不要被吓到，毕竟它才如此之短。<br />
本文将解释一下这个公式的含义。但我必须得说，如果没有上下文的话，再怎么看解释也是没用的，毕竟这些符号是什么意思都是作者定义的，所以，必须结合原书来理解。<br />
其中：<br />
<span style="color:#800080;">（1）</span> <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_4ae590f679b31f133939d1df256ac831.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\delta _j^L" /></span><script type='math/tex'>\delta _j^L</script> &nbsp;代表神经网络的第 L 层、第 j 个神经元产生的误差。<br />
<span style="color:#800080;">（2）</span>C 代表代价函数（cost function），a 代表神经网络的输出激活（activation）值，由于每一个神经元都有一个输出激活值，所以 a 是一个向量。把 a 看成一个变量， <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_67c812b472c1a6cf2a58e6abd6a802f0.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\frac{{\partial C}}{{\partial a}}" /></span><script type='math/tex'>\frac{{\partial C}}{{\partial a}}</script>  就表示用代价函数对输出激活值求导。<br />
<span style="color:#800080;">（3）</span> <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_9d43cb8bbcb702e9d5943de477f099e2.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\sigma " /></span><script type='math/tex'>\sigma </script>  是作者书中所说的&ldquo;<span style="color:#0000ff;">向量化函数</span>&rdquo;，其实就是激活函数，因为作者在书的前面章节中已经定义过&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_ad7cca5ff8e6f6f28cce41a3441d7f6e.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="{a^l} = \sigma ({w^l}{a^{l - 1}} + {b^l})" /></span><script type='math/tex'>{a^l} = \sigma ({w^l}{a^{l - 1}} + {b^l})</script> ，所以输出激活值就是把<span style="color:#b22222;">带权输入</span>再应用一个&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_9d43cb8bbcb702e9d5943de477f099e2.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\sigma " /></span><script type='math/tex'>\sigma </script> ，这就是激活函数。<br />
<span style="color:#800080;">（4）</span>z 代表的是<span style="color: rgb(178, 34, 34);">带权输入</span>，即&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_7aff64f9c576b307da59f0d9c46f72fa.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="{z^l} = {w^l}{a^{l - 1}} + {b^l}" /></span><script type='math/tex'>{z^l} = {w^l}{a^{l - 1}} + {b^l}</script> ，把 z 看作变量，所以&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_665290b678082738b67e8866ad3f6a80.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\sigma '\left( {z_j^L} \right)" /></span><script type='math/tex'>\sigma '\left( {z_j^L} \right)</script>  表示的就是激活函数对带权输入求导。数学公式已经忘得差不多的话，一定要注意这里不是表示两个式子相乘，而是一个表示求导的式子。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">http://www.codelast.com/</span></a><br />
现在先看（1）：为了理解这句话，要从此书前面部分的『<span style="color:#0000ff;">关于代价函数的两个假设</span>』一节说起。&ldquo;两个假设&rdquo;中的其中一个就是，神经网络的<span style="color:#0000ff;">代价</span>（cost）可以写成神经网络输出的激活值的函数：<br />
<span style="color:#ff0000;"> <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_c140bf6a84c352f4941c1fbbd96d72bf.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="C = C({a^L})" /></span><script type='math/tex'>C = C({a^L})</script> </span><br />
这里的  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_b24b7014b32a21b48434c4dc90e272f5.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="{a^L}" /></span><script type='math/tex'>{a^L}</script>  是一个向量，因为神经网络的某一层，会有N个神经元，每一个神经元都有一个输出激活值，例如&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_a6ee74264b8efe21daa277d6a32e6a4d.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="a_1^L" /></span><script type='math/tex'>a_1^L</script> ， <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_ee7f68db7b4500a06b7ce49f490f34bd.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="a_2^L" /></span><script type='math/tex'>a_2^L</script> ，等等。</p>
<p>知道了这一点，再来看看这句话里所说的<span style="color:#0000ff;">误差</span>是什么？在机器学习中，我们的目的是最小化代价函数（cost function），而根据高等数学的<a href="https://zh.wikipedia.org/wiki/%E5%AF%BC%E6%95%B0" target="_blank" rel="noopener noreferrer"><span style="background-color:#ffa07a;">导数</span></a>知识：</p>
<blockquote>
<p>
		一个函数在某一点的导数描述了这个函数在这一点附近的变化率。</p>
</blockquote>
<p>因此，如果用代价函数对输出激活值  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_b24b7014b32a21b48434c4dc90e272f5.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="{a^L}" /></span><script type='math/tex'>{a^L}</script>  求导，就可以刻划出输出激活值的改变，会对cost造成多大的影响： <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_6d5c8b4e1efeb9d3bf57b095b549b70b.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\frac{{\partial C}}{{\partial a_j^L}}" /></span><script type='math/tex'>\frac{{\partial C}}{{\partial a_j^L}}</script> <br />
顺水推舟，作者就定义了一个&ldquo;<span style="color:#0000ff;">误差</span>&rdquo;的概念，用来表示神经元的输出变化，会对cost造成多大的影响&mdash;&mdash;影响大，误差就大；影响小，误差就小。<br />
但是这里有一个概念上的替换需要注意：作者实际上并没有把误差定义成代价函数对输出激活值&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_b24b7014b32a21b48434c4dc90e272f5.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="{a^L}" /></span><script type='math/tex'>{a^L}</script>  的导数&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_6d5c8b4e1efeb9d3bf57b095b549b70b.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\frac{{\partial C}}{{\partial a_j^L}}" /></span><script type='math/tex'>\frac{{\partial C}}{{\partial a_j^L}}</script> ，而是代价函数对<span style="color:#b22222;">带权输入</span>  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_fbade9e36a3f36d3d676c1b808451dd7.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="z" /></span><script type='math/tex'>z</script> &nbsp;的导数  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_4bdf803130ad568f303aa3aea44348a4.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\frac{{\partial C}}{{\partial z_j^l}}" /></span><script type='math/tex'>\frac{{\partial C}}{{\partial z_j^l}}</script> <br />
我第一眼看到这个定义的时候，觉得把误差定义成代价函数对输出激活值的导数更自然&mdash;&mdash;作者已经在书里解释了为什么要这样做：结果是差不多的，但是数学推导会变得更复杂，所以就把误差定义成了一个看起来&ldquo;不那么自然&rdquo;的东西。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">http://www.codelast.com/</span></a><br />
总结一下：<br />
已知  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_485a27644c57abe902e57bac5197c811.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="C = C(a)" /></span><script type='math/tex'>C = C(a)</script> ， <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_37f6ccbcab27d286ebbc515145a1fa15.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="a = \sigma (z)" /></span><script type='math/tex'>a = \sigma (z)</script> ，并且我们希望用 C 对 z 的导数  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_41a29dbb5b21e86b7f278488ad365929.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\frac{{\partial C}}{{\partial z}}" /></span><script type='math/tex'>\frac{{\partial C}}{{\partial z}}</script>  来表示神经元的输出对 cost 造成的影响，所以根据<a href="https://zh.wikipedia.org/wiki/%E9%93%BE%E5%BC%8F%E6%B3%95%E5%88%99" target="_blank" rel="noopener noreferrer"><span style="background-color:#ffa07a;">复合函数的求导法则</span></a>，就可以得到反向传播的第一个基本方程了。</p>
<p>但有一点奇怪的是，为什么要定义这个&ldquo;误差&rdquo;呢？定义它是为了能找到计算&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_48399ef60145fb8d5497d0bd079929bc.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\frac{{\partial C}}{{\partial w}}" /></span><script type='math/tex'>\frac{{\partial C}}{{\partial w}}</script>  以及&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_3a62ff0b93cabadeea7fce624442a362.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="\frac{{\partial C}}{{\partial b}}" /></span><script type='math/tex'>\frac{{\partial C}}{{\partial b}}</script>  的方法&mdash;&mdash;计算这两个值就是反向传播的目的。</p>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e3%80%8aneural-networks-and-deep-learning%e3%80%8b%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0%ef%bc%9a%e5%8f%8d%e5%90%91%e4%bc%a0%e6%92%ad%e7%9a%844%e4%b8%aa%e5%9f%ba%e6%9c%ac%e6%96%b9/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 《Neural Networks and Deep Learning》读书笔记：最简单的识别MNIST的神经网络程序(1)</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e3%80%8aneural-networks-and-deep-learning%e3%80%8b%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0%ef%bc%9a%e6%9c%80%e7%ae%80%e5%8d%95%e7%9a%84%e8%af%86%e5%88%abmnist%e7%9a%84%e7%a5%9e/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e3%80%8aneural-networks-and-deep-learning%e3%80%8b%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0%ef%bc%9a%e6%9c%80%e7%ae%80%e5%8d%95%e7%9a%84%e8%af%86%e5%88%abmnist%e7%9a%84%e7%a5%9e/#comments</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Wed, 04 Jan 2017 16:27:05 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[deep learning]]></category>
		<category><![CDATA[MNIST]]></category>
		<category><![CDATA[Neural Networks]]></category>
		<category><![CDATA[深度学习]]></category>
		<category><![CDATA[神经网络]]></category>
		<guid isPermaLink="false">http://www.codelast.com/?p=9040</guid>

					<description><![CDATA[<p>
《<a href="http://neuralnetworksanddeeplearning.com/" rel="noopener noreferrer" target="_blank">Neural Networks and Deep Learning</a>》一书的中文译名是《神经网络与深度学习》，书如其名，不需要解释也知道它是讲什么的，这是本入门级的好书。<br />
在第一章中，作者展示了如何编写一个简单的、用于识别MNIST数据的Python神经网络程序。对于武林高手来说，看懂程序不会有任何困难，但对于我这样的Python渣则有很多困惑。所以我对做了一些笔记，希望同时也可以帮助有需要的人。<br />
<span id="more-9040"></span><br />
<span style="background-color:#00ff00;">『1』</span>原文及程序<br />
在这里，先把<a href="https://hit-scir.gitbooks.io/neural-networks-and-deep-learning-zh_cn/content/chap1/c1s6.html" rel="noopener noreferrer" target="_blank"><span style="background-color:#ffa07a;">中译版</span></a>部分贴上来，以方便后面的笔记记录（这只是一部分）：</p>
<p>在给出一个完整的清单之前，让我解释一下神经网络代码的核心特征，如下。核心是一个Network类，我们用来表示一个神经网络。这是我们用来初始化一个Network对象的代码:</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &#34;Lucida Console&#34;, &#34;DejaVu Sans Mono&#34;, Monaco, &#34;Courier New&#34;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 238, 128);">class</span> <span style="color: rgb(255, 221, 0);">Network</span><span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(128, 252, 255); font-style: italic;"><span style="color: rgb(128, 255, 187);">object</span></span><span style="color: rgb(225, 239, 255);">)</span><span style="color: rgb(225, 239, 255);">:</span>

    <span style="color: rgb(255, 238, 128);">def</span> <span style="color: rgb(255, 221, 0);"><span style="color: rgb(255, 176, 84);">__init__</span></span><span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(204, 204, 204);">self</span>, <span style="color: rgb(204, 204, 204);">sizes</span><span style="color: rgb(225, 239, 255);">)</span><span style="color: rgb(225, 239, 255);">:</span>
        <span style="color: rgb(255, 128, 225);">self</span>.num_layers <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(255, 176, 84);">len</span><span style="color: rgb(225, 239, 255);">(</span>sizes<span style="color: rgb(225, 239, 255);">)</span></span>
        <span style="color: rgb(255, 128, 225);">self</span>.sizes <span style="color: rgb(255, 157, 0);">=</span> sizes
        <span style="color: rgb(255, 128, 225);">self</span>.biases</pre>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e3%80%8aneural-networks-and-deep-learning%e3%80%8b%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0%ef%bc%9a%e6%9c%80%e7%ae%80%e5%8d%95%e7%9a%84%e8%af%86%e5%88%abmnist%e7%9a%84%e7%a5%9e/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p>
《<a href="http://neuralnetworksanddeeplearning.com/" rel="noopener noreferrer" target="_blank">Neural Networks and Deep Learning</a>》一书的中文译名是《神经网络与深度学习》，书如其名，不需要解释也知道它是讲什么的，这是本入门级的好书。<br />
在第一章中，作者展示了如何编写一个简单的、用于识别MNIST数据的Python神经网络程序。对于武林高手来说，看懂程序不会有任何困难，但对于我这样的Python渣则有很多困惑。所以我对做了一些笔记，希望同时也可以帮助有需要的人。<br />
<span id="more-9040"></span><br />
<span style="background-color:#00ff00;">『1』</span>原文及程序<br />
在这里，先把<a href="https://hit-scir.gitbooks.io/neural-networks-and-deep-learning-zh_cn/content/chap1/c1s6.html" rel="noopener noreferrer" target="_blank"><span style="background-color:#ffa07a;">中译版</span></a>部分贴上来，以方便后面的笔记记录（这只是一部分）：</p>
<p>在给出一个完整的清单之前，让我解释一下神经网络代码的核心特征，如下。核心是一个Network类，我们用来表示一个神经网络。这是我们用来初始化一个Network对象的代码:</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 238, 128);">class</span> <span style="color: rgb(255, 221, 0);">Network</span><span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(128, 252, 255); font-style: italic;"><span style="color: rgb(128, 255, 187);">object</span></span><span style="color: rgb(225, 239, 255);">)</span><span style="color: rgb(225, 239, 255);">:</span>

    <span style="color: rgb(255, 238, 128);">def</span> <span style="color: rgb(255, 221, 0);"><span style="color: rgb(255, 176, 84);">__init__</span></span><span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(204, 204, 204);">self</span>, <span style="color: rgb(204, 204, 204);">sizes</span><span style="color: rgb(225, 239, 255);">)</span><span style="color: rgb(225, 239, 255);">:</span>
        <span style="color: rgb(255, 128, 225);">self</span>.num_layers <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(255, 176, 84);">len</span><span style="color: rgb(225, 239, 255);">(</span>sizes<span style="color: rgb(225, 239, 255);">)</span></span>
        <span style="color: rgb(255, 128, 225);">self</span>.sizes <span style="color: rgb(255, 157, 0);">=</span> sizes
        <span style="color: rgb(255, 128, 225);">self</span>.biases <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 238, 128);">np.random.randn<span style="color: rgb(225, 239, 255);">(</span>y, <span style="color: rgb(255, 98, 140);">1</span><span style="color: rgb(225, 239, 255);">)</span></span> <span style="color: rgb(255, 157, 0);">for</span> y <span style="color: rgb(255, 157, 0);">in</span> sizes<span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 98, 140);">1</span>:<span style="color: rgb(225, 239, 255);">]</span><span style="color: rgb(225, 239, 255);">]</span>
        <span style="color: rgb(255, 128, 225);">self</span>.weights <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 238, 128);">np.random.randn<span style="color: rgb(225, 239, 255);">(</span>y, x<span style="color: rgb(225, 239, 255);">)</span></span> 
                        <span style="color: rgb(255, 157, 0);">for</span> x<span style="color: rgb(225, 239, 255);">,</span> y <span style="color: rgb(255, 157, 0);">in</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(255, 176, 84);">zip</span><span style="color: rgb(225, 239, 255);">(</span>sizes<span style="color: rgb(225, 239, 255);">[</span>:<span style="color: rgb(255, 157, 0);">-</span><span style="color: rgb(255, 98, 140);">1</span><span style="color: rgb(225, 239, 255);">]</span>, sizes<span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 98, 140);">1</span>:<span style="color: rgb(225, 239, 255);">]</span><span style="color: rgb(225, 239, 255);">)</span></span><span style="color: rgb(225, 239, 255);">]</span></pre>
<p></p>
<div>
	在这段代码中，列表sizes包含各层的神经元的数量。因此举个例子，如果我们想创建一个在第一层有2个神经元，第二层有3个神经元，最后一层有1个神经元的network对象，我们应这样写代码：</div>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
net <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(255, 238, 128);">Network<span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 98, 140);">2</span><span style="color: rgb(225, 239, 255);">,</span> <span style="color: rgb(255, 98, 140);">3</span><span style="color: rgb(225, 239, 255);">,</span> <span style="color: rgb(255, 98, 140);">1</span><span style="color: rgb(225, 239, 255);">]</span><span style="color: rgb(225, 239, 255);">)</span></span></pre>
<div>
	Network对象的偏差和权重都是被随机初始化的，使用Numpy的np.random.randn函数来生成均值为0，标准差为1的高斯分布。随机初始化给了我们的随机梯度下降算法一个起点。在后面的章节中我们将会发现更好的初始化权重和偏差的方法，但是现在将采用随机初始化。注意Network初始化代码假设第一层神经元是一个输入层，并对这些神经元不设置任何偏差，因为偏差仅在之后的层中使用。</div>
<div>
	同样注意，偏差和权重以列表存储在Numpy矩阵中。因此例如net.weights[1]是一个存储着连接第二层和第三层神经元权重的Numpy矩阵。（不是第一层和第二层，因为Python列中的索引从0开始）因此net.weights[1]相当冗长， 让我们就这样表示矩阵  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f1290186a5d0b1ceab27f4e77c0c5d68.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="w" /></span><script type='math/tex'>w</script>  。矩阵中的  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_6272ace6cf2db632988cf861215b8a01.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="{w_{jk}}" /></span><script type='math/tex'>{w_{jk}}</script>  是连接第二层的  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f7f7aa85081ca5a607c85e1c66bbaec4.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="{k^{th}}" /></span><script type='math/tex'>{k^{th}}</script>  神经元和第三层的  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_2aa0fb91ffd58e2722ab0090e22de59a.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="{j^{th}}" /></span><script type='math/tex'>{j^{th}}</script>  神经元的权重。</p>
<p>	<span style="background-color: rgb(0, 255, 0);">『2』</span>程序解读<br />
	正如上面的代码示例，创建一个Network对象的时候，传入的是一个list，例如 [2, 3, 1]，list中有几个元素就表示神经网络有几层，从list中的第一个元素开始，每一个元素依次表示第1层、每2层、&hellip;&hellip;第n层的神经元的数量。<br />
	这个不难理解，比较难理解的是 bias（偏差）以及 weight（权重）的表示方式。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	我们先来看 bias（偏差）：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 128, 225);">self</span>.biases <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 238, 128);">np.random.randn<span style="color: rgb(225, 239, 255);">(</span>y, <span style="color: rgb(255, 98, 140);">1</span><span style="color: rgb(225, 239, 255);">)</span></span> <span style="color: rgb(255, 157, 0);">for</span> y <span style="color: rgb(255, 157, 0);">in</span> sizes<span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 98, 140);">1</span>:<span style="color: rgb(225, 239, 255);">]</span><span style="color: rgb(225, 239, 255);">]</span></pre>
<p>	首先需要明确的是，中括号表明了 biases 是一个list，中括号里的内容是对这个list进行赋值的代码，它采用了一个for循环的方式来赋值，例如下面的代码：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
a <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(225, 239, 255);">[</span>i <span style="color: rgb(255, 157, 0);">for</span> i <span style="color: rgb(255, 157, 0);">in</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(255, 176, 84);">range</span><span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(255, 98, 140);">3</span><span style="color: rgb(225, 239, 255);">)</span></span><span style="color: rgb(225, 239, 255);">]</span>
<span style="color: rgb(255, 157, 0);">print</span>(a)</pre>
<p>	会输出结果：</p>
<blockquote>
<p>
			[0, 1, 2]</p>
</blockquote>
<p>	所以，np.random.randn(y, 1) for y in sizes[1:] 这部分代码表达的就是&mdash;&mdash; list中的每一个元素都是 np.random.randn(y, 1) 这个表达式的计算结果，而这个表达式是含有变量 y 的，y 必须要有实际的值才能计算，所以用一个for循环来给 y 赋值，y 能取的所有值就是对&nbsp;sizes[1:] 这个list进行遍历得到的。前面已经说过了，sizes本身是一个list，而sizes[1:] 表示的是取这个 list 从第2个元素开始的子集，给个例子：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
a <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 98, 140);">5</span><span style="color: rgb(225, 239, 255);">,</span> <span style="color: rgb(255, 98, 140);">6</span><span style="color: rgb(225, 239, 255);">,</span> <span style="color: rgb(255, 98, 140);">8</span><span style="color: rgb(225, 239, 255);">]</span>
<span style="color: rgb(255, 157, 0);">print</span>(a<span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 98, 140);">1</span>:<span style="color: rgb(225, 239, 255);">]</span>)</pre>
<p>	会输出：</p>
<blockquote>
<p>
			[6, 8]</p>
</blockquote>
<p>	所以，在我们前面用&nbsp;net = Network([2, 3, 1]) 这样的代码来创建了一个对象之后，sizes[1:] 的内容其实就是 <span style="color:#0000ff;">[3, 1]</span>，所以 y 的取值就是 3 和 1，所以 biases 这个list的第一个元素就是&nbsp;np.random.randn(3, 1)，第二个元素就是&nbsp;np.random.randn(1, 1)。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	我觉得经过这样解释，biases 在结构上看来是什么东西已经比较清楚了吧？<br />
	那么话说回来，我们虽然知道了 np.random.randn(3, 1) 是 biases 的第一个元素，但 np.random.randn() 又是什么鬼？<br />
	且听我道来：<br />
	np 是这个Python程序 import 进来的Numpy库的缩写：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 157, 0);">import</span> numpy <span style="color: rgb(255, 157, 0);">as</span> np</pre>
<p>	<a href="https://docs.scipy.org/doc/numpy/reference/generated/numpy.random.randn.html" rel="noopener noreferrer" target="_blank"><span style="background-color:#ffa07a;">randn()</span></a> 是Numpy这个库中，用于生成标准正态分布数据的一个函数。其实 randn(3, 1) 生成的是一个3x1的随机矩阵，我们可以在Python命令行中直接试验一下：</div>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 157, 0);">import</span> numpy <span style="color: rgb(255, 157, 0);">as</span> np

<span style="color: rgb(255, 238, 128);">np.random.randn<span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(255, 98, 140);">3</span>, <span style="color: rgb(255, 98, 140);">1</span><span style="color: rgb(225, 239, 255);">)</span></span></pre>
<p>
输出结果如下：</p>
<blockquote>
<div>
		array([[ 1.33160979],</div>
<div>
		&nbsp; &nbsp; &nbsp; &nbsp;[ 0.66314905],</div>
<div>
		&nbsp; &nbsp; &nbsp; &nbsp;[ 0.27303603]])</div>
</blockquote>
<p>可见，它输出的是一个3行，1列的随机数矩阵&mdash;&mdash;你看这输出多体贴，为了表明&ldquo;3行1列&rdquo;，它没有把数字都排在一行，而是特意放在了3行里。<br />
好了，现在我们已经彻底了解了 biases 的结构，那么再来看看，为什么它的第一个元素是3x1的矩阵，第二个元素是1x1的矩阵呢？<br />
这跟要创建的神经网络层的结构有关。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
如作者书中所说，&ldquo;假设第一层神经元是一个输入层，并对这些神经元不设置任何偏差，因为偏差仅在之后的层中使用&rdquo;，所以 biases 只有两个元素，而不是3个。但知道了这一点并不能解决我们心中的疑惑：为什么 biases[0] 是一个 3x1 的矩阵，biases[1] 是一个 1x1 的矩阵呢？</p>
<p>这就跟weight（权重）有关了，所以，我们不妨先来看看代码中，weight是如何定义的：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 128, 225);">self</span>.weights <span style="color: rgb(255, 157, 0);">=</span> <span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 238, 128);">np.random.randn<span style="color: rgb(225, 239, 255);">(</span>y, x<span style="color: rgb(225, 239, 255);">)</span></span> <span style="color: rgb(255, 157, 0);">for</span> x<span style="color: rgb(225, 239, 255);">,</span> y <span style="color: rgb(255, 157, 0);">in</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(255, 176, 84);">zip</span><span style="color: rgb(225, 239, 255);">(</span>sizes<span style="color: rgb(225, 239, 255);">[</span>:<span style="color: rgb(255, 157, 0);">-</span><span style="color: rgb(255, 98, 140);">1</span><span style="color: rgb(225, 239, 255);">]</span>, sizes<span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 98, 140);">1</span>:<span style="color: rgb(225, 239, 255);">]</span><span style="color: rgb(225, 239, 255);">)</span></span><span style="color: rgb(225, 239, 255);">]</span></pre>
<p>这个冗长的实现需要&ldquo;细细品味&rdquo;。<br />
首先，中括号表明 weights 是一个list，中括号里的代码对这个list的每一个元素进行赋值，list中的每一个元素都是一个 <span style="color:#0000ff;">np.random.randn(y, x)</span> &mdash;&mdash;这个东西我们刚才在解释 biases 的时候已经说过了，它是一个y行x列的随机数矩阵。那么y和x的具体值又是什么呢？它们是由for循环定义的：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 157, 0);">for</span> x, y <span style="color: rgb(255, 157, 0);">in</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(255, 176, 84);">zip</span><span style="color: rgb(225, 239, 255);">(</span>sizes<span style="color: rgb(225, 239, 255);">[</span>:<span style="color: rgb(255, 157, 0);">-</span><span style="color: rgb(255, 98, 140);">1</span><span style="color: rgb(225, 239, 255);">]</span>, sizes<span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 98, 140);">1</span>:<span style="color: rgb(225, 239, 255);">]</span><span style="color: rgb(225, 239, 255);">)</span></span></pre>
<p>首先要注意，这里是按 x, y 的顺序来赋值的，而不是 y, x，这和 <span style="color:#0000ff;">np.random.randn(</span><span style="color:#ff0000;">y, x</span><span style="color:#0000ff;">)</span> 中的顺序相反。<br />
其中，zip()是Python的一个内建函数，它接受一系列可迭代的对象（例如，在这里是两个list）作为参数，将对象中对应的元素打包成一个个tuple（元组），然后返回由这些tuples组成的list。<br />
为了形象地说明zip()的作用，我们来看看这句简单的代码：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 238, 128);"><span style="color: rgb(255, 176, 84);">zip</span><span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 98, 140);">3</span><span style="color: rgb(225, 239, 255);">,</span> <span style="color: rgb(255, 98, 140);">4</span><span style="color: rgb(225, 239, 255);">]</span>, <span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 98, 140);">5</span><span style="color: rgb(225, 239, 255);">,</span> <span style="color: rgb(255, 98, 140);">9</span><span style="color: rgb(225, 239, 255);">]</span><span style="color: rgb(225, 239, 255);">)</span></span></pre>
<p>它的输出是：</p>
<blockquote>
<p>
		[(3, 5), (4, 9)]</p>
</blockquote>
<p>可见，zip() 分别取出 [3, 4] 以及 [5, 9] 这两个 list 的第一个、第二个元素，然后合成了两个 tuple：(3, 5) 和 (4, 9)，然后再把这两个tuple组成一个list：[(3, 5), (4, 9)]。所以，假设我们有如下代码：</p>
<pre style="margin-top: 0px; margin-bottom: 0px; font-stretch: normal; font-size: 0.9333em; line-height: 1.5em; font-family: Consolas, &quot;Lucida Console&quot;, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Courier New&quot;, monospace; background: rgb(0, 34, 64); color: rgb(255, 255, 255);">
<span style="color: rgb(255, 157, 0);">for</span> x, y <span style="color: rgb(255, 157, 0);">in</span> <span style="color: rgb(255, 238, 128);"><span style="color: rgb(255, 176, 84);">zip</span><span style="color: rgb(225, 239, 255);">(</span><span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 98, 140);">3</span><span style="color: rgb(225, 239, 255);">,</span> <span style="color: rgb(255, 98, 140);">4</span><span style="color: rgb(225, 239, 255);">]</span>, <span style="color: rgb(225, 239, 255);">[</span><span style="color: rgb(255, 98, 140);">5</span><span style="color: rgb(225, 239, 255);">,</span> <span style="color: rgb(255, 98, 140);">9</span><span style="color: rgb(225, 239, 255);">]</span><span style="color: rgb(225, 239, 255);">)</span></span></pre>
<p>那么 x, y 的取值就有两组了：3, 5 和 4, 9。<br />
有了这样直观的对比，我们已经可以理解&nbsp;<span style="color:#0000ff;">for x, y in zip(sizes[:-1], sizes[1:])</span> 是什么含义了。其实 sizes 就是一个含有3个元素的list：[2, 3, 1]，因此 sizes[:-1] 就是去掉最后一个元素的子list，即 [2, 3]；而 sizes[1:] 就是去掉第一个元素的子list，即 [3, 1]。<br />
所以现在真相大白：x, y 的取值有两组，一组是 2, 3，另一组是 3, 1。<br />
再回去看 weights 的赋值代码，于是可以秒懂：<span style="color:#b22222;">weights 的第一个元素 weights[0] 是一个 3x2 的随机数矩阵，weights 的第二个元素 weights[1] 是一个 1x3 的随机数矩阵</span>。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
现在总结一下：<br />
<span style="color:#800080;">biases[0]：3x1 的矩阵<br />
biases[1]：1x1 的矩阵<br />
weights[0]：3x2 的矩阵<br />
weights[1]：1x3 的矩阵</span></p>
<p>虽然我们已经精确分析出了那段代码的含义，但有人可能还是要问：为什么创建的bias和weight是这些维度的？<br />
为了能帮助理解，我们画出这个神经网络的结构（第一层有2个神经元，第二层有3个神经元，最后一层有1个神经元）：<br />
<a href="http://www.codelast.com/" rel="noopener noreferrer" target="_blank"><img decoding="async" alt="three layer neural network" src="http://www.codelast.com/wp-content/uploads/2017/01/three_layer_neural_network.png" style="width: 580px; height: 379px;" /></a><br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
从图上我们可以一眼看出，第一层的输入向量（也就是&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_80e272ff6687340b6912d5181e02b03b.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="wx + b" /></span><script type='math/tex'>wx + b</script>  中的&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_9dd4e461268c8034f5c8564e155c67a6.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="x" /></span><script type='math/tex'>x</script>  ）是一个2行1列的向量，或者说是一个 2x1 的矩阵；第二层的&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_9dd4e461268c8034f5c8564e155c67a6.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="x" /></span><script type='math/tex'>x</script>  是一个3行1列的向量，或者说是一个 3x1 的矩阵。<br />
我们知道，除了输出层（output）之外，每一层的输入  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_9dd4e461268c8034f5c8564e155c67a6.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="x" /></span><script type='math/tex'>x</script>  都要经过一个  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_80e272ff6687340b6912d5181e02b03b.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="wx + b" /></span><script type='math/tex'>wx + b</script>  的运算（这里忽略了激励函数），得到一个矩阵，作为下一层的输入。式中既然有weight（w）和&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_9dd4e461268c8034f5c8564e155c67a6.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="x" /></span><script type='math/tex'>x</script> &nbsp;向量的点乘，weight矩阵的列数就必须和  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_9dd4e461268c8034f5c8564e155c67a6.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="x" /></span><script type='math/tex'>x</script>  向量的行数相等，所以这里是不是恰好符合这个规则呢？<br />
来看看：<br />
第一层&rarr;第二层的  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_80e272ff6687340b6912d5181e02b03b.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="wx + b" /></span><script type='math/tex'>wx + b</script>  运算就是 <span style="color:#0000ff;">weight[0]矩阵  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_9b56e546b8bf1f2b42864cdfdca88614.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt=" \cdot x" /></span><script type='math/tex'> \cdot x</script>  + biases[0] 矩阵</span>，即 (3x2矩阵)  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f02d71bd2ec3e8701fe84e597f122fb2.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt=" \cdot " /></span><script type='math/tex'> \cdot </script>  (2x1矩阵) + (3x1矩阵)，结果是一个 3x1 的矩阵，这个矩阵，作为下一层的输入，实际上就是下一层的&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_9dd4e461268c8034f5c8564e155c67a6.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="x" /></span><script type='math/tex'>x</script> 。前面我们分析过，第二层的&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_9dd4e461268c8034f5c8564e155c67a6.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="x" /></span><script type='math/tex'>x</script>  应该是一个 3x1 的矩阵，这与运算结果完全相符。<br />
第二层&rarr;第三层的&nbsp; <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_80e272ff6687340b6912d5181e02b03b.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="wx + b" /></span><script type='math/tex'>wx + b</script>  运算就是&nbsp;<span style="color: rgb(0, 0, 255);">weight[1]矩阵  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_9b56e546b8bf1f2b42864cdfdca88614.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt=" \cdot x" /></span><script type='math/tex'> \cdot x</script>  + biases[1] 矩阵</span>，即&nbsp;(1x3矩阵)  <span class='MathJax_Preview'><img src='https://www.codelast.com/wp-content/plugins/latex/cache/tex_f02d71bd2ec3e8701fe84e597f122fb2.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt=" \cdot " /></span><script type='math/tex'> \cdot </script>  (3x1矩阵) + (1x1矩阵)，结果是一个 1x1 的矩阵，其实就是一个标量，由于后面已经没有其他层，所以这个标量就是整个神经网络的output。</p>
<p>通过以上不厌其烦的分析，相信任何人都能搞明白那仅有不到10行的代码是如何巧妙地定义了一个神经网络，搞定！<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e3%80%8aneural-networks-and-deep-learning%e3%80%8b%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0%ef%bc%9a%e6%9c%80%e7%ae%80%e5%8d%95%e7%9a%84%e8%af%86%e5%88%abmnist%e7%9a%84%e7%a5%9e/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
	</channel>
</rss>
