# 웹 앱을 만들어 ML 모델 사용하기 이 강의에서는 _지난 세기 동안의 UFO 목격_ 데이터를 사용하여 ML 모델을 훈련시킬 것입니다. 이 데이터는 NUFORC의 데이터베이스에서 가져왔습니다. 배울 내용: - 훈련된 모델을 '피클링'하는 방법 - Flask 앱에서 모델을 사용하는 방법 노트북을 사용하여 데이터를 정리하고 모델을 훈련시키는 작업을 계속 진행할 것이지만, 이를 한 단계 더 발전시켜 웹 앱에서 모델을 사용하는 방법을 탐구할 것입니다. 이를 위해 Flask를 사용하여 웹 앱을 구축해야 합니다. ## [강의 전 퀴즈](https://ff-quizzes.netlify.app/en/ml/) ## 앱 구축하기 머신 러닝 모델을 소비하는 웹 앱을 구축하는 방법은 여러 가지가 있습니다. 웹 아키텍처는 모델 훈련 방식에 영향을 미칠 수 있습니다. 데이터 과학 팀이 훈련한 모델을 앱에서 사용해야 하는 비즈니스 환경을 상상해 보세요. ### 고려 사항 다음과 같은 질문을 해야 합니다: - **웹 앱인가 모바일 앱인가?** 모바일 앱을 구축하거나 IoT 환경에서 모델을 사용해야 한다면 [TensorFlow Lite](https://www.tensorflow.org/lite/)를 사용하여 Android 또는 iOS 앱에서 모델을 사용할 수 있습니다. - **모델은 어디에 위치할 것인가?** 클라우드인가 로컬인가? - **오프라인 지원.** 앱이 오프라인에서도 작동해야 하는가? - **모델을 훈련시킨 기술은 무엇인가?** 선택한 기술은 필요한 도구에 영향을 미칠 수 있습니다. - **TensorFlow 사용.** 예를 들어 TensorFlow를 사용하여 모델을 훈련시키는 경우, [TensorFlow.js](https://www.tensorflow.org/js/)를 사용하여 웹 앱에서 모델을 사용할 수 있도록 변환할 수 있습니다. - **PyTorch 사용.** [PyTorch](https://pytorch.org/)와 같은 라이브러리를 사용하여 모델을 구축하는 경우, [ONNX](https://onnx.ai/) (Open Neural Network Exchange) 형식으로 내보내 JavaScript 웹 앱에서 [Onnx Runtime](https://www.onnxruntime.ai/)을 사용할 수 있습니다. 이 옵션은 Scikit-learn으로 훈련된 모델을 다루는 향후 강의에서 탐구할 것입니다. - **Lobe.ai 또는 Azure Custom Vision 사용.** [Lobe.ai](https://lobe.ai/) 또는 [Azure Custom Vision](https://azure.microsoft.com/services/cognitive-services/custom-vision-service/?WT.mc_id=academic-77952-leestott)과 같은 ML SaaS(Software as a Service) 시스템을 사용하여 모델을 훈련시키는 경우, 이 소프트웨어는 클라우드에서 온라인 애플리케이션이 쿼리할 수 있는 맞춤형 API를 구축하는 등 다양한 플랫폼으로 모델을 내보내는 방법을 제공합니다. 또한 웹 브라우저에서 직접 모델을 훈련시킬 수 있는 전체 Flask 웹 앱을 구축할 수도 있습니다. 이는 JavaScript 환경에서 TensorFlow.js를 사용하여도 가능합니다. 우리의 경우, Python 기반 노트북을 사용해 왔으므로, 노트북에서 훈련된 모델을 Python으로 구축된 웹 앱에서 읽을 수 있는 형식으로 내보내는 단계를 탐구해 보겠습니다. ## 도구 이 작업을 위해 Flask와 Pickle이라는 두 가지 도구가 필요합니다. 둘 다 Python에서 실행됩니다. ✅ [Flask](https://palletsprojects.com/p/flask/)란 무엇인가요? Flask는 제작자들에 의해 '마이크로 프레임워크'로 정의되며, Python을 사용하여 웹 페이지를 구축하기 위한 템플릿 엔진과 웹 프레임워크의 기본 기능을 제공합니다. Flask를 사용하여 앱을 구축하는 연습을 하려면 [이 학습 모듈](https://docs.microsoft.com/learn/modules/python-flask-build-ai-web-app?WT.mc_id=academic-77952-leestott)을 확인하세요. ✅ [Pickle](https://docs.python.org/3/library/pickle.html)이란 무엇인가요? Pickle 🥒은 Python 객체 구조를 직렬화하고 역직렬화하는 Python 모듈입니다. 모델을 '피클링'하면 웹에서 사용할 수 있도록 구조를 직렬화하거나 평탄화합니다. 주의하세요: Pickle은 본질적으로 안전하지 않으므로 파일을 '언피클링'하라는 요청을 받을 경우 주의해야 합니다. 피클링된 파일은 `.pkl` 확장자를 가집니다. ## 실습 - 데이터 정리하기 이번 강의에서는 [NUFORC](https://nuforc.org) (National UFO Reporting Center)에서 수집한 80,000건의 UFO 목격 데이터를 사용합니다. 이 데이터에는 흥미로운 UFO 목격 설명이 포함되어 있습니다. 예를 들어: - **긴 설명 예시.** "밤에 풀밭에 빛이 비추고 그 빛에서 한 남자가 나타나 텍사스 인스트루먼트 주차장으로 달려간다." - **짧은 설명 예시.** "빛이 우리를 쫓아왔다." [ufos.csv](../../../../3-Web-App/1-Web-App/data/ufos.csv) 스프레드시트에는 목격이 발생한 `city`, `state`, `country`, 객체의 `shape`, 그리고 `latitude`와 `longitude`에 대한 열이 포함되어 있습니다. 이 강의에 포함된 빈 [노트북](../../../../3-Web-App/1-Web-App/notebook.ipynb)에서: 1. 이전 강의에서 했던 것처럼 `pandas`, `matplotlib`, `numpy`를 가져오고 ufos 스프레드시트를 가져옵니다. 샘플 데이터 세트를 확인할 수 있습니다: ```python import pandas as pd import numpy as np ufos = pd.read_csv('./data/ufos.csv') ufos.head() ``` 1. ufos 데이터를 새 제목으로 작은 데이터프레임으로 변환합니다. `Country` 필드의 고유 값을 확인하세요. ```python ufos = pd.DataFrame({'Seconds': ufos['duration (seconds)'], 'Country': ufos['country'],'Latitude': ufos['latitude'],'Longitude': ufos['longitude']}) ufos.Country.unique() ``` 1. 이제 null 값을 제거하고 1-60초 사이의 목격만 가져옴으로써 처리해야 할 데이터 양을 줄일 수 있습니다: ```python ufos.dropna(inplace=True) ufos = ufos[(ufos['Seconds'] >= 1) & (ufos['Seconds'] <= 60)] ufos.info() ``` 1. Scikit-learn의 `LabelEncoder` 라이브러리를 가져와 국가의 텍스트 값을 숫자로 변환합니다: ✅ LabelEncoder는 데이터를 알파벳 순서로 인코딩합니다. ```python from sklearn.preprocessing import LabelEncoder ufos['Country'] = LabelEncoder().fit_transform(ufos['Country']) ufos.head() ``` 데이터는 다음과 같이 보여야 합니다: ```output Seconds Country Latitude Longitude 2 20.0 3 53.200000 -2.916667 3 20.0 4 28.978333 -96.645833 14 30.0 4 35.823889 -80.253611 23 60.0 4 45.582778 -122.352222 24 3.0 3 51.783333 -0.783333 ``` ## 실습 - 모델 구축하기 이제 데이터를 훈련 및 테스트 그룹으로 나누어 모델을 훈련시킬 준비를 할 수 있습니다. 1. 훈련할 세 가지 특징을 X 벡터로 선택하고 y 벡터는 `Country`로 설정합니다. `Seconds`, `Latitude`, `Longitude`를 입력하여 국가 ID를 반환할 수 있도록 합니다. ```python from sklearn.model_selection import train_test_split Selected_features = ['Seconds','Latitude','Longitude'] X = ufos[Selected_features] y = ufos['Country'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0) ``` 1. 로지스틱 회귀를 사용하여 모델을 훈련시킵니다: ```python from sklearn.metrics import accuracy_score, classification_report from sklearn.linear_model import LogisticRegression model = LogisticRegression() model.fit(X_train, y_train) predictions = model.predict(X_test) print(classification_report(y_test, predictions)) print('Predicted labels: ', predictions) print('Accuracy: ', accuracy_score(y_test, predictions)) ``` 정확도는 **(약 95%)**로 나쁘지 않습니다. 이는 `Country`와 `Latitude/Longitude`가 상관관계가 있기 때문입니다. 이 모델은 혁신적이지는 않지만, 정리된 원시 데이터를 사용하여 모델을 훈련시키고 이를 웹 앱에서 사용하는 좋은 연습이 됩니다. ## 실습 - 모델 '피클링'하기 이제 모델을 _피클링_할 시간입니다! 몇 줄의 코드로 이를 수행할 수 있습니다. 모델이 _피클링_되면, 피클링된 모델을 로드하고 초, 위도, 경도 값을 포함하는 샘플 데이터 배열에 대해 테스트합니다. ```python import pickle model_filename = 'ufo-model.pkl' pickle.dump(model, open(model_filename,'wb')) model = pickle.load(open('ufo-model.pkl','rb')) print(model.predict([[50,44,-12]])) ``` 모델은 **'3'**을 반환하며, 이는 영국의 국가 코드입니다. 놀랍네요! 👽 ## 실습 - Flask 앱 구축하기 이제 Flask 앱을 구축하여 모델을 호출하고 더 시각적으로 보기 좋은 방식으로 결과를 반환할 수 있습니다. 1. _notebook.ipynb_ 파일 옆에 **web-app**이라는 폴더를 만듭니다. 이 폴더에는 _ufo-model.pkl_ 파일이 있어야 합니다. 1. 해당 폴더에 **static** 폴더와 그 안에 **css** 폴더, 그리고 **templates** 폴더를 만듭니다. 이제 다음과 같은 파일 및 디렉토리가 있어야 합니다: ```output web-app/ static/ css/ templates/ notebook.ipynb ufo-model.pkl ``` ✅ 완성된 앱의 보기 형태는 솔루션 폴더를 참조하세요. 1. _web-app_ 폴더에서 첫 번째 파일로 **requirements.txt**를 만듭니다. JavaScript 앱의 _package.json_처럼 이 파일은 앱에 필요한 종속성을 나열합니다. **requirements.txt**에 다음 줄을 추가합니다: ```text scikit-learn pandas numpy flask ``` 1. 이제 _web-app_으로 이동하여 이 파일을 실행합니다: ```bash cd web-app ``` 1. 터미널에서 `pip install`을 입력하여 _requirements.txt_에 나열된 라이브러리를 설치합니다: ```bash pip install -r requirements.txt ``` 1. 이제 앱을 완성하기 위해 세 개의 파일을 더 만들 준비가 되었습니다: 1. 루트에 **app.py**를 만듭니다. 2. _templates_ 디렉토리에 **index.html**을 만듭니다. 3. _static/css_ 디렉토리에 **styles.css**를 만듭니다. 1. _styles.css_ 파일을 몇 가지 스타일로 작성합니다: ```css body { width: 100%; height: 100%; font-family: 'Helvetica'; background: black; color: #fff; text-align: center; letter-spacing: 1.4px; font-size: 30px; } input { min-width: 150px; } .grid { width: 300px; border: 1px solid #2d2d2d; display: grid; justify-content: center; margin: 20px auto; } .box { color: #fff; background: #2d2d2d; padding: 12px; display: inline-block; } ``` 1. 다음으로 _index.html_ 파일을 작성합니다: ```html
According to the number of seconds, latitude and longitude, which country is likely to have reported seeing a UFO?
{{ prediction_text }}