딥러닝 파이토치 강좌, 텐서 다루기

딥러닝의 기본 구성 요소 중 하나는 텐서(tensor)입니다. 텐서는 N차원 배열을 나타내며, 파이토치에서는 신경망 학습의 기초로 사용됩니다. 본 강좌에서는 파이토치에서 텐서를 생성하고 다루는 방법에 대해 자세히 알아보겠습니다.

1. 텐서의 기본 이해

텐서는 기본적으로 숫자의 집합입니다. 0차원 텐서는 스칼라(scalar), 1차원 텐서는 벡터(vector), 2차원 텐서는 행렬(matrix), 3차원 텐서는 다차원 배열(array)으로 불립니다. 파이토치에서는 텐서를 쉽게 생성하고 조작할 수 있는 다양한 기능을 제공합니다.

1.1. 파이토치 설치하기

먼저, 파이토치를 설치해야 합니다. 아나콘다를 사용한다면 아래 코드를 실행하여 설치할 수 있습니다:

conda install pytorch torchvision torchaudio cpuonly -c pytorch

2. 텐서 생성하기

파이토치에서 텐서를 생성하는 방법은 여러 가지입니다. 가장 기본적인 방법은 torch.tensor() 함수를 사용하는 것입니다.

2.1. 기본적인 텐서 생성

import torch

# 리스트를 사용하여 텐서 생성
tensor1 = torch.tensor([1, 2, 3])
print(tensor1)

위 코드를 실행하면 다음과 같은 결과를 얻을 수 있습니다:

tensor([1, 2, 3])

2.2. 다양한 텐서 생성 방법

파이토치에서는 다양한 방법으로 텐서를 생성할 수 있습니다. 예를 들어:

  • torch.zeros(): 모든 요소가 0인 텐서 생성
  • torch.ones(): 모든 요소가 1인 텐서 생성
  • torch.arange(): 지정한 범위의 요소를 가진 텐서 생성
  • torch.randn(): 평균 0, 표준편차 1의 정규분포를 따르는 텐서 생성

예제 코드

# 다양한 텐서 생성
zeros_tensor = torch.zeros(3, 4)
ones_tensor = torch.ones(3, 4)
arange_tensor = torch.arange(0, 10, step=1)
random_tensor = torch.randn(3, 4)

print("Zeros Tensor:\n", zeros_tensor)
print("Ones Tensor:\n", ones_tensor)
print("Arange Tensor:\n", arange_tensor)
print("Random Tensor:\n", random_tensor)

3. 텐서의 속성

텐서는 다양한 속성을 가집니다. 텐서를 생성한 후, 그 속성을 확인할 수 있습니다. 아래는 주요 속성입니다:

  • tensor.shape: 텐서의 차원(shape)
  • tensor.dtype: 텐서의 데이터 타입
  • tensor.device: 텐서가 존재하는 디바이스(CPU 또는 GPU)

예제 코드

print("Shape:", tensor1.shape)
print("Data Type:", tensor1.dtype)
print("Device:", tensor1.device)

4. 텐서 연산

텐서는 다양한 연산을 지원합니다. 기본적인 산술 연산부터, 고급 연산까지 다양합니다.

4.1. 기본적인 산술 연산

tensor_a = torch.tensor([1, 2, 3])
tensor_b = torch.tensor([4, 5, 6])

# 덧셈
add_result = tensor_a + tensor_b
print("Addition Result:", add_result)

# 곱셈
mul_result = tensor_a * tensor_b
print("Multiplication Result:", mul_result)

4.2. 행렬 연산

행렬 곱셈은 torch.mm() 또는 @ 연산자를 사용하여 수행할 수 있습니다.

matrix_a = torch.tensor([[1, 2],
                              [3, 4]])

matrix_b = torch.tensor([[5, 6],
                          [7, 8]])

matrix_product = torch.mm(matrix_a, matrix_b)
print("Matrix Product:\n", matrix_product)

5. 텐서 슬라이싱 및 인덱싱

텐서는 N차원 배열이기 때문에 슬라이싱과 인덱싱을 통해 원하는 데이터를 추출할 수 있습니다.

5.1. 기본 인덱싱

tensor = torch.tensor([[1, 2, 3],
                           [4, 5, 6],
                           [7, 8, 9]])

# 첫 번째 행과 두 번째 열의 요소
element = tensor[0, 1]
print("Element at (0, 1):", element)

5.2. 슬라이싱

6. 텐서와 GPU

파이토치에서는 GPU를 활용하여 연산을 가속화 할 수 있습니다. 텐서를 GPU로 이동하려면 .to() 方法를 사용하면 됩니다.

예제 코드

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
tensor_gpu = tensor.to(device)
print("Tensor on GPU:", tensor_gpu)

7. 텐서의 변형

텐서를 다루다 보면 모양을 변형해야 할 때가 많습니다. 이를 위해 torch.view()torch.reshape()를 사용할 수 있습니다.

예제 코드

reshaped_tensor = tensor.view(1, 9)
print("Reshaped Tensor:\n", reshaped_tensor)

8. 종합 예제

지금까지 배운 내용들을 종합하여, 간단한 신경망 모델을 만들어 보겠습니다. MNIST 데이터셋을 이용하여 손글씨 숫자를 분류하는 모델을 만들어 보겠습니다.

파이토치 모델 생성

import torchvision.transforms as transforms
from torchvision import datasets
from torch.utils.data import DataLoader

# 데이터셋 다운로드 및 로드
transform = transforms.Compose([transforms.ToTensor()])
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)

# 검증하기 위한 간단한 모델 정의
import torch.nn as nn
import torch.optim as optim

class SimpleNN(nn.Module):
    def __init__(self):
        super(SimpleNN, self).__init__()
        self.fc1 = nn.Linear(28*28, 128)  # 28x28은 MNIST 이미지 크기
        self.fc2 = nn.Linear(128, 10)      # 10은 분류할 클래스 수

    def forward(self, x):
        x = x.view(-1, 28*28) # flatten the input
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x

# 모델과 손실 함수 및 옵티마이저 설정
model = SimpleNN().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 훈련 루프
for epoch in range(5):  # 5 에폭 훈련
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)

        optimizer.zero_grad()   # 이전 그래디언트 0으로 초기화
        output = model(data)    # 모델에 데이터 통과
        loss = criterion(output, target)  # 손실 계산
        loss.backward()         # 그래디언트 계산
        optimizer.step()        # 파라미터 업데이트

        if batch_idx % 100 == 0:
            print(f'Epoch: {epoch}, Batch: {batch_idx}, Loss: {loss.item()}')

위의 코드에서 우리는 MNIST 데이터셋을 학습하여 손글씨 숫자를 분류하는 단순한 신경망 모델을 구축했습니다. 텐서를 생성하고, 연산하고, GPU에서 실행하는 과정을 모두 포함하고 있습니다.

결론

이번 강좌에서는 파이토치에서 텐서를 생성하고 다루는 다양한 방법에 대해 알아보았습니다. 텐서는 딥러닝의 기본적인 구성 요소로, 모델 훈련 및 테스트 과정에서 중요한 역할을 합니다. 다음 단계에서는 더 복잡한 모델과 딥러닝 기법에 대해 학습할 수 있습니다.

감사합니다!