rocky250 commited on
Commit
da258d7
·
verified ·
1 Parent(s): 70b2f7a

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +94 -57
src/streamlit_app.py CHANGED
@@ -2,10 +2,10 @@ import streamlit as st
2
  import torch
3
  import torch.nn.functional as F
4
  import numpy as np
5
- from transformers import AutoTokenizer, AutoModelForSequenceClassification
6
  from normalizer import normalize
7
  import torch.nn as nn
8
- from transformers import AutoModel
9
 
10
  st.set_page_config(page_title="Political Sentiment", layout="wide")
11
 
@@ -13,38 +13,45 @@ class BanglaPoliticalNet(nn.Module):
13
  def __init__(self, num_classes=5):
14
  super().__init__()
15
  self.banglabert = AutoModel.from_pretrained("csebuetnlp/banglabert")
 
16
  self.hidden_size = self.banglabert.config.hidden_size
17
-
18
  self.cnn_layers = nn.ModuleList([
19
- nn.Conv1d(self.hidden_size, 128, kernel_size=k, padding=k//2)
20
  for k in [3,5,7]
21
  ])
22
-
23
  self.attention = nn.MultiheadAttention(self.hidden_size, 8, batch_first=True)
24
  self.classifier = nn.Sequential(
25
- nn.Dropout(0.3),
 
26
  nn.Linear(self.hidden_size, 512),
27
- nn.ReLU(),
28
- nn.Dropout(0.2),
29
- nn.Linear(512, num_classes)
 
 
30
  )
31
-
 
 
32
  def forward(self, input_ids, attention_mask=None):
33
  bert_out = self.banglabert(input_ids, attention_mask=attention_mask).last_hidden_state
 
 
 
34
 
35
- cnn_features = []
36
- for cnn in self.cnn_layers:
37
- cnn_out = cnn(bert_out.transpose(1,2)).transpose(1,2)
38
- cnn_features.append(F.relu(cnn_out))
39
 
40
- cnn_concat = torch.cat(cnn_features, dim=-1)
41
- proj = nn.Linear(384, self.hidden_size).to(input_ids.device)
42
- attn_input = proj(cnn_concat)
43
  attn_out, _ = self.attention(attn_input, attn_input, attn_input)
44
- attn_pooled = attn_out[:, 0, :]
 
 
 
45
 
46
- logits = self.classifier(attn_pooled)
47
- return logits
48
 
49
  st.markdown("""
50
  <style>
@@ -223,23 +230,44 @@ label_colors = {
223
  @st.cache_resource
224
  def load_models():
225
  models_loaded = {}
 
226
 
227
- target_models = {
228
  "model_banglabert": "rocky250/Sentiment-banglabert",
229
  "model_mbert": "rocky250/Sentiment-mbert",
230
  "model_bbase": "rocky250/Sentiment-bbase",
231
- "model_xlmr": "rocky250/Sentiment-xlmr",
232
- "bangla_political": "rocky250/bangla-political"
233
  }
234
 
235
- for name, repo in target_models.items():
236
  try:
237
  tokenizer = AutoTokenizer.from_pretrained(repo)
238
  model = AutoModelForSequenceClassification.from_pretrained(repo)
239
- models_loaded[name] = (tokenizer, model.to('cuda' if torch.cuda.is_available() else 'cpu'))
240
- except:
 
241
  continue
242
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  return models_loaded
244
 
245
  models_dict = load_models()
@@ -252,8 +280,11 @@ def predict_single_model(text, model_name):
252
  inputs = tokenizer(clean_text, return_tensors="pt", truncation=True, padding=True, max_length=128).to(device)
253
 
254
  with torch.no_grad():
255
- outputs = model(**inputs)
256
- logits = outputs.logits
 
 
 
257
 
258
  probs = F.softmax(logits, dim=1).cpu().numpy()[0]
259
  pred_id = np.argmax(probs)
@@ -280,6 +311,7 @@ def predict_ensemble(text):
280
  return final_pred, all_predictions, avg_probs
281
  return "Error", [], np.zeros(5)
282
 
 
283
  st.markdown("""
284
  <div style='
285
  text-align: center;
@@ -308,45 +340,50 @@ with col2:
308
  selected_model = None
309
  if mode == "Single Model":
310
  model_options = {name: name for name in models_dict.keys()}
311
- selected_model = st.selectbox("Select Model:", list(model_options.keys()), index=0)
 
 
 
312
 
313
  analyze_btn = st.button("ANALYZE SENTIMENT", type="primary", use_container_width=True)
314
 
315
  if analyze_btn and user_input.strip():
316
  with st.spinner('Processing with models...'):
317
  if mode == "Single Model":
318
- model_name = selected_model
319
- final_res, probs = predict_single_model(user_input, model_name)
320
-
321
- col1, col2 = st.columns([1, 2])
322
- with col1:
323
- st.markdown(f"""
324
- <div class="main-card" style="border-top: 8px solid {label_colors[final_res]}">
325
- <div class="result-title">{model_name}</div>
326
- <div class="result-value" style="color: {label_colors[final_res]}">{final_res}</div>
327
- <div style="font-size: 18px; color: #64748b; margin-top: 15px;">Confidence: {max(probs)*100:.1f}%</div>
328
- </div>
329
- """, unsafe_allow_html=True)
330
-
331
- with col2:
332
- st.markdown('<div class="section-header">Confidence Scores</div>', unsafe_allow_html=True)
333
- for i in range(5):
334
- label = id2label[i]
335
- prob = probs[i] * 100
336
- color = label_colors[label]
337
 
 
 
338
  st.markdown(f"""
339
- <div class="prob-row">
340
- <div class="prob-label">
341
- <span style="font-weight: 700;">{label}</span>
342
- <span style="font-weight: 700; color: {color};">{prob:.1f}%</span>
343
- </div>
344
- <div class="prob-bar-bg">
345
- <div class="prob-bar-fill" style="width: {min(prob, 100)}%; background: linear-gradient(90deg, {color}, {color}cc);"></div>
346
- </div>
347
  </div>
348
  """, unsafe_allow_html=True)
349
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
  else:
351
  final_res, all_votes, avg_probs = predict_ensemble(user_input)
352
 
 
2
  import torch
3
  import torch.nn.functional as F
4
  import numpy as np
5
+ from transformers import AutoTokenizer, AutoModelForSequenceClassification, AutoModel
6
  from normalizer import normalize
7
  import torch.nn as nn
8
+ from huggingface_hub import hf_hub_download
9
 
10
  st.set_page_config(page_title="Political Sentiment", layout="wide")
11
 
 
13
  def __init__(self, num_classes=5):
14
  super().__init__()
15
  self.banglabert = AutoModel.from_pretrained("csebuetnlp/banglabert")
16
+
17
  self.hidden_size = self.banglabert.config.hidden_size
18
+
19
  self.cnn_layers = nn.ModuleList([
20
+ nn.Conv1d(self.hidden_size, 128, kernel_size=k, padding=k//2)
21
  for k in [3,5,7]
22
  ])
23
+
24
  self.attention = nn.MultiheadAttention(self.hidden_size, 8, batch_first=True)
25
  self.classifier = nn.Sequential(
26
+ nn.LayerNorm(self.hidden_size),
27
+ nn.Dropout(0.4),
28
  nn.Linear(self.hidden_size, 512),
29
+ nn.GELU(),
30
+ nn.Dropout(0.3),
31
+ nn.Linear(512, 256),
32
+ nn.GELU(),
33
+ nn.Linear(256, num_classes)
34
  )
35
+
36
+ self.explainability_weights = nn.Parameter(torch.ones(num_classes) * 0.1)
37
+
38
  def forward(self, input_ids, attention_mask=None):
39
  bert_out = self.banglabert(input_ids, attention_mask=attention_mask).last_hidden_state
40
+
41
+ cnn_outs = [F.relu(cnn(bert_out.transpose(1,2)).transpose(1,2)) for cnn in self.cnn_layers]
42
+ cnn_concat = torch.cat(cnn_outs, dim=-1)
43
 
44
+ if not hasattr(self, 'cnn_proj'):
 
 
 
45
 
46
+ self.cnn_proj = nn.Linear(384, self.hidden_size).to(input_ids.device)
47
+
48
+ attn_input = self.cnn_proj(cnn_concat)
49
  attn_out, _ = self.attention(attn_input, attn_input, attn_input)
50
+ pooled = attn_out[:, 0, :]
51
+
52
+ logits = self.classifier(pooled)
53
+ return logits, self.explainability_weights
54
 
 
 
55
 
56
  st.markdown("""
57
  <style>
 
230
  @st.cache_resource
231
  def load_models():
232
  models_loaded = {}
233
+ device = 'cuda' if torch.cuda.is_available() else 'cpu'
234
 
235
+ standard_models = {
236
  "model_banglabert": "rocky250/Sentiment-banglabert",
237
  "model_mbert": "rocky250/Sentiment-mbert",
238
  "model_bbase": "rocky250/Sentiment-bbase",
239
+ "model_xlmr": "rocky250/Sentiment-xlmr"
 
240
  }
241
 
242
+ for name, repo in standard_models.items():
243
  try:
244
  tokenizer = AutoTokenizer.from_pretrained(repo)
245
  model = AutoModelForSequenceClassification.from_pretrained(repo)
246
+ models_loaded[name] = (tokenizer, model.to(device))
247
+ except Exception as e:
248
+ print(f"Skipped {name}: {e}")
249
  continue
250
+
251
+ try:
252
+
253
+ model_path = hf_hub_download(repo_id="rocky250/bangla-political", filename="pytorch_model.bin")
254
+
255
+
256
+ tokenizer = AutoTokenizer.from_pretrained("rocky250/bangla-political")
257
+
258
+
259
+ model = BanglaPoliticalNet(num_classes=5)
260
+
261
+
262
+ if not hasattr(model, 'cnn_proj'):
263
+ model.cnn_proj = nn.Linear(384, model.hidden_size)
264
+
265
+ model.load_state_dict(torch.load(model_path, map_location=device), strict=False)
266
+
267
+ models_loaded["bangla_political"] = (tokenizer, model.to(device))
268
+ except Exception as e:
269
+ print(f"Skipped bangla_political: {e}")
270
+
271
  return models_loaded
272
 
273
  models_dict = load_models()
 
280
  inputs = tokenizer(clean_text, return_tensors="pt", truncation=True, padding=True, max_length=128).to(device)
281
 
282
  with torch.no_grad():
283
+ if isinstance(model, BanglaPoliticalNet):
284
+ logits, _ = model(input_ids=inputs['input_ids'], attention_mask=inputs['attention_mask'])
285
+ else:
286
+ outputs = model(**inputs)
287
+ logits = outputs.logits
288
 
289
  probs = F.softmax(logits, dim=1).cpu().numpy()[0]
290
  pred_id = np.argmax(probs)
 
311
  return final_pred, all_predictions, avg_probs
312
  return "Error", [], np.zeros(5)
313
 
314
+
315
  st.markdown("""
316
  <div style='
317
  text-align: center;
 
340
  selected_model = None
341
  if mode == "Single Model":
342
  model_options = {name: name for name in models_dict.keys()}
343
+ if model_options:
344
+ selected_model = st.selectbox("Select Model:", list(model_options.keys()), index=0)
345
+ else:
346
+ st.warning("No models loaded.")
347
 
348
  analyze_btn = st.button("ANALYZE SENTIMENT", type="primary", use_container_width=True)
349
 
350
  if analyze_btn and user_input.strip():
351
  with st.spinner('Processing with models...'):
352
  if mode == "Single Model":
353
+ if selected_model:
354
+ final_res, probs = predict_single_model(user_input, selected_model)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
 
356
+ col1, col2 = st.columns([1, 2])
357
+ with col1:
358
  st.markdown(f"""
359
+ <div class="main-card" style="border-top: 8px solid {label_colors[final_res]}">
360
+ <div class="result-title">{selected_model}</div>
361
+ <div class="result-value" style="color: {label_colors[final_res]}">{final_res}</div>
362
+ <div style="font-size: 18px; color: #64748b; margin-top: 15px;">Confidence: {max(probs)*100:.1f}%</div>
 
 
 
 
363
  </div>
364
  """, unsafe_allow_html=True)
365
 
366
+ with col2:
367
+ st.markdown('<div class="section-header">Confidence Scores</div>', unsafe_allow_html=True)
368
+ for i in range(5):
369
+ label = id2label[i]
370
+ prob = probs[i] * 100
371
+ color = label_colors[label]
372
+
373
+ st.markdown(f"""
374
+ <div class="prob-row">
375
+ <div class="prob-label">
376
+ <span style="font-weight: 700;">{label}</span>
377
+ <span style="font-weight: 700; color: {color};">{prob:.1f}%</span>
378
+ </div>
379
+ <div class="prob-bar-bg">
380
+ <div class="prob-bar-fill" style="width: {min(prob, 100)}%; background: linear-gradient(90deg, {color}, {color}cc);"></div>
381
+ </div>
382
+ </div>
383
+ """, unsafe_allow_html=True)
384
+ else:
385
+ st.error("Model not selected or failed to load.")
386
+
387
  else:
388
  final_res, all_votes, avg_probs = predict_ensemble(user_input)
389