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%+ ✅