Ubuntu, Linux에서 압축하기 / 압축풀기

 

우분투나 리눅스 계열에서 주로 사용되는 gzip, tar, zip 커맨드를 정리하였다.

 

압축


tar 압축

tar -cvf <압축파일명.tar> <대상파일>

// EXAMPLE
tar -cvf abc.tar abc

 

tar.gz 압축

 

tar -zcvf <압축파일명.tar.gz> <대상파일>

// EXAMPLE
tar -zcvf abc.tar.gz abc

 

zip 압축

 

zip <압축파일.zip> <대상파일>

// EXAMPLE1 : 현재 디렉토리를 aaa.zip으로 압축
zip abc.zip ./*

// EXAMPLE2 : 현재 디렉토리 및 하위 디렉토리까지 모두 압축
zip abc.zip -r ./*

 

압축 풀기


 

tar 압축 풀기

tar -xvf <압축파일명.tar>

// EXAMPLE
tar -xvf abc.tar

 

tar.gz 압축 풀기

 

tar -zxvf <압축파일명.tar.gz>
// EXAMPLE
tar -zxvf abc.tar.gz

 

zip 압축 풀기

 

unzip <압축파일.zip>

// EXAMPLE1 : 현재 디렉토리에 압축 해제
unzip abc.zip

// EXAMPLE2 : 특정 디렉토리에 압축 해제
unzip abc.zip -d <경로>

 

 

 

 

출처:

cryptosalamander.tistory.com/99

 

'Linux_Ubuntu' 카테고리의 다른 글

프로세스 생성  (0) 2021.06.17
ubuntu 한글 설정  (0) 2021.06.15
ps 명령어 사용법  (0) 2021.06.11
VI Editor 사용법  (0) 2021.06.11
Ubuntu 18.04 설치 및 환경 셋팅 (RTX 3090, 2080) 및 기타 Tips  (0) 2021.06.11

게시 순서가 조금 이상하지만 AlexNet에 대해 리뷰하겠습니다.

 

AlexNet의 구조

일단 AlexNet이 나올 시기에는 GPU가 현재 GPU만큼 좋지 못했습니다.

그래서 논문 저자들은 많은 데이터를 다루기 위해서 2개의 GPU를 사용했습니다.

논문에 나와있는 빨간색 박스 부분이 이해가 가지 않아 github 검색중 위와 같은 형태로

모델을 구성한 코드를 발견할 수 있었습니다.

 

 

아래의 github를 참고삼아 나름대로 정리를 해보았습니다.

논문에서 공유한다는 의미를 concat과 split를 이용하였습니다.

 

참고 자료: https://github.com/demul/AlexNet/blob/master/model.py

 

 

ReLU

본 논문에서는 ReLU를 사용하여 sigmoid나 tanh보다 성능을 높였다고 나와있습니다.

ReLU는 0 미만의 값은 0으로 수렴하고, 0 이상의 값은 f(x) = x 로 수렴하게 됩니다.

ReLU의 문제점을 해결하기 위해 LeakyReLU 와 같은 Activation도 나왔으니 시간이 되면 정리를 해보겠습니다.

 

 

Local Response Normalization (LRN)

LRN은 현재는 잘 사용되지 않고 있는 방법으로 알고 있습니다.

위와 같은 식으로 이루어져 있고 자세한 정보를 얻고 싶다면 아래의 링크를 이용하는것이 좋아보입니다.

 

참고자료: 

https://towardsdatascience.com/difference-between-local-response-normalization-and-batch-normalization-272308c034ac

 

 

Overfitting

AlexNet에서는 Overfitting을 예방하기 위해 Data Augmentation과 Dropout을 이용했다고 나와있습니다.

 

 

 

 

 

Code

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

31_ResNext  (0) 2022.04.08
25_Pytorch_GoogLeNet 1x1 Convolution  (0) 2022.03.15
27_Pytorch_Custom_Dataset  (0) 2021.12.02
23_Pytorch_EfficientNet  (0) 2021.11.24
26_Pytorch_Inception-v2, v3 (미완)  (0) 2021.10.25

32, 32, 3 : 불러온 image 크기

저장하기

vector<uint8_t> input_test(32 * 32 * 3);

memcpy(input_test.data(), img.data, 32 * 32 * 3);

ofstream ofs("PATH/FILENAME", ios::binary);
if (ofs.is_open())
ofs.write((const char*)input_test.data(), input_test.size() * sizeof(uint8_t));
ofs.close();

 

불러오기

vector<float> img(1*14*512);

ifstream ifs("PATH/FILENAME", ios::binary);
if (ifs.is_open()) {
	ifs.read((char*)img.data(), img.size() * sizeof(float));
}
else {
	printf("There are no file. hr \n");
}
ifs.close();

'Language > C++' 카테고리의 다른 글

시간 측정  (0) 2023.03.16
C++ 시간 재기  (0) 2022.03.14
opencv vector to Mat  (0) 2021.12.23
Image to Base64, Base64 to Image  (0) 2021.11.18
파일 랜덤 추출  (0) 2021.10.14

TensorRT는 많은 종류의 layer들을 지원하고 지속적으로 확장하고 있습니다.

하지만 지원하는 layer가 특정한 상황에 맞지 않을 수도 있습니다.

그렇기 때문에 TensorRT는 Custom layer를 만들 수 있고 이를 위해 plugin을 제공합니다.

 

plugin에는 위와 같이 3종류가 있고 각각의 특성이 있습니다.

plugin을 사용하기 위해서는 PluginCreator를 사용하면 됩니다.

PluginCreator안에는 Name, Version, plugin field prameters 가 들어 있습니다.

Custom layer를 만들기 위해서는 libnvinfer_plugin.so library가 있어야 합니다.

 

 

 


IPluginV2 내부 함수 살펴보기

plugin layer를 연결하고 input, output data의 구조를 셋팅하는 IPluginV2 입니다.

IPluginV2 에는 굉장히 많은 함수가 있습니다.

Custom layer를 만들때 대부분의 method들은 모두 공통적으로 사용됩니다.

 

https://docs.nvidia.com/deeplearning/tensorrt/api/c_api/classnvinfer1_1_1_i_plugin_v2_i_o_ext.html#a9168d66dfaf07ccfdd058d49a25b3c9a

 

TensorRT: nvinfer1::IPluginV2IOExt Class Reference

Plugin class for user-implemented layers. Plugins are a mechanism for applications to implement custom layers. This interface provides additional capabilities to the IPluginV2Ext interface by extending different I/O data types and tensor formats. See alsoI

docs.nvidia.com

위는 공식 사이트에서 제공하는 docs로서 함수들이 설명되어 있는 사이트 입니다.

사이트를 토대로 간단하게 정리해보았습니다.

아래에 이상하거나 틀린 내용 있으면 댓글 부탁드립니다. ㅠ

 

 

 

⊙  getNbOutputs

    - 원본 : Get the number of outputs from the layer.

    - output tensor의 개수.

 

 

⊙  getOutputDimensions ☆

    - 원본 : Get the dimension of an output tensor.

    - output tensor의 차원.

 

 

⊙ supportsFormat   ,   supportsFormatCombination

    - 원본 : Check format support.

    - plugin에서 data type을 지원하는지에 대한 bool값

 

 

⊙  getOutputDataType

    - 원본 : Return the DataType of the plugin output at the requested index.

    - output의 data type을 반환해 줍니다.

 

 

⊙  configurePlugin

    - 원본 : Configure the layer with input and output data types.

    - layer들의 input, output의 data type을 구성합니다.

 

 

⊙  initialize ☆

    - 원본 : Initialize the layer for execution. This is called when the engine is created.

    - 실행을 위해 layer를 초기화 시켜줍니다.

    - engine이 생성될 때, 호출됩니다.

 

 

⊙  enqueue ☆

    - 원본 : Execute the layer.

    - layer를 실행시켜 줍니다.

 

 

⊙  terminate

    - 원본 : Release resources acquired during plugin layer initialization.

                This is called when the engine is destroyed.

    - 엔진을 더이상 사용하지 않을때 호출되고 엔진을 없애줍니다.

 

 

⊙  clone

    - 원본 : Clone the plugin object.

    - plugin을 복사해서 반환합니다.

 

 

⊙  destroy

    - 원본 : Destroy the plugin object. 

    - plugin object를 없애줍니다.

 

 

⊙  set / getPluginNamespace 

    - plugin의 name을 설정해주거나 가져옵니다.

 

 

⊙  canBroadcastInputAcrossBatch ???? 이건 무슨 소린지... 잘 모르겠다...

    - 원본 : Return true if plugin can use input that is broadcast across batch without replication.

    - plugin이 복제 없이 broadcast 되는 input을 사용할 수 있으면 True값을 반환합니다.

 

 

⊙  isOutputBroadcastAcrossBatch ???? 이건 무슨 소린지... 잘 모르겠다...

    - 원본 : Return true if output tensor is broadcast across a batch.

    - output tensor가 broadcast가 된다면  True를 반환합니다.

 

 


IPluginCreator 내부 함수 살펴보기

https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html#iplugincreator

 

Developer Guide :: NVIDIA Deep Learning TensorRT Documentation

The IConvolutionLayer computes a 2D (channel, height, and width) convolution or 3D (channel, depth, height, and width) convolution, with or without bias. Note: The operation that the IConvolutionLayer performs is actually a correlation. Therefore, it is a

docs.nvidia.com

위는 공식 사이트에서 제공하는 docs로서 함수들이 설명되어 있는 사이트 입니다.

사이트를 토대로 간단하게 정리해보았습니다.

아래에 이상하거나 틀린 내용 있으면 댓글 부탁드립니다. ㅠ

 

 

 

⊙  getPluginName

    - 원본 : Return the plugin name.

    - plugin의 이름을 반환.

 

 

⊙  getPluginVersion

    - 원본 : Return the plugin version.

    - plugin의 버전을 반환.

 

 

getFieldNames

    - 원본 : Return a list of fields that needs to be passed to createPlugin.

    - createPlugin을 만들기 위해 전달해야 하는 필드 리스트를 반환.

 

 

⊙  createPlugin

    - 원본 : Return a plugin object. Return nullptr in case of error.

    - plugin object를 반환하지만 error일 경우 nullptr을 반환합니다.

 

 

⊙  deserializePlugin

    - 원본 : It should return the plugin object to be used for inference.

    - 추론을 위한 plugin 객체를 반환.

 

 

⊙  set / getPluginNamespace

    - plugin creator의 namespace를 설정하거나 가져옵니다.

 

 

 


Custom layer 만들기

 

1. Plugin 만들어 주기

https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html#example4_add_custlay_int8

 

Developer Guide :: NVIDIA Deep Learning TensorRT Documentation

The IConvolutionLayer computes a 2D (channel, height, and width) convolution or 3D (channel, depth, height, and width) convolution, with or without bias. Note: The operation that the IConvolutionLayer performs is actually a correlation. Therefore, it is a

docs.nvidia.com

위의 공식 문서에서 제공해주는 Custom pooling layer의 예시를 기준으로 작성하겠습니다.

 

class PoolPlugin : public IPluginV2IOExt
{
    ...override virtual methods inherited from IPluginV2IOExt.
};

 

poolPlugin에서는

  • supportsFormatCombination
  • configurePlugin
  • enqueue

위의 세가지 method를 수정해주어야 합니다.

 

 

 


1. network에 Custom layer 추가하기

// Look up the plugin in the registry
IPluginV2 creator = getPluginRegistry()->getPluginCreator(pluginName, pluginVersion);
const PluginFieldCollection* pluginFC = creator->getFieldNames();

//populate the fields parameters for the plugin layer 
PluginFieldCollection *pluginData = parseAndFillFields(pluginFC, layerFields); 

//create the plugin object using the layerName and the plugin meta data
IPluginV2 *pluginObj = creator->createPlugin(layerName, pluginData);

//add the plugin to the TensorRT network 
IPluginV2Layer* layer = network.addPluginV2(&inputs[0], int(inputs.size()), pluginObj);
ITensor* data = layer.getOutput(0);
pluginObj->destroy() // Destroy the plugin object

 

 

 


 

 

 

 

※ 아래의 github는 공식 사이트에서 제공해주는 예시 코드들이며

Plugin을 만들때는 위에서 복사해서 사용하면 될것 같습니다.

https://github.com/NVIDIA/TensorRT/tree/main/plugin#tensorrt-plugins

 

GitHub - NVIDIA/TensorRT: TensorRT is a C++ library for high performance inference on NVIDIA GPUs and deep learning accelerators

TensorRT is a C++ library for high performance inference on NVIDIA GPUs and deep learning accelerators. - GitHub - NVIDIA/TensorRT: TensorRT is a C++ library for high performance inference on NVIDI...

github.com

 

 

※ TensorRT 공식 가이드 문서 : 

https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html#overview

https://github.com/NVIDIA/TensorRT/tree/main/plugin#tensorrt-plugins

 

※ 참고 자료:

https://seobway.tistory.com/entry/TensorRT-1-Build-tensorrt-engine-tensorRT-723?category=850806

 

※ 참고자료 : ONNX 변환 및 사용 - 갓꾸준희님

https://eehoeskrap.tistory.com/414

 

※ 참고 github - tensorRT 예제 코드 정리 잘되어 있음!

https://github.com/wang-xinyu/tensorrtx

 

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

06. TensorRT Resnet18  (0) 2023.03.21
05. TensorRT VGG  (0) 2023.03.11
02. TensorRT 다루기  (0) 2022.02.11
01. TensorRT 설치 및 다운로드  (0) 2022.02.11

TensorRT 공식 가이드 문서를 보며 작성하였습니다.

잘못된 점이 있다면 댓글 부탁드립니다.

 

TensorRT는 C++, Python API를 지원하지만

7.x.x 이하 버전에서 Python API는 Linux 환경만 지원하는 걸로 알고 있습니다. (불명확)

 

이 글은 C++ API 를 위주로 작성하겠습니다.

 

공식 가이드 문서상 TensorRT는 2단계로 작동합니다.

첫번째, Builder Phase : TensorRT에 Model Definition을 제공해주고 TensorRT가 GPU에 맞게 최적화를 진행합니다.

두번째, Runtime Phase : 최적화된 Model을 사용하면 됩니다!

 

그런데 말만 2단계지 더 많은것 같다...

 

 


1. Builder Phase

TensorRT에서의 Builder는 Model을 최적화 해주는 기능을 가지고 있으며,

Engine이라는 산출물을 Output으로 가집니다.

 

Build 내부 단계는 아래의 3단계입니다.

  1. Create network definition : network를 정의해줍니다.
  2. Specify a configuration for the builder : builder를 위한 환경을 명시해줍니다.
  3. Call the builder to create the engine : engine을 만들기 위해 builder를 사용합니다.

 

2. Runtime Phase

Runtim Phase는 아래의 2단계로 나뉘어 집니다.

  1. Deserialize a plan to create an engine : 생성된 엔진을 가져와서 사용합니다.
  2. Create an execution context from the engine : 자세히는 모르겠지만 가져온 엔진을 컨트롤...? 하는것 같다.

 

 

 

 


Builder Phase CODE

class Logger : public ILogger           
{
    void log(Severity severity, const char* msg) override
    {
        // suppress info-level messages
        if (severity <= Severity::kWARNING)
            std::cout << msg << std::endl;
    }
} logger;

builder를 만들기 위해서는 ILogger를 먼저 선언해줍니다.

 

 

 

IBuilder* builder = createInferBuilder(logger);

logger를 이용해 builder를 선언해줍니다.

 

 

 

IBuilderConfig* config = builder->createBuilderConfig();

config->setMaxWorkspaceSize(1U << 20);

그리고 builder의 config를 선언해줍니다.

여기서 config에는 많은 설정환경이 있고

그중에 setMaxWorkspaceSize는 Layer를 구축하는데 있어서 최대 Memory Size를 설정하는 옵션입니다.

 

 

 

uint32_t flag = 1U <<static_cast<uint32_t>
    (NetworkDefinitionCreationFlag::kEXPLICIT_BATCH) 

INetworkDefinition* network = builder->createNetworkV2(flag);

그 후 builder의 network를 선언해줍니다.

이제 network에 layer들을 정의 시켜줍니다.

 

 

 

#include “NvOnnxParser.h”

Using namespace nvonnxparser;

IParser*  parser = createParser(*network, logger);

parser->parseFromFile(modelFile, ILogger::Severity::kWARNING);
for (int32_t i = 0; i < parser.getNbErrors(); ++i)
{
	std::cout << parser->getError(i)->desc() << std::endl;
}

ONNX를 이용한다면 위와 같은 코드를 이용하면 됩니다.

직접 tensorRT로 layer를 구축하는 것은 다음 게시물에 게시하겠습니다.

 

 

 

IHostMemory*  serializedModel = builder->buildSerializedNetwork(*network, *config);

위에서 정의한 network와 config를 이용하여 engine을 build 및 serialize 해줍니다.

IHostMemory는 그냥 간단하게 handle이라고 생각하는게 맘편할거 같고...

 

여기서

1. builder->buildSerializeNetwork(*network, *config)

2. builder->buildEngineWithConfig(*network, *config)

두 종류의 함수를 사용할 수 있는데

 

 

 

2번 함수는 serialize를 제외하고 build만 적용하여

Output으로 ICudaEngine* 형식의 engine 을 반환하게 되고,

이 engine 을 저장하기 위해서는

IHostMemory* modelStream = engine->serialize();

serialize 한 후 저장을 진행해줍니다.

 

 

 

1번 함수는 엔진 생성 없이 build 및 serialize 해줍니다.

 

 

 

std::ofstream p("engine_name.engine", std::ios::binary);
if (!p) {
	std::cerr << "could not open plan output file" << std::endl;
	return -1;
}
p.write(reinterpret_cast<const char*>(serializedModel->data()), serializedModel->size());

위에서 생성된 serializedModel을 저장을 해줍니다.

build하는 과정에서 시간이 걸리므로 나중에 재사용하기 위해서는 engine 파일을 저장해두는 것이 좋습니다.

 

 

 

delete parser;
delete network;
delete config;
delete builder;
delete serializedModel

engine을 저장해줬으면 위에 선언했던 변수들을 delete 해줍니다.

 

 

 

 

 

 

 


Runtime Phase CODE

 

Build Phase 에서 ONNX를 통해 만들어준 engine을 사용해보겠습니다.

 

 

 

std::ifstream engineFile( fileName, std::ios::binary );
if ( !engineFile ) {
    std::cout << "can not open file : " << fileName << std::endl;
    return false;
}

먼저 저장된 engine 파일을 불러옵니다.

 

 

 

engineFile.seekg( 0, engineFile.end );
auto fsize = engineFile.tellg();
engineFile.seekg( 0, engineFile.beg );

불러온 engine 파일의 사이즈를 계산해주고 다시 파일의 시작부분으로 옮겨줍니다.

 

※ 참고사항

engineFile.seekg(A, B) → engineFile에서 B의 위치에서 A만큼의 위치

ex)

 - engineFile.seekg(0, engineFile.end) → engineFile의 끝에서 0만큼 이동한 위치

 - engineFile.seekg(0, engineFile.beg) → engineFile의 처음에서 0만큼 이동한 위치

 

 

 

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

그 후 engineFile 내부 데이터를 가져옵니다.

 

 

 

nvinfer1::IRuntime *runtime = nvinfer1::createInferRuntime( gLogger.getTRTLogger() );
engine_ = runtime->deserializeCudaEngine( engineData, fsize, nullptr );

마지막으로 engine을 deserialize하기 위해 IRuntime을 선언해주고 deserializeCudaEngine을 사용하면 됩니다.

 

 

 

 


Inference CODE

const char* INPUT_BLOB_NAME = "data";
const char* OUTPUT_BLOB_NAME = "prob";
void* buffers[2];

IExecutionContext *context = engine->createExecutionContext();
const int inputIndex = engine.getBindingIndex(INPUT_BLOB_NAME);
const int outputIndex = engine.getBindingIndex(OUTPUT_BLOB_NAME);

// Create GPU buffers on device
// GPU에 공간 할당을 해줍니다.
CHECK(cudaMalloc(&buffers[inputIndex], batchSize * 3 * INPUT_H * INPUT_W * sizeof(float)));
CHECK(cudaMalloc(&buffers[outputIndex], batchSize * OUTPUT_SIZE * sizeof(float)));

// Create stream
cudaStream_t stream;
CHECK(cudaStreamCreate(&stream));

// DMA input batch data to device, infer on the batch asynchronously, and DMA output back to host
// GPU의 할당된 공간에 data를 복사하고 실행해줍니다.
CHECK(cudaMemcpyAsync(buffers[inputIndex], input, batchSize * 3 * INPUT_H * INPUT_W * sizeof(float), cudaMemcpyHostToDevice, stream));
context.enqueue(batchSize, buffers, stream, nullptr);
CHECK(cudaMemcpyAsync(output, buffers[outputIndex], batchSize * OUTPUT_SIZE * sizeof(float), cudaMemcpyDeviceToHost, stream));
cudaStreamSynchronize(stream);

// Release stream and buffers
cudaStreamDestroy(stream);
CHECK(cudaFree(buffers[inputIndex]));
CHECK(cudaFree(buffers[outputIndex]));

 

 

 

 

 

 

 

 

 

 

 

※ TensorRT 공식 가이드 문서 : 

https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html#overview

https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html#build-phase-c

 

※ 참고 자료:

https://seobway.tistory.com/entry/TensorRT-1-Build-tensorrt-engine-tensorRT-723?category=850806

 

※ 참고자료 : ONNX 변환 및 사용 - 갓꾸준희님

https://eehoeskrap.tistory.com/414

 

※ 참고 github - tensorRT 예제 코드 정리 잘되어 있음!

https://github.com/wang-xinyu/tensorrtx

 

 

 

 

 

 

 

 

 

 

 

 

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

06. TensorRT Resnet18  (0) 2023.03.21
05. TensorRT VGG  (0) 2023.03.11
04. TensorRT Custom Layer 만들기  (0) 2022.02.14
01. TensorRT 설치 및 다운로드  (0) 2022.02.11

TensorRT란?

TensorRT는 이미 학습된 모델을 최적화 하여 추론 속도를 향상 시켜주는 모델 최적화 엔진입니다.

 

 


TensorRT 설치

https://developer.nvidia.com/tensorrt

 

NVIDIA TensorRT

NVIDIA TensorRT What is NVIDIA TensorRT Features Performance Metrics Framework Integrations Leading Adopters Resources NVIDIA TensorRT NVIDIA® TensorRT™ is an SDK for high-performance deep learning inference. It includes a deep learning inference optimi

developer.nvidia.com

 

위 사이트에 접속하여

GET STARTED 를 눌러줍니다.

 

 

 

Download Now> 를 눌러줍니다.

로그인 후 아래와 같이 버전별로 다운로드 할 수 있는 창이 뜹니다.

 

 

원하는 버전을 클릭해준 후

□ I Agree To the Terms of the NVIDIA TensorRT License Agreement

체크를 해준후 상세 버전을 다운로드 받을 수 있습니다.

 

TensorRT 다운로드 후

환경 변수를 설정해주면 됩니다.

 

ex)

1. Window

시스템 변수에 TRT_HOME으로 추가를 해줍니다.

그 후 Path -> 편집 -> 위 사진처럼 %TRT_HOME%\lib 추가

 

2. Linux

Linux는 ~/.bashrc 에 환경변수를 추가해주면 됩니다.

 

 

TensorRT Docker 이용할시

https://docs.nvidia.com/deeplearning/tensorrt/container-release-notes/rel_21-12.html#rel_21-12

 

Container Release Notes :: NVIDIA Deep Learning TensorRT Documentation

The NVIDIA container image for TensorRT, release 21.12, is available on NGC. Contents of the TensorRT container This container includes the following: The TensorRT C++ samples and C++ API documentation. The samples can be built by running make in the /work

docs.nvidia.com

cuda 경로 : usr/local/cuda-xx/

cudnn 경로 : usr/include

 

TRT_HOME 경로 잡기:

  • TRT_HOME : /workspace/tensorrt
  • include : /usr/include/x86-64-linux-gnu
  • lib : /usr/lib/x86-64-linux-gnu

 

 

Visual Studio 에서 사용하기

Visual Studio에서 사용하기 위해서는 경로를 잘 잡아주어야 합니다.

 

1. 프로젝트 속성 -> C/C++ -> General -> Additional Include Directories

경로\TensorRT-8.2.3.0\include 추가

 

2. 프로젝트 속성 -> Linker -> General -> Additional Library Directories

경로\TensorRT-8.2.3.0\lib 추가

 

3. 프로젝트 속성 -> Linker -> Input -> Additional Dependencies

nvinfer.lib
nvinfer_plugin.lib
nvonnxparser.lib
nvparsers.lib

추가

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

06. TensorRT Resnet18  (0) 2023.03.21
05. TensorRT VGG  (0) 2023.03.11
04. TensorRT Custom Layer 만들기  (0) 2022.02.14
02. TensorRT 다루기  (0) 2022.02.11

지난 게시글에 올렸던 Fast-RCNN 과는 딱봐도 차이점을 느낄 수 있습니다.

보시다시피 Fast R-CNN보다 더 빠르다고 이름에서부터 강하게 주장하고 있습니다.

이제 어떻게 Faster R-CNN이 더 빠른지 알아보도록 하겠습니다.

 

Fast R-CNN에서의 문제점

 - Selective Search 알고리즘으로 RoI를 계산하는 시간 소모가 크다.

 

 


Faster R-CNN

Faster R-CNN은 위에서 언급한 Fast R-CNN의 문제점을 해결하기 위해 RPN (Region Proposal Network)를 제안했습니다.

Faster R-CNN

위의 사진은 Faster R-CNN의 구조입니다.

1. 전체 이미지에서 Feature Map을 추출한다.

2. Feature Map을 RPN에 넣어 RoI를 추출해냅니다.

3. RPN에서 추출한 RoI를 Feature Map에 Projection 시켜줍니다.

4. 그 다음, RoI Pooling을 실행하여 Classification을 진행합니다.

 

 

 


Anchor Box

RPN에 들어가기전 Anchor Box에 대해 알아보겠습니다.

Anchor Box는 원본 이미지를 일정 간격의 grid로 나누어 각 grid를 Bounding Box로 간주합니다.

각 grid마다 9개의 Box가 생성되며 아래의 사진과 같이 여러 크기의 Box가 생성됩니다.

Anchor Box

즉, 오른쪽 원본 이미지에는 8x8x9 = 576개의 box가 생기게 됩니다.

 

 


RPN (Region Proposal Network)

RPN은 Fast R-CNN에서 Selective Search를 개선하기 위해 나왔습니다.

RPN

논문상의 RPN은 설명이 부족하다고 느꼈기 때문에 타블로그를 참고하여 작성하였습니다.

 

 

RPN Structure

RPN 동작 알고리즘

1. Feature Map을 Input Data로 받습니다.

2. 3x3 Convolution, 256 channel (Intermediate Layer)를 통과시켜 줍니다. 여기서 padding=1로 설정하여 사이즈를 유지시켜줍니다.

3. Classification과 Bounding Box Regression을 예측해주기 위해 1x1 Convolution을 통과시켜 줍니다. 각각, 18, 36 channel을 갖습니다.

    - 18 = 2(Objectness) x 9(Anchor)

    - 36 = 4(Bounding Box Regressor) x 9(Anchor)

4. 이후, class score에 따라 상위 N개의 region proposals만을 추출하고, NMS(Non maximum suppression)을 적용하여 일부 region proposals만들 Fast R-CNN에 전달하게 됩니다.

 

 


Multi-task Loss

출처 -&amp;amp;amp;amp;nbsp;https://herbwood.tistory.com/10

 

 


Training

이 부분은 코드 꼭 보기!

 

1) 먼저 Anchor generation layer에서 생성된 anchor box와 원본 이미지의 ground truth box를 사용하여 Anchor target layer에서 RPN을 학습시킬 positive/negative 데이터셋을 구성합니다. 이를 활용하여 RPN을 학습시킵니다. 이 과정에서 pre-trained된 VGG16 역시 학습됩니다. 

 

2) Anchor generation layer에서 생성한 anchor box와 학습된 RPN에 원본 이미지를 입력하여 얻은 feature maps를 사용하여 proposals layer에서 region proposals를 추출합니다. 이를 Proposal target layer에 전달하여 Fast R-CNN 모델을 학습시킬 positive/negative 데이터셋을 구성합니다. 이를 활용하여 Fast R-CNN을 학습시킵니다. 이 때 pre-trained된 VGG16 역시 학습됩니다. 

 

3) 앞서 학습시킨 RPN과 Fast R-CNN에서 RPN에 해당하는 부분만 학습(fine tune)시킵니다. 세부적인 학습 과정은 1)과 같습니다. 이 과정에서 두 네트워크끼리 공유하는 convolutional layer, 즉 pre-trained된 VGG16은 고정(freeze)합니다.  

 

4) 학습시킨 RPN(3)번 과정)을 활용하여 추출한 region proposals를 활용하여 Fast R-CNN을 학습(fine tune)시킵니다. 이 때 RPN과 pre-trained된 VGG16은 고정(freeze)합니다.

- 출처: https://herbwood.tistory.com/10

 

 


Code

zebras.jpg
0.35MB

https://www.youtube.com/watch?v=4yOcsWg-7g8

이곳에 친절하게 코드 설명과 작성하는 것이 나와 있어서 작성 및 정리를 해보겠습니다.

모든 코드가 들어있지는 않으며 아래 github에 전체 코드가 있습니다.

 

https://github.com/ajw1587/Pytorch_Study/blob/main/Faster_R_CNN_RPN.ipynb

 

GitHub - ajw1587/Pytorch_Study

Contribute to ajw1587/Pytorch_Study development by creating an account on GitHub.

github.com

herbwood 이분의 블로그가 굉장히 도움이 많이 됐습니다.

 

 

 

 

 


1) 먼저 이미지의 truth box를 확인해 봅니다. 또한 이미지를 800x800으로 resize 해주면서 좌표값들도 비율에 따라 조절해줍니다.

# BBox, labels 선언해주기 - x1, y1, x2, y2
origin_bbox = np.array([[200, 802, 623, 1094], [597, 715, 1038, 1070], 
                  [1088, 719, 1452, 1077], [1544, 791, 1914, 1083]]) 
labels = np.array([1, 1, 1, 1]) # 0: background, 1: zebra

copy_img = np.copy(origin_img)
for i in range(len(origin_bbox)):
  cv.rectangle(copy_img, (origin_bbox[i][0], origin_bbox[i][1]), (origin_bbox[i][2], origin_bbox[i][3]), color=(255, 0, 0), thickness=10)

plt.imshow(copy_img)
plt.show()
# Resize BBox
w_ratio = 800/origin_img.shape[1]
h_ratio = 800/origin_img.shape[0]

print('w_ratio : {}'.format(w_ratio))
print('h_ratio : {}\n'.format(h_ratio))

ratio_list = [w_ratio, h_ratio, w_ratio, h_ratio]
bbox = []

for box in origin_bbox:
  box = [int(a*b) for a,b in zip(box, ratio_list)]
  bbox.append(box)

bbox = np.array(bbox)
print(bbox)

copy_img = np.copy(img)
for i in range(len(bbox)):
  cv.rectangle(copy_img, (bbox[i][0], bbox[i][1]), (bbox[i][2], bbox[i][3]), color=(255, 0, 0), thickness=5)
plt.imshow(copy_img)
plt.show()

 

 

Create Extractor Model

2) VGG16을 통해 feature map을 추출해줍니다.

# Feature extractor

model = torchvision.models.vgg16(pretrained=True).to(device)
features = list(model.features)
print(len(features))
for i, layer in enumerate(features):
  print('{}th Layer : {}'.format(i, layer))
# Collect required layers
test_img = torch.zeros((1, 3, 800, 800)).float()
print(test_img.shape)

req_features = []
output = test_img.clone().to(device)

for feature in features:
  output = feature(output)
  if output.size()[2] < 800//16:
    break
  req_features.append(feature)
  output_channels = output.size()[1]

# Create Extractor Model
extractor = nn.Sequential(*req_features)

# test
transform = transforms.Compose([transforms.ToTensor()])
imgTensor = transform(img).to(device)
imgTensor = imgTensor.unsqueeze(0)
output_feature = extractor(imgTensor)

print(output_feature.shape)
# Visualize output_feature
imgs = output_feature.data.cpu().numpy().squeeze(0)
fig = plt.figure(figsize=(12, 4)) # figsize=전체사이즈
no = 1

for i in range(5):
  fig.add_subplot(1, 5, no)
  plt.imshow(imgs[i], cmap='gray')
  no += 1

plt.show()

 

 

Generate Anchors Boxes

3) Anchor generation layer에서는 anchor box를 생성하는 역할을 합니다. 이미지의 크기가 800x800이며, sub-sampling ratio=1/16이므로, 총 22500(=50x50)개의 anchor box를 생성해야 합니다. 서로 다른 scale과 aspect ratio를 가지는 9개의 anchor box를 생성해줍니다.anchor_boxes변수에 전체 anchor box의 좌표(x1, y1, x2, y2)를 저장합니다(anchor_boxes 변수의 크기는 (22500, 4)입니다). 

# Create Anchors Boxes Center
ctr = np.zeros((2500, 2)) # (x, y)

index = 0
for i in range(len(ctr_x)):
  for j in range(len(ctr_y)):
    ctr[index, 0] = ctr_x[i] - 8
    ctr[index, 1] = ctr_y[j] - 8
    index += 1
  
print(ctr.shape)
print(ctr[:10, :])

# Create Anchors Boxes
ratios = [0.5, 1, 2]
scales = [8, 16, 32]
sub_sample = 16

anchor_boxes = np.zeros(((feature_size * feature_size * 9), 4))
index = 0

for c in ctr:
  ctr_y, ctr_x = c
  for i in range(len(ratios)):
    for j in range(len(scales)):

      h = sub_sample * scales[j] * np.sqrt(ratios[i])
      w = sub_sample * scales[j] * np.sqrt(1./ratios[i])

      anchor_boxes[index, 0] = ctr_x - w/2.
      anchor_boxes[index, 1] = ctr_y - h/2.
      anchor_boxes[index, 2] = ctr_x + w/2.
      anchor_boxes[index, 3] = ctr_y + h/2.
      index += 1
  
print(anchor_boxes.shape)
print(anchor_boxes[:10, :])

 

 

Target Anchors

4) 이미지를 벗어나는 Anchor Box들을 없애주고 IoU 값들을 계산해줍니다.

# Choose anchor boxes inside the image

index_inside = np.where(
    (anchor_boxes[:, 0] >= 0) &
    (anchor_boxes[:, 1] >= 0) &
    (anchor_boxes[:, 2] <= 800) &
    (anchor_boxes[:, 3] <= 800))[0]
  
print(index_inside.shape)

valid_anchor_boxes = anchor_boxes[index_inside]
print(valid_anchor_boxes.shape)


# show anchor boxes images
img_clone3 = np.copy(img)
img_clone4 = cv.copyMakeBorder(img_clone3, 400, 400, 400, 400, cv.BORDER_CONSTANT, value=(255, 255, 255))
img_clone5 = np.copy(img_clone4)

for i in range(len(valid_anchor_boxes)):
# for i in range(1):
  x1 = int(valid_anchor_boxes[i][0])
  y1 = int(valid_anchor_boxes[i][1])
  x2 = int(valid_anchor_boxes[i][2])
  y2 = int(valid_anchor_boxes[i][3])

  cv.rectangle(img_clone5, (x1+400, y1+400), (x2+400, y2+400), color=(255, 0, 0), thickness=1)

plt.figure(figsize=(10,10))
plt.subplot(121), plt.imshow(img_clone4)
plt.subplot(122), plt.imshow(img_clone5)
plt.show()
# Calculate IoUs
ious = np.empty((len(valid_anchor_boxes), 4), dtype=np.float32)
ious.fill(0)
img_clone5 = np.copy(img)

# anchor boxes
for i, anchor_box in enumerate(valid_anchor_boxes):
  xa1, ya1, xa2, ya2 = anchor_box
  anchor_area = (xa2 - xa1) * (ya2 - ya1)

  # ground truth boxes
  for j, gt_box in enumerate(bbox):
    xb1, yb1, xb2, yb2 = gt_box
    box_area = (xb2 - xb1) * (yb2 - yb1)

    inter_x1 = max([xb1, xa1])
    inter_y1 = max([yb1, ya1])
    inter_x2 = min([xb2, xa2])
    inter_y2 = min([yb2, ya2])

    if (inter_x1 < inter_x2) and (inter_y1 < inter_y2):
      inter_area = (inter_x2 - inter_x1) * (inter_y2 - inter_y1)
      iou = inter_area / (anchor_area + box_area - inter_area)
    else:
      iou = 0
    
    ious[i,j] = iou

 

Positive / Negative Anchor Boxes

5) RPN을 학습시키기 위한 Positive, Negative Anchor Box를 나눠줍니다.

# Anchor Boxes의 ious 중 가장 큰 값을 가지는 iou 뽑기

# 각 Truth Box 별 가장 높은 iou값의 위치
gt_argmax_ious = ious.argmax(axis=0)
print(gt_argmax_ious)

# 각 Truth Box 별 가장 높은 iou값
gt_max_ious = ious[gt_argmax_ious, np.arange(ious.shape[1])]
print(gt_max_ious)

# 가장 높은 iou값들 추출
gt_argmax_ious = np.where(ious == gt_max_ious)[0]
print(gt_argmax_ious)
# 이미지 내에 있는 8940개의 Anchor Box가 각각 어떤 Truth Box와 연관이 많이 되어있는지
argmax_ious = ious.argmax(axis=1)
max_ious = ious[np.arange(len(index_inside)), argmax_ious]

# Label 정해주기
label = np.empty(len(index_inside), dtype = np.int32)
label.fill(-1)

pos_iou_threshold = 0.7
neg_iou_threshold = 0.3

label[gt_argmax_ious] = 1
label[max_ious >= pos_iou_threshold] = 1
label[max_ious < neg_iou_threshold] = 0
# First set the label=-1 and locations=0 of the 22500 anchor boxes, 
# and then fill in the locations and labels of the 8940 valid anchor boxes
# NOTICE: For each training epoch, we randomly select 128 positive + 128 negative 
# from 8940 valid anchor boxes, and the others are marked with -1

anchor_labels = np.empty((len(anchor_boxes),), dtype=label.dtype)
anchor_labels.fill(-1)
anchor_labels[index_inside] = label

anchor_locations = np.empty((len(anchor_boxes),) + anchor_boxes.shape[1:], dtype=anchor_locs.dtype)
anchor_locations.fill(0)
anchor_locations[index_inside, :] = anchor_locs

 

RPN

6) RPN을 정의해 줍니다.

# Send the features of the input image to the Region Proposal Network (RPN), 
# predict 22500 region proposals (ROIs)

in_channels = 512
mid_channels = 512
n_anchor = 9

conv1 = nn.Conv2d(in_channels, mid_channels, 3, 1, 1).to(device)
conv1.weight.data.normal_(0, 0.01)
conv1.bias.data.zero_()

# bounding box regressor
reg_layer = nn.Conv2d(mid_channels, n_anchor * 4, 1, 1, 0).to(device)
reg_layer.weight.data.normal_(0, 0.01)
reg_layer.bias.data.zero_()

# classifier (object or not)
cls_layer = nn.Conv2d(mid_channels, n_anchor * 2, 1, 1, 0).to(device)
cls_layer.weight.data.normal_(0, 0.01)
cls_layer.bias.data.zero_()

 

7) RPN의 LOSS를 정의 및 계산해줍니다.

rpn_score : RPN에 feature map을 input으로 넣어준 classifiacition ouput값

rpn_loc : RPN에 feature map을 input으로 넣어준 box regression ouput값

# For classification we use cross-entropy loss
rpn_cls_loss = F.cross_entropy(rpn_score, gt_rpn_score.long().to(device), ignore_index = -1)

# For Loc Loss
# only positive samples
pos = gt_rpn_score > 0
mask = pos.unsqueeze(1).expand_as(rpn_loc)

# take those bounding boxes whick have positive labels
mask_loc_preds = rpn_loc[mask].view(-1, 4)
mask_loc_targets = gt_rpn_loc[mask].view(-1, 4)

x = torch.abs(mask_loc_targets.cpu() - mask_loc_preds.cpu())
rpn_loc_loss = ((x < 1).float() * 0.5 * x ** 2) + ((x >= 1).float() * (x - 0.5))

# Combining both the rpn_cls_loss and rpn_reg_loss
rpn_lambda = 10
N_reg = (gt_rpn_score > 0).float().sum()
rpn_loc_loss = rpn_loc_loss.sum() / N_reg
rpn_loss = rpn_cls_loss + (rpn_lambda * rpn_loc_loss)

 

Proposal Layer

 8) Proposal Layer는 class scores, bounding box regressor와 anchor boxes를 추출하는 작업을 해줍니다.

먼저 score 변수에 저장된 objectness score를 내림차순으로 정렬한 후

objectness score 상위N(n_train_pre_nms=12000)개의 anchor box에 대하여 Non maximum suppression 알고리즘을 수행합니다.

 

# Send the 22500 ROIs predicted by RPN to Fast RCNN to predict bbox + classifications
# First use NMS (Non-maximum supression) to reduce 22500 ROI to 2000

nms_thresh = 0.7  # non-maximum supression (NMS) 
n_train_pre_nms = 12000 # no. of train pre-NMS
n_train_post_nms = 2000 # after nms, training Fast R-CNN using 2000 RPN proposals
n_test_pre_nms = 6000
n_test_post_nms = 300 # During testing we evaluate 300 proposals,
min_size = 16


# the labelled 22500 anchor boxes
# format converted from [x1, y1, x2, y2] to [ctrx, ctry, w, h]

anc_height = anchor_boxes[:, 3] - anchor_boxes[:, 1]
anc_width = anchor_boxes[:, 2] - anchor_boxes[:, 0]
anc_ctr_y = anchor_boxes[:, 1] + 0.5 * anc_height
anc_ctr_x = anchor_boxes[:, 0] + 0.5 * anc_width


# ctr_y = dy predicted by RPN * anchor_h + anchor_cy
# ctr_x similar
# h = exp(dh predicted by RPN) * anchor_h
# w similar

ctr_y = dy * anc_height[:, np.newaxis] + anc_ctr_y[:, np.newaxis]
ctr_x = dx * anc_width[:, np.newaxis] + anc_ctr_x[:, np.newaxis]
h = np.exp(dh) * anc_height[:, np.newaxis]
w = np.exp(dw) * anc_width[:, np.newaxis]


roi = np.zeros(pred_anchor_locs_numpy.shape, dtype=anchor_locs.dtype)
roi[:, 0::4] = ctr_x - 0.5 * w
roi[:, 1::4] = ctr_y - 0.5 * h
roi[:, 2::4] = ctr_x + 0.5 * w
roi[:, 3::4] = ctr_y + 0.5 * h

 

9) Non maximum suppression(select 2000 bounding boxes)

score 값이 높은걸 기준으로 IoU를 계산해주고 일정 이상값 이상이면 제외해줍니다.

# take all the roi boxes
x1 = roi[:, 0]
y1 = roi[:, 1]
x2 = roi[:, 2]
y2 = roi[:, 3]

# find the areas of all the boxes
areas = (x2 - x1 + 1) * (y2 - y1 + 1)


# take the indexes of order the probability score in descending order
# non maximum suppression
# 첫번째를 기준으로 iou값을 이용해 0.7 이하 값들로 다시 계산해준다.
order = order.argsort()[::-1] # 위에서 정렬을 해줬는데 왜 order에 argsort를 해주지?
keep = []

while (order.size > 0):
  i = order[0] # take the 1st elt in roder and append to keep
  keep.append(i)

  xx1 = np.maximum(x1[i], x1[order[1:]])
  yy1 = np.maximum(y1[i], y1[order[1:]])
  xx2 = np.minimum(x2[i], x2[order[1:]])
  yy2 = np.minimum(y2[i], y2[order[1:]])

  w = np.maximum(0.0, xx2 - xx1 + 1)
  h = np.maximum(0.0, yy2 - yy1 + 1)

  inter = w * h
  ovr = inter / (areas[i] + areas[order[1:]] - inter)
  inds = np.where(ovr <= nms_thresh)[0]
  order = order[inds + 1]

keep = keep[:n_train_post_nms] # while training/testing, use accordingly
roi = roi[keep]

 

Proposal Target Layer

 10) Fast R-CNN 모델을 학습시키기 위한 유용한 sample을 선택하는 것입니다. 학습을 위해 128개의 sample을 mini-batch로 구성합니다. 이 때 Proposal layer에서 얻은 anchor box 중 ground truth box와의 IoU 값이 0.5 이상인 box를 positive sample로, 0.5 미만인 box를 negative sample로 지정합니다(IoU를 구하는 과정은 코드를 참고하시기 바랍니다). 전체 mini-batch sample 중 1/4, 즉 32개가 positive sample이 되도록 구성합니다. 

# select the foreground rois as pre the pos_iou_thresh
# and n_sample x pos_ratio (128 x 0.25 = 32) foreground samples

pos_roi_per_image = 32
pos_index = np.where(max_iou >= pos_iou_thresh)[0]
pos_roi_per_this_image = int(min(pos_roi_per_image, pos_index.size))

if pos_index.size > 0:
  pos_index = np.random.choice(
      pos_index, size=pos_roi_per_this_image, replace=False)  


# Select background negative samples
# similarly we do for negative(background) region proposals

neg_index = np.where((max_iou < neg_iou_thresh_hi) &
                     (max_iou >= neg_iou_thresh_lo))[0]
neg_roi_per_this_image = n_sample - pos_roi_per_this_image
neg_roi_per_this_image = int(min(neg_roi_per_this_image, neg_index.size))

if neg_index.size > 0:
  neg_index = np.random.choice(
    neg_index, size = neg_roi_per_this_image, replace=False)

 

RoI pooling

11) Feature extractor를 통해 얻은 feature map과 Proposal Target layer에서 추출한 region proposals을 활용하여 RoI pooling을 수행합니다. 이 때 output feature map의 크기가 7x7이 되도록 설정합니다.

size = (7, 7)
adaptive_max_pool = nn.AdaptiveMaxPool2d(size[0], size[1])

output = []
rois = indices_and_rois.data.float()
rois[:, 1:].mul_(1/16.0) # sub-sampling ratio
rois = rois.long()
num_rois = rois.size(0)

for i in range(num_rois):
  roi = rois[i]
  im_idx = roi[0]
  im = output_feature.narrow(0, im_idx, 1)[..., roi[1]:(roi[3]+1), roi[2]:(roi[4]+1)]
  tmp = adaptive_max_pool(im)
  output.append(tmp[0])

output = torch.cat(output, 0)

 

 

 

 

 

 

 

 

참고:

 - https://arxiv.org/abs/1506.01497

 - https://yeomko.tistory.com/17

 - https://herbwood.tistory.com/10

 - https://herbwood.tistory.com/11

 - https://www.youtube.com/watch?v=4yOcsWg-7g8 ← 이거 꼭 보기! ★

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

06. Vision Transform (작성중)  (0) 2022.05.13
05. Yolo 버전별 비교  (0) 2022.05.13
03. Fast RCNN [Vision, Object Detection]  (0) 2022.01.21
02. SPP-Net [Vision, Object Detection]  (0) 2021.11.17
01. R-CNN [Vision, Object Detection]  (0) 2021.11.11
    # image_list
    root_dir = '../data'
    img_path_list = []
    for (root, dirs, files) in os.walk(root_dir):
        if len(files) > 0:
            for file_name in files:
                img_path = root + '/' + file_name
                img_path = img_path.replace('\\', '/')
                img_path_list.append(img_path)
    print(img_path_list)

+ Recent posts