머신러닝: PyTorch 텐서 기본 연산
PyTorch는 머신러닝 연구 및 개발에 널리 사용되는 오픈 소스 딥러닝 프레임워크이다. PyTorch의 핵심은 텐서(Tensor)인데, 텐서는 데이터를 저장하고 연산을 수행하는 기본 단위이다. 이 글에서는 PyTorch 텐서의 기본적인 연산들을 살펴보고, 실제 코드 예제를 통해 이해를 돕고자 한다. 텐서의 생성, 속성, 인덱싱, 그리고 다양한 연산 방법을 다룬다.
텐서 생성 및 초기화
PyTorch에서 텐서를 생성하는 방법은 다양하다. 가장 기본적인 방법은 torch.Tensor()
를 사용하는 것이다. 이 외에도 torch.zeros()
, torch.ones()
, torch.rand()
등을 사용하여 특정 값으로 초기화된 텐서를 생성할 수 있다.
import torch
# 빈 텐서 생성
x = torch.Tensor()
print(x)
# 0으로 채워진 텐서 생성
x = torch.zeros(5, 3)
print(x)
# 1로 채워진 텐서 생성
x = torch.ones(5, 3)
print(x)
# 무작위 값으로 채워진 텐서 생성
x = torch.rand(5, 3)
print(x)
# 리스트를 사용하여 텐서 생성
data = [[1, 2],[3, 4]]
x = torch.Tensor(data)
print(x)
torch.zeros(5, 3)
은 5행 3열의 0으로 채워진 텐서를 생성한다. torch.ones(5, 3)
은 마찬가지로 1로 채워진 텐서를 생성하며, torch.rand(5, 3)
은 0과 1 사이의 무작위 값으로 텐서를 채운다. 리스트를 사용하여 텐서를 생성할 수도 있다.
텐서 속성 및 자료형 변환
텐서의 속성은 텐서의 크기(shape), 자료형(dtype), 그리고 어느 장치(device)에 저장되어 있는지 등을 포함한다. shape
속성을 통해 텐서의 차원을 확인할 수 있고, dtype
속성을 통해 텐서의 자료형을 확인할 수 있다. 텐서의 자료형은 float32
, float64
, int32
, int64
등 다양하며, 필요에 따라 type()
함수를 사용하여 자료형을 변환할 수 있다.
# 텐서의 크기 확인
x = torch.randn(5, 3)
print(x.shape)
# 텐서의 자료형 확인
print(x.dtype)
# 텐서의 자료형 변환
x = x.double()
print(x.dtype)
x = x.int()
print(x.dtype)
torch.randn(5, 3)
은 평균이 0이고 분산이 1인 정규 분포에서 무작위 값을 추출하여 5행 3열의 텐서를 생성한다. .double()
함수를 사용하여 텐서의 자료형을 float64
로 변환할 수 있고, .int()
함수를 사용하여 int32
로 변환할 수 있다.
텐서 인덱싱 및 슬라이싱
텐서의 특정 요소에 접근하거나 일부분을 잘라내는 것을 인덱싱(indexing)과 슬라이싱(slicing)이라고 한다. 이는 파이썬의 리스트와 유사한 방식으로 동작한다. 0부터 시작하는 인덱스를 사용하여 텐서의 특정 위치에 있는 값을 가져오거나 수정할 수 있다.
# 텐서 인덱싱
x = torch.rand(5, 3)
print(x[0, 0]) # 첫 번째 행, 첫 번째 열의 요소
# 텐서 슬라이싱
print(x[:, 0]) # 모든 행, 첫 번째 열
print(x[0, :]) # 첫 번째 행, 모든 열
print(x[0:2, :]) # 첫 번째, 두 번째 행, 모든 열
x[0, 0]
은 텐서 x
의 첫 번째 행, 첫 번째 열에 있는 요소를 나타낸다. x[:, 0]
은 모든 행의 첫 번째 열을 나타내며, x[0, :]
은 첫 번째 행의 모든 열을 나타낸다. 슬라이싱을 통해 텐서의 일부분을 추출할 수 있다.
텐서 연산
PyTorch는 다양한 텐서 연산을 제공한다. 기본적인 사칙연산(+, -, *, /)은 물론, 행렬 곱셈, 지수 함수, 로그 함수, 삼각 함수 등 다양한 수학적 연산을 지원한다.
# 텐서 덧셈
x = torch.rand(2, 3)
y = torch.rand(2, 3)
z = x + y
print(z)
# 텐서 뺄셈
z = x - y
print(z)
# 텐서 곱셈 (element-wise)
z = x * y
print(z)
# 텐서 나눗셈
z = x / y
print(z)
# 행렬 곱셈
x = torch.rand(2, 3)
y = torch.rand(3, 2)
z = torch.matmul(x, y)
print(z)
torch.matmul(x, y)
는 행렬 x
와 y
의 행렬 곱셈을 수행한다. 텐서의 크기가 적절해야 행렬 곱셈이 가능하다. 덧셈, 뺄셈, 곱셈, 나눗셈은 element-wise로 수행되며, 같은 위치의 요소끼리 연산된다.
CUDA 텐서
GPU를 사용하여 텐서 연산을 가속화할 수 있다. CUDA는 NVIDIA에서 개발한 병렬 컴퓨팅 플랫폼이며, PyTorch는 CUDA를 지원하여 GPU를 활용한 텐서 연산을 가능하게 한다. torch.device('cuda')
를 사용하여 텐서를 GPU로 옮길 수 있다.
# CUDA 사용 가능 여부 확인
if torch.cuda.is_available():
device = torch.device('cuda')
else:
device = torch.device('cpu')
# 텐서를 GPU로 이동
x = torch.rand(5, 3)
x = x.to(device)
print(x)
torch.cuda.is_available()
함수를 사용하여 CUDA를 사용할 수 있는지 확인한다. CUDA를 사용할 수 있다면 torch.device('cuda')
를 사용하여 GPU 장치를 설정하고, .to(device)
함수를 사용하여 텐서를 GPU로 옮길 수 있다.
자동 미분 (Autograd)
PyTorch의 핵심 기능 중 하나는 자동 미분이다. 텐서의 연산 그래프를 자동으로 추적하여 미분값을 계산할 수 있다. 이는 신경망의 학습 과정에서 필수적인 기능이다. requires_grad=True
를 설정하여 텐서의 연산 기록을 추적할 수 있다.
# requires_grad 설정
x = torch.ones(2, 2, requires_grad=True)
print(x)
# 텐서 연산
y = x + 2
print(y)
# 연산 기록 확인
print(y.grad_fn)
# 더 복잡한 연산
z = y * y * 3
out = z.mean()
print(z, out)
# 미분 계산
out.backward()
# 기울기 확인
print(x.grad)
requires_grad=True
를 설정하면 PyTorch는 텐서에 대한 모든 연산을 추적하고, backward()
함수를 호출하여 미분값을 계산할 수 있다. 계산된 미분값은 .grad
속성에 저장된다.
PyTorch 텐서의 기본적인 연산들을 살펴보았다. 텐서 생성, 속성 확인, 인덱싱, 다양한 연산, CUDA 사용, 자동 미분 등은 PyTorch를 사용하여 머신러닝 모델을 개발하는 데 필수적인 개념들이다. 이러한 기본 지식을 바탕으로 더 복잡한 모델을 구현하고 실험해 볼 수 있다.
주요 용어 정리:
- 텐서 (Tensor): 데이터를 저장하고 연산을 수행하는 기본 단위 (Fundamental unit for data storage and computation)
- 자료형 (dtype): 텐서에 저장된 데이터의 종류 (Data type of the tensor)
- 인덱싱 (Indexing): 텐서의 특정 요소에 접근하는 방법 (Accessing specific elements in a tensor)
- 슬라이싱 (Slicing): 텐서의 일부분을 잘라내는 방법 (Extracting a portion of a tensor)
- CUDA: NVIDIA에서 개발한 병렬 컴퓨팅 플랫폼 (Parallel computing platform developed by NVIDIA)
- 자동 미분 (Autograd): 텐서 연산 그래프를 자동으로 추적하여 미분값을 계산하는 기능 (Automatic differentiation of tensor operations)