-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.xml
1190 lines (1149 loc) · 133 KB
/
index.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" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>想起床的方差</title>
<link>https://wakingupdelta.github.io/</link>
<description>Recent content on 想起床的方差</description>
<generator>Hugo -- gohugo.io</generator>
<language>zh-cn</language>
<copyright>想起床的方差</copyright>
<lastBuildDate>Wed, 26 Jun 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://wakingupdelta.github.io/index.xml" rel="self" type="application/rss+xml" /><item>
<title>completablefuture概览</title>
<link>https://wakingupdelta.github.io/p/completablefuture%E6%A6%82%E8%A7%88/</link>
<pubDate>Wed, 26 Jun 2024 00:00:00 +0000</pubDate>
<guid>https://wakingupdelta.github.io/p/completablefuture%E6%A6%82%E8%A7%88/</guid>
<description><h3 id="一线程池">一、线程池
</h3><p>核心参数</p>
<ul>
<li>corePoolSize 核心线程池大小</li>
<li>maximumPoolSize 线程池能创建线程的最大数量</li>
<li>keepAliveTime 空闲线程存活时间</li>
<li>workQueue 阻塞队列</li>
<li>handler 饱和策略</li>
</ul>
<p>execute方法提交任务后,执行逻辑</p>
<ul>
<li>小于核心线程数,创建新线程</li>
<li>阻塞队列未满,入队</li>
<li>线程池未满,创建</li>
<li>按饱和策略处理</li>
</ul>
<h3 id="二对比future">二、对比Future
</h3><p>特点</p>
<ul>
<li>支持回调通知
<ul>
<li>Future需不断轮询判断任务是否结束</li>
</ul>
</li>
<li>便于将不同异步操作组合
<ul>
<li>Future编排回调存在回调地狱问题</li>
</ul>
</li>
</ul>
<h3 id="三简单使用">三、简单使用
</h3><h4 id="31-创建">3.1 创建
</h4><p>通过静态方法创建实例</p>
<ul>
<li>runAsync 无返回值</li>
<li>supplyAsync 有返回值</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="n">CompletableFuture</span><span class="p">.</span><span class="na">runAsync</span><span class="p">(</span><span class="n">Runnable</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">CompletableFuture</span><span class="p">.</span><span class="na">runAsync</span><span class="p">(</span><span class="n">Runnable</span><span class="p">,</span><span class="w"> </span><span class="n">Executor</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">CompletableFuture</span><span class="p">.</span><span class="na">supplyAsync</span><span class="p">(</span><span class="n">Supplier</span><span class="o">&lt;</span><span class="n">U</span><span class="o">&gt;</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">CompletableFuture</span><span class="p">.</span><span class="na">supplyAsync</span><span class="p">(</span><span class="n">Supplier</span><span class="o">&lt;</span><span class="n">U</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">Executor</span><span class="p">);</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h4 id="32-依赖单个任务">3.2 依赖单个任务
</h4><h5 id="321-顺序执行">3.2.1 顺序执行
</h5><ul>
<li>thenRun 无入参,无返回值</li>
<li>thenAccept 有入参,无返回值</li>
<li>thenApply 有入参,有返回值</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="n">CompletableFuture</span><span class="p">.</span><span class="na">supplyAsync</span><span class="p">(()</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="s">&#34;request&#34;</span><span class="p">).</span><span class="na">thenRun</span><span class="p">(()</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="p">{});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">CompletableFuture</span><span class="p">.</span><span class="na">supplyAsync</span><span class="p">(()</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="s">&#34;request&#34;</span><span class="p">).</span><span class="na">thenAccept</span><span class="p">(</span><span class="n">request</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="p">{});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">CompletableFuture</span><span class="p">.</span><span class="na">supplyAsync</span><span class="p">(()</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="s">&#34;request&#34;</span><span class="p">).</span><span class="na">thenRun</span><span class="p">(</span><span class="n">request</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="s">&#34;print --&gt; &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">request</span><span class="p">);</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h5 id="322-异常处理">3.2.2 异常处理
</h5><p>两种方式 exceptionally 和 handle</p>
<h4 id="33-依赖多个任务">3.3 依赖多个任务
</h4><h5 id="331-and">3.3.1 and
</h5><ul>
<li>thenAfterBoth 无入参,无返回</li>
<li>thenAcceptBoth 有入参,无返回</li>
<li>thenCombine 有入参,有返回</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="n">cfA</span><span class="p">.</span><span class="na">runAfterBoth</span><span class="p">(</span><span class="n">cfB</span><span class="p">,</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="p">{});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">cfA</span><span class="p">.</span><span class="na">tehnAcceptBoth</span><span class="p">(</span><span class="n">cfB</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">A</span><span class="p">,</span><span class="w"> </span><span class="n">B</span><span class="p">)</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="p">{});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">cfA</span><span class="p">.</span><span class="na">tehnAcceptBoth</span><span class="p">(</span><span class="n">cfB</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">A</span><span class="p">,</span><span class="w"> </span><span class="n">B</span><span class="p">)</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="n">A</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">B</span><span class="p">);</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>静态方法 allOf 等待多个任务都完成,无返回值</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="n">CompletableFuture</span><span class="p">.</span><span class="na">allOf</span><span class="p">(</span><span class="n">cfA</span><span class="p">,</span><span class="w"> </span><span class="n">cfB</span><span class="p">,</span><span class="w"> </span><span class="n">cfC</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h5 id="332-or">3.3.2 or
</h5><ul>
<li>runAfterEither 无入参,无返回</li>
<li>acceptEither 有入参,无返回</li>
<li>applyToEither 有入参,有返回</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="n">cfA</span><span class="p">.</span><span class="na">runAfterEither</span><span class="p">(</span><span class="n">cfB</span><span class="p">,</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="p">{});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">cfA</span><span class="p">.</span><span class="na">tehnAcceptEither</span><span class="p">(</span><span class="n">cfB</span><span class="p">,</span><span class="w"> </span><span class="n">req</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="p">{});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">cfA</span><span class="p">.</span><span class="na">tehnAcceptEither</span><span class="p">(</span><span class="n">cfB</span><span class="p">,</span><span class="w"> </span><span class="n">req</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="s">&#34;req: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">req</span><span class="p">);</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>静态方法 anyOf 等待任一任务完成,返回类型为Object</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="n">CompletableFuture</span><span class="p">.</span><span class="na">anyOf</span><span class="p">(</span><span class="n">cfA</span><span class="p">,</span><span class="w"> </span><span class="n">cfB</span><span class="p">,</span><span class="w"> </span><span class="n">cfC</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h3 id="四基本原理">四、基本原理
</h3><p>CompletableFuture 有两个核心字段</p>
<ul>
<li>result 存当前CompletableFuture的结果</li>
<li>Completion 存依赖动作</li>
</ul>
<p>不同CompletableFuture 如何编排起来?</p>
<ul>
<li>CompletableFuture 为 被观察者,Completion为 观察者</li>
<li>当CompletableFuture完成后,通过postComplete方法通知Completion</li>
<li>形象上讲,这种机制 在 不同CompletableFuture节点 间 添加了 边</li>
</ul>
<h3 id="五注意事项">五、注意事项
</h3><h4 id="51-有无async后缀">5.1 有无Async后缀
</h4><p>不带Async后缀的方法</p>
<ul>
<li>如果注册时被依赖的操作已经执行完成,则由当前线程执行</li>
<li>如果注册时被依赖的操作还未执行完,则由回调线程执行</li>
</ul>
<p>带Async后缀的方法</p>
<ul>
<li>运行在指定线程池Executor</li>
<li>当不传递Executor时,会使用ForkJoinPool中的共用线程池CommonPool</li>
</ul>
<h4 id="52-thencompose">5.2 thenCompose
</h4><p>和thenCombine对比</p>
<ul>
<li>都是聚合任务</li>
<li>combine聚合结果,compose把多个cf实例组合成一个整体</li>
</ul>
<p>和thenApply对比</p>
<ul>
<li>thenApply接收的函数返回一个具体的值,thenCompose接收的函数返回一个新的cf实例</li>
<li>thenApply是同步,thenCompose是异步</li>
</ul>
<h3 id="参考资料">参考资料
</h3><p><a class="link" href="https://javadoop.com/post/completable-future" target="_blank" rel="noopener"
>[1] CompletableFuture使用介绍</a></p>
<p><a class="link" href="https://tech.meituan.com/2022/05/12/principles-and-practices-of-completablefuture.html" target="_blank" rel="noopener"
>[2] CompletableFuture原理与实践</a></p>
</description>
</item>
<item>
<title>javaweb概览</title>
<link>https://wakingupdelta.github.io/p/javaweb%E6%A6%82%E8%A7%88/</link>
<pubDate>Thu, 06 Jun 2024 00:00:00 +0000</pubDate>
<guid>https://wakingupdelta.github.io/p/javaweb%E6%A6%82%E8%A7%88/</guid>
<description><h3 id="一servlet">一、Servlet
</h3><p>Servlet是一套规范</p>
<ul>
<li>后端 遵守 规范 编写 小程序</li>
<li>web服务器 遵守 规范 调用 小程序
<ul>
<li>模拟流程
<ul>
<li>实例化Servlet、ServletRequest、ServletResponse</li>
<li>调用Servlet的service方法,ServletRequest、ServletResponse为入参</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>常见接口</p>
<ul>
<li>init 第一次请求 或 容器启动 调用</li>
<li>destroy 容器关闭 调用</li>
<li>service 每次请求调用</li>
<li>getServletConfig
<ul>
<li>一个Servlet对应一个ServletConfig</li>
<li>多个Servlet对应一个ServletContext</li>
</ul>
</li>
</ul>
<p>请求转发</p>
<ul>
<li>服务器内部行为、地址栏不变</li>
<li>调用新Servlet的service方法</li>
</ul>
<p>重定向</p>
<ul>
<li>客户端重新发请求、地址栏变化</li>
</ul>
<p>会话管理</p>
<ul>
<li>会话 &ndash; 一个客户端的多次请求</li>
<li>session 服务端
<ul>
<li>request.getSession
<ul>
<li>无cookie新建HttpSession,JSESSIONID以cookie形式写入HttpServletResponse中</li>
<li>有则查</li>
</ul>
</li>
</ul>
</li>
<li>cookie 客户端 浏览器发请求时携带</li>
<li>简单的登录校验
<ul>
<li>查session是否存key为user,有则表示登录成功,可执行业务逻辑</li>
<li>无则重定向至登录页面,查数据库验证账号和密码,正确则往session中存入user</li>
</ul>
</li>
</ul>
<p>域对象</p>
<ul>
<li>请求域 HttpServletRequest
<ul>
<li>数据只存在 该次请求中</li>
</ul>
</li>
<li>会话域 HttpSession
<ul>
<li>数据存全局,但只有携带正确JSESSIONID的请求能访问</li>
</ul>
</li>
<li>应用域 ServletContext
<ul>
<li>数据存全局</li>
</ul>
</li>
</ul>
<h3 id="二filter">二、Filter
</h3><p>一个规范,常见接口</p>
<ul>
<li>init 初始化方法,容器调用传入配置信息</li>
<li>doFilter 过滤方法,实现Servlet执行前、后的逻辑
<ul>
<li>入参ServletRequest、ServletResponse、FilterChain</li>
<li>FilterChain.doFilter(request, response) 放行请求,继续执行下一个Filter?
<ul>
<li>FilterChain 粗浅理解、责任链设计模式
<ul>
<li>Filter数组,存放Filter穿起来的链</li>
<li>下标指针,表示当前执行到哪个Filter</li>
<li>doFilter方法
<ul>
<li>判断指针位置,执行完毕,调用Servlet的service方法</li>
<li>否则,取出Filter,调用Filter的doFilter方法,入参为request、response、this
<ul>
<li>在执行下一个Filter的doFilter方法时,this.doFilter可能会被调用,较为复杂的递归</li>
<li>基于这种递归实现,可以使得多个Filter分层次将Servlet抱起来,优先级最高的Filter,在业务逻辑前最先执行,在业务逻辑后最后执行</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>destroy 销毁方法,容器回收过滤器对象前调用</li>
</ul>
<h3 id="三listener">三、Listener
</h3><p>观察者模式</p>
<p>分类</p>
<ul>
<li>监听对象划分
<ul>
<li>request、session、application</li>
</ul>
</li>
<li>监听事件划分 对应不同的接口方法
<ul>
<li>对象创建和销毁</li>
<li>数据更新</li>
<li>其他
<ul>
<li>HttpSessionBindingListener 监听 Listener 在 session域中的增加、移除</li>
<li>HttpSessionActivationListener 钝化监听器,监听某个对象在session中序列化、反序列化</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="四ajax">四、AJAX
</h3><p>Asynchronous JavaScript and XML</p>
<p>简单理解,js代码异步发送http请求,请求收到后回调函数执行,渲染xml页面</p>
</description>
</item>
<item>
<title>注意力机制概览</title>
<link>https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/</link>
<pubDate>Sun, 12 May 2024 00:00:00 +0000</pubDate>
<guid>https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/</guid>
<description><h1 id="一背景">一、背景
</h1><p>注意力机制可有效提高模型对特征的提取能力,进而提高模型精度。本文首先对经典的三种注意力学习方法进行介绍,后结合自己一点点浅薄认知,对注意力机制后续的改进方向进行归纳,希望对大家能有帮助</p>
<h1 id="二前置知识">二、前置知识
</h1><h2 id="21-通道注意力">2.1 通道注意力
</h2><img src="image-20240903143439161.png" alt="image-20240903143439161" style="zoom:67%;" />
对特征图进行全局平均池化,后经过两层全连接层,最后使用Sigmoid输出0-1之间的权重
<h2 id="22-空间注意力">2.2 空间注意力
</h2><img src="image-20240903143451755.png" alt="image-20240903143451755" style="zoom:67%;" />
将特征图进行压缩,得到空间方向上的权重图
<h2 id="23-self-attention">2.3 self-attention
</h2><img src="image-20240903143502737.png" alt="image-20240903143502737" style="zoom:67%;" />
<p>这里借助了Non-local Neural Networks中的一张图。self-attention本质上是一种空间注意机制,如上图所示,需要求解一个[THW, THW]的矩阵,该矩阵中的每一行,表示原特征图中的一点与其余点的关系</p>
<h1 id="三各种改进版本">三、各种改进版本
</h1><p>将改进的注意力机制主要分为四类</p>
<ul>
<li>跨特征:构建不同的特征表达,后进行融合</li>
<li>分组:对特征图按通道分组后,再使用注意力机制</li>
<li>self-attention:本质上,self-attention就是一系列矩阵运算,对运算过程中的某些步骤进行优化</li>
<li>空间+通道:很自然的想法,同时使用两种注意力机制</li>
</ul>
<h2 id="31-跨特征">3.1 跨特征
</h2><h4 id="311-bisenet">3.1.1 BiSeNet
</h4><img src="image-20240903143515154.png" alt="image-20240903143515154" style="zoom:67%;" />
对不同层次的特征使用通道注意力机制进行融合。这应该属于应用创新,没有构建新的注意力机制,而是将老的注意力机制应用到特征融合方向
<h4 id="312-sknet">3.1.2 SKNet
</h4><p><img src="https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143528059.png"
width="1257"
height="359"
srcset="https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143528059_hu4188395624d6c6de293fd145c8a93efd_185865_480x0_resize_box_3.png 480w, https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143528059_hu4188395624d6c6de293fd145c8a93efd_185865_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="image-20240903143528059"
class="gallery-image"
data-flex-grow="350"
data-flex-basis="840px"
></p>
<p>使用不同感受野卷积核构建多分支特征,将这些特征 add 后计算不同分支的同道注意力系数,后沿着通道方向进行加权求和</p>
<h2 id="32-分组">3.2 分组
</h2><h3 id="321-sgnet">3.2.1 SGNet
</h3><p><img src="https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143537682.png"
width="1252"
height="426"
srcset="https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143537682_hud065ca2fd1dda1682e5e65c580ff9f53_319318_480x0_resize_box_3.png 480w, https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143537682_hud065ca2fd1dda1682e5e65c580ff9f53_319318_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="image-20240903143537682"
class="gallery-image"
data-flex-grow="293"
data-flex-basis="705px"
></p>
<p>对每个组,先计算向量x的平均值(全局平均池化),后将利用该向量对特征图沿着通道 方向加权求和得到 空间注意力,再归一化,后经sigmoid函数输出</p>
<h3 id="322-sanet">3.2.2 SANet
</h3><p><img src="https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143548571.png"
width="1256"
height="347"
srcset="https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143548571_hube3e2276944c2386941e589284b66220_149550_480x0_resize_box_3.png 480w, https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143548571_hube3e2276944c2386941e589284b66220_149550_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="image-20240903143548571"
class="gallery-image"
data-flex-grow="361"
data-flex-basis="868px"
></p>
<p>将特征沿着通道分组,对每一组,再分成 空间注意力 和 通道注意力。对空间注意力,使用Group normalization实现。将分组结果进行拼接,后使用类似ShufflfleNet v2的方法进行channel shuffle</p>
<h2 id="33-self-attention">3.3 Self Attention
</h2><h3 id="331-non-local-attention">3.3.1 non local attention
</h3><img src="image-20240903143603023.png" alt="image-20240903143603023" style="zoom:67%;" />
<p>定义了不同形式计算向量相似性的函数,提出self attention是non local attention 的特例</p>
<h3 id="332-gcnet">3.3.2 GCNet
</h3><p><img src="https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143615249.png"
width="1260"
height="424"
srcset="https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143615249_hu1aa83e91a93954a70623cd5a573c4860_237508_480x0_resize_box_3.png 480w, https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143615249_hu1aa83e91a93954a70623cd5a573c4860_237508_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="image-20240903143615249"
class="gallery-image"
data-flex-grow="297"
data-flex-basis="713px"
></p>
<p>指出non local attention不同位置的attention map基本一致,只计算Cx1x1的特征图</p>
<h3 id="333-dual-attention">3.3.3 dual attention
</h3><img src="image-20240903143636442.png" alt="image-20240903143636442" style="zoom: 50%;" />
<p>并联non local attention 和 GCnet</p>
<h2 id="34-空间通道">3.4 空间+通道
</h2><h3 id="341-bam">3.4.1 BAM
</h3><p><img src="https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143651005.png"
width="1259"
height="445"
srcset="https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143651005_hu64b85001a552aa50dce13d8f55530e40_190059_480x0_resize_box_3.png 480w, https://wakingupdelta.github.io/p/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E6%A6%82%E8%A7%88/image-20240903143651005_hu64b85001a552aa50dce13d8f55530e40_190059_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="image-20240903143651005"
class="gallery-image"
data-flex-grow="282"
data-flex-basis="679px"
></p>
<p>并联,attention map先相加(利用了广播机制),后与原特征图相乘</p>
<h3 id="342-scse">3.4.2 scSE
</h3><img src="image-20240903143703961.png" alt="image-20240903143703961" style="zoom:50%;" />
<p>并联,attention map先各自相乘,后取最大值得到最终输出</p>
<h1 id="参考文献">参考文献
</h1><p><a class="link" href="https://openaccess.thecvf.com/content_ECCV_2018/papers/Changqian_Yu_BiSeNet_Bilateral_Segmentation_ECCV_2018_paper.pdf" target="_blank" rel="noopener"
>[1] BiSeNet: Bilateral Segmentation Network for Real-time Semantic Segmentation</a></p>
<p><a class="link" href="https://openaccess.thecvf.com/content_CVPR_2019/papers/Li_Selective_Kernel_Networks_CVPR_2019_paper.pdf" target="_blank" rel="noopener"
>[2] Selective Kernel Networks</a></p>
<p><a class="link" href="https://arxiv.org/pdf/1905.09646.pdf" target="_blank" rel="noopener"
>[3] Spatial Group-wise Enhance: Improving Semantic Feature Learning in Convolutional Networks</a></p>
<p><a class="link" href="https://arxiv.org/pdf/2102.00240.pdf" target="_blank" rel="noopener"
>[4] SA-NET: SHUFFLE ATTENTION FOR DEEP CONVOLUTIONAL NEURAL NETWORKS</a></p>
<p><a class="link" href="https://openaccess.thecvf.com/content_cvpr_2018/papers/Wang_Non-Local_Neural_Networks_CVPR_2018_paper.pdf" target="_blank" rel="noopener"
>[5] Non-local Neural Networks</a></p>
<p><a class="link" href="https://openaccess.thecvf.com/content_ICCVW_2019/papers/NeurArch/Cao_GCNet_Non-Local_Networks_Meet_Squeeze-Excitation_Networks_and_Beyond_ICCVW_2019_paper.pdf" target="_blank" rel="noopener"
>[6] GCNet: Non-local Networks Meet Squeeze-Excitation Networks and Beyond</a></p>
<p><a class="link" href="https://openaccess.thecvf.com/content_CVPR_2019/papers/Fu_Dual_Attention_Network_for_Scene_Segmentation_CVPR_2019_paper.pdf" target="_blank" rel="noopener"
>[7] Dual Attention Network for Scene Segmentation</a></p>
<p><a class="link" href="https://arxiv.org/pdf/1807.06514.pdf" target="_blank" rel="noopener"
>[8] BAM: Bottleneck Attention Module</a></p>
<p><a class="link" href="https://arxiv.org/pdf/1808.08127.pdf" target="_blank" rel="noopener"
>[9] Recalibrating Fully Convolutional Networks with Spatial and Channel ‘Squeeze &amp; Excitation’ Blocks</a></p>
</description>
</item>
<item>
<title>基于一致性的半监督学习</title>
<link>https://wakingupdelta.github.io/p/%E5%9F%BA%E4%BA%8E%E4%B8%80%E8%87%B4%E6%80%A7%E7%9A%84%E5%8D%8A%E7%9B%91%E7%9D%A3%E5%AD%A6%E4%B9%A0/</link>
<pubDate>Wed, 01 May 2024 00:00:00 +0000</pubDate>
<guid>https://wakingupdelta.github.io/p/%E5%9F%BA%E4%BA%8E%E4%B8%80%E8%87%B4%E6%80%A7%E7%9A%84%E5%8D%8A%E7%9B%91%E7%9D%A3%E5%AD%A6%E4%B9%A0/</guid>
<description><h1 id="一背景">一、背景
</h1><p>医学图像的标注成本十分高昂,其标注数据规模往往较小。通过半监督学习的方法,利用大量的未标注数据,可有效提高模型的学习能力</p>
<h1 id="二基本分类">二、基本分类
</h1><img src="image-20240903143111694.png" alt="image-20240903143111694" style="zoom: 50%;" />
<p>如上图所示,仅有正方形的数据点,无法学习真实的数据分布,通过引入大量的未标注的圆形点,可得知数据的真实情况,这便是半监督学习的基本原理。</p>
<p>对于有标注的输入样本,因为有标签作为监督信号,所以很自然可以定义损失函数。对于未标注样本,需要自行构建监督信号。基本可分为两大类,一类是熵最小化约束,使模型趋向于得出高置信度的预测结果,另一类则是一致性约束,对输入或模型添加各种干扰,但模型依然具有稳定的输出。一致性约束是本文的重点,简单来说,就是通过各种奇技淫巧,使得模型对一个输入,具有不同的输出,然后让两个输出趋向一致,这就能构建出监督信号</p>
<h1 id="三一致性约束">三、一致性约束
</h1><h2 id="31-基本架构">3.1 基本架构
</h2><h3 id="311-mean-teacher">3.1.1 mean teacher
</h3><img src="image-20240903143141868.png" alt="image-20240903143141868" style="zoom: 67%;" />
Mean Teacher模型是经典的半监督方法,学生模型通过EMA方法更新参数,然后约束教师模型和学生模型之间的一致性
<h3 id="312-多个子模型">3.1.2 多个子模型
</h3><img src="image-20240903143200747.png" alt="image-20240903143200747" style="zoom:80%;" />
直接构建两个独立的子模型,一个是卷积架构,另一个是transformer架构
<h3 id="313-多个解码器">3.1.3 多个解码器
</h3><img src="image-20240903143221906.png" alt="image-20240903143221906" style="zoom: 67%;" />
<p>多个解码器</p>
<h3 id="314-多尺度">3.1.4 多尺度
</h3><img src="image-20240903143240369.png" alt="image-20240903143240369" style="zoom: 67%;" />
使得解码器的不同层次输出保持一致性
<h2 id="32-技巧">3.2 技巧
</h2><p>基本架构应该就是上述的模型,后面就是使用各种技巧去提高模型的性能</p>
<h3 id="321-不确定性">3.2.1 不确定性
</h3><img src="image-20240903143300654.png" alt="image-20240903143300654" style="zoom:67%;" />
<p>两输出中肯定存在某些区域更重要,通过不确定性对其加权</p>
<h3 id="322-损失函数">3.2.2 损失函数
</h3><img src="image-20240903143315908.png" alt="image-20240903143315908" style="zoom:67%;" />
<p>类似知识蒸馏的方法,对输出取softmax操作时,添加温度参数T,使得具有更多信息,再去保持一致性。</p>
<h1 id="参考文献">参考文献
</h1><p><a class="link" href="https://proceedings.neurips.cc/paper/2017/file/68053af2923e00204c3ca7c6a3150cf7-Paper.pdf" target="_blank" rel="noopener"
>[1] Mean teachers are better role models: Weight-averaged consistency targets improve semi-supervised deep learning results</a><br>
<a class="link" href="https://proceedings.mlr.press/v172/luo22b/luo22b.pdf" target="_blank" rel="noopener"
>[2] Semi-Supervised Medical Image Segmentation via Cross Teaching between CNN and Transformer</a><br>
<a class="link" href="https://openaccess.thecvf.com/content_CVPR_2020/papers/Ouali_Semi-Supervised_Semantic_Segmentation_With_Cross-Consistency_Training_CVPR_2020_paper.pdf" target="_blank" rel="noopener"
>[3] Semi-Supervised Semantic Segmentation with Cross-Consistency Training</a><br>
<a class="link" href="https://arxiv.org/pdf/2012.07042.pdf" target="_blank" rel="noopener"
>[4] Efficient Semi-Supervised Gross Target Volume of Nasopharyngeal Carcinoma Segmentation via Uncertainty Rectified Pyramid Consistency</a><br>
<a class="link" href="https://arxiv.org/pdf/1907.07034.pdf" target="_blank" rel="noopener"
>[5] Uncertainty-aware Self-ensembling Model for Semi-supervised 3D Left Atrium Segmentation</a><br>
<a class="link" href="https://arxiv.org/pdf/2109.09960.pdf" target="_blank" rel="noopener"
>[6] Mutual Consistency Learning for Semi-supervised Medical Image Segmentation</a></p>
</description>
</item>
<item>
<title>改造nnUnet,嵌入第三方网络</title>
<link>https://wakingupdelta.github.io/p/%E6%94%B9%E9%80%A0nnunet%E5%B5%8C%E5%85%A5%E7%AC%AC%E4%B8%89%E6%96%B9%E7%BD%91%E7%BB%9C/</link>
<pubDate>Sun, 28 Apr 2024 00:00:00 +0000</pubDate>
<guid>https://wakingupdelta.github.io/p/%E6%94%B9%E9%80%A0nnunet%E5%B5%8C%E5%85%A5%E7%AC%AC%E4%B8%89%E6%96%B9%E7%BD%91%E7%BB%9C/</guid>
<description><h1 id="引言">引言
</h1><p><strong>nnUnet</strong> 是有监督的医学图像分割绕不开的话题,其卓越的性能和简易的方法,为相关研究者提供了一项强有力的工具。然而,由于高度封装性,在原先代码中嵌入自定义网络进行训练,并不是十分方便,本文旨在分享一点在使用 <strong>nnUnet</strong> 训练自定义网络过程中的一点经验,可能存在纰漏,欢迎在讨论区交流!</p>
<h1 id="一配置环境">一、配置环境
</h1><h2 id="11-硬件需求">1.1 硬件需求
</h2><p><strong>nnUnet</strong> 的建议环境是Linux,若使用Windows,需修改路径相关代码(斜杠和反斜杠的替换),很麻烦(不推荐)。博主是在Ubuntu环境中使用Pycharm进行 <strong>nnUnet</strong> 的学习</p>
<h2 id="12-软件需求">1.2 软件需求
</h2><p><strong>nnUnet</strong> 官方推荐的使用方法是在命令行,但这不方便初学者学习。为了使用Pycharm的调试功能,需修改两个文件的代码 <em><strong>nnunetv2/paths.py</strong></em> 和 <em><strong>nnunetv2/run/run_training.py</strong></em></p>
<h3 id="121-数据集路径">1.2.1 数据集路径
</h3><p>位于 <em><strong>nnunetv2/paths.py</strong></em> 文件中,将三个变量路径修改为自己的路径。<strong>custom_</strong> 是博主自己定义的文件,大家可以随意实现</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">custom_</span> <span class="kn">import</span> <span class="n">custom_config</span>
</span></span><span class="line"><span class="cl"><span class="n">base</span> <span class="o">=</span> <span class="n">custom_config</span><span class="p">[</span><span class="s1">&#39;base&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">preprocessing_output_dir</span> <span class="o">=</span> <span class="n">custom_config</span><span class="p">[</span><span class="s1">&#39;preprocessing_output_dir&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">network_training_output_dir_base</span> <span class="o">=</span> <span class="n">custom_config</span><span class="p">[</span><span class="s1">&#39;network_training_output_dir_base&#39;</span><span class="p">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="122-程序入口">1.2.2 程序入口
</h3><p>位于 <em><strong>nnunetv2/run/run_training.py</strong></em> 文件中,这里nnUnet训练代码的入口。由于不是命令行调用方式,需要将parser.add_argument的传入参数修改,添加 “-” 并设置 default 值。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">&#34;-network&#34;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;2d&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">&#34;-network_trainer&#34;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;nnUNetTrainerV2&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">&#34;-task&#34;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;666&#39;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&#34;can be task name or task id&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">&#34;-fold&#34;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;0&#39;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s1">&#39;0, 1, ..., 5 or &#39;</span><span class="nb">all</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="二构建网络">二、构建网络
</h1><h2 id="21-前置知识">2.1 前置知识
</h2><p><strong>nnUnet</strong> 默认使用深监督,意味着自定义网络输出应为一个列表形式。然而,在网络推理时,我们只需要最高分辨率的输出,不需要多层次输出。在nnUnet官方实现中,使用 <strong>deep_supervision</strong> 参数控制是否多层次输出。综上所述,自定义网络需要满足两个条件:</p>
<ul>
<li>支持多层次输出</li>
<li>使用变量deep_supervision控制输出类型</li>
</ul>
<h2 id="22-嵌入自定义网络">2.2 嵌入自定义网络
</h2><h3 id="221-包装网络">2.2.1 包装网络
</h3><p>这里提供一种对已有网络包装的方法,仅供参考</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torch.nn</span> <span class="k">as</span> <span class="nn">nn</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">custom_net</span><span class="p">(</span><span class="n">nn</span><span class="o">.</span><span class="n">Module</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,):</span>
</span></span><span class="line"><span class="cl"> <span class="nb">super</span><span class="p">(</span><span class="n">custom_net</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">deep_supervision</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># 使用你自己的网络</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">model</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">output</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">model</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">deep_supervision</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">[</span><span class="n">output</span><span class="p">,</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">output</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="222-嵌入主框架">2.2.2 嵌入主框架
</h3><p>将自定义网络嵌套进主框架。打开文件 <strong>nnunetv2/training/nnUNetTrainer/nnUNetTrainer.py</strong></p>
<p>替换函数 <strong>build_network_architecture</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">build_network_architecture</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">plans_manager</span><span class="p">:</span><span class="n">PlansManager</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">dataset_json</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">configuration_manager</span><span class="p">:</span><span class="n">ConfigurationManager</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">num_input_channels</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">enable_deep_supervision</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">nn</span><span class="o">.</span><span class="n">Module</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="kn">from</span> <span class="nn">dynamic_network_architectures.initialization.weight_init</span> <span class="kn">import</span> <span class="n">InitWeights_He</span>
</span></span><span class="line"><span class="cl"> <span class="n">model</span> <span class="o">=</span> <span class="n">custom_net</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="n">model</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">InitWeights_He</span><span class="p">(</span><span class="mf">1e-2</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">model</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="参考资料">参考资料
</h1><p><a class="link" href="https://www.nature.com/articles/s41592-020-01008-z." target="_blank" rel="noopener"
>[1] nnU-Net: a self-configuring method for deep learning-based biomedical image segmentation</a><br>
<a class="link" href="https://github.com/MIC-DKFZ/nnUNet" target="_blank" rel="noopener"
>[2] nnUnet</a></p>
</description>
</item>
<item>
<title>云顶之弈 辅助高亮显示</title>
<link>https://wakingupdelta.github.io/p/%E4%BA%91%E9%A1%B6%E4%B9%8B%E5%BC%88-%E8%BE%85%E5%8A%A9%E9%AB%98%E4%BA%AE%E6%98%BE%E7%A4%BA/</link>
<pubDate>Wed, 03 Jan 2024 00:00:00 +0000</pubDate>
<guid>https://wakingupdelta.github.io/p/%E4%BA%91%E9%A1%B6%E4%B9%8B%E5%BC%88-%E8%BE%85%E5%8A%A9%E9%AB%98%E4%BA%AE%E6%98%BE%E7%A4%BA/</guid>
<description><h1 id="一前言">一、前言
</h1><p>本文提供一个简易的demo,用于对目标阵容的高亮显示,避免猪脑过载或慢速思考。基本流程由两部分组成</p>
<ul>
<li>使用 <strong>tesseract</strong> 识别卡牌池名字,与目标阵容进行比较,得到卡牌坐标</li>
<li>基于坐标对卡牌高亮显示</li>
</ul>
<h1 id="二环境设置">二、环境设置
</h1><p>博主是在 <strong>windows</strong> 上运行,搭配 <strong>Pycharm</strong> 使用,使用该教程需要进行以下设置:</p>
<ol>
<li>将英雄联盟客户端语言设置为 <strong>英文</strong></li>
<li>游戏内设置分辨率为 <strong>1920*1080</strong>,<strong>无边框模式</strong></li>
<li>windows桌面,右键-&gt;显示设置-&gt;缩放与布局-&gt;更改文本、应用等项目的大小-&gt;<strong>100%</strong></li>
<li>通过参考资料 <a class="link" href="https://tesseract-ocr.github.io/tessdoc/Installation.html" target="_blank" rel="noopener"
>[1]</a> 安装 <strong>tesseract</strong>,并配置到 <strong>系统环境变量</strong></li>
<li>以 <strong>管理员</strong> 身份运行pycharm</li>
</ol>
<h1 id="三卡牌识别">三、卡牌识别
</h1><h2 id="31-候选框截取">3.1 候选框截取
</h2><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pyscreenshot</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">ocr</span> <span class="kn">import</span> <span class="n">get_text_from_image</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pynput</span> <span class="kn">import</span> <span class="n">keyboard</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">takeScreenshotROI</span><span class="p">(</span><span class="n">coordinates</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># 根据坐标截图</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">pyscreenshot</span><span class="o">.</span><span class="n">grab</span><span class="p">(</span><span class="n">coordinates</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_champions</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="n">width</span><span class="p">,</span> <span class="n">height</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1920</span><span class="p">,</span> <span class="mi">1080</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">left</span><span class="p">,</span> <span class="n">top</span><span class="p">,</span> <span class="n">right</span><span class="p">,</span> <span class="n">bottom</span> <span class="o">=</span> <span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">width</span> <span class="o">*</span> <span class="mf">0.25</span><span class="p">),</span> <span class="nb">int</span><span class="p">(</span><span class="n">height</span> <span class="o">*</span> <span class="mf">0.96</span><span class="p">),</span> <span class="nb">int</span><span class="p">(</span><span class="n">width</span> <span class="o">*</span> <span class="mf">0.77</span><span class="p">),</span> <span class="nb">int</span><span class="p">(</span><span class="n">height</span> <span class="o">*</span> <span class="mf">0.99</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="n">_width</span> <span class="o">=</span> <span class="p">(</span><span class="n">right</span><span class="o">-</span><span class="n">left</span><span class="p">)</span><span class="o">/</span><span class="mi">5</span>
</span></span><span class="line"><span class="cl"> <span class="n">champions_list</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">idx</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">coordinates</span> <span class="o">=</span> <span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">left</span> <span class="o">+</span> <span class="n">idx</span><span class="o">*</span><span class="n">_width</span><span class="p">)</span><span class="o">+</span><span class="mi">10</span><span class="p">,</span> <span class="n">top</span><span class="p">,</span> <span class="nb">int</span><span class="p">(</span><span class="n">left</span> <span class="o">+</span> <span class="p">(</span><span class="n">idx</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="n">_width</span><span class="p">)</span><span class="o">-</span><span class="mi">55</span><span class="p">,</span> <span class="n">bottom</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># 对卡牌池截图</span>
</span></span><span class="line"><span class="cl"> <span class="n">roi_example</span> <span class="o">=</span> <span class="n">takeScreenshotROI</span><span class="p">(</span><span class="n">coordinates</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># 函数get_text_from_image对截图进行ocr识别</span>
</span></span><span class="line"><span class="cl"> <span class="n">champion_name</span> <span class="o">=</span> <span class="n">get_text_from_image</span><span class="p">(</span><span class="n">roi_example</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">champions_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">champion_name</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">champions_list</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>计算左上和右下坐标 <em><strong>coordinates</strong></em>,后根据坐标截取屏幕。由于卡池共有五张牌,需要循环五次</p>
<h2 id="32-ocr识别">3.2 ocr识别
</h2><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Any</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">cv2</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">ImageGrab</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pytesseract</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 转为灰度图</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">image_grayscale</span><span class="p">(</span><span class="n">image</span><span class="p">:</span> <span class="n">ImageGrab</span><span class="o">.</span><span class="n">Image</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">cv2</span><span class="o">.</span><span class="n">cvtColor</span><span class="p">(</span><span class="n">image</span><span class="p">,</span> <span class="n">cv2</span><span class="o">.</span><span class="n">COLOR_BGR2GRAY</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 阈值分割</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">image_thresholding</span><span class="p">(</span><span class="n">image</span><span class="p">:</span> <span class="n">ImageGrab</span><span class="o">.</span><span class="n">Image</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">cv2</span><span class="o">.</span><span class="n">threshold</span><span class="p">(</span><span class="n">image</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="n">cv2</span><span class="o">.</span><span class="n">THRESH_BINARY_INV</span> <span class="o">+</span> <span class="n">cv2</span><span class="o">.</span><span class="n">THRESH_OTSU</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 转numpy</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">image_array</span><span class="p">(</span><span class="n">image</span><span class="p">:</span> <span class="n">ImageGrab</span><span class="o">.</span><span class="n">Image</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="s2">&#34;&#34;&#34;Turns the image into an array&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl"> <span class="n">image</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">image</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">image</span> <span class="o">=</span> <span class="n">image</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="p">:</span><span class="mi">3</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">image</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 调整尺寸</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">image_resize</span><span class="p">(</span><span class="n">image</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="s2">&#34;&#34;&#34;Resizes the image using the scale passed in argument two&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">image</span><span class="o">.</span><span class="n">width</span> <span class="o">*</span> <span class="n">scale</span><span class="p">,</span> <span class="n">image</span><span class="o">.</span><span class="n">height</span> <span class="o">*</span> <span class="n">scale</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">image</span><span class="o">.</span><span class="n">resize</span><span class="p">((</span><span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 对卡牌池截图进行ocr识别</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_text_from_image</span><span class="p">(</span><span class="n">image</span><span class="p">:</span> <span class="n">ImageGrab</span><span class="o">.</span><span class="n">Image</span><span class="p">,</span> <span class="n">whitelist</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">resize</span> <span class="o">=</span> <span class="n">image_resize</span><span class="p">(</span><span class="n">image</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">array</span> <span class="o">=</span> <span class="n">image_array</span><span class="p">(</span><span class="n">resize</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">grayscale</span> <span class="o">=</span> <span class="n">image_grayscale</span><span class="p">(</span><span class="n">array</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">thresholding</span> <span class="o">=</span> <span class="n">image_thresholding</span><span class="p">(</span><span class="n">grayscale</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">pytesseract</span><span class="o">.</span><span class="n">image_to_string</span><span class="p">(</span><span class="n">thresholding</span><span class="p">,</span> <span class="n">config</span><span class="o">=</span><span class="sa">f</span><span class="s1">&#39;--psm 7 -c tessedit_char_whitelist=</span><span class="si">{</span><span class="n">whitelist</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>由 <strong>3.1候选框</strong> 截取到的图片将作为参数,传入函数 <em><strong>get_text_from_image</strong></em> 进行识别,得到卡牌名</p>
<h1 id="四高亮显示">四、高亮显示
</h1><p>基于第三章的函数,会得到现在卡牌池的名字列表,将该列表与目标阵容进行比较,得到需高亮位置的坐标,后使用 <strong>Pyqt5</strong> 显示</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">PyQt5.QtWidgets</span> <span class="kn">import</span> <span class="o">*</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">PyQt5.QtGui</span> <span class="kn">import</span> <span class="o">*</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">PyQt5.QtCore</span> <span class="kn">import</span> <span class="n">Qt</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">sys</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">PyQt5</span> <span class="kn">import</span> <span class="n">QtCore</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Window</span><span class="p">(</span><span class="n">QMainWindow</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">display_list</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="nb">super</span><span class="p">(</span><span class="n">Window</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">QtCore</span><span class="o">.</span><span class="n">Qt</span><span class="o">.</span><span class="n">WindowStaysOnTopHint</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">setWindowFlag</span><span class="p">(</span><span class="n">Qt</span><span class="o">.</span><span class="n">FramelessWindowHint</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">setWindowTitle</span><span class="p">(</span><span class="s2">&#34;no title&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">setGeometry</span><span class="p">(</span><span class="mi">500</span><span class="p">,</span> <span class="mi">940</span><span class="p">,</span> <span class="mi">950</span><span class="p">,</span> <span class="mi">30</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># 卡牌池有四个位置,display_list表示需要标记recommen的卡牌</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">idx</span> <span class="ow">in</span> <span class="n">display_list</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">label</span> <span class="o">=</span> <span class="n">QLabel</span><span class="p">(</span><span class="s1">&#39;recommend&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">label</span><span class="o">.</span><span class="n">setStyleSheet</span><span class="p">(</span><span class="s2">&#34;background-color: lightgreen; border: 3px solid green&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">label</span><span class="o">.</span><span class="n">setGeometry</span><span class="p">(</span><span class="mi">200</span><span class="o">*</span><span class="n">idx</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">30</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">show</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">keyPressEvent</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">e</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">e</span><span class="o">.</span><span class="n">key</span><span class="p">()</span> <span class="o">==</span> <span class="n">Qt</span><span class="o">.</span><span class="n">Key_D</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">App</span> <span class="o">=</span> <span class="n">QApplication</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">win1</span> <span class="o">=</span> <span class="n">Window</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">App</span><span class="o">.</span><span class="n">exec</span><span class="p">()</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>效果预览</p>
<p><img src="https://wakingupdelta.github.io/p/%E4%BA%91%E9%A1%B6%E4%B9%8B%E5%BC%88-%E8%BE%85%E5%8A%A9%E9%AB%98%E4%BA%AE%E6%98%BE%E7%A4%BA/image-20240903143747782.png"
width="1127"
height="194"
srcset="https://wakingupdelta.github.io/p/%E4%BA%91%E9%A1%B6%E4%B9%8B%E5%BC%88-%E8%BE%85%E5%8A%A9%E9%AB%98%E4%BA%AE%E6%98%BE%E7%A4%BA/image-20240903143747782_hue5f4aaf8cdee5fb403bd4dfcaf3b663b_289827_480x0_resize_box_3.png 480w, https://wakingupdelta.github.io/p/%E4%BA%91%E9%A1%B6%E4%B9%8B%E5%BC%88-%E8%BE%85%E5%8A%A9%E9%AB%98%E4%BA%AE%E6%98%BE%E7%A4%BA/image-20240903143747782_hue5f4aaf8cdee5fb403bd4dfcaf3b663b_289827_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="image-20240903143747782"
class="gallery-image"
data-flex-grow="580"
data-flex-basis="1394px"
></p>
<h1 id="参考资料">参考资料
</h1><p><a class="link" href="https://tesseract-ocr.github.io/tessdoc/Installation.html" target="_blank" rel="noopener"
>[1] tesseract</a><br>
<a class="link" href="https://github.com/jfd02/TFT-OCR-BOT" target="_blank" rel="noopener"
>[2] TFT-OCR-BOT</a><br>
<a class="link" href="https://github.com/Eikinel/TFT-Auto-Buy" target="_blank" rel="noopener"
>[3] TFT-Auto-Buy</a><br>
<a class="link" href="https://github.com/luxiaolan6373/tft_zynp" target="_blank" rel="noopener"
>[4] tft_zynp</a></p>
</description>
</item>
<item>
<title>Ubuntu驱动安装,一发入魂</title>
<link>https://wakingupdelta.github.io/p/ubuntu%E9%A9%B1%E5%8A%A8%E5%AE%89%E8%A3%85%E4%B8%80%E5%8F%91%E5%85%A5%E9%AD%82/</link>
<pubDate>Mon, 13 Nov 2023 00:00:00 +0000</pubDate>
<guid>https://wakingupdelta.github.io/p/ubuntu%E9%A9%B1%E5%8A%A8%E5%AE%89%E8%A3%85%E4%B8%80%E5%8F%91%E5%85%A5%E9%AD%82/</guid>
<description><h1 id="前言">前言
</h1><p>闲着没事,折腾了个双系统,卡在显卡驱动安装,最后参考官方教程,一发入魂。原版教程是英文版 <a class="link" href="https://linuxconfig.org/how-to-install-the-nvidia-drivers-on-ubuntu-18-04-bionic-beaver-linux" target="_blank" rel="noopener"
>[1]</a>,本文将相关内容简单翻译,以方便大家使用。官方共列出三种安装方法,方法一、二为自动安装,方法三为手动安装;推荐使用第一种方法,简单且高效,第三种方法过于复杂,不推荐。这里不得不吐槽下,有很多教程将第二种方法和第三种方法糅合,纯属误人子弟!</p>
<h1 id="方法一基于官方库的自动安装">方法一:基于官方库的自动安装
</h1><p><strong>步骤一</strong>:使用命令 <strong>ubuntu-drivers devices</strong>,确定显卡型号和推荐的驱动版本,从输出信息可知,目前的显卡型号为GeForce GTX 1060,推荐的驱动版本为390</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"> $ ubuntu-drivers devices
</span></span><span class="line"><span class="cl">== /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 ==
</span></span><span class="line"><span class="cl">modalias : pci:v000010DEd00001180sv00001458sd0000353Cbc03sc00i00
</span></span><span class="line"><span class="cl">vendor : NVIDIA Corporation
</span></span><span class="line"><span class="cl">model : GP106 [GeForce GTX 1060 6GB]
</span></span><span class="line"><span class="cl">driver : nvidia-304 - distro non-free
</span></span><span class="line"><span class="cl">driver : nvidia-340 - distro non-free
</span></span><span class="line"><span class="cl">driver : nvidia-390 - distro non-free recommended
</span></span><span class="line"><span class="cl">driver : xserver-xorg-video-nouveau - distro free builtin
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">== cpu-microcode.py ==
</span></span><span class="line"><span class="cl">driver : intel-microcode - distro free
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>步骤二</strong>:自动安装第一步所推荐驱动</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ sudo ubuntu-drivers autoinstall
</span></span></code></pre></td></tr></table>
</div>
</div><p>也可以,手动安装特定版本</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ sudo apt install nvidia-340
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>步骤三</strong>:等待安装结束,后重启系统,使用命令 <strong>nvidia-smi</strong> 确认安装是否成功</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ nvidia-smi
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="方法二基于ppa库的自动安装">方法二:基于PPA库的自动安装
</h1><p><strong>步骤一</strong>:添加PPA库</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ sudo add-apt-repository ppa:graphics-drivers/ppa
</span></span><span class="line"><span class="cl">$ sudo apt update
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>步骤二</strong>:使用命令 <strong>ubuntu-drivers devices</strong> 查看推荐的驱动版本,可以发现,当添加PPA库后,推荐驱动版本更改为410,且注明为第三方包</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ ubuntu-drivers devices
</span></span><span class="line"><span class="cl">== /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 ==
</span></span><span class="line"><span class="cl">modalias : pci:v000010DEd00001C03sv00001043sd000085ABbc03sc00i00
</span></span><span class="line"><span class="cl">vendor : NVIDIA Corporation
</span></span><span class="line"><span class="cl">model : GP106 [GeForce GTX 1060 6GB]
</span></span><span class="line"><span class="cl">driver : nvidia-driver-390 - third-party free
</span></span><span class="line"><span class="cl">driver : nvidia-driver-410 - third-party free recommended
</span></span><span class="line"><span class="cl">driver : nvidia-driver-396 - third-party free
</span></span><span class="line"><span class="cl">driver : xserver-xorg-video-nouveau - distro free builtin
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>步骤三</strong>:自动安装步骤二所推荐驱动</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ sudo ubuntu-drivers autoinstall