본문 바로가기
MLOps

MLOps - 6. Streamlit

by cocacola0 2022. 5. 22.

출처 : 변성윤님 블로그.
출처 : 부스트캠프 AI Tech.

1. Streamlit

1.1 웹 서비스를 만드는 과정

  • 데이터 분석가(또는 데이터 사이언티스트 등)가 웹 서비스를 작업하는 Flow
  • 데이터 Product로 중요하게 된다면 프론트엔드/PM 조직과 협업
    • 단, 프론트엔드/PM 조직은 다른 웹도 만들고 있어서 빠르게 이터레이션이 어려움
  • 다른 조직의 도움 없이 빠르게 웹 서비스를 만드는 방법이 무엇일까? 이런 문제를 해결하기 위해 등장한 것이 Streamlit
  • 주의할 점 : 툴이나 라이브러리에 집착하지 말고, 점진적으로 문제를 해결하는 과정에 집중하기!
  • 현재 사용하는 도구의 장단점은 어떤 것이고 새로운 대안이 있을지 항상 생각해보기!
  • 강의에선 Voila - Streamlit 순서로 했지만, 추후엔 Streamlit부터 시작해도 괜찮음 모든 것은 프로젝트의 요구 조건에 따라 다름!

1.2 Streamlit의 대안

1) R의 Shiny
2) Flask, Fast API : 백엔드를 직접 구성 + 프론트엔드 작업도 진행
3) Dash : 제일 기능이 풍부한 Python 대시보드 라이브러리
4) Voila : Jupyter Notebook을 바로 시각화 가능

1.3 Streamlit Component

1.3.1 Streamlit 소개

1.3.2 Streamlit 장점

  • 파이썬 스크립트 코드를 조금만 수정하면 웹을 띄울 수 있음
  • 백엔드 개발이나 HTTP 요청을 구현하지 않아도 됨
  • 다양한 Component 제공해 대시보드 UI 구성할 수 있음
  • Streamlit Cloud도 존재해서 쉽게 배포할 수 있음(단, Community Plan은 Public Repo만 가능)
  • 화면 녹화 기능(Record) 존재

1.3.3 Streamlit 설치 & 실행

$ pip3 install streamlit
$ streamlit run streamlit-basic.py
$ streamlit run streamlit-basic.py --server.port 30003

1.3.4 Streamlit Component basics

# Title, Header, Write
import treamlit as st
import pandas as pd
import numpy as np
import time

st.title("Title")
st.header("Header")
st.subheader("subheader")

st.write("Write Something")


# streamlit button
if st.button("버튼이 클랙되면"):
    st.write("클리 후 보이는 메세지!")
if st.button("버튼이 클랙되면2"):
    st.write("클리 후 보이는 메세지!2") 


# streamlit checkbox
checkbox_btn = st.checkbox("체크박스 버튼")

if checkbox_btn:
    st.write("체크박스 버튼 클릭!")

checkbox_btn2 = st.checkbox("체크박스 버튼", value=True)
if checkbox_btn2:
    st.write("button2")


# streamlit pandas dataframe, markdown
# st.write : 보여줄 수 있는 것이면 어떤 것이든 보여줌
# st.dataframe : Interactive한 Dataframe, 컬럼 클릭이 가능하고 정렬도 가능
# st.table : Static한 Dataframe
df = pd.DataFrame({'first column' : [1,2,3,4,], 'second column' : [10,20,30,40]})
st.markdown('======')
st.write(df)
st.dataframe(df)
st.table(df)

# Dataframe의 Max 값을 색칠할 수 있음
st.dataframe(df.style.highlight_max(axis=0))
st.table(df.style.highlight_max(axis=0))


# streamlit metric, json
st.metric("My metric", 42,2)
st.json(df.to_json())


# Streamlit Line Chart
chart_data = pd.DataFrame(np.random.randn(20,3), columns = ['a','b','c'])
st.line_chart(chart_data)


# Streamlit map Chart
map_data = pd.DataFrame(np.random.randn(1000,2) / [50,50] , columns = ['lat','lon'])
st.map(map_data)


# Streamlit Chart
# 그 외에도 Plotly Chart 등을 쉽게 사용할 수 있음 
# Chart 문서 - https://docs.streamlit.io/library/api-reference/charts


# Streamlit Radio Button, Select Box
selected_item = st.radio("Radio Part", ('a','b','c'))
if selected_item == 'a':
    st.write('a')
elif selected_item == 'b':
    st.write('b')
elif selected_item == 'c':
    st.write('c!')

option = st.selectbox('please select in select box!', ('kyle','seongyun','zzsza'))
st.write('you selected: ', option) 


# Streamlit Multi Select Box
multi_select = st.multiselect('select multi!', ['a','b','c','d'])
st.write('you selected: ', multi_select) 


# Streamlit Slider
value = st.slider('select a range of values ', min = 0.0, max = 100.0, default = (25.0, 75.0))
st.write('values : ', values)


