4차 산업 혁명과 함께 각광을 받아 다양한 산업영역에서 법과 제도적인 규제의 완화와 함께 사용이 되어지고 있음
과거에는 인터넷 환경에서 서비를 제공하기 위해 서비스 제공자는 서비스 호스팅에 필요한 모든 것을 직접 구축
데이터 센터를 처음 구축할 때 서비스 아키텍처나 자원 예상 사용량 등을 고려해 구축
데이터 센터(물리적공간)
서버, 저장소
네트워크 방화벽, 보안
운영체제, 기타 개발 도구
전기, 온도, 습도 관리
운영/관리 인력
하지만 서버를 직접 구축하고 운영하는 자원과 인력 비용이 크고 운영 상황의 변화에 능동적으로 대응하기가 어려움
회사나 조직이 직접 모든 것을 구축하고 운영하지 않도록 도와주는 IDC 등장
서버 임대를 통해 자원을 효율적으로 이용하고 비용을 줄일 수 있었지만 대부분의 IDC의 서버 임대는 계약을 통해 일정 기간 임대를 하는 유연성이 떨어지는 구조
인터넷 사용자가 크게 증가하고 다양한 서비스를 제공하게 되면서 필요한 때에 필요한 만큼 서버를 증성하기 원하는 온디맨드 수요 증가
사용자 접속량이 늘어나 컴퓨팅 수요가 증가할 때는 오토 스케일링이 필요해요
평상시에 사용하지 않는 유휴 자원은 비용에서 빼주세요
필요한 시점에 바로 사용할 수 있게 운영체제나 필요한 소프트웨어는 미리 설치해주세요
클라우드라고 부르기도 하며 "인터넷 기반 컴퓨팅의 일종"
AWS는 클라우드 컴퓨팅을 클라우드 서비스 플랫폼에서 컴퓨팅 파워, DB 저장공간, 애플리케이션 및 기타 IT자원을 필요에 따라 인터넷을 통해 제공하고 사용한 만큼만 비용을 지불하는 것으로 정의
4차 산업혁명 시대에서 빅데이터의 수집, 저장, 분석을 위한 방대한 컴퓨팅 자원과 인공지능 개발을 위한 고성능 컴퓨터를 스타트업이나 중소기업이 처음부터 모든 것을 별도로 구입하지 않고도 적은 비용으로 빠르게 필요한 IT환경 마련 가능
클라우드 컴퓨팅은 속도, 접근성, 확장성, 생산성, 보안 및 안정성, 측정 가능성 등의 장점을 가짐
특히 인공지능 서비스 제공 시에 도커와 같은 가상화 기술을 통해 GPU 활용과 소프트웨어 설치 및 배포 등의 작업에 비용과 시간을 절감
클라우드 컴퓨팅은 구축 및 배포 유형에 따라 퍼블릭(Public), 프라이빗(Private), 하이브리드(Hybrid)의 세가지 형태로 구분
퍼블릭(Public)
프라이빗(Private)
하이브리드(Hybrid)
클라우드 서비스 제공 방식에 따라 IaaS, Paas, SaaS의 세가지 형태로 구분
On-Premises(Owning a car)
IaaS(Leasing a car): 인프라적인 측면만 클라우드를 사용
PaaS(Taking a taxi, 목적지만 선택) : 거기에 플랫폼적인 것도 클라우드를 통해 제공 받음
SaaS(Going by bus, 목적지도 정해짐) : 소프트웨어까지도 클라우드에서 제공 받음(Microsoft Office 365)
AWS, GCP, Azure, NCP 등 다양한 클라우드 벤드딜이 클라우드 서비스를 제공
AWS는 인프라와 기초 서비스 뿐만 아니라 사용자 니즈에 맞는 다양한 애플리케이션 서비스를 제공
Deep Learning AMI (Ubuntu 18.04) Version 50.0 AMI 를 이용하였다.
AWS계정을 만들어주고 새로운 인스턴스를 만들어 준뒤 kdt.pem 파일을 다운 받는다.
더 많은 AMI 에서 찾기 눌러서 강의 따라하기!
하기 전에 chmod 400 해야하는데 이 부분에서 윈도우는 cmd 창을 통해 바꾼다.
icacls.exe myec2.pem /reset
icacls.exe myec2.pem /grant:r %username%:(R)
icacls.exe myec2.pem /inheritance:r
visual studio code 설치
이미지의 위치에서 Remote - SSH, Remote Development 설치
각자의 코드는 다르다.
ssh -i "kdt.pem" ubuntu@자동 할당된 IP 주소
conda env list //로 확인
AWS EC와 Python Flask 기반 모델 학습 및 추론을 요청/응답하는 API 서버 개발
사용자는 기계와 소프트웨어를 제어하기 위해 인터페이스를 정해진 메뉴얼에 따라 활용하며 원하는 경험을 획득
Application Programming Interface의 약자로 기계와 기계, 소프트웨어와 소프트웨어 간의 커뮤니케이션을 위한 인터페이스를 의미
REST 아키텍처를 따르는 API로 HTTP URI를 통해 자원을 명시하고 HTTP Method를 통해 필요한 연산을 요청하고 반환하는 API를 지칭
- 사기꾼이 부정적인 방법으로 인출을 시도할때 인출을 위한 거래정보가 server로 넘어간다.
- sever는 모델이 필요로 하는 정보로 가공해서 인공지능에 넘겨주게 된다.
- 인공지능은 이를 분석해서 server에 결과를 제공한다.
- server는 이를 바탕으로 인출을 거부하게 된다.
문제정의, 데이터준비, 모델 학습 및 검증, 모델 배포, 검증, 모니터링 등의 과정을 통해 실제 서비스에 기계학습 모델을 적용
학습된 모델을 REST API 방식으로 배포하기 위해서 학습된 모델의 Serialization과 웹 프레임워크를 통해 배포 준비 필요
! 모든 과정은 연속성이 유지되어야 한다.
학습한 모델의 재사용 및 배포를 위해서 저장하고 불러오는 것
결과값은 확률적인 분포, 수치적인 값처럼 숫자의 형태로 나오기 때문에 결과값에 대한 후처리 작업을 해주어야 한다.
딥러닝 모델의 안정적인 serving을 위해 TensorFlow serving이나 TorchServe, TensorRT 같은 프레임워크를 사용하는 것이 일반적
# 아나콘다 가상환경 실행
conda activate pytorch_p36 #버전이 다를 수 있음
# template 소스코드 다운로드
git clone https://github.com.sackoh/kdt-ai-aws
cd ./kdt-ai-aws
# 필요한 라이브러리 설치
pip install -r requirements.txt
conda activate pytorch_p39
git clone https://github.com/sackoh/kdt-ai-aws
pip install -r requirements.txt
실습 진행을 위해 사전 준비한 코드를 실행하여 모델 학습 및 저장
Visual Studio에서 좌측상단의 탐색기를 실행 한뒤 Open Folder로 kdt-ai-aws를 열어준다.
#터미널 가서
conda activate pytorch_p37
#학습을 실행한다.
python train_ml.py
이미지를 보면 git에서 download 받고 train model을 하고 나온 정확도가 82.15%로 나온다. 그 후 전처리하고 저장하였다.
모델 폴더에 새로운 파일이 생성됐다.
# 모델을 관리할 수 있는, 전송하고 디스크에 쓸 수 있는
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`')
저장된 모델을 불러와 특정 입력 값에 대한 예측 수행
1. 터미널 환경에서 python 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'))
model_output = model.predict_proba(model_input)
model_output = model_output.argmax(axis=1)
id2label = {0: 'negative' , 1:'positive'}
print(f'sentiment : {id2label[model_output[0]]}')
먼저 joblib과 vectorizer를 확인한다.
(pytorch_p37) ubuntu@:~/kdt-ai-aws$ python
Python 3.7.10 | packaged by conda-forge | (default, Feb 19 2021, 16:07:37)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import joblib
# 각각의 위치에서 가져옴
>>> model = joblib.load('model/ml_model.pkl')
>>> model
MultinomialNB()
# vectorizer : 한글을 수치형으로 나타내기위해 음절단위로 쪼개고 음절을 몇 번 반복했는지 카운팅하여 벡터 형태로 나타낸 것
>>> vectorizer = joblib.load('model/ml_vectorizer.pkl')
>>> vectorizer
CountVectorizer(max_features=100000)
# 텍스트를 넣어 분석해보기
>>> text = '재미있는 영화입니다.'
>>> model_input = vectorizer.transform([text])
>>> model_input
# model_input에는 100000개의 값들이 들어있음
<1x100000 sparse matrix of type '<class 'numpy.int64'>'
with 2 stored elements in Compressed Sparse Row format>
>>> print(model_input.asformat('array'))
[[0 0 0 ... 0 0 0]]
# input을 모델에게 넣어 예측을 수행, model 안에는 다양한 메소드가 있는데 여기선 예측을 가져옴
>>> model_output = model.predict_proba(model_input)
# 모델은 확률분포의 형태로 나타남
>>> model_output
array([[0.02610797, 0.97389203]])
# 텍스트 문장이 긍정인지 부정인지 확인하기 위해 분석 결과를 후처리 작업함.
>>> model_output = model_output.argmax(axis=1)
>>> model_output
array([1])
>>> id2label = {0: 'negative' , 1:'positive'}
>>> print(f'sentiment : {id2label[model_output[0]]}')
sentiment : positive
joblib으로 serialization을 하고 pickle로 불러올 수는 없다.
handle()
#감성을 표현하는 API
class ModelHandler:
def __init__(self):
self.id2label = {0: 'negative', 1: 'positive'}
def _clean_text(self, text):
model_input = []
if isinstance(text, str):
cleaned_text = clean_text(text)
model_input.append(cleaned_text)
elif isinstance(text, (list, tuple)) and len(text) > 0 and (all(isinstance(t, str) for t in text)):
cleaned_text = itertools.chain((clean_text(t) for t in text))
model_input.extend(cleaned_text)
else:
model_input.append('')
return model_input
def handle(self, data):
# do above processes
# 전처리
model_input = self.preprocess(data)
# 모델을 불러와 인퍼런스를 통해 아웃풋을 냄
model_output = self.inference(model_input)
# 후처리 후 결과 반환
return self.postprocess(model_output)
initialize()
모델은 전역변수로 불러와야한다. 만약 inference를 할 때마다 모델을 불러오도록 한다면 그로 인해 발생하는 시간이나 자원 등의 낭비가 발생한다.
일반적으로 요청을 처리하기 전에 모델을 불러둔다.
def initialize(self, ):
# De-serializing model and loading vectorizer
import joblib
self.model = joblib.load('model/ml_model.pkl')
self.vectorizer = joblib.load('model/ml_vectorizer.pkl')
preprocess()
def preprocess(self, text):
# cleansing raw text
model_input = self._clean_text(text)
# vectorizing cleaned text
model_input = self.vectorizer.transform(model_input)
return model_input
inference()
def inference(self, data):
# get predictions from model as probabilities
model_output = self.model.predict_proba(model_input)
return model_output
postprocess()
def postprocess(self, model_output):
# process predictions to predicted label and output format
# 결과 값 중 가장 높은 확률 값을 뽑아옴
predicted_probabilities = model_output.max(axis=1)
# 뽑아온 확률 값이 어떤 id인지, 어떤 label에 해당하는지 뽑기
predicted_ids = model_output.argmax(axis=1)
# 뽑아온 값을 0,1 인데 api에서 사람이 이해할 수 있는 값으로 변환
predicted_labels = [self.id2label[id_] for id_ in predicted_ids]
return predicted_labels, predicted_probabilities
Testing ML model handler
>>> from model import MLModelHandler
>>> ml_handler = MLModelHandler()
>>> ml_handler
<model.MLModelHandler object at 0x7feeb38621d0>
>>> ml_handler.model
MultinomialNB()
>>> text = ['정말 재미있는 영화입니다.','정말 재미가 없습니다.']
>>> result = ml.handler.handle(text)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'ml' is not defined
>>> result = ml_handler.handle(text)
>>> result
(['positive', 'negative'], array([0.98689943, 0.79583852]))
네이버 영화리뷰 데이터로 학습한 ML/DL 모델을 활용해 감성분석 API 개발
AWS EC2와 Python Flask 기반 모델 학습 및 추론을 요청/응답하는 API 서버 개발
key : value 형태의 json포맷으로 요청을 받아 text index별로 key : value로 결과를 저장한 json포맷으로 결과 반환
사전 학습한 딥러닝 모델을 활용하여 머신러닝 모델 handler와 동일한 입력에 대해 동일한 결과를 반환하는 handler개발
사전 학습한 모델은 Hugging Face에서 제공하는 외부저장소에서 다운로드 받아 불러옴
import torch
def initialize(self, ):
from transformers import AutoTokenizer, AutoModelForSequenceClassification
self.model_name_or_path = 'sackoh/bert-base-multilingual-cased-nsmc'
self.AutoTokenizer = 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):
model_input = self._clean_text(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
#ML과 동일
def postprocess(self, model_output):
# 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):
# do above processes
model_input = self.preprocess(data)
model_output = self.inference(model_input)
return self.postprocess(model_output)
개발한 model handler가 원했던 대로 동작하는지 unittest
python -m unittest -v test_model_handler.py
model을 전역변수로 불러오고 요청된 텍스트에 대해 예측 결과를 반환하는 코드 입력
배포하기 위해
#결과로 Your service running on port 5000이라는 메시지를 받게 된다.
python app.py
원격에서 서버로 API에 요청하여 테스트 수행
터미널에서
python
Train API 추가
Serialization 실습에서 실행했던 ‘train_ml.py’ 참조하여 http://host:port/train 으로 모델 학습을 요청하는 API 추가
from time import time
from train_ml import *
start_time = time.now()
for mode in ['train', 'test']:
download_data(mode)
model, vectorizer = train_and_evaluate()
serialization(model, vectorizer)
response = time.now() - start_time