본문 바로가기

LibTorch

[LibTorch/C++] torch::Tensor, vector간 데이터 이동

 

딥러닝을 개발은 주로 Python에서 이루어지지만, 실제 환경에 적용하다보면 C++에서 직접 작업할 필요가 있습니다.

 

이때, PyTorch의 c++ 버전인 LibTorch를 활용하는 것도 하나의 방법이 될 수 있습니다.

 

PyTorch 자체도 c++을 python으로 감싼 것이지만, 막상 c++ documentation이 잘 되어있지 않습니다.

 

본 카테고리 글들은 개발 과정에서 사용하게 된 함수들을 기록하기 위함입니다.

 

궁금하신 사항은 댓글로 남겨주세요.

 

 

1-1. vector -> torch::Tensor

#include <torch/torch.h>
#include <vector>
#include <iostream>

using namespace std;
using namespace torch::indexing;

int main(){
    vector<double> tempVector({1, 2, 4, 3, 4, 3});
    torch::Tensor tempTensor;
    tempTensor = torch::from_blob(tempVector.data(), {(long) tempVector.size()}, torch::kF64);

    cout << "temp Vector = (";
    for (auto a : tempVector)
        cout << a << ", ";
    cout << ")" << endl;
    cout << "temp Tensor : " << tempTensor << endl;

    return 0;
}

torch::from_blob 함수를 사용하여 vector의 data를 이용한 tensor를 만들 수 있습니다.

torch::from_blob 함수 인자로는 data pointer, tensor 모양, tensor data type를 받습니다.

tesnor 모양은 {6}, {1, 6}, {2, 3}, {3, 2} 등 다양하게 {a, b, c, d, ...} 형태로 지정 가능합니다.

 

1-2. from_blob 사용시 주의사항

 

(1) vector의 data type과 torch의 data type을 동일하게 맞춰야합니다.

 

정상 결과(double -> torch::kF64)

temp Vector = (1, 2, 4, 3, 4, 3, )
temp Tensor :  1
 2
 4
 3
 4
 3
[ CPUDoubleType{6} ]

 

잘못된 결과 1(float -> torch::kF64)

temp Vector = (1, 2, 4, 3, 4, 3, )
temp Tensor :   2.0000e+00
  3.2000e+01
  3.2000e+01
 4.7924e-322
 6.9499e-310
 4.9407e-324
[ CPUDoubleType{6} ]

 

잘못된 결과 2(double -> torch::kF32)

temp Vector = (1, 2, 4, 3, 4, 3, )
temp Tensor :  0.0000
 1.8750
 0.0000
 2.0000
 0.0000
 2.2500
[ CPUFloatType{6} ]

 

(2) 데이터 미복사 문제

from_blob을 그냥 사용하면 값이 복사되지 않고 있는 data를 참조하게 됩니다.

#include <torch/torch.h>
#include <vector>
#include <iostream>

using namespace std;
using namespace torch::indexing;

int main(){
    torch::Tensor tempTensor;
    {
        vector<double> tempVector({1, 2, 4, 3, 4, 3});
        tempTensor = torch::from_blob(tempVector.data(), {(long) tempVector.size()}, torch::kF64);

        cout << "temp Vector = (";
        for (auto a: tempVector)
            cout << a << ", ";
        cout << ")" << endl;
        cout << "temp Tensor : " << tempTensor << endl;
    }
    cout << "temp Tensor : " << tempTensor << endl;

    return 0;
}

위 코드는 tempVector가 살아있을때 tempTensor를 출력하고, tempVector가 제거됐을때 tempTensor를 출력하는 코드입니다.

 

실행 결과

temp Vector = (1, 2, 4, 3, 4, 3, )
temp Tensor :  1
 2
 4
 3
 4
 3
[ CPUDoubleType{6} ]
temp Tensor :  4.6583e-310
 4.6583e-310
  4.0000e+00
  3.0000e+00
  4.0000e+00
  3.0000e+00
[ CPUDoubleType{6} ]

 

tempVector가 제거되면 tempTensor의 값도 쓰레기값으로 바뀌는 것이 보입니다.

이를 해결하기 위해 from_blob 라인 뒤에 .clone()을 추가하여 복사해주시면 됩니다.

tempTensor = torch::from_blob(tempVector.data(), {(long) tempVector.size()}, torch::kF64).clone(); // add clone()

결과

temp Vector = (1, 2, 4, 3, 4, 3, )
temp Tensor :  1
 2
 4
 3
 4
 3
[ CPUDoubleType{6} ]
temp Tensor :  1
 2
 4
 3
 4
 3
[ CPUDoubleType{6} ]

 

2. Tensor -> Vector

vector<float> tempVector(tempTensor.data_ptr<float>(), tempTensor.data_ptr<float>() + tempTensor.numel());

tempTensor.data_ptr<데이터타입>()을 통해 tensor의 data 포인터를 가져올 수 있습니다.

.numel()은 데이터 개수를 반환합니다.

여기서도 vector의 data type과 data_ptr의 데이터 타입을 같도록 만드는 것을 주의하시기 바랍니다.

'LibTorch' 카테고리의 다른 글

[LibTorch/C++] torch::Tensor indexing 방법  (0) 2022.06.14