-
Notifications
You must be signed in to change notification settings - Fork 429
/
Copy path周志华《机器学习》课后习题解答系列(六):Ch5.10 - 卷积神经网络实验.html
523 lines (442 loc) · 18.7 KB
/
周志华《机器学习》课后习题解答系列(六):Ch5.10 - 卷积神经网络实验.html
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
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
<!DOCTYPE html>
<html>
<head>
<title>周志华《机器学习》课后习题解答系列(六):Ch5.10 - 卷积神经网络实验</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
/* GitHub stylesheet for MarkdownPad (http://markdownpad.com) */
/* Author: Nicolas Hery - http://nicolashery.com */
/* Version: b13fe65ca28d2e568c6ed5d7f06581183df8f2ff */
/* Source: https://github.com/nicolahery/markdownpad-github */
/* RESET
=============================================================================*/
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
}
/* BODY
=============================================================================*/
body {
font-family: Helvetica, arial, freesans, clean, sans-serif;
font-size: 14px;
line-height: 1.6;
color: #333;
background-color: #fff;
padding: 20px;
max-width: 960px;
margin: 0 auto;
}
body>*:first-child {
margin-top: 0 !important;
}
body>*:last-child {
margin-bottom: 0 !important;
}
/* BLOCKS
=============================================================================*/
p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
}
/* HEADERS
=============================================================================*/
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
}
h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
font-size: inherit;
}
h1 {
font-size: 28px;
color: #000;
}
h2 {
font-size: 24px;
border-bottom: 1px solid #ccc;
color: #000;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
color: #777;
font-size: 14px;
}
body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
margin-top: 0;
padding-top: 0;
}
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}
h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
margin-top: 10px;
}
/* LINKS
=============================================================================*/
a {
color: #4183C4;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* LISTS
=============================================================================*/
ul, ol {
padding-left: 30px;
}
ul li > :first-child,
ol li > :first-child,
ul li ul:first-of-type,
ol li ol:first-of-type,
ul li ol:first-of-type,
ol li ul:first-of-type {
margin-top: 0px;
}
ul ul, ul ol, ol ol, ol ul {
margin-bottom: 0;
}
dl {
padding: 0;
}
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}
dl dt:first-child {
padding: 0;
}
dl dt>:first-child {
margin-top: 0px;
}
dl dt>:last-child {
margin-bottom: 0px;
}
dl dd {
margin: 0 0 15px;
padding: 0 15px;
}
dl dd>:first-child {
margin-top: 0px;
}
dl dd>:last-child {
margin-bottom: 0px;
}
/* CODE
=============================================================================*/
pre, code, tt {
font-size: 12px;
font-family: Consolas, "Liberation Mono", Courier, monospace;
}
code, tt {
margin: 0 0px;
padding: 0px 0px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}
pre>code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}
pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}
pre code, pre tt {
background-color: transparent;
border: none;
}
kbd {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #DDDDDD;
background-image: linear-gradient(#F1F1F1, #DDDDDD);
background-repeat: repeat-x;
border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
border-image: none;
border-radius: 2px 2px 2px 2px;
border-style: solid;
border-width: 1px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
line-height: 10px;
padding: 1px 4px;
}
/* QUOTES
=============================================================================*/
blockquote {
border-left: 4px solid #DDD;
padding: 0 15px;
color: #777;
}
blockquote>:first-child {
margin-top: 0px;
}
blockquote>:last-child {
margin-bottom: 0px;
}
/* HORIZONTAL RULES
=============================================================================*/
hr {
clear: both;
margin: 15px 0;
height: 0px;
overflow: hidden;
border: none;
background: transparent;
border-bottom: 4px solid #ddd;
padding: 0;
}
/* TABLES
=============================================================================*/
table th {
font-weight: bold;
}
table th, table td {
border: 1px solid #ccc;
padding: 6px 13px;
}
table tr {
border-top: 1px solid #ccc;
background-color: #fff;
}
table tr:nth-child(2n) {
background-color: #f8f8f8;
}
/* IMAGES
=============================================================================*/
img {
max-width: 100%
}
</style>
</head>
<body>
<p>本系列相关答案和源代码托管在我的Github上:<a href="https://github.com/PY131/Machine-Learning_ZhouZhihua">PY131/Machine-Learning_ZhouZhihua</a>.</p>
<h1>卷积神经网络实验 - 手写字符识别</h1>
<blockquote>
<p><img src="Ch5/5.10.png" /></p>
</blockquote>
<p>注:本题程实现基于python-theano(这里查看<a href="https://github.com/PY131/Machine-Learning_ZhouZhihua/tree/master/ch5_neural_networks/5.10_CNN">完整代码</a>和<a href="http://www-labs.iro.umontreal.ca/~lisa/deep/data/mnist/">数据集</a>)。</p>
<h2>1. 基础知识回顾</h2>
<h3>1.1. 核心思想</h3>
<p>卷积神经网络(Convolutional Neural Network, CNN)是“<strong>深度学习</strong>”的代表模型之一,是一种<strong>多隐层</strong>神经网络,正被广泛用于图像处理、语音识别等热点领域。</p>
<p>卷积神经网络的原理和特点,集中体现在以下三个核心思想当中:</p>
<ul>
<li><strong>局部感受野</strong>(Local Receptive Fields)</li>
<li><strong>权值共享</strong>(weight sharing)</li>
<li>时间或空间的<strong>亚采样</strong></li>
</ul>
<p>在整合了上述三大特点之后,卷积神经网络具备了很强的<strong>畸变容忍能力</strong>,能够从复杂的对象中<strong>隐式地<strong>进行</strong>特征提取与学习</strong>。 </p>
<h3>1.2. 结构和功能</h3>
<p>卷积神经网络同多层感知机(MLP)一样,通过设置多个隐层来实现对复杂模型的学习。如下图所示是一个手写字符识别的卷积神经网络结构示意图(书p114):</p>
<p><img src="Ch5/5.10.CNN_sketch.png" /></p>
<p>从图中可以看到卷积层(convolutional layer)和采样层(pooling layer)的复合,其功能简述如下:</p>
<ul>
<li>卷积层包含多个<strong>特征映射</strong>(feature map),它们采用相应的<strong>卷积滤波器</strong>从输入中提取特征;</li>
<li>采样层基于<strong>局部相关性</strong>原理对卷积层进行<strong>亚采样</strong>,从而在保留有用信息的同时减少数据量;</li>
</ul>
<p>通过多层复合,隐层最终输出目标维<strong>特征向量</strong>,通过连接层和输出层输出结果。</p>
<h3>1.3. 参数技巧</h3>
<p>神经网络的参数设计十分重要,关于CNN模型的一些参数的考虑(如隐层特征图数目和大小、滤波器大小等),可参考<a href="http://deeplearning.net/tutorial/lenet.html#lenet">Convolutional Neural Networks (LeNet)</a>文章最后<strong>Tips and Tricks</strong>的内容。</p>
<h2>2. 手写字符识别实验</h2>
<p>这里,我们采用<strong>python-theano深度学习库</strong>来实现基于<a href="http://yann.lecun.com/exdb/mnist/">MNIST</a>数据的字符识别实验。关于theano的基础使用可参考:<a href="http://blog.csdn.net/snoopy_yuan/article/details/71548243">深度学习基础 - 基于Theano-MLP的字符识别实验(MNIST)</a>或是<a href="http://deeplearning.net/tutorial/">Deep Learning Tutorials</a>。</p>
<h3>2.1. 数据获取及预处理</h3>
<p>这里我们采用经过规约的数据集<a href="http://www-labs.iro.umontreal.ca/~lisa/deep/data/mnist/">mnist.pkl.gz</a>,给出该数据集的部分信息如下:</p>
<ul>
<li><strong>维度属性</strong>:数据集包含3个子数据集,对应train_set、valid_set、test_set,样本规模分别为50000、10000、10000;每条样本包含:输入向量[1*784],对应输入图片灰度矩阵[28*28];输出值,对应图片类别标签(数字0-9);</li>
<li><strong>完整度</strong>:样本完整;</li>
<li><strong>平衡度</strong>:未知;</li>
<li><strong>更多信息</strong>:手写字符所覆盖的灰度已被人工调整到了图片的中部。</li>
</ul>
<p>下面是一些样例图片:</p>
<p><img src="Ch5/5.10.display_some.png" alt="样例图片" /></p>
<p>通过对数据集的分析,确定此处该数据集已无需额外的预处理即可使用,只是在使用时注意维度变换即可。</p>
<h3>2.2. 基于theano实现网络模型</h3>
<p>基于theano来训练一个卷积神经网络需要完成的内容包括:</p>
<ol>
<li><strong>参数初始化</strong>,采用<code>theano.shared</code>来达到权值共享,基于数据信息设计相关参数(隐层规模、滤波器大小、学习率、迭代次数限、若采样MSGD算法还需设置mini-batch大小等);</li>
<li>相关<strong>辅助函数</strong>,如采用<code>theano.function</code>实现tanh/sigmoid、似然损失函数等;</li>
<li><strong>卷积</strong>操作(Convolution)和<strong>池化</strong>操作(pooling),采用<code>theano.tensor.signal.conv2d</code>实现二维(2D)卷积;采用<code>theano.tensor.signal.pool.pool_2d</code>实现最大池化(max-pooling),</li>
<li>训练<strong>过程优化机制</strong>,如加入不同时间尺度的验证、测试机制,早停机制;</li>
<li>实现迭代训练程序并得出模型(即最优参数);</li>
</ol>
<p>进一步地:</p>
<ul>
<li>将卷积层与池化层(采样层)整个为一个复合层,称为<strong>卷积-池化层</strong>(<code>class LeNetConvPoolLayer</code>);</li>
<li>将模型的训练、验证、测试整合在一个程序块中,方便早停判断;</li>
</ul>
<p>这里还需进一步说明各层规模和滤波器大小的设置:</p>
<p>以当前样本为例,输入层大小<code>[28*28]</code>,若采用<code>5*5</code>的滤波器进行卷积,则第一个卷积层的特征图大小为<code>[24*24]</code>(ps. 28-5+1=24),若紧接着的亚采样模版大小为<code>[2*2]</code>,那么该池化层特征图大小为<code>[12*12]</code>(ps. 24/2=12)。同理,可计算出下一个卷积池化的特征图大小为<code>[8*8]</code>和<code>[4*4]</code>,再往后就只需要一个面向连接层的一维卷积层了,其节点数为当前的<code>feature maps</code>数。然后按照MLP模型给出连接层和输出层即可。</p>
<p>各层规模设置的样例程序如下:</p>
<pre><code>```python
layer1 = LeNetConvPoolLayer(
rng,
input=layer0.output,
image_shape=(batch_size, nkerns[0], 12, 12),
filter_shape=(nkerns[1], nkerns[0], 5, 5),
poolsize=(2, 2)
)
layer2_input = layer1.output.flatten(2)
# construct a fully-connected sigmoidal layer
layer2 = HiddenLayer(
rng,
input=layer2_input,
n_in=nkerns[1] * 4 * 4,
n_out=500,
activation=T.tanh
)
# classify the values of the fully-connected sigmoidal layer
layer3 = LogisticRegression(input=layer2.output, n_in=500, n_out=10)
```
</code></pre>
<p>给出该训练程序简化样例如下<a href="https://github.com/PY131/Machine-Learning_ZhouZhihua/blob/master/ch5_neural_networks/5.10_CNN/Mnist_CNN.py">查看完整程序</a>:</p>
<pre><code>```python
def evaluate_lenet5(learning_rate=0.1, # 学习率
n_epochs=200, # 迭代批数
dataset='mnist.pkl.gz', # 数据集文件
nkerns=[20, 50], # 每隐层特征图数目序列
batch_size=500): # mini-batch大小(for MSGD)
# 加载数据,生成训练集/验证集/测试集
datasets = load_data(dataset)
train_set_x, train_set_y = datasets[0]
valid_set_x, valid_set_y = datasets[1]
test_set_x, test_set_y = datasets[2]
...
# 搭建模型网络结构(包括上面的隐层sizes推导)
# 输入
layer0_input = x.reshape((batch_size, 1, 28, 28))
# 第一层 - 复合
layer0 = LeNetConvPoolLayer(
rng,
input=layer0_input,
image_shape=(batch_size, 1, 28, 28),
filter_shape=(nkerns[0], 1, 5, 5),
poolsize=(2, 2)
)
# 第二层 - 复合
layer1 = LeNetConvPoolLayer( ... )
# 第三层 - 隐层
layer2_input = layer1.output.flatten(2)
layer2 = HiddenLayer( ... )
# 全连接输出
layer3 = LogisticRegression(input=layer2.output, n_in=500, n_out=10)
# 似然损失函数
cost = layer3.negative_log_likelihood(y)
...
# 参数更新机制
updates = [
(param_i, param_i - learning_rate * grad_i)
for param_i, grad_i in zip(params, grads)
]
# 模型训练函数体
train_model = theano.function(
[index],
cost,
updates=updates,
givens={
x: train_set_x[index * batch_size: (index + 1) * batch_size],
y: train_set_y[index * batch_size: (index + 1) * batch_size]
}
)
########## 模型训练 ##########
# 早停机制设置
patience = 10000 # 迭代次数耐心上限
patience_increase = 2 # 耐心上限拓展步长
improvement_threshold = 0.995 # 精度明显提升判断
# 验证周期
validation_frequency = min(n_train_batches, patience // 2)
...
# 循环
while (epoch < n_epochs) and (not done_looping):
epoch = epoch + 1
# mini-batch迭代
for minibatch_index in range(n_train_batches):
...
# 模型训练(损失计算+参数更新)
cost_ij = train_model(minibatch_index)
# 模型验证(a batch训练完成)
if (iter + 1) % validation_frequency == 0:
# 计算0-1损失 - 验证误差
validation_losses = [validate_model(i) for i in range(n_valid_batches)]
this_validation_loss = numpy.mean(validation_losses)
...
# 如果取得更好模型(验证精度提升)
if this_validation_loss < best_validation_loss:
# 若精度提升明显,但耐心迭代次数上限达到,则提高迭代次数上限
if this_validation_loss < best_validation_loss * improvement_threshold:
patience = max(patience, iter * patience_increase)
...
# 进行测试(在验证精度提升时)以方便我们对比观测
test_losses = [
test_model(i)
for i in range(n_test_batches)
]
test_score = numpy.mean(test_losses)
...
# 早停判断
if patience <= iter:
done_looping = True
break
...
#返回所需信息
```
</code></pre>
<h3>2.3. 训练及测试结果</h3>
<p>这里采用MSGD(块随机梯度下降法)进行迭代寻优,下图是经过大约5万次迭代训练后得到的三种误差(训练/验证/测试)收敛曲线,可以看出其过程收敛性:</p>
<p><img src="Ch5/5.10.err_curve.png" alt="样例图片" /></p>
<p>显示出一些测试样本的预测结果如下图示:</p>
<p><img src="Ch5/5.10.display_tst.png" alt="样例图片" /></p>
<p>最终的运行结果打印如下:</p>
<pre><code># 最优验证误差结果
Best validation score of 1.080000 %
# 测试误差结果
Test performance 1.030000 %
# 过程时耗
The code for file Mnist_CNN.py ran for 90.23m
</code></pre>
<p>从这里的结果可以看出:一方面,卷积神经网络训练<strong>计算规模庞大</strong>(当前软硬件环境下耗时一个半小时,);另一方面,得到的<strong>模型精度很高</strong>(在测试集上实现了约99%的精度,这基本意味着MNIST问题得到了解决)。</p>
<h2>3. 总结</h2>
<p>通过该实验,我们注意到:</p>
<ul>
<li>CNN是一种<strong>优秀</strong>的机器学习模型,能够实现较困难的学习任务;</li>
<li>以CNN为代表的“深度学习”模型的训练往往面临着<strong>巨大的计算量</strong>,为优化实现,一方面需要提升软硬件配置环境,另一方面要<strong>合理设计训练机制</strong>,包括MSGD、早停、正则化等辅助方法的合理运用;</li>
<li><strong>参数设置</strong>合理与否严重影响模型的训练效率和实现效果;</li>
</ul>
<p>通过该实验,我们回顾了<strong>卷积神经网络</strong>及其所代表的<strong>深度学习<strong>概念,练习了基于</strong>python-theano计算框架</strong>下的机器学习建模方法,为进一步的学习研究积累的实践经验。</p>
<h2>4. 参考</h2>
<p>下面列出相关参考:</p>
<ul>
<li>本文直接教程:<a href="http://blog.csdn.net/snoopy_yuan/article/details/71548243">深度学习基础 - 基于Theano-MLP的字符识别实验(MNIST)</a></li>
<li>本文直接教程:<a href="http://deeplearning.net/tutorial/lenet.html">Convolutional Neural Networks (LeNet)</a></li>
<li>一个有趣的可视化网站:<a href="http://scs.ryerson.ca/~aharley/vis/conv/">“CNN-数字识别”模型可视化</a></li>
<li>一个深度学习主页:<a href="http://deeplearning.net/tutorial/contents.html">Contents - DeepLearning 0.1 documentation</a></li>
</ul>
</body>
</html>
<!-- This document was created with MarkdownPad, the Markdown editor for Windows (http://markdownpad.com) -->