본문 바로가기

[모두를 위한 딥러닝/시즌2] Lab-01 Tensor Manipulation

Lab-01 Tensor Manipulation

 

다음은 모두를 위한 딥러닝 시즌 2의 Lab-01-1 Tensor Manipulation 1Lab-01-2 Tensor Manipulation 2를 학습하고 요약정리한 내용입니다. 강의 내용을 기반으로 요약하되, 보충 설명이 필요한 경우 부스트코스 위키독스를 참고했습니다.

학습목표

텐서 조작(Tensor Manipulation)에 대해 알아본다.

핵심키워드

텐서(Tensor), 넘파이(NumPy), 텐서 조작(Tensor Manipulation), 브로드캐스팅(Broadcasting), 

View, Squeeze, Unsqueeze, Type Casting, Concatenate, Stacking, In-place Operation

1. 벡터, 행렬 그리고 텐서(Vector, Matrix and Tensor)


0차원은 스칼라(scala), 1차원은 벡터, 2차원은 행렬, 3차원은 텐서이다.

4차원은 3차원의 텐서를 위로 쌓은 것, 5차원은 4차원 텐서를 옆으로 쌓은 것, 6차원은 5차원을 뒤로 쌓은 것이다.

 

딥러닝을 할 때 다루고 있는 행렬 또는 텐서의 크기를 고려하는 것은 항상 중요하다!

앞으로 행렬과 텐서의 크기를 표현할 때 다음과 같은 방법으로 표기한다.

1)  2D Tensor(Typical Simple Setting) - 가장 전형적인 2차원 텐서

 • |t| = (batch size, dim)

 

2) 3D Tensor(Typical Computer Vision) - 비전 분야에서의 3차원 텐서

 • |t| = (batch size, width, height)

 

이미지의 경우 가로, 세로가 존재하므로 3차원 텐서가 된다. 가로는 너비(width), 세로는 높이(height)로 표현한다.

 

3) 3D Tensor(Typical Natural Language Processing) - NLP 분야에서의 3차원 텐서

 • |t| = (batch size, length, dim)

 

length는 문장 길이이고 dim은 단어 벡터의 차원이다. 문장 길이와 단어 벡터의 차원에 대해 보충 설명을 하자면 예를 들어 ['나는 사과를 좋아해']라는 문장이 있을 때 문장의 길이는 단어 단위로 계산하면 된다. ['나는', '사과를', '좋아해']이므로 문장의 길이는 3이다. 컴퓨터는 텍스트를 숫자로 처리하므로 각 단어를 벡터로 만들어 '나는'=[0.1, 0.2, 0.9], '사과를'=[0.3, 0.5, 0.1], '좋아해'=[0.5, 0.6, 0.7]로 변환했다고 하자. 그러면 단어 벡터의 차원은 3차원이므로 3이다. 이렇게 구성된 하나의 문장이 batch size만큼 존재한다고 보면 된다. 앞의 예시는 문장 하나이므로 |t|는 (1, 3, 3)이다.

 

Numpy와 Pytorch를 import해준다.

2. 넘파이 훑어보기(Numpy Review)


1) 1D Array with Numpy

Numpy로 1차원 벡터를 만들어보고 벡터의 차원과 크기를 출력해본다.

 • np.array(list): n차원의 배열, 즉 ndarray 생성

 • ndarray.ndim: 배열의 차원 수 출력

 • ndarray.shape: 배열의 크기 출력

2) 2D Array with Numpy

Numpy로 2차원 행렬을 만들어보고 행렬의 차원과 크기를 출력해본다.

3. 파이토치 텐서 선언하기(Pytorch Tensor Allocation)


1) 1D Array with Pytorch

앞서 Numpy로 진행했던 실습을 Pytorch로 똑같이 해본다. 1차원 벡터를 만들고 차원과 크기를 확인한다.

 • torch.Tensor(list/sequence) = torch.FloatTensor(list/sequence): float형 배열 생성

 • torch.Tensor.dim(): 배열의 차원 수 출력

 • torch.Tensor.shape = torch.Tensor.size(): 배열의 크기 출력

2) 2D Array with Pytorch

Pytorch로 2차원 행렬을 만들고 차원과 크기를 확인한다.

3) Broadcasting

행렬 간 덧셈, 뺄셈 연산 시 두 행렬의 크기가 같아야 하고 곱셈 연산 시 앞 행렬의 마지막 차원과 뒤 행렬의 첫 번째 차원이 일치해야 한다. 하지만 Pytorch에서는 자동적으로 사이즈를 맞춰주는 브로드캐스팅 기능을 제공한다! 따라서 벡터와 스칼라도, 크기가 다른 벡터끼리도 연산이 가능하다. 하지만 잘못 연산을 했어도 오류가 안 뜨기 때문에 브로드캐스팅 기능은 주의해서 사용해야 한다. 

4. 행렬 곱셈(Matrix Multiplication)


딥러닝에서 행렬곱을 많이 사용한다. mul과 matmul이 다르니 구분해서 사용해야 한다.

 • A.mul(B): A 텐서와 B 텐서의 원소별 곱셈 연산, 브로드캐스팅 기능 제공

 • A.matmul(B): A 행렬과 B 행렬의 행렬곱, 이때 A 행렬의 마지막 차원과 B 행렬의 첫 번째 차원이 같아야 함!

