REFERENCE

1. prepare_data

  • 데이터 다운로드 등의 기능을 수행할 메서드.
  • setup 전에 호출 됨.
  • main process + single process니까 device 별 실행 되야하는 기능은 해당 메서드에서 구현을 피해야 함.
  • DO NOT set state to the model (use setup instead) since this is NOT called on every device
    (e.g. self.split='train')

2. setup


 

아래처럼 깔끔하게 사용할 수도 있지만, Dataset등의 내부 멤버 변수가 필요하면 수동으로 콜해도 문제 없다.

dm = MNISTDataModule()
model = Model()
trainer.fit(model, datamodule=dm)
trainer.test(datamodule=dm)
trainer.validate(datamodule=dm)
trainer.predict(datamodule=dm)
dm = MNISTDataModule()
dm.prepare_data()
dm.setup(stage="fit")

model = Model(num_classes=dm.num_classes, width=dm.width, vocab=dm.vocab)
trainer.fit(model, dm)

dm.setup(stage="test")
trainer.test(datamodule=dm)

 

Save

torch.save(model.state_dict(), PATH)

보통 torch.save를 사용해서 pytorch model을 저장하는데 이때 보통 .pt, .pth의 확장자를 쓴다. 그러나 .pth의 경우 python path와 충돌 위험이 있기때문에 .pt 확장자를 사용하는 것을 추천한다. 

Save for resume

torch.save({
            'epoch': epoch,
            'model_state_dict': model.state_dict(),
            'optimizer_state_dict': optimizer.state_dict(),
            'loss': loss,
            ...
            }, PATH)

일반적으로 모델을 저장할 때 학습 재개(resuming)를 위해 모델 파라미터 뿐만 아니라 optimizer, loss, epoch, scheduler등 다양한 정보를 함께 저장한다. 그래서 이러한 checkpoint는 모델만 저장할 때에 비해서 용량이 훨씬 커진다. 이럴때는 .tar 확장자를 사용한다. 나는 주로 .pth.tar를 사용한다.

To save multiple components, organize them in a dictionary and use torch.save() to serialize the dictionary. A common PyTorch convention is to save these checkpoints using the .tar file extension.

reference

'Deep Learning > pytorch' 카테고리의 다른 글

torch.backends.cudnn.benchmark = True 의미  (0) 2021.08.23
[Pytorch] yolo to pytorch(0)  (0) 2021.05.17

예전에 vscode-ssh로 서버에 연결하려고 할 때, XHR failed가 뜨면서 문제가 됐던적이있다.

검색해보니 DNS문제 등등 다양한 문제가 있었는데 내 경우는 서버가 인터넷에 연결이 안되어있어서 필요한 vscode-server를 다운받지 못하는 문제인것으로 예상했다.

그래서 정말 다양한 방법을 시도해봤는데 결국 포기했다가 아래 링크를 찾았다. 

https://stackoverflow.com/questions/56671520/how-can-i-install-vscode-server-in-linux-offline

ssh 연결할때 뜨는 커밋 아이디가 있는데

위 이슈에 있는 링크에서 해당 커밋아이디의 파일을 다운받고

~/.vscode-server/bin/(commid id) 폴더에 해당 파일은 unzip하니 해결됐다

디테일한 명령어는 위 링크대로 따라했고 연결에 성공했다.

거의 일주일간의 삽질을 위 방법으로 해결할 수 있었다.

'Deep Learning > 기타' 카테고리의 다른 글

coco label items  (0) 2021.08.11
Darknet validationset 학습 포함 여부  (0) 2021.07.29

개인적으로 읽고 쓰는 공부용 리뷰입니다.

틀린 점이 있을 수도 있으니 감안하고 읽어주세요. 피드백은 댓글로 부탁드립니다.

[TensorRT] 1. Build tensorrt engine (tensorRT 7.2.3)


Serializie는 나중에 재사용을 위해 저장하기위한 포맷으로 바꾸는 것을 의미한다. inference에 사용하기 위해서는 그냥 deserializie한 뒤 쓰면 된다. 보통 빌드과정이 시간을 소요하기 때문에 매번 빌드하는 것을 피하기 위해 이 과정을 한다.

