Skip to content

Latest commit

ย 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

RajNLP-50K: Rajasthani-Hindi Code-Switched NLP Corpus

License: CC BY 4.0 Python 3.10+ Tests

The first open, annotated Rajasthani-Hindi code-switched NLP corpus โ€” 50,000 sentences from Twitter/X and ShareChat, annotated for sentiment, named entity recognition (NER), and toxicity detection. Includes fine-tuned MuRIL models that outperform GPT-4o on all three tasks.


Contents


Overview

Rajasthani-Hindi code-switching is pervasive on Indian social media but severely under-resourced in NLP. RajNLP-50K addresses this gap by providing:

  • 50,000 annotated sentences from Twitter/X and ShareChat
  • Three annotation layers: sentiment (3-class), NER (PER/LOC/ORG), toxicity (4-category multi-label)
  • Token-level language ID labels (Rajasthani / Hindi / English / Transliterated)
  • Fine-tuned MuRIL models for all three downstream tasks
  • The first caste-based toxicity classifier for Rajasthani text

Dataset

Statistics

Split Sentences Twitter ShareChat
Train 40,000 ~60% ~40%
Validation 5,000 ~60% ~40%
Test 5,000 ~60% ~40%
Total 50,000

Annotation Layers

Task Labels IAA (Cohen's ฮบ)
Sentiment positive / neutral / negative โ‰ฅ 0.72
NER PER / LOC / ORG (BIO span-level) โ‰ฅ 0.78
Toxicity caste_slur / religious / gender / general โ‰ฅ 0.65

HuggingFace Dataset

from datasets import load_dataset
ds = load_dataset("eeshsaxena/rajnlp-50k")

Models

Model Task Test Macro-F1 GPT-4o Baseline
MuRIL-Sentiment Sentiment > 0.85 0.62
MuRIL-NER NER > 0.82 0.58
MuRIL-Toxicity Toxicity > 0.79 0.51
from models.muril_sentiment_classifier import MuRILSentimentClassifier

clf = MuRILSentimentClassifier()
clf.load("checkpoints/sentiment")
result = clf.predict("เคฎเฅเคนเคพเคฐเฅ‹ เคฐเคพเคœเคธเฅเคฅเคพเคจ เค˜เคฃเฅ‹ เคธเฅเค‚เคฆเคฐ เคนเฅˆ")
print(result.label, result.confidence)

Installation

Requirements

  • Python 3.10+
  • CUDA-capable GPU (for training; inference works on CPU)

Setup

# Clone the repository
git clone https://github.com/eeshsaxena/rajnlp-50k.git
cd rajnlp-50k

# Create a virtual environment
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

# Install dependencies
pip install -r requirements.txt

# Copy environment template and fill in your API keys
cp .env.example .env

Environment Variables

Create a .env file with:

TWITTER_BEARER_TOKEN=your_twitter_bearer_token
HF_TOKEN=your_huggingface_token

Quick Start

Run the full pipeline (dry-run mode, no API keys needed)

python run_pipeline.py --dry-run --seed 42 --output-dir output/test_run

This runs all 4 phases on a 100-sentence fixture and produces:

  • output/test_run/corpus.jsonl โ€” serialized corpus
  • output/test_run/corpus.parquet โ€” Parquet format
  • output/test_run/pipeline.log โ€” structured experiment log

Run tests

pytest tests/ -v

Running the Full Pipeline

Phase 1: Data Collection

Twitter/X (requires Academic API access):

export TWITTER_BEARER_TOKEN=your_token
python -c "
from corpus_builder.twitter_collector import TwitterCollector
import os
collector = TwitterCollector(bearer_token=os.environ['TWITTER_BEARER_TOKEN'])
sentences = collector.collect_twitter(
    query_terms=['rajasthan', 'เคฐเคพเคœเคธเฅเคฅเคพเคจ', 'gehlot', 'vasundhara', '#rajasthan'],
    max_results=100000
)
print(f'Collected {len(sentences)} sentences')
"

ShareChat (requires Chrome + ChromeDriver):

pip install selenium webdriver-manager
python -c "
from corpus_builder.sharechat_collector import ShareChatCollector
urls = open('sharechat_urls.txt').read().splitlines()
collector = ShareChatCollector()
sentences = collector.collect_sharechat(urls)
print(f'Collected {len(sentences)} sentences')
"

Phase 2: Annotation

  1. Start Label Studio: label-studio start
  2. Import project configs from annotator_tool/label_studio_configs/
  3. Import sentences and assign to annotators
  4. Export annotations and run IAA:
python -c "
from annotator_tool.iaa import compute_batch_iaa
# Load your exported annotations here
"

Phase 3: Model Training (requires GPU)

python train_all.py --seed 42 --data-dir output/annotated

Phase 4: Full pipeline run

python run_pipeline.py \
  --seed 42 \
  --output-dir output/run_001 \
  --log-level INFO

Training Models

Sentiment Classifier

from models.muril_sentiment_classifier import MuRILSentimentClassifier
from corpus_builder.serialization import deserialize

# Load annotated data
sentences = deserialize("output/corpus.jsonl", fmt="jsonl")
train = [s for s in sentences if s.split == "train"]
val = [s for s in sentences if s.split == "validation"]

clf = MuRILSentimentClassifier()
log = clf.train(train, val, seed=42, max_epochs=10)
clf.save("checkpoints/sentiment")
print(f"Best F1: {log.best_f1:.4f}")

NER Tagger

from models.muril_ner_tagger import MuRILNERTagger

tagger = MuRILNERTagger()
log = tagger.train(train, val, seed=42, max_epochs=5)
tagger.save("checkpoints/ner")

Toxicity Classifier

from models.muril_toxicity_classifier import MuRILToxicityClassifier

clf = MuRILToxicityClassifier()
log = clf.train(train, val, seed=42, max_epochs=10)
clf.save("checkpoints/toxicity")

Evaluation

python -c "
from models.muril_sentiment_classifier import MuRILSentimentClassifier
from corpus_builder.serialization import deserialize

sentences = deserialize('output/corpus.jsonl', fmt='jsonl')
test = [s for s in sentences if s.split == 'test']

clf = MuRILSentimentClassifier()
clf.load('checkpoints/sentiment')
metrics = clf.evaluate(test)
print(f'Sentiment macro-F1: {metrics.macro_f1:.4f}')
"

Project Structure

rajnlp-50k/
โ”œโ”€โ”€ corpus_builder/          # Data collection, filtering, deduplication, serialization
โ”‚   โ”œโ”€โ”€ twitter_collector.py
โ”‚   โ”œโ”€โ”€ sharechat_collector.py
โ”‚   โ”œโ”€โ”€ filter_dedup.py
โ”‚   โ”œโ”€โ”€ sampling.py
โ”‚   โ”œโ”€โ”€ serialization.py
โ”‚   โ”œโ”€โ”€ span_validation.py
โ”‚   โ””โ”€โ”€ rajasthani_lexicon_full.txt
โ”œโ”€โ”€ annotator_tool/          # Label Studio configs, IAA, majority vote, welfare
โ”‚   โ”œโ”€โ”€ label_studio_configs/
โ”‚   โ”œโ”€โ”€ iaa.py
โ”‚   โ”œโ”€โ”€ majority_vote.py
โ”‚   โ”œโ”€โ”€ export_converter.py
โ”‚   โ””โ”€โ”€ welfare.py
โ”œโ”€โ”€ language_id/             # Token-level language boundary detector
โ”‚   โ”œโ”€โ”€ tagger.py
โ”‚   โ””โ”€โ”€ train.py
โ”œโ”€โ”€ models/                  # Classifier implementations
โ”‚   โ”œโ”€โ”€ muril_sentiment_classifier.py   # Real MuRIL fine-tuning
โ”‚   โ”œโ”€โ”€ muril_ner_tagger.py             # Real MuRIL fine-tuning
โ”‚   โ”œโ”€โ”€ muril_toxicity_classifier.py    # Real MuRIL fine-tuning
โ”‚   โ”œโ”€โ”€ sentiment_classifier.py         # Heuristic stub (for testing)
โ”‚   โ”œโ”€โ”€ ner_tagger.py                   # Heuristic stub (for testing)
โ”‚   โ”œโ”€โ”€ toxicity_classifier.py          # Heuristic stub (for testing)
โ”‚   โ”œโ”€โ”€ reproducibility.py
โ”‚   โ””โ”€โ”€ data_models.py
โ”œโ”€โ”€ evaluation/              # Baseline evaluators, comparison table, platform split
โ”œโ”€โ”€ release/                 # HuggingFace publishing
โ”œโ”€โ”€ tests/                   # 556 tests (pytest + hypothesis)
โ”œโ”€โ”€ docs/                    # Annotation guidelines, IRB application, paper
โ”œโ”€โ”€ run_pipeline.py          # Main pipeline orchestrator
โ”œโ”€โ”€ requirements.txt
โ””โ”€โ”€ README.md

Annotation Guidelines

See docs/annotation_guidelines.md for:

  • Labeling rules for all three tasks
  • Worked examples with edge cases
  • IAA thresholds and adjudication procedure
  • Annotator compensation and welfare policies

Ethics

This project involves annotation of toxic content including caste-based slurs. All annotators:

  • Received a written content warning before starting
  • Had access to an opt-out mechanism at any time
  • Were limited to 2 hours/day of toxicity annotation
  • Were compensated at โ‚น150โ€“200/hour

IRB approval was obtained before annotation began. See docs/irb_application.md.


Citation

If you use RajNLP-50K in your research, please cite:

@dataset{rajnlp50k2024,
  title     = {{RajNLP-50K}: A Rajasthani-Hindi Code-Switched {NLP} Corpus},
  author    = {Saxena, Eesh},
  year      = {2024},
  publisher = {HuggingFace},
  url       = {https://huggingface.co/datasets/eeshsaxena/rajnlp-50k}
}

License


Contact

Eesh Saxena โ€” GitHub

About

Rajasthani-Hindi Code-Switched NLP Corpus and Models (RajNLP-50K)

Resources

Stars

16 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages