본문 바로가기

딥러닝/Pytorch

Pytorch:torch.gather 를 이해해보자

2021-09-15 목차 작성

2021-09-18 글씨크기 수정

개요

Torch.gather

 

 

개요


부스트캠프 ai Tech2기를 한지 벌써 3주차가 되고 있습니다. 예전에는, 저와 팀원(캠퍼)분들 모두 따끈따끈

ai뉴비들이었습니다.

 

한주, 한주 지나가면서 팀원분들의 질문 수준도 점점 올라가면서 서로서로 답변해주기 점점 어려워지고 있습니다..;;

 

 

오늘 , 그 질문들 중 최고봉의 질문이 나왔다고 생각합니다.  

 

 

PyTorch.gather 함수는 무엇인가??????

 

 

gather함수를 쓰다보면 텐서의 차원개념이 햇갈립니다.

 

 

차원이 1 인 텐서(dim=0)는 쉽습니다 . 

 

차원이 2인 텐서(dim=1)까지도 할만합니다.

 

 

 

차원이 3인 텐서(dim=2)부터 인간의 이해범위를 넘어가는거 같습니다.

 

 

 

차원이 4라면 ??? 

 

 

 

 

차원이 4인 텐서를 시각화하기 정말 힘듭니다.그 이상은 더 힘들겟죠.. ㅠㅠ

 

 

 

 

우주공간의 11차원 ,26차원 도 그릴건가요?

 

 

못그려요.. ㅡㅡ

 

 

그러면?

 

 

수식으로 표현해야죠!!!!!

 

 

Torch.gather

 

저는 gather함수를 수학적으로 이해해야한다고 생각합니다.

 

input output

 

 

수학적으로 이해하기 위해선 우선 torch.gather 함수의 paramter들이 무엇이 있는지 알아야합니다.

 

input:

 

input으로 받는 텐서에요.

 

dim: 

 

어떤 axis를 변동을 줄지 정해주는거에요(아래에서 더 자세히 설명할게요)

 

index:

 

output의 shape를 지정하고 , 어떻게 치환해줄지 정해주는거에요(아래에서 더 자세히 설명할게요)

 

 

return값:

out

 

how to calculate gather

 

어떻게 수학적으로 보는지 실습을 통해 알아보도록 하겠습니다.

 

ex)

import torch

 

A = torch.Tensor([[12],

                  [34]])

 

Q1: A의 대각성분을 shape이 (,2)인 tensor로 만들어보세요.

 

A의대각성분을 수식적으로 표현해볼까요?

 

A[0][0],A[1][1] 를 떠올리셧다면 반은 성공한겁니다.

 

이를 일반식으로 적으면 A[i][i] 일 겁니다. (0<=i<=1)

 

gather가 해줘야할일은 shape(1,2) 인 텐서에 A[i][i]를 대입해주는 겁니다.

(왜 shape(1,2)에 대입을 해줘야하는지는 추후 나옵니다.)

 

indexing방식으로 표현하자면, 

A[0][0] -> out[0][0] ,A[1][1] -> out[0][1]

 

 

대입해주는 거겟죠?

 

여기서 변하는 부분은 눈치채셧겠지만, 색깔로 칠한 부분이겟죠?ㅎㅎ

 

따라서, dim parameter 값으로 0를 사용합니다.

 

색깔을 칠한 부분을 보면  A의 indexing 값과 out의 indexing값은 다릅니다. 

 

따라서, 어떻게 다른지 지정을 해줘야합니다.  

 

그 역할을 하는것이 index입니다.

 

ex) index[0][1] = 1이고 , dim=0 이면 out의[0][1] 자리에 A[1][1] 값을 넣는것입니다.

식으로 표현하면 , out[0][1]=A[index[0][1]][1] 이 되는 거겟죠.

 

index에는 torch.tensor.arange(2).reshape(1,2) 가 들어가야합니다.

 

주의할점은 index와 A의 차원이 같아야합니다.

 

따라서, output의 원소의 수는 같지만, 차원은 A와 같은 차원이 되도록 처리해준것입니다.

 

 

결과적으로

Ans.

import torch

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

# torch.gather 함수를 써서 해보세요!

output=torch.gather(A,0,torch.arange(2).reshape(1,2))
# output=A
output=output.reshape(2)
print(output.shape)
# 아래 코드는 수정하실 필요가 없습니다!
if torch.all(output == torch.Tensor([1, 4])):
    print("🎉🎉🎉 성공!!! 🎉🎉🎉")
else:
    print("🦆 다시 도전해봐요!")

이러한 코드를 적으시면 됩니다.

 

 

2차원 텐서에 대하여 적용하는것은 쉬었나요?

2차원 텐서에 대하여 적용할 때는, 위 코드가 아니더라도 시행착오를 통해 같은 결과를 도출해 낼 수 있습니다. 

그럼, 좀 더 매운 문제를 내보도록 하겠습니다.

 

Q2.

[[[1  2]
  [3  4]]
 [[5  6]                                   [[1  4]
  [7  8]]] 3차원 텐서에서 대각선 요소만 가져와서 [5  8]] 이라는 2차원 텐서를 만들고 싶어요!

 

Ans???

 

시각화 NO NO NO!!!

 

 

 

 

 

 

 

아까 했던 로직을 그대로 적용해봅시다.

 

input 의대각성분을 수식적으로 표현해볼까요?

 

 

A[0][0][0],A[0][1][1],A[1][0][0],A[1][1][1] 로 다들 나오셧을거에요.

 

이를 일반식으로 작성하면 , A[k][i][i] 에요 (0<=k<=1 , 0<=i<=1)

 

output의 shape은 (2,2)를 원하고 있네요 .

 

하지만, dimension(차원) 을 맞춰줘야 하니까 , (1,2,2) ,(2,1,2),(2,2,1)이 index의 shape으로 가능하겟죠.

 

저는 이번엔 한번 (1,2,2)shape으로 해보겠습니다.

 

A[k][i][i] -> out[0][k][i] 가 되어야 겟죠

 

하지만, 이렇게하면  ,axis를 0,1 둘다 바꿔야해서 안되죠

 

따라서, (2,1,2) shape으로 해보겠습니다.

 

(k,i,i)->(k,0,i) 가 됩니다.

 

axis= 1를 바꿔주면서 하면 되겟죠

 

index=torch.arange(2).expand(2,2).reshape(2,1,2)로 하면 되겟죠

 

ANS

import torch

A = torch.Tensor([[[1, 2],
                   [3, 4]],
                  [[5, 6],
                   [7, 8]]])

# torch.gather 함수를 써서 해보세요!

index=torch.arange(2).expand(2,2).reshape(2,1,2)

output = torch.gather(A,1,index).view(2,2)
# print(A[1][0][0])
# output=A
print(output)

# 아래 코드는 수정하실 필요가 없습니다!
if torch.all(output == torch.Tensor([[1, 4], [5, 8]])):
    print("🎉🎉🎉 성공!!! 🎉🎉🎉")
else:
    print("🦆 다시 도전해봐요!")

가 됩니다.

 

 

BONUS

저희는 지금까지 정해진 크기의 입력에서 대각선 요소를 가져왔는데
임의의 크기의 3D 텐서에서도 마찬가지로 대각선 요소를 가져와서 2D 텐서를 만들 수 있을까요?

ANS

 

더보기

#TODO BY YOURSELF

#정답은 8월20일날 올리겠습니다. 

 

#보는것보다 직접해보는것이 도움이됩니다.  힌트는 다 드렸습니다.

 

 

※아직 작성중..ㅡㅡ