// code for serializing ICudaEngine
IHostMemory *serializedModel = engine->serialize();
// store model to disk
// <…>
 serializedModel->destroy();

-

Deserialize code, The final argument is a plugin layer factory for applications using custom layers. For more information, see [Extending TensorRT With Custom Layers]
별거아니고, 마지막에 nullptr는 iplugin for custom layer인데 없다면 그냥 nullptr넣으면 된다.

// code for deserializing ICudaEngine
IRuntime* runtime = createInferRuntime(gLogger);
ICudaEngine* engine = runtime->deserializeCudaEngine(modelData, modelSize, nullptr)

주의 할점은 trt version, gpu, platform을 항시 잘 체크해야한다.

  • Serialized engines are not portable across platforms or TensorRT versions.
  • Engines are specific to the exact GPU model they were built on.

 

위에는 tensorrt reference의 코드인데 처음에보고 어떻게 더 추가해야할지 몰라서 막막했다.
아래는 실제로 내가 사용하는 serializing & save 코드다.

여기서 engine_ 은 빌드가 성공적으로 된 ICudaEngine이다.

bool saveEngine( std::string &fileName ) const 
{
    std::ofstream engineFile( fileName, std::ios::binary );
    if ( !engineFile ) {
        gLogFatal << "Cannot open engine file : " << fileName << std::endl;
        return false;
    }

    if ( engine_ == nullptr ) {
        gLogError << "Engine is not defined" << std::endl;
        return false;
    }
    nvinfer1::IHostMemory *serializedEngine{engine_->serialize()};
    if ( serializedEngine == nullptr ) {
        gLogError << "Engine serialization failed" << std::endl;
        return false;
    }

    engineFile.write( static_cast<char *>( serializedEngine->data() ),
                      serializedEngine->size() );
    if ( engineFile.fail() ) {
        gLogError << "Failed to save Engine." << std::endl;
        return false;
    }
    std::cout << "Successfully save to : " << fileName << std::endl;
    return true;
}

 

다음은 저장된 ICudaEngine을 load후 다시 deserializing하는 코드다. 

bool Load( const std::string &fileName ) {
    std::ifstream engineFile( fileName, std::ios::binary );
    if ( !engineFile ) {
        std::cout << "can not open file : " << fileName << std::endl;
        return false;
    }
    engineFile.seekg( 0, engineFile.end );
    auto fsize = engineFile.tellg();
    engineFile.seekg( 0, engineFile.beg );

    std::vector<char> engineData( fsize );
    engineFile.read( engineData.data(), fsize );

    Load( engineData.data(), ( long int )fsize );
    return true;
}

bool Load( const void *engineData, const long int fsize ) {
    nvinfer1::IRuntime *runtime = nvinfer1::createInferRuntime( gLogger.getTRTLogger() );
    engine_ = runtime->deserializeCudaEngine( engineData, fsize, nullptr );
    // if u want DLA core setting, then u shoud write code here
    runtime->destroy();
    return true;
}

두가지 방법으로 load할수있어서 오버로딩해놨다.

끝 

'Deep Learning > tensorrt' 카테고리의 다른 글

[TensorRT] 1. Build tensorrt engine (tensorRT 7.2.3)  (6) 2021.03.24

의미 그대로 cudnn의 benchmark를 통해 최적의 backend 연산을 찾는 flag를 true로 하겠단 의미.

CNN에서 대부분의 연산을 차지하는 convolution의 경우, 아래 사진의(출처의 두번째 링크) 지원하는 연산 중 최적의 알고리즘을 찾아 적용한다.

cf) 확실한 것은 아니지만 아마 이 벤치마크는 모델이 상수처럼 작동할 때 최적의 연산을 찾을 수 있을 것이다. 예를 들어서 입력크기가 고정되어 모델이 static하게 작동한다면 이 flag가 유효하겠지만, 
입력크기가 다양하거나 또는 dynamic한 연산이 모델의 fowarding에 포함된 경우는 큰 효과를 보지 못할 수도 있을 것같다. 

출처 : https://discuss.pytorch.org/t/why-does-winograd-algorithm-speedup-convolution-given-that-mul-and-add-cost-the-same-clock-cycles-on-gpu/89993/4

