본문 바로가기

AI/PyTorch

PyTorch 텐서 조작 #텐서 선언 #곱셈 #평균 #덧셈 #최대 #아그맥스

백터, 행렬, 텐서 (Vector, Matrix, Tensor)

- 벡터 : 1차원으로 구성된 값, 1차원 텐서라고 부르기도 함

- 행렬 : 2차원으로 구성된 값, 2차원 텐서라고 부르기도 함

- 텐서 : 3차원 이상으로 구성된 값, 3,4,5...차원 텐서라고 부를 수 있음

- PyTorch Tensor Shape Convention : 딥러닝에서 다루고 있는 행렬이나 텐서의 크기는 중요함

 

텐서 표기
2D Tensor(Typical Simple Setting) |t| = (Batch size, dim), 2차원 텐서의 크기 |t|를 (batch size × dimension)으로 표현하였을 경우
3D Tensor(Typical Computer Vision) |t| = (batch size, width, height), 비전 분야에서의 3차원 텐서
3D Tensor(Typical natural Language Processing) |t| = (batch size, length, dim), NLP 분야에서의 3차원 센서

 


넘파이로 텐서 만들기(벡터와 행렬 만들기)

 

1. numpy import

# numpy 임포트
import numpy as np

 

 

2. 1D with Numpy

- 넘파이로 1차원 텐서(벡터) 생성

# Numpy로 1차원 텐서(벡터) 생성
t = np.array([0., 1., 2., 3., 4., 5., 6.]) 
print(t)

[0. 1. 2. 3. 4. 5. 6.]

 

 

- 1차원 텐서인 벡터의 차원과 크기 출력

# 1차원 텐서인 벡터의 차원과 크기 출력
print(t.ndim) # 차원 출력
print(t.shape) # 크기 출력

1

(7,)

 

 

- 넘파이에서 각 벡터의 원소에 접근, 넘파이 인덱스는 0부터 시작

# Numpy에서 각 벡터의 원소에 접근하는 방법
# Numpy에서 인덱스는 0부터 시작

print(t[0], t[1], t[-1]) # 각 인덱스 원소 출력

0.0 1.0 6.0

 

 

- 넘파이에서 범위를 지정해 출력

# 범위 지정

print(t[2:5], t[4:-1]) # 2~4번 인덱스, 4번~끝에서 첫번째까지 인덱스

[2. 3. 4.] [4. 5.]

 

print(t[:2], t[3:]) # 1번 인덱스까지, 3번부터 끝까지

[0. 1.] [3. 4. 5. 6.]

 

 

3. 2D with Numpy

- 넘파이로 2차원 행렬 생성

# 넘파이로 2차원 행렬 생성
t = np.array([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.], [10., 11., 12.]])
print(t)

[[ 1. 2. 3.]

 [ 4. 5. 6.]

 [ 7. 8. 9.]

 [10. 11. 12.]]

 

 

- 생성한 행렬의 차원과 크기 출력

print(t.ndim) # 2차원
print(t.shape) # 4행 3열의 크기

2

(4, 3)

 


파이토치 텐서 선언(PyTorch Tensor Allocation)

 

1. 토치 임포트

# torch 임포트
import torch

 

 

2. 1D with PyTorch

- 파이토치 1차원 텐서(벡터) 생성

# 파이토치 1차원 텐서(벡터) 생성
t = torch.FloatTensor([0., 1., 2., 3., 4., 5., 6.])
print(t)

tensor([0., 1., 2., 3., 4., 5., 6.])

 

 

- 생성한 1차원 텐서의 차원, 크기 확인

print(t.dim()) # 차원
print(t.shape) # 크기
print(t.size()) # 크기

1

torch.Size([7])

torch.Size([7])

 

 

- 생성한 1차원 텐서에 접근

print(t[0], t[1], t[-1])  # 인덱스로 접근
print(t[2:5], t[4:-1])    # 슬라이싱
print(t[:2], t[3:])       # 슬라이싱

tensor(0.) tensor(1.) tensor(6.)

tensor([2., 3., 4.]) tensor([4., 5.])

tensor([0., 1.]) tensor([3., 4., 5., 6.])

 

 

3. 2D with PyTorch

- 파이토치로 2차원 텐서(행렬) 생성

# 파이토치로 2차원 텐서(행렬) 생성
t = torch.FloatTensor([[1., 2., 3.],
                       [4., 5., 6.],
                       [7., 8., 9.],
                       [10., 11., 12.]
                      ])
print(t)

tensor([[ 1., 2., 3.],

          [ 4., 5., 6.],

          [ 7., 8., 9.],

          [10., 11., 12.]])

 

 

