欲速不達

일을 급히 하고자 서두르면 도리어 이루지 못한다.

Fantastic AI, Fantastic World

DS | Data Science/ML | Machine Learning

[Pytorch] 파이토치 연산자 : 사칙연산, 인덱싱

_껀이_ 2022. 9. 28. 11:51
728x90
반응형

 

Pytorch는 벡터, 행렬 등의 다양한 연산을 지원한다. 기본적인 사칙연산부터 선형대수, 나아가서는 머신러닝에 중요한 모듈을 구성할 수 있는 메서드를 포함한다.

 

1. torch 사칙 연산

1)  torch.add()

torch.add()는 '+'로 대체 가능하며 벡터 혹은 행렬의 해당 위치의 값을 더해준다. 모양이 같은 벡터나 행렬이 아니어도 각 위치에 대해 값이 연산된다.

import torch

A, B = torch.tensor([2]), torch.tensor([3])
torch.add(A,B)
>> tensor([5])

 

tensor([2])와 tensor([3]) 길이가 1인 1차원 텐서이므로 연산 결과는 tensor([5])의 1차원 텐서로 나온다.

torch.add(A,7)
>> tensor([9])

 

위의 코드와 같이 tensor와 int 값이 피연산자로 입력될 수 있는데 이때도 tensor로 변환해서 연산이 된다. 입력값 중 하나라도 tensor로 입력되면 결과값은 tensor 값으로 출력된다.

C, D = torch.tensor([1,2,3]), torch.tensor([[4],[5],[6]])
torch.add(C,D)

>> tensor([[ 5],[ 6],[ 7],
           [ 8],[ 9],[10],
           [11],[12],[13]])

모양이 다른 tensor지만, 각 위치 값에 대해 연산이 작용되어서 새로운 모양의 행렬이 되었다. (1,3) + (3,1) = (3,3) 크기의 행렬 값이 나온다.

 

 

아래의 torch.sub() : 뺄셈, torch.mul() : 곱셈, torch.div() : 나눗셈은 위의 torch.add()와 유사하게 작동하기 때문에 설명은 생략하고 예시 코드만 작성해 놓았다.

 

2) torch.sub()

A, B = torch.tensor([5]), torch.tensor([3])
torch.sub(A,B)
>> tensor([2])

 

3) torch.mul()

A, B = torch.tensor([2]), torch.tensor([3])
torch.add(A,B)
>> tensor([6])

 

4) torch.div()

A, B = torch.tensor([6]), torch.tensor([3])
torch.add(A,B)
>> tensor([2])

 

 

5) torch.matmul() : 행렬곱

torch.matmul()은 행렬곱을 지원한다. 위의 torch.mul()이 입력값 간의 같은 위치에서의 곱셈 연산을 했다면, matmul()에서는 행렬곱을 한다.

 

행렬곱은 연산되는 순서에 따라 모양을 조절해주어야한다.

A = torch.tensor([[1,2,3],
                  [4,5,6]])
B = torch.tensor([10,20,30])

torch.matmul(A,B)
>> tensor([140,320])

matmul()은 A@B.T의 값을 한번 더 Transpose해서 반환해준다. 작동방식은 행렬곱과 같으며, 입력되는 텐서의 모양에 주의해야 된다.

 

6) torch.addmm()

torch.addmm()은 torch.add()와 torch.matmul()을 조합한 것이다. 피연산자로는 M, mat1, mat2가 순서대로 입력되며, mat1과 mat2를 matmul한 다음 M과 더해주는 것과 같다.

M = torch.randn(2, 3)
mat1 = torch.randn(2, 3)
mat2 = torch.randn(3, 3)

torch.addmm(M, mat1, mat2)
>> tensor([[-1.4530, -0.8033, -2.7922],
           [-0.2319,  1.0977, -0.9210]])

torch.add(M,torch.matmul(mat1,mat2))
>> tensor([[-1.4530, -0.8033, -2.7922],
           [-0.2319,  1.0977, -0.9210]])

이때 M의 모양은 mat1과 mat2의 행렬곱한 결과와 모양이 같아야 연산이 가능하다.

 

 

이 외의 연산 예시나 설명되지 않은 부분은 아래 공식문서에서 확인할 수 있다.

 

https://pytorch.org/docs/stable/torch.html

 

torch — PyTorch 1.12 documentation

Shortcuts

pytorch.org

 

 

2. Indexing : 인덱싱

1) torch.select_index(input, axis, index)

텐서의 특정 인덱스에 해당하는 값을 찾을 때 torch.select_index(input, axis, index)를 사용한다.

A = torch.Tensor([[1, 2],
                  [3, 4]])

indices = torch.tensor([0])
output = torch.index_select(A,1,indices)
>> tensor([[1],
           [3]])

input 위치에 인덱스를 찾으려는 대상 행렬을 넣고, axis에는 찾으려는 축을 넣는다. axis = 0은 x축, axis = 1은 y축 방향에서 값을 찾으며 인덱스 값에 해당하는 값을 찾는다. 인덱스 값으로는 텐서를 입력으로 한다. 

 

axis 값이 다른 메서드와는 다르게 axis=0에서부터 최저차원으로 할당되는 것과 인덱스 값에 들어가야하는 텐서값을 명확하게 조절할 줄 모르는 점 때문에 개인적으로 선호하지는 않지만, 대량의 데이터에 대해서 특정 열 혹은 행을 뽑아낼때 유용할 것으로 보인다.

 

2) 일반적인 파이썬 리스트 인덱싱 방법

제목 그대로 일반적인 파이썬 리스트 인덱싱 방법과 같다.

A = torch.Tensor([[1, 2],
                  [3, 4]])
                  
output = torch.tensor([A[0][0],A[1][0]])
>> tensor([1, 3])

매우 이해하기가 쉽고 직관적이라는 장점은 있지만, 차수가 높을 경우에는 인덱싱 작성 과정에서 오류가 날 수 있으니 주의해야한다.

 

3) torch.gather(input, axis, index) : 대각 요소 추출

A = torch.Tensor([[1, 2],
                  [3, 4]])

output = torch.gather(A, 1, torch.tensor([[0],[1]]))
>> tensor([[1],
           [4]])

gather는 input으로 들어온 대상 행렬을 index만큼 대각선 요소를 추출한다. 시작은 좌측최상단 요소부터 인덱스가 0으로 시작한다. 이때, 인덱스로 들어오는 텐서는 대상 행렬(A)의 크기보다 작거나 같아야하며, axis는 일반적인 axis 개념과 같이 0 : 대상행렬의 최고차수부터 시작한다.

 

 

 

728x90
반응형