본문 바로가기

부스트캠프 AI Tech 3기/이론 : U-stage

[Day6] Pytorch 2. Pytorch Basics : Tensor, data types, handling, operations, formula

Pytorch

  • numpy
    numpy 기반
  • autograd
    자동미분 지원
  • function
    다양한 형태의 함수와 모델 지원

Tensor

다차원 arrays를 표현하는 pytorch 클래스

python의 list = numpy 의 ndarray = pytorch 의 tensor = tensorflow의 tensor

import numpy as np
import torch

arr=list(range(10))
print(arr)

np_array=np.array(arr)
print(f"type : {type(np_array)}, ndim : {np_array.ndim}, shape : {np_array.shape}")
torch_tensor=torch.tensor(arr)
print(f"type : {type(torch_tensor)}, ndim : {torch_tensor.ndim}, shape : {torch_tensor.shape}")
torch_ftensor=torch.FloatTensor(arr)
print(f"type : {type(torch_ftensor)}, ndim : {torch_ftensor.ndim}, shape : {torch_ftensor.shape}")
torch_fnp=torch.from_numpy(np_array)
print(f"type : {type(torch_fnp)}, ndim : {torch_fnp.ndim}, shape : {torch_fnp.shape}")
>>>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
type : <class 'numpy.ndarray'>, ndim : 1, shape : (10,)
type : <class 'torch.Tensor'>, ndim : 1, shape : torch.Size([10])
type : <class 'torch.Tensor'>, ndim : 1, shape : torch.Size([10])
type : <class 'torch.Tensor'>, ndim : 1, shape : torch.Size([10])

tensor, FloatTensor, from_numpy등 으로 tensor을 만들 수 있다.

 

Tensor data types

https://pytorch.org/docs/stable/tensors.html

 

torch.Tensor — PyTorch 1.10.1 documentation

Shortcuts

pytorch.org

각 data type에 대응하는 tensor 타입을 페이지에서 볼 수 있다.

특이한 점은 GPU를 사용할 때 쓰는 tensor타입이 다르다는 것이다

torch_tensor.device
>>>device(type='cpu')

그래서 지금 사용중인 텐서가 메모리(=cpu)에 올라가 있는지 GPU에 올라가 있는지 확인하고 변경할 수 있는 속성이다.

현재는 메모리에 올라가 있다.

 

GPU에 올리기 위해서는 GPU가 필요한데 노트북이나 데스크탑에 없다면

colab>런타임>런타임 유형변경>GPU를 통해서 GPU를 사용해 볼 수 있다

if torch.cuda.is_available():
    torch_cuda=torch_tensor.to('cuda')
torch_cuda.device
>>>device(type='cuda', index=0)

이렇게 type='cuda'이면 GPU에 올라가 있는 것이다.

 

Tensor handling

텐서 모양을 다루어보고 크기를 변경해보자

tensor=torch.rand(size=(1,3,2))
tensor
>>>tensor([[[0.4723, 0.2442],
         [0.9367, 0.0366],
         [0.9045, 0.4830]]])
  • view(=reshape)
    tensor.view([-1,6])
    >>>tensor([[0.4723, 0.2442, 0.9367, 0.0366, 0.9045, 0.4830]])
    
    tensor.reshape([-1,6])
    >>>tensor([[0.4723, 0.2442, 0.9367, 0.0366, 0.9045, 0.4830]])​
    reshape과 view는 copy방식에서만 차이가 난다.
    view는 기존의 값(메모리 주소)만 가져와서 보여주는 형태만 바꾸어 준 것이다.
    하지만 reshape은 메모리 할당을 할 때, 값이 바뀌게 되면 주소를 가져오는 것이 아니라 copy를 해서 가져온다.
    복잡하다면 view를 주로 사용하면 좋다.
  • squeeze
    차원 삭제
    tensor의 shape이 1인 것을 모두 삭제한다
    tensor1=tensor.squeeze()
    print(tensor1.shape)
    tensor1
    >>>torch.Size([3, 2])
    tensor([[0.4723, 0.2442],
            [0.9367, 0.0366],
            [0.9045, 0.4830]])​
    (1,3,2)->(3,2)로 1인 차원이 삭제 되었다

  • unsqueeze
    차원 추가
    tensor.unsqueeze(dim=3)
    >>>tensor([[[[0.4723],
              [0.2442]],
    
             [[0.9367],
              [0.0366]],
    
             [[0.9045],
              [0.4830]]]])​
     안에서부터 밖으로 숫자가 작아진다
    가장 바깥에 추가하고싶으면 dim=0을 넣으면 된다
    현재에서는 가장 안의 dim으로 3을 넣었더니 각 숫자마다[]가 생기는 것으로 차원이 추가된 것을 확인할 수 있다

 

Tensor Operations

t1=torch.tensor(np.arange(0,10).reshape(2,5))
t2=torch.tensor(np.arange(10,101,10).reshape(2,5))

print(t1)
print(t2)
>>>tensor([[0, 1, 2, 3, 4],
        [5, 6, 7, 8, 9]], dtype=torch.int32)
