Tensor 조작

J. Hwang·2024년 8월 6일
0

Indexing

  • tensor의 특정 위치의 요소에 접근하는 것
  • 1-D tensor indexing은 numpy 1d array와 같음.
  • 그러나 2-D부터는 달라지는데, m행 n열의 요소를 인덱싱하고자 할 때 numpy에서는 np1[m][n] 과 같이 접근했다면 tensor의 경우 t1[m, n] 과 같이 접근한다.

Slicing

  • 부분 집합을 선택하여 새로운 sub-tensor를 생성
  • 1-D tensor slicing은 numpy 1d array와 같음.
  • slicing에서도 2-D tensor부터는 numpy와 달라져서 [1][2:4] 가 아니라 [1, 2:4]와 같이 표현한다.

tensor의 모양 변경 (1) view()

  • view() 메서드를 활용해서 텐서의 모양을 변경할 수 있는데, tensor의 메모리가 연속적으로 할당된 경우에 사용이 가능하다.

Q. 메모리가 연속적으로 할당된 경우란?
→ 정의 상으로는 "tensor의 데이터 타입과 차원 정보에 기반하여 메모리에서 충분한 공간을 할당 받아 데이터를 저장한 상태"라고는 하는데, 무슨 말인지 이해하기 어렵다. 간단히 이해하자면, a = torch.tensor([1, 2, 3, 4]) 과 같이 생성된 데이터는 각 요소들이 메모리에 연속적으로 할당된 경우라 문제가 없지만, 기존 텐서를 슬라이싱 등을 통해 일부 요소만 선택해 새로운 텐서를 만들었다면 메모리가 비연속적으로 할당된 것이 된다. 즉 이 경우에는 view() 메서드를 사용할 수 없다.
→ 메모리가 연속적으로 할당되었는지 확인하고 싶다면, a.is_contiguous() 로 확인할 수 있다. True가 return되면 연속적, False가 return되면 비연속적으로 메모리가 할당된 것이다.
→ 메모리가 비연속적으로 할당된 텐서를 연속적으로 할당된 텐서로 만들고 싶을 때에는 b = a.contiguous() 를 이용하면 된다.

  • view()는 numpy의 reshape 기능과 같다.
a = torch.tensor([1, 2, 3, 4, 5, 6])
b = a.view(2, 3)    # 2행 3열로 재구성
# b = [[1, 2, 3], [4, 5, 6]]
  • 3-D tensor로 모양을 바꿀 경우, a.view(m, n, l) 과 같이 표현하고 n x l 행렬을 m개 만드는 것을 의미한다.

Flatten

  • numpy의 flatten()과 같다.
  • 데이터를 신경망 모델에 적합한 형태로 전처리하기 위해 많이 활용한다.
  • b = torch.flatten(a) or b = a.flatten()
  • 3-D 이상의 tensor 부터는 특정 차원의 범위를 평탄화 할 수 있다.
# a-tensor의 m번째 차원 ~ n번째 차원까지 평탄화
b = torch.flatten(a, m, n)

# a-tensor의 0번째~마지막 차원까지 평탄화 -> 1D tensor
b = torch.flatten(a, 0)    

# example
# a-tensor is a 3-D tensor
a = torch.randn([m, n, l])

# b is now a 2-D tensor with size m x (n*l).
b = torch.flatten(a, 1, 0)

# c is now a 2-D tensor with size (m*n) x l.
c = torch.flatten(a, 0, 1)

tensor의 모양 변경 (2) reshape()

  • view()와는 달리 메모리가 연속적이지 않아도 사용 가능하다. 다만 성능이 저하된다는 단점이 있음.
  • 1-D tensor a를 m행 n열의 2-D tensor로 변환 : b = a.reshape(m, n)
  • 1-D tensor a를 m개의 n행 l열의 3-D tensor로 변환 : b = a.reshape(m, n, l)

Transpose

  • tensor의 특정한 두 차원의 축을 서로 바꿈
  • b = a.transpose(m, n) 으로 m차원과 n차원의 축을 바꾼다.

Squeeze

  • squeeze는 dim이 1인 차원을 축소하는 기능이다. 예를 들어 a = torch.randn(1, 1, 4) 라는 3-D tensor가 있다. 이 tensor-a는 1개의 1행 4열로 이루어진 데이터인데, 사실상 4개의 요소로 이루어진 1-D tensor와 다를 것이 없다. 이런 경우 굳이 고차원의 데이터로 다룰 필요가 없으므로 불필요한 차원의 수를 줄이는 것이다.
  • b = torch.squeeze(a)
  • 그러나 위의 tensor-a 예시에서, dim이 1인 차원 두 개 중 하나만 축소하고 싶을 수도 있다. 그럴 때는 축소하고자 하는 dim을 명시해주면 된다.
# a is a 3-D tensor.
a = torch.randn(1, 1, 4) 

# b is a 2-D tensor with size 1 x 4.
b = torch.squeeze(a, dim=0)
b.size()     # torch.Size([1, 4])

# c is a 2-D tensor with size 1 x 4.
c = torch.squeeze(a, dim=1)
c.size()     # torch.Size([1, 4])

Unsqueeze

  • squeeze와는 반대로 dim 1인 차원을 확장하는 기능.
  • b = torch.unsqueeze(a, dim=n) 을 하면 n차원으로 dim이 1인 차원을 확장시킨다.
# a is a 2-D tensor with size 3 x 4.
a = torch.randin(3, 4)

# b is a 3-D tensor with 3x1x4. (three 1 x 4 matrices)
b = torch.unsqueeze(a, dim=1)

Stack

  • tensor들을 결합하는 기능
  • tensor1 = torch.stack((a, b, c), dim=n) 을 이용하면 dim-n인 축을 생성하여 tensor a, b, c를 결합시키게 된다. dim 옵션의 default 값은 0이다.

Cat

  • 같은 차원의 tensor들을 연결하는 기능
  • c = torch.cat((a,b), dim=n)을 이용하면 dim n을 기준으로 tensor b와 c를 연결한다.
a = torch.tensor([[0, 1], [2, 3]])   # 2-D tensor
b = torch.tensor([[4, 5]])       # 2-D tensor   
c = torch.cat((a,b), dim=0)     # concat a, b along with dim = 0
# c = tensor([[0, 1], [2, 3], [4, 5]])    # 3 x 2 matrix

Expand

  • 행 또는 열의 개수가 1개인 tensor의 차원의 크기를 확장하는 기능
  • b = a.expand(m, n) 과 같이 사용하여 m x n 의 크기를 가지는 tensor로 확장.
a = torch.tensor([1, 2, 3])     # 2-D tensor with size 1 x 3 
b = a.expand(4, 3)
# b = tensor([1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]])

Repeat

  • tensor의 요소들을 반복해서 크기를 확장하는 기능
  • 추가 메모리를 할당하기 때문에 expand 보다 메모리 효율성이 떨어짐
  • b = a.repeat(m, n) 과 같이 사용하여 dim = 0 축으로 m번 반복하고, dim = 1 축으로 n번 반복하여 tensor의 크기를 확장함
a = torch.tensor([[1, 2], [3, 4]])
b = a.repeat(2, 3)
# b = tensor([[1, 2, 1, 2, 1, 2],
#        [3, 4, 3, 4, 3, 4],
#        [1, 2, 1, 2, 1, 2],
#        [3, 4, 3, 4, 3, 4]])
profile
Let it code

0개의 댓글