Chuyển tới nội dung chính

ML/AI Service - Smart City Platform

1. Tổng Quan​

ML Service là dịch vụ Machine Learning được xây dựng bằng FastAPI (Python), chịu trách nhiệm phân loại tự động dữ liệu IoT thành các mức độ quan trọng (HOT/COLD) bằng thuật toán IsolationForest.

Vai trò trong hệ thống​

Data Flow Chi Tiết​

                              ML-SERVICE
┌────────────────────────────────────────┐
│ │
Sensor Data │ ┌─────────────┐ │
↓ │ │ Prediction │ │
┌─────────┐ │ │ │ │
│ Backend │ ──────────►│ │ confidence? │ │
│ (Java) │ POST │ └──────┬──────┘ │
└────┬────┘ /predict │ │ │
│ │ ┌─────┴─────┐ │
│ │ │ │ │
│ │ >0.8 ≤0.8 │
│ │ │ │ │
│ │ ▼ ▼ │
│ │ ┌──────┐ ┌──────────┐ │
│ │ │Return│ │ Return │ │
│ │ │HOT/ │ │ HOT/COLD │ │
│ │ │COLD │ │ + │ │
│ │ └──┬───┘ │ Log to │ │
│ │ │ │ SQLite │◄─── UNKNOWN │
│ │ │ └────┬─────┘ lưu ở đây! │
│ │ │ │ │
│ └─────┼────────────┼─────────────────────┘
│ │ │
◄───────────────────────┘ │
│ │
│ HOT/COLD only │
│ (Backend không biết UNKNOWN) │
▼ ▼
┌─────────┐ ┌──────────┐
│ Redis │ ← HOT │ SQLite │ ← UNKNOWN
│ MongoDB │ ← COLD │ (in ML) │ events
└─────────┘ └──────────┘

Giải thích:

  • confidence > 0.8: Model tin tưởng → trả về HOT/COLD trực tiếp
  • confidence ≤ 0.8: Model không chắc chắn → vẫn trả HOT/COLD nhưng log vào SQLite để review
  • Backend: Chỉ nhận HOT/COLD, không biết về UNKNOWN (backward compatible)
  • SQLite: Lưu trữ các events cần operator review

2. Công Nghệ Sử Dụng​

Công nghệPhiên bảnVai trò
FastAPI0.104+Web framework (async, high performance)
scikit-learn1.3+Machine Learning library
IsolationForest-Anomaly detection algorithm
Python3.10Runtime
Uvicorn-ASGI server
Joblib-Model serialization

Tại sao chọn FastAPI?​

  • ✅ Async native - Xử lý đồng thời nhiều request
  • ✅ Auto validation với Pydantic schemas
  • ✅ Auto docs tại /docs (Swagger UI)
  • ✅ High performance - Ngang với NodeJS, Go

Tại sao chọn IsolationForest?​

  • ✅ Unsupervised - Không cần labeled data
  • ✅ Fast inference - ~10-15ms per prediction
  • ✅ Robust - Hoạt động tốt với sensor data
  • ✅ Simple - Dễ deploy và maintain

3. Kiến Trúc Source Code​

ml-service/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI application entry point
│ ├── config.py # Configuration & semantic mapping
│ └── models/
│ ├── loader.py # Model loading utilities
│ ├── schemas.py # Pydantic request/response schemas
│ ├── temperature_model.pkl
│ ├── humidity_model.pkl
│ └── co2_model.pkl
├── train_models.py # Training script
├── requirements.txt
├── Dockerfile
└── entrypoint.sh # Auto-train on startup

Mô tả các file chính​

FileChức năng
main.pyFastAPI app, endpoints /predict, /health
config.pyPaths, semantic map cho camera events
loader.pyLoad models từ .pkl files
schemas.pyPydantic schemas cho request/response
train_models.pyScript huấn luyện IsolationForest

4. API Endpoints​

4.1 POST /predict​

Phân loại dữ liệu sensor hoặc camera event.

Request - Sensor:

{
"source": "sensor",
"metric_type": "temperature",
"value": 45.5
}

Response:

