Spaces:
Runtime error
Runtime error
| 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.", | |
| } | |
| 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) | |