Edge AI trong thiết bị y tế tại nhà: On-device model compression

Tóm tắt nội dung chính
Edge AI trong thiết bị y tế tại nhà đang mở ra cơ hội đưa trí tuệ nhân tạo vào các phòng khám cá nhân, giúp chẩn đoán sớm, giảm tải bệnh viện.
On‑device model compression là chìa khóa để mô hình AI chạy mượt trên vi‑xử lý nhúng (CPU, MCU, NPU) với bộ nhớ và năng lượng hạn chế.
– Bài viết sẽ đi sâu vào vấn đề thực tiễn, giải pháp tổng quan, hướng dẫn chi tiết từng bước triển khai, template quy trình, lỗi phổ biến & cách sửa, cách scale, chi phí thực tế, số liệu trước‑sau, và FAQ.
– Kèm theo bảng so sánh, sơ đồ workflow, công thức tính toánba câu chuyện thực tế để bạn có cái nhìn toàn diện và có thể áp dụng ngay.


1. Vấn đề thật mà mình và khách hay gặp mỗi ngày

⚡ Hiệu năng: Một mô hình AI chuẩn (ví dụ: ResNet‑50) có kích thước 98 MB, thời gian suy luận trên Raspberry Pi 4 khoảng 2,3 s – quá chậm để cung cấp phản hồi thời gian thực cho người dùng tại nhà.
🐛 Bug: Khi triển khai trên MCU (STM32H7), bộ nhớ flash chỉ 2 MB, RAM 1 MB, mô hình không thể load được, gây “segmentation fault”.
🛡️ Bảo mật: Dữ liệu sinh trắc học (ECG, SpO₂) được thu thập và xử lý trên thiết bị, nếu gửi lên đám mây mà không mã hoá, nguy cơ rò rỉ thông tin cá nhân rất cao.

Khách hàng thường hỏi:

  • “Mô hình AI có thể chạy trên thiết bị nào mà không cần internet?”
  • “Chi phí đầu tư phần cứng và phần mềm sẽ tăng bao nhiêu khi mình muốn nén mô hình?”
  • “Nếu muốn mở rộng sang 10 000 thiết bị, quy trình chuẩn hoá như thế nào?”

2. Giải pháp tổng quan (text art)

+-------------------+        +-------------------+        +-------------------+
|   Thu thập dữ liệu|  --->  |  Tiền xử lý (DSP) |  --->  |  On‑device AI     |
|   (ECG, PPG, …)   |        |  (Noise cancel)   |        |  (Compressed)    |
+-------------------+        +-------------------+        +-------------------+
          |                         |                           |
          |                         |                           |
          v                         v                           v
   +-------------------+   +-------------------+        +-------------------+
   |  Lưu trữ cục bộ   |   |  Kiểm tra an toàn |        |  Phản hồi người   |
   |  (SQLite/Flash)   |   |  (Threshold)      |        |  dùng (LED/Screen)|
   +-------------------+   +-------------------+        +-------------------+

Quy trình:
1. Thu thập → 2. Tiền xử lý → 3. Nén mô hình → 4. Triển khai → 5. Giám sát & cập nhật OTA.


3. Hướng dẫn chi tiết từng bước, ứng dụng thực tế

Bước 1: Chuẩn bị dữ liệu & tiền xử lý

# Python script (PC) – chuẩn bị dataset ECG
import wfdb, numpy as np

def load_ecg(record_path):
    record = wfdb.rdrecord(record_path)
    signal = record.p_signal[:,0]   # kênh Lead‑I
    # Loại bỏ baseline wander bằng high‑pass filter 0.5 Hz
    from scipy.signal import butter, filtfilt
    b,a = butter(2, 0.5/(500/2), btype='high')
    clean = filtfilt(b, a, signal)
    return clean
  • Lưu ý: Dữ liệu phải được chuẩn hoá (z‑score) và cắt thành đoạn 5 s để phù hợp với input của mô hình.

