This repository has been archived by the owner on Aug 24, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtk1.tex
807 lines (709 loc) · 32.2 KB
/
tk1.tex
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
% Encoding: UTF8
% \documentclass{ctexart}
\documentclass[openany]{ctexbook}
\usepackage{graphicx}
\usepackage{amsfonts}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage[mathscr]{eucal}
\usepackage{pythonhighlight}
\usepackage{fancyhdr}
\usepackage{bbm}
\usepackage{textcomp}
\usepackage[top=1in,bottom=1in, left=1in, right=1in]{geometry}
\usepackage[hidelinks]{hyperref}
\usepackage{subcaption}
\usepackage{listings}
\usepackage{xcolor}
\hypersetup{
colorlinks,
linkcolor={red!50!black},
citecolor={blue!50!black},
urlcolor={blue!80!black}
}
\lstset{
columns=fixed,
numbers=left, % 在左侧显示行号
frame=none, % 不显示背景边框
backgroundcolor=\color[RGB]{245,245,244}, % 设定背景颜色
keywordstyle=\color[RGB]{40,40,255}, % 设定关键字颜色
numberstyle=\footnotesize\color{darkgray}, % 设定行号格式
commentstyle=\it\color[RGB]{0,96,96}, % 设置代码注释的格式
stringstyle=\rmfamily\slshape\color[RGB]{128,0,0}, % 设置字符串格式
showstringspaces=false, % 设置语言
}
\newcommand{\warn}[1] {\fcolorbox{red!20}{red!20} {\color{red} #1}}
\newcommand{\info}[1] {\fcolorbox{blue!20}{blue!20} {\color{blue} #1}}
\begin{document}
\begin{titlepage}
\pagenumbering{roman}
\title{NVIDIA Jetson TK1使用介绍文档}
\author{闻超\\v0.1.0}
\date{\today}
\maketitle
\setcounter{page}{1}
\tableofcontents
\end{titlepage}
\pagenumbering{arabic}
\chapter{NVIDIA Jetson TK1介绍}
\section{硬件参数介绍}
\paragraph{尺寸}
127mm x 127mm
\paragraph{TK1 SOC}
CPU+GPU+ISP一体设计
\paragraph{GPU}
NVIDIA Kepler ``GK20a'' GPU with 192 SM3.2 CUDA cores (upto 326 GFLOPS)
\paragraph{CPU}
NVIDIA 2.32GHz ARM quad-core Cortex-A15 CPU
\paragraph{DRAM}
2GB DDR3L 933MHz EMC x16 使用 64-bit 数据位宽
\paragraph{存储}
16GB fast eMMC 4.51
\paragraph{mini-PCIe}
此接口可用于SSD、WiFi、以太网的扩展
\begin{figure}[h]
\centering
\includegraphics[width=5.5in]{1.jpg}
\caption{TK1硬件组件介绍}
\end{figure}
\section{入门资料汇总}
对于第一次使用TK1的童鞋们,可以仔细阅读以下网址提供的资料:\url{http://elinux.org/Jetson_TK1}
TK1开发板的一些资料下载网址:\url{https://developer.nvidia.com/jetson-tk1}
入门视频教学:\url{http://www.iqiyi.com/a_19rrhc0aql.html}
\section{接口相关注意事项}
\begin{enumerate}
\item Jetson TK1只提供一个USB接口,因此若想连接鼠标、键盘等外设,可以自己购买一个USB-HUB来使用
\item Jetson TK1提供的显示接口是HDMI,如果没有HDMI接口显示器,可以买一个HDMI转VGA或者DVI接口线即可
\end{enumerate}
\section{Jetson TK1 支持的实验框架}
TK1支持许多常见的Machine Learning、Computer Vision框架。详细列表可见\url{http://elinux.org/Jetson_TK1#Tutorials_for_developing_with_Jetson_TK1}
同时,近些年深度学习多种框架出现,TK1也在不同程度上支持这些框架,这些在上面的网址中可能没有详细说明,具体请见本文档后续的内容。
\chapter{开箱与GUI系统安装}
\section{开箱使用}
首先,连接好电源和显示器、鼠标等外设之后,按电源键进入命令行界面进行带GUI的系统的安装过程。
也就是Linux的Ubuntu发行版。可以看到,屏幕上有相关提示:
\begin{figure}[h]
\centering
\includegraphics[width=5.5in]{2.jpg}
\caption{第一次使用时的命令行界面}
\end{figure}
进入安装目录
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
cd NVIDIA-INSTALLER
\end{lstlisting}}
运行安装脚本
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
sudo ./installer.sh
\end{lstlisting}}
按提示输入密码,都是\warn{ubuntu}
安装完成之后,重启机器
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
sudo reboot
\end{lstlisting}}
至此,开箱的第一步工作已经完成,可以看到,现在已经可以进入Ubuntu系统了。
\begin{figure}[h]
\centering
\includegraphics[width=5.5in]{3.jpg}
\caption{Ubuntu系统桌面}
\end{figure}
\section{配置远程连接}
暂未完成
\chapter{CUDA的安装}
\section{下载并安装CUDA包}
Jetson TK1支持NVIDIA CUDA,不过暂时仍旧只对低版本支持较好,高版本的支持情况可以等待本文档的后续更新。
下载安装包:\url{https://developer.nvidia.com/cuda-toolkit-60}
如图所示,应该选择对应的CUDA版本,由于TK的出厂时间较早,支持的比较好的版本是6.0,而且要选择\warn{Linux for Tegra}这个版本。
\begin{figure}[h]
\centering
\includegraphics[width=5.5in]{4.png}
\caption{CUDA6release界面}
\end{figure}
下载后可以见到deb包
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
ls
cuda-repo-l4t-r19.2_6.0-42_armhf.deb
\end{lstlisting}}
安装deb包
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
sudo apt-get update
sudo dpkg -i xxx.deb
\end{lstlisting}}
安装samples和toolkit
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
sudo apt-get install cuda-samples-6-0
sudo apt-get install cuda-toolkit-6-0
\end{lstlisting}}
设置当前用户下可以访问GPU
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
sudo usermod -a -G video ubuntu
\end{lstlisting}}
\warn{修改环境变量}
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
vim ~/.bashrc
\end{lstlisting}}
在后面加上
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
# Add CUDA bin and lib path
export PATH=/usr/local/cuda-6.0/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-6.0/lib:$LD_LIBRARY_PATH
\end{lstlisting}}
更新bashrc
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
source .bashrc
\end{lstlisting}}
检查是否安装正常
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
nvcc -V
\end{lstlisting}}
如图所示即为安装完成。
\begin{figure}[h]
\centering
\includegraphics[width=4in]{5.png}
\caption{CUDA安装完成}
\end{figure}
\pagebreak
\section{编译与运行例程}
进入cuda目录并查看当前目录中是否有samples
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
cd /usr/local/cuda
ls
\end{lstlisting}}
\begin{figure}[h]
\centering
\includegraphics[width=6in]{6.png}
\caption{目录文件}
\end{figure}
将samples拷贝到所需要的目录
\info{cuda-install-samples-6.0.sh}是bin下面的文件,应该已经添加到PATH环境变量,不需要绝对路径即可运行,如果不能运行,请检查是否添加了环境变量。
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
cuda-install-samples-6.0.sh /home/ubuntu/
\end{lstlisting}}
回到主目录下查看
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
cd
ls
\end{lstlisting}}
如果有名为
\info{NVIDIA\_CUDA-6.0\_Samples}
的文件夹拷贝samples就完成了。
下面我们编译CUDA的samples
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
cd NVIDIA_CUDA-6.0_Samples
make
\end{lstlisting}}
编译完成之后我们可以在
{\setmainfont{Courier New Bold} ./bin/armv7l/linux/release/gnueabihf}
找到编译好的文件
一下是运行某些例程的截图,可以自行探索。
\begin{figure*}[h]
\centering
\begin{subfigure}[h!]{0.5\textwidth}
\centering
\includegraphics[height=1.8in]{8.png}
\caption{sample截图1}
\end{subfigure}%
~
\begin{subfigure}[h!]{0.5\textwidth}
\centering
\includegraphics[height=1.8in]{9.png}
\caption{sample截图2}
\end{subfigure}
\caption{例程截图}
\end{figure*}
\chapter{安装OpenCV}
\section{OpenCV下载}
首先注册NVIDIA的开发者账号\url{https://developer.nvidia.com}
下载OpenCV,下载地址:\url{https://developer.nvidia.com/linux-tegra-rel-19}
选择如下两个安装包,下载
\begin{figure}[h]
\centering
\includegraphics[width=6in]{10.png}
\caption{OpenCV TK1所需优化包}
\end{figure}
下载OpenCV源码,此处下载的版本虽然不是2.4.8但是仍可以编译通过,建议尽量选择与之匹配的版本,2.4.9即可。
直接从下面的网址下载即可,如果速度较慢建议通过带有VPN的机器下载完成后拷贝到TK1中。
可以点此下载:
\href{http://downloads.sourceforge.net/project/opencvlibrary/opencv-unix/2.4.9/opencv-2.4.9.zip}{OpenCV2.4.9下载}
也可以选择如下的命令行方式:
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
wget http://downloads.sourceforge.net/project/opencvlibrary/\
opencv-unix/2.4.9/opencv-2.4.9.zip
\end{lstlisting}}
完成后可以看到如下的文件,表明下载完成
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
libopencv4tegra_2.4.8.2_armhf.deb
libopencv4tegra-dev_2.4.8.2_armhf.deb
opencv-2.4.9.zip
\end{lstlisting}}
\section{安装OpenCV依赖}
首先更新源,并且安装OpenCV的若干依赖库。需要注意的是,这些库并非必须,全部安装可以支持较多格式,请根据需要进行安装。
必须安装的用MUST标出。
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
sudo apt-get update
# MUST Some general development libraries
sudo apt-get install build-essential -y
sudo apt-get install make cmake cmake-curses-gui g++ git -y
# MUST Required libraries
sudo apt-get install libgtk2.0-dev pkg-config -y
sudo apt-get libavcodec-dev libavformat-dev libswscale-dev -y
# Python libraries
sudo apt-get install python-dev python-numpy -y
# Other dependent libraries
sudo apt-get libavutil-dev libv4l-dev libeigen3-dev -y
sudo apt-get libglew1.6-dev libtbb2 libtbb-dev libjpeg-dev -y
sudo apt-get libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev -y
\end{lstlisting}}
接下来安装之前下载的两个deb包
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
sudo dpkg -i libopencv4tegra_2.4.8.2_armhf.deb
sudo dpkg -i libopencv4tegra-dev_2.4.8.2_armhf.deb
\end{lstlisting}}
\section{源码编译OpenCV}
首先解压缩OpenCV的源代码,然后建立编译需要的build目录。
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
unzip opencv-2.4.9.zip
cd ~/opencv-2.4.9
mkdir build
cd build
\end{lstlisting}}
接下来我们可以查看cmake的编译选项:
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
ccmake ..
\end{lstlisting}}
需要注意的是,查看是否有CUDA支持,是否有Python支持。
\begin{figure}[h]
\centering
\includegraphics[width=5.5in]{11.png}
\caption{ccmake编译选项的可视化显示}
\end{figure}
编译并安装OpenCV
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
sudo make -j4
sudo make install
\end{lstlisting}}
若能如图所示,表示OpenCV的Python支持安装成功。
\begin{figure}[h]
\centering
\includegraphics[width=5.5in]{12.png}
\caption{Python显示OpenCV版本}
\end{figure}
如果想测试GPU支持,可以到如下目录运行samples
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
cd ~/opencv-2.4.9/samples/gpu
./hog --video 768x576.avi
\end{lstlisting}}
至此,OpenCV安装成功!
\chapter{YOLO Draknet编译}
\section{编译安装Darknet}
首先拉取repo,然后进行编译
\warn{此处的编译仅针对CPU版本,支持CUDA的GPU编译方式注意下一小节内容}
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
git clone https://github.com/pjreddie/darknet.git
cd darknet
make
\end{lstlisting}}
等待编译完成之后尝试运行
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
./darknet
\end{lstlisting}}
应该得到如下的输出
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
usage: ./darknet <function>
\end{lstlisting}}
至此,YOLO Darknet编译安装完成。
\section{支持CUDA的编译}
尽管YOLO Darknet已经有较快的物体检测速度,但是使用GPU可以得到数十倍甚至近百倍的速度加成,下面介绍如何在编译时支持CUDA。
需要修改Makefile文件,有以下几点需要注意。
将原来的Makefile
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=make]
GPU=0
...
OPENCV=0
...
ARCH= -gencode arch=compute_20,code=[sm_20,sm_21] \
-gencode arch=compute_30,code=sm_30 \
-gencode arch=compute_35,code=sm_35 \
-gencode arch=compute_50,code=[sm_50,compute_50] \
-gencode arch=compute_52,code=[sm_52,compute_52]
...
LDFLAGS+= -L/usr/local/cuda/lib64 -lcuda -lcudart -lcublas -lcurand
\end{lstlisting}}
改为支持CUDA的编译选项
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=make]
GPU=1
...
OPENCV=1
...
ARCH= -gencode arch=compute_20,code=compute_20
...
LDFLAGS+= -L/usr/local/cuda/lib -lcuda -lcudart -lcublas -lcurand
\end{lstlisting}}
\section{测试安装结果}
测试一下GPU的支持以及OpenCV的支持
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
# Test OpenCV
./darknet imtest data/eagle.jpg
# Test GPU
wget http://pjreddie.com/media/files/yolo.weights
./darknet -i 0 detect cfg/yolo.cfg yolo.weights data/dog.jpg
\end{lstlisting}}
如下图可以认为Draknet也安装成功。
\begin{figure*}[h]
\centering
\begin{subfigure}[h!]{0.5\textwidth}
\centering
\includegraphics[height=1.8in]{13.png}
\caption{Darknet OpenCV测试}
\end{subfigure}%
~
\begin{subfigure}[h!]{0.5\textwidth}
\centering
\includegraphics[height=1.8in]{14.png}
\caption{Darknet GPU测试}
\end{subfigure}
\caption{Darknet运行结果截图}
\end{figure*}
\chapter{NVIDIA tk1 实际工程项目实践}
\section{使用YOLO并结合摄像头实现image/video object detection}
YOLO算法使用的darknet模型框架只依赖CUDA,可以直接在tk1上运行。
对于网络权重的训练部分在服务器端进行,tk1上直接进行测试。
对于源码分析一下:
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=c]
void run_yolo(int argc, char **argv)
{
char *prefix = find_char_arg(argc, argv, "-prefix", 0);
float thresh = find_float_arg(argc, argv, "-thresh", .2);
int cam_index = find_int_arg(argc, argv, "-c", 0);
int frame_skip = find_int_arg(argc, argv, "-s", 0);
if(argc < 4){
fprintf(stderr, "usage: %s %s [train/test/valid] \
[cfg] [weights (optional)]\n", argv[0], argv[1]);
return;
}
char *cfg = argv[3];
char *weights = (argc > 4) ? argv[4] : 0;
char *filename = (argc > 5) ? argv[5]: 0;
if(0==strcmp(argv[2], "test"))
test_yolo(cfg, weights, filename, thresh);
else if(0==strcmp(argv[2], "train"))
train_yolo(cfg, weights);
else if(0==strcmp(argv[2], "valid"))
validate_yolo(cfg, weights);
else if(0==strcmp(argv[2], "recall"))
validate_yolo_recall(cfg, weights);
else if(0==strcmp(argv[2], "demo"))
demo(cfg, weights, thresh, cam_index, \
filename, voc_names, 20, frame_skip, prefix);
}
\end{lstlisting}}
通过分析上面的代码,在运行YOLO的时候,如果是图片,就应该选择test作为参数;
如果是视频的格式,就选择demo作为视频的参数,并且要注意传入摄像头的编号。
\subsection{yolo模型介绍}
% 这里简单介绍YOLO
\subsubsection{模型思想}
YOLO的核心思想就是利用整张图作为网络的输入,直接在输出层回归bounding box的位置和bounding box所属的类别。
faster RCNN中也直接用整张图作为输入,但是faster-RCNN整体还是采用了RCNN那种 proposal+classifier的思想,只不过是将提取proposal的步骤放在CNN中实现了。
具体采用的实现方法:
将一幅图像分成SxS个网格(grid cell),如果某个object的中心 落在这个网格中,则这个网格就负责预测这个object。
每个网格要预测B个bounding box,每个bounding box除了要回归自身的位置之外,还要附带预测一个confidence值。
这个confidence代表了所预测的box中含有object的置信度和这个box预测的有多准两重信息,其值是这样计算的:
$$Pr(Object)*IOU^{truth}_{predict}$$
其中如果有object落在一个grid cell里,第一项取1,否则取0。 第二项是预测的bounding box和实际的groundtruth之间的IoU值。
每个bounding box要预测(x, y, w, h)和confidence共5个值,每个网格还要预测一个类别信息,记为C类。则SxS个网格,每个网格要预测B个bounding box还要预测C个categories。输出就是S x S x (5*B+C)的一个tensor。
注意:class信息是针对每个网格的,confidence信息是针对每个bounding box的。
在PASCAL VOC数据集中,图像输入为448x448,取S=7,B=2,一共有20个类别(C=20)。则输出就是7x7x30的一个tensor。
在test的时候,每个网格预测的class信息和bounding box预测的confidence信息相乘,就得到每个bounding box的class-specific confidence score:
$$Pr(Class_i|Object)*Pr(Object)*IOU^{truth}_{predict}=Pr(Class_i)*IOU^{truth}_{predict}$$
等式左边第一项就是每个网格预测的类别信息,第二三项就是每个bounding box预测的confidence。这个乘积即encode了预测的box属于某一类的概率,也有该box准确度的信息。
得到每个box的class-specific confidence score以后,设置阈值,滤掉得分低的boxes,对保留的boxes进行NMS处理,就得到最终的检测结果。
\subsubsection{损失函数的设计}
在实现中,最主要的就是怎么设计损失函数,让这个三个方面得到很好的平衡。作者简单粗暴的全部采用了sum-squared error loss来做这件事。
这种做法存在以下几个问题:
\begin{enumerate}
\item 8维的localization error和20维的classification error同等重要显然是不合理的;
\item 如果一个网格中没有object(一幅图中这种网格很多),那么就会将这些网格中的box的confidence push到0,相比于较少的有object的网格,这种做法是overpowering的,这会导致网络不稳定甚至发散。
\end{enumerate}
解决办法:
更重视8维的坐标预测,给这些损失前面赋予更大的loss weight, 记为在pascal VOC训练中取5。
对没有object的box的confidence loss,赋予小的loss weight,记为在pascal VOC训练中取0.5。
有object的box的confidence loss和类别的loss的loss weight正常取1。
对不同大小的box预测中,相比于大box预测偏一点,小box预测偏一点肯定更不能被忍受的。而sum-square error loss中对同样的偏移loss是一样。
为了缓和这个问题,作者用了一个比较取巧的办法,就是将box的width和height取平方根代替原本的height和width。
最后的损失函数:
\begin{multline}
\lambda_{coord}\sum_{i=0}^{S^2}\sum_{j=0}^{B}\mathbbm{1}^{obj}_{ij}[(x_i-\hat{x_i})^{2}+(y_i-\hat{y_i})^{2}]\\
+\lambda_{coord}\sum_{i=0}^{S^2}\sum_{j=0}^{B}\mathbbm{1}^{obj}_{ij}[(\sqrt{w_i}-\sqrt{\hat{w_i}})^{2}\\
+(\sqrt{h_i}-\sqrt{\hat{h_i}})^{2}]+\sum_{i=0}^{S^2}\sum_{j=0}^{B}\mathbbm{1}^{obj}_{ij}(C_i-\hat{C_i})^{2}\\
+\lambda_{noobj}\sum_{i=0}^{S^2}\sum_{j=0}^{B}\mathbbm{1}^{noobj}_{ij}(C_i-\hat{C_i})^{2}+\sum_{i=0}^{S^2}\mathbbm{1}^{obj}_{i}\sum_{c \in classes}(p_i(c)-\hat{p_i}(c))^2
\nonumber
\end{multline}
\subsubsection{模型缺点}
\begin{enumerate}
\item YOLO对相互靠的很近的物体,还有很小的群体 检测效果不好,这是因为一个网格中只预测了两个框,并且只属于一类。
\item 对测试图像中,同一类物体出现的新的不常见的长宽比和其他情况是。泛化能力偏弱。
\item 由于损失函数的问题,定位误差是影响检测效果的主要原因。尤其是大小物体的处理上,还有待加强。
\end{enumerate}
\subsubsection{网络结构}
下面是YOLO算法使用的网络模型的结构:
\begin{figure}[h]
\centering
\includegraphics[width=5.5in]{15.png}
\caption{YOLO的网络结构模型}
\end{figure}
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
layer filters size input output
0 conv 32 3 x 3 / 1 416 x 416 x 3 -> 416 x 416 x 32
1 max 2 x 2 / 2 416 x 416 x 32 -> 208 x 208 x 32
2 conv 64 3 x 3 / 1 208 x 208 x 32 -> 208 x 208 x 64
3 max 2 x 2 / 2 208 x 208 x 64 -> 104 x 104 x 64
4 conv 128 3 x 3 / 1 104 x 104 x 64 -> 104 x 104 x 128
5 conv 64 1 x 1 / 1 104 x 104 x 128 -> 104 x 104 x 64
6 conv 128 3 x 3 / 1 104 x 104 x 64 -> 104 x 104 x 128
7 max 2 x 2 / 2 104 x 104 x 128 -> 52 x 52 x 128
8 conv 256 3 x 3 / 1 52 x 52 x 128 -> 52 x 52 x 256
9 conv 128 1 x 1 / 1 52 x 52 x 256 -> 52 x 52 x 128
10 conv 256 3 x 3 / 1 52 x 52 x 128 -> 52 x 52 x 256
11 max 2 x 2 / 2 52 x 52 x 256 -> 26 x 26 x 256
12 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512
13 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256
14 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512
15 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256
16 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512
17 max 2 x 2 / 2 26 x 26 x 512 -> 13 x 13 x 512
18 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024
19 conv 512 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 512
20 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024
21 conv 512 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 512
22 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024
23 conv 1024 3 x 3 / 1 13 x 13 x1024 -> 13 x 13 x1024
24 conv 1024 3 x 3 / 1 13 x 13 x1024 -> 13 x 13 x1024
25 route 16
26 reorg / 2 26 x 26 x 512 -> 13 x 13 x2048
27 route 26 24
28 conv 1024 3 x 3 / 1 13 x 13 x3072 -> 13 x 13 x1024
29 conv 425 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 425
30 detection
\end{lstlisting}}
\subsection{可选的tiny-yolo模型}
由于YOLO模型相对于tk1的计算能力来说还是比较庞大,所以可以选用更小但是速度更快的tiny-YOLO来实现video级别的物体检测。
当然这样做的代价是牺牲了准确度。
% 这里展示tiny yolo
\subsection{Image object detection}
对于图片,参数选择是test,调用\info{test\_yolo}
函数。对于图片测试,只需要运行下面的命令即可。
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
./darknet detector test cfg/coco.data cfg/yolo.cfg yolo.weights <image path>
\end{lstlisting}}
\subsection{Video object detection}
对于视频,实时进行object detection,需要调用的是
\info{demo}
函数。需要传入待分析的视频文件或者camera的number。
tk1并不自带摄像头,好在可以使用USB摄像头,无需任何驱动,直接可用。传入的num是0。
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
./darknet detector demo cfg/coco.data cfg/yolo.cfg yolo.weights -c <num>
\end{lstlisting}}
或者可以传入一个视频文件,YOLO会将object detection的结果实时输出。
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=bash]
./darknet detector demo cfg/coco.data cfg/yolo.cfg yolo.weights <video file>
\end{lstlisting}}
\section{基于OpenCV和HOG特征的行人检测}
\subsection{HOG检测原理}
HOG特征描述子(HOG descriptors)是由Navneet Dalal和 Bill Triggs在2005年的一篇介绍行人检测方法的论文提到的特征描述子。
HOG属于特征提取,它统计梯度直方图特征。具体来说就是将梯度方向(0->360°)划分为9个区间,将图像化为16x16的若干个block,每个block在化为4个cell(8x8)。对每一个cell,算出每一点的梯度方向和模,按梯度方向增加对应bin的值,最终综合N个cell的梯度直方图形成一个高维描述子向量。实际实现的时候会有各种插值。
选用的分类器是经典的SVM。检测框架为经典的滑动窗口法,即在位置空间和尺度空间遍历搜索检测。
\subsection{HOG检测代码}
利用安装好的OpenCV2,我们调用其中的api,写一个用于行人图片检测程序。
从命令行读入图片的路径,使用HOG来进行特征检测,最后输出行人位置的bounding box。
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=python]
from __future__ import print_function
import numpy as np
import cv2
def inside(r, q):
rx, ry, rw, rh = r
qx, qy, qw, qh = q
return rx > qx and ry > qy and rx + rw < qx + qw and ry + rh < qy + qh
def draw_detections(img, rects, thickness = 1):
for x, y, w, h in rects:
# the HOG detector returns slightly larger rectangles
# than the real objects.
# so we slightly shrink the rectangles to get a nicer output.
pad_w, pad_h = int(0.15*w), int(0.05*h)
cv2.rectangle(img, (x+pad_w, y+pad_h),
(x+w-pad_w, y+h-pad_h), (0, 255, 0), thickness)
if __name__ == '__main__':
import sys
from glob import glob
import itertools as it
print(__doc__)
hog = cv2.HOGDescriptor()
hog.setSVMDetector( cv2.HOGDescriptor_getDefaultPeopleDetector() )
default = ['./data/1.jpg '] if len(sys.argv[1:]) == 0 else []
for fn in it.chain(*map(glob, default + sys.argv[1:])):
print(fn, ' - ',)
try:
img = cv2.imread(fn)
if img is None:
print('Failed to load image file:', fn)
continue
except:
print('loading error')
continue
found, w = hog.detectMultiScale(img, winStride=(8,8),
padding=(32,32), scale=1.05)
found_filtered = []
for ri, r in enumerate(found):
for qi, q in enumerate(found):
if ri != qi and inside(r, q):
break
else:
found_filtered.append(r)
draw_detections(img, found)
draw_detections(img, found_filtered, 3)
print('%d (%d) found' % (len(found_filtered), len(found)))
cv2.imshow('img', img)
ch = cv2.waitKey()
if ch == 27:
break
cv2.destroyAllWindows()
\end{lstlisting}}
\subsection{行人检测的运行于结果评测}
\begin{figure*}[h]
\centering
\begin{subfigure}[h!]{0.5\textwidth}
\centering
\includegraphics[height=2in]{16.png}
\caption{测试图1}
\end{subfigure}%
~
\begin{subfigure}[h!]{0.5\textwidth}
\centering
\includegraphics[height=2in]{17.png}
\caption{测试图2}
\end{subfigure}
\caption{OpenCV行人检测运行结果截图}
\end{figure*}
通过上述的图片的测试结果,在tk1上运行的基于HOG特征利用OpenCV框架的行人检测的效果较好,能够对图片中的行人进行检测。
但是也应当看出如果是背影的行人的检测效果不佳,对于过大或者过小的目标的检测效果也有待提高。
对于HOG这种基于图像特征提取的shallow模型来说达到这种效果已经是比较令人满意了。
由于OpenCV封装的HOG特征提取的效率较高,在tk1这种嵌入式设备上也有较好的效果。
\section{基于OpenCV的 face detection}
OpenCV框架的人脸检测是基于Haar特征提取的。这里我们先暂时不分析Haar特征提取的原理,单纯看一下如何利用OpenCV进行人脸的检测。
\subsection{人脸检测的代码}
{\setmainfont{Courier New Bold} % 设置代码字体
\begin{lstlisting}[language=python]
#!/usr/bin/python
import sys
import cv2.cv as cv
from optparse import OptionParser
min_size = (20, 20)
image_scale = 2
haar_scale = 1.2
min_neighbors = 2
haar_flags = 0
def detect_and_draw(img, cascade):
# allocate temporary images
gray = cv.CreateImage((img.width,img.height), 8, 1)
small_img = cv.CreateImage((cv.Round(img.width / image_scale),
cv.Round (img.height / image_scale)), 8, 1)
# convert color input image to grayscale
cv.CvtColor(img, gray, cv.CV_BGR2GRAY)
# scale input image for faster processing
cv.Resize(gray, small_img, cv.CV_INTER_LINEAR)
cv.EqualizeHist(small_img, small_img)
if(cascade):
t = cv.GetTickCount()
faces = cv.HaarDetectObjects(small_img, cascade, cv.CreateMemStorage(0),
haar_scale, min_neighbors, haar_flags, min_size)
t = cv.GetTickCount() - t
print "detection time = %gms" % (t/(cv.GetTickFrequency()*1000.))
if faces:
for ((x, y, w, h), n) in faces:
# the input to cv.HaarDetectObjects was resized, so scale the
# bounding box of each face and convert it to two CvPoints
pt1 = (int(x * image_scale), int(y * image_scale))
pt2 = (int((x + w) * image_scale), int((y + h) * image_scale))
cv.Rectangle(img, pt1, pt2, cv.RGB(255, 0, 0), 3, 8, 0)
cv.ShowImage("result", img)
if __name__ == '__main__':
parser = OptionParser(usage = "usage: %prog [options] \
[filename|camera_index]")
parser.add_option("-c", "--cascade", action="store", dest="cascade",
type="str", help="Haar cascade file, default %default",
default = "../data/haarcascades/haarcascade_frontalface_alt.xml")
(options, args) = parser.parse_args()
cascade = cv.Load(options.cascade)
if len(args) != 1:
parser.print_help()
sys.exit(1)
input_name = args[0]
if input_name.isdigit():
capture = cv.CreateCameraCapture(int(input_name))
else:
capture = None
cv.NamedWindow("result", 1)
if capture:
frame_copy = None
while True:
frame = cv.QueryFrame(capture)
if not frame:
cv.WaitKey(0)
break
if not frame_copy:
frame_copy = cv.CreateImage((frame.width,frame.height),
cv.IPL_DEPTH_8U, frame.nChannels)
if frame.origin == cv.IPL_ORIGIN_TL:
cv.Copy(frame, frame_copy)
else:
cv.Flip(frame, frame_copy, 0)
detect_and_draw(frame_copy, cascade)
if cv.WaitKey(10) >= 0:
break
else:
image = cv.LoadImage(input_name, 1)
detect_and_draw(image, cascade)
cv.WaitKey(0)
cv.DestroyWindow("result")
\end{lstlisting}}
\subsection{人脸检测的结果}
\begin{figure}[h]
\centering
\includegraphics[width=5.5in]{18.png}
\caption{基于Haar特征的人脸检测}
\end{figure}
检测的结果还是比较好的,但是基于Haar的特征提取器对于较小和角度不太好的人脸的检测效果一般,有待提升。
\end{document}