https://docs.nvidia.com/deeplearning/cudnn/developer-guide/index.html#tensor-ops-conv-functions-supported-algos

https://discuss.pytorch.org/t/what-does-torch-backends-cudnn-benchmark-do/5936

 

'Deep Learning > pytorch' 카테고리의 다른 글

[pytorch] save pytorch model  (0) 2021.09.15
[Pytorch] yolo to pytorch(0)  (0) 2021.05.17

coco label 얻기

ids = list(sorted(coco.imgs.keys()))
coco_idx = [ids[idx]]  # from index to coco_index
coco.loadAnns(self.coco.getAnnIds(coco_idx))

아래처럼 object별로 7개의 key값을 가짐

segmentation은 annotation type이 두개가있다.
segmentation1 : list[float], polygon 좌표 xy인데 flatten시켰다. 
segmentation2 :  a run-length-encoded (RLE) bit mask 
    'counts' :
    'size'     :

area : 객체 안에 속한 pixel 수

iscrowd :  0 또는 1, 1이면 정확도 측정할 때 제외함 

image_id : 현재 객체가 속한 image의 index, 그래서 같은 이미지에 있는 객체들은 값이 같음. (82783: coco2014train)

bbox : bounding box 좌표, 좌상단xy wh로 구성되어있으며 normalizing 안되어있음

category_id : ojbect의 class index 총 80개며 1~90사이의 값을 가짐

id : 각 object에 대한 id인데 어떻게 라벨링 되는지는 모르겠음.

 

아 category_id가 좀 다를 것이다 0~79의 80개 class가 아니라 1~90으로 나온다. 몇개 삭제된 클래스가 있다. 아래 tuple써서 치환(?)하면 됨
(255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 255, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 255, 24, 25, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 255, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 255, 60, 255, 255, 61, 255, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 255, 73, 74, 75, 76, 77, 78, 79)

 

https://github.com/cocodataset/cocoapi/issues/184

https://github.com/facebookresearch/Detectron/issues/100

https://www.immersivelimit.com/tutorials/create-coco-annotations-from-scratch

https://www.youtube.com/watch?v=h6s61a_pqfM 

 

'Deep Learning > 기타' 카테고리의 다른 글

vscode에서 서버 연결할 때, XHR failed  (0) 2021.08.26
Darknet validationset 학습 포함 여부  (0) 2021.07.29

 

링크 : darknet pretrained weights with MS-COCO detection dataset

틈틈히 작업하던 yolo to pytorch가 완성단계라 위 링크 weights들의 정확도를 재생산하는 것을 통해 검증하려고 하는데 validationset에 대한 결과가 이상하리만큼 높게 나오는 것을 발견했다.

yolov4 같은 겨우 width=608 height=608 in cfg: 65.7% mAP@0.5 (43.5% AP@0.5:0.95)  라고 적혀 있는데 (testset기준) 

coco 2017 validationset(5k)로 직접 evaluation 했더니

 Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.500
 Average Precision  (AP) @[ IoU=0.50       | area=   all | maxDets=100 ] = 0.741

 

이 나왔다. 위 결과는 testset(40k)일테니 낮은건 이해하지만 유난히 높게 나왔다는 생각이 들어 조금 알아봤다.

 

왜 유난히 높다라는 생각이 들었냐면, 후속논문인 sclaed yolov4 에서 validationset을 통해 측정을 한 결과가 다음과 같다. yolov4-P5경우 896x896 이미지를 사용했는데 51.7 / 70.3 (아래 테이블 참조)이다. 따라서 위에서 yolov4로 돌린 결과가 이상하다고 볼 수 있다. 

 

첫번째로 yolov4를 학습할 때, validationset이 포함됐나?를 떠올렸다. 그러면 높은 결과가 이해가 되니까.

그러나 darknet 위키를 찾은결과 학습에는 분명히 validation 5k를 제외하고 학습이 되었다. 정말 이상해서 더 자료를 찾다가 원하는 내용의 issue를 찾았다.

The custom splits (trainvalno5k.txt and 5k.txt) for COCO 2014 are supposed to be the same as the default splits for COCO 2017 but they are not. This could explain why YOLOv4 does not produce the same validation results on both but a significantly better mAP on val2017. Also, this implies YOLO may be trained on a different training set compared with other object detectors. Then a direct comparison might not be fair. Any clarifications?