Bước 2: Huấn luyện mô hình gốc (trên GPU)

# TensorFlow – mô hình CNN đơn giản cho arrhythmia detection
import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Conv1D(32, 5, activation='relu', input_shape=(5000,1)),
    tf.keras.layers.MaxPooling1D(2),
    tf.keras.layers.Conv1D(64, 3, activation='relu'),
    tf.keras.layers.GlobalAveragePooling1D(),
    tf.keras.layers.Dense(2, activation='softmax')
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(train_dataset, epochs=30, validation_data=val_dataset)
  • Kết quả: Accuracy ≈ 96 % trên tập validation.

Bước 3: Nén mô hình (On‑device model compression)

3.1. Pruning (cắt tỉa)

import tensorflow_model_optimization as tfmot

prune_low_magnitude = tfmot.sparsity.keras.prune_low_magnitude
pruned_model = prune_low_magnitude(model, 
    pruning_schedule=tfmot.sparsity.keras.PolynomialDecay(initial_sparsity=0.0,
                                                          final_sparsity=0.7,
                                                          begin_step=0,
                                                          end_step=1000))
pruned_model.compile(optimizer='adam',
                     loss='sparse_categorical_crossentropy',
                     metrics=['accuracy'])
pruned_model.fit(train_dataset, epochs=5, validation_data=val_dataset)

3.2. Quantization‑aware training (QAT)

quant_aware_model = tfmot.quantization.keras.quantize_model(pruned_model)
quant_aware_model.compile(optimizer='adam',
                          loss='sparse_categorical_crossentropy',
                          metrics=['accuracy'])
quant_aware_model.fit(train_dataset, epochs=3, validation_data=val_dataset)

3.3. Export to TensorFlow Lite (TFLite)

