ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [PyTorch] Deep learning with PyTorch - Intro
    Machine Learning/PyTorch 2022. 4. 27. 13:12
    728x90

     

    PyTorch로 딥러닝 하기: 60분 만에 끝장내기의 초간단 정리입니다.
    학습 및 정리 과정에서 들었던 의문이나 궁금한 사항에 대한 답도 설명에 추가했습니다. 
    실습은 구글 코랩(Google Colab) 을 통해 쉽게 따라 하실 수 있습니다.

     

    Pytorch

    Python 기반의 연산 패키지, 오픈 소스 Machine Learning 프레임워크

    • GPU 이용 연산 필요한 경우 사용 (Numpy 대체)
    • 신경망 구현에 유용한 라이브러리 제공
    • TensorFlow와 양대산맥을 이루는 딥러닝 연구 플랫폼 / 실제 서비스와 프로덕션 배포에도 사용

     

    Tensors

    배열이나 행렬과 유사한 자료구조 / Numpy의 ndarray와 유사 / GPU를 사용한 연산 가속 가능

    import torch
    import numpy as np

     

    1) 텐서 초기화

    • 데이터로부터 직접(directly) 생성 - 자료형(data type) 자동으로 유추
      • torch.tensor()
    data = [[1, 2], [3, 4]]
    x_data = torch.tensor(data)

     

    • NumPy 배열로부터 생성
      • torch.from_numpy()
    np_array = np.array(data)
    x_np = torch.from_numpy(np_array)

     

    • 다른 텐서로부터 생성
      • torch.ones_like()
      • torch.rand_like()
    x_ones = torch.ones_like(x_data) # x_data의 속성을 유지합니다.
    print(f"Ones Tensor: \n {x_ones} \n")
    
    x_rand = torch.rand_like(x_data, dtype=torch.float) # x_data의 속성을 덮어씁니다.
    print(f"Random Tensor: \n {x_rand} \n")
    Ones Tensor: 
     tensor([[1, 1],
            [1, 1]]) 
    
    Random Tensor: 
     tensor([[0.7803, 0.1358],
            [0.9131, 0.9045]])

     

    • 무작위(random) 또는 상수(constant) 값 사용
      • shape : 텐서의 차원(dimension) 나타내는 튜플
      • torch.rand() / torch.ones() / torch.zeros()
    shape = (2, 3,)
    rand_tensor = torch.rand(shape)
    ones_tensor = torch.ones(shape)
    zeros_tensor = torch.zeros(shape)
    
    print(f"Random Tensor: \n {rand_tensor} \n")
    print(f"Ones Tensor: \n {ones_tensor} \n")
    print(f"Zeros Tensor: \n {zeros_tensor}")
    Random Tensor: 
     tensor([[0.0607, 0.6287, 0.8601],
            [0.3853, 0.9052, 0.9199]]) 
    
    Ones Tensor: 
     tensor([[1., 1., 1.],
            [1., 1., 1.]]) 
    
    Zeros Tensor: 
     tensor([[0., 0., 0.],
            [0., 0., 0.]])

     


    2) 텐서의 속성(Attribute)

     

    • 텐서의 모양(shape), 자료형(datatype) 및 어느 장치에 저장되는지를 나타냄
      • variable.shape (=variable.size())
      • variable.dtype
      • variable.device
    tensor = torch.rand(3, 4)
    
    print(f"Shape of tensor: {tensor.shape}")
    print(f"Datatype of tensor: {tensor.dtype}")
    print(f"Device tensor is stored on: {tensor.device}")
    Shape of tensor: torch.Size([3, 4])
    Datatype of tensor: torch.float32
    Device tensor is stored on: cpu

     


     

    3) 텐서 연산(Operation)

    • 전치, 인덱싱, 슬라이싱, 수학 계산, 선형 대수, 샘플링 등 많은 연산  - [link]
    • 연산들은 GPU(일반적으로 CPU 보다 빠름)에서 실행 가능
    • Colab - Edit > Notebook Settings (수정 > 노트 설정)에서 GPU 할당 가능

     

    # GPU가 존재하면 텐서를 이동합니다
    if torch.cuda.is_available():
      tensor = tensor.to('cuda')
      print(f"Device tensor is stored on: {tensor.device}")
    Device tensor is stored on: cuda:0

     

    • NumPy 식의 표준 인덱싱 및 슬라이싱
    tensor = torch.ones(4, 4)
    tensor[:,1] = 0
    print(tensor)
    tensor([[1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 1., 1.]])

     

    • 텐서 합치기
      • torch.cat()
    t0 = torch.cat([tensor, tensor, tensor], dim=0)
    print(t0)
    print(t0.shape)
    
    t1 = torch.cat([tensor, tensor, tensor], dim=1)
    print(t1)
    print(t1.shape)
    tensor([[1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 1., 1.]])
    torch.Size([12, 4])
    tensor([[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
            [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
            [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
            [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.]])
    torch.Size([4, 12])

     

    • 텐서 곱하기
    tensor[2,2] = 2
    tensor[3,3] = 3
    
    # 요소별 곱(element-wise product)을 계산합니다
    print(f"tensor.mul(tensor) \n {tensor.mul(tensor)} \n")
    # 다른 문법:
    print(f"tensor * tensor \n {tensor * tensor}")
    tensor.mul(tensor) 
     tensor([[1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 4., 1.],
            [1., 0., 1., 9.]]) 
    
    tensor * tensor 
     tensor([[1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 4., 1.],
            [1., 0., 1., 9.]])

     

    • 두 텐서 간의 행렬 곱(matrix multiplication)
      • variable.T : 전치
      • matmul() (= @ 연산자)
    print(f"tensor.matmul(tensor.T) \n {tensor.matmul(tensor.T)} \n")
    # 다른 문법:
    print(f"tensor @ tensor.T \n {tensor @ tensor.T}")
    tensor.matmul(tensor.T) 
     tensor([[ 3.,  3.,  4.,  5.],
            [ 3.,  3.,  4.,  5.],
            [ 4.,  4.,  6.,  6.],
            [ 5.,  5.,  6., 11.]]) 
    
    tensor @ tensor.T 
     tensor([[ 3.,  3.,  4.,  5.],
            [ 3.,  3.,  4.,  5.],
            [ 4.,  4.,  6.,  6.],
            [ 5.,  5.,  6., 11.]])

     

    • 바꿔치기(in-place) 연산 - '_' 접미사를 갖는 연산들은 in-place 연산
      • ex) x.copy_() 나 x.t_()는 x를 변경함
    print(tensor, "\n")
    tensor.add_(5)
    print(tensor)
    tensor([[1., 0., 1., 1.],
            [1., 0., 1., 1.],
            [1., 0., 2., 1.],
            [1., 0., 1., 3.]]) 
    
    tensor([[6., 5., 6., 6.],
            [6., 5., 6., 6.],
            [6., 5., 7., 6.],
            [6., 5., 6., 8.]])
    주의 : in-place 연산은 메모리를 일부 절약하지만, 기록(history)이 삭제되어 도함수 계산에 문제 발생 가능(권장 x)

     


     

    4) NumPy 변환(Bridge)

    • CPU 상의 텐서와 NumPy 배열은 메모리 공간을 공유하기 때문에, 하나를 변경하면 다른 하나도 변경
    • PyTorch의 Tensor로 Numpy의 ndarray 를 대체했을 때 GPU에서 16배 이상의 속도 향상 가능(참고)

     

    4.1) 텐서를 NumPy 배열로 변환

    t = torch.ones(5)
    print(f"t: {t}")
    n = t.numpy()
    print(f"n: {n}")
    t: tensor([1., 1., 1., 1., 1.])
    n: [1. 1. 1. 1. 1.]

     

    • 텐서의 변경 사항이 NumPy 배열에도 반영
    t.add_(1)
    print(f"t: {t}")
    print(f"n: {n}")
    t: tensor([2., 2., 2., 2., 2.])
    n: [2. 2. 2. 2. 2.]

     

    4.2) NumPy 배열을 텐서로 변환

    n = np.ones(5)
    t = torch.from_numpy(n)

     

    • NumPy 배열의 변경 사항이 텐서에 반영
    np.add(n, 1, out=n)
    print(f"t: {t}")
    print(f"n: {n}")
    t: tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
    n: [2. 2. 2. 2. 2.]

     


     

    5) 추가 유용한 함수

    • 크기 변경 : tensor의 크기(size)나 모양(shape)을 변경하고 싶다면 torch.view를 사용
    x = torch.ones(4, 4)
    y = x.view(16)
    z = x.view(-1, 8) # -1은 다른 차원들을 사용하여 유추 -> torch.Size([2,8])
    
    print("x", x)
    print("y", y)
    print("z", z)
    x tensor([[1., 1., 1., 1.],
            [1., 1., 1., 1.],
            [1., 1., 1., 1.],
            [1., 1., 1., 1.]])
    y tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
    z tensor([[1., 1., 1., 1., 1., 1., 1., 1.],
            [1., 1., 1., 1., 1., 1., 1., 1.]])

     

    • .item() : 하나의 값만 scalar로 추출 가능
    x = torch.randn(1)
    print(x)
    print(x.item())
    tensor([-0.0118])
    -0.011786350980401039

     

    랜덤한 값을 가지는 텐서 생성

    •  랜덤 값으로 채워진 텐서를 생성하는 명령
      • torch.rand() : 0과 1 사이의 숫자를 균등하게 생성
      • torch.rand_like() : 사이즈를 튜플로 입력하지 않고 기존의 텐서로 정의
      • torch.randn() : 평균이 0이고 표준편차가 1인 가우시안 정규분포를 이용해 생성
      • torch.randn_like() : 사이즈를 튜플로 입력하지 않고 기존의 텐서로 정의
      • torch.randint() : 주어진 범위 내의 정수를 균등하게 생성, 자료형은 torch.float32
      • torch.randint_like() : 사이즈를 튜플로 입력하지 않고 기존의 텐서로 정의
      • torch.randperm() : 주어진 범위 내의 정수를 랜덤 하게 생성

     

    • 랜덤 생성에 사용되는 시드(seed)는 torch.manual_seed() 명령으로 설정한다.
    torch.manual_seed(0)
    
    a = torch.rand(5)
    b = torch.randn(5)
    c = torch.randint(10, size=(5,))
    d = torch.randperm(5)
    
    print(a)
    print(b)
    print(c)
    print(d)
    tensor([0.4963, 0.7682, 0.0885, 0.1320, 0.3074])
    tensor([ 0.5507,  0.2704,  0.6472,  0.2490, -0.3354])
    tensor([8, 4, 3, 6, 9])
    tensor([1, 3, 4, 2, 0])

     

     

    728x90

    댓글

Designed by Tistory.