지난 시간, 우리는 텐서가 행렬 혹은 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.]])
sqrt
나 log
함수 역시 각 원소별 적용이 가능하다.
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])
아래는 현재 검색 가능한 파이토치 딥러닝 책 광고입니다! 파트너스 활동을 통해서 일정액의 수수료를 받을 수 있다고 하네요.ㅎㅎ 언젠가 제가 쓰는 이 블로그도 저 자리에 끼어있었으면 좋겠네요ㅎㅎ 밑에 책들은 한번 사서 읽어보고, 리뷰를 올려보도록 하겠습니다. =]
'Python' 카테고리의 다른 글
신경망과 회귀분석 비교하기 (Neural Net vs. Regression) (0) | 2020.07.22 |
---|---|
파이토치, 신경망 정의 (Custom nn Modules) (0) | 2020.07.20 |
파이토치, 미분 자동추적 기능 (Autograd) 에 대하여 (0) | 2020.07.18 |
R과 파이토치, 텐서의 변환 (Bridge) (2) | 2020.07.15 |
파이토치, 텐서 (Tensor) 만들기 (0) | 2020.07.15 |
댓글