Django

 

Python 기반 웹 프레임 워크. 한 Project는 여러 App으로 구성되어 있다. App 각각은 특정 명령을 수행하는 View나 Template의 모음이라고 생각하면 된다.

 

Djnago vs Flask

 

둘 다 Python 기반 웹 프레임 워크지만, 지향성이 다르다.

 

flask는 늘 앞에 micro가 붙는다. 이는 최소한의 기능을 갖고 있다는 것으로, 여기에 추가적 모듈을 붙여가며 빌드업을 하는 구조이고,

 

Django는 이미 거의 모든 것이 내장되어 있는 구조로 되어 있다. 큰 것 안에 우리가 원하는 것을 부분부분 채워 나가면서 프로젝트를 이뤄나가는 구조이다.


Django의 구성 요소

 

  • manage.py
    • 장고를 실행하게 하는 파일
  • (proj_name) file
    •  __init__.py
      • proj_name file 디렉토리가 파이썬 모듈로써 인식되게 하는 역할
    • asgi.py / wsgi.py
      • 서버에서 실제 장고 프로젝트를 가동할 때 다루게 되는 곳
    • settings.py
      • 전반적 python django 프로젝트에 설정 사항을 반영하는 파일
      • 내부 구성 요소
        • SECRET_KEY
          • 장고 프로젝트에 대한 secret key
        • DEBUG 
          • True면 파이썬 프로젝트를 디버깅 모드로 실행
        • ALLOWED HOST 
          • 리스트 내 주소를 넣어 어떤 주소에 대해 장고 프로젝트에 접근할 수 있는지 결정하게 됨
        • INSTALLED_APPS / MIDDLEWARE
          • 여러 앱 / 미들웨어 중 어떤 것을 설치하게 되는지 확인할 수 있다
        • ROOT_URLCONF
          • 프로젝트에서 URL 관리를 어떤 모듈에서 진행할 것인지 담당
        • TEMPLATES
          • 실제 보는 화면에 관한 요소들이 담겨 있는 부분
        • WSGI-APPLICATION
          • 파이썬 상에서 웹 서버와 소통하는 데 필요한 어플리케이션 담당
        • DATABASE
          • 프로젝트 상에서 다루게 되는 여러 자료들을 저장하는 곳을 담당
        • AUTH_PASSWORD_VALIDATORS
          • 패스워드 관리
        • STATIC_URL
          • 정적 파일들(CSS, JavaScript, Images)을 어느 폴더에 담아둘지 결정
    • urls.py
      • URL 관리

App의 구성요소

 

  • admin.py
    • admin 페이지에 관한 부분
  • apps.py 
    • 앱에 관한 설정에 관한 부분
  • models.py
    • 앱에 쓰일 데이터베이스 스키마 등을 클래스 형태로 작성해줄 수 있다.
  • tests.py
    • 프로젝트의 테스트 케이스에 대해 설명
  • views.py
    • 앱에서 view를 어떻게 관리해줄 것인가에 대한 코드 작성 가능

Django의 MVT Pattern

 

그림 출처 : www.onlinetutorialspoint.com/django/django-mvt-basic-application-example.html

 

어떤 User가 있을 때 그 User가 Request를 보낸다. Django(server) 입장에선 이 Request를 URL(urls.py)이 인식하게 된다. 즉, 어떤 경로에 대한 요청이 들어갔는지 체크한다.

들어온 경로가 urls.py에 있다면 View(view.py)에 보내게 된다. view에는 들어온 요청을 처리하는 logic이 담겨있다.

이 요청을 처리하다 보면 데이터베이스를 처리하는 경우도 생길텐데 그 데이터베이스를 처리하는 부분은 Model이라는 부분이다. 장고는 DB를 ORM 구조(Object Related Model)로 관리한다.

응답하는 과정에서 특정 웹페이지를 보여줘야 하는 경우도 생길텐데 이는 Template에서 관리한다. 이는 html 파일등 + template 언어로 전달해줄 수 있다. template 언어를 이용하면 view에서 처리한 변수들을 html에 임베딩해서 함께 출력해줄 수 있다.


Django 프로젝트 시작하기

 

장고 프로젝트 생성

 

django-admin startproject <proj_name>

 

서버 가동

 

python manage.py runserver

 

django App 만들기

 

django-admin startapp <app_name>

 

※ 이 때 프로젝트 폴더로 이동한 후에 만들어 주어야 한다! (cd proj_name) (manage.py있는 폴더에서 만들어 주면 됨)

 

Django 관리자 계정 생성

 

python manage.py migrate => default로 만들어진 데이터베이스들에 대한 여러 정보가 반영되게 된다.

python manage.py createsuperuser

 

http://127.0.0.1:8000/admin/에서 관리자 계정으로 로그인을 하면 추가한 데이터베이스에 대해서도 관리가 가능해진다.


View로 Request Handling 하기

 

정말 간단한 View를 만들어보자

 

view.py

 

from django.shortcuts import render, HttpResponse # HttpResponse 모듈 추가

