728x90
반응형

얼마만의 포스팅인지... 가장 최근에 한 포스팅이 2021년 05월 17일이니, 반년 조금 넘는 기간 동안 포스팅을 안 했다.

나름의 변명이라면 올해 4월에 새로운 직장에 가고, 프로젝트를 하나 둘 맡아서 하다 보니 정신이 없기도 했고, 프로젝트를 어느 정도 마무리 짓고 여유가 나자 그놈의 디아블로 2가 나와버리는 바람에 시간이 슉 지나가버렸다.

너무도 감사하고, 죄송스럽게도 많은 분들께서 찾아와 주셔서, 미약한 실력이나마 도움이 될 수 있기를 바라며 다시 한번 포스팅을 해보고자 한다. 과연, 포스팅하고자 했던 것들을 전부 올리고, 새로운 영역을 파헤쳐 갈 수 있을까?

 

 

 

 

데이터 프레임, 데이터 조회하기

Python을 사용하는 데이터 분석가에게 가장 기초가 되는 Pandas를 다룬 것이 올해 초인 2021.02.24일이었으니, 다음에 뭘 다루려 했었는지 가물가물하다. 앞서 DataFrame의 Index와 Column명을 가지고 노는 법에 대해 알아봤으니, 이번 포스팅에서는 Index와 Column명을 이용해서 내가 원하는 데이터만 가지고 오는 법에 대해 알아보도록 하겠다.

데이터 프레임의 가장 큰 장점은 누구든지 이해하기 쉬운 형태로 데이터를 볼 수 있다는 것이지만, 데이터의 양이 많아질수록 한눈에 들어오지 않을 정도로 데이터가 거대해지기 때문에, 내게 필요한 데이터만 조회하는 법을 알아야 한다.

데이터 프레임의 조회 방식은 크게 index와 column 명으로 조회하는 방법, 데이터의 순서를 기반으로 조회하는 방법,  Boolean으로 조회하는 방법이 있는데, 이를 찬찬히 알아보도록 하자.

 

내가 원하는 데이터를 가지고 오기

  • 내가 원하는 데이터를 가지고 오는 방법은 크게 3 가지가 있다.
  1. 내가 원하는 행을 가지고 오기
  2. 내가 원하는 열을 가지고 오기
  3. 내가 원하는 행과 열을 가지고 오기
  • 여기서 내가 원하는 행을 가지고 오는 방법이 비교적 복잡하며, 원하는 행을 가지고 온 후 내가 필요한 열을 설정해주면, 문제는 쉽게 해결된다.
  • 그러므로, 행을 가지고 오는 방법을 위주로 다뤄보도록 하자.
  • Pandas의 DataFrame에서 내가 원하는 행을 가지고 오는 방법도 크게 3가지가 있다.
  1. Index를 이용해서 가지고 오기(loc)
  2. 위치를 이용해서 가지고 오기(슬라이싱, iloc)
  3. 조건을 이용해서 가지고 오기(Boolean)
  • 이번 포스트에서는 Index를 이용해 내가 원하는 데이터를 가지고 오는 방법에 대해 다뤄보도록 하자.

 

 

 

 

1. 예제 데이터 가지고 오기

※ 예제 데이터

해당 예제 데이터는 이름, 성별, 학년, 반, 국어, 수학, 영어, 사회, 과학 총 9개의 열(Column)과 80개의 행(Row)으로 구성된 csv파일이다. 당분간 이 데이터로 학습을 진행해보도록 하자.

시험점수.csv
0.00MB

  • 다운로드 받은 위 예제 데이터("시험점수.csv")파일을 내 워킹 디렉토리(Working Directory)로 이동시키거나, 파일의 경로를 이용해서 불러와보도록 하자.
>>> import pandas as pd
>>> import numpy as np

>>> FILE_PATH = "시험점수.csv"
>>> 시험점수 = pd.read_csv(FILE_PATH, encoding="euckr")
>>> 시험점수

  • R과 비교되는 파이썬의 가장 큰 장점은 한글 사용이 비교적 자유롭다는 것이다.
  • 파이썬은 utf-8 기반으로 만들어져 있기 때문에 데이터뿐만 아니라 변수명을 한글로 써도 큰 문제가 없다.
  • 혹시 모르는 에러가 발생할 위험이 있으므로, 그래도 영어를 사용하는 것을 추천한다!!
  • 한글이 들어 있는 파일이라면 파일의 경로만을 이용해서 데이터를 가져오는 경우, 한글이 깨지는 경우가 있는데, 이는 대부분 Encoding 문제로, pd.read_csv() 함수의 encoding 파라미터를 "euckr"로 지정하면 거의 해결된다.

 

 

 

 

2. Index를 이용해서 데이터를 가지고 오기.

  • 데이터 프레임에서 내가 원하는 행을 조회하는 가장 빠른 방법은 Index를 이용하는 것이다.
    • Index는 유일하게 존재하는 고유한 값일 수도 있으나, 중복된 값일 수도 있다.
    • Index를 이용한다면, 데이터 조회뿐만 아니라 데이터 병합(Merging)도 쉽게 할 수 있다.
  • Index로 조회하는 방법은 다음과 같다.
  • df.loc[index]: index에 해당하는 DataFrame의 행을 가지고 온다.

 

 

2.1. 하나의 index를 가지고 와보자.

  • index 60번을 가지고 와보자.
>>> 시험점수.loc[60]
이름    민준
성별    남자
학년     4
반      1
국어    90
수학    75
영어    80
사회    70
과학    60
Name: 60, dtype: object

>>> type(시험점수.loc[60])
pandas.core.series.Series
  • 하나의 index를 조회하자, Series Type으로 해당 index 정보가 조회되는 것을 볼 수 있다.
  • 이 시리즈에서 이름을 하나의 값으로 가지고 와보도록 하자.
>>> Index60_Sr = 시험점수.loc[60]
>>> Index60_Sr["이름"]
'민준'
  • 파이썬의 딕셔너리(Dictionary) 객체처럼 내가 원하는 변수명을 key로 주니, 내가 원하는 값이 반환되는 것을 볼 수 있다.

 

 

 

 

2.2. 여러 개의 index를 가지고 와보자.

  • 이번에는 여러 개의 index를 한 번에 가지고 와보도록 하자.
  • 15, 20, 30, 45번의 Row를 가지고 와보도록 하겠다.
  • 여러개의 index를 한번에 조회는 내가 원하는 index들이 들어있는 list를 만들어 loc에 넣으면 된다.
>>> 시험점수.loc[[15,20,30,45]]

  • 이전과 다르게 이번에는 index에 해당하는 데이터 프레임으로 결과가 조회되는 것을 볼 수 있다.
  • 위 방법을 응용하면 Index A부터 Index B까지 조회도 가능하다.
>>> index_range = range(15,20) 
>>> 시험점수.loc[index_range]

>>> 시험점수.loc[15:20]

  • 다만 Index의 범위를 이용하여 탐색하는 방법은 위 방법보다 다음에 다룰 Slicing이 더 많이 사용되므로, 이런 것도 있구나~ 하고 넘어가도록 하자.

※ 주의 사항

  • 일반적인 파이썬 슬라이싱 방식은 start:end 일 경우, start부터 end-1까지의 연속된 값을 반환하나, .loc[start:end]는 start 부터 end 까지의 연속된 index를 조회한다.
시험점수[15:20]

  • 일반적인 슬라이싱 방식은 위 방식으로 하며, DataFrame.loc[Index]는 Index에 속해 있는 모든 index의 행을 가지고 온다.

 

 

 

 

2.3. index와 column으로 조회해보자.

  • 해당 Index에서 특정 Column의 데이터만 보고 싶다면, index와 column을 동시에 넣어 조회하면 된다.
  • 앞서 소개한 df.loc[index]를 아래와 같이 쓰면 된다.
    • df.loc[index, column]
  • 16번 index의 국어 점수를 조회해보자.
>>> 시험점수.loc[16, "국어"]
75
  • 해당 방법을 통해 내가 필요한 값을 하나의 원소로 출력하였다.
  • 이번에는 index 16의 이름, 학년, 반, 국어 점수를 동시에 출력해보도록 하자.
>>> 시험점수.loc[16, ["이름", "학년", "반", "국어"]]
이름    정숙
학년     1
반      2
국어    75
Name: 16, dtype: object
  • 내가 필요한 index들을 list에 담아 조회하였듯, 조회하고자 하는 column들을 list에 넣어 조회하면 해결된다.
  • 이번엔 index를 16, 20, 25로 column을 이름, 학년, 반, 국어로 조회해보자.
>>> 시험점수.loc[[16, 20, 25], ["이름", "학년", "반", "국어"]]

 

 

 

 

2.4. 값을 Index에 넣어 조회해보자.

  • 앞서 다뤘던 방법들은 내가 원하는 Index를 알고 있다는 전제하에 유용하지만, 대부분 Index는 자동으로 설정되는 0~n 사이의 값이므로 이를 활용하는 것은 쉽지 않다.
  • 이럴 땐, 특정 열을 Index로 만들어 조회하는 것으로 이 문제를 해결할 수 있다.
  • "이름" column을 Index로 만들어보자.
  • df.set_index(column, drop=True, inplace=False): column을 df의 index로 설정한다.
>>> 시험점수.set_index("이름", inplace=True)
>>> 시험점수

  • inplace = True로 설정하면, df.set_index의 대상인 df에 바로 이를 적용할 수 있다.
  • default인 inplace를 False로 하면 df.set_index의 결과만 출력한다.
  • drop=False로 설정하면, 기존 index를 제거하지 않고 데이터 프레임의 열로 추가한다.
  • index를 "영철"로 조회해보자.
>>> 시험점수.loc["영철"]

  • DataFrame의 Index는 고유한 값이 아니어도 설정 가능하므로, 위와 같이 "이름"이 "영철"에 해당하는 Row를 모두 가지고 오는 것을 볼 수 있다.
  • Index를 초기 상태로 돌려보자.
>>> 시험점수.reset_index(drop=False, inplace=True)
>>> 시험점수

  • 이번에는 학년이 1학년인 사람들만 조회해보도록 하자.
>>> 시험점수.set_index("학년", inplace=True)
>>> 시험점수.loc[1]

 

 

 

 

2.5. 다중 값을 Index로 조회해보자.

  • 지금까지 하나의 열만 Index로 넣어 조회를 해보았다.
  • 그렇다면, 여러 개의 열을 Index에 넣어 내가 원하는 행만 조회할 수는 없을까?
  • 이때는 크게 2가지 방법이 있다.
  1. Multi Index를 만들어 조회하기
  2. 조회를 위한 열을 만들기
  • 먼저 Multi index를 만드는 법부터 알아보도록 하자.
  • Index를 다시 초기화하고 학년과 반으로 Multi index를 만들어보도록 하겠다.
>>> 시험점수.reset_index(drop=False, inplace=True)
>>> 시험점수.set_index(["학년", "반"], inplace=True)
>>> 시험점수

  • 2학년 1반 사람들을 조회해보도록 하자.
  • Multi Index는 Python의 Tuple로 생성되므로, Tuple로 조회하면 된다.
>>> 시험점수.loc[(2,1)]

  • 3개 이상의 열을 Multi Index로 만들어 조회도 가능하다.
  • 이번에는 학년, 반, 이름으로 Multi Index를 만들어보자.
>>> 시험점수.reset_index(drop=False, inplace=True)
>>> 시험점수.set_index(["학년", "반", "이름"], inplace=True)
>>> 시험점수

  • 이번에는 2학년 1반의 영철을 조회해보도록 하자.
>>> 시험점수.loc[(2,1,"영철")]
성별     남자
국어    100
수학     80
영어     75
사회     80
과학     45
Name: (2, 1, 영철), dtype: object
  • 위와 같은 방법을 통해 내가 원하는 Column을 Index로 만들어 조회해보았다.
  • 다만, 해당 방법의 한계점은 특정한 하나의 값만 조회가 가능하므로, 수학 점수와 같은 연속형 데이터의 범위에 대해서는 조회가 불가능하다는 단점이 있다.
  • 물론, 이용해 우회하여 해결할 수 있기는 하다.

 

 

 

 

2.6. 새로운 열을 만들어 조회하기

  • 지금까지는 기존에 존재하는 열을 그대로 Index로 만들어 조회를 하였다.
  • 이번에는 내가 필요로 하는 값에 대한 변수를 만들고, 이 변수를 Index로 만들어 조회를 해보도록 하겠다.
  • 수학 점수가 70점 이상인 사람들을 표시하는 새로운 변수를 만들어보자.
    • 조건을 이용한 새로운 변수 만들기는 추후 자세히 다룰 테니 이번엔 단순 참고용으로 보도록 하자.
>>> 시험점수["수학_mask"] = np.where(시험점수["수학"] >=70, "수학_70점_이상", "수학_70점_미만")
>>> 시험점수

  • 70점 이상은 "70점_이상", 70점 미만은 "70점_미만"인 수학_mask"라는 변수를 생성하였다.
  • 새로 만든 "수학_mask"변수를 이용해서 70점 이상인 사람들만 출력해보도록 하자.
