CoolFace
Apppublic

KorahDavid001/neural-network-api

sourceHugging Faceupdated 11mo agoView on Hugging Face
0likes
app.py195 linesDownload Raw Back to root
1import streamlit as st
2import torch
3import torch.nn as nn
4import numpy as np
5import pandas as pd
6
7# Set page config
8st.set_page_config(
9    page_title="Neural Network Classifier",
10    page_icon="๐Ÿง ",
11    layout="wide"
12)
13
14# Model architecture
15class ReuploadingNN(nn.Module):
16    def __init__(self, input_dim, hidden_dim, num_layers):
17        super().__init__()
18        self.input_dim = input_dim
19        self.hidden_dim = hidden_dim
20        self.num_layers = num_layers
21        self.layers = nn.ModuleList([nn.Linear(input_dim, hidden_dim), nn.ReLU()])
22        for _ in range(num_layers - 1):
23            self.layers.append(nn.Linear(hidden_dim + input_dim, hidden_dim))
24            self.layers.append(nn.ReLU())
25        self.output_layer = nn.Linear(hidden_dim, 1)
26
27    def forward(self, x):
28        original_input = x
29        x = self.layers[0](x)
30        x = self.layers[1](x)
31        for i in range(2, len(self.layers), 2):
32            x = torch.cat([x, original_input], dim=1)
33            x = self.layers[i](x)
34            x = self.layers[i+1](x)
35        return torch.sigmoid(self.output_layer(x))
36
37# Load model
38@st.cache_resource
39def load_model():
40    checkpoint = torch.load('best_model.pth', map_location='cpu')
41    model = ReuploadingNN(
42        checkpoint['input_dim'], 
43        checkpoint['hyperparameters']['hidden_dim'], 
44        checkpoint['hyperparameters']['num_layers']
45    )
46    model.load_state_dict(checkpoint['model_state_dict'])
47    model.eval()
48
49    norm_params = np.load('normalization_params.npz')
50    return model, norm_params['mean'], norm_params['std'], checkpoint
51
52model, mean, std, checkpoint = load_model()
53
54# Title and description
55st.title("๐Ÿง  Neural Network Signal Classifier")
56st.markdown("### Classify signals as **Signal** or **Background**")
57
58# Display model info
59with st.expander("โ„น๏ธ Model Information"):
60    st.write(f"**Model Type:** ReuploadingNN")
61    st.write(f"**Hidden Dimensions:** {checkpoint['hyperparameters']['hidden_dim']}")
62    st.write(f"**Number of Layers:** {checkpoint['hyperparameters']['num_layers']}")
63    st.write(f"**Validation AUC:** {checkpoint['val_auc']:.4f}")
64    st.write(f"**Input Features:** {checkpoint['input_dim']}")
65
66# Feature names
67feature_names = [
68    "10th Percentile", "90th Percentile", "Energy", "Entropy",
69    "Interquartile Range", "Kurtosis", "Maximum", "Mean Absolute Deviation",
70    "Mean", "Median", "Minimum", "Range", "Robust Mean Absolute Deviation",
71    "Root Mean Squared", "Skewness", "Total Energy", "Uniformity", "Variance"
72]
73
74# Two tabs: Manual input and CSV upload
75tab1, tab2 = st.tabs(["๐Ÿ“ Manual Input", "๐Ÿ“ Upload CSV"])
76
77with tab1:
78    st.markdown("#### Enter feature values:")
79
80    # Create 3 columns for inputs
81    cols = st.columns(3)
82    features = []
83
84    for i, name in enumerate(feature_names):
85        with cols[i % 3]:
86            value = st.number_input(
87                name, 
88                value=0.0, 
89                format="%.6f",
90                key=f"feature_{i}"
91            )
92            features.append(value)
93
94    if st.button("๐ŸŽฏ Predict", type="primary", use_container_width=True):
95        # Make prediction
96        features_array = np.array(features, dtype=np.float32)
97        features_normalized = (features_array - mean) / std
98
99        with torch.no_grad():
100            input_tensor = torch.tensor(features_normalized, dtype=torch.float32).unsqueeze(0)
101            probability = model(input_tensor).item()
102
103        prediction_class = 'Signal' if probability > 0.5 else 'Background'
104        confidence = abs(probability - 0.5) * 2
105
106        # Display results
107        st.markdown("---")
108        st.markdown("### ๐Ÿ“Š Prediction Results")
109
110        col1, col2, col3 = st.columns(3)
111
112        with col1:
113            if prediction_class == 'Signal':
114                st.success(f"### ๐ŸŽฏ {prediction_class}")
115            else:
116                st.info(f"### ๐Ÿ”ต {prediction_class}")
117
118        with col2:
119            st.metric("Probability", f"{probability:.4f}")
120
121        with col3:
122            st.metric("Confidence", f"{confidence:.2%}")
123
124        st.progress(probability)
125
126with tab2:
127    st.markdown("#### Upload a CSV file")
128    st.info("๐Ÿ“Œ If your CSV has labels in the first column, they will be automatically removed")
129
130    uploaded_file = st.file_uploader("Choose a CSV file", type="csv")
131
132    if uploaded_file is not None:
133        # Read CSV
134        df = pd.read_csv(uploaded_file)
135
136        # Remove non-numeric columns (like 'signal', 'Subject', etc.)
137        df_numeric = df.select_dtypes(include=[np.number])
138
139        # If first column looks like labels (0/1), skip it
140        if df_numeric.shape[1] > 18:
141            st.info("Detected label column - removing it")
142            df_numeric = df_numeric.iloc[:, 1:]
143
144        st.write(f"Loaded {len(df_numeric)} samples with {df_numeric.shape[1]} features")
145        st.dataframe(df_numeric.head())
146
147        if df_numeric.shape[1] != 18:
148            st.error(f"โš ๏ธ Expected 18 features, but got {df_numeric.shape[1]}. Please check your CSV.")
149        else:
150            if st.button("๐ŸŽฏ Predict All", type="primary"):
151                predictions = []
152                progress_bar = st.progress(0)
153
154                for idx, row in df_numeric.iterrows():
155                    features_array = row.values.astype(np.float32)
156                    features_normalized = (features_array - mean) / std
157
158                    with torch.no_grad():
159                        input_tensor = torch.tensor(features_normalized, dtype=torch.float32).unsqueeze(0)
160                        probability = model(input_tensor).item()
161
162                    prediction_class = 'Signal' if probability > 0.5 else 'Background'
163                    predictions.append({
164                        'Sample': idx + 1,
165                        'Class': prediction_class,
166                        'Probability': probability
167                    })
168
169                    progress_bar.progress((idx + 1) / len(df_numeric))
170
171                results_df = pd.DataFrame(predictions)
172                st.markdown("### ๐Ÿ“Š Batch Prediction Results")
173                st.dataframe(results_df)
174
175                signal_count = len(results_df[results_df['Class'] == 'Signal'])
176                background_count = len(results_df[results_df['Class'] == 'Background'])
177
178                col1, col2 = st.columns(2)
179                with col1:
180                    st.metric("๐ŸŽฏ Signal", signal_count)
181                with col2:
182                    st.metric("๐Ÿ”ต Background", background_count)
183
184                csv = results_df.to_csv(index=False)
185                st.download_button(
186                    "๐Ÿ“ฅ Download Results",
187                    csv,
188                    "predictions.csv",
189                    "text/csv",
190                    key='download-csv'
191                )
192
193st.markdown("---")
194st.markdown("Made with โค๏ธ using Streamlit")
195