# Create your views here.
def index(request):
    return HttpResponse('Hello World!')

 

urls.py

 

from homepage.views import index # 실행할 함수 명시

urlpatterns = [
    path('admin/', admin.site.urls), # 127.0.0.1/admin/
    path('', index) # 127.0.0.1/ URL 요청이 들어오면 index 함수를 실행하라.
]

 

settings.py

 

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'homepage' # 생성한 앱 이름을 꼭 추가해주어야 한다. 그래야 앱으로 인식하여 실행을 해준다.
]

 

실행 결과

 

 


Template으로 보여줄 화면 구성하기

 

render -> html 문서를 따로 관리해주는 함수

 

render 인자 -> render ( request, '.html', {} )

 

생성한 어플 폴더 내에 template 폴더를 생성 후 그 안에

index.html 파일을 생성한 후 이를 django에 반영시켜보자 

 

visual studio code에서 ! + tab을 눌러주면 기본 html 규격 자동완성이 된다. 편리함!

 

index.html

 

<!DOCTYPE html>
<html>
    <head>
        <title>Python django example</title>
    </head>
    <body>
        <!--열린 태그--> 
        <h1>
            Title
        </h1>
        <!--닫힌 태그-->
        <p>나는 능이버섯이당</p>
    </body>
</html>

 

views.py

 

from django.shortcuts import render

def index(request):
    return render(request, 'index.html', {})

 

settings.py

 

import os

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(BASE_DIR,'hompage','template')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

 

실행 결과

 


고정된 자료가 아닌 동적으로 변화하는 자료 보여주기

 

views.py

 

def index(request):
    number = 10
    return render(request, 'index.html', {"my_num":number})

 

index.html

 

<!DOCTYPE html>
<html>
    <head>
        <title>Python django example</title>
    </head>
    <body>
        <!--열린 태그--> 
        <h1>
            Title
        </h1>
        <!--닫힌 태그-->
        <p>나는 능이버섯이당</p>
        <!-- Template language -->
        <p>{{ my_num }}</p>
    </body>
</html>

 

실행 결과

 

 

 

{{}}라는 템플릿 문법을 이용해 직접적으로 데이터를 넣어줄 수 있다.


템플릿 필터 적용

 

views.py

 

def index(request):
    name = "Michael"
    return render(request, 'index.html', {"my_name":name})

 

index.html

 

<!DOCTYPE html>
<html>
    <head>
        <title>Python django example</title>
    </head>
    <body>
        <!--열린 태그--> 
        <h1>
            Title
        </h1>
        <!--닫힌 태그-->
        <p>나는 능이버섯이당</p>
        <!--Template language-->
        <!--Template filter | -->
        <p>{{ my_name|length }}</p>
        <p>{{ my_name|upper }}</p>
    </body>
</html>

 

실행 결과

 


Template tag

 

views.py

 

def index(request):
    # return HttpResponse('<h1>Hello World!<h1>')
    nums= [1,2,3,4,5]
    return render(request, 'index.html', {"my_list":nums})

 

index.html

 

<!DOCTYPE html>
<html>
    <head>
        <title>Python django example</title>
    </head>
    <body>
        <!--열린 태그--> 
        <h1>
            Title
        </h1>
        <!--닫힌 태그-->
        <p>나는 능이버섯이당</p>
        {% for element in my_list %}
            {%if not element|divisibleby:"2"%}
                <p>{{element}}</p>
            {%endif%}
        {% endfor %}
    </body>
</html>

 

실행 결과

 

 

EDA ( Exploratory Data Analysis )

 

EDA - Heart Attack Analysis

 

데이터 다운로드 : www.kaggle.com/rashikrahmanpritom/heart-attack-analysis-prediction-dataset/code

 

Heart Attack Analysis & Prediction Dataset

A dataset for heart attack classification

www.kaggle.com

1. 분석의 목적과 변수 확인

 

목적 : 심장마비 가능성이 높은 사람들의 특징이 무엇일까?

 

변수

 

  • age
    • 나이
  • sex
    • 성별
  • cp
    • 가슴 통증 종류
  • trtpbs
    • 혈압
  • chol
    • BMI 센서를 통해 가져온 콜레스테롤
  • fbs
    • 공복 혈당
  • restecg
    • 휴식 심전도 결과
  • thalachh
    • 최대 심박수 달성
  • exng
    • 운동으로 인한 협심증
  • oldpeak
    • 이전 피크
  • output
    • 심장마비 가능성 적으면 0, 많으면 1

 

 

2. 데이터 전체적으로 살펴보기 

 

 

 

이번 데이터는 운 좋게도 결측치가 하나도 없음을 알 수 있다. 결측치에 대한 처리 부분은 생각하지 않아도 되겠다.ㅎㅎ

 

3. 데이터의 개별 속성 파악하기

 

(1) 심장 마비 가능성이 높은 사람 수 확인

 


(2) 가슴 통증 유형에 따른 심장마비 가능성이 높은 인원 파악

 

 

 

=> 비정형 협심증, 비 협심증, 무증상 환자는 심장마비가 올 가능성이 더 높다는 것을 알 수 있다.


