Introduction
This tutorial demonstrates how to build a text classification system for bank transactions using TensorFlow and deploy it on mobile platforms. The system automatically categorizes transaction descriptions and implements a micro-savings mechanism based on spending behavior analysis. This tutorial focuses on Switzerland market. Swiss Francs(CHF) is their currency.
The complete implementation covers synthetic data generation, model training in Google Colab, TensorFlow Lite conversion, and mobile integration for both iOS and Android platforms.
Github Link For below tutorial resource
Use Case: Automated Transaction Classification and Micro-Savings
Problem Statement
Traditional budgeting applications require manual transaction categorization, leading to poor user adoption and inconsistent data quality. Our solution automates this process using machine learning to classify transactions and implement behavioral-based savings.
Classification System
The model classifies bank transactions into three categories with corresponding savings rates:
Category | Description | Savings Rate | Examples |
---|---|---|---|
Normal | Essential expenses and regular income | 1% | Groceries, utilities, salary, rent |
Avoidable | Non-essential but reasonable expenses | 2% | Dining out, subscriptions, entertainment |
Regrettable | Impulse purchases and unnecessary expenses | 5% | Luxury items, duplicate purchases, late-night shopping |
System Architecture
The following diagram illustrates the transaction processing workflow:
Figure 1: Transaction classification and savings mechanism workflow
Savings Mechanism Workflow
- Transaction Input: Bank transaction description received
- Text Classification: TensorFlow Lite model processes the description
- Percentage Deduction: Apply savings rate based on classification:
- Normal transactions: 1% deduction
- Avoidable transactions: 2% deduction
- Regrettable transactions: 5% deduction
- Fund Accumulation: Deducted amounts accumulate in savings account
- Automatic Investment: When fund reaches 50 CHF threshold, trigger investment
Technical Components
The implementation consists of four main components:
- Data Generation Pipeline
- Synthetic transaction data generator
- Data validation and improvement scripts
- Training dataset preparation
- Model Training Infrastructure
- Google Colab training environment
- TensorFlow text classification model
- Model evaluation and optimization
- Mobile Deployment
- TensorFlow Lite model conversion
- iOS Swift integration
- Android Kotlin/Java integration
Why Local Models
This implementation uses on-device inference through TensorFlow Lite rather than cloud-based APIs for several critical reasons:
Cost Optimization
- Eliminates per-request API costs by offloading inference to user devices
- Reduces server infrastructure requirements and operational expenses
- Scales efficiently as user base grows without proportional cost increases
Privacy Compliance
- Sensitive financial data remains on the user’s device
- Complies with GDPR, PCI DSS, and regional financial privacy regulations
- Eliminates data transmission risks and potential breach vectors
- No server-side storage of transaction descriptions required
Offline Availability
- Classification works without internet connectivity
- Critical for real-time transaction processing and savings calculations
- You can have model dependcy management and version management via tools like Firebase
Performance Benefits
- Sub-100ms inference (Most Times) latency on modern mobile devices
- No network round-trip delays
- Consistent response times independent of server load
Expected Outcomes
This tutorial will demonstrate how to:
- Generate synthetic banking data for machine learning training
- Build and train a text classification model using TensorFlow
- Convert trained models to TensorFlow Lite for mobile deployment
- Integrate ML models into native mobile applications
- Implement automated savings logic based on classification results
The resulting system provides automated transaction categorization with 85%+ accuracy while maintaining user privacy through on-device processing.
Synthetic Data Generation
Machine learning models require substantial training data to achieve reliable performance. Since real banking transaction data is sensitive and restricted, we generate synthetic transaction descriptions that mirror real-world patterns while maintaining privacy compliance.
Data Generator Script
The primary data generation script creates realistic transaction descriptions across our three classification categories:
import random
import pandas as pd
# 20 merchants per category
MERCHANT_CATEGORIES = {
"normal": [
"Migros Supermarket", "Coop Groceries", "Pharmacy Zürich", "SBB Ticket", "PostFinance Bill Pay",
"Denner", "Lidl", "Aldi", "Swisscom", "Manor", "Tchibo", "Helsana Health", "City Bus Ticket",
"Swiss Post", "Bookstore", "Local Bakery", "Apotheke Zürich", "Mobile Top-Up", "Cablecom", "Sunrise Telecom"
],
"avoidable": [
"Amazon Online", "Starbucks", "H&M Clothing", "Zara Outlet", "Gas Station", "C&A", "MediaMarkt", "Burger King",
"Mobile Accessories", "Spotify", "Netflix", "IKEA", "Decathlon", "Uber Eats", "Globus", "AliExpress",
"Online Gaming", "Domino's Pizza", "Electronics Mall", "Snack Vending Machine"
],
"regrettable": [
"McDonald's", "Cigarette Shop", "Bar Zürich", "Late Night Kebab", "Liquor Store", "24/7 Shop",
"Fast Food Van", "Sports Betting", "Hookah Lounge", "After Party Club", "Beer Shop", "Fried Chicken Stand",
"Mini Bar", "Nightlife Lounge", "Vodka & More", "Late Night Donuts", "Whiskey World", "Shisha Zone",
"Pub Crawl ZH", "Late Night Snacks"
]
}
def generate_transaction():
category = random.choice(list(MERCHANT_CATEGORIES.keys()))
merchant = random.choice(MERCHANT_CATEGORIES[category])
# Randomize amount range per category
if category == "normal":
amount = round(random.uniform(5, 80), 2)
elif category == "avoidable":
amount = round(random.uniform(10, 100), 2)
else: # regrettable
amount = round(random.uniform(5, 50), 2)
transaction_text = f"{merchant} - CHF {amount}"
return {
"merchant_name": merchant,
"transaction_amount": amount,
"transaction_text": transaction_text,
"transaction_type": category
}
def generate_dataset(num_samples=5000, output_csv="synthetic_transactions.csv"):
data = [generate_transaction() for _ in range(num_samples)]
df = pd.DataFrame(data)
df.to_csv(output_csv, index=False)
print(f"Generated {num_samples} synthetic transactions to: {output_csv}")
if __name__ == "__main__":
generate_dataset(num_samples=5000)
Key Design Decisions
Merchant Categorization Strategy
- Normal: Essential services (groceries, utilities, healthcare, transportation)
- Avoidable: Discretionary but reasonable spending (retail, subscriptions, dining)
- Regrettable: Impulse and potentially harmful purchases (fast food, gambling, alcohol)
Amount Distribution Logic
- Normal transactions: 5-80 CHF (broader range for essentials)
- Avoidable transactions: 10-100 CHF (higher ceiling for retail purchases)
- Regrettable transactions: 5-50 CHF (lower range for impulse buys)
Transaction Format
Follows standard Swiss banking description format: "Merchant Name - CHF Amount"
Data Improvement Script
The data improvement script normalizes text formatting for consistent model training:
import pandas as pd
# Load the generated dataset
df = pd.read_csv("synthetic_transactions.csv")
# Normalize transaction text to lowercase
df['transaction_text'] = df['transaction_text'].str.lower()
# Save processed data
df.to_csv("synthetic_transactions_processed.csv", index=False)
print("Data preprocessing completed")
Text Normalization Benefits
Consistency: Eliminates case sensitivity variations in merchant names Model Performance: Reduces vocabulary size and improves pattern recognition Real-world Compatibility: Matches typical banking data format variations
Generated Dataset Structure
The resulting CSV contains the following columns:
Column | Type | Description | Example |
---|---|---|---|
merchant_name |
String | Business name | “Migros Supermarket” |
transaction_amount |
Float | Transaction value | 45.67 |
transaction_text |
String | Full description | “migros supermarket - chf 45.67” |
transaction_type |
String | Classification label | “normal” |
Usage Instructions
- Generate initial dataset:
python data_generator.py
- Apply text normalization:
python data_improver.py
- Verify output:
import pandas as pd df = pd.read_csv("synthetic_transactions_processed.csv") print(df.head()) print(f"Dataset size: {len(df)} transactions") print(f"Category distribution:\n{df['transaction_type'].value_counts()}")
The processed dataset provides 5,000 balanced training samples ready for TensorFlow model training. The synthetic approach ensures privacy compliance while generating realistic transaction patterns for effective classification model development.
TensorFlow Model Training in Google Colab
Note: When I tried from Tensorflow documentation, some code were outdated. I have to search, read through documentation, use chatgpt/gemini to figure out missing items. If you want to try this sometime later, and if the below code is outdated, feel free to repeat what i did. World moves fast!😅
This section covers training a text classification model using TensorFlow in Google Colab and converting it to TensorFlow Lite for mobile deployment.
Environment Setup
Create a new Google Colab notebook and install the required dependencies:
import pandas as pd
import numpy as np
import tensorflow as tf
from sklearn.model_selection import train_test_split
from tensorflow.keras.layers import TextVectorization
from google.colab import files
Data Loading and Preprocessing
Upload the synthetic dataset generated in the previous step and prepare it for training:
df = pd.read_csv("synthetic_transactions.csv")
# Create label mapping for categorical encoding
label_to_index = {'normal': 0, 'avoidable': 1, 'regrettable': 2}
index_to_label = {v: k for k, v in label_to_index.items()}
df['label'] = df['transaction_type'].map(label_to_index)
# Split dataset into training and validation sets
X_train_raw, X_val_raw, y_train, y_val = train_test_split(
df['transaction_text'].values,
df['label'].values,
test_size=0.2,
random_state=42
)
Text Vectorization Configuration
Configure text preprocessing parameters for optimal mobile performance:
# Vectorization parameters optimized for mobile deployment
max_tokens = 1000 # Vocabulary size limit
sequence_length = 20 # Maximum input sequence length
# Initialize text vectorizer
vectorizer = TextVectorization(
max_tokens=max_tokens,
output_mode='int',
output_sequence_length=sequence_length
)
# Adapt vectorizer to training data and transform datasets
vectorizer.adapt(X_train_raw)
X_train = vectorizer(X_train_raw)
X_val = vectorizer(X_val_raw)
Model Architecture
We can now build a lightweight neural network suitable for our use case
model = tf.keras.Sequential([
tf.keras.layers.Embedding(
input_dim=max_tokens,
output_dim=16,
input_length=sequence_length
),
tf.keras.layers.GlobalAveragePooling1D(),
tf.keras.layers.Dense(32, activation='relu'),
tf.keras.layers.Dense(3, activation='softmax') # 3 output classes
])
# Compile model with standard classification settings
model.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
Model Training
Train the model with the synthetic dataset:
# Train model for 10 epochs
history = model.fit(
X_train, y_train,
validation_data=(X_val, y_val),
epochs=10,
batch_size=32
)
# Export trained model in SavedModel format
model.export("transaction_classifier_savedmodel")
Expected Training Results:
- Training accuracy: ~100% (synthetic data with clear patterns)
- Validation accuracy: ~100%
- Training time: <2 minutes on Colab
TensorFlow Lite Conversion
Convert the trained model to TensorFlow Lite format for mobile deployment:
# Initialize TFLite converter from SavedModel
converter = tf.lite.TFLiteConverter.from_saved_model("transaction_classifier_savedmodel")
# Convert model to TensorFlow Lite format
tflite_model = converter.convert()
# Save TFLite model file
with open("transaction_classifier.tflite", "wb") as f:
f.write(tflite_model)
print("TFLite model saved as 'new_transaction_classifier.tflite'")
Model Validation
Test the trained model with sample transactions to verify classification accuracy:
# Define test samples covering all categories
sample_texts = [
"Night club - CHF 14.90", # regrettable
"Coop Groceries - CHF 25.00", # normal
"Amazon Online - CHF 49.99", # avoidable
"Liquor Store - CHF 18.00", # regrettable
"Pharmacy Zürich - CHF 32.10" # normal
]
# Run inference on test samples
X_test = vectorizer(tf.constant(sample_texts))
predictions = model.predict(X_test)
predicted_labels = [np.argmax(p) for p in predictions]
# Display prediction results
print("\nSample Predictions:")
for text, pred in zip(sample_texts, predicted_labels):
print(f"{text} --> Predicted: {index_to_label[pred]}")
Model Download
Download the TensorFlow Lite model for mobile integration:
from google.colab import files
# Download TFLite model to local machine
files.download("new_transaction_classifier.tflite")
Model Specifications
The resulting TensorFlow Lite model has the following characteristics:
Specification | Value |
---|---|
Model size | ~68 KB |
Input shape | (1, 20) integers |
Output shape | (1, 3) probabilities |
Vocabulary size | 1000 tokens |
Inference time | <50ms on mobile |
Key Implementation Details
Embedding Layer: Converts text tokens to dense vectors (16 dimensions) GlobalAveragePooling1D: Aggregates sequence information into fixed-size representation Dense Layers: Fully connected layers for classification with ReLU activation Softmax Output: Probability distribution over three transaction categories
The trained model achieves perfect accuracy on synthetic data due to clear categorical patterns in the generated dataset. Real-world performance may vary but should maintain high accuracy for similar transaction patterns.
Vocabulary Download
We need to download this vectorizer, which we will need in next part for loading same vocabulary in iOS and Android TensorFlow interpreter.
vocabulary = vectorizer.get_vocabulary()
vocab_dict = {word: idx for idx, word in enumerate(vocabulary)}
# Save vocabulary to JSON file
import json
with open("vocabulary.json", "w") as f:
json.dump(vocab_dict, f)
print(f"Vocabulary saved with {len(vocab_dict)} tokens")
# Also download the vocabulary file
files.download("vocabulary.json")
Alternative: CreateML Training
TLDR: Good for iOS/macOS and not optimized for andorid
For iOS-focused development, Apple’s CreateML provides a streamlined approach to train text classification models without coding. This method produces CoreML models (.mlmodel) optimized for Apple platforms.
Prerequisites
- macOS device with Xcode installed
- CreateML app (available through Xcode or Mac App Store)
- Synthetic transaction dataset (CSV format)
Training Process
Step 1: Launch CreateML Open CreateML application and select “Text Classification” template.
Step 2: Data Upload
- Click “Training Data” section
- Upload the
synthetic_transactions.csv
file generated previously - CreateML automatically detects columns:
transaction_text
(input) andtransaction_type
(label)
Step 3: Model Training
- Click “Train” button
- Training completes in 1-2 minutes
- Achieves 100% accuracy on synthetic dataset
Step 4: Model Validation (Optional)
- Upload test dataset in “Testing Data” section
- CreateML evaluates model performance on unseen data
Step 5: Interactive Testing Use the Preview panel to test individual predictions:
Input: "Night Bar"
Output: regrettable (98% confidence)
Input: "Night Club"
Output: regrettable (77% confidence)
Step 6: Model Export
- Navigate to Output tab
- Click “Get” to save the trained model
- Save as
TransactionClassifier.mlmodel
Model Performance Comparison
Test Input | Prediction | Confidence | Notes |
---|---|---|---|
“Night Bar” | regrettable | 98% | High confidence for exact match |
“Night Club” | regrettable | 77% | Lower confidence for similar pattern |
“Coop Groceries” | normal | 99% | Clear essential category |
“Amazon Online” | avoidable | 95% | Recognized shopping pattern |
CreateML vs TensorFlow Comparison
Aspect | CreateML | TensorFlow |
---|---|---|
Platform Support | iOS/macOS only | Cross-platform |
Training Complexity | GUI-based, no coding | Code-based implementation |
Model Format | CoreML (.mlmodel) | TensorFlow Lite (.tflite) |
Training Time | 1-2 minutes | 2-3 minutes |
Model Size | ~45 KB | ~68 KB |
Integration | Native iOS/macOS | Requires TensorFlow Lite runtime |
iOS Integration Benefits
Native Performance: CoreML models run directly on Apple’s Neural Engine Automatic Optimization: CreateML optimizes models for specific device capabilities Seamless Integration: Direct import into Xcode projects without external dependencies On-device Processing: Full privacy compliance with local inference
Limitations
Platform Restriction: Models only compatible with iOS and macOS applications Limited Customization: Less control over model architecture compared to TensorFlow Vendor Lock-in: Dependency on Apple’s machine learning ecosystem
When to Choose CreateML
- Developing exclusively for iOS/macOS platforms
- Prefer visual training interface over code
- Need maximum performance on Apple devices
- Want native integration without external dependencies
For cross-platform applications requiring Android support, TensorFlow remains the recommended approach despite CreateML’s simplicity advantages.
Will CreateML work for Android
I would not recommend any Create ML models to work in android as the CreateML optimizations don’t translate well to ONNX or TFLite. You may lose quantization, custom layers, or platform-specific acceleration (like Metal on iOS). It may work for simple text classification or regression, but you will see differences in complex tabular classifications or regressions or recommendations.
1. Convert Core ML to ONNX
# Install coremltools and onnxmltools
pip install coremltools onnxmltools
# Convert Core ML to ONNX (Python)
import coremltools as ct
import onnxmltools
coreml_model = ct.models.MLModel("model.mlmodel")
onnx_model = onnxmltools.convert_coreml(coreml_model, target_opset=13)
onnxmltools.utils.save_model(onnx_model, "model.onnx")
2. Convert ONNX to TFLite
# Install tf2onnx and TensorFlow
pip install tf2onnx tensorflow
# Convert ONNX to TensorFlow SavedModel
python -m tf2onnx.convert --onnx model.onnx --output model.pb
# Convert SavedModel to TFLite
import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model("model.pb")
tflite_model = converter.convert()
open("model.tflite", "wb").write(tflite_model)
3. Use TFLite Model in Android
// Load TFLite model
Interpreter tflite = new Interpreter(loadModelFile("model.tflite"));
// Run inference
float[][] input = new float[1][...];
float[][] output = new float[1][...];
tflite.run(input, output);
Important Info
The trained model achieves perfect accuracy on synthetic data due to clear categorical patterns in the generated dataset.
Real-world performance may vary but should maintain high accuracy for similar transaction patterns. Expect more anamolies and imperfections in real world though.
Now we will have final part to integrate in native iOS and Android