Search
Duplicate
moon
sun

3.스트림릿concept

0.최종목표

[ 아이리스 품종 예측기 ]

1.핵심 concept

1.
스트림릿 (Streamlit) 프레임워크는 UI 요소와 실시간 연동되는 파이썬 기반의 컴포넌트 객체를 통해 사용자와 상호 작용
2.
스트림릿은 먼저 파이썬 스크립트가 최초 실행될 때 화면의 레이아웃과 구성 요소를 배치
•
파이썬 스크립트란? 파이썬으로 작성된 코드
•
.py 확장자를 가진 실행 가능한 텍스트 파일

2.반응형 프로그래밍

1.
반응형 프로그램 특징: UI 요소에 일어나는 변화를 효과적으로 감지하고 처리하기 위해 애플리케이션의 데이터 상태와 UI 요소의 상태를 동기화하여 관리
2.
원리: 스트림릿 환경에서 수행되는 파이썬 스크립트는 스트림릿에서 관리하는 프론트엔드 엔진으로 전달되어 화면상의 컴포넌트로 출력됨
[ 스트림릿 프레임워크에서 파이썬 스크립트와 UI 요소가 연동하는 과정을 나타내는 다이어그램 ]
1.
스트림릿의 프론트엔드 엔진은 SPA(Single Page Application)로 동작하기 때문에 최초 출력 이후에는 웹 페이지 전체를 리로드하지 않고, 서버로부터 받은 데이터나 정보를 바탕으로 화면을 업데이트 하는 방식
2.
주목할 부분: 사용자가 화면상의 컴포넌트에 인터랙션을 가하면, 스트림릿 프레임워크는 애플리케이션의 상태를 최신화하기 위해 파이썬 스크립트 전체를 다시 실행한다는 점
import streamlit as st print("start...") text = "지정된 텍스트를 제목, 부제목, 글, 인풋 등으로" st.header(text, divider='rainbow') st.subheader(text) st.title(text) st.write(text) st.text_input(label="Title", placeholder=text) st.write("# Bar Chart") vocab_logits = { "나는": 0.01, "내일": 0.03, "오늘": 0.25, "어제": 0.3, "산에": 0.4, "학교에": 0.5, "집에": 0.65, "오른다": 1.2, "간다": 1.05, "왔다": 0.95} st.bar_chart(vocab_logits) # 중앙 정렬 캡션 st.markdown( "<p style='text-align: center; color: gray;'>막대차트</p>", unsafe_allow_html=True) print("end...")
Python
복사

2-1.반응확인

화면의 input 상자에 텍스트를 입력한 후 탭 등을 클릭하여 포커스를 벗어나면 콘솔 창에
’’ start… end… ’’
이 출력되는 것을 볼 수 있음

3.파이썬의 데코레이터

[양파고의 한마디] 파이썬 함수 def를 튜닝할때, 또는 확장할 때
1.
정의
•
함수를 인자로 받아, 기능을 확장한 후 다시 함수로 반환하는 고차 함수
1.
형태
•
@데코레이터_이름 형태로 함수 위에 붙여 사용
1.
기본 구조
•
기존 함수를 감싸는 래퍼(wrapper) 함수를 정의하는 방식
# 데코레이터의 기본구조 # 데코레이터라는 '고차함수'만들기 def my_decorator(func): # 1. 함수(func)를 인자로 받음 def wrapper(): # 2. 내부 래퍼 함수 정의 print("함수 실행 전") func() # 3. 원래 함수 실행 print("함수 실행 후") return wrapper # 4. 감싼 함수 반환 # 타입 확인 type(my_decorator)
Python
복사
function
Plain Text
복사
# 이렇게 데코레이터 단독으로는 실행불가 @my_decorator # 아래 함수는 이제 wrapper()로 감싸진 상태
Python
복사
Cell In[6], line 2 @my_decorator # 아래 함수는 이제 wrapper()로 감싸진 상태 ^ SyntaxError: incomplete input
Plain Text
복사
@my_decorator # 아래 함수는 이제 wrapper()로 감싸진 상태 def say_hello(): print("안녕하세요!") say_hello()
Python
복사
함수 실행 전 안녕하세요! 함수 실행 후
Plain Text
복사

3-1.데코레이터의 주요역할

1.
로깅(logging)
•
함수가 호출될 때 로그 기록
2.
성능 측정
•
함수 실행 시간 측정
3.
인증 처리
•
사용자 권한 확인 후 실행 허용
4.
캐싱(cache)
•
동일 입력에 대해 결과 저장 및 재사용
5.
예외 처리
•
함수 내부에서 발생하는 예외를 외부에서 핸들링
[왜 쓰는가?]
➡️ 함수 실행 전/후에 추가 동작을 삽입, 또는 실행 조건을 제어할 수 있음
➡️함수 내부를 바꾸지 않아도, 외부에서 기능을 덧붙일 수 있음 (→ 유지보수, 재사용성 향상)
# 실행시간 측정 데코레이터 import time # 타이머 측정 데코레이터코레이터 def timer(func): def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print(f"{func.__name__} 실행 시간: {end - start:.4f}초") return result return wrapper @timerdef slow_function(): time.sleep(2) print("완료!") slow_function()
Python
복사
완료! slow_function 실행 시간: 2.0014초
Plain Text
복사

