oewis16 commited on
Commit
b9fe86b
Β·
verified Β·
1 Parent(s): f784919

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -31
app.py CHANGED
@@ -27,31 +27,36 @@ CLASS_RISK = {
27
  }
28
  COLORS = ['#2ecc71','#3498db','#e74c3c','#f39c12','#9b59b6']
29
 
30
- @spaces.GPU
31
  def build_model():
32
- m = models.Sequential([
33
- layers.Input(shape=(187, 1)),
34
- layers.Conv1D(64, 7, padding='same', activation='relu', kernel_regularizer=regularizers.l2(1e-4)),
35
- layers.BatchNormalization(), layers.MaxPooling1D(2), layers.Dropout(0.2),
36
- layers.Conv1D(128, 5, padding='same', activation='relu', kernel_regularizer=regularizers.l2(1e-4)),
37
- layers.BatchNormalization(), layers.MaxPooling1D(2), layers.Dropout(0.25),
38
- layers.Conv1D(256, 3, padding='same', activation='relu', kernel_regularizer=regularizers.l2(1e-4)),
39
- layers.BatchNormalization(), layers.MaxPooling1D(2), layers.Dropout(0.3),
40
- layers.Conv1D(256, 3, padding='same', activation='relu', kernel_regularizer=regularizers.l2(1e-4)),
41
- layers.BatchNormalization(), layers.GlobalAveragePooling1D(), layers.Dropout(0.3),
42
- layers.Dense(256, activation='relu', kernel_regularizer=regularizers.l2(1e-4)),
43
- layers.BatchNormalization(), layers.Dropout(0.4),
44
- layers.Dense(128, activation='relu', kernel_regularizer=regularizers.l2(1e-4)),
45
- layers.Dropout(0.3),
46
- layers.Dense(5, activation='softmax')
47
- ], name="CNN_ECG")
48
- m.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
49
- m.load_weights("cnn_weights.weights.h5")
 
 
 
 
 
50
  return m
51
 
52
  model = build_model()
53
 
54
- @spaces.GPU
55
  def predict_ecg(text_input):
56
  try:
57
  cleaned = text_input.replace(",", " ").replace("\n", " ").replace("\t", " ")
@@ -66,9 +71,12 @@ def predict_ecg(text_input):
66
 
67
  scaler = MinMaxScaler()
68
  signal_scaled = scaler.fit_transform(features.reshape(-1, 1)).reshape(1, 187, 1)
69
- probs = model.predict(signal_scaled, verbose=0)[0]
70
- pred_class = int(np.argmax(probs))
71
- confidence = float(np.max(probs)) * 100
 
 
 
72
 
73
  fig, axes = plt.subplots(1, 2, figsize=(14, 4))
74
  fig.patch.set_facecolor('#0e1117')
@@ -89,7 +97,8 @@ def predict_ecg(text_input):
89
 
90
  ax2 = axes[1]
91
  ax2.set_facecolor('#1a1a2e')
92
- bars = ax2.barh([CLASS_MAPPING[i] for i in range(5)], probs*100, color=COLORS, alpha=0.85)
 
93
  for bar, val in zip(bars, probs):
94
  ax2.text(val*100+0.5, bar.get_y()+bar.get_height()/2,
95
  f"{val*100:.1f}%", va='center', color='white', fontsize=9)
@@ -102,10 +111,10 @@ def predict_ecg(text_input):
102
 
103
  plt.tight_layout()
104
 
105
- result = f"**πŸ€– Predicted:** {CLASS_MAPPING[pred_class]}\n\n**πŸ“Š Confidence:** {confidence:.2f}%\n\n**βš•οΈ Risk:** {CLASS_RISK[pred_class]}"
106
  true_out = ""
107
  if true_label is not None:
108
- match = "βœ… Correct!" if pred_class == true_label else "❌ Incorrect"
109
  true_out = f"**🏷️ True Label:** {CLASS_MAPPING.get(true_label,'Unknown')} β€” {match}"
110
  stats = f"**Signal Stats:** R-peak={features.max():.4f} @ t={r_idx} | Min={features.min():.4f} | Mean={features.mean():.4f} | Std={features.std():.4f}"
111
 
@@ -114,6 +123,7 @@ def predict_ecg(text_input):
114
  except Exception as e:
115
  return None, f"❌ Error: {str(e)}", "", ""
116
 
 
117
  with gr.Blocks(title="ECG Classification") as demo:
118
  gr.Markdown("""
119
  # πŸ«€ ECG Arrhythmia Classification
@@ -122,8 +132,11 @@ with gr.Blocks(title="ECG Classification") as demo:
122
  """)
123
  with gr.Row():
124
  with gr.Column(scale=1):
125
- text_input = gr.Textbox(label="Paste 187 or 188 ECG values", lines=8,
126
- placeholder="0.5, 0.8, 0.3, 1.0 ...")
 
 
 
127
  predict_btn = gr.Button("β–Ά Run Prediction", variant="primary")
