RyanNerd
라덕'Story
RyanNerd
  • 분류 전체보기 (117)
    • Study Note (80)
      • Python (3)
      • R (1)
      • Airflow (7)
      • 통계 (26)
      • Machine Learning (16)
      • Streamlit (9)
      • Django (1)
      • Deep Learning (12)
      • dbt (2)
      • SQL (3)
    • 빅데이터분석기사 (1)
      • 필기 (1)
    • Programmers (28)
      • Python (13)
      • SQL (15)
    • Project (3)
      • Django (3)
    • Mac (2)

블로그 메뉴

  • NaverBlog
  • 홈

최근 글

전체 방문자
오늘
어제
hELLO · Designed By 정상우.
RyanNerd

라덕'Story

Study Note/Streamlit

AI 모델, 직접 만들어서 웹으로 배포하기 (A to Z)

2025. 12. 29. 16:09

지금까지는 남이 만든 모델을 가져온다고 가정했지만, 오늘은 직접 의료 데이터를 생성하고, AI를 학습시켜 파일(.pkl)로 저장한 뒤, 웹 서비스로 띄우는 전체 과정을 실습합니다.

이 과정은 크게 주방(모델 학습)과 홀(웹 서비스)로 나뉩니다.

 

1부. 주방: 의료 데이터 생성 및 모델 저장 (train_model.py)

먼저 주피터 노트북이나 파이썬 스크립트에서 실행할 코드입니다. 가상의 심장병 데이터를 만들고, RandomForest로 학습시킨 뒤, 그 '뇌'를 heart_model.pkl이라는 파일로 박제(Serialize)합니다.

import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import joblib  # 모델을 파일로 저장하는 라이브러리

# 1. 가상의 심장병 데이터 생성 (500명)
def generate_data():
    np.random.seed(42)
    n = 500
    df = pd.DataFrame({
        'Age': np.random.randint(20, 90, n),
        'BMI': np.random.normal(25, 4, n).round(1),
        'Blood_Pressure': np.random.randint(90, 180, n), # 혈압
        'Cholesterol': np.random.randint(120, 300, n),   # 콜레스테롤
        'Sex': np.random.choice([0, 1], n),              # 0:여성, 1:남성
        'Risk': np.random.choice([0, 1], n, p=[0.7, 0.3]) # 0:정상, 1:심장병
    })
    return df

print("데이터 생성 중...")
df = generate_data()

# 2. 모델 학습
X = df[['Age', 'BMI', 'Blood_Pressure', 'Cholesterol', 'Sex']]
y = df['Risk']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)

# 정확도 확인
score = accuracy_score(y_test, model.predict(X_test))
print(f"모델 학습 완료! 정확도: {score:.2f}")

# 3. 모델을 파일로 저장 (.pkl) -> 이 부분이 핵심!
joblib.dump(model, 'heart_model.pkl') 
print("모델이 'heart_model.pkl' 파일로 저장되었습니다.")

 

실행 결과: 이 코드를 한 번 실행하면, 같은 폴더에 heart_model.pkl이라는 파일이 생깁니다. 이제 AI의 두뇌가 파일로 준비된 것입니다!

 

2부. 홀: Streamlit으로 AI 웹 서비스 만들기 (app.py)

이제 방금 만든 heart_model.pkl 파일을 불러와서, 의사가 환자 정보를 입력하면 예측 결과를 보여주는 웹 앱을 만듭니다.

 

핵심 포인트:

  1. joblib.load()로 모델 불러오기
  2. @st.cache_resource로 모델 로딩 속도 최적화
  3. 사용자 입력(위젯)을 모델 학습 때와 똑같은 컬럼 순서로 맞추기
# app.py
import streamlit as st
import pandas as pd
import numpy as np
import joblib
import os

# --- 1. 페이지 설정 ---
st.set_page_config(page_title="심장병 예측 AI")

# --- 2. 모델 로딩 (캐싱 사용) ---
# 모델 파일은 한 번만 불러오면 되므로 cache_resource를 씁니다.
@st.cache_resource
def load_ai_model():
    if os.path.exists('heart_model.pkl'):
        return joblib.load('heart_model.pkl')
    else:
        return None

st.title("AI 심장병 위험도 진단 시스템")
st.markdown("---")

# 모델 불러오기
model = load_ai_model()

