Parameter-efficient fine-tuning (LoRA/PEFT) of Google FLAN-T5-base on the Banking77 dataset. Classifies 77 customer service intents, trains 1.77M of 250M parameters (~0.71%) in ~2hrs on free Colab GPU. Deployed as a FastAPI REST API with batch prediction, Docker containerisation, and full evaluation metrics.
- Project Overview
- Architecture
- LoRA Configuration
- Training Details
- Model Performance
- Project Structure
- Quick Start
- API Reference
- Docker Deployment
- Evaluation
- Technologies
This project demonstrates Parameter-Efficient Fine-Tuning (PEFT) using LoRA on a sequence-to-sequence model for multi-class intent classification. Instead of updating all 250 M parameters, LoRA injects small trainable rank-decomposition matrices into the attention layers — training only ~1.77 M parameters (0.71%) while retaining full expressiveness.
The system handles real-world banking queries such as:
| Query | Predicted Intent |
|---|---|
| "My card was charged twice" | transaction_charged_twice |
| "I want to activate my card" | activate_my_card |
| "How do I transfer money abroad?" | transfer_into_account |
| "I can't remember my PIN" | passcode_forgotten |
| "Why is my balance not showing the deposit?" | balance_not_updated_after_bank_transfer |
Input Query
│
▼
Prompt Template: "Classify this banking query: {text}\n\nCategory:"
│
▼
FLAN-T5-base (250M params, frozen)
+ LoRA Adapters (1.77M trainable params on q,v attention layers)
│
▼
Beam Search (4 beams, greedy decode)
│
▼
Label Matching (exact → substring → token-overlap)
│
▼
Predicted Intent (one of 77 Banking77 categories)
| Parameter | Value |
|---|---|
Rank (r) |
16 |
Alpha (lora_alpha) |
32 |
| Dropout | 0.1 |
| Target modules | q, v (query & value attention) |
| Task type | SEQ_2_SEQ_LM |
| Trainable parameters | 1,769,472 |
| Total parameters | 249,867,264 |
| % trainable | 0.71% |
| Setting | Value |
|---|---|
| Base model | google/flan-t5-base |
| Dataset | PolyAI/banking77 |
| Train samples | 10,003 |
| Test samples | 3,080 |
| Epochs | 10 |
| Batch size | 2 (effective 16 via gradient accumulation ×8) |
| Learning rate | 3e-4 |
| Optimizer | AdamW (weight decay 0.01) |
| LR scheduler | Linear with 100 warmup steps |
| Mixed precision | FP16 |
| Logging steps | 50 |
| Output dir | ./lora_adapter_improved |
Training environment: Google Colab (T4 GPU, 15 GB VRAM)
Evaluated on the Banking77 test split (3,080 samples) using evaluate.py:
| Metric | Score |
|---|---|
| Overall Accuracy | ~82–85% |
| Macro F1 | ~0.82 |
| Weighted F1 | ~0.83 |
| Macro Precision | ~0.84 |
| Macro Recall | ~0.82 |
| Inference speed (CPU) | ~150–200 ms / query |
| Inference speed (GPU) | ~15–25 ms / query |
Note: Exact numbers depend on the training run. Run
python evaluate.pyto reproduce metrics on your adapter weights. The training loss showed convergence, with occasional spikes due to FP16 on CPU — these stabilise on GPU.
LoRA decomposes weight updates into two small matrices A ∈ R^{r×d} and B ∈ R^{d×r}, where r=16. The effective delta ΔW = BA is added to the frozen weight at inference. This gives:
- 4× lower GPU memory vs full fine-tuning
- ~3× faster training
- Adapter file size < 10 MB (vs 1 GB for the full model)
bankbot-lora-flant5-fastapi/
├── app/
│ ├── __init__.py
│ └── main.py # FastAPI application
├── banking-classifier-api/ # Standalone API copy (for cloud deploy)
├── models/
│ └── lora_adapter_improved/ # Trained LoRA adapter weights
│ ├── adapter_config.json
│ ├── adapter_model.safetensors
│ ├── tokenizer.json
│ ├── tokenizer_config.json
│ ├── special_tokens_map.json
│ └── spiece.model
├── FineTuning_LoRA.ipynb # Training notebook (run on Colab)
├── evaluate.py # Offline evaluation script
├── test_api.py # API integration tests
├── requirements.txt # Python dependencies
├── Dockerfile # Container config
├── .dockerignore
├── index.html # Simple web UI
└── README.md
- Python 3.9+
- CUDA-capable GPU (optional, but recommended for training/fast inference)
git clone https://github.com/aneessaheba/peft-banking-classifier.git
cd peft-banking-classifier
pip install -r requirements.txtuvicorn app.main:app --host 0.0.0.0 --port 8000 --reloadOpen http://localhost:8000/docs for the interactive Swagger UI.
import requests
response = requests.post(
"http://localhost:8000/predict",
json={"text": "My card was charged twice"}
)
print(response.json())
# {'text': 'My card was charged twice', 'predicted_category': 'transaction_charged_twice', 'confidence': 'high'}Open FineTuning_LoRA.ipynb in Google Colab (GPU runtime recommended) and run all cells sequentially:
- Install dependencies
- Check GPU availability
- Load Banking77 dataset
- Load FLAN-T5-base
- Apply LoRA configuration
- Preprocess & tokenize data
- Train (10 epochs, ~30–40 min on T4)
- Evaluate & save adapter
Returns API metadata and available endpoints.
{"status": "healthy", "model_loaded": true, "device": "cuda", "categories_count": 77}Returns the full list of 77 Banking77 intent labels.
Classify a single query.
Request:
{"text": "I want to activate my card"}Response:
{
"text": "I want to activate my card",
"predicted_category": "activate_my_card",
"confidence": "high"
}Classify up to 100 queries in one call.
Request:
["My card was stolen", "How do I top up?", "Transfer money abroad"]Response:
{
"predictions": [
{"text": "My card was stolen", "predicted_category": "lost_or_stolen_card"},
{"text": "How do I top up?", "predicted_category": "topping_up_by_card"},
{"text": "Transfer money abroad", "predicted_category": "transfer_into_account"}
],
"count": 3,
"success": true
}# Build
docker build -t bankbot-classifier .
# Run
docker run -p 8000:8000 bankbot-classifierAPI available at http://localhost:8000
Run the offline evaluation script against the Banking77 test set:
# Evaluate on 500 test samples (fast)
python evaluate.py --max-samples 500
# Full test set evaluation (3,080 samples)
python evaluate.py --max-samples 0
# Custom model path
python evaluate.py --model-path ./models/lora_adapter_improved --split testOutputs:
- Console: accuracy, F1, precision, recall, per-class breakdown
evaluation_results.json— full metrics as JSONconfusion_matrix.png— 77×77 confusion matrix heatmap
# Start server first, then:
python test_api.py --base-url http://localhost:8000| Component | Library / Tool |
|---|---|
| Base model | google/flan-t5-base (HuggingFace Transformers) |
| Fine-tuning | PEFT (LoRA) |
| Training | PyTorch + HuggingFace Trainer |
| Dataset | PolyAI/banking77 (HuggingFace Datasets) |
| API framework | FastAPI + Uvicorn |
| Validation | Pydantic v2 |
| Containerisation | Docker |
| Evaluation | scikit-learn |
| Training environment | Google Colab (T4 GPU) |
Anees Saheba — aneessaheba.guddi@sjsu.edu San José State University