즉 coco2017과 darknet에서 쓰는 split (train, val, test)가 다르다. 이것은 trainset이 다르단 소리고 결과가 불공정하지않냐? 라는 질문이다.

그러면서 coco2014와 2017의 차이점도 친절하게 official에서 긁어놨다.

The only difference is the splits which COCO 2017 adopts as the long-ime convention from COCO 2014 in early object detection work. The detectron repo explicitly describes the COCO Minival Annotations (5k) as follows:

Our custom minival and valminusminival annotations are available for download here. Please note that minival is exactly equivalent to the recently defined 2017 val set. Similarly, the union of valminusminival and the 2014 train is exactly equivalent to the 2017 train set.

즉 2014와 2017은 이미지가 전혀 바뀐게 없고 split만 바꼈다는 것인데 다음과 같다. (valminusminival의 존재를 처음 앎;)

COCO_2017_train = COCO_2014_train + valminusminival 
COCO_2017_val = minival

거기에 대한 답은 이렇다.

- testset은 같다.
- validation이 다르지만 결국엔 똑같은 장수를 validation으로 뺐고 test는 같으니 결과는 문제없다!.
심지어 우리는 최종 weight에 5k를 빼고학습했으니 오히려 마이너스 요소가 될 수 있다. 가 답변이다.

왜 다른 split을 쓰는지는 나도 모르겠지만, test로 성능측정하려면 서버에 결과제출해야해서 귀찮은데..하 아무튼 이런 이슈가 존재한다. 

'Deep Learning > 기타' 카테고리의 다른 글

vscode에서 서버 연결할 때, XHR failed  (0) 2021.08.26
coco label items  (0) 2021.08.11

darknet은 하나의 딥러닝 framework로 볼 수 있는데, 대표적으로 darknet18,53등의 classification 모델을 포함한 yolov3 for detection등의 모델 등이 있다.
나는 pytorch를 주로 쓰는데, 위에 언급한 모델들은 darknet이라는 c++계열의 framework를 쓴다. 그래서 나는 이걸 파이토치로 옮겨오는 방법을 많이 고민했고 그 동안 고민했던 그 흔적들을 정리해보려고한다.
어.. cfg 파일이 뭐니 weight파일이 뭐니 이러한 기초적인 설명은 다 건너 뛸거다. 왜냐면 이글은 공유보다 내 개인적인 기록이 목적인 용도니까.
맨 처음은 당연히 cfg파일을 파싱하는 부분이다.
다크넷의; cfg파일을 보면 각 레이어는 '[' ']' 두 기호로 대표적인 역할을 구분하고 있고, 그 이후로 기타 세부적인 옵션들을 정의하고있다. 그래서 아래 코드는 cfg파일에서 [] 두 기호를 토대로 레이어를 구분하고, 그 옵션들은 저장하는 코드이다.

cfg conv layer 예시
def parse_cfg(self, cfgfile): ''' cfgfile : cfgfile path, e.g. ./cfg/yolov3.cfg return : list of blocks. each block describes a block in the neural network to be built. ''' print(f"parse from '{cfgfile}'") fp = open(cfgfile, 'r') lines = fp.readlines() fp.close() lines = [line.strip() for line in lines if line.strip()] # 공백 제거 lines = [line for line in lines if line[0] != '#'] # 주석 제거 blocks = [] block = {} for line in lines: if line[0] == '[': if block: blocks.append(block) block = {} block["type"] = line[1:-1] if block['type'] == 'convolutional': block['batch_normalize'] = 0 else: key, value = line.split('=') block[key.rstrip()] = value.lstrip() blocks.append(block) print("done", end="\n\n") return blocks[0], blocks[1:]

맨 마지막에 block0 과 그 이후를 구분하는 이유는 모든 다크넷 cfg는 맨처음에 [net]으로 미니배치가 얼마인지, 입력 height widht가 얼마인지등을 정의해놓는데 이것을 구분하기 위함이다.
self 키워드가 있는것을 보아 이미 클래스 내부 함수인 것을 알겠지만 사실 외부 함수로 짜도 그만이라, 아무튼