(3) 나이에 따른 심장 마비 가능성 환자 확인

 

 

=> 오히려 40대-50대 비교적 젊은 환자들이 심장 마비 가능성이 더 높음을 확인할 수 있다.


(4) 성별에 따른 심장 마비 가능성 환자 확인

 

 

=> 남성이 여성에 비해 심장 마비 가능성이 더 높은 것을 확인할 수 있었다.

 

(5) 최대 심박수에 따른 심장 마비 가능성 환자 확인

 

 

=> 최대 심박수가 150을 초과하는 순간부터 심장 마비 가능성이 더 높아지는 것을 확인할 수 있다.

 

(6) 콜레스테롤에 따른 심장 마비 가능성 환자 확인

 


=> 의외로 콜레스테롤은 심장 마비 가능성에 큰 영향을 끼치지 않는다는 것을 확인할 수 있었다. 

 

4. 데이터 복합 요소에 대해 살펴보기

 

(1) 나이 + 콜레스테롤에 따른 심장 마비 가능성 확인

 


 => 나이와 콜레스테롤에 연관이 없고, 심장 마비 가능성 또한 연관이 없음을 알 수 있었다....

 

(2) 나이 + 성별에 따른 심장 마비 가능성 확인

 

 

=> 남성과 여성 둘 다 고령보다는 낮은 연령에서 더 심장 마비 가능성이 높은 환자가 많은 것으로 나타났다.

 

 

이외에 다른 좋은 가설이나 내용 중 틀린 부분이 있다면 언제든지 댓글 달아주셔서 피드백주시면 감사하겠습니다.

EDA ( Exploratory Data Analysis )

 

데이터 그 자체만으로 인사이트를 얻어내는 접근법 => 시각화 / 통계적 수치 / numpy, pandas

 

EDA process

 

  1. 분석의 목적과 변수 확인
    • 왜 분석하려는지 목적을 명확히 하고, column들을 확인한다.
  2. 데이터 전체적으로 살펴보기
    • 상관관계 파악
    • NA가 없는지 파악
    • 데이터 사이즈 파악
  3. 데이터의 개별 속성 파악하기

EDA with Example - Titanic

 

데이터 다운로드 : www.kaggle.com/c/titanic/data?select=train.csv

 

Titanic - Machine Learning from Disaster

Start here! Predict survival on the Titanic and get familiar with ML basics

www.kaggle.com

 

  1. 분석의 목적과 변수 확인

 

목적 : 살아남은 사람들은 어떤 특징을 갖고 있었을지 확인

 

변수

 

  • survival
    • 생존했는지의 여부
  • pclass
    • 1등급석 / 2등급석 / 3등급석
  • sex
    • 남자 / 여자
  • Age
    • 연도기준 나이
  • sibsp
    • 형제 자매나 배우자가 몇 명이 타고 있었는가
  • parch
    • 부모와 자식이 얼마나 타고 있었는가
  • ticket
    • 티켓 번호
  • fare
    • 탑승객이 얼마를 내고 탔는가
  • cabin
    • 승무원 번호
  • embarked
    • 항구의 정보
    • C / Q / S의 범주형 자료

 

2. 데이터 전체적으로 살펴보기 

 

dataframe.describe()를 통해 수치형 데이터에 대한 요약을 확인할 수 있다.

 

 

dataframe.corr()을 통해 상관관계를 알 수 있다.

 

 

그러나, 상관성은 인과성이 아니다! 상관관계가 유의미하게 나왔다고 해서 반드시 둘 사이의 인과성이 존재한다고 말할 수는 없다

 

dataframe.isnull()을 통해 결측치를 확인할 수 있다.

 

 

결측치에 대한 부분은 어떻게 바라볼지에 대해서도 생각해야하기 때문에 결측치에 대한 처리도 중요하다.

 

3. 데이터의 개별 속성 파악하기

 

(1) 생존자와 사망자 수 확인

 

value_counts() 이용

 

 

sns.countplot() 이용

 


(2) Pclass에 따른 인원 파악

 

groupby 후 count()

 

 

각 Pclass 마다의 생존자 인원은?

 

각 Pclass 마다 생존 비율은?

 

 

히트맵을 통해서도 확인하기

 

 

=> Pclass가 좋은 등급이면 등급일수록 생존 확률이 높구나!


(3) Sex

 

성별에 따른 생존자 수 확인

 

 

catplot()을 이용하기

 

=> 남성보다 여성의 생존자가 더 많은 것을 확인할 수 있다.


(4) Age (결측치 존재)

 

fig, ax = plt.subplots(1, 1, figsize=(10, 5))
sns.kdeplot(x=titanic_df[titanic_df.Survived == 1]['Age'], ax=ax)
sns.kdeplot(x=titanic_df[titanic_df.Survived == 0]['Age'], ax=ax)

plt.legend(['Survived','Dead'])

plt.show()

 

 

=> 약자(어린이, 노인)의 경우 더 많이 생존한 것을 확인할 수 있다.

 

