웬디의 기묘한 이야기

글 작성자: WENDYS
반응형

젯슨 나노의 설치 및 샘플 동작이 궁금하신 분들은 아래 링크에서 먼저 보고오셔도 좋습니다.

 

https://wendys.tistory.com/143

 

[AI] 젯슨 나노(Jetson Nano) darknet YOLO v3 설치 및 샘플 돌려보기

젯슨 나노 (jetson nano) darknet 신경망 오픈소스 프로젝트 YOLO v3 설치하기 https://pjreddie.com/darknet/ Darknet: Open Source Neural Networks in C Nightmare Use Darknet's black magic to conjure ghost..

wendys.tistory.com

 

젯슨 나노의 기본 동작은 확인해봤다면 이제 입맛에 맞게 응용을 해서 사용을 하고 싶은 마음이 들게 됩니다.

소스 코드 분석시 필요한 코드를 찾는 능력도 중요하지만 필요한 코드를 찾기위해선 YOLO같은 콘솔 응용프로그램에서는 main부터 찾아가는게 편하기때문에 main code 위치를 알려드리겠습니다.

 

그렇다면 이제 darknet YOLO v3 소스를 마음껏 뜯어고칠 수 있도록 소스를 찾아가 봅시다.

 

https://pjreddie.com/media/files/papers/YOLOv3.pdf

 

darknet/Makefile

darknet을 다운받은 경로로 가서 Makefile을 확인하여 main이 포함되어있는 소스코드를 확인할 수 있으며, 그 외에도 빌드 옵션들의 설정을 변경하거나 확인할 수 있습니다.

GPU=1
CUDNN=1
CUDNN_HALF=0
OPENCV=1
AVX=0
OPENMP=0
LIBSO=0
ZED_CAMERA=0

...

VPATH=./src/
EXEC=darknet
OBJDIR=./obj/

ifeq ($(LIBSO), 1)
LIBNAMESO=libdarknet.so
APPNAMESO=uselib
endif

CC=gcc
CPP=g++
NVCC=nvcc
OPTS=-Ofast
LDFLAGS= -lm -pthread
COMMON= -Iinclude/ -I3rdparty/stb/include
CFLAGS=-Wall -Wfatal-errors -Wno-unused-result -Wno-unknown-pragmas -fPIC
...

 

Value Description
VPATH=./src/ 소스파일 경로는 ./src/로 정의되어있다.
EXEC=darknet main source file 이름은 darknet.c 이다.
OBJDIR=./obj/ build시 생성되는 object 파일들은 해당 경로에 출력된다.

 

위에서 확인할 수 있듯이 EXEC=darknet임을 확인하여 ./src/darknet.c파일에 main함수가 존재한다는 것을 알 수 있습니다. 만약 다른 곳으로 이동하더라도 Makefile 정보를 이용하여 main source file을 찾으면 됩니다.

 

darknet/src/darknet.c

main source code를 보면 알 수 있는 점 중 하나는 다양한 명령어에 의해 실제로 어떻게 동작하는지를 따라가 볼 수 있게 됩니다.

 