클래스 내에서 위처럼 짜면 1단계는 완성이다.
이 다음에는 저 block(list())를 통해서 어떻게 pytorch 에서 forwarding을 구성하는지를 구성하겠다.
늘 말하지만, 언제 업로드 될진 모른다.

'Deep Learning > pytorch' 카테고리의 다른 글

[pytorch] save pytorch model  (0) 2021.09.15
torch.backends.cudnn.benchmark = True 의미  (0) 2021.08.23

개인적으로 읽고 쓰는 공부용 리뷰입니다.

틀린 점이 있을 수도 있으니 감안하고 읽어주세요. 피드백은 댓글로 부탁드립니다.

paper overview

  • 논문링크 : paper link
  • fully convolutional network 
  • encoding & decoding

2015 CVPR에 나온 논문으로([Submitted on 14 Nov 2014 (v1), last revised 8 Mar 2015 (this version, v2)]), 2021년인 지금 깊게 공부하기엔 매우 올드하지만, 이 논문은 semantic segmentation의 초석을 닦은 연구라고 생각하기때문에, 한번쯤은 짚고 갈 필요가 매우 있다고 생각한다. 이 논문의 핵심은 semantic segmentation과 fully convolution이다.  semantic segmentation은 일반적인 classification과 유사하지만 결과물만 다르다. 이미지 전체를 토대로 classification을 하는 것이 아닌 픽셀단위로 classification을 하는 것이다. imagnet dataset을 예시로 들어보자면 classification 네트워크의 경우 ouput shape가 n x 1000 이라면 segmentation의 경우라면 ouput shape가 입력과 크기가 똑같은  N x H x W x 1000이 될 것 이다. 물론 imagenet으로는 학습 못한다. segmentation용으로 레이블링 된 데이터가 없으므로.

저 그림은 voc dataset이다. 그리고 이 데이터셋은 클래스가 21개다. 그렇기 때문에 위 그림의 아웃풋의 채널이 21인 것이다. pixelwise prediction 전까지는 classification downsampling과정이랑 같다. 그러나 그 뒤에 아웃풋의 shape가 다르다. 이 차이점이다. 보통 feature를 뽑아내는 과정을 encoding이라고 하고, 이 후에 이미지 크기로 다시 복원하는 과정을 decoding이라고 한다. 위 그림에는 이 디코딩 과정이 생략된 것이다. 그리고 이 모든 과정을 convolution layer로만 네트워크를 구축했다. 그래서 논문 이름이 fully convolutional network인 것이다. 보통 classification은 마지막에 fully connected layer(fcl)이 붙는데 fcl은 고정된 크기의 인풋을 요구한다. 근데 이게 사라졌으니까, 이론적으로는 크기에 불변이다. ㅋㅋ 근데 stride가 1/2씩 떨어지고 보통 1/32까지 떨구기때문에 입력 이미지의 크기는 32의 배수로 한다. ( 아니어도 되는데 fowarding 맞추기가 귀찮다.) 

figure 2의 위쪽은 classification을 의미한다. 이 과정이 semantic segmentation으로 포함되면 아래 부분처럼 heatmap형식으로 나타나는 것을 보여주는 figure다. 

figure 3는 fcn의 전체적인 플로우다. 전체적으로 encoding 과정은 전체적으로 VGG와 같다. 풀링레이어는 풀1에서 풀5까지 다섯개의 레이어가 있다. 각각 1/2씩 해상도가 떨어져서 1/32까지 떨어진다. 컨브6,7은 기존의 fcl을 컨볼루션으로 대체한 것이다. 32x 16x 8x 4x 2x 얘네들은 upsample layer로, transposed conv를 의미한다. feature map이 겹쳐져 있는부분은 덧셈을 의미한다. 

pool5 만 사용한것이 fcn32. pool5+ pool4가 fcn 16, pool5,4,3다 쓴것이 fcn8이다 fcn뒤에 붙은것은 아웃풋 피쳐맵의 누적 스트라이드라고 생각하면 된다. 

