-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
3817 lines (3816 loc) · 730 KB
/
search.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
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>Ambari中Heartbeat lost问题</title>
<url>/p/2019/06/11/2992bf74/</url>
<content><![CDATA[<p>公司采用HDP的大数据平台,周六周日突然停电后,周一上班通过ambari发现组件heartbeat都lost。查了一圈,发现应该是正好碰到了低版本HDP的bug。下面是实践后有效的解决方式。<br><a id="more"></a></p>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/2992bf74/ed3e16f24c88e74bffe8d2f1df0846ce.png?x-oss-process=style/blog" alt="ambari-agent.log"></p>
<ol>
<li>确保防火墙关闭,能够ping通ambari-server服务所在机器的IP</li>
<li><p>升级openssl服务</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">yum upgrade openssl</span><br></pre></td></tr></table></figure>
</li>
<li><p>关闭 openssl 的检查</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sed -i <span class="string">'s/verify=platform_default/verify=disable/'</span> /etc/python/cert-verification.cfg</span><br></pre></td></tr></table></figure>
</li>
<li><p>先停掉ambari-server,然后依次停掉各个ambari-agent</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ambari-server stop</span><br><span class="line">ambari-agent stop</span><br></pre></td></tr></table></figure>
</li>
<li><p>在所有ambari-agent节点上,修改ambari-agent.ini文件的[security],新增force_https_protocol如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">vi /etc/ambari-agent/conf/ambari-agent.ini</span><br><span class="line">[security]</span><br><span class="line">force_https_protocol=PROTOCOL_TLSv1_2</span><br></pre></td></tr></table></figure>
</li>
<li><p>依次开启ambari-agent,最后开启ambari-server</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ambari-server start</span><br><span class="line">ambari-agent start</span><br></pre></td></tr></table></figure>
</li>
</ol>
<hr>
<p>参考:<br><a href="https://community.hortonworks.com/questions/121978/openssl-compatibility.html?childToView=138080#answer-138080" target="_blank" rel="noopener">https://community.hortonworks.com/questions/121978/openssl-compatibility.html?childToView=138080#answer-138080</a></p>
]]></content>
<categories>
<category>FAQ</category>
<category>BigData</category>
</categories>
<tags>
<tag>hdp</tag>
<tag>ambari</tag>
<tag>heartbeat</tag>
<tag>大数据</tag>
</tags>
</entry>
<entry>
<title>设计模式简介</title>
<url>/p/2020/02/05/8a7312b/</url>
<content><![CDATA[<blockquote>
<p>软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。</p>
</blockquote>
<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>设计模式(英语 design pattern)是对面向对象设计中<strong>反复出现的问题</strong>的解决方案。这个术语是在1990年代由Erich Gamma等人从建筑设计领域引入到计算机科学中来的。这个术语的含义还存有争议。算法不是设计模式,因为算法致力于解决问题而非设计问题。设计模式通常描述了一组相互紧密作用的类与对象。设计模式提供一种讨论软件设计的公共语言,使得熟练设计者的设计经验可以被初学者和其他设计者掌握。设计模式还为软件重构提供了目标。</p>
<h3 id="什么是-GOF(四人帮,全拼-Gang-of-Four)?"><a href="#什么是-GOF(四人帮,全拼-Gang-of-Four)?" class="headerlink" title="什么是 GOF(四人帮,全拼 Gang of Four)?"></a>什么是 GOF(四人帮,全拼 Gang of Four)?</h3><p>在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。</p>
<p>四位作者合称 GOF(四人帮,全拼 Gang of Four)。他们所提出的设计模式主要是基于以下的面向对象设计原则。</p>
<ul>
<li><strong>对接口编程而不是对实现编程</strong>。</li>
<li><strong>优先使用对象组合而不是继承</strong>。</li>
</ul>
<a id="more"></a>
<h2 id="基本要素"><a href="#基本要素" class="headerlink" title="基本要素"></a>基本要素</h2><p>软件设计模式使人们可以更加简单方便地复用成功的设计和体系结构,它通常包含以下几个基本要素:模式名称、别名、动机、问题、解决方案、效果、结构、模式角色、合作关系、实现方法、适用性、已知应用、例程、模式扩展和相关模式等,其中最关键的元素包括以下 4 个主要部分。<br><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/8a7312b/Q20200205213002.png" alt="软件模式基本结构"></p>
<ol>
<li>模式名称<br>每一个模式都有自己的名字,通常用一两个词来描述,可以根据模式的问题、特点、解决方案、功能和效果来命名。模式名称(PatternName)有助于我们理解和记忆该模式,也方便我们来讨论自己的设计。</li>
<li>问题<br>问题(Problem)描述了该模式的应用环境,即何时使用该模式。它解释了设计问题和问题存在的前因后果,以及必须满足的一系列先决条件。</li>
<li>解决方案<br>模式问题的解决方案(Solution)包括设计的组成成分、它们之间的相互关系及各自的职责和协作方式。因为模式就像一个模板,可应用于多种不同场合,所以解决方案并不描述一个特定而具体的设计或实现,而是提供设计问题的抽象描述和怎样用一个具有一般意义的元素组合(类或对象的 组合)来解决这个问题。</li>
<li>效果<br>描述了模式的应用效果以及使用该模式应该权衡的问题,即模式的优缺点。主要是对时间和空间的衡量,以及该模式对系统的灵活性、扩充性、可移植性的影响,也考虑其实现问题。显式地列出这些效果(Consequence)对理解和评价这些模式有很大的帮助。</li>
</ol>
<h2 id="设计原则"><a href="#设计原则" class="headerlink" title="设计原则"></a>设计原则</h2><table>
<thead>
<tr>
<th style="text-align:left">设计原则名称</th>
<th style="text-align:left">定 义</th>
<th style="text-align:center">使用频率</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><a href="#开闭原则">开闭原则 (Open-Closed Principle, OCP)</a></td>
<td style="text-align:left">软件实体应对扩展开放,而对修改关闭</td>
<td style="text-align:center">★★★★★</td>
</tr>
<tr>
<td style="text-align:left"><a href="#单一职责原则">单一职责原则 (Single Responsibility Principle, SRP)</a></td>
<td style="text-align:left">一个类只负责一个功能领域中的相应职责</td>
<td style="text-align:center">★★★★☆</td>
</tr>
<tr>
<td style="text-align:left"><a href="#里氏代换原则">里氏代换原则 (Liskov Substitution Principle, LSP)</a></td>
<td style="text-align:left">所有引用基类对象的地方能够透明地使用其子类的对象</td>
<td style="text-align:center">★★★★★</td>
</tr>
<tr>
<td style="text-align:left"><a href="#依赖倒转原则">依赖倒转原则 (Dependence Inversion Principle, DIP)</a></td>
<td style="text-align:left">抽象不应该依赖于细节,细节应该依赖于抽象</td>
<td style="text-align:center">★★★★★</td>
</tr>
<tr>
<td style="text-align:left"><a href="#接口隔离原则">接口隔离原则 (Interface Segregation Principle, ISP)</a></td>
<td style="text-align:left">使用多个专门的接口,而不使用单一的总接口</td>
<td style="text-align:center">★★☆☆☆</td>
</tr>
<tr>
<td style="text-align:left"><a href="#迪米特法则">迪米特法则 (Law of Demeter, LoD)或称最少知识原则(Least Knowledge Principle,LKP)</a></td>
<td style="text-align:left">一个软件实体应当尽可能少地与其他实体发生相互作用</td>
<td style="text-align:center">★★★☆☆</td>
</tr>
<tr>
<td style="text-align:left"><a href="#合成复用原则">合成复用原则 (Composite Reuse Principle, CRP)</a></td>
<td style="text-align:left">尽量使用对象组合,而不是继承来达到复用的目的</td>
<td style="text-align:center">★★★★☆</td>
</tr>
</tbody>
</table>
<h3 id="开闭原则"><a href="#开闭原则" class="headerlink" title="开闭原则"></a>开闭原则</h3><p>开闭原则就是说对扩展开放,对修改关闭。当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求。开闭原则是面向对象程序设计的终极目标,它使软件实体拥有一定的适应性和灵活性的同时具备稳定性和延续性。具体来说,其作用如下:</p>
<ul>
<li>对软件测试的影响<br>软件遵守开闭原则的话,软件测试时只需要对扩展的代码进行测试就可以了,因为原有的测试代码仍然能够正常运行。</li>
<li>可以提高代码的可复用性<br>粒度越小,被复用的可能性就越大;在面向对象的程序设计中,根据原子和抽象编程可以提高代码的可复用性。</li>
<li>可以提高软件的可维护性<br>遵守开闭原则的软件,其稳定性高和延续性强,从而易于扩展和维护。</li>
</ul>
<p>可以通过“<strong>抽象约束、封装变化</strong>“来实现开闭原则,即通过接口或者抽象类为软件实体定义一个相对稳定的抽象层,而将相同的可变因素封装在相同的具体实现类中。<br>因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要发生变化时,只需要根据需求重新派生一个实现类来扩展就可以了。</p>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/8a7312b/page_3.png" alt="某CRM中客户信息图形统计模块"></p>
<h3 id="单一职责原则"><a href="#单一职责原则" class="headerlink" title="单一职责原则"></a>单一职责原则</h3><p>这里的职责是指类变化的原因,单一职责原则规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分。单一职责原则的核心就是控制类的粒度大小、<strong>将对象解耦、提高其内聚性</strong>。如果遵循单一职责原则将有以下优点:</p>
<ul>
<li>降低类的复杂度。一个类只负责一项职责,其逻辑肯定要比负责多项职责简单得多。</li>
<li>提高类的可读性。复杂性降低,自然其可读性会提高。</li>
<li>提高系统的可维护性。可读性提高,那自然更容易维护了。</li>
<li>变更引起的风险降低。变更是必然的,如果单一职责原则遵守得好,当修改一个功能时,可以显著降低对其他功能的影响。</li>
</ul>
<p>单一职责原则是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,再封装到不同的类或模块中。而发现类的多重职责需要设计人员具有较强的分析设计能力和相关重构经验。</p>
<p>单一职责同样也适用于方法。一个方法应该尽可能做好一件事情。如果一个方法处理的事情太多,其颗粒度会变得很粗,不利于重用。</p>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/8a7312b/page_2.png" alt="某CRM中客户信息图形统计模块"></p>
<h3 id="里氏代换原则"><a href="#里氏代换原则" class="headerlink" title="里氏代换原则"></a>里氏代换原则</h3><p>里氏替换原则主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中蕴含的原理。里氏替换原则是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。具体来说,其作用如下:</p>
<ul>
<li>里氏替换原则是实现开闭原则的重要方式之一。</li>
<li>它克服了继承中重写父类造成的可复用性变差的缺点。</li>
<li>它是动作正确性的保证。即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。</li>
</ul>
<p>里氏替换原则通俗来讲就是:<strong>子类可以扩展父类的功能,但不能改变父类原有的功能</strong>。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。</p>
<ul>
<li>如果通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的概率会非常大。</li>
<li>如果程序违背了里氏替换原则,则继承类的对象在基类出现的地方会出现运行错误。这时其修正方法是:取消原来的继承关系,重新设计它们之间的关系。</li>
</ul>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/8a7312b/page_4.png" alt="某CRM中客户信息图形统计模块"></p>
<h3 id="依赖倒转原则"><a href="#依赖倒转原则" class="headerlink" title="依赖倒转原则"></a>依赖倒转原则</h3><p>依赖倒置原则的原始定义为:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程。依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给它们的实现类去完成。具体来说,其作用如下:</p>
<ul>
<li>依赖倒置原则可以降低类间的耦合性。</li>
<li>依赖倒置原则可以提高系统的稳定性。</li>
<li>依赖倒置原则可以减少并行开发引起的风险。</li>
<li>依赖倒置原则可以提高代码的可读性和可维护性。</li>
</ul>
<p>依赖倒置原则的目的是通过要<strong>面向接口</strong>的编程来降低类间的耦合性,所以我们在实际编程中只要遵循以下几点,就能在项目中满足这个规则。</p>
<ul>
<li>每个类尽量提供接口或抽象类,或者两者都具备。</li>
<li>变量的声明类型尽量是接口或者是抽象类。</li>
<li>任何类都不应该从具体类派生。</li>
<li>使用继承时尽量遵循里氏替换原则。</li>
</ul>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/8a7312b/page_5.png" alt="某CRM中客户信息图形统计模块"></p>
<h3 id="接口隔离原则"><a href="#接口隔离原则" class="headerlink" title="接口隔离原则"></a>接口隔离原则</h3><p>要求程序员尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含客户感兴趣的方法。要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。</p>
<blockquote>
<p>接口隔离原则和单一职责都是为了提高类的内聚性、降低它们之间的耦合性,体现了封装的思想,但两者是不同的:</p>
<ul>
<li>单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离。</li>
<li>单一职责原则主要是约束类,它针对的是程序中的实现和细节;接口隔离原则主要约束接口,主要针对抽象和程序整体框架的构建。</li>
</ul>
</blockquote>
<p>接口隔离原则是为了约束接口、降低类对接口的依赖性,遵循接口隔离原则有以下5个优点:</p>
<ul>
<li>将臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。</li>
<li>接口隔离提高了系统的内聚性,减少了对外交互,降低了系统的耦合性。</li>
<li>如果接口的粒度大小定义合理,能够保证系统的稳定性;但是,如果定义过小,则会造成接口数量过多,使设计复杂化;如果定义太大,灵活性降低,无法提供定制服务,给整体项目带来无法预料的风险。</li>
<li>使用多个专门的接口还能够体现对象的层次,因为可以通过接口的继承,实现对总接口的定义。</li>
<li>能减少项目工程中的代码冗余。过大的大接口里面通常放置许多不用的方法,当实现这个接口的时候,被迫设计冗余的代码。</li>
</ul>
<p>在具体应用接口隔离原则时,应该根据以下几个规则来衡量。</p>
<ul>
<li>接口尽量小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。</li>
<li>为依赖接口的类定制服务。只提供调用者需要的方法,屏蔽不需要的方法。</li>
<li>了解环境,拒绝盲从。每个项目或产品都有选定的环境因素,环境不同,接口拆分的标准就不同深入了解业务逻辑。</li>
<li>提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。</li>
</ul>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/8a7312b/page_6.png" alt="某CRM中客户信息图形统计模块"></p>
<h3 id="迪米特法则"><a href="#迪米特法则" class="headerlink" title="迪米特法则"></a>迪米特法则</h3><p>迪米特法则的定义是:只与你的直接朋友交谈,不跟“陌生人”说话。其含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。迪米特法则中的“朋友”是指:当前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等,这些对象同当前对象存在关联、聚合或组合关系,可以直接访问这些对象的方法。</p>
<p>迪米特法则要求限制软件实体之间通信的宽度和深度,正确使用迪米特法则将有以下两个优点:</p>
<ul>
<li>降低了类之间的耦合度,提高了模块的相对独立性。</li>
<li>由于亲合度降低,从而提高了类的可复用率和系统的扩展性。</li>
</ul>
<p><em>但是,过度使用迪米特法则会使系统产生大量的中介类,从而增加系统的复杂性,使模块之间的通信效率降低。所以,在釆用迪米特法则时需要反复权衡,确保高内聚和低耦合的同时,保证系统的结构清晰。</em></p>
<p>在运用迪米特法则时要注意以下几点:</p>
<ul>
<li>在类的划分上,应该创建弱耦合的类。类与类之间的耦合越弱,就越有利于实现可复用的目标。</li>
<li>在类的结构设计上,尽量降低类成员的访问权限。</li>
<li>在类的设计上,优先考虑将一个类设置成不变类。</li>
<li>在对其他类的引用上,将引用其他对象的次数降到最低。</li>
<li>不暴露类的属性成员,而应该提供相应的访问器(set 和 get 方法)。</li>
<li>谨慎使用序列化(Serializable)功能。</li>
</ul>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/8a7312b/page_7.png" alt="某CRM中业务操作窗口模块"></p>
<h3 id="合成复用原则"><a href="#合成复用原则" class="headerlink" title="合成复用原则"></a>合成复用原则</h3><p>合成复用原则又叫组合/聚合复用原则(Composition/Aggregate Reuse Principle,CARP)。它要求在软件复用时,要尽量先<strong>使用组合或者聚合等关联关系</strong>来实现,其次才考虑使用继承关系来实现。如果要使用继承关系,则必须严格遵循里氏替换原则。合成复用原则同里氏替换原则相辅相成的,两者都是开闭原则的具体实现规范。</p>
<blockquote>
<p>通常类的复用分为继承复用和合成复用两种,继承复用虽然有简单和易实现的优点,但它也存在以下缺点。</p>
<ol>
<li>继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。</li>
<li>子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。</li>
<li>它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化。</li>
</ol>
</blockquote>
<p>采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点。</p>
<ul>
<li>它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。</li>
<li>新旧类之间的耦合度低。这种复用所需的依赖较少,新对象存取成分对象的唯一方法是通过成分对象的接口。</li>
<li>复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。</li>
</ul>
<p>合成复用原则是通过将已有的对象纳入新对象中,作为新对象的成员对象来实现的,新对象可以调用已有对象的功能,从而达到复用。</p>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/8a7312b/page_8.png" alt="某CRM中客户信息图形统计模块"></p>
<h2 id="分类"><a href="#分类" class="headerlink" title="分类"></a>分类</h2><p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/8a7312b/1354152786_2931.jpg" alt="设计模式之间的关系"></p>
<h3 id="创建型模式(Creational-Patterns)"><a href="#创建型模式(Creational-Patterns)" class="headerlink" title="创建型模式(Creational Patterns)"></a>创建型模式(Creational Patterns)</h3><p>创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是“<strong>将对象的创建与使用分离</strong>”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节,对象的创建由相关的工厂来完成。就像我们去商场购买商品时,不需要知道商品是怎么生产出来一样,因为它们由专门的厂商生产。</p>
<p>创建型模式分为以下几种。</p>
<ul>
<li><strong>单例(Singleton)模式</strong>:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。</li>
<li><strong>原型(Prototype)模式</strong>:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。</li>
<li><strong>工厂方法(FactoryMethod)模式</strong>:定义一个用于创建产品的接口,由子类决定生产什么产品。</li>
<li><strong>抽象工厂(AbstractFactory)模式</strong>:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。</li>
<li><strong>建造者(Builder)模式</strong>:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。</li>
</ul>
<p>以上 5 种创建型模式,除了工厂方法模式属于类创建型模式,其他的全部属于对象创建型模式。</p>
<h4 id="单例模式(Singleton-Pattern)"><a href="#单例模式(Singleton-Pattern)" class="headerlink" title="单例模式(Singleton Pattern)"></a>单例模式(Singleton Pattern)</h4><blockquote>
<p>在有些系统中,为了节省内存资源、保证数据内容的一致性,对某些类要求只能创建一个实例,这就是所谓的单例模式。</p>
</blockquote>
<h4 id="原型模式(Prototype-Pattern)"><a href="#原型模式(Prototype-Pattern)" class="headerlink" title="原型模式(Prototype Pattern)"></a>原型模式(Prototype Pattern)</h4><h4 id="工厂模式(Factory-Pattern)"><a href="#工厂模式(Factory-Pattern)" class="headerlink" title="工厂模式(Factory Pattern)"></a>工厂模式(Factory Pattern)</h4><h4 id="抽象工厂模式(Abstract-Factory-Pattern)"><a href="#抽象工厂模式(Abstract-Factory-Pattern)" class="headerlink" title="抽象工厂模式(Abstract Factory Pattern)"></a>抽象工厂模式(Abstract Factory Pattern)</h4><h4 id="建造者模式(Builder-Pattern)"><a href="#建造者模式(Builder-Pattern)" class="headerlink" title="建造者模式(Builder Pattern)"></a>建造者模式(Builder Pattern)</h4><h3 id="结构型模式(Structural-Patterns)"><a href="#结构型模式(Structural-Patterns)" class="headerlink" title="结构型模式(Structural Patterns)"></a>结构型模式(Structural Patterns)</h3><p>结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。<br>由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。</p>
<p>结构型模式分为以下 7 种:</p>
<ul>
<li><strong>代理(Proxy)模式</strong>:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。</li>
<li><strong>适配器(Adapter)模式</strong>:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。</li>
<li><strong>桥接(Bridge)模式</strong>:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现的,从而降低了抽象和实现这两个可变维度的耦合度。</li>
<li><strong>装饰(Decorator)模式</strong>:动态地给对象增加一些职责,即增加其额外的功能。</li>
<li><strong>外观(Facade)模式</strong>:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。</li>
<li><strong>享元(Flyweight)模式</strong>:运用共享技术来有效地支持大量细粒度对象的复用。</li>
<li><strong>组合(Composite)模式</strong>:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。</li>
</ul>
<p>以上 7 种结构型模式,除了适配器模式分为类结构型模式和对象结构型模式两种,其他的全部属于对象结构型模式。</p>
<h4 id="适配器模式(Adapter-Pattern)"><a href="#适配器模式(Adapter-Pattern)" class="headerlink" title="适配器模式(Adapter Pattern)"></a>适配器模式(Adapter Pattern)</h4><h4 id="桥接模式(Bridge-Pattern)"><a href="#桥接模式(Bridge-Pattern)" class="headerlink" title="桥接模式(Bridge Pattern)"></a>桥接模式(Bridge Pattern)</h4><h4 id="过滤器模式(Filter、Criteria-Pattern)"><a href="#过滤器模式(Filter、Criteria-Pattern)" class="headerlink" title="过滤器模式(Filter、Criteria Pattern)"></a>过滤器模式(Filter、Criteria Pattern)</h4><h4 id="组合模式(Composite-Pattern)"><a href="#组合模式(Composite-Pattern)" class="headerlink" title="组合模式(Composite Pattern)"></a>组合模式(Composite Pattern)</h4><h4 id="装饰器模式(Decorator-Pattern)"><a href="#装饰器模式(Decorator-Pattern)" class="headerlink" title="装饰器模式(Decorator Pattern)"></a>装饰器模式(Decorator Pattern)</h4><h4 id="外观模式(Facade-Pattern)"><a href="#外观模式(Facade-Pattern)" class="headerlink" title="外观模式(Facade Pattern)"></a>外观模式(Facade Pattern)</h4><h4 id="享元模式(Flyweight-Pattern)"><a href="#享元模式(Flyweight-Pattern)" class="headerlink" title="享元模式(Flyweight Pattern)"></a>享元模式(Flyweight Pattern)</h4><h4 id="代理模式(Proxy-Pattern)"><a href="#代理模式(Proxy-Pattern)" class="headerlink" title="代理模式(Proxy Pattern)"></a>代理模式(Proxy Pattern)</h4><h3 id="行为型模式(Behavioral-Patterns)"><a href="#行为型模式(Behavioral-Patterns)" class="headerlink" title="行为型模式(Behavioral Patterns)"></a>行为型模式(Behavioral Patterns)</h3><p>行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。</p>
<p>行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。</p>
<p>行为型模式是 GoF 设计模式中最为庞大的一类,它包含以下 11 种模式。</p>
<ul>
<li><strong>模板方法(Template Method)模式</strong>:定义一个操作中的算法骨架,将算法的一些步骤延迟到子类中,使得子类在可以不改变该算法结构的情况下重定义该算法的某些特定步骤。</li>
<li><strong>策略(Strategy)模式</strong>:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。</li>
<li><strong>命令(Command)模式</strong>:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。</li>
<li><strong>职责链(Chain of Responsibility)模式</strong>:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。</li>
<li><strong>状态(State)模式</strong>:允许一个对象在其内部状态发生改变时改变其行为能力。</li>
<li><strong>观察者(Observer)模式</strong>:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。</li>
<li><strong>中介者(Mediator)模式</strong>:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。</li>
<li><strong>迭代器(Iterator)模式</strong>:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。</li>
<li><strong>访问者(Visitor)模式</strong>:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。</li>
<li><strong>备忘录(Memento)模式</strong>:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。</li>
<li><strong>解释器(Interpreter)模式</strong>:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。</li>
</ul>
<p>以上 11 种行为型模式,除了模板方法模式和解释器模式是类行为型模式,其他的全部属于对象行为型模式,下面我们将详细介绍它们的特点、结构与应用。</p>
<h4 id="责任链模式(Chain-of-Responsibility-Pattern)"><a href="#责任链模式(Chain-of-Responsibility-Pattern)" class="headerlink" title="责任链模式(Chain of Responsibility Pattern)"></a>责任链模式(Chain of Responsibility Pattern)</h4><h4 id="命令模式(Command-Pattern)"><a href="#命令模式(Command-Pattern)" class="headerlink" title="命令模式(Command Pattern)"></a>命令模式(Command Pattern)</h4><h4 id="解释器模式(Interpreter-Pattern)"><a href="#解释器模式(Interpreter-Pattern)" class="headerlink" title="解释器模式(Interpreter Pattern)"></a>解释器模式(Interpreter Pattern)</h4><h4 id="迭代器模式(Iterator-Pattern)"><a href="#迭代器模式(Iterator-Pattern)" class="headerlink" title="迭代器模式(Iterator Pattern)"></a>迭代器模式(Iterator Pattern)</h4><h4 id="中介者模式(Mediator-Pattern)"><a href="#中介者模式(Mediator-Pattern)" class="headerlink" title="中介者模式(Mediator Pattern)"></a>中介者模式(Mediator Pattern)</h4><h4 id="备忘录模式(Memento-Pattern)"><a href="#备忘录模式(Memento-Pattern)" class="headerlink" title="备忘录模式(Memento Pattern)"></a>备忘录模式(Memento Pattern)</h4><h4 id="观察者模式(Observer-Pattern)"><a href="#观察者模式(Observer-Pattern)" class="headerlink" title="观察者模式(Observer Pattern)"></a>观察者模式(Observer Pattern)</h4><h4 id="状态模式(State-Pattern)"><a href="#状态模式(State-Pattern)" class="headerlink" title="状态模式(State Pattern)"></a>状态模式(State Pattern)</h4><h4 id="空对象模式(Null-Object-Pattern)"><a href="#空对象模式(Null-Object-Pattern)" class="headerlink" title="空对象模式(Null Object Pattern)"></a>空对象模式(Null Object Pattern)</h4><h4 id="策略模式(Strategy-Pattern)"><a href="#策略模式(Strategy-Pattern)" class="headerlink" title="策略模式(Strategy Pattern)"></a>策略模式(Strategy Pattern)</h4><h4 id="模板模式(Template-Pattern)"><a href="#模板模式(Template-Pattern)" class="headerlink" title="模板模式(Template Pattern)"></a>模板模式(Template Pattern)</h4><h4 id="访问者模式(Visitor-Pattern)"><a href="#访问者模式(Visitor-Pattern)" class="headerlink" title="访问者模式(Visitor Pattern)"></a>访问者模式(Visitor Pattern)</h4><h3 id="J2EE-模式"><a href="#J2EE-模式" class="headerlink" title="J2EE 模式"></a>J2EE 模式</h3><h4 id="MVC-模式(MVC-Pattern)"><a href="#MVC-模式(MVC-Pattern)" class="headerlink" title="MVC 模式(MVC Pattern)"></a>MVC 模式(MVC Pattern)</h4><h4 id="业务代表模式(Business-Delegate-Pattern)"><a href="#业务代表模式(Business-Delegate-Pattern)" class="headerlink" title="业务代表模式(Business Delegate Pattern)"></a>业务代表模式(Business Delegate Pattern)</h4><h4 id="组合实体模式(Composite-Entity-Pattern)"><a href="#组合实体模式(Composite-Entity-Pattern)" class="headerlink" title="组合实体模式(Composite Entity Pattern)"></a>组合实体模式(Composite Entity Pattern)</h4><h4 id="数据访问对象模式(Data-Access-Object-Pattern)"><a href="#数据访问对象模式(Data-Access-Object-Pattern)" class="headerlink" title="数据访问对象模式(Data Access Object Pattern)"></a>数据访问对象模式(Data Access Object Pattern)</h4><h4 id="前端控制器模式(Front-Controller-Pattern)"><a href="#前端控制器模式(Front-Controller-Pattern)" class="headerlink" title="前端控制器模式(Front Controller Pattern)"></a>前端控制器模式(Front Controller Pattern)</h4><h4 id="拦截过滤器模式(Intercepting-Filter-Pattern)"><a href="#拦截过滤器模式(Intercepting-Filter-Pattern)" class="headerlink" title="拦截过滤器模式(Intercepting Filter Pattern)"></a>拦截过滤器模式(Intercepting Filter Pattern)</h4><h4 id="服务定位器模式(Service-Locator-Pattern)"><a href="#服务定位器模式(Service-Locator-Pattern)" class="headerlink" title="服务定位器模式(Service Locator Pattern)"></a>服务定位器模式(Service Locator Pattern)</h4><h4 id="传输对象模式(Transfer-Object-Pattern)"><a href="#传输对象模式(Transfer-Object-Pattern)" class="headerlink" title="传输对象模式(Transfer Object Pattern)"></a>传输对象模式(Transfer Object Pattern)</h4><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><p>[^3]:<a href="https://baike.baidu.com/item/%E8%BD%AF%E4%BB%B6%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/2117635?fromtitle=%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F&fromid=1212549&fr=aladdin" target="_blank" rel="noopener">https://baike.baidu.com/item/%E8%BD%AF%E4%BB%B6%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/2117635?fromtitle=%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F&fromid=1212549&fr=aladdin</a></p>
]]></content>
<categories>
<category>TODO</category>
<category>Java</category>
<category>Design Patterns</category>
</categories>
<tags>
<tag>java</tag>
<tag>design patterns</tag>
</tags>
</entry>
<entry>
<title>Task1 线性回归&Softmax与分类模型&多层感知机</title>
<url>/p/2020/02/13/966c0826/</url>
<content><![CDATA[<h1 id="线性回归"><a href="#线性回归" class="headerlink" title="线性回归"></a>线性回归</h1><h2 id="线性回归的基本要素"><a href="#线性回归的基本要素" class="headerlink" title="线性回归的基本要素"></a>线性回归的基本要素</h2><h3 id="模型"><a href="#模型" class="headerlink" title="模型"></a>模型</h3><p>为了简单起见,这里我们假设价格只取决于房屋状况的两个因素,即面积(平方米)和房龄(年)。接下来我们希望探索价格与这两个因素的具体关系。线性回归假设输出与各个输入之间是线性关系:</p>
<h3 id="数据集"><a href="#数据集" class="headerlink" title="数据集"></a>数据集</h3><p>我们通常收集一系列的真实数据,例如多栋房屋的真实售出价格和它们对应的面积和房龄。我们希望在这个数据上面寻找模型参数来使模型的预测价格与真实价格的误差最小。在机器学习术语里,该数据集被称为训练数据集(training data set)或训练集(training set),一栋房屋被称为一个样本(sample),其真实售出价格叫作标签(label),用来预测标签的两个因素叫作特征(feature)。特征用来表征样本的特点。</p>
<h3 id="损失函数"><a href="#损失函数" class="headerlink" title="损失函数"></a>损失函数</h3><p>在模型训练中,我们需要衡量价格预测值与真实值之间的误差。通常我们会选取一个非负数作为误差,且数值越小表示误差越小。一个常用的选择是平方函数。 它在评估索引为 的样本误差的表达式为</p>
<a id="more"></a>
<h3 id="优化函数-随机梯度下降"><a href="#优化函数-随机梯度下降" class="headerlink" title="优化函数 - 随机梯度下降"></a>优化函数 - 随机梯度下降</h3><p>当模型和损失函数形式较为简单时,上面的误差最小化问题的解可以直接用公式表达出来。这类解叫作解析解(analytical solution)。本节使用的线性回归和平方误差刚好属于这个范畴。然而,大多数深度学习模型并没有解析解,只能通过优化算法有限次迭代模型参数来尽可能降低损失函数的值。这类解叫作数值解(numerical solution)。</p>
<p>在求数值解的优化算法中,小批量随机梯度下降(mini-batch stochastic gradient descent)在深度学习中被广泛使用。它的算法很简单:先选取一组模型参数的初始值,如随机选取;接下来对参数进行多次迭代,使每次迭代都可能降低损失函数的值。在每次迭代中,先随机均匀采样一个由固定数目训练数据样本所组成的小批量(mini-batch),然后求小批量中数据样本的平均损失有关模型参数的导数(梯度),最后用此结果与预先设定的一个正数的乘积作为模型参数在本次迭代的减小量。</p>
<p>学习率: 代表在每次优化中,能够学习的步长的大小<br>批量大小: 是小批量计算中的批量大小batch size</p>
<p>总结一下,优化函数的有以下两个步骤:</p>
<p>(i)初始化模型参数,一般来说使用随机初始化;<br>(ii)我们在数据上迭代多次,通过在负梯度方向移动参数来更新每个参数。</p>
<h2 id="矢量计算"><a href="#矢量计算" class="headerlink" title="矢量计算"></a>矢量计算</h2><p>在模型训练或预测时,我们常常会同时处理多个数据样本并用到矢量计算。在介绍线性回归的矢量计算表达式之前,让我们先考虑对两个向量相加的两种方法。</p>
<p>向量相加的一种方法是,将这两个向量按元素逐一做标量加法。<br>向量相加的另一种方法是,将这两个向量直接做矢量加法。</p>
<h2 id="笔记整理"><a href="#笔记整理" class="headerlink" title="笔记整理"></a>笔记整理</h2><p>实现顺序</p>
<ol>
<li>生成数据集:随机标签,指定参数,计算标准结果添加噪声</li>
<li>定义模型</li>
<li>定义损失函数</li>
<li>定义优化模型</li>
<li>训练模型<ol>
<li>设置超参,初始化模型参数</li>
<li>每次迭代中,小批量读取数据,初始化模型计算预测值,损失函数计算插值,反向传播求梯度,优化算法更新参数,参数梯度清零</li>
</ol>
</li>
</ol>
<ul>
<li>数据集一般分为训练集、验证集、测试集</li>
<li>真实预测值称为label,用来预测标签的因素feature</li>
<li>预测结果偏差:损失函数(均方误差),可以直接求和多个样本</li>
<li>调整模型参数:优化函数(梯度下降,梯度反方向),迭代后损失函数值减小</li>
</ul>
<h1 id="Softmax与分类模型"><a href="#Softmax与分类模型" class="headerlink" title="Softmax与分类模型"></a>Softmax与分类模型</h1><blockquote>
<p>Softmax逻辑回归模型是logistic回归模型在多分类问题上的推广,在多分类问题中,类标签y可以取两个以上的值。 Softmax回归模型对于诸如MNIST手写数字分类等问题是很有用的,该问题的目的是辨识10个不同的单个数字。Softmax回归是有监督的,不过后面也会介绍它与深度学习无监督学习方法的结合。</p>
</blockquote>
<p>在机器学习尤其是深度学习中,softmax是个非常常用而且比较重要的函数,尤其在多分类的场景中使用广泛。他把一些输入映射为0-1之间的实数,并且归一化保证和为1,因此多分类的概率之和也刚好为1。<br>首先我们简单来看看softmax是什么意思。顾名思义,softmax由两个单词组成,其中一个是max。对于max我们都很熟悉,比如有两个变量a,b。如果a>b,则max为a,反之为b。用伪码简单描述一下就是<code>if a > b return a; else b</code>。<br>另外一个单词为soft。max存在的一个问题是什么呢?如果将max看成一个分类问题,就是非黑即白,最后的输出是一个确定的变量。更多的时候,我们希望输出的是取到某个分类的概率,或者说,我们希望分值大的那一项被经常取到,而分值较小的那一项也有一定的概率偶尔被取到,所以我们就应用到了soft的概念,即最后的输出是每个分类被取到的概率。</p>
<h2 id="Softmax的定义-3"><a href="#Softmax的定义-3" class="headerlink" title="Softmax的定义^3"></a>Softmax的定义<a href="https://blog.csdn.net/bitcarmanlee/article/details/82320853" target="_blank" rel="noopener">^3</a></h2><p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/966c0826/5236230-12cd299a8d571d1e.png" alt="求导过程"></p>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/966c0826/5236230-c91debe62a989306.png" alt="求导过程"></p>
<h2 id="笔记整理-1"><a href="#笔记整理-1" class="headerlink" title="笔记整理"></a>笔记整理</h2><p>这是由于softmax函数的常数不变性,即softmax(x)=softmax(x+c),推导如下:<br>$$<br>softmax(x_i)=\frac{exp(x_i)}{\sum_jexp(x_j)}<br>$$</p>
<p>$$<br>(softmax(x+c))_i=\frac{exp(x_i+c)}{\sum_j exp(x_j+c)}=\frac{exp(c)exp(x_i)}{exp(c)\sum_jexp(x_j)}=\frac{exp(x_i)}{\sum_jexp(x_j)}=(softmax(x))_i<br>$$<br>上面的exp(c)之所以可以消除,是因为exp(a+b)=exp(a)*exp(b)这个特性将exp(c)提取出来了。<br>在计算softmax概率的时候,为了保证数值稳定性(numerical stability),我们可以选择给输入项减去一个常数,比如x的每个元素都要减去一个x中的最大元素。当输入项很大的时候,如果不减这样一个常数,取指数之后结果会变得非常大,发生溢出的现象,导致结果出现inf。</p>
<p>softmax函数是来自于sigmoid函数在多分类情况下的推广,他们的相同之处:</p>
<ol>
<li>都具有良好的数据压缩能力是实数域R→[ 0 , 1 ]的映射函数,可以将杂乱无序没有实际含义的数字直接转化为每个分类的可能性概率。</li>
<li>都具有非常漂亮的导数形式,便于反向传播计算。</li>
<li>它们都是 soft version of max ,都可以将数据的差异明显化。</li>
</ol>
<p>相同的,他们具有着不同的特点,sigmoid函数可以看成softmax函数的特例,softmax函数也可以看作sigmoid函数的推广。</p>
<ol>
<li>sigmoid函数前提假设是样本服从伯努利 (Bernoulli) 分布的假设,而softmax则是基于多项式分布。首先证明多项分布属于指数分布族,这样就可以使用广义线性模型来拟合这个多项分布,由广义线性模型推导出的目标函数即为Softmax回归的分类模型。 </li>
<li>sigmoid函数用于分辨每一种情况的可能性,所以用sigmoid函数实现多分类问题的时候,概率并不是归一的,反映的是每个情况的发生概率,因此非互斥的问题使用sigmoid函数可以获得比较漂亮的结果;softmax函数最初的设计思路适用于首先数字识别这样的互斥的多分类问题,因此进行了归一化操作,使得最后预测的结果是唯一的。</li>
</ol>
<p>softmax基本概念</p>
<ul>
<li>分类问题: 用来预测种类,图像识别,离散数值来表示不同类别</li>
<li>权重失量</li>
<li>神经网络图<br>单层神经网络,类别与变量间对应关系</li>
<li>输出问题<ol>
<li>范围不确定</li>
<li>真实为离散值,输出不确定范围误差难以衡量</li>
</ol>
</li>
<li>softmax值变换为值为正和为1,不改变预测类别输出</li>
<li>小批量矢量计算</li>
<li>交叉熵,保证正确预测类别的值大<br><code>print(X.sum(dim=0, keepdim=True))#按相同列求和,保留列特征</code><br><code>print(X.sum(dim=1, keepdim=True))#按相同行求和,保留行特征</code></li>
</ul>
<h1 id="多层感知机"><a href="#多层感知机" class="headerlink" title="多层感知机"></a>多层感知机</h1><p>多层感知器(MLP,Multilayer Perceptron)是一种前馈人工神经网络模型,其将输入的多个数据集映射到单一的输出的数据集上。</p>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/966c0826/mlp.svg" alt="带有隐藏层的多层感知机。它含有一个隐藏层,该层中有5个隐藏单元"></p>
<p>多层感知机在单层神经网络的基础上引入了一到多个隐藏层(hidden layer)。隐藏层位于输入层和输出层之间。<br>所示的多层感知机中,输入和输出个数分别为4和3,中间的隐藏层中包含了5个隐藏单元(hidden unit)。由于输入层不涉及计算,上图中的多层感知机的层数为2。由上图可见,隐藏层中的神经元和输入层中各个输入完全连接,输出层中的神经元和隐藏层中的各个神经元也完全连接。因此,多层感知机中的隐藏层和输出层都是全连接层。</p>
<p>具体来说,给定一个小批量样本$\boldsymbol{X} \in \mathbb{R}^{n \times d}$ ,其批量大小为 n ,输入个数为 d 。假设多层感知机只有一个隐藏层,其中隐藏单元个数为 h 。记隐藏层的输出(也称为隐藏层变量或隐藏变量)为 H ,有$\boldsymbol{H} \in \mathbb{R}^{n \times h}$ 。因为隐藏层和输出层均是全连接层,可以设隐藏层的权重参数和偏差参数分别为$\boldsymbol{W}_h \in \mathbb{R}^{d \times h}$和$\boldsymbol{b}_h \in \mathbb{R}^{1 \times h}$,输出层的权重和偏差参数分别为$\boldsymbol{W}_o \in \mathbb{R}^{h \times q}$和$\boldsymbol{b}_o \in \mathbb{R}^{1 \times q}$。</p>
<p>我们先来看一种含单隐藏层的多层感知机的设计。其输出$\boldsymbol{O} \in \mathbb{R}^{n \times q}$的计算为<br>$$<br>\begin{split}\begin{aligned}<br>\boldsymbol{H} &= \boldsymbol{X} \boldsymbol{W}_h + \boldsymbol{b}_h,\<br>\boldsymbol{O} &= \boldsymbol{H} \boldsymbol{W}_o + \boldsymbol{b}_o,<br>\end{aligned}\end{split}<br>$$</p>
<p>也就是将隐藏层的输出直接作为输出层的输入。如果将以上两个式子联立起来,可以得到<br>$$<br>\boldsymbol{O} = (\boldsymbol{X} \boldsymbol{W}_h + \boldsymbol{b}_h)\boldsymbol{W}_o + \boldsymbol{b}_o = \boldsymbol{X} \boldsymbol{W}_h\boldsymbol{W}_o + \boldsymbol{b}_h \boldsymbol{W}_o + \boldsymbol{b}_o.<br>$$</p>
<p>从联立后的式子可以看出,虽然神经网络引入了隐藏层,却依然等价于一个单层神经网络:其中输出层权重参数为$\boldsymbol{W}_h\boldsymbol{W}_o$,偏差参数为$\boldsymbol{b}_h \boldsymbol{W}_o + \boldsymbol{b}_o$。不难发现,即便再添加更多的隐藏层,以上设计依然只能与仅含输出层的单层神经网络等价。</p>
<h2 id="笔记整理-2"><a href="#笔记整理-2" class="headerlink" title="笔记整理"></a>笔记整理</h2><p>多层感知机中最为重要的自然是“多层”,多层中涉及到的隐藏层的目的是为了将线性的神经网络复杂化,更加有效的逼近满足条件的任何一个函数。<br>因此文中先证明了一个最常见的思路,即两个线性层复合,是不可行的,无论多少层线性层复合最后得到的结果仍然是等价于线性层。这个结果的逻辑来自与线性代数中,H=XW+b 是一个仿射变换,通过W变换和b平移,而O=HW2+b2 则是通过W2变换和b2平移,最终经过矩阵的乘法和加法的运算法则(分配律)得到最终仍然是对X的仿射变换。<br>在线性层复合不行的情况下,最容易想到的思路就是将隐藏层变成非线性的,即通过一个“激励函数”将隐藏层的输出改变。<br>因此这里主要讨论一下,为什么添加激励函数后可以拟合“几乎”任意一个函数。<br>将函数分成三类:逻辑函数,分类函数,连续函数(分类的原则是输入输出形式)</p>
<ol>
<li>通过一个激励函数可以完成简单的或与非门逻辑,因此通过隐藏层中神经元复合就可以完成任何一个逻辑函数拟合。只需要通过神经网络的拟合将真值表完全表示</li>
<li>通过之前使用的线性分类器构成的线性边界进行复合便可以得到任意一个分类函数。</li>
<li>通过积分微元法的思想可以拟合任何一个普通的可积函数</li>
</ol>
<h2 id="Epoch-Batch-Iteration"><a href="#Epoch-Batch-Iteration" class="headerlink" title="Epoch, Batch, Iteration"></a>Epoch, Batch, Iteration</h2><p>深度学习的优化算法,说白了就是梯度下降。每次的参数更新有两种方式。</p>
<p>第一种,遍历全部数据集算一次损失函数,然后算函数对各个参数的梯度,更新梯度。这种方法每更新一次参数都要把数据集里的所有样本都看一遍,计算量开销大,计算速度慢,不支持在线学习,这称为Batch gradient descent,批梯度下降。</p>
<p>另一种,每看一个数据就算一下损失函数,然后求梯度更新参数,这个称为随机梯度下降,stochastic gradient descent。这个方法速度比较快,但是收敛性能不太好,可能在最优点附近晃来晃去,hit不到最优点。两次参数的更新也有可能互相抵消掉,造成目标函数震荡的比较剧烈。</p>
<p>为了克服两种方法的缺点,现在一般采用的是一种折中手段,mini-batch gradient decent,小批的梯度下降,这种方法把数据分为若干个批,按批来更新参数,这样,一个批中的一组数据共同决定了本次梯度的方向,下降起来就不容易跑偏,减少了随机性。另一方面因为批的样本数与整个数据集相比小了很多,计算量也不是很大。</p>
<p>现在用的优化器SGD是stochastic gradient descent的缩写,但不代表是一个样本就更新一回,还是基于mini-batch的。<br>那 batch epoch iteration代表什么呢?</p>
<ul>
<li>batchsize:批大小。在深度学习中,一般采用SGD训练,即每次训练在训练集中取batchsize个样本训练;</li>
<li>iteration:1个iteration等于使用batchsize个样本训练一次;</li>
<li>epoch:1个epoch等于使用训练集中的全部样本训练一次,通俗的讲epoch的值就是整个数据集被轮几次。</li>
</ul>
<p>比如训练集有500个样本,batchsize = 10 ,那么训练完整个样本集:iteration=50,epoch=1.<br>batch: 深度学习每一次参数的更新所需要损失函数并不是由一个数据获得的,而是由一组数据加权得到的,这一组数据的数量就是batchsize。<br>batchsize最大是样本总数N,此时就是Full batch learning;最小是1,即每次只训练一个样本,这就是在线学习(Online Learning)。当我们分批学习时,每次使用过全部训练数据完成一次Forword运算以及一次BP运算,成为完成了一次epoch。</p>
<p>mnist 数据集有 60000 张图片作为训练数据,10000 张图片作为测试数据。假设现在选择 Batch Size = 100 对模型进行训练。迭代30000次。</p>
<p>每个 Epoch 要训练的图片数量:60000(训练集上的所有图像)</p>
<ul>
<li>训练集具有的 Batch 个数: 60000/100=600</li>
<li>每个 Epoch 需要完成的 Batch 个数: 600</li>
<li>每个 Epoch 具有的 Iteration 个数: 600(完成一个Batch训练,相当于参数迭代一次)</li>
<li>每个 Epoch 中发生模型权重更新的次数:600</li>
<li>训练 10 个Epoch后,模型权重更新的次数: 600*10=6000</li>
<li>不同Epoch的训练,其实用的是同一个训练集的数据。第1个Epoch和第10个Epoch虽然用的都是训练集的60000图片,但是对模型的权重更新值却是完全不同的。因为不同Epoch的模型处于代价函数空间上的不同位置,模型的训练代越靠后,越接近谷底,其代价越小。</li>
<li>总共完成30000次迭代,相当于完成了 30000/600=50 个Epoch</li>
</ul>
<h1 id="笔记整理-3"><a href="#笔记整理-3" class="headerlink" title="笔记整理"></a>笔记整理</h1><ul>
<li><p>训练集、验证集和测试集的比例应该怎么去进行分配呢?<br>传统上是6:2:2的比例,但是不同的情况下你的选择应当不同。这方面的研究也有很多,如果你想要知道我们在设置比例的时候应当参考那些东西,可以去看Isabelle Guyon的这篇论文:A scaling law for the validation-set training-set size ratio 。他的个人主页(<a href="http://www.clopinet.com/isabelle/)里也展示了他对于这个问题的研究。" target="_blank" rel="noopener">http://www.clopinet.com/isabelle/)里也展示了他对于这个问题的研究。</a></p>
</li>
<li><p>训练集、验证集和测试集的数据是否可以有所重合?<br>有些时候我们的数据太少了,又不想使用数据增强,那么训练集、验证集和测试集的数据是否可以有所重合呢?这方面的研究就更多了,各种交叉方法,感兴趣的话可以去看Filzmoser这一篇文章Repeated double cross validation</p>
</li>
<li><p>torch.mm 和 torch.mul 的区别?<br>torch.mm是矩阵相乘,torch.mul是按元素相乘</p>
</li>
<li><p>torch.manual_seed(1)的作用?<br>设置随机种子,使实验结果可以复现</p>
</li>
<li><p>optimizer.zero_grad()的作用?<br>使梯度置零,防止不同batch得到的梯度累加</p>
</li>
<li><p>为什么选择的激活函数普遍具有梯度消失的特点?<br>开始的时候我一直好奇为什么选择的激活函数普遍具有梯度消失的特点,这样不就让部分神经元失活使最后结果出问题吗?后来看到一篇文章的描述才发现,正是因为模拟人脑的生物神经网络的方法。在2001年有研究表明生物脑的神经元工作具有稀疏性,这样可以节约尽可能多的能量,据研究,只有大约1%-4%的神经元被激活参与,绝大多数情况下,神经元是处于抑制状态的,因此ReLu函数反而是更加优秀的近似生物激活函数。<br>所以第一个问题,抑制现象是必须发生的,这样能更好的拟合特征。<br>那么自然也引申出了第二个问题,为什么sigmoid函数这类函数不行?</p>
</li>
</ul>
<ol>
<li>中间部分梯度值过小(最大只有0.25)因此即使在中间部分也没有办法明显的激活,反而会在多层中失活,表现非常不好。</li>
<li>指数运算在计算中过于复杂,不利于运算,反而ReLu函数用最简单的梯度<br>在第二条解决之后,我们来看看ReLu函数所遇到的问题,</li>
<li>在负向部分完全失活,如果选择的超参数不好等情况,可能会出现过多神经元失活,从而整个网络死亡。</li>
<li>ReLu函数不是zero-centered,即激活函数输出的总是非负值,而gradient也是非负值,在back propagate情况下总会得到与输入x相同的结果,同正或者同负,因此收敛会显著受到影响,一些要减小的参数和要增加的参数会受到捆绑限制。<br>这两个问题的解决方法分别是</li>
<li>如果出现神经元失活的情况,可以选择调整超参数或者换成Leaky ReLu 但是,没有证据证明任何情况下都是Leaky-ReLu好</li>
<li>针对非zero-centered情况,可以选择用minibatch gradient decent 通过batch里面的正负调整,或者使用ELU(Exponential Linear Units)但是同样具有计算量过大的情况,同样没有证据ELU总是优于ReLU。<br>所以绝大多数情况下建议使用ReLu。</li>
</ol>
<h1 id="pytorch内的函数"><a href="#pytorch内的函数" class="headerlink" title="pytorch内的函数"></a>pytorch内的函数</h1><p>torch.ones()/torch.zeros(),与MATLAB的ones/zeros很接近。初始化生成<br>均匀分布<br>torch.rand(<em>sizes, out=None) → Tensor<br>返回一个张量,包含了从区间[0, 1)的均匀分布中抽取的一组随机数。张量的形状由参数sizes定义。<br>标准正态分布<br>torch.randn(</em>sizes, out=None) → Tensor<br>返回一个张量,包含了从标准正态分布(均值为0,方差为1,即高斯白噪声)中抽取的一组随机数。张量的形状由参数sizes定义。<br>torch.mul(a, b)是矩阵a和b对应位相乘,a和b的维度必须相等,比如a的维度是(1, 2),b的维度是(1, 2),返回的仍是(1, 2)的矩阵<br>torch.mm(a, b)是矩阵a和b矩阵相乘,比如a的维度是(1, 2),b的维度是(2, 3),返回的就是(1, 3)的矩阵<br>torch.Tensor是一种包含单一数据类型元素的多维矩阵,定义了7种CPU tensor和8种GPU tensor类型。<br>random.shuffle(a):用于将一个列表中的元素打乱。shuffle() 是不能直接访问的,需要导入 random 模块,然后通过 random 静态对象调用该方法。<br>backward()是pytorch中提供的函数,配套有require_grad:<br>1.所有的tensor都有.requires_grad属性,可以设置这个属性.x = tensor.ones(2,4,requires_grad=True)<br>2.如果想改变这个属性,就调用tensor.requires_grad_()方法: x.requires_grad_(False)</p>
<h1 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h1>]]></content>
<categories>
<category>Datawhale</category>
<category>动手学深度学习</category>
</categories>
<tags>
<tag>datawhale</tag>
<tag>dl</tag>
<tag>深度学习</tag>
<tag>deep learning</tag>
<tag>动手学深度学习</tag>
</tags>
</entry>
<entry>
<title>Task2 文本预处理;语言模型;循环神经网络基础</title>
<url>/p/2020/02/13/b2a59db2/</url>
<content><![CDATA[<h1 id="文本预处理"><a href="#文本预处理" class="headerlink" title="文本预处理"></a>文本预处理</h1><p>文本预处理步骤:<br>1.读取文本 2.分词 3.构建字典 建立索引<br>Vocab字典构建步骤:<br>1.统计词频,去重筛选掉低频词<br>2.根据需求添加特殊的token<br>3.建立字典,将每个token建立映射到唯一的索引<br>4.建立索引到token的映射</p>
<p>建立词典:<br>词典的主要作用是将每一个词映射到一个唯一的索引号,主要构建了一个idx_to_token列表来存储所有的词,一个token_to_idx来存储所有词的索引。<br>在实现的的流程上是:<br>对语料进行分词,生成一个token列表,里面包含了语料的分词结果<br>对分好的词统计词频,然后根据词频来构建词典(统计好的词频完成了去重的操作,同时也保留了词的频率,方便后续的操作)<br>其中有一些名词的作用是视频里提出来的<br>pad的作用是在采用批量样本训练时,对于长度不同的样本(句子),对于短的样本采用pad进行填充,使得每个样本的长度是一致的<br>bos( begin of sentence)和eos(end of sentence)是用来表示一句话的开始和结尾<br>unk(unknow)的作用是,处理遇到从未出现在预料库的词时都统一认为是unknow ,在代码中还可以将一些频率特别低的词也归为这一类</p>
<ol>
<li>建立字典,设置阈值</li>
<li>去重筛选词,特殊需求token</li>
<li>count_corpus统计词频,得到counter</li>
<li>增删,利用空列表<ul>
<li>pad:二维矩阵长度不一,短句子补token利用pad</li>
<li>bos:开始token</li>
<li>eos:结束token</li>
<li>unk:未登录词当作unk</li>
</ul>
</li>
<li>词到索引号<a id="more"></a>
</li>
</ol>
<h1 id="语言模型"><a href="#语言模型" class="headerlink" title="语言模型"></a>语言模型</h1><h1 id="循环神经网络基础"><a href="#循环神经网络基础" class="headerlink" title="循环神经网络基础"></a>循环神经网络基础</h1>]]></content>
<categories>
<category>Datawhale</category>
<category>动手学深度学习</category>
</categories>
<tags>
<tag>datawhale</tag>
<tag>dl</tag>
<tag>深度学习</tag>
<tag>deep learning</tag>
<tag>动手学深度学习</tag>
</tags>
</entry>
<entry>
<title>《动手学深度学习》组队学习课程简介</title>
<url>/p/2020/02/13/f33d322f/</url>
<content><![CDATA[<blockquote>
<p><a href="https://www.boyuai.com/elites/course/cZu18YmweLv10OeV" target="_blank" rel="noopener">https://www.boyuai.com/elites/course/cZu18YmweLv10OeV</a></p>
</blockquote>
<p>本课程面向希望更多的通过代码实践去学习深度学习原理的同学和在职人士。</p>
<p>《动手学深度学习》是2019年国内最受欢迎的人工智能学习教材之一,伯禹教育携手上海交通大学团队,以此书的知识架构为基础,沿用了其中的原理讲解文档,并将代码框架由MXNET迁移至PyTorch,还对这些优质的实践代码制作了讲解视频。其中部分PyTorch代码来自GitHub开源仓库:<a href="https://github.com/ShusenTang/Dive-into-DL-PyTorch。" target="_blank" rel="noopener">https://github.com/ShusenTang/Dive-into-DL-PyTorch。</a></p>
<p>通过这门课程的学习,你将可以对深度学习中常见的方法以及相关的应用有一个从原理到实践的全面了解。</p>
<p>本课程主要针对代码进行讲解,理论基础较为薄弱的同学,建议配合《动手学深度学习》书籍或本平台上《机器学习》相关知识点学习。</p>
<p>《动手学深度学习》官方网址:<a href="http://zh.gluon.ai/" target="_blank" rel="noopener">http://zh.gluon.ai/</a> ——面向中文读者的能运行、可讨论的深度学习教科书。</p>
<a id="more"></a>
<hr>
<p>通俗来说,<strong>机器学习</strong>是一门讨论各式各样的适用于不同问题的函数形式,以及如何使用数据来有效地获取函数参数具体值的学科。<strong>深度学习</strong>是指机器学习中的一类函数,它们的形式通常为多层神经网络。近年来,仰仗着大数据集和强大的硬件,深度学习已逐渐成为处理图像、文本语料和声音信号等复杂高维度数据的主要方法。</p>
<h2 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h2><p>在描述深度学习的特点之前,我们先回顾并概括一下机器学习和深度学习的关系。机器学习研究如何使计算机系统利用经验改善性能。它是人工智能领域的分支,也是实现人工智能的一种手段。在机器学习的众多研究方向中,表征学习关注如何自动找出表示数据的合适方式,以便更好地将输入变换为正确的输出,而本书要重点探讨的深度学习是具有多级表示的表征学习方法。在每一级(从原始数据开始),深度学习通过简单的函数将该级的表示变换为更高级的表示。因此,深度学习模型也可以看作是由许多简单函数复合而成的函数。当这些复合的函数足够多时,深度学习模型就可以表达非常复杂的变换。</p>
<p>深度学习可以逐级表示越来越抽象的概念或模式。以图像为例,它的输入是一堆原始像素值。深度学习模型中,图像可以逐级表示为特定位置和角度的边缘、由边缘组合得出的花纹、由多种花纹进一步汇合得到的特定部位的模式等。最终,模型能够较容易根据更高级的表示完成给定的任务,如识别图像中的物体。值得一提的是,作为表征学习的一种,深度学习将自动找出每一级表示数据的合适方式。</p>
<p>因此,深度学习的一个外在特点是端到端的训练。也就是说,并不是将单独调试的部分拼凑起来组成一个系统,而是将整个系统组建好之后一起训练。比如说,计算机视觉科学家之前曾一度将特征抽取与机器学习模型的构建分开处理,像是Canny边缘探测 [20] 和SIFT特征提取 [21] 曾占据统治性地位达10年以上,但这也就是人类能找到的最好方法了。当深度学习进入这个领域后,这些特征提取方法就被性能更强的自动优化的逐级过滤器替代了。</p>
<p>相似地,在自然语言处理领域,词袋模型多年来都被认为是不二之选 [22]。词袋模型是将一个句子映射到一个词频向量的模型,但这样的做法完全忽视了单词的排列顺序或者句中的标点符号。不幸的是,我们也没有能力来手工抽取更好的特征。但是自动化的算法反而可以从所有可能的特征中搜寻最好的那个,这也带来了极大的进步。例如,语义相关的词嵌入能够在向量空间中完成如下推理:“柏林 - 德国 + 中国 = 北京”。可以看出,这些都是端到端训练整个系统带来的效果。</p>
<p>除端到端的训练以外,我们也正在经历从含参数统计模型转向完全无参数的模型。当数据非常稀缺时,我们需要通过简化对现实的假设来得到实用的模型。当数据充足时,我们就可以用能更好地拟合现实的无参数模型来替代这些含参数模型。这也使我们可以得到更精确的模型,尽管需要牺牲一些可解释性。</p>
<p>相对其它经典的机器学习方法而言,深度学习的不同在于:对非最优解的包容、对非凸非线性优化的使用,以及勇于尝试没有被证明过的方法。这种在处理统计问题上的新经验主义吸引了大量人才的涌入,使得大量实际问题有了更好的解决方案。尽管大部分情况下需要为深度学习修改甚至重新发明已经存在数十年的工具,但是这绝对是一件非常有意义并令人兴奋的事。</p>
]]></content>
<categories>
<category>Datawhale</category>
<category>动手学深度学习</category>
</categories>
<tags>
<tag>datawhale</tag>
<tag>dl</tag>
<tag>深度学习</tag>
<tag>deep learning</tag>
<tag>动手学深度学习</tag>
</tags>
</entry>
<entry>
<title>Task3 过拟合、欠拟合及其解决方案;梯度消失、梯度爆炸;循环神经网络进阶</title>
<url>/p/2020/02/13/bd42c6ba/</url>
<content><![CDATA[<h1 id="过拟合、欠拟合及其解决方案"><a href="#过拟合、欠拟合及其解决方案" class="headerlink" title="过拟合、欠拟合及其解决方案"></a>过拟合、欠拟合及其解决方案</h1><h2 id="模型选择、过拟合和欠拟合"><a href="#模型选择、过拟合和欠拟合" class="headerlink" title="模型选择、过拟合和欠拟合"></a>模型选择、过拟合和欠拟合</h2><h3 id="训练误差和泛化误差"><a href="#训练误差和泛化误差" class="headerlink" title="训练误差和泛化误差"></a>训练误差和泛化误差</h3><p>在解释上述现象之前,我们需要区分训练误差(training error)和泛化误差(generalization error)。通俗来讲,前者指模型在训练数据集上表现出的误差,后者指模型在任意一个测试数据样本上表现出的误差的期望,并常常通过测试数据集上的误差来近似。计算训练误差和泛化误差可以使用之前介绍过的损失函数,例如线性回归用到的平方损失函数和softmax回归用到的交叉熵损失函数。</p>
<p>机器学习模型应关注降低泛化误差。<br><a id="more"></a></p>
<h3 id="模型选择"><a href="#模型选择" class="headerlink" title="模型选择"></a>模型选择</h3><h4 id="验证数据集"><a href="#验证数据集" class="headerlink" title="验证数据集"></a>验证数据集</h4><p>从严格意义上讲,测试集只能在所有超参数和模型参数选定后使用一次。不可以使用测试数据选择模型,如调参。由于无法从训练误差估计泛化误差,因此也不应只依赖训练数据选择模型。鉴于此,我们可以预留一部分在训练数据集和测试数据集以外的数据来进行模型选择。这部分数据被称为验证数据集,简称验证集(validation set)。例如,我们可以从给定的训练集中随机选取一小部分作为验证集,而将剩余部分作为真正的训练集。</p>
<h4 id="K折交叉验证"><a href="#K折交叉验证" class="headerlink" title="K折交叉验证"></a>K折交叉验证</h4><p>由于验证数据集不参与模型训练,当训练数据不够用时,预留大量的验证数据显得太奢侈。一种改善的方法是K折交叉验证(K-fold cross-validation)。在K折交叉验证中,我们把原始训练数据集分割成K个不重合的子数据集,然后我们做K次模型训练和验证。每一次,我们使用一个子数据集验证模型,并使用其他K-1个子数据集来训练模型。在这K次训练和验证中,每次用来验证模型的子数据集都不同。最后,我们对这K次训练误差和验证误差分别求平均。</p>
<h3 id="过拟合和欠拟合"><a href="#过拟合和欠拟合" class="headerlink" title="过拟合和欠拟合"></a>过拟合和欠拟合</h3><p>接下来,我们将探究模型训练中经常出现的两类典型问题:</p>
<ul>
<li>一类是模型无法得到较低的训练误差,我们将这一现象称作欠拟合(underfitting);</li>
<li>另一类是模型的训练误差远小于它在测试数据集上的误差,我们称该现象为过拟合(overfitting)。 在实践中,我们要尽可能同时应对欠拟合和过拟合。虽然有很多因素可能导致这两种拟合问题,在这里我们重点讨论两个因素:模型复杂度和训练数据集大小。</li>
</ul>
<h4 id="模型复杂度"><a href="#模型复杂度" class="headerlink" title="模型复杂度"></a>模型复杂度</h4><p>为了解释模型复杂度,我们以多项式函数拟合为例。给定一个由标量数据特征和对应的标量标签组成的训练数据集,多项式函数拟合的目标是找一个阶多项式函数<br>$$ \hat{y} = b + \sum_{k=1}^K x^k w_k $$<br>来近似$y$ 。在上式中,$w_k$是模型的权重参数,$b$是偏差参数。与线性回归相同,多项式函数拟合也使用平方损失函数。特别地,一阶多项式函数拟合又叫线性函数拟合。</p>
<p>给定训练数据集,模型复杂度和误差之间的关系:</p>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/b2a59db2/q5jc27wxoj.png" alt></p>
<h4 id="训练数据集大小"><a href="#训练数据集大小" class="headerlink" title="训练数据集大小"></a>训练数据集大小</h4><p>影响欠拟合和过拟合的另一个重要因素是训练数据集的大小。一般来说,如果训练数据集中样本数过少,特别是比模型参数数量(按元素计)更少时,过拟合更容易发生。此外,泛化误差不会随训练数据集里样本数量增加而增大。因此,在计算资源允许的范围之内,我们通常希望训练数据集大一些,特别是在模型复杂度较高时,例如层数较多的深度学习模型。</p>
<h3 id="多项式函数拟合实验"><a href="#多项式函数拟合实验" class="headerlink" title="多项式函数拟合实验"></a>多项式函数拟合实验</h3><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">%matplotlib inline</span><br><span class="line"><span class="keyword">import</span> torch</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> sys</span><br><span class="line">sys.path.append(<span class="string">"/home/kesci/input"</span>)</span><br><span class="line"><span class="keyword">import</span> d2lzh1981 <span class="keyword">as</span> d2l</span><br><span class="line">print(torch.__version__) <span class="comment"># 1.3.0</span></span><br></pre></td></tr></table></figure>
<h4 id="初始化模型参数"><a href="#初始化模型参数" class="headerlink" title="初始化模型参数"></a>初始化模型参数</h4><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">n_train, n_test, true_w, true_b = <span class="number">100</span>, <span class="number">100</span>, [<span class="number">1.2</span>, <span class="number">-3.4</span>, <span class="number">5.6</span>], <span class="number">5</span></span><br><span class="line">features = torch.randn((n_train + n_test, <span class="number">1</span>))</span><br><span class="line">poly_features = torch.cat((features, torch.pow(features, <span class="number">2</span>), torch.pow(features, <span class="number">3</span>)), <span class="number">1</span>) </span><br><span class="line">labels = (true_w[<span class="number">0</span>] * poly_features[:, <span class="number">0</span>] + true_w[<span class="number">1</span>] * poly_features[:, <span class="number">1</span>]</span><br><span class="line"> + true_w[<span class="number">2</span>] * poly_features[:, <span class="number">2</span>] + true_b)</span><br><span class="line">labels += torch.tensor(np.random.normal(<span class="number">0</span>, <span class="number">0.01</span>, size=labels.size()), dtype=torch.float)</span><br><span class="line"></span><br><span class="line">features[:<span class="number">2</span>], poly_features[:<span class="number">2</span>], labels[:<span class="number">2</span>]</span><br><span class="line"><span class="comment"># (tensor([[-0.8589],</span></span><br><span class="line"><span class="comment"># [-0.2534]]), tensor([[-0.8589, 0.7377, -0.6335],</span></span><br><span class="line"><span class="comment"># [-0.2534, 0.0642, -0.0163]]), tensor([-2.0794, 4.4039]))</span></span><br></pre></td></tr></table></figure>
<h4 id="定义、训练和测试模型"><a href="#定义、训练和测试模型" class="headerlink" title="定义、训练和测试模型"></a>定义、训练和测试模型</h4><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">semilogy</span><span class="params">(x_vals, y_vals, x_label, y_label, x2_vals=None, y2_vals=None,</span></span></span><br><span class="line"><span class="function"><span class="params"> legend=None, figsize=<span class="params">(<span class="number">3.5</span>, <span class="number">2.5</span>)</span>)</span>:</span></span><br><span class="line"> <span class="comment"># d2l.set_figsize(figsize)</span></span><br><span class="line"> d2l.plt.xlabel(x_label)</span><br><span class="line"> d2l.plt.ylabel(y_label)</span><br><span class="line"> d2l.plt.semilogy(x_vals, y_vals)</span><br><span class="line"> <span class="keyword">if</span> x2_vals <span class="keyword">and</span> y2_vals:</span><br><span class="line"> d2l.plt.semilogy(x2_vals, y2_vals, linestyle=<span class="string">':'</span>)</span><br><span class="line"> d2l.plt.legend(legend)</span><br><span class="line"></span><br><span class="line">num_epochs, loss = <span class="number">100</span>, torch.nn.MSELoss()</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">fit_and_plot</span><span class="params">(train_features, test_features, train_labels, test_labels)</span>:</span></span><br><span class="line"> <span class="comment"># 初始化网络模型</span></span><br><span class="line"> net = torch.nn.Linear(train_features.shape[<span class="number">-1</span>], <span class="number">1</span>)</span><br><span class="line"> <span class="comment"># 通过Linear文档可知,pytorch已经将参数初始化了,所以我们这里就不手动初始化了</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 设置批量大小</span></span><br><span class="line"> batch_size = min(<span class="number">10</span>, train_labels.shape[<span class="number">0</span>]) </span><br><span class="line"> dataset = torch.utils.data.TensorDataset(train_features, train_labels) <span class="comment"># 设置数据集</span></span><br><span class="line"> train_iter = torch.utils.data.DataLoader(dataset, batch_size, shuffle=<span class="literal">True</span>) <span class="comment"># 设置获取数据方式</span></span><br><span class="line"> </span><br><span class="line"> optimizer = torch.optim.SGD(net.parameters(), lr=<span class="number">0.01</span>) <span class="comment"># 设置优化函数,使用的是随机梯度下降优化</span></span><br><span class="line"> train_ls, test_ls = [], []</span><br><span class="line"> <span class="keyword">for</span> _ <span class="keyword">in</span> range(num_epochs):</span><br><span class="line"> <span class="keyword">for</span> X, y <span class="keyword">in</span> train_iter: <span class="comment"># 取一个批量的数据</span></span><br><span class="line"> l = loss(net(X), y.view(<span class="number">-1</span>, <span class="number">1</span>)) <span class="comment"># 输入到网络中计算输出,并和标签比较求得损失函数</span></span><br><span class="line"> optimizer.zero_grad() <span class="comment"># 梯度清零,防止梯度累加干扰优化</span></span><br><span class="line"> l.backward() <span class="comment"># 求梯度</span></span><br><span class="line"> optimizer.step() <span class="comment"># 迭代优化函数,进行参数优化</span></span><br><span class="line"> train_labels = train_labels.view(<span class="number">-1</span>, <span class="number">1</span>)</span><br><span class="line"> test_labels = test_labels.view(<span class="number">-1</span>, <span class="number">1</span>)</span><br><span class="line"> train_ls.append(loss(net(train_features), train_labels).item()) <span class="comment"># 将训练损失保存到train_ls中</span></span><br><span class="line"> test_ls.append(loss(net(test_features), test_labels).item()) <span class="comment"># 将测试损失保存到test_ls中</span></span><br><span class="line"> print(<span class="string">'final epoch: train loss'</span>, train_ls[<span class="number">-1</span>], <span class="string">'test loss'</span>, test_ls[<span class="number">-1</span>]) </span><br><span class="line"> semilogy(range(<span class="number">1</span>, num_epochs + <span class="number">1</span>), train_ls, <span class="string">'epochs'</span>, <span class="string">'loss'</span>,</span><br><span class="line"> range(<span class="number">1</span>, num_epochs + <span class="number">1</span>), test_ls, [<span class="string">'train'</span>, <span class="string">'test'</span>])</span><br><span class="line"> print(<span class="string">'weight:'</span>, net.weight.data,</span><br><span class="line"> <span class="string">'\nbias:'</span>, net.bias.data)</span><br></pre></td></tr></table></figure>
<h4 id="三阶多项式函数拟合(正常)"><a href="#三阶多项式函数拟合(正常)" class="headerlink" title="三阶多项式函数拟合(正常)"></a>三阶多项式函数拟合(正常)</h4><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">fit_and_plot(poly_features[:n_train, :], poly_features[n_train:, :], labels[:n_train], labels[n_train:])</span><br><span class="line"><span class="comment"># final epoch: train loss 8887.298828125 test loss 1145.94287109375</span></span><br><span class="line"><span class="comment"># weight: tensor([[-8.5120, 19.0351, 12.8616]]) </span></span><br><span class="line"><span class="comment"># bias: tensor([-5.4607])</span></span><br></pre></td></tr></table></figure>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/b2a59db2/q5jc27wxoj.png" alt></p>
<h4 id="线性函数拟合(欠拟合)"><a href="#线性函数拟合(欠拟合)" class="headerlink" title="线性函数拟合(欠拟合)"></a>线性函数拟合(欠拟合)</h4><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">fit_and_plot(features[:n_train, :], features[n_train:, :], labels[:n_train], labels[n_train:])</span><br><span class="line"><span class="comment"># final epoch: train loss 781.689453125 test loss 329.79852294921875</span></span><br><span class="line"><span class="comment"># weight: tensor([[26.8753]]) </span></span><br><span class="line"><span class="comment"># bias: tensor([6.1426])</span></span><br></pre></td></tr></table></figure>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/b2a59db2/q5jf5al2tv.png" alt></p>
<h4 id="训练样本不足(过拟合)"><a href="#训练样本不足(过拟合)" class="headerlink" title="训练样本不足(过拟合)"></a>训练样本不足(过拟合)</h4><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">fit_and_plot(poly_features[<span class="number">0</span>:<span class="number">2</span>, :], poly_features[n_train:, :], labels[<span class="number">0</span>:<span class="number">2</span>], labels[n_train:])</span><br><span class="line"><span class="comment"># final epoch: train loss 6.23520565032959 test loss 409.9844665527344</span></span><br><span class="line"><span class="comment"># weight: tensor([[ 0.9729, -0.9612, 0.7259]]) </span></span><br><span class="line"><span class="comment"># bias: tensor([1.6334])</span></span><br></pre></td></tr></table></figure>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/b2a59db2/q5jf5bd11u.png" alt></p>
<h2 id="权重衰减"><a href="#权重衰减" class="headerlink" title="权重衰减"></a>权重衰减</h2><h3 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h3><p>权重衰减等价于$L_2$范数正则化(regularization)。正则化通过为模型损失函数添加惩罚项使学出的模型参数值较小,是应对过拟合的常用手段。</p>
<h3 id="L2-范数正则化(regularization)"><a href="#L2-范数正则化(regularization)" class="headerlink" title="L2 范数正则化(regularization)"></a>L2 范数正则化(regularization)</h3><p>$L_2$范数正则化在模型原损失函数基础上添加$L_2$范数惩罚项,从而得到训练所需要最小化的函数。$L_2$范数惩罚项指的是模型权重参数每个元素的平方和与一个正的常数的乘积。以线性回归中的线性回归损失函数为例</p>
<p>$$ \ell(w_1, w_2, b) = \frac{1}{n} \sum_{i=1}^n \frac{1}{2}\left(x_1^{(i)} w_1 + x_2^{(i)} w_2 + b - y^{(i)}\right)^2 $$</p>
<p>其中$w_1, w_2$是权重参数,$b$是偏差参数,样本$i$的输入为$x_1^{(i)}, x_2^{(i)}$,标签为$y^{(i)}$,样本数为$n$。将权重参数用向量$\boldsymbol{w} = [w_1, w_2]$表示,带有$L_2$范数惩罚项的新损失函数为</p>
<p>$$ \ell(w_1, w_2, b) + \frac{\lambda}{2n} |\boldsymbol{w}|^2, $$</p>
<p>其中超参数$\lambda > 0$。当权重参数均为0时,惩罚项最小。当$\lambda$较大时,惩罚项在损失函数中的比重较大,这通常会使学到的权重参数的元素较接近0。当$\lambda$设为0时,惩罚项完全不起作用。上式中$L_2$范数平方$|\boldsymbol{w}|^2$展开后得到$w_1^2 + w_2^2$。 有了$L_2$范数惩罚项后,在小批量随机梯度下降中,我们将线性回归一节中权重$w_1$和$w_2$的迭代方式更改为<br>$$<br>\begin{aligned} w_1 &\leftarrow \left(1- \frac{\eta\lambda}{|\mathcal{B}|} \right)w_1 - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}}x_1^{(i)} \left(x_1^{(i)} w_1 + x_2^{(i)} w_2 + b - y^{(i)}\right),\ w_2 &\leftarrow \left(1- \frac{\eta\lambda}{|\mathcal{B}|} \right)w_2 - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}}x_2^{(i)} \left(x_1^{(i)} w_1 + x_2^{(i)} w_2 + b - y^{(i)}\right). \end{aligned}<br>$$</p>
<p>可见,范数正则化令权重和先自乘小于1的数,再减去不含惩罚项的梯度。因此,范数正则化又叫权重衰减。权重衰减通过惩罚绝对值较大的模型参数为需要学习的模型增加了限制,这可能对过拟合有效。</p>
<h3 id="高维线性回归实验从零开始的实现"><a href="#高维线性回归实验从零开始的实现" class="headerlink" title="高维线性回归实验从零开始的实现"></a>高维线性回归实验从零开始的实现</h3><p>下面,我们以高维线性回归为例来引入一个过拟合问题,并使用权重衰减来应对过拟合$p$。设数据样本特征的维度为$x_1, x_2, \ldots, x_p$。对于训练数据集和测试数据集中特征为的任一样本,我们使用如下的线性函数来生成该样本的标签:<br>$$<br>y = 0.05 + \sum_{i = 1}^p 0.01x_i + \epsilon<br>$$<br>其中噪声项$\epsilon$服从均值为0、标准差为0.01的正态分布。为了较容易地观察过拟合,我们考虑高维线性回归问题,如设维度$p=200$;同时,我们特意把训练数据集的样本数设低,如20。<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">%matplotlib inline</span><br><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> torch.nn <span class="keyword">as</span> nn</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> sys</span><br><span class="line">sys.path.append(<span class="string">"/home/kesci/input"</span>)</span><br><span class="line"><span class="keyword">import</span> d2lzh1981 <span class="keyword">as</span> d2l</span><br><span class="line"></span><br><span class="line">print(torch.__version__) <span class="comment"># 1.3.0</span></span><br></pre></td></tr></table></figure></p>
<h4 id="初始化模型参数-1"><a href="#初始化模型参数-1" class="headerlink" title="初始化模型参数"></a>初始化模型参数</h4><p>与前面观察过拟合和欠拟合现象的时候相似,在这里不再解释。<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">n_train, n_test, num_inputs = <span class="number">20</span>, <span class="number">100</span>, <span class="number">200</span></span><br><span class="line">true_w, true_b = torch.ones(num_inputs, <span class="number">1</span>) * <span class="number">0.01</span>, <span class="number">0.05</span></span><br><span class="line"></span><br><span class="line">features = torch.randn((n_train + n_test, num_inputs))</span><br><span class="line">labels = torch.matmul(features, true_w) + true_b</span><br><span class="line">labels += torch.tensor(np.random.normal(<span class="number">0</span>, <span class="number">0.01</span>, size=labels.size()), dtype=torch.float)</span><br><span class="line">train_features, test_features = features[:n_train, :], features[n_train:, :]</span><br><span class="line">train_labels, test_labels = labels[:n_train], labels[n_train:]</span><br><span class="line"><span class="comment"># 定义参数初始化函数,初始化模型参数并且附上梯度</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">init_params</span><span class="params">()</span>:</span></span><br><span class="line"> w = torch.randn((num_inputs, <span class="number">1</span>), requires_grad=<span class="literal">True</span>)</span><br><span class="line"> b = torch.zeros(<span class="number">1</span>, requires_grad=<span class="literal">True</span>)</span><br><span class="line"> <span class="keyword">return</span> [w, b]</span><br></pre></td></tr></table></figure></p>
<h4 id="定义L2范数惩罚项"><a href="#定义L2范数惩罚项" class="headerlink" title="定义L2范数惩罚项"></a>定义L2范数惩罚项</h4><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">l2_penalty</span><span class="params">(w)</span>:</span></span><br><span class="line"> <span class="keyword">return</span> (w**<span class="number">2</span>).sum() / <span class="number">2</span></span><br></pre></td></tr></table></figure>
<h4 id="定义训练和测试"><a href="#定义训练和测试" class="headerlink" title="定义训练和测试"></a>定义训练和测试</h4><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">batch_size, num_epochs, lr = <span class="number">1</span>, <span class="number">100</span>, <span class="number">0.003</span></span><br><span class="line">net, loss = d2l.linreg, d2l.squared_loss</span><br><span class="line"></span><br><span class="line">dataset = torch.utils.data.TensorDataset(train_features, train_labels)</span><br><span class="line">train_iter = torch.utils.data.DataLoader(dataset, batch_size, shuffle=<span class="literal">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">fit_and_plot</span><span class="params">(lambd)</span>:</span></span><br><span class="line"> w, b = init_params()</span><br><span class="line"> train_ls, test_ls = [], []</span><br><span class="line"> <span class="keyword">for</span> _ <span class="keyword">in</span> range(num_epochs):</span><br><span class="line"> <span class="keyword">for</span> X, y <span class="keyword">in</span> train_iter:</span><br><span class="line"> <span class="comment"># 添加了L2范数惩罚项</span></span><br><span class="line"> l = loss(net(X, w, b), y) + lambd * l2_penalty(w)</span><br><span class="line"> l = l.sum()</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> w.grad <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line"> w.grad.data.zero_()</span><br><span class="line"> b.grad.data.zero_()</span><br><span class="line"> l.backward()</span><br><span class="line"> d2l.sgd([w, b], lr, batch_size)</span><br><span class="line"> train_ls.append(loss(net(train_features, w, b), train_labels).mean().item())</span><br><span class="line"> test_ls.append(loss(net(test_features, w, b), test_labels).mean().item())</span><br><span class="line"> d2l.semilogy(range(<span class="number">1</span>, num_epochs + <span class="number">1</span>), train_ls, <span class="string">'epochs'</span>, <span class="string">'loss'</span>,</span><br><span class="line"> range(<span class="number">1</span>, num_epochs + <span class="number">1</span>), test_ls, [<span class="string">'train'</span>, <span class="string">'test'</span>])</span><br><span class="line"> print(<span class="string">'L2 norm of w:'</span>, w.norm().item())</span><br></pre></td></tr></table></figure>
<h4 id="观察过拟合"><a href="#观察过拟合" class="headerlink" title="观察过拟合"></a>观察过拟合</h4><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">fit_and_plot(lambd=<span class="number">0</span>)</span><br><span class="line"><span class="comment"># L2 norm of w: 11.6444091796875</span></span><br></pre></td></tr></table></figure>
<h4 id="使用权重衰减"><a href="#使用权重衰减" class="headerlink" title="使用权重衰减"></a>使用权重衰减</h4><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">fit_and_plot(lambd=<span class="number">3</span>)</span><br><span class="line"><span class="comment"># L2 norm of w: 0.04063604772090912</span></span><br></pre></td></tr></table></figure>
<h4 id="简洁实现"><a href="#简洁实现" class="headerlink" title="简洁实现"></a>简洁实现</h4><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">fit_and_plot_pytorch</span><span class="params">(wd)</span>:</span></span><br><span class="line"> <span class="comment"># 对权重参数衰减。权重名称一般是以weight结尾</span></span><br><span class="line"> net = nn.Linear(num_inputs, <span class="number">1</span>)</span><br><span class="line"> nn.init.normal_(net.weight, mean=<span class="number">0</span>, std=<span class="number">1</span>)</span><br><span class="line"> nn.init.normal_(net.bias, mean=<span class="number">0</span>, std=<span class="number">1</span>)</span><br><span class="line"> optimizer_w = torch.optim.SGD(params=[net.weight], lr=lr, weight_decay=wd) <span class="comment"># 对权重参数衰减</span></span><br><span class="line"> optimizer_b = torch.optim.SGD(params=[net.bias], lr=lr) <span class="comment"># 不对偏差参数衰减</span></span><br><span class="line"> </span><br><span class="line"> train_ls, test_ls = [], []</span><br><span class="line"> <span class="keyword">for</span> _ <span class="keyword">in</span> range(num_epochs):</span><br><span class="line"> <span class="keyword">for</span> X, y <span class="keyword">in</span> train_iter:</span><br><span class="line"> l = loss(net(X), y).mean()</span><br><span class="line"> optimizer_w.zero_grad()</span><br><span class="line"> optimizer_b.zero_grad()</span><br><span class="line"> </span><br><span class="line"> l.backward()</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 对两个optimizer实例分别调用step函数,从而分别更新权重和偏差</span></span><br><span class="line"> optimizer_w.step()</span><br><span class="line"> optimizer_b.step()</span><br><span class="line"> train_ls.append(loss(net(train_features), train_labels).mean().item())</span><br><span class="line"> test_ls.append(loss(net(test_features), test_labels).mean().item())</span><br><span class="line"> d2l.semilogy(range(<span class="number">1</span>, num_epochs + <span class="number">1</span>), train_ls, <span class="string">'epochs'</span>, <span class="string">'loss'</span>,</span><br><span class="line"> range(<span class="number">1</span>, num_epochs + <span class="number">1</span>), test_ls, [<span class="string">'train'</span>, <span class="string">'test'</span>])</span><br><span class="line"> print(<span class="string">'L2 norm of w:'</span>, net.weight.data.norm().item())</span><br><span class="line"></span><br><span class="line">fit_and_plot_pytorch(<span class="number">0</span>)</span><br><span class="line"><span class="comment"># L2 norm of w: 13.361410140991211</span></span><br><span class="line"></span><br><span class="line">fit_and_plot_pytorch(<span class="number">3</span>)</span><br><span class="line"><span class="comment"># L2 norm of w: 0.051789578050374985</span></span><br></pre></td></tr></table></figure>
<h2 id="丢弃法"><a href="#丢弃法" class="headerlink" title="丢弃法"></a>丢弃法</h2><p>多层感知机中神经网络图描述了一个单隐藏层的多层感知机。其中输入个数为4,隐藏单元个数为5,且隐藏单元$h_i$($i=1, \ldots, 5$)的计算表达式为<br>$$<br>h_i = \phi\left(x_1 w_{1i} + x_2 w_{2i} + x_3 w_{3i} + x_4 w_{4i} + b_i\right)<br>$$<br>这里是$\phi$激活函数,$x_1, \ldots, x_4$是输入,隐藏单元的权重参数为$w_{1i}, \ldots, w_{4i}$,偏差参数为$b_i$。当对该隐藏层使用丢弃法时,该层的隐藏单元将有一定概率被丢弃掉。设丢弃概率为$p$,那么有$p$的概率$h_i$会被清零,有$1-p$的概率$h_i$会除以$1-p$做拉伸。丢弃概率是丢弃法的超参数。具体来说,设随机变量$\xi_i$为0和1的概率分别$p$为和$1-p$。使用丢弃法时我们计算新的隐藏单元$h_i’$</p>
<p>$$<br>h_i’ = \frac{\xi_i}{1-p} h_i<br>$$<br>由于$E(\xi_i) = 1-p$,因此<br>$$<br>E(h_i’) = \frac{E(\xi_i)}{1-p}h_i = h_i<br>$$</p>
<p>即丢弃法不改变其输入的期望值。让我们对之前多层感知机的神经网络中的隐藏层使用丢弃法,一种可能的结果如图所示,其中$h_2$和$h_5$被清零。这时输出值的计算不再依赖$h_2$和$h_5$,在反向传播时,与这两个隐藏单元相关的权重的梯度均为0。由于在训练中隐藏层神经元的丢弃是随机的,即$h_1, \ldots, h_5$都有可能被清零,输出层的计算无法过度依赖$h_1, \ldots, h_5$中的任一个,从而在训练模型时起到正则化的作用,并可以用来应对过拟合。在测试模型时,我们为了拿到更加确定性的结果,一般不使用丢弃法</p>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/b2a59db2/q5jd69in3m.png" alt></p>
<h3 id="丢弃法从零开始的实现"><a href="#丢弃法从零开始的实现" class="headerlink" title="丢弃法从零开始的实现"></a>丢弃法从零开始的实现</h3><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">%matplotlib inline</span><br><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> torch.nn <span class="keyword">as</span> nn</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> sys</span><br><span class="line">sys.path.append(<span class="string">"/home/kesci/input"</span>)</span><br><span class="line"><span class="keyword">import</span> d2lzh1981 <span class="keyword">as</span> d2l</span><br><span class="line"></span><br><span class="line">print(torch.__version__) <span class="comment"># 1.3.0</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">dropout</span><span class="params">(X, drop_prob)</span>:</span></span><br><span class="line"> X = X.float()</span><br><span class="line"> <span class="keyword">assert</span> <span class="number">0</span> <= drop_prob <= <span class="number">1</span></span><br><span class="line"> keep_prob = <span class="number">1</span> - drop_prob</span><br><span class="line"> <span class="comment"># 这种情况下把全部元素都丢弃</span></span><br><span class="line"> <span class="keyword">if</span> keep_prob == <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">return</span> torch.zeros_like(X)</span><br><span class="line"> mask = (torch.rand(X.shape) < keep_prob).float()</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> mask * X / keep_prob</span><br><span class="line"></span><br><span class="line">X = torch.arange(<span class="number">16</span>).view(<span class="number">2</span>, <span class="number">8</span>)</span><br><span class="line">dropout(X, <span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># tensor([[ 0., 1., 2., 3., 4., 5., 6., 7.],</span></span><br><span class="line"><span class="comment"># [ 8., 9., 10., 11., 12., 13., 14., 15.]])</span></span><br><span class="line">dropout(X, <span class="number">0.5</span>)</span><br><span class="line"><span class="comment"># tensor([[ 0., 0., 0., 6., 8., 10., 0., 14.],</span></span><br><span class="line"><span class="comment"># [ 0., 0., 20., 0., 0., 0., 28., 0.]])</span></span><br><span class="line">dropout(X, <span class="number">1.0</span>)</span><br><span class="line"><span class="comment"># tensor([[0., 0., 0., 0., 0., 0., 0., 0.],</span></span><br><span class="line"><span class="comment"># [0., 0., 0., 0., 0., 0., 0., 0.]])</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 参数的初始化</span></span><br><span class="line">num_inputs, num_outputs, num_hiddens1, num_hiddens2 = <span class="number">784</span>, <span class="number">10</span>, <span class="number">256</span>, <span class="number">256</span></span><br><span class="line"></span><br><span class="line">W1 = torch.tensor(np.random.normal(<span class="number">0</span>, <span class="number">0.01</span>, size=(num_inputs, num_hiddens1)), dtype=torch.float, requires_grad=<span class="literal">True</span>)</span><br><span class="line">b1 = torch.zeros(num_hiddens1, requires_grad=<span class="literal">True</span>)</span><br><span class="line">W2 = torch.tensor(np.random.normal(<span class="number">0</span>, <span class="number">0.01</span>, size=(num_hiddens1, num_hiddens2)), dtype=torch.float, requires_grad=<span class="literal">True</span>)</span><br><span class="line">b2 = torch.zeros(num_hiddens2, requires_grad=<span class="literal">True</span>)</span><br><span class="line">W3 = torch.tensor(np.random.normal(<span class="number">0</span>, <span class="number">0.01</span>, size=(num_hiddens2, num_outputs)), dtype=torch.float, requires_grad=<span class="literal">True</span>)</span><br><span class="line">b3 = torch.zeros(num_outputs, requires_grad=<span class="literal">True</span>)</span><br><span class="line"></span><br><span class="line">params = [W1, b1, W2, b2, W3, b3]</span><br><span class="line">drop_prob1, drop_prob2 = <span class="number">0.2</span>, <span class="number">0.5</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">net</span><span class="params">(X, is_training=True)</span>:</span></span><br><span class="line"> X = X.view(<span class="number">-1</span>, num_inputs)</span><br><span class="line"> H1 = (torch.matmul(X, W1) + b1).relu()</span><br><span class="line"> <span class="keyword">if</span> is_training: <span class="comment"># 只在训练模型时使用丢弃法</span></span><br><span class="line"> H1 = dropout(H1, drop_prob1) <span class="comment"># 在第一层全连接后添加丢弃层</span></span><br><span class="line"> H2 = (torch.matmul(H1, W2) + b2).relu()</span><br><span class="line"> <span class="keyword">if</span> is_training:</span><br><span class="line"> H2 = dropout(H2, drop_prob2) <span class="comment"># 在第二层全连接后添加丢弃层</span></span><br><span class="line"> <span class="keyword">return</span> torch.matmul(H2, W3) + b3</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">evaluate_accuracy</span><span class="params">(data_iter, net)</span>:</span></span><br><span class="line"> acc_sum, n = <span class="number">0.0</span>, <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> X, y <span class="keyword">in</span> data_iter:</span><br><span class="line"> <span class="keyword">if</span> isinstance(net, torch.nn.Module):</span><br><span class="line"> net.eval() <span class="comment"># 评估模式, 这会关闭dropout</span></span><br><span class="line"> acc_sum += (net(X).argmax(dim=<span class="number">1</span>) == y).float().sum().item()</span><br><span class="line"> net.train() <span class="comment"># 改回训练模式</span></span><br><span class="line"> <span class="keyword">else</span>: <span class="comment"># 自定义的模型</span></span><br><span class="line"> <span class="keyword">if</span>(<span class="string">'is_training'</span> <span class="keyword">in</span> net.__code__.co_varnames): <span class="comment"># 如果有is_training这个参数</span></span><br><span class="line"> <span class="comment"># 将is_training设置成False</span></span><br><span class="line"> acc_sum += (net(X, is_training=<span class="literal">False</span>).argmax(dim=<span class="number">1</span>) == y).float().sum().item() </span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> acc_sum += (net(X).argmax(dim=<span class="number">1</span>) == y).float().sum().item() </span><br><span class="line"> n += y.shape[<span class="number">0</span>]</span><br><span class="line"> <span class="keyword">return</span> acc_sum / n</span><br><span class="line">num_epochs, lr, batch_size = <span class="number">5</span>, <span class="number">100.0</span>, <span class="number">256</span> <span class="comment"># 这里的学习率设置的很大,原因与之前相同。</span></span><br><span class="line">loss = torch.nn.CrossEntropyLoss()</span><br><span class="line">train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, root=<span class="string">'/home/kesci/input/FashionMNIST2065'</span>)</span><br><span class="line">d2l.train_ch3(</span><br><span class="line"> net,</span><br><span class="line"> train_iter,</span><br><span class="line"> test_iter,</span><br><span class="line"> loss,</span><br><span class="line"> num_epochs,</span><br><span class="line"> batch_size,</span><br><span class="line"> params,</span><br><span class="line"> lr)</span><br><span class="line"><span class="comment"># epoch 1, loss 0.0046, train acc 0.549, test acc 0.704</span></span><br><span class="line"><span class="comment"># epoch 2, loss 0.0023, train acc 0.785, test acc 0.737</span></span><br><span class="line"><span class="comment"># epoch 3, loss 0.0019, train acc 0.825, test acc 0.834</span></span><br><span class="line"><span class="comment"># epoch 4, loss 0.0017, train acc 0.842, test acc 0.763</span></span><br><span class="line"><span class="comment"># epoch 5, loss 0.0016, train acc 0.848, test acc 0.813</span></span><br></pre></td></tr></table></figure>
<h3 id="简洁实现-1"><a href="#简洁实现-1" class="headerlink" title="简洁实现"></a>简洁实现</h3><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">net = nn.Sequential(</span><br><span class="line"> d2l.FlattenLayer(),</span><br><span class="line"> nn.Linear(num_inputs, num_hiddens1),</span><br><span class="line"> nn.ReLU(),</span><br><span class="line"> nn.Dropout(drop_prob1),</span><br><span class="line"> nn.Linear(num_hiddens1, num_hiddens2), </span><br><span class="line"> nn.ReLU(),</span><br><span class="line"> nn.Dropout(drop_prob2),</span><br><span class="line"> nn.Linear(num_hiddens2, <span class="number">10</span>)</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> param <span class="keyword">in</span> net.parameters():</span><br><span class="line"> nn.init.normal_(param, mean=<span class="number">0</span>, std=<span class="number">0.01</span>)</span><br><span class="line">optimizer = torch.optim.SGD(net.parameters(), lr=<span class="number">0.5</span>)</span><br><span class="line">d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, <span class="literal">None</span>, <span class="literal">None</span>, optimizer)</span><br><span class="line"></span><br><span class="line"><span class="comment"># epoch 1, loss 0.0046, train acc 0.553, test acc 0.736</span></span><br><span class="line"><span class="comment"># epoch 2, loss 0.0023, train acc 0.785, test acc 0.803</span></span><br><span class="line"><span class="comment"># epoch 3, loss 0.0019, train acc 0.818, test acc 0.756</span></span><br><span class="line"><span class="comment"># epoch 4, loss 0.0018, train acc 0.835, test acc 0.829</span></span><br><span class="line"><span class="comment"># epoch 5, loss 0.0016, train acc 0.848, test acc 0.851</span></span><br></pre></td></tr></table></figure>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><ul>
<li>欠拟合现象:模型无法达到一个较低的误差</li>
<li>过拟合现象:训练误差较低但是泛化误差依然较高,二者相差较大</li>
</ul>
<h2 id="笔记整理"><a href="#笔记整理" class="headerlink" title="笔记整理"></a>笔记整理</h2><ol>
<li><p>为什么优化器中只对权重参数设置衰减,而不对偏置参数设置衰减呢?<br>对偏置增加正则也是可以的,但是对偏置增加正则不会明显的产生很好的效果。而且偏置并不会像权重一样对数据非常敏感,所以不用担心偏置会学习到数据中的噪声。而且大的偏置也会使得我们的网络更加灵活,所以一般不对偏置做正则化。</p>
</li>
<li><p>L2范数惩罚项通过惩罚绝对值较大的参数的方法来应对过拟合的。这里面的惩罚绝对值较大的参数是什么意思?<br>L2处理 权重会先自乘小于1的系数,再减去不含惩罚项的梯度;系数相等的情况下,绝对值较大的参数损失较大,故而惩罚较大。</p>
</li>
<li><p>按照最开始的说法,训练集,测试集(用来测试训练成果),验证集(用来训练超参数或者选择模型),但K折交叉验证为什么只有k-1个训练和1个验证,没有测试集?“。在这K次训练和验证中,每次用来验证模型的子数据集都不同。最后,我们对这K次训练误差和验证误差分别求平均。”那么这里的k次训练误差是哪里来的呢?<br>正常的训练过程是分为训练数据和测试数据,但是如果只使用训练数据得到的模型效果不一定是最好的,所以在训练集中划分出验证集,训练集和验证集的划分有很多中,但是最常用的就是k折交叉验证,就是把训练数据分成k份,用其中的 k-1份训练模型,用剩下的一份来验证模型的泛化能力,循环操作,选择最佳的超参数组合,之后再用全部数据训练得到一个模型,再用测试数据来看模型的最终效果。</p>
</li>
<li><p>有一个疑问。dropout(x,0.5)16个数按照0.5的概率丢弃,不应该是丢弃8个数字吗?是老师的口误吗?<br>丢弃率是指某个单元被丢弃(或者说被置为零)的概率。如丢弃率=0.5,表明每个单元都有50%的概率被置零,但各个单元之间是相互独立的。如,16个数(或者说16个单元)按照0.5概率丢弃,会出现16个数都被丢弃(或者16个数都被保留)的情况,概率为0.5^16;当然还有很多种被保留或丢弃的情况组合,最终的统计平均或者说期望是8个。</p>
</li>
<li><p>dropout的时候为什么要进行1-p的拉伸?<br>假设dropout概率为p,那么每个节点被保留的概率是1-p<br>以p=0.3为例,假如某一个全连接层有10个输入节点<br>训练时启用dropout,因此理想情况是7个节点能够向后传递信息。<br>而实际使用时不用dropout,因此10个节点能向后传递信息。<br>因此输出节点接收到的信号强度是不一样的,为了平衡训练和预测时的这种量级差异。<br>可以选择在训练的时候,对每个输入节点进行 除(1-p) 的操作,来进行“拉伸”</p>
</li>
<li><p>权重衰减可以有效处理过拟合的情况,这应该符合奥卡姆剃刀原理的吧?? 权重衰减可避免突出参数的负面干扰,而且经过数据验证也可看到这样确实有更好的拟合效果;但这样的结果是否与我们一直接触的大众数据有关呢,面对一些非常规的数据,比如说地震监测数据等,这种情况需要更显著地区段跳跃,那么这种处理方式还有效吗???<br>符合,引入正则项实际上是学习器的一种归纳偏好,即:选用尽可能简单的模型,避免过拟合,因为这样能够有更好的泛化性能。 这是一个增强泛化性能的通用的处理方式,当然如果你的模型如果本身准确率就不高,不会产生过拟合,那这种做法当然效果不好</p>
</li>
</ol>
<h1 id="梯度消失、梯度爆炸以及Kaggle房价预测"><a href="#梯度消失、梯度爆炸以及Kaggle房价预测" class="headerlink" title="梯度消失、梯度爆炸以及Kaggle房价预测"></a>梯度消失、梯度爆炸以及Kaggle房价预测</h1><h2 id="梯度消失和梯度爆炸"><a href="#梯度消失和梯度爆炸" class="headerlink" title="梯度消失和梯度爆炸"></a>梯度消失和梯度爆炸</h2><p>深度模型有关数值稳定性的典型问题是消失(vanishing)和爆炸(explosion)。</p>
<p><strong>当神经网络的层数较多时,模型的数值稳定性容易变差。</strong></p>
<p>假设一个层数为$L$的多层感知机的第$l$层$\boldsymbol{H}^{(l)}$的权重参数为$\boldsymbol{W}^{(l)}$,输出层$\boldsymbol{H}^{(l)}$的权重参数为$\boldsymbol{W}^{(l)}$。为了便于讨论,不考虑偏差参数,且设所有隐藏层的激活函数为恒等映射(identity mapping)$\phi(x) = x$。给定输入$X$,多层感知机的第$l$层的输出$\boldsymbol{H}^{(l)} = \boldsymbol{X} \boldsymbol{W}^{(1)} \boldsymbol{W}^{(2)} \ldots \boldsymbol{W}^{(l)}$。此时,如果层数$l$较大,$\boldsymbol{H}^{(l)}$的计算可能会出现衰减或爆炸。举个例子,假设输入和所有层的权重参数都是标量,如权重参数为0.2和5,多层感知机的第30层输出为输入$\boldsymbol{X}$分别与$0.2^{30} \approx 1 \times 10^{-21}$(消失)和$5^{30} \approx 9 \times 10^{20}$(爆炸)的乘积。当层数较多时,梯度的计算也容易出现消失或爆炸。</p>
<h3 id="随机初始化模型参数"><a href="#随机初始化模型参数" class="headerlink" title="随机初始化模型参数"></a>随机初始化模型参数</h3><p>在神经网络中,通常需要随机初始化模型参数。下面我们来解释这样做的原因。</p>
<p>回顾多层感知机一节描述的多层感知机。为了方便解释,假设输出层只保留一个输出单元$o_1$(删去$o_2$和$o_3$以及指向它们的箭头),且隐藏层使用相同的激活函数。如果将每个隐藏单元的参数都初始化为相等的值,那么在正向传播时每个隐藏单元将根据相同的输入计算出相同的值,并传递至输出层。在反向传播中,每个隐藏单元的参数梯度值相等。因此,这些参数在使用基于梯度的优化算法迭代后值依然相等。之后的迭代也是如此。在这种情况下,无论隐藏单元有多少,隐藏层本质上只有1个隐藏单元在发挥作用。因此,正如在前面的实验中所做的那样,我们通常将神经网络的模型参数,特别是权重参数,进行随机初始化。</p>
<p>Image Name</p>
<h3 id="PyTorch的默认随机初始化"><a href="#PyTorch的默认随机初始化" class="headerlink" title="PyTorch的默认随机初始化"></a>PyTorch的默认随机初始化</h3><p>随机初始化模型参数的方法有很多。在线性回归的简洁实现中,我们使用<code>torch.nn.init.normal_()</code>使模型net的权重参数采用正态分布的随机初始化方式。不过,PyTorch中<code>nn.Module</code>的模块参数都采取了较为合理的初始化策略(不同类型的layer具体采样的哪一种初始化方法的可参考源代码),因此一般不用我们考虑。</p>
<h3 id="Xavier随机初始化"><a href="#Xavier随机初始化" class="headerlink" title="Xavier随机初始化"></a>Xavier随机初始化</h3><p>还有一种比较常用的随机初始化方法叫作Xavier随机初始化。 假设某全连接层的输入个数为$a$,输出个数为$b$,Xavier随机初始化将使该层中权重参数的每个元素都随机采样于均匀分布<br>$$<br>U\left(-\sqrt{\frac{6}{a+b}}, \sqrt{\frac{6}{a+b}}\right).<br>$$<br>它的设计主要考虑到,模型参数初始化后,每层输出的方差不该受该层输入个数影响,且每层梯度的方差也不该受该层输出个数影响。</p>
<h2 id="考虑到环境因素的其他问题"><a href="#考虑到环境因素的其他问题" class="headerlink" title="考虑到环境因素的其他问题"></a>考虑到环境因素的其他问题</h2><h3 id="协变量偏移"><a href="#协变量偏移" class="headerlink" title="协变量偏移"></a>协变量偏移</h3><p>这里我们假设,虽然输入的分布可能随时间而改变,但是标记函数,即条件分布$P(y∣x)$不会改变。虽然这个问题容易理解,但在实践中也容易忽视。</p>
<p>想想区分猫和狗的一个例子。我们的训练数据使用的是猫和狗的真实的照片,但是在测试时,我们被要求对猫和狗的卡通图片进行分类。</p>
<p>cat cat dog dog<br>Image Name Image Name Image Name Image Name<br>测试数据:</p>
<p>cat cat dog dog<br>Image Name Image Name Image Name Image Name<br>显然,这不太可能奏效。训练集由照片组成,而测试集只包含卡通。在一个看起来与测试集有着本质不同的数据集上进行训练,而不考虑如何适应新的情况,这是不是一个好主意。不幸的是,这是一个非常常见的陷阱。</p>
<p>统计学家称这种协变量变化是因为问题的根源在于特征分布的变化(即协变量的变化)。数学上,我们可以说P(x)改变了,但P(y∣x)保持不变。尽管它的有用性并不局限于此,当我们认为x导致y时,协变量移位通常是正确的假设。</p>
<h3 id="标签偏移"><a href="#标签偏移" class="headerlink" title="标签偏移"></a>标签偏移</h3><p>当我们认为导致偏移的是标签P(y)上的边缘分布的变化,但类条件分布是不变的P(x∣y)时,就会出现相反的问题。当我们认为y导致x时,标签偏移是一个合理的假设。例如,通常我们希望根据其表现来预测诊断结果。在这种情况下,我们认为诊断引起的表现,即疾病引起的症状。有时标签偏移和协变量移位假设可以同时成立。例如,当真正的标签函数是确定的和不变的,那么协变量偏移将始终保持,包括如果标签偏移也保持。有趣的是,当我们期望标签偏移和协变量偏移保持时,使用来自标签偏移假设的方法通常是有利的。这是因为这些方法倾向于操作看起来像标签的对象,这(在深度学习中)与处理看起来像输入的对象(在深度学习中)相比相对容易一些。</p>
<p>病因(要预测的诊断结果)导致 症状(观察到的结果)。</p>
<p>训练数据集,数据很少只包含流感p(y)的样本。</p>
<p>而测试数据集有流感p(y)和流感q(y),其中不变的是流感症状p(x|y)。</p>
<h3 id="概念偏移"><a href="#概念偏移" class="headerlink" title="概念偏移"></a>概念偏移</h3><p>另一个相关的问题出现在概念转换中,即标签本身的定义发生变化的情况。这听起来很奇怪,毕竟猫就是猫。的确,猫的定义可能不会改变,但我们能不能对软饮料也这么说呢?事实证明,如果我们周游美国,按地理位置转移数据来源,我们会发现,即使是如图所示的这个简单术语的定义也会发生相当大的概念转变。</p>
<p>Image Name</p>
<p>美国软饮料名称的概念转变<br>如果我们要建立一个机器翻译系统,分布P(y∣x)可能因我们的位置而异。这个问题很难发现。另一个可取之处是P(y∣x)通常只是逐渐变化。</p>
<h2 id="Kaggle房价预测"><a href="#Kaggle房价预测" class="headerlink" title="Kaggle房价预测"></a>Kaggle房价预测</h2><p>作为深度学习基础篇章的总结,我们将对本章内容学以致用。下面,让我们动手实战一个Kaggle比赛:房价预测。本节将提供未经调优的数据的预处理、模型的设计和超参数的选择。我们希望读者通过动手操作、仔细观察实验现象、认真分析实验结果并不断调整方法,得到令自己满意的结果。<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> torch.nn <span class="keyword">as</span> nn</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> pandas <span class="keyword">as</span> pd</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line">sys.path.append(<span class="string">"/home/kesci/input"</span>)</span><br><span class="line"><span class="keyword">import</span> d2lzh1981 <span class="keyword">as</span> d2l</span><br><span class="line">print(torch.__version__)</span><br><span class="line">torch.set_default_tensor_type(torch.FloatTensor)</span><br><span class="line"><span class="comment"># 1.3.0</span></span><br></pre></td></tr></table></figure></p>
<h3 id="获取和读取数据集"><a href="#获取和读取数据集" class="headerlink" title="获取和读取数据集"></a>获取和读取数据集</h3><p>比赛数据分为训练数据集和测试数据集。两个数据集都包括每栋房子的特征,如街道类型、建造年份、房顶类型、地下室状况等特征值。这些特征值有连续的数字、离散的标签甚至是缺失值“na”。只有训练数据集包括了每栋房子的价格,也就是标签。我们可以访问比赛网页,点击“Data”标签,并下载这些数据集。</p>
<p>我们将通过pandas库读入并处理数据。在导入本节需要的包前请确保已安装pandas库。 假设解压后的数据位于/home/kesci/input/houseprices2807/目录,它包括两个csv文件。下面使用pandas读取这两个文件。<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">test_data = pd.read_csv(<span class="string">"/home/kesci/input/houseprices2807/house-prices-advanced-regression-techniques/test.csv"</span>)</span><br><span class="line">train_data = pd.read_csv(<span class="string">"/home/kesci/input/houseprices2807/house-prices-advanced-regression-techniques/train.csv"</span>)</span><br></pre></td></tr></table></figure></p>
<p>训练数据集包括1460个样本、80个特征和1个标签。<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">train_data.shape <span class="comment"># (1460, 81)</span></span><br></pre></td></tr></table></figure></p>
<p>测试数据集包括1459个样本和80个特征。我们需要将测试数据集中每个样本的标签预测出来。<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">test_data.shape <span class="comment"># (1459, 80)</span></span><br></pre></td></tr></table></figure></p>
<p>让我们来查看前4个样本的前4个特征、后2个特征和标签(SalePrice):<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">train_data.iloc[<span class="number">0</span>:<span class="number">4</span>, [<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">-3</span>, <span class="number">-2</span>, <span class="number">-1</span>]]</span><br><span class="line"><span class="comment"># Id MSSubClass MSZoning LotFrontage SaleType SaleCondition SalePrice</span></span><br><span class="line"><span class="comment"># 0 1 60 RL 65.0 WD Normal 208500</span></span><br><span class="line"><span class="comment"># 1 2 20 RL 80.0 WD Normal 181500</span></span><br><span class="line"><span class="comment"># 2 3 60 RL 68.0 WD Normal 223500</span></span><br><span class="line"><span class="comment"># 3 4 70 RL 60.0 WD Abnorml 140000</span></span><br></pre></td></tr></table></figure></p>
<p>可以看到第一个特征是Id,它能帮助模型记住每个训练样本,但难以推广到测试样本,所以我们不使用它来训练。我们将所有的训练数据和测试数据的79个特征按样本连结。<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">all_features = pd.concat((train_data.iloc[:, <span class="number">1</span>:<span class="number">-1</span>], test_data.iloc[:, <span class="number">1</span>:]))</span><br></pre></td></tr></table></figure></p>
<h3 id="预处理数据"><a href="#预处理数据" class="headerlink" title="预处理数据"></a>预处理数据</h3><p>我们对连续数值的特征做标准化(standardization):设该特征在整个数据集上的均值为,标准差为。那么,我们可以将该特征的每个值先减去再除以得到标准化后的每个特征值。对于缺失的特征值,我们将其替换成该特征的均值。<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">numeric_features = all_features.dtypes[all_features.dtypes != <span class="string">'object'</span>].index</span><br><span class="line">all_features[numeric_features] = all_features[numeric_features].apply</span><br><span class="line"> <span class="keyword">lambda</span> x: (x - x.mean()) / (x.std()))</span><br><span class="line"><span class="comment"># 标准化后,每个数值特征的均值变为0,所以可以直接用0来替换缺失值</span></span><br><span class="line">all_features[numeric_features] = all_features[numeric_features].fillna(<span class="number">0</span>)</span><br></pre></td></tr></table></figure></p>
<p>接下来将离散数值转成指示特征。举个例子,假设特征MSZoning里面有两个不同的离散值RL和RM,那么这一步转换将去掉MSZoning特征,并新加两个特征MSZoning_RL和MSZoning_RM,其值为0或1。如果一个样本原来在MSZoning里的值为RL,那么有MSZoning_RL=1且MSZoning_RM=0。<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment"># dummy_na=True将缺失值也当作合法的特征值并为其创建指示特征</span></span><br><span class="line">all_features = pd.get_dummies(all_features, dummy_na=<span class="literal">True</span>)</span><br><span class="line">all_features.shape <span class="comment"># (2919, 331)</span></span><br></pre></td></tr></table></figure></p>
<p>可以看到这一步转换将特征数从79增加到了331。</p>
<p>最后,通过values属性得到NumPy格式的数据,并转成Tensor方便后面的训练。<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">n_train = train_data.shape[<span class="number">0</span>]</span><br><span class="line">train_features = torch.tensor(all_features[:n_train].values, dtype=torch.float)</span><br><span class="line">test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float)</span><br><span class="line">train_labels = torch.tensor(train_data.SalePrice.values, dtype=torch.float).view(<span class="number">-1</span>, <span class="number">1</span>)</span><br></pre></td></tr></table></figure></p>
<h3 id="训练模型"><a href="#训练模型" class="headerlink" title="训练模型"></a>训练模型</h3><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">loss = torch.nn.MSELoss()</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">get_net</span><span class="params">(feature_num)</span>:</span></span><br><span class="line"> net = nn.Linear(feature_num, <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">for</span> param <span class="keyword">in</span> net.parameters():</span><br><span class="line"> nn.init.normal_(param, mean=<span class="number">0</span>, std=<span class="number">0.01</span>)</span><br><span class="line"> <span class="keyword">return</span> net</span><br></pre></td></tr></table></figure>
<p>下面定义比赛用来评价模型的对数均方根误差。给定预测值和对应的真实标签,它的定义为</p>
<p>对数均方根误差的实现如下。<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">log_rmse</span><span class="params">(net, features, labels)</span>:</span></span><br><span class="line"> <span class="keyword">with</span> torch.no_grad():</span><br><span class="line"> <span class="comment"># 将小于1的值设成1,使得取对数时数值更稳定</span></span><br><span class="line"> clipped_preds = torch.max(net(features), torch.tensor(<span class="number">1.0</span>))</span><br><span class="line"> rmse = torch.sqrt(<span class="number">2</span> * loss(clipped_preds.log(), labels.log()).mean())</span><br><span class="line"> <span class="keyword">return</span> rmse.item()</span><br></pre></td></tr></table></figure></p>
<p>下面的训练函数跟本章中前几节的不同在于使用了Adam优化算法。相对之前使用的小批量随机梯度下降,它对学习率相对不那么敏感。我们将在之后的“优化算法”一章里详细介绍它。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">train</span><span class="params">(net, train_features, train_labels, test_features, test_labels,</span></span></span><br><span class="line"><span class="function"><span class="params"> num_epochs, learning_rate, weight_decay, batch_size)</span>:</span></span><br><span class="line"> train_ls, test_ls = [], []</span><br><span class="line"> dataset = torch.utils.data.TensorDataset(train_features, train_labels)</span><br><span class="line"> train_iter = torch.utils.data.DataLoader(dataset, batch_size, shuffle=<span class="literal">True</span>)</span><br><span class="line"> <span class="comment"># 这里使用了Adam优化算法</span></span><br><span class="line"> optimizer = torch.optim.Adam(params=net.parameters(), lr=learning_rate, weight_decay=weight_decay) </span><br><span class="line"> net = net.float()</span><br><span class="line"> <span class="keyword">for</span> epoch <span class="keyword">in</span> range(num_epochs):</span><br><span class="line"> <span class="keyword">for</span> X, y <span class="keyword">in</span> train_iter:</span><br><span class="line"> l = loss(net(X.float()), y.float())</span><br><span class="line"> optimizer.zero_grad()</span><br><span class="line"> l.backward()</span><br><span class="line"> optimizer.step()</span><br><span class="line"> train_ls.append(log_rmse(net, train_features, train_labels))</span><br><span class="line"> <span class="keyword">if</span> test_labels <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line"> test_ls.append(log_rmse(net, test_features, test_labels))</span><br><span class="line"> <span class="keyword">return</span> train_ls, test_ls</span><br></pre></td></tr></table></figure>
<h3 id="K折交叉验证-1"><a href="#K折交叉验证-1" class="headerlink" title="K折交叉验证"></a>K折交叉验证</h3><p>我们在模型选择、欠拟合和过拟合中介绍了折交叉验证。它将被用来选择模型设计并调节超参数。下面实现了一个函数,它返回第i折交叉验证时所需要的训练和验证数据。<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">get_k_fold_data</span><span class="params">(k, i, X, y)</span>:</span></span><br><span class="line"> <span class="comment"># 返回第i折交叉验证时所需要的训练和验证数据</span></span><br><span class="line"> <span class="keyword">assert</span> k > <span class="number">1</span></span><br><span class="line"> fold_size = X.shape[<span class="number">0</span>] // k</span><br><span class="line"> X_train, y_train = <span class="literal">None</span>, <span class="literal">None</span></span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> range(k):</span><br><span class="line"> idx = slice(j * fold_size, (j + <span class="number">1</span>) * fold_size)</span><br><span class="line"> X_part, y_part = X[idx, :], y[idx]</span><br><span class="line"> <span class="keyword">if</span> j == i:</span><br><span class="line"> X_valid, y_valid = X_part, y_part</span><br><span class="line"> <span class="keyword">elif</span> X_train <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line"> X_train, y_train = X_part, y_part</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> X_train = torch.cat((X_train, X_part), dim=<span class="number">0</span>)</span><br><span class="line"> y_train = torch.cat((y_train, y_part), dim=<span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> X_train, y_train, X_valid, y_valid</span><br></pre></td></tr></table></figure></p>
<p>在折交叉验证中我们训练次并返回训练和验证的平均误差</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">k_fold</span><span class="params">(k, X_train, y_train, num_epochs,</span></span></span><br><span class="line"><span class="function"><span class="params"> learning_rate, weight_decay, batch_size)</span>:</span></span><br><span class="line"> train_l_sum, valid_l_sum = <span class="number">0</span>, <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(k):</span><br><span class="line"> data = get_k_fold_data(k, i, X_train, y_train)</span><br><span class="line"> net = get_net(X_train.shape[<span class="number">1</span>])</span><br><span class="line"> train_ls, valid_ls = train(net, *data, num_epochs, learning_rate,</span><br><span class="line"> weight_decay, batch_size)</span><br><span class="line"> train_l_sum += train_ls[<span class="number">-1</span>]</span><br><span class="line"> valid_l_sum += valid_ls[<span class="number">-1</span>]</span><br><span class="line"> <span class="keyword">if</span> i == <span class="number">0</span>:</span><br><span class="line"> d2l.semilogy(range(<span class="number">1</span>, num_epochs + <span class="number">1</span>), train_ls, <span class="string">'epochs'</span>, <span class="string">'rmse'</span>,</span><br><span class="line"> range(<span class="number">1</span>, num_epochs + <span class="number">1</span>), valid_ls,</span><br><span class="line"> [<span class="string">'train'</span>, <span class="string">'valid'</span>])</span><br><span class="line"> print(<span class="string">'fold %d, train rmse %f, valid rmse %f'</span> % (i, train_ls[<span class="number">-1</span>], valid_ls[<span class="number">-1</span>]))</span><br><span class="line"> <span class="keyword">return</span> train_l_sum / k, valid_l_sum / k</span><br></pre></td></tr></table></figure>
<h3 id="模型选择-1"><a href="#模型选择-1" class="headerlink" title="模型选择"></a>模型选择</h3><p>我们使用一组未经调优的超参数并计算交叉验证误差。可以改动这些超参数来尽可能减小平均测试误差。 有时候你会发现一组参数的训练误差可以达到很低,但是在折交叉验证上的误差可能反而较高。这种现象很可能是由过拟合造成的。因此,当训练误差降低时,我们要观察折交叉验证上的误差是否也相应降低。<br><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">k, num_epochs, lr, weight_decay, batch_size = <span class="number">5</span>, <span class="number">100</span>, <span class="number">5</span>, <span class="number">0</span>, <span class="number">64</span></span><br><span class="line">train_l, valid_l = k_fold(k, train_features, train_labels, num_epochs, lr, weight_decay, batch_size)</span><br><span class="line">print(<span class="string">'%d-fold validation: avg train rmse %f, avg valid rmse %f'</span> % (k, train_l, valid_l))</span><br><span class="line"><span class="comment"># fold 0, train rmse 0.241365, valid rmse 0.223083</span></span><br><span class="line"><span class="comment"># fold 1, train rmse 0.229118, valid rmse 0.267488</span></span><br><span class="line"><span class="comment"># fold 2, train rmse 0.232072, valid rmse 0.237995</span></span><br><span class="line"><span class="comment"># fold 3, train rmse 0.238050, valid rmse 0.218671</span></span><br><span class="line"><span class="comment"># fold 4, train rmse 0.231004, valid rmse 0.259185</span></span><br><span class="line"><span class="comment"># 5-fold validation: avg train rmse 0.234322, avg valid rmse 0.241284</span></span><br></pre></td></tr></table></figure></p>
<h3 id="预测并在Kaggle中提交结果"><a href="#预测并在Kaggle中提交结果" class="headerlink" title="预测并在Kaggle中提交结果"></a>预测并在Kaggle中提交结果</h3><p>下面定义预测函数。在预测之前,我们会使用完整的训练数据集来重新训练模型,并将预测结果存成提交所需要的格式。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">train_and_pred</span><span class="params">(train_features, test_features, train_labels, test_data,</span></span></span><br><span class="line"><span class="function"><span class="params"> num_epochs, lr, weight_decay, batch_size)</span>:</span></span><br><span class="line"> net = get_net(train_features.shape[<span class="number">1</span>])</span><br><span class="line"> train_ls, _ = train(net, train_features, train_labels, <span class="literal">None</span>, <span class="literal">None</span>,</span><br><span class="line"> num_epochs, lr, weight_decay, batch_size)</span><br><span class="line"> d2l.semilogy(range(<span class="number">1</span>, num_epochs + <span class="number">1</span>), train_ls, <span class="string">'epochs'</span>, <span class="string">'rmse'</span>)</span><br><span class="line"> print(<span class="string">'train rmse %f'</span> % train_ls[<span class="number">-1</span>])</span><br><span class="line"> preds = net(test_features).detach().numpy()</span><br><span class="line"> test_data[<span class="string">'SalePrice'</span>] = pd.Series(preds.reshape(<span class="number">1</span>, <span class="number">-1</span>)[<span class="number">0</span>])</span><br><span class="line"> submission = pd.concat([test_data[<span class="string">'Id'</span>], test_data[<span class="string">'SalePrice'</span>]], axis=<span class="number">1</span>)</span><br><span class="line"> submission.to_csv(<span class="string">'./submission.csv'</span>, index=<span class="literal">False</span>)</span><br><span class="line"> <span class="comment"># sample_submission_data = pd.read_csv("../input/house-prices-advanced-regression-techniques/sample_submission.csv")</span></span><br></pre></td></tr></table></figure>
<p>设计好模型并调好超参数之后,下一步就是对测试数据集上的房屋样本做价格预测。如果我们得到与交叉验证时差不多的训练误差,那么这个结果很可能是理想的,可以在Kaggle上提交结果。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">train_and_pred(train_features, test_features, train_labels, test_data, num_epochs, lr, weight_decay, batch_size)</span><br></pre></td></tr></table></figure>
<h2 id="笔记整理-1"><a href="#笔记整理-1" class="headerlink" title="笔记整理"></a>笔记整理</h2><ol>
<li><p>标签偏移指的是出现训练中不存在的标签,而圣诞礼物属于训练中存在的标签</p>
</li>
<li><p>请问反向传播是怎么回事?<br>将权重沿负梯度方向进行小步长的位移,可以逐渐的使loss函数下降,从而让模型具有好的效果。<br>反向传播其实就是从终点的loss往回回溯出每一个变量的梯度,从而好进行梯度下降的优化。<br>我看到梯度下降知识点的视频已放出,可以去学习一下,应该就对反向传播的意义有比较好的理解了。</p>
</li>
<li><p>还是不懂标签偏移量和协变量偏移是什么?<br>标签偏移是在P(x∣y),在y的条件下x的概率,可以假设为y不变的情况下x的概率,而现实是y导致x发生了变化,而y是变化的所以就发生了标签偏移,因为y是标签。<br>而协变量偏移P(y∣x),同理可以假设为在x不变的情况下y的概率,而现实是x发生了变化导致y发生了变化,所以就发生了协变量偏移,x为变量。</p>
</li>
<li><p>在反向传播中,每个隐藏单元的参数梯度值相等,这是为什么呢?<br>算出来相等那就确实相等,不是一定会相等</p>
</li>
</ol>
<h1 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h1>]]></content>
<categories>
<category>Datawhale</category>
<category>动手学深度学习</category>
</categories>
<tags>
<tag>datawhale</tag>
<tag>dl</tag>
<tag>深度学习</tag>
<tag>deep learning</tag>
<tag>动手学深度学习</tag>
</tags>
</entry>
<entry>
<title>解决hbase中region in transition的问题</title>
<url>/p/2019/06/18/d99909a6/</url>
<content><![CDATA[<p>由于RIT问题导致hbase的regionserver起不来。</p>
<a id="more"></a>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/d99909a6/e5357743b2cd6a51f8ea3461e0e14b3f.png" alt="region in transition情况"><br><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/d99909a6/e3cbbf5c9a240ca109110bd3f8c9b8a6.png" alt="ambari中的hbase"></p>
<h1 id="删除hdfs中的表文件"><a href="#删除hdfs中的表文件" class="headerlink" title="删除hdfs中的表文件"></a>删除hdfs中的表文件</h1><p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/d99909a6/318413a12eeeea61e4d8ed5ba4f81514.png" alt="删除hdfs中的表文件"><br><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">su hdfs</span><br><span class="line">hdfs dfs -rm -r -f /apps/hbase/data/data/default/gdelt</span><br><span class="line">hdfs dfs -rm -r -f /apps/hbase/data/data/default/gdelt_gdelt_2dquickstart_z3_geom_dtg_v6</span><br></pre></td></tr></table></figure></p>
<h1 id="重启hbase后,修复hbase"><a href="#重启hbase后,修复hbase" class="headerlink" title="重启hbase后,修复hbase"></a>重启hbase后,修复hbase</h1><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">su hbase</span><br><span class="line">hbase hbck -repair</span><br></pre></td></tr></table></figure>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/d99909a6/441af90ee32ae54b0670a253b0d9780f.png" alt="修复hbase"></p>
<h1 id="链接zk,删除僵尸表"><a href="#链接zk,删除僵尸表" class="headerlink" title="链接zk,删除僵尸表"></a>链接zk,删除僵尸表</h1><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cd</span> /usr/hdp/2.6.5.0-292/zookeeper/bin/</span><br><span class="line">./zkCli.sh</span><br><span class="line">ls /hbase/table</span><br><span class="line">rmr /hbase/table/gdelt</span><br></pre></td></tr></table></figure>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/d99909a6/5972c536549f882184b1b91efcb47ee9.png" alt="删除僵尸表"></p>
<h1 id="在zk中删除rit相关信息"><a href="#在zk中删除rit相关信息" class="headerlink" title="在zk中删除rit相关信息"></a>在zk中删除rit相关信息</h1><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ls /hbase/region-in-transition</span><br><span class="line">rmr /hbase/region-in-transition/6f6f4f8204ccaa0b71df08591de155ba</span><br></pre></td></tr></table></figure>
<h1 id="重启hbase"><a href="#重启hbase" class="headerlink" title="重启hbase"></a>重启hbase</h1>]]></content>
<categories>
<category>FAQ</category>
<category>BigData</category>
</categories>
<tags>
<tag>hdp</tag>
<tag>ambari</tag>
<tag>大数据</tag>
<tag>rit</tag>
<tag>hbase</tag>
<tag>region in transition</tag>
</tags>
</entry>
<entry>
<title>Task4 机器翻译及相关技术;注意力机制与Seq2seq模型;Transformer</title>
<url>/p/2020/02/13/92342664/</url>
<content><![CDATA[<h1 id="机器翻译及相关技术"><a href="#机器翻译及相关技术" class="headerlink" title="机器翻译及相关技术"></a>机器翻译及相关技术</h1><h2 id="笔记整理"><a href="#笔记整理" class="headerlink" title="笔记整理"></a>笔记整理</h2><p>数据预处理</p>
<ol>
<li>读取数据,处理数据中的编码问题,并将无效的字符串删除</li>
<li>分词,分词的目的就是将字符串转换成单词组成的列表。目前有很多现成的分词工具可以直接使用,也可以直接按照空格进行分词(不推荐,因为分词不是很准确)</li>
<li>建立词典,将单词组成的列表编程单词id组成的列表,这里会得到如下几样东西<ol>
<li>去重后词典,及其中单词对应的索引列表</li>
<li>还可以得到给定索引找到其对应的单词的列表,以及给定单词得到对应索引的字典。</li>
<li>原始语料所有词对应的词典索引的列表</li>
</ol>
</li>
<li>对数据进行padding操作。</li>
<li>制作数据生成器,但是需要注意的是对于翻译任务的数据格式,机器翻译的输入是一段文本序列,输出也是一段文本序列。</li>
</ol>
<a id="more"></a>
<p>Seq2Seq模型的构建</p>
<ol>
<li>Seq2Seq模型由很多钟,但是整体框架都是基于先编码后解码的框架。也就是先对输入序列使用循环神经网络对他进行编码,编码成一个向量之后,再将编码得到的向量作为一个新的解码循环神经网络的隐藏状态的输入,进行解码,一次输出一个序列的元素,再将模型训练输出的序列元素与真实标签计算损失进行学习。</li>
<li>词嵌入,一般情况下输入到编码网络中的数据不是一个onehot向量而是经过了编码之后的向量,比如由word2vec技术,让编码后的向量由更加丰富的含义。</li>
<li>在进行编码和解码的过程中数据都是以时间步展开,也就是(Seq_len,)这种形式的数据进行处理的</li>
<li>对于编码与解码的循环神经网络,可以通过控制隐藏层的层数及每一层隐藏层神经元的数量来控制模型的复杂度</li>
<li>编码部分,RNN的用0初始化隐含状态,最后的输出主要是隐藏状态,编码RNN输出的隐含状态认为是其对应的编码向量</li>
<li>解码器的整体形状与编码器是一样的,只不过解码器的模型的隐藏状态是由编码器的输出的隐藏状态初始化的。</li>
</ol>
<p>损失函数</p>
<ol>
<li>解码器的输出是一个和词典维度相同的向量,其每个值对应与向量索引位置对应词的分数,一般是选择分数最大的那个词作为最终的输出。</li>
<li>在计算损失函数之前,要把padding去掉,因为padding的部分不参与计算</li>
</ol>
<p>测试</p>
<ol>
<li>解码器在测试的时候需要将模型的输出作为下一个时间步的输入</li>
<li>Beam Search搜索算法。<ol>
<li>假设预测的时候词典的大小为3,内容为a,b,c. beam size为2,解码的时候过程如下</li>
<li>生成第一个词的时候,选择概率最大的两个词,假设为a,c.那么当前的两个序列就是a和c。</li>
<li>生成第二个词的时候,将当前序列a和c,分别与此表中的所有词进行组合,得到新的6个序列aa ab ac ca cb cc,计算每个序列的得分,并选择得分最高的2个序列,作为新的当前序列,假如为aa cb </li>
<li>后面不断重复这个过程,直到遇到结束符或者达到最大长度为止,最终输出得分最高的2个序列。</li>
</ol>
</li>
</ol>
<p>想问问大家 做word_embedding 为什么会用到训练过程呀?一感觉就是一个词 转成 索引 再根据字典大小 转成词向量 ,字典大小应该是固定的,那不就可以直接得出,为何训练呢~ 类比前面学到的 把词转换成索引再转成one hot向量 (字符级时)</p>
<p>训练了才能获取嵌入词向量啊<br>通用任务是可以不训练,用别人训好的,但是要想取得更好的效果,最好还是在实际数据分布下训一个word-embedding“过拟合”一下。<br>举个形象点的例子,某一通用点的语料库上训的embedding可能在检测辱骂场景就很不好用,有些很关键的词分布是差异很大的,甚至没出现过。<br>假设使用one hot编码的话,那些词的表示是没有语义的,比如representation(男人) - representation(女人) = representation(男孩) - representation(女孩) 是得不到的。word embedding中最常见的word2vev使用语料库训练的时候,实际在进行两个事情,一个是根据前一个词猜后一个词,还有一个是某个词的上下文,也就是前后词猜中间这个。这样的方式得到表示会包含语义,但是也会有其他问题,所以word embedding也有很多不同的方法。</p>
<p>1.为何代码处source和target分别不同方式预处理数据(增加start/end),而不统一用True<br> src_array, src_valid_len = build_array(source, src_vocab, max_len, True)<br> tgt_array, tgt_valid_len = build_array(target, tgt_vocab, max_len, False)</p>
<p>2.如何设定max_len?<br>src_vocab, tgt_vocab, train_iter = load_data_nmt(batch_size=2, max_len=8) </p>
<p>3.在encoder和decoder会分别设置embedding层,如果导入已训练好的word embedding,希望参数不参加训练,该如何设置?</p>
<p>1.build_array中,你所说的True的parameter是is_source…所以在生成target数据的时候要设定为False。可以去看build_array函数的定义。<br>2.max_len的选取要看source和target数据集的句长统计. 可以选择所有句长平均值。<br>3.<br>self.embed = nn.Embedding(vocab_size, embedding_size)<br>self.embed.weight.data.copy_(torch.from_numpy(pretrained_embeddings))<br>self.embed.weight.requires_grad = False<br>这里pretrained_embeddings就是预训练好的词向量array</p>
<p>在进行word_embedding的时候应该要把参数padding_index设置为pad的token吧..这样pad对应的词向量就不会参与训练了?<br>是的,此时padding_idx所在的行初始化为0 ,并且不会反向传播</p>
<p>这里都默认大家知道lstm是什么了,然而我忘了。。。decoder的初始输入包含encoder最后一个hidden state以及一个memory cell<br>这个memory cell是什么?<br>memory cell就是LSTM的基本单元</p>
<h1 id="注意力机制与Seq2seq模型"><a href="#注意力机制与Seq2seq模型" class="headerlink" title="注意力机制与Seq2seq模型"></a>注意力机制与Seq2seq模型</h1><h2 id="笔记整理-1"><a href="#笔记整理-1" class="headerlink" title="笔记整理"></a>笔记整理</h2><p>那个masked_softmax为什么要repeat?<br>X shape: (batch_size, seq_length, input_dim)<br>valid_length指一个sequence的有效长度,所以shape应该为(batch_size, seq_length)<br>当valid_length是一个1-D tensor的时候,表示同一个batch的每个sequence有效长度相同,因此要在同一batch内进行repeat</p>
<h1 id="Transformer"><a href="#Transformer" class="headerlink" title="Transformer"></a>Transformer</h1><h2 id="笔记整理-2"><a href="#笔记整理-2" class="headerlink" title="笔记整理"></a>笔记整理</h2><p>我在transpose_qkv函数里输出原始的X的形状是[2,4,9]和注释里写的[batch_size,sql_len,hidden_size<em>num_heads]不一样,,这是为什么?<br>MultiHeadAttention层初始化的hidden_size其实是hidden_size </em> num_heads<br>例子里<code>num_heads=3, hidden_size=3</code>,总的<code>all_hidden_size=9</code></p>
]]></content>
<categories>
<category>Datawhale</category>
<category>动手学深度学习</category>
</categories>
<tags>
<tag>datawhale</tag>
<tag>dl</tag>
<tag>深度学习</tag>
<tag>deep learning</tag>
<tag>动手学深度学习</tag>
</tags>
</entry>
<entry>
<title>Task5 卷积神经网络基础;leNet;卷积神经网络进阶</title>
<url>/p/2020/02/13/aa23684a/</url>
<content><![CDATA[<h1 id="卷积神经网络基础"><a href="#卷积神经网络基础" class="headerlink" title="卷积神经网络基础"></a>卷积神经网络基础</h1><h2 id="笔记整理"><a href="#笔记整理" class="headerlink" title="笔记整理"></a>笔记整理</h2><p>通过观察互相关运算可知,输入数据(这里以二维数组为例)的边缘部分相较于中间部分来说,使用的次数较少,对于一些存储重要信息的边缘数据来说,这无疑是重大的损失,这里可以通过填充来解决这一问题吗??也就是在输入数据的边缘填充0,使得原来的边缘数据中心化???<br> padding解决不了这个问题,因为padding的内容其实是不包含信息量的0。<br> 这个问题感觉是个不错的思考~但是又感觉很奇怪,平时是遇不到这个问题的。<br> 比如给你一张狗的图片,shape 224<em>224,你换成 222</em>222,你不可能不认识它了。<br> 比如即使你使用7<em>7的大卷积核,损失的也仅仅是边缘的3个像素而已。<br> 更何况现在都是3</em>3的卷积核,那1个像素是不会包含什么重要信息的。</p>
<p> padding的用途之一就是弥补特征提取时可能造成的边缘信息缺失。我们人在观察图片内容的过程,其实也是就是一个特征提取的过程。人在拍摄照片时,习惯将重要的事物放在图片中央,所以,在用卷积操作提取图片特征时,中间运算次数多,两边少,这是能满足大多数图像重要信息提取的。但是,当你的图片中边缘有重要信息,而卷积核又取得相对较大时,为了更好的保留边缘信息,我们可以考虑使用SAME padding,保持特征图不缩小(具体计算公式见我给出的PPT)。楼上这位朋友解释说“padding解决不了这个问题,因为padding的内容其实是不包含信息量的0。”,这不太对。因为他忽略了虽然padding的0不含信息,但是原始图片(或是FM)的边缘是包含信息的啊,而且你认为边缘信息对你当前要处理的任务来说是重要的,所以,你在要SAME padding处理,以尽可能多提取边缘信息啊。</p>
<a id="more"></a>
<p> 老师提出问题<br> conv2d.weight.data -= lr <em> conv2d.weight.grad<br> conv2d.bias.data -= lr </em> conv2d.bias.grad<br> 上面两行代码,如果删掉.data会发生什么?如果遇到一些问题,如何解决?<br> 经测试:如果删掉.data,也就是代码变为:<br> conv2d.weight -= lr <em> conv2d.weight.grad<br> conv2d.bias -= lr </em> conv2d.bias.grad<br> 会报错:RuntimeError: a leaf Variable that requires grad has been used in an in-place operation.<br> 这里给出一种解决方法:<br> with torch.no_grad( ):<br> conv2d.weight -= lr <em> conv2d.weight.grad<br> conv2d.bias -= lr </em> conv2d.bias.grad</p>
<p> 为什么两个连续的3×3卷积核的感受野与一个5×5卷积核的感受野相同?<br> 比如一个7X7的图像,经过一次5<em>5的卷积核后形成一个3</em>3的特征图;<br> 同样一个7X7的图像,经过两次次3<em>3的卷积核后才形成形成一个3</em>3的特征图。</p>
<p> 例子中的Kernel都是固定值,但是再torch的nn.Conv2d()中只给出了kernel_size的值,这是为什么,是因为kernel value也是一个学习的变量吗?<br> kernel_size 是需要手动调整的,但是在训练过程中并不需要学习。<br> 因此kernel_size准确来说是一个超参数,目前越来越趋向于使用小的卷积核,如1<em>1,3</em>3。</p>
<pre><code>kernel_size(即卷积核大小)这是需要人为设定的参数,该参数是不需要学习的,当然大小不同,卷积结果也是不同的。经过大量实验表明,大多选用1*1、3*3、5*5等尺寸较小且长宽为奇数的卷积核。
对于卷积核内的数值(可以认为是对应卷积作用区域下像素值的权重大小),这个数值是需要学习。当给定kernel_size时,函数即会初始化该卷积核内的数值。
</code></pre><p> 卷积层和池化的区别?<br> 最大的区别是,池化层没有需要学习的特征<br> 卷积层用来学习识别某一种特征<br> 池化层的主要作用是降维<br> 卷积层当设置步长>1时也可以用来完成降维的工作</p>
<h1 id="leNet"><a href="#leNet" class="headerlink" title="leNet"></a>leNet</h1><h2 id="笔记整理-1"><a href="#笔记整理-1" class="headerlink" title="笔记整理"></a>笔记整理</h2><p>在训练测试过程中,每次都对optimizer进行清零处理,为啥结果的acc还是呈现递增的趋势<br> acc 是 accuracy,准确率,当然是越高越好啦。<br> optimizer = optim.SGD(net.parameters(), lr=lr),对优化器清零是清除的梯度,防止梯度累加,为下一波梯度计算留空间。而学习的参数并不清零,所以参数越来越优。<br> 和前面梯度优化的例子一样,清零不影响网络的记忆性(不能说是连续的,目前的还很难达到连续性智能)</p>
<p>1、在构建网络时,卷积核应该怎么设置呢?这块可以讲解下吗?还是说可以通过梯度传播调整<br>2、卷积的时候图像个数增加是因为引入多个卷积核吗?<br>3、构建网络时时是否每次卷积完毕必须引入池化层?还是说这个看网络设计者的调节</p>
<ol>
<li>很多同学都在问这块的问题,如何设计神经网络,其实不是这么课程重点需要关注的问题。<br> 实际使用时往往不需要你来设计,基本上都是用经典结构,最多是进行一些改造。<br> 那么到底如何设计呢?这块一两句话肯定说不清,可以按照发展顺序阅读经典论文,去寻求一些模型设计经验的线索。<br> LeNet -> AlexNet -> VGG -> GoogleNet -> ResNet -> DenseNet 等等,后面就不说了,还有数不尽的论文等待着去学习。。。</li>
<li>这个问题提问我没太看明白</li>
<li>不是每个卷积层后面都要池化,经常是多个卷积层后面接一个池化层。<br> 池化是为了降维,我们最终希望提取到的是一些抽象的有代表性的特征,而不是很多很多感受野非常小的细节特征,例如纹理,颜色等。<br> 而且有的网络也会不使用池化层,而是使用步长>1的卷积层来替代pool层完成降维的工作。</li>
</ol>
<p>池化层可以改变通道数?<br>池化层不是输入与输出的通道数相同,池化层的内核和padding可以改变特征的宽和高,但是通道数量不是不变的吗?<br> 标准的池化层不改变通道数,手动实现当然更改平均池化或者最大池化运算的通道数层,但效果差异不大,因为可以通过卷积层改变通道数。</p>
<p>这里选择的池化,放大放小的比例,通道数似乎没有明确的说明,原理是什么??<br>如果是经验数据的话,这个可不可以成为学习的对象,通过调整卷积核和padding的大小能否选择出更好的网络??<br> 当然可以通过调整看看会不会效果更好,这些都是人为设定的。</p>
<p>请问从pooling的6通道变成卷积层的16通道的详细变换过程是怎样的,依据是什么?<br> 通道的数量取决于卷积核的数量,只不过LeNet的作者选择了16个</p>
<p>在卷积、池化的过程中,会出现通到数增加的情况,这应该是为了尽可能地提取特征信息;在leNet网络里面,通道数的变化比例是最优的吗??? 里面是否有理论支持,或者是一个经验数据呢?????<br> leNet网络里面的通道数变化比例在原始论文没有明确的理论支持,应该是一个经验数据</p>
<h1 id="卷积神经网络进阶"><a href="#卷积神经网络进阶" class="headerlink" title="卷积神经网络进阶"></a>卷积神经网络进阶</h1><h2 id="笔记整理-2"><a href="#笔记整理-2" class="headerlink" title="笔记整理"></a>笔记整理</h2><p>这里的ALNet引入了一个概念,就是按某一个概率p将某处权重置0,那么按这个网络前进后,还可以进行反向传播吗??? 还有就是我们这里按一定规律取消部分神经元的作用,也就相当于采用另一种模型方式,那么我们这里的AlexNet就相当于一个模型集了,这理论上应该可以从多方面提取特征信息;然而就像人的大脑分成很多部分一样,如果我们不是单纯地使用一个简单的概率来规划神经元的使用,而是将不同神经元分成不同的区域或者进行更有效的规划,会不会让AI更连续呢??? 就像张钹院士在18年的一次报告中提到的,对于不满足“5个条件”的数据,也能很好预测<br> 可以,不更新失活单元的权重就行了。</p>
<p>多换一个数据集的话(主要是size的变化),NiN block是不是仅需要改变第一个Convolution的大小,而后续的1x1的Convolution保持不变?<br> 是的,你观察到了卷积和全连接的一个重要的差别,卷积其实不关心特征图的H和W。<br> 如果你从10分类shape224<em>224</em>3的彩色数据集,切换到一个2分类shape160<em>160</em>1的灰度图数据集。<br> 只需要替换第一个卷积的input_channel 和最后一个卷积或者全连接层的output_channel。<br> 而如果你是从彩色数据集换成了彩色数据集,第一个卷积甚至都不需要发生变化。</p>
<p>卷积其实不关心特征图的H和W“的原因是什么呢?<br> 卷积的工作流程是,以一定的卷积核大小,一定的步长,在特征图的不同位置,用同一个卷积核来进行互相关运算。<br> 这就好像是,一个卷积核是用来提取某一种局部特征的,它在图像中的不同位置来寻找是否有符合它所关心的特征的局部区域。<br> 这种工作机制导致了图像的尺寸(宽和高)并不影响卷积运算,只有通道数的变化才会影响。</p>
<p>inception网络第一个7<em>7卷积层后面为什么要加relu激活?<br>或者说b2中1</em>1卷积和3*3卷积为什么没加relu?还有inception定义中的p1 = F.relu(self.p1_1(x)),F是什么?<br> F是torch.nn.functional,前面有<code>import torch.nn.functional as F</code><br> 激活的话</p>
<ul>
<li>1x1 conv除了改变channel数,还有增加非线性的作用,一般都会跟着一个激活层</li>
<li>其他感觉比较玄学设计,CV里可能跟ReLU可以做到单侧抑制增加稀疏有关吧</li>
</ul>
]]></content>
<categories>
<category>Datawhale</category>
<category>动手学深度学习</category>
</categories>
<tags>
<tag>datawhale</tag>
<tag>dl</tag>
<tag>深度学习</tag>
<tag>deep learning</tag>
<tag>动手学深度学习</tag>
</tags>
</entry>
<entry>
<title>Day1 数据初识</title>
<url>/p/2019/04/07/2612ecd/</url>
<content><![CDATA[<h2 id="任务"><a href="#任务" class="headerlink" title="任务"></a>任务</h2><p>建立模型通过长文本数据正文(article),预测文本对应的类别(class)</p>
<h2 id="数据"><a href="#数据" class="headerlink" title="数据"></a>数据</h2><p>数据包含2个csv文件:</p>
<ol>
<li><p>train_set.csv 此数据集用于训练模型,每一行对应一篇文章。文章分别在“字”和“词”的级别上做了脱敏处理。共有四列:<br>第一列是文章的索引(id),第二列是文章正文在“字”级别上的表示,即字符相隔正文(article);第三列是在“词”级别上的表示,即词语相隔正文(word_seg);第四列是这篇文章的标注(class)。<br>注:每一个数字对应一个“字”,或“词”,或“标点符号”。“字”的编号与“词”的编号是独立的!</p>
</li>
<li><p>test_set.csv:此数据用于测试。数据格式同train_set.csv,但不包含class。<br>注:test_set与train_test中文章id的编号是独立的。</p>
</li>
</ol>
<h2 id="评分标准"><a href="#评分标准" class="headerlink" title="评分标准"></a>评分标准</h2><p>评分算法:binary-classification<br>采用各个品类F1指标的算术平均值,它是Precision 和 Recall 的调和平均数。</p>
<p>其中,Pi是表示第i个种类对应的Precision, Ri是表示第i个种类对应Recall。</p>
<a id="more"></a>
<hr>
<h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd</span><br><span class="line"></span><br><span class="line">data_train = pd.read_csv(<span class="string">'../dc-nlp/data/train_set.csv'</span>)</span><br><span class="line">data_test = pd.read_csv(<span class="string">'../dc-nlp/data/test_set.csv'</span>)</span><br><span class="line"></span><br><span class="line">data_train.drop(columns=<span class="string">'article'</span>, inplace=<span class="literal">True</span>)</span><br><span class="line">data_test.drop(columns=<span class="string">'article'</span>, inplace=<span class="literal">True</span>)</span><br><span class="line">f_all = pd.concat(objs=[data_train, data_test], axis=<span class="number">0</span>, sort=<span class="literal">True</span>)</span><br><span class="line">y_train = (data_train[<span class="string">'class'</span>] - <span class="number">1</span>).values</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category>Datawhale</category>
</categories>
<tags>
<tag>datawhale</tag>
<tag>达观杯</tag>
<tag>nlp</tag>
</tags>
</entry>
<entry>
<title>Day1 机器学习概述</title>
<url>/p/2020/01/07/7dbd4cd6/</url>
<content><![CDATA[<h2 id="任务"><a href="#任务" class="headerlink" title="任务"></a>任务</h2><h3 id="理论部分"><a href="#理论部分" class="headerlink" title="理论部分"></a>理论部分</h3><ul>
<li>机器学习介绍:机器学习是什么,怎么来的,理论基础是什么,为了解决什么问题。</li>
<li>机器学习分类:<ul>
<li>按学习方式分:有监督、无监督、半监督 </li>
<li>按任务类型分:回归、分类、聚类、降维 生成模型与判别模型</li>
</ul>
</li>
<li>机器学习方法三要素:<ul>
<li><strong>模型</strong> </li>
<li><strong>策略</strong>:损失函数 </li>
<li><strong>算法</strong>:梯度下降法、牛顿法、拟牛顿法</li>
<li>模型评估指标:R2、RMSE、accuracy、precision、recall、F1、ROC、AUC、Confusion Matrix </li>
<li>复杂度度量:偏差与方差、过拟合与欠拟合、结构风险与经验风险、泛化能力、正则化 </li>
<li>模型选择:正则化、交叉验证 </li>
<li>采样:样本不均衡 </li>
<li>特征处理:归一化、标准化、离散化、one-hot编码 </li>
<li>模型调优:网格搜索寻优、随机搜索寻优</li>
</ul>
</li>
</ul>
<a id="more"></a>
<h2 id="机器学习综述"><a href="#机器学习综述" class="headerlink" title="机器学习综述"></a>机器学习综述</h2><blockquote>
<p>2016年3月,阿尔法围棋与围棋世界冠军、职业九段棋手李世石进行围棋人机大战,以4比1的总比分获胜。深度学习开始进行大众的视野中。深度学习其实是机器学习的一个分支,我们今天来看看机器学习是什么。机器学习是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。它是人工智能的核心,是使计算机具有智能的根本途径。 </p>
</blockquote>
<h3 id="机器学习的发展"><a href="#机器学习的发展" class="headerlink" title="机器学习的发展"></a>机器学习的发展</h3><p>其中,机器学习(Machine Learning)的各个阶段发展历程列表如下。</p>
<table><br><br><tr><th>时间段</th><th>机器学习理论</th><th>代表性成果</th></tr><br><br><tr><td rowspan="2">二十世纪五十年代初</td><td>人工智能研究处于推理期</td><td>A. Newell和H. Simon的“逻辑理论家”(Logic Theorist)程序证明了数学原理,以及此后的“通用问题求解”(General Problem Solving)程序。</td></tr><br><tr><td>已出现机器学习的相关研究</td><td>1952年,阿瑟·萨缪尔(Arthur Samuel)在IBM公司研制了一个西洋跳棋程序,这是人工智能下棋问题的由来。</td></tr><br><tr><td>二十世纪五十年代中后期</td><td>开始出现基于神经网络的“连接主义”(Connectionism)学习</td><td>F. Rosenblatt提出了感知机(Perceptron),但该感知机只能处理线性分类问题,处理不了“异或”逻辑。还有B. Widrow提出的Adaline。</td></tr><br><tr><td rowspan="4">二十世纪六七十年代</td><td>基于逻辑表示的“符号主义”(Symbolism)学习技术蓬勃发展</td><td>P. Winston的结构学习系统,R. S. Michalski的基于逻辑的归纳学习系统,以及E. B. Hunt的概念学习系统。</td></tr><br><tr><td>以决策理论为基础的学习技术</td><td> </td></tr><br><tr><td>强化学习技术</td><td>N. J. Nilson的“学习机器”。</td></tr><br><tr><td>统计学习理论的一些奠基性成果</td><td>支持向量,VC维,结构风险最小化原则。</td></tr><br><tr><td rowspan="4">二十世纪八十年代至九十年代中期</td><td>机械学习(死记硬背式学习)<br>示教学习(从指令中学习)<br>类比学习(通过观察和发现学习)<br>归纳学习(从样例中学习)</td><td>学习方式分类</td></tr><br><tr><td>从样例中学习的主流技术之一:(1)符号主义学习<br>(2)基于逻辑的学习</td><td>(1)决策树(decision tree)。<br>(2)归纳逻辑程序设计(Inductive Logic Programming, ILP)具有很强的知识表示能力,可以较容易地表达出复杂的数据关系,但会导致学习过程面临的假设空间太大,复杂度极高,因此,问题规模稍大就难以有效地进行学习。</td></tr><br><tr><td>从样例中学习的主流技术之二:基于神经网络的连接主义学习</td><td>1983年,J. J. Hopfield利用神经网络求解“流动推销员问题”这个NP难题。1986年,D. E. Rumelhart等人重新发明了BP算法,BP算法一直是被应用得最广泛的机器学习算法之一。</td></tr><br><tr><td>二十世纪八十年代是机器学习成为一个独立的学科领域,各种机器学习技术百花初绽的时期</td><td>连接主义学习的最大局限是“试错性”,学习过程涉及大量参数,而参数的设置缺乏理论指导,主要靠手工“调参”,参数调节失之毫厘,学习结果可能谬以千里。</td></tr><br><tr><td>二十世纪九十年代中期</td><td>统计学习(Statistical Learning)</td><td>支持向量机(Support Vector Machine,SVM),核方法(Kernel Methods)。</td></tr><br><tr><td>二十一世纪初至今</td><td>深度学习(Deep Learning)</td><td>深度学习兴起的原因有二:数据量大,机器计算能力强。</td></tr><br><br></table>
<h3 id="机器学习分类-6"><a href="#机器学习分类-6" class="headerlink" title="机器学习分类 ^6"></a>机器学习分类 <a href="https://machinelearningmastery.com/a-tour-of-machine-learning-algorithms/" target="_blank" rel="noopener">^6</a></h3><ol>
<li><p>监督学习<br> 监督学习是指利用一组已知类别的样本调整分类器的参数,使其达到所要求性能的过程,也称为监督训练或有教师学习。在监督学习的过程中会提供对错指示,通过不断地重复训练,使其找到给定的训练数据集中的某种模式或规律,当新的数据到来时,可以根据这个函数预测结果。监督学习的训练集要求包括输入和输出,主要应用于分类和预测。<br><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/7dbd4cd6/Supervised-Learning-Algorithms.png" alt="Supervised Learning"></p>
</li>
<li><p>非监督学习<br> 与监督学习不同,在非监督学习中,无须对数据集进行标记,即没有输出。其需要从数据集中发现隐含的某种结构,从而获得样本数据的结构特征,判断哪些数据比较相似。因此,非监督学习目标不是告诉计算机怎么做,而是让它去学习怎样做事情。<br><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/7dbd4cd6/Unsupervised-Learning-Algorithms.png" alt="Unsupervised Learning"></p>
</li>
<li><p>半监督学习<br> 半监督学习是监督学习和非监督学习的结合,其在训练阶段使用的是未标记的数据和已标记的数据,不仅要学习属性之间的结构关系,也要输出分类模型进行预测。<br><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/7dbd4cd6/Semi-supervised-Learning-Algorithms.png" alt="Semi-Supervised Learning"></p>
</li>
<li><p>强化学习<br> 强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题。</p>
</li>
</ol>
<h3 id="机器学习模型"><a href="#机器学习模型" class="headerlink" title="机器学习模型"></a>机器学习模型</h3><p>机器学习 = 数据(data) + 模型(model) + 优化方法(optimal strategy)</p>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/7dbd4cd6/machinelearningalgorithms.png" alt="机器学习的算法导图"></p>
<p><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/7dbd4cd6/A%20few%20useful%20things%20to%20know%20about%20machine%20learning.jpg" alt="机器学习的注意事项"></p>
<p><strong> 常见的机器学习算法 </strong></p>
<ol>
<li>Linear Algorithms<ol>
<li>Linear Regression</li>
<li>Lasso Regression </li>
<li>Ridge Regression</li>
<li>Logistic Regression</li>
</ol>
</li>
<li>Decision Tree<ol>
<li>ID3</li>
<li>C4.5</li>
<li>CART</li>
</ol>
</li>
<li>SVM</li>
<li>Naive Bayes Algorithms<ol>
<li>Naive Bayes</li>
<li>Gaussian Naive Bayes</li>
<li>Multinomial Naive Bayes</li>
<li>Bayesian Belief Network (BBN)</li>
<li>Bayesian Network (BN)</li>
</ol>
</li>
<li>kNN</li>
<li>Clustering Algorithms<ol>
<li>k-Means</li>
<li>k-Medians</li>
<li>Expectation Maximisation (EM)</li>
<li>Hierarchical Clustering</li>
</ol>
</li>
<li>K-Means</li>
<li>Random Forest</li>
<li>Dimensionality Reduction Algorithms</li>
<li>Gradient Boosting algorithms<ol>
<li>GBM</li>
<li>XGBoost</li>
<li>LightGBM</li>
<li>CatBoost</li>
</ol>
</li>
<li>Deep Learning Algorithms<ol>
<li>Convolutional Neural Network (CNN)</li>
<li>Recurrent Neural Networks (RNNs)</li>
<li>Long Short-Term Memory Networks (LSTMs)</li>
<li>Stacked Auto-Encoders</li>
<li>Deep Boltzmann Machine (DBM)</li>
<li>Deep Belief Networks (DBN)</li>
</ol>
</li>
</ol>
<h3 id="机器学习损失函数-8"><a href="#机器学习损失函数-8" class="headerlink" title="机器学习损失函数 ^8"></a>机器学习损失函数 <a href="https://www.cnblogs.com/lliuye/p/9549881.html" target="_blank" rel="noopener">^8</a></h3><ol>
<li><p>0-1损失函数(0-1 loss function)<br>$$<br> L(y,f(x)) =<br> \begin{cases}<br> 0, & \text{y = f(x)} \<br> 1, & \text{y $\neq$ f(x)}<br> \end{cases}<br>$$<br>也就是说,当预测错误时,损失函数为1,当预测正确时,损失函数值为0。该损失函数不考虑预测值和真实值的误差程度。只要错误,就是1。</p>
</li>
<li><p>绝对值损失函数(absolute loss function)<br>$$<br> L(y,f(x))=|y-f(x)|<br>$$<br>该损失函数的意义和上面差不多,只不过是取了绝对值而不是求绝对值,差距不会被平方放大。</p>
</li>
<li><p>平方损失函数(quadratic loss function)<br>$$<br> L(y,f(x))=(y-f(x))^2<br>$$<br>是指预测值与实际值差的平方。</p>
</li>
<li><p>log对数损失函数(logarithmic loss function)<br>$$<br> L(y,f(x))=log(1+e^{-yf(x)})<br>$$<br>这个损失函数就比较难理解了。事实上,该损失函数用到了极大似然估计的思想。P(Y|X)通俗的解释就是:在当前模型的基础上,对于样本X,其预测值为Y,也就是预测正确的概率。由于概率之间的同时满足需要使用乘法,为了将其转化为加法,我们将其取对数。最后由于是损失函数,所以预测正确的概率越高,其损失值应该是越小,因此再加个负号取个反。</p>
</li>
<li><p>指数损失函数<br>$$<br> L(y,f(x))=exp(-yf(x))<br>$$</p>
</li>
<li><p>Hinge损失函数<br>Hinge loss一般分类算法中的损失函数,尤其是SVM,其定义为:<br>$$<br> L(w,b)=max{0,1-yf(x)}<br>$$<br>其中$$ y=+1 $$或$$ y=−1 $$ ,$$ f(x)=wx+b $$,当为SVM的线性核时。</p>
</li>
</ol>
<h3 id="机器学习优化方法"><a href="#机器学习优化方法" class="headerlink" title="机器学习优化方法"></a>机器学习优化方法</h3><p>梯度下降是最常用的优化方法之一,它使用梯度的反方向$\nabla_\theta J(\theta)$更新参数$\theta$,使得目标函数$J(\theta)$达到最小化的一种优化方法,这种方法我们叫做梯度更新。</p>
<ol>
<li>(全量)梯度下降<br>$$<br> \theta=\theta-\eta\nabla_\theta J(\theta)<br>$$</li>
<li>随机梯度下降<br>$$<br> \theta=\theta-\eta\nabla_\theta J(\theta;x^{(i)},y^{(i)})<br>$$</li>
<li>小批量梯度下降<br>$$<br> \theta=\theta-\eta\nabla_\theta J(\theta;x^{(i:i+n)},y^{(i:i+n)})<br>$$</li>
<li>引入动量的梯度下降<br>$$<br> \begin{cases}<br> v_t=\gamma v_{t-1}+\eta \nabla_\theta J(\theta) \<br> \theta=\theta-v_t<br> \end{cases}<br>$$</li>
<li>自适应学习率的Adagrad算法<br>$$<br> \begin{cases}<br> g_t= \nabla_\theta J(\theta) \<br> \theta_{t+1}=\theta_{t,i}-\frac{\eta}{\sqrt{G_t+\varepsilon}} \cdot g_t<br> \end{cases}<br>$$</li>
<li>牛顿法<br>$$<br> \theta_{t+1}=\theta_t-H^{-1}\nabla_\theta J(\theta_t)<br>$$<br>其中:<br>$t$: 迭代的轮数<br>$\eta$: 学习率<br>$G_t$: 前t次迭代的梯度和<br>$\varepsilon:$很小的数,防止除0错误<br>$H$: 损失函数相当于$\theta$的Hession矩阵在$\theta_t$处的估计</li>
</ol>
<h3 id="机器学习的评价指标-8"><a href="#机器学习的评价指标-8" class="headerlink" title="机器学习的评价指标 ^8"></a>机器学习的评价指标 <a href="https://www.cnblogs.com/lliuye/p/9549881.html" target="_blank" rel="noopener">^8</a></h3><ol>
<li><p>均方误差 MSE(Mean Squared Error)<br>$$<br> MSE(y,f(x))=\frac{1}{N}\sum_{i=1}^{N}(y-f(x))^2<br>$$<br>均方误差是指参数估计值与参数真值之差平方的期望值; MSE可以评价数据的变化程度,MSE的值越小,说明预测模型描述实验数据具有更好的精确度。( $ i $表示第$ i $个样本,$ N $ 表示样本总数)<br><strong>通常用来做回归问题的代价函数。</strong></p>
</li>
<li><p>平均绝对误差 MAE(Mean Absolute Error)<br>$$<br> MSE(y,f(x))=\frac{1}{N}\sum_{i=1}^{N}|y-f(x)|<br>$$<br>平均绝对误差是绝对误差的平均值 ,平均绝对误差能更好地反映预测值误差的实际情况。<br><strong>通常用来作为回归算法的性能指标。</strong></p>
</li>
<li><p>均方根误差 RMSE(Root Mean Squard Error)<br>$$<br> RMSE(y,f(x))=\frac{1}{1+MSE(y,f(x))}<br>$$<br>均方根误差是均方误差的算术平方根,能够直观观测预测值与实际值的离散程度。<br><strong>通常用来作为回归算法的性能指标。</strong></p>
</li>
<li><p>Top-k准确率<br>$$<br> Top_k(y,pre_y)=\begin{cases}<br> 1, {y \in pre_y} \<br> 0, {y \notin pre_y}<br> \end{cases}<br>$$</p>
</li>
<li><p>混淆矩阵 [9]<br><table><br><tr><th>混淆矩阵</th><br><th>Predicted as Positive</th><th>Predicted as Negative</th><br></tr><br><tr><td>Labeled as Positive</td><td>True Positive(TP)</td><td>False Negative(FN)</td></tr><br><tr><td>Labeled as Negative</td><td>False Positive(FP)</td><td>True Negative(TN)</td></tr><br></table></p>
<ul>
<li>真正例(True Positive, TP):真实类别为正例, 预测类别为正例</li>
<li>假负例(False Negative, FN): 真实类别为正例, 预测类别为负例</li>
<li>假正例(False Positive, FP): 真实类别为负例, 预测类别为正例 </li>
<li>真负例(True Negative, TN): 真实类别为负例, 预测类别为负例</li>
<li>真正率(True Positive Rate, TPR): 被预测为正的正样本数 / 正样本实际数<br>$$<br> TPR=\frac{TP}{TP+FN}<br>$$</li>
<li><p>假负率(False Negative Rate, FNR): 被预测为负的正样本数/正样本实际数<br>$$<br> FNR=\frac{FN}{TP+FN}<br>$$</p>
</li>
<li><p>假正率(False Positive Rate, FPR): 被预测为正的负样本数/负样本实际数,<br>$$<br> FPR=\frac{FP}{FP+TN}<br>$$</p>
</li>
<li>真负率(True Negative Rate, TNR): 被预测为负的负样本数/负样本实际数,<br>$$<br> TNR=\frac{TN}{FP+TN}<br>$$</li>
<li>准确率(Accuracy)<br>$$<br> ACC=\frac{TP+TN}{TP+FN+FP+TN}<br>$$</li>
<li>精准率<br>$$<br> P=\frac{TP}{TP+FP}<br>$$</li>
<li>召回率<br>$$<br> R=\frac{TP}{TP+FN}<br>$$</li>
<li>F1-Score<br>$$<br> \frac{2}{F_1}=\frac{1}{P}+\frac{1}{R}<br>$$</li>
<li>ROC<br>ROC曲线的横轴为“假正例率”,纵轴为“真正例率”。以FPR为横坐标,TPR为纵坐标,那么ROC曲线就是改变各种阈值后得到的所有坐标点 (FPR,TPR) 的连线,画出来如下。红线是随机乱猜情况下的ROC,曲线越靠左上角,分类器越佳。</li>
<li><p>AUC(Area Under Curve)<br>AUC就是ROC曲线下的面积。真实情况下,由于数据是一个一个的,阈值被离散化,呈现的曲线便是锯齿状的,当然数据越多,阈值分的越细,”曲线”越光滑。<br><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/7dbd4cd6/f11f3a292df5e0feaafde78c566034a85fdf7251.jpg" alt></p>
<p>用AUC判断分类器(预测模型)优劣的标准:</p>
<ul>
<li>AUC = 1 是完美分类器,采用这个预测模型时,存在至少一个阈值能得出完美预测。绝大多数预测的场合,不存在完美分类器.</li>
<li>0.5 < AUC < 1,优于随机猜测。这个分类器(模型)妥善设定阈值的话,能有预测价值.</li>
<li>AUC < 0.5,比随机猜测还差;但只要总是反预测而行,就优于随机猜测.</li>
</ul>
</li>
</ul>
</li>
</ol>
<h3 id="机器学习模型选择"><a href="#机器学习模型选择" class="headerlink" title="机器学习模型选择"></a>机器学习模型选择</h3><ol>
<li><p>交叉验证<br>所有数据分为三部分:训练集、交叉验证集和测试集。交叉验证集不仅在选择模型时有用,在超参数选择、正则项参数 [公式] 和评价模型中也很有用。</p>
</li>
<li><p>k-折叠交叉验证</p>
<ul>
<li>假设训练集为S ,将训练集等分为k份:${S_1, S_2, …, S_k}$。</li>
<li>然后每次从集合中拿出k-1份进行训练</li>
<li>利用集合中剩下的那一份来进行测试并计算损失值</li>
<li>最后得到k次测试得到的损失值,并选择平均损失值最小的模型</li>
</ul>
</li>
<li><p>Bias与Variance,欠拟合与过拟合 <a href="https://zhuanlan.zhihu.com/p/30844838" target="_blank" rel="noopener">^12</a><br>如下图,针对同一组数据的三种模型,可以看出来中间的模型可以更好的表现数据,其中左边的模型一般称为欠拟合,右边的模型称为过拟合。<br><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/7dbd4cd6/v2-fa2af9b3bae2515771ad627f2af14a5b_r.jpg" alt><br><strong>欠拟合</strong>一般表示模型对数据的表现能力不足,通常是模型的复杂度不够,并且Bias高,训练集的损失值高,测试集的损失值也高.<br><strong>过拟合</strong>一般表示模型对数据的表现能力过好,通常是模型的复杂度过高,并且Variance高,训练集的损失值低,测试集的损失值高.<br><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/7dbd4cd6/v2-e20cd1183ec930a3edc94b30274be29e_r.jpg" alt><br><img data-src="https://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/7dbd4cd6/v2-22287dec5b6205a5cd45cf6c24773aac_hd.jpg" alt><br>Bias描述的是模型与数据表现的真实情况的差别,Variance描述的是我们的假设与最好的假设之间的差别。</p>
</li>
<li><p>解决方法</p>
<ul>
<li>增加训练样本: 解决高Variance情况</li>
<li>减少特征维数: 解决高Variance情况</li>
<li>增加特征维数: 解决高Bias情况</li>
<li>增加模型复杂度: 解决高Bias情况</li>
<li>减小模型复杂度: 解决高Variance情况</li>
</ul>
</li>
</ol>
<h3 id="机器学习参数调优"><a href="#机器学习参数调优" class="headerlink" title="机器学习参数调优"></a>机器学习参数调优</h3><ol>
<li><p>网格搜索<br>一种调参手段;穷举搜索:在所有候选的参数选择中,通过循环遍历,尝试每一种可能性,表现最好的参数就是最终的结果</p>
</li>
<li><p>随机搜索<br>与网格搜索相比,随机搜索并未尝试所有参数值,而是从指定的分布中采样固定数量的参数设置。它的理论依据是,如果随即样本点集足够大,那么也可以找到全局的最大或最小值,或它们的近似值。通过对搜索范围的随机取样,随机搜索一般会比网格搜索要快一些。</p>
</li>
<li><p>贝叶斯优化算法<br>贝叶斯优化用于机器学习调参由J. Snoek(2012)提出,主要思想是,给定优化的目标函数(广义的函数,只需指定输入和输出即可,无需知道内部结构以及数学性质),通过不断地添加样本点来更新目标函数的后验分布(高斯过程,直到后验分布基本贴合于真实分布。简单的说,就是考虑了上一次参数的信息,从而更好的调整当前的参数。</p>
</li>
</ol>
<h3 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h3>]]></content>
<categories>
<category>Datawhale</category>
<category>初级算法梳理</category>
</categories>
<tags>
<tag>datawhale</tag>
<tag>ml</tag>
<tag>机器学习</tag>
<tag>machine learning</tag>
</tags>
</entry>
<entry>
<title>Day2 学习TF-IDF理论并实践</title>
<url>/p/2019/04/07/a4fc168b/</url>
<content><![CDATA[<h2 id="任务"><a href="#任务" class="headerlink" title="任务"></a>任务</h2><p>学习TF-IDF理论并实践,使用TF-IDF表示文本</p>
<a id="more"></a>
<hr>
<h2 id="TF-IDF-Term-Frequency–Inverse-Document-Frequency"><a href="#TF-IDF-Term-Frequency–Inverse-Document-Frequency" class="headerlink" title="TF-IDF(Term Frequency–Inverse Document Frequency)"></a>TF-IDF(Term Frequency–Inverse Document Frequency)</h2><blockquote>
<p>主要思想是:如果词i在一篇文档j中出现的频率高,并且在其他文档中很少出现,则认为词i具有很好的区分能力,适合用来把文章j和其他文章区分开来。适合用来分类。</p>
</blockquote>
<p>TF-IDF实际上是:TF * IDF<br>$$ tfidf_{i,j}=tf_{i,j}\times idf_{i} $$</p>
<p>TF词频(Term Frequency):某一个给定的词语在该文件中出现的频率。<br>$$ tf_{i,j}=\frac{n_{i,j} }{\sum <em>{k}n</em>{k,j}} $$</p>
<p>IDF逆向文件频率(Inverse Document Frequency):是一个词语普遍重要性的度量。如果包含词条t的文档越少,也就是n越小,IDF越大,则说明词条t具有很好的类别区分能力。如果某一类文档C中包含词条t的文档数为m,而其它类包含t的文档总数为k,显然所有包含t的文档数n=m+k,当m大的时候,n也大,按照IDF公式得到的IDF的值会小,就说明该词条t类别区分能力不强。<br>$$ idf_{i}=lg\frac{\left | D \right |}{\left | \left { j:t_{i}\in d_{j} \right } \right |} $$</p>
<hr>
<h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd</span><br><span class="line"><span class="keyword">from</span> sklearn.feature_extraction.text <span class="keyword">import</span> TfidfVectorizer</span><br><span class="line"></span><br><span class="line">vectorizer = TfidfVectorizer(ngram_range=(<span class="number">1</span>, <span class="number">2</span>), min_df=<span class="number">3</span>, max_df=<span class="number">0.9</span>, sublinear_tf=<span class="literal">True</span>)</span><br><span class="line">vectorizer.fit(train_set[<span class="string">'word_seg'</span>])</span><br><span class="line">x_train = vectorizer.transform(train_set[<span class="string">'word_seg'</span>])</span><br><span class="line">x_val = vectorizer.transform(val_set[<span class="string">'word_seg'</span>])</span><br><span class="line"></span><br><span class="line">print(x_trains)</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category>Datawhale</category>
</categories>
<tags>
<tag>datawhale</tag>
<tag>nlp</tag>
<tag>machine learning</tag>
<tag>tf-idf</tag>
</tags>
</entry>
<entry>
<title>Day3 学习Word2Vec理论并实践</title>
<url>/p/2019/04/09/40163d71/</url>
<content><![CDATA[<h2 id="任务"><a href="#任务" class="headerlink" title="任务"></a>任务</h2><p>学习word2vec词向量原理并实践,用来表示文本</p>
<h2 id="资料"><a href="#资料" class="headerlink" title="资料"></a>资料</h2><p><a href="https://www.bilibili.com/video/av41393758/?p=2" target="_blank" rel="noopener">CS224n 斯坦福深度自然语言处理课</a><br><a id="more"></a></p>
<hr>
<h2 id="One-Hot编码"><a href="#One-Hot编码" class="headerlink" title="One-Hot编码"></a>One-Hot编码</h2><blockquote>
<p>One-Hot编码,又称为一位有效编码,主要是采用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效。</p>
</blockquote>
<p>One-Hot编码是分类变量作为二进制向量的表示。这首先要求将分类值映射到整数值。然后,每个整数值被表示为二进制向量,除了整数的索引之外,它都是零值,它被标记为1。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> sklearn <span class="keyword">import</span> preprocessing </span><br><span class="line"> </span><br><span class="line">enc = preprocessing.OneHotEncoder() </span><br><span class="line">enc.fit([[<span class="number">0</span>,<span class="number">0</span>,<span class="number">3</span>],[<span class="number">1</span>,<span class="number">1</span>,<span class="number">0</span>],[<span class="number">0</span>,<span class="number">2</span>,<span class="number">1</span>],[<span class="number">1</span>,<span class="number">0</span>,<span class="number">2</span>]]) <span class="comment">#这里一共有4个数据,3种特征</span></span><br><span class="line"> </span><br><span class="line">array = enc.transform([[<span class="number">0</span>,<span class="number">1</span>,<span class="number">3</span>]]).toarray() <span class="comment">#这里使用一个新的数据来测试</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">print</span> array <span class="comment"># [[ 1 0 0 1 0 0 0 0 1]]</span></span><br></pre></td></tr></table></figure>
<p>将离散型特征进行one-hot编码的作用,是为了让距离计算更合理,但如果特征是离散的,并且不用one-hot编码就可以很合理的计算出距离,那么就没必要进行one-hot编码。</p>
<h2 id="Word2Vec"><a href="#Word2Vec" class="headerlink" title="Word2Vec"></a>Word2Vec</h2><blockquote>
<p>Word2vec,是一群用来产生词向量(word embedding)的相关模型。这些模型为浅而双层的神经网络,用来训练以重新建构语言学之词文本。</p>
</blockquote>
<p>Predict between every word and its context word!</p>
<p>两种算法:Skip-grams(SG)和Continuous Bag of Words(CBOW)<br><img data-src="http://lingmoumou-blog.oss-cn-beijing.aliyuncs.com/blog/sg-and-cbow.jpg?Expires=1554825387&OSSAccessKeyId=TMP.AQEikGQYqIYajs8ySbZHclaK0dte9NKTBtT652mkGdKgh--kqX9etfeD_AH4ADAtAhRE8PfThSeXBuFYPSaQvhEC81yUkgIVAOn1w4pDv6Atbb-YyivFf7W_L16C&Signature=cNbuThZa5T0HaFd7PrWS8zB4lYQ%3D" alt="SG&CBOW"></p>
<h3 id="SG-Skip-Gram"><a href="#SG-Skip-Gram" class="headerlink" title="SG(Skip-Gram)"></a>SG(Skip-Gram)</h3><blockquote>
<p>顾名思义,Skip-gram 就是“跳过某些符号”,是一个简单但却非常实用的模型。</p>
</blockquote>
<p>Skip-grams模型输入是特定的一个词的词向量,而输出是特定词对应的上下文词向量。<br>Skip-gram 模型解决的是n元模型中,因为窗口大小的限制,导致超出窗口范围的词语与当前词之间的关系不能被正确地反映到模型之中,如果单纯扩大窗口大小又会增加训练的复杂度。<br>例如,句子“中国足球踢得真是太烂了”有4个3元词组,分别是“中国足球踢得”、“足球踢得真是”、“踢得真是太烂”、“真是太烂了”,可是我们发现,这个句子的本意就是“中国足球太烂”可是上述 4个3元词组并不能反映出这个信息。Skip-gram 模型却允许某些词被跳过,因此可以组成“中国足球太烂”这个3元词组。 如果允许跳过2个词,即 2-Skip-gram。</p>
<h3 id="CBOW-Continuous-Bag-of-Words"><a href="#CBOW-Continuous-Bag-of-Words" class="headerlink" title="CBOW(Continuous Bag-of-Words)"></a>CBOW(Continuous Bag-of-Words)</h3><blockquote>
<p>Skip-Gram模型和CBOW的思路是反着来的,CBOW的训练输入是某一个特征词的上下文相关的词对应的词向量,而输出就是这特定的一个词的词向量。</p>