4. 데이터 복합 요소에 대해 살펴보기

 

(1) 성별 + Pclass vs Survived

 

sns.catplot(x="Pclass", y="Survived", hue = "Sex", kind="point", data = titanic_df)
plt.show()

 

=> Pclass가 1과 2이면서 여성이었던 사람들은 Survived의 추정치가 높았고, Pclass가 2와 3이면서 남성이었던 사람들은 Survived의 추정치가 0.2정도로 매우 낮은 것을 확인할 수 있다.

 

(2) Age + Pclass

 

## Age graph with Pclass

titanic_df['Age'][titanic_df.Pclass == 1].plot(kind='kde')
titanic_df['Age'][titanic_df.Pclass == 2].plot(kind='kde')
titanic_df['Age'][titanic_df.Pclass == 3].plot(kind='kde')

plt.legend(['1st class','2nd class','3rd class'])
plt.show()

 

 

=> class가 더 높은 class일수록 나잇대가 높아진다는 것을 확인할 수 있다.

'AI > KDT 인공지능' 카테고리의 다른 글

[05/17] Web Application with Django  (0) 2021.05.17
[05/12] EDA mini project  (0) 2021.05.12
[05/11] AWS를 활용한 인공지능 모델 배포  (0) 2021.05.11
[05/10] Web Application with Flask  (0) 2021.05.09
[05/06] Matplotlib  (0) 2021.05.06

클라우드 기초

 

클라우드 컴퓨팅 서비스를 제공받기 전에는 서비스 제공자는 서비스 호스팅에 필요한 다음과 같은 모든 것들을 직접 구축하였다.

 

  • 데이터 센터 (물리적 공간)
  • 서버, 저장소
  • 네트워크 방화벽, 보안
  • 운영체제, 기타 개발도구
  • 전기, 온도, 습도 관리
  • 운영 / 관리 인력

그러나 서버를 직접 구축하고 운영하는 자원과 인력 비용이 크고 운영 상황의 변화에 능동적 대응이 어려웠다.

그래서 회사나 조직이 직접 모든 것을 구축하고 운영하지 않도록 도와주는

IDC(Internet Data Center)가 등장하였다.

IDC는 서버 운영에 필요한 공간, 네트워크, 유지 보수 등의 서비스를 제공한다.

IDC 입주자가 직접 서버를 구입해 들어오기도 하지만 불필요한 자원 혹은 유휴 자원이 발생하기 때문에 IDC에서 직접 서버를 임대해주기도 한다.

 

서버 임대를 통해 자원을 효율적으로 이용하고 비용을 줄일 수 있었지만 대부분 IDC의 서버 임대는 계약을 통해 일정 기간 임대를 하는 유연성이 떨어지는 구조였다.

 

인터넷 사용자가 크게 증가하고, 다양한 서비스를 제공하게 되며 필요한 때에 필요한 만큼 서버를 증설하길 원하는 온디맨드의 수요가 증가하게 된다.

 

ex)

사용자 접속량이 늘어나 컴퓨팅 수요가 증가할 때는 오토 스케일링이 필요

평상 시에 사용하지 않는 유휴 자원은 비용에서 빼주어야 한다

필요한 시점에서 바로 사용할 수 있게 운영체제나 필요한 소프트웨어는 미리 설치해주도록 한다

 

그러면서 등장하게 된 것이 바로 Cloud Computing이다.

Cloud Computing은 "인터넷 기반 컴퓨팅의 일종"이라고 부른다.

2006년 아마존이 클라우드를 통한 저장공간 및 연산 자원 제공 서비스인 S3와 EC2를 개시하며 본격적인 클라우드 컴퓨팅 시대가 개막이 되었다.

 

AWS는 클라우드 컴퓨팅을 클라우드 서비스 플랫폼에서 컴퓨팅 파워, DB 저장공간, 애플리케이션 및 기타 IT 자원을 필요에 따라 인터넷을 통해 제공하고 사용한 만큼만 비용을 지불하는 것으로 정의하였다.

 

4차 산업혁명 시대에서는 빅데이터의 수집, 저장, 분석을 위한 방대한 컴퓨팅 자원이 필요하고, 인공지능 개발을 위한 고성능 컴퓨터가 필요한데 이 모든 것을 별도로 구입하지 않고도 적은 비용으로 빠르게 필요한 IT 환경 마련을 가능하게 해주어 클라우드 컴퓨팅이 더더욱 중요시되고 있다.

 

클라우드 컴퓨팅은 다음과 같은 장점을 갖는다.

 

  • 속도 - 주문형 셀프서비스
    • 클라우드 제공자와 별도의 커뮤니케이션 없이 원하는 클라우드 서비스를 바로 이용 가능하게 한다.
  • 접근성
    • 인터넷을 통해 사용자의 위치, 시간과 관계없이 어떤 디바이스로도 접근이 가능하다.
  • 확장성
    • 갑작스러운 이용량 증가나 변화에 신속하고 유연하게 추가 확장이 가능하다.
  • 생산성
    • 하드웨어, 소프트웨어 설치에 들어가는 시간과 비용 절감으로 핵심업무에 집중할 수 있게 해준다.
  • 보안, 안정성
    • 클라우드 공급자가 전체적으로 보안이나 안정성에 대해 준비해준다.
  • 측정가능성
    • 분초 단위로 사용자가 클라우드 서비스를 사용한만큼만 계량하여 과금하여 효율적인 소비가 가능하다.

 

