파이토치(Pytorch) - 텐서(Tensor) 튜토리얼

미남로그·2021년 12월 18일
0

대부분의 머신러닝 워크플로우는 데이터 작업과 모델 생성, 모델 매개변수 최적화, 학습된 모델 저장 등이 포함됩니다.

파이토치 사이트에서 제공하는 튜토리얼도 위의 개념에 대해 더 자세히 알아볼 수 있습니다.

튜토리얼 사용 방법에 따르면 다른 딥러닝 프레임워크에 익숙하다면 0. 빠른 시작을 보고 바로 PyTorch의 API를 익히는 것을 추천합니다.

딥러닝 프레임워크가 처음이라면 단계별(step-by-step) 가이드의 첫 번째인 1. 텐서(Tensor) 부터 시작합니다.

저는 굳이 따지자면 딥러닝 프레임워크가 처음은 아니지만 파이토치로 실습을 하다 보니 낯선 점이 많아 하나씩 해보려고 합니다.


파이토치 튜토리얼

  1. 빠른 시작
  2. 텐서(Tensor)
  3. Dataset과 DataLoader
  4. 변형(Transform)
  5. 신경망 모델 구성하기
  6. 자동 미분(Automatic Differentiation)
  7. 최적화 단계(Optimization Loop)
  8. 모델 저장하고 불러오고 사용하기


1. 텐서(TENSOR)

텐서는 배열(array)나 행렬(matrix)와 매우 유사한 특수한 자료구조입니다.

Pytorch에서는 텐서를 사용하여 모델의 입력(input)과 출력(output), 그리고 모델의 매개변수들을 부호화(encode)합니다.

텐서는 GPU나 다른 하드웨어 가속기에서 실행할 수 있다는 점과 제외한다면 NumPy의 ndaaray와 유사합니다.

실제로 텐서와 넘파이 배열(array)는 동일한 내부 메모리를 공유할 수 있어 데이터를 중복할 필요가 없습니다.

텐서는 또한 Autograd에서 살펴볼 자동 미분(automatic differentiation)에 최적화되어 있습니다.

import torch
import numpy as np


2. 텐서(TENSOR) 초기화

텐서는 여러가지 방법으로 초기화할 수 있습니다.


1. 데이터로부터 직접(directly) 생성하기

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

데이터로부터 직접 생성이 가능합니다.

데이터의 자료형은 자동으로 유추합니다.


2. Numpy 배열로부터 생성하기

np_array = np.array(data)
x_np = torch.from_numpy(np_array)

넘파이 배열로도 텐서 생성이 가능합니다.

그 반대도 가능합니다. to_numpy 사용


3. 다른 텐서로부터 생성하기

명시적으로 override 하지 않는다면, 인자로 주어진 텐서의 shape, datatype을 유지합니다.

x_ones = torch.ones_like(x_data) # x_data의 속성 유지
print(f'Ones Tensor: \n {x_ones} \n')

x_rand = torch.rand_like(x_data, dtype=torch.float) # x_data의 속성을 덮어씁니다.
print(f'Random Tensor: \n {x_rand} \n'

Out:

Ones Tensor:
 tensor([[1, 1],
        [1, 1]])

Random Tensor:
 tensor([[0.4738, 0.5467],
        [0.5430, 0.1616]])

4. 무작위(random) 또는 상수(constant) 값을 사용하기

shape은 텐서의 차원을 나타내는 튜플로 아래 함수들에서는 출력 텐서의 차원을 결정합니다.

shape = (2,3,)
rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)

