| --- |
| language: |
| - ar |
| - en |
| - fr |
| license: mit |
| tags: |
| - aspect-based-sentiment-analysis |
| - absa |
| - arabic-nlp |
| - arabic-dialects |
| - franco-arabic |
| - ensemble |
| - marbert |
| - arabert |
| - camelbert |
| - xlm-roberta |
| - text-classification |
| - multi-label-classification |
| pipeline_tag: text-classification |
| --- |
| |
| # DeepX-AI-Hackathon-ABSA |
|
|
| **A multi-dialect, multilingual Aspect-Based Sentiment Analysis (ABSA) system for Arabic reviews (Modern Standard Arabic, dialectal Arabic, Franco-Arabic, English, and French).** |
|
|
| An **ensemble** of 4 independently fine-tuned transformer backbones, combined with a language-aware routing system, purpose-built for real-world user reviews (e.g. Google Maps, Play Store, food delivery apps) written in mixed scripts and dialects β including Egyptian, Gulf, and Levantine Arabic, and Franco-Arabic (Arabic written with Latin letters and digits). |
|
|
| --- |
|
|
| ## π Overview |
|
|
| This project is a complete **two-stage pipeline** that extracts, for every review: |
|
|
| 1. **Aspects** mentioned in the review (e.g. food, service, price, cleanlinessβ¦). |
| 2. **Sentiment** associated with each individual aspect (positive / negative / neutral). |
|
|
| The final output for each review is a set of **(aspect, sentiment) tuples**: |
|
|
| ```json |
| { |
| "review_id": 12345, |
| "aspects": [ |
| {"aspect": "food", "sentiment": "positive"}, |
| {"aspect": "service", "sentiment": "negative"} |
| ] |
| } |
| ``` |
|
|
| ### Why an ensemble of 4 models? |
|
|
| Real-world Arabic reviews are far from uniform β the same user might write in Modern Standard Arabic, a regional dialect, Franco-Arabic (Latin letters + digits standing in for Arabic sounds), or plain English/French. To handle this diversity, four different backbones were fine-tuned, each with a different strength, and their outputs are combined via a **language-routed, weighted soft-voting ensemble**. |
|
|
| --- |
|
|
| ## π§ Architecture |
|
|
| ### Stage 1 β Aspect Detection (Multi-Label Classification) |
|
|
| For every review text, the model predicts which of 9 aspect categories are mentioned: |
|
|
| | Aspect | Description | |
| |---|---| |
| | `food` | Food and taste | |
| | `service` | Service and staff | |
| | `price` | Price and cost | |
| | `cleanliness` | Cleanliness and hygiene | |
| | `delivery` | Delivery and shipping | |
| | `ambiance` | Ambiance and atmosphere | |
| | `app_experience` | App or website experience | |
| | `general` | Overall experience | |
| | `none` | No clear aspect (rating-only comment) | |
|
|
| **Model architecture:** |
| ``` |
| Review text β Backbone (BERT / RoBERTa) β [CLS] embedding |
| β |
| Metadata Fusion (concatenated with text embedding): |
| - Star rating β Embedding |
| - Business category β Embedding |
| - Platform (Google Maps / Play Store) β Embedding |
| β |
| MLP + LayerNorm + Dropout |
| β |
| Linear layer β 9 logits (multi-label) |
| β |
| Sigmoid + per-class decision threshold |
| ``` |
|
|
| ### Stage 2 β Sentiment Classification (per aspect) |
|
|
| Once the aspects are extracted, for every (review, aspect) pair an **aspect-aware question** is built: |
|
|
| - Arabic backbones: `[ΩΨ¬ΩΩ
=X] <text> [SEP] Ω
Ψ§ Ψ±Ψ§ΩΩ ΩΩ <aspect> Ψ` |
| - Latin-script backbone (XLM-R): `[stars=X] <text> [SEP] what about the <aspect> ?` |
|
|
| The pair is then classified into one of 3 classes: `positive` / `negative` / `neutral`. |
|
|
| ``` |
| (Text + aspect question) β Backbone β [CLS] |
| β |
| Metadata Fusion + Aspect Embedding |
| β |
| MLP (128) β 3 logits |
| β |
| Softmax |
| ``` |
|
|
| --- |
|
|
| ## π Language Router |
|
|
| Before any modeling, every text is automatically routed into one of the following categories using regex heuristics and marker-word dictionaries: |
|
|
| | Route | Description | |
| |---|---| |
| | `arabic` | Predominantly Arabic script (Arabic-character ratio > 70%) | |
| | `mixed` | A mix of Arabic and Latin script | |
| | `franco` | Franco-Arabic (e.g. `momtaz awy`, `7elw giddan`) | |
| | `latin` | Fully English or French | |
| | `other_script` | Other scripts (Chinese, Korean, Russian, etc.) | |
| | `empty_rating_only` | Empty / too short to classify β falls back to a star-rating rule | |
|
|
| > **Important fix (V2):** Very short texts (1β2 words) without a clear sentiment word (e.g. "Up" or "Shady") are *not* routed to Franco β they're routed to `empty_rating_only` instead, since model predictions on such short strings are less reliable than a simple star-based rule. |
|
|
| ### Which backbones handle which route? |
|
|
| ```python |
| ROUTE_BACKBONES = { |
| 'arabic': ['marbert', 'arabert', 'camelbert', 'xlmr'], |
| 'mixed': ['marbert', 'camelbert', 'xlmr'], |
| 'franco': ['marbert', 'arabert', 'camelbert', 'xlmr'], |
| 'latin': ['xlmr'], |
| 'other_script': ['xlmr'], |
| 'empty_rating_only': [], # handled entirely by a hand-written star-based rule |
| } |
| ``` |
|
|
| --- |
|
|
| ## ποΈ Backbones |
|
|
| | # | Name | Hugging Face ID | Strength | Aspect F1 (val) | Sentiment F1 (val) | |
| |---|---|---|---|---|---| |
| | 1 | **MARBERT v2** | `UBC-NLP/MARBERTv2` | Arabic dialects / Twitter-style text | 0.8707 | 0.7811 | |
| | 2 | **AraBERT (Twitter)** | `aubmindlab/bert-base-arabertv02-twitter` | Best overall performance on MSA/dialectal text | **0.9371** | **0.8144** | |
| | 3 | **CAMeLBERT-DA** | `CAMeL-Lab/bert-base-arabic-camelbert-da` | Specialized in dialectal Arabic | 0.9371 | 0.8092 | |
| | 4 | **XLM-RoBERTa base** | `FacebookAI/xlm-roberta-base` | Multilingual β English, French, Franco-Arabic | 0.8025 | 0.7533 | |
|
|
| **Training data notes:** |
| - `MARBERT` and `XLM-R` were trained on an **expanded dataset**: real Arabic reviews + **synthetically generated Franco-Arabic** variants (see below). |
| - `AraBERT` and `CAMeLBERT` were trained on real Arabic data only. |
|
|
| --- |
|
|
| ## π² Synthetic Franco-Arabic Data Augmentation |
|
|
| Since real Franco-Arabic examples are scarce in the training set, an **automatic Arabic β Franco-Arabic converter** was built, based on: |
|
|
| 1. A **common-word dictionary** (60+ frequent Arabic words/phrases mapped to their typical Franco-Arabic spellings, e.g. `Ω
Ω
ΨͺΨ§Ψ² β mumtaz/momtaz`, `Ω
Ψ΄ β mesh/mish`). |
| 2. A **character-level transliteration map** for the remaining words (e.g. `Ψ β 7`, `ΨΉ β 3`, `ΨΊ β 8`). |
| 3. Controlled randomness (75% chance of using the common-word dictionary) to mimic natural spelling variation. |
|
|
| This expanded the `MARBERT`/`XLM-R` training set from **1,971** to **3,809** samples. |
|
|
| --- |
|
|
| ## βοΈ Ensemble & Weight Tuning |
|
|
| After training the four backbones, a **weighted soft-voting ensemble** combines their probability outputs, weighted per model, and thresholded per aspect class. |
|
|
| ### Weights (from a grid search over 625 combinations on the validation set): |
|
|
| | Model | Weight | |
| |---|---| |
| | MARBERT | 0.5 | |
| | AraBERT | 1.5 | |
| | CAMeLBERT | 1.2 | |
| | XLM-R | 0.5 | |
|
|
| > The fixed weights actually used for final test-set inference were: `{'marbert': 1.2, 'arabert': 1.2, 'camelbert': 1.0, 'xlmr': 0.7}` β see [`ensemble_weights.json`](./ensemble_weights.json). |
|
|
| ### Per-aspect decision thresholds |
|
|
| Saved in [`thresholds.npy`](./thresholds.npy): |
|
|
| | Aspect | Threshold | |
| |---|---| |
| | food | 0.50 | |
| | service | 0.46 | |
| | price | 0.36 | |
| | cleanliness | 0.46 | |
| | delivery | 0.32 | |
| | ambiance | 0.46 | |
| | app_experience | 0.36 | |
| | general | 0.46 | |
| | none | 0.52 | |
| |
| --- |
| |
| ## π Post-Processing Rules |
| |
| 1. **Empty / rating-only reviews** (`empty_rating_only`) skip the models entirely and are classified directly from the star rating: |
| - β β₯ 4 β `general: positive` |
| - β β€ 2 β `general: negative` |
| - β = 3 β `none: neutral` |
| 2. **Max 6 aspects** per review (kept by highest predicted probability). |
| 3. If `none` co-occurs with other aspects, `none` is dropped (a specific aspect and "no aspect" together are contradictory). |
| 4. If no aspect crosses its threshold, `none: neutral` is used as a default. |
| 5. If a sentiment prediction is unavailable for a given aspect, the star rating is used as a fallback. |
| |
| --- |
| |
| ## π Results (Validation Set β 1,971 reviews) |
| |
| ### Main metric: Tuple F1 (aspect + sentiment must both match) |
| |
| | Metric | Value | |
| |---|---| |
| | **Tuple F1** | **0.9056** (90.56%) | |
| | Precision | 0.9062 | |
| | Recall | 0.9049 | |
| | Aspect F1 (aspect detection only) | 0.9860 | |
| | Sentiment accuracy (given correct aspect) | 0.9184 | |
| | Review exact match (all tuples correct per review) | 0.8772 | |
| |
| ### Performance by route |
| |
| | Route | # Samples | F1 | |
| |---|---|---| |
| | Arabic | 1,814 | 0.9182 | |
| | Latin | 4 | 1.0000 | |
| | Mixed | 24 | 0.8667 | |
| | Empty / rating-only | 129 | 0.6124 | |
| |
| ### Performance by aspect |
| |
| | Aspect | F1 | |
| |---|---| |
| | food | 0.9989 | |
| | service | 0.9980 | |
| | cleanliness | 0.9946 | |
| | delivery | 0.9938 | |
| | price | 0.9929 | |
| | ambiance | 0.9973 | |
| | app_experience | 0.9956 | |
| | general | 0.9367 | |
| | none | 0.6796 | |
|
|
| ### Sentiment confusion matrix (when the aspect is correctly detected) |
|
|
| | Gold \ Pred | negative | neutral | positive | |
| |---|---|---|---| |
| | **negative** | 1405 | 84 | 38 | |
| | **neutral** | 10 | 97 | 17 | |
| | **positive** | 43 | 76 | 1514 | |
|
|
| --- |
|
|
| ## π Repository Contents |
|
|
| ``` |
| DeepX-AI-Hackathon-ABSA/ |
| βββ models/ # Weights for all 4 backbones (Stage 1 + Stage 2) |
| βββ ensemble_weights.json # Final ensemble weights |
| βββ thresholds.npy # Per-aspect decision thresholds (9 values) |
| βββ submission.json # Predictions on the unlabeled set |
| βββ submission_test.json # Predictions on the hidden test set |
| βββ __huggingface_repos__.json # Repository metadata |
| βββ README.md # This file |
| ``` |
|
|
| --- |
|
|
| ## π Usage |
|
|
| > β οΈ This is **not** a single model loadable with `AutoModel` and a standard `pipeline()`. It is an **ensemble of 4 backbones plus custom language-routing, preprocessing, and post-processing logic**. Running inference requires the full inference code (from the original training notebook), not just the saved weights. |
|
|
| ### Inference outline: |
|
|
| ```python |
| from transformers import AutoTokenizer, AutoModel |
| import torch, json, numpy as np |
| |
| BACKBONES = { |
| 'marbert': 'UBC-NLP/MARBERTv2', |
| 'arabert': 'aubmindlab/bert-base-arabertv02-twitter', |
| 'camelbert': 'CAMeL-Lab/bert-base-arabic-camelbert-da', |
| 'xlmr': 'FacebookAI/xlm-roberta-base', |
| } |
| |
| # 1. Load the Stage-1 (aspect) and Stage-2 (sentiment) checkpoints from models/ |
| # 2. Route each text via detect_language() |
| # 3. Preprocess it according to its route via preprocess_by_route() |
| # 4. Run the backbones listed in ROUTE_BACKBONES[route] |
| # 5. Combine outputs with the weights in ensemble_weights.json |
| # 6. Apply the per-aspect thresholds in thresholds.npy |
| # 7. Apply the post-processing rules to build the final prediction |
| ``` |
|
|
| For the complete code (model definitions, helper functions, preprocessing, and ensembling logic), see the original training notebook shipped alongside this project. |
|
|
| --- |
|
|
| ## π― Intended Use |
|
|
| - Multi-dialect customer review analysis (Google Maps / Play Store / food-delivery platforms). |
| - Extracting per-aspect strengths and weaknesses (food, service, price, cleanliness, β¦) for business owners. |
| - Sentiment dashboards for restaurants, hotels, delivery apps, clinics, and e-commerce. |
|
|
| ## β οΈ Limitations |
|
|
| - Performance on very short / empty reviews (`empty_rating_only`) is comparatively weaker (F1 = 0.61) since it relies purely on a star-rating rule rather than the model. |
| - The `none` aspect has weaker performance (F1 = 0.68), reflecting the difficulty of distinguishing "no clear aspect" from a generic "general" comment. |
| - Trained on only 1,971 labeled reviews β a relatively small dataset, which may limit generalization to domains not well represented in training (e.g. medical or real-estate reviews). |
| - Franco-Arabic training examples are synthetically generated rather than fully authentic, which may reduce accuracy on unusual real-world Franco-Arabic spelling patterns. |
|
|
| ## π Context |
|
|
| This model was developed as part of the **DeepX AI Hackathon**, addressing an Aspect-Based Sentiment Analysis (ABSA) task on multilingual, multi-dialect Arabic reviews. |
|
|
| ## π License |
|
|
| MIT |
|
|
| --- |
|
|
| *For questions about this model, please open a Discussion on the Hugging Face repository page.* |