클라우드 컴퓨팅은 구축 및 배포 유형에 따라 세 가지 형태로 구분한다.

 

  • 프라이빗 (Private) 
    • 고객이 자체 데이터센터에서 직접 클라우드 서비스를 구축하는 형태이다.
    • 내부 계열사나 고객에게만 제공하여 인프라 확충은 쉬우나 IT 기술 확보가 어려운 단점이 있다.
    • 보안이 좋고 커스터마이제이션이 가능하며 글로벌 클라우드 사업자가 IT 기술만 패키지형태로 판매하기도 한다.
  • 퍼블릭 (Public)
    • 서비스 유지를 위한 모든 인프라와 IT 기술을 클라우드에서 사용한다.
    • AWS, GCP, Azure와 같은 외부 클라우드 컴퓨팅 사업자가 IT 자원을 소유하고 인터넷을 통해 제공한다.
    • IT 관리 인력이나 인프라 구축 비용이 없는 경우에 유용하다.
  • 하이브리드 (Hybrid)
    • 고객의 핵심 시스템은 내부에 두면서 외부의 클라우드를 활용하는 형태이다.
    • IT 기술은 클라우드에서 받고 서비스 유지를 위한 인프라는 고객의 것을 혼용한다.
    • 퍼블릭의 경제성과 프라이빗의 보안성을 모두 고려한 형태이다.

 

클라우드 서비스 제공 방식에 따라 모델이 다음과 같이 달라지게 된다.

 

그림 출처 : www.whatap.io/ko/blog/9/

클라우드 서비스 제공 모델

 

이를 자동차로 예를 들면 다음과 같다.

 

  • On-Premises
    • Owning a car
    • 차 관리부터 운전, 목적지 결정까지 모든 것을 차주인 내가 해야 한다.
  • IaaS
    • Leasing a car
    • 운전만 직접 하고, 목적지만 정하면 된다.
  • PaaS
    • Taking a taxi
    • 목적지만 정하면 된다.
  • SaaS
    • Going by bus
    • 버스가 알아서 정해져있는 목적지까지 가준다.

AWS를 사용할 환경을 세팅하여 보자

 

ec2 생성

 

1. AMI 선택

 

딥러닝 AMI가 설치된 EC2를 생성해 필요 개발 환경 사전 세팅 

 

검색 부분에 Deep learning 입력

 

 

2. 인스턴스 유형 선택 & 보안 그룹 설정

 

프리티어인 t2.micro 또는 computing에 최적화된 가장 저렴한 c5.large 인스턴스 유형 선택 후 "다음 : 인스턴스 세부정보 구성" 클릭

 

"단계 6 : 보안그룹 구성"이 나올 때까지 계속 다음 클릭

 

원격으로 API 서버에 접근 / 호출할 수 있도록 사용자 설정 포트를 새로 생성 (ex. 포트범위 : 5000, 소스 0.0.0.0/0) 후 검토 및 시작

 

 

3. 키 페어 생성 & 인스턴스 시작 검토

 

보안을 위한 키 페어 생성을 위해 키 페어 이름을 입력하고 "키 페어 다운로드"를 클릭해 키 페어 다운로드

 

다운로드한 키 페어는 이후 인스턴스에 접속하기 위해 필요

 

인스턴스 시작

 


탄력적 IP 설정

 

1. 탄력적 IP 생성

 

인스턴스를 중지 또는 종료 후 다시 시작하거나 생성하게 되면 기존 퍼블릭 IP가 변경됨

 

퍼블릭 IP를 고정으로 사용하고 싶을 때 탄력적 IP 주소를 할당할 수 있으나 추가 과금 발생

 

탄력적 IP 생성을 위해 "탄력적 IP 주소 할당" 클릭

 

 

 

2. 탄력적 IP를 인스턴스에 연결

 

 

3. 연결 확인

 


VS Code로 환경 테스트

 

1. 인스턴스 연결 초기화(Initialization)

 

다운로드 받은 키 페어가 있는 위치에서 AWS 가이드에 따라 진행

 

Mac OS 또는 Linux는 자체 터미널로 바로 수행 가능

 

Windows는 OpenSSH 클라이언트 설치 후 CMD 또는 PowerShell에서 진행 가능

 

 

2. 원격 접속 및 개발을 위한 VS Code 플러그인 설치

 

 

3. 인스턴스에 접속

 

Remote-SSH : Connect to Host 선택

 

ssh -i "암호키" ubuntu@public-ip-address 입력

 

Select SSH configuration file

 

4. 터미널 열고 환경 확인

 

터미널에서 "conda env list"로 세팅되어 있는 가상환경 확인

 