{
"label": "HOT",
"uri": "https://schema.org/Warning",
"desc": "Temperature Anomaly Detected",
"metric_type": "temperature",
"value": 45.5
}

Request - Camera:

{
"source": "camera",
"event": "fire"
}

Response:

{
"label": "HOT",
"uri": "https://schema.org/FireEvent",
"desc": "Fire Hazard Detected"
}

4.2 GET /health​

Health check endpoint.

Response:

{
"status": "ok",
"models_loaded": {
"temperature": true,
"humidity": true,
"co2": true
},
"total_models": 3
}

4.3 GET /​

Root endpoint.

Response:

{
"service": "ML Anomaly Detection",
"version": "1.0.0",
"status": "running",
"docs": "/docs"
}

5. Thuật Toán IsolationForest​

5.1 Nguyên lý hoạt động​

IsolationForest phát hiện anomaly bằng cách cô lập các điểm dữ liệu:

Core Idea: Điểm bất thường dễ bị cô lập hơn điểm bình thường

Dữ liệu bình thường          Dữ liệu bất thường
(dense cluster) (isolated)

o o o
o O O o ← Cần nhiều x ← Chỉ 1-2 splits
o o o splits là isolate được!

5.2 Quy trình​

  1. Build Random Forest - Tạo 100 random decision trees
  2. Random Splits - Mỗi tree split ngẫu nhiên theo feature và value
  3. Path Length - Đo độ sâu cần thiết để isolate mỗi điểm
  4. Anomaly Score - Điểm càng nông = càng bất thường

5.3 Công thức​

Anomaly Score: s(x, n) = 2^(-E(h(x)) / c(n))

Trong đó:
- E(h(x)): Path length trung bình
- c(n): Normalization factor
- s < 0.5: Normal (inlier)
- s > 0.5: Anomaly (outlier)

5.4 Trong code​

# IsolationForest returns: 1 = Normal, -1 = Anomaly
prediction = model.predict([[value]])

if prediction[0] == 1:
label = "COLD" # Normal
else:
label = "HOT" # Anomaly

6. Training Data​

6.1 Temperature Model​

  • Range: 15-35°C (normal urban temperature)
  • Samples: 10,000 (uniform + seasonal patterns)
  • Contamination: 0.1 (10% anomalies expected)

6.2 Humidity Model​

  • Range: 30-80%
  • Samples: 10,000
  • Contamination: 0.1

6.3 CO2 Model​

  • Range: 350-900 ppm (safe levels)
  • Samples: 7,000 (outdoor + indoor)
  • Contamination: 0.1

7. Semantic Mapping (Camera Events)​

Camera events được map trực tiếp theo bảng:

EventLabelURIDescription
fireHOTschema.org/FireEventFire Hazard Detected
accidentHOTschema.org/TrafficIncidentTraffic Accident
traffic_jamWARMw3id.org/sosa/ObservationTraffic Congestion
normalCOLDschema.org/SafeConditionNormal Conditions
unknownUNKNOWNschema.org/ThingUnknown Event

8. Performance​

8.1 Latency​

MetricValue
Average~15ms
p95~30ms
p99~50ms

8.2 Resource Usage​

ResourceUsage
Memory~150-200MB
CPU<10% at 20 req/s
Startup~2-3 seconds

9. Deployment​

# Build
docker build -t smart-city-ml ./ml-service

# Run
docker run -p 8000:8000 smart-city-ml

Docker Compose​

docker compose up -d ml-service

Manual (Development)​

cd ml-service
pip install -r requirements.txt

# Train models (if not exist)
python train_models.py

# Start server
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

10. Demo Commands​

# Health check
curl http://localhost:8000/health

# Predict normal temperature
curl -X POST http://localhost:8000/predict \
-H "Content-Type: application/json" \
-d '{"source":"sensor","value":25,"metric_type":"temperature"}'
# → label: COLD

# Predict anomaly temperature
curl -X POST http://localhost:8000/predict \
-H "Content-Type: application/json" \
-d '{"source":"sensor","value":80,"metric_type":"temperature"}'
# → label: HOT

# Camera event
curl -X POST http://localhost:8000/predict \
-H "Content-Type: application/json" \
-d '{"source":"camera","event":"fire"}'
# → label: HOT

