Download train.py from dpratapx/restaurant-inspector-api-dev: direct link, hf CLI and curl.
- Browser
- Download file 4.61 kB
-
https://huggingface.co/spaces/dpratapx/restaurant-inspector-api-dev/resolve/main/train.py
- Command line
-
hf download hf://spaces/dpratapx/restaurant-inspector-api-dev/train.py
-
curl -L -o train.py https://huggingface.co/spaces/dpratapx/restaurant-inspector-api-dev/resolve/main/train.py
4.61 kB
| """ | |
| Training script for Restaurant Aspect Classifier. | |
| Fine-tunes DistilBERT on Yelp reviews with rule-based aspect labeling. | |
| """ | |
| from datasets import load_dataset | |
| from transformers import ( | |
| AutoModelForSequenceClassification, | |
| AutoTokenizer, | |
| Trainer, | |
| TrainingArguments, | |
| ) | |
| # Aspect categories | |
| ASPECTS = ["FOOD", "SERVICE", "HYGIENE", "PARKING", "CLEANLINESS"] | |
| def label_aspects(text: str, label: int) -> list[float]: | |
| """ | |
| Create aspect labels from review text and overall sentiment. | |
| Args: | |
| text: Review text | |
| label: Overall sentiment (0=negative, 1=positive) | |
| Returns: | |
| List of 5 scores (0.0-1.0) for each aspect | |
| """ | |
| base_score = float(label) | |
| scores = [base_score] * 5 # Initialize all aspects with base score | |
| text_lower = text.lower() | |
| # HYGIENE (index 2) | |
| if any(word in text_lower for word in ["dirty", "filthy", "gross", "disgusting"]): | |
| scores[2] = 0.0 | |
| elif any(word in text_lower for word in ["clean", "spotless", "sanitary"]): | |
| scores[2] = 1.0 | |
| # FOOD (index 0) | |
| if any(word in text_lower for word in ["delicious", "tasty", "amazing", "excellent"]): | |
| scores[0] = 1.0 | |
| elif any(word in text_lower for word in ["terrible", "awful", "bland", "disgusting"]): | |
| scores[0] = 0.0 | |
| # SERVICE (index 1) | |
| if any(word in text_lower for word in ["friendly", "attentive", "helpful", "great service"]): | |
| scores[1] = 1.0 | |
| elif any(word in text_lower for word in ["rude", "slow", "terrible service", "unfriendly"]): | |
| scores[1] = 0.0 | |
| # PARKING (index 3) | |
| if "parking" in text_lower: | |
| if label == 0 or any(word in text_lower for word in ["no parking", "parking nightmare"]): | |
| scores[3] = 0.0 | |
| else: | |
| scores[3] = 1.0 | |
| # CLEANLINESS (index 4) - similar to hygiene | |
| if any(word in text_lower for word in ["dirty", "messy", "unkempt"]): | |
| scores[4] = 0.0 | |
| elif any(word in text_lower for word in ["clean", "tidy", "well-maintained"]): | |
| scores[4] = 1.0 | |
| return scores | |
| def main(): | |
| """Train the model.""" | |
| print("π Starting Restaurant Aspect Classifier Training\n") | |
| # Load dataset | |
| print("π₯ Loading Yelp dataset (1500 samples)...") | |
| dataset = load_dataset("yelp_polarity", split="train[:1500]", trust_remote_code=True) | |
| print(f"β Loaded {len(dataset)} reviews\n") | |
| # Create aspect labels | |
| print("π·οΈ Creating aspect labels from reviews...") | |
| dataset = dataset.map( | |
| lambda x: {"aspects": label_aspects(x["text"], x["label"])}, | |
| desc="Labeling aspects", | |
| ) | |
| print("β Aspect labels created\n") | |
| # Load tokenizer and model | |
| print("π€ Loading DistilBERT model and tokenizer...") | |
| tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased") | |
| model = AutoModelForSequenceClassification.from_pretrained( | |
| "distilbert-base-uncased", | |
| num_labels=5, | |
| problem_type="multi_label_classification", | |
| ) | |
| print("β Model loaded\n") | |
| # Tokenize dataset | |
| print("βοΈ Tokenizing text...") | |
| def tokenize_function(examples): | |
| return tokenizer( | |
| examples["text"], | |
| truncation=True, | |
| padding="max_length", | |
| max_length=256, | |
| ) | |
| tokenized_dataset = dataset.map( | |
| tokenize_function, | |
| batched=True, | |
| desc="Tokenizing", | |
| ) | |
| # Prepare dataset for training | |
| tokenized_dataset = tokenized_dataset.rename_column("aspects", "labels") | |
| tokenized_dataset.set_format( | |
| type="torch", | |
| columns=["input_ids", "attention_mask", "labels"], | |
| ) | |
| print("β Tokenization complete\n") | |
| # Training arguments | |
| training_args = TrainingArguments( | |
| output_dir="./model", | |
| num_train_epochs=2, | |
| per_device_train_batch_size=8, | |
| warmup_steps=50, | |
| logging_steps=10, | |
| save_strategy="epoch", | |
| save_total_limit=1, | |
| report_to="none", | |
| push_to_hub=False, | |
| ) | |
| # Create trainer | |
| trainer = Trainer( | |
| model=model, | |
| args=training_args, | |
| train_dataset=tokenized_dataset, | |
| ) | |
| # Train | |
| print("π― Training model (this will take ~45 minutes)...\n") | |
| trainer.train() | |
| print("\nβ Training complete!\n") | |
| # Save model | |
| print("πΎ Saving model and tokenizer...") | |
| model.save_pretrained("./model") | |
| tokenizer.save_pretrained("./model") | |
| print("β Model saved to ./model/\n") | |
| print("π Training complete! You can now run: uvicorn main:app --reload") | |
| if __name__ == "__main__": | |
| main() | |