>>> 시험점수.set_index("수학_mask", inplace=True)
>>> 시험점수.loc["수학_70점_이상"]

  • 이미지가 너무 커서 일부만 표시해보았다. 길이가 48인 결과가 나왔다면, 제대로 나온 것이다.
>>> len(시험점수.loc["수학_70점_이상"])
48
  • 이번엔 영어 점수가 70점 이상인 사람을 추가해보자.
>>> 시험점수.reset_index(drop=False, inplace=True)
>>> 시험점수["영어_mask"] = np.where(시험점수["영어"] >=70, "영어_70점_이상", "영어_70점_미만")
>>> 시험점수

  • 이번엔 수학 점수가 70점 이상이면서, 영어 점수도 70점 이상인 사람을 출력해보자.
  • Multi Indexing을 사용할 수도 있으나, 이번에는 수학_mask와 영어_mask를 하나로 합쳐서 Index를 만들어보겠다.
>>> 시험점수["key"] = 시험점수["수학_mask"] + "&"+ 시험점수["영어_mask"]
>>> 시험점수.set_index("key", inplace=True)
>>> 시험점수.loc["수학_70점_이상&영어_70점_이상"]

  • 이미지가 너무 커서 일부만 표현하였으며, 길이가 35가 나오면 정상이다.
>>> len(시험점수.loc["수학_70점_이상&영어_70점_이상"])
35
  • 위와 같은 새로운 변수를 만들어 Index로 바꾸는 방법은 이해를 돕기 위해 변수를 지저분하게 만들었지만, 이보다 깔끔하게 할 수 있는 방법을 다음에 포스팅해보도록 하겠다.

 

 

 

지금까지 Index를 이용한 데이터 프레임 행 조회 방법에 대해 알아보았다. 다음 포스트에서는 위치를 이용한 행 조회에 대해 알아보도록 하겠다.

728x90
반응형
728x90
반응형

리눅스 서버에 CUDA 세팅하기

 이전 포스트에서 CUDA 세팅에 필요한 CUDA와 cuDNN을 다운로드하였다. 이번 포스트에서는 CUDA를 설치해보도록 하겠다.

 

 

 

 

0. 다른 버전의 CUDA가 설치되어 있는지 확인하기

  • 현재 CUDA를 세팅하는 환경은 wsl2를 이용하여 만들어진 가상 환경이기 때문에 엔비디아 드라이버가 설치되어 CUDA가 꼬일 문제가 없지만, 윈도우 PC나 사용하려는 텐서플로우 버전과 기존 서버에 세팅된 CUDA 버전이 다른 경우, 기존 NVIDIA 파일과 CUDA를 제거해줘야 한다.
  • 현재 환경에 엔비디아 드라이버가 설치되어 있다면, 다음과 같은 방법으로 그래픽 드라이버 정보를 얻을 수 있다.
nvidia-smi
nvcc -V
  • CUDA가 설치되어 있다면, nvcc -V를 확인하면 된다.
  • 경우에 따라 nvcc -V에서 출력되는 쿠다와 nvidia-smi에서 출력되는 CUDA Version이 다른 경우가 있는데, 이는 CUDA가 꼬여 있는 것일 수 있기 때문에 이후에 Tensorflow 사용 시, 충돌이 일어날 수 있다. 때문에 CUDA 파일과 nvidia 관련 파일을 완전히 제거하여, CUDA를 맞춰주는 것이 좋다.
  • nvidia-smi 입력 시 출력되는 화면은 다음과 같다.

  • nvcc -V 입력 시 출력되는 화면은 다음과 같다.

  • 엔비디아 드라이버와 쿠다를 제거하는 방법은 다음과 같다.
# nvidia driver 삭제
sudo apt-get remove --purge '^nvidia-.*'

# CUDA 삭제
sudo apt-get --purge remove 'cuda*'
sudo apt-get autoremove --purge 'cuda*'

# CUDA 남은 파일 삭제
sudo rm -rf /usr/local/cuda
sudo rm -rf /usr/local/cuda-10.1
  • 엔비디아 드라이버와 쿠다 제거 후, 성공적으로 제거되었는지 확인하기 위해, nvidia-smi, nvcc -V와 같은 코드를 입력하여, 제대로 제거되었는지 확인하자.
  • 그러나, CUDA가 여러 개 깔려 있거나, 여러 개의 GPU 서버의 GPU가 연결 되어 있는 경우, 위 방법대로 제거하더라도, nvidia-smi나 nvcc -V가 다시 출력될 수 있다.

 

 

 

 

1. CUDA 설치하기

  • 이전 포스트에서 다운로드하였던 CUDA 파일을 실행하기 전에 권한을 부여하도록 하자.
  • 이전 포스트까지 Download 디렉터리에 받았던 파일들은 다음과 같다.

  • 위 사진에서 cuda_11.0.2_450.51.05_linux.run에 chmod를 사용하여, 777 권한을 부여하자.
chmod 777 cuda_11.0.2_450.51.05_linux.run
ll

  • 이제 cuda_11.0.2_450.51.05_linux.run을 실행하여 CUDA를 설치하도록 하자.
./cuda_11.0.2_450.51.05_linux.run

 

gcc 에러 발생

  • CUDA 설치 시, 다음과 같은 에러가 뜰 수도 있다.
  • Failed to verify gcc version. See log at /tmp/cuda-installer.log for details.
  • 관련 로그를 확인하기 위해 위 에러가 말해준 위치로 이동해보자.

  • 위 내용을 보니, gcc 가 없어서 발생한 문제임을 알 수 있다.
  • gcc를 설치하여, 위 문제를 해결해줘야 한다.
  • 위 문제가 뜬 경우 apt를 비롯한 가장 기본적인 세팅도 안되어 있는 것이므로, 가능한 위와 같은 상황에선 인터넷을 열어달라 하여, 위와 같은 기본적인 세팅은 해놓는 것을 추천한다.
  • 위 문제의 해결 방안은 다음과 같다.
sudo apt update
sudo apt install build-essential
sudo apt-get install manpages-dev
  • 위 코드는 sudo 권한이 반드시 필요하기 때문에 지금까지와 달리 꼭 sudo를 입력해주도록 하자.
  • 기본적으로 gcc는 7.5.0으로 설치되므로, 버전도 업그레이드하도록 하자.
sudo apt -y install gcc-8 g++-8
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 8
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 8

 

CUDA 설치 재진행

  • 다시 CUDA 설치를 진행하도록 하겠다.
./cuda_11.0.2_450.51.05_linux.run

  • accept를 입력하여 진행하자

  • 위/아래 방향키로 이동, 왼쪽/오른쪽 방향키로 +가 있는 영역 세부 표시, 엔터 입력 시 X 체크 또는 해제를 실시할 수 있다.
  • 지금 같이 CUDA, cuDNN 관련 사항이 완전히 없는 경우, 모두 체크하여 설치를 진행하도록 하자.
  • Install을 눌러, 계속 진행해보자.

 

컴파일러 에러 발생

  • 이번에는 컴파일러 버전이 맞지 않아, 컴파일러 에러가 발생하였다.
sudo apt-get install build-essential

 

경로 문제

  • 위 명령어를 입력하여, 해당 오류 관련 패키지를 설치해주자.
  • 이번에는 다음과 같은 에러가 등장하였다.

  • 특정 디렉터리가 존재하지 않아 발생하는 에러로 보인다.
  • sudo 권한을 주어 설치하도록 하자.
sudo ./cuda_11.0.2_450.51.05_linux.run

  • 성공적으로 CUDA를 설치하였다.
  • Toolkit과 Cuda Samples가 설치된 위치를 볼 수 있으며, 이제 cuda를 사용하기 위해 PATH 설정을 하도록 하자.

 

CUDA PATH 설정

  • CUDA를 사용하기 위해선 전역 변수를 수정해줘야 한다.
  • 만약 우분투 사용자마다 다른 CUDA를 사용하고자 하는 경우, 사용자의 home 디렉터리의 .bachrc를 수정하면 된다.
cd
sudo vim /etc/bash.bashrc
  • cd를 입력하여 최초 경로로 돌아가자.
  • 위 명령어를 입력하여 출력된 화면의 맨 마지막에 위 CUDA 설치 후, 출력된 CUDA PATH를 다음과 같이 설정해주도록 하자.
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

  • 위 입력된 사항을 esc > :wq 를 입력하여 저장하도록 하자.
  • PATH 지정 후, 위 사항을 터미널에 바로 적용해주도록 하자.
source /etc/bash.bashrc
  • nvcc -V를 입력하여 CUDA가 성공적으로 설치된 것을 확인하도록 하자.
nvcc -V

  • 성공적으로 CUDA가 설정된 것을 볼 수 있다.

 

 

 

 

2. cuDNN 설치

  • cuDNN 설치는 cuDNN 폴더의 압축해제 후, 그 안에 있는 파일들을 이전에 설치하였던 CUDA 파일의 안에 복사해서 옮겨줘야 한다.
  • 그러므로, 이전에 cuda를 설치하였던 경로를 먼저 보도록 하자.
whereis cuda

  • Download 디렉터리로 돌아가 이전에 다운로드하였던 cuDNN 파일의 압축을 풀도록 하자.
cd Download
ll
tar -xvf cudnn-11.0-linux-x64-v8.0.5.39.tgz

  • 압축 해제 후, 생성된 파일을 확인해보자
ll
cd cuda
ll

  • cuda 디렉터리 안에 있는 include, lib64 폴더의 하위 파일들을 이전에 설치하였던 cuda의 include와 lib64 폴더로 복사하면 된다.
  • 이전에 확인했던 cuda의 경로로 include의 하위 파일들 lib64 하위 파일들을 각각 해당하는 디렉터리로 이동시키자
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*
  • cuDNN 설치가 제대로 되었는지 확인해보자
cat /usr/local/cuda-11.0/include/cudnn_version.h | grep CUDNN_MAJOR -A 2

  • 위 내용을 보면 cudnn 8.0.5가 성공적으로 설치된 것을 볼 수 있다.
728x90
반응형
728x90
반응형

리눅스 서버에 CUDA 세팅하기

 이전 포스팅에서 우분투 서버에 주피터 노트북을 세팅하는 방법에 대해 알아보았다. 이번 포스트에서는 우분투 서버에 CUDA를 세팅하고, Tensorflow를 이용해 CUDA 세팅이 제대로 되었는지 확인하는 방법에 대해 알아보도록 하겠다.

 

 

 

 

1. Tensorflow가 GPU를 정상적으로 인식하고 있는지 확인

  • Tensorflow를 설치하였더라도, GPU를 사용하기 위해서는 사용하고자 하는 Tensorflow 버전에 맞는 CUDA와 Cudnn을 설치해야 한다.
  • Tensorflow가 현재 인지하고 있는 사용 가능한 CPU, GPU를 확인하는 방법은 다음과 같다.
from tensorflow.python.client import device_lib
device_lib.list_local_devices()

  • 위 사진을 보면, JSON 형태로 CPU와 GPU가 출력된다. 만약 CPU와 GPU가 1개 이상인 경우 "/device:CPU:0", "/device:CPU:1", "/device:CPU:2",..., "/device:GPU:0", "/device:GPU:1", "/device:GPU:2", ...와 같은 식으로 N개의 해당하는 device와 기종 설명 등 간략한 정보가 출력되게 된다.
  • 해당 번호를 기반으로 Tensorflow 사용 시, 원하는 장비를 선택할 수 있다.

 

 

 

 

2. 필요한 CUDA와 cuDNN 버전 확인하기

  • CUDA와 cuDNN을 설치하기 전에 자신이 사용하려고 하는 Tensorflow 버전을 구체적으로 알아야한다.
  • 프로그래밍에 익숙하지 않은 사람이라면, 최신 라이브러리일수록 좋은 것이라고 단순하게 생각할 수 있는데, 최신 버전은 알려지지 않은 오류가 존재할 가능성이 높은 안정되지 않은 상태일 수 있기 때문에, 이러한 이슈를 알아보고 설치하는 것을 추천한다.
  • 이번 포스트에서는 tensorflow-2.4.0을 사용할 것이므로, 그에 해당하는 CUDA와 cuDNN을 설치하도록 하겠다.
  • Tensorflow 버전별 CUDA와 cuDNN 정보는 Tensorflow 공식 홈페이지를 보면 알 수 있다.
  • https://www.tensorflow.org/install/source
 

소스에서 빌드  |  TensorFlow

소스에서 TensorFlow pip 패키지를 빌드하고 Ubuntu Linux 및 macOS에 설치합니다. 명령어는 다른 시스템에도 적용될 수 있지만, Ubuntu 및 macOS용으로만 테스트되었으며 지원됩니다. 참고: 잘 테스트되고

www.tensorflow.org

  • 해당 사이트를 보면, tensorflow-2.4.0에 해당하는 GPU는 cuDNN 8.0, CUDA 11.0임을 알 수 있다.

 

 

 

 

3. CUDA 다운로드하기

  • CUDA와 cuDNN 다운 및 설치 방법은 이전 포스트 "텐서플로우(Tensorflow)와 tensorflow-gpu 설치방법"과 매우 유사하며, 이번에는 리눅스 버전으로 다운을 받아보도록 하자.
  • 자신이 원하는 버전에 해당하는 CUDA를 다운로드하기 위해선 아래 홈페이지로 이동하면 된다.
  • https://developer.nvidia.com/cuda-toolkit-archive
 

