<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>蛤鑫和他的一帮小弟</title>
  
  
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://qingfenghcy.github.io/"/>
  <updated>2018-04-26T08:26:09.000Z</updated>
  <id>http://qingfenghcy.github.io/</id>
  
  <author>
    <name>Chunyu Hao</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>线性回归(原理+代码实现)</title>
    <link href="http://qingfenghcy.github.io/2018/04/26/%E5%8F%8D%E5%90%91%E4%BC%A0%E6%92%AD/"/>
    <id>http://qingfenghcy.github.io/2018/04/26/反向传播/</id>
    <published>2018-04-26T08:26:19.267Z</published>
    <updated>2018-04-26T08:26:09.000Z</updated>
    
    <content type="html"><![CDATA[<p><font face="黑体" size="4"></font></p><h1 id="intuition"><a href="#intuition" class="headerlink" title="intuition"></a>intuition</h1><p>&emsp;&emsp;在我们的现实生活中，常常会遇到如下的问题，比如说我通过一个人的一些面部特征，比如说眼睛的大小，皱纹的程度，头发的浓密情况(笑)等特征情况，来猜猜看这个人的岁数;又比如说我们是在银行工作,然后我们又想要通过一个人的一些日常情况，比如说他的存款数，按时守约数,家庭人员数量等特征来给他进行信用评分，然后来决定要不要给他发放信用卡。而在上述的两个问题有这样一个共同点,那就是我们拥有了一些来描述某个目标(比如人)的一些特征属型，然后来给这个目标一个分数，即我们通过一些特征，来得到一个分数，而这个分数是连续的数值，并且属于实数范围内，那么我们就可以将这个问题划分为一个<strong>回归问题</strong>。<br><br><br><br><br><br>&emsp;&emsp;那么机器学习中的回归问题又是指的是什么呢?让我们来回想一下我们中学时代的一些问题比如说我们刚学习函数y=x的时候，老师会说:小明，我告诉你x=1,那么你能告诉我y等于多少吗？那你会说，so easy啊，就是1嘛。然后老师又说那我任意给你一个数值，你都能知道是对应的y是多少吗？那你会说，知道啊，那你说x是多少y就是多少嘛，因为有公式y=x啊！好了，接下来，我们反过来看，假如说老师先给了你一些描述x和y对应关系的点，比如说老师告诉你x=1的时候y=1，x=3的时候y=3,x=100的时候y=100,然后老师对你说:小明，你能告诉老师y和x的对应关系吗？？那你会说y=x啊老师。老师又说了，一定是y=x吗？这时候你就会想一想说不一定啊，那我只是在我看到的资料上面这个公式符合，但是并不一定能够适用于普遍情况啊，万一x=2时y=2.1呢。<br><br><br>&emsp;&emsp;所以说所谓的机器学习问题，就是说我们设计一个演算法(所谓的机器)，然后给机器看我们已经有的数据，然后让机器自己去学习相对应的方法(即训练),等到训练后让我们告诉机器一个x的值，然后机器告诉我们y的值是多少，大体上来讲，<strong>机器学习</strong>所做的事，就是这样的简单。<br><br><br>&emsp;&emsp;而线性回归是机器学习的一种具体方法，怎么说呢，就像上面所说的我们看到了一些x和y的取值，那么我们得想一想办法将他们联系起来，但是我们又比较笨，只学了一些简单的函数比如说y=kx(k代表权重，未知值),那么我们就先用这个笨笨的表示法去猜一猜好了。对于文章刚开始的问题，我们可以重新这么定义，我们不是已经知道了目标的某些特征了吗，那么我们给每个特征一个权重值，代表它有多重要，那么在我们后续的打分中，权重大的特征给分数的影响就会大一些。<br><br><br>&emsp;&emsp;问题可以这么定义：<strong>我们要得到打分分数y,对于每个特征，我们分配相对应的权重w0,w1,w2…，那么最后的分数就是$w_0x_0 + w_1x_1 + w_2x_2…$啊</strong>，这和我们初中学的直线的表示方法也差不多嘛，不过是从$y=kx$变成了$y=k_1x_1+k_2x_2+k_3x_3$了，好了，那我们要怎么样自动找出来所需要的$w$值呢?<br><br><br>&emsp;&emsp;我们可以这样试试看，我先把现在打分得到的分数先拿到，然后跟真正的分数对比(比如说我们判断一个人年龄的时候，先收集好一些人的特征和他们对应的年龄),然后测量一下他们的差值，比如说我们用$$(h-y)^2$$来表示他们的差距，其中h是预测的分数，y是真正的分数，之所以用平方是因为如果两个值差的远的话，这样测出来的差距会很大，并且这个差距是非负的，而这个函数又比较简单。那么一个好的权值集合$w_1,w_2….$是什么样子的呢？？那么理所当然的我们会想，就是让这个差距很小啊，要是0的话最好了，所以说我们就要来调整这些w的值使得这个差距越来越小。那么问题来了，要怎么样调整w的值呢???<br><br><br>&emsp;&emsp;好了，再次让我们回到初中来，假如说有一个函数是这样的，$差距=(w-2)^2$,你来选一个w的值使得差距最小，你会不会选啊?那么我们这里所做的工作不久是这样吗，回忆一下在这里$差距=(xw - y)^2$,那也是一样的啊，这里的x和y都是常数啊，是已经给我们的的数值了,到了这里你会说，哎呀，那我要求它的最小值，那我可以配方啊，但是高中的时候我们不是学过一种更快的方法吗，对$w$求导，然后让那个式子等于0解出来$w$的值就可以了啊。哇，你会说，原来机器学习求解的方法我们高中就学过了啊。<br><br><br>但是在这里我们并不用让导数等于0的方法来求最小值(虽然你也可以这么做),这里我们用梯度下降的方法来进行优化，而梯度下降，大家可以自己网上找一找教程博客来看看，其基础的思想其实很简单，在这里就不介绍了。总之我们同样是要对$w$求导，但是最后的时候我们不解$f(w)=0$而是直接更新$w$的值.</p><center><img src="/lhx/linerRegression/resized.jpg" alt=""></center><h1 id="预备知识"><a href="#预备知识" class="headerlink" title="预备知识"></a>预备知识</h1><p>&emsp;&emsp;好吧好吧，下面来交个大家一点所谓的大学知识，我们定义一个向量是数的集合，就是里面放了一堆数，然后都是竖的比如说<br>$$<br>a=<br>\left[<br>\begin{matrix}<br>1 \\<br>2 \\<br>3<br>\end{matrix}<br>\right]<br>$$<br>,然后转置，就是把一个向量放平，<br>$$a^T=<br>\left[<br>\begin{matrix}<br>1&amp;2&amp;3<br>\end{matrix}<br>\right]$$<br>同理,平的’向量’再转置，就变成了竖的。<br><br><br>&emsp;&emsp;然后就是向量相乘，一个平的向量乘上(dot)一个竖的向量，我们这样定义$a.dot(b)$,这个运算我们可以这么想，就是把平的向量放成竖的，然后在横的方向上高度相同的数值相乘，然后再把不同高度的数值累加起来（有点啰嗦，看例子）比如</p><p>$$<br>\left[<br>\begin{matrix}<br>a &amp; b &amp; c<br>\end{matrix}<br>\right]<br>\left[<br>\begin{matrix}<br>d \\<br>e \\<br>f<br>\end{matrix}<br>\right]=<br>\left[<br>\begin{matrix}<br>a \\<br>b \\<br>c<br>\end{matrix}<br>\right]*<br>\left[<br>\begin{matrix}<br>d \\<br>e \\<br>f<br>\end{matrix}<br>\right] =<br>ad+be+cf<br>$$</p><p>在这里我们做一个约定那就是有*的是对应位置相乘，没有的的是向量相乘。<br><br></p><h1 id="踏上征途"><a href="#踏上征途" class="headerlink" title="踏上征途"></a>踏上征途</h1><p>&emsp;&emsp;现在我们有了一些大学的知识了，我们就可以继续我们的机器学习之旅了，首先我们将我们的权重放在一个向量里面，假设我们现在要预测一个人的年龄，有三个特征眼睛大小，脸部皱纹程度，头发浓密程度，他们各自有一个权重，那么我们现在的$$<br>w=<br>\left[<br>\begin{matrix}<br>w1 \\<br>w2 \\<br>w3<br>\end{matrix}<br>\right]<br>$$<br>,然后假设我们现在已经收集了三个人的数据了，数据如下<br>$$<br>X=<br>\left[<br>\begin{matrix}<br>眼大小&amp;皱纹度&amp;头发 \\<br>x11&amp;x12&amp;x13 \\<br>x21&amp;x22&amp;x23 \\<br>x31&amp;x32&amp;x33<br>\end{matrix}<br>\right],<br>y =<br>\left[<br>\begin{matrix}<br>y1 \\<br>y2 \\<br>y3<br>\end{matrix}<br>\right]<br>$$</p><p>因为有了我们刚才学过的向量知识，我们现在可以同时计算三个人的评分了，用$h=Xw$,这里我们不就是进行了三次平的向量与竖的向量的向量相乘吗？然后将得到的结果放在相应的位置，所以$$<br>Xw=<br>\left[<br>\begin{matrix}<br>x11w1+x12w2+x13w3 \\<br>x21w1+x22w2+x23w3 \\<br>x31w1+x32w2+x33w3<br>\end{matrix}<br>\right]<br>=h<br>$$<br>,然后用$(h-y)^2$就可以得到我们在每个样本上的差距，最后我们再把这些差距叠加起来就得到了总的差距了，这里我们得到的差错向量是3*1的大小，然后我们要把这些向量的差距加起来，最后得到一个总的差距量，还记得刚才我们解释的那个平的向量和竖的向量相乘的过程吗？？如果这个平的向量和竖的向量是一样的那么<br>$$<br>\left[<br>\begin{matrix}<br>a&amp;b&amp;c<br>\end{matrix}<br>\right]<br>\left[<br>\begin{matrix}<br>a \\<br>b \\<br>c<br>\end{matrix}<br>\right]<br>=<br>\left[<br>\begin{matrix}<br>a \\<br>b \\<br>c<br>\end{matrix}<br>\right]*<br>\left[<br>\begin{matrix}<br>a \\<br>b \\<br>c<br>\end{matrix}<br>\right]<br>=a^2+b^2+c^2<br>$$<br>，OK，现在找到将这些差距叠加的方法了，我们将这个差距向量先放平然后再与原来的它相乘，我们就把这些差距的总和得到了。记得我们上一章中$$差距=(xw-y)^2$$吗，我们现在来看一下向量形式下它又长什么样子。上面的步骤合起来我们有总的差距$$loss=(Xw-y)^T(Xw-y)$$,这个式子中的$Xw-y$就是差距向量，而带T的是放平的，那么上面算出来的loss就是一个实数啦。<br><br><br>&emsp;&emsp;好了，根据上一章所说的我们只要对w求导，然后让它等于0，解出$w$是多少就好了嘛，而对于$w$的求导过程实际上就是遵循了一种称为链式法则的东西，就是你要对$w$求导，首先要对他上一层的东西东西求导，然后一层一层深入。好，为了给初学者进行求导的全貌，我们将上面的式子进行<strong>一步一步</strong>拆解，首先我们先得到预测值$$h=Xw$$,然后我们得到了差距值向量$$deff= h-y$$,最后将不同样本的差距值累加得到总的差距值$$loss=deff^Tdeff$$,然后我们要对$w$求导，我们首先得求$$ \frac{\partial loss}{\partial deff}$$,然后求$$ \frac{\partial deff}{\partial h}$$,最后求$$ \frac{\partial h}{\partial w}$$,即$$ \frac{\partial loss}{\partial w}= \frac{\partial loss}{\partial deff}\frac{\partial deff}{\partial h}\frac{\partial h}{\partial w}$$,这就是所谓的链式法则。<br><br><br>&emsp;&emsp;好的，首先我们先来求$$ \frac{\partial loss}{\partial deff}$$这一步的正向$$loss=deff^Tdeff$$实际上是在求向量每个点的平方和，所以说对它求导结果是$$2deff$$<br><br><br>&emsp;&emsp;接下来是$$deff = h-y$$,那么$$\frac{\partial deff}{\partial h}=1$$<br><br><br>最后是$$Xw=h$$,这一步比较麻烦，假设这时候我们已经从前两步传回来的$$dh= \frac{\partial loss}{\partial deff}\frac{\partial deff}{\partial h}$$。好的下面我们来看图，我们在这一步需要计算的是对$w$向量进行求导，那么我们首先来看看对$w_1$求导试试，在正向传播的时候,我们的$w_1$被用在了计算$h_1,h_2,h_3$，所以说当梯度传回来的时候$dh_1,dh_2,dh_3$都会将误差传给$w_1$，我们来看一下比如说$h_1$在被计算的时候是用了x的第一个行向量和w向量计算所得到的，那么$$\frac{\partial h1}{\partial w1}=x_{11}$$,再乘上我们对应的穿回来的梯度$dh_1$，那么这部分对$w1$的贡献就是$dh_1x_{11}$,而$w_1$参与计算了$h_1,h_2,h_3$,所以说$dw_1=dh_1 x_{11}+dh_2x_{21}+dh_3x_{31}$,那么我们可以总结出规律了，那就是你求对于列向量$w$求导，每一个位置上的导数值就是$X$中对应的列与$dh$的每个位置对应位置相乘,如图所示。<br><br><img src="/lhx/linerRegression/1.jpg" alt="1"><br><img src="/lhx/linerRegression/2.jpg" alt="2"><br><img src="/lhx/linerRegression/3.jpg" alt="3"></p><p>求点积的过程我们可以用$a^Ta$来代替，所以上式我们$$dh^TX$$就可以得到我们的$dw$，但是注意这时候得到的$dw$是平的，我们应该取转置，或者直接在求导的时候取转置，这样的话<br>$$<br>dw=X^Tdh<br>$$<br><br><br>好了，让我们把所有的东西加在一起,所以最后我们有</p><p>$$<br>\frac{\partial loss}{\partial w}=<br>\frac{\partial loss}{\partial deff}<br>\frac{\partial deff}{\partial h}<br>\frac{\partial h}{\partial w}=<br>X^Tdh=X^T*1*2deff = 2X^T(Xw-y)<br>$$</p><p><br><br>在这里我们让这个式子等于0,可以解出</p><p>$$<br>w=(X^TX)^{-1}X^Ty<br>$$<br>但是在这里我们打算用梯度下降的方法来进行优化，我们给定一定的学习速率lr，那么我们进行优化的公式就可以这么描述:$$w = w - lr \frac{\partial loss}{\partial w}$$</p><p>OK，到了这里你终于能够长舒一口气了,恭喜你已经走到了这一步。下面我们来你看看代码是怎么实现的。<br></p><p><br><br>首先我们先导入需要的包,然后创建一些假的数据<br><br><br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line">首先将我们的数据初始</span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">这里假设我们得到了一些人的特征X和相对应的标签y</span></span><br><span class="line"><span class="string">比如这里得到了3个样本，每个样本有3个特征,而3个样本的分数分别是6,5,3</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line">X = np.array([[<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>],</span><br><span class="line">              [<span class="number">0</span>,<span class="number">1</span>,<span class="number">1</span>],</span><br><span class="line">              [<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>]])</span><br><span class="line">y = np.array([[<span class="number">6</span>],</span><br><span class="line">              [<span class="number">5</span>],</span><br><span class="line">              [<span class="number">3</span>]])</span><br><span class="line">print(X.shape)</span><br><span class="line">print(y.shape)</span><br><span class="line"></span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">初始化权重，这里简单的初始成为了0,因为每个人有3个特征(3列)，所以w的维度是3*1</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line">w = np.zeros((<span class="number">3</span>, <span class="number">1</span>))</span><br><span class="line">print(w)</span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">然后我们计算 h = X * w 的值,在这里矩阵相乘的话用np.dot()函数</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line">h = X.dot(w)</span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">这里得到的h是我们预测完的坐标向量,然后我们要用它和真实的坐标向量进行对比并计算损失</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line">deff = h - y</span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">下一步我们应该计算出总的差距值，用一个向量的转置乘上它自身以得到损失和</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line">loss = deff.T.dot(deff)</span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">打印损失</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line">print(loss)</span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">然后进行反向传播,首先求ddeff</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line">ddeff = <span class="number">2</span> * deff</span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">然后是根据公式dh = 1 * ddeff</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line">dh = <span class="number">1</span> * ddeff</span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">然后计算dw</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line">dw = X.T.dot(dh)</span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">这样就完成了一次反向传播</span></span><br><span class="line"><span class="string">'''</span></span><br></pre></td></tr></table></figure></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">将这些拼接在一起，给定一定的学习率lr, 进行多次前向反向传播</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line">lr = <span class="number">0.01</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1000</span>):</span><br><span class="line">    <span class="comment">#前向</span></span><br><span class="line">    h = X.dot(w)</span><br><span class="line">    deff = h-y</span><br><span class="line">    <span class="comment">#每100次正反传播打印一次损失</span></span><br><span class="line">    loss = deff.T.dot(deff)</span><br><span class="line">    <span class="keyword">if</span> i % <span class="number">100</span> == <span class="number">0</span>:</span><br><span class="line">        print(loss)</span><br><span class="line">    <span class="comment">#反向传播</span></span><br><span class="line">    ddeff = <span class="number">2</span> * deff</span><br><span class="line">    dh = <span class="number">1</span> * ddeff</span><br><span class="line">    dw = X.T.dot(dh)</span><br><span class="line">    <span class="comment">#更新权值</span></span><br><span class="line">    w = w - lr * dw</span><br></pre></td></tr></table></figure><p>out:<br>[[ 70.]]<br>[[ 0.0078892]]<br>[[ 0.00078922]]<br>[[ 0.00011647]]<br>[[  2.53712989e-05]]<br>[[  6.73698338e-06]]<br>[[  1.91013569e-06]]<br>[[  5.51543066e-07]]<br>[[  1.60022359e-07]]<br>[[  4.64861570e-08]]<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">可以看到我们的损失是一直在降低的，同时我们查看w的值可以发现它学到的权重如下，这个这个权重在我们的样本X和预测y上完美符合，这说明我们的机器已经学习到了最适合它的参数</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line">print(w)</span><br></pre></td></tr></table></figure></p><p>array([[ 0.99987689],<br>       [ 2.00015464],<br>       [ 2.99993077]])</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">同样的,我们可以利用链式求导法则一次性，一步算出dw的值,然后进行更新</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line">X = np.array([[<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>],</span><br><span class="line">              [<span class="number">0</span>,<span class="number">1</span>,<span class="number">1</span>],</span><br><span class="line">              [<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>]])</span><br><span class="line">​</span><br><span class="line">​</span><br><span class="line">y = np.array([[<span class="number">6</span>],</span><br><span class="line">              [<span class="number">5</span>],</span><br><span class="line">              [<span class="number">3</span>]])</span><br><span class="line">w = np.zeros((<span class="number">3</span>, <span class="number">1</span>))</span><br><span class="line"></span><br><span class="line">lr = <span class="number">0.01</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1000</span>):</span><br><span class="line">    dw = <span class="number">2</span>*X.T.dot(X.dot(w)-y)</span><br><span class="line">    w = w - lr * dw</span><br><span class="line"></span><br><span class="line">print(w)</span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">array([[ 0.99987689],</span></span><br><span class="line"><span class="string">       [ 2.00015464],</span></span><br><span class="line"><span class="string">       [ 2.99993077]])</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">对于此问题我们也可以用公式来直接求出w的值</span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line">w =  np.linalg.inv((X.T.dot(X))).dot(X.T).dot(y)</span><br><span class="line"></span><br><span class="line">print(w)</span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">array([[ 1.],</span></span><br><span class="line"><span class="string">       [ 2.],</span></span><br><span class="line"><span class="string">       [ 3.]])</span></span><br><span class="line"><span class="string">'''</span></span><br></pre></td></tr></table></figure><p>可以看到我们上述的三个方法都得到了 $w_1=1,w_2=2,w_3=3$ 的结果，而这个参数正好吻合了训练集</p><p><code>`</code></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;&lt;font face=&quot;黑体&quot; size=&quot;4&quot;&gt;&lt;/font&gt;&lt;/p&gt;
&lt;h1 id=&quot;intuition&quot;&gt;&lt;a href=&quot;#intuition&quot; class=&quot;headerlink&quot; title=&quot;intuition&quot;&gt;&lt;/a&gt;intuition&lt;/h1&gt;&lt;p&gt;&amp;e
      
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>卷积神经网络中的反向传播(概念+代码)</title>
    <link href="http://qingfenghcy.github.io/2018/04/26/%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/"/>
    <id>http://qingfenghcy.github.io/2018/04/26/卷积神经网络/</id>
    <published>2018-04-26T08:12:56.163Z</published>
    <updated>2018-04-26T08:12:40.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>申明:这篇文章是阅读了medium给我进行推荐的一篇文章后写的总结材料，原文章在<a href="https://becominghuman.ai/back-propagation-in-convolutional-neural-networks-intuition-and-code-714ef1c38199" target="_blank" rel="noopener">这里</a>。</p></blockquote><h3 id="链式法则"><a href="#链式法则" class="headerlink" title="链式法则"></a>链式法则</h3><p><center><img src="/lhx/convNet/8.png" alt=""></center><br><br></p><p><center><img src="/lhx/convNet/2.png" alt=""></center><br>如果你理解了链式法则，那么我们可以继续了。</p><h2 id="卷积神经网络"><a href="#卷积神经网络" class="headerlink" title="卷积神经网络"></a>卷积神经网络</h2><p>下面先给出一些结论，假设我们输入的某一层的数据长宽是$H \times W$,核的大小是$k$(假设核是正方形的),然后padding的大小是$p$,移动的步伐stride是$s$,那么我们下一层得到的数据的$h$是$$\frac{H-k+2p}{s} + 1$$同理下一层得到的数据的$w$是$$\frac{W-k+2p}{s} + 1$$</p><h3 id="正向传播"><a href="#正向传播" class="headerlink" title="正向传播"></a>正向传播</h3><p>为了理解卷积神经网络中的反向传播，我们假设输入输出的通道数是1。<br><br>下面的卷积图用了$3 \times 3$大小的输入数据，同时用了$2 \times 2$的卷积核，每次移动(stride)1步，并且没有padding填充，那么根据上面的公式，我们可以算出来这层经过卷积后输出数据的大小是$2 \times 2$的。为了理解反向传播，我们首先来看看正向传播是怎么样工作的。</p><p><center><img src="/lhx/convNet/9.gif" alt=""></center><br>如图我们可以清楚的看到在进行正向卷积运算的全过程。</p><p><center><img src="/lhx/convNet/3.jpg" alt=""></center></p><p><center><img src="/lhx/convNet/4.jpg" alt=""></center><br><br></p><h3 id="反向传播"><a href="#反向传播" class="headerlink" title="反向传播"></a>反向传播</h3><p>在继续之前，让我们先来做一些约定.</p><p><center><img src="/lhx/convNet/5.jpg" alt=""></center><br>现在，让我们来实现反向传播算法，我们可以假设从后面一层穿回来的梯度误差是$\partial h$,然后我们要计算这一层中的导数$\partial x和\partial w$,为什么呢？因为计算$\partial w$可以让我们通过这一次反向传播更新这一层的参数$w$,而计算$\partial x$是因为这一层的数据是通过上一层计算得来的，所以要把梯度传回去，我们需要借助$x$这个媒介(如果是最开始的输入数据，比如第0层，就没必要计算了)。<br><br><br>这一层的每一个$w$参与计算了输出层的每一个$h$，所以说在更新每一个$w$的时候，要叠加传回来的所有$dh$的误差。如图所示。</p><p><center><img src="/lhx/convNet/1.gif" alt=""></center><br>接下来让我们一起来实现正向和反向传播算法.首先是导入数据<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line">np.random.seed(<span class="number">42</span>)</span><br><span class="line"></span><br><span class="line">X = np.array([[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>],</span><br><span class="line">            [<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>],</span><br><span class="line">            [<span class="number">7</span>,<span class="number">8</span>,<span class="number">9</span>]])</span><br><span class="line">w = np.ones((<span class="number">2</span>,<span class="number">2</span>))</span><br></pre></td></tr></table></figure></p><p>然后进行正向传播<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">forward</span><span class="params">(X, w)</span>:</span></span><br><span class="line">    <span class="comment">#得到长宽</span></span><br><span class="line">    height, width = X.shape</span><br><span class="line">    <span class="comment">#得到核的大小</span></span><br><span class="line">    kernel_size = w.shape[<span class="number">0</span>]</span><br><span class="line">    <span class="comment">#根据公式算新的高度和宽度</span></span><br><span class="line">    new_height = (height - kernel_size) + <span class="number">1</span> </span><br><span class="line">    new_width = (width - kernel_size) + <span class="number">1</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">#创建输出数据</span></span><br><span class="line">    out = np.zeros((new_height, new_width))</span><br><span class="line">    </span><br><span class="line">    <span class="comment">#卷积过程</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> range(new_height):</span><br><span class="line">        <span class="keyword">for</span> j <span class="keyword">in</span> range(new_width):</span><br><span class="line">            <span class="comment">#得到框里的数据</span></span><br><span class="line">            box = X[i:i+kernel_size, j:j+kernel_size]</span><br><span class="line">            <span class="comment">#点积</span></span><br><span class="line">            out[i][j] = np.sum(w * box)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">#将X和w存储起来，计算梯度的时候要用，还记得我们计算w的梯度的时候，每个框里的x和dh相乘吗？所以要把X存储起来</span></span><br><span class="line">    cache = [X, w]</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> out, cache</span><br></pre></td></tr></table></figure></p><p>传播<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">out, cache = forward(X, w)</span><br><span class="line">print(out)</span><br></pre></td></tr></table></figure></p><p>输出是<br>array([[ 12.,  16.],<br>       [ 24.,  28.]])<br>我们可以手动计算来看一下，这是正确的。<br>然后进行反向传播<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#这里我们只计算dw</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">backward</span><span class="params">(dH, cache)</span>:</span></span><br><span class="line">    <span class="comment">#得到X</span></span><br><span class="line">    X, w = cache</span><br><span class="line">    new_height, new_width = dH.shape</span><br><span class="line">    kernel_size = w.shape[<span class="number">0</span>]</span><br><span class="line">    </span><br><span class="line">    <span class="comment">#dw大小和w相同</span></span><br><span class="line">    dw = np.zeros_like(w)</span><br><span class="line">    <span class="comment">#进行反向传播</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> range(new_height):</span><br><span class="line">        <span class="keyword">for</span> j <span class="keyword">in</span> range(new_width):</span><br><span class="line">            <span class="comment">#同理在X中得到框里的数据</span></span><br><span class="line">            box = X[i:i+kernel_size, j:j+kernel_size]</span><br><span class="line">            dw += box * dH[i][j]</span><br><span class="line">                </span><br><span class="line">    <span class="keyword">return</span> dw</span><br></pre></td></tr></table></figure></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#假设传回来的梯度都是1</span></span><br><span class="line">dH = np.ones_like(out)</span><br></pre></td></tr></table></figure><p>传播<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">dw = backward(dH, cache)</span><br><span class="line">print(dw)</span><br></pre></td></tr></table></figure></p><p>array([[ 12.,  16.],<br>       [ 24.,  28.]])<br>通过手动计算，我们可以计算得出此梯度是正确的.<br><br><br>到此为止，我们就学会了卷积神经网络中的梯度流动。</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;blockquote&gt;
&lt;p&gt;申明:这篇文章是阅读了medium给我进行推荐的一篇文章后写的总结材料，原文章在&lt;a href=&quot;https://becominghuman.ai/back-propagation-in-convolutional-neural-networks-
      
    
    </summary>
    
    
  </entry>
  
</feed>
