쉬엄쉬엄블로그

PyTorch Basics 본문

부스트캠프 AI Tech 4기

PyTorch Basics

쉬엄쉬엄블로그 2023. 5. 11. 13:12
728x90

이 색깔은 주석이라 무시하셔도 됩니다.

PyTorch Basics

PyTorch Operations

  • numpy + AutoGrad
    • PyTorch를 공부할 때 numpy만 잘 알아도 쉽게 이해할 수 있음

Tensor

  • 다차원 Arrays를 표현하는 PyTorch 클래스

  • 사실상 numpy의 ndarray와 동일

    • 그러므로 TensorFlow의 Tensor와도 동일
  • Tensor를 생성하는 함수도 거의 동일

  • numpy - ndarray

      import numpy as np
      n_array = np.arange(10).reshape(2,5)
      print(n_array)
      print("ndim :", n_array.ndim, "shape : ", n_array.shape)
  • pytorch - tensor

      import torch
      t_array = torch.FloatTensor(n_array)
      print(t_array)
      print("ndim :", t_array.ndim, "shape : ", t_array.shape)

Array to Tensor

  • Tensor 생성은 list나 ndarray를 사용 가능

  • data to tensor

      data = [[3, 5], [10, 5]]
      x_data = torch.tensor(data)
      x_data
      # tensor([[ 3,  5],
      #         [10,  5]])
  • ndarray to tensor

      nd_array_ex = np.array(data)
      tensor_array = torch.from_numpy(nd_array_ex)
      tensor_array
      # tensor([[ 3,  5],
      #         [10,  5]])

Tensor data types

  • 기본적으로 tensor가 가질 수 있는 data 타입은 numpy와 동일
  • GPU를 쓸 수 있게 해주냐 없느냐의 차이가 있음

numpy like operations

  • 기본적으로 pytorch의 대부분의 사용법이 그대로 적용됨

      data = [[3, 5, 20], [10, 5, 50], [1, 5, 10]]
      x_data = torch.tensor(data)
    
      x_data[1:]
      # tensor([[10,  5, 50],
      #         [ 1,  5, 10]])
    
      x_data[:2, 1:]
      # tensor([[ 5, 20],
      #         [ 5, 50]])
    
      x_data.flatten()
      # tensor([ 3,  5, 20, 10,  5, 50,  1,  5, 10])
    
      torch.ones_like(x_data)
      # tensor([[1, 1, 1],
      #         [1, 1, 1],
      #         [1, 1, 1]])
    
      x_data.numpy()
      # array([[ 3,  5, 20],
      #        [10,  5, 50],
      #        [ 1,  5, 10]])
    
      x_data.shape
      # torch.Size([3, 3])
    
      x_data.dtype
      # torch.int64
  • pytorch의 tensor는 GPU에 올려서 사용가능

      x_data.device
      # device(type='cpu')
    
      if torch.cuda.is_available():
          x_data_cuda = x_data.to('cuda')
      x_data_cuda.device
      # device(type='cuda', index=0)

Tensor handling

  • view, squeeze, unsqueeze 등으로 tensor 조정가능

    • view : reshape과 동일하게 tensor의 shape을 변환

      • reshape 대신 view를 사용하는 것을 추천
      • view는 call by reference처럼 reshape은 call by value처럼 적용되는 듯
    • squeeze : 차원의 개수가 1인 차원을 삭제 (압축)

    • unsqueeze : 차원의 개수가 1인 차원을 추가

      tensor_ex = torch.rand(size=(2, 3, 2))
      tensor_ex
      # tensor([[[0.2241, 0.7548],
      #          [0.8304, 0.0921],
      #          [0.3622, 0.1289]],
      # 
      #         [[0.3631, 0.0160],
      #          [0.4605, 0.4266],
      #          [0.1298, 0.5042]]])
      
      tensor_ex.view([-1, 6])
      # tensor([[0.2241, 0.7548, 0.8304, 0.0921, 0.3622, 0.1289],
      #         [0.3631, 0.0160, 0.4605, 0.4266, 0.1298, 0.5042]])
      
      tensor_ex.reshape([-1,6])
      # tensor([[0.2241, 0.7548, 0.8304, 0.0921, 0.3622, 0.1289],
      #         [0.3631, 0.0160, 0.4605, 0.4266, 0.1298, 0.5042]])
      
      a = torch.zeros(3, 2)
      b = a.view(2, 3)
      a.fill_(1)
      # tensor([[1., 1.],
      #         [1., 1.],
      #         [1., 1.]])
      
      a
      # tensor([[1., 1.],
      #         [1., 1.],
      #         [1., 1.]])
      
      b
      # tensor([[1., 1., 1.],
      #         [1., 1., 1.]])
      
      a = torch.zeros(3, 2)
      b = a.t().reshape(6)
      a.fill_(1)
      # tensor([[1., 1.],
      #         [1., 1.],
      #         [1., 1.]])
      
      a
      # tensor([[1., 1.],
      #         [1., 1.],
      #         [1., 1.]])
      
      b
      # tensor([0., 0., 0., 0., 0., 0.])
      
  • squeeze와 unsqueeze

      tensor_ex = torch.rand(size=(2, 1, 2))
      tensor_ex.squeeze()
      # tensor([[0.6175, 0.0451],
      #         [0.8196, 0.7854]])
    
      tensor_ex = torch.rand(size=(2, 2))
      tensor_ex.unsqueeze(0).shape
      # torch.Size([1, 2, 2])
    
      tensor_ex.unsqueeze(1).shape
      # torch.Size([2, 1, 2])
    
      tensor_ex.unsqueeze(2).shape
      # torch.Size([2, 2, 1])