print(f'Random Tensor: \n {rand_tensor} \n')
print(f'Ones Tensor: \n {ones_tensor} \n'
print(f'Zeros Tensor: \n {zeros_tensor}')

Out:

Random Tensor:
 tensor([[0.7759, 0.1138, 0.4539],
        [0.6169, 0.2986, 0.2102]])

Ones Tensor:
 tensor([[1., 1., 1.],
        [1., 1., 1.]])

Zeros Tensor:
 tensor([[0., 0., 0.],
        [0., 0., 0.]])


3. 텐서의 속성(Attribute)

텐서의 속성은 텐서의 shape, datatype 및 어느 장치에 저장되는지를 나타냅니다.

tensor = torch.rand(3,4)

print(f"Shape of tensor: {tensor.shape}")
print(f"Datatype of tensor: {tensor.dtype}")
print(f"Device tensor is stored on: {tensor.device}")

Out:

Shape of tensor: torch.Size([3, 4])
Datatype of tensor: torch.float32
Device tensor is stored on: cpu


4. 텐서의 연산(Operation)

transposing, indexing, slicing, 수학 계산, 선형 대수, random sampling 등 100가지 이상의 텐서 연산이 있습니다.

각 연산들은 GPU에서 실행할 수 있지만 기본적으로 텐서는 CPU에 생성됩니다.

.to 메소드를 이용하면 GPU로 이동 가능합니다.

장치들 간에 큰 텐서들을 복사하는 것은 시간과 메모리 측면에서 비용이 많이 든다는 것을 기억하세요.

if torch.cuda.is_available():
	tensor = tensor.to('cuda')

1. Numpy식의 표준 인덱싱과 슬라이싱

tensor = torch.ones(4,4)
print('First row: ', tensor[0])
print('First column: ', tensor[:, 0])
print('Last column: ', tensor[..., -1])
tensor[:,1] = 0
print(tensor)

Out:

First row:  tensor([1., 1., 1., 1.])
First column:  tensor([1., 1., 1., 1.])
Last column: tensor([1., 1., 1., 1.])
tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])

2. 텐서 합치기

torch.cat 을 사용하여 주어진 차원에 따라 일련의 텐서를 연결할 수 있음.

t1 = torch.cat([tensor, tensor, tensor], dim=1)
print(t1)

Out:

tensor([[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.]])

3. 산술 연산(Arithmetic operation)

# 두 텐서 간의 행렬 곱(matrix multiplication)을 계산. y1, y2, y3은 모두 같은 값을 가짐.
y1 = tensor @ tensor.T
y2 = tensor.matmul(tensor.T)

y3 = torch.rand_like(tensor)
torch.matmul(tensor, tensor.T, out=y3)

# 요소별 곱(element-wise product)을 계산함. z1, z2, z3는 모두 같은 값을 가짐.
z1 = tensor * tensor
z2 = tensor.mul(tensor)

z3 = torch.rand_like(tensor)
torch.mul(tensor, tensor, out=z3)

4. 단일-요소(single-element) 텐서

텐서의 모든 값을 하나로 집계(aggregate)하여 요소가 하나인 텐서의 경우, item() 을 사용하여 Python 숫자 값으로 변환할 수 있습니다.

agg = tensor.sum()
agg_item = agg.item()
print(agg_item, type(agg_item))

Out:

12.0 <class 'float'>

5. 바꿔치기(in-place) 연산

연산 결과를 피연산자(operand)에 저장하는 연산을 바꿔치기 연산이라고 부르며, _ 접미사를 갖는다.

예를 들어: x.copy_(y)x.t_()x 를 변경한다.

print(tensor, '\n')
tensor.add_(5)
print(tensor)

Out:

tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])

tensor([[6., 5., 6., 6.],
        [6., 5., 6., 6.],
        [6., 5., 6., 6.],
        [6., 5., 6., 6.]])


5. NumPy 변환(Bridge)

1. 텐서를 Numpy 배열로 변환하기

t = torch.ones(5)
print(f't: {t}')
n = t.numpy()
print(f'n: {n}')

Out:

t: tensor([1., 1., 1., 1., 1.])
n: [1. 1. 1. 1. 1.]

텐서의 변경 사항이 NumPy 배열에 반영됩니다.

t.add_(1)
print(f't: {t}')
print(f'n: {n}')

Out:

t: tensor([2., 2., 2., 2., 2.])
n: [2. 2. 2. 2. 2.]

2. NumPy 배열을 텐서로 변환하기

n = np.ones(5)
t = torch.from_numpy(n)

NumPy 배열의 변경 사항이 텐서에 반영된다.

np.add(n, 1, out=n)
print(f't: {t}')
print(f'n: {n}')

Out:

t: tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
n: [2. 2. 2. 2. 2.]

여기까지가 파이토치의 '텐서(Tensor)'에 대한 개념이었습니다. Numpy의 array와 비교해볼 수 있는 시간이었습니다. 👏

profile
미남이 귀엽죠

0개의 댓글