CUDA Toolkit Archive

Previous releases of the CUDA Toolkit, GPU Computing SDK, documentation and developer drivers can be found using the links below. Please select the release you want from the list below, and be sure to check www.nvidia.com/drivers for more recent production

developer.nvidia.com

  • 해당 웹사이트에서 CUDA Toolkit 11.0을 클릭하도록 하자.

  • 이번에 Tensorflow를 세팅하고자 하는 서버는 오프라인 우분투 18.04이므로, 다음과 같은 버튼을 클릭하여 설치 파일을 받도록 하자.

  • 위와 같이 누르는 경우, 우리에게 익숙한 파일 다운로드 버튼이 아닌 리눅스 환경에서 파일을 다운로드할 수 있는 명령어가 출력된다.

  • 위 명령어에서 첫 줄인 "wget ~"은 CUDA 설치 파일을 다운로드하는 것이며, 두 번째 줄은 해당 파일을 실행하는 것이다.
  • 인터넷이 되는 우분투 환경으로 이동하여, 이전에 만들어놨던 Download 디렉터리로 이동해서 해당 파일을 다운로드하도록 하자.
wget http://developer.download.nvidia.com/compute/cuda/11.0.2/local_installers/cuda_11.0.2_450.51.05_linux.run

  • 다운 완료 후, 파일이 Download 디렉터리에 설치 파일이 존재하는 것을 확인하도록 하자.
ll

  • 성공적으로 CUDA 11.0 설치 파일이 다운된 것을 볼 수 있다.

 

 

 

 

4. cuDNN 다운로드하기

 

cuDNN Archive

NVIDIA cuDNN is a GPU-accelerated library of primitives for deep neural networks.

developer.nvidia.com

  • cuDNN을 보면, CUDA 버전에 맞는 것이 무엇인지 볼 수 있다.
  • cuDNN은 CUDA Deep Neural Network의 약자로, 딥러닝 관련 연산을 빠르게 해주는 라이브러리들이 모여있는 패치 파일이라고 생각하면 된다.
  • cuDNN 파일은 windows와 마찬가지로 CUDA 설치 후, 압축을 푼 cuDNN 파일을 설치된 CUDA 파일에 덮어 씌워주면 된다.
  • 설치하고자 하는 운영체제에 맞는 cuDNN을 다운로드하도록 하자. 우분투는 단순하게 Linux로 다운로드하여도 상관없다.
  • cuDNN은 CUDA와 달리 NVIDIA 홈페이지 로그인이 필요하므로, 해당 작업 진행 후, cuDNN을 받도록 하자.

  • 로그인 후, 해당 버튼을 누르면 "cudnn-11.0-linux-x64-v8.0.5.39.tar" 또는 뒤에 ".solitairetheme8" 라고 붙은 파일이 다운로드하여진다. 이 경우 윈도우 다운로드 파일에 받아지기 때문에 리눅스로 이동시키는 과정이 필요하다.
  • CUDA를 설치하고자 하는 리눅스 서버와 로컬 PC가 FTP가 뚫려 있는 경우 파일질라(FILEZILLA)와 같은 무료 FTP 클라이언트를 이용하는 것이 가장 직관적인 방법이며, USB를 이용하여 파일을 이동시킬 수도 있다.
  • 해당 포스트는 wsl2를 이용하여 해당 과정을 진행하므로, c드라이브에 "Linux_mv"라는 이름의 임의의 디렉터리를 생성하고, cuDNN 파일을 이동시켰다.
cd /mnt/c/Linux_mv
mv cudnn-11.0-linux-x64-v8.0.5.39.tgz /home/gooopy123/Download
cd
cd Download
ll

 

 

 

 

 이제 CUDA 설치를 위한 기본적인 준비가 되었다. 다음 포스트에서는 CUDA 설치를 진행해보도록 하겠다.

728x90
반응형
728x90
반응형

 

리눅스 서버에 가상 환경 활성화와 주피터 노트북 세팅

 지금까지 파이썬 기반 오프라인 분석 서버 구축을 위한 밑 작업을 해보았다. 이번 포스트에서는 오프라인 우분투 환경에 에 이전에 만들었던 가상 환경을 활성화시키고, 주피터 노트북을 세팅해보도록 하겠다.

 

 

 

 

0. 오프라인 우분투 환경 준비

  • 해당 포스트는 분석 환경 구축의 대상이 되는 서버가 오프라인, OS가 우분투이며, 우분투는 이미 설치되어 있다는 전제하에 진행하도록 하겠다.
  • 이를 실습하고 싶으나, 오프라인 우분투 서버가 존재하지 않다면, 가상 머신을 이용해 이와 유사한 환경을 만들어보겠다.
  • 가상 머신은 wsl2를 사용하며, 우분투 버전은 18.04이다.
  • wsl2 사용 방법은 이전 포스트인 "Python 리눅스 서버에 분석 환경 구축1 - 가상머신과 아나콘다 설치"를 참고하도록 하겠다.
  • 지금까지의 포스팅을 따라온 사람이라면, 기존에 설치하였던 우분투를 제거하고, 재설치하여 아나콘다가 깔려있지 않은 환경을 만들어주자.
  • 아래와 같이 아무것도 설치되지 않은 상태에서 진행하도록 하겠다.

 

 

 

 

 

1. 아나콘다 설치 및 가상 환경 활성화 준비

  • 이전 포스트에서 외부로 옮겨놓았던, 리눅스 아나콘다 설치 파일과 가상 환경 압축 파일을 리눅스 서버로 옮기자.
  • 옮기는 방법은 USB를 이용하거나, 파일질라(FileZilla) 등을 이용해서 이동시키도록 하자.
  • 이동시키는 가장 쉬운 방법은, Local PC와 리눅스 서버가 sftp 포트(22)가 뚫려 있다는 상태에서, 파일질라를 사용하는 것이다.
  • 해당 포스트는 위 과정이 해결되어 있다는 전제하에 진행하도록 하겠다.
  • 추후 필요에 따라 위 과정을 다뤄보도록 하겠다.
# Download 디렉토리 생성
mkdir Download
  • Donwload 디렉토리를 만들고, 이전에 준비한 파일들을 모두 이동시키자.
  • 이번 포스트는 wsl2 환경에서 진행하므로, 상황이 약간씩 다르지만, 전체적인 흐름은 동일하다.
# wsl2 환경에서 가상 환경 압축 파일과 아나콘다 설치 파일 이동
cd /mnt/c/Anal_Env_Set
mv ./Anaconda3-2020.11-Linux-x86_64.sh /home/gooopy123/Download
mv ./New_Env.tar /home/gooopy123/Download
# Download 디렉토리에 파일이 정상적으로 이동되었는지 확인
cd
cd Download
ll

 

1.1. 아나콘다 설치

 

1.2. 가상 환경 이동 및 압축 풀기

  • 아나콘다가 설치 완료되었다는 전제하에, 이전 포스트에서 만들었던 가상 환경 압축 파일을 아나콘다 디렉토리로 이동시켜보자.
# 가상 환경 압축파일 이동
mv New_Env.tar /home/gooopy123/anaconda3/envs
cd /home/gooopy123/anaconda3/envs
ll

  • 이동된 New_Env.tar 파일의 압축을 풀어보도록 하자.
# 가상 환경 압축 파일 압축 해제
tar -xvf New_Env.tar
  • tar -xvf 압축파일.tar: "압축파일.tar"의 압축을 푼다.
  • 가상 환경 압축을 해제 후, 해당 압축 파일을 인식하는지 확인해보자.
# 가상 환경 목록 확인
conda env list

  • 위와 같이 성공적으로 이전에 만들었던 가상 환경이 생성된 것을 확인할 수 있다.
  • 가상 환경의 압축파일은 용량만 차지하므로, 이제 삭제하도록 하자.
# 가상 환경 압축 파일 제거
rm New_Env.tar

 

 

 

 

 

2. 주피터 노트북 설정

  • 가상 환경을 활성화하기 전에 반드시 해줘야 하는 것이 Base 환경에서 주피터 노트북을 설치하고, 설정하는 것이다.
  • 주피터 노트북 설치는 반드시 Base 환경에서 해주어야 한다.
  • Base 환경에서 주피터 노트북 설치는 pip install 사용 시, 오프라인에서도 진행 가능하다.
# 주피터 노트북 설치
pip install jupyter notebook

# 주피터 노트북 설정 파일 생성
jupyter-notebook --generate-config
  • 주피터 노트북 설치 후, 주피터 노트북 설정 파일을 생성하도록 하자.

  • 위 과정 진행 시, 위와 같이 .jupyter/ 디렉토리가 생성된 것을 확인할 수 있다.

 

2.1. 주피터 노트북 비밀번호 생성

  • 주피터 노트북 설정을 손대기 전에 주피터 노트북에서 사용할, 암호화된 비밀번호를 생성하기 위해 ipython을 실행하자.
# ipython 실행
ipython

  • 주피터 노트북 설치 시, ipython이 같이 설치되는데, ipython은 주피터 노트북의 셀과 동일한 기능을 수행한다.
# 암호화된 비밀 번호 생성
from notebook.auth import security
security.passwd()

  • 위와 같이 비밀 번호를 생성하면, 암호화된 비밀번호를 출력하는데, 이를 반드시 어딘가에 복사해놓도록 하자.
# ipython 빠져나오기
exit()
  • exit()를 입력하여 ipython에서 터미널로 빠져나오자.

 

2.2. 주피터 노트북 워킹 디렉토리 생성

  • 주피터 노트북을 설정하기 앞서, 주피터 노트북의 워킹 디렉토리를 미리 만들어놓자.
mkdir Analysis
cd Analysis

# 현 주소 확인
pwd

  • 주피터 노트북의 워킹 디렉토리로 사용할 디렉토리의 주소도 복사해놓도록 하자.

 

2.3. 주피터 노트북 설정

  • 아까 생성하였던, 주피터 노트북 설정 파일이 있는 경로로 이동하고, 설정 파일을 실행해보자.
# 경로 이동
cd ~/.jupyter

# 주피터 노트북 설정 파일 실행
vi jupyter_notebook_config.py

  • 위 코드 실행 시, 위와 같은 파란색 글로 가득 찬 화면이 뜨게 된다.
  • 여기서 특정 명령어를 입력하면, 주피터 노트북에 해당 기능이 반영된다.
  • 설정할 수 있는 유용한 몇 가지 기능을 소개하면 다음과 같다.
# 필수
c = get_config()
c.JupyterApp.config_file_name = 'jupyter_notebook_config.py'

# 접속 허용 ip
c.NotebookApp.allow_origin = '*' # 접속 허용 ip로 *는 전체 허용을 의미한다.

# 서버 ip
c.NotebookApp.ip = 'xxx.xx.xxx.xxx'

# 주피터 노트북 실행 시, 브라우저로 열지(True), url을 출력할지 정한다(False).
c.NotebookApp.open_browser = False

# 주피터 노트북 비밀번호
c.NotebookApp.password = u'아까 복사해놓은 암호화된 비밀번호를 넣어주자'

# 주피터 노트북 포트 설정
c.NotebookApp.port = 8888

# 주피터 노트북 홈 디렉토리 설정
c.NotebookApp.notebook_dir = '아까 복사해놓은 홈 디렉토리 주소를 넣어주자'
  • 위 코드 중 필요한 부분을 선택하여, 넣어주도록 하자.
  • 위 코드를 보기 쉽도록 위 파란 화면 최상단에 넣어주도록 하자.
  • 위 상태에서 i를 누르면 INSERT 모드로 바뀌며, 수정 가능해진다.

  • 필요한 코드를 전부 입력한 후, esc를 누르고, shift + ; 키를 누르면, 위 화면에서 빠져나올 수 있는 키를 입력할 수 있게 된다.
  • q를 입력 후 enter를 치면 현 상태를 저장하지 않고 그냥 빠져나오며, wq를 입력 후 enter를 치면 현 상태를 저장하고 빠져나온다.

 

2.4. 주피터 노트북 실행

  • 위 과정까지 마친 후, 터미널에 jupyter notebook을 입력하면, jupyter notebook으로 이동할 수 있는 url이 나온다.
  • 위 방법을 통해, 특정 url과 port를 설정하면, 해당 주소를 즐겨찾기 설정하여, 쉽게 이동할 수 있다.
# 주피터 노트북 실행
jupyter notebook

  • 해당 포스트는 서버가 아닌, Local PC에 분석 환경을 구축하였기 때문에, IP주소를 따로 입력하지 않아도 괜찮다.
    (위 화면이 뜨지 않는다면, 무언가 오타를 내지 않았는지 꼭 확인해보자)
  • 출력된 위 http:localhost:8892/를 복사하여, 크롬에 붙여 넣어 보자.
  • 그러면, 우리에게 익숙한 주피터 노트북 화면이 출력된다.

  • 아까 만들었던 비밀 번호를 입력하고 이동해보자

  • 이제 우리에게 익숙한 주피터 노트북을 우분투 환경에서 사용할 수 있다.

 

 

 

 

 