Tensor operations

  • 기본적인 tensor의 operations는 numpy와 동일

      n1 = np.arange(10).reshape(2,5)
      n2 = np.arange(10).reshape(5,2)
      t1 = torch.FloatTensor(n1)
      t2 = torch.FloatTensor(n2)
    
      t1 + t1
      # tensor([[ 0.,  2.,  4.,  6.,  8.],
      #         [10., 12., 14., 16., 18.]])
    
      t1 - t1
      # tensor([[0., 0., 0., 0., 0.],
      #         [0., 0., 0., 0., 0.]])
    
      t1 + 10
      # tensor([[10., 11., 12., 13., 14.],
      #         [15., 16., 17., 18., 19.]])
    
      t1 + t2
      ---------------------------------------------------------------------------
      RuntimeError                              Traceback (most recent call last)
      <ipython-input-32-9ac58c83af08> in <module>
      ----> 1 t1 + t2
    
      RuntimeError: The size of tensor a (5) must match the size of tensor b (2) at non-singleton dimension 1
      ---------------------------------------------------------------------------
  • 행렬곱셈 연산 함수는 dot이 아닌 mm 사용

    • 내적을 구할 때는 dot
    • 행렬간 연산을 할 때는 mm
    n2 = np.arange(10).reshape(5,2)
    t2 = torch.FloatTensor(n2)
    
    t1.mm(t2)
    # tensor([[ 60.,  70.],
    #         [160., 195.]])
    
    t1.dot(t2)
    ---------------------------------------------------------------------------
    RuntimeError                              Traceback (most recent call last)
    <ipython-input-37-e9d95797f0ac> in <module>
    ----> 1 t1.dot(t2)
    
    RuntimeError: 1D tensors expected, but got 2D and 2D tensors
    ---------------------------------------------------------------------------
    
    t1.matmul(t2)
    # tensor([[ 60.,  70.],
    #         [160., 195.]])
    
    a = torch.rand(10)
    b = torch.rand(10)
    a.dot(b)
    # tensor(3.7768)
    
    a
    # tensor([0.0551, 0.2704, 0.6091, 0.4992, 0.8537, 0.7814, 0.8016, 0.8468, 0.8652, 0.8580])
    
    a = torch.rand(10)
    b = torch.rand(10)
    a.mm(b)
    ---------------------------------------------------------------------------
    RuntimeError                              Traceback (most recent call last)
    <ipython-input-41-b53804119df5> in <module>
        1 a = torch.rand(10)
        2 b = torch.rand(10)
    ----> 3 a.mm(b)
    
    RuntimeError: self must be a matrix
    ---------------------------------------------------------------------------
    
    t1.dot(t2)
    ---------------------------------------------------------------------------
    RuntimeError                              Traceback (most recent call last)
    <ipython-input-42-e9d95797f0ac> in <module>
    ----> 1 t1.dot(t2)
    
    RuntimeError: 1D tensors expected, but got 2D and 2D tensors
    ---------------------------------------------------------------------------
    
    t1.matmul(t2)
    # tensor([[ 60.,  70.],
    #         [160., 195.]])
  • mm은 broadcasting 지원 안함, matmul은 broadcasting 지원 함

      a = torch.rand(10)
      b = torch.rand(10)
      a.dot(b)
      # tensor(1.6425)
    
      a = torch.rand(10)
      b = torch.rand(10)
      a.mm(b)
      ---------------------------------------------------------------------------
      RuntimeError                              Traceback (most recent call last)
      <ipython-input-45-b53804119df5> in <module>
            1 a = torch.rand(10)
            2 b = torch.rand(10)
      ----> 3 a.mm(b)
    
      RuntimeError: self must be a matrix
      ---------------------------------------------------------------------------
    
      a = torch.rand(5, 2, 3)
      b = torch.rand(5)
      a.mm(b)
      ---------------------------------------------------------------------------
      RuntimeError                              Traceback (most recent call last)
      <ipython-input-46-8eb1e1aa56cc> in <module>
            1 a = torch.rand(5,2, 3)
            2 b = torch.rand(5)
      ----> 3 a.mm(b)
    
      RuntimeError: self must be a matrix
      ---------------------------------------------------------------------------
    
      a = torch.rand(5, 2, 3)
      b = torch.rand(3)
      a.matmul(b)
    
      # tensor([[0.8852, 0.5109],
      #         [0.2697, 0.6508],
      #         [0.4165, 0.6240],
      #         [0.9187, 0.3721],
      #         [0.7430, 0.4134]])
    
      a[0].mm(torch.unsqueeze(b,1)).squeeze()
      # tensor([0.8852, 0.5109])
    
      a[1].mm(torch.unsqueeze(b,1))
      # tensor([[0.2697],
      #         [0.6508]])
    
      a[2].mm(torch.unsqueeze(b,1))
      # tensor([[0.4165],
      #         [0.6240]])
    
      a[3].mm(torch.unsqueeze(b,1))
      # tensor([[0.9187],
      #         [0.3721]])
    
      a[4].mm(torch.unsqueeze(b,1))
      # tensor([[0.7430],
      #         [0.4134]])
    • broadcasting은 결과를 헷갈리게 만드는 요소가 될 수도 있기 때문에 명확하게 사용하고 싶다면 mm 사용

