KorahDavid001/neural-network-api
0
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 