이것저것 기록

[DL, PyTorch] 텐서 슬라이싱, 브로드캐스팅, 기본 연산 본문

Data Science/ML & DL

[DL, PyTorch] 텐서 슬라이싱, 브로드캐스팅, 기본 연산

anweh 2020. 10. 10. 20:29

 

 

 

1. 브로드캐스팅 

두 행렬 A, B가 있을 때, 원래는 두 행렬의 크기가 같아야지만 덧셈/뺄셈을 수행할 수가 있다. 

그리고 두 행렬의 곱셈을 할 때는 (A x B) A의 마지막 차원과 B의 마지막 차원이 일치해야한다. 

 

이를 위해 파이토치에서는 브로드캐스팅 이라는 기능을 제공한다. 

브로드캐스팅 기능은 서로 크기가 다른 행렬들이 사칙연산을 수행할 수 있도록 자동으로 크기를 맞춰서 연산을 수행하게 해준다. 

import numpy as np
import torch 

# Case 1 : 같은 크기의 행렬
m1 = torch.FloatTensor([[3, 3]])
m2 = torch.FloatTensor([[2, 2]])
print(f'shape: m1 = {m1.shape}, m2 = {m2.shape}')
m3 = m1 + m2 
print(m3, m3.shape)



# Case 2 : 벡터와 행렬
m1 = torch.FloatTensor([[1, 2]])
m2 = torch.FloatTensor([3]) # [3] -> [3, 3]
print(f'shape: m1 = {m1.shape}, m2 = {m2.shape}')
m3 = m1 + m2 
print(m3, m3.shape)


# Case 3 : 크기가 다른 두 개의 행렬 
m1 = torch.FloatTensor([[1, 2]])
m2 = torch.FloatTensor([[3], [4]])
print(f'shape: m1 = {m1.shape}, m2 = {m2.shape}')
m3 = m1 + m2 
print(m3, m3.shape)

 

 

2. 텐서 슬라이싱

import numpy as np
import torch 

a = torch.empty(6, 6, dtype=torch.float)
print(a)
print(a.size())


# 첫 번째 행의 네 번째 열에 있는 원소
b = a[0, 3]
print(b)


# 네번째 열과 다섯번째 열에 있는 모든 원소
b = a[:, 3:5]
print(b)

 

 

3. 연산 

3.1 행렬곱셈, 곱셈 

import numpy as np
import torch 


# 행렬곱셈 (.matmul)
m1 = torch.FloatTensor([[1, 2], [3, 4]])
m2 = torch.FloatTensor([[1], [2]])
print('Shape of Matrix 1: ', m1.shape) # 2 x 2
print('Shape of Matrix 2: ', m2.shape) # 2 x 1
print(m1.matmul(m2)) # 2 x 1

# 곱셈 (.mul) -- element-wise 곱셈
m1 = torch.FloatTensor([[1, 2], [3, 4]])
m2 = torch.FloatTensor([[1], [2]])
print('Shape of Matrix 1: ', m1.shape) # 2 x 2
print('Shape of Matrix 2: ', m2.shape) # 2 x 1
print(m1 * m2) # 2 x 2
print(m1.mul(m2))

행렬곱셈에서 두 개의 행렬 A와 B가 matmul하게 되면 결과로 나오는 행렬의 크기는 행렬 A의 첫번째 차원, 행렬 B의 마지막 차원을 따르게 된다.

위의 예제에서 m1의 첫번째 차원은 2, m2의 마지막 차원은 1이므로 결과값의 크기는 2 x 1이 된 것이다.

element-wise 곱셈에선 서로 다른 크기의 행렬이 브로드캐스팅 된 후에 곱셈이 수행된다.

이는 동일한 크기의 행렬이 동일한 위치에 있는 원소끼리 곱하는 것과 같은 결과를 얻게 된다. 

 

 

3.2 평균

import numpy as np
import torch 


# 1차원 행렬의 평균 
t1 = torch.FloatTensor([2, 3])
print(t1)
print(t1.mean()) # tensor(2.5000)


# 2차원 행렬의 평균
t2 = torch.FloatTensor([[3, 3], [6, 9]])
print(t2) 
print(t2.mean()) # tensor(5.2500)


# dim값을 인자로 주기 
print(t2.mean(dim=0)) # tensor([4.5000, 6.0000])
print(t2.mean(dim=1)) # tensor([3.0000, 7.5000])
print(t2.mean(dim=-1)) # tensor([3.0000, 7.5000])

.mean()에서 dim을 인자로 주게 되면 어느 차원을 기준으로 평균을 구할지 설정할 수 있다.

아무 것도 설정하지 않으면 전체 평균을 계산하고

dim=0은 첫번째차원 즉 행을 기준으로 평균을 계산한다. 

dim=1은 두번째 차원 즉 열을 기준으로 평균을 계산하고 dim=-1은 마지막 차원으로 평균을 계산하는데 위의 예제에선 마지막 차원 = 열이므로 t2.mean(dim=1)과 출력값이 동일하게 되는 것이다. 

 

3.3 덧셈 

import numpy as np
import torch 


# 1차원 행렬의 합 
t1 = torch.FloatTensor([2, 3])
print(t1)
print(t1.sum()) # tensor(5.)


# 2차원 행렬의 합
t2 = torch.FloatTensor([[3, 3], [6, 9]])
print(t2)
print(t2.sum()) # tensor(21.)
print(t2.sum(dim=0)) # tensor([ 9., 12.])
print(t2.sum(dim=1)) # tensor([ 6., 15.])
print(t2.sum(dim=-1)) # tensor([ 6., 15.])

덧셈은 평균과 완전히 동일하다. (평균 대신 덧셈을 하는 것 이외엔 사용 방법이 동일함.) 

 

 

3.4 최대, 아그맥스 

# max & argmax
t = torch.FloatTensor([[1, 3], [6, 9]])

print(t.max())
print(t.max(dim=0))

print('Max: ', t.max(dim=0)[0])
print('Argmax: ', t.max(dim=0)[1])

print(t.max(dim=1))
print(t.max(dim=-1))

최대(max)는 최대값을 반환하고 아그맥스(argmax)는 최대값을 가진 인덱스를 반환한다. 

차원을 지정하면 두개의 데이터를 뽑을 수 있다.

t.max(dim=0)[0]이 최대값(max)를 나타내고,

t.max(dim=0)[1]이 최대값을 갖는 데이터 인덱스를 나타내게 된다.

 

 

 

참고 링크: wikidocs.net/52460 

Comments