본문 바로가기
Python

파이토치, 텐서 (Tensor) 의 연산

by 슬통이 2020. 7. 15.
반응형

지난 시간, 우리는 텐서가 행렬 혹은 Array의 다른 이름이라는 것을 배웠다. 오늘은 행렬들의 연산에 대하여 다루어보자.

파이토치 (Pytorch) 불러오기 및 행렬 선언

import torch

이번 튜토리얼에서 사용할 텐서들을 만들어보자.

torch.manual_seed(1234)
## <torch._C.Generator object at 0x7f8f824768d0>
A = torch.arange(1.0, 13.0).view(4, 3)
B = torch.rand(4, 3)
C = torch.rand(3, 4)
A; B; C
## tensor([[ 1.,  2.,  3.],
##         [ 4.,  5.,  6.],
##         [ 7.,  8.,  9.],
##         [10., 11., 12.]])
## tensor([[0.0290, 0.4019, 0.2598],
##         [0.3666, 0.0583, 0.7006],
##         [0.0518, 0.4681, 0.6738],
##         [0.3315, 0.7837, 0.5631]])
## tensor([[0.7749, 0.8208, 0.2793, 0.6817],
##         [0.2837, 0.6567, 0.2388, 0.7313],
##         [0.6012, 0.3043, 0.2548, 0.6294]])

행렬 덧셈과 뺄셈

R에서 배운 vectorized 프로그래밍에 익숙하다면 행렬들의 연산이 아주 자연스럽게 느껴질 것이다. 크기가 같은 행렬 A, B는 다음과 같이 더하고 뺄 수 있다.

A + B
## tensor([[ 1.0290,  2.4019,  3.2598],
##         [ 4.3666,  5.0583,  6.7006],
##         [ 7.0518,  8.4681,  9.6738],
##         [10.3315, 11.7837, 12.5631]])
A - B
## tensor([[ 0.9710,  1.5981,  2.7402],
##         [ 3.6334,  4.9417,  5.2994],
##         [ 6.9482,  7.5319,  8.3262],
##         [ 9.6685, 10.2163, 11.4369]])

R에서와 마찬가지로, 행렬과 상수와의 사칙연산은 각 원소에 적용되는 것을 확인하자.

A - 1
## tensor([[ 0.,  1.,  2.],
##         [ 3.,  4.,  5.],
##         [ 6.,  7.,  8.],
##         [ 9., 10., 11.]])
B + 2
## tensor([[2.0290, 2.4019, 2.2598],
##         [2.3666, 2.0583, 2.7006],
##         [2.0518, 2.4681, 2.6738],
##         [2.3315, 2.7837, 2.5631]])
A * 3
## tensor([[ 3.,  6.,  9.],
##         [12., 15., 18.],
##         [21., 24., 27.],
##         [30., 33., 36.]])
B**2

# A의 각 원소를 3으로 나눈 나머지
## tensor([[0.0008, 0.1615, 0.0675],
##         [0.1344, 0.0034, 0.4909],
##         [0.0027, 0.2192, 0.4540],
##         [0.1099, 0.6142, 0.3170]])
A % 3 
## tensor([[1., 2., 0.],
##         [1., 2., 0.],
##         [1., 2., 0.],
##         [1., 2., 0.]])

sqrtlog 함수 역시 각 원소별 적용이 가능하다.

torch.sqrt(A)
## tensor([[1.0000, 1.4142, 1.7321],
##         [2.0000, 2.2361, 2.4495],
##         [2.6458, 2.8284, 3.0000],
##         [3.1623, 3.3166, 3.4641]])
torch.log(B)
## tensor([[-3.5412, -0.9116, -1.3477],
##         [-1.0034, -2.8421, -0.3558],
##         [-2.9604, -0.7590, -0.3948],
##         [-1.1042, -0.2437, -0.5744]])

행렬 곱셈

행렬 곱셈 역시 R에서 행렬들의 움짐임과 똑같다. 그냥 곱하면 원소별로 곱해지고,

A * B
## tensor([[0.0290, 0.8038, 0.7795],
##         [1.4666, 0.2915, 4.2039],
##         [0.3626, 3.7451, 6.0643],
##         [3.3146, 8.6208, 6.7568]])

R에서는 행렬끼리의 일반적인 곱셈을 하려면 %*% 기호를 사용했지만, 파이토치에서는 다음과 같이 @ 기호를 사용한다.

A @ C
## tensor([[ 3.1459,  3.0472,  1.5210,  4.0324],
##         [ 8.1251,  8.3928,  3.8394, 10.1594],
##         [13.1044, 13.7384,  6.1578, 16.2865],
##         [18.0836, 19.0840,  8.4761, 22.4136]])

파이토치의 행렬 곱셈은 다음과 같은 방법들도 있으니 알아두자.