네트워크의 stride가 커지면 더 complex한 feature를 학습할수는 있지만 spatial information이 사라지기 마련이다. fcn은 이것을 앞쪽의 feature map을 inference에서 활용하는 쪽으로 방향을 잡았고, 많은 이 후 논문들이 이러한 방식을 택하고 있다. 따라서 결과 이미지로보나 수치로보나 fcn8s가 제일 좋다. 

개인적으로 읽고 쓰는 공부용 리뷰입니다.

틀린 점이 있을 수도 있으니 감안하고 읽어주세요. 피드백은 댓글로 부탁드립니다.

본래는 0. Install tensorrt 부터 하고싶었는데 아.. 설치과정은 굳이 리뷰하기 귀찮다
그리고 어차피 이걸 누가 주의깊게 읽을거라고 생각안한다.
원래 논문도 매주 하나씩 리뷰하려고 했는데 이게 상당히 시간을 요하는 작업이라 이게 이후에 이어질지는 사실 나도 잘 모르겠다.
아무튼 이번에 쓰는 포스트는 어떤 과정을 통해 내가 학습한 모델이 tensorrt 모델로 변환이 되는지 정리하려고 한다.
아래는 레퍼런스다.
https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/#create_network_c
https://docs.nvidia.com/deeplearning/tensorrt/api/c_api/index.html
eehoeskrap.tistory.com/
레퍼런스를 먼저 말하는 이유는 위에 링크를 안보고는 바로 이해하기 힘들 것 같아서이다. 세번째에 링크된 꾸준희님 블로그는 관련된 포스트가 많다. 그리고 내가 쓰는 글에 비해 훨씬 나을 것 이다.
아무튼, nvidia에서는 빠른 속도를 위해 다양한 프레임워크에서 학습된 custom model들을 gpu에 최적화 시켜주는 라이브러리를 제공하는데 이게 tensorrt다. 결론만 말하자면, tensorrt(이하 trt)의 목적은 빠른 inference 속도를 위한 것이다.
이 과정이 처음에 접하기에는 굉장히 복잡하다.
다시 본 내용으로 와서 나는 pytorch, tensorflow 또는 caffe 등 다양한 framework를 통해 딥러닝 모델을 학습을 시킨다. 그리고 nvidia에서 만든 이 tensorrt는 이러한 모델을 parsing하는 기능을 제공하며, gpu에 최적화시켜 보다 빠른 추론속도를 가능케해주는 라이브러리다. 좋다. 단순히 trtexec를 써도되지만, 좀더 깊게 내가 직접 빌드할때가 분명히 있을것 이다. 그리고 100% 나처럼 무조건 다 직접 이해하고 짜야만 직성이 풀리는 사람도 있을 것이다. 삽질을 좋아하는 사람.
그리고 더좋은건 c++ 과 python 두 언어에 대한 api를 제공한다. pytorch를 사용하는 입장에서, 당연히 python api를 사용하고 싶지만, 그럴여건이 되지 않을 때도 있다. 이 포스트는 c++ 뉴비인(나 포함) 사람들에게 혹시나 도움이 될까 쓰는 개인 저장용 포스트다.(참고로 python api는 window를 지원하지않는다)
이 포스트를 보기전에 상단의 레퍼런스 첫번째 링크 적어도 2.1은 정독하는걸 매우 추천한다.
trt에서 custom model을 trt engine으로 빌드하는 과정은 다음과 같은 과정을 거친다. 이 과정의 목적은 tensorrt에서 사용하는 ICudaEngine을 만드는 것이다. 그리고 이 아래로 bold 처리된 것은 모두 클래스다.
1. create IBuilder by using createInferBuilder with Logger.(logger는 trt sample code에 있는거 사용 추천)
2. create IBuilderConfig by using IBuilder::createBuilderConfig().
3. define IBuilderConfig options. ex) fp16, int8, dla etc..
4. create INetworkDefinition by using IBuilder::createNetworkV2().
5. create proper IParser for defining INetworkDefinition.
6. define INetworkDefinition by using IParser::parse
7. call IBuilder::buildEngineWithConfig() with pre-defined INetworkDefinition & IBuilderConfig
8. save or run ICudaEngine with IExecutionContext
대충 흐름이 파악됐다면, 이제 천천히 한단계씩 보면 된다.

