import streamlit as st import torch from transformers import AutoModelForSequenceClassification, AutoTokenizer from html import escape @st.cache_resource def load_model_and_tokenizer(path: str): with st.spinner("Loading the model... It may take some time"): tokenizer = AutoTokenizer.from_pretrained(path) model = AutoModelForSequenceClassification.from_pretrained(path, output_attentions=True) device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model.to(device) model.eval() return tokenizer, model, device def predict_top_p(title, summary, tokenizer, model, device, p=0.95, max_length=320, min_prob=0.01): text = f"Title: {title} [SEP] Abstract: {summary}" inputs = tokenizer( text, return_tensors="pt", truncation=True, max_length=max_length ).to(device) with torch.no_grad(): outputs = model(**inputs) probs = torch.sigmoid(outputs.logits).cpu().squeeze().numpy() all_preds = [] for i, prob_val in enumerate(probs): code = model.config.id2label[i] all_preds.append((code, float(prob_val))) all_preds.sort(key=lambda x: x[1], reverse=True) selected = [] cumulative_prob = 0.0 for code, prob in all_preds: if prob < min_prob: break selected.append((code, prob)) cumulative_prob += prob if cumulative_prob >= p: break return selected, cumulative_prob def predict_top_n(title, summary, tokenizer, model, device, n=5, max_length=320, min_prob=0.01): text = f"Title: {title} [SEP] Abstract: {summary}" inputs = tokenizer( text, return_tensors="pt", truncation=True, max_length=max_length ).to(device) with torch.no_grad(): outputs = model(**inputs) probs = torch.sigmoid(outputs.logits).cpu().squeeze().numpy() all_preds = [] for i, prob_val in enumerate(probs): code = model.config.id2label[i] all_preds.append((code, float(prob_val))) all_preds.sort(key=lambda x: x[1], reverse=True) selected = [] cumulative_prob = 0.0 for code, prob in all_preds: if prob < min_prob: continue selected.append((code, prob)) cumulative_prob += prob if len(selected) >= n: break return selected, cumulative_prob def get_label_index(label, model): return int(next(i for i, lbl in model.config.id2label.items() if lbl == label)) def explain_prediction(text, label, tokenizer, model, device, max_length=320): inputs = tokenizer( text, return_tensors="pt", truncation=True, max_length=max_length ).to(device) input_ids = inputs["input_ids"] attention_mask = inputs["attention_mask"] token_type_ids = inputs.get("token_type_ids") if token_type_ids is not None: token_type_ids = token_type_ids.to(device) embeds = model.get_input_embeddings()(input_ids) embeds.retain_grad() model.zero_grad(set_to_none=True) outputs = model( inputs_embeds=embeds, attention_mask=attention_mask, token_type_ids=token_type_ids, ) label_idx = get_label_index(label, model) logit = outputs.logits[0, label_idx] prob = torch.sigmoid(logit).item() logit.backward() grads = embeds.grad[0] contrib = (grads * embeds[0]).sum(dim=-1).detach().cpu() tokens = tokenizer.convert_ids_to_tokens(input_ids[0].detach().cpu()) scores = contrib.tolist() return tokens, scores, prob def render_token_heatmap(tokens, scores): skip = {"[CLS]", "[SEP]", "[PAD]"} items = [(t, s) for t, s in zip(tokens, scores) if t not in skip] if not items: return "