# Streamlit Input Box, Caption, Code, Latex
text_input = st.text_input('input text')
st.write(text_input)

password_input = st.text_input("암호를 입력해주세요 : ", type = "password")

number_input = st.number_input("숫자를 입력해주세요")
st.write(number_input)

st.date_input("날짜를 입력하세요")
st.time_input("시간을 입력하세요")

st.caption("This is caption")
st.code("a = 123")
st.latex("\int a x^2 \,dx")


# Sidebar에는 파라미터를 지정하거나, 암호를 설정할 수 있음
st.sidebar.button("hi")
# 기존 method 앞에 sidebar를 붙이면 sidebar에 보이게 됨


# Streamlit Layout - Columns
col1, col2, col3, col4 = st.columns(4)
col1.write("this is col1")
col2.write("this is col2")
col3.write("this is col3")
col4.write("this is col4!")


# Streamlit Layout - Expander
with st.expander("클릭하면 열려요!"):
    st.write("content!")


# Streamlit Spinner
# 연산이 진행되는 도중 메세지를 보여주고 싶은 경우
with st.spinner("Please wait.."):
    time.sleep(5)


# Streamlit Ballons
# 직접 실행 
st.ballons()


# Streamlit Status Box
st.success("Success")
st.info("Info")
st.warning("Warning")
st.error("Error message")


# Streamlit Form
with st.form(key = "입력 form"):
    username = st.text_input("Username")
    password = st.text_input("Password", type="password")
    st.form_submit_button("login")


# Streamlit File Uploader
uploaded_file = st.file_uploader("Choose a file", type = ["png","jpg","jpeg"])


# Streamlit API Document
# https://docs.streamlit.io/library/api-reference

1.3.5 Streamlit Cheat Sheet

1.3.6 Streamlit Data Flow

  • Streamlit의 화면에서 무언가 업데이트되면 전체 Streamlit 코드가 다시 실행
    • 1) Code가 수정되는 경우
    • 2) 사용자가 Streamlit의 위젯과 상호작용하는 경우(버튼 클릭, 입력 상자에 텍스트 입력시 등)

1.4 Session State

  • Streamlit의 Data Flow로 인해 매번 코드가 재실행되며 중복 이벤트를 할 수 없음
    • Global Variable 처럼 서로 공유할 수 있는 변수가 필요
  • Streamlit 0.84 버전에 session_state가 개발됨
  • st.session_state.{session_state_value}
  • session_state_value에 저장해서 활용하는 방식

1.4.1 Session State가 없다면

  • Increment 버튼을 누르면 +1, Decrement 버튼을 누르면 -1이 되는 Counter 예제
  • 버튼을 누를 때마다 코드가 재실행되어 count_value = 0 으로 되서
    • increment button을 몇번 클릭해도 값은 1
    • decrement button을 몇번 클릭해도 값은 -1
st.title("Counter Example without session state")
count_value = 0
increment = st.button('Increment')
if increment:
    count_value += 1

decrement = st.button('Decrement')
if decrement:
    count_value -= 1

st.write('Count = ', count_value)

1.4.2 Session State가 있다면

  • 의도된 대로 정상 작동
st.title("Counter Example with session state")

if 'count' not in st.session_state:
    st.session_state.count = 0

increment = st.button('Increment')
if increment:
    st.session_state.count += 1

decrement = st.button('Decrement')
if decrement:
    st.session_state.count -= 1

st.write('Count = ', st.session_state.count)

1.4.3 Session State more info

1.5 Streamlit Cache - @st.cache

  • 매번 다시 실행하는 특성 때문에 데이터도 매번 다시 읽을 수 있음
  • 이런 경우 @st.cache 데코레이터를 사용해 캐싱하면 좋음(캐싱 : 성능을 위해 메모리 등에 저장하는 행위)
  • 데이터를 읽는 함수를 만들고, 데코레이터를 적용
DATE_COLUMN = 'date/time'
DATA_URL = ("https://s3-us-west-2.amazonaws.com/streamlit-demo-data/uber-raw-data-sep14.csv.gz")

@st.cache
def load_data(nrow):
    data = pd.read_csv(DATA_URL, nrows=nrows)
    lowercase = lambda x: str(x).lower()
    data.remane(lowercase, axis='columns', inplace=True)
    data[DATE_COLUMN] = pd.to_datetime(data[DATA_COLUMN])
    return data 

'MLOps' 카테고리의 다른 글

MLOps - 8. Streamlit 실습  (0) 2022.05.23
MLOps - 7. Streamlit  (0) 2022.05.23
MLOps - 5. Voila, ipywidget  (0) 2022.05.21
MLOps - 4. Voila, ipywidget  (0) 2022.05.20
MLOps - 3. 머신러닝 프로젝트 라이프 사이클  (0) 2022.05.19

댓글