참고자료: https://wikidocs.net/book/2788
벡터, 행렬 그리고 텐서
1️⃣백터, 행렬, 텐서 이해하기
- 스칼라: 차원이 없는 값
- 벡터: 1차원으로 구성된 값
- 행렬(Matrix): 2차원으로 구성된 값
- 텐서(Tensor): 3차원으로 구성된 값
👉🏻데이터 사이언스 분야 한정으로 3차원 이상의 텐서는 그냥 다차원 행렬 또는 배열로 간주할 수 있다. 또 벡터나 행렬을 그냥 1차원 텐서, 2차원 텐서라고 부르기도 한다.
2️⃣PyTorch Tensor Shape Convention
👉🏻다루고 있는 텐서의 크기를 고려하는게 중요한데 행렬과 텐서의 크기 표현 방식을 알아보자!
✅2D Tensor(2차원 텐서)
✅3D Tensor - 비전 분야에서의 3차원 텐서
👉🏻일반적인 자연어 처리보다 비전분야(이미지, 영상 처리)를 다루면 더 복잡한 텐서를 다룬다.
✅3D Tensor - NLP 분야에서의 3차원 텐서
👉🏻batch size, 문장 길이, 단어 벡터의 차원 이라는 3차원 텐서를 사용한다.
넘파이로 텐서 만들기(벡터와 행렬 만들기)
import numpy as np
👉🏻먼저 Numpy를 import해준다.
1️⃣1D with Numpy
t = np.array([0., 1., 2., 3., 4., 5., 6.])
#파이썬으로 설명하면 List를 생성해서 np.array로 1차원 array로 변환함.
print(t)
#[0. 1. 2. 3. 4. 5. 6.]
👉🏻Numpy로 1차원 텐서인 벡터를 만든다.
print('Rank of t: ', t.ndim)
print('Shape of t:', t.shape)
#Rank of t: 1
#Shape of t: (7,)
👉🏻1차원 텐서인 벡터의 차원과 크기를 출력한다.
- .ndim: 몇 차원인지 출력한다. → 현재는 백터라 1차원(1차원 벡터, 2차원 행렬, 3차원 텐서)
- .shape: 크기를 출력한다. (7,)은 (1, 7)을 의미한다. (1 x 7)
✅Numpy 기초
print('t[0] t[1] t[-1] = ', t[0], t[1], t[-1])
#t[0] t[1] t[-1] = 0.0 1.0 6.0
👉🏻인덱스로 원소에 접근할 수 있다.
print('t[2:5] t[4:-1] = ', t[2:5], t[4:-1])
print('t[:2] t[3:] = ', t[:2], t[3:])
#t[2:5] t[4:-1] = [2. 3. 4.] [4. 5.]
#t[:2] t[3:] = [0. 1.] [3. 4. 5. 6.]
👉🏻[시작 번호 : 끝 번호]로 범위를 지정해 원소를 가져올 수 있다.
2️⃣2D with Numpy
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.]]
👉🏻2차원 행렬을 만들었다.
print('Rank of t: ', t.ndim)
print('Shape of t: ', t.shape)
#Rank of t: 2
#Shape of t: (4, 3)
👉🏻차원과 모양은 다음과 같다.
파이토치 텐서 선언하기
import torch
👉🏻먼저 torch를 import해준다.
1️⃣1D with PyTorch
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])
👉🏻차원과 크기를 출력했다. shape, size 둘 다 크기를 출력한다.
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.])
👉🏻같은 방법으로 원소에 접근할 수 있다.
2️⃣2D with PyTorch
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.size())
#2
#torch.Size([4, 3])
print(t[:, 1])
print(t[:, 1].size())
#tensor([ 2., 5., 8., 11.])
#torch.Size([4])
👉🏻 첫번째 차원을 전체 선택한 상황에서 두번째 차원의 첫번째 것만 가져온다.
print(t[:, :-1])
#tensor([[ 1., 2.],
# [ 4., 5.],
# [ 7., 8.],
# [10., 11.]])
👉🏻첫번째 차원을 전체 선택한 상황에서 두번째 차원에서는 맨 마지막에서 첫번째를 제외하고 다 가져온다.
브로드캐스팅(Broadcasting)
👉🏻행렬의 덧셈과 뺄셈을 할 때는 두 행렬의 크기가 같아야 한다. 그리고 곱셈을 할 때는 A행렬의 마지막 차원과 B행렬의 첫번째 차원일 일치해야 한다. 하지만 딥러닝을 할 때 크기가 다른 행렬 또는 텐서의 사칙 연산이 필요한 순간이 온다. 이를 위해 파이토치에서는 자동으로 크기를 맞춰 연산을 수행하는 브로드캐스팅 기능을 제공한다.
1️⃣같은 크기일 때 연산
m1 = torch.FloatTensor([[3, 3]])
m2 = torch.FloatTensor([[2, 2]])
print(m1 + m2)
#tensor([[5., 5.]])
👉🏻둘 다 크기가 (1, 2)이므로 문제없이 덧셈이 가능하다.
2️⃣다른 크기일 때 연산
# Vector + scalar
m1 = torch.FloatTensor([[1, 2]])
m2 = torch.FloatTensor([3])
print(m1 + m2)
#tensor([[4., 5.]])
👉🏻m1의 크기는 (1, 2)이지만 m2의 크기는 (1, )이므로 파이토치가 m2를 (1, 2)로 아래와 같이 변경하여 연산을 수행한다.
- [3] -> [3, 3]
# 2 x 1 Vector + 1 x 2 Vector
n1 = torch.FloatTensor([[1, 2]])
n2 = torch.FloatTensor([[3], [4]])
print(n1 + n2)
#tensor([[4., 5.],
# [5., 6.]])
👉🏻n1은 (1, 2), n2는 (2, 1)이기 때문에 두 벡터의 크기를 (2, 2)로 변경하여 덧셈한다.
[1, 2]
==> [[1, 2],
[1, 2]]
[3]
[4]
==> [[3, 3],
[4, 4]]
👉🏻변경 과정
자주 사용하는 기능
1️⃣행렬 곱셈과 곱셈의 차이(Matrix Multiplication Vs. Multiplication)
- .matmul: 행렬 곱셈
- .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.matmul(m2)) #2 x 1
#Shape of Matrix 1: torch.Size([2, 2])
#Shape of Matrix 2: torch.Size([2, 1])
#tensor([[ 5.],
# [11.]])
👉🏻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))
#Shape of Matrix 1: torch.Size([2, 2])
#Shape of Matrix 2: torch.Size([2, 1])
#tensor([[1., 2.],
# [6., 8.]])
#tensor([[1., 2.],
# [6., 8.]])
👉🏻서로 다른 크기의 행렬이 브로드캐스팅된 후에 element-wise 곱셈을 수행했다. 이는 * 또는 mul()을 통해 수행한다.
# 브로드캐스팅 과정
[1]
[2]
==> [[1, 1],
[2, 2]]
2️⃣평균(Mean)
t = torch.FloatTensor([1, 2])
print(t.mean())
#tensor(1.5000)
👉🏻1차원 벡터의 평균을 구했다.
t = torch.FloatTensor([[1, 2], [3, 4]])
print(t)
print(t.mean())
#tensor([[1., 2.],
# [3., 4.]])
#tensor(2.5000)
👉🏻2차원 행렬의 평균을 구했다. 4개의 원소의 평균이 나온다.
print(t.mean(dim=0))
#tensor([2., 3.])
# 실제 연산 과정
t.mean(dim=0)은 입력에서 첫번째 차원을 제거한다.
[[1., 2.],
[3., 4.]]
1과 3의 평균을 구하고, 2와 4의 평균을 구한다.
결과 ==> [2., 3.]
👉🏻차원을 인자로 주었다. dim=0이라는 것은 첫 번째 차원(행)을 의미한다. 인자로 dim을 준다면 해당 차원을 제거한다는 의미가 된다. 그러므로 열만 남겨서 평균을 구한다.
print(t.mean(dim=1))
tensor([1.5000, 3.5000])
# 실제 연산 결과는 (2 × 1)
[1. 5]
[3. 5]
👉🏻두번째 차원을 제거하면 서 열이 제거된 텐서가 되어야 한다.
3️⃣덧셈(Sum)
👉🏻평균과 연산방법, 인자가 의미하는 바가 똑같고 덧셈으로 바뀌었을 뿐이다.
t = torch.FloatTensor([[1, 2], [3, 4]])
print(t)
print(t.sum()) # 단순히 원소 전체의 덧셈을 수행
print(t.sum(dim=0)) # 행을 제거
print(t.sum(dim=1)) # 열을 제거
print(t.sum(dim=-1)) # 열을 제거
#tensor([[1., 2.],
# [3., 4.]])
#tensor(10.)
#tensor([4., 6.])
#tensor([3., 7.])
#tensor([3., 7.])
4️⃣최대(Max)와 아그맥스(ArgMax)
👉🏻Max는 원소의 최대값을 리턴하고 ArgMax는 최대값을 가진 인덱스를 리턴한다.
t = torch.FloatTensor([[1, 2], [3, 4]])
print(t)
print(t.max())
#tensor([[1., 2.],
# [3., 4.]])
#tensor(4.)
👉🏻최대값 4를 리턴한다.
print(t.max(dim=0))
(tensor([3., 4.]), tensor([1, 1]))
# [1, 1]의 의미
#[[1, 2],
# [3, 4]]
#첫번째 열에서 0번 인덱스는 1, 1번 인덱스는 3입니다.
#두번째 열에서 0번 인덱스는 2, 1번 인덱스는 4입니다.
#다시 말해 3과 4의 인덱스는 [1, 1]입니다.
👉🏻인자로 dim=0을 주어 첫번째 차원을 제거했다. [3, 4]뿐만 아니라 [1, 1]도 함께 리턴되는데 이는 max에 dim 인자를 주면 argmax도 함께 리턴하는 특징때문이다.
print('Max: ', t.max(dim=0)[0])
print('Argmax: ', t.max(dim=0)[1])
#Max: tensor([3., 4.])
#Argmax: tensor([1, 1])
👉🏻두 개를 함께 리턴받는 것이 아니라 max 또는 argmax만 리턴받고 싶다면 다음과 같이 리턴값에도 인덱스를 부여하면 된다.
'그 땐 AI했지 > 그 땐 DeepLearning했지' 카테고리의 다른 글
[TAVE/study] ch03 선형 회귀 | 02 자동 미분 (0) | 2022.04.07 |
---|---|
[TAVE/study] ch03 선형 회귀 | 01 선형 회귀 (0) | 2022.04.07 |
[TAVE/study] ch02 파이토치 기초 | 04 파이썬 클래스 (0) | 2022.04.01 |
[TAVE/study] ch02 파이토치 기초 | 03 텐서 조작하기② (0) | 2022.04.01 |
[TAVE/study] ch02 파이토치 기초 | 01 파이토치 패키지의 기본 구성 (0) | 2022.03.31 |