forked from clinjie/clinjie.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
507 lines (313 loc) · 206 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>临街小站</title>
<link href="/atom.xml" rel="self"/>
<link href="http://peihao.space/"/>
<updated>2017-12-31T10:59:50.042Z</updated>
<id>http://peihao.space/</id>
<author>
<name>clinjie</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>冬</title>
<link href="http://peihao.space/2017/12/09/winter/"/>
<id>http://peihao.space/2017/12/09/winter/</id>
<published>2017-12-09T10:56:13.000Z</published>
<updated>2017-12-31T10:59:50.042Z</updated>
<content type="html"><![CDATA[<center><br><br>绯冬荥韵 芳崋灼灼<br><br></center>]]></content>
<summary type="html">
<center><br><br>绯冬荥韵 芳崋灼灼<br><br></center>
</summary>
<category term="随笔" scheme="http://peihao.space/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="随笔" scheme="http://peihao.space/tags/%E9%9A%8F%E7%AC%94/"/>
</entry>
<entry>
<title>秋</title>
<link href="http://peihao.space/2017/10/09/autumn/"/>
<id>http://peihao.space/2017/10/09/autumn/</id>
<published>2017-10-09T10:56:05.000Z</published>
<updated>2017-12-31T11:07:56.703Z</updated>
<content type="html"><![CDATA[<center><br><br>清秋氲旒,夜阑潇潇<br><br></center>]]></content>
<summary type="html">
<center><br><br>清秋氲旒,夜阑潇潇<br><br></center>
</summary>
<category term="随笔" scheme="http://peihao.space/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="随笔" scheme="http://peihao.space/tags/%E9%9A%8F%E7%AC%94/"/>
</entry>
<entry>
<title>夏</title>
<link href="http://peihao.space/2017/06/09/summer/"/>
<id>http://peihao.space/2017/06/09/summer/</id>
<published>2017-06-09T10:55:56.000Z</published>
<updated>2017-12-31T10:57:28.172Z</updated>
<content type="html"><![CDATA[<center><br><br>盛夏流苏,光影斑斑<br><br></center>]]></content>
<summary type="html">
<center><br><br>盛夏流苏,光影斑斑<br><br></center>
</summary>
<category term="随笔" scheme="http://peihao.space/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="随笔" scheme="http://peihao.space/tags/%E9%9A%8F%E7%AC%94/"/>
</entry>
<entry>
<title>word2vec</title>
<link href="http://peihao.space/2017/03/28/word2vec/"/>
<id>http://peihao.space/2017/03/28/word2vec/</id>
<published>2017-03-28T11:18:42.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<p>仅适用基于Hierarchical Softmax。</p><p>edit. 适用Negative Smapling</p><p><a href="http://download.csdn.net/detail/peihaozhu/9796105" target="_blank" rel="external">资源</a></p><p>word2vec通过训练将每个词映射成K维实数向量。通过词之间的距离,比如cosine相似度,欧式距离等来判断他们之间的语义相似度。根据词频使用哈弗慢编码,使得所有词频相似的词隐藏层的激活内容基本一致。出现频率越高的词语,他们激活的隐藏层数目越少,这样有效的降低了计算的复杂度。<br><a id="more"></a></p><blockquote><p>用one-hot来通俗简单的理解,有三个词“麦克风”、“话筒”、“杯子”,用one-hot编码,三个词对应[1, 0, 0], [0, 1, 0],[0, 0, 1]。当成千上万的词语,会造成每个词向量含有很多0,也就是稀疏编码,所以我们需要降维。比如说,上面的三个词语可以表示为[0, 1], [0.4, 0.9],[1, 0]。这里要注意的是“麦克风”和“话筒”的意思很接近,所以它们对应的向量也很接近,即空间距离短,向量夹角小。</p></blockquote><p><img src="http://peihao.space/img/article/ml/word1.png" alt=""></p><p><strong>分布式假设,其核心思想为出现于上下文情景中的词汇都有相类似的语义。</strong></p><p>word2vec中用到的两个重要模型-CBOW(Continuous Bag-of-Words Model)模型和Skip-gram(Contunuous Skip-gram)模型。</p><p>两个模型都包含三层:输入层、投影层和输出层。前者是在已知当前词$w_t$的上下文$w_{t-2},w_{t-1},w_{t+1},w_{t+2}$的前提下预测当前词$w_t$,即$P(w_t \mid w_{t-2},w_{t-1},w_{t+1},w_{t+2})$;后者恰恰相反,在已知当前词$w_t$的前提下,预测上下文$w_{t-2},w_{t-1},w_{t+1},w_{t+2}$,也就是$P(w_{t-2},w_{t-1},w_{t+1},w_{t+2} \mid w_t)$</p><p><img src="http://peihao.space/img/article/ml/word2.png" alt=""></p><h1 id="CBOW模型">CBOW模型</h1><p>CBOW模型包括三层:输入层投影层和输出层。</p><p><img src="http://peihao.space/img/article/ml/word3.png" alt=""><br>上面讲过CBOW模型网络结构是通过上下文context对当前词target做预测,求$P(w_t \mid w_{t-1},w_{t+1})$。</p><p>这里是假设Context(w)由w前后各c个词构成</p><ol><li><p>输入层:包含Context(w)中2c个词的词向量$v(Context(w)_1),v(Context(w)_2),…,v(Context(w)_{2c})$,$Context(w) \in R^m$,这里,m的含义同上表示词向量的长度。</p></li><li><p>投影层:将输出层的2c个向量做求和累加,即$x_w=\sum_{i=1}^{2c}v(Countext(w)_i) \in R^m$</p></li><li><p>输出层:输出层对应一个二叉树,以语聊中出现的词当叶子节点,以各次在语聊中出现的次数当权值构造出来哈夫曼树。在哈夫曼树中,叶子节点一共$\mid D \mid$个,分别对应词典D中词,非叶子结点N-1个</p></li></ol><p>取一个适当大小的窗口当做context window,输入层读入窗口内的词,将它们的向量(K维,初始随机)加和在一起,形成隐藏层K个节点。输出层是一个巨大的二叉树,叶节点代表语料里所有的词(语料含有V个独立的词,则二叉树有|V|个叶节点)。而这整颗二叉树构建的算法就是Huffman树。这样,对于叶节点的每一个词,就会有一个全局唯一的编码,形如”010011”,不妨记左子树为1,右子树为0。接下来,隐层的每一个节点都会跟二叉树的内节点有连边,于是对于二叉树的每一个内节点都会有K条连边,每条边上也会有权值。</p><p>对于语料库中的某个词$w_$t,对应着二叉树的某个叶子节点,因此它必然有一个二进制编码,如”010011”。在训练阶段,当给定上下文,要预测后面的词$w_t$的时候,我们就从二叉树的根节点开始遍历,这里的目标就是预测这个词的二进制编号的每一位。即对于给定的上下文,我们的目标是使得预测词的二进制编码概率最大。形象地说,我们希望在根节点,词向量和与根节点相连经过logistic计算得到bit=1的概率尽量接近0,在第二层,希望其bit=1的概率尽量接近1,这么一直下去,我们把一路上计算得到的概率相乘,即得到目标词$w_t$在当前网络下的概率$P(w_t\mid w_{t-1},w_{t+1})$。显而易见,按照目标词的二进制编码计算到最后的概率值就是归一化的.</p><p>模型的目标式子$p(w \mid Context(w))=\prod\limits_{j=2}^N p(d_j^w \mid x_w,\theta_{j-1}^w)$,用<strong>SGD</strong>训练优化模型,过程中更新相关的参数值(输入之后的加和向量值$x$,哈夫曼树中的内部节点向量$\theta$,以及原始的输入context中的所有向量参数$w$),每次取出一个样本$(context(w),w)$做训练,就要对整体的参数进行更新一次。对于$\theta$和$x$的值,通过SGD求偏导更新,而没有直接参与训练预测的原始context输入词向量$w$,我们通过$x$这个所有context词的加和向量来更新词向量$w$。把梯度贡献的更新项分配到所有输入中。</p><h1 id="Skip-gram">Skip-gram</h1><blockquote><p>Skip-Gram模型采取CBOW的逆过程的动机在于:CBOW算法对于很多分布式信息进行了平滑处理(例如将一整段上下文信息视为一个单一观察量)。很多情况下,对于小型的数据集,这一处理是有帮助的。相形之下,Skip-Gram模型将每个“上下文-目标词汇”的组合视为一个新观察量,这种做法在大型数据集中会更为有效。</p></blockquote><p>Skip-gram模型包括两层:输入层和输出层,相比CBOW,少了投影层,因为它不需要对所有的context词进行特征向量相加。</p><p><img src="http://peihao.space/img/article/ml/word4.png" alt=""></p><ol><li><p>输入层:目标词的词向量$v(w) \in R^m$</p></li><li><p>输出层:与CBOW类似,输出层十一颗哈夫曼树</p></li></ol><p>大体上来讲,Skip-Gramm与CBOW的流程相反,通过目标词对context进行预测,Skip-Gramm将其定义为$p(Context(w)\mid w)=\prod\limits_{w \in Context(w)} p(u \mid w)$,而上市中的$p(u \mid w)$可以按照上面的思想,通过哈夫曼树的路径节点乘积确定:$p(u \mid w)=\prod\limits_{j=2}^{l^u} p(d_j^u \mid v(w),\theta_{j-1}^u)$</p><p>之后就是对公式进行MLE的SGD优化。要注意的是,因为这里是要对context词进行预测,所以要从哈夫曼树的根部到叶子结点,进行$\mid context \mid$次。每次预测之后,都要处理完一个Context中的一个词之后,就要更新输入词的特征向量。</p><hr><p>下面开始介绍基于Negative Smapling的模型,翻译过来就是负采样模型,是由NCE(Noise Contrastive Estimation)的一个简化版本,目的是用来提高训练速度并改善词向量的质量。与上面介绍的基于Hierarchical Softmax的CBOW和Skip-gram相比,这种不使用复杂的哈夫曼树,而使用相对简单的随机负采样。因为在计算损失函数的时候,只是有我们挑选出来的k个noise word,而非整个的语料库V,这使得训练非常快。大幅度提高性能。</p><p>假设要求的未知的概率密度函数为X,已知的概率密度是Y,如果知道了X与Y的关系,那么X也就可以求出来。本质就是利用已知的概率密度估计未知的概率密度函数。</p><h1 id="负采样">负采样</h1><p>算法主要讲对于一个给定的词w,如何生成$NEG(w)$。</p><p>词典$D$中的词在语料$C$中出现的次数有高有低,高频词应该被选为负样本的概率应该高点,低的反之,本质上是一个带权采样,这就是大体的要求。</p><p>记$l_0=0,l_k=\sum\limits_{j=1}^k len(w_j),k=1,2,3…,N$,这里$w_j$表示词典D中的第j个词,则以${l_j}^N_{j=0}$为部分节点可得到区间$[0,1]$上的一个等距划分,$I_i=(l_{i-1},l_i],i=1,2,…,N$为N个剖分区间。</p><p>进一步的引入区间$[0,1]$上的等距离剖分,剖分节点为${m_j}_{j=0}^M$,其中$M > > N$</p><p><img src="http://peihao.space/img/article/ml/word5.png" alt=""></p><p>将内部剖分节点${m_j}^{M-1}_{j=1}$投影到非等距剖分上,则可建立${m_j}^{M-1}_{j=1}$与区间${I_j}^N_{j=1}$的映射关系。之后每次生成一个$[1,M-1]$间的堆积整数r,通过映射关系就能确定选择那个词作负样本。注意万一选中的就是w自己,则跳过。</p><h1 id="基于负采样的CBOW">基于负采样的CBOW</h1><p>在CBOW模型中,一直词w的上下文Context(w),需要预测w,因此对于给定的Countext(w),词w就是一个正样本,其他词就是负样本(分类问题)。</p><p>假定现在选好了关于Countext(w)的负采样集$NEG(w) \neq \emptyset$,并且<br>$$L^w(\hat{w})=<br>\begin{cases}<br>1,\hat{w}=w;\0,\hat{w}=w<br>\end{cases}<br>$$</p><p>表示词$\hat{w}$的标签,即正样本的标签为1,负样本的标签为0.</p><p>对于一个给定的正样本(Context(w),w),<strong>我们希望最大化</strong>$$g(w)=\prod_{u \in {w} \bigcup NEG(w)} p(u \mid Context(w))$$</p><p>其中<br>$$p(u\mid Context(w))=<br>\begin{cases}<br>\sigma(x^T_w\theta^u),\ \ L^w(u)=1;\ \ 1-\sigma(x^T_w\theta^u), \ \ L^w(u)=0<br>\end{cases}<br>$$</p><p>这里$x_w$表示Context(w)中各词的词向量之和,而$\theta^u \in R^m$表示词u对应的一个辅助向量,其实就是word-embeding中的嵌入值。</p><p>$\sigma(x_w^T \theta^w)$表示当上下文为Context(w)时,预测中心词为w的概率,而$\sigma(x^T_w\theta^u)\, u \in NEG(w)$则表示上下文为Context(w)时,预测中心词为u的概率。式子$g(w)$表示,所有在NEG集合加上实际的中心词w概率相乘,最大化这个式子,每一项,如果是实际的中心词w,最大化$p$,如果属于NEG集合,最大化$(1-p)$。增大正样本的概率同时降低负样本的概率。</p><p>之后的内容就是使用SGD对求解最大化这个公式进行训练,参数的更新,包括$\theta$对应词的嵌入,$x$对应Context(w)中各词的词向量之和,以及通过$x$更新最初的输入词$w$的向量,对于整个数据集,当梯度下降的过程中不断地更新参数,对应产生的效果就是不断地移动每个单词的嵌套向量,直到可以把真实单词和噪声单词很好得区分开。</p><h1 id="基于负采样的Skip-gram">基于负采样的Skip-gram</h1><p>对于一个给定的样本$(w,Context(w))$,我们希望最大化$$g(w)=\prod\limits_{\hat{w} \in Context(w)}\prod\limits_{u \in {w} \bigcup NEG^{\hat{w}}(w)} p(u\mid \hat{w})$$</p><p>其中$$p(u\mid \hat{w})=\begin{cases}\sigma(v(\hat{w})^T\theta^u, \ \ L^w(u)=1; \ \1-\sigma(v(\hat{w})^T\theta^u, \ \ L^w(u)=0 \end{cases}$$</p><p>这里$NEG^{\hat{w}}(w)$表示处理词$\hat{w}$时候生成的负样本子集,于是对于一个给定的语料库C,函数$$G=\prod\limits_{w\in C}g(w)$$<br>作为整体优化的目标,然后为了变成和项,我们取对数等等。</p><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><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></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 class="keyword">import</span> tensorflow.python.platform</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> collections</span><br><span class="line"><span class="keyword">import</span> math</span><br><span class="line"><span class="keyword">from</span> six.moves <span class="keyword">import</span> xrange</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> random</span><br><span class="line"><span class="keyword">import</span> tensorflow <span class="keyword">as</span> tf</span><br><span class="line"><span class="keyword">import</span> urllib.request</span><br><span class="line"><span class="keyword">import</span> zipfile</span><br><span class="line"></span><br><span class="line"><span class="comment"># Step 1: Download the data.</span></span><br><span class="line">url = <span class="string">'http://mattmahoney.net/dc/'</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">maybe_download</span><span class="params">(filename, expected_bytes)</span>:</span></span><br><span class="line"> <span class="string">"""Download a file if not present, and make sure it's the right size."""</span></span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> os.path.exists(filename):</span><br><span class="line"> filename, _ = urllib.request.urlretrieve(url + filename, filename)</span><br><span class="line"> <span class="comment"># 文件信息获取</span></span><br><span class="line"> statinfo = os.stat(filename)</span><br><span class="line"> <span class="keyword">if</span> statinfo.st_size == expected_bytes:</span><br><span class="line"> print(<span class="string">'Found and verified'</span>, filename)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> print(statinfo.st_size)</span><br><span class="line"> <span class="keyword">raise</span> Exception(</span><br><span class="line"> <span class="string">'Failed to verify '</span> + filename + <span class="string">'. Can you get to it with a browser?'</span>)</span><br><span class="line"> <span class="keyword">return</span> filename</span><br><span class="line"></span><br><span class="line">filename = maybe_download(<span class="string">'text8.zip'</span>, <span class="number">31344016</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># Read the data into a string.</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">read_data</span><span class="params">(filename)</span>:</span></span><br><span class="line"> f = zipfile.ZipFile(filename)</span><br><span class="line"> <span class="comment"># 获取压缩文件中的文件列表,返回第一个文件内容,根据空格进行分割成列表。</span></span><br><span class="line"> <span class="keyword">for</span> name <span class="keyword">in</span> f.namelist():</span><br><span class="line"> <span class="keyword">return</span> f.read(name).split()</span><br><span class="line"> f.close()</span><br><span class="line"></span><br><span class="line">words = read_data(filename)</span><br><span class="line">print(<span class="string">'Data size'</span>, len(words))</span><br><span class="line"></span><br><span class="line"><span class="comment"># Step 2: Build the dictionary and replace rare words with UNK token.#将稀少的词使用UNK替换</span></span><br><span class="line">vocabulary_size = <span class="number">50000</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">build_dataset</span><span class="params">(words)</span>:</span></span><br><span class="line"> count = [[<span class="string">'UNK'</span>, -<span class="number">1</span>]]<span class="comment"># 词'UNK'代表UnKnow</span></span><br><span class="line"> <span class="comment"># 将count扩展,使用collections模块的计数器,根据出现次数的多少进行排序然后填充进count,排序之后UNK为第一位。s.most_common(n)方法返回对象s的Top n数据,没有指定的话,返回全部</span></span><br><span class="line"> count.extend(collections.Counter(words).most_common(vocabulary_size - <span class="number">1</span>))</span><br><span class="line"> dictionary = dict()</span><br><span class="line"> <span class="keyword">for</span> word, _ <span class="keyword">in</span> count:<span class="comment">#count中按item有两个内容:str以及对应的times频率。定义一个字典对象,键为str,对应的值为上面count中按str频率高低的排名例如 the:1,of:2。。。</span></span><br><span class="line"> dictionary[word] = len(dictionary)</span><br><span class="line"> data = list()</span><br><span class="line"> unk_count = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> word <span class="keyword">in</span> words:</span><br><span class="line"> <span class="keyword">if</span> word <span class="keyword">in</span> dictionary:</span><br><span class="line"> index = dictionary[word]</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> index = <span class="number">0</span> <span class="comment"># dictionary['UNK'] 注意之前在dictionary中根据排序,UNK还是在第一位,对应的值为0</span></span><br><span class="line"> unk_count = unk_count + <span class="number">1</span></span><br><span class="line"> <span class="comment"># index代表了词对应的排名,出现一次,填充进data中一次。data中包含的是原来文件中词对应的排名列表</span></span><br><span class="line"> data.append(index)</span><br><span class="line"> count[<span class="number">0</span>][<span class="number">1</span>] = unk_count <span class="comment"># count是一个二维的元祖,一个元素是'UNK':times,count[0][1]代表的就是UNK对应的频率</span></span><br><span class="line"> reverse_dictionary = dict(zip(dictionary.values(), dictionary.keys()))<span class="comment">#键值对reverse</span></span><br><span class="line"> <span class="keyword">return</span> data, count, dictionary, reverse_dictionary</span><br><span class="line"></span><br><span class="line">data, count, dictionary, reverse_dictionary = build_dataset(words)</span><br><span class="line"><span class="keyword">del</span> words <span class="comment"># Hint to reduce memory.</span></span><br><span class="line">print(<span class="string">'Most common words (+UNK)'</span>, count[:<span class="number">5</span>])<span class="comment"># 输出频率最高的5个词</span></span><br><span class="line">print(<span class="string">'Sample data'</span>, data[:<span class="number">10</span>])</span><br><span class="line"></span><br><span class="line">data_index = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># Step 4: Function to generate a training batch for the skip-gram model.</span></span><br><span class="line"><span class="comment"># num_skips 训练样本的源端要使用几次,出于n-skip算法的原因,一个中心词要对应多个周边词,也就是说一个中心词target要预测几次周边词,对应的词的数量</span></span><br><span class="line"><span class="comment"># skip_window 左右各考虑多少个词,skip_windows*2=num_skips</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">generate_batch</span><span class="params">(batch_size, num_skips, skip_window)</span>:</span></span><br><span class="line"> <span class="keyword">global</span> data_index</span><br><span class="line"> <span class="keyword">assert</span> batch_size % num_skips == <span class="number">0</span></span><br><span class="line"> <span class="keyword">assert</span> num_skips <= <span class="number">2</span> * skip_window</span><br><span class="line"> <span class="comment"># ndarray本质是数组,其不同于一般的数组,或者Python 的list的地方在于它可以有N 维(dimentions),也可简单理解为数组里面嵌套数组。</span></span><br><span class="line"> batch = np.ndarray(shape=(batch_size), dtype=np.int32)</span><br><span class="line"> labels = np.ndarray(shape=(batch_size, <span class="number">1</span>), dtype=np.int32)</span><br><span class="line"> span = <span class="number">2</span> * skip_window + <span class="number">1</span> <span class="comment"># [ skip_window target skip_window ]</span></span><br><span class="line"> buffer = collections.deque(maxlen=span)</span><br><span class="line"> <span class="keyword">for</span> _ <span class="keyword">in</span> range(span):</span><br><span class="line"> <span class="comment"># 最初的填充,填充进原来文本中word的频率</span></span><br><span class="line"> buffer.append(data[data_index])</span><br><span class="line"> <span class="comment"># 因为data_index是全局变量,训练要很多步,后面取余</span></span><br><span class="line"> data_index = (data_index + <span class="number">1</span>) % len(data)</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range((int)(batch_size / num_skips)):<span class="comment">#batch中样batch_size个样本,衣蛾target有num_skips个样本</span></span><br><span class="line"> target = skip_window <span class="comment"># target label at the center of the buffer</span></span><br><span class="line"> targets_to_avoid = [ skip_window ]</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> range(num_skips):</span><br><span class="line"> <span class="keyword">while</span> target <span class="keyword">in</span> targets_to_avoid:</span><br><span class="line"> <span class="comment"># 进行了num_skips轮,每次找到一个不在target_to_avoid中的元素,实际上就是每次找一个与target配对的word</span></span><br><span class="line"> target = random.randint(<span class="number">0</span>, span - <span class="number">1</span>)</span><br><span class="line"> targets_to_avoid.append(target)</span><br><span class="line"> batch[i * num_skips + j] = buffer[skip_window] <span class="comment">#batch中是连续的num_skips个target词</span></span><br><span class="line"> labels[i * num_skips + j, <span class="number">0</span>] = buffer[target]<span class="comment">#label中连续的num_skip个周边词</span></span><br><span class="line"> buffer.append(data[data_index])<span class="comment">#buffer是有容量限制的,之前的状态是满的,此时会将最早的元素挤出去</span></span><br><span class="line"> data_index = (data_index + <span class="number">1</span>) % len(data)</span><br><span class="line"> <span class="keyword">return</span> batch, labels</span><br><span class="line"></span><br><span class="line">batch, labels = generate_batch(batch_size=<span class="number">8</span>, num_skips=<span class="number">2</span>, skip_window=<span class="number">1</span>)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">8</span>):</span><br><span class="line"> print(batch[i], <span class="string">'->'</span>, labels[i, <span class="number">0</span>])</span><br><span class="line"> print(reverse_dictionary[batch[i]], <span class="string">'->'</span>, reverse_dictionary[labels[i, <span class="number">0</span>]])</span><br><span class="line"></span><br><span class="line"><span class="comment"># Step 5: Build and train a skip-gram model.</span></span><br><span class="line"></span><br><span class="line">batch_size = <span class="number">128</span></span><br><span class="line">embedding_size = <span class="number">128</span> <span class="comment"># 嵌入矩阵的密度,或者说是矩阵长度,batch_size要和embedding_size一致</span></span><br><span class="line">skip_window = <span class="number">1</span> <span class="comment"># How many words to consider left and right.</span></span><br><span class="line">num_skips = <span class="number">2</span> <span class="comment"># How many times to re-use an input to generate a label.</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 构造NEG集合相关参数,集合中的元素就作为分类结果的干扰</span></span><br><span class="line">valid_size = <span class="number">16</span> <span class="comment"># Random set of words to evaluate similarity on.#随机的word集合估计相似度</span></span><br><span class="line">valid_window = <span class="number">100</span> <span class="comment"># 选择在头部分布的开发样本</span></span><br><span class="line">valid_examples = np.array(random.sample(xrange(valid_window), valid_size))<span class="comment"># 从[0,valid_window]中随机的获取valid_size个数值返回</span></span><br><span class="line">num_sampled = <span class="number">64</span> <span class="comment"># 负采样的个数</span></span><br><span class="line"></span><br><span class="line">graph = tf.Graph()</span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> graph.as_default():</span><br><span class="line"></span><br><span class="line"> <span class="comment"># Input data.</span></span><br><span class="line"> train_inputs = tf.placeholder(tf.int32, shape=[batch_size])</span><br><span class="line"> train_labels = tf.placeholder(tf.int32, shape=[batch_size, <span class="number">1</span>])</span><br><span class="line"> valid_dataset = tf.constant(valid_examples, dtype=tf.int32)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># Construct the variables.</span></span><br><span class="line"> embeddings = tf.Variable(<span class="comment">#使用唯一的随机值来初始化大矩阵,shape=[vocabulary_size, embedding_size]</span></span><br><span class="line"> tf.random_uniform([vocabulary_size, embedding_size], -<span class="number">1.0</span>, <span class="number">1.0</span>))</span><br><span class="line"> nce_weights = tf.Variable(<span class="comment">#每个word定义一个权重值与偏差</span></span><br><span class="line"> <span class="comment"># tf.truncated_normal初始函数将根据所得到的均值和标准差,生成一个随机分布。shape=[vocabulary_size, embedding_size]</span></span><br><span class="line"> tf.truncated_normal([vocabulary_size, embedding_size],</span><br><span class="line"> stddev=<span class="number">1.0</span> / math.sqrt(embedding_size)))</span><br><span class="line"> nce_biases = tf.Variable(tf.zeros([vocabulary_size]))</span><br><span class="line"></span><br><span class="line"> <span class="comment"># Look up embeddings for inputs. 根据train_inputs中的id,寻找embeddings中的对应元素。比如,train_inputs=[1,3,5],则找出embeddings中下标为1,3,5的向量组成一个矩阵返回。</span></span><br><span class="line"> embed = tf.nn.embedding_lookup(embeddings, train_inputs)<span class="comment">#这里是从train_inputs给的索引值找到embeddings大矩阵中的对应的嵌入值</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># Compute the average NCE loss for the batch.</span></span><br><span class="line"> <span class="comment"># tf.nce_loss automatically draws a new sample of the negative labels each</span></span><br><span class="line"> <span class="comment"># time we evaluate the loss.</span></span><br><span class="line"> loss = tf.reduce_mean(<span class="comment"># reduce_mean是平均值 vocabulary_size代表可能的数目 num_sampled代表per batch随机抽样的个数</span></span><br><span class="line"> tf.nn.nce_loss(nce_weights, nce_biases, train_labels,embed,<span class="comment">#这里的参数都是按batch计算的,而非具体的某个样本.同时要注意的是原文件中参数排序出错,这里修正</span></span><br><span class="line"> num_sampled, vocabulary_size))</span><br><span class="line"></span><br><span class="line"> optimizer = tf.train.GradientDescentOptimizer(<span class="number">1.0</span>).minimize(loss)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 计算在minibatch和所有的embedding的cosine相似度</span></span><br><span class="line"> norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), <span class="number">1</span>, keep_dims=<span class="keyword">True</span>))<span class="comment">#tf.reduce_sum就是求和</span></span><br><span class="line"> normalized_embeddings = embeddings / norm<span class="comment"># 正则化嵌入值</span></span><br><span class="line"> valid_embeddings = tf.nn.embedding_lookup( <span class="comment">#NEG集嵌入值</span></span><br><span class="line"> normalized_embeddings, valid_dataset)<span class="comment">#寻找NEG集合中对应的正则化后的嵌入值</span></span><br><span class="line"> similarity = tf.matmul(<span class="comment">#NEG集合正则化后的嵌入值与词典集合正则化后的嵌入值的矩阵乘</span></span><br><span class="line"> valid_embeddings, normalized_embeddings, transpose_b=<span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Step 6: Begin training</span></span><br><span class="line">num_steps = <span class="number">100001</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> tf.Session(graph=graph) <span class="keyword">as</span> session:</span><br><span class="line"> <span class="comment"># We must initialize all variables before we use them.</span></span><br><span class="line"> tf.initialize_all_variables().run()</span><br><span class="line"> print(<span class="string">"Initialized"</span>)</span><br><span class="line"></span><br><span class="line"> average_loss = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> step <span class="keyword">in</span> xrange(num_steps):</span><br><span class="line"> batch_inputs, batch_labels = generate_batch(</span><br><span class="line"> batch_size, num_skips, skip_window)</span><br><span class="line"> feed_dict = {train_inputs : batch_inputs, train_labels : batch_labels}</span><br><span class="line"></span><br><span class="line"> <span class="comment"># We perform one update step by evaluating the optimizer op (including it</span></span><br><span class="line"> <span class="comment"># in the list of returned values for session.run()</span></span><br><span class="line"> _, loss_val = session.run([optimizer, loss], feed_dict=feed_dict)</span><br><span class="line"> average_loss += loss_val</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> step % <span class="number">2000</span> == <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">if</span> step > <span class="number">0</span>:</span><br><span class="line"> average_loss = average_loss / <span class="number">2000</span></span><br><span class="line"> <span class="comment"># The average loss is an estimate of the loss over the last 2000 batches.</span></span><br><span class="line"> print(<span class="string">"Average loss at step "</span>, step, <span class="string">": "</span>, average_loss)</span><br><span class="line"> average_loss = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 这里是构建nosie词作</span></span><br><span class="line"> <span class="comment"># 注意这里的代价是很大的,没500步差不多就会减慢20%的计算</span></span><br><span class="line"> <span class="keyword">if</span> step % <span class="number">10000</span> == <span class="number">0</span>:</span><br><span class="line"> sim = similarity.eval()</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> xrange(valid_size):</span><br><span class="line"> valid_word = reverse_dictionary[valid_examples[i]]</span><br><span class="line"> top_k = <span class="number">8</span> <span class="comment"># number of nearest neighbors#</span></span><br><span class="line"> nearest = (-sim[i, :]).argsort()[<span class="number">1</span>:top_k+<span class="number">1</span>]<span class="comment"># 返回的是按相似度排序后元素值的索引值</span></span><br><span class="line"> log_str = <span class="string">"Nearest to %s:"</span> % valid_word</span><br><span class="line"> <span class="keyword">for</span> k <span class="keyword">in</span> xrange(top_k):</span><br><span class="line"> close_word = reverse_dictionary[nearest[k]]</span><br><span class="line"> log_str = <span class="string">"%s %s,"</span> % (log_str, close_word)</span><br><span class="line"> print(log_str)</span><br><span class="line"> final_embeddings = normalized_embeddings.eval()</span><br><span class="line"></span><br><span class="line"><span class="comment"># Step 7: Visualize the embeddings.</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">plot_with_labels</span><span class="params">(low_dim_embs, labels, filename=<span class="string">'tsne.png'</span>)</span>:</span></span><br><span class="line"> <span class="keyword">assert</span> low_dim_embs.shape[<span class="number">0</span>] >= len(labels), <span class="string">"More labels than embeddings"</span></span><br><span class="line"> plt.figure(figsize=(<span class="number">18</span>, <span class="number">18</span>)) <span class="comment">#in inches</span></span><br><span class="line"> <span class="keyword">for</span> i, label <span class="keyword">in</span> enumerate(labels):</span><br><span class="line"> x, y = low_dim_embs[i,:]</span><br><span class="line"> plt.scatter(x, y)</span><br><span class="line"> plt.annotate(label,</span><br><span class="line"> xy=(x, y),</span><br><span class="line"> xytext=(<span class="number">5</span>, <span class="number">2</span>),</span><br><span class="line"> textcoords=<span class="string">'offset points'</span>,</span><br><span class="line"> ha=<span class="string">'right'</span>,</span><br><span class="line"> va=<span class="string">'bottom'</span>)</span><br><span class="line"></span><br><span class="line"> plt.savefig(filename)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> <span class="keyword">from</span> sklearn.manifold <span class="keyword">import</span> TSNE</span><br><span class="line"> <span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br><span class="line"></span><br><span class="line"> tsne = TSNE(perplexity=<span class="number">30</span>, n_components=<span class="number">2</span>, init=<span class="string">'pca'</span>, n_iter=<span class="number">5000</span>)</span><br><span class="line"> plot_only = <span class="number">500</span></span><br><span class="line"> low_dim_embs = tsne.fit_transform(final_embeddings[:plot_only,:])</span><br><span class="line"> labels = list(dictionary.keys())[:plot_only]</span><br><span class="line"> plot_with_labels(low_dim_embs, labels)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">except</span> ImportError:</span><br><span class="line"> print(<span class="string">"Please install sklearn and matplotlib to visualize embeddings."</span>)<span class="string">'''</span></span><br></pre></td></tr></table></figure><p>运行结果如下:</p><p><img src="http://peihao.space/img/article/ml/tsne.png" alt=""></p>]]></content>
<summary type="html">
<p>仅适用基于Hierarchical Softmax。</p>
<p>edit. 适用Negative Smapling</p>
<p><a href="http://download.csdn.net/detail/peihaozhu/9796105">资源</a></p>
<p>word2vec通过训练将每个词映射成K维实数向量。通过词之间的距离,比如cosine相似度,欧式距离等来判断他们之间的语义相似度。根据词频使用哈弗慢编码,使得所有词频相似的词隐藏层的激活内容基本一致。出现频率越高的词语,他们激活的隐藏层数目越少,这样有效的降低了计算的复杂度。<br>
</summary>
<category term="ML" scheme="http://peihao.space/categories/ML/"/>
<category term="ML" scheme="http://peihao.space/tags/ML/"/>
</entry>
<entry>
<title>TensorFlow简单使用Cifar数据集</title>
<link href="http://peihao.space/2017/03/26/tf-cifar/"/>
<id>http://peihao.space/2017/03/26/tf-cifar/</id>
<published>2017-03-26T14:18:42.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<p>这篇文章是对TensorFlow官方例子:CIFAR-10数据集分类的理解记录。</p><p>对CIFAR-10 数据集的分类是机器学习中一个公开的基准测试问题,其任务是对一组大小为32x32的RGB图像进行分类,这些图像涵盖了10个类别:</p><p>飞机, 汽车, 鸟, 猫, 鹿, 狗, 青蛙, 马, 船以及卡车。</p><p><a href="http://www.cs.toronto.edu/~kriz/cifar.html" target="_blank" rel="external">数据集主页</a></p><p><a href="https://github.com/tensorflow/models/tree/master/tutorials/image/cifar10" target="_blank" rel="external">Python项目代码页面</a></p><p>这里主要介绍<code>cifar10_input.py</code>、<code>caifar10.py</code>、<code>caifar_train.py</code>和<code>cifar10_eval.py</code><br><a id="more"></a></p><h1 id="模型输入">模型输入</h1><p><code>cifar10_input.py</code>文件,从二进制文件<code>cifar-10-binary.tar.gz</code>中提取数据</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">distorted_inputs</span><span class="params">(data_dir, batch_size)</span>:</span></span><br><span class="line"></span><br><span class="line"> filenames = [os.path.join(data_dir, <span class="string">'data_batch_%d.bin'</span> % i)</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> xrange(<span class="number">1</span>, <span class="number">6</span>)]</span><br><span class="line"> <span class="keyword">for</span> f <span class="keyword">in</span> filenames:</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> tf.gfile.Exists(f):</span><br><span class="line"> <span class="keyword">raise</span> ValueError(<span class="string">'Failed to find file: '</span> + f)</span><br><span class="line"></span><br><span class="line"> filename_queue = tf.train.string_input_producer(filenames)</span><br><span class="line"></span><br><span class="line"> read_input = read_cifar10(filename_queue)</span><br><span class="line"> reshaped_image = tf.cast(read_input.uint8image, tf.float32)</span><br><span class="line"></span><br><span class="line"> height = IMAGE_SIZE</span><br><span class="line"> width = IMAGE_SIZE</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> distorted_image = tf.random_crop(reshaped_image, [height, width, <span class="number">3</span>])</span><br><span class="line"> distorted_image = tf.image.random_flip_left_right(distorted_image)</span><br><span class="line"> distorted_image = tf.image.random_brightness(distorted_image,</span><br><span class="line"> max_delta=<span class="number">63</span>)</span><br><span class="line"> distorted_image = tf.image.random_contrast(distorted_image,</span><br><span class="line"> lower=<span class="number">0.2</span>, upper=<span class="number">1.8</span>)</span><br><span class="line"> float_image = tf.image.per_image_standardization(distorted_image)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> float_image.set_shape([height, width, <span class="number">3</span>])</span><br><span class="line"> read_input.label.set_shape([<span class="number">1</span>])</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> min_fraction_of_examples_in_queue = <span class="number">0.4</span></span><br><span class="line"> min_queue_examples = int(NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN *</span><br><span class="line"> min_fraction_of_examples_in_queue)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> _generate_image_and_label_batch(float_image,read_input.label,min_queue_examples, batch_size,shuffle=<span class="keyword">True</span>)</span><br></pre></td></tr></table></figure><p>主要函数有两个,<code>inputs</code>和<code>distorted_inputs</code>,这里贴出来的是<code>distorted_inputs</code>。两个方法都是从训练/测试 数据集文件中读取数据,后者针对测试集,裁剪图像、提取变换成相应的格式,前者针对训练集,在变化成需要格式前,还要进行图像的处理,如翻转,亮度变换、随机替换等等来增加数据集。返回的是构建生成的数据样本和标签。</p><h1 id="模型构建">模型构建</h1><p>使用CNN模型,包括两级卷基层、两级全连接层和最后的softmax激励函数输出。</p><h2 id="模型">模型</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="function"><span class="keyword">def</span> <span class="title">inference</span><span class="params">(images)</span>:</span></span><br><span class="line"> <span class="comment"># 卷基层1</span></span><br><span class="line"> <span class="keyword">with</span> tf.variable_scope(<span class="string">'conv1'</span>) <span class="keyword">as</span> scope:</span><br><span class="line"> <span class="comment"># 过滤器</span></span><br><span class="line"> kernel = _variable_with_weight_decay(<span class="string">'weights'</span>,</span><br><span class="line"> shape=[<span class="number">5</span>, <span class="number">5</span>, <span class="number">3</span>, <span class="number">64</span>],</span><br><span class="line"> stddev=<span class="number">5e-2</span>,</span><br><span class="line"> wd=<span class="number">0.0</span>)</span><br><span class="line"> conv = tf.nn.conv2d(images, kernel, [<span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>], padding=<span class="string">'SAME'</span>)</span><br><span class="line"> <span class="comment"># 偏置</span></span><br><span class="line"> biases = _variable_on_cpu(<span class="string">'biases'</span>, [<span class="number">64</span>], tf.constant_initializer(<span class="number">0.0</span>))</span><br><span class="line"> pre_activation = tf.nn.bias_add(conv, biases)</span><br><span class="line"> <span class="comment"># Relu非线性处理</span></span><br><span class="line"> conv1 = tf.nn.relu(pre_activation, name=scope.name)</span><br><span class="line"> _activation_summary(conv1)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 池化降维</span></span><br><span class="line"> pool1 = tf.nn.max_pool(conv1, ksize=[<span class="number">1</span>, <span class="number">3</span>, <span class="number">3</span>, <span class="number">1</span>], strides=[<span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">1</span>],</span><br><span class="line"> padding=<span class="string">'SAME'</span>, name=<span class="string">'pool1'</span>)</span><br><span class="line"> <span class="comment"># 归一化处理</span></span><br><span class="line"> norm1 = tf.nn.lrn(pool1, <span class="number">4</span>, bias=<span class="number">1.0</span>, alpha=<span class="number">0.001</span> / <span class="number">9.0</span>, beta=<span class="number">0.75</span>,name=<span class="string">'norm1'</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 卷积层2</span></span><br><span class="line"> <span class="keyword">with</span> tf.variable_scope(<span class="string">'conv2'</span>) <span class="keyword">as</span> scope:</span><br><span class="line"> kernel = _variable_with_weight_decay(<span class="string">'weights'</span>,</span><br><span class="line"> shape=[<span class="number">5</span>, <span class="number">5</span>, <span class="number">64</span>, <span class="number">64</span>],</span><br><span class="line"> stddev=<span class="number">5e-2</span>,</span><br><span class="line"> wd=<span class="number">0.0</span>)</span><br><span class="line"> conv = tf.nn.conv2d(norm1, kernel, [<span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>], padding=<span class="string">'SAME'</span>)</span><br><span class="line"> biases = _variable_on_cpu(<span class="string">'biases'</span>, [<span class="number">64</span>], tf.constant_initializer(<span class="number">0.1</span>))</span><br><span class="line"> pre_activation = tf.nn.bias_add(conv, biases)</span><br><span class="line"> conv2 = tf.nn.relu(pre_activation, name=scope.name)</span><br><span class="line"> _activation_summary(conv2)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 归一化</span></span><br><span class="line"> norm2 = tf.nn.lrn(conv2, <span class="number">4</span>, bias=<span class="number">1.0</span>, alpha=<span class="number">0.001</span> / <span class="number">9.0</span>, beta=<span class="number">0.75</span>, name=<span class="string">'norm2'</span>)</span><br><span class="line"> <span class="comment"># 池化</span></span><br><span class="line"> pool2 = tf.nn.max_pool(norm2, ksize=[<span class="number">1</span>, <span class="number">3</span>, <span class="number">3</span>, <span class="number">1</span>],strides=[<span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">1</span>], padding=<span class="string">'SAME'</span>, name=<span class="string">'pool2'</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 全连接层</span></span><br><span class="line"> <span class="keyword">with</span> tf.variable_scope(<span class="string">'local3'</span>) <span class="keyword">as</span> scope:</span><br><span class="line"> <span class="comment"># 尺寸对应全连接层变换处理</span></span><br><span class="line"> reshape = tf.reshape(pool2, [FLAGS.batch_size, -<span class="number">1</span>])</span><br><span class="line"> dim = reshape.get_shape()[<span class="number">1</span>].value</span><br><span class="line"> weights = _variable_with_weight_decay(<span class="string">'weights'</span>, shape=[dim, <span class="number">384</span>],</span><br><span class="line"> stddev=<span class="number">0.04</span>, wd=<span class="number">0.004</span>)</span><br><span class="line"> biases = _variable_on_cpu(<span class="string">'biases'</span>, [<span class="number">384</span>], tf.constant_initializer(<span class="number">0.1</span>))</span><br><span class="line"> <span class="comment"># 不再使用卷积乘tf.nn.conv2d,直接矩阵乘</span></span><br><span class="line"> local3 = tf.nn.relu(tf.matmul(reshape, weights) + biases, name=scope.name)</span><br><span class="line"> _activation_summary(local3)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 全连接层2</span></span><br><span class="line"> <span class="keyword">with</span> tf.variable_scope(<span class="string">'local4'</span>) <span class="keyword">as</span> scope:</span><br><span class="line"> weights = _variable_with_weight_decay(<span class="string">'weights'</span>, shape=[<span class="number">384</span>, <span class="number">192</span>],stddev=<span class="number">0.04</span>, wd=<span class="number">0.004</span>)</span><br><span class="line"> biases = _variable_on_cpu(<span class="string">'biases'</span>, [<span class="number">192</span>], tf.constant_initializer(<span class="number">0.1</span>))</span><br><span class="line"> local4 = tf.nn.relu(tf.matmul(local3, weights) + biases, name=scope.name)</span><br><span class="line"> _activation_summary(local4)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># (WX + b),线性logit,这里没使用softmax直接输出未归一化的logits是因为需要在loss中直接计算熵,使用的sparse_softmax_cross_entropy_with_logits函数接受的是未归一化的形式</span></span><br><span class="line"> <span class="keyword">with</span> tf.variable_scope(<span class="string">'softmax_linear'</span>) <span class="keyword">as</span> scope:</span><br><span class="line"> weights = _variable_with_weight_decay(<span class="string">'weights'</span>, [<span class="number">192</span>, NUM_CLASSES],stddev=<span class="number">1</span>/<span class="number">192.0</span>,wd=<span class="number">0.0</span>)</span><br><span class="line"> biases = _variable_on_cpu(<span class="string">'biases'</span>, [NUM_CLASSES],tf.constant_initializer(<span class="number">0.0</span>))</span><br><span class="line"> softmax_linear = tf.add(tf.matmul(local4, weights), biases, name=scope.name)</span><br><span class="line"> _activation_summary(softmax_linear)</span><br><span class="line"> <span class="keyword">return</span> softmax_linear</span><br></pre></td></tr></table></figure><h1 id="训练阶段">训练阶段</h1><h2 id="loss">loss</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">loss</span><span class="params">(logits, labels)</span>:</span></span><br><span class="line"><span class="comment"># 接受从模型构造函数inference返回的logits,以及从input或者distorted_inputs中的label部分,返回损失tensor</span></span><br><span class="line"> labels = tf.cast(labels, tf.int64)</span><br><span class="line"> cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(</span><br><span class="line"> labels=labels, logits=logits, name=<span class="string">'cross_entropy_per_example'</span>)</span><br><span class="line"> cross_entropy_mean = tf.reduce_mean(cross_entropy, name=<span class="string">'cross_entropy'</span>)</span><br><span class="line"> tf.add_to_collection(<span class="string">'losses'</span>, cross_entropy_mean)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># The total loss is defined as the cross entropy loss plus all of the weight</span></span><br><span class="line"> <span class="comment"># decay terms (L2 loss).</span></span><br><span class="line"> <span class="keyword">return</span> tf.add_n(tf.get_collection(<span class="string">'losses'</span>), name=<span class="string">'total_loss'</span>)</span><br></pre></td></tr></table></figure><h2 id="train">train</h2><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></pre></td><td class="code"><pre><span class="line"><span class="comment">#接受参数:总损失def train(total_loss, global_step):</span></span><br><span class="line"></span><br><span class="line"> num_batches_per_epoch = NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN / FLAGS.batch_size</span><br><span class="line"> decay_steps = int(num_batches_per_epoch * NUM_EPOCHS_PER_DECAY)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 根据当前的训练步数、衰减速度、初始的学习速率确定更新新的学习速率.staircase=True,标明按照梯度下降衰减。即global_step,每隔decay_steps, learing_rate会按照LEARNING_RATE_DECAY_FACTOR(衰减系数)衰减一次。 如果straircase = false, 代表 learning rate 按照连续函数衰减, 即每训练一次,learning rate 都会衰减一次</span></span><br><span class="line"> lr = tf.train.exponential_decay(INITIAL_LEARNING_RATE,</span><br><span class="line"> global_step,</span><br><span class="line"> decay_steps,</span><br><span class="line"> LEARNING_RATE_DECAY_FACTOR,</span><br><span class="line"> staircase=<span class="keyword">True</span>)</span><br><span class="line"> tf.summary.scalar(<span class="string">'learning_rate'</span>, lr)</span><br><span class="line"></span><br><span class="line"> loss_averages_op = _add_loss_summaries(total_loss)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 计算梯度。函数tf.control_dependencies,计算单元梯度计算要在统计之后</span></span><br><span class="line"> <span class="keyword">with</span> tf.control_dependencies([loss_averages_op]):</span><br><span class="line"> opt = tf.train.GradientDescentOptimizer(lr)</span><br><span class="line"> grads = opt.compute_gradients(total_loss)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 梯度更新参数:计算完了,就反向传播一次,更新被训练的参数</span></span><br><span class="line"> apply_gradient_op = opt.apply_gradients(grads, global_step=global_step)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> var <span class="keyword">in</span> tf.trainable_variables():</span><br><span class="line"> tf.summary.histogram(var.op.name, var)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> grad, var <span class="keyword">in</span> grads:</span><br><span class="line"> <span class="keyword">if</span> grad <span class="keyword">is</span> <span class="keyword">not</span> <span class="keyword">None</span>:</span><br><span class="line"> tf.summary.histogram(var.op.name + <span class="string">'/gradients'</span>, grad)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 指数移动平均,是指tensorflow会创建一个变量(一般称为shadow variable)来储存某个变量的指数移动平均值,在训练过程中,每训练一次,变量都会学习到一个新的值,则对应的shadow变量也会跟着更新一次(更新需要run update op)。在训练过程中,只会不断更新shadow变量的值,而不会在模型中使用这个shadow变量。这个shadow变量一般是提供给评估过程使用的。 我理解的是,直接使用学习到的变量值进行评估,会导致评估有一定的波动性,如果使用变量的移动平均值替换变量进行评估,则会使评估过程更稳定,而且获得的评估效果也更好。</span></span><br><span class="line"> variable_averages = tf.train.ExponentialMovingAverage(</span><br><span class="line"> MOVING_AVERAGE_DECAY, global_step)</span><br><span class="line"> variables_averages_op = variable_averages.apply(tf.trainable_variables())</span><br><span class="line"></span><br><span class="line"> <span class="keyword">with</span> tf.control_dependencies([apply_gradient_op, variables_averages_op]):</span><br><span class="line"> train_op = tf.no_op(name=<span class="string">'train'</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 返回训练op</span></span><br><span class="line"> <span class="keyword">return</span> train_op</span><br></pre></td></tr></table></figure><h1 id="测试阶段">测试阶段</h1><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 测试一次的函数,saver是操作模型参数文件checkpoints的对象;top_k_op计算准确率def eval_once(saver, summary_writer, top_k_op, summary_op): </span></span><br><span class="line"> <span class="keyword">with</span> tf.Session() <span class="keyword">as</span> sess:</span><br><span class="line"> ckpt = tf.train.get_checkpoint_state(FLAGS.checkpoint_dir)</span><br><span class="line"> <span class="keyword">if</span> ckpt <span class="keyword">and</span> ckpt.model_checkpoint_path:</span><br><span class="line"> <span class="comment"># 从checkpoint取出参数</span></span><br><span class="line"> saver.restore(sess, ckpt.model_checkpoint_path)</span><br><span class="line"> global_step = ckpt.model_checkpoint_path.split(<span class="string">'/'</span>)[-<span class="number">1</span>].split(<span class="string">'-'</span>)[-<span class="number">1</span>]</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> print(<span class="string">'No checkpoint file found'</span>)</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 开始测试样本队列,多线程</span></span><br><span class="line"> coord = tf.train.Coordinator()</span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> threads = []</span><br><span class="line"> <span class="comment"># tensorflow单独创建一个queue runner线程,它负责从文件中读取样本数据,并将其装载到一个队列中。我们只需要开启这个线程,在需要数据时从队列中获取想要的size的数据集就可以了,队列数据的装载由该线程自动实现的。</span></span><br><span class="line"> <span class="keyword">for</span> qr <span class="keyword">in</span> tf.get_collection(tf.GraphKeys.QUEUE_RUNNERS):</span><br><span class="line"> threads.extend(qr.create_threads(sess, coord=coord, daemon=<span class="keyword">True</span>,</span><br><span class="line"> start=<span class="keyword">True</span>))</span><br><span class="line"></span><br><span class="line"> num_iter = int(math.ceil(FLAGS.num_examples / FLAGS.batch_size))</span><br><span class="line"> true_count = <span class="number">0</span> <span class="comment"># Counts the number of correct predictions.</span></span><br><span class="line"> total_sample_count = num_iter * FLAGS.batch_size</span><br><span class="line"> step = <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> step < num_iter <span class="keyword">and</span> <span class="keyword">not</span> coord.should_stop():</span><br><span class="line"> <span class="comment"># 计算准确率</span></span><br><span class="line"> predictions = sess.run([top_k_op])</span><br><span class="line"> true_count += np.sum(predictions)</span><br><span class="line"> step += <span class="number">1</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 计算准确率</span></span><br><span class="line"> precision = true_count / total_sample_count</span><br><span class="line"> print(<span class="string">'%s: precision @ 1 = %.3f'</span> % (datetime.now(), precision))</span><br><span class="line"></span><br><span class="line"> summary = tf.Summary()</span><br><span class="line"> summary.ParseFromString(sess.run(summary_op))</span><br><span class="line"> summary.value.add(tag=<span class="string">'Precision @ 1'</span>, simple_value=precision)</span><br><span class="line"> summary_writer.add_summary(summary, global_step)</span><br><span class="line"> <span class="keyword">except</span> Exception <span class="keyword">as</span> e: <span class="comment"># pylint: disable=broad-except</span></span><br><span class="line"> coord.request_stop(e)</span><br><span class="line"></span><br><span class="line"> coord.request_stop()</span><br><span class="line"> coord.join(threads, stop_grace_period_secs=<span class="number">10</span>)</span><br></pre></td></tr></table></figure><h1 id="其他">其他</h1><p>关于tf.train.shuffle_batch 中的参数 shuffle、min_after_dequeue</p><p>shuffle的作用在于指定是否需要随机打乱样本的顺序,一般作用于训练阶段,提高鲁棒性。</p><ol><li>当shuffle = false时,每次dequeue是从队列中按顺序取数据,遵从先入先出的原则</li><li>当shuffle = true时,每次从队列中dequeue取数据时,不再按顺序,而是随机的,所以打乱了样本的原有顺序。</li></ol><p>shuffle还要配合参数min_after_dequeue使用才能发挥作用。这个参数min_after_dequeue的意思是队列中,做dequeue(取数据)的操作后,queue runner线程要保证队列中至少剩下min_after_dequeue个数据。如果min_after_dequeue设置的过少,则即使shuffle为true,也达不到好的混合效果。</p><p>因为我们的目的肯定是想尽最大可能的混合数据,因此设置min_after_dequeue,可以保证每次dequeue后都有足够量的数据填充尽队列,保证下次dequeue时可以很充分的混合数据。</p><p>但是min_after_dequeue也不能设置的太大,这样会导致队列填充的时间变长,尤其是在最初的装载阶段,会花费比较长的时间。</p><hr><h2 id="关于训练与测试">关于训练与测试</h2><p>在以前的教程中,都是将训练和评估放在一个程序中运行,而在这个教程中,训练和评估是分开在两个独立的程序中进行的,之所以这样做,是因为评估过程不会直接使用训练学习到的模型参数(trainable variable的值),而是要使用的是变量的滑动平均(shadow variable)来代替原有变量进行评估。</p><p>具体的实现方法是,在训练过程中,为每个trainable variable 添加 指数滑动平均变量,然后每训练1000步就将模型训练到的变量值保存在checkpoint中,评估过程运行时,从最新存储的checkpoint中取出模型的shadow variable,赋值给对应的变量,然后进行评估</p>]]></content>
<summary type="html">
<p>这篇文章是对TensorFlow官方例子:CIFAR-10数据集分类的理解记录。</p>
<p>对CIFAR-10 数据集的分类是机器学习中一个公开的基准测试问题,其任务是对一组大小为32x32的RGB图像进行分类,这些图像涵盖了10个类别:</p>
<p>飞机, 汽车, 鸟, 猫, 鹿, 狗, 青蛙, 马, 船以及卡车。</p>
<p><a href="http://www.cs.toronto.edu/~kriz/cifar.html">数据集主页</a></p>
<p><a href="https://github.com/tensorflow/models/tree/master/tutorials/image/cifar10">Python项目代码页面</a></p>
<p>这里主要介绍<code>cifar10_input.py</code>、<code>caifar10.py</code>、<code>caifar_train.py</code>和<code>cifar10_eval.py</code><br>
</summary>
<category term="Tensorflow" scheme="http://peihao.space/categories/Tensorflow/"/>
<category term="Tensorflow" scheme="http://peihao.space/tags/Tensorflow/"/>
</entry>
<entry>
<title>Dropout</title>
<link href="http://peihao.space/2017/03/23/dropout/"/>
<id>http://peihao.space/2017/03/23/dropout/</id>
<published>2017-03-23T14:18:42.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="前言">前言</h1><p>训练神经网络模型时,如果<strong>训练样本较少,为了防止模型过拟合</strong>,Dropout可以作为一种trikc供选择。Dropout是hintion最近2年提出的,源于其文章<a href="https://arxiv.org/abs/1207.0580" target="_blank" rel="external">Improving neural networks by preventing co-adaptation of feature detectors</a>.中文大意为:通过阻止特征检测器的共同作用来提高神经网络的性能。本篇博文就是按照这篇论文简单介绍下Dropout的思想。</p><p>大部分内容来源<a href="http://www.cnblogs.com/tornadomeet/p/3258122.html" target="_blank" rel="external">tornadomeet</a>,先记录,之后填充。<br><a id="more"></a></p><h1 id="基础知识">基础知识</h1><p> Dropout是指在模型训练时随机让网络某些隐含层节点的权重不工作,不工作的那些节点可以暂时认为不是网络结构的一部分,但是它的权重得保留下来(只是暂时不更新而已),因为下次样本输入时它可能又得工作了(有点抽象,具体实现看后面的实验部分)。</p><p> 按照hinton的文章,他使用Dropout时训练阶段和测试阶段做了如下操作:</p><p> 在样本的训练阶段,在没有采用pre-training的网络时(Dropout当然可以结合pre-training一起使用),hintion并不是像通常那样对权值采用L2范数惩罚,而是对每个隐含节点的权值L2范数设置一个上限bound,当训练过程中如果该节点不满足bound约束,则用该bound值对权值进行一个规范化操作(即同时除以该L2范数值),说是这样可以让权值更新初始的时候有个大的学习率供衰减,并且可以搜索更多的权值空间。</p><p> 在模型的测试阶段,使用”mean network(均值网络)”来得到隐含层的输出,其实就是在网络前向传播到输出层前时隐含层节点的输出值都要减半(如果dropout的比例为50%),其理由文章说了一些,可以去查看(没理解)。</p><p> 关于Dropout,文章中没有给出任何数学解释,Hintion的直观解释和理由如下:</p><ol><li><p>由于每次用输入网络的样本进行权值更新时,隐含节点都是以一定概率随机出现,因此不能保证每2个隐含节点每次都同时出现,这样权值的更新不再依赖于有固定关系隐含节点的共同作用,阻止了某些特征仅仅在其它特定特征下才有效果的情况。</p></li><li><p>可以将dropout看作是模型平均的一种。对于每次输入到网络中的样本(可能是一个样本,也可能是一个batch的样本),其对应的网络结构都是不同的,但所有的这些不同的网络结构又同时share隐含节点的权值。这样不同的样本就对应不同的模型,是bagging的一种极端情况。个人感觉这个解释稍微靠谱些,和bagging,boosting理论有点像,但又不完全相同。</p></li><li><p>native bayes是dropout的一个特例。Native bayes有个错误的前提,即假设各个特征之间相互独立,这样在训练样本比较少的情况下,单独对每个特征进行学习,测试时将所有的特征都相乘,且在实际应用时效果还不错。而Droput每次不是训练一个特征,而是一部分隐含层特征。</p></li><li><p>还有一个比较有意思的解释是,Dropout类似于性别在生物进化中的角色,物种为了使适应不断变化的环境,性别的出现有效的阻止了过拟合,即避免环境改变时物种可能面临的灭亡。</p></li></ol><p>下面一个使用MNIST的CNN小例子使用dropout:</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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 进行20000次训练</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">20000</span>):</span><br><span class="line"><span class="comment"># 随机取出50个样本数据,包括图片的灰度值x [28*28],以及label数据y_</span></span><br><span class="line"> batch = mnist.train.next_batch(<span class="number">50</span>)</span><br><span class="line"> <span class="keyword">if</span> i%<span class="number">100</span> == <span class="number">0</span>:</span><br><span class="line"> <span class="comment"># 这里没有再学习权值和偏置,没有对他们更新,是使用训练集做了一个简单的测试,所以概率设置为1</span></span><br><span class="line"> train_accuracy = accuracy.eval(feed_dict={</span><br><span class="line"> x:batch[<span class="number">0</span>], y_: batch[<span class="number">1</span>], keep_prob: <span class="number">1.0</span>})</span><br><span class="line"> print(<span class="string">"step %d, training accuracy %g"</span>%(i, train_accuracy))</span><br><span class="line"><span class="comment"># 训练时使用dropout,概率为0.5</span></span><br><span class="line"> train_step.run(feed_dict={x: batch[<span class="number">0</span>], y_: batch[<span class="number">1</span>], keep_prob: <span class="number">0.5</span>})</span><br><span class="line"></span><br><span class="line"><span class="comment"># 测试时不使用dropout,将概率设置为1</span></span><br><span class="line">print(<span class="string">"test accuracy %g"</span>%accuracy.eval(feed_dict={</span><br><span class="line"> x: mnist.test.images, y_: mnist.test.labels, keep_prob: <span class="number">1.0</span>}))</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h1 id="前言">前言</h1><p>训练神经网络模型时,如果<strong>训练样本较少,为了防止模型过拟合</strong>,Dropout可以作为一种trikc供选择。Dropout是hintion最近2年提出的,源于其文章<a href="https://arxiv.org/abs/1207.0580">Improving neural networks by preventing co-adaptation of feature detectors</a>.中文大意为:通过阻止特征检测器的共同作用来提高神经网络的性能。本篇博文就是按照这篇论文简单介绍下Dropout的思想。</p>
<p>大部分内容来源<a href="http://www.cnblogs.com/tornadomeet/p/3258122.html">tornadomeet</a>,先记录,之后填充。<br>
</summary>
<category term="ML" scheme="http://peihao.space/categories/ML/"/>
<category term="ML" scheme="http://peihao.space/tags/ML/"/>
</entry>
<entry>
<title>(转载)CNN卷积神经网络</title>
<link href="http://peihao.space/2017/03/22/cnn/"/>
<id>http://peihao.space/2017/03/22/cnn/</id>
<published>2017-03-22T14:18:42.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="先述">先述</h1><p><a href="https://ujjwalkarn.me/2016/08/11/intuitive-explanation-convnets/" target="_blank" rel="external">卷积神经网络-翻译</a><a href="https://ujjwalkarn.me/2016/08/11/intuitive-explanation-convnets/" target="_blank" rel="external"> 英文原文</a>(ConvNets 或者 CNNs)属于神经网络的范畴,已经在诸如图像识别和分类的领域证明了其高效的能力。卷积神经网络可以成功识别人脸、物体和交通信号,从而为机器人和自动驾驶汽车提供视力。</p><p><img src="http://peihao.space/img/article/ml/x3.png" alt=""><br><a id="more"></a><br>上图中,ConvNet主要有四个操作:</p><ol><li>卷积</li><li>非线性处理(ReLU)</li><li>池化pooling</li><li>分类</li></ol><h2 id="图像是像素值的矩阵">图像是像素值的矩阵</h2><p>本质上来说,每张图像都可以表示为像素值的矩阵:</p><p><img src="http://peihao.space/img/article/ml/x4.gif" alt=""></p><p>通道 (chain)常用于表示图像的某种组成。一个标准数字相机拍摄的图像会有三通道 - 红、绿和蓝;你可以把它们看作是互相堆叠在一起的二维矩阵(每一个通道代表一个颜色),每个通道的像素值在 0 到 255 的范围内。</p><p>灰度图像,仅仅只有一个通道。在本篇文章中,我们仅考虑灰度图像,这样我们就只有一个二维的矩阵来表示图像。矩阵中各个像素的值在 0 到 255 的范围内——零表示黑色,255 表示白色。</p><h2 id="卷积">卷积</h2><p><strong>卷积的主要目的是为了从输入图像中提取特征。卷积可以通过从输入的一小块数据中学到图像的特征,并可以保留像素间的空间关系。</strong></p><p>每张图像都可以看作是像素值的矩阵。考虑一下一个 5 x 5 的图像,它的像素值仅为 0 或者 1(注意对于灰度图像而言,像素值的范围是 0 到 255,下面像素值为 0 和 1 的绿色矩阵仅为特例),同时,考虑下另一个 3 x 3 的矩阵。接下来,5 x 5 的图像和 3 x 3 的矩阵的卷积可以按下图所示的动画一样计算:</p><p><img src="http://peihao.space/img/article/ml/x2.gif" alt=""></p><p>现在停下来好好理解下上面的计算是怎么完成的。我们用橙色的矩阵在原始图像(绿色)上滑动,每次滑动一个像素(也叫做“步长”),在每个位置上,我们计算对应元素的乘积(两个矩阵间),并把乘积的和作为最后的结果,得到输出矩阵(粉色)中的每一个元素的值。注意,3 x 3 的矩阵每次步长中仅可以“看到”输入图像的一部分。</p><p>在 CNN 的术语中,3x3 的矩阵叫做“滤波器(filter)”或者“核(kernel)”或者“特征检测器(feature detector)”,通过在图像上滑动滤波器并计算点乘得到矩阵叫做“卷积特征(Convolved Feature)”或者“激活图(Activation Map)”或者“特征图(Feature Map)”。记住滤波器在原始输入图像上的作用是特征检测器。</p><p>不同滤波器对上图卷积的效果。通过在卷积操作前修改滤波矩阵的数值,我们可以进行诸如边缘检测、锐化和模糊等操作 —— 这表明不同的滤波器可以从图中检测到不同的特征,比如边缘、曲线等。</p><p>在实践中,CNN 会在训练过程中学习到这些滤波器的值(尽管我们依然需要在训练前指定诸如滤波器的个数、滤波器的大小、网络架构等参数)。我们使用的滤波器越多,提取到的图像特征就越多,网络所能在未知图像上识别的模式也就越好。</p><p>特征图的大小(卷积特征)由下面三个参数控制,我们需要在卷积前确定它们:</p><ul><li><p>深度(Depth):深度对应的是卷积操作所需的滤波器个数。在下图的网络中,我们使用三个不同的滤波器对原始图像进行卷积操作,这样就可以生成三个不同的特征图。你可以把这三个特征图看作是堆叠的 2d 矩阵,那么,特征图的“深度”就是三。</p></li><li><p>步长(Stride):步长是我们在输入矩阵上滑动滤波矩阵的像素数。当步长为 1 时,我们每次移动滤波器一个像素的位置。当步长为 2 时,我们每次移动滤波器会跳过 2 个像素。步长越大,将会得到更小的特征图。</p></li><li><p>零填充(Zero-padding):有时,在输入矩阵的边缘使用零值进行填充,这样我们就可以对输入图像矩阵的边缘进行滤波。零填充的一大好处是可以让我们控制特征图的大小。使用零填充的也叫做泛卷积,不适用零填充的叫做严格卷积。这个概念在下面的参考文献 14 中介绍的非常详细。</p></li></ul><h2 id="ReLU">ReLU</h2><p>每次的卷积操作后都使用了一个叫做 ReLU 的操作。ReLU 表示修正线性单元(Rectified Linear Unit),是一个非线性操作。它的输入如下所示:</p><p><img src="http://peihao.space/img/article/ml/x5.png" alt=""></p><p>ReLU 是一个元素级别的操作(应用到各个像素),并将特征图中的所有小于 0 的像素值设置为零。ReLU 的目的是在 ConvNet 中引入非线性,因为在大部分的我们希望 ConvNet 学习的实际数据是非线性的(卷积是一个线性操作——元素级别的矩阵相乘和相加,所以我们需要通过使用非线性函数 ReLU 来引入非线性。</p><h2 id="池化">池化</h2><p>空间池化(Spatial Pooling)(也叫做亚采用或者下采样)降低了各个特征图的维度,但可以保持大部分重要的信息。空间池化有下面几种方式:最大化、平均化、加和等等。</p><p>对于最大池化(Max Pooling),我们定义一个空间邻域(比如,2x2 的窗口),并从窗口内的修正特征图中取出最大的元素。除了取最大元素,我们也可以取平均(Average Pooling)或者对窗口内的元素求和。在实际中,最大池化被证明效果更好一些。</p><p>我们以 2 个元素(也叫做“步长”)滑动我们 2x2 的窗口,并在每个区域内取最大值。如上图所示,这样操作可以降低我们特征图的维度。</p><p><img src="http://peihao.space/img/article/ml/x6.png" alt=""></p><p>池化函数可以逐渐降低输入表示的空间尺度。特别地,池化:</p><ul><li>使输入表示(特征维度)变得更小,并且网络中的参数和计算的数量更加可控的减小,因此,可以控制过拟合</li><li>使网络对于输入图像中更小的变化、冗余和变换变得不变性(输入的微小冗余将不会改变池化的输出——因为我们在局部邻域中使用了最大化/平均值的操作。</li><li>帮助我们获取图像最大程度上的尺度不变性(准确的词是“不变性”)。它非常的强大,因为我们可以检测图像中的物体,无论它们位置在哪里(参考 18 和 19 获取详细信息)。</li></ul><p>到目前为止我们了解了卷积、ReLU 和池化是如何操作的。理解这些层是构建任意 CNN 的基础是很重要的。我们有两组卷积、ReLU & 池化层 —— 第二组卷积层使用六个滤波器对第一组的池化层的输出继续卷积,得到一共六个特征图。接下来对所有六个特征图应用 ReLU。接着我们对六个修正特征图分别进行最大池化操作。</p><p>这些层一起就可以从图像中提取有用的特征,并在网络中引入非线性,减少特征维度,同时保持这些特征具有某种程度上的尺度变化不变性。</p><p>第二组池化层的输出作为全连接层的输入,我们会在下一部分介绍全连接层。</p><h2 id="全连接层">全连接层</h2><p>全连接层是传统的多层感知器,在输出层使用的是 softmax 激活函数(也可以使用其他像 SVM 的分类器,但在本文中只使用 softmax)。“全连接(Fully Connected)”这个词表明前面层的所有神经元都与下一层的所有神经元连接。</p><p>卷积和池化层的输出表示了输入图像的高级特征。全连接层的目的是为了使用这些特征把输入图像基于训练数据集进行分类。</p><p>除了分类,添加一个全连接层也(一般)是学习这些特征的非线性组合的简单方法。从卷积和池化层得到的大多数特征可能对分类任务有效,但这些特征的组合可能会更好。</p><p>从全连接层得到的输出概率和为 1。这个可以在输出层使用 softmax 作为激活函数进行保证。softmax 函数输入一个任意大于 0 值的矢量,并把它们转换为零一之间的数值矢量,其和为一。</p><p><strong>卷积 + 池化层的作用是从输入图像中提取特征,而全连接层的作用是分类器。</strong></p><h1 id="小结">小结</h1><p>完整的卷积网络的训练过程可以总结如下:</p><ol><li><p>第一步:我们初始化所有的滤波器,使用随机值设置参数/权重</p></li><li><p>第二步:网络接收一张训练图像作为输入,通过前向传播过程(卷积、ReLU 和池化操作,以及全连接层的前向传播),找到各个类的输出概率</p><ul><li>我们假设船这张图像的输出概率是 [0.2, 0.4, 0.1, 0.3]</li><li>因为对于第一张训练样本的权重是随机分配的,输出的概率也是随机的</li></ul></li><li>第三步:在输出层计算总误差(计算 4 类的和)<ul><li>Total Error = ∑ ½ (target probability – output probability) ²</li></ul></li><li>第四步:使用反向传播算法,根据网络的权重计算误差的梯度,并使用梯度下降算法更新所有滤波器的值/权重以及参数的值,使输出误差最小化<ul><li>权重的更新与它们对总误差的占比有关</li><li>当同样的图像再次作为输入,这时的输出概率可能会是 [0.1, 0.1, 0.7, 0.1],这就与目标矢量 [0, 0, 1, 0] 更接近了</li><li>这表明网络已经通过调节权重/滤波器,可以正确对这张特定图像的分类,这样输出的误差就减小了</li><li>像滤波器数量、滤波器大小、网络结构等这样的参数,在第一步前都是固定的,在训练过程中保持不变——仅仅是滤波器矩阵的值和连接权重在更新</li></ul></li><li>第五步:对训练数据中所有的图像重复步骤 1 ~ 4</li></ol><h1 id="补充">补充</h1><p>有时候,我们会在池化前后进行局部对比度归一化层(local contract normalization)。这个归一化包括两个部分:局部做减和局部做除</p><p>自然图像存在低阶和高阶的统计特征,低阶(例如二阶)的统计特征是满足高斯分布的,但高阶的统计特性是非高斯分布。图像中,空间上相邻的像素点有着很强的相关性。而对于PCA来说,因为它是对协方差矩阵操作,所以可以去掉输入图像的二阶相关性,但是却无法去掉高阶相关性。而有人证明了除以一个隐含的变量就可以去除高阶相关性。</p><p> 对输入图像的每一个像素,我们计算其邻域(例如3x3窗口)的均值,然后每个像素先减去这个均值,再除以这个邻域窗口(例如3x3窗口)拉成的9维向量的欧几里德范数(如果这个范数大于1的时候才除:这个约束是为了保证归一化只作用于减少响应(除以大于1的数值变小),而不会加强响应(除以小于1的数值变大))。也有论文在计算均值和范数的时候,都加入了距离的影响,也就是距离离该窗口中心越远,影响越小,例如加个高斯权重窗口(空间上相邻的像素点的相关性随着距离变大而变小)。</p><p> 数据归一化,就是将数据映射到[0,1]或[-1,1]区间或更小的区间,比如(0.1,0.9) 。</p><p> 为什么要归一化处理?</p><ol><li>输入数据的单位不一样,有些数据的范围可能特别大,导致的结果是神经网络收敛慢、训练时间长。</li><li>数据范围大的输入在模式分类中的作用可能会偏大,而数据范围小的输入作用就可能会偏小。</li><li>由于神经网络输出层的激活函数的值域是有限制的,因此需要将网络训练的目标数据映射到激活函数的值域。例如神经网络的输出层若采用S形激活函数,由于S形函数的值域限制在(0,1),也就是说神经网络的输出只能限制在(0,1),所以训练数据的输出就要归一化到[0,1]区间。</li><li>S形激活函数在(0,1)区间以外区域很平缓,区分度太小。例如S形函数f(X)在参数a=1时,f(100)与f(5)只相差0.0067。</li></ol>]]></content>
<summary type="html">
<h1 id="先述">先述</h1><p><a href="https://ujjwalkarn.me/2016/08/11/intuitive-explanation-convnets/">卷积神经网络-翻译</a><a href="https://ujjwalkarn.me/2016/08/11/intuitive-explanation-convnets/"> 英文原文</a>(ConvNets 或者 CNNs)属于神经网络的范畴,已经在诸如图像识别和分类的领域证明了其高效的能力。卷积神经网络可以成功识别人脸、物体和交通信号,从而为机器人和自动驾驶汽车提供视力。</p>
<p><img src="http://peihao.space/img/article/ml/x3.png" alt=""><br>
</summary>
<category term="ML" scheme="http://peihao.space/categories/ML/"/>
<category term="ML" scheme="http://peihao.space/tags/ML/"/>
</entry>
<entry>
<title>MAP、SRM、ERM与MLE</title>
<link href="http://peihao.space/2017/03/20/MAP-MLE-SRM/"/>
<id>http://peihao.space/2017/03/20/MAP-MLE-SRM/</id>
<published>2017-03-20T03:22:09.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="最大似然与经验风险最小化">最大似然与经验风险最小化</h1><blockquote><p>当模型是条件概率分布,损失函数是对数损失函数时,经验风险最小化就等价于极大似然估计</p></blockquote><p>首先给出对数形式的ERM的公式:<br>$$\min \frac{1}{n}\sum\limits_{i=1}^n L(y_i,p(y_i\mid x_i))$$</p><p>其中$L(y_i,f(x_i))$是损失函数,输出预测值为$f(x_i)$,n是观察到的样本数。</p><hr><p>最大似然的前提是从模型总体随机抽取样本观测值,所有的采样都是独立同分布的。<br><a id="more"></a><br>假设$x_1,x_2,…,x_n$为独立同分布的采样,$\theta$为模型参数,f为我们使用的模型,我们使用条件概率分布,遵循独立同分布。假设我们需要根据观察数据$x$估计没有观察到的总体参数$\theta$:</p><p>$$f(x_1,x_2,…,x_n \mid \theta)=f(x_1 \mid \theta)\times f(x_2 \mid \theta)\times…\times f(x_n \mid \theta)$$</p><p>此时似然定义为:</p><p>$$L(\theta \mid x_1,x_2,…,x_n)=P(x_1,x_2,…,x_n\mid \theta)=\prod\limits_{i=1}^n f(x_i \mid \theta)$$</p><p>在实际应用中常用的是取两边取对数,并取似然值得平均值:</p><p>$$\frac{1}{n} \log L(\theta \mid x_1,x_2,…,x_n)=\frac{1}{n} \sum\limits_{i=1}^n \log f(x_i \mid \theta)$$</p><p>去取极大似然估计MLE:</p><p>$$\arg\max\limits_{\theta} \frac{1}{n} \sum\limits_{i=1}^n \log f(x_i\mid \theta)=\min \frac{1}{n}\sum\limits_{i=1}^n - \log f(x_i \mid \theta)$$</p><p>$-\log f(x_i\mid \theta)$可以看做是对数似然损失函数。可以明显看出此时的经验风险最小化就等价于极大似然估计。上式是要求参数$\theta$,在这个参数条件下,使得已知数据$x$出现的概率最大。</p><h1 id="后验概率与结构风险最小化">后验概率与结构风险最小化</h1><blockquote><p>当模型是条件概率分布、损失函数是对数损失函数、模型复杂度由模型的先验概率表示时,结构风险最小化就等价于最大后验概率估计。</p></blockquote><p>最大后验估计是根据经验数据获得对难以观察的量的点估计。与最大似然估计类似,但是最大的不同时,最大后验估计的融入了要估计量的先验分布在其中。故最大后验估计可以看做规则化的最大似然估计。</p><h2 id="MAP推导">MAP推导</h2><p>先来一段后验概率最大化MAP的推导,摘自<a href="https://zh.wikipedia.org/wiki/%E6%9C%80%E5%A4%A7%E5%90%8E%E9%AA%8C%E6%A6%82%E7%8E%87" target="_blank" rel="external">Wiki</a>:</p><p>假设我们需要根据观察数据$x$估计没有观察到的总体参数 $\theta$,让$f$作为$x$的采样分布,这样$f(x\mid \theta)$就是在那个题参数为$\theta$时$x$的概率。函数$\theta \to f(x \mid \theta)$,即为似然函数,其估计$\hat{\theta}_{ML}(x)=\arg\max\limits_{\theta}f(x\mid \theta)$,就是$\theta$的最大似然估计。</p><p>假设$\theta$存在一个先验分布$g$,这就允许我们将$\theta$作为贝叶斯分布中的随机变量,这样$\theta$的后验分布就是:</p><p>$$\theta \to \frac{f(x \mid \theta)g(\theta)}{\int_{\Theta}f(x \mid \theta_1)g(\theta_1)d\theta_1}$$</p><p>其中$\Theta$是$g$的域,上式分母的下部就相当于对已知数据$x$概率的估计,这里用的公式是贝叶斯公式,由先验概率去求后验概率$P(A\mid B)=(P(B\mid A)*P(A))/P(B)$。</p><p>最大后验估计方法估计$\theta$为这个随机变量的后验分布的众数:</p><p>$$\hat{\theta}_{MAP}(x)=\arg\max\limits_{\theta} \frac{f(x \mid \theta)g(\theta)}{\int_{\Theta}f(x \mid \theta_1)g(\theta_1)d\theta_1}=\arg\max\limits_{\theta}f(x\mid \theta)g(\theta)$$</p><p>后验分布的分母与$\theta$ 无关,在求解中分母不变,当成一个常数使用,所以在优化过程中不起作用。注意当前验$g$是常数函数时最大后验概率与最大似然估计的重合。</p><h2 id="先验概率">先验概率</h2><p>这里我先对我理解的先验概率含义做个叙述。<a href="http://blog.csdn.net/upon\_the\_yun/article/details/8915283" target="_blank" rel="external">先验分布</a>,我理解的就是在没有输入数据或者其他数据,根据经验主观或者频数客观的对整个模型的各个结果集占比的推测。</p><p>举例来说:假设有五个袋子,各袋中都有无限量的饼干(樱桃口味或柠檬口味),已知五个袋子中两种口味的比例分别是</p><ol><li>樱桃 100%</li><li>樱桃 75% + 柠檬 25%</li><li>樱桃 50% + 柠檬 50%</li><li>樱桃 25% + 柠檬 75%</li><li>柠檬 100%</li></ol><p>如果只有如上所述条件,那问从同一个袋子中连续拿到2个柠檬饼干,那么这个袋子最有可能是上述五个的哪一个?</p><p>我们首先采用MLE来解这个问题。假设从袋子中能拿出柠檬饼干的概率为p(我们通过这个概率p来确定是从哪个袋子中拿出来的),则似然函数可以写作:</p><p>$$p(两个柠檬饼干 \mid 袋子)=p^2$$</p><p>由于p的取值是一个离散值,即上面描述中的0,25%,50%,75%,1。我们只需要评估一下这五个值哪个值使得似然函数最大即可,得到为袋子5。这里便是最大似然估计的结果。</p><p>上述最大似然估计有一个问题,就是没有考虑到模型本身的概率分布,下面我们扩展这个饼干的问题。</p><p>假设拿到袋子1或5的机率都是0.1,拿到2或4的机率都是0.2,拿到3的机率是0.4,那同样上述问题的答案呢?这个时候就变MAP了。我们根据公式<br>$$\hat{\theta}_{MAP}(x)=\arg\max\limits_{\theta} \frac{f(x \mid \theta)g(\theta)}{\int_{\Theta}f(x \mid \theta_1)g(\theta_1)d\theta_1}=\arg\max\limits_{\theta}f(x\mid \theta)g(\theta)$$<br>写出我们的MAP函数:$MAP=p^2 \times g$</p><p>根据题意的描述可知,p的取值分别为0,25%,50%,75%,1,g的取值分别为0.1,0.2,0.4,0.2,0.1.分别计算出MAP函数的结果为:0,0.0125,0.125,0.28125,0.1.由上可知,通过MAP估计可得结果是从第四个袋子中取得的最高。</p><h2 id="SRM与MAP">SRM与MAP</h2><p>我们对MAP进行一些变换(先加上对数,再将对数展开),则上式等价于:</p><p>$$\hat{\theta}_{MAP}(x)=\arg\max\limits_{\theta} [\ln f(x\mid \theta)+\ln g(\theta)]$$</p><p>进一步的,有:</p><p>$$\hat{\theta}_{MAP}(x)=\arg\max\limits_{\theta} \ln f(x \mid \theta)+\arg\max\limits_{\theta} \ln g(\theta)$$<br>可以发现,等式右边第一部分刚好为最大似然估计的公式,我们将最大似然估计的公式写出:</p><p>$$\max \frac{1}{n}\sum\limits_{i=1}^n \ln f(x_i \mid \theta)$$<br>将最大似然估计的公式代入,然后通过增加负号将最大后验概率分布公式的max改为min。这样,最大后验概率估计的公式可以写成下面这样:</p><p>$$\hat{\theta}_{MAP}(x)=\arg\min\limits_{\theta}{[\frac{1}{n}\sum\limits_{i=1}^n-\ln f(x_i \mid \theta)]- g(\theta)}$$</p><p>对比结构风险最小化公式:</p><p>$$\min\limits_{f \in F}\frac{1}{n}\sum\limits_{i=1}^n L(y_i,f(x_i))+\lambda J(f)$$</p><p>由于$f(\mid)$是模型,可以是条件概率分布模型,那么$-\ln f(x_i\mid \theta)$便可以看做是对数似然损失函数。</p><p>$g(\theta)$表示模型的先验概率,<strong>模型的复杂度与模型的先验概率没有必然的正比反比关系</strong>。这里我为了推导,暂且假定先验概率与模型复杂度成反比,$-g(\theta)$可以认为与复杂度成正比,$-g(\theta)$越大,复杂度越高。</p><p>此时,上式中的后半项就对应着结构风险最小化中的正则项。</p>]]></content>
<summary type="html">
<h1 id="最大似然与经验风险最小化">最大似然与经验风险最小化</h1><blockquote>
<p>当模型是条件概率分布,损失函数是对数损失函数时,经验风险最小化就等价于极大似然估计</p>
</blockquote>
<p>首先给出对数形式的ERM的公式:<br>$$\min \frac{1}{n}\sum\limits_{i=1}^n L(y_i,p(y_i\mid x_i))$$</p>
<p>其中$L(y_i,f(x_i))$是损失函数,输出预测值为$f(x_i)$,n是观察到的样本数。</p>
<hr>
<p>最大似然的前提是从模型总体随机抽取样本观测值,所有的采样都是独立同分布的。<br>
</summary>
<category term="数学" scheme="http://peihao.space/categories/%E6%95%B0%E5%AD%A6/"/>
<category term="数学" scheme="http://peihao.space/tags/%E6%95%B0%E5%AD%A6/"/>
</entry>
<entry>
<title>梯度坐标下降</title>
<link href="http://peihao.space/2017/03/17/lagrange-coordinate/"/>
<id>http://peihao.space/2017/03/17/lagrange-coordinate/</id>
<published>2017-03-17T03:22:09.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="梯度下降">梯度下降</h1><p>梯度下降法是一种常用的一阶优化方法,是求解无约束优化问题方法之一。</p><p>原理:考虑无约束优化问题$$\min_x f(x)$$,其中$f(x)$为连续可微函数,若能构造一个序列$x^0,x^1,x^2,…$满足$$f(x^{t+1}) < f(x^t),\ t=0,1,2…$$<br><a id="more"></a><br>不断迭代执行该过程即可收敛到局部极小点。根据泰勒展开式:$$f(x+\Delta x) \approx f(x)+\Delta x^T \nabla f(x)$$</p><p>欲满足:$$f(x+\Delta x) \ < f(x)$$也就是近似满足<br>:$$f(x)+\Delta x^T \nabla f(x)\ <\ f(x)\ \rightleftharpoons \Delta x f(x) \ < 0$$</p><p>为了保证$\Delta x f(x) \ < \ 0$成立,这里一般设置$\Delta x\ = \ -\gamma \nabla f(x)$这就是梯度下降法。当连续的两次迭代结果差小于阈值或者到达一定的迭代次数后,得到极小点</p><p>通过选取合适的步长,保证通过梯度下降收敛到局部极小点。当目标函数为凸函数时,局部极小点就对应着函数的全局最小点。</p><h1 id="坐标下降法">坐标下降法</h1><p>坐标下降法是一种非梯度优化方法,在每次迭代中沿一个坐标方向进行搜索,通过循环使用不同的坐标方向来达到目标函数的局部极小值。</p><p>他的原理就是在各个维度上搜索当前维度上函数的最小值,知道维度循环完毕。</p><p>不妨假设目标是求解函数$f(x)$的极小值,其中$x=(x_1,x_2,…,x_d)^T \ \in R^d$是一个d维向量。从初始点$x_0$开始,坐标下降法通过迭代构造序列求解问题,$x^{t+1}$的第i个分量$x_i^{t+1}$构造为$$x_i^{t+1}= \arg\min\limits_{y \in R} f(x_1^(t+1),…,x_{i-1}^{t+1},y,x_{i+1}^t,…,x_d^t)$$</p><p>通过迭代执行过程显然有$$f(x^0)\geq f(x^1) \geq f(x^2)$$</p><p>这里要注意函数必须要可微,否则不成立。</p>]]></content>
<summary type="html">
<h1 id="梯度下降">梯度下降</h1><p>梯度下降法是一种常用的一阶优化方法,是求解无约束优化问题方法之一。</p>
<p>原理:考虑无约束优化问题$$\min_x f(x)$$,其中$f(x)$为连续可微函数,若能构造一个序列$x^0,x^1,x^2,…$满足$$f(x^{t+1}) &lt; f(x^t),\ t=0,1,2…$$<br>
</summary>
<category term="数学" scheme="http://peihao.space/categories/%E6%95%B0%E5%AD%A6/"/>
<category term="数学" scheme="http://peihao.space/tags/%E6%95%B0%E5%AD%A6/"/>
</entry>
<entry>
<title>对偶问题</title>
<link href="http://peihao.space/2017/03/16/lagrange-dual/"/>
<id>http://peihao.space/2017/03/16/lagrange-dual/</id>
<published>2017-03-16T09:22:09.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="对偶问题">对偶问题</h1><p>再来看不等式约束优化问题:</p><p>$$<br>\begin{aligned}<br>&\min\limits_{x} \ f(x)\\<br>&s.t.\ \ h_i(x)=0,\ i=1,2,…,m\\<br>&g_j(x) \leq 0,\ j=1,2,…,n\\<br>\end{aligned}<br>$$</p><hr><p>定义Lagrange如下:<br>$$<br>L(x,\lambda,\mu)=f(x)+\sum\limits_{i=1}^m\lambda_ih_i(x)+\sum\limits_{j=1}^n\mu_jg_j(x)<br>$$</p><p>在优化理论中,目标函数 f(x) 会有多种形式:<a id="more"></a>如果目标函数和约束条件都为变量 x 的线性函数, 称该问题为线性规划; 如果目标函数为二次函数, 约束条件为线性函数, 称该最优化问题为二次规划; 如果目标函数或者约束条件均为非线性函数, 称该最优化问题为非线性规划。每个线性规划问题都有一个与之对应的对偶问题,对偶问题有非常良好的性质,以下列举几个:</p><ul><li>对偶问题的对偶是原问题;</li><li>无论原始问题是否是凸的,对偶问题都是凸优化问题;</li><li>对偶问题可以给出原始问题一个下界;</li><li>当满足一定条件时,原始问题与对偶问题的解是完全等价的;</li></ul><p>上式的拉格朗日对偶函数:</p><p>$$<br>\begin{aligned}<br>\Gamma(\lambda,\mu)=<br>&\inf\limits_{x \in D}\ L(x,\lambda,\mu)\\<br>=&\inf\limits_{x \in D}\lbrace f(x)+\sum\limits_{i=1}^m \lambda_i h_i(x)+\sum\limits_{j=1}^n \mu_jg_j(x) \rbrace<br>\end{aligned}<br>$$</p><p>若$\hat{x} \in D$是约束问题可行域的点,则对任意的$\mu \geq 0$和$\lambda$都有$\sum\limits_{i=1}^m \lambda_i h_i(x) + \sum\limits_{j=1}^n\mu_j g_j(x) \leq 0$</p><p>进而有</p><p>$$\Gamma(\lambda,\mu)=\inf\limits_{x \in D}L(x,\lambda,\mu) \leq L(\hat{x},\lambda,\mu) \leq f(\hat{x})$$</p><p>若对上面约束优化问题的最优值为$p^*$,则对任意$\mu \geq 0$和$\lambda$都有</p><p>$$\Gamma(\lambda,\mu)\leq p^*$$</p><p>对偶函数的最大值对应着原来约束条件优化问题的最大值,也就是说对偶问题能给主问题最优值的下界。</p><p>那么对偶函数能获得的最好的下界是什么呢?</p><p>$$\max\limits_{\lambda,\mu}\ \Gamma(\lambda,\mu)\ s.t. \ \mu \geq 0$$</p><p>这就是原来约束问题对应的对偶问题,$\mu,\lambda$叫对偶变量。为了方便,我们把它称为对偶式,原来约束问题称为原式。</p><h2 id="强弱对偶">强弱对偶</h2><p>假设对偶式的最优值为$d^<em>$,显然有$d^</em> \leq p^<em>$,这称为弱对偶性,如果$d^</em> = p^*$,称为强对偶性。</p><p>如果主问题为凸优化问题(例如原式中$f(x),g_j(x)$都是凸函数,$h_i(x)$是仿射函数),且可行域中至少有一点使不等式约束严格成立,此时强对偶成立。</p><p>强对偶下,将拉格朗日函数分别对原变量和对偶变量求导,再令导数为零,即可得到原变量与对偶变量的数值关系。</p>]]></content>
<summary type="html">
<h1 id="对偶问题">对偶问题</h1><p>再来看不等式约束优化问题:</p>
<p>$$<br>\begin{aligned}<br>&amp;\min\limits_{x} \ f(x)\\<br>&amp;s.t.\ \ h_i(x)=0,\ i=1,2,…,m\\<br>&amp;g_j(x) \leq 0,\ j=1,2,…,n\\<br>\end{aligned}<br>$$</p>
<hr>
<p>定义Lagrange如下:<br>$$<br>L(x,\lambda,\mu)=f(x)+\sum\limits_{i=1}^m\lambda_ih_i(x)+\sum\limits_{j=1}^n\mu_jg_j(x)<br>$$</p>
<p>在优化理论中,目标函数 f(x) 会有多种形式:
</summary>
<category term="数学" scheme="http://peihao.space/categories/%E6%95%B0%E5%AD%A6/"/>
<category term="数学" scheme="http://peihao.space/tags/%E6%95%B0%E5%AD%A6/"/>
</entry>
<entry>
<title>乘子与KKT</title>
<link href="http://peihao.space/2017/03/16/lagrange-kkt/"/>
<id>http://peihao.space/2017/03/16/lagrange-kkt/</id>
<published>2017-03-16T06:22:09.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="拉格朗日乘子法">拉格朗日乘子法</h1><p>拉格朗日乘子法(Lagrange multipliers)是一种寻找多元函数在一组约束下的极值的方法。通过引入拉格朗日乘子,可将有$d$个变量与$k$个约束条件的最优化问题转化为具有$d+k$个变量的无约束优化问题求解</p><p>基本的拉格朗日乘子法就是求函数$f(x_1,x_2,…)$在$g(x_1,x_2,…)=0$的约束条件下的极值的方法。主要思想是将约束条件与原函数联系在一起,使能配成与变量数量相等的等式方程,从而求得原函数极值的各个变量的解。</p><hr><p>例子:假设需要求极值的目标函数为$f(x)$,约束条件为$\phi(x,y)=M$<br><a id="more"></a><br>设$g(x,y)=M-\phi(x,y)$,定义一个新函数$F(x,y,\lambda)=f(x,y)+\lambda g(x,y)$</p><p>求偏导:</p><p>$$<br>\begin{cases}<br>&\frac{\partial F}{\partial x}=0 \\<br>&\frac{\partial F}{\partial y}=0\\<br>&\frac{\partial F}{\partial \lambda}=0<br>\end{cases}<br>$$</p><p>求出$x,y,\lambda$的值,代入即可得到目标函数的极值。</p><hr><p>机器学习中的拉格朗日乘子法,一般用于求解约束优化问题的方法,当目标函数是凸函数时,求解最小值,使用拉格朗日乘子法求得的局部最优解就是全局最优解。类似的,在凹函数中,求得的最大值,局部最大解就是全局最大解。</p><p>在没有约束条件下,直接使用求导取指即可,但是有了约束条件后,就不能这样任意的小了,需要首先满足约束条件之后再求解。</p><p>在二维空间中求解,假设约束条件是一个曲线:<img src="http://peihao.space/img/article/ml/ml-intro10-3.png" alt=""></p><p>环线是目标函数的取值的等高线,需要紧贴约束线来满足约束条件求得理想值。</p><p>图中可以很清晰的看出来,与约束条件相切的等高线正合适。至于其他的与约束条件曲线相切的都不能考虑,因为这种取值一部分是符合约束条件的,一部分不能满足约束条件。</p><p>曲线相切,实际上就是法线向量平行,同方向或者反方向。最优解处,f和g的斜率平行。也就是说,存在一个非零实数与其中一个斜率相乘,等于另外一个曲线的斜率。这个实数称之为$\lambda$,或者$-\lambda$随便啦</p><p>$\nabla[f(x,y)+\lambda(g(x,y)-c)]=0$</p><p>一旦求出λ的值,将其套入下式,易求在无约束极值和极值所对应的点。</p><p> $F \left( x , y \right) = f \left( x , y \right) + \lambda \left( g \left( x , y \right) - c \right)$</p><p>新方程$F(x,y)$在达到极值时与$f(x,y)$相等,因为$F(x,y)$达到极值时$g(x,y)-c$总等于零。</p><p>定义拉格朗日函数:$L(x,\lambda)=f(x)+\lambda g(x)$ 将其对$x$的偏导数$\nabla_xL(x,\lambda)$置零即得式子$\nabla f(x)+\lambda g(x)=0$;同时对$\lambda$的偏导数$\nabla_{\lambda}L(x,\lambda)$置零即得约束条件$g(x)=0$。所以原约束问题转换成了对拉格朗日函数$L(x,\lambda)$的无约束优化问题。</p><h1 id="KKT">KKT</h1><p><img src="http://peihao.space/img/article/ml/ml-intro10-4.png" alt=""></p><blockquote><p><a href="http://www.cnblogs.com/sddai/p/5730116.html" target="_blank" rel="external">KKT</a></p></blockquote><p>现在考虑不等式$g(x) \leq 0$,如上图,此时最优点$x$或者在$g(x)<0$也就是环形区域内;或者在$g(x)=0$环形线上。</p><p>对于$g(x)<0$的情况,约束$g(x) \leq 0$不起作用,可以直接通过条件$\nabla f(x)=0$来获得最优点,这里等价于将$\lambda=0$之后求解$\nabla _x L(x,\lambda)=0$</p><p>$g(x)=0$的情况类似与上图左侧,但是有一些区别。在拉格朗日乘子中,约束条件$g(x)$与$f(x)$保持梯度平行即可,可就是说参数$\lambda$无关正负;到了这里,我们好好分析一下,假设两者的梯度是同方向的,都是向外(就是环线区域外,相反方向当然也可以)。我们都知道,函数是按沿着梯度方向增大,所以$f(x)$在区域外的值是大于区域内的值,也就是说,区域内的值是小值。我们的目标就是在约束条件下求$\min f(x)$,这里区域内是满足约束条件的,所以最优值显然不在环线上取,而是在区域内取。如果我们非要在环线上取怎么办?两个函数的梯度方向相反。这样才符合我们的认知嘛,梯度相反,同一个方向一个变小一个变大,环线是临界值,很符合人们的罗辑思维。</p><p>接着说不等式约束条件,整合上面的两种情况:</p><ul><li>$g(x)<0$,约束条件不起作用,使$\lambda=0$</li><li>$g(x)=0$,约束条件使得$\lambda > 0$</li></ul><p>所以必有$\lambda g(x)=0$</p><p>KKT条件推出来了:</p><p>$$<br>\begin{cases}<br>&g(x) \leq 0;\\<br>&\lambda \geq 0;\\<br>&\mu_jg_j(x)=0;\\<br>\end{cases}.<br>$$</p><h1 id="推广">推广</h1><p>推广到多个约束,考虑有m个等式约束和n个不等式约束,优化问题<br>$$<br>\begin{cases}<br>&\min\limits_x f(x)\\<br>&s.t. h_i(x)=0 \ \ (i=1,…,m),\\<br>&g_j(x) \leq 0 \ \ (j=1,…,n).\\<br>\end{cases}<br>$$</p><p>引入拉格朗日乘子$\lambda=(\lambda_1,\lambda_2,…,\lambda_m)^T$和$\mu=(\mu_1,\mu_2,…,\mu_n)^T$,相应的拉格朗日函数为<br>$$<br>L(x,\lambda,\mu)=f(x)+\sum\limits_{i=1}^m\lambda_ih_i(x)+\sum\limits_{j=1}^n\mu_jg_j(x)<br>$$</p><p>引入的拉格朗日乘子条件与KKT条件为:</p><p>$$<br>\begin{cases}<br>&h_i(x)=0;\\<br>&\lambda_i \neq 0;\\<br>&g_j(x) \leq 0;\\<br>&\mu_j \geq 0;\\<br>&\mu_jg_j(x)=0.\\<br>&\end{cases}<br>$$</p>]]></content>
<summary type="html">
<h1 id="拉格朗日乘子法">拉格朗日乘子法</h1><p>拉格朗日乘子法(Lagrange multipliers)是一种寻找多元函数在一组约束下的极值的方法。通过引入拉格朗日乘子,可将有$d$个变量与$k$个约束条件的最优化问题转化为具有$d+k$个变量的无约束优化问题求解</p>
<p>基本的拉格朗日乘子法就是求函数$f(x_1,x_2,…)$在$g(x_1,x_2,…)=0$的约束条件下的极值的方法。主要思想是将约束条件与原函数联系在一起,使能配成与变量数量相等的等式方程,从而求得原函数极值的各个变量的解。</p>
<hr>
<p>例子:假设需要求极值的目标函数为$f(x)$,约束条件为$\phi(x,y)=M$<br>
</summary>
<category term="数学" scheme="http://peihao.space/categories/%E6%95%B0%E5%AD%A6/"/>
<category term="数学" scheme="http://peihao.space/tags/%E6%95%B0%E5%AD%A6/"/>
</entry>
<entry>
<title>半监督学习</title>
<link href="http://peihao.space/2017/03/13/ml-semi-supervised/"/>
<id>http://peihao.space/2017/03/13/ml-semi-supervised/</id>
<published>2017-03-13T11:17:14.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="主动学习与半监督">主动学习与半监督</h1><p>假设我们有训练样本集$D_l={ (x_1,y_1),(x_2,y_2),…,(x_l,y_l) }$,l个样本的类别标记已知,称为有标记(labeled);此外还有$D_u={ x_1,x_2,…,x_u },l \ll u$,这u个样本样本的类别标记未知,称为未标记的unlabeled样本。</p><p>若直接使用之前一直介绍的监督学习,则仅有$D_l$能用于构建模型,剩余的未标记样本都浪费了;另一方面远小于u数量的标记样本往往由于训练样本不足,学得模型的泛化能力往往不佳。<br><a id="more"></a></p><h2 id="主动学习">主动学习</h2><p>一个做法是用$D_l$先训练一个模型,使用这个模型在$D_u$中拿一个模型出来,寻求专家知识,判定结果,然后把这个新标记的样本加入到$D_l$中重新训练一个模型,然后再去$D_u$中获取一个新的未标记样本。。。;如果每次都能挑出来对改善模型性能帮助大的瓜,则只需要询问专家较少的次数就能构建出较强的模型,大幅度的降低标记成本。称为主动学习(active learning),其目标是使用尽量少的查询获取尽量好的性能。</p><h2 id="半监督学习">半监督学习</h2><p>半监督(semi supervised)让学习器不依赖外界交互(针对主动学习的专家经验)、自动的利用未标记样本来提升学习性能。主要是考虑如何利用少量的标注样本和大量的未标注样本进行训练和分类。</p><p>半监督学习进一步可分为纯半监督学习和直推学习。前者假定训练数据中的未标记样本并非待预测的数据,而后者假定学习过程中所考虑的未标记样本是待预测数据,学习目的是在这些未标记样本上获得最优泛化能力。也就是说,纯半监督学习是基于开放世界,希望学得的模型能适用于训练过程中未观测带的数据;直推学习是基于封闭世界假设,仅试图对学习过程中观察到的未标记数据进行预测。<br><img src="http://peihao.space/img/article/ml/ml-intro10-2.png" alt=""></p><h1 id="生成式方法">生成式方法</h1><p>生成模型是半监督学习的一种模型,生成式方法是直接基于生成式模型的方法。此类方法假设所有数据(labeled、unlabeled)都是由同一个潜在的模型生成的,这个假设使得我们能够通过潜在模型的参数将未标记数据与学习目标联系起来,而未标记数据的标记则可看作模型的缺失参数,基于EM算法进行极大似然估计求解。</p><p>给定样本x,其真实类别标记为$y \in Y$,其中$Y = { 1,2,…,N }$为所有可能的类别。假设样本由高斯混合模型生成,且每个类别对应一个高斯混合成分:$p(x)=\sum\limits_{i=1}^N \alpha_i \cdot p(x \mid \mu_i,\sum_i)$</p><p>其中,混合系数$\alpha \geq 0,\sum_{i=1}^N \alpha_i=1;p(x \mid \mu_i,\sum_i)$是样本x属于第i个高斯混合成分的概率;$\mu_i$和$\sum_i$为该高斯混合成分的参数。</p><p>令$f(x) \in Y$表示模型f对x的预测标记,$\Theta \in { 1,2,…,N }$表示样本x隶属的高斯混合成分。由最大化后验概率可知:</p><p>$$<br>f(x)=arg \max\limits_{j \in Y} p(y= j \mid x)<br>=arg \max\limits_{j \in Y} \sum\limits_{i=1}^Np(y=j,\Theta=i \mid x)<br>=arg \max\limits_{j \in Y} \sum\limits_{i=1}^Np(y=j,\Theta=i,x)\cdot p(\Theta =i \mid x)<br>$$</p><p>其中$p(\Theta=i \mid x)=\frac{\alpha_i \cdot p(x \mid \mu_i,\sum_i)}{\sum\limits_{i=1}^N\alpha_i \cdot p(x \mid \mu_i,\sum_i)}$(不涉及样本标记)是样本x由第i个高斯混合成分生成的后验概率,$p(y=j \mid \Theta =i ,x)$是x由第i个高斯混合成分且类别为j的概率。</p><p>给定标记样本集$D_l={ (x_1,y_1),(x_2,y_2),…,(x_l,y_l) }$和未标记样本集合$D_u={ x_{l+1},x_{l+2},…,x_{l+u} },l \ll u l+u=m$假定所有样本独立同分布,且都是由同一个高斯混合模型生成。用极大似然估计法来估计高斯混合模型的参数,使用EM算法。</p><h1 id="半监督SVM">半监督SVM</h1><p>半监督SVM(简称S3VM)是支持向量机在半监督学习上的推广,在不考虑未标记样本时,支持向量机试图找到最大间隔划分超平面,而在考虑未标记样本后,S3VM试图找<strong>能将两类有标记样本分开,且穿过数据低密度区域</strong>的划分超平面。</p><p>简单介绍一下其中最出名的TSVM,针对二分类问题,TSVM考虑对未标记样本进行各种可能的标记指派,然后再所有这些结果中寻求一个在所有样本(包括labeled and unlabeled)上间隔最大化的划分超平面。一旦划分超平面确定,未标记样本最终标记就是预测结果。</p><p>显然上面的思路是利用穷举方法,这样明显效率不高,TSVM在上面再进一步。给定$D_l={(x_1,y_1),(x_2,y_2),…,(x_l,y_l)}$和$D_u={x_{l+1},x_{l+2},…,x_{l+u}},y_i \in {-1,+1},l \ll u,l+u=m$。TSVM的学习目标就是为$D_u$中的样本给出预测标记$\hat{y}=(\hat{y}_{l+1},\hat{y}_{l+2},…,\hat{y}_{l+u}),\hat{y_i} \in {-1,+1}$,使得:$\min\limits_{\omega,b,\hat{y},\xi}\frac{1}{2}\mid\mid \omega \mid\mid_2^2+C_l\sum\limits_{i=1}^l \xi_i +C_u \sum\limits_{i=l+1}^m \xi_i$</p><p>上式中,$(\omega,b)$确定了一个划分超平面;$\xi$为松弛向量,$\xi_i(i=1,2,…,l)$对应于有标记样本,$\xi_i(i=l+1,l+2,…,m)$对应与未标记样本;$C_l,C_u$是由用户指定的用于平衡模型复杂度、有标记样本与未标记样本重要程度的这种参数。</p><p>它使用有标记样本学得一个SVM,然后使用这个SVM对未标记的数据进行标记指派,将SVM预测的结果作为伪标记赋予未标记样本。接下来TSVM找出两个标记指派为异类且很可能发生错误的未标记样本,交换标记,重新求得更新后SVM的划分超平面和松弛向量(在这一步中,因为SVM求得的伪标记往往是不准确的,所以需要设置好$C_l,C_u$,将$C_l$值大一点,标明有标记样本的作用更大);然后再找两个标记指派为异类且很可能发生错误的未标记样本,交换。。标记指派完成后逐渐提高未标记样本对优化目标的影响,进行下一轮标记指派调整。。直到$C_u=C_l$</p><h1 id="图半监督">图半监督</h1><p>思想:相似或者相关联的顶点尽可能的赋予相同标记连接,以保证图的标记尽可能的平滑。相似性或者关系度越高,连接的权值越大。</p><p>定义相似矩阵$W=(w_{ij})_{(l+u)\times(l+u)},w_{ij}=exp(-\frac{\mid\mid x_i-x_j \mid\mid^2}{2\sigma^2})\ if\ e=(x_i,e_j) \in E\ else\ 0$其中$\sigma$是带宽系数,用于控制权值的减缓程度。$w_{ij}$随着欧式距离的增加会减少。</p><p>标记传递算法:已标记数据$Rightarrow$近邻未标记数据$Rightarrow$次级近邻未标记数据</p><h1 id="协同训练">协同训练</h1><p>协同训练(co-training)使用多学习器,学习器之间的分歧对未标记数据的利用很重要。</p><p>一个数据对象往往同时拥有多个属性集,每个属性集构成一个视图。假设不同的试图有相容性,即其包含的关于输出空间的信息是一只的,当两个一起考虑就会有大概率使得与真实标记接近。不同视图信息的互补性会给学习器的构建带来很多便利。</p><p>协同训练正是使用了多视图的相容互补性,假设数据有两个充分且条件独立视图。充分是指每个视图都包含足以产生最优学习器的信息,条件独立则是指在给定类别的标记下两个视图独立。协同训练使用下面的策略使用未标记数据:首先在每个视图上基于有标记样本分别训练出一个分类器,然后让每个分类器分别去挑选自己最有把握的未标记样本赋予伪标记,并将伪标记样本提供给另一个分类器作为新增的有标记样本用于训练更新。。。之后就是不断的过程迭代,直到分类器不再更新。</p><p>协同学习也可以在单视图上使用,例如使用不同的学习方法、不同的数据采样、甚至不同的参数设置。</p><h1 id="半监督聚类">半监督聚类</h1><p>聚类是一种典型的无监督学习任务,不过我们通常能够获取一些额外的信息:必连与勿连信息,即两个样本一定属于一个label、一定不属于一个label;第二种就是获得少量的有标记样本。</p>]]></content>
<summary type="html">
<h1 id="主动学习与半监督">主动学习与半监督</h1><p>假设我们有训练样本集$D_l={ (x_1,y_1),(x_2,y_2),…,(x_l,y_l) }$,l个样本的类别标记已知,称为有标记(labeled);此外还有$D_u={ x_1,x_2,…,x_u },l \ll u$,这u个样本样本的类别标记未知,称为未标记的unlabeled样本。</p>
<p>若直接使用之前一直介绍的监督学习,则仅有$D_l$能用于构建模型,剩余的未标记样本都浪费了;另一方面远小于u数量的标记样本往往由于训练样本不足,学得模型的泛化能力往往不佳。<br>
</summary>
</entry>
<entry>
<title>特征选择/稀疏学习</title>
<link href="http://peihao.space/2017/03/12/ml-feature-chosen/"/>
<id>http://peihao.space/2017/03/12/ml-feature-chosen/</id>
<published>2017-03-12T08:10:23.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="范数">范数</h1><ul><li>$L_0$范数表示向量中非零元素的个数:$\mid\mid x \mid\mid_0 = count(x_i) while x_i \neq 0$</li></ul><p>使用这个范数希望参数的大部分元素是0(稀疏数据),通过最优化范数,可以寻找最优稀疏特征,不过这个范数的最优问题是NP难度。</p><ul><li>$L_1$范数表示向量中每个元素绝对值的和:$\mid\mid x \mid\mid_1=\sum_{i=1}^n \mid x_i \mid$</li></ul><a id="more"></a><p>$L_1$范数是$L_0$范数的最优凸优化,常用$L_1$代替$L_0$范数。</p><ul><li><p>$L_2$范数即欧式距离:$\mid\mid x \mid\mid_2=\sqrt{\sum_{i=1}^n x_i^2}$</p></li><li><p>Forbenius范数:$\mid\mid A \mid\mid_F = \sqrt{\sum\limits_{i=1}^m\sum\limits_{j=1}^n \mid a_{ij} \mid^2}$</p></li></ul><h1 id="子图搜索与特征选择">子图搜索与特征选择</h1><p>给定特征集合${a_1,a_2,…,a_d }$,我们可将每个特征看作一个候选子集,对这d个候选单特征子集进行评价,假定$a_2$最优,于是将$a_2$作为第一轮的选定集;然后,在上一轮的选定集中加入一个特征,构成包含两个特征的候选子集,假定在这d-1个候选两特征子集中$(a_2,a_4)$最优,且优于$(a_2)$,于是将$(a_2,a_4)$作为本轮的选定集;</p><p>……假定在第it+1轮时,最优的候选(k+1)特征子集不如上一轮的选定集,则停止生成候选子集,并将上一轮选定的k特征集合作为特征选择结果.这样逐渐增加相关特征的策略称为“前向”(forward)搜索。</p><p>类似的,若我们从完整的特征集合开始,每次尝试去掉一个无关特征,这样逐渐减少特征的策略称为“后向”(backward)搜索.还可将前向与后向搜索结合起来,每一轮逐渐增加选定相关特征(这些特征在后续轮中将确定不会被去除同时减少无关特征,这样的策略称为“双向”(bidirectional)搜索.</p><p>常见的特征选择方法大致分为三类,过滤式、包裹式和嵌入式。</p><h1 id="过滤式">过滤式</h1><p>过滤式先对数据集进行特征选择,然后再训练学习器,特侦选择过程与后续学习器无关。这相当于先用特征选择过程对初始特征进行过滤,再用过滤后的特征来训练模型。</p><h2 id="Relif">Relif</h2><p>过滤式特征选择方法,方法设计了一个相关统计量度量特征的重要性。统计量是一个向量,每个向量分别对应与一个初始特征,而特征子集的重要性则是由子集中每个特征对应的相关统计量分量之和决定。</p><p>过滤的方法就是设定一个阈值$\tau$,选择比$\tau$大的相关统计量分量对应的特征即可。</p><p>给定训练集${(x_1,y_1),(x_2,y_2),…,(x_m,y_m)}$,对每个示例$x_i$,算法先在$x_i$的同类样本中寻找其最近邻$x_{i,nh}$,称为猜中近邻,再从$x_i$的异类样本中寻找其最近临$x_{i,nm}$,称为猜错近邻,然后相关统计量对应于属性j的分量为:$\delta^j=\sum\limits_i -diff(x_i^j,x_{i,nh}^j)^2+diff(x_i^j,x_{i,nm}^j)^2$</p><p>其中$x_a^j$表示样本$x_a$在属性j上的取指,若属性j为离散型,则$diff(x_a^j,x_b^j)=0 if x_a^j==x_b^j else 1$,若是连续型,$diff(x_a^j,x_b^j)=\mid x_a^j-x_b^j \mid$</p><p>若$x_i$与其猜中近邻在属性j上的距离小于$x_i$与其猜错近邻的距离,则说明属性j对区分同类与异类样本是有益的,则增大属性j对应的统计分量。</p><h1 id="包裹式选择">包裹式选择</h1><p>包裹式特征选择直接把最终将要使用的学习器性能作为特征子集的评价准则。</p><p>从最终学习性能来看,包裹式选择比过滤式更好,然而需要的开销要大得多。</p><h2 id="LVM">LVM</h2><p>使用随机策略进行子图搜集,并以最终分类器的误差作为特征子集的评价准则。随机搜索,每次都要进行学习,交叉验证的结果作为误差标准比较,所以开销比较大。</p><h1 id="嵌入式选择">嵌入式选择</h1><p>嵌入式特征选择是将特征选择过程与学习器训练过程融为一体,两者在同一个优化过程中完成,即在学习器训练过程中自动的进行了特征选择。</p><p>给定数据集$D={(x_1,y_1),(x_2,y_2),…,(x_m,y_m)}$,我们考虑最简单的线性回归模型,以平方误差为损失函数:</p><p>$\min\limits_{\omega} \sum\limits_{i=1}^m (y_i-\omega^Tx_i)^2$</p><p>当样本特征很多,样本数目较少时,容易陷入过拟合,此时需要加入正则化项:</p><p>$\min\limits_{\omega} \sum\limits_{i=1}^m (y_i-\omega^Tx_i)^2+\lambda\mid\mid \omega \mid\mid_2^2$</p><p>$\min\limits_{\omega} \sum\limits_{i=1}^m (y_i-\omega^Tx_i)^2+\lambda\mid\mid \omega \mid\mid_1^2$</p><p>分别使用了$L_2,L_1$范数,前者能比后者更易于获得稀疏解:求得的$\omega$有更少的非零向量。所以$\omega$取得的稀疏解意味着初始的d个特征中仅有对应着$\omega$的非零分量特征才会出现在最终模型中,于是求解$L_1$范数正则化的结果是得到了仅采用一部分初始特征的模型,基于$L_1$正则化的学习方法就是一种嵌入式特征选择方法。</p><h1 id="稀疏表示与字典学习">稀疏表示与字典学习</h1><p>稀疏表达形式对学习任务来说有不少的好处,例如线性的SVM之所以在文本数据上有很好的性能,就是因为文本数据使用上述的字频表示后有高度的稀疏性,使大多数问题变得线性可分。同时稀疏表示可以减少存储空间。</p><p>若给定数据集D是稠密的,普通非稀疏数据,我们需要一个“字典”,将样本转化成为合适的稀疏表示形式,使得模型复杂度降低,称为字典学习或者稀疏编码。</p><p>字典学习侧重于学得字典的过程;稀疏编码偏重对样本进行稀疏表达的过程。</p><p>给定数据集(训练集)${x_1,x_2,…,x_m}$,字典学习最简单的形式为$\min\limits_{B,\alpha_i}\sum\limits_{i=1}^m \mid\mid x_i-B\alpha_i \mid\mid_2^2 +\lambda\sum\limits_{i=1}^m \mid\mid \alpha_i \mid\mid_1$</p><p>前面的部分是最小化训练样本与学习的字典学习模型之间的误差,后面则是字典学习模型的$L_1$范数,即寻找稀疏数据。</p><p>其中B为字典矩阵,k为字典词汇量,由用户设定,$\alpha_i \in R^k$是样本$x_i \in R^d$的稀疏表示。</p><p>因为这里我们需要对B和%\alpha%进行学习,我们使用变量交替优化的策略求解。</p><ul><li>固定字典B,我ie每个样本$x_i$找到相应的$\alpha_i$</li></ul><p>$\min\limits_{\alpha_i} \mid\mid x_i-B\alpha_i \mid\mid_2^2 + \alpha\mid \alpha_i \mid_1$</p><ul><li>固定$\alpha_i$来更新字典B,此时原式改为了$\min\limits_{B}\mid\mid X-BA \mid\mid_F^2$</li></ul><p>其中$A=(\alpha_1,\alpha_2,…,\alpha_m)$,</p><p>初始化字典B后,迭代这两步,通过设置k的数值控制稀疏程度。</p><h1 id="压缩感知">压缩感知</h1><p>压缩感知关注的是如何利用信号本身所具有的稀疏性,从部分观测样本中恢复原信号。通常认为压缩感知分为:感知测量和重构恢复两个阶段。前者关注如何对原始信号进行处理以获得稀疏样本表示,这方面技术包括傅里叶变换、小波变换以及字典学习和稀疏编码;重构恢复则主要针对基于稀疏性从少量观测中恢复原信号,这部分是压缩感知的核心。</p>]]></content>
<summary type="html">
<h1 id="范数">范数</h1><ul>
<li>$L_0$范数表示向量中非零元素的个数:$\mid\mid x \mid\mid_0 = count(x_i) while x_i \neq 0$</li>
</ul>
<p>使用这个范数希望参数的大部分元素是0(稀疏数据),通过最优化范数,可以寻找最优稀疏特征,不过这个范数的最优问题是NP难度。</p>
<ul>
<li>$L_1$范数表示向量中每个元素绝对值的和:$\mid\mid x \mid\mid_1=\sum_{i=1}^n \mid x_i \mid$</li>
</ul>
</summary>
<category term="ML" scheme="http://peihao.space/categories/ML/"/>
<category term="ML" scheme="http://peihao.space/tags/ML/"/>
</entry>
<entry>
<title>周报(1)</title>
<link href="http://peihao.space/2017/03/10/week-report310/"/>
<id>http://peihao.space/2017/03/10/week-report310/</id>
<published>2017-03-10T04:00:13.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="周报3-10">周报3.10</h1><p>这次周报,主要回顾从周一下午在公司开完会回来后的工作情况以及状态。</p><h2 id="状态">状态</h2><ul><li>时间:由于每天坚持健身锻炼,以及在临睡前习惯的观看某栏目的逻辑思维导论,拖拖拉拉的晚上会睡的比较迟。早上也是醒的蛮晚。这些习惯会在月底前的一周里改正。</li></ul><a id="more"></a><ul><li>地点:现在每天宿舍里空调打孔,噪音比较大。除了早上在寝室学习之外,之前没在实验室的会议室学习前,都会到教三的三楼自习。周二开始在保密会议室内学习,晚上九点半离开。</li></ul><ul><li>效率:工作效率方面,白天的学习效率很低,经常会被外界的环境影响;在封闭的实验室内效率提高不少,特别是晚上六点之后。deadline是第一生产力,那个时候开始有时间危机,想着不能又白白浪费一天时间,逐渐不去理会外界干扰。同时在会议室的办公桌上可以使用外接的大屏显示器辅助工作,感觉很棒。</li></ul><h2 id="工作情况">工作情况</h2><p>目前是三月份,导师要我们9月份之前确定论文的题目,留给我们几乎半年的时间。所以这一阶段的前几十天我主要目标是在导师的指引下,在自己感兴趣的、或者认为有前景的领域粗粗的学一学,领略一番,期望遇到自己有深入进去欲望的方向、点。</p><p>最近一直在看南大周教授的《机器学习》和李航老师的《统计学习方法》。第一遍读不求甚解,没有公示的推倒,只是在顺着作者的思路学习,目的就是了解这一领域的基础知识、原理与技术。</p><p>两本书都对数学有一定的要求。上学期的《概率论与随机过程》课程中的部分章节在这里派上了用场,但是还有一些需要用到本科时的内容,包括《概率论与数理统计》、《线性代数》甚至《高级数学》。由于我没有参加统考,没有对这几门课程有系统的复习,几年过去,说实话遗忘了很多。类似协方差$Cov(\vec{x},\vec{y})$,特征值$\lambda$,矩阵的秩、迹、线性空间、欧氏空间、超平面等等很多定义、用法都要用到。这些有的是我学过还记得,有的学过忘掉了,还有部分没有接触过的,往往一个书上式子的理解都需要很长时间。不过嘛,这是我必经的路。前天听了同学的介绍,准备在网络上听一些课程,期望有所好转。</p><p>这期间开始使用latex。</p><p>周四,也就是昨天参加了在《中欧在5G及物联网领域的合作》会议。主要内容就是5G的最新进展以及物联网领域的突飞猛进。会议基本以英文演说为主,很多由于英文水平有限没有很好的理解,不过几个突出表达的新技术名词记录下来,回来查看资料还是大开眼见。几个关键词:光通信LIFI、AIOTI物联网组织、ICT合作。</p><p>昨天拿到了上届学长学姐的开题报告,到写周报前,只是把题目、时间安排简单的浏览了一下。</p>]]></content>
<summary type="html">
<h1 id="周报3-10">周报3.10</h1><p>这次周报,主要回顾从周一下午在公司开完会回来后的工作情况以及状态。</p>
<h2 id="状态">状态</h2><ul>
<li>时间:由于每天坚持健身锻炼,以及在临睡前习惯的观看某栏目的逻辑思维导论,拖拖拉拉的晚上会睡的比较迟。早上也是醒的蛮晚。这些习惯会在月底前的一周里改正。</li>
</ul>
</summary>
<category term="周报" scheme="http://peihao.space/categories/%E5%91%A8%E6%8A%A5/"/>
<category term="周报" scheme="http://peihao.space/tags/%E5%91%A8%E6%8A%A5/"/>
</entry>
<entry>
<title>降维</title>
<link href="http://peihao.space/2017/03/09/ml-dimension-reduction/"/>
<id>http://peihao.space/2017/03/09/ml-dimension-reduction/</id>
<published>2017-03-09T02:36:28.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="k近邻学习">k近邻学习</h1><p>k近邻(k-Nearest Neighboor,KNN)是一种常用的监督学习方法:给定测试样本,基于某种距离距离度量找出训练集中与其最靠近的k个训练样本,然后基于这k个训练样本的信息对本样本进行预测。分类学习中通常使用投票法,少数服从多数;回归学习中则使用平均法。通常为了体现出靠近的距离指标,在分类学习与回归学习中使用加权法,越靠近样本的权值越大。</p><p>给定测试样本x,若其最近邻样本为z,则最近邻分类器出错的概率就是x与z类别标记不同的概率:$P(err)=1-\sum\limits_{c \in y}P(c \mid x)P(c \mid z)$</p><a id="more"></a><p>假设样本独立同分布,且对任意x和任意小正数$\delta$,在x附近$\delta$距离范围内找到一个训练样本z;令$c^T=arg \max\limits_{c \in y}P(c \mid x)$表示贝叶斯最优分类器的结果,有:</p><p>$$<br>P(err)=1-\sum\limits_{c \in y}P(c \mid x)P(c \mid z)<br>\approx1-\sum\limits_{c \in y}P^2(c \mid x)<br>\leq 1- P^2(c^T \mid x)<br>=(1+P(c^T \mid x))(1-P(c^T \mid x))<br>\leq 2 \times (1-p(c^T \mid x))<br>$$</p><p>可以看出,在这种理想条件下KNN分类器的泛化错误率不超过贝叶斯错误率的两倍。</p><h1 id="降维">降维</h1><p>上面的讨论的基础是在足够小的距离内都有相邻的样本作为参考,考虑到做个属性(也就是多个维度)的情况,需要的合适的样本数量回事天文数字。高维度空间会给距离计算带来很大麻烦。</p><p><img src="http://peihao.space/img/article/ml/ml-intro9-2.png" alt=""></p><p>一般采用的方式是通过某种数学变换将原始高维属性空间转变为一个低维子空间。子空间中样本密度大幅提升。</p><p><img src="http://peihao.space/img/article/ml/ml-intro9-1.png" alt=""></p><h2 id="MDS">MDS</h2><p>MDS即多维缩放(Multiple Dimensional Scaling),是要就将原始空间中样本间的距离在低维空间中得以保持。</p><p>假定m个样本在原始空间的距离矩阵为$D \in R^{m \times m}$,在第i行j列的元素$dist_{ij}$为样本$x_i$到$s_j$的距离。目标是获得样本在$d^c$维空间的表示$Z \in R^{d^c \times m},d^c \leq d$,且任意两个样本在$d^c$维空间的欧式距离等于原始空间$\mid\mid z_i-z_j \mid\mid = dist_{ij}$</p><p>令$B=Z^TZ \in R^{m \times m}$,其中B为降维后样本的内积矩阵,$b_{ij}=b_{ji}=z_i^Tz_j$</p><p>$$<br>dist_{i.}^2=\frac{1}{m}\sum\limits_{j=1}^m dist_{ij}^2<br>dist_{.j}^2=\frac{1}{m}\sum\limits_{i=1}^m dist_{ij}^2<br>dist_{..}^2=\frac{1}{m^2}\sum\limits_{i=1}^m\sum\limits_{j=1}^m dist_{ij}^2<br>$$</p><p>由以上的式子推出:</p><p>$b_ij=-\frac{1}{2}(dist_{ij}^2-dist_{i.}^2-dist_{.j}^2+dist_{..}^2)$</p><p>依次求出矩阵B中所有的元素,然后对矩阵做特征值分解:$B=V\Lambda V^T$其中V为特征向量矩阵,$\Lambda$为特征值构成的对角矩阵。假定其中有$d^c$个非零特征值,构成对角矩阵$\Lambda_x=diag(\lambda_1,\lambda_2,…,\lambda_{dx})$,令$Vx$表示相应的特征向量矩阵,则:</p><p>$Z=\Lambda_c^{1/2}V_c^T \in R^(d^c \times m)$</p><h1 id="主成分分析">主成分分析</h1><p>通过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量,转换后的这组变量叫主成分。</p><p>主成份(Principal Component Analysis)分析是降维(Dimension Reduction)的重要手段。每一个主成分都是数据在某一个方向上的投影,在不同的方向上这些数据方差Variance的大小由其特征值(eigenvalue)决定。一般我们会选取最大的几个特征值所在的特征向量(eigenvector),这些方向上的信息丰富,一般认为包含了更多我们所感兴趣的信息。</p><blockquote><p>在很多情形,变量之间是有一定的相关关系的,当两个变量之间有一定相关关系时,可以解释为这两个变量反映此课题的信息有一定的重叠。主成分分析是对于原先提出的所有变量,将重复的变量(关系紧密的变量)删去多余,建立尽可能少的新变量,使得这些新变量是两两不相关的,而且这些新变量在反映课题的信息方面尽可能保持原有的信息。</p></blockquote><p>设法将原来变量重新组合成一组新的互相无关的几个综合变量,同时根据实际需要从中可以取出几个较少的综合变量尽可能多地反映原来变量的信息的统计方法叫做主成分分析或称主分量分析,是数学上用来降维的一种方法。</p><p>先定义一些变量:</p><p>样本$(\vec{x_1},\vec{x_2},\vec{x_3},…,\vec{x_m})$</p><p>投影变换得到的 <strong>新坐标系</strong>${ \vec{\omega_1},\vec{\omega_2},…,\vec{\omega_d}, }$</p><p>样本点在低维坐标系中的投影是$z_i=(z_{i1};z_{i2};z_{i3};…;z_{id_‘};)$</p><p>其中$z_{ij}=\vec{\omega}_j^T\vec{x_i}$是x在低维坐标系下的第j维坐标</p><p>投影点方差是$\sum_i W^Tx_ix_i^TW$ 优化目标是最大化这个方差,使得在投影之后尽可能的分散</p><p>PCA一般有以下几个步骤:</p><ol><li><p>数据减去均值:样本中心化$\sum_i \vec{x_i}=\vec{0}$</p></li><li><p>计算协方差矩阵:$C=\frac{XX^T}{N}$</p></li><li><p>计算协方差矩阵的特征矢量和特征值:对协方差矩阵$\frac{XX^T}{N}$特征分解$CU=U\Lambda$,其中C为方差矩阵,U为计算的特征矢量,$\Lambda$是对角线矩阵$\Lambda=diag(\lambda_1,\lambda_2,…,\lambda_d)$</p></li><li><p><strong>选择成分组成模式矢量</strong>对应最大特征值的特征矢量就是数据的主成分:取最大的d个特征值所对应的特征向量$u_1,u_2,…,u_d$</p></li></ol><p>一般地,从协方差矩阵找到特征矢量以后,下一步就是按照特征值由大到小进行排列,这将给出成分的重要性级别。现在,如果你喜欢,可以忽略那些重要性很小的成分,当然这会丢失一些信息,但是如果对应的特征值很小,你不会丢失很多信息。</p><ol><li>获得投影的新数据$y_i=U_k^T x_i$</li></ol><h1 id="核化线性降维">核化线性降维</h1><p>线性降维假设从高维空间到低维度空间的函数映射是线性的,然而在不少的现实任务中,可能需要非线性映射才能找到恰当的低维嵌入。</p><p>非线性降维的一种常用方法是基于核技巧对线性降维方法进行”核化”。</p><blockquote><p><a href="http://zhanxw.com/blog/2011/02/kernel-pca-%E5%8E%9F%E7%90%86%E5%92%8C%E6%BC%94%E7%A4%BA/" target="_blank" rel="external">在KPCA中</a>,除了在PCA中的一些先决条件外,我们认为原有的数据有更高的维数,我们可以在更高的维度空间中做PCA分析(即在更高维里,把原始数据向不同方向进行投影)</p></blockquote><p>我们拿到样本点,需要将它映射到高维空间中,然后使用PCA算法进行降维。</p><p>假定我们将在高维特征空间中把数据投影到由W确定的超平面上,即PCA欲求解$(\sum\limits_{i=1}^m)\vec(W)=\lambda \vec{W}$ (拉格朗日乘子法)</p><p>其中$z_i$是样本点在高维特征空间的像,有$\vec{W}=\sum\limits_{i=1}^m z_i \alpha _i$</p><p>$\alpha_i=\frac{1}{\lambda}z_i^T \vec{W}$</p><p>z是由原始属性空间中的样本点x通过映射$\phi$产生。但是在映射到高维空间这一步,一般情况下,我们并不知道映射函数$phi$的具体形,不知道要映射到哪重维度上,于是引入核函数$\kappa(x_i,x_j)=\phi(x_i)^T\phi(x_j)$</p><p>化简式子:$KA=\lambda A$,K为$\kappa$对应核矩阵,$A=(\alpha_1;\alpha_2;…;\alpha_m)$</p><p>上式是特征值分解问题,取K对应的最大的d个特征值对应的特征向量。</p><p>对于新样本x,投影的第j维坐标为$z_j=\omega_j^T \phi(x)=\sum\limits_{i=1}^m \alpha_i^j \kappa(x_i,x)$</p><h1 id="流形学习">流形学习</h1><p>流形是一类借鉴了拓扑流形概念的降维方法,在局部有欧式空间的性质,能用欧式距离来进行距离计算。</p><p>若低维流形嵌入到高维空间中,则数据样本在高维空间的分布虽然看上去非常复杂,但在局部上仍具有欧式空间的性质。因此可以容易的在局部建立降维映射关系,然后再设法将局部映射关系推广到全局。</p><h2 id="等度量映射">等度量映射</h2><p>等度量映射(Isometric Mapping)认为低维流形嵌入到高维空间后,直接在高维空间中计算直线距离具有误导性,因为高维空间中的直线距离往往在低维嵌入流形上是不可达的。</p><p><img src="http://peihao.space/img/article/ml/ml-intro9-3.png" alt=""></p><p>对每个点基于欧式距离找出其近邻点,然后就能建立一个近邻连接图,图中近邻点之间存在连接,而非近邻之间不存在连接,于是计算两点间测地线距离的问题,转变为了计算近邻点之间最短路径问题。</p><p>步骤:</p><ol><li><p>确定$x_i$的k近邻,并将$x_i$与k近邻之间的距离设置为欧氏距离,与其他点的距离设置为无穷大</p></li><li><p>调用最短路径算法计算任意来那个样本之间的距离$dist(x_i,dist_j)$</p></li><li><p>将$dist(x_i,dist_j)$作为MDS算法的输入求解</p></li></ol><h2 id="局部线性嵌入">局部线性嵌入</h2><p>局部线性嵌入(Locally Linear Embedding,LEE)试图保持邻域内样本之间的线性关系。假定样本点$x_i$的坐标能通过他的邻域样本$x_j,x_k,x_l$的坐标通过线性组合组成,$x_i=w_{ij}x_j+w_{ik}x_k+w_{il}x_l$</p><p>LLE希望关系在低维空间中得以保持。</p><p><img src="http://peihao.space/img/article/ml/ml-intro9-4.png" alt=""></p><p>LLE算法的主要原理就是先在高维空间,计算出相应的重构系数序列$W={w_1,w_2,…,_m}$,随后在低维空间中通过相同的重构系数获取投影点。</p><p>令$Z=(z_1,z_2,…,z_m) \in R^{d^. \times m}$</p><p>$M = (I-W)^T(I-W)$则寻求最小化:$\min\limits_z tr(ZMZ^T)$,约束条件$ZZ^T=I$</p><p>上式通过特征值分解,M最小的$d^.$个特征值对应的特征向量组成的矩阵就是$Z^T$,即在低维的投影</p><h1 id="度量学习">度量学习</h1><p>对两个d维样本$x_i x_j$,他们之间的平方欧式距离可写为:$dist^2(x_i,x_j)=dist_{ij,1}^2+dist_{ij,2}^2+…+dist_{ij,d}^2$</p><p>其中$dist_{ij,k}$表示$x_i,x_j$在第k维上的距离,若嘉定不同属性的重要程度不一样,可以引入属性权重$\omega$</p><p>$dist^2(w_i,x_j)=\omega_1\cdot dist_{ij,1}^2+\omega_2\cdot dist_{ij,2}^2+…+\omega_d\cdot dist_{ij,d}^2=(x_i-x_j)^T W(x_i-x_j)$</p><p>其中$\omega_i \geq 0,W=diag(\omega)$是一个对角矩阵</p><p>W是对角矩阵,坐标轴正交,属性之间无关;然而现实中并不是这样将W图换位一个普通的半正定对称矩阵M,得到马氏距离。</p><p>其中M称作“度量矩阵”,而度量学习是对M进行学习。M必须是正定对称的,即必有正交基P使得M能写成$M=PP^T$</p><p>对M的学习,我们需要把M直接嵌入到需要提高效率的评价指标中,通过优化指标求得M</p>]]></content>
<summary type="html">
<h1 id="k近邻学习">k近邻学习</h1><p>k近邻(k-Nearest Neighboor,KNN)是一种常用的监督学习方法:给定测试样本,基于某种距离距离度量找出训练集中与其最靠近的k个训练样本,然后基于这k个训练样本的信息对本样本进行预测。分类学习中通常使用投票法,少数服从多数;回归学习中则使用平均法。通常为了体现出靠近的距离指标,在分类学习与回归学习中使用加权法,越靠近样本的权值越大。</p>
<p>给定测试样本x,若其最近邻样本为z,则最近邻分类器出错的概率就是x与z类别标记不同的概率:$P(err)=1-\sum\limits_{c \in y}P(c \mid x)P(c \mid z)$</p>
</summary>
<category term="ML" scheme="http://peihao.space/categories/ML/"/>
<category term="ML" scheme="http://peihao.space/tags/ML/"/>
</entry>
<entry>
<title>聚类</title>
<link href="http://peihao.space/2017/03/08/ml-clustering/"/>
<id>http://peihao.space/2017/03/08/ml-clustering/</id>
<published>2017-03-08T05:18:42.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<p>机器学习可以根据样本是否有标签分类为有监督学习与无监督学习,前面介绍的基本都是有监督学习。无监督学习中,目标通过对无标记训练样本的学习来揭示数据的内在性质及规律。</p><p>聚类试图将数据集中的样本划分为若干个通常不相交的子集,每个子集称为一个簇(cluster)。通过这样的划分,每个簇可能对应与一些潜在的类别。这些类别两两不相交,并起来是整个数据集,聚类的结果就是产生一个标签结果序列。 <a id="more"></a></p><h1 id="性能度量">性能度量</h1><p>对聚类来讲,我们需要通过某种性能来评估聚类效果的好坏;若明确了最终要使用的性能度量,可以直接将其作为聚类过程的优化目标。</p><p>聚类性能度量大致有两类,一类是将聚类结果与某个参考模型进行比较,称为外部指标;另一类是直接考察聚类结果而不利用任何参考模型,称为内部指标。</p><h2 id="外部指标">外部指标</h2><p>对数据集$D={x_1,x_2,…,x_m}$,假定通过聚类给出额簇划分为$C={C_1,C_2,…,C_k}$,参考模型给出的簇划分为$C^`={C_1^T,C_2^T,…,C_s^T}$。相应的,令$\lambda$与$\lambda^T$分别表示与C和$C^T$对应的簇标记向量。注意的是,参考模型给出的划分类别数量不一定等于通过聚类得到的数量。</p><p>样本两两配对:</p><ol><li><p>$a=\mid SS \mid ,SS={(x_i,x_j)\mid \lambda_i = \lambda_j,\lambda_i^T=\lambda_j^T,i<j}$</p></li><li><p>$b=\mid SS \mid ,SD={(x_i,x_j)\mid \lambda_i = \lambda_j,\lambda_i^T\neq \lambda_j^T,i<j}$</p></li><li><p>$c=\mid SS \mid ,DS={(x_i,x_j)\mid \lambda_i \neq \lambda_j,\lambda_i^T=\lambda_j^T,i<j}$</p></li><li><p>$a=\mid SS \mid ,DD={(x_i,x_j)\mid \lambda_i \neq \lambda_j,\lambda_i^T \neq \lambda_j^T,i<j}$</p></li></ol><p>集合SS包含了C中隶属于相同簇且在$C^`$中也隶属于相同簇的样本对,集合SD包含了在C中隶属于相同簇但在$C^T$中隶属于不同簇的样本对</p><ol><li><p>Jaccard系数:$JC=\frac{a}{a+b+c}$</p></li><li><p>FM指数:$FMI=\sqrt{\frac{a}{a+b}\frac{a}{a+c}}$</p></li><li><p>Rand指数:$RI=\frac{2(a+d)}{m(m-1)}$</p></li></ol><p>上述性能度量的结果值均在[0,1]区间,值越大越好。</p><h2 id="内部指标">内部指标</h2><p>考虑聚类结果的簇划分$C={C_1,C_2,…,C_k}$,定义</p><ol><li><p>$avg(C)=\frac{2}{\mid C \mid(\mid C \mid -1)}\sum_{1 \leq i < j \leq \mid C \mid}dist(x_i,x_j)$</p></li><li><p>$diam(C)=\max_{1 \leq i <j \leq \mid C \mid}dist(x_i,x_j)$;</p></li><li><p>$d_\min(C_i,C_j)=\min_{x_i \in C_i , x_j \in C_j} dist(x_i,x_j)$</p></li><li><p>$d_cen(C_i,C_j)=dist(\mu_i,\mu_j)$</p></li></ol><p>上面的式子中,dist计算两个样本之间的距离;$\mu$代表簇的中心点$\mu=\frac{\sum_{1 \leq i \leq \mid C \mid x_i}}{\mid C \mid}$;avg(C)uiying与簇内样本间的平均距离,diam(C)对应与簇C内样本间的最远距离,$d_min(C_i,C<em>j)$对应与簇i和簇j最近样本间的距离;$d</em>{cen}(C_i,C_j)$对应与簇i和j中心点间的距离。</p><p>基于上面的指标,推出下面几个内部指标:</p><ol><li><p>$DBI=\frac{1}{k}\sum\limits_{i=1}^k\max\limits_{j \neq i}(\frac{avg(C_i)+avg(C_j)}{d_{cen}(\mu_i,\mu_j)})$</p></li><li><p>$DI=\min\limits_{1 \leq i \leq k}{ \min\limits_{j \neq i}(\frac{d_{min}(C_i,C_j)}{\max_{1\leq l \leq k diam(C_l)}}) }$</p></li></ol><p>显然,DBI的值越小越好,DI值越大越好</p><h1 id="距离计算">距离计算</h1><p>在讨论距离计算的时候,属性是否定义了”序”关系很重要。例如定义域为${ 1,2,3 }$能直接在属性值上计算距离,这样的属性成为有序属性;而定义域为{ 飞机、火车、轮船 }这样的离散属性则不能直接在属性值上计算距离,称为无序属性。</p><p>对有序属性的距离计算,通常使用Minkowski distance:$dist_{mk}(x_i,x_j)=(\sum\limits_{u=1}^n \mid x_{iu}-x_{ju} \mid^p)^{\frac{1}{p}}$</p><p>对无需属性采用VDM算式:$VDM_p(a,b)=\sum\limits_{i=1}^k\mid \frac{m_{u,a,i}}{m_{u,a}}-\frac{m_{u,b,i}}{m_u,b} \mid ^p$</p><p>其中$m_{u,a} m_{u,a,i}$分别表示在属性u上取值a的样本数以及在第i个样本簇中属性u上取值为a的样本数。k为样本簇数</p><p>混合处理,假定有$n_c$个有序属性以及$n-n_c$个无序属性:</p><p>$MinkorDM_p(x_i,x_j)=(\sum\limits_{u=1}^{n_c}\mid x_{iu}-x_{ju} \mid ^p +\sum\limits_{u=n_c+1}^n VDM_p(x_{iu},x_{ju}))^{\frac{1}{p}}$</p><p>属性重要性不同时,可以加权处理</p><h1 id="原型聚类">原型聚类</h1><p>原型聚类算法假设聚类结构能够通过一组原型刻画,通常情况下算法先对原型进行初始化,然后对原型进行迭代更新。</p><h2 id="k均值算法">k均值算法</h2><p>给定样本集$D={x_1,x_2,…,x_m}$,k均值算法针对聚类所得簇划分${ C_1,C_2,…,C_k }$最小化平方误差。$E=\sum\limits_{i=1}^k\sum\limits_{x \in C_i}\mid\mid x-\mu_i \mid\mid_2^2$</p><p>其中$\mu_i=\frac{\sum_{x \in C_i}\vec{x}}{\mid C_i \mid}$是簇$C_i$的均值向量。上式在一定程度上刻画了簇内样本围绕簇均值向量的紧密吃呢孤独,E值越小则簇内样本相似度越高。k均值采用贪心策略,通过迭代优化来近似求解上式。</p><h2 id="学习向量量化">学习向量量化</h2><p>学习向量量化(LVQ)试图找到一组原型向量来刻画聚类结构,它假设数据样本带有类别标记,学习过程利用样本的这些监督信息来辅助聚类。</p><p>算法首先对原型向量进行优化,然后对原型向量进行迭代优化。在每一轮的迭代中,算法随机选取一个有标记训练样本,找出与其距离最近的原型向量,并根据两者的类别标记是否一致来对原型向量进行更新。</p><p>在更新原型向量上,对样本$x_i$,若最近的原型向量$p_i$与$x_j$的类别标记相同,则令$p_i$向$x_j$方向靠拢;否则更新原型向量与$x_j$之间距离增大,远离$x_j$</p><h2 id="高斯混合聚类">高斯混合聚类</h2><p>统计学习的模型有两种,一种是概率模型,一种是非概率模型。所谓概率模型,是指训练模型的形式是P(Y|X)。输入是X,输出是Y,训练后模型得到的输出不是一个具体的值,而是一系列的概率值(对应于分类问题来说,就是输入X对应于各个不同Y(类)的概率),然后我们选取概率最大的那个类作为判决对象(软分类–soft assignment)。所谓非概率模型,是指训练模型是一个决策函数Y=f(X),输入数据X是多少就可以投影得到唯一的Y,即判决结果(硬分类–hard assignment)。</p><p>高斯混合模型GMM就是指对样本的概率密度分布进行估计,而估计采用的模型(训练模型)就是几个高斯模型的加权和。每个高斯模型代表一个聚类。对样本中的数据分别在几个高斯模型上进行投影,就会分别得到在各个类上的概率,选取概率最大的类作为判决结果。</p><p><code>理论上可以通过增加模型的数量,用GMM近似任何概率分布</code></p><p>混合高斯模型定义:$p(x)=\sum_{k=1}^k \pi_kp(x \mid k)$</p><p>其中k为模型的个数;$\pi_k$为第k个高斯的权重;$p(x\mid k)$则为第k个高斯概率密度,其均值为$\mu_k$,方差为$\theta_k$。对此概率密度的估计就是要求出$\pi_k,\mu_k,\theta_k$。当求出p(x)的表达式后,求和式的各项的结果就分别代表样本x属于各个类的概率。</p><p>在做参数估计的时候,常采用的是最大似然方法。最大似然法就是使样本点在估计的概率密度函数上的概率值最大。由于概率值一般都很小,N 很大的时候, 连乘的结果非常小,容易造成浮点数下溢。所以我们通常取log,将目标改写成:$\max\sum\limits_{i=1}^N log(\sum\limits_{k=1}^K\pi_kN(x_i \mid \mu_k,\theta_k))$</p><p>一般用来做参数估计的时候,我们都是通过对待求变量进行求导来求极值,在上式中,log函数中又有求和,你想用求导的方法算的话方程组将会非常复杂,没有闭合解。可以采用的求解方法是EM算法——将求解分为两步:第一步,假设知道各个高斯模型的参数(可以初始化一个,或者基于上一步迭代结果),去估计每个高斯模型的权值;第二步,基于估计的权值,回过头再去确定高斯模型的参数。重复这两个步骤,直到波动很小,近似达到极值(注意这里是极值不是最值,EM算法会陷入局部最优)。具体表达如下:</p><p>E:对滴i个样本$x_i$来说,它由第k个模型生成的概率为:$\vec{w_i}(k)=\frac{\pi_kN(x_i \mid \mu_k,\theta_k)}{\sum\limits_{j=1}^K \pi_jN(x_i \mid \mu_j,\theta_j)}$</p><p>在这一步,假设高斯模型的参数是已知的,有上一步迭代而来或者由初始值决定</p><p>M:得到每个点的生成概率以后,对样本$x_i$来说,他的$\vec{w}_i(k)x_i$的值是由第k个高斯模型产生的。换句话说,第k个高斯模型很产生了$\vec{w}_i(k)x_i(i=1……N)$这些数据。这样在估计第k个高斯模型参数时,我们就用$\vec{w}_i(k)x_i(i=1……N)$这些数据去做参数估计:</p><p>$\mu_k=\frac{\sum\limits_{i=1}^N \vec{w}_i (k)x_i}{N}$</p><p>$\theta_k=\frac{\sum\limits_{i=1}^N\vec{w}_i(k)(x_i-\mu_k)(x_i-\mu_k)^T}{N_k}$</p><p>$N_k=\sum\limits_{i=1}^N\vec{w}_i(k)$</p><p>重复E和M知道算法收敛</p><h1 id="密度聚类">密度聚类</h1><ol><li><p>$\epsilon$邻域:对象O的是与O为中心,$\epsilon$为半径的空间,参数$\epsilon > 0$,是用户指定每个对象的领域半径值。</p></li><li><p>MinPts(领域密度阀值):对象的$\epsilon$邻域的对象数量。</p></li><li><p>核心对象:如果对象O的$\epsilon$邻域对象数量至少包含MinPts个对象,则该对象是核心对象。</p></li><li><p>直接密度可达:如果对象p在核心对象q的$\epsilon$邻域内,则p是从q直接密度可达的。</p></li><li><p>密度可达:在DBSCAN中,p是从q(核心对象)密度可达的,如果存在对象链$(p_1,p_2,…,p_n)$,使得$p_1=x_i,p_n=x_j$,且有$p_{i+1}$由$p_i$直接密度直达</p></li><li><p>密度相连:对$x_i$和$x_j$,若存在$x_k$使得$x_i,x_j$均由$x_k$密度可达,则两者密度相连。</p></li></ol><p><img src="http://peihao.space/img/article/ml/ml-intro8-1.png" alt=""></p><p>DBSCAN算法先任选数据集中的一个核心对象为种子,再由此出发确定相应的聚类簇。具体的,现根据给定的邻域参数$(\epsilon,MinPys)$找出所有的核心对象;然后以任意核心对象为出发点,找出由其密度可达的样本生成聚类簇,知道所有核心对象均被访问过为止。</p><h1 id="层次聚类">层次聚类</h1><p>层次聚类试图在不同层次对数据集进行划分,从而形成树形的聚类结构。数据集的划分可采用自底向上的聚合策略,也可选择自顶下下的分析策略。</p><p>AGNES是一种自底向上聚合策略的层次聚合算法。他先将数据集合中每个样本看作一个初始聚类簇,然后再算法运行的每一步中找出距离最近的两个聚类簇合并,该过程不断重复,直至达到预设的聚类簇个数。</p><p>算法的关键是如何找到最近的两个聚类簇,然后不断的进行合并。给定聚类簇$C_i$和$C_j$,通过下面的式子计算距离:</p><p>最小距离: $d_min(C_i,C_j)=\min\limits_{x \in C_,z \in C_j} dist(x,z)$</p><p>最大距离: $d_max(C_i,C_j)=\max\limits_{x \in C_,z \in C_j} dist(x,z)$</p><p>平均距离: $d_avg(C_i,C_j)=\frac{\sum\limits_{x \in C_i}\sum\limits_{z \in C_j}dist(x,z)}{\mid C_i \mid \mid C_j \mid}$</p><p>当使用不同的距离公式作为算法的因数时,算法分别被称为单链接,全连接以及均链接。算法首先对仅含一个样本样本的初始聚类簇和相应的距离矩阵进行初始化;然后不断合并距离最近的聚类簇,并对合并得到的新聚类簇距离矩阵进行更新;不断重复,直到聚类簇数量减少到预设目标。</p>]]></content>
<summary type="html">
<p>机器学习可以根据样本是否有标签分类为有监督学习与无监督学习,前面介绍的基本都是有监督学习。无监督学习中,目标通过对无标记训练样本的学习来揭示数据的内在性质及规律。</p>
<p>聚类试图将数据集中的样本划分为若干个通常不相交的子集,每个子集称为一个簇(cluster)。通过这样的划分,每个簇可能对应与一些潜在的类别。这些类别两两不相交,并起来是整个数据集,聚类的结果就是产生一个标签结果序列。
</summary>
<category term="ML" scheme="http://peihao.space/categories/ML/"/>
<category term="ML" scheme="http://peihao.space/tags/ML/"/>
</entry>
<entry>
<title>集成学习</title>
<link href="http://peihao.space/2017/03/07/ml-integration/"/>
<id>http://peihao.space/2017/03/07/ml-integration/</id>
<published>2017-03-07T05:18:42.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="个体集成">个体集成</h1><p>集成学习通过构建并结合多个学习器来完成学习任务,先产生一组个体学习器,再用某种策略把他们结合起来。个体学习器通常由一个现有的学习算法从训练数据产生。</p><p>同质集成:个体全是相同类型的学习器,称为基学习器</p><p>异质集成:个体可以是不同的学习器,称为组件学习器</p><p>根据个体学习器的生成方式,目前的集成学习方法大致分为两大类,即个体学习器间存在强依赖关系、必须串行生成的序列化方法Boosting;以及不存在强依赖关系,可同时生成的并行化方法Bagging和随机森林。</p><a id="more"></a><p>欲构建泛化能力强的集成,getInstance学习器应该好而不同。</p><h1 id="Boosting">Boosting</h1><p>先从初始训练集中训练一个基学习器,再根据基学习器的表现对训练样本分布进行调整,使得先前基学习器做错的训练样本在后续受到更多关注。然后基于调整后的样本分布来训练下一个基学习器,如此重复进行,直至基学习器数目达到事先制定的值T,最终将这T个基学习器进行加权结合。</p><h2 id="AdaBoost">AdaBoost</h2><p>假设训练数据集具有均匀的权值分布,即每个训练样本在基本分类器的学习中作用相同。</p><p>AdaBoost反复学习基本分类器,在每一轮,=1,2,…,M顺次的执行下面的操作:</p><ol><li><p>使用当前分布$D_m$加权的训练数据集,学习基本分类器$G_m(x)$</p></li><li><p>计算基本分类器$G_m(x)$在加权训练数据集上的分类误差率:$e_m=p(G_m(x_i) \neq y_i)=\sum\limits_{G_m(x_i)\neq y_i}\omega_{mi}$</p></li></ol><p>这里,$\omega_{mi}$表示第m轮中第i个实例的权值,$\sum\limits_{i=1}^N\omega_{mi}=1$</p><ol><li><p>计算基本分类器$G_m(x)$的系数$\alpha_m$表示$G_m(x)$在最终分类器中的重要性。当上面计算的$e_m \leq \frac{1}{2}$时,$\alpha \geq 0$,并且随着分类误差的减小增大,所以<strong>分类误差率越小的基本分类器在最终分类器中的作用越大</strong></p></li><li><p>更新训练数据的权值分布为下一轮做准备,被基本分类器$G_m(x)$误分类样本的权值得到扩大,所以<strong>误分类样本在下一轮学习中起更大更大作用</strong></p></li></ol><p>最后通过线性组合实现M个基本分类器的加权表决,$\alpha_m$表示了基本分类器的重要性</p><h1 id="并行化方法">并行化方法</h1><h2 id="Bagging">Bagging</h2><p>Bagging基于自助取样法,给定包含m个样本的数据集,先随机取出一个样本放入采样集中,在吧该样本放回到初始数据集合中,使得下次采样时候仍有可能被选中。经过m次随机采样操作,得到含有m个样本的采样集。</p><p>根据上面的自助采样方法,我们得到T个含有m个训练样本(m个训练样本很有可能有重复的),然后基于每个采样集训练一个基学习器。在对预测输出进行结合时,Bagging通常对分类任务使用简单投票法,对回归任务使用简单平均法。若分类预测出现同样票数情况,可以随机选择一个。</p><h2 id="随机森林">随机森林</h2><p>随机森林(Random Forest,RF)是Bagging的一个变体。RF在以决策树为基学习器构建Bagging的基础上,进一步在决策树的训练过程中引入了随机属性选择。</p><p>传统决策树在选择划分属性时是在当前节点的属性集合(假定有d个属性中选择一个最优属性),而在RF中对基决策树的每个节点,先从该节点的属性集合中随机选择一个包含k属性的子集,然后再从这个子集中选择一个最优属性用于划分。k决定了随机性,一般推荐$k=log_2 d$</p>]]></content>
<summary type="html">
<h1 id="个体集成">个体集成</h1><p>集成学习通过构建并结合多个学习器来完成学习任务,先产生一组个体学习器,再用某种策略把他们结合起来。个体学习器通常由一个现有的学习算法从训练数据产生。</p>
<p>同质集成:个体全是相同类型的学习器,称为基学习器</p>
<p>异质集成:个体可以是不同的学习器,称为组件学习器</p>
<p>根据个体学习器的生成方式,目前的集成学习方法大致分为两大类,即个体学习器间存在强依赖关系、必须串行生成的序列化方法Boosting;以及不存在强依赖关系,可同时生成的并行化方法Bagging和随机森林。</p>
</summary>
<category term="ML" scheme="http://peihao.space/categories/ML/"/>
<category term="ML" scheme="http://peihao.space/tags/ML/"/>
</entry>
<entry>
<title>贝叶斯Bayesian</title>
<link href="http://peihao.space/2017/03/06/ml-intro7/"/>
<id>http://peihao.space/2017/03/06/ml-intro7/</id>
<published>2017-03-06T05:18:42.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="贝叶斯决策论">贝叶斯决策论</h1><p>在相关概率已知的情况下,贝叶斯决策论考虑如何基于这些概率和误判损失选择最优的类别标记。</p><p>假设有N中可能的类别标记${c_1,c_2,c_3,…,c_N}, \lambda_{ij}$是将一个真实标记为$c_j$的样本误分类为i产生的损失。推出来样本x分类为$c_i$所产生的期望损失:</p><p>$R(c_i \mid x)=\sum\limits_{j=1}^N \lambda_{ij}P(c_j \mid x)$</p><a id="more"></a><p>显然对每个样本x,若能最小化条件风险$R(h(x)\mid x)$,即在每个样本上选择那个使条件风险$R(c\mid x)$最小的类别标记,总体风险R(h)也将最小化。</p><p>$h^{*}(x)=arg_{c in y}\min R(c\mid x)$</p><p>此时$h^<em>$称为贝叶斯最优分类器,与之对应的总体风险$R(h^</em>)$称为贝叶斯风险。$1-R(h^*)$反映了分类器能达到的理论上限。</p><p>若目标是最小化分类错误率,则误判损失$\lambda_{ij}$可写为:$\lambda_{ij} =0 if i==j else 1$</p><p>此时的条件风险:$R(c \mid x)=1-P(c \mid x)$,于是最小化分类错误率的贝叶斯最优分类器为$h^*(x)=arg_{c \in y}\max P(c \mid x)$</p><p>这里有两种策略估计后验概率$P(c \mid x)$:</p><ol><li><p>给定x,直接建模$P(c \mid x)$预测c,这种判别式模型,之前介绍的决策树、神经网络、SVM都可行</p></li><li><p>对联合分布P(x,c)建模,之后获得$P(c \mid x)$,这种生成式建模 $P(c \mid x)=\frac{P(c)P(x \mid c)}{P()x}$</p></li></ol><p>上式,其中$P(c)$是累先验概率,也就是预估概率;$P(x \mid c)$是样本x相对于类标记c的类条件概率,也称为似然likelihood;$P(x)$是用于归一化的证据因子。对于给定样本x,证据因子$P(x)$与类标记无关。</p><p>类先验概率$P(c)$表达了样本空间中各类样本所占的比例;当训练集中包含充足的独立同分布样本时,$P(c)$可通过各类样本出现的频率估计。</p><h1 id="极大似然估计">极大似然估计</h1><p>估计类条件概率的一种常用策略就是先假定其具有某种确定的概率分布形式,再基于训练样本对概率分布的参数进行估计。</p><p>具体到上节的类条件概率上,记关于类别c的类条件概率为$P(x \mid c)$,假定$P(x \mid c)$具有确定的形式并且被参数向量$\theta_c$唯一确定,则我们的任务就是利用训练集D估计参数$\theta_c$。此时我们记$P(x \mid c)$为$P(x \mid \theta_c)$</p><h1 id="朴素贝叶斯分类器">朴素贝叶斯分类器</h1><p>基于贝叶斯公式来估计后验概率$P(c \mid x)$的主要困难在于累条件概率$P(x \mid c)$是所有属性上的联合概率,难以从有限的训练样本直接估计得到。</p><p>为了避开这个障碍,朴素贝叶斯分类采用属性条件独立性假设:对已知类别假设所有的属性相互独立。</p><p>$P(c \mid x)=\frac{P(c)P(x \mid c)}{P(x)}=\frac{P(c)}{P(x)}\prod\limits_{i=1}^dP(x_i \mid c)$</p><p>其中d为属性数目,$x_i$为x在第i个属性上的取值。</p><p>由于对所有的类别来讲$P(x)$相同,因此贝叶斯判定准则有$h_{nb}=arg\max\limits_{c \in y}P(c)\prod\limits_{i=1}^dP(x_i \mid c)$</p><p>显然朴素贝叶斯分类器的训练过程就是基于训练集D来估计类先验概率P(c),并为ie每个属性估计条件概率$p(x_i \mid c)$</p><h2 id="小例子">小例子</h2><p>令$D_c$表示训练集D中第c类样本组成的集合,若有充足的独立同分布样本,则可以容易的估计出类先验概率:$P(c)=\frac{\mid D_c \mid}{\mid D \mid}$</p><p>对离散属性而言,令$D_{c,x_i}$表示$D_c$中在第i个属性上取值为$x_i$的样本组成的集合,则条件概率$P(x_i \mid c)$可以估计为:$P(x_i \mid c)=\frac{\mid D_{c,x_i} \mid}{\mid D_c \mid}$</p><p>对于连续属性,假定$p(x_i \mid c) \sim N(\mu_{c,i},\theta_{c,i}^2)$,其中$\mu_{c,i}$和$\theta_{c,i}^2$分别是第c类样本在第i个属性上取指的均值和方差。$p(x_i \mid c)=\frac{exp^({-\frac{(x_i-\mu_{c,i})^2}{2\theta_{c,i}^2}})}{\sqrt{2\pi}\theta_{c,i}}$</p><h2 id="拉普拉斯修正">拉普拉斯修正</h2><p>如果某个属性在训练集中没有与某个类同时出现过,则直接使用上式判别将出现问题。具体表现在连乘过程中,一个变量为0,则整个式子都为0.为了避免这种情况的发生,使用拉普拉丝修正:$\hat{P(c)}=\frac{\mid D_c \mid+1}{\mid D \mid+N}$,条件概率修正为$\hat{P}(x_i \mid c)=\frac{\mid D_{c,x_i} \mid+1}{\mid D_c \mid+N_i}$</p><h1 id="半朴素贝叶斯">半朴素贝叶斯</h1><p>放宽朴素贝叶斯分类中对属性条件独立性的要求,使得贝叶斯更加的普适性,人们在朴素贝叶斯的基础上提出了半朴素贝叶斯。</p><p>半朴素贝叶斯适当的考虑一部分属性间的相互依赖关系,从而不至于彻底忽略比较强的属性依赖;但是为了避免问题陷入到复杂的联合概率计算中,一般会对属性依赖的数量有要求。</p><p>假定只能最多一个依赖关系,也就是”独依赖估计”:$P(c\mid x) \propto P(c)\prod\limits_{i=1}^dP(x_i \mid c,pa_i) $</p><p>其中$pa_i$为属性$x_i$所依赖的属性,称为$x_i$的父属性。若每个属性的父属性都已知,则可直接使用之前的公式求解;否则我们需要确定每个属性的父属性。</p><p><img src="http://peihao.space/img/article/ml/ml-intro7-1.png" alt=""></p><p>上图是朴素贝叶斯(独、无依赖立)以及两种常见的半贝叶斯(独依赖):SPODE(SUper Parent ODE)和TAN(Tree Augmented naive Bayes)</p><p>SPODE中有一个超属性,属性如果有依赖,则都依赖到此属性上面;</p><p>TAN则是在最大带权生成树算法基础上通过转换将依赖结构化简。</p><p>AODE(Averaged One Dependent Estimator)尝试将每个属性作为超父来构建SPODE,然后将那些有足够训练数据支撑的SPODE继承起来作为最终结果。</p><h1 id="贝叶斯网">贝叶斯网</h1><p>贝叶斯网B由结构G和参数$\Theta$两部分组成,即$B=\langle F,\Theta \rangle$。网络结构G是一个有向无环图,每个节点对应一个属性,若两个属性有直接的依赖关系,则由一条边连接起来;参数$\Theta$定量的描述依赖关系。例如属性$x_i$在G中的父节点集为$\pi_i$,则$\Theta$包含了每个属性的条件概率表$\theta_{x_i \mid \pi_i}=P_B(x_i \mid \pi_i)$</p><p>贝叶斯网有效的表达了属性间的条件独立性。给定父节点集合,贝叶斯网假设每个属性与它的非后裔属性独立。</p><h2 id="学习">学习</h2><p>正常情况下,我们并不知晓网络结构,需要通过学习方法建立或匹配上适当的网络结构。</p><p>评分搜索:定义评分函数来评估贝叶斯网与训练数据的契合程度,然后基于这个评分函数来寻找结构最优的贝叶斯网。</p><h1 id="EM算法">EM算法</h1><p>对于不完整的训练样本,或者说是未观测的变量,学名是隐变量:令X表示已观测变量集,Z表示隐变量集,$\Theta$表示模型参数</p><p>对$\Theta$做极大似然估计,则最大化对数似然$LL(\Theta \mid X,Z)=ln P(X,Z\mid \Theta)$</p><p>无法直接求解的隐变量,通过对Z计算期望,最大化已观测数据的对数“边际似然”</p><p>EM算法是常用的估计参数隐变量的迭代方法:</p><p><strong>(E)若参数$\Theta$已知,则可根据训练数据推断出最优隐变量Z的值</strong></p><p><strong>(M)反之做Z值已知,可方便的对参数$\Theta$做极大似然估计</strong></p><p>以初始值$\Theta^0$迭代步骤:</p><ol><li><p>基于$\Theta^t$推断隐变量Z的期望记为$Z^t$</p></li><li><p>基于已观测变量X和$Z^t$对参数$\Theta$做极大似然估计,记为$\Theta^{t+1}$</p></li></ol>]]></content>
<summary type="html">
<h1 id="贝叶斯决策论">贝叶斯决策论</h1><p>在相关概率已知的情况下,贝叶斯决策论考虑如何基于这些概率和误判损失选择最优的类别标记。</p>
<p>假设有N中可能的类别标记${c_1,c_2,c_3,…,c_N}, \lambda_{ij}$是将一个真实标记为$c_j$的样本误分类为i产生的损失。推出来样本x分类为$c_i$所产生的期望损失:</p>
<p>$R(c_i \mid x)=\sum\limits_{j=1}^N \lambda_{ij}P(c_j \mid x)$</p>
</summary>
<category term="ML" scheme="http://peihao.space/categories/ML/"/>
<category term="ML" scheme="http://peihao.space/tags/ML/"/>
</entry>
<entry>
<title>ML学习-SVM</title>
<link href="http://peihao.space/2017/03/05/ml-intro6/"/>
<id>http://peihao.space/2017/03/05/ml-intro6/</id>
<published>2017-03-05T05:18:42.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<p>支持向量机(Support Vector Machine)的求解通常是借助凸优化技术。</p><h1 id="间隔与支持向量">间隔与支持向量</h1><p>给定训练样本集$D={(x_1,y_1),(x_2,y_2),…,(x_m,y_m)},y_i \in (-1,+1 )$ 分类学习最基本的思想就是基于训练集D在样本空间中找到一个划分超平面,将不同类别的样本分开。SVM就是帮助我们寻找到众多划分超平面中最符合的。<br><a id="more"></a><br>怎样定义符合这个指标呢,作为分类问题,训练中能够尽可能划分出不同类别的样本是基本,然后在测试集中也能表现出来很好的分类能力,对未见示例泛化能力最强。在训练中表现的就是对训练样本局部扰动容忍度最高。</p><h2 id="公式表示">公式表示</h2><p>划分超平面可以用此式表示:</p><p>$\vec{\omega}^T \vec{x} + b=0$</p><p>其中$\vec{\omega}=(\omega_1;\omega_2;…;\omega_d)$为法向量,决定了超平面的方向;b为位向量,决定了超平面与原点之间的距离。</p><p>样本空间中任意点到超平面x到超平面$(\vec{\omega},b)$的距离可写为:</p><p>$r=\frac{\mid\vec{\omega}^T \vec{x}+b\mid}{\mid\mid \vec{\omega}\mid\mid}$</p><p>设置函数:</p><ol><li><p>$\omega^T x_i + b \geq +1 , y_i= +1$</p></li><li><p>$\omega^T x_i + b \leq -1 , y_i= -1$</p></li></ol><p>简化两个式子:</p><p>$y_i(\omega^T x_i +b) \geq 1 , i=1,2,…,m$<br>这个是之后式子的约束条件</p><p>距离超平面最近的几个训练样本点使得上面的不等式等号成立,它们被称为支持向量(support vector),两个异类支持向量到超平面的距离之和称为间隔(margin)</p><p>$\gamma = \frac{2}{\omega}$</p><p><img src="http://peihao.space/img/article/ml/ml-intro6-1.png" alt=""></p><p>为了使得间隔最大,也就是求$\max\limits_{w,b} \frac{2}{\mid\mid \omega \mid\mid}$</p><p>转换为$\min\limits_{w,b}\frac{\mid\mid \omega \mid\mid^2}{2}$</p><p>这就是支持向量机</p><h1 id="对偶问题">对偶问题</h1><p>模型$f(x)=\vec{\omega}^T \vec{x}+b$,参数$\omega b$是模型参数。而$\min\limits_{w,b}\frac{\mid\mid \omega \mid\mid^2}{2}$是一个凸二次规划,除了使用现成的优化计算包外,我们可以使用数学上的对偶关系更高效的求出结果。</p><p>对这个凸二次规划式子添加拉格朗日乘子$\alpha \geq 0$,则问题的拉格朗日函数可写为:</p><p><strong>$L(\vec{\omega},b,\vec{\alpha})=\frac{1}{2}\mid\mid \omega \mid\mid^2+\sum\limits_{i=1}^m\alpha_i(1-y_i(\omega^Tx_i+b))$</strong></p><p>令L对$\omega b$的偏导为零可得:</p><ol><li><p>$\omega=\sum\limits_{i=1}^m \alpha_iy_ix_i$</p></li><li><p>$0=\sum\limits_{i=1}^m\alpha_iy_i$</p></li></ol><p>式1代入拉格朗日式子,式2作为约束函数,得到上一小节式子的对偶问题:</p><p>$\max\limits_{\alpha} \sum_{i=1}^m\alpha_i-\frac{1}{2}\sum_{i=1}^m\sum_{j=1}^m \alpha_i \alpha_j y_i y_jx_i^T x_j$</p><p>约束条件:$\sum\limits_{i=1}^m\alpha_iy_i=0$</p><p>上式是南教授《机器学习》书中记录的式子,这里认为下面式子可能更好理解</p><p>$\max\limits_{\alpha} \sum_{i=1}^m\alpha_i+\frac{1}{2}\sum_{i=1}^m\sum_{j=1}^m \alpha_i \alpha_j y_i y_jx_i^T x_j$</p><p>从上式解出$\vec{\alpha}$之后,求出$\vec{\omega}$和b即可得到模型:</p><p>$f(\vec{x})=\vec{\omega}^T\vec{x}+b=\sum\limits_{i=1}^m \alpha_iy_ix_i^T\vec{x}+b$</p><p>支持向量机一个极其重要的特性就是:训练完成后,大部分的训练样本不需要保存,最终模型仅与支持向量有关。上式是一个二次规划问题,求解的高效办法是使用SMO。</p><h2 id="使用SMO求解">使用SMO求解</h2><p>SMO(Sequential Minimal Optimization)基本思路:固定$\alpha_i$之外的所有参数,然后求$\alpha_i$上的极值。</p><p>具体到这个问题,由于存在约束条件$\sum\limits_{i=1}^m\alpha_iy_i=0$,固定$\alpha$之外的值,则$\alpha$值都能导出。所以采用了部分的调整,每次固定两个变量$\alpha_i \alpha_j$之外的其余参数,之后不断执行下述步骤直到收敛:</p><ol><li><p>选取一对需要更新的变量$\alpha_i \alpha_j$</p></li><li><p>固定其余参数,求解上个小结推导出的式子更新$\alpha_i \alpha_j$</p></li></ol><p>对于两个需要更新参数$\alpha_i$和$\alpha_j$的选取,遵循一个规则,使选取的两变量所对应样本之间的间隔最大。</p><h1 id="核函数">核函数</h1><p>这个部分解决不能线性可分问题。</p><p>这类问题,一般是将样本从原始空间映射到更高维的特征空间,使得样本在高维度空间中线性可分。</p><h2 id="引出">引出</h2><p>令$\phi(\vec{x})$表示将$\vec{x}$映射后的特征向量,于是在特征空间中划分超平面对应的模型可以表示为:</p><p>$f(\vec{x})=\omega^T \phi(\vec{x})+b$</p><p>类似在线性可分情况下的式子:</p><p>$\min\limits_{\vec{w},b} \frac{\mid\mid \vec{\omega} \mid\mid^2}{2}$</p><p>约束条件:</p><p>$y_i(\vec{\omega}^T \phi(x_i)+b) \geq 1, i=1,2,…,m$</p><p>对偶问题:</p><p>$\max\limits_{\alpha} \sum\limits_{i=1}^m\alpha_i-\frac{1}{2}\sum\limits_{i=1}^m\sum\limits_{j=1}^m \alpha_i\alpha_jy_iy_j \phi(x_i)^T\phi(x_j)$</p><p>约束条件:$\sum\limits_{i=1}^m \alpha_i y_i =0$</p><p>关键问题$\phi(x_i)^T\phi(x_j)$是映射到特征空间之后的内积。由于维度太高不易计算,构造这样的函数:</p><p>$\kappa(\vec{x}_i,\vec{x}_j)=\langle \phi(x_i),\phi(x_j) \rangle = \phi(x_i)^T\phi(x_j)$</p><p>原式求解得到:</p><p>$f(\vec{x})=\vec{\omega}^T\phi(\vec{x})+b$</p><p>$=\sum\limits_{i=1}^m\alpha_iy_i\phi(x_i)^T\phi(x)+b$</p><p>$=\sum\limits_{i=1}^m\alpha_iy_i\kappa(x,x_i)+b$</p><p>这里的\kappa就是核函数。</p><p><img src="http://peihao.space/img/article/ml/ml-intro6-2.png" alt=""></p><p><img src="http://peihao.space/img/article/ml/ml-intro6-3.png" alt=""></p><h2 id="核函数组合">核函数组合</h2><ol><li>$\kappa_1$和$\kappa_2$都是核函数,则对于任意正数$\gamma_1$和$\gamma_2$的线性组合:$\gamma_1\kappa_1 + \gamma_2\kappa_2$</li></ol><ol><li><p>核函数的内积: $\kappa_1 \bigotimes \kappa_2(\vec{x},\vec{z})=\kappa_1(\vec{x},\vec{z})\kappa_2(\vec{x},\vec{z})$</p></li><li><p>对于任意函数$g(x)$,$\kappa(\vec{x},\vec{z})=g(x)\kappa_1(\vec{x},\vec{z})g(z)$</p></li></ol><p>都是核函数</p><h1 id="软间隔">软间隔</h1><p>为了缓解某些连核函数都无法有效处理的分类问题,需要允许SVM在一些样本上出错,即允许某些样本不满足约束$y_i(\vec{w}^Tx_i+b) \geq 1$,引入了软间隔概念。</p><p>优化目标可以修改为:</p><p>$\min\limits{\vec{\omega},b}\frac{\mid\mid \omega \mid\mid^2}{2}+C\sum\limits_{i=1}^m\ell_{0/1}(y_i(\vec{\omega}^Tx_i+b)-1)$</p><p>其中$C > 0$是一个常数,$\ell_{0/1}$是”0/1损失函数”</p><p>$\ell_{0/1}(z) = 1 if z<0 else 0$</p><p>当C无穷大时,所有样本均需要满足约束,等价于前面小结的式子;C为可数实数,则允许样本不满足约束</p><p>为了使得$\ell$容易求导,通常使用下面几个数学性质较好的式子替代:</p><p><img src="http://peihao.space/img/article/ml/ml-intro6-4.png" alt=""></p><p>代入原式,然后使用松弛变量$\xi_i \geq 0$,松弛变量$\xi$替换原来C后面的部分,表示样本不满足约束的程度。</p><p>使用之前介绍的对偶问题求解出最终的答案。</p><h1 id="支持向量回归">支持向量回归</h1><p>支持向量回归(Support Vector Regression)假设我们能够容忍f(x)与y之间最多有$\epsilon$的误差,即仅当f(x)与y之间差别的绝对值大于$\epsilon$时才算损失。</p><p>相当于以f(x)为中心,构建了一个宽度为$2\epsilon$的间隔带,落在带内的样本是正确的。</p><p><img src="http://peihao.space/img/article/ml/ml-ml-intro6-4.png" alt=""></p><p>SVR问题可用式子表示:</p><p>$\min\limits{\vec{\omega},b}\frac{\mid\mid \omega \mid\mid^2}{2}+C\sum\limits_{i=1}^m\ell_{\epsilon}(f(x_i-y_i))$</p><p>其中$\ell_{\epsilon}$:$\ell_{\epsilon} ==0 if \mid z\mid \leq \epsilon else (\mid z \mid - \epsilon)$</p><ol><li><p>引入松弛变量$\xi_{i}$和$\hat{\xi_{i}}$,原式重写为$\min\limits_{\vec{\omega},b,\xi_{i},\hat{\xi_{i}}}\frac{\mid\mid \vec{\omega}\mid\mid^2}{2}+C\sum\limits_{i=1}^m(\xi_{i} + \hat{\xi_{i}})$</p></li><li><p>引入拉格朗日乘子,求对偶问题</p></li><li><p>推导出带有核函数的算式</p></li></ol>]]></content>
<summary type="html">
<p>支持向量机(Support Vector Machine)的求解通常是借助凸优化技术。</p>
<h1 id="间隔与支持向量">间隔与支持向量</h1><p>给定训练样本集$D={(x_1,y_1),(x_2,y_2),…,(x_m,y_m)},y_i \in (-1,+1 )$ 分类学习最基本的思想就是基于训练集D在样本空间中找到一个划分超平面,将不同类别的样本分开。SVM就是帮助我们寻找到众多划分超平面中最符合的。<br>
</summary>
<category term="ML" scheme="http://peihao.space/categories/ML/"/>
<category term="ML" scheme="http://peihao.space/tags/ML/"/>
</entry>
<entry>
<title>ML学习-神经网络</title>
<link href="http://peihao.space/2017/03/04/ml-intro5/"/>
<id>http://peihao.space/2017/03/04/ml-intro5/</id>
<published>2017-03-04T05:18:42.000Z</published>
<updated>2017-09-14T15:37:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="神经元">神经元</h1><p>Neural Network<a href="ufldl.stanford.edu/wiki/index.php/神经网络">神经网络</a>:是由具有适应性的简单单元组成的广泛并进行互联的网络,他的组织能够模拟生物神经系统对真实的世界物体做出的交互反应</p><p>神经网络由一个个神经元(neuron)互联组成,神经元可以看作一个处理函数,当这个函数的输入超过某一个阈值,经过处理后单元会向其他单元发送信号。<br><a id="more"></a></p><p><img src="http://ufldl.stanford.edu/wiki/images/thumb/3/3d/SingleNeuron.png/300px-SingleNeuron.png" alt=""><br>单元的输入来自其他单元传递过来的信号,这些信号通过带权重的连接进行传递。当前单元接受来自其余单元的带权重的信号和与阈值比较,符合条件的产生输出。</p><h1 id="感知机">感知机</h1><p>感知机由两层神经元组成,输入层接收外界输入信号后传递给输出层,输出层是阈值逻辑单元。</p><p>感知机通过简单的算术组合可以轻易的实现与或非逻辑运算。</p><p>实现逻辑类似于$y=f(\sum_i\omega_ix_i-\theta)$,其中w是权重向量,x是输入信号,$\theta$则是阈值。</p><p>阈值可看作是一个固定输入(x值)为-1的dummy node所对应的连接权重$\omega_{n+1}$,这样权重和阈值就可以统一学习。</p><h2 id="学习规则">学习规则</h2><ol><li><p>$\omega_i \leftarrow \omega_i + \Delta \omega_i$</p></li><li><p>$\Delta \omega_i = \eta(y-\hat{y})x_i$</p></li></ol><p>其中$\eta \in (0,1)$称为学习率。若感知机对训练样例(x,y)预测正确,即$\hat{y}=y$,则感知机不改变,否则将根据错误的程度进行权重调整。</p><h2 id="非线性与多重神经元">非线性与多重神经元</h2><p>要解决非线性可分问题,需考虑多层功能神经元。例如异或问题。</p><p>一般的多层功能神经元都设置在输入层与输出层之间,也称作隐含层。每一层都有独立的激活函数功能神经元。<br><img src="http://ufldl.stanford.edu/wiki/images/thumb/4/40/Network3322.png/500px-Network3322.png" alt=""><br>功能更强大的神经网络:每层神经元与下一层神经元完全互联,而同层之间不存在连接,也不存在跨层连接。要注意的是,这里的相邻层连接是双向的。这种分类型的神经网络通常被称为”多层前馈神经网络”(multi-layer feedforward neural networks)这种网络的输入层的功能仅仅是接受输入,隐层以及输出层有功能神经元,进行函数处理。</p><h1 id="学习过程">学习过程</h1><p>神经网络就是根据训练数据来调整神经元之间的连接权以及每个功能神经元的阈值。</p><p>著名的BP算法就是神经网络一种训练学习算法。</p><h1 id="BP误差逆传">BP误差逆传</h1><p>多层神经网络中最著名的学习算法就是BP误差逆传算法(erroe BackPropagation)。</p><p>BP算法可以训练包括多层前馈神经网络、递归神经网络等。</p><p>BP算法的目标是要最小化训练集D上的累计误差。作为一个迭代类型的算法,,迭代的每一轮采用广义的感机学习规则对参数进行更新估计。其中学习率$\eta \in (0,1)$控制着算法中每次迭代的更新步长,$\eta$太大容易造成迭代的震荡,太小则会影响收敛速度,</p><h2 id="算法流程">算法流程</h2><ol><li><p>将输入示例提供给输入层神经元,然后逐层将信号前传,直到产生输出层的结果</p></li><li><p>计算输出层的误差,将误差逆向传播至隐层神经元</p></li><li><p>根据隐层神经元的误差对连接券和阈值进行调整</p></li><li><p>迭代,直到达到某个停止条件,如训练误差小于某个数值</p></li></ol><p>以目标的负梯度方向为参数进行调整。分别计算出输出层、隐层的梯度以及对应的阈值bias,然后去更新神经元之间的权值和阈值。再进行输出层隐层的梯度。。。不断的循环,直到误差小于预设值。</p><h2 id="对过拟合的策略">对过拟合的策略</h2><p>由于BP算法强大的学习能力,经常会在训练集上过度学习造成过拟合现象,反而在测试集上的表现不好。通常可以采用”早停”策略:将数据集分为训练集和验证集,训练集用来计算梯度、更新连接权以及阈值,验证集则用来估计误差。训练集误差降低但验证集误差升高时,停止训练,同时返回具有最小验证集误差的连接权和阈值。</p><h2 id="全局与局部">全局与局部</h2><p>用E表示神经网络在训练集上的误差,则E是关于连接权w和阈值$\theta$的函数,此时神经网络的训练过程可看作是一个参数的寻优过程,即在参数空间中找一组最优参数使得E最小。</p><p>直观的得看,局部最小解(local minimum)是参数空间中的某个点,它相邻的误差函数值均不小于该点的函数值;</p><p>全局最小解(global minimum)是指参数空间中所有的点误差函数值都不小于该店的误差函数值。</p><p>显然有全局最小解必然是局部最小解,反之未必。参数空间中梯度为零的点,其误差值小于临点的误差函数值,称为局部最小。</p><h2 id="搜索方式">搜索方式</h2><p>根据梯度的值决定参数最优搜索的方向是最广泛的办法。例如负梯度方向是函数值下降最快的方向,因此梯度下降法就是沿着负梯度方向搜索最优解。若误差函数在当前点的梯度为零,则已达到局部极小。</p><p>如果只有一个局部最小点,则为全局最小解。从局部最优找到全局最优的办法就是要从局部最优中挑出来,继续搜索下去。因为搜索到局部最优后,梯度为零,会造成搜索停滞。</p><ol><li><p>取多组不同参数值初始化多个神经网络,取其中误差最小的解作为最终的参数。相当于从不同的初始值开始搜索猜测。</p></li><li><p>使用模拟退火法(在blog之前的文章中有介绍)。模拟退退火有一定的概率接受比当前解差的解,有助于跳出局部极小。而迭代过程,接受次优解的概率逐渐降低,从而保证了算法的稳定性。</p></li><li><p>随机梯度下降</p></li></ol><h1 id="其余常见的神经网络">其余常见的神经网络</h1><h2 id="RBF网络">RBF网络</h2><p>单隐层前馈神经网络的一种,输出层是对隐层神经元还输出的线性组合。假定输入为d维向量$\vec{x}$输出为实值,可表示为:</p><p>$\phi(x)=\sum_{i=1}^{q}\omega_i\rho(x,c_i)$</p><p>q为隐层神经元个数,$c_i$和$\omega_i$分别是第i个隐层神经元对应的中心和权重。$\rho(x,c_i)$是径向基函数,是某种沿径向对称的标量函数。通常定义为样本x到数据中心<br>$c_i$之间的欧式距离的单调函数。</p><h2 id="ART网络">ART网络</h2><p>竞争学习(competitive learning)是神经网络中常用的无监督学习策略。</p><p>网络的输出神经元相互竞争,每一时刻仅有一个竞争获胜的神经元被激活,其他神经元状态被抑制。</p><h2 id="SOM网络">SOM网络</h2><p>自组织映射,是一种竞争学习型的无监督神经网络。能将高位输入数据降维,同时保持输入数据的拓扑结构。即将高维空间中相似的样本点映射到网络输出层的邻近神经元。</p><p>在接受一个训练样本之后,每个输出层神经元会计算该样本与自身携带的权向量之间的距离,距离最近的神经元称为最佳匹配单元。然后调整最佳匹配单元及邻近神经元的权向量,使得这些权向量与当前输入样本距离缩小。这个过程不断迭代,知道收敛。</p><h2 id="级连相关">级连相关</h2><p>级联: 建立层次连接的层级结构。开始训练时,只有几本的输入输出层,随着训练的进行,新的隐层神经元逐渐加入。</p><p>相关: 通过最大化新神经元的输出与网络误差之间的相关性来训练相关的参数。</p><h2 id="Elman">Elman</h2><p>Elman网络是递归神经网络(recurrent neural networks)的一种。递归神经网络可以让一些神经元的输出反馈作为输入信号。</p><h1 id="深度学习">深度学习</h1><p>深度学习的概念源于人工神经网络的研究。含多隐层的多层感知器就是一种深度学习结构。深度学习通过组合低层特征形成更加抽象的高层表示属性类别或特征,以发现数据的分布式特征表示。</p><p>同机器学习方法一样,深度机器学习方法也有监督学习与无监督学习之分.不同的学习框架下建立的学习模型很是不同.例如,卷积神经网络(Convolutional neural networks,简称CNNs)就是一种深度的监督学习下的机器学习模型,而深度置信网(Deep Belief Nets,简称DBNs)就是一种无监督学习下的机器学习模型。</p><p>DBN每次训练一层隐节点,训练时将上一层隐节点的输出作为下一层隐节点的输入。整个网络完成后,再进程微调。</p><p>CNN节省训练开销的策略是”权共享”,让一组神经元使用相同的连接权。</p><p>无论是DBN还是CNN,其多隐层堆叠,每层对上层的处理机制,可以看作是对输入信号逐层加工,从而把初始的与输出目标联系不密切的输入转换呈密切。通过多层处理,逐渐的将初始的低层特征转转成高层特征表示,用简单模型完成复杂的分类任务。</p><h1 id="CNN卷积神经网络">CNN卷积神经网络</h1><p>在图像处理中,往往把图像表示为像素的向量,比如一个1000×1000的图像,可以表示为一个1000000的向量。在上一节中提到的神经网络中,如果隐含层数目与输入层一样,即也是1000000时,那么输入层到隐含层的参数数据为1000000×1000000=10^12,这样就太多了,基本没法训练。所以图像处理要想练成神经网络大法,必先减少参数加快速度。</p><p>卷积神经网络有两种神器可以降低参数数目。第一种神器叫做局部感知野。一般认为人对外界的认知是从局部到全局的,而图像的空间联系也是局部的像素联系较为紧密,而距离较远的像素相关性则较弱。因而,每个神经元其实没有必要对全局图像进行感知,只需要对局部进行感知,然后在更高层将局部的信息综合起来就得到了全局的信息。</p><p><img src="http://peihao.space/img/article/ml/x1.jpg" alt=""></p><p>在上右图中,假如每个神经元只和10×10个像素值相连,那么权值数据为1000000×100个参数,减少为原来的千分之一。而那10×10个像素值对应的10×10个参数,其实就相当于卷积操作。</p><p>第二级神器,即权值共享。在上面的局部连接中,每个神经元都对应100个参数,一共1000000个神经元,如果这1000000个神经元的100个参数都是相等的,那么参数数目就变为100了。</p><p>怎么理解权值共享呢?我们可以这100个参数(也就是卷积操作)看成是提取特征的方式,该方式与位置无关。这其中隐含的原理则是:图像的一部分的统计特性与其他部分是一样的。这也意味着我们在这一部分学习的特征也能用在另一部分上,所以对于这个图像上的所有位置,我们都能使用同样的学习特征。</p><p>更直观一些,当从一个大尺寸图像中随机选取一小块,比如说 8×8 作为样本,并且从这个小块样本中学习到了一些特征,这时我们可以把从这个 8×8 样本中学习到的特征作为探测器,应用到这个图像的任意地方中去。特别是,我们可以用从 8×8 样本中所学习到的特征跟原本的大尺寸图像作卷积,从而对这个大尺寸图像上的任一位置获得一个不同特征的激活值。</p><p>如下图所示,展示了一个33的<strong>卷积</strong>核在55的图像上做卷积的过程。每个卷积都是一种特征提取方式,就像一个筛子,将图像中符合条件(激活值越大越符合条件)的部分筛选出来。</p><p><img src="http://peihao.space/img/article/ml/x2.gif" alt=""></p>]]></content>
<summary type="html">
<h1 id="神经元">神经元</h1><p>Neural Network<a href="ufldl.stanford.edu/wiki/index.php/神经网络">神经网络</a>:是由具有适应性的简单单元组成的广泛并进行互联的网络,他的组织能够模拟生物神经系统对真实的世界物体做出的交互反应</p>
<p>神经网络由一个个神经元(neuron)互联组成,神经元可以看作一个处理函数,当这个函数的输入超过某一个阈值,经过处理后单元会向其他单元发送信号。<br>
</summary>
<category term="ML" scheme="http://peihao.space/categories/ML/"/>
<category term="ML" scheme="http://peihao.space/tags/ML/"/>
</entry>
</feed>