11. Integration với Backend​

Backend (Spring Boot) gọi ML Service qua REST API:

@Service
public class MLServiceClient {

@Value("${ml.service.url}")
private String mlServiceUrl;

public String classify(SensorData data) {
String url = mlServiceUrl + "/predict";

Map<String, Object> request = Map.of(
"source", "sensor",
"metric_type", data.getMetricType(),
"value", data.getValue()
);

MLResponse response = restTemplate.postForObject(
url, request, MLResponse.class
);

return response.getLabel(); // "HOT" or "COLD"
}
}

12. Auto-Retraining Model​

12.1 Kiến trúc Retraining​

┌─────────────────────────────────────────────────────────────┐
│ ML-SERVICE │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ FastAPI │ │ Worker │ │
│ │ (Main) │ │ Thread │ │
│ │ │ │ (Daemon) │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ │ Predictions │ Check mỗi 1 giờ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Models │◄─── HOT-SWAP─┤ Retrainer │ │
│ │ (Global) │ (Atomic) │ │ │
│ └──────────────┘ └──────┬───────┘ │
│ │ │
│ │ Query labeled data │
│ ▼ │
│ ┌──────────────┐ │
│ │ SQLite │ │
│ │ Database │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘

12.2 Quy trình Retraining​

┌─────────────────┐
│ Check mỗi 1 giờ │
└────────┬────────┘
▼
┌─────────────────┐
│ Labeled data │
│ >= 100 samples? │
└────────┬────────┘
│
Yes │ No → Skip
▼
┌─────────────────┐
│ Load original │
│ training data │
└────────┬────────┘
▼
┌─────────────────┐
│ Combine with │
│ new labeled data│
└────────┬────────┘
▼
┌─────────────────┐
│ Train new │
│ IsolationForest │
└────────┬────────┘
▼
┌─────────────────┐
│ Validate model │
│ (>= 80% acc) │
└────────┬────────┘
│
Pass │ Fail → Keep old
▼
┌─────────────────┐
│ Backup old │
│ HOT-SWAP new │
│ Save to disk │
└─────────────────┘

12.3 Hot-Swap Mechanism​

Zero downtime update:

# Atomic operation - Thread-safe trong Python (GIL)
models["temperature"] = new_model

# Predictions tiếp tục KHÔNG GIÁN ĐOẠN!
# - Thread đang predict: dùng old model
# - Thread mới: dùng new model
# - Không có locking, không có downtime

12.4 Validation Rules​

RuleThresholdMục đích
Min samples>= 100Đủ data để retrain
Accuracy>= 80%Không làm model kém đi
Normal rate>= 80%Vẫn nhận ra patterns cũ

12.5 Retraining Code Logic​

class RetrainingWorker(Thread):
def run(self):
while True:
for metric_type in ["temperature", "humidity", "co2"]:
# 1. Query labeled events
labeled = db.get_labeled_for_training(metric_type)

if len(labeled) >= 100:
# 2. Load original + new data
original = load_original_data(metric_type)
combined = np.vstack([original, labeled])

# 3. Train new model
new_model = IsolationForest().fit(combined)

# 4. Validate
if validate(new_model, original):
# 5. Backup + Hot-swap
backup(models[metric_type])
models[metric_type] = new_model

# 6. Mark data as used
db.mark_used_for_training(labeled)

sleep(3600) # 1 hour

12.6 Benefits​

  • ✅ Continuous Learning - Model tự cải thiện
  • ✅ Zero Downtime - Hot-swap atomic
  • ✅ Automatic - Không cần manual intervention
  • ✅ Safe - Validate trước khi deploy

13. Tổng Kết​

Đã hoàn thành​

  • ✅ IsolationForest anomaly detection
  • ✅ 3 models: temperature, humidity, CO2
  • ✅ REST API với FastAPI
  • ✅ Camera event semantic mapping
  • ✅ Docker deployment
  • ✅ Auto-train on startup

Metrics​

MetricTargetAchieved
Latency<50ms~15ms ✅
Models33 ✅
Uptime99%99%+ ✅