128
  gr.Markdown("""
129
  | Label | Class | Risk |
@@ -140,9 +153,11 @@ with gr.Blocks(title="ECG Classification") as demo:
140
  true_out = gr.Markdown()
141
  stats_out = gr.Markdown()
142
 
143
- predict_btn.click(predict_ecg, inputs=[text_input],
144
- outputs=[plot_out, result_out, true_out, stats_out])
145
-
 
 
146
  gr.Markdown("*DEPI Final Project 2025*")
147
 
148
  demo.launch(ssr_mode=False)
 
27
  }
28
  COLORS = ['#2ecc71','#3498db','#e74c3c','#f39c12','#9b59b6']
29
 
30
+ # ── Build model on CPU at startup ─────────────────────────────────────────────
31
  def build_model():
32
+ with tf.device('/CPU:0'):
33
+ m = models.Sequential([
34
+ layers.Input(shape=(187, 1)),
35
+ layers.Conv1D(64, 7, padding='same', activation='relu',
36
+ kernel_regularizer=regularizers.l2(1e-4)),
37
+ layers.BatchNormalization(), layers.MaxPooling1D(2), layers.Dropout(0.2),
38
+ layers.Conv1D(128, 5, padding='same', activation='relu',
39
+ kernel_regularizer=regularizers.l2(1e-4)),
40
+ layers.BatchNormalization(), layers.MaxPooling1D(2), layers.Dropout(0.25),
41
+ layers.Conv1D(256, 3, padding='same', activation='relu',
42
+ kernel_regularizer=regularizers.l2(1e-4)),
43
+ layers.BatchNormalization(), layers.MaxPooling1D(2), layers.Dropout(0.3),
44
+ layers.Conv1D(256, 3, padding='same', activation='relu',
45
+ kernel_regularizer=regularizers.l2(1e-4)),
46
+ layers.BatchNormalization(), layers.GlobalAveragePooling1D(), layers.Dropout(0.3),
47
+ layers.Dense(256, activation='relu', kernel_regularizer=regularizers.l2(1e-4)),
48
+ layers.BatchNormalization(), layers.Dropout(0.4),
49
+ layers.Dense(128, activation='relu', kernel_regularizer=regularizers.l2(1e-4)),
50
+ layers.Dropout(0.3),
51
+ layers.Dense(5, activation='softmax')
52
+ ], name="CNN_ECG")
53
+ m.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
54
+ m.load_weights("cnn_weights.weights.h5")
55
  return m
56
 
57
  model = build_model()
58
 
59
+ # ── Predict ───────────────────────────────────────────────────────────────────
60
  def predict_ecg(text_input):
61
  try:
62
  cleaned = text_input.replace(",", " ").replace("\n", " ").replace("\t", " ")
 
71
 
72
  scaler = MinMaxScaler()
73
  signal_scaled = scaler.fit_transform(features.reshape(-1, 1)).reshape(1, 187, 1)
74
+
75
+ with tf.device('/CPU:0'):
76
+ probs = model.predict(signal_scaled, verbose=0)[0]
77
+
78
+ pred_class = int(np.argmax(probs))
79
+ confidence = float(np.max(probs)) * 100
80
 
81
  fig, axes = plt.subplots(1, 2, figsize=(14, 4))
82
  fig.patch.set_facecolor('#0e1117')
 
97
 
98
  ax2 = axes[1]
99
  ax2.set_facecolor('#1a1a2e')
100
+ bars = ax2.barh([CLASS_MAPPING[i] for i in range(5)],
101
+ probs * 100, color=COLORS, alpha=0.85)
102
  for bar, val in zip(bars, probs):
103
  ax2.text(val*100+0.5, bar.get_y()+bar.get_height()/2,
104
  f"{val*100:.1f}%", va='center', color='white', fontsize=9)
 
111
 
112
  plt.tight_layout()
113
 
114
+ result = f"**πŸ€– Predicted:** {CLASS_MAPPING[pred_class]}\n\n**πŸ“Š Confidence:** {confidence:.2f}%\n\n**βš•οΈ Risk:** {CLASS_RISK[pred_class]}"
115
  true_out = ""
116
  if true_label is not None:
117
+ match = "βœ… Correct!" if pred_class == true_label else "❌ Incorrect"
118
  true_out = f"**🏷️ True Label:** {CLASS_MAPPING.get(true_label,'Unknown')} β€” {match}"
119
  stats = f"**Signal Stats:** R-peak={features.max():.4f} @ t={r_idx} | Min={features.min():.4f} | Mean={features.mean():.4f} | Std={features.std():.4f}"
120
 
 
123
  except Exception as e:
124
  return None, f"❌ Error: {str(e)}", "", ""
125
 
126
+ # ── UI ────────────────────────────────────────────────────────────────────────
127
  with gr.Blocks(title="ECG Classification") as demo:
128
  gr.Markdown("""
129
  # πŸ«€ ECG Arrhythmia Classification
 
132
  """)
133
  with gr.Row():
134
  with gr.Column(scale=1):
135
+ text_input = gr.Textbox(
136
+ label="Paste 187 or 188 ECG values",
137
+ lines=8,
138
+ placeholder="0.5, 0.8, 0.3, 1.0 ..."
139
+ )
140
  predict_btn = gr.Button("β–Ά Run Prediction", variant="primary")
141
  gr.Markdown("""
142
  | Label | Class | Risk |
 
153
  true_out = gr.Markdown()
154
  stats_out = gr.Markdown()
155
 
156
+ predict_btn.click(
157
+ predict_ecg,
158
+ inputs=[text_input],
159
+ outputs=[plot_out, result_out, true_out, stats_out]
160
+ )
161
  gr.Markdown("*DEPI Final Project 2025*")
162
 
163
  demo.launch(ssr_mode=False)