(Winodws 환경에서 실습 실패....)


API to serve ML model

 

Architecture of API to serve ML model

 

AWS EC2와 Python Flask 기반 모델 학습 및 추론을 요청/응답하는 API 서버 개발

 

그림 출처 : 프로그래머스 스쿨

 

사용자는 기계와 소프트웨어를 제어하기 위해 인터페이스를 정해진 매뉴얼에 따라 활용해 원하는 경험을 획득한다.

인터페이스는 상호 합의된 매뉴얼에 따라 적절한 입력을 받아 기대되는 출력을 제공할 수 있어야 한다.

 

API(Application Programming Interface)란? 기계와 기계, 소프트웨어와 소프트웨어 간 커뮤니케이션을 위한 인터페이스를 의미한다.

 

노드와 노드 간 데이터를 주고 받기 위한 인터페이스로, 사전에 정해진 정의에 따라 입력이 들어왔을 때 적절한 출력을 전달해야 한다.

 

RESTful API는 REST 아키텍처를 따르는 API로, HTTP URI를 통해 자원을 명시하고 HTTP Method를 통해 필요한 연산을 요청하고 반환하는 API를 지칭한다.

RESTful API는 데이터나 정보의 교환/요청 등을 위한 인터페이스를 REST 아키텍처를 따라 구현한 API이다.

 

ML/DL model inference

 

일반적으로 데이터 값을 담아 요청하고 모델이 추론한 결과에 대한 return을 json 형태로 보통 반환하도록 설계한다.

RESTful API는 요청 메시지만 봐도 어떤 내용으로 되어있는지 알 수 있도록 표현된다. 즉, 메세지만 봐도 object를 detect하는 API인지 Pose estimation의 API인지 등 모델의 종류를 대략적으로 파악이 가능하고, 어떤 정보들을 제공받을 수 있는지 알 수 있다.

 

문제정의, 데이터 준비, 모델 학습 및 검증, 모델 배포, 모니터링 등의 과정을 통해 실제 서비스에 기계학습 모델을 적용할 수 있다.

 

학습된 모델을 REST API 방식으로 배포하기 위해선 학습된 모델의 Serialization과 웹 프레임워크를 통해 배포 준비가 필요하다.

모델을 Serving할 때는 학습 시 데이터 분포나 처리 방법과의 연속성 유지가 필요하며, 모델을 배포하는 환경에 따라 다양한 Serving Framework를 고려해 활용해야 한다.

 

Serialization이란? 학습된 모델의 재사용 및 배포를 위해 저장하고 불러오는 것이다. 

Serialization을 통해 ML/DL model object를 disk에 write하여 어디든 전송하고 불러올 수 있는 형태로 변환하고,

De-Serialization을 통해 Python 혹은 다른 환경에서 model을 불러와 추론/학습에 사용한다.

모델을 배포하는 환경을 고려해 환경에 맞는 올바른 방법으로 Serialization을 해야 De-serialization이 가능하다.

 

모델은 단순히 Feature Engineering 과정을 통해 입력한 데이터를 Feature의 형태로 반환하여 준다. 보통 Feature는 숫자 형태로 조합되어 있는데 결과 또한 수치적 형태기 때문에 API 서비스로 제공을 할 때는 결과값에 대한 정보를 Labeling하거나 결과에 대한 후처리 작업을 해야한다. 이러한 일련의 과정을 Handler(후처리 뿐만 아니라 초기화, 전처리 등도...)를 통해 수행하도록 해준다.

 

딥러닝 모델의 안정적인 Serving을 위해선 Tensorflow serving, TrochServe, TensorRT같은 프레임워크를 사용하는 것이 일반적이다. (전용 serving tool) 대용량 데이터 배치처리와 딥러닝 모델의 활용이 늘며 multi node, multi GPU 환경에서의 안정적인 모델 서빙을 위함이다. 

 

Flask와 같은 웹프레임워크는 클라이언트로부터 요청을 처리하기 위해 주로 사용한다. (외부 통신)

별도의 모델 추론을 위한 API 서버를 운용해 내부 혹은 외부 통신을 통해 예측/추론값을 반환한다.


Serialization & De-serialization

 

실제로 모델을 배포해보자.

 

# 아나콘다 가상환경 실행

conda activate pytorch_p36

# template 소스코드 다운로드

git clone https://github.com/sackoh/kdt-ai-aws
cd ./kdt-ai-was

# 필요 라이브러리 설치

pip install -r requirements.txt

 

사전 준비한 코드를 실행해 모델 학습 및 저장

 

python train_ml.py

 

serialization code 확인

 

def serialization(model, vectorizer):
    import joblib
    os.makedirs('model', exist_ok=True)
    joblib.dump(vectorizer, 'model/ml_vectorizer.pkl')
    logger.info(f'Saved vectorizer to `model/ml_vectorizer.pkl`')
    joblib.dump(model, 'model/ml_model.pkl')
    logger.info(f'Saved model to `model/ml_model.pkl`')

 

