레이블이 mac인 게시물을 표시합니다. 모든 게시물 표시
레이블이 mac인 게시물을 표시합니다. 모든 게시물 표시

20250115

Streamlit : 이미지 분류 및 데이터 시각화 앱 만들기 (Mac 환경)

사내에 데이터 시각화용 작은 대시보드가 필요했다. 처음엔 Next.js나 FastAPI + React 조합을 떠올렸는데, "백엔드 한 명 + 디자이너 없음 + 결과는 사내에서만 쓴다"는 상황이면 Streamlit이 압도적이다. 코드 한 파일로 UI가 다 나온다. 이 글은 Mac에서 Streamlit 이미지 분류 + 차트 앱 만들어본 기록.

실제로 써본 후기부터 말하면, 데이터팀이나 분석 엔지니어가 "프로토타입 수준으로 빠르게 결과를 팀에 공유"할 땐 이만한 게 없다. 반면 제품 수준 UI 커스터마이징에는 한계가 있어서 그건 다른 도구로 가야 함.

1. 개발 환경

Python + Streamlit 설치

  1. Python: 3.12/3.13 기준. 공식 사이트에서 설치하거나 brew install python.
  2. 가상 환경:
    python3 -m venv streamlit_env
    source streamlit_env/bin/activate
  3. 라이브러리 설치:
    pip install streamlit pandas numpy matplotlib tensorflow_hub pillow

참고. Apple Silicon Mac (M1/M2/M3)에서는 tensorflow-macos가 더 매끈하게 돌아간다. 그냥 pip install tensorflow로 되는 경우도 있는데, 드물게 Metal 가속 설정에서 이슈가 나는데 그땐 macos 전용 패키지로 갈아치우는 게 빠르다.

설치 확인

streamlit hello

브라우저가 자동으로 열리면서 데모 앱이 뜨면 성공.

2. 앱 코드

이미지 분류 + 라인차트 + 사이드바 슬라이더가 한 파일에. Streamlit의 매력은 이거다 - 흐름이 그냥 Python 스크립트랑 똑같음.

import streamlit as st
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import tensorflow_hub as hub
from PIL import Image

# 앱 제목 및 설명
st.title("이미지 분류 및 데이터 시각화 앱")
st.write("이 앱은 업로드된 이미지를 분류하고 데이터를 시각화합니다.")

# 이미지 업로드 및 분류
uploaded_file = st.file_uploader("이미지를 업로드하세요", type=["jpg", "png", "jpeg"])
if uploaded_file is not None:
    image = Image.open(uploaded_file)
    st.image(image, caption="업로드된 이미지", use_column_width=True)
    st.write("이미지를 분류 중입니다...")

    # TensorFlow Hub에서 사전 학습된 모델 로드
    model = hub.load("https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/classification/5")
    image = image.resize((224, 224))
    image_array = np.array(image) / 255.0  # 정규화
    image_array = np.expand_dims(image_array, axis=0)

    predictions = model(image_array)
    st.write("분류 결과:", predictions.numpy())

# 데이터 시각화
st.header("데이터 시각화")
data = pd.DataFrame(
    np.random.randn(100, 3),
    columns=['특성 A', '특성 B', '특성 C']
)
st.line_chart(data)

# 사이드바 예제
st.sidebar.header("사이드바 설정")
range_slider = st.sidebar.slider("값 범위 선택", 0, 100, (25, 75))
st.sidebar.write(f"선택된 범위: {range_slider}")

주의 하나. 위 코드에서 hub.load(...)를 매 실행마다 호출한다. Streamlit은 사용자 상호작용마다 스크립트 전체를 다시 돌리는 구조라 이대로 두면 매번 모델 로딩 → 느리다. 실전에선 @st.cache_resource 데코레이터로 감싸야 한다. 그럼 프로세스 수명 동안 한 번만 로드됨. 아래처럼:

@st.cache_resource
def load_model():
    return hub.load("https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/classification/5")

model = load_model()

예전엔 @st.cache 하나로 다 처리했는데 최근 Streamlit은 데이터와 리소스를 구분한다. 데이터는 @st.cache_data, 모델/DB 연결 같은 건 @st.cache_resource. 기억해두면 좋음.

3. 코드 저장 및 실행

nano image_classification_app.py
cd /path/to/your/directory
streamlit run image_classification_app.py

http://localhost:8501 에서 확인.

4. 기능

  • 이미지 업로드/분류: MobileNet V2 (ImageNet 사전학습) 사용. 실제로는 ImageNet 1000 클래스 인덱스라 결과 해석 위해 labels 파일 하나 더 받아서 매핑해야 실사용 가능함.
  • 데이터 시각화: 무작위 DataFrame을 라인차트로. st.line_chart가 기본 축 설정까지 알아서 해줌.
  • 사이드바: 슬라이더 하나로 상호작용 UX 완성.

5. 쓰면서 느낀 것

장점이 명확한 만큼 한계도 있다. Streamlit은 위에서 아래로 스크립트가 흐르는 구조라 복잡한 폼이나 여러 탭 로직이 얽히면 state 관리가 난감해진다. st.session_state가 있지만 React처럼 세밀한 컴포넌트 분리는 어렵다. 진짜 제품 UI면 Next.js로 가는 게 맞다.

반대로 사내 도구 / 데모 / 분석 리포트 용도로는 거의 최고 수준이다. 한 파일 250줄 안에 "차트 + 업로드 + 필터 + 테이블"까지 다 들어간다. 배포도 Streamlit Cloud 무료 티어로 붙이면 끝.

  • 모델/DB 연결은 @st.cache_resource, 데이터프레임 가공은 @st.cache_data
  • 페이지 여러 개 필요하면 pages/ 폴더로 자동 멀티페이지
  • 사내 배포면 streamlit run ... --server.port 8080 --server.address 0.0.0.0 으로 nginx 뒤에 붙이는 게 깔끔