3. 가상 환경 주피터 노트북에 연결하기

  • 아까 실행했던 주피터 노트북을 종료해보자
  • 주피터 노트북 종료는 브라우저의 우측 상단에서 Quit를 클릭하거나, 터미널에서 ctrl+z를 입력하여 중지시키면 된다.
  • ctrl+z는 리눅스에서 특정 기능이 수행 중일 때, 사용하면 그 기능을 중지시킬 수 있다.
  • 윈도우에서는 가상 환경 생성 시, 해당하는 주피터 노트북 실행 파일과 커널이 따로 생성되므로, 실행하기 쉬웠으나, 우분투에서는 가상 환경 커널을 추가하여 가상 환경을 사용한다.
  • 먼저 사용할 가상 머신을 활성화 하자.
# 가상 환경 활성화
conda activate New_Env

# 가상 환경 커널 추가
python -m ipykernel install --user --name=New_Env --display-name="New_E_Kernel"

# base로 환경 변경
conda activate base

# 주피터 노트북 실행
jupyter notebook
  • --user --name 뒤에는 연결하고자 하는 가상 환경의 이름을 넣으면 된다.
  • --display-name 뒤에는 주피터 노트북에서 출력하고 싶은 커널 이름을 넣어주면 된다.

  • 다시 주피터 노트북을 실행하고, 방금 만들었던 New_E_Kernel 커널로 파이썬 쉘을 만들어보자.

  • 주피터 노트북을 실행하여 New를 클릭해보면 New_E_Kernel라는 추가한 커널이 생긴 것을 볼 수 있다.
  • 파이썬 파일을 만들어보자.

  • Kernel의 Change kernel에 New_E_Kernel이 추가된 것도 볼 수 있다.
  • 이를 이용해서 커널도 얼마든지 바꿀 수 있다.
  • 적용되어 있는 커널은 우측 상단에서 확인할 수 있다.

  • 커널 변경 시, 아나콘다에서 기본적으로 제공하지 않는 패키지인 tensorflow가 성공적으로 가동되는 것을 볼 수 있다.

 

3.1. 가상 환경 커널 제거

  • 추가로 생성된 가상 환경 커널을 삭제하고 싶다면 다음과 같이 하면 된다.
# 적용되어 있는 가상환경 커널 목록을 확인한다.
jupyter kernelspec list

# 적용되어 있는 가상환경 커널의 적용을 해제한다.
jupyter kernelspec uninstall 가상환경이름

# 가상환경 삭제
conda env remove -n 가상환경이름
  • 가상 환경 커널 추가 시, 표시되는 커널의 이름과 가상 환경의 이름이 일치하지 않을 수 있으므로, kernelspec list를 확인하는 것이 좋다
  • 커널을 제거하지 않더라도 가상 환경은 삭제 가능하다.

 

 

 

 지금까지 우분투 환경에서 주피터 노트북을 사용하는 방법에 대해 알아보았다. 지금 상태에서도 데이터 분석을 진행할 수는 있으나, 현재 GPU 설정을 하지는 않은 상태기 때문에, CPU만 사용해서 분석을 진행할 수 있다.

 다음 포스트에서는 우분투 환경에 CUDA를 세팅하는 방법에 대해 알아보도록 하자.

728x90
반응형
728x90
반응형

리눅스 서버에 가상 환경 만들기

 이전 포스트에서 가상 머신을 통해 리눅스 서버를 만들고, 아나콘다를 설치해보았다. 이번 포스트에서는 아나콘다를 이용해 가상 환경을 만들고, 이를 압축하여, 외부로 내보내는 과정을 학습해보도록 하겠다.

 

 

 

 

1. 아나콘다 가상환경

  • 지난 포스트까지 진행했다면, 아래와 같은 경로에 위치해 있을 것이다.
    (지난 포스트와 PC의 이름이 다른 이유는, 다른 PC로 동일한 환경을 구축해서 진행한 것이기 때문으로, 신경 쓰지 않아도 된다)

 

1.1. 가상 환경을 생성해보자.

conda create -n New_Env python=3.8

  • conda create -n 가상 환경_이름 python=원하는_파이썬_버전: "원하는_파이썬_버전"으로 새로운 가상 환경을 만든다. 생성되는 가상환경 이름은 "가상환경_이름"이다.
  • 가상 환경 생성은 온라인 환경에서만 가능하므로, 반드시 인터넷이 가능한 PC에서 실시하도록 하자.

 

1.2. 존재하는 가상 환경 리스트를 확인해보고, 방금 생성한 가상환경을 활성화시켜보자.

conda env list
conda activate New_Env

  • conda env list: 아나콘다에 존재하는 가상환경 리스트를 출력한다.
  • conda activate 가상환경이름: "가상환경이름"을 활성화한다.

 

1.3. 필요한 패키지를 설치한다.

  • "pip install 패키지==버전"이나 "conda install 패키지==버전"을 입력하여, 필요한 패키지를 설치하자.
    (가상 환경에 설치하므로, 둘 중 아무거나 사용해도 된다.)
  • tensorflow 2.4.0 버전, tensorflow-gpu 2.4.0 버전, pytorch 1.8.1 버전, simplejson을 설치해보자.
pip install tensorflow==2.4.0
pip install tensorflow-gpu==2.4.0
pip install torch==1.8.1
pip install simplejson
pip install jupyter notebook
  • 텐서플로우나 파이토치는 cuda, cudnn 버전이 맞아야 하기 때문에 자신이 사용할 텐서플로우 버전을 확실히 해야 한다.
  • 밖으로 내보낼 가상환경에는 반드시 jupyter notebook을 설치해주자. 주피터 노트북을 다운받으면, ipython, ipykernel과 같은 주피터 노트북 사용에 관련된 주요 라이브러리가 자동으로 다운 받아진다.

 

1.4. 설치한 패키지가 정상적으로 설치되었는지, 패키지 리스트를 확인해보자.

conda list

  • 위에서 출력된 결과를 보면, 방금 설치하였던 패키지들이 모두 정상적으로 설치된 것을 볼 수 있다.
  • 혹시 필요한 패키지가 더 있다면, 위 과정을 추가로 진행하기 바란다.

 

 

 

 

 

2. 가상 환경 밖으로 내보내기

  • "conda env export > 가상환경이름.yaml"을 사용하면, 가상 환경의 형태를 내보낼 수 있으나, 이는 구조만 내보내는 것이기 때문에, 인터넷이 안 되는 서버에서는 사용할 수가 없다.
  • 그러나, 생성한 가상 환경을 그대로 압축하여, 외부로 내보내면 오프라인 환경에서도 가상환경을 그대로 사용할 수 있다.

 

2.1. 생성한 가상환경 압축하기

  • 생성된 가상 환경은 설치한 anaconda3 디렉터리의 envs 디렉터리에 위치해 있다.
cd ./anaconda3/envs/
ll

  • 방금 생성하였던 New_Env를 압축해보자.
tar -cvf New_Env.tar New_Env
  • tar -cvf 압축후_폴더명.tar 압축할_폴더명: "압축할_폴더명" 디렉토리를 "압축후_폴더명.tar"로 압축한다.
  • 압축된 경로를 확인해보자.

 

2.2. 압축된 가상환경 내보내기

  • 압축된 가상 환경을 윈도우 환경의 c드라이브로 내보내자.
  • c드라이브에 Anal_Env_Set 디렉토리를 미리 생성하고, 이 곳으로 압축 파일을 이동시키자.
  • wsl2에서 c드라이브, d드라이브와 같은 윈도우 디렉토리로 이동하려면 /mnt 경로로 이동하면 된다.
mv New_Env.tar /mnt/c/Anal_Env_Set

  • 확인해보니, 압축했던 파일이 사라진 것을 볼 수 있다.
  • 파일을 이동시키기로 한 위치로 가서 파일이 이동한 것을 확인해보자.
cd /mnt/c/Anal_Env_Set
ll

  • 이동시키려는 디렉토리로 압축 파일이 이동한 것을 볼 수 있다.

 

2.3. 아나콘다 설치 파일도 밖으로 이동시키자.

  • 분석 서버는 가상 머신의 환경과 동일하므로, 이전 포스트에서 설치하였던, 아나콘다 설치 파일도 밖으로 내보내도록 하자.
cd
cd Download
ll

mv Anaconda3-2020.11-Linux-x86_64.sh /mnt/c/Anal_Env_Set

 

2.4. 이동된 파일들을 확인해보자.

  • 윈도우에서 이동시킨 파일들이 이동된 것을 확인해보자.

 

 

 

 

  지금까지 아나콘다를 이용하여, 가상 환경을 만들고 필요한 패키지들을 설치해보았다. 만약, 다른 라이브러리가 더 필요하다면, 필요한 라이브러리를 더 추가하여 다시 내보내면 된다.

 다음 포스트에서는 새로운 오프라인 서버 환경을 대상으로 분석 환경 구축을 실시해보자.

728x90
반응형
728x90
반응형

리눅스 서버에 분석 환경 구축

분석을 하기 위해선 분석을 할 수 있는 환경을 만드는 것이 가장 중요하다. 아무리 수많은 분석 기법들을 알고 있더라도, 스스로 분석 환경을 구축하지 못한다면 아무것도 진행할 수 없기 때문이다.

 이전 포스트까지는 일반적으로 사용자가 사용하는 컴퓨터(Local)에 분석 환경을 구축하는 것에 대해 알아보았다. 그러나, 대용량 데이터를 다루는 현장에서는 Local PC로 데이터 분석을 진행하는 것엔 한계가 있기 때문에 분석용 서버에서 분석을 진행하게 된다.

 그러나, 대부분의 서버는 보안을 위해 오프라인으로 구축되어 있으며, 우리에게 익숙한 OS인 Windows가 아닌 Ububtu, CentOS와 같은 Linux로 설치되어 있으며, 쓸모없는 자원 낭비를 막기 위해 CLI레벨로 구성되어 있어, 실행 시 그냥 검은 화면만 나온다(우리에게 익숙한 윈도우 화면은 GUI레벨이다).

 일반적으로 서버의 환경 설정은 도커(Docker)를 이용하여 구축하지만, 단순히 파이썬(Python) 기반의 분석 환경을 구축하고자 한다면, 앞서 학습했던 아나콘다 가상 환경(Virtual Environment)만 사용해도 충분하다.

 이번 포스트에서는 오프라인 우분투(Ubuntu) 서버에 딥러닝 분석 환경을 구축하는 과정을 학습해보도록 하겠다.

 

 

 

 

 

1. 준비물과 진행 과정

 오프라인 서버 분석 환경 구축과 연습에는 인터넷이 되는 Local PC 하나만 있으면 충분하다. 분석 서버를 단순하게 설명해보면, "성능이 엄청나게 좋지만 인터넷이 안 되는 리눅스 OS가 설치된 컴퓨터"라고 할 수 있다.

 앞으로 우리가 진행할 과정을 간단하게 요약해보면 다음과 같다.

  1. 인터넷이 되는 윈도우 컴퓨터에 분석 서버와 동일한 리눅스 배포 버전 가상 머신 설치
    (이번 포스트에서는 Ubuntu 18.04를 대상으로 하겠다.)
  2. 가상 머신에 아나콘다를 설치
  3. 가상 환경 생성 후, 필요한 패키지 모두 설치 및 이를 압축하여 외부로 내보내기
  4. 사용하고자 하는 텐서플로우(파이토치) 버전에 맞는 Cuda, Cudnn 다운로드
  5. 압축된 가상환경, 아나콘다 설치 파일, Cuda, Cudnn을 인터넷이 안되는 리눅스 서버에 이동시키기
    (가상 머신을 새로 만들고, 인터넷 선을 뽑은 후 진행하면, 오프라인 우분투 서버가 된다.)
  6. 이동된 파일 모두 설치

 꽤 복잡해 보이지만, 익숙하지 않아서 그렇지, 앞서 다뤄봤던 윈도우 환경에서 분석 환경 설정하는 방법과 동일하다.

 

 

 

 

 

2. 가상 머신(우분투) 설치하기 - wsl2

 가상 머신을 설치하는 방법을 두 가지 소개해보자면, 다음과 같다.

  1. Virtual Machine 프로그램을 사용하여, 가상 머신 만들기
  2. wsl2를 사용하여, 가상 머신 만들기

 Virtual Machine 프로그램을 사용하면, 내 컴퓨터에 작은 컴퓨터를 만드는 것처럼 진행할 수 있지만, 과정이 꽤 복잡하고, 자원을 분리해서 사용하며, 가상 머신 종료 등의 과정이 꽤 번거롭기 때문에, 이번 포스트에서는 마이크로 소프트의 wsl2를 사용해서 가상 머신을 만들어보도록 하겠다.

 

2.1. wsl2(Windows Subsystem for Linux 2)

  • wsl2는 Linux용 Windows 하위 시스템의 약자로, Virtual Machine보다 쉽게 가상 머신을 만들 수 있다.
  • 자원도 따로 나눌 필요가 없으며, 머신 종료 등의 번거로운 과정이 매우 간단한다.
  • 윈도우에서 도커(Docker)나 리눅스 개발을 할 수 있다.

 