tensor([[ 10,  20,  30,  40,  50],
        [ 60,  70,  80,  90, 100]], dtype=torch.int32)
  • +
    t1+t2
    >>>tensor([[ 10,  21,  32,  43,  54],
            [ 65,  76,  87,  98, 109]], dtype=torch.int32)​
  • -
    t1-t2
    >>>tensor([[-10, -19, -28, -37, -46],
            [-55, -64, -73, -82, -91]], dtype=torch.int32)​
  • 스칼라 덧셈
    t1+10
    >>>tensor([[10, 11, 12, 13, 14],
            [15, 16, 17, 18, 19]], dtype=torch.int32)​
  • 스칼라 곱셈
    t1*10
    >>>tensor([[ 0, 10, 20, 30, 40],
            [50, 60, 70, 80, 90]], dtype=torch.int32)​
  • 벡터 곱셈 (내적)
    1차원 * 1차원
    t1=torch.tensor(np.arange(5))
    print(t1)
    t1.dot(t1)
    >>>tensor([0, 1, 2, 3, 4], dtype=torch.int32)
    tensor(30, dtype=torch.int32)​
  • 행렬 곱셈
    다차원 * 다차원
    t1=torch.tensor(np.arange(10).reshape(2,5))
    t2=torch.tensor(np.arange(10,20).reshape(5,-1))
    t1.mm(t2)
    >>>tensor([[160, 170],
            [510, 545]], dtype=torch.int32)​
  • 행렬 곱셈(broadcasting)
    위의 mm 과 같지만 matmul은 broadcasting이 가능하다.
    행렬 사이즈가 모자르면 늘려주는 것으로 broadcasting을 간단하게 이해할 수 있다
    하지만 자칫하면 잘못된 식이지만 계산은 되는 것 처럼 보이기 때문에 헷갈릴 수 있다.
    t1=torch.tensor(np.arange(24).reshape(2,3,4))
    print(t1)
    t2=torch.tensor(np.arange(4).reshape(4))
    print(t2)
    t1.matmul(t2)
    >>>ensor([[[ 0,  1,  2,  3],
             [ 4,  5,  6,  7],
             [ 8,  9, 10, 11]],
    
            [[12, 13, 14, 15],
             [16, 17, 18, 19],
             [20, 21, 22, 23]]], dtype=torch.int32)
    tensor([0, 1, 2, 3], dtype=torch.int32)
    tensor([[ 14,  38,  62],
            [ 86, 110, 134]], dtype=torch.int32)​

ML/DL formula

  • softmax
    import torch.nn.functional as F
    tensor=torch.rand(3)
    print('tensor : ',tensor)
    soft_tensor=F.softmax(tensor,dim=0)
    soft_tensor
    >>>tensor :  tensor([0.2970, 0.1430, 0.1812])
    tensor([0.3639, 0.3120, 0.3241])​
  • argmax
    tensor=torch.randint(5,(3,5))
    print(tensor)
    tensor1=tensor.argmax(dim=0)
    print('axis=0',tensor1)
    tensor2=tensor.argmax(dim=1)
    print('axis=1',tensor2)
    >>>tensor([[0, 0, 3, 3, 1],
            [3, 2, 4, 3, 3],
            [2, 2, 3, 3, 2]])
    axis=0 tensor([1, 2, 1, 2, 1])
    axis=1 tensor([3, 2, 3])​
  • one_hot
    F.one_hot(tensor2)
    >>>tensor([[0, 0, 0, 1],
            [0, 0, 1, 0],
            [0, 0, 0, 1]])​
    위의 agrmax 예제에서 값의 최대가 4가 아닌 3이어서 열 생성이 5개가 아닌 4개만 되었다고 추측할 수 있다
  • cartesian_prod
    python의 intertoold처럼 모든 경우의 수를 구해주는 카르테지안 곱이 있다
    t1=torch.tensor([1,2,3])
    t2=torch.tensor([4,5,6])
    torch.cartesian_prod(t1,t2)
    >>>tensor([[1, 4],
            [1, 5],
            [1, 6],
            [2, 4],
            [2, 5],
            [2, 6],
            [3, 4],
            [3, 5],
            [3, 6]])​

Autograd

자동미분

backward 함수를 사용해서 구현할 수 있다

미분을 해주는 대상이 되는 것은 requires_grad 속성을 True로 해준다

w=torch.tensor(3.0, requires_grad=True)
y=w**2
z=y+5
z.backward()
w.grad
>>>tensor(6.)

$$ y= w^2$$

$$z=y+5$$

$$ \frac{\partial{z}}{\partial{w}}=\frac{\partial{z}}{\partial{y}}\frac{\partial{y}}{\partial{w}} = 2w $$

$$2\times3=6$$

a=torch.tensor([5.0,6.0], requires_grad=True)
b=torch.tensor([2.0,3.0], requires_grad=True)

y= 2*a**3 +b**4
external_grad=torch.tensor([1,1])
y.backward(gradient=external_grad)
print(external_grad)

print(a.grad)
print(b.grad)
>>>tensor([1, 1])
tensor([150., 216.])
tensor([ 32., 108.])

backward에서 미분이 일어난다

$$y=2a^3+b^4$$

$$\frac{\partial{y}}{\partial{a}}=6a^2$$

$$\frac{\partial{y}}{\partial{b}}=4b^3$$

$$6\times 5 \times 5=150$$