이수안컴퓨터연구소의 파이토치(PyTorch) 기초 영상을 보고 정리한 내용입니다.
✅ operations
텐서의 연산은 덧셈, 뺄셈, 곱셈, 나눗셈의 사칙연산과 내적(dot product)이 존재한다.
사칙연산은 torch에서 제공하는 메서드나 기본 연산자인 +, -, *, / 을 사용한다.
import torch
x = torch.tensor([[1, 2], [3, 4]])
y = torch.tensor([[5, 6], [7, 8]])
✔️ 덧셈
print(x + y)
# output
# tensor([[ 6, 8],
# [10, 12]])
print(torch.add(x, y))
# output
# tensor([[ 6, 8],
# [10, 12]])
덧셈은 + 연산자를 사용하거나 torch.add()
를 사용한다.
+ 연산자를 사용하든 torch.add()를 사용하든 둘의 결과는 동일하다.
result = torch.empty(2, 2)
torch.add(x, y, out=result)
print(result)
# output
# tensor([[ 6., 8.],
# [10., 12.]])
torch.add()를 사용할 때 out 옵션을 사용하면 결과 텐서를 인자로 제공할 수 있다.
따라서 x와 y를 더한 값이 result에 들어가게 된다.
y.add_(x)
print(y)
# output
# tensor([[ 6, 8],
# [10, 12]])
위와 같이 in-place 방식을 사용할 수도 있다.
다른 코드들과는 달리 위 방식에서는 x와 y를 더한 결과를 출력하거나 다른 텐서에 저장하는 것이 아니라 피연산자가 될 텐서에 다른 텐서를 직접 더한다.
따라서 위 코드에서는 y에 x를 더하고 있기 때문에 y를 출력했을 때 x + y의 값이 들어있는 것을 확인할 수 있다.
참고로 in-place 방식으로 텐서의 값을 변경하는 경우 연산의 뒤에 _가 붙는다.
✔️ 뺄셈
print(x-y)
print(torch.sub(x, y))
print(x.sub(y))
# output
# tensor([[-5, -6],
# [-7, -8]])
# tensor([[-5, -6],
# [-7, -8]])
# tensor([[-5, -6],
# [-7, -8]])
뺄셈은 - 연산자를 사용하거나 torch.sub()
를 사용한다.
✔️ 곱셈
print(x * y)
print(torch.mul(x, y))
print(x.mul(y))
# output
# tensor([[ 6, 16],
# [30, 48]])
# tensor([[ 6, 16],
# [30, 48]])
# tensor([[ 6, 16],
# [30, 48]])
곱셈은 * 연산자를 사용하거나 torch.mul()
을 사용한다.
✔️ 나눗셈
print(x / y)
print(torch.div(x, y))
print(x.div(y))
# output
# tensor([[0.1667, 0.2500],
# [0.3000, 0.3333]])
# tensor([[0.1667, 0.2500],
# [0.3000, 0.3333]])
# tensor([[0.1667, 0.2500],
# [0.3000, 0.3333]])
나눗셈은 / 연산자를 사용하거나 torch.div()
를 사용한다.
✔️ 내적
print(torch.mm(x, y))
# output
# tensor([[26, 32],
# [58, 72]])
내적은 따로 연산자가 존재하지 않는다.
대신 torch.mm()
을 사용하여 내적 값을 구할 수 있다.
✅ manipulations
✔️ 인덱싱
텐서는 NumPy와 같이 인덱싱으로 값에 접근할 수 있다.
import torch
x = torch.tensor([[1, 2], [3, 4]])
print(x)
print(x[0])
print(x[:, 1])
# output
# tensor([[1, 2],
# [3, 4]])
# tensor([1, 2])
# tensor([2, 4])
✔️ view
Tensor.view()
는 텐서의 크기나 모양을 변경한다.
Tensor.view(*shape)
인자로는 바뀔 shape이 주어지며 Tensor의 값은 동일하지만 shape이 바뀐 새로운 Tensor가 리턴된다.
x = torch.randn(3, 5)
a = x.view(15)
b = x.view(5, -1)
print(x.size())
print(a.size())
print(b.size())
# output
# torch.Size([3, 5])
# torch.Size([15])
# torch.Size([5, 3])
✔️ item
Tensor.item()
은 텐서에 스칼라 값 하나가 존재할 경우 그 값을 얻어올 수 있다.
해당 텐서에 2개 이상의 값이 있을 경우에는 .item()을 적용할 수 없다.
이 경우 ValueError: only one element tensors can be converted to Python scalars 라는 에러를 확인할 수 있다.
x = torch.randn(1)
print(x)
print(x.item())
# output
# tensor([-0.4725])
# -0.47247570753097534
✔️ squeeze
Tensor.squeeze()
는 텐서의 차원을 축소(제거)한 새로운 텐서를 반환한다.
tensor = torch.rand(1, 3, 3)
print(tensor)
t = tensor.squeeze()
print(t)
print(t.shape)
# output
# tensor([[[0.2378, 0.1449, 0.1843],
# [0.4728, 0.0580, 0.9944],
# [0.2301, 0.1764, 0.2485]]])
# tensor([[0.2378, 0.1449, 0.1843],
# [0.4728, 0.0580, 0.9944],
# [0.2301, 0.1764, 0.2485]])
# torch.Size([3, 3])
1x3x3의 텐서에 대해 .squeeze()를 적용했을 때 3x3으로 차원이 축소된 것을 확인할 수 있다.
✔️ unsqueeze
Tensor.unsqueeze()
는 .squeeze()와는 반대로 텐서의 차원을 증가(생성)시킨 새로운 텐서를 반환한다.
이 경우 증가시킬 차원의 방향을 dim 옵션으로 지정해주어야 한다.
tensor = torch.rand(1, 3, 3)
print(tensor)
t = tensor.unsqueeze(dim=0)
print(t)
print(t.shape)
# output
# tensor([[[0.3780, 0.5946, 0.6233],
# [0.0215, 0.3017, 0.6218],
# [0.0466, 0.6926, 0.7092]]])
# tensor([[[[0.3780, 0.5946, 0.6233],
# [0.0215, 0.3017, 0.6218],
# [0.0466, 0.6926, 0.7092]]]])
# torch.Size([1, 1, 3, 3])
✔️ stack
torch.stack()
은 텐서들을 결합한다.
torch.stack(tensors, dim=0, *, out=None)
이때 dim의 기본값은 0이다.
따라서 dim 옵션을 따로 지정하지 않았을 경우 아래 방향으로 텐서들이 결합한 형태이다.
x = torch.FloatTensor([1, 4])
y = torch.FloatTensor([2, 5])
z = torch.FloatTensor([3, 6])
print(torch.stack([x, y, z]))
# output
# tensor([[1., 4.],
# [2., 5.],
# [3., 6.]])
✔️ cat
torch.cat()
은 torch.stack()과 동일하게 텐서를 결합하는 메서드이다.
해당 차원을 늘려준 후 결합하기 때문에 쌓을 dim이 존재해야 하고 dim을 지정해 주어야 한다.
x = torch.randn(3, 3)
y = torch.randn(3, 3)
z = torch.cat((x, y), dim=0)
print(z)
print(z.size())
# output
# tensor([[ 1.1492, -1.5953, 0.8305],
# [-0.3136, 0.0373, -1.1060],
# [-2.9980, 0.2925, 1.7472],
# [-0.5904, 2.1679, -0.1241],
# [-0.0538, -1.1872, -0.3323],
# [-0.5231, 0.0733, -0.4277]])
# torch.Size([6, 3])
✔️ chunk
torch.chunk()
는 텐서를 여러 개로 나눌 때 사용한다.
torch.chunk(input, chunks, dim=0)
나눌 대상이 될 텐서와 나눌 개수, 나눌 차원의 방향을 인자로 받는다.
즉, torch.chunk()는 나눌 텐서의 개수가 정해져 있을 때 사용한다.
tensor = torch.rand(3, 6)
t1, t2, t3 = torch.chunk(tensor, 3, dim=1)
# 3은 chunk의 개수, dim은 기준이될 dim
print(tensor)
print(t1)
print(t2)
print(t3)
# output
# tensor([[0.9393, 0.9592, 0.5965, 0.0793, 0.7652, 0.9374],
# [0.8259, 0.7901, 0.4846, 0.0010, 0.3290, 0.4188],
# [0.6288, 0.6366, 0.2115, 0.5906, 0.0591, 0.0450]])
# tensor([[0.9393, 0.9592],
# [0.8259, 0.7901],
# [0.6288, 0.6366]])
# tensor([[0.5965, 0.0793],
# [0.4846, 0.0010],
# [0.2115, 0.5906]])
# tensor([[0.7652, 0.9374],
# [0.3290, 0.4188],
# [0.0591, 0.0450]])
✔️ split
torch.split()
도 텐서를 여러 개로 나눌 때 사용한다.
torch.chunk()가 나눌 텐서의 개수를 지정한다면 torch.split()은 나누어진 텐서 하나 당 크기를 지정한다.
tensor = torch.rand(3, 6)
t1, t2 = torch.split(tensor, 3, dim=1)
print(tensor)
print(t1)
print(t2)
# output
# tensor([[0.3084, 0.0062, 0.5784, 0.1557, 0.7011, 0.2024],
# [0.9844, 0.7181, 0.0286, 0.1599, 0.7431, 0.8248],
# [0.2361, 0.0135, 0.7826, 0.9212, 0.2481, 0.9945]])
# tensor([[0.3084, 0.0062, 0.5784],
# [0.9844, 0.7181, 0.0286],
# [0.2361, 0.0135, 0.7826]])
# tensor([[0.1557, 0.7011, 0.2024],
# [0.1599, 0.7431, 0.8248],
# [0.9212, 0.2481, 0.9945]])
따라서 torch.chunk()와 torch.split()에 동일한 인자를 주었을 때 같은 인자 3에 대해 결과값이 다르게 나타난다.
torch.chunk()는 텐서를 3개로 나누는 반면 torch.split()은 나누어진 텐서 하나당 크기를 3으로 지정한다.
따라서 torch.chunk()는 t1, t2, t3의 3개의 텐서를 얻을 수 있고 torch.split()은 t1, t2의 2개의 텐서를 얻는다.
✅ torch ↔ numpy
torch는 NumPy와 호환이 가능하다.
Torch의 Tensor를 NumPy의 array로 변환할 수 있고 그 반대의 경우도 가능하다.
numpy()
: torch -> numpyfrom_numpy()
: numpy -> torch
텐서가 CPU 상에 존재한다면 NumPy 배열은 메모리공간을 공유하기 때문에 텐서가 변하면 배열의 값도 변한다. (반대의 경우도 동일하다.)
a = torch.ones(7)
b = a.numpy()
print(a)
print(b)
# output
# tensor([1., 1., 1., 1., 1., 1., 1.])
# [1. 1. 1. 1. 1. 1. 1.]
a.add_(1)
print(a)
print(b)
# output
# tensor([2., 2., 2., 2., 2., 2., 2.])
# [2. 2. 2. 2. 2. 2. 2.]
.numpy()를 이용해 a라는 텐서를 NumPy의 array로 변환했다.
이 경우 a의 값을 변경하면 array인 b의 값도 변경된 것을 확인할 수 있다.
import numpy as np
a = np.ones(7)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)
# output
# [2. 2. 2. 2. 2. 2. 2.]
# tensor([2., 2., 2., 2., 2., 2., 2.], dtype=torch.float64)
.from_numpy()를 이용해 배열을 텐서로 변경했다.
이 경우에도 하나의 값이 변하면 다른 하나의 값이 변경된다.
🔍 참조
torch.Tensor.view https://pytorch.org/docs/stable/generated/torch.Tensor.view.html
torch.stack https://pytorch.org/docs/stable/generated/torch.stack.html?highlight=stack#torch.stack
'Python > PyTorch' 카테고리의 다른 글
[PyTorch] Torchvision과 utils.data (0) | 2022.02.23 |
---|---|
[PyTorch] nn과 nn.functional (0) | 2022.02.23 |
[PyTorch] CUDA와 자동미분 (0) | 2022.02.23 |
[PyTorch] 파이토치와 텐서 (0) | 2022.02.22 |
댓글