2.2. wsl2 설치 및 주의 사항

  • wsl2 설치는 마이크로 소프트 공식 홈페이지에서 아주 쉽게 설명해주고 있으므로, 기본적으로 해당 웹사이트를 참고하기 바란다.
  • wsl2는 다음과 같은 주의 사항을 반드시 따라야만 사용할 수 있다.
  1. 윈도우10 업데이트가 최신 버전일 것: 윈도우 업데이트 확인은 "시작 버튼의 설정 > 업데이트 및 보안"을 통해 확인할 수 있다. "업데이트 확인"을 해본 후, 윈도우 업데이트를 실시하고, 만약 wsl2가 정상적으로 설치되지 않는다면, 컴퓨터를 재부팅하여 업데이트를 마무리해주길 바란다.
  2. CPU가 너무 구형이 아닐 것: Hyper-V를 구동시켜야만, wsl2와 같은 가상 머신을 사용할 수 있다. 2010년대 이전 CPU는 Hyper-V를 지원하지 않는 경우가 꽤 많으므로, 주의하길 바란다.
  3. 가상화 설정: "작업 관리자 > 성능"으로 들어가서 CPU의 가상화가 "사용"으로 되어 있는지 확인한다. 만약 사용이 안되어 있는 경우, BIOS에 들어가서 가상화를 설정해주어야 한다(메인보드 제조사마다 방식이 다르므로, 자신의 메인보드에 맞는 방법을 찾도록 하자).

  • 설명에서 헷갈릴 수 있는 부분은 "PowerShell의 관리자 권한 실행"이라 생각되는데, 시작 옆의 검색 기능을 이용하면 쉽게 할 수 있다.

  • 이번 학습에서 Linux는 Ubuntu 18.04를 사용할 것이지만, 자신이 다루고자 하는 서버의 리눅스 환경이 다른 경우, 자신에게 맞는 것을 설치하면 된다(명령어는 크게 다르지 않으며, 명령어가 다르더라도 과정은 동일하다)
  • 윈도우 터미널(Windows Terminal)을 마이크로소프트 스토어(Microsoft store)에서 설치하면, 보다 쉽게 wsl2의 기능을 사용할 수 있지만, 이번 포스트에서는 서버 환경과 동일한 상황에서 보기 위해 설치한 Ubuntu에서 진행해보겠다.

 

2.3. wsl2 설치 완료 후, 우분투 구동

  • 우분투 설치 후, 설치된 파일을 실행해주자
  • 실행 후, ID와 Password는 자신이 원하는 것으로 아무거나 입력해주면 된다.
  • 그 후, 아래와 같은 화면으로 이동해주자.

 

 

 

 

 

3. 아나콘다 설치하기

  • 설치된 가상 환경에 어떤 파일이 있는지 확인해보자.
ll

  • ll: 현 디렉토리에 있는 파일들을 모두 보여주며, 해당 파일의 권한 등을 색으로 표현해준다.
    (만약, 위와 같은 화면이 나오지 않는다면, cd를 입력하고 enter를 쳐서, 기본 디렉토리로 이동해주자)

 

3.1. Download 디렉토리 생성

  • Download 디렉토리를 생성하여, 앞으로 다운로드할 파일들이 저장될 공간을 분리해주자.
    (필수는 아니지만 디렉토리 정리가 잘될수록 관리가 쉬워지므로, 가능하면 꼭 해주도록 하자.)
mkdir Download
ll

  • mkdir 디렉토리_이름: "디렉토리_이름"을 현 디렉토리에 생성한다.

 

3.2. 아나콘다 설치 파일을 Download 디렉토리에 설치하자

  • 아나콘다를 설치하는 방법은 이전에 다뤘던 "python 파이썬과 아나콘다" 포스트와 거의 유사하다.
  • 해당 포스트를 참고하여 아래 화면으로 이동해보자.
    (아나콘다 버전에 따라 UI가 조금씩 달라질 수 있지만, 기본적인 방법은 같다)

  • Ubuntu는 Linux의 버전 중 하나이므로, Linux installer를 누르면 된다.
  • Tensorflow를 사용할 것이므로 64Bit를 다운로드 받아야한다.
  • "마우스 오른쪽 클릭 > 위 빨간 박스를 클릭"하여, 다운로드 받을 파일의 링크 주소를 복사하자.
cd Download
wget https://repo.anaconda.com/archive/Anaconda3-2020.11-Linux-x86_64.sh
ll
  • 리눅스 화면에서 복사는, 복사하고 싶은 구간 드래그이며, 붙여 넣기는 커서에 마우스 오른쪽 클릭을 하면 된다.

  • wget 링크_주소: 인터넷에서 "링크_주소"에 해당하는 파일을 다운로드한다.

 

3.3. 아나콘다 설치 파일 권한 부여 및 실행

  • 설치된 아나콘다 설치 파일의 색을 보면, 흰색으로 되어 있는 것을 볼 수 있다.
  • 해당 파일을 실행하기 위해 권한을 부여해보도록 하자.
chmod 755 Anaconda3-2020.11-Linux-x86_64.sh
ll

  • 권한이 부여되어 파일의 색이 녹색으로 바뀐 것을 볼 수 있다.
  • 해당 파일을 실행해보자.
./Anaconda3-2020.11-Linux-x86_64.sh

  • Enter를 눌러, 쭉 진행해보자.

  • 뭔가 엄청나게 많은 글이 뜨는데, 아나콘다 설치에 대한 약관이므로, 계속 엔터를 눌러 약관을 끝까지 내려주자.

  • yes를 입력하여 설치를 진행해주자.

  • Enter를 눌러서 아래 경로에 아나콘다를 설치해주자

  • yes를 입력해서, conda init 명령어로 Anaconda를 초기화 해주자.

 

3.4. 아나콘다 PATH 설정

  • 위 과정까지 진행했다면, linux를 종료했다가 다시 키거나, bashrc를 실행하여 PATH를 설정해줘야 한다.
source ~/.bashrc

  • 위 코드를 진행하면, 맨 왼쪽의 녹색 이름 옆에 (base)라는 글이 붙은 것을 볼 수 있다.
  • 이는, 아나콘다 쉘이 실행된 것으로, 성공적으로 아나콘다가 설치 및 실행된 것을 볼 수 있다.
  • 초기 화면으로 빠져나와, 설치된 아나콘다를 확인해보자.
cd
ll

  • 위 사진을 보면, 성공적으로 anaconda3가 설치된 것을 볼 수 있다.

 

 

 

 지금까지 윈도우에 리눅스 기반 가상머신을 설치하고, 해당 가상머신에 아나콘다를 설치해보았다. 위 과정은 아나콘다 설치 파일을 다운로드하는 과정까지만 인터넷이 필요하며, 이후의 과정에서는 오프라인으로 진행해도 된다.

 즉, 위 과정은 이후 분석 서버에 환경을 구축할 때도 다시 한번 진행되는 내용이다.

 다음 포스트에서는 아나콘다 가상 환경을 만들고, 이를 압축하여, 외부로 내보내는 방법에 대해 알아보도록 하겠다.

728x90
반응형
728x90
반응형

선형 회귀 모델 - 경사 하강법(Gradient descent, GD)

 지난 포스트까지 정규방정식(Normal Equation)과 최소제곱법(Least Squares method)을 이용하여 선형 회귀(Linear Regression)의 모델 파라미터를 계산해보았다.

 정규방정식이나 최소제곱법을 이용하여 모델 파라미터를 계산하는 경우, 공식이 꽤나 단순하고 단 한 번만 연산을 해도 된다는 장점이 있지만, 칼럼의 양이 2배 늘어나는 경우 정규방정식은 계산 시간이 최대 약 8배까지 증가하며, 최소제곱법은 계산 시간이 최대 4배까지 증가한다는 단점이 있다고 하였다.

 때문에, 데이터의 피처(컬럼의 수)가 매우 많거나 데이터 자체가 큰 경우, 정규방정식이나 최소제곱법을 사용하여 선형 회귀의 모델 파라미터를 계산하는 것보다. 경사 하강법(Gradient descent)을 사용하여 계산하는 것이 보다 유리하다.

 이번 포스트에서는 경사 하강법에 대해 알아보고, 경사하강법을 사용하여 선형 회귀 모형으로 학습을 해보도록 하겠다.

 

 

 

 

 

1. 경사 하강법이란?

  • 앞서 우리는 선형 회귀 모델의 손실 함수인 MSE에 대해 알아보았다.

$$ MSE = \frac{1}{n}\sum_{i=1}^{n}(\hat{y_i} - y_i)^2 $$

  • MSE에서 $\hat{y_i} = \theta x + b$이므로($\theta$: 계수, $x$: 실제 값, $b$: 절편), 학습을 통해 알고자 하는 미지수인 모델 파라미터 $\theta$는 1개의 최적해를 갖는 이차 함수 형태인 것을 알 수 있다.
  • 때문에 손실 함수의 개형은 아래와 같다.

  • 선형 회귀 모델을 비롯한 머신러닝 알고리즘에서 최고의 모델 파라미터를 찾는 방법은 손실 함수(Loss function)을 최소로 만드는 점 $\alpha$를 찾는 것이다.
  • 정규방정식이나 최소제곱법은 우리가 찾고자 하는 $\alpha$를 한 번에 찾는 방법이고, 경사 하강법은 손실 함수의 랜덤 한 위치에서 기울기를 계산하고, 기울기가 0이 되는 방향으로 학습률(Learning rate)만큼 점진적으로 이동하여, 최적해 $alpha$를 찾는 방법이다.
  • 위 과정은 전역 최적해(Global minimub)를 찾기 위해 반복 수행되며, 반복 수행된다는 의미는 다양한 랜덤한 위치에서 경사 하강법이 실시된다는 의미다.
  • 보다 자세히 경사 하강법의 원리를 알고자 하는 경우, 이전 포스트인 "딥러닝-6.0. 최적화(1)-손실함수와 경사하강법"을 참고하기 바란다.

 

1.1 경사 하강법의 한계점

  • 경사 하강법의 태생적 문제로 인해 다음과 같은 한계점이 존재한다.
  1. 데이터가 많아질수록 계산량 증가: 학습 데이터의 양이 늘어나는 경우, 계산량이 매우 커져 학습 속도가 느려진다.
  2. 지역 최소해(Local minimum) 문제: 실제 손실 함수의 형태는 위 그래프처럼 매끈하지 않고, 울퉁불퉁하기 때문에 실제로 찾아야 하는 전역 최적해(Global minimum)가 아닌 지역 최소해(Local minimum)를 찾을 수 있다.
  3. Plateau 문제: 평평한 지역(Plateau)에 들어가서, 학습이 더 이상 진행되지 못하는 문제
  4. Zigzag 문제: 찾아야 하는 해가 많아질수록 차원이 복잡해져, 제대로 해를 찾지 못하는 문제

 

 

 

 

 

2. 경사 하강법의 공식 - 배치 경사 하강법(Batch Gradient Descent)


  • 앞서 봤던 MSE 공식을 이번에는 벡터 형태로 가지고 와보자.

$$ MSE(X, h_{\theta}) = MSE(\theta) = \frac{1}{n}\sum_{i=1}^{n}(\theta^Tx^{(i)} - y^{(i)})^2 $$

  • 위 식을 모델 파라미터 $\theta$에 대해 편미분 해보자.

$$\frac{\partial}{\partial \theta_j}MSE(\theta) = \frac{2}{n}\sum_{i=1}^{n}(\theta^T x^{(i)} - y^{(i)})x_{j}^{i}$$

  • 위 편미분 결과에 대하여, 모든 모델 파라미터 $\theta_j$의 성분에 대한 편미분으로 구성된 열벡터로 만들어보고, 이를 행렬식으로 바꿔보자.

$$\bigtriangledown_{\theta} MSE(\theta) =
\begin{pmatrix} \frac{\partial}{\partial \theta_0}MSE(\theta)
\\ \frac{\partial}{\partial \theta_1}MSE(\theta)
\\ \vdots 
\\ \frac{\partial}{\partial \theta_0}MSE(\theta)
\end{pmatrix} = \frac{2}{m}X^T(X\theta - y)$$

  • 경사 하강법 공식은 다음과 같다.

$$x_{i+1} = x_i - \eta \bigtriangledown f(x_i)$$

  • 위 경사 하강법 공식에서 손실함수 $\bigtriangledown f(x_i)$의 위치에, 위에서 구한 $MSE$의 편미분 행렬식인 $\bigtriangledown_{\theta} MSE(\theta)$을 넣어주고, 미지수$x$도 선형 회귀의 모델 파라미터인 $\theta$로 바꿔 선형 회귀 모델에 대한 경사 하강법 공식으로 만들어주자.