joblib 패키지를 통해 model을 지정한 경로에 저장한 것을 확인할 수 있다.

 

de-serialization code 확인

 

저장된 모델을 불러와 특정 입력 값에 대한 예측을 수행하게 된다.

 

  1. 터미널 환경에서 python 또는 ipython, jupyter notebook 실행
  2. 아래 예제 코드 테스트하여 de-serialization 확인
# De-serialization
import joblib
model = joblib.load('model/ml_model.pkl')
vectorizer = joblib.load('model/ml_vectorizer.pkl')

# Test loaded model and vectorizer
text = '재미있는 영화입니다.'

model_input = vectorizer.transform([text])
print(model_input.asformat('array'))
# <1x100000 sparse matrix of type '<class 'numpy.int64'>' with 2 stored elements in Compressed Sparse Row format

model_output = model.predict_proba(model_input)
print(model_output)
# array([0.02610797, 0.97389203])
model_output = model_output.argmax(axis=1)
print(model_output)
# array([1])
id2label = {0 : 'negative', 1 : 'positive'}
print(f'sentiment : {id2label[model_output[0]]}')
# sentiment : positive

 

Serialization과 De-serialization 방법은 동일해야 한다.

joblib으로 serialization을 하고 pickle로 불러올 수 없다.


Inference를 위한 model handler 개발

 

Skeleton of model handler to serve model

class ModelHandler:
	def __init__(self):
    	self.id2label = {0: 'negative', 1: 'positive'}
        
    def _clean_text(self, text): # data 전처리 함수
    	pass
        
class MLModelHandler(BaseHandler):
	def __init__(self):
    	super().__init__()
        self.initialize()
    
    def initialize(self, **kwargs):
    	# De-serializing model and loading vectorizer
        import joblib
        self.model = joblib.load('model/ml_model.pkl')
        self.vectorizer = joblib.load('model/ml_vectorizer.pkl')
    
    def preprocess(self, text):
    	# cleansing raw text
        model_input = self._clean_text(text)
        
        # vectorize cleaned text
        model_input = self.vectorizer.transform(model_input)
        return model_input
    
    def inference(self, data): #불러온 모델에 대해 추론
        # get predictions from model as probabilities
    	model_output = self.model.predict_proba(model_input)
        return model_output
    
    def postprocess(self, data):
    	# process predictions to predicted label and output format
        predicted_probabilities = model_output.max(axis=1)
        predicted_ids = model_output.argmax(axis=1)
        predicted_labels = [self.id2label[id_] for id_ in predicted_ids]
        return predicted_labels, predicted_probabilities
    
    def handle(self, data): #일련의 과정을 handle. api에서는 이 부분만 call하게 된다.
        # do above processes
    	model_input = self.preprocess(data)
        model_output = self.inference(model_input)
        return self.postprocess(model_output)
        
        
# handler 수행 (cmd)

from model import MLModelHandler
ml_hanlder = MLModelHandler()

text = ["정말 재밌는 영화다.", "정말 재미없다."]
result = ml_handler.handle(text)
print(result)
# (['positive', 'negative'], array([0.98683823, 0.79660478])

 

  • initialize()
    • 데이터 처리나 모델, configuration 등 초기화
      • Configuration 등 초기화
      • (Optional) 신경망 구성하고 초기화
      • 사전 학습한 모델이나 전처리기 불러오기 (De-serialization)
        • 모델을 불러올 땐 전역변수로 불러와야 한다. inference 할 때마다 모델을 불러오도록 하면 그로 인해 발생하는 시간이나 자원 등의 낭비 발생
        • 일반적으로 요청 처리 전 모델을 불러 둔다.
  • preprocess()
    • Raw input을 전처리 및 모델 입력 가능 형태로 변환
      • Raw input 전처리
        • 데이터 cleansing의 목적과 학습된 모델 학습 당시 scaling이나 처리 방식과 맞춰주는 것이 필요하다.
      • 모델에 입력가능한 형태로 변환
        • vectorization, converting to id 등의 작업
  • inference()
    • 입력된 값에 대한 예측 / 추론
      • 각 모델의 predict 방식으로 예측 확률분포 값 반환
  • postprocess()
    • 모델의 예측값을 response에 맞게 후처리 작업
      • 예측된 결과에 대한 후처리 작업
      • 보통 모델이 반환하는 건 확률분포와 같은 값이기 때문에 response에서 받아야 하는 정보로 처리하는 역할을 많이 함.
  • handle()
    • 요청 정보를 받아 적절한 응답 반환
      • 정의된 양식으로 데이터가 입력됐는지 확인
      • 입력 값에 대한 전처리 및 모델에 입력하기 위한 형태로 변환
      • 모델 추론
      • 모델 반환값의 후처리 작업
      • 결과 반환

Flask 기반 감성분석 API 개발

 

네이버 영화리뷰 감성분석 개요

 

나이브베이지안 모델과 딥러닝 모델로 학습한 두 개의 모델을 서빙하며 0은 부정, 1은 긍정 의미.

학습에 사용한 데이터는 박은정 님이 공개한 NSMC 데이터

 

