지난 글(2편)에서는 LibTorch 환경을 설정하고 C++에서 간단한 텐서를 생성해 출력하는 "Hello LibTorch" 예제를 실습했습니다. 이제 본격적으로 텐서 연산을 조금 더 다뤄보며, C++에서 PyTorch 텐서와 유사한 감각으로 연산을 하는 방법을 익혀봅시다.
이번 글에서는 다음을 다룹니다.
- 텐서 생성 방법과 다양한 초기화 방식
- 기초적인 텐서 연산(덧셈, 곱셈, 행렬 연산 등)
- 텐서 모양(Shape) 확인 및 변경
- GPU(CUDA) 사용을 위한 기초 개념 (CUDA 지원 환경일 경우)
- 작은 예제 코드를 통해 실습
이 과정을 통해 C++에서도 Python PyTorch API와 크게 다르지 않은 직관적인 방식으로 텐서를 다룰 수 있음을 확인할 수 있습니다.
텐서 생성하기
LibTorch에서는 PyTorch와 유사하게 다양한 텐서 초기화 함수를 제공합니다.
예를 들어, 다음과 같이 다양한 텐서를 만들 수 있습니다.
- 랜덤 텐서 (rand): 균등분포 난수
- randn: 정규분포 난수
- zeros: 0으로 초기화된 텐서
- ones: 1로 초기화된 텐서
- full: 특정 스칼라값으로 초기화된 텐서
- arange: 파이썬의 range처럼 연속적인 값으로 구성된 텐서
예제 코드 1: 다양한 초기화
#include <torch/torch.h>
#include <iostream>
int main() {
auto t1 = torch::zeros({2, 3});
auto t2 = torch::ones({2, 3});
auto t3 = torch::arange(0, 6).reshape({2, 3});
auto t4 = torch::randn({2, 3});
std::cout << "t1 (zeros):\n" << t1 << "\n\n";
std::cout << "t2 (ones):\n" << t2 << "\n\n";
std::cout << "t3 (arange -> reshape):\n" << t3 << "\n\n";
std::cout << "t4 (randn):\n" << t4 << "\n\n";
return 0;
}
설명:
- torch::zeros({2, 3})는 (2x3) 형태의 텐서, 모든 요소가 0
- torch::ones({2, 3})는 모든 요소가 1인 텐서
- torch::arange(0, 6)은 [0, 1, 2, 3, 4, 5]로 구성된 1D 텐서를 만든 뒤 .reshape({2, 3})로 2x3 텐서 형태 변경
- torch::randn({2,3})는 평균 0, 표준편차 1의 정규분포에서 샘플링된 난수 텐서 생성
이 코드를 빌드하고 실행하면 각 텐서의 값이 출력되는 것을 확인할 수 있습니다.
기본 연산하기
텐서 간 산술 연산도 Python PyTorch와 동일하게 +, -, *, / 오퍼레이터나 대응되는 함수들을 사용할 수 있습니다.
예제 코드 2: 기본 연산
#include <torch/torch.h>
#include <iostream>
int main() {
auto a = torch::ones({2, 2});
auto b = torch::full({2, 2}, 2.0);
std::cout << "a:\n" << a << "\n\n";
std::cout << "b:\n" << b << "\n\n";
auto c = a + b; // 텐서 덧셈
auto d = a * b; // 텐서 곱셈
auto e = b - a; // 텐서 뺄셈
auto f = a / b; // 텐서 나눗셈
std::cout << "c = a + b:\n" << c << "\n\n";
std::cout << "d = a * b:\n" << d << "\n\n";
std::cout << "e = b - a:\n" << e << "\n\n";
std::cout << "f = a / b:\n" << f << "\n\n";
return 0;
}
실행하면 a, b 텐서와 더해진 결과, 곱해진 결과 등을 확인할 수 있습니다.
텐서 모양 조작하기
딥러닝을 하다 보면 텐서 모양(Shape)을 바꾸거나, 차원을 추가/제거하는 일이 빈번합니다. LibTorch는 .reshape(), .view(), .unsqueeze(), .squeeze() 등의 함수를 통해 모양을 쉽게 변경할 수 있습니다.
- .reshape({new_shape}): 텐서의 원소 수를 유지한 채 새로운 모양으로 변환
- .view({new_shape}): reshape와 비슷하지만 메모리 연속성(Contiguous) 문제를 유념
- .unsqueeze(dim): 특정 차원을 추가
- .squeeze(): 크기가 1인 차원을 제거
예제 코드 3: 모양 조정
#include <torch/torch.h>
#include <iostream>
int main() {
auto x = torch::arange(0, 12); // [0,1,2,3,4,5,6,7,8,9,10,11]
std::cout << "x:\n" << x << "\n\n";
auto x_reshaped = x.reshape({3, 4});
std::cout << "x_reshaped (3x4):\n" << x_reshaped << "\n\n";
// 차원 추가: 현재 (3,4) 형태에서 맨 앞에 1차원 추가 -> (1,3,4)
auto x_unsqueezed = x_reshaped.unsqueeze(0);
std::cout << "x_unsqueezed (1x3x4):\n" << x_unsqueezed << "\n\n";
// 다시 squeeze로 크기가 1인 차원 제거하면 (3,4)
auto x_squeezed = x_unsqueezed.squeeze();
std::cout << "x_squeezed (3x4):\n" << x_squeezed << "\n\n";
return 0;
}
출력 결과를 통해 차원 변화 과정을 확인할 수 있습니다.
텐서의 Device(GPU) 설정하기
LibTorch 텐서는 CPU를 기본 장치로 사용합니다. 하지만 CUDA 지원 버전을 사용하고, 시스템에 NVIDIA GPU가 있다면 .to(torch::kCUDA) 메서드를 통해 텐서를 GPU로 옮길 수 있습니다.
예를 들어, 다음과 같이 텐서를 GPU로 옮길 수 있습니다. (GPU 환경 아닐 경우, 이 코드를 실행하면 에러가 날 수 있으니 GPU 환경에서만 시도하세요.)
예제 코드 4: GPU 사용하기(옵션)
#include <torch/torch.h>
#include <iostream>
int main() {
// GPU가 가능한 환경이면
if (torch::cuda::is_available()) {
auto device = torch::Device(torch::kCUDA);
auto gpu_tensor = torch::ones({2, 2}, device);
std::cout << "gpu_tensor on CUDA:\n" << gpu_tensor << "\n\n";
} else {
std::cout << "CUDA is not available on this system.\n";
}
return 0;
}
설명:
- torch::cuda::is_available()를 통해 CUDA 사용 가능 여부 확인
- 사용 가능하다면 torch::Device(torch::kCUDA)로 디바이스 객체를 만들고, 텐서 생성 시 device 인자를 넘겨 GPU 상에 텐서를 생성
CPU 상의 텐서를 GPU로 옮기고 싶다면 tensor.to(device)를 사용할 수도 있습니다.
정리
이번 글에서는 다음 내용을 배웠습니다.
- 다양한 텐서 초기화 방법 (zeros, ones, arange, randn 등)
- 기본 산술 연산 (+, -, *, /)
- 텐서 모양 조작 (reshape, unsqueeze, squeeze)
- GPU 디바이스 사용법 (옵션)
이를 통해 C++ LibTorch에서도 Python PyTorch와 유사한 텐서 조작이 가능함을 확인했습니다. 이제 텐서 연산에 익숙해지면, 다음 글(4편)에서는 Python에서 학습한 모델을 C++에서 불러와 추론하는 과정을 다룰 것입니다. 이를 통해 단순한 텐서 연산에서 한 단계 더 나아가 딥러닝 모델을 실제로 C++ 환경에서 활용하는 방법을 살펴보겠습니다.
참고 자료
- PyTorch 공식 홈페이지: https://pytorch.org/
- LibTorch C++ Docs: https://pytorch.org/cppdocs/
- 파이토치 텐서 연산 튜토리얼 (Python 기반 예제):
- https://pytorch.org/tutorials/beginner/blitz/tensor_tutorial.html
(여기서 소개하는 연산들은 C++ LibTorch에서도 거의 동일하게 적용 가능)
- https://pytorch.org/tutorials/beginner/blitz/tensor_tutorial.html
- YouTube: PyTorch Tutorial: https://www.youtube.com/c/PyTorch
'개발 이야기 > PyTorch (파이토치)' 카테고리의 다른 글
[LibTorch 입문] 6편: C++과 Python 사이에서 텐서 교환하기 (0) | 2024.12.11 |
---|---|
[LibTorch 입문] 5편: pybind11로 C++ 코드를 Python에 바인딩하기 (0) | 2024.12.11 |
[LibTorch 입문] 4편: Python 모델을 C++에서 TorchScript로 추론하기 (1) | 2024.12.10 |
[LibTorch 입문] 2편: LibTorch 환경 셋업과 CMake 프로젝트 기초 (0) | 2024.12.09 |
[LibTorch 입문] 1편: PyTorch와 LibTorch 소개, 그리고 목표 설정 (32) | 2024.12.09 |