$$\theta_{i+1} = \theta_i - \eta \bigtriangledown MSE(\theta) = \theta_i - \frac{2}{m} \eta X^T(X\theta - y)$$


  • 위 공식은 매 경사 하강법 스텝에서 전체 훈련 세트 $X$에 대해 계산한다. 이를 배치 경사 하강법(Batch gradient descent)라 하며, 매 스텝에서 훈련 데이터 전체를 대상으로 최적해를 찾기 때문에 계산 시간도 길고, 소모되는 컴퓨터 자원의 양도 많다.
  • 때문에 매우 큰 데이터를 대상으로 할 때는 위 공식인 배치 경사 하강법을 사용하지 않는 것이 좋으며, 무작위 샘플 데이터 셋을 추출해, 그 샘플에 대해서만 경사 하강법을 실시하는 확률적 경사 하강법(Stochastic Gradient Descent, SGD)을 실시하는 것이 좋다.
  • 그러나, 경사 하강법은 특성 수에 민감하지 않기 때문에, 특성 수가 매우 많은 경우, 정규방정식이나 특잇값 분해(SVD)를 이용한 최소제곱법보다 경사 하강법을 사용하여 학습하는 것이 좋다.
  • 경사 하강법 공식의 $\eta$는 학습률(Learning rate)라 하며, 에타라고 발음한다. 경사 하강법은 현재(n)의 파라미터 $\theta$에서 MSE의 편미분 벡터에 학습률을 곱한 수치만큼 아래 방향으로 이동한다.

 

 

 

 

 

3. 넘파이 코드를 이용해서 배치 경사 하강법을 구현해보자.

  • 위에서 행렬식으로 만든 경사 하강법 함수는 다음과 같다.

$$\theta_{i+1} = \theta_i - \frac{2}{m} \eta X^T(X\theta - y)$$

  • 경사 하강법은 최적의 모델 파라미터를 찾기 위해 전체 데이터에 대하여 m번 반복하여 계산된다.
  • 이 반복되는 것을 학습 단위라고 하며, Epoch(에포크), Batch size(배치 사이즈), Iteration(이터레이션)에 대한 기본 개념을 알아야 한다.
  1. Epochs: 전체 데이터를 학습 시키는 횟수
  2. Batch size: 연산 한 번에 들어가는 데이터의 크기
  3. Iteration: 1 epoch를 마치는데 필요한 모델 파라미터 업데이터의 횟수

 

3.1. 사용할 데이터

  • 데이터는 이전 포스트에서 사용했던 컬럼이 1개인 데이터를 사용해보겠다.
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1234)

def f(x):
    return 3 * x + 4

X = 2 * np.random.rand(100, 1)
Y = f(X) + np.random.randn(100, 1)

# 상수항을 위해 모든 원소가 1인 컬럼을 추가함
X_b = np.c_[X, np.ones((100, 1))]
  • 생성한 데이터를 sklearn 라이브러리의 LinearRegression 모델을 사용하여, 학습시켜보겠다.
  • sklearn의 LinearRegression에 학습시킬 때는 상수항을 위해 모든 원소가 1인 컬럼을 추가하지 않아도 된다.
# sklearn 라이브러리의 선형 회귀 모형
from sklearn.linear_model import LinearRegression

LR_model = LinearRegression()
LR_model.fit(X, Y)
>>> LR_model.coef_, LR_model.intercept_
(array([[2.94132381]]), array([4.07630632]))
  • 숨겨진 패턴인 함수 $f(x) = 3x + 4$의 계수 3과 상수 4에 근사한 결과가 나왔다.

 

3.2. 배치 경사 하강법 코드

def Batch_GD(x, y, eta=0.01, iteration_N=1000):
    
    # 초기 무작위 파라미터
    theta = np.random.randn(x.shape[1], 1)

    for iteration in range(iteration_N):

        # MSE의 편미분 벡터
        gradients = (2/x.shape[0])* x.T.dot(x.dot(theta) - y)
        theta = theta - eta * gradients
        
    return theta
>>> Batch_GD(X_b, Y, 0.01, 1000)
array([[3.02789289],
       [3.97237607]])
  • 학습률 eta나 파라미터 갱신 횟수 iteration_N과 같은 분석가가 직접 설정하는 파라미터를 머신러닝에서는 하이퍼 파라미터라고 한다.
  • 학습률이 크면 클수록 빠르게 최적해에 수렴하나, 너무 크게 이동하므로 전역 최적해에 수렴하지 못할 수 있다.
  • 학습률을 보다 크게 학습시켜보자.
>>> Batch_GD(X_b, Y, 0.1, 1000)
array([[2.94132381],
       [4.07630632]])
  • 학습률이 0.1로 10배나 커지자, 보다 빠르게 수렴하여 최소제곱법(LSM)을 사용하여 회귀 모델의 최적의 파라미터를 계산하는 sklearn의 LinearRegression과 같은 결과가 나왔다.

 

 

 

 

 

4. 학습률과 Iteration에 따른 수렴 속도의 차이 시각화

  • 위에서 만든 Batch_GD 함수를 약간 수정하여, 갱신된 파라미터에 대한 예측값을 plot으로 시각화하는 함수를 만들어보자.
# 전체 시각화
def draw_eta(x, y, eta_, iteration_N_):
    
    plt.scatter(x, y)
    
    # 상수항을 위한 모든 원소가 1인 컬럼 추가
    x_b = np.c_[x, np.ones((X.shape[0], 1))]
    Batch_GD_Visual(x_b, y, eta=eta_, iteration_N=iteration_N_)
    
    # 제목
    plt.xlabel("X", fontsize = 15)
    plt.ylabel("Y", fontsize = 15, rotation = 0)
    plt.title(f"$\eta$={eta_}", fontsize = 20, pad=15)
    
    plt.xlim(0, 2)
    plt.ylim(0, 15)
    
    plt.show()



# 갱신되는 theta에 따른 경사 하강법 시각화
def Batch_GD_Visual(x, y, eta=0.01, iteration_N=1000):

    # 초기 무작위 파라미터
    theta = np.random.randn(x.shape[1], 1)

    for iteration in range(iteration_N):

        # MSE의 편미분 벡터
        gradients = (2/x.shape[0])* x.T.dot(x.dot(theta) - y)
        theta = theta - eta * gradients
        
        # 경사 하강법을 통해 바뀐 theta로 예측한 값
        new_Y = np.array([[0,1],[2,1]]).dot(theta)
        plt.plot([0,2], new_Y, c = "r", alpha = 0.2)
        
    return theta
  • draw_eta는 시각화 코드를 정리해놓은 함수다.
  • Batch_GD_Visual은 갱신되는 $\theta$에 따른 경사 하강법을 시각화하는 함수로, 옅은 빨간색 선을 그린다.

4.1. iteration은 50이고, 학습률이 변하는 경우

  • iteration 1000은 꽤 큰 값이므로, 작은 50으로 설정해놓고 학습률만 바꿔보자.
  • 학습률이 0.01인 경우
eta_ = 0.01
iteration_N_ = 50
draw_eta(X, Y, eta_, iteration_N_)

 

  • 학습률이 0.1인 경우
eta_ = 0.1
iteration_N_ = 50
draw_eta(X, Y, eta_, iteration_N_)

 

  • 학습률이 0.5인 경우
eta_ = 0.5
iteration_N_ = 50
draw_eta(X, Y, eta_, iteration_N_)

  • 위 결과를 보면, 학습률이 커지면 커질수록 빠르게 최적해를 찾아가는 것을 볼 수 있지만, $\eta=0.5$ 같이 지나치게 큰 경우, 모델 파라미터가 큰 폭으로 요동치는 것을 볼 수 있다.
  • 위에서 볼 수 있듯, 데이터에 맞는 적절한 학습률을 찾는 것은 매우 중요하다.

4.2. 학습률은 0.01이고, iteration이 변하는 경우

  • 학습률을 최적해에 비교적 늦게 수렴하는 0.01로 잡고, 파라미터 갱신 횟수인 iteration만 바꿔보자.
    (꽤 많은 머신러닝 알고리즘에서 Learning rate의 기본값을 0.01로 잡아놓는다.)
  • iteration이 10인 경우
eta_ = 0.01
iteration_N_ = 10
draw_eta(X, Y, eta_, iteration_N_)

  • iteration이 30인 경우
eta_ = 0.01
iteration_N_ = 30
draw_eta(X, Y, eta_, iteration_N_)

  • iteration이 100인 경우
eta_ = 0.01
iteration_N_ = 100
draw_eta(X, Y, eta_, iteration_N_)

  • 위 결과를 보면, 파라미터 갱신량도 필요치보다 작은 경우, 최적해를 찾기 전에 경사 하강이 끝나버리고, 필요치 보다 큰 경우, 최적해를 찾고 파라미터가 더 이상 변하지 않는 시간 낭비가 발생하는 것을 볼 수 있다.
  • 이에 대한 해결책으로는, iteration을 애초에 크게 잡은 후, 경사 하강법 알고리즘에 규제를 추가하여, 모델 파라미터의 변화량이 허용오차(tolerance) $\varepsilon$보다 작아지면 최적해에 도달한 것으로 판단하고 모델 파라미터 갱신을 중지시키는 것이다.

 

 

[참고 서적]

 

 

 

 이번 포스트에서는 배치 경사 하강법을 이용하여 선형 회귀 모형을 만들어보았다. 배치 경사 하강법은 데이터가 지나치게 큰 경우 계산 시간이 지나치게 오래 걸리는 정규방정식이나 최소제곱법보다 빠르게 최적해를 찾을 수 있다.

 그러나, 학습률, 파라미터 갱신 횟수(iteration)과 같은 하이퍼 파라미터를 제대로 잡지 않는다면, 학습 시간이 필요보다 길어지거나, 최적해에 수렴하지 못할 수 있으므로, 최적의 하이퍼 파라미터를 찾을 수 있어야 한다.

 배치 경사 하강법은 모든 데이터에 대한 편미분 벡터를 계산하게 되므로, 데이터의 크기가 이보다 더 커지는 경우, 학습 시간이 더 길어질 수 있다. 다음 포스트에서는 이 문제를 해결한 확률적 경사 하강법에 대해 알아보도록 하겠다.

728x90
반응형
728x90
반응형

선형 회귀의 구현 - 정규방정식과 최소제곱법

 지난 포스트에서 머신러닝에서 선형 회귀 모델의 기본적인 원리에 대해 알아보았다. 이번 포스트는 정규방정식을 넘파이 함수로 구현해보고, 정규방정식으로 찾아낸 최적의 모델 파라미터를 이용해서 새로운 데이터에 대해 예측을 해보자.

 

 

 

 

1. 선형성을 갖는 무작위 데이터를 만들어보자.

  • 임의의 선형 데이터를 만들어 정규방정식에 넣어보도록 하자.
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1234)

def f(x):
    return 3 * x + 4

X = 2 * np.random.rand(100, 1)
Y = f(X) + np.random.randn(100, 1)
  • np.random.rand(shape): 0~1 사이의 표준 정규 분포 난수를 shape의 형태대로 생성
  • np.random.randn(shape): 평균 0, 표준편차 1의 가우시안 표준 정규 분포 난수를 shape의 형태대로 생성
  • 0에서 1 사이의 난수 X에 2를 곱하여, 값의 범위를 더 넓게 하였다.
  • 숨겨진 패턴은 함수 $f(x) = 3x + 4$이며, $f(x)$에 $N(0,1)$인 가우시안 표준 정규 분포를 더해 노이즈를 주었다.
plt.scatter(X, Y)

plt.xlabel("X", fontsize=15)
plt.ylabel("Y", rotation=0, fontsize=15)
plt.show()

 

 

 

 

 

2. 넘파이 코드를 사용해서 정규방정식을 구현해보자.

  • 정규방정식 함수는 다음과 같다.

$$\hat{\theta} = (X^TX)^{-1}X^Ty$$

  • 위 정규방정식 함수를 넘파이 라이브러리의 함수를 사용해서 함수로 만들어보자.
# 정규방정식
def NormalEquation(X, Y):
    
    return np.linalg.inv(np.dot(X.T, X)).dot(X.T).dot(Y)
  • np.linalg.inv(): 역행렬
  • np.dot(mat1, mat2): 행렬 mat1과 mat2의 행렬 곱 연산을 한다.
  • mat1.dot(mat2): 행렬 mat1과 mat2의 행렬 곱 연산을 한다.

 

2.1. 배열 X와 Y를 넣어보자

>>> NormalEquation(X, Y)
array([[6.00122666]])
  • 위 데이터에서 숨겨진 패턴인 함수 $f(x)$는 $f(x) = 3x + 4$이므로, 3과 4가 출력되어야 하지만, 원소가 단 하나만 출력되었다.
  • 이는 함수 $f(x)$에 들어가는 배열 X에 절편에 대한 칼럼이 반영되지 않았기 때문이다.
  • 절편 4는 4*1이므로, 배열 X에 모든 원소가 1인 칼럼을 하나 추가해주고, 정규방정식을 수행해보도록 하자.

 

2.2. 절편에 대한 칼럼이 반영된 배열 X와 Y를 넣어보자.

# 절편에 대한 1로 구성된 벡터를 추가함.
>>> X_b = np.c_[X, np.ones((100, 1))]

# 정규방정식을 통해 최적의 계수를 찾아냄
>>> NormalEquation(X_b, Y)
array([[2.94132381],
       [4.07630632]])
  • np.c_[array1, array2]: array1과 array2를 컬럼 방향으로 붙인다(오른쪽에 붙인다)
  • 위 결과를 보면, 숨겨진 패턴인 함수 $f(x) = 3x + 4$의 계수인 3과 4와 아주 가까운 값이 도출된 것을 볼 수 있다.
  • 숨겨진 패턴의 계수 3과 4가 나오지 않은 이유는, 의도적으로 노이즈를 주었기 때문이며, 그 노이즈를 반영하였을 때, 숨겨진 패턴에 가장 가까운 모델 파라미터가 출력된 것이다.

 

