모델을 서빙하는 방법에는 여러 가지가 있지만, 그중 대표적으로 두 가지가 있다.
1. 배치 서빙 (Batch Serving)
- 일정한 주기마다 한 번에 많은 데이터를 처리하는 방식
- 일괄 처리
- 대량의 데이터를 한꺼번에 처리하는 것이 효율적일 때 사용
- 비실시간 응답 (ex. 야간에 하루 동안 수집된 데이터를 처리하여 다음 날 아침에 결과를 제공하는 경우)
2. 온라인 서빙
- 실시간으로 데이터를 처리하는 방식
- 실시간 응답
- 상시 가동: 모델이 항상 실행되어 있어야 한다
그리고 어떤 도구를 사용할 것인지에 따라 크게 4가지가 있다.
1. REST API 기반 모델 서빙
- HTTP 프로토콜을 사용하기 때문에 설정이 간단하고 널리 사용
2. gRPC 프레임워크를 이용한 모델 서빙
- Google Remote Procedure Call는 HTTP/2를 기반으로 하는 프레임워크이다.
- 클라이언트와 서버 간의 양방향 스트리밍을 지원하여 실시간 데이터 처리가 가능하다.
3. Serverless Serving
- 서버를 관리하지 않고도 코드를 실행할 수 있는 클라우드 컴퓨팅 모델이다.
- 대표적으로 AWS Lambda, Google Cloud Functions 등이 있다.
4. Kubernetes 기반 서빙
- 컨테이너화된 애플리케이션을 자동으로 배포, 확장 및 관리하는 오픈 소스 플랫폼이다.
- 비싸다 ^^;;
그 중 나는 online serving 방법을 사용했다. 그리고 REST API 기반 모델 서빙을 하기로 했다. output으로 하나의 값만 나오면 되었고, fastapi로 간단히 구축할 수 있을 것 같았다. (fastapi 사용해 본 후기는 배포할 때도 uvicorn의 미들웨어 세팅을 해주면 되었고 빠른 개방 속도, 성능, 자동 문서화를 해주었기에 진-짜 편했다.)
TensorFlow를 프레임워크로 써도 되지만 (이건 모델을 저장하고 load 할 필요X, 모델 그래도 사용) 내가 사용하는 LigntGBM은 대규모 모델은 아니기에 fastapi로 사용했다. 그리고 서빙도 tensorflow serving을 이용하면 기존 api서버, 인퍼런스 서버를 따로 구축해야 하는데 굳이 그 정도의 대규모 모델도 아니고 api서버만 구축하면 되었기에 사용을 안 했다.
나는 머신러닝, 딥러닝 모델 두 개를 학습하고 서빙해보았다! 모델 2개는 colab 환경에서 학습된 모델이다. TensorFlow 같은 프레임워크를 쓰고 싶었지만 노트북에는 GPU가 없기에 코랩을 사용했다. 그리고 FastAPI를 사용해서 서버를 구축했지만 나중에는 serverless 로 aws lamba를 써보고 싶긴 하다.
사실 모델 각 두 개는 2명의 팀원에게 맡겼지만. 이것을 백엔드로 api 통신을 하기 위해서는 나도 코드를 이해하고 구축해야 했다.
LightGBM 모델 구축, 서빙 과정
LightGBM은 gradient boosting machine이다. 앙상블기법! 이 프레임워크는 여러 개의 약한 학습기(주로 결정 트리)를 순차적으로 학습하여 강력한 예측 모델을 구축한다. 주요 개념은 각 단계에서 이전 모델의 오류를 보정하는 방식으로 새로운 모델을 추가하는 것이다. 그래서 정확도도 높고, 속도도 빠르기에 사용하였다.
LightGBM 모델은 정치성향을 분류하는 데 사용하였다. 뉴스 기사 링크를 넣으면 정치 성향을 보수, 진보, 중도 중에서 결과가 나오게 하고 각 성향이 퍼센트로 나오게끔 했다.
0. 데이터 전처리
title, content, label 총 3개의 데이터가 있다.
그 과정에서 TF-IDF 벡터화를 사용한다. TF-IDF 벡터화란 문서 내 단어의 중요도를 평가하여 텍스트 데이터를 벡터 형태로 변환하는 기법이다. 텍스트는 자연어로 되어 있어 바로 분석하기 어렵기 때문에, 각 단어를 수치화된 벡터로 변환하여 알고리즘이 이를 처리하고 분석할 수 있게 한다.
1. 모델 학습
버블로우는 약 72,000개의 정치 기사를 학습 데이터로 사용하여 정치 성향 분석 모델을 개발했다. 이 모델은 TF-IDF 벡터화를 통해 텍스트 데이터를 수치화하고, LightGBM 알고리즘을 사용하여 정치 성향을 예측한다 모델의 정확도는 약 0.974로, 높은 예측 성능을 자랑한다. 중도 성향 판단을 위해 예측 확률이 0.5에서 크게 변동되지 않는 경우를 중도로 분류한다.
2. 최종 모델
# TF-IDF 벡터화
tfidf_vectorizer = TfidfVectorizer(max_features=5000)
X_tfidf = tfidf_vectorizer.fit_transform(X)
# 데이터 나누기
X_train, X_test, y_train, y_test = train_test_split(X_tfidf, y, test_size=0.2, random_state=100)
# LightGBM 모델 훈련
lgbm_model = LGBMClassifier()
lgbm_model.fit(X_train, y_train)
3. 모델서빙
모델 저장을 먼저 해준다.
import pickle
# 모델과 벡터라이저를 하나의 딕셔너리 객체로 묶음
model_and_vectorizer = {'model': lgbm_model, 'vectorizer': tfidf_vectorizer}
# 딕셔너리 객체를 파일로 저장
with open("model_and_vectorizer.dump", "wb") as fw:
pickle.dump(model_and_vectorizer, fw)
그리고 모델 저장한 걸 불러와서 FastAPI 프레임워크 사용했다. 원래 따로 models.py와 domain을 분리하지만 이건 그냥 한 파일 main.py에 써주었다. 서빙만 하는 코드니까ㅎ
# 데이터 저장
class Politics(BaseModel):
title: str
content: str
with open("model_and_vectorizer.dump", "rb")as f:
loaded_data = pickle.load(f)
# 불러온 데이터에서 모델과 벡터라이저를 각각 추출
loaded_model = loaded_data['model']
loaded_vectorizer = loaded_data['vectorizer']
# 새 데이터의 '제목'과 '내용'을 결합
@app.post("/predict", status_code=200)
async def predict_tf(x: Politics):
# '제목'과 '내용'을 하나의 문자열로 결합하여 리스트에 넣은 후 DataFrame 생성
new_data = pd.DataFrame({"data": [x.title + ' ' + x.content]})
X_new_tfidf = loaded_vectorizer.transform(new_data['data'])
res = loaded_model.predict(X_new_tfidf)
percentage = loaded_model.predict_proba(X_new_tfidf)[0] #정치 성향 결과
percentage0 = percentage[0] #보수 성향 퍼센트
percentage1 = percentage[1] #진보 성향 퍼센트
return {"prediction": res.tolist(), "percentage0": percentage0, "percentage1": percentage1}
따라서 output으로 정치 결과를 list로, 각 퍼센트를 float로 준다.
그다음에 배포까지 해야 한다.. 😇 지금은 로컬에서만 사용가능하기 때문 aws ec2로 배포하면 된다. uvicorn은 ASGI 서버로 FastAPI를 실행하는 데 사용된다. 그래서 fastapi 앞에 uvicorn을 사용해서 웹서버가 파이썬 스크립트와 잘 통신할 수 있게 하였다.
FastAPI는 아래처럼 swagger UI를 제공하기 때문에 너무 편하다
최종본은 이렇게 링크를 넣으면 정치 성향이 나오게끔 구현했다.
두 번째 모델
개체명 인식 - KcELECTRA , 감정 분석 - RoBERTa
KcELECTRA 모델은 NLP를 사용하는데 특화되었고 한국어 데이터셋으로 사전 학습된 모델이므로 한국어 텍스트에서의 개체명 인식 성능이 뛰어나기에 선택하였다. RoBERTa는 BERT는 구글에서 개발한 사전 학습된 언어 모델이다. 이걸 성능을 향상한 자연어 처리 모델인 Robustly optimized BERT approach를 사용했다. 페이스북에서 개발했고 텍스트 분류 작업에 정확도를 보이기에 사용하였다. 특히 양방향 문맥을 모두 고려하기에 감정분석에서는 단어의 문맥이 중요하기 때문에 사용했다.
KcELECTRA 모델은 경제 기사에서 기업 명을 추출하는 데 사용했고, RoBERTa 모델은 그 기업에 대해서 긍정인지 부정인지 그 퍼센트는 얼마인지 나오게끔 사용했다.
이 모델도 online serving방식을 사용했고 fastapi로 서버를 구축했다. 그리고 ec2를 이용해서 배포하면 되지만,, GPU를 사용하는 모델이기에 ec2 인스턴스 유형을 평소에 쓰는 t2.micro(프리 티어)를 쓸 수 없었다. GPU를 지원하는 g4dn.xlarge, p3.2xlarge 이런 거를 사용하기 때문에 비용적으로 많이 나올 수 있었다. 그래서 도커로 컨테이너로 띄워두고 로컬 서버를 외부에서 접근할 수 있도록만 해줬다. ngrok 최고 !
모델은 위에처럼 load해도 되고 아래처럼 다른 파일에서 import 해도 된다.
@app.route('/analyze', methods=['POST'])
def analyze():
if request.method == 'POST':
data = request.get_json()
text = data.get('text')
df = pd.DataFrame(columns=["본문"])
df = df._append({'본문': text}, ignore_index=True)
sentence_list = spliter(df)
df1 = ner_go(sentence_list)
df2 = sa_go(df1)
ner_result = ner_organizer(df2)
sa_result, sa_positive, sa_negative = sa_organizer(df2)
return json.dumps({'ner_result': ner_result, 'sa_result': sa_result
, 'sa_positive': sa_positive, 'sa_negative': sa_negative}
, ensure_ascii = False)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
배포대신 도커를 이용해서 IP를 열어두고, ngrok을 이용해서 공개 서버로 사용할 수 있게 했다.
아래처럼 Dockerfile을 작성하면 된다.
FROM python:3.12-slim
WORKDIR /app
COPY . /app
RUN pip install --no-cache-dir -r requirements.txt
RUN pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
CMD ["python", "app.py"]
(ngrok 사용하라는 아이디어를 제공해 주신 루트님 감사를 ^_^)
근데 로컬 서버를 공개 서버로 사용하는 엔그록은 넘 좋지만 도커 컨테이너를 down하고 up 할 때마다 ip가 바뀐다.. 그래서 항상 url를 바꾸어 주어야 하는 단점이 있지만 그래도 무료인게 어디야.... 라는 마음으로 사용!
최종본은 이렇다. 경제 기사를 넣어주면 개체명 인식 결과와 그에 대한 감정이다. 컨테이너를 계속 키고 끄기 번거로워서 지금은 bubblow에서 사용하고 있지는 않다.
주 기능인 모델 완성되었고 이제 무엇이냐.. 백엔드와 프론트를 구축해야 했다.. 모델 서빙과 웹 서버를 동시에 구축해야 했을 때 머리가 복잡했지만 그래도 완성은 해야 했기에 디자인은 많이 포기하고 기능에 집중했었다. 그건 다음 이야기에 계속 🥲
'졸업프로젝트' 카테고리의 다른 글
[졸업프로젝트 회고] 아쉬운점과 개선점 (1) | 2024.07.10 |
---|---|
[졸업 프로젝트] FastAPI와 PostgreSQL 연동하기 (feat. GCP로 배포까지) (2) | 2024.05.06 |
[졸업 프로젝트 Bubblow] 네이버뉴스 크롤링 하기 (4) | 2024.04.07 |
[졸업 프로젝트] Bubblow 소개 (7) | 2024.03.29 |