Gorio Tech Blog search

PyTorch 사용법 - 02. Linear Regression Model

|

PyTorch 사용법 - 00. References
PyTorch 사용법 - 01. 소개 및 설치
PyTorch 사용법 - 02. Linear Regression Model
PyTorch 사용법 - 03. How to Use PyTorch


이 글에서는 가장 기본 모델인 Linear Regression Model의 Pytorch 프로젝트를 살펴본다.

사용되는 torch 함수들의 사용법은 여기에서 확인할 수 있다.


프로젝트 구조

  • 02_Linear_Regression_Model/
    • main.py
    • data/
      • 02_Linear_Regression_Model_Data.csv
    • results/
  1. 일반적으로 데이터는 data/ 디렉토리에 넣는다.
  2. 코드는 git에 두고, data/.gitignore 파일에 추가하여 데이터는 git에 올리지 않는다. 파일은 다른 서버에 두고 필요할 때 다운로드한다. 일반적으로 dataset은 그 크기가 수 GB 혹은 그 이상도 될 수 있기 때문에 upload/download 시간이 굉장히 길어지기도 하고, Git이 100MB 이상의 큰 파일은 업로드를 지원하지 않기 때문이기도 하다.

물론 이 예제 프로젝트는 너무 간단하여 그냥 data/ 디렉토리 없이 해도 상관없다.
그리고 output/ 또는 results/ 디렉토리를 만들도록 한다.


Import

import pandas as pd

import torch
from torch import nn

import matplotlib.pyplot as plt

다음 파일을 다운로드하여 data/ 디렉토리에 넣는다.

02_Linear_Regression_Model_Data.csv

  1. torch: 설명이 필요없다.
  2. from torch import nn: nn은 Neural Network의 약자이다. torch의 nn 라이브러리는 Neural Network의 모든 것을 포괄하며, Deep-Learning의 가장 기본이 되는 1-Layer Linear Model도 nn.Linear 클래스를 사용한다. 이 예제에서도 nn.Linear를 쓴다.
    • nn.Module은 모든 Neural Network Model의 Base Class이다. 모든 Neural Network Model(흔히 Net이라고 쓴다)은 nn.Module의 subclass이다. nn.Module을 상속한 어떤 subclass가 Neural Network Model로 사용되려면 다음 두 메서드를 override해야 한다.
      • __init__(self): Initialize. 여러분이 사용하고 싶은, Model에 사용될 구성 요소들을 정의 및 초기화한다. 대개 다음과 같이 사용된다.
        • self.conv1 = nn.Conv2d(1, 20, 5)
        • self.conv2 = nn.Conv2d(20, 20, 5)
        • self.linear1 = nn.Linear(1, 20, bias=True)
      • forward(self, x): Specify the connections. __init__에서 정의된 요소들을 잘 연결하여 모델을 구성한다. Nested Tree Structure가 될 수도 있다. 주로 다음처럼 사용된다.
        • x = F.relu(self.conv1(x))
        • return F.relu(self.conv2(x))
    • 다른 말로는 위의 두 메서드를 override하기만 하면 손쉽게 Custom net을 구현할 수 있다는 뜻이기도 하다.
  3. 참고: torch.autograd.Variable은 이전에는 auto gradient 계산을 위해 tensor에 필수적으로 씌워 주어야 했으나, PyTorch 0.4.0 버전 이후로 torch.Tensortorch.autograd.Variable 클래스가 통합되었다. 따라서 PyTorch 구버전을 사용할 예정이 아니라면 Variable은 쓸 필요가 전혀 없다.

Load Data

데이터 준비

지금의 경우는 전처리할 필요가 없으므로 그냥 데이터를 불러오기만 하면 된다. 데이터가 어떻게 생겼는지도 확인해 보자.
데이터가 어떤지 살펴보는 것은 모델을 결정하는 데 있어 매우 중요하다.

다운로드는 여기에서 할 수 있다.

data = pd.read_csv('data/02_Linear_Regression_Model_Data.csv')
# Avoid copy data, just refer
x = torch.from_numpy(data['x'].values).unsqueeze(dim=1).float()
y = torch.from_numpy(data['y'].values).unsqueeze(dim=1).float()

plt.xlim(0, 11);    plt.ylim(0, 8)
plt.title('02_Linear_Regression_Model_Data')
plt.scatter(x, y)

plt.show()

02_Linear_Regression_Model_Data

from_numpy로 불러오는 이유는 데이터를 복사하여 새로 텐서를 생성하는 대신 원 데이터와 메모리를 공유하는 텐서를 쓰기 위함이다. 지금은 상관없지만 대용량의 데이터를 다룰 때에는 어떤 함수가 데이터를 복사하는지 아닌지를 확실하게 알아둘 필요가 있다.
물론, 정말 대용량의 데이터의 경우는 read_csv로 한번에 불러오지 못한다. 이는 데이터를 batch로 조금씩 가져오는 것으로 해결하는데, 이에 대해서는 나중에 살펴보자.

참고: 이 데이터는 다음 코드를 통해 생성되었다.

x = torch.arange(1, 11, dtype=torch.float).unsqueeze(dim=1)
y = x / 2 + 1 + torch.randn(10).unsqueeze(dim=1) / 5

data = torch.cat((x, y), dim=1)
data = pd.DataFrame(data.numpy())

data.to_csv('data/02_Linear_Regression_Model_Data.csv', header=['x', 'y'])

Define and Load Model

매우 간단한 모델이므로 코드도 짧다.
여기서는 여러분의 편의를 위해 함수들의 parameter 이름을 명시하도록 한다.

PyTorch에서 Linear 모델은 torch.nn.Linear 클래스를 사용한다. 여기서는 단지 x를 y로 mapping하는 일차원 직선($ y = wx + b $)을 찾고 싶은 것이므로, in_featuresout_features는 모두 1이다.
nn.Linearnn.Module의 subclass로 in_features개의 input을 선형변환을 거쳐 out_features개의 output으로 변환한다. parameter 개수는 $ (in _ features \times out _ features [ + out _ features]) $ 개이다. 마지막 항은 bias이다.