2.3. 변수 $x$가 2개인 데이터에 대하여 정규방정식을 이용해 최적해를 구해보자.

  • 이번에는 숨겨진 패턴이 $h(x) = 3x_1 + 4x_2 + 5$인 함수에 대하여 구해보자.
  • 변수  $x$가 2개이므로, 컬럼의 수는 2개가 되어야 한다.
X1 = 2 * np.random.rand(100, 2)

def h(x):
    x1 = x[:,0]
    x2 = x[:,1]
    
    result = 3 * x1 + 4 * x2 + 5
    
    return result.reshape(100, 1)

Y1 = h(X1) + np.random.randn(100, 1)

# 절편을 위해 모든 원소가 1인 컬럼 추가
X1_b = np.c_[X1, np.ones((100, 1))]
>>> NormalEquation(X1_b, Y1)
array([[2.93017703],
       [4.19897028],
       [4.90893137]])
  • 각 계수의 값이 3, 4, 5에 근사하게 나왔으나, 실제 값과 어느 정도 거리가 있다.
  • 데이터의 양이 늘어날수록 실제 계수에 더 가까워진다.
X2 = 2 * np.random.rand(10000, 2)

def h(x):
    x1 = x[:,0]
    x2 = x[:,1]
    
    result = 3 * x1 + 4 * x2 + 5
    
    return result.reshape(10000, 1)

Y2 = h(X2) + np.random.randn(10000, 1)
X2_b = np.c_[X2, np.ones((10000, 1))]
>>> NormalEquation(X2_b, Y2)
array([[2.98528199],
       [4.01290386],
       [5.00091078]])

 

 

 

 

 

3. 찾아낸 모델 파라미터를 이용해서 예측을 해보자.

  • 정규방정식을 통해 계산해 낸 선형 회귀 모델의 파라미터 $\hat{\theta}$를 사용해서 새로운 데이터가 들어갔을 때, 그 결과를 예측해보자.
def predict_linear_R(X, theta):
    
    R_n = X.shape[0]
    
    try:
        C_n = X.shape[1]
    except:
        C_n = 1
    
    X_Reshape = X.reshape(R_n, C_n)
    X_concat_1 = np.c_[X_Reshape, np.ones((R_n,1))]
    
    return X_concat_1.dot(theta)

 

3.1. 독립변수가 1개인 경우

  • 처음 만들었던 칼럼이 1개 있는 데이터의 최적 모델 파라미터에 대하여, 새로운 데이터를 넣어 새로운 데이터에 대한 예측 값을 뽑아보자.
  • 새로운 데이터는 [0, 1, 2]로 구성된 벡터이다.
def f(x):
    return 3 * x + 4

X = 2 * np.random.rand(100, 1)
Y = f(X) + np.random.randn(100, 1)

X_b = np.c_[X, np.ones((100, 1))]
best_theta = NormalEquation(X_b, Y)
>>> best_theta
array([[2.94132381],
       [4.07630632]])
# 새로운 데이터
>>> new_X = np.array([0, 1, 2]).reshape((3,1))

# 새로운 데이터를 학습된 선형 회귀 모형에 넣어 예측된 결과
>>> pred_LR = predict_linear_R(new_X, best_theta)
>>> pred_LR
array([[4.07630632],
       [7.01763013],
       [9.95895394]])
  • 기존에 그린 산점도 위에 예측된 결과를 그려보자.
plt.scatter(X, Y, label="real")
plt.plot(new_X, pred_LR.reshape(new_X.shape), color = "red", label="predict")

plt.xlabel("X", fontsize=15)
plt.ylabel("Y", rotation=0, fontsize=15)
plt.legend(loc="lower right")
plt.show()

 

3.2. 독립변수가 2개인 경우

X1 = 2 * np.random.rand(100, 2)

def h(x):
    x1 = x[:,0]
    x2 = x[:,1]
    
    result = 3 * x1 + 4 * x2 + 5
    
    return result.reshape(100, 1)

Y1 = h(X1) + np.random.randn(100, 1)
X1_b = np.c_[X1, np.ones((100, 1))]
best_theta1 = NormalEquation(X1_b, Y1)
>>> best_theta1
array([[2.93017703],
       [4.19897028],
       [4.90893137]])
>>> new_X1 = np.array([[0, 1],[0.5, 1.5],[1, 2]])

>>> predict_linear_R(new_X1, best_theta1)
array([[ 9.10790166],
       [12.67247531],
       [16.23704897]])
  • 독립변수가 2개 이상인 경우, 독립 변수의 축 2개 + 종속변수의 축 1개로 3개 이상의 축이 생겨, 시각화가 어려워진다. 그러므로, 시각화는 생략하도록 하겠다.
  • 최적의 모델 파라미터만 찾아내면, 쉽게 회귀 모델을 사용해서, 예측값을 찾아낼 수 있다.

 

 

 

 

 

4. 사이킷런을 사용해서 선형 회귀를 실시해보자.

  • 사이킷런을 사용하면, 더 쉽게 위 과정을 진행할 수 있다.
from sklearn.linear_model import LinearRegression

lin_R = LinearRegression()
  • 사용하고자 하는 모델인 선형 회귀 모형을 객체로 만들었다.
  • 앞서 만든 데이터 X와 Y를 사용하여, 최적의 모델 파라미터를 찾아보자.
# 선형 회귀 모형 학습
>>> lin_R.fit(X, Y)

# 계수와 절편 출력
>>> lin_R.coef_, lin_R.intercept_
(array([[2.94132381]]), array([4.07630632]))

# Numpy로 만든 정규방정식의 결과
>>> best_theta
array([[2.94132381],
       [4.07630632]])
  • 모델.fit(array1, array2): 원하는 모델을 학습시킨다. array1은 훈련 데이터(Test data), array2는 레이블 데이터(Label data)다.
  • 선형회귀모델.intercept_, 선형회귀모델.coef_: sklearn을 사용하여, 선형 회귀 모형을 학습시키면, 계수와 절편의 값이 따로 출력된다. coef_는 계수이며, intercept_는 절편이다.
  • sklearn을 사용하여 계산된 결과와 numpy를 사용하여 만든 정규방정식의 결과가 동일한 것을 볼 수 있다.
  • 이번에는 학습된 모델 파라미터를 사용하여, 새로운 데이터가 들어갔을 때의 결과를 예측해보자.
# sklearn을 이용하여 예측한 결과
>>> lin_R.predict(new_X)
array([[4.07630632],
       [7.01763013],
       [9.95895394]])
       
# numpy 라이브러리를 사용하여 예측한 결과
>>> predict_linear_R(new_X, best_theta)
array([[4.07630632],
       [7.01763013],
       [9.95895394]])
  • 모델.predict(array): array에 모델 파라미터를 계산하여, 예측된 결과를 출력한다.

 

 

 

 

 

5. 정규방정식의 한계점

5.1. 의사역행렬(Pseudoinvese matrix)과 최소제곱법(LSM)

  • 앞서 우리가 학습하였던 정규방정식에는 큰 한계점이 존재한다.
  • 정규방정식 공식 $\hat{\theta} = (X^TX)^{-1}X^Ty$에는 역행렬이 포함되어 있는데, 역행렬은 항상 존재하는 것이 아니기 때문에 역행렬이 존재하지 않는다면, 정규방정식 공식은 작동하지 않을 수 있다.
  • 때문에 등장하는 것이 무어-펜로즈 역행렬(Moore-Penrose pseudoinverse matrix)이라고도 불리는 의사역행렬(Pseudoinverse matrix)을 사용하여 다음과 같은 공식으로 최적의 모델 파라미터를 찾아내게 된다.

$$ \hat{\theta} = X^{+}y$$

  • 의사역행렬은 특잇값 분해(Singular value decomposition, SVD)라는 표준 행렬 분해 기법을 통해 계산되며, 의사역행렬은 역행렬이 없는 행렬에 대해서도 계산을 할 수 있기 때문에 정규방정식의 한계점을 해결할 수 있으며, 계산 속도 또한 빠르다.
  • 선형 회귀 모델의 회귀 계수(모델 파라미터)를 추정할 때, 가장 많이 사용되는 기법인 최소제곱법(Least squares method, LSM)은 의사역행렬을 사용하여 해를 구하므로, sklearn의 선형 회귀 모델은 정규방정식이 아닌 최소제곱법을 기반으로 계산한다.
>>> np.linalg.lstsq(X_b, Y, rcond=1e-6)
(array([[2.94132381],
        [4.07630632]]),
 array([92.72583695]),
 2,
 array([14.98211623,  3.69398772]))
  • np.linalg.lstsq(array1, array2): array1, array2의 최소제곱해를 선형 행렬 방정식으로 반환한다.
  • 위 함수를 사용하면 총 4개의 결과가 반환되는데, 여기서 맨 처음에 반환된 결과인 최소제곱해만 신경 쓰면 된다.
# 최소제곱해
>>> np.linalg.lstsq(X_b, Y, rcond=1e-6)[0]
array([[2.94132381],
       [4.07630632]])
       
       
# Numpy로 만든 정규방정식의 결과
>>> best_theta
array([[2.94132381],
       [4.07630632]])
  • 보시다시피 최소제곱법을 사용해서 구하는 최소제곱해와 정규방정식의 결과는 동일한 것을 알 수 있다.
  • 그러나, 최소제곱법은 의사역행렬을 통해 계산되기 때문에 역행렬이 존재하지 않는 대상에 대해서도 계산이 가능하다.

 

5.2. 정규방정식의 계산복잡도

  • 정규방정식은 역행렬 계산, 행렬 곱 등 다양한 행렬 연산이 들어가기 때문에 계산 복잡도(Computation complexity)가 매우 크다.
  • 정규방정식을 사용할 때, 특성의 수가 2배 늘어나면, 계산 시간이 약 5.3배에서 8배로 증가하며, 특잇값 분해(SVD)를 통해 의사역행렬을 구한다 할지라도 특성의 수가 2배 늘어나는 경우, 계산 시간이 약 4배 증가하게 된다.
  • 즉, 칼럼의 수가 늘어나면 늘어날수록 계산 시간이 기하급수적으로 늘어나기 때문에, 칼럼이 많은 데이터를 정규방정식이나 최소제곱법으로 구하는 경우, 시간이 매우 오래 걸리게 된다.
    (행의 수가 늘어나는 경우, 늘어난 샘플 수만큼 선형적으로 소모 시간이 증가하기 때문에 행의 수는 큰 영향을 안 준다.)
  • 만약, 칼럼의 양이나 데이터 자체가 매우 많은 경우, 계산량이 지나치게 많아, 메모리를 넘어설 수 있기 때문에, 정규방정식이나 최소제곱법을 사용하지 못할 수도 있다.

 

 

[참고]

numpy.org/doc/stable/reference/generated/numpy.linalg.lstsq.html

 

numpy.linalg.lstsq — NumPy v1.20 Manual

Cut-off ratio for small singular values of a. For the purposes of rank determination, singular values are treated as zero if they are smaller than rcond times the largest singular value of a. Changed in version 1.14.0: If not set, a FutureWarning is given.

numpy.org

blog.daum.net/jungjin1980/77

 

특이값 분해

출처 : http://darkpgmr.tistory.com/106 활용도 측면에서 선형대수학의 꽃이라 할 수 있는 특이값 분해(Singular Value Decomposition, SVD)에 대한 내용입니다. 보통은 복소수 공간을 포함하여 정의하는 것이..

blog.daum.net

 

 

 

 지금까지 정규방정식과 정규방정식의 한계점을 보완한 최소제곱법에 대해 간략히 알아보고, 코드화해 보았다. 최소제곱법은 선형 회귀 모형을 다룰 때, 굉장히 심도 있게 공부해야 하는 부분이므로, 기초 통계학 부분에서 보다 자세히 다루도록 하겠다.

 다음 포스트에서는 선형 회귀 모형을 정규방정식이나 최소제곱법이 아닌, 경사하강법을 사용해서 구하는 방법에 대해 알아보도록 하겠다.

728x90
반응형
728x90
반응형

선형 회귀(Linear Regression)

 통계학의 꽃이라고도 불리는 선형 회귀(Linear Regression)는 수많은 머신러닝 알고리즘의 기반이 되기도 하기 때문에, 반드시 그 원리를 이해해야하는 알고리즘 중 하나다.

 선형 회귀의 원리를 단순하게 말하자면, 관찰값으로부터 가장 거리가 짧은 데이터를 대표할 수 있는 선을 긋는 것이며, 그 선을 회귀식이라고 한다. 관찰값으로부터 가장 짧은 거리인지를 평가하는 방법은 최소제곱법(Least Square Method)이 주로 사용된다.

 

 

 

 

1. 회귀식


$$\hat{y} = \theta_0 + \theta_1x_1 + \theta_2x_2 + \cdots + \theta_nx_n \ \ \ \cdots①$$

