-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
2360 lines (2211 loc) · 239 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
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"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>https://FuNian788.github.io</id>
<title>Zexian Li</title>
<updated>2021-07-20T07:48:24.372Z</updated>
<generator>https://github.com/jpmonette/feed</generator>
<link rel="alternate" href="https://FuNian788.github.io"/>
<link rel="self" href="https://FuNian788.github.io/atom.xml"/>
<subtitle>Colorful life.</subtitle>
<logo>https://FuNian788.github.io/images/avatar.png</logo>
<icon>https://FuNian788.github.io/favicon.ico</icon>
<rights>All rights reserved 2021, Zexian Li</rights>
<entry>
<title type="html"><![CDATA[目标检测(object detection)论文小记]]></title>
<id>https://FuNian788.github.io/post/detection/</id>
<link href="https://FuNian788.github.io/post/detection/">
</link>
<updated>2021-06-26T03:23:13.000Z</updated>
<content type="html"><![CDATA[<p>简单记录最近阅读的几篇有趣的目标检测论文🎅<br>
<ul class="markdownIt-TOC">
<li>
<ul>
<li><a href="#%E6%96%B9%E6%B3%95%E7%BB%BC%E8%BF%B0">方法综述</a></li>
<li><a href="#%E8%AF%84%E4%BB%B7%E6%8C%87%E6%A0%87">评价指标</a></li>
<li><a href="#%E5%B8%B8%E7%94%A8%E6%95%B0%E6%8D%AE%E9%9B%86">常用数据集</a></li>
<li><a href="#%E8%AE%BA%E6%96%87%E7%AC%94%E8%AE%B0">论文笔记</a>
<ul>
<li><a href="#1-2021-cvpryolof-you-only-look-one-level-feature">(1) (2021 CVPR)YOLOF: You Only Look One-level Feature</a></li>
<li><a href="#2-fairretinanet-focal-loss-for-dense-object-detection">(2) (FAIR)RetinaNet: Focal Loss for Dense Object Detection</a></li>
<li><a href="#3-2019-iccvfcos-fully-convolutional-one-stage-object-detection">(3) (2019 ICCV)FCOS: Fully Convolutional One-Stage Object Detection</a></li>
<li><a href="#4-2020-cvpr-oralatss-bridging-the-gap-between-anchor-based-and-anchor-free-detection-via-adaptive-training-sample-selection">(4) (2020 CVPR oral)ATSS: Bridging the Gap Between Anchor-based and Anchor-free Detection via Adaptive Training Sample Selection</a></li>
<li><a href="#5-2019-cvprhr-net-deep-high-resolution-representation-learning-for-visual-recognition">(5) (2019 CVPR)HR-Net: Deep High-Resolution Representation Learning for Visual Recognition</a></li>
<li><a href="#6-2018-eccvcornernet-detecting-objects-as-paired-keypoints">(6) (2018 ECCV)CornerNet: Detecting Objects as Paired Keypoints</a></li>
</ul>
</li>
<li><a href="#%E5%9F%BA%E6%9C%AC%E5%B8%B8%E8%AF%86">基本常识</a></li>
</ul>
</li>
</ul>
</p>
<h2 id="方法综述">方法综述</h2>
<p>目标检测的主流方法是anchor-based,也存在一些anchor-free的尝试。<br>
<strong>anchor-based</strong>:在图片上铺海量的预设anchor,随后对anchor进行种类预测和n次边界回归。通常来说,双阶段方法对边界修正的次数会多于单阶段方法,所以二阶段方法通常有较高的精度,单阶段方法常有较高的计算效率。</p>
<ul>
<li>one-stage<br>
均匀且密集地采样以获得海量候选框,随后进行分类(eg SSD)</li>
<li>two-stage<br>
在筛选过的、稀疏的候选框(滤掉了绝大多数背景/负样本)上进行分类(eg Faster R-CNN)</li>
</ul>
<p><strong>anchor-free</strong>:不使用预设anchor,直接检测物体。</p>
<ul>
<li>keypoint-based<br>
先定位一些预设的/自学习得到的关键点,再依此生成候选框以检测物体(eg Cornernet预测候选框的左上角和右下角点,再进行组合)</li>
<li>center-based<br>
将物体正中心点/中心区域视为正样本,再基于此预测该位置到目标四条边框的距离(eg FCOS将前景框的所有像素点均视为正样本,随后对每个点回归其到框边界的距离)</li>
</ul>
<h2 id="评价指标">评价指标</h2>
<p>mAP</p>
<h2 id="常用数据集">常用数据集</h2>
<p>MS COCO:包含80类物体。数据集划分如下:train有80k图片,val有40k图片。<br>
MSCOCO 2017: training118k validation5k(val) testing about20k无标注(test-dev)<br>
trainval35k部分的115K图片(train的80k图片+)用于训练,minival部分的5k图片用于validation。</p>
<!--
## 指标比对
以COCO数据集AP作为基准指标,比较各方法如下:
| ID | paper | AP | AP50 | AP75 | APs | APm | APl |
| :--: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| 1 | YOLOF | 37.7 | 56.9 | 40.6 | 19.1 | 42.5 | 53.2 |
-->
<h2 id="论文笔记">论文笔记</h2>
<h3 id="1-2021-cvpryolof-you-only-look-one-level-feature">(1) <a href="https://arxiv.org/abs/2103.09460">(2021 CVPR)YOLOF: You Only Look One-level Feature</a></h3>
<ul>
<li>Motivation</li>
</ul>
<p>对RetinaNet的FPN结构做消解实验发现:SiMo仅轻微掉点,故C5特征可能就已涵盖了检测所需要的足够信息;SiMo明显优于MiSo,故分治策略(即多检测头)的重要性远大于融合输入特征的重要性。由上述两点,决定将输入从多输入砍到单输入。<br>
通常认为FPN的核心优势在于多特征融合(multi-scale feature fusion)和分治策略(divide-and-conquer)。本文提出,FPN最大的优势是在密集目标检测时使用分治策略(逐级检测)来进行优化。<br>
<img src="https://FuNian788.github.io/post-images/object_detection/yolof_1.png" alt="RetinaNet-FPN-单多输入-单多输出" loading="lazy"></p>
<p>分治策略可以视为一种优化的方法:将大问题拆分成小问题来解决。但其多头结构降低检测速度,使结构更复杂,带来了更大的空间负担。决定将多输出砍到单输出。</p>
<ul>
<li>主要贡献</li>
</ul>
<p>将FPN简化成单输入(32倍下采样的C5特征)单输出的结构,同时为了弥补SiSo到MiMo的性能差距:</p>
<ol>
<li>
<p>C5特征的感受野大小受限<br>
提出了空洞编码器(Dilated Encoder)来获取多尺度特征</p>
</li>
<li>
<p>Positive anchor对应的GT大小不均衡<br>
提出均衡匹配策略(Uniform Matching)来解决单特征图中稀疏anchor引起的positive anchor不平衡问题。</p>
</li>
</ol>
<p>COCO数据集上,在效果相当的同时,YOLOF可以:<br>
比FPN版本速度快了2.5倍;比DETR的训练轮次少了7倍;比YOLOv4快了13%。</p>
<ul>
<li>
<p>overall<br>
<img src="https://FuNian788.github.io/post-images/object_detection/yolof_2.png" alt="YOLOF结构" loading="lazy"></p>
</li>
<li>
<p>实现细节</p>
</li>
</ul>
<ol>
<li>
<p>空洞编码器<br>
C5特征的感受野很小,只能cover小物体;使用连续的dilated conv疯狂扩展感受野后,只能捕获大物体。故使用残差结构+空洞卷积,使模型既可以捕获小物体,也能捕获大物体。<br>
<img src="https://FuNian788.github.io/post-images/object_detection/yolof_3.png" alt="dilated encoder" loading="lazy"><br>
模型的Projector部分,使用1*1卷积减少通道数,使用3*3卷积修复语义信息;残差块部分使用四个不同dilated rate,不共享参数的block,每个block中,第一个conv降通道数,第二个dilated conv扩大感受野,第三个conv恢复通道数。</p>
</li>
<li>
<p>均衡匹配策略<br>
MiMo模型可以在不同的输出层级上定义不同大小的anchor,然而SiSo模型只有单层输出,对应的anchor数量自然变少。anchor本就容易和大尺度样本有较大的overlap,假设将与任GT bbox的IoU>0.5的anchor定义为positive anchor,那单输入特征图&少anchor时,anchor的不均衡就更为明显:positive anchor主要由大样本占据;模型的重心在大样本上,检出小样本的数量变少。<br>
<img src="https://FuNian788.github.io/post-images/object_detection/yolof_4.png" alt="positive anchor均衡性" loading="lazy"><br>
Uniform Matching:对于每个GT bbox,选取距其最近的K=4个anchor作为positive anchor。<br>
YOLOF在C5 feature的每个位置上构建5个anchor,尺度分别为{32, 64, 128, 256, 512}。</p>
</li>
</ol>
<ul>
<li>改进/Challenge/idea/Que</li>
</ul>
<hr>
<h3 id="2-fairretinanet-focal-loss-for-dense-object-detection">(2) <a href="https://arxiv.org/abs/1708.02002">(FAIR)RetinaNet: Focal Loss for Dense Object Detection</a></h3>
<ul>
<li>Motication<br>
one-stage方法和two-stage方法的核心区别在于:two-stage送去分类器的候选框是稀疏的(过滤了绝大多数背景样本),而为了实现检测任务,one-stage必须在图片内进行密集的均匀采样,得到未经过滤的候选框并依此去cover所有空间位置。自然地,one-stage这种采样方法得到的候选框中以容易被分类的背景框居多。two-stage方法的候选框大概在1~2k个,one-stage方法的候选框却可达到100k个左右。</li>
</ul>
<p>为什么two-stage方法常常更准呢?本文认为其核心问题在于<strong>训练检测器时样本所属前景-背景类别的不均衡性</strong>(the extreme foreground-background class imbalance encountered during training of dense detectors)。基于此,作者在交叉熵损失函数的基础上提出了Focal Loss,有效阻止海量的、易被分类的背景样本主导训练过程,在对其进行降权的同时,让网络更加关注难样本(更多是正样本)的分类过程。总体来说,当网络对一个样本的预测越准确,该样本对loss的贡献程度越低。</p>
<ul>
<li>
<p>主要贡献<br>
提出Focal Loss来解决正负样本不均衡的问题;基于此提出one-stage的RetinaNet,在保持优良速度的同时具有大幅超过two-stage方法的精度,达到SOTA。</p>
</li>
<li>
<p>overall<br>
对于交叉熵损失函数,在真值类别时,<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>L</mi><mi>o</mi><mi>s</mi><mi>s</mi><mo>=</mo><mo>−</mo><mi>l</mi><mi>o</mi><mi>g</mi><mo>(</mo><mi>P</mi><mo>)</mo></mrow><annotation encoding="application/x-tex">Loss = -log(P)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault">L</span><span class="mord mathdefault">o</span><span class="mord mathdefault">s</span><span class="mord mathdefault">s</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">−</span><span class="mord mathdefault" style="margin-right:0.01968em;">l</span><span class="mord mathdefault">o</span><span class="mord mathdefault" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="mclose">)</span></span></span></span>,在其他类别时,<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>L</mi><mi>o</mi><mi>s</mi><mi>s</mi><mo>=</mo><mo>−</mo><mi>l</mi><mi>o</mi><mi>g</mi><mo>(</mo><mn>1</mn><mo>−</mo><mi>P</mi><mo>)</mo></mrow><annotation encoding="application/x-tex">Loss = -log(1 - P)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault">L</span><span class="mord mathdefault">o</span><span class="mord mathdefault">s</span><span class="mord mathdefault">s</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">−</span><span class="mord mathdefault" style="margin-right:0.01968em;">l</span><span class="mord mathdefault">o</span><span class="mord mathdefault" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="mclose">)</span></span></span></span>。作者认为在此中,简单样本带来的loss不足够小,当简单的背景样本过于多的时候还是可以主宰整个训练过程。为了将训练的注意力集中在难样本上,作者提出了如下图的focal loss。<br>
<img src="https://FuNian788.github.io/post-images/object_detection/retinanet_1.png" alt="positive anchor均衡性" loading="lazy"><br>
假设模型输出概率<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>P</mi></mrow><annotation encoding="application/x-tex">P</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.13889em;">P</span></span></span></span>。对应地,在两种情况下分析模型处理简单样本的过程:在真值类别下,<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>P</mi></mrow><annotation encoding="application/x-tex">P</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.13889em;">P</span></span></span></span>很大,接近于1,<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>P</mi><mi>t</mi></msub><mo>=</mo><mi>P</mi></mrow><annotation encoding="application/x-tex">P_{t} = P</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2805559999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">t</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.13889em;">P</span></span></span></span>,这时损失函数的值就超小;在其他类别下,预测得很准时<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>P</mi></mrow><annotation encoding="application/x-tex">P</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.13889em;">P</span></span></span></span>应该很小,接近于0,此时的<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>P</mi><mi>t</mi></msub><mo>=</mo><mn>1</mn><mo>−</mo><mi>P</mi></mrow><annotation encoding="application/x-tex">P_{t} = 1 - P</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2805559999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">t</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.13889em;">P</span></span></span></span>还是很大,损失函数仍然很小。反之,处理难样本时的损失函数没有被削减。</p>
</li>
</ul>
<figure data-type="image" tabindex="1"><img src="https://FuNian788.github.io/post-images/object_detection/retinanet_2.png" alt="RetinaNet结构图" loading="lazy"></figure>
<!--
* 实现细节
1. anchor
在每个位置上,
在不同的输出特征图上限制检出物体的大小。
* 改进/Challenge/idea/Que
-->
<hr>
<h3 id="3-2019-iccvfcos-fully-convolutional-one-stage-object-detection">(3) <a href="https://arxiv.org/abs/1904.01355">(2019 ICCV)FCOS: Fully Convolutional One-Stage Object Detection</a></h3>
<ul>
<li>针对痛点:</li>
</ul>
<ol>
<li>anchor-based方法需要人为设计框的尺寸及超参数,这些参数的优劣会造成显著地性能差异,且人为设计的候选框很难匹配尺度多变的目标;</li>
<li>anchor-based方法常需要海量的候选框(eg FPN在800见方的图片中需要180K个anchor),过多的负样本框会造成训练时的样本不平衡;训练时对IoU的不断计算也会导致较大的计算开销;</li>
<li>传统的anchor-free & one-stage方法有<strong>两大弊端</strong>,一是只将anchor中心点所在的网格试做正样本,这种样本不平衡对recall有较大负面影响;一是很难处理重叠物体(anchor方法可很好的解决重叠问题)。</li>
</ol>
<ul>
<li>主要贡献:</li>
</ul>
<ol>
<li>FCN(fully convolutional networks)已其他领域开展得如火如荼,eg语义分割,首在object detection领域基于FCN方法实现的FCOS有助于复用其他领域经验。</li>
<li>anchor-free的FCOS省去了调参的负担,在计算更轻量、训练更容易的同时有着不亚于two-stage/anchor-based方法的精度,启发了对anchor必要性的思考。</li>
<li>提出one-stage的FCN-based网络,提出基于FPN的多尺度预测和center-ness方法,有效解决了当下存在的两大弊端。</li>
</ol>
<ul>
<li>实现流程:<br>
网络的流程图如下所示:<br>
<img src="https://FuNian788.github.io/post-images/TAD/FCOS_1.png" alt="流程图" loading="lazy"><br>
对于单个候选框,每层网络输出一个K维分类label、一个4维距离坐标和一个center-ness得分。该网络较常用的anchor-based方法减少了近9倍的参数量。</li>
<li>实现细节:</li>
</ul>
<ol>
<li>one-stage FCN网络<br>
针对弊端一,FCOS不再只将中心点所在的网格视为正样本,而是将GT bbox所覆盖的所有网格均视为正样本。因此,FCOS舍弃了anchor-based方法中先确定候选框中心位置,再以依此对anchor进行回归的做法,具体地,如下左图所示,对每个前景框的每个点(location),都预测其到GT bbox的上下左右四条边的距离[t, b, l, r],该做法与FCN-based方法在语义分割领域的实现思路一致,且值得注意的是,与anchor-based方法仅将与GT bbox有较高IoU的anchor作为正样本相比,FCOS将GT内的所有像素均作为正样本进行训练,无形中获取了更多更准的信息。<br>
<img src="https://FuNian788.github.io/post-images/TAD/FCOS_2.png" alt="示例图" loading="lazy"><br>
对于某层feature map上的location点(x, y),基于当前层的步长s,先将其映射到原始输入图上的点<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mo>(</mo><mo>⌊</mo><mfrac><mi>s</mi><mn>2</mn></mfrac><mo>⌋</mo><mo>+</mo><mi>x</mi><mi>s</mi><mo separator="true">,</mo><mo>⌊</mo><mfrac><mi>s</mi><mn>2</mn></mfrac><mo>⌋</mo><mo>+</mo><mi>y</mi><mi>s</mi><mo>)</mo></mrow><annotation encoding="application/x-tex">(\lfloor \frac s2 \rfloor + xs, \lfloor \frac s2 \rfloor + ys)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.095em;vertical-align:-0.345em;"></span><span class="mopen">(</span><span class="mopen">⌊</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.695392em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">s</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose">⌋</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.095em;vertical-align:-0.345em;"></span><span class="mord mathdefault">x</span><span class="mord mathdefault">s</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mopen">⌊</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.695392em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">s</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose">⌋</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">y</span><span class="mord mathdefault">s</span><span class="mclose">)</span></span></span></span>,用映射后的坐标再进行到框边距离的预测,使用指数函数输出四个非负距离量,考虑到不同尺度feature map预测物体大小不同,单纯的指数函数得到距离有失偏颇,FCOS在指数函数中加入可学习参数s(distance = exp(s * x))来适应各个尺度的预测。<br>
损失函数方面,分类方面使用focal loss,坐标回归方面使用IOU loss。</li>
<li>基于FPN的多尺度预测<br>
为解决重叠候选框时的分类问题(如上图右),anchor-based方法在不同特征尺度设计不同尺寸的候选框,FCOS则遵循FPN的思路,在不同的feature map层检测不同尺度的目标,且<strong>通过阈值直接限制了每一层检出框的尺寸大小</strong>。在FCOS的五个回归branch中,若预测得到的边长长度不符合当前层的长度限制,直接将其视为负样本,这样便粗暴地解决了不同层内目标含有重叠区域的问题。对于同一层内的重叠区域,FCOS直接使用最小的区域作为回归目标(即使同一层内两个同类物体有重叠,小物体会马上被检出,而大物体也定会在未重叠的区域被检出;但不得不说该方法存在理论缺陷,就是同一层内两个不同类物体有重叠,在重叠部分的location可能会返回A物体的种类和B物体的候选框)。依此,FCOS在多尺度预测的同时很好地解决了物体重叠的问题。<br>
如流程图所示,C3、C4、C5是backbone的feature map,通过1*1的卷积层得到P3、P4、P5,而P6和P7则是由P5、P6经过stride为2的卷积层得到的,不同层之间的heads共享权重。<br>
直觉上可能会认为FCOS的BPR(best possible recall,检测器能实现的recall上限,只要有一个anchor涉及到GT框便将其纳入BPR计算范畴内)会受到FCN-based方法中大步长的制约,但实际上FCOS的BPR甚至优于传统的anchor-based方法,所以recall不是FCOS需要着重解决的问题,或者说FPN解决了这一问题。</li>
<li>center-ness分支<br>
在前两步之后,FCOS的性能较anchor-based方法仍有一定的gap,这主要是由一些距物体中心较远的location产生的低质量候选框导致的,FCOS在不引入更多超参数的情况下提出了center-ness分支直接而有效地减少了低质量候选框。<br>
<img src="https://FuNian788.github.io/post-images/TAD/FCOS_3.png" alt="center-ness" loading="lazy"><br>
center-ness的核心思想是,一个GT bbox内的点很多,但它们对目标的贡献是不同的。偏图像中心的点包含了更多的目标信息,理应得到重视;偏图像边界的点包含的信息相对较少,甚至点可能就不在目标上,这些location提出的候选框的质量常较低,理应设置更小的权重。center-ness表征了一个点到其预测候选框中心的距离,其表达式如下所示:</li>
</ol>
<p class='katex-block'><span class="katex-display"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>c</mi><mi>e</mi><mi>n</mi><mi>t</mi><mi>e</mi><mi>r</mi><mo>−</mo><mi>n</mi><mi>e</mi><mi>s</mi><mi>s</mi><mo>=</mo><msqrt><mrow><mfrac><mrow><mi>m</mi><mi>i</mi><mi>n</mi><mo>(</mo><mi>l</mi><mo separator="true">,</mo><mi>r</mi><mo>)</mo></mrow><mrow><mi>m</mi><mi>a</mi><mi>x</mi><mo>(</mo><mi>l</mi><mo separator="true">,</mo><mi>r</mi><mo>)</mo></mrow></mfrac><mo>∗</mo><mfrac><mrow><mi>m</mi><mi>i</mi><mi>n</mi><mo>(</mo><mi>t</mi><mo separator="true">,</mo><mi>b</mi><mo>)</mo></mrow><mrow><mi>m</mi><mi>a</mi><mi>x</mi><mo>(</mo><mi>t</mi><mo separator="true">,</mo><mi>b</mi><mo>)</mo></mrow></mfrac></mrow></msqrt></mrow><annotation encoding="application/x-tex">center-ness = \sqrt{ \frac {min(l, r)}{max(l, r)} * \frac {min(t, b)}{max(t, b)} }
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69841em;vertical-align:-0.08333em;"></span><span class="mord mathdefault">c</span><span class="mord mathdefault">e</span><span class="mord mathdefault">n</span><span class="mord mathdefault">t</span><span class="mord mathdefault">e</span><span class="mord mathdefault" style="margin-right:0.02778em;">r</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">n</span><span class="mord mathdefault">e</span><span class="mord mathdefault">s</span><span class="mord mathdefault">s</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:3.04em;vertical-align:-1.160625em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.879375em;"><span class="svg-align" style="top:-5em;"><span class="pstrut" style="height:5em;"></span><span class="mord" style="padding-left:1em;"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathdefault">m</span><span class="mord mathdefault">a</span><span class="mord mathdefault">x</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.01968em;">l</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.02778em;">r</span><span class="mclose">)</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathdefault">m</span><span class="mord mathdefault">i</span><span class="mord mathdefault">n</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.01968em;">l</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.02778em;">r</span><span class="mclose">)</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.936em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathdefault">m</span><span class="mord mathdefault">a</span><span class="mord mathdefault">x</span><span class="mopen">(</span><span class="mord mathdefault">t</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault">b</span><span class="mclose">)</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathdefault">m</span><span class="mord mathdefault">i</span><span class="mord mathdefault">n</span><span class="mopen">(</span><span class="mord mathdefault">t</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault">b</span><span class="mclose">)</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.936em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span><span style="top:-3.839375em;"><span class="pstrut" style="height:5em;"></span><span class="hide-tail" style="min-width:1.02em;height:3.08em;"><svg width='400em' height='3.08em' viewBox='0 0 400000 3240' preserveAspectRatio='xMinYMin slice'><path d='M473,2793c339.3,-1799.3,509.3,-2700,510,-2702
c3.3,-7.3,9.3,-11,18,-11H400000v40H1017.7s-90.5,478,-276.2,1466c-185.7,988,
-279.5,1483,-281.5,1485c-2,6,-10,9,-24,9c-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,
-16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200c0,-1.3,-5.3,8.7,-16,30c-10.7,
21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26s76,-153,76,-153s77,-151,
77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104,606z
M1001 80H400000v40H1017z'/></svg></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:1.160625em;"><span></span></span></span></span></span></span></span></span></span></p>
<p>当该点为候选框中心时,center-ness的值为1,该点离中心越远,其值越接近0,使用交叉熵损失函数进行训练。center-ness仅在测试时使用,将其与分类得分(classification score)相乘,共同作为候选框的得分,随后进行NMS筛选。</p>
<!--
* 对动作检测的启发
1. FCN网络结构
2. 动作框预测方式:遍历视频的每一个时刻,返回其到所属动作开始/结束时刻的时间距离
3. 基于FPN的多尺度预测:如果出现了动作套娃(eg运动里套打篮球),可以考虑使用这种方法来一起检出;其他情况下则不合适,eg峰谷峰时如何只取两个峰。但多尺度思路可以应用于尺度不同的任务。
4. 如果一个候选框和GT的IoU较低,其就是一个低质量候选框,这时如果其confidence得分很高,就是Fasle Positive了。center-ness的应用,可以有效解决当前实践中**置信度最高的候选框可能不是最好的**这一问题。
FCOS认为中心lcoation预测的框是高质量的,边缘location预测的框是低质量的,通过表征location位置的center-ness指标来衡量框的质量,利用其削减低质量候选框得分,从而在NMS阶段保留下真正好的候选框。
在动作检测中,center-ness可以IoU的形式出现,拓展地,可以参考IoUNet新建一个独立的网络去预测候选框和GT的IoU以参与得分评价(FCOS的center-ness计算更为简洁,只是在原有预测基础上进行简单比例计算,并没有涉及神经网络架构);而如果搭建FCOS-based的动作检测框架,可以直接利用center-ness思路,但要考虑动作并没有明确中心点这一问题。
-->
<hr>
<h3 id="4-2020-cvpr-oralatss-bridging-the-gap-between-anchor-based-and-anchor-free-detection-via-adaptive-training-sample-selection">(4) <a href="https://arxiv.org/abs/1912.02424">(2020 CVPR oral)ATSS: Bridging the Gap Between Anchor-based and Anchor-free Detection via Adaptive Training Sample Selection</a></h3>
<ul>
<li>Motivation<br>
对比anchor-based one-stage RetinaNet和anchor-free center-based FCOS,二者有以下三个明显的区别:</li>
</ul>
<ol>
<li>每个像素点(location)处铺设anchor的数量<br>
RetinaNet以每个location为中心位置铺设多个anchor;FCOS视每个location为一个点,再回归该点到该点所在候选框的边界的距离。</li>
<li><strong>定义正负训练样本的方法</strong><br>
RetinaNet将与GT bbox的IoU大于阈值的anchor视为正样本;FCOS将GT bbox内的所有像素点视为正样本。</li>
<li>在何种载体上回归<br>
RetinaNet在铺设的anchor上回归;FCOS在像素点上进行物体定位。<br>
实验表明,性能gap的核心在于第二点。</li>
</ol>
<ul>
<li>主要贡献<br>
首先指出:anchor-based方法和anchor-free方法的本质区别在于<strong>如何定义正负训练样本</strong>,也正是这带来了性能上的差距。如果在训练中使用相同的定义正负样本的方法,那无论是基于box还是point进行回归,最后都不会有显著的性能差异。</li>
</ul>
<p>提出了一种自适应的训练样本筛选策略(ATSS, adaptive training sample selection)来依据目标的统计特征自动地筛选样本。</p>
<ul>
<li>实验过程</li>
</ul>
<ol>
<li>
<p>补齐性能差距<br>
对于mAP,RetinaNet为32.5,FCOS为37.8。为探究anchor-based和anchor-free方法的真正区别,需消除FCOS各种trick对于性能gap的影响:RetinaNet每个像素点处仅许产生一个候选框,再将FCOS的各种trick添加到RetinaNet上(In GT box代表限制GT的正样本数量):<br>
<img src="https://FuNian788.github.io/post-images/object_detection/ATSS_1.png" alt="RetinaNet FCOS实验结果对比" loading="lazy"><br>
这时的性能:RetinaNet 37.0 vs FCOS 37.8,仍存在0.8个点的差距。此时anchor-based和anchor-free方法仅有两点不同:检测器分类头对于正负样本的定义、检测器回归头是从anchor回归还是从中心点回归。下面对这两点进行进一步实验,探寻到底哪一个才是问题的关键。</p>
</li>
<li>
<p>分类part<br>
RetinaNet在不同的FPN层级使用IoU来定义样本:将每个目标对应的best anchor和IoU大于阈值的anchor标为正样本,将IoU小于阈值的anchor标为负样本,舍弃剩余anchor。<br>
FCOS在不同的FPN层级基于空间位置和目标尺度来定义样本:中心点在GT bbox内的为候选正样本,再基于目标尺度和FPN层级的匹配性从中筛选得到真正的正样本,剩余为负样本。<br>
<img src="https://FuNian788.github.io/post-images/object_detection/ATSS_2.png" alt="RetinaNet FCOS定义正负样本方法" loading="lazy"></p>
</li>
<li>
<p>回归part<br>
RetinaNet回归4个offset(x, y, w, h),FCOS回归到边界的四个距离(l, r, t, b)。<br>
<img src="https://FuNian788.github.io/post-images/object_detection/ATSS_4.png" alt="RetinaNet FCOS回归方法对比" loading="lazy"></p>
</li>
<li>
<p>性能对比<br>
实验中,只改变了定义样本的方式,但数据可以从多个角度进行分析:<br>
看每一列,回归的方法确定后,RetinaNet和FCOS均会因定义样本的方式而产生较大的性能gap。<br>
<img src="https://FuNian788.github.io/post-images/object_detection/ATSS_3.png" alt="RetinaNet FCOS性能对比" loading="lazy"><br>
以上实验说明,anchor-based和anchor-free方法性能差距的核心在于<strong>训练时定义正负样本的方式不同</strong>。<br>
PS 看每一行,分类时定义正负样本的方法对齐后,尽管回归方式不同,RetinaNet和FCOS(更进一步地,anchor-based和anchor-free)性能却基本相同。</p>
</li>
</ol>
<ul>
<li>
<p>提出改进<br>
FCOS提出的定义正负样本的方法优于之前基于IoU的方法,但这些方法都很依赖超参的设置。本文更进一步地,提出了无超参、鲁棒的、依赖数据特征的定义正负样本新方法ATSS(Adaptive Training Sample Selection)。<br>
<img src="https://FuNian788.github.io/post-images/object_detection/ATSS_5.png" alt="ATSS" loading="lazy"><br>
简要概括:对于GT G,在每一层找k个距其L2距离最近的anchor,组成候选positive anchor的集合P'。随后计算G和P'的IoU,统计其IoU的均值方差并修正,最后保留IoU大于修正值且中心在G内的所有positive anchor,将其组成正样本集合P;剩余的anchor作为负样本。<br>
补充优点:这种方法不会像IoU方法,对大物体表现出明显的青睐,在一定程度上保证了尺度的均衡性。<br>
实验表明,ATSS对于k的大小不敏感,对于anchor的scale和ratio不敏感,具有很好的鲁棒性。</p>
</li>
<li>
<p>实验结果<br>
<img src="https://FuNian788.github.io/post-images/object_detection/ATSS_6.png" alt="ATSS实验结果" loading="lazy"><br>
实验结果表现出了有趣的insight。第一行是原始RetinaNet(每个位置9个anchor),后几行都是每个位置1个anchor。实验结果表明,对于传统的IoU筛选策略,在每个位置多设置一些anchor是有涨点的(37.0 -> 38.4)。然而在优秀的筛选策略ATSS下,每个位置有一个anchor就够了,设置很多不同scale和ratio的anchor反倒没有什么用。</p>
</li>
<li>
<p>改进/Challenge/idea/Que</p>
</li>
</ul>
<hr>
<h3 id="5-2019-cvprhr-net-deep-high-resolution-representation-learning-for-visual-recognition">(5) <a href="https://arxiv.org/abs/1908.07919">(2019 CVPR)HR-Net: Deep High-Resolution Representation Learning for Visual Recognition</a></h3>
<ul>
<li>
<p>Motivation<br>
现有方法常先使用卷积层将输入编码至low-resolution representation,再从中恢复出high-resolution representation(全流程eg U-Net)。然而高分辨率信息对于position-sensitive的任务十分重要。</p>
</li>
<li>
<p>主要贡献<br>
HR-Net在全阶段都维持了高分辨率表示,从而获取更丰富的语义信息和更准确的空间位置。<br>
核心部件:<br>
(1) <strong>并行</strong>的高分辨率到低分辨率的卷积流(connect the high-to-low resolution convolution streams in parallel)<br>
(2) 重复融合多分辨率流的信息(repreatedly exchange the information across resolutions)</p>
</li>
<li>
<p>overall<br>
如下图所示,第一行一直保持高分辨率信息。四个阶段中,每阶段都在增加稍低分辨率的并行卷积流(一行行增加),同时通过不同分辨率卷积流的信息交换实现多分辨率融合。<br>
<img src="https://FuNian788.github.io/post-images/object_detection/HR-Net_1.png" alt="overall" loading="lazy"><br>
如下图所示,融合不同分辨率特征的方法是有区别的:高分辨率到低分辨率使用n个stride为2的3*3卷积进行下采样;同分辨率直接相加;低分辨率到高分辨率使用n个(双线性差值+1*1卷积层)实现上采样和通道对齐。<br>
<img src="https://FuNian788.github.io/post-images/object_detection/HR-Net_2.png" alt="信息融合" loading="lazy"></p>
</li>
</ul>
<p>HRNetV1,HRNetV2和HRNetV2p的结构图如下所示。HRNetV1只输出高分辨率流,用于人体姿态估计;HRNetV2将低分辨率流上采样后将四个流的特征叠加起来,用于语义分割;HRNetV2p在HRNetV2的基础上多了下采样的过程,用于目标检测。<br>
<img src="https://FuNian788.github.io/post-images/object_detection/HR-Net_3.png" alt="backbone" loading="lazy"></p>
<ul>
<li>改进/Challenge/idea/Que<br>
Related Work中包含了很多文章,eg如何从低分辨率信息中学习,如何重建高分辨率信息,如何维持高分辨率信息,可以好好学习一下。</li>
</ul>
<hr>
<h3 id="6-2018-eccvcornernet-detecting-objects-as-paired-keypoints">(6) <a href="https://arxiv.org/abs/180.01244">(2018 ECCV)CornerNet: Detecting Objects as Paired Keypoints</a></h3>
<p>该论文为anchor-free的目标检测论文。</p>
<ul>
<li>针对痛点<br>
为覆盖真值,需要大量的anchor,这会造成正负样本的不平衡并降低训练速度;同时anchor的设计需要大量人为设计的超参数和结构,与DL的核心思路不符。</li>
<li>主要贡献<br>
CornerNet使用候选框左上角和右下角的点来表示bounding box,在摒弃anchor复杂设计的基础上大幅精简了网络的输出;同时论文提出了corner pooling方法以进行更好的角点定位。</li>
<li>实现流程<br>
如下图所示,卷积层输出一个包含所有左上角点的热图(heatmap),输出一个包含所有右下角点的热图(heatmap),为每个检出角点输出一个嵌入向量(embedding vector)。网络通过训练,为同一目标的角点输出尽可能相似的嵌入向量。<br>
<img src="https://FuNian788.github.io/post-images/TAD/Corner_1.png" alt="流程图" loading="lazy"><br>
更详细的细节如下图,两个预测模块(prediction module)是独立的,每个模块都有独有的corner pooling层,并基于此输出heatmap,embedding和offset。<br>
<img src="https://FuNian788.github.io/post-images/TAD/Corner_2.png" alt="详细流程图" loading="lazy"><br>
这种寻找左上/右下点并将其聚合起来的bottom-up方法是受到skeleton-detection的相关研究启发的。</li>
<li>实现细节</li>
</ul>
<ol>
<li>角点检测<br>
对于输出,以左上角点对应的heatmap为例,heatmap的尺寸为K*H*W,其中K个通道分别代表K个类别,每个通道均为二值mask,表示某一像素点是不是该类别下的角点。<br>
对于每一个角点,都有其对应的唯一真值点,但训练时并不采用简单的0-1损失函数,而是基于2D高斯核,对以真值为圆心,以特定值为半径的的圆内的预测值给予相对较小的惩罚(半径大小与目标尺寸有关,需保证以圆内点作为角点的候选框与GT的IoU大于0.3),具体损失函数采用focal loss的变种。<br>
很多网络采用降采样层来获得全局信息、减少存储空间,此时输出的尺寸常小于输入的尺寸,目标边界的定位准确性不免受像素点对齐的影响。为避免此问题,网络在将heatmap中的点映射回原输入图像前先行预测offset以对角点坐标进行微调,对应的offset为<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>O</mi><mo>=</mo><mo>(</mo><mfrac><mi>x</mi><mi>n</mi></mfrac><mo>−</mo><mo>⌊</mo><mfrac><mi>x</mi><mi>n</mi></mfrac><mo>⌋</mo><mo separator="true">,</mo><mfrac><mi>y</mi><mi>n</mi></mfrac><mo>−</mo><mo>⌊</mo><mfrac><mi>y</mi><mi>n</mi></mfrac><mo>⌋</mo><mo>)</mo></mrow><annotation encoding="application/x-tex">O = (\frac {x}{n} - \lfloor \frac {x}{n} \rfloor, \frac {y}{n} - \lfloor \frac {y}{n} \rfloor)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.02778em;">O</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.095em;vertical-align:-0.345em;"></span><span class="mopen">(</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.695392em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">n</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">x</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.095em;vertical-align:-0.345em;"></span><span class="mopen">⌊</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.695392em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">n</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">x</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose">⌋</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7475em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">n</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.446108em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">y</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.095em;vertical-align:-0.345em;"></span><span class="mopen">⌊</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7475em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">n</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.446108em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">y</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose">⌋</span><span class="mclose">)</span></span></span></span>,具体回归时采用Smooth L1损失函数。</li>
<li>角点合并<br>
模型为所有检测到的角点输出一维embedding,并基于embedding间的距离进行聚类。采用pull-push损失函数。<br>
在对corner heatmap进行max pooling+NMS操作后,得到100个最有可能的左上角点和100个最有可能的右下角点,在用offset进行校正后,比较左上/右下角点embedding间的L1距离,舍弃距离大于阈值和非同一类别的角点对,保留下来的角点对为初步结果,角点对中两角点的平均值作为检测得分。</li>
<li>角点池化(Corner Pooling)<br>
对于目标检测来讲,角点处可能不存在目标信息,且目标信息都处于角点的同一方向。基于此先验信息,将局部max-pooling转变成corner pooling,其核心思想为对于左上角点,目标在其右下方,故只对角点右侧和下侧的特征进行池化(而非右下侧),具体示意如下图所示:<br>
<img src="https://FuNian788.github.io/post-images/TAD/Corner_3.png" alt="corner pooling" loading="lazy"><br>
且实验表明,corner pooling在尺度大小不同的区域上表现近似相同,展现了一定的稳定性。</li>
<li>详细的网络结构如下图所示:<br>
<img src="https://FuNian788.github.io/post-images/TAD/Corner_4.png" alt="网络结构" loading="lazy"><br>
其中backbone采用了在人体骨架检测中广泛应用的沙漏网络(Hourglass network)的变种。</li>
</ol>
<hr>
<!--
## 基础模型
### (1) [(2017 CVPR)ResNeXt: Aggregated Residual Transformations for Deep Neural Networks](https://arxiv.org/abs/1611.05431)
[^_^]: Read in 2021/04/29
* Motivation
VGG & ResNet这类网络通过堆叠相同形状的block来构建深网络,且这种简洁的策略在不同数据集上表现出了优秀的鲁棒性;尽管Inception类网络可以在特定数据上以较低的运算开销展现卓越的性能,但其手工设计痕迹明显,任务迁移时需重新精调网络结构和超参数,成本较高。如何合并这两者?
Inception结构通常遵循split->transform->merge范式,这是否是Inception成功的关键?(split: 使用许多1\*1卷积将输入拆成多个低通道embedding;transform: 使用一些3\*3和5\*5的卷积来转换信息;merge: 使用通过concate将上述输出综合)
* 主要贡献
提出ResNeXt,既使用了repeat layer策略(from VGG & ResNet),又以一种简单、可扩展的方式利用split-transform-merge策略(from Inception)。
* overall

* 实现细节
* 改进/Challenge/idea/Que
---
### (n) [(2021 CVPR)PAPER NAME](https://arxiv.org/abs/2103.09460)
[^_^]: Read in 2021/04/26
* Motivation
* 主要贡献
* overall
* 实现细节
* 改进/Challenge/idea/Que
-->
<h2 id="基本常识">基本常识</h2>
<ol>
<li>论文中的<code>1x</code>代表以batch size为16,在COCO数据集上训练90k个iter,约为118287张图片上的12.17个epoch。2x等以此类推。</li>
<li>anchor:所有的anchor都参与classification分支的反向传播,此时的损失函数是在K+1类上的交叉熵损失函数,但只有positive anchor才参与regression分支的反向传播。positive的常用定义是IoU阈值,当然也存在一些根据近邻程度的匹配算法。</li>
<li>Anchor的设计存在很多定义方式,但都是在初始anchor(eg 16*16的正方形)上进行变换。<br>
在单feature map上(eg Faster RCNN),可设定areas和aspect ratio;在多feature map上(eg FPN),可在aspect ratio和areas之外设定scale。<br>
areas指面积,对应的是边长扩大比例(eg2的3、4、5次幂),这样可得到原图像上对应的anchor大小eg 128*128,256*256,512*512。aspect ratio是在面积不变的情况下改变长宽比(eg 1:2,1:1,2:1),以128*128为例可得到eg 184*96,128*128,96*184。这样就有三种面积,每种面积下三种比例,故RPN在每个点处生成9个候选框。<br>
scale指anchor的缩放比例,eg<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msup><mn>2</mn><mn>0</mn></msup><mi mathvariant="normal">,</mi><msup><mn>2</mn><mrow><mn>1</mn><mi mathvariant="normal">/</mi><mn>3</mn></mrow></msup><mo>=</mo><mn>1.26</mn><mi mathvariant="normal">,</mi><msup><mn>2</mn><mrow><mn>2</mn><mi mathvariant="normal">/</mi><mn>3</mn></mrow></msup><mo>=</mo><mn>1.59</mn></mrow><annotation encoding="application/x-tex">2^{0},2^{1/3}=1.26,2^{2/3}=1.59</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8879999999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span></span></span></span></span></span></span></span></span><span class="mord cjk_fallback">,</span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8879999999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span><span class="mord mtight">/</span><span class="mord mtight">3</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8879999999999999em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord">.</span><span class="mord">2</span><span class="mord">6</span><span class="mord cjk_fallback">,</span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8879999999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span><span class="mord mtight">/</span><span class="mord mtight">3</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord">.</span><span class="mord">5</span><span class="mord">9</span></span></span></span>。当然这也和FPN中有多种尺度的特征图输出有关。</li>
</ol>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[脚本切换conda环境踩坑记录]]></title>
<id>https://FuNian788.github.io/post/anaconda-sh/</id>
<link href="https://FuNian788.github.io/post/anaconda-sh/">
</link>
<updated>2021-05-29T02:50:23.000Z</updated>
<content type="html"><![CDATA[<p><ul class="markdownIt-TOC">
<li>
<ul>
<li>
<ul>
<li><a href="#1-%E4%BF%AE%E6%94%B9%E5%90%AF%E5%8A%A8%E9%A1%B9%E4%BB%A5%E5%AE%9E%E7%8E%B0docker%E5%90%AF%E5%8A%A8%E5%90%8E%E8%87%AA%E5%8A%A8%E5%88%87%E6%8D%A2conda%E7%8E%AF%E5%A2%83">1. 修改启动项以实现Docker启动后自动切换conda环境</a></li>
<li><a href="#2-%E5%9C%A8cron%E5%AE%9A%E6%97%B6%E6%89%A7%E8%A1%8C%E7%9A%84shell%E8%84%9A%E6%9C%AC%E5%86%85%E5%AE%9E%E7%8E%B0conda%E7%9A%84%E7%8E%AF%E5%A2%83%E5%88%87%E6%8D%A2">2. 在cron定时执行的Shell脚本内实现conda的环境切换</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</p>
<h3 id="1-修改启动项以实现docker启动后自动切换conda环境">1. 修改启动项以实现Docker启动后自动切换conda环境</h3>
<p>第一次踩坑是在项目中,甲方要求以封装启动脚本的形式实现Docker启动便运行程序的功能,而我的生产环境是在Docker内Anaconda下进行配置的。尽管Docker启动后conda会直接接管,但如何利用脚本切换到自己配置的环境,是亟待解决的问题。<br>
最核心的问题是:与终端不同,Shell脚本中无法使用conda关键字。<br>
最后的解决方法十分简单粗暴,通过<code>conda init</code>找到conda对应的<code>.bashrc</code>路径,修改其内容,加入如下指令:</p>
<pre><code class="language-shell">source activate
conda deactivate
conda activate lzx
</code></pre>
<p>其原理是conda在启动时会执行conda对应的<code>./bashrc</code>的内容以进行初始化(我们平时打开终端其实也进行了执行<code>.bashrc</code>的过程,之所以conda会自动替代原生Python也是因为安装conda时其在<code>.bashrc</code>中注入了<code>conda activate base</code>命令)。<br>
这种方法的确能实现项目需求,但明显不够优雅,迁移性也不高,如本文第二部分记录所示,有更好的方法。<br>
吸取的教训主要有二,一是都用Docker了还加什么Anaconda,直接pip不香么;二是直接在conda主环境配置不好么,自己单开环境哪里香了?</p>
<h3 id="2-在cron定时执行的shell脚本内实现conda的环境切换">2. 在cron定时执行的Shell脚本内实现conda的环境切换</h3>
<p>第二次踩坑是在ubuntu下设置cron定时执行脚本但未执行,使用<code>tail -f /var/log/cron.log</code>实时查看日志缺发现对应文件不存在,通过<a href="https://blog.csdn.net/ningningjj/article/details/104532157">blog</a>解决问题。<br>
后续遇到如下错误日志:</p>
<pre><code>(CRON) info (No MTA installed, discarding output)
</code></pre>
<p>参照<a href="https://blog.csdn.net/win_turn/article/details/53000899?fps=1&locationNum=2">win_turn的博客</a>,通过注释输出语句和安装邮件服务器解决了该问题。<br>
此时我的脚本是这个样子的:</p>
<pre><code class="language-Shell">#!/usr/bin/env bash
source activate
conda deactivate
conda activate lzx
python /home1/lizexian/clock_in/clock_in.py
</code></pre>
<p>通过不断查看<code>/var/spool/mail</code>文件夹下cron报错的邮件,最终的问题来到了老生常谈的shell不认conda关键字以及无法切换conda环境上。<br>
绝境中发现<a href="https://www.zhihu.com/question/322406344/answer/742158645">以默的知乎解答</a>,亲测使用此可以利用shell脚本激活及切换conda虚拟环境,原博实现如下:</p>
<pre><code class="language-shell">#!/bin/bash
source /YOUR_CONDA_PATH/bin/activate your_env
python --version
</code></pre>
<p>对应到我个人的实现如下:</p>
<pre><code class="language-shell">#!/bin/bash
source /home/user/anaconda3/bin/activate lzx
python /home1/lizexian/clock_in/clock_in.py
</code></pre>
<p>当然,在调试过程中还遇到了一些小麻烦,例如用<code>chmod u+x a.sh</code>赋予执行权限、将所有路径更改为绝对路径等(事实证明并非定要输入Python的绝对路径),此处不再赘述。</p>
<p>至此,妈妈再也不用担心我的conda环境了🎢</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[MEGVII常用命令]]></title>
<id>https://FuNian788.github.io/post/megvii-chang-yong-ming-ling/</id>
<link href="https://FuNian788.github.io/post/megvii-chang-yong-ming-ling/">
</link>
<updated>2021-05-15T12:46:35.000Z</updated>
<content type="html"><![CDATA[<p><ul class="markdownIt-TOC">
<li>
<ul>
<li><a href="#%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B%E6%B5%81%E7%A8%8Bpipeline">目标检测流程pipeline</a>
<ul>
<li><a href="#%E5%88%9B%E5%BB%BAworkspace2">创建workspace2</a></li>
<li><a href="#%E8%84%9A%E6%9C%AC%E4%B8%80%E9%94%AE%E9%85%8D%E7%BD%AE%E5%9F%BA%E7%A1%80%E7%8E%AF%E5%A2%83">脚本一键配置基础环境</a></li>
<li><a href="#%E5%AE%89%E8%A3%85anaconda">安装Anaconda</a></li>
<li><a href="#%E5%88%9B%E5%BB%BA%E5%B9%B6%E6%BF%80%E6%B4%BB%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83">创建并激活虚拟环境</a></li>
<li><a href="#%E5%AE%89%E8%A3%85rluanch%E5%92%8Crrun">安装rluanch和rrun</a></li>
<li><a href="#%E4%B8%8B%E8%BD%BDcvpack2">下载cvpack2</a>
<ul>
<li><a href="#%E5%BF%AB%E6%8D%B7%E6%96%B9%E6%B3%95">快捷方法</a></li>
<li><a href="#%E9%80%9A%E7%94%A8%E6%96%B9%E6%B3%95">通用方法</a></li>
</ul>
</li>
<li><a href="#%E9%85%8D%E7%BD%AEcvpack2">配置cvpack2</a></li>
<li><a href="#%E5%9C%A8cvpack2_playground%E4%B8%8B%E8%AE%AD%E7%BB%83">在cvpack2_playground下训练</a></li>
<li><a href="#inference">inference</a></li>
<li><a href="#vscode%E6%96%87%E4%BB%B6%E6%A0%8F%E8%B0%83%E6%95%B4">VScode文件栏调整</a></li>
<li><a href="#coco%E6%95%B0%E6%8D%AE%E9%9B%86%E4%B8%8B%E8%BD%BD">coco数据集下载</a></li>
</ul>
</li>
<li><a href="#oss%E5%91%BD%E4%BB%A4">oss命令</a>
<ul>
<li><a href="#rlaunch%E5%91%BD%E4%BB%A4">rlaunch命令</a></li>
<li><a href="#ssh-permission-denied">SSH permission denied</a></li>
<li><a href="#gitlab%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4">gitlab常用命令</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</p>
<h2 id="目标检测流程pipeline">目标检测流程pipeline</h2>
<h3 id="创建workspace2">创建workspace2</h3>
<ul>
<li>在<a href="https://www.brainpp.cn/hh-b/console/job?type=ws2">计算平台</a>创建一个workspace2。</li>
<li>创建好后复制内网ssh,eg<code>ssh -CAXY [email protected]</code>,使用VScode的remote-SSH插件打开。如有问题可直接配置<code>/Users/lizexian/.ssh/config</code>如下:</li>
</ul>
<pre><code class="language-Shell">Host hh-b-internal.brainpp.cn
HostName hh-b-internal.brainpp.cn
Compression yes
ForwardAgent yes
ForwardX11 yes
ForwardX11Trusted yes
User minguk.lizexian.ws2
</code></pre>
<h3 id="脚本一键配置基础环境">脚本一键配置基础环境</h3>
<ul>
<li>下载ntools</li>
</ul>
<pre><code class="language-Shell">git clone [email protected]:research_model/ntools2.git
</code></pre>
<ul>
<li>一键配置</li>
</ul>
<pre><code class="language-Shell">cd ntools2/setup
sudo chown -R $USER ~/.local/
./setup_ws2.sh && source ~/.bashrc
cd ..
./configure
./install.sh
</code></pre>
<ul>
<li>配置并测试oss</li>
</ul>
<pre><code class="language-Shell">aws configure
# Get below from 'https://www.brainpp.cn/account/security'
# input E7dv5T2Qm9V1ljMemHY9
# input L4p-snrN5uGMKa86z0QAV4grERktTeef
# input NONE
# input NONE
oss ls
</code></pre>
<h3 id="安装anaconda">安装Anaconda</h3>
<ul>
<li>下载anaconda包</li>
</ul>
<pre><code class="language-shell">cd /home/lizexian
oss cp s3://lizexian/Anaconda3-5.3.1-Linux-x86_64.sh .
</code></pre>
<ul>
<li>安装anaconda</li>
</ul>
<pre><code class="language-Shell">bash Anaconda3-5.3.1-Linux-x86_64.sh
</code></pre>
<p>安装过程一路回车即可,默认刷新bash,不安装vscode</p>
<ul>
<li>刷新bashrc</li>
</ul>
<pre><code class="language-Shell">source ~/.bashrc
</code></pre>
<p>如果没有修改默认bash,可通过如下方法激活conda</p>
<blockquote>
<p><code>vim ~/.bashrc</code><br>
<code>shift + g</code> jump to the last line<br>
<code>export PATH="/home/lizexian/anaconda3/bin:$PATH"</code><br>
<code>source ~/.bashrc</code></p>
</blockquote>
<p>如果无法使用conda activate激活,可使用如下</p>
<blockquote>
<p><code>source activate cvpack</code></p>
</blockquote>
<h3 id="创建并激活虚拟环境">创建并激活虚拟环境</h3>
<pre><code class="language-shell">conda create -n cvpack python=3.7
conda activate cvpack
</code></pre>
<blockquote>
<p>如在wuhu-a集群遇到HTTPERROR时,可修改conda源:修改~/.condarc如下</p>
</blockquote>
<pre><code class="language-Shell">channels:
- https://mirrors.ustc.edu.cn/anaconda/pkgs/main/
- https://mirrors.ustc.edu.cn/anaconda/cloud/conda-forge/
- https://mirrors.ustc.edu.cn/anaconda/pkgs/free/
show_channel_urls: true
</code></pre>
<h3 id="安装rluanch和rrun">安装rluanch和rrun</h3>
<pre><code class="language-Shell">sudo apt update && sudo apt install -y brainpp
pip3 install --user rrun
</code></pre>
<h3 id="下载cvpack2">下载cvpack2</h3>
<h4 id="快捷方法">快捷方法</h4>
<ul>
<li>下载预打包的YOLOF_cvpack2</li>
</ul>
<pre><code class="language-Shell">oss cp s3://lizexian/yolof0511.zip .
unzip -qq yolof.zip
# zip -q -r yolof.zip cvpack2/
# oss cp yolof0511.zip s3://lizexian
</code></pre>
<h4 id="通用方法">通用方法</h4>
<ul>
<li>下载cvpack2</li>
</ul>
<pre><code class="language-Shell"># 1. Download without cvpack2_playground
# git clone [email protected]:base-detection/cvpack2.git
# 2. Download with cvpack2_playground
git clone --recursive [email protected]:zhubenjin/cvpack2.git
</code></pre>
<ul>
<li>修改requirement.txt</li>
</ul>
<pre><code class="language-Shell">torch==1.6.0 # torch==1.7.1
torchvision==0.7.0 # torchvision==0.8.2
</code></pre>
<ul>
<li>根据YOLOF修改cvpack2<br>
详见YOLOF的README.txt文档</li>
</ul>
<h3 id="配置cvpack2">配置cvpack2</h3>
<ul>
<li>安装依赖项并下载COCO数据集</li>
</ul>
<pre><code class="language-Shell">pip install 'git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI'
cd cvpack2
bash tools/setup/install.sh all hhb
# 'all' option will download COCO dataset to '/data/Datasets/COCO' while 'lib' will not.
# datasets/cvpack2_prepare coco
</code></pre>
<p>如果占卡的时候遇到问题,可直接使用如下语句进行手动编译:</p>
<blockquote>
<p><code>rlaunch --cpu=8 --gpu=2 --memory=10240 -- bash</code><br>
<code>python setup.py build develop --user</code></p>
</blockquote>
<p>再手动测试是否安装成功</p>
<blockquote>
<p><code>conda activate cvpack</code><br>
<code>python</code><br>
<code>import cvpack2</code></p>
</blockquote>
<p>单独下载COCO数据集的方法</p>
<blockquote>
<p><code>oss sync --no-progress s3://generalDetection/mscoco_raw_data/coco2017 /data/Datasets/COCO</code><br>
<code># val2017.zip 815585330</code><br>
<code># train2017.zip 19336861798</code><br>
<code>unzip -qq annotations_trainval2017.zip</code><br>
<code>unzip -qq val2017.zip # val2017: 163840</code><br>
<code>unzip -qq train2017.zip # train2017: 3846144</code></p>
</blockquote>
<h3 id="在cvpack2_playground下训练">在cvpack2_playground下训练</h3>
<ul>
<li>建立数据集的软连接</li>
</ul>
<pre><code class="language-Shell"># build. `ln -s source_address target_address`
ln -s /data/Datasets/COCO /home/lizexian/cvpack2/datasets/coco
# delete. `rm -rf address`
# NOTE not `rm -rf ./test_cjk_in/` which will delete files instead of link.
rm -rf ./test_chk_ln
</code></pre>
<ul>
<li>占卡及训练</li>
</ul>
<pre><code class="language-Shell">tmux
rlaunch --cpu=8 --gpu=8 --memory=200000 -- bash
cd /home/lizexian/cvpack2/cvpack2_playground/examples/detection/coco/yolof/yolofv1.res50.1x
conda activate cvpack
cvpack2_train --num-gpus 8
</code></pre>
<blockquote>
<p>YOLOF至少需要4张卡</p>
</blockquote>
<h3 id="inference">inference</h3>
<p>模型会自动进行inference,结果保存在<code>/data/Outputs/model_logs/cvpack2_playground/examples/detection/coco/yolof/yolofv1.res50.1x/inference/coco_instances_results.json</code>路径下。对应地,该路径下的log、pth等文件会自动上传到<code>s3://cvpack2dumps/lizexian/playground/examples/detection/coco/yolof/yolofv1.res50.1x/</code>路径下。</p>
<h3 id="vscode文件栏调整">VScode文件栏调整</h3>
<ul>
<li>Command + , 呼叫设置栏</li>
<li>在Files: exclude中添加忽略模式</li>
</ul>
<pre><code class="language-json">"files.exclude": {
"**/.aws": true,
"**/.bash_history": true,
"**/.bash_logout": true,
"**/.bashrc": true,
"**/.bashrc-anaconda3.bak": true,
"**/.cache": true,
"**/.conda": true,
"**/.config": true,
"**/.gnupg": true,
"**/.local": true,
"**/.nv": true,
"**/.profile": true,
"**/.python_history": true,
"**/.rlaunch": true,
"**/.ssh": true,
"**/.sudo_as_admin_successful": true,
"**/.tmux.conf": true,
"**/.vim": true,
"**/.vimrc": true,
"**/.wgetrc": true,
"**/.Xauthority": true
}
</code></pre>
<h3 id="coco数据集下载">coco数据集下载</h3>
<p>optionB+d退出<br>
tmux attach<br>
optionB+N切换</p>
<p>s3://cvpack2dump/root/<br>
/data/outputs/、</p>
<p>base config line 46</p>
<p>cvpack2_test --num-gpus 8 <br>
MODEL.WEIGHTS /path/to/your/checkpoint.pth \ # if necessary<br>
OUTPUT_DIR /path/to/save_dir # don't need to specify this in defalut</p>
<h2 id="oss命令">oss命令</h2>
<p>自有路径:<code>lizexian</code> or <code>s3://lizexian</code><br>
oss的常用指令包括:ls、cp、mv、rm、sync。可使用 --exclude 和 --include 选项指定规则来筛选要操作的文件或者目录。</p>
<pre><code class="language-Shell">oss ls lizexian/file
oss cp 1.py s3://lizexian
oss cp yolof s3://lizexian --recursive
oss cp s3://lizexian/1.py ./
oss mv 1.py s3://lizexian
oss rm s3://lizexian/*.py
</code></pre>
<h3 id="rlaunch命令">rlaunch命令</h3>
<p>使用rluanch命令动态申请资源并运行程序</p>
<pre><code class="language-Shell">rlaunch --cpu=4 --gpu=4 --memory=30000 -- python3 train.py
rlaunch --cpu=4 --gpu=4 --memory=30000 --max-wait-time=24h -- bash
rlaunch -P1 --cpu=8 --gpu=8 --memory=200000 -- cvpack2_train --num-gpus 8 # can be killed
rlaunch --predict-only
</code></pre>
<h3 id="ssh-permission-denied">SSH permission denied</h3>
<pre><code class="language-Shell">ssh-add ~/.ssh/id_rsa_megvii
</code></pre>
<h3 id="gitlab常用命令">gitlab常用命令</h3>
<pre><code class="language-Shell">git init
git remote add origin gitLINK
git add .
git checkout -b branchNAME
git commit -m 'INFO'
git push origin branchNAME:branchNAME2
# delete online branch
git push origin --delete NAME
# delete local branch
git branch -d NAME
</code></pre>
<pre><code class="language-Shell">git pull origin master
git push -u origin master
git push -u origin master -f
</code></pre>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[一文看懂Python装饰器(Decorators)]]></title>
<id>https://FuNian788.github.io/post/python-decorators/</id>
<link href="https://FuNian788.github.io/post/python-decorators/">
</link>
<updated>2021-04-12T11:05:23.000Z</updated>
<content type="html"><![CDATA[<p>在代码中接触了许多有关Python装饰器的内容,简单写一篇博客来记录一下,以作归纳总结。<br>
“装饰器的强大在于它能够在不修改原有业务逻辑的情况下对代码进行扩展,权限校验、用户认证、日志记录、性能测试、事务处理、缓存等都是装饰器的绝佳应用场景,它能够最大程度地对代码进行复用。”<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup><br>
装饰器最简单的功能就是做日志记录和时间统计。下面以日志记录的代码为例引入装饰器的概念,其中在函数定义上一行中的@便是Python对应装饰器的语法糖。</p>
<pre><code class="language-Python">def my_logging(func):
def wrapper():
print("{} begins.".format(func.__name__))
return func()
return wrapper
@my_logging
def my_func():
print("Welcome to my blog.")
if __name__ == "__main__":
# The decaorator replace 'my_func = my_logging(my_func)'
my_func()
# --------Result---------
# my_func begins.
# Welcome to my blog.
</code></pre>
<p>只要能正确理解Python中函数名的实际内涵、函数名作为参数传递的过程,便能很清晰看懂上述示例。请务必理解清楚再继续阅读,下面深入探讨较复杂情况下装饰器使用的示例都是对上例的扩展:</p>
<h3 id="1被装饰函数涉及多个参数">(1)被装饰函数涉及多个参数</h3>
<p>如果上例中的my_func函数带有参数,我们只需要在wrapper函数中加上对应参数即可正常调用;如果my_func函数涉及若干个参数,我们可以使用*args和**kargs传递参数(可以这样理解,在函数传递参数时使用*args作为形参,在使用参数时直接用args作为实参)。后一种情况的示例代码如下:</p>
<pre><code class="language-Python">def my_logging(func):
def wrapper(a, *args, **kargs):
print("{} begins.".format(func.__name__))
return func(a, *args, **kargs)
return wrapper
@my_logging
def my_func(a, *args, **kargs):
print("Welcome to my blog.")
print("a = {}".format(a))
print("I can get 'args': {}.".format(args))
print("I can get 'kargs': {}.".format(kargs))
if __name__ == "__main__":
my_func(1, 2, 3, 4, b=5, c=6, d=7)
# --------Result---------
# my_func begins.
# Welcome to my blog.
# a = 1
# I can get 'args': (2, 3, 4). type: tuple
# ps: *args: 2,3,4
# I can get 'kargs': {'b': 5, 'c': 6, 'd': 7}. type: dict
# ps: *kargs: b c d
</code></pre>
<p>可以这样近似地理解,我们在主函数处执行</p>
<pre><code class="language-Python">my_func = my_logging(my_func)
my_func(1, 2, 3, 4, b=5, c=6, d=7)
</code></pre>
<p>而这些最后在my_logging中变成了执行<code>wrapper((a, *args, **kargs))</code>。<br>
上述代码中涉及到了**闭包(Closure)**的概念<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>。 在函数内部创建一个内嵌函数是合法的,且内嵌函数只有在外部函数的作用域内方可正常调用。如果一个外函数中定义了一个内函数,且内函数体内引用到了内函数体外、外函数内的变量,这时外函数通过return返回内函数的引用时,会把涉及到的内函数体外的变量和内函数打包成一个整体(闭包)返回,内部函数即为闭包函数,闭包函数所引用的外部定义的变量叫做自由变量。可以参照下例了解闭包的概念:</p>
<pre><code class="language-Python">def outer(x):
a = x
def inner(y):
b = y
print(a+b)
return inner
f1 = outer(1) # 返回inner函数对象和外部引用变量a的闭包
f1(10) # 相当于inner(10),输出11
</code></pre>
<p>通常一个函数运行结束的时候,临时变量会被销毁,但闭包是一个特殊情况。当外函数发现自己的临时变量将来会在内函数中用到,则外函数在结束并返回内函数的同时会把外函数的临时变量同内函数绑定在一起,这保证了外函数结束后内函数的正常使用。<br>
示例中的my_logging函数和wrapper函数正是同样的闭包形式。</p>
<h3 id="2装饰器带参数">(2)装饰器带参数</h3>
<p>此处的high_level_logging函数便是带参数的装饰器,该装饰器的返回值是最初示例中那个基本的装饰器。high_level_logging可以被理解为对最基本装饰器的函数封装,或一个含有参数的闭包,其内部执行过程就像套娃一样<s>禁止套娃🤐</s>。</p>
<pre><code class="language-Python">import logging
def high_level_logging(level='info'):
def my_logging(func):
def wrapper():
print("{} begins.".format(func.__name__))
if level == 'warn':
logging.warning("Attention!")
return func()
return wrapper
return my_logging
@high_level_logging(level='warn')
def my_func():
print("Welcome to my blog.")
if __name__ == "__main__":
my_func()
# --------Result---------
# my_func begins.
# WARNING:root:Attention!
# Welcome to my blog.
</code></pre>
<p>当执行<code>@high_level_logging(level='warn')</code>时,Python发现该封装并将参数传递到装饰器的环境中。</p>
<h3 id="3类装饰器">(3)类装饰器</h3>
<p>装饰器可以是类,使用类装饰器主要依靠类的__call__方法。简要示例如下:</p>
<pre><code class="language-Python">class my_logging():
def __init__(self, func):
self._func = func
def __call__(self):
print("{} begins.".format(self._func.__name__))
self._func()
@my_logging
def my_func():
print("Welcome to my blog.")
if __name__ == "__main__":
my_func()
# --------Result---------
# my_func begins.
# Welcome to my blog.
</code></pre>
<p>当然,类装饰器也可以带参数。<br>
为了更直观显示属性,有时需要调用functools.wraps模块以完成原函数(eg: my_func)的元信息(eg: __name__)到装饰器内函数的拷贝。使用方法即在内函数前加上新的装饰器<code>@wraps(inner)</code>。可参考如下示例:</p>
<pre><code class="language-Python">from functools import wraps
def my_logging(func):
@wraps(func)
def wrapper():
print("{} begins.".format(func.__name__))
return func()
return wrapper
@my_logging
def my_func():
print("Welcome to my blog.")
if __name__ == "__main__":
my_func()
print(my_func.__name__) # my_func
</code></pre>
<p>同样地,存储状态的装饰器可以大幅缩减程序的运行时间:</p>
<pre><code class="language-Python">class MyCahe(object):
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
if not args in self.cache:
self.cache[args] = self.func(*args)
return self.cache[args]
@MyCahe
def fib(n):
if n <= 1:
return 1
return fib(n - 1) + fib(n - 2)
print(fib(3))
</code></pre>
<p>需要注意的是,一个函数可以同时定义多个装饰器,执行顺序是由近到远:</p>
<pre><code class="language-Python">@a
@b
@c
def f ():
pass
</code></pre>
<p>等同于<code>f=a(b(c(f)))</code>。</p>
<!--
今后可能再研究研究再补充博客
https://zhuanlan.zhihu.com/p/53837833
https://zhuanlan.zhihu.com/p/88529507
https://zhuanlan.zhihu.com/p/51554168
-->
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>援引自刘志军的博客https://zhuanlan.zhihu.com/p/27449649。 <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>关于闭包的解释援引自大江狗的博客 https://zhuanlan.zhihu.com/p/51158386,稍作修改。 <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Python实现微信小程序自动打卡]]></title>
<id>https://FuNian788.github.io/post/python-wechat-clock-in/</id>
<link href="https://FuNian788.github.io/post/python-wechat-clock-in/">
</link>
<updated>2021-03-16T01:12:42.000Z</updated>
<content type="html"><![CDATA[<p>每天手动打卡实在太繁琐了,作为coder,有没有捷径可走?理论上可以有!<br>
<strong>前边的话:本博客仅讨论技术实现,疫情防控需谨慎,如有异常请及时上报。</strong><br>
<ul class="markdownIt-TOC">
<li>
<ul>
<li>
<ul>
<li><a href="#charles-iphone%E6%8A%93%E5%8C%85">Charles + iPhone抓包</a></li>
<li><a href="#%E6%89%93%E5%8D%A1%E4%BB%A3%E7%A0%81">打卡代码</a></li>
<li><a href="#%E5%AE%9A%E6%97%B6%E5%90%AF%E5%8A%A8">定时启动</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</p>
<h3 id="charles-iphone抓包">Charles + iPhone抓包</h3>
<p>将iPhone和电脑连在同一wifi下,设置手机http代理,安装SSL证书,安装并信任描述文件。<br>
点击手机端打卡界面,在Charles上得到手机端的HTTP请求列表;在手机端填写打卡页面并提交,在对应HTTP使用Charles的compose功能获取手机发送的json文件。<br>
(具体细节可参考<a href="https://blog.csdn.net/y277an/article/details/103573163">y2777an的博客</a>)</p>
<h3 id="打卡代码">打卡代码</h3>
<p>代码思路为,先登录北航sso并验证(<code>login()函数</code>),获取上次提交的信息并进行修改(<code>get_info()函数</code>),随后向服务器提交json文件并验证(post()函数)。<code>bark()函数</code>基于ios APP bark,实现了打卡失败时向iPhone自动发送提醒的功能。代码添加了日志功能。<br>
具体代码如下所示:</p>
<pre><code class="language-Python"># -*- coding: utf-8 -*-
# /usr/bin/python
import requests
import json
import time
import sys
import urllib.request