감성분석 API 개발 방향

 

영화 리뷰 텍스트 POST predict 요청

 

ex) 영화가 재미없어요.

 

 

do_fast 요청 정보에 따라 ML 또는 DL 모델로 예측

 

 

감성분석 결과 반환

 

ex)

 

{ "text" : "영화가 재미없어요.",

"label" : "negative",

"confidence" : 0.89231 } 

 

 

API 정의

 

key : value 형태의 json 포맷으로 요청을 받아 text index 별로 key : value로 결과를 저장한 json 포맷으로 결과 반환

 

POST 방식으로 predict 요청

do_fast true로 할 경우 빠른 추론이 가능한 ML 모델로 추론,

false의 경우 추론 속도는 비교적 느리지만 정확도가 높은 DL 모델로 추론.

 

Add Deep Learning model handler

 

(앞에서 만든건 Machine Learning model handler)

 

사전 학습한 딥러닝 모델을 활용해 머신러닝 모델 handler와 동일한 입력에 대해 동일한 결과를 반환하는 handler 개발

사전 학습한 모델은 Hugging Face에서 제공하는 외부 저장소에서 다운로드 받아 불러옴

 

import torch

class DLModelHandler(ModelHandler):
    def initialize(self, ):
        # De-serializing model and loading vectorizer
        from transformers import AutoTokenizer, AutoModelForSequenceClassification
        self.model_name_or_path = 'sackoh/bert-base-multilingual-cased-nsmc'
        self.tokenizer = AutoTokenizer.from_pretrained(self.model_name_or_path)
        self.model = AutoModelForSequenceClassification.from_pretrained(self.model_name_or_path)
        self.model.to('cpu')

    def preprocess(self, text):
        # preprocess raw text
        model_input = self._clean_text(text)

        # vectorize cleaned text
        model_input = self.tokenizer(text, return_tensors='pt', padding=True)
        return model_input

    def inference(self, model_input):
        with torch.no_grad():
            model_output = self.model(**model_input)[0].cpu()
            model_output = 1.0 / (1.0 + torch.exp(-model_output))
            model_output = model_output.numpy().astype('float')
        return model_output
    
    def postprocess(self, data):
    	# process predictions to predicted label and output format
        predicted_probabilities = model_output.max(axis=1)
        predicted_ids = model_output.argmax(axis=1)
        predicted_labels = [self.id2label[id_] for id_ in predicted_ids]
        return predicted_labels, predicted_probabilities
    
    def handle(self, data): 
    	model_input = self.preprocess(data)
        model_output = self.inference(model_input)
        return self.postprocess(model_output)

 

Unittest model handlers

 

개발한 model handler가 원했던 대로 동작하는지 unittest

 

(terminal)

 python -m unittest -v test_model_handler.py

 

Flask API 개발 & 배포

 

from flask import Flask, request, json
from model import MLModelHandler, DLModelHandler

app = Flask(__name__)

# assign model handler as global variable
ml_handler = MLModelHandler()
dl_handler = DLModelHandler()

@app.route("/predict", methods=["POST"])
def predict():
	# handle request and body
    body = request.get_json()
    text = body.get('text', '')
    text = [text] if isinstance(text, str) else text
    do_fast = body.get('do_fast', True)
    
	# model inference
    if do_fast:
    	predictions = ml_handler.handle(text)
    else:
    	predictions = dl_handler.handle(text)
    # predictions => (['positive', 'negative'], array([0.98683823, 0.79660478]))
    
	#response
    result = json.dumps({str(i): {'text' : t, 'label' : l, 'confidence' : c}
    					for i, (t, l, c) in enumerate(zip(text, predictions[0], predictions[1]))})
    return result


if __name__ == "__main__":
    app.run(host="0.0.0.0", port='5000', debug=True)

 

Test API on remote

 

원격에서 서버로 API에 요청하여 테스트 수행

 

host : EC2 인스턴스 생성 시 받은 퍼블릭 IP 주소 또는 직접 할당한 탄력적 IP 주소

port : EC2 인스턴스 생성 시 설정했던 port 번호 (ex. 5000)

 

(terminal)

curl -d '{"text" : ["영화 오랜만에 봤는데 괜찮은 영화였어", "정말 지루했어"], "use_fast" : false}' \
-H "Content-Type: application/json" \
-X POST \
http://host:port/predict
import requests
url = 'http://host:port/predict'
data = {"text" : ["영화 오랜만에 봤는데 괜찮은 영화였어", "정말 지루했어"], "use_fast" : false}
response = requests.post(url, json=data)
print(response.content)

 

'AI > KDT 인공지능' 카테고리의 다른 글

[05/12] EDA mini project  (0) 2021.05.12
[05/12] 데이터 씹고 뜯고 맛보고 즐기기 - EDA  (0) 2021.05.11
[05/10] Web Application with Flask  (0) 2021.05.09
[05/06] Matplotlib  (0) 2021.05.06
[05/05] 데이터 다루기 - Pandas  (0) 2021.05.05

+ Recent posts