from torch import nn

model = nn.Linear(in_features=1, out_features=1, bias=True)
print(model)
print(model.weight)
print(model.bias)

"""
Linear(in_features=1, out_features=1, bias=True)
Parameter containing:
tensor([[-0.9360]], requires_grad=True)
Parameter containing:
tensor([0.7960], requires_grad=True)
"""

별다른 utility 함수가 필요 없으므로 따로 utils.py는 만들지 않는다.


Set Loss function(creterion) and Optimizer

적절한 모델을 선정할 때와 마찬가지로 loss function과 optimizer를 결정하는 것은 학습 속도와 성능을 결정짓는 중요한 부분이다.
지금과 같이 간단한 Linear Regression Model에서는 어느 것을 사용해도 학습이 잘 된다. 하지만, 일반적으로 성능이 좋은 AdamOptimizer를 사용하도록 하겠다.

criterion = nn.MSELoss()
optimizer = torch.optim.Adam(params=model.parameters(), lr=0.01)

print(model(x))

"""
tensor([[-0.1399],
        [-1.0759],
        [-2.0119],
        [-2.9478],
        [-3.8838],
        [-4.8197],
        [-5.7557],
        [-6.6917],
        [-7.6276],
        [-8.5636]], grad_fn=<ThAddmmBackward>)
"""

참고: 보통 변수명은 criterion 혹은 loss_function 등을 이용한다.


Train Model

Train은 다음과 같이 이루어진다.

  1. 모델에 데이터를 통과시켜 예측값(현재 모델의 weights로 prediction)을 얻은 뒤
  2. 실제 정답과 loss를 비교하고
  3. gradient를 계산한다.
  4. 이 값을 통해 weights를 업데이트한다(backpropagation).
for step in range(500):
    prediction = model(x)
    loss = criterion(input=prediction, target=y)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if step % 20 == 0:
        """
        Show your intermediate results
        """
        pass

코드의 각 라인을 설명하면 다음과 같다.

  1. prediction: 모델에 데이터(x)를 집어넣었을 때 예측값(y). 여기서는 $ y = wx + b $의 결과들이다.
  2. loss: criterion이 MSELoss로 설정되어 있으므로, prediction과 y의 평균제곱오차를 계산한다.
  3. optimizer.zero_grad(): optimizer의 grad를 0으로 설정한다. PyTorch는 parameter들의 gradient를 계산해줄 때 grad는 계속 누적되도록 되어 있다. 따라서 gradient를 다시 계산할 때에는 0으로 세팅해주어야 한다.
  4. loss.backward(): gradient 계산을 역전파(backpropagation)한다.
  5. optimizer.step(): 계산한 gradient를 토대로 parameter를 업데이트한다($ w \leftarrow w - \alpha \Delta w, b \leftarrow b - \alpha \Delta b $)
  6. 학습 결과를 중도에 확인하고 싶으면 그래프를 중간에 계속 그려주는 것도 한 방법이다.

Visualize and save results

결과를 그래프로 보여주는 부분은 matplotlib.pyplot에 대한 내용이므로 여기서는 넘어가도록 하겠다.

def display_results(model, x, y):
    prediction = model(x)
    loss = criterion(input=prediction, target=y)
    
    plt.clf()
    plt.xlim(0, 11);    plt.ylim(0, 8)
    plt.scatter(x.data.numpy(), y.data.numpy())
    plt.plot(x.data.numpy(), prediction.data.numpy(), 'b--')
    plt.title('loss={:.4}, w={:.4}, b={:.4}'.format(loss.data.item(), model.weight.data.item(), model.bias.data.item()))
    plt.show()
    # plt.savefig('results/02_Linear_Regression_Model_trained.png')

display_results(model, x, y)

02_Linear_Regression_Model_Trained

모델을 저장하려면 torch.save 함수를 이용한다. 저장할 모델은 대개 .pt 확장자를 사용한다.

torch.save(obj=model, f='02_Linear_Regression_Model.pt')

참고: .pt 파일로 저장한 PyTorch 모델을 load해서 사용하려면 다음과 같이 한다. 이는 나중에 Transfer Learning과 함께 자세히 다루도록 하겠다.

loaded_model = torch.load(f='02_Linear_Regression_Model.pt')

display_results(loaded_model, x, y)

정확히 같은 결과를 볼 수 있을 것이다.


전체 코드는 여기에서 살펴볼 수 있다.


Comment  Read more

PyTorch 사용법 - 01. 소개 및 설치

|

PyTorch 사용법 - 00. References
PyTorch 사용법 - 01. 소개 및 설치
PyTorch 사용법 - 02. Linear Regression Model
PyTorch 사용법 - 03. How to Use PyTorch


2023.06.13 updated

간단한 소개

PyTorch는 유연성과 속도를 모두 갖춘 딥러닝 연구 플랫폼이다. GPU 사용이 가능하기 때문에 속도가 상당히 빠르다.
또 입문 난이도가 높지 않은 편이고 코드가 간결하다.


설치 방법

여기를 참조한다. 자신에게 맞는 OS, package manager, Python 버전, CUDA 버전 등을 선택하면 그에 맞는 명령어 집합이 나온다. 이를 명령창에 실행하면 설치가 진행된다.
torchvision을 설치할 경우에 무슨 라이브러리가 없다면서 에러 메시지가 뜨긴 하는데, 사용하는 데 별 문제는 없을 것이다. 만약 자신이 그 부분을 꼭 써야 한다면 에러를 해결하고 넘어가자.

설치를 완료했으면, 명령창에 다음과 같이 입력해보자. Anadonda를 플랫폼으로 사용한다면 conda 설정은 직접 해 주어야 한다.

python

# 이 부분은 Python Interpreter에서 입력함.
import torch  
x = torch.randn(3,5)  
print(x)

결과가 대략 다음과 같이 나오면 설치가 완료되었다. 숫자가 다른 것은 랜덤이니 신경 쓰지 말자.