1. create IBuilder by using createInferBuilder with Logger

IBuilderICudaEngine을 만들기 위한 이런저것들을 정의할 클래스다.
auto builder = UniquePtr<IBuilder>(createInferBuilder(gLogger.getTRTLogger()));
대충 이런식으로 만든다 UniquePtr은 내가만든 포인터 형식인데 그냥 아래처럼 쓰면된다. 효율적인 포인터 사용을 위해 nvidia코드를 베낀것이다. 아무튼 여기까진 쉽다.
IBuilder* builder = nvinfer1::createInferBuilder(gLogger.getTRTLogger());
레퍼런스에 있는 예시처럼 (아래) 간단하게 만들어도 되지만, 그냥 sample코드에있는 logger.h, logging.h, 등등을 복붙해서 사용하는 것을 추천한다.
class Logger : public ILogger
{
void log(Severity severity, const char* msg) override
{
// suppress info-level messages
if (severity != Severity::kINFO)
std::cout << msg << std::endl;
}
} gLogger;

2. create IBuilderConfig by using IBuilder::createBuilderConfig().

auto config = UniquePtr<IBuilderConfig>( builder->createBuilderConfig() );
IBuilder를 만들었으면 위처럼 builderconfig를 만든다. 이글을 볼때쯤엔 다알겠지만 trt engine을 빌드할때, fp16(half), int8 등의 옵션을 쓰며 build할 수 있다. 이러한 옵션을 IBuilderConfig가 정의한다. 자세한건 다음에 블로깅될 포스트 또는 레퍼런스를 참고하면된다. 참고로 dla를 쓸지안쓸지도 이 클래스로 정의한다.

3. define IBuilderConfig options. ex) fp16, int8, dla etc..

2번에서 에서 얘기했다

4. create INetworkDefinition by using IBuilder::createNetworkV2().

auto network = UniquePtr<INetworkDefinition>(builder->createNetworkV2(explicitBatch));
위처럼 만든다. 뭐냐면 그냥 내 커스텀 모델의 네트워크 정보들을 담는 변수다. 이 변수를 만드는 과정이다.

5. create proper IParser for defining INetworkDefinition.

INetworkDefinition을 정의하기위해선 적절한 parser를 사용해야한다. 당연히 trt자체로 parser를 제공한다. 세가지 parser를 제공한다. caffer, uff, onnx. IParser는 다음처럼 만들면 된다. 간단하다.
auto parser = nvonnxparser::createParser(*network, gLogger);
auto parser = nvcaffeparser1::createCaffeParser();
auto parser = nvuffparser::createUffParser();

6. define INetworkDefinition by using IParser::parse

IParser를 만들었으면 IParser::parse()를 통해 내 INetworkDefinition을 정의하면된다. IParser::parse()를 이용하면 된다.
아마 직접 코드를 짜서 빌드를한다면 99.9%여기에서 에러가 날것이다. 지원하지 않는 레이어도 많고 연산도 많다. 해결 방법은 두가지다. 지원하는 레이어로만 구성해서 원하는 결과가 나오도록 모델을 구성하던가, 직접 커스텀 레이어를 짜던가. 후자는 나중에 포스팅이 될것이다 언젠간.

7. call IBuilder::buildEngineWithConfig() with pre-defined INetworkDefinition & IBuilderConfig
아무튼 이제 INetworkDefinitionIBuilderConfig를 정의했을것이다. 그럼 이제 빌드만 하면 된다. 아래처럼 IBuilder::createBuilderConfig()를 호출하면된다.
mEngine = shared_ptr<ICudaEngine>(
builder->buildEngineWithConfig( *network, *config ), InferDeleter() );
return 값이 ICudaEngine이다.




끝이다.

이제 이 결과 값으로 inference를 하면 된다. 저장을하던가. 근데 저장하려면 serealizing이 필요하다. 나중에 포스팅하겠다.
그리고 중요한건 이 아웃풋 엔진은 gpu에 최적화과 되어있는 상태다. 즉 내가 지금 이 과정까지 gtx 1080 에서 했다면 gtx titan에서 못쓴다. 가능하긴 하지만 비추천한다. 관련 officail 링크다. docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html#troubleshooting

+ Recent posts