- 생성한 2차원 텐서의 차원 및 크기 확인

print(t.dim()) # 차원
print(t.shape) # 크기
print(t.size()) # 크기

2

torch.Size([4, 3])

torch.Size([4, 3])

 

 

- 생성한 2차원 텐서 접근

print(t[:, 1]) # 첫 번째 차원을 전체 선택한 상황에서 두번째 차원의 첫번째 것만 가져옴
print(t[:, 0].size())

tensor([ 2., 5., 8., 11.])

torch.Size([4])

 

print(t[:, :-1]) # 첫번째 차원을 전체 선택한 상황에서 두번째 차원에서는 맨 마지막에서 첫번째를 제외하고 다 가져온다.

tensor([[ 1., 2.],

          [ 4., 5.],

          [ 7., 8.],

          [10., 11.]])

 

 

4. 브로드캐스팅(Brodcasting)

- 원칙적으로 행렬의 크기가 같아야만 행렬의 덧셈, 뺄셈이 가능하지만 파이토치는 자동으로 크기를 맞춰서 연산을 수행하는 브로드캐스팅이라는 기능을 제공

 

 

- 두 행렬의 크기가 같은 경우 행렬의 덧셈

# 두 행렬의 크기가 같은 경우
m1 = torch.FloatTensor([[3, 3]])
m2 = torch.FloatTensor([[2, 2]])
print(m1 + m2)

tensor([[5., 5.]])

 

 

- 두 행렬의 크기가 다른 경우 행렬의 덧셈

# 두 행렬의 크기가 다른 경우
m1 = torch.FloatTensor([[1, 2]])
m2 = torch.FloatTensor([3]) # [3] -> 파이토치는 [3, 3]으로 자동 변환하여 계산한다.
print(m1 + m2)

tensor([[4., 5.]])

 

 

5. 자주 사용되는 기능

1) 행렬 곱셈과 원소별 곱셈의 차이

- 파이토치 텐서로 행렬 곱셈, mautmul() 사용

# 파이토치 텐서로 행렬 곱셈, muatmul() 사용
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)
print(m2)
print(m1.matmul(m2)) # 2 x 1

Shape of Matrix 1: torch.Size([2, 2])

Shape of Matrix 2: torch.Size([2, 1])

tensor([[1., 2.],

          [3., 4.]])

tensor([[1.],

          [2.]])

tensor([[ 5.],

          [11.]])

 

* 행렬의 곱셈에 대한 개념은 구글링을 해보자.

 

 

- 원소별 곱셈, mul() 사용

# element-wise 곱셈: 동일한 크기의 행렬이 동일한 위치에 있는 원소끼리 곱함, mul() 사용
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)
print(m2)
print(m1 * m2) # 2 x 2
print(m1.mul(m2))

Shape of Matrix 1: torch.Size([2, 2])

Shape of Matrix 2: torch.Size([2, 1])

tensor([[1., 2.],

          [3., 4.]])

tensor([[1.],

          [2.]])

tensor([[1., 2.],

          [6., 8.]])

tensor([[1., 2.],

          [6., 8.]])

 

 

2) 행렬 평균

- 평균은 mean()을 사용

# mean() 사용
t = torch.FloatTensor([1, 2])
print(t)
print(t.mean())

tensor([1., 2.])

tensor(1.5000)

 

 

- 2차원 행렬로 평균 값 계산

# 2차원 행렬로 평균 값 구하기
t = torch.FloatTensor([[1, 2], [3, 4]])
print(t)
print(t.mean()) # 4개 원소의 평균이 나옴

tensor([[1., 2.],

          [3., 4.]])

tensor(2.5000)

 

 

- 차원 dimension을 인자로 주는 경우

# 차원 dimension을 인자로 주는 경우
'''
dim = 0 은 첫번째 차원을 의미, 행렬에서 첫번째 차원은 '행'을 의미, 인자로 dim을 주면 해당 차원을 제거한다는 의미, 
이는 행열에서 '열' 만을 남긴다는 의미
'''
print(t.mean(dim=0)) # dim=0은 입력에서 첫번째 차원을 제거, 1과 3의 평균, 2와 4의 평균을 구하게 된다.

tensor([2., 3.])

 

print(t.mean(dim=1)) # dim=1은 입력에서 열의 차원이 제거, 크기에서 (2,1)이 됨, 1과 2의 평균, 3과 4의 평균을 구함

tensor([1.5000, 3.5000])

 

print(t.mean(dim=-1)) # dim=-1은 입력에서 마지막 차원을 제거한다는 의미고, 이는 결국 열을 제거한다는 의미

tensor([1.5000, 3.5000])

 

 

3) 행렬 덧셈