3-2.스트림릿에서 캐시 데코레이터

[2_cash.py]
캐시 데코레이터 사용예시
import streamlit as st import time @st.cache_datadef load_data(): time.sleep(3) # API나 DB에서 데이터를 가져온다고 가정 return {"a": 1, "b": 2} st.write("데이터:", load_data())
Python
복사
# lru_cache 캐시 기능 맛보기 # 함수의 반환 값을 자동으로 캐싱(Memoization) 해주는 내장 데코레이터 # 동일한 인자를 가진 함수가 반복 호출될 때 중복 계산을 피하고 빠르게 결과를 반환할 수 있도록 도와줌 import time from functools import lru_cache # 캐시 기능을 위한 데코레이터: maxsize=None이면 무제한 캐싱 @lru_cache(maxsize=None) def load_data(): print("데이터를 로딩 중입니다... (3초 대기)") time.sleep(3) # API나 DB에서 데이터를 가져오는 시뮬레이션 return {"a": 1, "b": 2} # 첫 번째 실행 (3초 소요) print("첫 번째 실행:") data = load_data() print("데이터:", data) # 두 번째 실행 (즉시 반환됨) print("\n두 번째 실행:") data = load_data() print("데이터:", data)
Python
복사
첫 번째 실행: 데이터를 로딩 중입니다... (3초 대기) 데이터: {'a': 1, 'b': 2} 두 번째 실행: 데이터: {'a': 1, 'b': 2}
Plain Text
복사

3-3.스트림릿 캐시데코레이터 미사용시

import streamlit as st import time def get_vocab_logits(): print(f"get_vocab_logits() starting") time.sleep(10) # 실제 상황에서는 LLM 추론에 해당 (10초 지연) vocab_logits = {"나는": 0.01,"내일": 0.03,"오늘": 0.25,"어제": 0.3, "산에": 0.4,"학교에": 0.5,"집에": 0.65, 오른다": 1.2,"간다": 1.05,"왔다": 0.95} print(f"get_vocab_logits() ending") return vocab_logits text = "마지막 레이어의 로짓값을 가정"st.header(text, divider='rainbow') st.subheader(text) st.title(text) st.write(text) st.text_input(label="Title", placeholder=text) st.write("# Bar Chart") st.bar_chart(get_vocab_logits()) st.caption(text)
Python
복사

코드 해석

•
이 코드는 Streamlit을 이용해 LLM의 마지막 레이어 로짓(logits)을 시각화하는 흐름을 보여주는 스크립트
[전체 흐름 요약]
1.
제목 및 UI 텍스트를 Streamlit으로 렌더링
2.
get_vocab_logits() 함수를 통해 로짓 데이터 생성 (10초 지연)
3.
해당 데이터를 bar_chart()를 통해 시각화
4.
캡션 표시
[실행결과 분석]
1.
input 상자에 글자를 입력하고 탭을 클릭하면, 약 10초 동안 위와 같이 그래프가 흐리게 나타나면서 지연 현상이 발생함
2.
이런 현상이 나타나는 이유는, 사용자의 상호작용에 의해 화면에 변화가 생기면, 이를 반영하기 위해 파이썬 스크립트 전체가 다시 실행되어야 하고, 그 과정에서 로짓 산출을 위해 10초 간의 대기 시간이 발생하기 때문
3.
이러한 불합리 점을 개선하기 위해 스트림릿에서는 캐싱 데코레이터 매커니즘을 제공
4.
@st.cache_data 데코레이터를 사용하면 함수를 실행한 결과가 캐시에 보관됨➡️ 이후부터는, 파라미터가 달라졌거나 구현 내용이 달라진 경우에 한해서만 함수를 다시 실행
5.
만일 함수의 코드가 변경되지 않았고, 이전에 호출된 파라미터와 동일하다면, 캐시에 보관되어 있는 결과를 반환함으로써 불필요한 재실행이 되지 않음

3-4. 스트림릿 캐시데코레이터 사용시

# st_cache_data.py import streamlit as st import time @st.cache_datadef get_vocab_logits(param=0): print(f"get_vocab_logits({param}) starting") time.sleep(10) vocab_logits = {"나는": 0.01,"내일": 0.03,"오늘": 0.25,"어제": 0.3,"산에": 0.4,"학교에": 0.5,"집에": 0.65, "오른다": 1.2,"간다": 1.05,"왔다": 0.95} vocab_logits = {word: logit + param for word, logit in vocab_logits.items()} print(f"get_vocab_logits({param}) ending") return vocab_logits text = "마지막 레이어의 로짓값을 가정"st.header(text, divider='rainbow') st.subheader(text) st.title(text) st.write(text) user_input = st.number_input(label="로짓값에 더해지는 숫자를 입력하세요.", value=0) st.write("# Bar Chart") st.bar_chart(get_vocab_logits(user_input)) st.caption(text)
Python
복사