5. 다른 기본 오퍼레이션들(Other Basic Ops)


 • torch.Tensor.mean(): 텐서의 평균 출력

 • torch.Tensor.mean(dim): 해당 차원(dim)을 제거하여 평균 출력

 

dim=0이라는 것은 첫번째 차원을 의미하는데 행렬에서 첫 번째 차원은 '행'이다. 다시 말해 행렬에서 '열'만 남기겠다는 의미이다. 기존 행렬의 크기가 (2, 2)였지만 t.mean(dim=0)를 수행하면 열의 차원만 보존되면서 (1,2)=(2,)가 된다.

 

sum은 mean과 똑같다. 단지 평균이 아니라 합계를 구할 뿐이다.

 • torch.Tensor.sum(): 텐서의 합계 출력

 • torch.Tensor.sum(dim): 해당 차원(dim)을 제거하여 합계 출력

 

 • torch.Tensor.max(): 원소의 최대값(max) 리턴

 • torch.Tensor.max(dim): 해당 차원(dim)을 제거하여 원소의 최댓값(max)과 최댓값을 가진 인덱스(argmax)리턴

 

t는 현재 (2,2) 크기의 행렬이다. t.max(dim=0)를 할 경우 dimension 0, 즉 행의 차원을 제거한다는 의미이므로 (1, 2) = (2,) 크기의 벡터를 만든다. 행을 제거하는 과정에서 앞서 sum 메소드에서는 1+3=4, 2+4=6을 했다면 max 메소드에서는 1과 3중 큰 값=3, 2와 4중 큰 값=4이므로 max는 [3, 4]이다. 최댓값을 가진 인덱스는 1과 3중 두 번째인 3이었으므로 index=1, 2와 4중 두 번째인 4였으므로 index=1이라서 argmax는 [1, 1]이다.

 

파이토치에서 view는 넘파이에서 reshape과 같은 역할을 한다.

자유자재로 내가 원하는 shape을 만들 수 있어야 하므로 매우 중요하다!

 • torch.Tensor.view(원하는 크기): 텐서 안의 원소의 개수는 그대로 유지하되 텐서의 크기를 변경

참고로 -1로 설정하면 내가 계산하지 않아도 알아서 맞춰준다.

 

 • torch.Tensor.squeeze(): 차원이 1인 차원을 제거

 • torch.Tensor.squeeze(dim): 해당 차원(dim)이 1인 경우 해당 차원 제거

 

unsqueez는 squeeze와 반대이다. 1인 차원을 제거하는 것이 아니라 추가한다.

 • torch.Tensor.unsqueeze(dim): 특정 위치(dim)에 1인 차원을 추가

 

자료형을 변환하는 것을 Type Casting이라고 한다.

 • torch.Tensor.long(): long 타입으로 변환

 • torch.Tensor.float(): float 타입으로 변환

 

딥러닝에서는 주로 모델의 입력 또는 중간 연산에서 두 개의 텐서를 연결하는 경우가 많다. 두 텐서를 연결해서 입력으로 사용하는 것은 두 가지의 정보를 모두 사용한다는 의미를 가지고 있다.

 • torch.Tensor.cat([A, B, …]): A, B, 텐서를 모두 연결

 • torch.Tensor.cat([A, B, …], dim): A, B,  텐서를 모두 연결하되 해당 차원(dim)을 늘리도록 함

 

연결하는 또 다른 방법으로 stacking이 있다. stack이 더 많은 연산을 포함하고 있어 앞의 cat보다 stack이 더 편리할 때가 있다. 

 • torch.Tensor.stack([A, B, …]): A, B,  텐서를 모두 쌓아 연결

 • torch.Tensor.stack([A, B, ], dim): A, B,  텐서를 모두 쌓되 해당 차원(dim)을 늘리도록 함

 

cat과 stack의 차이가 헷갈리다면 아래를 참고하자. cat은 텐서들을 이어붙여준다면 stack은 텐서 그대로 쌓아준다.

 

>>> x = torch.FloatTensor([1, 4])
>>> y = torch.FloatTensor([2, 5])
>>> z = torch.FloatTensor([3, 6])

>>> torch.cat([x, y, z])
tensor([1., 4., 2., 5., 3., 6.])

>>> torch.stack([x, y, z])
tensor([[1., 4.],
        [2., 5.],
        [3., 6.]])
        
>>> torch.cat([x.unsqueeze(0), y.unsqueeze(0), z.unsqueeze(0)], dim=0)
tensor([[1., 4.],
        [2., 5.],
        [3., 6.]])

 

 • torch.Tensor.ones_like(x): x 텐서와 동일한 크기지만 1로만 값이 채워진 텐서 생성

 • torch.Tensor.zeros_like(x): x 텐서와 동일한 크기지만 0으로만 값이 채워진 텐서 생성

 

cpu와 gpu를 모두 사용하거나 multiple gpu를 사용할 때 ones_like, zeros_like을 사용하면 같은 device에 텐서를 선언해줘 연산 시행 시 에러가 안 난다고 한다!

 

 

 • 연산 뒤에 _: 덮어쓰기 연산 수행

 

연산 수행의 결과를 대입하는 것보다 속도가 빠르지만 큰 이점은 없을 수 있다.