- 텐서의 덧셈(sum)은 평균(mean)과 연산 방법과 인자가 의미하는 것이 동일

 

 

- 2차원 텐서 생성

# 2차원 텐서 생성
t = torch.FloatTensor([[1,2], [3,4]])
print(t)

tensor([[1., 2.],

          [3., 4.]])

 

 

- 생성한 텐서의 덧셈 및 인자를 활용한 덧셈 수행

print(t.sum()) # 단순히 원소 전체의 덧셈을 수행
print(t.sum(dim=0)) # 행을 제거
print(t.sum(dim=1)) # 열을 제거
print(t.sum(dim=-1)) # 열을 제거

tensor(10.)

tensor([4., 6.])

tensor([3., 7.])

tensor([3., 7.])

 

 

4) 최대(Max)와 아그맥스(ArgMax)

- 최대(Max)는 원소의 최대값을 리턴, 아그맥스(ArgMax)는 최대값을 가진 인덱스를 리턴

 

 

- (2,2) 크기의 행렬 선언

# 2차원 행렬 생성
t = torch.FloatTensor([[1, 2], [3, 4]])
print(t)

tensor([[1., 2.],

          [3., 4.]])

 

 

- max 실행

# max 실행
print(t.max())

tensor(4.) # 원소들 중 최대값은 4이다.

 

 

- 인자로 dim = 0을 주고 max 실행, max 인자에 dim 인자를 주면 argmax도 함께 리턴된다.

print(t.max(dim=0))

torch.return_types.max(

values=tensor([3., 4.]),

indices=tensor([1, 1]))

# dim 을 0으로 주면 첫번째 차원(행)을 제거한다는 의미, dim 을 1로 주면 두번째 차원(열)을 제거한다는 의미

 

 

- dim 인자를 주고 max나 argmax 하나만 리턴받고 싶다면 리턴값에 인덱스 부여

# dim 인자를 주고 max나 argmax 하나만 리턴받고 싶다면 리턴값에 인덱스를 부여
print('Max: ', t.max(dim=0)[0])
print('Argmax: ', t.max(dim=0)[1])

Max: tensor([3., 4.])

Argmax: tensor([1, 1])

 

 

- dim = 1로 인자를 주었을 때와 dim = -1로 인자를 주었을 때(열을 제거했을 때)

# dim = 1로 인자를 주었을 때와 dim = -1로 인자를 주었을 때
print(t.max(dim=1))
print(t.max(dim=-1))

torch.return_types.max(

values=tensor([2., 4.]),

indices=tensor([1, 1]))

torch.return_types.max(

values=tensor([2., 4.]),

indices=tensor([1, 1]))

 

 


텐서와 차원(dimension) 을 그림으로 이해해 보자.

 

2차원 텐서와 sum(), dimension

# 2차원 텐서(행렬)
t2 = torch.FloatTensor([
                       [1,2],
                       [3,4],
                       [5,6],
                       [7,8]                      
])

print(t2)
print(t2.dim()) # 차원
print(t2.size())# 크기
print(t2.shape) # 크기

t2 구조

 

- dimention = 0 일 때 sum()

print(t2.sum(dim = 0))

dim = 0 일 때 sum() 결과
t2.sum(dim = 0)

 

 

- dimention = 1 일 때 sum()

print(t2.sum(dim = 1))

dim = 1 일 때 sum() 결과
t2.sum(dim = 1)

 

 


3차원 텐서와 sum(), dimension

# 3차원 텐서
t3 = torch.FloatTensor([
                        [[1,2],
                         [3,4]
                         ],
                        [[5,6],
                         [7,8]
                         ]                       
])
print(t3)
print(t3.dim()) # 차원
print(t3.size())# 크기
print(t3.shape) # 크기

t3 구조

 

 

- dimention = 0 일 때 sum()

print(t3.sum(dim = 0))

dim = 0 일 때 sum() 결과

 

t3.sum(dim = 0)

 

 

- dimention = 1 일 때 sum()

print(t3.sum(dim = 1))

 

dim = 1 일 때 sum() 결과
t3.sum(dim = 1)

 

 

 

- dimention = 2 일 때 sum()

print(t3.sum(dim = 2))

dim = 2 일 때 sum() 결과
t3.sum(dim = 2)

 

 


참고:

https://wikidocs.net/book/2788

 

PyTorch로 시작하는 딥 러닝 입문

이 책은 딥 러닝 프레임워크 PyTorch를 사용하여 딥 러닝에 입문하는 것을 목표로 합니다. 이 책은 2019년에 작성된 책으로 비영리적 목적으로 작성되어 출판 ...

wikidocs.net

 

반응형