코드해석

[핵심 흐름]
1.
사용자 입력 받기
•
st.number_input()을 통해 사용자로부터 숫자 입력
1.
로짓 호출 및 차트 출력
•
bar_chart()로 결과를 시각화
[데코레이터]
•
@st.cache_data Streamlit의 데이터 캐시 데코레이터로, 동일한 입력값이면 결과를 캐시하여 재실행 방지
[특이사항]
•
예상대로 처음 실행한 파라미터에서 대해서는 지연 현상이 발생하지만, 이미 실행했던 파라미터에서 대해서는 지연 없이 화면에 그래프로 출력되는 것을 확인할 수 있음

4.리소스 캐싱

1.
또 하나의 데코레이터
•
@st.cache_data 데코레이터가 데이터에 대한 캐싱 메커니즘을 적용
•
@st.cache_resource 데코레이터는 머신러닝 모델이나 데이터베이스 컨넥션 등의 리소스를 효율적으로 사용하도록 도움
•
@st.cache_resource를 사용하면 프로그램에서 사용되는 이러한 리소스를 한 번만 로드하거나 연결하고, 이후의 호출에서는 캐싱된 인스턴스를 재사용함으로써 처리 시간을 단축할 수 있음

✅ 공통점

항목
설명
목적
불필요한 중복 연산 방지, 성능 최적화
캐시 위치
Streamlit 내부 메모리
자동 무효화
함수 내부 코드 또는 입력값 변경 시 캐시 무효화
사용 방식
함수 위에 데코레이터 형식으로 선언

⚖️ 차이점 비교

항목
@st.cache_data
@st.cache_resource
주 용도
데이터 연산 결과 캐싱
객체 또는 리소스 재사용
적합 대상
데이터프레임, 리스트, 딕셔너리 등(읽기 전용 결과)
머신러닝 모델, DB 연결, API 클라이언트 등
반환값
계산 결과(데이터)
객체 그 자체 (상태 포함)
상태 유지
❌ 불가능 (순수 함수 전제)
✅ 가능 (상태 있는 객체도 재사용)
대표 예시
pd.read_csv(), api.get_data()
load_model(), sqlite.connect()

📌 어떤 상황에서 무엇을 써야 할까?

상황
추천 캐시
대용량 CSV나 API 결과를 반복 사용
@st.cache_data
데이터 처리 함수가 오래 걸리는 경우
@st.cache_data
Scikit-learn, LLM 모델 등 학습된 모델 불러오기
@st.cache_resource
DB 연결 객체를 유지하며 재사용하고 싶을 때
@st.cache_resource
외부 리소스를 초기화하고 한 번만 쓰고 싶을 때
@st.cache_resource

4-1.데이터 캐쉬 실습

[3_data_cash.py]
import streamlit as st import pandas as pd @st.cache_datadef load_csv(): return pd.read_csv("data_cash\data.csv") df = load_csv() st.dataframe(df)
Python
복사

4-2.resource 캐쉬 실습

import streamlit as st # 파이썬 객체를 직렬화(serialize)하거나 병렬 처리(parallel processing)를 할 때 사용 라이브러리 # ML 모델 저장/로딩, 큰 데이터 구조 저장, 병렬 연산 처리 등에 자주 활용 import joblib #해당 모델은 아이리스 분류 모델에 대해 학습된 모델pkl임임 @st.cache_resource def load_model(): return joblib.load("model_pkl/model.pkl") model = load_model() prediction = model.predict([[1, 2, 2.5, 3.1]]) st.write("예측:", prediction)
Python
복사

4-3.data+resource 캐쉬 실습

import streamlit as st import joblib # 🌱 학습된 모델 로딩 (캐시 사용으로 효율성 향상) @st.cache_resource def load_model(): return joblib.load("model_pkl/model.pkl") model = load_model() st.title("🌸 아이리스 품종 예측기") st.markdown("꽃받침과 꽃잎의 길이/너비를 입력하면 품종을 예측합니다.") # 📥 사용자 입력 받기 sepal_length = st.number_input("① Sepal Length (cm)", min_value=0.0, max_value=10.0, value=5.1) sepal_width = st.number_input("② Sepal Width (cm)", min_value=0.0, max_value=10.0, value=3.5) petal_length = st.number_input("③ Petal Length (cm)", min_value=0.0, max_value=10.0, value=1.4) petal_width = st.number_input("④ Petal Width (cm)", min_value=0.0, max_value=10.0, value=0.2) # 🧮 입력값 배열 생성 user_input = [[sepal_length, sepal_width, petal_length, petal_width]] # 🔍 예측 실행 버튼 if st.button("예측 실행"): prediction = model.predict(user_input) st.success(f"🌼 예측 결과: `{prediction[0]}` 품종으로 분류됨")
Python
복사