converter = tf.lite.TFLiteConverter.from_keras_model(quant_aware_model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()
open("ecg_classifier.tflite", "wb").write(tflite_model)

Bước 4: Đánh giá mô hình nén trên thiết bị nhúng

Thông số Mô hình gốc Sau pruning Sau QAT (TFLite)
Kích thước (MB) 98 31 7.2
Compression Ratio (%) 0 68% 92.6%
Thời gian suy luận (ms) on Raspberry Pi 4 2300 820 210
Thời gian suy luận (ms) on STM32H7 (NPU) – (không chạy) – (không chạy) 45
Độ chính xác (%) 96.0 95.3 94.8

⚡ Công thức tính Compression Ratio
Compression Ratio = (Kích thước mô hình gốc – Kích thước mô hình nén) / Kích thước mô hình gốc × 100%

\huge Compression\_Ratio=\frac{Original\_Size-Compressed\_Size}{Original\_Size}\times 100

Giải thích: Nếu mô hình gốc 98 MB, sau QAT còn 7.2 MB → Compression Ratio ≈ 92.6 %.

Bước 5: Triển khai trên thiết bị (C/C++)

// main.c – chạy inference TFLite trên STM32H7
#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "model_data.h"   // tflite model binary

constexpr int kTensorArenaSize = 10 * 1024;
uint8_t tensor_arena[kTensorArenaSize];

int main(void) {
    tflite::AllOpsResolver resolver;
    const tflite::Model* model = tflite::GetModel(g_ecg_classifier_tflite);
    tflite::MicroInterpreter interpreter(model, resolver, tensor_arena, kTensorArenaSize);
    interpreter.AllocateTensors();

    // Input: 5000 float32 values (ECG 5s @ 1kHz)
    float* input = interpreter.input(0)->data.f;
    // ... copy pre‑processed ECG signal vào input ...

    interpreter.Invoke();

    float* output = interpreter.output(0)->data.f;
    // output[0] = normal, output[1] = arrhythmia
    if (output[1] > 0.7f) {
        // bật LED báo cảnh báo
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
    }
    while (1);
}
  • Lưu ý: kTensorArenaSize phải đủ cho bộ nhớ tạm thời; trên STM32H7 thường 10 KB là đủ cho mô hình 7 MB đã quantized.

Bước 6: Cập nhật OTA (Over‑the‑Air)

  1. Server: lưu trữ file .tflite và file manifest (phiên bản, checksum).
  2. Device: kiểm tra phiên bản hiện tại, tải xuống nếu có phiên bản mới, xác thực checksum, ghi vào flash và reset.

4. Template quy trình tham khảo

Giai đoạn Công cụ Đầu ra Kiểm tra
Thu thập & tiền xử lý Python + SciPy .npy (signal) Visual inspection, SNR ≥ 20 dB
Huấn luyện TensorFlow / PyTorch .h5 hoặc .pt Accuracy ≥ 95 %
Pruning TF‑MOT .h5 (pruned) Sparsity ≥ 70 %
QAT TF‑MOT .tflite Size ≤ 10 MB, Accuracy loss ≤ 1 %
Kiểm thử nhúng TFLite‑Micro + CMake Binary firmware Latency ≤ 50 ms, RAM ≤ 200 KB
OTA Mbed‑TLS + HTTP Firmware package Checksum OK, Rollback nếu thất bại

5. Những lỗi phổ biến & cách sửa

Lỗi Mô tả Cách khắc phục
🐛 “Segmentation fault” khi load model Kích thước mô hình vượt quá RAM của MCU. Sử dụng quantization + pruning để giảm kích thước, hoặc chuyển sang MCU có NPU (STM32H7).
⚡ Thời gian suy luận > 200 ms Model chưa được tối ưu cho phần cứng. Áp dụng post‑training quantization (int8) và operator fusion.
🛡️ Checksum không khớp khi OTA File bị hỏng trong quá trình truyền. Dùng TLS + chunked transfer + retry logic.
⚡ Độ chính xác giảm > 2 % Pruning quá mức hoặc dữ liệu tiền xử lý không đồng nhất. Giảm mức pruning (ví dụ 60 % → 70 %) và chuẩn hoá lại pipeline tiền xử lý.
🐛 Lỗi “Unsupported op” TFLite Micro không hỗ trợ một số layer. Thay layer bằng DepthwiseConv2D hoặc custom op được đăng ký.

> Best Practice: Luôn giữ phiên bản backup của mô hình gốc và kiểm tra accuracy trên bộ dữ liệu validation sau mỗi bước nén.


6. Khi muốn scale lớn thì làm sao

  1. Containerize pipeline: Docker + GitLab CI để tự động hoá quá trình training → pruning → QAT → export.
  2. Model Registry: Sử dụng MLflow để lưu trữ phiên bản mô hình, metadata (size, accuracy, hardware target).
  3. Edge Orchestration: Triển khai K3s trên các gateway (Raspberry Pi) để quản lý hàng nghìn thiết bị, thực hiện rolling update OTA.
  4. Monitoring: Thu thập inference latencyerror rate qua Prometheus + Grafana, thiết lập alert khi latency > 100 ms.
  5. Cost Optimization: Chọn chipset có NPU tích hợp (e.g., Edge‑TPU, NXP i.MX 8) để giảm chi phí điện năng và tăng throughput.

7. Chi phí thực tế

Hạng mục Đơn vị Giá (VND) Ghi chú
Raspberry Pi 4 (4 GB) 1 chiếc 1.200.000 Dùng để prototyping
STM32H7 Nucleo (128 KB Flash, 1 MB RAM) 1 chiếc 2.500.000 Thiết bị production
Edge‑TPU USB Accelerator 1 chiếc 3.800.000 Tăng tốc inference int8
Phần mềm (TensorFlow, TF‑MOT) Miễn phí Open‑source
Chi phí cloud (training GPU) 1 tháng 4.000.000 1× V100 8 GB
OTA Server (AWS Lightsail) 1 năm 1.500.000 512 MB RAM, 20 GB SSD
Tổng chi phí cho 1000 thiết bị ≈ 3.2 tỷ Bao gồm phần cứng, phần mềm, vận hành

ROI = (Tổng lợi ích – Chi phí đầu tư) / Chi phí đầu tư × 100%

\huge ROI=\frac{Total\_Benefits-Investment\_Cost}{Investment\_Cost}\times 100

Giải thích: Nếu giảm 30 % số lần nhập viện nhờ chẩn đoán sớm, ước tính lợi ích 15 tỷ VND/năm → ROI ≈ 370 %.


8. Số liệu trước – sau

Chỉ số Trước nén Sau nén (QAT) Cải thiện
Kích thước mô hình 98 MB 7.2 MB 92.6 % giảm
Thời gian suy luận (Raspberry Pi 4) 2.3 s 0.21 s ≈10× nhanh hơn
Thời gian suy luận (STM32H7) – (không chạy) 45 ms ≤50 ms đáp ứng thời gian thực
Độ chính xác 96.0 % 94.8 % -1.2 % (chấp nhận)
Năng lượng tiêu thụ (mAh) 150 mAh/giờ 45 mAh/giờ ≈70 % tiết kiệm

9. FAQ hay gặp nhất

Q1: Mô hình có cần kết nối internet để hoạt động?
A: Không. Sau khi nén và triển khai, toàn bộ inference diễn ra on‑device. Internet chỉ cần cho cập nhật OTAđồng bộ log (nếu muốn).

Q2: Có thể dùng PyTorch thay TensorFlow không?
A: Có, nhưng hiện tại TensorFlow Lite for Microcontrollers hỗ trợ tốt hơn cho MCU. Nếu dùng PyTorch, cần chuyển sang ONNX → TFLite qua công cụ onnx-tflite.

Q3: Làm sao để bảo mật dữ liệu ECG trên thiết bị?
A: Áp dụng AES‑256 GCM để mã hoá dữ liệu lưu trữ, và TLS 1.3 cho mọi giao tiếp OTA. Ngoài ra, isolated execution environment (TrustZone) trên MCU hỗ trợ bảo vệ khóa.

Q4: Khi mô hình mới được training, có cần tái‑train lại toàn bộ pipeline?
A: Không bắt buộc. Bạn có thể fine‑tune mô hình gốc trên dataset mới, sau đó chỉ chạy lại pruning → QAT → export.

Q5: Chi phí năng lượng cho một thiết bị y tế tại nhà là bao nhiêu?
A: Với mô hình QAT chạy trên STM32H7, tiêu thụ trung bình ≈ 45 mAh/giờ. Nếu dùng pin 2000 mAh, thời gian hoạt động liên tục khoảng 44 giờ – đủ cho một ngày sử dụng và sạc lại qua USB.


10. Giờ tới lượt bạn

  • Bước 1: Thu thập một bộ dữ liệu ECG mẫu (ít nhất 500 đoạn 5 s) và chuẩn hoá.
  • Bước 2: Thử huấn luyện một mô hình CNN đơn giản trên máy tính cá nhân, đo accuracy.
  • Bước 3: Áp dụng pruningquantization‑aware training theo hướng dẫn trên, xuất ra file .tflite.
  • Bước 4: Đưa file .tflite lên một board STM32H7 (hoặc Raspberry Pi 4) và chạy inference, đo thời gian.
  • Bước 5: Thiết lập một server OTA đơn giản (Node.js + Express) để thử cập nhật mô hình từ xa.

Nếu gặp bất kỳ khó khăn nào, đừng ngại thử nghiệm và ghi lại log; mỗi lỗi là một bước tiến gần hơn tới sản phẩm thực tế.


Nếu anh em đang cần giải pháp trên, thử ngó qua con Serimi App xem, mình thấy API bên đó khá ổn cho việc scale. Hoặc liên hệ mình để được trao đổi nhanh hơn nhé.

Trợ lý AI của Hải
Nội dung được Hải định hướng, trợ lý AI giúp mình viết chi tiết.
Chia sẻ tới bạn bè và gia đình