01_run_pytorch.PNG


GPU 사용을 위한 설치

GPU 사용을 위한 필수 절차는 다음과 같다.

추천 조합: torch 2.0.1, nvidia-driver-515, cuda 11.7

Ubuntu의 경우 여기를 참조해도 된다.

  1. 호환성 체크
    1. 컴퓨터에 있는 GPU의 compute capability 확인
    2. compute capability에 맞는 CUDA SDK 버전 확인
    3. CUDA, nvidia-driver 호환 확인
      • 여기에서 확인
      • CUDA toolkit 호환성 확인은 여기에서
    4. Pytorch와 CUDA의 호환성 확인
      • 설치하고자 하는 PyTorch(또는 Tensorflow)가 지원하는 최신 CUDA 버전이 있다. 이보다 상위 버전의 CUDA를 설치하면 PyTorch 코드가 제대로 돌아가지 않는다.
      • Pytorch 홈페이지에서 정해주는 CUDA 버전을 설치하는 쪽이 편하다. 2023.06.13 기준 추천 최신 버전은 11.7이다.
    5. CUDA에 맞는 cuDNN 버전 확인
      • 여기에서 확인할 수 있다.
  2. 이전 버전의 CUDA 제거
    1. CUDA를 여러 개 쓸 수도 있지만, 이전 버전의 CUDA를 제거해 주면 좋다.
      1. Windows의 경우 NVIDIA 관련 프로그램 제거를 해 주면 된다.
      2. Ubuntu의 경우 살짝 까다로운데, 터미널에 다음 코드를 입력한다.
         sudo apt-get purge nvidia*
         # sudo apt-get remove --purge '^nvidia-.*'
         sudo apt-get autoremove
         sudo apt-get autoclean
         sudo rm -rf /usr/local/cuda*
        
      3. 혹시 오류가 뜨면 아래 7. 오류 해결법을 참조하자.
    2. 예전엔 어땠는지 잘 모르겠지만 최근 CUDA 설치 시 그에 맞는 nvidia-driver가 같이 설치된다. 따로 특정 버전의 driver를 요구하는 것이 아니라면 그대로 설치하자.
  3. Nvidia Driver 설치
    1. Windows의 경우 Geforce Experience 혹은 Nvidia에서 적절한 버전의 Driver를 설치한다.
    2. Ubuntu의 경우 다음 코드를 입력해 본다.
       # 가능 드라이버 확인 
       sudo apt search nvidia-driver   # 또는 ubuntu-drivers devices
       # 특정 드라이버 설치 
       sudo apt-get install nvidia-driver-515
      
  4. CUDA 설치
    1. Windows
      1. CUDA toolkit archive에서 원하는 CUDA를 다운받는다. 운영체제와 버전 등을 체크하고, 가능하면 Installer Type은 network가 아닌 local로 받는다. 인터넷으로 설치하면서 받는 것이 아닌 한번에 설치파일을 받는 식이다.
        • 같은 버전인데 update가 추가된 버전이 있다. 보통은 이것까지 추가로 설치해 주는 쪽이 좋다. base installer를 먼저 설치한 뒤에 추가로 설치해 주도록 하자.
      2. 설치 파일로 CUDA를 설치한다. 설치 시에는 다른 프로그램을 설치하거나 제거하는 중이면 실행이 되지 않으니 주의하자.
      3. cuda visual studio integration 관련해서 설치 실패가 뜨는 경우가 많은데, 이 부분이 필요한 코드를 실행할 일이 있다면 이 단계에서 다시 설치해 주는 것이 좋다. Visual Studio를 설치하면 해결이 되는 경우가 많다.
      4. C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0\bin을 등록하자. 버전에 따른 경로를 유의하자.
        • 실행이 잘 안 되는 경우 상위 또는 하위 폴더 몇 개를 추가 등록하면 되는 경우도 있다.
    2. Ubuntu 18.04(CUDA 11.0 기준)
      1. 역시 CUDA toolkit archive에 접속한다. Linux 버전에 따라서 알맞게 선택한다. Ubuntu 18.04를 선택한다면, 일반적으로 Linux - x86_64 - Ubuntu - 18.04를 따른다.
      2. 다음으로 Installer Type이 있는데, runfile의 경우는 .exe 파일처럼 실행이 가능하고, deb(local)은 터미널에 코드를 몇 줄 입력하면 되는 방식이다.
      3. runfile을 선택하면 다음 비슷한 코드를 실행하라고 안내가 뜬다.
         wget http://developer.download.nvidia.com/compute/cuda/11.0.2/local_installers/cuda_11.0.2_450.51.05_linux.run
         chmod +x cuda_11.0.2_450.51.05_linux.run
         sudo sh cuda_11.0.2_450.51.05_linux.run
         # 참고로 위 커맨드에 --silent 옵션을 주면 nvidia-driver, toolkit, docs 등이 조용히 다 설치된다. 
        
      4. 아래 줄까지 실행하면 안내 페이지가 뜬다.
        1. 드라이버가 이전에 설치된 게 있다고 뜨는데, 미리 제거해 두는 것이 편하긴 하다. 그러나 제거하지 않아도 될 때도 있다. 엔터키를 누르면 X 표시가 토글된다.
        2. 다음으로 계약 동의를 위해 accept를 입력하고 엔터키를 누른다.
        3. 그냥 기본으로 두고 Install을 해도 된다. 그러나 Driver 설치 단계에서 오류가 나면(설치 실패시 로그를 확인하라고 뜬다), Driver을 엔터키를 눌러 체크 해제한다. CUDA symbolic link를 대체하고 싶지 않다면 역시 symbolic link 부분을 체크 해제한다.
        4. 정상적으로 설치가 된다면 다음과 비슷한 것을 볼 수 있다.
           ===========
           = Summary =
           ===========
          
           Driver:   Not Selected
           Toolkit:  Installed in /usr/local/cuda-11.0/
           Samples:  Installed in /root/, but missing recommended libraries
          
           Please make sure that
           -   PATH includes /usr/local/cuda-11.0/bin
           -   LD_LIBRARY_PATH includes /usr/local/cuda-11.0/lib64, or, 
           add /usr/local/cuda-11.0/lib64 to /etc/ld.so.conf and run ldconfig as root
          
        5. sudo vim /etc/bash.bashrc을 실행한 다음, 파일의 가장 아래쪽에 다음 코드를 추가하자. 버전에 따른 경로를 유의하자.
           export PATH=/usr/local/cuda-11.0/bin:$PATH
           export LD_LIBRARY_PATH=/usr/local/cuda-11.0/lib64:$LD_LIBRARY_PATH
           export LD_LIBRARY_PATH=/usr/local/cuda-11.0/extras/CUPTI/lib64:$LD_LIBRARY_PATH
          
        6. 다음 코드를 실행하여 변경 사항을 적용한다.
           source /etc/bash.bashrc
          
      5. deb(local)을 선택하면 터미널에 코드 몇 줄을 입력하면 된다. 이전에 CUDA 설치가 꼬인 것이 아니라면 보통은 에러 없이 설치된다. 버전에 따라 경로가 달라지므로 유의하자.
         wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin
         sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600
         wget http://developer.download.nvidia.com/compute/cuda/11.0.2/local_installers/cuda-repo-ubuntu1804-11-0-local_11.0.2-450.51.05-1_amd64.deb
         sudo dpkg -i cuda-repo-ubuntu1804-11-0-local_11.0.2-450.51.05-1_amd64.deb
         sudo apt-key add /var/cuda-repo-ubuntu1804-11-0-local/7fa2af80.pub
         sudo apt-get update
         sudo apt-get -y install cuda
        
  5. cuDNN 설치
    1. Windows
      1. 우선 cudnn-archive에서 사용하고자 하는 CUDA에 맞는 버전(cuDNN Library for Windows (x86))을 찾아 다운받는다. login이 필요하다.
      2. 압축을 풀어 CUDA 설치 폴더(C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0)에 붙여넣기 하면 된다. 폴더 경로는 설치한 CUDA 버전에 따라 달라진다.
    2. Ubuntu 18.04(cudnn 8.0.3 기준)
      1. 비슷하게 여기에서 cuDNN Library for Linux (x86_64)을 받는다. 이유는 잘 모르겠으나 wget으로 잘 받아지지 않는 경우가 있으니 브라우저로 접속하여 다운로드하자.
      2. 받고 나서 tar xvf cudnn-11.0-linux-x64-v8.0.3.33.tgz으로 압축을 해제한다.
      3. 생성된 CUDA 폴더로 이동하여 파일들을 복사한다.
         cd cuda
         sudo cp include/cudnn* /usr/local/cuda-11.0/include
         sudo cp lib64/libcudnn* /usr/local/cuda-11.0/lib64/
         sudo chmod a+r /usr/local/cuda-11.0/lib64/libcudnn*
        
      4. 설치되었는지 확인하자.
         cat /usr/local/cuda-11.0/include/cudnn_version.h | grep CUDNN_MAJOR -A 2
        

        결과:

         R -A 2
         #define CUDNN_MAJOR 8
         #define CUDNN_MINOR 0
         #define CUDNN_PATCHLEVEL 3
         --
         #define CUDNN_VERSION (CUDNN_MAJOR * 1000 + CUDNN_MINOR * 100 + CUDNN_PATCHLEVEL)
        
         #endif /* CUDNN_VERSION_H */
        

        8.2.0임을 확인할 수 있다.

  6. 설치 확인
    1. NVCC를 통해 CUDA 설치를 확인해보자.
       nvcc -V
       dpkg - l | grep CUDA 
       dpkg - l | grep cuDNN
      

      만약 nvcc가 없으면 다음을 입력하자.

       sudo apt install nvidia-cuda-toolkit
      
    2. 다음 코드를 python을 실행하여 입력해보고 True가 뜨면 성공한 것이다.
       import torch
       torch.cuda.is_available()
      
  7. 에러 해결법
    1. E: sub process /usr/bin/dpkg returned an error code (1)의 에러가 뜬다면 다음을 터미널에 입력한다.
       sudo rm /var/lib/dpkg/info/*
       sudo dpkg --configure -a
       sudo apt update -y
      
    2. NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running. 에러가 뜨면 nvidia-driver를 재설치해야 한다.
       # 설치된 driver 확인
       sudo apt --installed list | grep nvidia-driver
       # 문제 있는 driver 삭제(보통 전부 삭제)
       sudo apt remove nvidia-driver-<version>
       sudo apt autoremove
       # 재설치 & 재부팅
       sudo apt-get install nvidia-driver-<원래 driver 버전>
       sudo reboot now
      
    3. nvidia-smi를 쓰려고 하는데 VNML: Driver/library version mismatch라는 에러가 날 때가 있다. 그런 경우 lsmod | grep nvidia를 터미널에 입력하고 nvidia kernel을 unload하면 된다. 오른쪽 column에 무언가 있다면 unload하면 된다.
       sudo rmmod nvidia_drm
       sudo rmmod nvidia_modeset
       sudo rmmod nvidia_uvm
       sudo rmmod nvidia
      

      위의 작업 도중 rmmod:ERROR: Module nvidia is in use라는 에러가 뜨면 nvidia 관련 process를 종료시켜주자.

       sudo lsof /dev/nvidia*
       sudo kill -9 <process_id>
      

      다시 lsmod | grep nvidia를 하고 아무 것도 안 뜬다면 완료된 것이다.

에러 해결법

서버에서 gpu사용을 위한 설치를 진행하다 보면 수많은 에러를 마주하게 될 수도 있다…

  • Command not found: nvidia-smi
    • CUDA를 설치 또는 재설치한다.
  • couldn't communicate with the nvidia-driver
    • nvidia-driver를 재설치한다.

참고: Ubuntu Python 설치

python 3.7 이후 버전은 (그 이전 버전도 있을 수 있다) apt-get 설치를 지원한다.

sudo apt update
sudo apt install python3.7 
sudo apt install python3.8
sudo apt install python3.9
# sudo apt-get install python3 python3-pip python3-dev python3-setuptools

Python이 여러 개 설치되어 터미널에 python을 입력했을 때 원하는 버전이 나오지 않는다면 vim ~/.bashrc로 파일을 열고 맨 아래에 다음과 비슷하게 추가하자.

# 명확하게 하길 원한다면 경로를 직접 지정하는 것이 편하다. 
# 최신 버전의 경우 '/usr/bin/python*` 또는 `/usr/local/bin/python*` 경로에 존재한다.
alias python='/usr/bin/python3.9'

# 오래된 서버에서 python 2 대신 3을 사용하고 싶은 경우
alias python=python3
alias pip=pip3

:wq를 입력하여 저장하고 나온 뒤 터미널에 source ~/.bashrc를 입력하여 변경사항을 적용하자.

Python 버전의 우선순위를 쓰고 싶다면 Python을 먼저 선택지에 추가해야 한다.

sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.9 2
# 마지막 숫자는 우선순위로 클수록 높은 우선권을 갖는다.

우선순위를 변경하고자 하는 경우 다음 명령을 입력하여 숫자를 누르고 엔터키를 누른다.

sudo update-alternatives --config python3

다시 auto mode로 돌아가려면 sudo update-alternatives --auto python3을 입력한다.

재설치 방법

sudo python3 -m pip uninstall pip 
sudo apt-get install python3-pip --reinstall

오류 해결법

ModuleNotFoundError: No module named ‘pip._internal’ 오류

다음 두 가지를 시도해본다.

# 재설치
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py --force-reinstall
# pip upgrade
python -m pip install --user --upgrade pip

pip3 on python3.9 fails on ‘HTMLParser’ object has no attribute ‘unescape’ 오류

pip3 install --upgrade setuptools
# 안 되면 다음을 시도한다.
pip3 install --upgrade pip
pip3 install --upgrade distlib

PyTorch Project 구조

프로젝트의 구조는 코딩하는 사람 마음대로이긴 하나, 기본적으로는 다음과 같은 구조를 따른다.

  1. Set HyperParameter and Run
  2. Load Data
  3. Define and Load Models 3-1. Define util functions
  4. Set Loss function(creterion) and Optimizer
  5. Train Model
  6. Visualize and save results

PyTorch는 각 단계에서 다음의 장점을 갖는다.

  1. PyTorch가 아닌 Python의 특징인데, 여러분은 많은 Machine Learning 코드를 보면서 python train.py --epochs 50 --batch-size 16 등 많은 옵션을 설정할 수 있는 것을 보았을 것이다. Python의 argparse 패키지는 이것을 가능하게 해 준다.
  2. 데이터 로드 시 DataLoader라는 클래스를 제공한다. DataLoader를 통해 데이터를 불러오면, 이 안에서 데이터 처리에 대한 거의 모든 것을 쉽게 수행할 수 있다.
    • 이를테면 Data Augmentation 같은 것도 전부 제공된다.
    • 여러 종류의 Data Transformation이 지원된다.
  3. 일반적인 모델을 불러올 때는 다른 Deep Learning Framework도 대체로 간결하지만, PyTorch는 torchvision이라는 패키지에서 따로 pretrain까지 된 모델들을 제공하므로 다른 곳에서 모델을 다운로드할 필요 없이 이를 바로 쓸 수 있다. 2-1. 많은 프로그래머들이 utils.py에 유틸리티 함수(예를 들면 YOLO에서 IoU를 구하는 함수)를 따로 빼내어 여러 가지를 한번에 정의한다. 프로젝트에서 부가적인 부분은 따로 관리하는 것이 가독성이 좋다.
  4. 이 부분은 다른 Deep Learning Framework와 비슷하다.
  5. Tensorflow와는 달리 Session을 설정할 필요가 없다.
  6. 이 부분도 역시 비슷하다.

다음 글에서는 Linear Regression Model을 예로 들어서 간단한 프로젝트의 구조를 설명하도록 하겠다.


References

PyTorch에서 자주 사용되는 함수들을 정리한 글이다.

Comment  Read more

PyTorch 사용법 - 00. References

|

PyTorch 사용법 - 00. References
PyTorch 사용법 - 01. 소개 및 설치
PyTorch 사용법 - 02. Linear Regression Model
PyTorch 사용법 - 03. How to Use PyTorch


본 글의 일부 예제는 Pytorch Documentation에서 가져왔음을 밝힙니다.


데이터 타입(dtype)

모든 텐서는 기본적으로 dtype을 갖고 있다. 데이터 타입(dtype)이란 데이터가 정수형인지, 실수형인지, 얼마나 큰 범위를 가질 수 있는지 등을 나타낸다.
종류는 아래 표와 같다.

Data type dtype CPU tensor GPU tensor
32-bit floating point torch.float32 or torch.float torch.FloatTensor torch.cuda.FloatTensor
64-bit floating point torch.float64 or torch.double torch.DoubleTensor torch.cuda.DoubleTensor
16-bit floating point torch.float16 or torch.half torch.HalfTensor torch.cuda.HalfTensor
8-bit integer (unsigned) torch.uint8 torch.ByteTensor torch.cuda.ByteTensor
8-bit integer (signed) torch.int8 torch.CharTensor torch.cuda.CharTensor
16-bit integer (signed) torch.int16 or torch.short torch.ShortTensor torch.cuda.ShortTensor
32-bit integer (signed) torch.int32 or torch.int torch.IntTensor torch.cuda.IntTensor
64-bit integer (signed) torch.int64 or torch.long torch.LongTensor torch.cuda.LongTensor

사용법은 어렵지 않다. 텐서 생성시 dtype=torch.float과 같이 parameter를 지정해 주기만 하면 된다.


Tensor Creation

torch.arange

# torch.arange(start=0, end, step=1, out=None, dtype=None, 
#              layout=torch.strided, device=None, requires_grad=False) → Tensor

start 이상 end 미만까지 step 간격으로 dtype 타입인 1차원 텐서를 생성한다.

out parameter로 결과 텐서를 저장할 변수(텐서)를 지정할 수 있다.

>>> torch.arange(start=1, end=9, step=2)
tensor([1, 3, 5, 7])

torch.linspace

# torch.linspace(start, end, steps=100, out=None, dtype=None, 
#                layout=torch.strided, device=None, requires_grad=False) → Tensor

start 이상 end 미만까지 총 steps 개수의 dtype 타입인 1차원 텐서를 생성한다.
torch.arange에서 step은 간격을, torch.linspace에서 steps는 개수를 의미한다.

>>> torch.linspace(-10, 10, steps=5)
tensor([-10.,  -5.,   0.,   5.,  10.])
>>> torch.linspace(0, 10, steps=10)
tensor([ 0.0000,  1.1111,  2.2222,  3.3333,  4.4444,  
         5.5556,  6.6667,  7.7778,  8.8889, 10.0000])

torch.from_numpy

# torch.from_numpy(ndarray) → Tensor

numpy array인 ndarray로부터 텐서를 만든다. 이 함수는 데이터를 복사가 아닌 참조를 한다.
from_numpy로 만들어진 텐서는 해당 ndarray와 메모리를 공유하며, 어느 한쪽의 데이터를 변경 시 둘 다 변경된다.

>>> a = numpy.array([1, 2, 3])
>>> t = torch.from_numpy(a)
>>> print(t)
tensor([ 1,  2,  3])
>>> t[0] = -1
>>> print(a)
array([-1,  2,  3])

torch.randn

# torch.randn(*sizes, out=None, dtype=None, 
#             layout=torch.strided, device=None, requires_grad=False) → Tensor

N(0, 1) 정규분포를 따르는 sizes 크기의 텐서를 생성한다.

>>> torch.randn(2, 3)
tensor([[ 1.5954,  2.8929, -1.0923],
        [ 1.1719, -0.4709, -0.1996]])

Tensor Reshape

torch.unsqueeze(Tensor.unsqueeze)

# torch.unsqueeze(input, dim, out=None) → Tensor

dim parameter 위치에 길이 1짜리 차원을 추가한 텐서를 만든다. 이 함수는 데이터를 복사가 아닌 참조를 한다. 원본 텐서와 메모리를 공유하며, 어느 한쪽의 데이터를 변경 시 둘 다 변경된다.

dim은 [ -input.dim() - 1, input.dim() + 1] 범위를 갖는다. 음수 dim은 dim + input.dim() + 1과 같다.
원본 텐서의 size가 (2, 3, 4)라면, unsqueeze(1) 버전은 (2, 1, 3, 4), unsqueeze(2) 버전은 (2, 3, 1, 4)이다.

>>> x = torch.tensor([1, 2, 3])
>>> x
tensor([1, 2, 3])
>>> y = x.unsqueeze(1)
>>> y
tensor([[1],
        [2],
        [3]])
>>> x.size(), y.size()
(torch.Size([3]), torch.Size([3, 1]))

>>> y[0][0] = -1
>>> y
tensor([[-1],
        [ 2],
        [ 3]])
>>> x
tensor([-1,  2,  3])

Tensor Operation

torch.cat

# torch.cat(seq, dim=0, out=None) → Tensor

두 텐서를 이어 붙인다(concatenate). 데이터를 복사한다.
concatenate하는 차원을 제외하고는 size가 같거나 empty여야 한다. 즉 shape=(2, 3, 4)인 텐서는 shape=(2, 1, 4)와는 dim=1일 때만 concatenate가 가능하다.

>>> x = torch.arange(0, 6).reshape(2, 3)
>>> y = torch.arange(100, 104).reshape(2, 2)
>>> x
tensor([[0, 1, 2],
        [3, 4, 5]])
>>> y
tensor([[100, 101],
        [102, 103]])
>>> torch.cat((x, y), dim=1)
tensor([[  0,   1,   2, 100, 101],
        [  3,   4,   5, 102, 103]])

torch.Tensor.backward


torch.nn

torch.nn.Linear

# class torch.nn.Linear(in_features, out_features, bias=True)

Linear 모델 클래스를 생성한다.
in_features 길이의 데이터를 Linear Transformation을 통해 out_features 길이의 데이터로 변환할 수 있다.

>>> from torch import nn
>>> model = nn.Linear(in_features=3, out_features=2, bias=True)

>>> print(model)
Linear(in_features=3, out_features=2, bias=True)
>>> print(model.weight)
Parameter containing:
tensor([[-0.3469,  0.1542, -0.4830],
        [-0.2903,  0.4949,  0.4592]], requires_grad=True)
>>> print(model.bias)
Parameter containing:
tensor([-0.0965,  0.5427], requires_grad=True)

torch.nn.MSELoss


torch.optim

torch.optim.Adam

torch.optim.Optimizer.zero_grad

torch.optim.Optimizer.step


Save and Load

torch.save


01_new_repository


Comment  Read more

파이썬 정규표현식(re) 사용법 - 09. 기타 기능

|

파이썬 정규표현식(re) 사용법 - 01. Basic
파이썬 정규표현식(re) 사용법 - 02. 문자, 경계, flags
파이썬 정규표현식(re) 사용법 - 03. OR, 반복
파이썬 정규표현식(re) 사용법 - 04. 그룹, 캡처
파이썬 정규표현식(re) 사용법 - 05. 주석, 치환, 분리
파이썬 정규표현식(re) 사용법 - 06. 치환 함수, 양방탐색, 조건문
파이썬 정규표현식(re) 사용법 - 07. 예제(숫자)
파이썬 정규표현식(re) 사용법 - 08. 예제(단어, 행)
파이썬 정규표현식(re) 사용법 - 09. 기타 기능


이 글에서는 re 패키지에 포함된, 지금까지의 글에서 다루지 않았던 함수와 속성 등을 다루도록 하겠다.

본 글에서 정규표현식은 regex와 같이, 일반 문자열은 ‘regex’와 같이 표시하도록 한다.

파이썬 버전은 3.6을 기준으로 하나, 3.x 버전이면 (아마) 동일하게 쓸 수 있다.
2.7 버전은 한글을 포함한 비 알파벳 문자 처리가 다르다.


함수

re.escape(string)

re.escape 함수는 문자열을 입력받으면 특수문자들을 이스케이프 처리시켜 준다.

pattern = r'((\d)\2{4,})'
print(re.escape(pattern))

결과

\(\(\\d\)\\2\{4\,\}\)

re.purge()

사실 설명하지 않은 것이 있는데, re 패키지는 re.compile로 만들어 놓은 객체들을 cache에 저장해 둔다. 최대 100개까지라고 알려져 있으며, 그 수를 넘어갈 경우 초기화된다고 한다.
물론 여러분은 아마 한 프로그램 내에서 100개 이상의 다른 정규식을 쓸 일은 없으니 크게 신경 쓸 필요는 없다.

re.purge 함수는 이 cache를 초기화하는 함수이다.

re.purge()

결과

결과는 아무것도 출력되지 않는다.


속성

re.RegexFlag

이전 글에서 flags를 설명했었는데, 이 flag들이 어떤 것이 있는지 알려주는 객체가 re 안에 내장되어 있다.

for flag in re.RegexFlag:
    print(flag)

결과

RegexFlag.ASCII
RegexFlag.IGNORECASE
RegexFlag.LOCALE
RegexFlag.UNICODE
RegexFlag.MULTILINE
RegexFlag.DOTALL
RegexFlag.VERBOSE
RegexFlag.TEMPLATE
RegexFlag.DEBUG

re.TEMPLATE

아마 쓸 일이 없을 듯하므로 설명은 생략한다. (?)

다만 이런 것이 있다는 것만 소개한다.


re.DEBUG

reObj를 출력하면 컴파일한 정규식을 그대로 출력하던 것을 기억할 것이다. re.debug는 일종의 디버깅 모드로서, 정규식의 대략적인 구조를 알 수 있다.
말 그대로 디버깅용으로 쓰면 될 듯하다.

r = re.compile('\d{3,6}', re.DEBUG)
print(r)
print(r.findall('AS 123123 ars'))

결과

MAX_REPEAT 3 6
  IN
    CATEGORY CATEGORY_DIGIT
re.compile('\\d{3,6}', re.DEBUG)
['123123']

reObj의 사용법은 기본 compile된 객체와 완전히 같다.


re.error

re.error는 compile 함수에 전달된 문자열이 유효하지 않은 정규식일 때 발생하는 에러 타입이다. try-except 구문으로 처리하면 된다. 자세한 사용법은 아래 예시로만 보여도 충분할 듯 하다.

참고로 아래 코드의 phi는 원주율을 소수점 1만 자리까지 저장한 문자열이다.

regex_list = [
    r'((\d)\2{4,})',
    r'((\d)\1{4,})'
]

for regex in regex_list:
    try:
        reObj = re.compile(regex)
        print(list(map(lambda x: x[0], reObj.findall(phi))))
    except re.error:
        print("<Invalid regular expression %s>" % regex)
    finally:
        print('done')

결과

['999999']
done
<Invalid regular expression ((\d)\1{4,})>
done

무엇이 유효하지 않은지는 연습문제로 남겨두도록 하겠다.

조금 더 자세한 사용법은 여기를 참조한다.


이것으로 정규표현식에 대한 글을 마치도록 한다.
조금 더 복잡한 예제를 정리해 두면 좋겠지만, 그때그때 맞게 쓰는 것이 더 나을 것 같아서 굳이 따로 정리할 필요는 없을 것 같다.

Comment  Read more

GitHub 사용법 - 08. Conflict

|

주의: 이 글을 읽는 여러분이, 만약 git을 많이 써 봐서 익숙한 것이 아니라면, 반드시 손으로 직접 따라 칠 것을 권한다. 눈으로만 보면 100% 잊어버린다.

저번 글에서 작업하던 것을 이어서 한다. 저번 글에서는 diff, add, commit, .gitignore에 대해서 알아보았다.


Conflict

Conflict는 이름 그대로 충돌인데, 다음의 경우일 때 conflict가 생긴다.

같은 파일의 같은 부분을 동시에 두 곳(이상)에서 수정했을 때

이런 경우는 보통 여러 사람의 분업이 명확하게 이루어지지 않아 코드의 같은 부분을 수정할 때 일어난다.
물론 1인 팀에서도 코드 관리를 잘못하여, 혹은 여러 컴퓨터에서 작업하게 될 때 이러한 실수가 일어나기도 한다.

Conflict의 발생 및 해결 순서는 다음과 같다.

  1. 동시에 같은 파일의 같은 부분을 수정하고, merge 혹은 push를 할 때 일어난다. 이는 같은 파일을 수정했다 하더라도 명확히 다른 부분이 수정되었다면 git이 알아서 병합 과정을 처리해준다는 뜻이다.
    • 충돌이 일어났다면, git은 병합 과정을 진행하지 않고 충돌 상태를 그대로 둔다. 알아서 처리하는 대신 사용자가 충돌을 살펴보고 원하는 코드만 남길 때까지 기다린다.
  2. 사용자가 편집기에서 코드를 원하는 부분만 남긴다. 충돌이 일어난 부분은 git이 명확하게 표시를 해 준다.
    • 표시를 한다는 것은, 실제로 코드 파일을 git이 수정한다는 뜻이다. 물론 알아서 충돌을 해결한다는 뜻이 아니라, “여기 충돌 생겼어”하고 강력하게 표시를 한다는 뜻이다. 만약 코드 테스트를 한다면 틀림없이 이 부분에서 syntax error가 뜬다.
  3. 사용자가 직접 수정을 끝냈으면, commit을 한 다음 merge 혹은 push 작업을 완료한다.
    • 이때 따로 새로운 commit이 생기는 대신 원래 있어야 할 merge commit만 생성된다.

하나씩 살펴보자.


1. Conflict 발생시키기

일부러는 절대 해서는 안 되지만, 예시를 보여주어야 하기 때문에 고의로 conflict를 발생시켜 보겠다.

일단은 git_tutorial repo의 3rd-branch로 이동한 다음, git rebase master 명령을 실행한다.
2nd-branch부터 시작한 수정사항이 반영되어있지 않기 때문이다.

git checkout 3rd-branch
git rebase master

second.py의 마지막에 다음을 추가한다.

git_tutorial repo의 2nd-branch로 이동한 다음, first.py의 마지막에 다음을 추가한다.

git checkout 2nd-branch

print("Desired sentence in 2nd-branch")

commit을 한 뒤, master branch에서 2nd-branch의 내용을 merge한다.

git add first.py
git commit -m “Desired commit from 2nd-branch”
git checkout master
git merge 2nd-branch

그리고 3rd-branch로 이동하여 비슷하게 반복한다. 수정하는 파일은 당연히 first.py이다.

git checkout 3rd-branch

print("Unwanted sentence in 3nd-branch")

git add first.py
git commit -m “Unwanted commit from 2nd-branch”
git checkout master
git merge 3rd-branch

01_conflict

예상대로 conflict가 뜬다.


2. Conflict 해결하기

이제 편집기로 가서 first.py를 살펴보라. 메모장 코딩을 하는 것이 아니라면, 에러 표시줄이 여럿 보일 것이다.

02_file

파일을 살펴보면 확실히 어느 부분에서 conflict가 일어났는지 바로 확인이 가능하다.
참고로 필자와 빈 줄의 개수가 달라도 별 상관은 없다.

git이 수정해놓은 부분을 보면 다음과 갈은 구조로 되어 있다.

<<<<<<< HEAD
(현재 브랜치의 HEAD의 내용)
=======
(merge한 브랜치의 내용)
>>>>>>> (merge한 브랜치 내용)

여기서 각 브랜치의 내용 중 사용자가 원하는 부분만 남기고 모두 지우면 된다. 한쪽 브랜치의 내용만 남길 수도 있고, 양쪽 모두의 내용의 일부 혹은 전체를 남길 수도 있다.

수정을 마쳤으면 필요 없는 부분인 <<<<<<< HEAD, =======, >>>>>>> <branch> 등은 모두 제거하면 된다.

04_resolve

예상대로 남길 부분은 “Desired sentence”이므로 이 문장만 남기고 나머지 부분은 모두 삭제하면 된다.

IDE에 따라서는 다음과 같이 표시될 수도 있다. 이때는 조금 더 편하게 진행할 수 있다.
아래 예시는 Visual Studio Code의 경우이다.

03_vscode

수정하기 전 ‘변경 사항 비교’를 누르면 어떤 부분이 다른지를 양쪽에 나누어 보여준다.
내용을 확인한 뒤 ‘현재 변경 사항 수락’을 누르면 원하는 부분만 남겨지고 나머지는 알아서 삭제될 것이다. 물론 다른 부분을 남겨도 상관없다.


3. commit(merge) & push하기

그리고 수정한 파일을 git add 명령으로 추가한 뒤 commit한다. 정상적으로 처리되었는지 보기 위해 로그도 한번 출력해 보자.

git add first.py
git commit

05_commit

ESC 입력 후 :wq
git log –oneline

06_merge

이러면 conflict가 해결된 것이다. remote repo에 push하자.

git push

그리고 3rd-branch로 이동하여 rebase를 한다.

git checkout 3rd-branch
git rebase master


4. Conflict가 발생하지 않는 경우

조금 전 처음에 했던 것처럼 2nd-branch로 이동해 업데이트한다.

git checkout 2nd-branch
git rebase master

이번엔 first.py 파일 끝에 다음을 추가한다.

print("This is the 2nd sentence written in 2nd-branch.")

그리고 second.py의 내용은 다음 문장 빼고 모두 지운다.

print("This is the 1st sentence written in 2nd-branch.")

다시 비슷한 과정을 반복한다.

git add *.py
git commit -m “No-collision commit from 2nd-branch”
git checkout master
git merge 2nd-branch

git checkout 3rd-branch

다음으로는 3rd-branch로 이동하여, first.py 파일의 내용을 다음 문장 빼고는 모두 지운다.
지우기 전에, print("This is the 1st sentence written in 2nd-branch.") 문장은 없어야 정상이다. 있다면, checkout을 제대로 했는지 살펴보라.

print("Desired sentence in 2nd-branch")

git add first.py
git commit -m “No-collision commit from 3rd-branch”
git checkout master
git merge 3rd-branch

07_no_conflict

문제없이 잘 병합된 것을 확인할 수 있다. 다른 파일, 혹은 같은 파일을 수정했더라도 수정한 부분이 다르면 conflict가 일어나지 않는다.
위 예시의 경우 first.py를 2nd-branch에서는 파일의 끝 부분을, 3rd-branch에서는 파일의 시작 부분을 수정했기 때문에 문제가 일어나지 않았다.


5. 이유없이 conflict가 생기는 것 같은 경우

사실 이유가 없는 경우는 없지만, 간혹 두 branch 간 차이가 전혀 없어 보이고 파일 수정까지 끝마쳤는데도 conflict가 계속해서 발생하는 경우가 있다.

다른 원인일 수도 있지만, 정말로 아무 차이도 없어 보인다면 운영체제의 line-feed 문자의 차이로 인한 문제일 수 있다.
즉 Windows는 '\r\n'을, Linux나 Mac은 '\n'을 개행 문자로 사용하기 때문인데, 이 차이를 제대로 인식하지 못해 실패하는 경우가 있으니 참고하면 되겠다.

해결법은 다음과 갈다.

git config merge.renormalize true

그리고 merge를 시도하면 된다.


다음 글에서는 Git 전체 명령어 사용법을 다룬다.


Git 명령어

GitHub 사용법 - 00. Command List에서 원하는 명령어를 찾아 볼 수 있다.

Comment  Read more