<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Junyan Wu</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://junyanwu.github.io/</id>
  <link href="https://junyanwu.github.io/" rel="alternate"/>
  <link href="https://junyanwu.github.io/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Junyan Wu</rights>
  <subtitle>但行好事，莫问前程</subtitle>
  <title>SIGMA's BLOG</title>
  <updated>2026-08-18T05:18:12.528Z</updated>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="CNN" scheme="https://junyanwu.github.io/tags/CNN/"/>
    <category term="DL&amp;ML" scheme="https://junyanwu.github.io/tags/DL-ML/"/>
    <category term="离散的笔记" scheme="https://junyanwu.github.io/tags/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/"/>
    <content>
      <![CDATA[<h3 id="卷积操作"><a href="#卷积操作" class="headerlink" title="卷积操作"></a><em>卷积操作</em></h3><script type="math/tex; mode=display">O = \frac{W-K+2P}{S}+1</script><p>$O$是output_shape，$W$是image，$K$是filter，$P$是padding，$S$是stride</p><p><em>stride = 1</em></p><p><img src="/images/CNN_stride1.png" alt=""></p><p><em>stride = 2</em></p><p><img src="/images/CNN_stride2.png" alt=""></p><h3 id="Padding"><a href="#Padding" class="headerlink" title="Padding"></a><em>Padding</em></h3><ul><li>padding的计算公式与conv一样</li><li>zero padding</li></ul><script type="math/tex; mode=display">Zero Padding = \frac{(K-1)}{2}</script><p>有这些情况会使用zero padding</p><ul><li>卷积后image尺寸很小，但我们又想使用conv</li><li>由于image尺寸跟filter尺寸的原因</li></ul><p><img src="/images/CNN_padding.png" alt=""></p><h3 id="pooling"><a href="#pooling" class="headerlink" title="pooling"></a><em>pooling</em></h3><p>也叫downsampling（下采样）层，最常用的是max-pooling</p><p><em>stride = 2</em></p><p><img src="/images/CNN_maxpooling" alt=""></p><h3 id="ReLu"><a href="#ReLu" class="headerlink" title="ReLu"></a><em>ReLu</em></h3><p>优点：</p><ul><li>因为它在准确度不发生明显改变的情况下能把训练速度提高很多</li><li>能够减轻vanishing gradient problem<br>—指梯度以指数方式在层中消失，导致网络较底层的训练速度非常慢</li><li>把negative activation变为0，增加了模型的非线性特征，而且不影响感受域</li></ul><p>参见 Geoffrey Hinton（即深度学习之父）的论文：Rectified Linear Units Improve Restricted Boltzmann Machines</p><h3 id="Dropout"><a href="#Dropout" class="headerlink" title="Dropout"></a><em>Dropout</em></h3><p>随机丢弃神经元，简单来说，就是在训练过程中在Dropout层设置一个随机的激活参数集，在forward pass中将这些激活参数集设置为0。</p><p>理解了大概，这部分细节需要详细看看</p><blockquote><p>参考资料<br><a href="https://www.zhihu.com/question/52668301" target="_blank" rel="noopener">https://www.zhihu.com/question/52668301</a></p></blockquote>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/CNN/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/CNN/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h3 id="卷积操作"><a href="#卷积操作" class="headerlink" title="卷积操作"></a><em>卷积操作</em></h3><script type="math/tex; mode=display">O = \frac{W-K+2P}{]]>
    </summary>
    <title>Convolutional Neural Networks</title>
    <updated>2026-08-18T05:18:12.528Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="DL&amp;ML" scheme="https://junyanwu.github.io/tags/DL-ML/"/>
    <category term="离散的笔记" scheme="https://junyanwu.github.io/tags/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/"/>
    <category term="Term" scheme="https://junyanwu.github.io/tags/Term/"/>
    <content>
      <![CDATA[<h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><p>转自<a href="http://blog.csdn.net/jinxiaonian11/article/details/53467437" target="_blank" rel="noopener">这里</a></p><p>什么是掩膜（mask）</p><p>数字图像处理中的掩膜的概念是借鉴于PCB制版的过程，在半导体制造中，许多芯片工艺步骤采用光刻技术，用于这些步骤的图形“底片”称为掩膜（也称作“掩模”），其作用是：在硅片上选定的区域中对一个不透明的图形模板遮盖，继而下面的腐蚀或扩散将只影响选定的区域以外的区域。</p><p>图像掩膜与其类似，用选定的图像、图形或物体，对处理的图像（全部或局部）进行遮挡，来控制图像处理的区域或处理过程。<br>光学图像处理中,掩模可以是胶片、滤光片等。数字图像处理中,掩模为二维矩阵数组,有时也用多值图像。数字图像处理中,图像掩模主要用于：</p><p>①提取感兴趣区,用预先制作的感兴趣区掩模与待处理图像相乘,得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为0。<br>②屏蔽作用,用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区作处理或统计。<br>③结构特征提取,用相似性变量或图像匹配方法检测和提取图像中与掩模相似的结构特征。<br>④特殊形状图像的制作。</p><p>掩膜是一种图像滤镜的模板，实用掩膜经常处理的是遥感图像。当提取道路或者河流，或者房屋时，通过一个n*n的矩阵来对图像进行像素过滤，然后将我们需要的地物或者标志突出显示出来。这个矩阵就是一种掩膜。</p><h3 id="实例"><a href="#实例" class="headerlink" title="实例"></a>实例</h3><p>简单例子见<a href="http://www.cnblogs.com/skyfsm/p/6894685.html" target="_blank" rel="noopener">这里</a></p><p>进一步的例子还有<a href="https://github.com/bbfamily/prisma_abu" target="_blank" rel="noopener">这里</a></p>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/CV_mask/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/CV_mask/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><p>转自<a href="http://blog.csdn.net/jinxiaonian11/article/details/53467437]]>
    </summary>
    <title>Mask的概念解读</title>
    <updated>2026-08-18T05:18:12.528Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="CNN" scheme="https://junyanwu.github.io/tags/CNN/"/>
    <category term="DL&amp;ML" scheme="https://junyanwu.github.io/tags/DL-ML/"/>
    <category term="离散的笔记" scheme="https://junyanwu.github.io/tags/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/"/>
    <category term="FCN" scheme="https://junyanwu.github.io/tags/FCN/"/>
    <content>
      <![CDATA[<ul><li><a href="https://people.eecs.berkeley.edu/~jonlong/long_shelhamer_fcn.pdf" target="_blank" rel="noopener">Here is the paper</a></li></ul><h3 id="question"><a href="#question" class="headerlink" title="question"></a>question</h3><ul><li>translation invariance是指什么，有什么作用</li><li>其中一种loss：IoU —— Intersection of Union</li><li>Ground Truth<br>-</li></ul><hr><h3 id="3"><a href="#3" class="headerlink" title="3."></a>3.</h3><p><strong>convnet = h <em> w </em> d (height, width, color channel)</strong></p><p>基于translation invariance</p><hr><h3 id="三种技术"><a href="#三种技术" class="headerlink" title="三种技术"></a>三种技术</h3><ul><li>卷积化（Convolutional）</li><li>上采样（Upsample）</li><li>跳跃结构（Skip Layer）</li></ul><hr><h3 id="卷积化"><a href="#卷积化" class="headerlink" title="卷积化"></a>卷积化</h3><p>FC换成Conv以保留图像的空间信息</p><p><img src="/images/FCN_structure.png" alt=""></p><hr><h3 id="上采样"><a href="#上采样" class="headerlink" title="上采样"></a>上采样</h3><blockquote><p>此处的上采样即是反卷积（Deconvolution）。当然关于这个名字不同框架不同，Caffe和Kera里叫Deconvolution，而tensorflow里叫conv_transpose。CS231n这门课中说，叫conv_transpose更为合适。</p></blockquote><hr><h3 id="Loss"><a href="#Loss" class="headerlink" title="Loss"></a>Loss</h3><blockquote><p>对于最终输出的每一个像素的类别信息，我们并不把所有的像素点的结果计算到loss中进行反向传播，而是只取其中一部分的像素点。这个想法是有点道理的，因为每一个紧密相邻的像素点之前的特征差距可能并不大，如果每一个像素点都计算在内，那么就相当于我们对某一组特征增加了很高的权重。但好在我们对所有像素点都增加权重的话，这个影响还是会抵消的。</p></blockquote>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/FCN/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/FCN/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<ul>
<li><a href="https://people.eecs.berkeley.edu/~jonlong/long_shelhamer_fcn.pdf" target="_blank" rel="noopener">Here is the paper</a></li]]>
    </summary>
    <title>Fully Convolutional Networks</title>
    <updated>2026-08-18T05:18:12.527Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="DL&amp;ML" scheme="https://junyanwu.github.io/tags/DL-ML/"/>
    <category term="Paper Reading" scheme="https://junyanwu.github.io/tags/Paper-Reading/"/>
    <category term="Capsules" scheme="https://junyanwu.github.io/tags/Capsules/"/>
    <category term="Code" scheme="https://junyanwu.github.io/tags/Code/"/>
    <content>
      <![CDATA[<h1 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h1><p>本文记录了阅读论文<a href="https://arxiv.org/pdf/1710.09829" target="_blank" rel="noopener">《<em>Dynamic Routing Between Capsules</em>》</a>以及<a href="https://github.com/naturomics/CapsNet-Tensorflow" target="_blank" rel="noopener">naturomics的代码</a>的理解与收获，若有错误欢迎指出（wjy.f@qq.com），转载请注明出处。</p><p>若想通过视频快速了解，可以看看下面两个链接，讲得比较生动易理解（不过还是推荐读论文）：</p><ul><li><a href="https://www.bilibili.com/video/av16594836/?from=search&amp;seid=12945685157419672339" target="_blank" rel="noopener">Capsule Networks教程(by Aurélie)</a></li><li><a href="https://www.bilibili.com/video/av16820289/" target="_blank" rel="noopener">用Tensorflow实现Capsule(by Aurélie)</a></li></ul><p><br></p><h1 id="Main"><a href="#Main" class="headerlink" title="Main"></a>Main</h1><h2 id="CapsNet"><a href="#CapsNet" class="headerlink" title="CapsNet"></a>CapsNet</h2><h3 id="结构概述"><a href="#结构概述" class="headerlink" title="结构概述"></a>结构概述</h3><p>论文仅仅是提出了一个可行的方案，目的是为了证明<code>Capsule</code>这个思想的可行性，目前还较为粗略，有很多改进空间。论文有两个比较突出的创新点：</p><ul><li>采用 routing-by-agreement mechainsm 决定两层capsule之间的连接以及参数$c_{ij}$的更新方式</li><li>用向量输出替代标量输出</li></ul><p>下图是论文中所采用的神经网络结构：</p><p><img src="/images/capsule_figure1.png" alt=""></p><p>看完这幅图应该大概能理解CapsNet的结构。它先是对图像用了两次卷积得到PrimaryCaps，然后用<em>Routing-By-Agreement Mechanism</em>得到DigitCaps。最后，求DigitCaps中的10个向量的长度，比如说最长的是第4个向量，那么就意味着CapsNet识别出当前输入的图片是数字4。</p><p>看到这里，何为<code>Capsule</code>？在PrimaryCaps中，它指的是长度为8的向量，共6<em>6</em>32个。而在DigitCaps中，它指的是16维的向量，共10个。所以Capsule其实对应着传统神经网络的scalar，只是一个scalar能够表征的信息太少了，所以将其扩展为向量，这样它就能够表示更多的信息。有人说，之所以提出这种想法是因为Hinton观察到人的大脑不是像神经网络一样严格分层，而是一簇簇神经元作为一个整体的。</p><p>CapsNet的结构是Image(input)-&gt;Conv1-&gt;PrimaryCaps-&gt;DigitCaps(output)-&gt;Reconstruction，下文也会按照这个顺序来讲解</p><p>在下文中，若 i 指 $layer_l$ 的某一个capsule ，那么 j 就是指 $layer_{l+1}$ 的某一个capsule。</p><h3 id="image-to-ReLU-Conv1-to-PrimaryCaps"><a href="#image-to-ReLU-Conv1-to-PrimaryCaps" class="headerlink" title="image to ReLU Conv1 to PrimaryCaps"></a>image to ReLU Conv1 to PrimaryCaps</h3><p>论文使用的是MNIST手写识别数据集，每张图片的大小都是28*28。</p><p>流程：</p><ol><li><p>image(28 * 28)</p></li><li><p>images $\to$ <code>Conv(num_outputs=256, kernel_size=9, stride=1, padding=&#39;VALID&#39;) + ReLU</code> $\to$ Conv1(256*20*20)</p></li><li><p>Conv1 $\to$ <code>Conv(num_outputs=256, kernel_size=9, stride=2, padding=&quot;VALID&quot;) + ReLU</code> $\to$ PrimaryCaps(256*6*6)</p></li></ol><p>这里可能会有人奇怪，这里不过是用了256个filter产生256个feature map，图片为什么会画成(32*8*6*6)的形式，这是因为后面的路由算法是将一个长度为8的向量当做一个整体来计算的。</p><h3 id="PrimaryCaps-to-DigitCaps-amp-Dynamic-Routing"><a href="#PrimaryCaps-to-DigitCaps-amp-Dynamic-Routing" class="headerlink" title="PrimaryCaps to DigitCaps &amp; Dynamic Routing"></a>PrimaryCaps to DigitCaps &amp; Dynamic Routing</h3><ul><li>下面讲解从PrimaryCaps $\to$ DigitCaps的计算过程，其中主要应用了<em>Routing-By-Agreement Mechanism</em></li></ul><p><strong>一张图表示他们之间的关系：</strong></p><p><img src="/images/capsule_routing.png" alt=""></p><p>注意，图片中仅展示了一个$v_j,j\in(1,10)$的求解过程，其他$v_j$同理可得。</p><p><strong>公式</strong></p><script type="math/tex; mode=display">\hat{u}_{j|i} = W_{ij} u_i \tag{1}</script><ul><li>$u_i(i \in [6 × 6 × 32])$： 表示PrimaryCaps的某个8D的Capsule</li><li>$\hat{u}_{j|i}$： 论文中称之为低一层的capsules的“prediction vectors”</li></ul><script type="math/tex; mode=display">c_{ij} = \frac{exp(b_{ij})}{\sum_{k}exp(b_{ik})} \tag{2}</script><ul><li>$b_{ij}$： 初始化为0，更新方法是 $b_{ij} \leftarrow b_{ij} + \hat{u}_{j|i} v_j$。 其中$a_{ij} = \hat{u}_{j|i} v_j$表示$capsule_j$（即$v_j$）跟$capsule_i$的prediction vector（即$\hat{u}_{j|i}$）的agreement（契合度）。<strong>值越大，表示两个向量的方向越相似，两个向量所表示的性质越相近</strong>。由 $c_{ij}$ 的公式知，$b_{ij}$ 的值越大（意味着两个向量的方向越相似），$c_{ij}$ 的值越大，<strong>$capsule_i$ 越倾向于将信息传送给 $capsule_j$</strong> 。</li><li>$c_{ij}$： 由动态路由算法更新的coupling coefficients，并且 $\sum<em>{i} c\</em>{ij} = 1$（此时$j$为某确定的常数）</li></ul><script type="math/tex; mode=display">s_j = \sum_{i} c_{ij} \hat{u}_{j|i} \tag{3}</script><ul><li>$s_j$： $capsule_j$ 的所有input之和。</li></ul><script type="math/tex; mode=display">squash(s_j):v_j = \frac{\|s_j\|^2}{1+\|s_j\|^2}\frac{s_j}{\|s_j\|} \tag{4}</script><ul><li>$squash()$： 非线性函数，保留了向量的方向，使长的向量越长，短的向量越短，并且长度都压缩在0-1之内</li><li>$v_j$： 由dynamic routing计算出来的PrimaryCaps的output。在文章中就是指最后的输出DigitCaps，共有10个（因为有10个数字，即10类）Capsule。每个capsule有16维，每一维都代表着数字的某些属性（粗细、倾斜程度等等）。<strong>向量的长度代表了当前输入是类 $j$ 的概率</strong>。</li></ul><h3 id="Dynamic-Routing算法流程"><a href="#Dynamic-Routing算法流程" class="headerlink" title="Dynamic Routing算法流程"></a>Dynamic Routing算法流程</h3><p><img src="/images/procedure1.png" alt=""></p><p>整个过程如下所示（图片来自<a href="https://github.com/naturomics/" target="_blank" rel="noopener">naturomics</a>的ppt）：</p><p><img src="/images/capsule_routingbyagreement.png" alt=""></p><h3 id="Reconstruction"><a href="#Reconstruction" class="headerlink" title="Reconstruction"></a>Reconstruction</h3><p>CapsNet使用Reconstruction作为Regularization。其做法是将DigitCaps的十个输出向量$v_j$中长度最长的向量，经过3个FC层（结构如下图所示）重构出原来的图像，通过对比重构的图像和原图像的差异(pixel-wise)，得到reconstruction loss。用来重构的这三个FC层一起称为<code>Decoder</code>。</p><p><img src="/images/capsule_decoder.png" alt=""></p><h3 id="Total-loss"><a href="#Total-loss" class="headerlink" title="Total loss"></a>Total loss</h3><p>由于有多个类的存在，所以不能用cross entropy，论文中使用了SVM中常用的损失函数Margin loss来代替</p><p><strong>Margin loss</strong></p><p><img src="/images/cap_lossfunc.png" alt=""></p><ul><li>k： class k，$k\in[1, 10]$</li><li>$m^+=0.9, m^-=0.1$ （自己设定）</li><li><p>$\lambda$ （比例系数，用来调整两者的比重）：</p><blockquote><p>The λ down-weighting of the loss for absent digit classes stops the initial learning from shrinking the lengths of the activity vectors of all the digit capsules. We use λ = 0.5.</p></blockquote></li><li><p>如果输入的数字图像是class k，那么$T_k=1$</p></li><li>| 示例 | 输入输出 | $|v_k|$ | $L_k$ |<br>| — | ——————————- | ——- | ——- |<br>| TT | 输入数字k 预测结果为数字k | 比较大 | 比较小 |<br>| TF | 输入数字k 预测结果非数字k | 比较小 | 比较大 |<br>| FT | 输入非数字k 预测结果为数字k | 比较大 | 比较大 |<br>| FF | 输入非数字k 预测结果非数字k | 比较小 | 比较小 |</li><li>可以看出，在假阳性和假阴性的示例中，$L_k$的值比较大。</li></ul><p><strong>Reconstruction loss</strong></p><p>计算原图像与重构的图像在对应的pixel位置上的值之差，求和得到Reconstruction loss</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></pre></td><td class="code"><pre><span class="line">将原图像x(<span class="number">28</span>, <span class="number">28</span>)reshape成orgin(<span class="number">784</span>)</span><br><span class="line">再将重构的图像decoded(<span class="number">784</span>)</span><br><span class="line">squared = square(decoded - orgin)</span><br><span class="line">reconstruction_loss = mean(squared)</span><br></pre></td></tr></table></figure><p>即</p><script type="math/tex; mode=display">Reconstruction Loss=\frac{1}{784} * \sum_{i=1}^{784}(decoded_i - orgin_i)^2</script><p>最后：</p><script type="math/tex; mode=display">TotalLoss = MarginLoss + ReconstructionLoss</script><p><br></p><h2 id="实验"><a href="#实验" class="headerlink" title="实验"></a>实验</h2><p><strong>MNIST</strong></p><p>l=label, p=prediction, r=reconstruction。下面最右的两列展示了模式是如何在5和3之间纠结的。而其它列表明了模型不仅保留了图片的细节并且平滑了噪声。</p><p><img src="/images/capsule_ex2.jpg" alt=""></p><p><img src="/images/capsule_ex1.jpg" alt=""></p><p><strong>Dimension perturbations</strong></p><p>改变DigitCaps中的capsule的16维中的一维，这个被改变的capsule所重构出来的图像也会有所变化（比如笔画变得更粗）。这表明了capsule学习到了entity，并且每一维都代表着entity的某个feature，具有很强的解释性。</p><p><img src="/images/capsule_ex3.jpg" alt=""></p><p><strong>MultiMNIST</strong></p><p>L指的是两个label，R指的是两个用于重构的图像。上面白色的是input image，下面红绿色重叠的是重构的图像。</p><p>如下图所示，实验把两个激活程度最高的capsule对应的数字作为识别结果，据此对识别到的图像元素进行了重构。对于左边中识别正确的样本（L指真实标签，R指激活程度最高的两个胶囊对应的标签），可以看到由于不同的capsule各自工作，在一个识别结果中用到的特征并不会影响到另一个识别结果，不受重叠的影响（或者说重叠部分的特征可以复用）。</p><p>另一方面，每个capsule还是需要足够多的周边信息支持，而不是一味地认为重叠部分的特征就需要复用。下图中间是选了一个高激活程度的capsule和一个低激活程度capsule的结果（* R表示其中一个数字既不是真实标签也不是识别结果，L仍然为真实标签）。可以看到，在（5，0）图中，关注“7”的capsule并没有找到足够多的“7”的特征，所以激活很弱；（1，8）图中也是因为没有“0”的支持特征，所以重叠的部分也没有在“0”的capsule中用第二次。</p><p>最右R:P:(2, 7)指的是预测结果是2,7，然后将代表2和7的capsule重构。</p><p><img src="/images/capsule_multiMNIST.png" alt=""></p><p><br></p><h2 id="CapsNet与tradictional-neuron的对比"><a href="#CapsNet与tradictional-neuron的对比" class="headerlink" title="CapsNet与tradictional neuron的对比"></a>CapsNet与tradictional neuron的对比</h2><p>（图片来自<a href="https://github.com/naturomics/CapsNet-Tensorflow" target="_blank" rel="noopener">naturomics</a>）：</p><p><img src="/images/capsule_diff.png" alt=""></p><p><br></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p><strong>为什么要用Routing-by-agreement？</strong></p><p>传统的CNN里面，conv后面是max-pooling层，但是max-pooling只保留了唯一一个最活跃的特征，而Routing则有效得多。</p><p>Routing-by-agreement有以下几个好处：</p><ul><li>由于上一层的capsule会逐渐倾向于将信息传到下一层与它相似的capsule，这样就能够给下一层capsule干净清晰的信号，减少噪声，从而更快地学习到entity</li><li>通过追溯当前被激活的capsule的信号传输路径，我们可以操控part-whole中的part，并且清楚知道哪一个part属于哪一个entity（比如说识别一个由三角形和长方形组成的房屋，在$layer l$可能有个capsule是检测三角形，有个capsule检测长方形，则在$layer l+1$有能够得到检测房屋的capsule。此为ppart-whole的关系）。</li><li>可以很容易地解析重叠的entity，比如重叠的数字识别。</li></ul><blockquote><p>the capsules in the first layer try to predict what the second layer capsules will output</p></blockquote><p><br></p><h2 id="代码阅读"><a href="#代码阅读" class="headerlink" title="代码阅读"></a>代码阅读</h2><p><a href="https://github.com/naturomics/CapsNet-Tensorflow" target="_blank" rel="noopener">代码link</a></p><p>由于代码基本上都是按照文章思路来写的，所以不重复讲，而是介绍主要的结构。</p><p><strong>目录</strong></p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">CapsNet-Tensorflow</span><br><span class="line">  - capsLayer.py</span><br><span class="line">      定义了capsLayer的实现方法。</span><br><span class="line">      由于论文中提及的capsLayer有两种:</span><br><span class="line">        PrimaryCaps(without routing)</span><br><span class="line">        DigitCaps(with routing)</span><br><span class="line">      所以该文件里面也包含了这两种Layer的实现方式</span><br><span class="line">      另外，该文件还有:</span><br><span class="line">        routing</span><br><span class="line">        squash</span><br><span class="line"></span><br><span class="line">  - capsNet.py</span><br><span class="line">      定义了CapsNet类</span><br><span class="line">      包含：</span><br><span class="line">        build_arch()  # 定义结构</span><br><span class="line">        loss()        # 定义loss</span><br><span class="line"></span><br><span class="line">  - config.py</span><br><span class="line">      超参数设定</span><br><span class="line"></span><br><span class="line">  - main.py</span><br><span class="line">      程序入口</span><br><span class="line"></span><br><span class="line">  - utils.py</span><br><span class="line">      用于读取MNIST的数据</span><br></pre></td></tr></table></figure><p>主要代码：</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><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><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">CapsNet</span>(<span class="title class_ inherited__">object</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, is_training=<span class="literal">True</span></span>):</span><br><span class="line">        <span class="variable language_">self</span>.graph = tf.Graph()</span><br><span class="line">        <span class="keyword">with</span> <span class="variable language_">self</span>.graph.as_default():</span><br><span class="line">            <span class="keyword">if</span> is_training:  <span class="comment"># 如果是在训练过程中</span></span><br><span class="line">                <span class="variable language_">self</span>.X, <span class="variable language_">self</span>.labels = get_batch_data()  <span class="comment"># 获取training data和label</span></span><br><span class="line">                <span class="variable language_">self</span>.Y = tf.one_hot(<span class="variable language_">self</span>.labels, depth=<span class="number">10</span>, axis=<span class="number">1</span>, dtype=tf.float32)  <span class="comment"># 对label做onehot</span></span><br><span class="line"></span><br><span class="line">                <span class="variable language_">self</span>.build_arch()  <span class="comment"># 搭建CapsNet的结构</span></span><br><span class="line">                <span class="variable language_">self</span>.loss()        <span class="comment"># 定义loss</span></span><br><span class="line">                <span class="variable language_">self</span>._summary()</span><br><span class="line"></span><br><span class="line">                <span class="comment"># t_vars = tf.trainable_variables()</span></span><br><span class="line">                <span class="variable language_">self</span>.global_step = tf.Variable(<span class="number">0</span>, name=<span class="string">&#x27;global_step&#x27;</span>, trainable=<span class="literal">False</span>)</span><br><span class="line">                <span class="variable language_">self</span>.optimizer = tf.train.AdamOptimizer()  <span class="comment"># 使用AdamOptimizer</span></span><br><span class="line">                <span class="variable language_">self</span>.train_op = <span class="variable language_">self</span>.optimizer.minimize(<span class="variable language_">self</span>.total_loss, global_step=<span class="variable language_">self</span>.global_step)  <span class="comment"># var_list=t_vars)</span></span><br><span class="line">            <span class="keyword">elif</span> cfg.mask_with_y:  <span class="comment"># 如果是已经训练完</span></span><br><span class="line">                <span class="variable language_">self</span>.X = tf.placeholder(tf.float32,</span><br><span class="line">                                        shape=(cfg.batch_size, <span class="number">28</span>, <span class="number">28</span>, <span class="number">1</span>))</span><br><span class="line">                <span class="variable language_">self</span>.Y = tf.placeholder(tf.float32, shape=(cfg.batch_size, <span class="number">10</span>, <span class="number">1</span>))</span><br><span class="line">                <span class="variable language_">self</span>.build_arch()</span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="variable language_">self</span>.X = tf.placeholder(tf.float32,</span><br><span class="line">                                        shape=(cfg.batch_size, <span class="number">28</span>, <span class="number">28</span>, <span class="number">1</span>))</span><br><span class="line">                <span class="variable language_">self</span>.build_arch()</span><br><span class="line"></span><br><span class="line">        tf.logging.info(<span class="string">&#x27;Seting up the main structure&#x27;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">build_arch</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="keyword">with</span> tf.variable_scope(<span class="string">&#x27;Conv1_layer&#x27;</span>):</span><br><span class="line">            <span class="comment"># Conv1, [batch_size, 20, 20, 256]</span></span><br><span class="line">            conv1 = tf.contrib.layers.conv2d(<span class="variable language_">self</span>.X, num_outputs=<span class="number">256</span>,</span><br><span class="line">                                             kernel_size=<span class="number">9</span>, stride=<span class="number">1</span>,</span><br><span class="line">                                             padding=<span class="string">&#x27;VALID&#x27;</span>)</span><br><span class="line">            <span class="keyword">assert</span> conv1.get_shape() == [cfg.batch_size, <span class="number">20</span>, <span class="number">20</span>, <span class="number">256</span>]</span><br><span class="line"></span><br><span class="line">        <span class="comment"># Primary Capsules layer, return [batch_size, 1152, 8, 1]</span></span><br><span class="line">        <span class="keyword">with</span> tf.variable_scope(<span class="string">&#x27;PrimaryCaps_layer&#x27;</span>):</span><br><span class="line">            primaryCaps = CapsLayer(num_outputs=<span class="number">32</span>, vec_len=<span class="number">8</span>, with_routing=<span class="literal">False</span>, layer_type=<span class="string">&#x27;CONV&#x27;</span>)</span><br><span class="line">            caps1 = primaryCaps(conv1, kernel_size=<span class="number">9</span>, stride=<span class="number">2</span>)</span><br><span class="line">            <span class="keyword">assert</span> caps1.get_shape() == [cfg.batch_size, <span class="number">1152</span>, <span class="number">8</span>, <span class="number">1</span>]</span><br><span class="line"></span><br><span class="line">        <span class="comment"># DigitCaps layer, return [batch_size, 10, 16, 1]</span></span><br><span class="line">        <span class="keyword">with</span> tf.variable_scope(<span class="string">&#x27;DigitCaps_layer&#x27;</span>):</span><br><span class="line">            digitCaps = CapsLayer(num_outputs=<span class="number">10</span>, vec_len=<span class="number">16</span>, with_routing=<span class="literal">True</span>, layer_type=<span class="string">&#x27;FC&#x27;</span>)</span><br><span class="line">            <span class="variable language_">self</span>.caps2 = digitCaps(caps1)</span><br><span class="line"></span><br><span class="line">        <span class="comment"># Decoder structure in Fig. 2</span></span><br><span class="line">        <span class="comment"># 1. Do masking, how:</span></span><br><span class="line">        <span class="keyword">with</span> tf.variable_scope(<span class="string">&#x27;Masking&#x27;</span>):</span><br><span class="line">            <span class="comment"># a). calc ||v_c||, then do softmax(||v_c||)</span></span><br><span class="line">            <span class="comment"># [batch_size, 10, 16, 1] =&gt; [batch_size, 10, 1, 1]</span></span><br><span class="line">            <span class="variable language_">self</span>.v_length = tf.sqrt(tf.reduce_sum(tf.square(<span class="variable language_">self</span>.caps2),</span><br><span class="line">                                                  axis=<span class="number">2</span>, keep_dims=<span class="literal">True</span>) + epsilon)</span><br><span class="line">            <span class="variable language_">self</span>.softmax_v = tf.nn.softmax(<span class="variable language_">self</span>.v_length, dim=<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">assert</span> <span class="variable language_">self</span>.softmax_v.get_shape() == [cfg.batch_size, <span class="number">10</span>, <span class="number">1</span>, <span class="number">1</span>]</span><br><span class="line"></span><br><span class="line">            <span class="comment"># b). pick out the index of max softmax val of the 10 caps</span></span><br><span class="line">            <span class="comment"># [batch_size, 10, 1, 1] =&gt; [batch_size] (index)</span></span><br><span class="line">            <span class="variable language_">self</span>.argmax_idx = tf.to_int32(tf.argmax(<span class="variable language_">self</span>.softmax_v, axis=<span class="number">1</span>))</span><br><span class="line">            <span class="keyword">assert</span> <span class="variable language_">self</span>.argmax_idx.get_shape() == [cfg.batch_size, <span class="number">1</span>, <span class="number">1</span>]</span><br><span class="line">            <span class="variable language_">self</span>.argmax_idx = tf.reshape(<span class="variable language_">self</span>.argmax_idx, shape=(cfg.batch_size, ))</span><br><span class="line"></span><br><span class="line">            <span class="comment"># Method 1.</span></span><br><span class="line">            <span class="keyword">if</span> <span class="keyword">not</span> cfg.mask_with_y:</span><br><span class="line">                <span class="comment"># c). indexing</span></span><br><span class="line">                <span class="comment"># It&#x27;s not easy to understand the indexing process with argmax_idx</span></span><br><span class="line">                <span class="comment"># as we are 3-dim animal</span></span><br><span class="line">                masked_v = []</span><br><span class="line">                <span class="keyword">for</span> batch_size <span class="keyword">in</span> <span class="built_in">range</span>(cfg.batch_size):</span><br><span class="line">                    v = <span class="variable language_">self</span>.caps2[batch_size][<span class="variable language_">self</span>.argmax_idx[batch_size], :]</span><br><span class="line">                    masked_v.append(tf.reshape(v, shape=(<span class="number">1</span>, <span class="number">1</span>, <span class="number">16</span>, <span class="number">1</span>)))</span><br><span class="line"></span><br><span class="line">                <span class="variable language_">self</span>.masked_v = tf.concat(masked_v, axis=<span class="number">0</span>)</span><br><span class="line">                <span class="keyword">assert</span> <span class="variable language_">self</span>.masked_v.get_shape() == [cfg.batch_size, <span class="number">1</span>, <span class="number">16</span>, <span class="number">1</span>]</span><br><span class="line">            <span class="comment"># Method 2. masking with true label, default mode</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="comment"># self.masked_v = tf.matmul(tf.squeeze(self.caps2), tf.reshape(self.Y, (-1, 10, 1)), transpose_a=True)</span></span><br><span class="line">                <span class="variable language_">self</span>.masked_v = tf.multiply(tf.squeeze(<span class="variable language_">self</span>.caps2), tf.reshape(<span class="variable language_">self</span>.Y, (-<span class="number">1</span>, <span class="number">10</span>, <span class="number">1</span>)))</span><br><span class="line">                <span class="variable language_">self</span>.v_length = tf.sqrt(tf.reduce_sum(tf.square(<span class="variable language_">self</span>.caps2), axis=<span class="number">2</span>, keep_dims=<span class="literal">True</span>) + epsilon)</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 2. Reconstructe the MNIST images with 3 FC layers</span></span><br><span class="line">        <span class="comment"># [batch_size, 1, 16, 1] =&gt; [batch_size, 16] =&gt; [batch_size, 512]</span></span><br><span class="line">        <span class="keyword">with</span> tf.variable_scope(<span class="string">&#x27;Decoder&#x27;</span>):</span><br><span class="line">            vector_j = tf.reshape(<span class="variable language_">self</span>.masked_v, shape=(cfg.batch_size, -<span class="number">1</span>))</span><br><span class="line">            fc1 = tf.contrib.layers.fully_connected(vector_j, num_outputs=<span class="number">512</span>)</span><br><span class="line">            <span class="keyword">assert</span> fc1.get_shape() == [cfg.batch_size, <span class="number">512</span>]</span><br><span class="line">            fc2 = tf.contrib.layers.fully_connected(fc1, num_outputs=<span class="number">1024</span>)</span><br><span class="line">            <span class="keyword">assert</span> fc2.get_shape() == [cfg.batch_size, <span class="number">1024</span>]</span><br><span class="line">            <span class="variable language_">self</span>.decoded = tf.contrib.layers.fully_connected(fc2, num_outputs=<span class="number">784</span>, activation_fn=tf.sigmoid)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">loss</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="comment"># 1. The margin loss</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># [batch_size, 10, 1, 1]</span></span><br><span class="line">        <span class="comment"># max_l = max(0, m_plus-||v_c||)^2</span></span><br><span class="line">        max_l = tf.square(tf.maximum(<span class="number">0.</span>, cfg.m_plus - <span class="variable language_">self</span>.v_length))</span><br><span class="line">        <span class="comment"># max_r = max(0, ||v_c||-m_minus)^2</span></span><br><span class="line">        max_r = tf.square(tf.maximum(<span class="number">0.</span>, <span class="variable language_">self</span>.v_length - cfg.m_minus))</span><br><span class="line">        <span class="keyword">assert</span> max_l.get_shape() == [cfg.batch_size, <span class="number">10</span>, <span class="number">1</span>, <span class="number">1</span>]</span><br><span class="line"></span><br><span class="line">        <span class="comment"># reshape: [batch_size, 10, 1, 1] =&gt; [batch_size, 10]</span></span><br><span class="line">        max_l = tf.reshape(max_l, shape=(cfg.batch_size, -<span class="number">1</span>))</span><br><span class="line">        max_r = tf.reshape(max_r, shape=(cfg.batch_size, -<span class="number">1</span>))</span><br><span class="line"></span><br><span class="line">        <span class="comment"># calc T_c: [batch_size, 10]</span></span><br><span class="line">        <span class="comment"># T_c = Y, is my understanding correct? Try it.</span></span><br><span class="line">        T_c = <span class="variable language_">self</span>.Y</span><br><span class="line">        <span class="comment"># [batch_size, 10], element-wise multiply</span></span><br><span class="line">        L_c = T_c * max_l + cfg.lambda_val * (<span class="number">1</span> - T_c) * max_r</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">self</span>.margin_loss = tf.reduce_mean(tf.reduce_sum(L_c, axis=<span class="number">1</span>))</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 2. The reconstruction loss</span></span><br><span class="line">        orgin = tf.reshape(<span class="variable language_">self</span>.X, shape=(cfg.batch_size, -<span class="number">1</span>))</span><br><span class="line">        squared = tf.square(<span class="variable language_">self</span>.decoded - orgin)</span><br><span class="line">        <span class="variable language_">self</span>.reconstruction_err = tf.reduce_mean(squared)</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 3. Total loss</span></span><br><span class="line">        <span class="comment"># The paper uses sum of squared error as reconstruction error, but we</span></span><br><span class="line">        <span class="comment"># have used reduce_mean in `# 2 The reconstruction loss` to calculate</span></span><br><span class="line">        <span class="comment"># mean squared error. In order to keep in line with the paper,the</span></span><br><span class="line">        <span class="comment"># regularization scale should be 0.0005*784=0.392</span></span><br><span class="line">        <span class="variable language_">self</span>.total_loss = <span class="variable language_">self</span>.margin_loss + cfg.regularization_scale * <span class="variable language_">self</span>.reconstruction_err</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/paper/Dynamic_Routing_Between_Capsules%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/paper/Dynamic_Routing_Between_Capsules%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h1 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h1><p>本文记录了阅读论文<a href="https://arxiv.org/pdf/1710.09829" target]]>
    </summary>
    <title>Dynamic Routing Between Capsules论文阅读</title>
    <updated>2026-08-18T05:18:12.527Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="DL&amp;ML" scheme="https://junyanwu.github.io/tags/DL-ML/"/>
    <category term="Paper Reading" scheme="https://junyanwu.github.io/tags/Paper-Reading/"/>
    <category term="Code" scheme="https://junyanwu.github.io/tags/Code/"/>
    <category term="GCN" scheme="https://junyanwu.github.io/tags/GCN/"/>
    <category term="GCRN" scheme="https://junyanwu.github.io/tags/GCRN/"/>
    <content>
      <![CDATA[<h2 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h2><ul><li>论文及源代码：<a href="https://github.com/youngjoo-epfl/gconvRNN" target="_blank" rel="noopener">点击这里</a></li></ul><p>若发现存在错误，欢迎指正。</p><p>GCN，是基于Spectral Graph Theory所研究出来的一种方法，它主要的好处是利用了SGT里面一些已有的结论和方法，来得到图的性质。GCRN是一个将GCN和RNN结合起来使用的模型，能处理具有空间和时序的数据。</p><p>源代码的目录结构：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">gconvRNN</span><br><span class="line">  - datasets</span><br><span class="line">    - ptb.char.test.txt</span><br><span class="line">    - ptb.char.train.txt</span><br><span class="line">    - ptb.char.valid.txt</span><br><span class="line">  - gcrn_main.py  # 整个程序的入口</span><br><span class="line">  - config.py  # 用于配置超参数</span><br><span class="line">  - graph.py  # 与图相关的操作，比如laplacian矩阵</span><br><span class="line">  - model.py  # 模型的定义</span><br><span class="line">  - trainer.py  # 定义了训练过程</span><br><span class="line">  - utils.py  # 数据预处理、工具</span><br></pre></td></tr></table></figure><p>在源码中，GCRN用于预测单词字符序列</p><p>本文从三个方面讲解GCRN源码的处理思路</p><ul><li>数据预处理</li><li>GCRN实现思路</li><li>开始训练</li><li>代码附录</li></ul><h2 id="数据预处理："><a href="#数据预处理：" class="headerlink" title="数据预处理："></a>数据预处理：</h2><p><em>train\valid\test 数据集的格式都是一样的：</em></p><blockquote><p>a e r <em> b a n k n o t e </em> b e r l i t z <em> c a l l o w a y </em> c e n t r u s t <em> c l u e t t </em> f r o m s t e i n <em> g i t a n o </em> g u t e r m a n <em> h y d r o - q u e b e c </em> i p o <em> k i a </em> m e m o t e c <em> m l x </em> n a h b <em> p u n t s </em> r a k e <em> r e g a t t a </em> r u b e n s <em> s i m </em> s n a c k - f o o d <em> s s a n g y o n g </em> s w a p o <em> w a c h t e r<br> p i e r r e </em> &lt; u n k &gt; <em> N </em> y e a r s <em> o l d </em> w i l l <em> j o i n </em> t h e <em> b o a r d </em> a s <em> a </em> n o n e x e c u t i v e <em> d i r e c t o r </em> n o v . <em> N<br> m r . </em> &lt; u n k &gt; <em> i s </em> c h a i r m a n <em> o f </em> &lt; u n k &gt; <em> n . v . </em> t h e <em> d u t c h </em> p u b l i s h i n g _ g r o u p</p></blockquote><ul><li><code>UNK</code> - “unknown token” - is used to replace the rare words that did not fit in your vocabulary. So your sentence <code>My name is guotong1998</code> will be translated into <code>My name is _unk_</code></li></ul><p><strong>1. 将句子按字典映射成数字序列</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">for every sentences:</span><br><span class="line">  在句子后面加“|”（人为地添加句子的结束标识符）</span><br><span class="line">  将句子里面的*每个字符*映射成该字符在字典中*对应的数字*</span><br></pre></td></tr></table></figure><p>例如：</p><p>p i e r r e <em> &lt; u n k &gt; </em> N <em> y e a r s </em> o l d <em> w i l l </em> j o i n <em> t h e </em> b o a r d <em> a s </em> a <em> n o n e x e c u t i v e </em> d i r e c t o r <em> n o v . </em> N |</p><p>[24, 10, 1, 2, 2, 1, 3, 27, 15, 5, 6, 28, 3, 29, 3, 14, 1, 0, 2, 16, 3, 7, 9, 21, 3, 13, 10, 9, 9, 3, 30, 7, 10, 5, 3, 8, 20, 1, 3, 4, 7, 0, 2, 21, 3, 0, 16, 3, 0, 3, 5, 7, 5, 1, 25, 1, 12, 15, 8, 10, 31, 1, 3, 21, 10, 2, 1, 12, 8, 7, 2, 3, 5, 7, 31, 32, 3, 29, 26]</p><p><strong>2. 构造邻接矩阵</strong></p><p><img src="/images/adj.png" alt=""></p><p>得到邻接矩阵的值：</p><p><img src="/images/adj_value.png" alt=""></p><h2 id="GCRN实现思路："><a href="#GCRN实现思路：" class="headerlink" title="GCRN实现思路："></a>GCRN实现思路：</h2><p>GCRN = GCN + RNN。</p><p><em>公式</em>：</p><p><img src="/images/gconv.png" alt=""></p><p><img src="/images/lstm_func.png" alt=""></p><p><strong>但是</strong> 代码中的实现方式稍有不同</p><p><strong>GCN</strong> ：</p><script type="math/tex; mode=display">L = adj/adj.max</script><script type="math/tex; mode=display">Laplacian = \frac{2L}{lmax} - I</script><script type="math/tex; mode=display">T_k(x) = 2LT_{k-1}(x)-T_{k-2}(x)</script><p>每次得到的 $T_k(x)$ 都与x做concat，最后得到的x与W相乘</p><p><strong>LSTM</strong> ：</p><p><img src="/images/gcn_lstm.png" alt=""></p><h2 id="开始训练"><a href="#开始训练" class="headerlink" title="开始训练"></a>开始训练</h2><p>数据预处理 -&gt; model定义 -&gt; train</p><p><img src="/images/dataflow.png" alt=""></p><p>输出<code>ouput</code>的shape为(batch_size, num_node, num_unit) —— (20, 50, 50)。由于设置了有50个LSTM units，所以这里需要使所有units的输出做线性变换，使其变为一个值：</p><ul><li><code>prediction = output * W -b</code>，这里的<code>prediction</code>的shape为(20, 50, 1)</li></ul><p>那么，所有时刻的输出的shape为(50, 20, 50, 1)</p><h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><p><strong>GCN实现方法</strong></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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">cheby_conv</span>(<span class="params">x, L, lmax, feat_out, K, W</span>):</span><br><span class="line">    <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">    x : [batch_size, N_node, feat_in] - input of each time step</span></span><br><span class="line"><span class="string">    nSample : number of samples = batch_size</span></span><br><span class="line"><span class="string">    nNode : number of node in graph</span></span><br><span class="line"><span class="string">    feat_in : number of input feature</span></span><br><span class="line"><span class="string">    feat_out : number of output feature</span></span><br><span class="line"><span class="string">    L : laplacian</span></span><br><span class="line"><span class="string">    lmax : ?</span></span><br><span class="line"><span class="string">    K : size of kernel(number of cheby coefficients)</span></span><br><span class="line"><span class="string">    W : cheby_conv weight [K * feat_in, feat_out]</span></span><br><span class="line"><span class="string">    &#x27;&#x27;&#x27;</span></span><br><span class="line">    nSample, nNode, feat_in = x.get_shape()</span><br><span class="line">    nSample, nNode, feat_in = <span class="built_in">int</span>(nSample), <span class="built_in">int</span>(nNode), <span class="built_in">int</span>(feat_in)</span><br><span class="line">    L = graph.rescale_L(L, lmax) <span class="comment">#What is this operation?? --&gt; rescale Laplacian</span></span><br><span class="line">    L = L.tocoo()</span><br><span class="line"></span><br><span class="line">    indices = np.column_stack((L.row, L.col))</span><br><span class="line">    L = tf.SparseTensor(indices, L.data, L.shape)</span><br><span class="line">    L = tf.sparse_reorder(L)</span><br><span class="line"></span><br><span class="line">    x0 = tf.transpose(x, perm=[<span class="number">1</span>, <span class="number">2</span>, <span class="number">0</span>]) <span class="comment">#change it to [nNode, feat_in, nSample]</span></span><br><span class="line">    x0 = tf.reshape(x0, [nNode, feat_in*nSample])</span><br><span class="line">    x = tf.expand_dims(x0, <span class="number">0</span>) <span class="comment"># make it [1, nNode, feat_in*nSample]</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">concat</span>(<span class="params">x, x_</span>):</span><br><span class="line">        x_ = tf.expand_dims(x_, <span class="number">0</span>)</span><br><span class="line">        <span class="keyword">return</span> tf.concat([x, x_], axis=<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> K &gt; <span class="number">1</span>:</span><br><span class="line">        x1 = tf.sparse_tensor_dense_matmul(L, x0)</span><br><span class="line">        x = concat(x, x1)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> k <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">2</span>, K):</span><br><span class="line">        x2 = <span class="number">2</span> * tf.sparse_tensor_dense_matmul(L, x1) - x0</span><br><span class="line">        x = concat(x, x2)</span><br><span class="line">        x0, x1 = x1, x2</span><br><span class="line"></span><br><span class="line">    x = tf.reshape(x, [K, nNode, feat_in, nSample])</span><br><span class="line">    x = tf.transpose(x, perm=[<span class="number">3</span>,<span class="number">1</span>,<span class="number">2</span>,<span class="number">0</span>])</span><br><span class="line">    x = tf.reshape(x, [nSample*nNode, feat_in*K])</span><br><span class="line"></span><br><span class="line">    x = tf.matmul(x, W) <span class="comment">#No Bias term?? -&gt; Yes</span></span><br><span class="line">    out = tf.reshape(x, [nSample, nNode, feat_out])</span><br><span class="line">    <span class="keyword">return</span> out</span><br></pre></td></tr></table></figure><p><strong>LSTM实现方法</strong></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><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><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">__call__</span>(<span class="params">self, inputs, state, scope=<span class="literal">None</span></span>):</span><br><span class="line">    <span class="keyword">with</span> tf.variable_scope(scope <span class="keyword">or</span> <span class="built_in">type</span>(<span class="variable language_">self</span>).__name__):</span><br><span class="line">        <span class="keyword">if</span> <span class="variable language_">self</span>._state_is_tuple:</span><br><span class="line">            c, h = state</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            c, h = tf.split(value=state, num_or_size_splits=<span class="number">2</span>, axis=<span class="number">1</span>)</span><br><span class="line">        laplacian = <span class="variable language_">self</span>._laplacian</span><br><span class="line">        lmax = <span class="variable language_">self</span>._lmax</span><br><span class="line">        K = <span class="variable language_">self</span>._K</span><br><span class="line">        feat_in = <span class="variable language_">self</span>._feat_in</span><br><span class="line"></span><br><span class="line">        <span class="comment">#The inputs : [batch_size, nNode, feat_in, nTime?] size tensor</span></span><br><span class="line">        <span class="keyword">if</span> feat_in <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">            <span class="comment">#Take out the shape of input</span></span><br><span class="line">            batch_size, nNode, feat_in = inputs.get_shape()</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">&quot;hey!&quot;</span>)</span><br><span class="line"></span><br><span class="line">        feat_out = <span class="variable language_">self</span>._num_units</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> K <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">            K = <span class="number">2</span></span><br><span class="line"></span><br><span class="line">        scope = tf.get_variable_scope()</span><br><span class="line">        <span class="keyword">with</span> tf.variable_scope(scope) <span class="keyword">as</span> scope:</span><br><span class="line">            <span class="keyword">try</span>:</span><br><span class="line">                <span class="comment">#Need four diff Wconv weight + for Hidden weight</span></span><br><span class="line">                Wzxt = tf.get_variable(<span class="string">&quot;Wzxt&quot;</span>, [K*feat_in, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line">                Wixt = tf.get_variable(<span class="string">&quot;Wixt&quot;</span>, [K*feat_in, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line">                Wfxt = tf.get_variable(<span class="string">&quot;Wfxt&quot;</span>, [K*feat_in, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line">                Woxt = tf.get_variable(<span class="string">&quot;Woxt&quot;</span>, [K*feat_in, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line"></span><br><span class="line">                Wzht = tf.get_variable(<span class="string">&quot;Wzht&quot;</span>, [K*feat_out, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line">                Wiht = tf.get_variable(<span class="string">&quot;Wiht&quot;</span>, [K*feat_out, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line">                Wfht = tf.get_variable(<span class="string">&quot;Wfht&quot;</span>, [K*feat_out, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line">                Woht = tf.get_variable(<span class="string">&quot;Woht&quot;</span>, [K*feat_out, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line">            <span class="keyword">except</span> ValueError:</span><br><span class="line">                scope.reuse_variables()</span><br><span class="line">                Wzxt = tf.get_variable(<span class="string">&quot;Wzxt&quot;</span>, [K*feat_in, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line">                Wixt = tf.get_variable(<span class="string">&quot;Wixt&quot;</span>, [K*feat_in, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line">                Wfxt = tf.get_variable(<span class="string">&quot;Wfxt&quot;</span>, [K*feat_in, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line">                Woxt = tf.get_variable(<span class="string">&quot;Woxt&quot;</span>, [K*feat_in, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line"></span><br><span class="line">                Wzht = tf.get_variable(<span class="string">&quot;Wzht&quot;</span>, [K*feat_out, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line">                Wiht = tf.get_variable(<span class="string">&quot;Wiht&quot;</span>, [K*feat_out, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line">                Wfht = tf.get_variable(<span class="string">&quot;Wfht&quot;</span>, [K*feat_out, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line">                Woht = tf.get_variable(<span class="string">&quot;Woht&quot;</span>, [K*feat_out, feat_out], dtype=tf.float32,</span><br><span class="line">                                       initializer=tf.random_uniform_initializer(minval=-<span class="number">0.1</span>, maxval=<span class="number">0.1</span>))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">            bzt = tf.get_variable(<span class="string">&quot;bzt&quot;</span>, [feat_out])</span><br><span class="line">            bit = tf.get_variable(<span class="string">&quot;bit&quot;</span>, [feat_out])</span><br><span class="line">            bft = tf.get_variable(<span class="string">&quot;bft&quot;</span>, [feat_out])</span><br><span class="line">            bot = tf.get_variable(<span class="string">&quot;bot&quot;</span>, [feat_out])</span><br><span class="line"></span><br><span class="line">            <span class="comment"># gconv Calculation</span></span><br><span class="line">            zxt = cheby_conv(inputs, laplacian, lmax, feat_out, K, Wzxt)</span><br><span class="line">            zht = cheby_conv(h, laplacian, lmax, feat_out, K, Wzht)</span><br><span class="line">            zt  = zxt + zht + bzt</span><br><span class="line">            zt  = tf.tanh(zt)</span><br><span class="line"></span><br><span class="line">            ixt = cheby_conv(inputs, laplacian, lmax, feat_out, K, Wixt)</span><br><span class="line">            iht = cheby_conv(h, laplacian, lmax, feat_out, K, Wiht)</span><br><span class="line">            it  = ixt + iht + bit</span><br><span class="line">            it  = tf.sigmoid(it)</span><br><span class="line"></span><br><span class="line">            fxt = cheby_conv(inputs, laplacian, lmax, feat_out, K, Wfxt)</span><br><span class="line">            fht = cheby_conv(h, laplacian, lmax, feat_out, K, Wfht)</span><br><span class="line">            ft  = fxt + fht + bft</span><br><span class="line">            ft  = tf.sigmoid(ft)</span><br><span class="line"></span><br><span class="line">            oxt = cheby_conv(inputs, laplacian, lmax, feat_out, K, Woxt)</span><br><span class="line">            oht = cheby_conv(h, laplacian, lmax, feat_out, K, Woht)</span><br><span class="line">            ot  = oxt + oht + bot</span><br><span class="line">            ot  = tf.sigmoid(ot)</span><br><span class="line"></span><br><span class="line">            <span class="comment"># c</span></span><br><span class="line">            new_c = ft*c + it*zt</span><br><span class="line"></span><br><span class="line">            <span class="comment"># h</span></span><br><span class="line">            new_h = ot*tf.tanh(new_c)</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> <span class="variable language_">self</span>._state_is_tuple:</span><br><span class="line">                new_state = LSTMStateTuple(new_c, new_h)</span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                new_state = tf.concat([new_c, new_h], <span class="number">1</span>)</span><br><span class="line">            <span class="keyword">return</span> new_h, new_state</span><br></pre></td></tr></table></figure><h3 id="其他变量"><a href="#其他变量" class="headerlink" title="其他变量"></a>其他变量</h3><div class="table-container"><table><thead><tr><th>变量</th><th>shape</th><th>meaning</th></tr></thead><tbody><tr><td>rnn_input</td><td>(20, 50, 1, 50)</td><td>(batch_size, num_node, feat_in, num_time_steps)</td></tr><tr><td>rnn_input_seq</td><td>(20, 50, 1) * 50</td><td>(batch_size, num_node, feat_in) * num_time_steps</td></tr><tr><td>rnn_output</td><td>(20, 50)</td><td>(batch_size, num_time_steps)</td></tr><tr><td>rnn_output_seq</td><td>(20) * 50</td><td>(batch_size) * num_time_steps</td></tr><tr><td>num_hidden</td><td>50</td><td>隐藏层单元</td></tr><tr><td>x_batches</td><td>(5017, 20, 50)</td><td>[-1, batch_size, seq_length]</td></tr><tr><td>y_batches</td><td>(5017, 20, 50)</td><td>[-1, batch_size, seq_length]</td></tr><tr><td>outputs</td><td>(50, 20, 50, 50)</td><td>(50个时刻50个输出, batch_size, num_node, num_unit)</td></tr><tr><td>output</td><td>(20, 50, 50)</td><td>outputs的单个时刻输出(batch_size, num_node, num_unit)</td></tr></tbody></table></div><h2 id="Laplacian-matrix"><a href="#Laplacian-matrix" class="headerlink" title="Laplacian matrix"></a>Laplacian matrix</h2><p><img src="/images/laplacian_example.png" alt=""></p><p><strong>Properties</strong></p><p>对一个无向图$G$和他的laplacian matrix $L$，有特征值$\lambda_0 \leq \lambda_1 \leq \lambda_2 …$：</p><ul><li>L是对称的</li><li>L是半正定的（即所有$\lambda_i &gt; 0$），这可以在关联矩阵部分验证，也同样可以从Laplacian是对称并且对角占优(diagonally dominant)得出</li><li>L是M-matrix（它的非对角线上的项是负的，但它的特征值的实部为负）</li><li>行或列相加结果为0</li><li>L的最小非零特征值称为谱间隙（spectral gap）</li><li>图中连通分量的个数是拉普拉斯算子的零空间维数和0特征值的代数多重性</li><li>拉普拉斯矩阵是奇异的</li></ul><h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><ol><li>代码实现里面的公式跟论文是否真的不一样</li><li>x2 = 2 * tf.sparse_tensor_dense_matmul(L, x1) - x0 起到一个什么作用</li></ol><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>补充一下，后来跟实验室的小伙伴谈论过后对GCN有了比较深刻的认识。上面问题中的第二点，其实跟GCN的K的大小有关。K=1，表示包含了该节点一条的信息。至于为什么会这样，这是因为在计算过程中与由adj mnatrix得来的Laplacian相乘，每乘一次，就会多包含一跳的节点信息。</p>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/paper/GCRN/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/paper/GCRN/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h2 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h2><ul>
<li>论文及源代码：<a href="https://github.com/youngjoo-epfl/gco]]>
    </summary>
    <title>GCRN代码解读</title>
    <updated>2026-08-18T05:18:12.527Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="DL&amp;ML" scheme="https://junyanwu.github.io/tags/DL-ML/"/>
    <category term="离散的笔记" scheme="https://junyanwu.github.io/tags/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/"/>
    <category term="Term" scheme="https://junyanwu.github.io/tags/Term/"/>
    <category term="Loss" scheme="https://junyanwu.github.io/tags/Loss/"/>
    <content>
      <![CDATA[<ul><li><a href="https://en.wikipedia.org/wiki/Huber_loss" target="_blank" rel="noopener">wikipedia</a></li></ul><p>在统计学里面，Huber loss是一个在robust regression里面用的loss func。它对离群点没平方差那么敏感。</p><p><em>定义</em></p><p><img src="https://wikimedia.org/api/rest_v1/media/math/render/svg/e384efc4ae2632cb0bd714462b7c38c272098cf5" alt=""></p><p>其中，$|a| = \delta, a = y-f(x)$。$\delta$是参数，$f(x)$是模型的预测值，$y$是真实值。</p><p>可以看到，当$a &lt; \delta$时，L是二次的；否则，则是线性的。</p>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/Huber_loss/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/Huber_loss/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<ul>
<li><a href="https://en.wikipedia.org/wiki/Huber_loss" target="_blank" rel="noopener">wikipedia</a></li>
</ul>
<p>在统计学里面，Huber loss是一个在]]>
    </summary>
    <title>Huber loss</title>
    <updated>2026-08-18T05:18:12.527Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="DL&amp;ML" scheme="https://junyanwu.github.io/tags/DL-ML/"/>
    <category term="离散的笔记" scheme="https://junyanwu.github.io/tags/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/"/>
    <category term="RNN" scheme="https://junyanwu.github.io/tags/RNN/"/>
    <content>
      <![CDATA[<h1 id="Why-RNN"><a href="#Why-RNN" class="headerlink" title="Why RNN"></a>Why RNN</h1><p>某些任务是需要NN具有记忆的，比如</p><ul><li>我 来了 台北</li><li>我 离开了 台北</li></ul><p>要确定我要离开还是来了台北，需要知道前一个单词是什么。这就需要网络具有记忆，于是就提出了RNN。</p><h1 id="Why-RNN’s-error-surface-so-rough"><a href="#Why-RNN’s-error-surface-so-rough" class="headerlink" title="Why RNN’s error surface so rough"></a>Why RNN’s error surface so rough</h1><p>这是长距离传输引起的。假设有一个RNN，它的 memory 等于上一个时刻的 memory * w。除了第一个时刻 input = 1 之外，其他所有时刻 input = 0。那么在经过1001个时刻的传输后：</p><script type="math/tex; mode=display">w = 1，1*w^{1000} = 1</script><script type="math/tex; mode=display">w = 1.01，1*w^{1000} = 20000</script><script type="math/tex; mode=display">w = 0.99，1*w^{1000} = 0</script><script type="math/tex; mode=display">w = 0.01，1*w^{1000} = 0</script><p>可以看到，w发生微小的变化会引起蝴蝶效应。这是长距离传输里面存在的问题，也是 error surface 抖动如此大的原因所在。</p><p>当然，这是李宏毅视频里面说的，我的问题是，这明显是一个单调函数，如何会引起剧烈抖动？</p><p>可能跟 training 过程中参数的微小变化有关。但是参数存在以下变动情况：</p><ul><li>参数经常有微小变化。这个应该不会形成蝴蝶效应吧？</li><li>参数单调增减一段时间又单调减增。不明。</li><li>参数总体是单调的。这种情况应该是逐渐变化的，不会出现剧烈抖动吧？</li><li>参数经常剧烈变化，即 Gradient 值突然很大。根据前面视频的内容，RNN应该就是这种情况。只是如果是这种情况，他举上面那个长距离传输例子既不是都不相关了吗？</li></ul><p>后来我通过编程发现，<code>result *= w</code>这种运算一开始 <code>result(t)-result(t-1)</code>只有0.几，但是到后面就有100+。</p><p><strong>所以</strong>，这确实是原因所在，训练越到后面，Gradient 的值变化越来越大，error surface 的动荡越频繁越明显。所以作者想了下面的解决办法。</p><p><strong>how to solve</strong></p><p>由于RNN的 error surface 太陡峭，所以训练的时候有个技巧，就是当 Gradient 超过某个 threshold 的时候就不要让它超过那个 threshold 。比如说超过了15，就让它 = 15。这样，参数的变化就会相对不会起飞太严重。</p><h1 id="RNN的training-trick"><a href="#RNN的training-trick" class="headerlink" title="RNN的training trick"></a>RNN的training trick</h1><h3 id="Identity-matrix-ReLU"><a href="#Identity-matrix-ReLU" class="headerlink" title="Identity matrix + ReLU"></a>Identity matrix + ReLU</h3><p>对于一般的RNN来说，可以用单位矩阵+ReLU来初始化RNN，会有很好的效果</p><hr><h1 id="LSTM"><a href="#LSTM" class="headerlink" title="LSTM"></a>LSTM</h1><h3 id="具体实现用到的技巧"><a href="#具体实现用到的技巧" class="headerlink" title="具体实现用到的技巧"></a>具体实现用到的技巧</h3><p>假设它的三个 GATE 的输入都是线性的，例如对 input-gate 来说，y = a1x1+a2x2+a3x3+a4b。它可以通过令 a4 = -10 来使 input-gate 有一定的阈值。</p><h3 id="LSTM-trick"><a href="#LSTM-trick" class="headerlink" title="LSTM trick"></a>LSTM trick</h3><hr><h1 id="GRU"><a href="#GRU" class="headerlink" title="GRU"></a>GRU</h1><p>如果发现LSTM过拟合很严重，可以试试这个。</p><hr><h1 id="Gradient-vanished"><a href="#Gradient-vanished" class="headerlink" title="Gradient vanished"></a>Gradient vanished</h1><p>提到上面的问题顺便提下 Gradient vanished</p><p>是 sigmoid 导致的。因为 sigmoid 的值在 [0, 1] 之间，所以在很深的网络里面会使每次的值越来越小，从而出现 vanished。</p><h5 id="其实，Rough-和-Vanished-本质上都是长距离传输导致的问题。"><a href="#其实，Rough-和-Vanished-本质上都是长距离传输导致的问题。" class="headerlink" title="其实，Rough 和 Vanished 本质上都是长距离传输导致的问题。"></a>其实，Rough 和 Vanished 本质上都是长距离传输导致的问题。</h5>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/RNN/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/RNN/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h1 id="Why-RNN"><a href="#Why-RNN" class="headerlink" title="Why RNN"></a>Why RNN</h1><p>某些任务是需要NN具有记忆的，比如</p>
<ul>
<li>我 来了 台北</li>
<li>我]]>
    </summary>
    <title>关于RNN的一些问题</title>
    <updated>2026-08-18T05:18:12.527Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="离散的笔记" scheme="https://junyanwu.github.io/tags/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/"/>
    <content>
      <![CDATA[<p>view the blog <a href="http://blog.minitab.com/blog/adventures-in-statistics-2/regression-analysis-how-do-i-interpret-r-squared-and-assess-the-goodness-of-fit" target="_blank" rel="noopener">here</a></p><p>R-squared是描述所训练出来的线性模型和数据的契合程度。</p><p><em>定义</em></p><p>R-squared = Explained variation / Total variation</p><p>R-squared是在0-100%之间的百分数</p><ul><li>0%表示model不能解释均值附近的数据的变化</li><li>100%表示model解释了均值附近所有数据</li></ul><p>通常来说，R-squared的值越高，model与数据的契合度越好（不绝对）。</p>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/R_squared/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/R_squared/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<p>view the blog <a href="http://blog.minitab.com/blog/adventures-in-statistics-2/regression-analysis-how-do-i-interpret-r-squared-and-asses]]>
    </summary>
    <title>R-squared</title>
    <updated>2026-08-18T05:18:12.526Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="DL&amp;ML" scheme="https://junyanwu.github.io/tags/DL-ML/"/>
    <category term="Paper Reading" scheme="https://junyanwu.github.io/tags/Paper-Reading/"/>
    <category term="GCN" scheme="https://junyanwu.github.io/tags/GCN/"/>
    <content>
      <![CDATA[<h2 id="2-Fast-Approximate-Convolutions-On-Graphs"><a href="#2-Fast-Approximate-Convolutions-On-Graphs" class="headerlink" title="2 Fast Approximate Convolutions On Graphs"></a>2 Fast Approximate Convolutions On Graphs</h2><ul><li>介绍基于图的神经网络模型 $f(X, A)$ 的理论基础</li></ul><script type="math/tex; mode=display">H^{(l+1)} = \sigma( \tilde{D}^{-\frac{1}{2}} \tilde{A} \tilde{D}^{-\frac{1}{2}} H^{(l)} W^{l} ) \tag2</script><ul><li>$\tilde{A} = A + I_N$：加了自连接的无向图的邻接矩阵</li><li>$\tilde{D} = \sum_{j} \tilde{A}_{ij}$：度矩阵</li><li>$W^{l}$：可训练的权重矩阵</li><li>$\sigma(\cdot)$：激活函数，如ReLU</li><li>$H^{(l)} \in R^{N * D}$：matrix of activations in the $l^{th}$ layer; $H^{(0)} = X$</li></ul><p>对于这个propagation rule，论文中提供了一个解释：<strong>Weisfeiler-Lehman algorithm</strong>，附录里面有解释，下面是原论文</p><blockquote><p>Boris Weisfeiler and A. A. Lehmann.  A reduction of a graph to a canonical form and an algebraarising during this reduction.Nauchno-Technicheskaya Informatsia, 2(9):12–16, 1968.</p></blockquote><p><br></p><h3 id="2-1-Spectral-Graph-Convolutions"><a href="#2-1-Spectral-Graph-Convolutions" class="headerlink" title="2.1 Spectral Graph Convolutions"></a>2.1 Spectral Graph Convolutions</h3><p>Spectral conv on graph定义为信号 $x \in R^{N}$ (每个节点都是一个标量)与filter $g_{\theta} = diag(\theta)$ (在Fourier domain中由 $\theta \in R^{N}$ 参数化的filter)：</p><script type="math/tex; mode=display">g_{\theta} \star x = U g_{\theta} U^T x \tag3</script><ul><li>U：normalized graph Laplacian <em>L</em> 的<strong>特征向量矩阵</strong></li><li><em>L</em> ：$L = I_N - D^{-\frac{1}{2}} A D^{-\frac{1}{2}} = U \Lambda U^T$</li></ul><blockquote><p>注：<br><br>这里就有很多问题了。</p><ol><li>首先，上文说 $g_{\theta}$ 是频域中的filter，一个频域的函数与时域的x做卷积？我查的资料没这个说法。</li><li>文中说U是L的特征向量矩阵，是由L得到的（具体看上面L的解释），那么可不可以说，U跟 $g_{\theta}$ 是没有运算关系的？</li><li>文中说$U^T x$是对x的傅里叶变化。所以Laplacian的特征向量矩阵还能做傅里叶变换？是有种变换叫拉普拉斯变换，但是不清楚与拉普拉斯矩阵的联系。</li></ol></blockquote><p>先把这些问题放一边，按照论文的解释， $g_{\theta}$ 是一个在Fourier domain的对角矩阵，而L的 $\Lambda$ 是它的一个特例。当L化成$U \Lambda U^T$的时候，由于L是时域的，所以$U^T$ 相当于是将其转为频域，$U$ 相当于将其转回时域。由于矩阵乘法满足结合律，所以论文说$U^T x$表示x的傅里叶变换，而$g_{\theta}$ 看作 $g_{\theta}( \Lambda )$。</p><p>(3)式的计算复杂度是 $O(N^2)$ ，太昂贵了，特别是在节点很多的时候计算L的特征值特征向量。下面这篇论文建议用 <em>Chebyshev polynomials</em> 来近似计算 $g_{\theta}( \Lambda )$ ：</p><blockquote><p>David K. Hammond, Pierre Vandergheynst, and R ́emi Gribonval.  Wavelets on graphs via spectralgraph theory.Applied and Computational Harmonic Analysis, 30(2):129–150, 2011.</p></blockquote><p>那么</p><script type="math/tex; mode=display">g_{\theta^{'}}( \Lambda ) \approx \sum_{k=0}^{K} {\theta}_{k}^{'} T_k({ \tilde{\Lambda} }) \tag4</script><ul><li><p>$\tilde{ \Lambda } = \frac{2}{\lambda_{max}} \Lambda - I_N$，$\lambda_{max}$ 表示L最大的特征值</p></li><li><p>$\theta^{‘} \in R^K$ 是vector of Chebyshev coefficients</p></li><li><p>$T_k(x) = 2 x T_{k-1} - T_{k-2}$，$T_0(x) = 1$，$T_1(x) = x$</p></li></ul><p>回到(3)式</p><script type="math/tex; mode=display">g_{\theta^{'}} \star x \approx \sum_{k=0}^{K} {\theta}_{k}^{'} T_k({\tilde{L}}) x \tag5</script><ul><li>$\tilde{L} = \frac{2}{\lambda_{max}} L - I_N$</li></ul><p>需要注意的事，现在的（5）式是Laplacian的K阶多项式，是<code>K-localized</code>的了。K指的是K steps away from the central node($K^{th}$-order neighborhood)</p><p>(5)式的计算复杂度是$O(|\varepsilon|)$ (linear in the number of edges)</p><p><strong>总结：</strong></p><p>2.1 讲的主要是</p><ul><li>Spectral conv on graph的定义</li><li>如何利用Chebyshev polynomials近似计算(3)式</li></ul><p><br></p><h3 id="2-2-Layer-wise-Linear-model"><a href="#2-2-Layer-wise-Linear-model" class="headerlink" title="2.2 Layer-wise Linear model"></a>2.2 Layer-wise Linear model</h3><p>将(5)式叠加，并且“each layer followed by a point-wise non-linearity”， 就形成了基于图卷积的神经网络。现在令K=1，那么函数就变成了关于L的线性函数，即“a linear function on the graph Laplacian spectrum”。</p><p>论文上直观地认为，不去明确限定Chebyshev polynomials的参数可以缓和对图上局部邻居结构的过拟合，这种图有着非常广的节点度分布。(这里省略了一部分内容)</p><p>在这种线性GCN下，近似 $\lambda_{max} \approx 2$，因为我们期望神经网络参数可以在训练中适应这种标量变化。在这种近似下，(5)式变为：</p><script type="math/tex; mode=display">g_{\theta^{'}} \star x \approx \theta_{0}^{'} x + \theta_{1}^{'} (L - I_N) x = \theta_{0}^{'} x - \theta_{1}^{'} D^{-\frac{1}{2}} A D^{-\frac{1}{2}} x \tag6</script><ul><li>filter的参数 $\theta_{0}^{‘}$ 和 $\theta_{1}^{‘}$ 可以在整个graph中共享</li></ul><p>filter以这种形式应用相当于对某个节点的$k^{th}$-order neighborhood做了高效的卷积(k是filtering operation的数量，或者是神经网络模型conv层的数量)</p><p>在实践中，<strong>限制参数</strong> 的数量可以解决过拟合，并且最小化operation的数量，所以再如下进行简化：</p><script type="math/tex; mode=display">g_{\theta^{'}} \star x \approx \theta (I_N + D^{-\frac{1}{2}} A D^{-\frac{1}{2}}) x \tag7</script><ul><li>$\theta = \theta_{0}^{‘} = - \theta_{1}^{‘}$</li></ul><p>问题是，重复这个operator会导致数值不稳定和梯度爆炸/消失，因此再用一个renormalization trick：$I_N + D^{-\frac{1}{2}} A D^{-\frac{1}{2}} \to \tilde{D}^{-\frac{1}{2}} \tilde{A} \tilde{D}^{-\frac{1}{2}}$，即令$\tilde{A} = A + I_N$，$\tilde{D}_{ii} = \sum_j \tilde{A}_{ij}$</p><p>之前说X是N×1的，我们可以一般化，使$X \in \mathbb{R}^{N \times C}$，C是input channels。于是(7)式化为：</p><script type="math/tex; mode=display">Z = \tilde{D}^{-\frac{1}{2}} \tilde{A} \tilde{D}^{-\frac{1}{2}} X \Theta \tag8</script><ul><li>$\Theta \in \mathbb{R}^{C \times F}$：filter的参数矩阵</li><li>$Z \in \mathbb{R}^{N \times F}$：X卷积后的信号矩阵</li><li>复杂度：$O(| \varepsilon | FC)$，因为$\tilde{A} X$可以实现为sparse matrix与dense matrix的product。</li></ul><p><br></p><h2 id="3-Semi-Supervised-Node-Classification"><a href="#3-Semi-Supervised-Node-Classification" class="headerlink" title="3 Semi-Supervised Node Classification"></a>3 Semi-Supervised Node Classification</h2><h3 id="3-1-Example"><a href="#3-1-Example" class="headerlink" title="3.1 Example"></a>3.1 Example</h3><p>这里，定义两层GCN做图的半监督节点分类，先计算$\hat{A} = \tilde{D}^{-\frac{1}{2}} \tilde{A} \tilde{D}^{-\frac{1}{2}}$，然后有</p><script type="math/tex; mode=display">Z = f(X, A) = softmax(\hat{A} ReLU(\hat{A} X W^{0})W^{(1)}) \tag9</script><ul><li><p>$softmax(x_i) = \frac{1}{sum} exp(x_i)，sum = \sum_i exp(x_i)$。注，softmax是row-wise的</p></li><li><p>$W^{0}，W^{(1)}$ 是通过gradient descent训练得到的，这里用的是batch gradient descent，每次training迭代用的都是整个数据集(需要将dataset放在内存)。</p></li><li>Stochasticity in the training process is introduced viadropout (Srivastava et al., 2014).  We leave memory-efficient extensions with mini-batch stochasticgradient descent for future work.</li></ul><p><strong>Loss function</strong></p><p>采用cross-entropy</p><script type="math/tex; mode=display">L = - \sum_{l \in y_L} \sum_{f =1}^{F} Y_{lf} lnZ_{lf} \tag{10}</script><ul><li>$y_L$：有label的节点集</li></ul><p><br></p><h3 id="3-2-Implementation"><a href="#3-2-Implementation" class="headerlink" title="3.2 Implementation"></a>3.2 Implementation</h3><p>在实践中，用Tensorflow来高效地使用GPU计算(Mart ́ın Abadi et al. TensorFlow: Large-scale machine learning on heterogeneous systems, 2015.)，(9)式使用sparse-dense matrix multiplications，复杂度$O(| \varepsilon | CHF)$</p><p><br></p><h2 id="7-Discussion"><a href="#7-Discussion" class="headerlink" title="7 Discussion"></a>7 Discussion</h2><h3 id="7-1-Semi-Supervised-Model"><a href="#7-1-Semi-Supervised-Model" class="headerlink" title="7.1 Semi-Supervised Model"></a>7.1 Semi-Supervised Model</h3><p>我们的方法好！很好！非常好！</p><p>基于graph-Laplacian regularization的方法很大可能会因为它的假设——边只编码节点的相似性。另一方面，基于Skip-gram的方法会因为它们是基于难以优化的“multi-step pipeline”而受限。</p><p>我们的renormalized propagation model(8式)效果很好！</p><h3 id="7-2-Limitations-And-Future-work"><a href="#7-2-Limitations-And-Future-work" class="headerlink" title="7.2 Limitations And Future work"></a>7.2 Limitations And Future work</h3><ul><li>对内存要求比较高</li><li>我们的框架并不天然地支持有向图和边的特征</li><li>我们假设self-connection与edges to neighboring nodes的重要性是一样的。对于某些数据集，<script type="math/tex">\tilde{A} = A + \lambda I_N \tag{11}</script> 会更好。其中 $\lambda$ 可以学习得到。</li></ul>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/paper/Semi_Supervised_Classification_With_Graph_Conv_Networks/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/paper/Semi_Supervised_Classification_With_Graph_Conv_Networks/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h2 id="2-Fast-Approximate-Convolutions-On-Graphs"><a href="#2-Fast-Approximate-Convolutions-On-Graphs" class="headerlink" title="2 Fast App]]>
    </summary>
    <title>SEMI-SUPERVISED CLASSIFICATION WITH GRAPH CONVOLUTIONAL NETWORKS</title>
    <updated>2026-08-18T05:18:12.527Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="DL&amp;ML" scheme="https://junyanwu.github.io/tags/DL-ML/"/>
    <category term="离散的笔记" scheme="https://junyanwu.github.io/tags/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/"/>
    <category term="Code" scheme="https://junyanwu.github.io/tags/Code/"/>
    <content>
      <![CDATA[<h3 id="Sparse-matrix"><a href="#Sparse-matrix" class="headerlink" title="Sparse matrix"></a>Sparse matrix</h3><p><strong>稀疏矩阵指的是矩阵里面的元素大多都是0值。</strong></p><p>与 sparse 相对的，就是 <strong>dense</strong>, which most elements of the matrix are nonzero</p><p>矩阵的稀疏性 = zero-valued elements / total number of elements</p><script type="math/tex; mode=display">Sparsity = \frac{N_{0}}{N_{all}}</script><h3 id="Sparse-Representation"><a href="#Sparse-Representation" class="headerlink" title="Sparse Representation"></a>Sparse Representation</h3><p><strong>Q：稀疏表达有什么好处？</strong></p><p>稀疏表达的意义在于降维，但是我还是不知道这个怎么搞得</p><p><strong>Q：稀疏表达 sparse representation 与 降维 dimensionality reduction 本质区别在哪？</strong></p><p>降维是将原 space 里的数据在某一个 subspace 里面表达，而稀疏表达是在 a union subspace 里面表达。</p><p><strong>举个例子</strong></p><p>(x, y, z)的空间中，(x, y)就是其中一个 subspace 。而 a union subspace 就包含了多个 subspace ，比如[(x, y), (y, z), (z, x)]就是 a union subspace。</p><p><strong>Q：如何求得数据的稀疏矩阵？</strong></p><p>to be continue</p><h3 id="Storing-a-sparse-matrix"><a href="#Storing-a-sparse-matrix" class="headerlink" title="Storing a sparse matrix"></a>Storing a sparse matrix</h3><p><strong>Compressed sparse row(CSR, CRS pr Yale format)</strong></p><script type="math/tex; mode=display">MatrixA =\begin{pmatrix}  0 & 0 & 0 & 0 \\  5 & 8 & 0 & 0 \\  0 & 0 & 3 & 0 \\  0 & 6 & 0 & 0 \\\end{pmatrix}</script>```python# dataA = data = (5, 8, 3, 6)# indptr的第一个元素为0，数值表示共有多少非零元素IA = indptr = (0, 0, 2, 3, 4)# 每个data的indexJA = indices = (0, 1, 2, 1)<figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;script type=&quot;math/tex; mode=display&quot;&gt;</span><br><span class="line">MatrixB =</span><br><span class="line">\begin&#123;pmatrix&#125;</span><br><span class="line">  10 &amp; 20 &amp; 0 &amp; 0 &amp; 0 &amp; 0 \\</span><br><span class="line">  0 &amp; 30 &amp; 0 &amp; 40 &amp; 0 &amp; 0 \\</span><br><span class="line">  0 &amp; 0 &amp; 50 &amp; 60 &amp; 70 &amp; 0 \\</span><br><span class="line">  0 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 80 \\</span><br><span class="line">\end&#123;pmatrix&#125;&lt;/script&gt;```python</span><br><span class="line">A = data = (10, 20, 30, 40, 50, 60, 70, 80)</span><br><span class="line">IA = indptr = (0, 2, 4, 7, 8)</span><br><span class="line">JA = indices = (0, 1, 1, 3, 2, 3, 4, 5)</span><br></pre></td></tr></table></figure><p><strong>List of list(LIL)</strong></p><p>LIL stores one list per row, with each entry containing the column index and the value. Typically, these entries are kept sorted by column index for faster lookup. This is another format good for incremental matrix construction.</p><figure class="highlight plaintext"><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">MatrixA:</span><br><span class="line"></span><br><span class="line">(1, 0) 5</span><br><span class="line">(1, 1) 8</span><br><span class="line">(2, 2) 3</span><br><span class="line">(1, 1) 6</span><br><span class="line"></span><br><span class="line">MatrixB:</span><br><span class="line"></span><br><span class="line">(0, 0) 10</span><br><span class="line">(0, 1) 20</span><br><span class="line">(1, 1) 30</span><br><span class="line">(1, 3) 40</span><br><span class="line">(2, 2) 50</span><br><span class="line">(2, 3) 60</span><br><span class="line">(2, 4) 70</span><br><span class="line">(3, 5) 80</span><br></pre></td></tr></table></figure><p>例子：<a href="https://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_.28CSR.2C_CRS_or_Yale_format.29" target="_blank" rel="noopener">这里</a></p><p><br><br><br></p><blockquote><p>参考:<br><a href="https://www.zhihu.com/question/26602796/answer/33431062" target="_blank" rel="noopener">https://www.zhihu.com/question/26602796/answer/33431062</a><br><a href="https://www.zhihu.com/question/24124122/answer/50403932" target="_blank" rel="noopener">https://www.zhihu.com/question/24124122/answer/50403932</a><br><a href="https://en.wikipedia.org/wiki/Sparse_matrix" target="_blank" rel="noopener">https://en.wikipedia.org/wiki/Sparse_matrix</a></p></blockquote>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/Sparse_matrix/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/Sparse_matrix/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h3 id="Sparse-matrix"><a href="#Sparse-matrix" class="headerlink" title="Sparse matrix"></a>Sparse matrix</h3><p><strong>稀疏矩阵指的是矩阵里面的元素大多都是]]>
    </summary>
    <title>Sparse matrix</title>
    <updated>2026-08-18T05:18:12.527Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="CNN" scheme="https://junyanwu.github.io/tags/CNN/"/>
    <category term="DL&amp;ML" scheme="https://junyanwu.github.io/tags/DL-ML/"/>
    <category term="离散的笔记" scheme="https://junyanwu.github.io/tags/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/"/>
    <category term="Code" scheme="https://junyanwu.github.io/tags/Code/"/>
    <category term="UNet" scheme="https://junyanwu.github.io/tags/UNet/"/>
    <content>
      <![CDATA[<h2 id="结构"><a href="#结构" class="headerlink" title="　结构"></a>　结构</h2><p><img src="/images/UNet_structure.png" alt=""></p><h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><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><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">get_unet</span>():</span><br><span class="line">    concat_axis = <span class="number">3</span></span><br><span class="line">    inputs = Input((IW, IH, <span class="number">3</span>))</span><br><span class="line">    conv1 = Conv2D(<span class="number">32</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(inputs)</span><br><span class="line">    conv1 = Convolution2D(<span class="number">32</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(conv1)</span><br><span class="line">    pool1 = MaxPooling2D(pool_size=(<span class="number">2</span>, <span class="number">2</span>))(conv1)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;conv1&#x27;</span>, conv1.shape)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;pool1&#x27;</span>, pool1.shape)</span><br><span class="line"></span><br><span class="line">    conv2 = Convolution2D(<span class="number">64</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(pool1)</span><br><span class="line">    conv2 = Convolution2D(<span class="number">64</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(conv2)</span><br><span class="line">    pool2 = MaxPooling2D(pool_size=(<span class="number">2</span>, <span class="number">2</span>))(conv2)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;conv2&#x27;</span>, conv2.shape)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;pool2&#x27;</span>, pool2.shape)</span><br><span class="line"></span><br><span class="line">    conv3 = Convolution2D(<span class="number">128</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(pool2)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;conv3&#x27;</span>, conv3.shape)</span><br><span class="line">    conv3 = Convolution2D(<span class="number">128</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(conv3)</span><br><span class="line">    pool3 = MaxPooling2D(pool_size=(<span class="number">2</span>, <span class="number">2</span>))(conv3)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;conv3&#x27;</span>, conv3.shape)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;pool3&#x27;</span>, pool3.shape)</span><br><span class="line"></span><br><span class="line">    conv4 = Convolution2D(<span class="number">256</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(pool3)</span><br><span class="line">    conv4 = Convolution2D(<span class="number">256</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(conv4)</span><br><span class="line">    pool4 = MaxPooling2D(pool_size=(<span class="number">2</span>, <span class="number">2</span>))(conv4)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;conv4&#x27;</span>, conv4.shape)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;pool4&#x27;</span>, pool4.shape)</span><br><span class="line"></span><br><span class="line">    conv5 = Convolution2D(<span class="number">512</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(pool4)</span><br><span class="line">    conv5 = Convolution2D(<span class="number">512</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(conv5)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;conv5&#x27;</span>, conv5.shape)</span><br><span class="line"></span><br><span class="line">    USampling6 = UpSampling2D(size=(<span class="number">2</span>, <span class="number">2</span>))(conv5)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;USampling6&#x27;</span>, USampling6.shape)</span><br><span class="line">    up6 = concatenate([USampling6, conv4], axis=concat_axis)</span><br><span class="line">    conv6 = Convolution2D(<span class="number">256</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(up6)</span><br><span class="line">    conv6 = Convolution2D(<span class="number">256</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(conv6)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;conv6&#x27;</span>, conv6.shape)</span><br><span class="line"></span><br><span class="line">    USampling7 = UpSampling2D(size=(<span class="number">2</span>, <span class="number">2</span>))(conv6)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;USampling7&#x27;</span>, USampling7.shape)</span><br><span class="line">    up7 = concatenate([USampling7, conv3], axis=concat_axis)</span><br><span class="line">    conv7 = Convolution2D(<span class="number">128</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(up7)</span><br><span class="line">    conv7 = Convolution2D(<span class="number">128</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(conv7)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;conv7&#x27;</span>, conv7.shape)</span><br><span class="line"></span><br><span class="line">    USampling8 = UpSampling2D(size=(<span class="number">2</span>, <span class="number">2</span>))(conv7)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;USampling8&#x27;</span>, USampling8.shape)</span><br><span class="line">    up8 = concatenate([USampling8, conv2], axis=concat_axis)</span><br><span class="line">    conv8 = Convolution2D(<span class="number">64</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(up8)</span><br><span class="line">    conv8 = Convolution2D(<span class="number">64</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(conv8)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;conv8&#x27;</span>, conv8.shape)</span><br><span class="line"></span><br><span class="line">    USampling9 = UpSampling2D(size=(<span class="number">2</span>, <span class="number">2</span>))(conv8)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;USampling9&#x27;</span>, USampling9.shape)</span><br><span class="line">    up9 = concatenate([USampling9, conv1], axis=concat_axis)</span><br><span class="line">    conv9 = Convolution2D(<span class="number">32</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(up9)</span><br><span class="line">    conv9 = Convolution2D(<span class="number">32</span>, (<span class="number">3</span>, <span class="number">3</span>), activation=<span class="string">&#x27;relu&#x27;</span>, padding=<span class="string">&#x27;same&#x27;</span>)(conv9)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;conv9&#x27;</span>, conv9.shape)</span><br><span class="line"></span><br><span class="line">    conv10 = Convolution2D(N_Cls, (<span class="number">1</span>, <span class="number">1</span>), activation=<span class="string">&#x27;sigmoid&#x27;</span>)(conv9)</span><br><span class="line"></span><br><span class="line">    model = Model(<span class="built_in">input</span>=inputs, output=conv10)</span><br><span class="line">    model.<span class="built_in">compile</span>(optimizer=Adam(), loss=<span class="string">&#x27;binary_crossentropy&#x27;</span>, metrics=[jaccard_coef, jaccard_coef_int, <span class="string">&#x27;accuracy&#x27;</span>])</span><br><span class="line">    <span class="keyword">return</span> model</span><br></pre></td></tr></table></figure><h2 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h2><ul><li>UNet的结构对输入数据的尺寸是有要求的，我也没搞清楚FCN宣称的对输入图片大小没要求，必须使其在conv、pooling后的W和H都能被2整除，否则后面USampling会出现尺寸不一致的问题。</li><li>关于label，必须是(IW, IH, 1)这种格式，不然出错。另外，如果是多类识别，需要用keras.preprocessing.tocate???事先处理，转换成类别vector，或者你的label本来就是1,2,3标记好了的也可以不用转。</li></ul>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/UNet/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/UNet/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h2 id="结构"><a href="#结构" class="headerlink" title="　结构"></a>　结构</h2><p><img src="/images/UNet_structure.png" alt=""></p>
<h2 id="代码"><a hre]]>
    </summary>
    <title>UNet结构及代码</title>
    <updated>2026-08-18T05:18:12.528Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="DL&amp;ML" scheme="https://junyanwu.github.io/tags/DL-ML/"/>
    <category term="离散的笔记" scheme="https://junyanwu.github.io/tags/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/"/>
    <content>
      <![CDATA[<h2 id="Xavier"><a href="#Xavier" class="headerlink" title="Xavier"></a>Xavier</h2><ul><li><p>此方法用于初始化参数</p></li><li><p>初始化方法：</p><p>定义参数所在层的input_shape = n，output_shape = m，那么参数将以均匀分布的方式在以下在 $[-\sqrt{\frac{6}{m+n}}, \sqrt{\frac{6}{m+n}}]$ 的范围内进行初始化</p></li></ul>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/Xarvier/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/Xarvier/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h2 id="Xavier"><a href="#Xavier" class="headerlink" title="Xavier"></a>Xavier</h2><ul>
<li><p>此方法用于初始化参数</p>
</li>
<li><p>初始化方法：</p>
<p>定义参]]>
    </summary>
    <title>Xavier初始化方法</title>
    <updated>2026-08-18T05:18:12.526Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="CNN" scheme="https://junyanwu.github.io/tags/CNN/"/>
    <category term="离散的笔记" scheme="https://junyanwu.github.io/tags/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/"/>
    <category term="Code" scheme="https://junyanwu.github.io/tags/Code/"/>
    <category term="Theano" scheme="https://junyanwu.github.io/tags/Theano/"/>
    <content>
      <![CDATA[<ul><li><a href="http://deeplearning.net/tutorial/lenet.html" target="_blank" rel="noopener">原文链接</a></li></ul><h3 id="代码解读"><a href="#代码解读" class="headerlink" title="代码解读"></a>代码解读</h3><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><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> theano</span><br><span class="line"><span class="keyword">from</span> theano <span class="keyword">import</span> tensor <span class="keyword">as</span> T</span><br><span class="line"><span class="keyword">from</span> theano.tensor.nnet <span class="keyword">import</span> conv2d</span><br><span class="line"><span class="keyword">import</span> numpy</span><br><span class="line"></span><br><span class="line">rng = numpy.random.RandomState(<span class="number">23455</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># instantiate 4D tensor for input</span></span><br><span class="line"><span class="built_in">input</span> = T.tensor4(name=<span class="string">&#x27;input&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># initialize shared variable for weights.</span></span><br><span class="line">w_shp = (<span class="number">2</span>, <span class="number">3</span>, <span class="number">9</span>, <span class="number">9</span>)</span><br><span class="line">w_bound = numpy.sqrt(<span class="number">3</span> * <span class="number">9</span> * <span class="number">9</span>)</span><br><span class="line">W = theano.shared( numpy.asarray(</span><br><span class="line">            rng.uniform(</span><br><span class="line">                low=-<span class="number">1.0</span> / w_bound,</span><br><span class="line">                high=<span class="number">1.0</span> / w_bound,</span><br><span class="line">                size=w_shp),</span><br><span class="line">            dtype=<span class="built_in">input</span>.dtype), name =<span class="string">&#x27;W&#x27;</span>)</span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">用uniform初始化</span></span><br><span class="line"><span class="string">不知为何定义shape为(2, 3, 9, 9)</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># initialize shared variable for bias (1D tensor) with random values</span></span><br><span class="line"><span class="comment"># IMPORTANT: biases are usually initialized to zero. However in this</span></span><br><span class="line"><span class="comment"># particular application, we simply apply the convolutional layer to</span></span><br><span class="line"><span class="comment"># an image without learning the parameters. We therefore initialize</span></span><br><span class="line"><span class="comment"># them to random values to &quot;simulate&quot; learning.</span></span><br><span class="line">b_shp = (<span class="number">2</span>,)</span><br><span class="line">b = theano.shared(numpy.asarray(</span><br><span class="line">            rng.uniform(low=-<span class="number">.5</span>, high=<span class="number">.5</span>, size=b_shp),</span><br><span class="line">            dtype=<span class="built_in">input</span>.dtype), name =<span class="string">&#x27;b&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># build symbolic expression that computes the convolution of input with filters in w</span></span><br><span class="line">conv_out = conv2d(<span class="built_in">input</span>, W)</span><br><span class="line"></span><br><span class="line"><span class="comment"># build symbolic expression to add bias and apply activation function, i.e. produce neural net layer output</span></span><br><span class="line">output = T.nnet.sigmoid(conv_out + b.dimshuffle(<span class="string">&#x27;x&#x27;</span>, <span class="number">0</span>, <span class="string">&#x27;x&#x27;</span>, <span class="string">&#x27;x&#x27;</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment"># create theano function to compute filtered images</span></span><br><span class="line">f = theano.function([<span class="built_in">input</span>], output)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> numpy</span><br><span class="line"><span class="keyword">import</span> pylab</span><br><span class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image</span><br><span class="line"></span><br><span class="line"><span class="comment"># open random image of dimensions 639x516</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">这里要加&#x27;rb&#x27;，不然报Unicode错，字符不能以utf-8编码，16，32都不行</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line">img = Image.<span class="built_in">open</span>(<span class="built_in">open</span>(<span class="string">&#x27;doc/images/3wolfmoon.jpg&#x27;</span>, <span class="string">&#x27;rb&#x27;</span>))</span><br><span class="line"><span class="comment"># dimensions are (height, width, channel)</span></span><br><span class="line">img = numpy.asarray(img, dtype=<span class="string">&#x27;float64&#x27;</span>) / <span class="number">256.</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># put image in 4D tensor of shape (1, 3, height, width)</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">这里img.shape = (639, 516, 3)</span></span><br><span class="line"><span class="string">img.transpose(2, 0, 1).shape = (3, 639, 516)</span></span><br><span class="line"><span class="string">img_.shape = (1, 3, 639, 516)</span></span><br><span class="line"><span class="string">reshape将数组变成</span></span><br><span class="line"><span class="string">0：1</span></span><br><span class="line"><span class="string">  0：3</span></span><br><span class="line"><span class="string">    0：639</span></span><br><span class="line"><span class="string">      0：516</span></span><br><span class="line"><span class="string">这个样子</span></span><br><span class="line"><span class="string">初步估计，首先3是图像的RGB，后面的是尺寸。为方便处理，转换成3在前面。</span></span><br><span class="line"><span class="string">然后由于input定义为4D的所以要做这个处理。对input的4D分别是：</span></span><br><span class="line"><span class="string">&gt; mini-batch size, number of input feature maps, image height, image width</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line">img_ = img.transpose(<span class="number">2</span>, <span class="number">0</span>, <span class="number">1</span>).reshape(<span class="number">1</span>, <span class="number">3</span>, <span class="number">639</span>, <span class="number">516</span>)</span><br><span class="line">filtered_img = f(img_)</span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">filtered_img.shape(1, 2, 631,508)</span></span><br><span class="line"><span class="string">不理解为何处理后变为2</span></span><br><span class="line"><span class="string">更新：是由W,b的shape决定的，当改为3，输出也是3</span></span><br><span class="line"><span class="string">改为3后如图三所示</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="comment"># plot original image and first and second components of output</span></span><br><span class="line">pylab.subplot(<span class="number">1</span>, <span class="number">3</span>, <span class="number">1</span>); pylab.axis(<span class="string">&#x27;off&#x27;</span>); pylab.imshow(img)</span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">这句的作用是将处理后的结果以灰图显示，若不加如图二</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line">pylab.gray();</span><br><span class="line"><span class="comment"># recall that the convOp output (filtered image) is actually a &quot;minibatch&quot;,</span></span><br><span class="line"><span class="comment"># of size 1 here, so we take index 0 in the first dimension:</span></span><br><span class="line">pylab.subplot(<span class="number">1</span>, <span class="number">3</span>, <span class="number">2</span>); pylab.axis(<span class="string">&#x27;off&#x27;</span>); pylab.imshow(filtered_img[<span class="number">0</span>, <span class="number">0</span>, :, :])</span><br><span class="line">pylab.subplot(<span class="number">1</span>, <span class="number">3</span>, <span class="number">3</span>); pylab.axis(<span class="string">&#x27;off&#x27;</span>); pylab.imshow(filtered_img[<span class="number">0</span>, <span class="number">1</span>, :, :])</span><br><span class="line">pylab.show()</span><br></pre></td></tr></table></figure><p><img src="http://deeplearning.net/tutorial/_images/3wolfmoon_output.png" alt="网站原图"></p><p><img src="/images/wolf_no_gray.png" alt="no_gray"></p><p><img src="/images/wolf_shape3.png" alt="shape改为3"></p>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/conv/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/conv/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<ul>
<li><a href="http://deeplearning.net/tutorial/lenet.html" target="_blank" rel="noopener">原文链接</a></li>
</ul>
<h3 id="代码解读"><a href="#代码]]>
    </summary>
    <title>CNN的theano实现</title>
    <updated>2026-08-18T05:18:12.527Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="CNN" scheme="https://junyanwu.github.io/tags/CNN/"/>
    <category term="DL&amp;ML" scheme="https://junyanwu.github.io/tags/DL-ML/"/>
    <category term="离散的笔记" scheme="https://junyanwu.github.io/tags/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/"/>
    <category term="Code" scheme="https://junyanwu.github.io/tags/Code/"/>
    <category term="LeNet" scheme="https://junyanwu.github.io/tags/LeNet/"/>
    <content>
      <![CDATA[<blockquote><p>本代码还有点小问题没解决，应该直接运行会报错，不过不影响理解，时间关系不过于纠结</p></blockquote><p>This tutorial introduces the LeNet5 neural network architecture<br>using Theano.  LeNet5 is a convolutional neural network, good for<br>classifying images. This tutorial shows how to build the architecture,<br>and comes with all the hyper-parameters you need to reproduce the<br>paper’s MNIST results.</p><p>This implementation simplifies the model in the following ways:</p><ul><li>LeNetConvPool doesn’t implement location-specific gain and bias parameters</li><li>LeNetConvPool doesn’t implement pooling by average, it implements pooling<br>by max.</li><li>Digit classification is implemented with a logistic regression rather than<br>an RBF network</li><li>LeNet5 was not fully-connected convolutions at second layer</li></ul><p>References:</p><ul><li>Y. LeCun, L. Bottou, Y. Bengio and P. Haffner:<br>Gradient-Based Learning Applied to Document<br>Recognition, Proceedings of the IEEE, 86(11):2278-2324, November 1998.<br><a href="http://yann.lecun.com/exdb/publis/pdf/lecun-98.pdf" target="_blank" rel="noopener">http://yann.lecun.com/exdb/publis/pdf/lecun-98.pdf</a></li></ul><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><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> __future__ <span class="keyword">import</span> print_function</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> timeit</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> numpy</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> theano</span><br><span class="line"><span class="keyword">import</span> theano.tensor <span class="keyword">as</span> T</span><br><span class="line"><span class="keyword">from</span> theano.tensor.signal <span class="keyword">import</span> pool</span><br><span class="line"><span class="keyword">from</span> theano.tensor.nnet <span class="keyword">import</span> conv2d</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> code.logistic_sgd <span class="keyword">import</span> LogisticRegression, load_data</span><br><span class="line"><span class="keyword">from</span> code.mlp <span class="keyword">import</span> HiddenLayer</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">LeNetConvPoolLayer</span>(<span class="title class_ inherited__">object</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, rng, <span class="built_in">input</span>, filter_shape, image_shape, poolsize=(<span class="params"><span class="number">2</span>, <span class="number">2</span></span>)</span>):</span><br><span class="line">        <span class="keyword">assert</span> image_shape[<span class="number">1</span>] == filter_shape[<span class="number">1</span>]</span><br><span class="line">        <span class="variable language_">self</span>.<span class="built_in">input</span> = <span class="built_in">input</span></span><br><span class="line"></span><br><span class="line">        fan_in = numpy.prod(filter_shape[<span class="number">1</span>:])</span><br><span class="line">        fan_out = (filter_shape[<span class="number">0</span>] * numpy.prod(filter_shape[<span class="number">2</span>:]) //</span><br><span class="line">                   numpy.prod(poolsize))</span><br><span class="line"></span><br><span class="line">        <span class="comment"># Xarvier初始化方法</span></span><br><span class="line">        W_bound = numpy.sqrt(<span class="number">6.</span> / (fan_in + fan_out))</span><br><span class="line">        <span class="comment"># 均匀分布</span></span><br><span class="line">        <span class="variable language_">self</span>.W = theano.shared(</span><br><span class="line">            numpy.asarray(</span><br><span class="line">                rng.uniform(low=-W_bound, high=W_bound, size=filter_shape),</span><br><span class="line">                dtype=theano.config.floatX</span><br><span class="line">            ),</span><br><span class="line">            borrow=<span class="literal">True</span></span><br><span class="line">        )</span><br><span class="line"></span><br><span class="line">        b_values = numpy.zeros((filter_shape[<span class="number">0</span>],), dtype=theano.config.floatX)</span><br><span class="line">        <span class="comment"># 一个filter一个b</span></span><br><span class="line">        <span class="variable language_">self</span>.b = theano.shared(value=b_values, borrow=<span class="literal">True</span>)</span><br><span class="line"></span><br><span class="line">        conv_out = conv2d(</span><br><span class="line">            <span class="built_in">input</span>=<span class="built_in">input</span>,</span><br><span class="line">            filters=<span class="variable language_">self</span>.W,</span><br><span class="line">            filter_shape=filter_shape,</span><br><span class="line">            input_shape=image_shape</span><br><span class="line">        )</span><br><span class="line"></span><br><span class="line">        pooled_out = pool.pool_2d(</span><br><span class="line">            <span class="built_in">input</span>=conv_out,</span><br><span class="line">            ds=poolsize,</span><br><span class="line">            ignore_border=<span class="literal">True</span></span><br><span class="line">        )</span><br><span class="line"></span><br><span class="line">        <span class="comment"># add the bias term. Since the bias is a vector (1D array), we first</span></span><br><span class="line">        <span class="comment"># reshape it to a tensor of shape (1, n_filters, 1, 1). Each bias will</span></span><br><span class="line">        <span class="comment"># thus be broadcasted across mini-batches and feature map</span></span><br><span class="line">        <span class="comment"># width &amp; height</span></span><br><span class="line">        <span class="variable language_">self</span>.output = T.tanh(pooled_out + <span class="variable language_">self</span>.b.dimshuffle(<span class="string">&#x27;x&#x27;</span>, <span class="number">0</span>, <span class="string">&#x27;x&#x27;</span>, <span class="string">&#x27;x&#x27;</span>))</span><br><span class="line"></span><br><span class="line">        <span class="comment"># store parameters of this layer</span></span><br><span class="line">        <span class="variable language_">self</span>.params = [<span class="variable language_">self</span>.W, <span class="variable language_">self</span>.b]</span><br><span class="line"></span><br><span class="line">        <span class="comment"># keep track of model input</span></span><br><span class="line">        <span class="variable language_">self</span>.<span class="built_in">input</span> = <span class="built_in">input</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">evaluate_lenet5</span>(<span class="params">learning_rate=<span class="number">0.1</span>, n_epochs=<span class="number">200</span>,</span></span><br><span class="line"><span class="params">                    dataset=<span class="string">&#x27;mnist.pkl.gz&#x27;</span>,</span></span><br><span class="line"><span class="params">                    nkerns=[<span class="number">20</span>, <span class="number">50</span>], batch_size=<span class="number">500</span></span>):</span><br><span class="line">    rng = numpy.random.RandomState(<span class="number">23455</span>)</span><br><span class="line">    datasets = load_data(dataset)</span><br><span class="line"></span><br><span class="line">    train_set_x, train_set_y = datasets[<span class="number">0</span>]</span><br><span class="line">    valid_set_x, valid_set_y = datasets[<span class="number">1</span>]</span><br><span class="line">    test_set_x, test_set_y = datasets[<span class="number">2</span>]</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;train:&#x27;</span>, train_set_x.shape, train_set_y.shape)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;valid:&#x27;</span>, valid_set_x.shape, valid_set_y.shape)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;test:&#x27;</span>, test_set_x.shape, test_set_y.shape)</span><br><span class="line"></span><br><span class="line">    n_train_batches = train_set_x.get_value(borrow=<span class="literal">True</span>).shape[<span class="number">0</span>]</span><br><span class="line">    n_valid_batches = valid_set_x.get_value(borrow=<span class="literal">True</span>).shape[<span class="number">0</span>]</span><br><span class="line">    n_test_batches = test_set_x.get_value(borrow=<span class="literal">True</span>).shape[<span class="number">0</span>]</span><br><span class="line">    <span class="comment"># // 除取整，返回商的整数部分</span></span><br><span class="line">    <span class="comment"># 求有几个batch</span></span><br><span class="line">    n_train_batches //= batch_size</span><br><span class="line">    n_valid_batches //= batch_size</span><br><span class="line">    n_test_batches //= batch_size</span><br><span class="line"></span><br><span class="line">    <span class="comment"># lscalar是一种TensorType，意思是long scalar，</span></span><br><span class="line">    <span class="comment"># 他们的不同之处是是dtype、ndim、brodcastable</span></span><br><span class="line">    <span class="comment"># http://deeplearning.net/software/theano/library/tensor/basic.html</span></span><br><span class="line">    index = T.lscalar()</span><br><span class="line"></span><br><span class="line">    x = T.matrix(<span class="string">&#x27;x&#x27;</span>)</span><br><span class="line">    y = T.ivector(<span class="string">&#x27;y&#x27;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;... building the model&#x27;</span>)</span><br><span class="line"></span><br><span class="line">    layer0_input = x.reshape((batch_size, <span class="number">1</span>, <span class="number">28</span>, <span class="number">28</span>))</span><br><span class="line">    layer0 = LeNetConvPoolLayer(</span><br><span class="line">        rng,</span><br><span class="line">        <span class="built_in">input</span>=layer0_input,</span><br><span class="line">        image_shape=(batch_size, <span class="number">1</span>, <span class="number">28</span>, <span class="number">28</span>),</span><br><span class="line">        filter_shape=(nkerns[<span class="number">0</span>], <span class="number">1</span>, <span class="number">5</span>, <span class="number">5</span>),</span><br><span class="line">        poolsize=(<span class="number">2</span>, <span class="number">2</span>)</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    layer1 = LeNetConvPoolLayer(</span><br><span class="line">        rng,</span><br><span class="line">        <span class="comment"># 注意这里，直接就填layer0.output，不用自己算了</span></span><br><span class="line">        <span class="built_in">input</span>=layer0.output,</span><br><span class="line">        <span class="comment"># 上一层有nkerns[0]个filter</span></span><br><span class="line">        <span class="comment"># 一个image和n个filter得到n张feature map</span></span><br><span class="line">        <span class="comment"># 就相当于一个image被处理出了n个channel</span></span><br><span class="line">        image_shape=(batch_size, nkerns[<span class="number">0</span>], <span class="number">12</span>, <span class="number">12</span>),</span><br><span class="line">        filter_shape=(nkerns[<span class="number">1</span>], nkerns[<span class="number">0</span>], <span class="number">5</span>, <span class="number">5</span>),</span><br><span class="line">        poolsize=(<span class="number">2</span>, <span class="number">2</span>)</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 被flatten成2D的</span></span><br><span class="line">    layer2_input = layer1.output.flatten(<span class="number">2</span>)</span><br><span class="line">    layer2 = HiddenLayer(</span><br><span class="line">        rng,</span><br><span class="line">        <span class="built_in">input</span>=layer2_input,</span><br><span class="line">        n_in=nkerns[<span class="number">1</span>] * <span class="number">4</span> * <span class="number">4</span>,</span><br><span class="line">        n_out=<span class="number">500</span>,</span><br><span class="line">        activation=T.tanh</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    layer3 = LogisticRegression(<span class="built_in">input</span>=layer2_input, n_in=<span class="number">500</span>, n_out=<span class="number">10</span>)</span><br><span class="line"></span><br><span class="line">    cost = layer3.negative_log_likelihood(y)</span><br><span class="line"></span><br><span class="line">    test_model = theano.function(</span><br><span class="line">        [index],</span><br><span class="line">        layer3.errors(y),</span><br><span class="line">        givens=&#123;</span><br><span class="line">            x: test_set_x[index * batch_size: (index + <span class="number">1</span>) * batch_size],</span><br><span class="line">            y: test_set_y[index * batch_size: (index + <span class="number">1</span>) * batch_size]</span><br><span class="line">        &#125;</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    validate_model = theano.function(</span><br><span class="line">        [index],</span><br><span class="line">        layer3.errors(y),</span><br><span class="line">        givens=&#123;</span><br><span class="line">            x: valid_set_x[index * batch_size: (index + <span class="number">1</span>) * batch_size],</span><br><span class="line">            y: valid_set_y[index * batch_size: (index + <span class="number">1</span>) * batch_size]</span><br><span class="line">        &#125;</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    params = layer3.params + layer2.params + layer1.params + layer0.params</span><br><span class="line">    grads = T.grad(cost, params)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 首先grads是已定义的求导运算，在运行时grads包含所有layer所有参数的导数</span></span><br><span class="line">    <span class="comment"># updates的每一个elem都是(param_i, 已使用GD更新的param_i)</span></span><br><span class="line">    updates = [</span><br><span class="line">        (param_i, param_i - learning_rate * grad_i)</span><br><span class="line">        <span class="keyword">for</span> param_i, grad_i <span class="keyword">in</span> <span class="built_in">zip</span>(params, grads)</span><br><span class="line">    ]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 它是一条数据一条数据地训练的...</span></span><br><span class="line">    train_model = theano.function(</span><br><span class="line">        [index],</span><br><span class="line">        cost,</span><br><span class="line">        updates=updates,</span><br><span class="line">        givens=&#123;</span><br><span class="line">            x: train_set_x[index * batch_size: (index + <span class="number">1</span>) * batch_size],</span><br><span class="line">            y: train_set_y[index * batch_size: (index + <span class="number">1</span>) * batch_size]</span><br><span class="line">        &#125;</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;... training&#x27;</span>)</span><br><span class="line">    patience = <span class="number">10000</span></span><br><span class="line">    patience_increase = <span class="number">2</span></span><br><span class="line">    improvement_threshold = <span class="number">0.995</span></span><br><span class="line">    validation_frequency = <span class="built_in">min</span>(n_train_batches, patience // <span class="number">2</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># inf = infinite 无穷大</span></span><br><span class="line">    best_validation_loss = numpy.inf</span><br><span class="line">    best_iter = <span class="number">0</span></span><br><span class="line">    test_score = <span class="number">0.</span></span><br><span class="line">    start_time = timeit.default_timer</span><br><span class="line"></span><br><span class="line">    epoch = <span class="number">0</span></span><br><span class="line">    done_looping = <span class="literal">False</span></span><br><span class="line">    <span class="comment"># 设置训练的终止条件</span></span><br><span class="line">    <span class="keyword">while</span> (epoch &lt; n_epochs) <span class="keyword">and</span> (<span class="keyword">not</span> done_looping):</span><br><span class="line">        epoch = epoch + <span class="number">1</span></span><br><span class="line">        <span class="comment"># 每个batch一次</span></span><br><span class="line">        <span class="keyword">for</span> minibatch_index <span class="keyword">in</span> <span class="built_in">range</span>(n_train_batches):</span><br><span class="line">            <span class="comment"># iter是目前遍历到第几组数据</span></span><br><span class="line">            <span class="built_in">iter</span> = (epoch - <span class="number">1</span>) * n_train_batches + minibatch_index</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> <span class="built_in">iter</span> % <span class="number">100</span> == <span class="number">0</span>:</span><br><span class="line">                <span class="built_in">print</span>(<span class="string">&#x27;training @ iter = &#x27;</span>, <span class="built_in">iter</span>)</span><br><span class="line">            <span class="comment"># minibatch_index是训练到目前batch中的第几个</span></span><br><span class="line">            <span class="comment"># train_model输出的是cost</span></span><br><span class="line">            cost_ij = train_model(minibatch_index)</span><br><span class="line">            <span class="comment"># 如果一个epoch完了</span></span><br><span class="line">            <span class="keyword">if</span> (<span class="built_in">iter</span> + <span class="number">1</span>) % validation_frequency == <span class="number">0</span>:</span><br><span class="line"></span><br><span class="line">                <span class="comment"># compute zero-one loss on validation set</span></span><br><span class="line">                <span class="comment"># 将每个batch的val_loss加起来求mean</span></span><br><span class="line">                validation_losses = [validate_model(i) <span class="keyword">for</span> i</span><br><span class="line">                                     <span class="keyword">in</span> <span class="built_in">range</span>(n_valid_batches)]</span><br><span class="line">                this_validation_loss = numpy.mean(validation_losses)</span><br><span class="line">                <span class="built_in">print</span>(<span class="string">&#x27;epoch %i, minibatch %i/%i, validation error %f %%&#x27;</span> %</span><br><span class="line">                      (epoch, minibatch_index + <span class="number">1</span>, n_train_batches,</span><br><span class="line">                       this_validation_loss * <span class="number">100.</span>))</span><br><span class="line"></span><br><span class="line">                <span class="comment"># if we got the best validation score until now</span></span><br><span class="line">                <span class="keyword">if</span> this_validation_loss &lt; best_validation_loss:</span><br><span class="line"></span><br><span class="line">                    <span class="comment"># improve patience if loss improvement is good enough</span></span><br><span class="line">                    <span class="keyword">if</span> this_validation_loss &lt; best_validation_loss * \</span><br><span class="line">                            improvement_threshold:</span><br><span class="line">                        <span class="comment"># 如果val_loss还有提高的话，就把patience设大一些</span></span><br><span class="line">                        patience = <span class="built_in">max</span>(patience, <span class="built_in">iter</span> * patience_increase)</span><br><span class="line"></span><br><span class="line">                    <span class="comment"># save best validation score and iteration number</span></span><br><span class="line">                    best_validation_loss = this_validation_loss</span><br><span class="line">                    best_iter = <span class="built_in">iter</span></span><br><span class="line"></span><br><span class="line">                    <span class="comment"># test it on the test set</span></span><br><span class="line">                    test_losses = [</span><br><span class="line">                        test_model(i)</span><br><span class="line">                        <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(n_test_batches)</span><br><span class="line">                    ]</span><br><span class="line">                    test_score = numpy.mean(test_losses)</span><br><span class="line">                    <span class="built_in">print</span>((<span class="string">&#x27;     epoch %i, minibatch %i/%i, test error of &#x27;</span></span><br><span class="line">                           <span class="string">&#x27;best model %f %%&#x27;</span>) %</span><br><span class="line">                          (epoch, minibatch_index + <span class="number">1</span>, n_train_batches,</span><br><span class="line">                           test_score * <span class="number">100.</span>))</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> patience &lt;= <span class="built_in">iter</span>:</span><br><span class="line">                done_looping = <span class="literal">True</span></span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line">    end_time = timeit.default_timer()</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;Optimization complete.&#x27;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;Best validation score of %f %% obtained at iteration %i, &#x27;</span></span><br><span class="line">          <span class="string">&#x27;with test performance %f %%&#x27;</span> %</span><br><span class="line">          (best_validation_loss * <span class="number">100.</span>, best_iter + <span class="number">1</span>, test_score * <span class="number">100.</span>))</span><br><span class="line">    <span class="built_in">print</span>((<span class="string">&#x27;The code for file &#x27;</span> +</span><br><span class="line">           os.path.split(__file__)[<span class="number">1</span>] +</span><br><span class="line">           <span class="string">&#x27; ran for %.2fm&#x27;</span> % ((end_time - start_time) / <span class="number">60.</span>)), file=sys.stderr)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    evaluate_lenet5()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">experiment</span>(<span class="params">state, channel</span>):</span><br><span class="line">    evaluate_lenet5(state.learning_rate, dataset=state.dataset)</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/convolutional_mlp/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/convolutional_mlp/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<blockquote>
<p>本代码还有点小问题没解决，应该直接运行会报错，不过不影响理解，时间关系不过于纠结</p>
</blockquote>
<p>This tutorial introduces the LeNet5 neural network architectur]]>
    </summary>
    <title>LeNet代码走读</title>
    <updated>2026-08-18T05:18:12.528Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="CNN" scheme="https://junyanwu.github.io/tags/CNN/"/>
    <category term="DL&amp;ML" scheme="https://junyanwu.github.io/tags/DL-ML/"/>
    <category term="离散的笔记" scheme="https://junyanwu.github.io/tags/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/"/>
    <content>
      <![CDATA[<h1 id="实质"><a href="#实质" class="headerlink" title="实质"></a>实质</h1><p>经过一番推算，其tc前后的shape的计算方式是conv求输出size的逆运算</p><p>从1式</p><script type="math/tex; mode=display">O = \frac{W+2P-K}{S} + 1</script><p>到2式</p><script type="math/tex; mode=display">W = (O - 1) * S + K - 2P</script><h3 id="注意"><a href="#注意" class="headerlink" title="　注意"></a>　注意</h3><ul><li>2式中，S和K值相同，而2*2的kernal size，K=2，这点和conv不一样。</li><li>有一个巨坑！若keras中的conv的padding=’same’，函数会填充使得输入输出尺寸相同！</li></ul><h3 id="结合UNet"><a href="#结合UNet" class="headerlink" title="结合UNet"></a>结合UNet</h3><p>UNet的结构对输入数据的尺寸是有要求的，必须使其在conv、pooling后的W和H都能被2整除，否则后面USampling会出现尺寸不一致的问题。</p>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/transposed_convolution/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/transposed_convolution/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h1 id="实质"><a href="#实质" class="headerlink" title="实质"></a>实质</h1><p>经过一番推算，其tc前后的shape的计算方式是conv求输出size的逆运算</p>
<p>从1式</p>
<script type="m]]>
    </summary>
    <title>Transpoed Convolution的一些坑</title>
    <updated>2026-08-18T05:18:12.527Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Deep Learning" scheme="https://junyanwu.github.io/categories/Deep-Learning/"/>
    <category term="CNN" scheme="https://junyanwu.github.io/tags/CNN/"/>
    <category term="离散的笔记" scheme="https://junyanwu.github.io/tags/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/"/>
    <category term="Theano" scheme="https://junyanwu.github.io/tags/Theano/"/>
    <content>
      <![CDATA[<h3 id="pooling"><a href="#pooling" class="headerlink" title="pooling"></a>pooling</h3><p>下面的代码主要是想告诉我们ignore_border=True/False的区别，看output就知道了。由于没有说明stride大小，pool_2d默认处理为跟pool_shape一样<br>```pythonfrom theano.tensor.signal import pool<p>input &#x3D; T.dtensor4(‘input’)<br>maxpool_shape &#x3D; (2, 2)<br>pool_out &#x3D; pool.pool_2d(input, maxpool_shape, ignore_border&#x3D;True)<br>f &#x3D; theano.function([input],pool_out)</p><p>invals &#x3D; numpy.random.RandomState(1).rand(3, 2, 5, 5)<br>print ‘With ignore_border set to True:’<br>print ‘invals[0, 0, :, :] &#x3D;\n’, invals[0, 0, :, :]<br>print ‘output[0, 0, :, :] &#x3D;\n’, f(invals)[0, 0, :, :]</p><p>pool_out &#x3D; pool.pool_2d(input, maxpool_shape, ignore_border&#x3D;False)<br>f &#x3D; theano.function([input],pool_out)<br>print ‘With ignore_border set to False:’<br>print ‘invals[1, 0, :, :] &#x3D;\n ‘, invals[1, 0, :, :]<br>print ‘output[1, 0, :, :] &#x3D;\n ‘, f(invals)[1, 0, :, :]</p><figure class="highlight plaintext"><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">&lt;h3 id=&quot;output&quot;&gt;&lt;a href=&quot;#output&quot; class=&quot;headerlink&quot; title=&quot;output&quot;&gt;&lt;/a&gt;output&lt;/h3&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>With ignore_border set to True:<br>    invals[0, 0, :, :] &#x3D;<br>    [[  4.17022005e-01   7.20324493e-01   1.14374817e-04   3.02332573e-01 1.46755891e-01]<br>     [  9.23385948e-02   1.86260211e-01   3.45560727e-01   3.96767474e-01 5.38816734e-01]<br>     [  4.19194514e-01   6.85219500e-01   2.04452250e-01   8.78117436e-01 2.73875932e-02]<br>     [  6.70467510e-01   4.17304802e-01   5.58689828e-01   1.40386939e-01 1.98101489e-01]<br>     [  8.00744569e-01   9.68261576e-01   3.13424178e-01   6.92322616e-01 8.76389152e-01]]<br>    output[0, 0, :, :] &#x3D;<br>    [[ 0.72032449  0.39676747]<br>     [ 0.6852195   0.87811744]]</p><p>With ignore_border set to False:<br>    invals[1, 0, :, :] &#x3D;<br>    [[ 0.01936696  0.67883553  0.21162812  0.26554666  0.49157316]<br>     [ 0.05336255  0.57411761  0.14672857  0.58930554  0.69975836]<br>     [ 0.10233443  0.41405599  0.69440016  0.41417927  0.04995346]<br>     [ 0.53589641  0.66379465  0.51488911  0.94459476  0.58655504]<br>     [ 0.90340192  0.1374747   0.13927635  0.80739129  0.39767684]]<br>    output[1, 0, :, :] &#x3D;<br>    [[ 0.67883553  0.58930554  0.69975836]<br>     [ 0.66379465  0.94459476  0.58655504]<br>     [ 0.90340192  0.80739129  0.39767684]]<br>&#96;&#96;&#96;</p>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/pooling/</id>
    <link href="https://junyanwu.github.io/2017/12/21/deeplearning/%E7%A6%BB%E6%95%A3%E7%9A%84%E7%AC%94%E8%AE%B0/pooling/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h3 id="pooling"><a href="#pooling" class="headerlink" title="pooling"></a>pooling</h3><p>下面的代码主要是想告诉我们ignore_border=True/False的区别，看output就知]]>
    </summary>
    <title>Theano_Pooling_参数ignore_border的解释</title>
    <updated>2026-08-18T05:18:12.528Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Linux" scheme="https://junyanwu.github.io/categories/Linux/"/>
    <category term="Linux" scheme="https://junyanwu.github.io/tags/Linux/"/>
    <category term="Github Page" scheme="https://junyanwu.github.io/tags/Github-Page/"/>
    <content>
      <![CDATA[<h3 id="Github-Page"><a href="#Github-Page" class="headerlink" title="Github Page"></a>Github Page</h3><p>在github上新建一个repo，命名为：username.github.io</p><p>git clone 刚刚新建的repo</p><h3 id="安装Hexo"><a href="#安装Hexo" class="headerlink" title="安装Hexo"></a>安装Hexo</h3><p><a href="https://hexo.io/zh-cn/docs/index.html" target="_blank" rel="noopener">安装教程</a></p><p>将<code>概述</code>与<code>建站</code>做好就可以了</p><p><strong>若安装出错或者链接超时</strong></p><figure class="highlight plaintext"><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">npm install -g cnpm --registry=https://registry.npm.taobao.org</span><br><span class="line">npm config set registry https://registry.npm.taobao.org</span><br><span class="line"></span><br><span class="line">所以之后的npm install命令 都改成cnpm install就可以啦</span><br></pre></td></tr></table></figure><h3 id="配置主题"><a href="#配置主题" class="headerlink" title="配置主题"></a>配置主题</h3><p>在 <a href="https://hexo.io/themes/" target="_blank" rel="noopener">https://hexo.io/themes/</a> 上找一个喜欢的主题，按它的说明添加到自己的项目里面，就可以了。</p>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/linux/Github_Page_Hexo_%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/</id>
    <link href="https://junyanwu.github.io/2017/12/21/linux/Github_Page_Hexo_%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h3 id="Github-Page"><a href="#Github-Page" class="headerlink" title="Github Page"></a>Github Page</h3><p>在github上新建一个repo，命名为：username.gith]]>
    </summary>
    <title>Hexo+Github Page搭建教程</title>
    <updated>2026-08-18T05:18:12.528Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Linux" scheme="https://junyanwu.github.io/categories/Linux/"/>
    <category term="Linux" scheme="https://junyanwu.github.io/tags/Linux/"/>
    <content>
      <![CDATA[<h2 id="SS安装方法"><a href="#SS安装方法" class="headerlink" title="SS安装方法"></a>SS安装方法</h2><p>PPA is for Ubuntu &gt;= 14.04.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> add-apt-repository ppa:hzwhuang/ss-qt5</span><br><span class="line"><span class="built_in">sudo</span> apt-get update</span><br><span class="line"><span class="built_in">sudo</span> apt-get install shadowsocks-qt5</span><br></pre></td></tr></table></figure><p>账号购买地址：<a href="https://sslinkcom.com/" target="_blank" rel="noopener">https://sslinkcom.com/</a> (可能会时不时被封)</p><p>联系方式：sslinkcom@gmail.com</p><h2 id="SwitchyOmega"><a href="#SwitchyOmega" class="headerlink" title="SwitchyOmega"></a>SwitchyOmega</h2><p>到github上搜，然后在chrome里面安装完后，按<a href="https://www.switchyomega.com/settings.html" target="_blank" rel="noopener">官方说明</a>配置。</p><p>注意：proxy一项，server设置为local的，port也是。具体的server和port在SS账号里面有</p>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/linux/SSqt5+SwitchyOmega/</id>
    <link href="https://junyanwu.github.io/2017/12/21/linux/SSqt5+SwitchyOmega/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h2 id="SS安装方法"><a href="#SS安装方法" class="headerlink" title="SS安装方法"></a>SS安装方法</h2><p>PPA is for Ubuntu &gt;= 14.04.</p>

<figure class="hig]]>
    </summary>
    <title>Linux下Shadowsocks+SwitchOmega</title>
    <updated>2026-08-18T05:18:12.529Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Linux" scheme="https://junyanwu.github.io/categories/Linux/"/>
    <category term="Linux" scheme="https://junyanwu.github.io/tags/Linux/"/>
    <content>
      <![CDATA[<h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">CPU：Intel E3-1231 v3 @ 3.40GHz</span><br><span class="line">显卡：GTX970</span><br><span class="line">内存：16G</span><br><span class="line">硬盘：SSD256G+HHD2T</span><br><span class="line"></span><br><span class="line">拟安装：Ubuntu16.04</span><br></pre></td></tr></table></figure><h2 id="出现的问题"><a href="#出现的问题" class="headerlink" title="出现的问题"></a>出现的问题</h2><ol><li>无法进入install ubuntu</li><li>进入install ubuntu开始安装时提示<blockquote><p>“The attempt to mount a file system with type vfat in SCSI2 (0,0,0), partition #1 (sda) at /boot/efi failed You may resume partitioning from the partitioning menu.”</p></blockquote></li><li>安装完重启后无法进入系统，看不到grub，直接黑屏</li></ol><h2 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h2><h3 id="1-无法进入install-ubuntu"><a href="#1-无法进入install-ubuntu" class="headerlink" title="1.无法进入install ubuntu"></a>1.无法进入install ubuntu</h3><p>进入livecd的grub界面，光标移动到install ubuntu，按e进入编辑模式，找到”quite splash” 然后改为“quite splash nomodeset”，按F10</p><h3 id="2-提示”The-attempt-to-mount-a-file-system-…-at-boot-efi-failed-…”"><a href="#2-提示”The-attempt-to-mount-a-file-system-…-at-boot-efi-failed-…”" class="headerlink" title="2.提示”The attempt to mount a file system … at /boot/efi failed …”"></a>2.提示”The attempt to mount a file system … at /boot/efi failed …”</h3><p>问题出在你的硬盘没有EFI分区，当安装程序试图创建引导项的时候就会出错。</p><p>进入PE系统用DG分区工具，选快速分区，里面可以选<strong>MBR</strong>或者<strong>GUID</strong>。选GUID，把左下角“重建EFI分区”和“MS?分区”勾上，然后再重新安装ubuntu</p><h3 id="3-安装完重启后无法进入系统，看不到grub，直接黑屏"><a href="#3-安装完重启后无法进入系统，看不到grub，直接黑屏" class="headerlink" title="3.安装完重启后无法进入系统，看不到grub，直接黑屏"></a>3.安装完重启后无法进入系统，看不到grub，直接黑屏</h3><p>两个办法</p><h4 id="办法1"><a href="#办法1" class="headerlink" title="办法1"></a>办法1</h4><p>用livecd，选“try ubuntu without installing”，按e，如上加“nomodeset”，进入ubuntu。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"># sda3为ubuntu所在分区，这个要换成你自己的</span><br><span class="line">sudo mount /dev/sda3 /mnt</span><br><span class="line">cd /mnt</span><br><span class="line">sudo vi etc/default/grub</span><br><span class="line"></span><br><span class="line">GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet splash&quot;</span><br><span class="line">## 改为</span><br><span class="line">GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet splash nomodeset&quot;</span><br></pre></td></tr></table></figure><p>本办法试了，对我木有用。不过可能对某些情况有用。</p><h4 id="办法2"><a href="#办法2" class="headerlink" title="办法2"></a>办法2</h4><p>由于我的硬盘只装了一个ubuntu，所以不显示grub会直接进入系统，但是由于ubuntu跟GTX970不兼容（我怀疑是我这个显卡品牌奇葩），所以直接黑屏。</p><p>所以目的很明确，就是要调出grub</p><p>有几种办法：</p><ul><li>再装一个win，多了个启动项就会出现grub让你选操作系统</li><li>开机后按住shift，会进入grub，然后按e进入编辑模式，将”quiet splash”改为”quiet splash nomodeset”，按F10。进入系统后装好nvidia驱动。</li></ul><h1 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h1><p>本次我先装了ubuntu再装win10的官方iso，于是ubuntu就无法引导启动了。搞了整整一个白天尝试各种我能想到的找到的办法都没办法调出grub，包括重装ubuntu的grub、重新配置EFI分区的引导文件、删除win10的引导项然后重新装grub、copy另一台一样的机子的EFI分区文件等等等。鉴于时间关系，我没有继续深究EFI的工作原理，以及win的引导与grub的原理，后来我直接再次重装了。</p><p>我推荐分区还是用MBR好些，如果你的硬盘不超过2T的话，因为easyBCD真的很好用。装win的话还是用GHO镜像吧，又快又保险。如果不想折腾，先装win再装linux，否则grub死活调不出来。</p>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/linux/Ubuntu+GTX970%E6%97%A0%E6%B3%95%E5%AE%89%E8%A3%85Ubuntu%7C%E5%AE%89%E8%A3%85%E5%AE%8C%E5%90%8E%E9%BB%91%E5%B1%8F/</id>
    <link href="https://junyanwu.github.io/2017/12/21/linux/Ubuntu+GTX970%E6%97%A0%E6%B3%95%E5%AE%89%E8%A3%85Ubuntu%7C%E5%AE%89%E8%A3%85%E5%AE%8C%E5%90%8E%E9%BB%91%E5%B1%8F/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre>]]>
    </summary>
    <title>GTX970无法安装Ubuntu16.04|安装后黑屏</title>
    <updated>2026-08-18T05:18:12.528Z</updated>
  </entry>
  <entry>
    <author>
      <name>Junyan Wu</name>
    </author>
    <category term="Linux" scheme="https://junyanwu.github.io/categories/Linux/"/>
    <category term="Linux" scheme="https://junyanwu.github.io/tags/Linux/"/>
    <content>
      <![CDATA[<h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p><a href="https://www.vmware.com/cn/products/workstation-for-linux.html" target="_blank" rel="noopener">https://www.vmware.com/cn/products/workstation-for-linux.html</a></p><p>下载完后<br>```chmod +x VMware...sudo ./VMware...```</p><p><strong>VMware Workstation Pro 14 序列号</strong>：<br>```AF70K-DNWEQ-H8DPY-0XN7X-MCAUAYF5XA-62G0P-48EDP-U4WEG-YPKZFYZ35U-4PED5-M881Z-87WEV-NY2XAFC382-DFDDL-4801Q-KNYNT-YVAR6GA18K-DRXE3-488TZ-J4ZNX-PZAXAFF590-2DX83-M81LZ-XDM7E-MKUT4```</p>]]>
    </content>
    <id>https://junyanwu.github.io/2017/12/21/linux/VMware%E7%9B%B8%E5%85%B3/</id>
    <link href="https://junyanwu.github.io/2017/12/21/linux/VMware%E7%9B%B8%E5%85%B3/"/>
    <published>2017-12-21T03:05:23.000Z</published>
    <summary>
      <![CDATA[<h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p><a href="https://www.vmware.com/cn/products/workstation-for-linux.html]]>
    </summary>
    <title>Linux下VMware安装教程</title>
    <updated>2026-08-18T05:18:12.529Z</updated>
  </entry>
</feed>
