actRecog / src /streamlit_app.py
Fola-lad's picture
ui adjustment phyphox instruction adjustment
c37dadc
Raw
History Blame Contribute Delete
7.16 kB
import os
import streamlit as st
import numpy as np
import pandas as pd
# Paths anchored to the repo root regardless of working directory
_SRC_DIR = os.path.dirname(os.path.abspath(__file__))
_REPO_ROOT = os.path.dirname(_SRC_DIR)
_SAMPLES_PATH = os.path.join(_REPO_ROOT, "data", "samples.csv")
_NORM_PATH = os.path.join(_REPO_ROOT, "data", "norm_params.json")
LABEL_MAP = {
0: "WALKING",
1: "WALKING_UPSTAIRS",
2: "WALKING_DOWNSTAIRS",
3: "SITTING",
4: "STANDING",
5: "LAYING",
}
EXPLANATIONS = {
"LAYING": "Minimal movement detected across all axes with low acceleration magnitude: consistent with a stationary horizontal posture.",
"SITTING": "Low dynamic acceleration with a stable gravity component suggests a stationary upright posture with little body movement.",
"STANDING": "Similar to sitting but with slight postural micro-movements. This class is often the hardest to distinguish from sitting.",
"WALKING": "Rhythmic periodic acceleration with peaks on the vertical axis: consistent with level walking at normal cadence.",
"WALKING_DOWNSTAIRS": "Downward gravitational shift with higher impact peaks characteristic of descending a staircase.",
"WALKING_UPSTAIRS": "Elevated vertical acceleration effort with upward body displacement: consistent with climbing stairs.",
}
@st.cache_resource
def load_model(filename: str):
try:
from huggingface_hub import hf_hub_download
import tensorflow as tf
from model_def import FeedForwardNetwork, Conv1DNetwork # noqa: F401
model_path = hf_hub_download(
repo_id="Group3DActRecog/actRecog",
filename=filename,
repo_type="space",
)
model = tf.keras.models.load_model(
model_path,
custom_objects={
"FeedForwardNetwork": FeedForwardNetwork,
"Conv1DNetwork": Conv1DNetwork,
},
)
return model, "ready"
except Exception as e:
return None, f"error: {e}"
st.set_page_config(
page_title="Human Activity Recognition",
page_icon="🏃",
layout="wide",
)
st.title("Human Activity Recognition")
st.markdown(
"Deep learning classifier trained on 561 smartphone sensor features "
"from the [UCI HAR dataset](https://www.kaggle.com/datasets/uciml/human-activity-recognition-with-smartphones). "
"Classifies six daily activities from accelerometer and gyroscope readings."
)
with st.sidebar:
st.header("About")
st.markdown("""
**Dataset:** UCI Human Activity Recognition
**Subjects:** 30 volunteers aged 19–48
**Sensor:** Samsung Galaxy S II (waist-mounted)
**Sampling rate:** 50Hz
**Features:** 561 time + frequency domain features
**Classes:** 6 activities of daily living
""")
st.markdown("---")
st.markdown("**Models**")
st.markdown("""
**FFN**: Feedforward Network
Dense(512) → Dense(256) → Dense(128)
BatchNorm + Dropout(0.3) per layer
**CNN**: 1D Convolutional Network
Conv1D(64) → Conv1D(128) → Conv1D(256)
GlobalAvgPool → Dense(128)
""")
st.markdown("---")
ffn_model, ffn_status = load_model("model.keras")
cnn_model, cnn_status = load_model("har_cnn.keras")
if ffn_status != "ready" or cnn_status != "ready":
if ffn_status != "ready":
st.warning(f"FFN not loaded: {ffn_status}")
if cnn_status != "ready":
st.warning(f"CNN not loaded: {cnn_status}")
tab1, tab2 = st.tabs(["Select a Sample", "Upload Phyphox CSV"])
with tab1:
st.subheader("Select a pre-loaded test sample")
st.caption(
"Each sample is one 2.56-second window of sensor data "
"from a test subject the model has never seen during training."
)
try:
samples_df = pd.read_csv(_SAMPLES_PATH)
feature_cols = [c for c in samples_df.columns if c not in ["Activity", "subject"]]
sample_labels = [
f"Sample {i+1} : {row['Activity']}"
for i, (_, row) in enumerate(samples_df.iterrows())
]
selected = st.selectbox("Choose a sample:", sample_labels)
selected_idx = sample_labels.index(selected)
selected_row = samples_df.iloc[selected_idx]
true_label = selected_row["Activity"]
feature_vector = selected_row[feature_cols].values.astype(np.float32)
col1, col2 = st.columns(2)
with col1:
st.metric("True Activity", true_label)
with col2:
st.metric("Feature count", len(feature_vector))
if st.button("Classify this sample", type="primary"):
if ffn_status != "ready" or cnn_status != "ready":
st.error("One or both models not loaded: cannot predict yet.")
else:
arr = feature_vector.reshape(1, -1)
ffn_probs = ffn_model.predict(arr, verbose=0)[0]
cnn_probs = cnn_model.predict(arr, verbose=0)[0]
ffn_idx = int(np.argmax(ffn_probs))
cnn_idx = int(np.argmax(cnn_probs))
ffn_label = LABEL_MAP[ffn_idx]
cnn_label = LABEL_MAP[cnn_idx]
ffn_conf = float(ffn_probs[ffn_idx]) * 100
cnn_conf = float(cnn_probs[cnn_idx]) * 100
st.markdown("---")
st.subheader("Model comparison")
left, right = st.columns(2)
with left:
st.markdown("#### Feedforward Network")
if ffn_label == true_label:
st.success(f"**{ffn_label}** · {ffn_conf:.1f}% confidence · ✓ Correct")
else:
st.error(f"**{ffn_label}** · {ffn_conf:.1f}% confidence · ✗ Incorrect (true: {true_label})")
st.markdown(f"_{EXPLANATIONS[ffn_label]}_")
st.markdown("**Confidence across all classes**")
st.bar_chart(pd.DataFrame(
{"Confidence (%)": [float(ffn_probs[i]) * 100 for i in range(6)]},
index=[LABEL_MAP[i] for i in range(6)]
))
with right:
st.markdown("#### 1D Convolutional Network")
if cnn_label == true_label:
st.success(f"**{cnn_label}** · {cnn_conf:.1f}% confidence · ✓ Correct")
else:
st.error(f"**{cnn_label}** · {cnn_conf:.1f}% confidence · ✗ Incorrect (true: {true_label})")
st.markdown(f"_{EXPLANATIONS[cnn_label]}_")
st.markdown("**Confidence across all classes**")
st.bar_chart(pd.DataFrame(
{"Confidence (%)": [float(cnn_probs[i]) * 100 for i in range(6)]},
index=[LABEL_MAP[i] for i in range(6)]
))
except FileNotFoundError:
st.error("Sample data file not found. Add `data/samples.csv` to the repo.")
with tab2:
from phyphox_app_block import render_phyphox_tab
render_phyphox_tab(ffn_model, ffn_status, cnn_model, cnn_status, _NORM_PATH)