if model is None:
    st.error("모델 파일(heart_model.pkl)을 찾을 수 없습니다. 1부 코드를 먼저 실행해주세요!")
else:
    # --- 3. 사이드바: 환자 정보 입력 (위젯) ---
    st.sidebar.header("환자 정보 입력")
    
    # 모델 학습 때 사용한 변수: Age, BMI, Blood_Pressure, Cholesterol, Sex
    age = st.sidebar.slider("나이 (Age)", 20, 90, 45)
    
    gender = st.sidebar.radio("성별 (Sex)", ["남성", "여성"])
    # 학습할 때 남성=1, 여성=0으로 했으므로 변환 필요
    sex_value = 1 if gender == "남성" else 0
    
    bmi = st.sidebar.number_input("BMI (체질량지수)", 15.0, 40.0, 24.5)
    bp = st.sidebar.number_input("혈압 (Blood Pressure)", 90, 200, 120)
    chol = st.sidebar.number_input("콜레스테롤 (Cholesterol)", 100, 400, 190)

    # --- 4. 메인 화면: 예측 실행 ---
    st.subheader("환자 임상 데이터 확인")
    
    # 입력받은 값을 데이터프레임으로 만듭니다. (컬럼 이름과 순서가 학습 때와 같아야 함!)
    input_df = pd.DataFrame({
        'Age': [age],
        'BMI': [bmi],
        'Blood_Pressure': [bp],
        'Cholesterol': [chol],
        'Sex': [sex_value]
    })
    
    # 입력 데이터 보여주기
    st.dataframe(input_df)

    predict_btn = st.button("진단 결과 예측 (Predict)")

    if predict_btn:
        # 모델 예측
        prediction = model.predict(input_df)[0]
        probability = model.predict_proba(input_df)[0][1] # 심장병일 확률 (1일 확률)

        st.markdown("---")
        st.subheader("AI 분석 결과")

        # 결과 시각화 (Progress Bar 활용)
        st.write(f"심장질환 발병 확률: {probability*100:.1f}%")
        st.progress(float(probability)) # 0.0 ~ 1.0 사이 값 필요

        if prediction == 1:
            st.error("고위험군 (High Risk) 으로 예측됩니다.")
            st.write("권장 사항: 정밀 심혈관 검사 및 전문의 상담이 필요합니다.")
        else:
            st.success("저위험군 (Low Risk) 으로 예측됩니다.")
            st.write("권장 사항: 현재 상태를 유지하며 정기 검진을 받으세요.")

 

 

정리

  1. Training (학습): train_model.py를 실행해서 데이터를 공부시키고 heart_model.pkl이라는 뇌를 만들었습니다.
  2. Serving (배포): app.py를 실행(streamlit run app.py)해서 그 뇌를 웹사이트에 이식했습니다.

[실행 순서 요약]

  1. 터미널에서 python train_model.py 실행 $\rightarrow$ heart_model.pkl 생성 확인.
  2. 터미널에서 streamlit run app.py 실행 $\rightarrow$ 웹 브라우저 열림.
  3. 웹에서 값을 바꾸고 버튼 클릭 $\rightarrow$ AI가 실시간으로 응답!

'Study Note > Streamlit' 카테고리의 다른 글

[Django x Streamlit] 의료 데이터 분석 플랫폼 구축하기: ORM부터 웹 대시보드까지  (0) 2025.12.30
[Streamlit 대시보드] 숫자로 말하는 데이터: st.metric과 멀티페이지 앱(MPA) 설계  (0) 2025.12.29
"내 앱은 왜 자꾸 까먹을까?" : Session State와 Caching 완벽 해부  (0) 2025.12.29
속도는 올리고 코드는 깔끔하게  (0) 2025.12.29
의료 데이터 분석, 웹으로 띄우기 (기초편)  (0) 2025.12.29
    'Study Note/Streamlit' 카테고리의 다른 글
    • [Django x Streamlit] 의료 데이터 분석 플랫폼 구축하기: ORM부터 웹 대시보드까지
    • [Streamlit 대시보드] 숫자로 말하는 데이터: st.metric과 멀티페이지 앱(MPA) 설계
    • "내 앱은 왜 자꾸 까먹을까?" : Session State와 Caching 완벽 해부
    • 속도는 올리고 코드는 깔끔하게
    RyanNerd
    RyanNerd
    라이언 덕후의 일상 스토리~

    티스토리툴바