torch.mm(A, C)
## tensor([[ 3.1459,  3.0472,  1.5210,  4.0324],
##         [ 8.1251,  8.3928,  3.8394, 10.1594],
##         [13.1044, 13.7384,  6.1578, 16.2865],
##         [18.0836, 19.0840,  8.4761, 22.4136]])
torch.matmul(A, C)
## tensor([[ 3.1459,  3.0472,  1.5210,  4.0324],
##         [ 8.1251,  8.3928,  3.8394, 10.1594],
##         [13.1044, 13.7384,  6.1578, 16.2865],
##         [18.0836, 19.0840,  8.4761, 22.4136]])
A.mm(C)
## tensor([[ 3.1459,  3.0472,  1.5210,  4.0324],
##         [ 8.1251,  8.3928,  3.8394, 10.1594],
##         [13.1044, 13.7384,  6.1578, 16.2865],
##         [18.0836, 19.0840,  8.4761, 22.4136]])
A.matmul(C)
## tensor([[ 3.1459,  3.0472,  1.5210,  4.0324],
##         [ 8.1251,  8.3928,  3.8394, 10.1594],
##         [13.1044, 13.7384,  6.1578, 16.2865],
##         [18.0836, 19.0840,  8.4761, 22.4136]])

행렬 전치 (transpose)

전치는 주어진 행렬을 flip하는 것인데, 다음의 문법 구조를 가지고 있다.

torch.transpose(input, dim0, dim1)

dim0, dim1는 바꿀 차원을 의미한다. ‘바꿀 차원을 의미한다?’ 라고 생각할 수 있다. 맞다. 우리가 행렬을 전치하는 경우에는 transpose를 취하는 대상이 2차원이므로 지정해주는 차원이 정해져있다. 하지만, 텐서의 차원이 3차원이 되면서 부터는 전치를 해주는 차원을 지정해줘야한다.

A
## tensor([[ 1.,  2.,  3.],
##         [ 4.,  5.,  6.],
##         [ 7.,  8.,  9.],
##         [10., 11., 12.]])
A.transpose(0, 1)
## tensor([[ 1.,  4.,  7., 10.],
##         [ 2.,  5.,  8., 11.],
##         [ 3.,  6.,  9., 12.]])

3차원 텐서의 경우는 다음을 참고하자.

D = torch.arange(1, 19).view(2, 3, 3)
D

# 3차원 텐서의 차원은 0, 1, 2 세가지가 있다.
## tensor([[[ 1,  2,  3],
##          [ 4,  5,  6],
##          [ 7,  8,  9]],
## 
##         [[10, 11, 12],
##          [13, 14, 15],
##          [16, 17, 18]]])
D.transpose(1, 2)
## tensor([[[ 1,  4,  7],
##          [ 2,  5,  8],
##          [ 3,  6,  9]],
## 
##         [[10, 13, 16],
##          [11, 14, 17],
##          [12, 15, 18]]])

3차원 텐서는 나중에 시간을 내어따로 배워보도록 하자.

행렬과 벡터 연산

다음 연산에서 우리는 행렬과 열, 행 벡터의 연산은 차원이 맞을 경우 우리가 예상한대로 된다는 것을 알 수 있다.

A + torch.tensor([1.0, 2.0, 3.0])
## tensor([[ 2.,  4.,  6.],
##         [ 5.,  7.,  9.],
##         [ 8., 10., 12.],
##         [11., 13., 15.]])
A + torch.tensor([[1.0],
                  [2.0],
                  [3.0],
                  [4.0]])
## tensor([[ 2.,  3.,  4.],
##         [ 6.,  7.,  8.],
##         [10., 11., 12.],
##         [14., 15., 16.]])

벡터와 벡터 연산, 내적과 외적

벡터끼리의 연산도 행렬과 행렬끼리의 연산과 마찬가지라고 생각하면 된다.

a = torch.arange(1, 4).view(-1, 3)
b = torch.arange(3, 6).view(3,-1)
a @ b
## tensor([[26]])
b @ a
## tensor([[ 3,  6,  9],
##         [ 4,  8, 12],
##         [ 5, 10, 15]])

한가지 주의할 점은 벡터끼리의 연산이더라도 꼭 차원을 선언해줘서 열벡터와 행벡터를 분명히 해줘야 한다는 점이다.

a = torch.arange(1, 4)
b = torch.arange(3, 6).view(3,-1)
b @ a

위의 코드는 연산 에러가 나는데, 이유는 a의 차원이 b의 차원과 맞지 않기 때문이다.

a = torch.arange(1, 4)
b = torch.arange(3, 6).view(3,-1)
a.size()
## torch.Size([3])
b.size()
## torch.Size([3, 1])

아래는 현재 검색 가능한 파이토치 딥러닝 책 광고입니다! 파트너스 활동을 통해서 일정액의 수수료를 받을 수 있다고 하네요.ㅎㅎ 언젠가 제가 쓰는 이 블로그도 저 자리에 끼어있었으면 좋겠네요ㅎㅎ 밑에 책들은 한번 사서 읽어보고, 리뷰를 올려보도록 하겠습니다. =]

 

파이토치 첫걸음:딥러닝 기초부터 RNN 오토인코더 GAN 실전 기법까지, 한빛미디어 펭귄브로의 3분 딥러닝 파이토치맛:PyTorch 코드로 맛보는, 한빛미디어 딥러닝에 목마른 사람들을 위한 PyTorch:개인용 GPU 학습 서버 구축부터 딥러닝까지, 비제이퍼블릭 PyTorch로 시작하는 딥러닝:딥러닝 기초에서 최신 모던 아키텍처까지, 에이콘출판 [제이펍] 파이토치 첫걸음

반응형

댓글