욤미의 개발일지

3. 파이토치 기초(PyTorch Basic): 텐서의 연산 본문

PyTorch

3. 파이토치 기초(PyTorch Basic): 텐서의 연산

욤미 2023. 3. 29. 22:08
728x90
반응형

📌 구글 colab에서 실습한 내용


Numpy와 동일하게 슬라이싱과 인덱싱 가능하다.

tensor = torch.ones(3, 4)
tensor[:,1] = 0
print(tensor)
'''
tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])
'''

1. 텐서 연결하기(Concatenate)

- torch.cat

t1 = torch.cat([tensor, tensor, tensor], dim=0) # 가장 큰 차원에서 부터 0, 행 추가
print(t1)
'''
tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])
'''
t1 = torch.cat([tensor, tensor, tensor], dim=1) # 열 추가
print(t1)
'''
tensor([[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.]])
'''
  • 딥 러닝에서는 주로 모델의 입력 또는 중간 연산에서 두 개의 텐서를 연결하는 경우가 많다.
  • 두 텐서를 연결해서 입력으로 사용하는 것은 두 가지의 정보를 모두 사용한다는 의미를 가지고 있다.

2. 텐서 스택킹(Stacking)

concatenate하는 다른 방법으로 많은 연산을 포함하고 있기때문에 torch.cat보다 편리할 때가 있다.

아래 코드는 (3, 2) 텐서를 만드는데 이는 torch.cat([x.unsqueeze(0), y.unsqueeze(0), z.unsqueeze(0)], dim=0) 와 동일한 작업이다.

x = torch.FloatTensor([1, 4])
y = torch.FloatTensor([2, 5])
z = torch.FloatTensor([3, 6])
print(torch.stack([x, y, z]))
'''
tensor([[1., 4.],
        [2., 5.],
        [3., 6.]])
'''

dim 인자를 줘서 다른 차원이 증가하도록 텐서를 쌓을 수도 있다. 

print(torch.stack([x, y, z], dim=1)) # 두번째 차원이 증가하도록
'''
tensor([[1., 2., 3.],
        [4., 5., 6.]])
'''

3. 텐서 곱하기

1) Matrix Multiplication

텐서를 곱하는 방법 중에서 행렬곱 연산

print(f"tensor.matmul(tensor.T) \n {tensor.matmul(tensor.T)} \n")
print(f"tensor @ tensor.T \n {tensor @ tensor.T}")
'''
tensor.matmul(tensor.T) 
 tensor([[3., 3., 3.],
        [3., 3., 3.],
        [3., 3., 3.]]) 

tensor @ tensor.T 
 tensor([[3., 3., 3.],
        [3., 3., 3.],
        [3., 3., 3.]])
'''

1)  Element-wise Product

행렬의 요소별 곱 연산

print(f"tensor.mul(tensor) \n {tensor.mul(tensor)} \n")
print(f"tensor * tensor \n {tensor * tensor}")
'''
tensor.mul(tensor) 
 tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]]) 

tensor * tensor 
 tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])
'''

4. 평균 (Mean)

기본적으로 모든 원소의 평균을 구한다. dim. 즉, 차원(dimension)을 인자로 주는 경우 해당 차원을 제거한다는 의미이다.

print(t2.mean()) # 전체원소의 평균 tensor(1.5000)
print(t2.mean(dim=0)) # 첫 번째 차원 제거, 0은 행을 의미, 행을 제거함, 열에 대한 평균 tensor([1., 2.])
print(t2.mean(dim=1)) # 두 번째 차원 제거, 1은 열을 의미, 열을 제거함, 행에 대한 평균 tensor([1.5000, 1.5000])
print(t2.mean(dim=-1)) # 마지막 차원 제거, 열을 제거함, 행에 대한 평균 tensor([1.5000, 1.5000])

5. 덧셈 (Sum)

평균과 연산 방법이나 인자가 의미하는 바가 동일하다.

print(t2.sum()) # 전체원소의 덧셈 tensor(6.)
print(t2.sum(dim=0)) # 첫 번째 차원 제거, 0은 행을 의미, 행을 제거함, 열에 대한 덧셈 tensor([2., 4.])
print(t2.sum(dim=1)) # 두 번째 차원 제거, 1은 열을 의미, 열을 제거함, 행에 대한 덧셈 tensor([3., 3.])
print(t2.sum(dim=-1)) # 마지막 차원 제거, 열을 제거함, 행에 대한 덧셈 tensor([3., 3.])

5. 최대(Max), 아그맥스(ArgMax)

  • 최대: 원소의 최댓값을 리턴
  • 아그맥스: 최댓값을 가진 원소의 인덱스를 리턴
t = torch.FloatTensor([[1, 2], [3, 4]])
print(t.max()) # tensor(4.)
print(t.argmax()) # tensor(3)

max에 dim = 0을 인자로 주면 첫번째 차원을 제거한다. = 행의 차원을 제거 = 열에 대해서 최댓값을 구한다.

max 에 dim인자를 주면 argmax도 함께 리턴
첫번째 열에서 0번 인덱스는 1, 1번 인덱스는 3 → 둘 중 큰 값은 3

두번째 열에서 0번 인덱스는 2, 1번 인덱스는 4 → 둘 중 큰 값은 4   
→ 3과 4의 인덱스는 [1, 1]이다.

print(t.max(dim=0)) # Returns two values: max and argmax
'''
torch.return_types.max(
values=tensor([3., 4.]),
indices=tensor([1, 1]))
'''

6. 브로드캐스팅(Broadcasting)

두 행렬을 연산할 때,

  • 덧셈과 뺄셈은 행렬 A, B의 크기가 같다
  • 곱셈에서는 행렬 A, B를 곱할 때 A의 마지막 차원과 B의 첫번째 차원이 일치한다.

하지만, 딥러닝을 하다보면 크기가 다른 행렬 또는 텐서에 대해서 연산을 수행해야하는 경우가 생긴다.

이를 위해서 자동으로 크기를 맞춰서 연산을 수행하는 것이 브로드캐스팅이라는 기능이다.

# 벡터와 스칼라의 덧셈 연산
m1 = torch.FloatTensor([1, 2])
m2 = torch.FloatTensor([3]) # 스칼라, [3] → [3, 3]
print(m1 + m2) # tensor([4., 5.])

# 모양이 다른 두 벡터 연산
m1 = torch.FloatTensor([1, 2]) #  →  [[1, 2], [1, 2]]
m2 = torch.FloatTensor([[3], [4]]) #  → [[3, 3], [4, 4]]
print(m1 + m2)
'''
tensor([[4., 5.],
        [5., 6.]])
'''

7. 덮어쓰기 연산(In-plac Operation)

(2 x 2) 텐서에 2를 곱하고 기존 값을 출력해보면 원래대로 출력된다.
하지만 연산 뒤에 _를 붙이면 기존 값을 덮어쓴다.

x = torch.FloatTensor([[1, 2], [3, 4]])
print(x.mul(2.)) # (2 x 2) 텐서에 2 곱하기
print(x) # 곱한값을 x에 저장하지 않음

print(x.mul_(2.)) # 값을 덮어쓰기
print(x)
'''
tensor([[2., 4.],
        [6., 8.]])
tensor([[1., 2.],
        [3., 4.]])
tensor([[2., 4.],
        [6., 8.]])
tensor([[2., 4.],
        [6., 8.]])
'''
728x90
반응형
Comments