Tensor operations for ML/DL formula

  • nn.functional 모듈을 통해 다양한 수식 변환을 지원함

      import torch
      import torch.nn.functional as F
    
      tensor = torch.FloatTensor([0.5, 0.7, 0.1])
      h_tensor = F.softmax(tensor, dim=0)
      h_tensor
      # tensor([0.3458, 0.4224, 0.2318])
    
      y = torch.randint(5, (10,5))
      print(y)
      # tensor([[3, 1, 1, 4, 1],
      #         [3, 0, 0, 4, 2],
      #         [2, 2, 1, 0, 2],
      #         [3, 3, 0, 2, 2],
      #         [0, 1, 2, 3, 3],
      #         [4, 1, 2, 0, 4],
      #         [3, 4, 0, 3, 1],
      #         [1, 1, 3, 0, 3],
      #         [3, 1, 1, 3, 1],
      #         [4, 3, 3, 4, 2]])
    
      y_label = y.argmax(dim=1)
      y_label
      # tensor([3, 3, 0, 0, 3, 0, 1, 2, 0, 0])
    
      torch.nn.functional.one_hot(y_label)
      # tensor([[0, 0, 0, 1],
      #         [0, 0, 0, 1],
      #         [1, 0, 0, 0],
      #         [1, 0, 0, 0],
      #         [0, 0, 0, 1],
      #         [1, 0, 0, 0],
      #         [0, 1, 0, 0],
      #         [0, 0, 1, 0],
      #         [1, 0, 0, 0],
      #         [1, 0, 0, 0]])
    
      import itertools
      a = [1, 2, 3]
      b = [4, 5]
      list(itertools.product(a, b))
      # [(1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3, 5)]
    
      tensor_a = torch.tensor(a)
      tensor_b = torch.tensor(b)
      torch.cartesian_prod(tensor_a, tensor_b)
      # tensor([[1, 4],
      #         [1, 5],
      #         [2, 4],
      #         [2, 5],
      #         [3, 4],
      #         [3, 5]])

AutoGrad

  • PyTorch의 핵심은 자동 미분이 지원 → backward 함수 사용

    $y = w^2 \z = 10y + 25 \z = 10w^2 + 25$

      w = torch.tensor(2.0, requires_grad=True)
      y = w**2
      z = 10*y + 50
      z.backward()
      z # z식에 w가 2일 때 값이 90
      # tensor(90., grad_fn=<AddBackward0>)
    
      w.grad # z에 대해서 w로 편미분했을 때 w가 2인 경우에 값이 40
      # tensor(40.)

    $Q = 3a^3 - b^2$

    $\frac{\partial Q}{\partial a} = 9a^2 \ \ \
    \frac{\partial Q}{\partial b} = -2b$

      a = torch.tensor([2., 3.], requires_grad=True)
      b = torch.tensor([6., 4.], requires_grad=True)
      Q = 3*a**3 - b**2
      external_grad = torch.tensor([1., 1.])
      Q.backward(gradient=external_grad)
      Q # Q식에 a가 [2, 3], b가 [6, 4]일 때 값이 (-12, 65)
      # tensor([-12.,  65.], grad_fn=<SubBackward0>)
    
      a.grad # Q식에 대해서 a로 편미분했을 때 a가 [2, 3]인 경우에 값이 (36, 81)
      # tensor([36., 81.])
    
      b.grad # Q식에 대해서 b로 편미분했을 때 b가 [6, 4]인 경우에 값이 (-12, -8)
      # tensor([-12.,  -8.])

출처: 부스트캠프 AI Tech 4기(NAVER Connect Foundation)

'부스트캠프 AI Tech 4기' 카테고리의 다른 글

Custom Model 제작  (0) 2023.05.13
PyTorch 프로젝트 구조 이해하기  (0) 2023.05.12
PyTorch 소개  (2) 2023.05.10
RNN 기초  (0) 2023.05.09
CNN 기초  (0) 2023.05.08
Comments