|
import gradio as gr |
|
import torch |
|
from transformers import DebertaV2Model, DebertaV2Config, AutoTokenizer, PreTrainedModel |
|
from transformers.models.deberta.modeling_deberta import ContextPooler |
|
from transformers import pipeline, AutoModelForSequenceClassification |
|
import torch.nn as nn |
|
|
|
|
|
model_card = "microsoft/mdeberta-v3-base" |
|
subjectivity_only_model = "MatteoFasulo/mdeberta-v3-base-subjectivity-multilingual-no-arabic" |
|
sentiment_model = "MatteoFasulo/mdeberta-v3-base-subjectivity-sentiment-multilingual-no-arabic" |
|
|
|
|
|
examples = [ |
|
['Example1'], |
|
['Example2'], |
|
['Example3'], |
|
] |
|
|
|
|
|
class CustomModel(PreTrainedModel): |
|
config_class = DebertaV2Config |
|
|
|
def __init__(self, config, sentiment_dim=3, num_labels=2, *args, **kwargs): |
|
super().__init__(config, *args, **kwargs) |
|
self.deberta = DebertaV2Model(config) |
|
self.pooler = ContextPooler(config) |
|
output_dim = self.pooler.output_dim |
|
self.dropout = nn.Dropout(0.1) |
|
|
|
self.classifier = nn.Linear(output_dim + sentiment_dim, num_labels) |
|
|
|
def forward(self, input_ids, positive, neutral, negative, token_type_ids=None, attention_mask=None, labels=None): |
|
outputs = self.deberta(input_ids=input_ids, attention_mask=attention_mask) |
|
|
|
encoder_layer = outputs[0] |
|
pooled_output = self.pooler(encoder_layer) |
|
|
|
|
|
sentiment_features = torch.stack((positive, neutral, negative), dim=1) |
|
|
|
|
|
combined_features = torch.cat((pooled_output, sentiment_features), dim=1) |
|
|
|
|
|
logits = self.classifier(self.dropout(combined_features)) |
|
|
|
return {'logits': logits} |
|
|
|
|
|
def load_tokenizer(model_name: str): |
|
return AutoTokenizer.from_pretrained(model_name) |
|
|
|
|
|
def load_model(model_name: str): |
|
|
|
if 'sentiment' in model_name: |
|
config = DebertaV2Config.from_pretrained( |
|
model_name, |
|
num_labels=2, |
|
id2label={0: 'OBJ', 1: 'SUBJ'}, |
|
label2id={'OBJ': 0, 'SUBJ': 1}, |
|
output_attentions=False, |
|
output_hidden_states=False |
|
) |
|
|
|
model = CustomModel(config=config, sentiment_dim=3, num_labels=2).from_pretrained(model_name) |
|
|
|
else: |
|
model = AutoModelForSequenceClassification.from_pretrained( |
|
model_name, |
|
num_labels=2, |
|
id2label={0: 'OBJ', 1: 'SUBJ'}, |
|
label2id={'OBJ': 0, 'SUBJ': 1}, |
|
output_attentions=False, |
|
output_hidden_states=False |
|
) |
|
|
|
return model |
|
|
|
|
|
def get_sentiment_values(text: str): |
|
pipe = pipeline("sentiment-analysis", model="cardiffnlp/twitter-xlm-roberta-base-sentiment", tokenizer="cardiffnlp/twitter-xlm-roberta-base-sentiment", top_k=None) |
|
sentiments = pipe(text)[0] |
|
return {k:v for k,v in [(list(sentiment.values())[0], list(sentiment.values())[1]) for sentiment in sentiments]} |
|
|
|
|
|
def analyze(text): |
|
|
|
sentiment_values = get_sentiment_values(text) |
|
|
|
|
|
tokenizer = load_tokenizer(model_card) |
|
sentiment_model = load_model(sentiment_model) |
|
subjectivity_model = load_model(subjectivity_only_model) |
|
|
|
|
|
inputs = tokenizer(text, padding=True, truncation=True, max_length=256, return_tensors='pt') |
|
|
|
|
|
positive = sentiment_values['positive'] |
|
neutral = sentiment_values['neutral'] |
|
negative = sentiment_values['negative'] |
|
|
|
inputs['positive'] = torch.tensor(positive).unsqueeze(0) |
|
inputs['neutral'] = torch.tensor(neutral).unsqueeze(0) |
|
inputs['negative'] = torch.tensor(negative).unsqueeze(0) |
|
|
|
|
|
outputs1 = sentiment_model(**inputs) |
|
logits1 = outputs1.get('logits') |
|
|
|
|
|
p1 = torch.nn.functional.softmax(logits1, dim=1)[0] |
|
|
|
|
|
outputs2 = subjectivity_model(**inputs) |
|
logits2 = outputs2.get('logits') |
|
|
|
p2 = torch.nn.functional.softmax(logits2, dim=1)[0] |
|
|
|
|
|
return { |
|
'Positive': f"{positive:.2%}", 'Neutral': f"{neutral:.2%}", 'Negative': f"{negative:.2%}", |
|
'Sent-Subj OBJ': f"{p1[0]:.2%}", 'Sent-Subj SUBJ': f"{p1[1]:.2%}", |
|
'TextOnly OBJ': f"{p2[0]:.2%}", 'TextOnly SUBJ': f"{p2[1]:.2%}" |
|
} |
|
|
|
|
|
with gr.Blocks(theme=gr.themes.Soft(), css=""" |
|
#result_table td { padding: 8px; font-size: 1rem; } |
|
#header { text-align: center; font-size: 2rem; font-weight: bold; margin-bottom: 10px; } |
|
""") as demo: |
|
gr.Markdown("<div id='header'>π Advanced Subjectivity & Sentiment Dashboard π</div>") |
|
with gr.Row(): |
|
txt = gr.Textbox(label="Enter text to analyze", placeholder="Paste news sentence here...", lines=2) |
|
btn = gr.Button("Analyze π", variant="primary") |
|
with gr.Tabs(): |
|
with gr.TabItem("Overview π"): |
|
chart = gr.BarPlot(x="category", y="value", label="Results", elem_id="result_chart") |
|
with gr.TabItem("Raw Scores π"): |
|
table = gr.Dataframe(headers=["Metric", "Value"], datatype=["str","str"], interactive=False, elem_id="result_table") |
|
with gr.TabItem("About βΉοΈ"): |
|
gr.Markdown("This dashboard uses two DeBERTa-based models (with and without sentiment integration) to detect subjectivity, alongside sentiment scores from an XLM-RoBERTa model.") |
|
with gr.Row(): |
|
gr.Markdown("### Examples:") |
|
gr.Examples( |
|
examples=examples, |
|
inputs=txt, |
|
label="Examples", |
|
elem_id="example_list", |
|
cache_examples=True, |
|
) |
|
|
|
btn.click(fn=analyze, inputs=txt, outputs=[chart, table]) |
|
|
|
demo.queue().launch(server_name="0.0.0.0", share=True) |