Step 4: Implement the UI with StreamLit¶
In step 3, we have implemented a Flow which dynamically creates a Work when a new request is added to the requests list.
From the UI, we create 3 pages with StreamLit:
Page 1: Create a form with add a new request to the Flow state requests.
Page 2: Iterate through all the requests and display the associated information.
Page 3: Display the entire App State.
Render All Pages¶
def render_fn(state: AppState):
import streamlit as st
page_names_to_funcs = {
"Create a new Run": partial(page_1__create_new_run, state=state),
"View your Runs": partial(page_2__view_run_lists, state=state),
"View the App state": partial(page_3__view_app_state, state=state),
}
selected_page = st.sidebar.selectbox(
"Select a page", page_names_to_funcs.keys())
page_names_to_funcs[selected_page]()
Page 1
def page_1__create_new_run(state):
import streamlit as st
st.markdown("# Create a new Run 🎈")
# 1: Collect arguments from the users
id = st.text_input("Name your run", value="my_first_run")
github_repo = st.text_input(
"Enter a Github Repo URL", value="https://github.com/Lightning-AI/lightning-quick-start.git"
)
default_script_args = (
"--trainer.max_epochs=5"
" --trainer.limit_train_batches=4"
" --trainer.limit_val_batches=4"
" --trainer.callbacks=ModelCheckpoint"
" --trainer.callbacks.monitor=val_acc"
)
default_requirements = "torchvision, pytorch_lightning, jsonargparse[signatures]"
script_path = st.text_input("Enter your script to run", value="train_script.py")
script_args = st.text_input("Enter your base script arguments", value=default_script_args)
requirements = st.text_input("Enter your requirements", value=default_requirements)
ml_framework = st.radio(
"Select your ML Training Frameworks", options=["PyTorch Lightning", "Keras", "Tensorflow"]
)
if ml_framework not in ("PyTorch Lightning"):
st.write(f"{ml_framework} isn't supported yet.")
return
clicked = st.button("Submit")
# 2: If clicked, create a new request.
if clicked:
new_request = {
"id": id,
"train": {
"github_repo": github_repo,
"script_path": script_path,
"script_args": script_args.split(" "),
"requirements": requirements.split(" "),
"ml_framework": ml_framework,
},
}
# 3: IMPORTANT: Add a new request to the state in-place.
# The flow receives the UI request and dynamically create
# and run the associated work from the request information.
state.requests = state.requests + [new_request]
Page 2
def page_2__view_run_lists(state):
import streamlit as st
st.markdown("# Run Lists 🎈")
# 1: Iterate through all the requests in the state.
for i, r in enumerate(state.requests):
i = str(i)
# 2: Display information such as request, logs, work state, model score.
work = state._state["structures"]["ws"]["works"][f"w_{i}"]
with st.expander(f"Expand to view Run {i}", expanded=False):
if st.checkbox("Expand to view your configuration", key=i):
st.json(r)
if st.checkbox("Expand to view logs", key=i):
st.code(body=work["vars"]["logs"])
if st.checkbox("Expand to view your work state", key=i):
work["vars"].pop("logs")
st.json(work)
best_model_score = r.get("best_model_score", None)
if best_model_score:
if st.checkbox("Expand to view your run performance", key=i):
st.json({"best_model_score": best_model_score, "best_model_path": r.get("best_model_path")})
Page 3
def page_3__view_app_state(state):
import streamlit as st
st.markdown("# App State 🎈")
st.write(state._state)