int main(int argc, char **argv)
{
#ifdef _DEBUG
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif

	int i;
	for (i = 0; i < argc; ++i) {
		if (!argv[i]) continue;
		strip_args(argv[i]);
	}

    //test_resize("data/bad.jpg");
    //test_box();
    //test_convolutional_layer();
    if(argc < 2){
        fprintf(stderr, "usage: %s <function>\n", argv[0]);
        return 0;
    }
    gpu_index = find_int_arg(argc, argv, "-i", 0);
    if(find_arg(argc, argv, "-nogpu")) {
        gpu_index = -1;
        printf("\n Currently Darknet doesn't support -nogpu flag. If you want to use CPU - please compile Darknet with GPU=0 in the Makefile, or compile darknet_no_gpu.sln on Windows.\n");
        exit(-1);
    }

#ifndef GPU
    gpu_index = -1;
#else
    if(gpu_index >= 0){
        cuda_set_device(gpu_index);
        CHECK_CUDA(cudaSetDeviceFlags(cudaDeviceScheduleBlockingSync));
    }
#endif

    if (0 == strcmp(argv[1], "average")){
        average(argc, argv);
    } else if (0 == strcmp(argv[1], "yolo")){
        run_yolo(argc, argv);
    } else if (0 == strcmp(argv[1], "voxel")){
        run_voxel(argc, argv);
    } else if (0 == strcmp(argv[1], "super")){
        run_super(argc, argv);
    } else if (0 == strcmp(argv[1], "detector")){
        run_detector(argc, argv);
    } else if (0 == strcmp(argv[1], "detect")){
        float thresh = find_float_arg(argc, argv, "-thresh", .24);
		int ext_output = find_arg(argc, argv, "-ext_output");
        char *filename = (argc > 4) ? argv[4]: 0;
        test_detector("cfg/coco.data", argv[2], argv[3], filename, thresh, 0.5, 0, ext_output, 0, NULL, 0);
    } else if (0 == strcmp(argv[1], "cifar")){
        run_cifar(argc, argv);
    } else if (0 == strcmp(argv[1], "go")){
        run_go(argc, argv);
    } else if (0 == strcmp(argv[1], "rnn")){
        run_char_rnn(argc, argv);
    } else if (0 == strcmp(argv[1], "vid")){
        run_vid_rnn(argc, argv);
    } else if (0 == strcmp(argv[1], "coco")){
        run_coco(argc, argv);
    } else if (0 == strcmp(argv[1], "classify")){
        predict_classifier("cfg/imagenet1k.data", argv[2], argv[3], argv[4], 5);
    } else if (0 == strcmp(argv[1], "classifier")){
        run_classifier(argc, argv);
    } else if (0 == strcmp(argv[1], "art")){
        run_art(argc, argv);
    } else if (0 == strcmp(argv[1], "tag")){
        run_tag(argc, argv);
    } else if (0 == strcmp(argv[1], "compare")){
        run_compare(argc, argv);
    } else if (0 == strcmp(argv[1], "dice")){
        run_dice(argc, argv);
    } else if (0 == strcmp(argv[1], "writing")){
        run_writing(argc, argv);
    } else if (0 == strcmp(argv[1], "3d")){
        composite_3d(argv[2], argv[3], argv[4], (argc > 5) ? atof(argv[5]) : 0);
    } else if (0 == strcmp(argv[1], "test")){
        test_resize(argv[2]);
    } else if (0 == strcmp(argv[1], "captcha")){
        run_captcha(argc, argv);
    } else if (0 == strcmp(argv[1], "nightmare")){
        run_nightmare(argc, argv);
    } else if (0 == strcmp(argv[1], "rgbgr")){
        rgbgr_net(argv[2], argv[3], argv[4]);
    } else if (0 == strcmp(argv[1], "reset")){
        reset_normalize_net(argv[2], argv[3], argv[4]);
    } else if (0 == strcmp(argv[1], "denormalize")){
        denormalize_net(argv[2], argv[3], argv[4]);
    } else if (0 == strcmp(argv[1], "statistics")){
        statistics_net(argv[2], argv[3]);
    } else if (0 == strcmp(argv[1], "normalize")){
        normalize_net(argv[2], argv[3], argv[4]);
    } else if (0 == strcmp(argv[1], "rescale")){
        rescale_net(argv[2], argv[3], argv[4]);
    } else if (0 == strcmp(argv[1], "ops")){
        operations(argv[2]);
    } else if (0 == strcmp(argv[1], "speed")){
        speed(argv[2], (argc > 3 && argv[3]) ? atoi(argv[3]) : 0);
    } else if (0 == strcmp(argv[1], "oneoff")){
        oneoff(argv[2], argv[3], argv[4]);
    } else if (0 == strcmp(argv[1], "partial")){
        partial(argv[2], argv[3], argv[4], atoi(argv[5]));
    } else if (0 == strcmp(argv[1], "average")){
        average(argc, argv);
    } else if (0 == strcmp(argv[1], "visualize")){
        visualize(argv[2], (argc > 3) ? argv[3] : 0);
    } else if (0 == strcmp(argv[1], "imtest")){
        test_resize(argv[2]);
    } else {
        fprintf(stderr, "Not an option: %s\n", argv[1]);
    }
    return 0;
}

기본 샘플에 보게 되면 detect, detector를 이용한 명령어를 가장 많이 볼 수 있게 되며, 그 외에도 이렇게나 많은 명령어들이 존재하고 있습니다.

 

darknet YOLO detect, detector 무슨 차이?

darknet yolo sample을 돌려봤을 때 사용했던 명령어는 바로 detect입니다.

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg

그렇다면 detect와 detector 과연 무슨 차이가 있을까요??

 

Command Description
detect 단일 이미지, 또는 멀티 이미지 등에서 물체를 인식할 때 사용
detector 웹캠, 비디오 등 동영상에서 물체를 인식할 때 사용

 

약간의 차이점이 존재하네요

그리고 코드에서 보면 알 수 있듯이 detect 명령어를 사용할 때는 조건을 추가할 수 있게 됩니다.

        float thresh = find_float_arg(argc, argv, "-thresh", .24);
		int ext_output = find_arg(argc, argv, "-ext_output");
        char *filename = (argc > 4) ? argv[4]: 0;
        test_detector("cfg/coco.data", argv[2], argv[3], filename, thresh, 0.5, 0, ext_output, 0, NULL, 0);

 

Command Description
-thresh

YOLO v3의 임계치를 조정할 수 있습니다.

원래 YOLO는 25% 이상인 물체만 표시를 하게 되는데, 해당 옵션을 이용하여 0% 이상인 모든 물체를 표시하게 하거나, 50% 이상의 물체만 탐지를 하는 등의 설정이 가능합니다.

-ext_output

결과에 대해 상세한 정보를 표시하는 옵션

 

이런 명령어들의 사용법은 darknet 공식 홈페이지를 통해서도 알 수 있지만 현재 개발이 활발하게 진행 중인 AlexeyAB 링크에서 확인하는 게 좋습니다. 저는 AlexeyAB의 darknet 소스를 이용하고 있습니다.

 

https://github.com/AlexeyAB/darknet

 

AlexeyAB/darknet

Windows and Linux version of Darknet Yolo v3 & v2 Neural Networks for object detection (Tensor Cores are used) - AlexeyAB/darknet

github.com

더 다양한 명령어들은 직접 분석해보도록 합니다 :)

반응형