$$\hat{y} = h_\theta(x) = \theta \cdot x   \ \ \ \cdots②$$


  • 회귀식은 기본적으로 해가 $n$개인 일차 연립방정식의 형태이며, 계수와 특성의 값의 곱의 합에 편향(Bias, 절편 - Intercept)을 더한 것이다.
  • $\theta_n$는 해당 관찰값의 계수로, 관찰값 $x_n$가 예측값에 미치는 영향을 보여준다.
  • 계수 $\theta$는 음과 양의 부호를 가질 수 있으며, 이를 통해 해당 특성(변수, 필드)가 종속변수(예측값)에 어떠한 영향을 주는지 볼 수 있다.

1.1. 식 ①의 설명

  • $\hat{y}$: 예측값으로, 종속변수(Dependent variable)이라 한다.
  • $n$: 특성의 수, 독립변수(Independent variable)의 수이다.
  • $x_i$: $i$번째 특성값으로, $i$번째 독립변수를 의미한다.
  • $\theta_j$: $j$번째 모델 파라미터로, 머신러닝 알고리즘 스스로가 학습을 통해 찾아내는 값이다.

1.2. 식 ②의 설명

  • 식 ①을 벡터 형태로 바꾼 것으로, $\theta$와 $x$가 열 벡터(Column vector) 라면, 예측은 $\hat{y} = \theta^Tx$가 된다.
  • 열 벡터란 하나의 열(Column)을 가진 2D 배열이며, $\theta^T$는 열벡터 $\theta$의 전치(Transpose)이다.
  • 두 열 벡터 $\theta$와 $x$의 길이는 서로 동일하므로, 전치 벡터와 길이가 동일한 벡터를 곱하면, 동일한 위치의 원소끼리 곱하고, 더하는 효과가 발생한다.
  • $\theta$: 편향 $\theta_0$와 계수 $\theta_1, \theta_2, \cdots, \theta_n$에 대한 모델 파라미터 벡터다.
  • $x$: $x_0, x_1, \cdots, x_n$까지의 데이터의 특성 벡터다. $x_0$는 편향과 곱해지는 값이므로 무조건 1이다.
  • $\theta \cdot x$: 벡터 $\theta$와 $x$의 점곱으로, $\theta_0x_0 + \theta_1x_1 + \theta_2x_2 + \cdots + \theta_nx_n$과 같다.
  • $h_\theta$: 모델 파라미터 $\theta$를 사용한 가설(Hypothesis) 함수다.

 

 

 

 

 

2. 손실함수 RMSE & MSE

  • 선형 회귀 모델의 학습은 훈련 데이터 셋(Train dataset)에 가장 잘 맞는 모델 파라미터($\theta$)를 찾아내는 것이다.
  • 이를 위해 모델이 훈련 데이터에 얼마나 잘 맞는지 측정해야한다.
  • 선형 회귀 모형은 평균 제곱근 오차(Root Mean Square Error, RMSE)를 사용하여, 모델의 성능을 평가하며, RMSE를 최소화하는 $\theta$를 찾아내는 것이 선형 회귀 모델의 학습 과정이다.
  • RMSE 공식은 다음과 같다.

$$RMSE = \sqrt{\frac{1}{n}\sum_{i=1}^{n}(\hat{y_i} - y_i)^2}$$

$$ RMSE(X, h_{\theta}) = RMSE(\theta) = \sqrt{\frac{1}{n}\sum_{i=1}^{n}(\theta^Tx^{(i)} - y^{(i)})^2} $$


  • 평균 제곱근 오차(RMSE)의 원리는 표준편차와 동일하다. 예측값과 실제 관측값의 편차 제곱의 합의 평균에 제곱근을 씌워 제곱의 합을 보정해주는 것이다.
  • 평균 제곱근 오차(RMSE)에 대하여 더 자세히 알고자하는 경우, 다음 포스트 "딥러닝-5.2. 손실함수(3)-평균제곱근오차(RMSE)"를 참고하길 바란다.
  • 예측값과 실제값의 편차의 평균에 가장 근사한 지표는 RMSE지만, 실제 선형 회귀 모델을 만들 때는 평균 제곱 오차(Mean Square Error, MSE)가 더 많이 사용된다.
  • MSE 공식은 다음과 같다.

$$ MSE = \frac{1}{n}\sum_{i=1}^{n}(\hat{y_i} - y_i)^2 $$

$$ MSE(X, h_{\theta}) = MSE(\theta) = \frac{1}{n}\sum_{i=1}^{n}(\theta^Tx^{(i)} - y^{(i)})^2 $$


  • RMSE보다 MSE를 사용하는 이유는 제곱근을 사용하지 않았기 때문에 실제 값보다 증폭된 결과가 도출되긴 하지만, 공식이 더 간단하며, 미분하기도 쉽다.
    어차피 MSE로 도출된 결과들을 비교하기 때문에 다른 모델과 비교할 때, 보다 엄격한 결과가 나오는 RMSE를 굳이 사용할 필요가 없다.
  • MSE에 대해 보다 자세히 알고자 하는 경우, 다음 포스트 "딥러닝-5.1. 손실함수(2)-평균제곱오차(MSE)"를 참고하기 바란다.
  • 선형 회귀 모델에서의 학습은 비용 함수(Cost function, 손실 함수 - Loss function)인 RMSE나 MSE를 최소로 만드는 $\theta$를 찾는 것이다.

 

 

 

 

 

3. 정규방정식(Normal equation)


$$\hat{\theta} = (X^TX)^{-1}X^Ty$$


  • $\hat{\theta}$: 비용 함수를 최소화하는 $\theta$값이다.
  • $y$: $y^(1)$부터 $y^{(m)}$까지 포함하는 타깃 벡터다.
  • 정규방정식(Normal equation, Ordinary least squares, linear least squrares)는 선형 회귀에서 모델 파라미터인 $\theta$를 예측하기 위해 사용하는 최적화 알고리즘이다.
  • 위 정규방정식은 MSE를 통해 유도 된다.

 

3.1. 정규방정식의 유도

  • MSE 공식은 다음과 같다. $MSE(\theta) = \frac{1}{n}\sum_{i=1}^{n}(\theta^Tx^{(i)} - y^{(i)})^2$ 
  • 위 공식을 보면, MSE 공식은 $\theta^T$에 대하여 이차함수의 개형을 갖는 것을 알 수 있다.
  • 그러므로, MSE을 $theta^T$에 대하여 편미분의 결과가 0이 나오게 하는 $\theta^T$의 값이 MSE를 최소로 만드는 값임을 알 수 있다.
  • 위 내용을 이용하여, 정규방정식을 유도해보자.

 

3.2. 정규방정식과 경사하강법의 차이점

  • 대표적인 최적화 알고리즘인 경사하강법(참고: "딥러닝-6.0. 최적화(1)-손실함수와 경사하강법")은 학습률(Learning rate)를 기반으로 점진적으로 최적해를 찾아간다.
  • MSE를 유도하여 만들어진 정규방정식은 행렬 연산을 통해 한 번에 최적해를 구한다.
  • 정규방정식은 행렬 연산을 통해 결과를 구하기 때문에 피처의 크기(Column * Row의 양)가 커지면 커질수록 계산 시간이 오래 걸린다.
  • 경사하강법은 계산이 일어나 기본적으로 소모되는 시간이 크긴 하지만, 아무리 피처의 크기가 크더라도 일정 시간 안에 최적해를 찾아낼 수 있다.
  • 즉, 피처의 크기가 지나치게 크다면 선형 회귀에서도 경사하강법을 사용하는 것이 좋으며, 피처의 크기가 적당한 수준이라면, 정규방정식을 사용하도록 하자.

 

 

[참고]

 

 

 

 다음 포스트에서는 파이썬 넘파이(Numpy) 함수만을 사용해서 선형 회귀 모델을 구현해보고, 사이킷런을 사용해서 선형 회귀 모델을 사용해보도록 하자.

728x90
반응형
728x90
반응형

테스트와 검증

 이전 포스트에서는 머신 러닝 사용 시 주의해야 할 사항에 대해 알아보았다. 이번 포스트에서는 학습이 끝난 모델을 어떻게 평가하는지에 대해 알아보도록 하겠다.

 

 

 

 

1. 데이터 셋 나누기

  • 학습이 완료된 모델이 새로운 데이터에 대해 얼마나 잘 일반화되는지 알아보기 위해선, 학습에 사용하지 않은 새로운 데이터를 실제로 넣어보고, 잘 작동하는지 확인해봐야 한다.
  • 그러나, 현장에서 새로운 데이터를 구하는 것은 굉장히 어려운 일이기 때문에, 학습에 사용할 훈련 데이터를 훈련 데이터 셋(Train dataset)과 테스트 데이터 셋(Test dataset)으로 나누는 것이 가장 현실적이다.
  • 훈련 데이터셋으로 학습을 진행하고, 테스트 데이터 셋을 이용해서 모델을 평가하면, 테스트 데이터 셋에 대한 모델의 오차 비율을 얻을 수 있으며, 이를 일반화 오차(Generalization error) 또는 외부 샘플 오차(Out-of-sample error)라고 한다.
  • 훈련 데이터에 대한 오차는 낮으나, 테스트 데이터에 대한 오차인 일반화 오차가 높다면, 이는 모델이 훈련 데이터에 과적합(Overfitting) 되었다는 것을 의미한다.
  • 위 경우, 훈련 데이터에 과적합되는 것을 피하기 위해, 일반화 오차를 줄이는 방향으로, 하이퍼 파라미터 튜닝 등 다양한 작업을 수행할 수 있는데, 이 경우 단순히 결과 지표를 뽑기 위해 사용해야 하는 테스트 데이터 셋에 모델이 과적합되는 문제가 발생할 수 있다.

1.1. 검증 데이터 셋(Validation dataset)

  • 검증 데이터 셋은 모델이 시험 셋(Test dataset)에 과대적합되는 것을 막기 위해, 훈련 데이터 셋에서 일부분을 추가로 추출하여, 모델 적합도의 기준으로 사용하는 데이터 셋이다.
  • 전체 데이터 셋의 규모가 적거나, 검증 데이터 셋이 훈련 데이터 셋을 대표하지 못한다면, 데이터가 편향되는 결과가 발생할 수 있으므로, 교차 검증(Cross-Validation)과 같은 다양한 방법으로, 이를 해결한다.
  • 물론, 데이터 셋의 양이 굉장히 많다면, 교차 검증은 현실적으로 사용이 불가능하며, 훈련 셋의 각 클래스별 비율에 맞는 데이터 셋을 추출하여, 대표성이 높은 검증 셋을 뽑을 수 있다.
  • 이외 데이터 셋에 대한 보다 자세한 정보를 알고자 하면, 이전 포스트인 "Tensorflow-1.0. 기초(1)-데이터 셋 만들기"와 "Tensorflow-3.2. 이미지 분류 모델(2)-검증 셋(Validation set)"을 참고하기 바란다.

 

 

 

 

 

2. 하이퍼 파라미터 튜닝

  • 하이퍼 파라미터 튜닝은 위에서 만든 학습 셋(Train set), 검증 셋(Validation set), 시험 셋(Test set)을 사용하여, 모델을 평가하며, 모델의 일반화 오차가 최소화되는 하이퍼 파라미터를 탐색하는 과정이다.
  • 앞서 이야기 한, 학습 셋으로 만들어진 모델의 하이퍼 파라미터를 시험 셋에 과대적합 시키는 현상을 막기 위해, 검증 셋을 사용하는 것을 홀드 아웃 검증(Holdout validation)이라고 한다.
  • 하이퍼 파라미터를 탐색하는 과정은 그리드 서치(Greed search), 랜덤 서치(RandomizedSearch), 베이지안 옵티마이저(Baysian optimizer) 등의 방법을 통해 가장 적합한 하이퍼 파라미터를 찾아낸다.

 

 

 

 

 

3. 공짜 점심 없음(No free lunch, NFL) 이론

  • 1996년 David Wolpert가 발표한 "The Lack of A Priori Distinctions Between Learning Algorithms."에서 나온 공짜 점심 없음 이론은, 경험해보기 전까진 해당 데이터에 더 잘 맞을 것이라고 보장할 수 있는 모델은 존재하지 않는다는 내용이다.
  • 머신러닝 알고리즘에서 사용되는 모델들은 관측된 데이터들을 간소한 것으로, 새로 들어온 데이터에서 일반적이지 않을 것으로 보이는 불필요한 세부 사항을 제거하는 것이다.
  • 이러한 불필요한 세부 사항은 각 머신러닝 알고리즘이 만들어진 원리에 따라 다르게 정해진다.
  • 때문에, 가장 핫한 머신러닝 모델 중 하나인 딥러닝 모델의 성능이 아무리 좋다고 할지라도, 경우에 따라서는 훨씬 단순한 선형 회귀 모델이 해당 데이터에는 더 적합할 수도 있다는 의미이다.
  • 때문에 해당 데이터에 관련된 다양한 모델들을 평가해보고, 이를 비교하여, 적절한 모델을 선택하도록 해야 한다.
  • 이는, 모든 머신러닝 모델을 각 데이터에 적용하라는 것이 아니라, 데이터의 복잡도, 데이터의 크기, 해당 데이터 성격에 관련된 모델 등 다양한 요소를 감안하여, 적합한 머신러닝 모델을 일부 선택한 후, 이들을 비교해보라는 의미이다.

 

 

[참고 서적]

728x90
반응형

+ Recent posts