Voriacare · Edge Medical Imaging

Cardiac-CT Pipeline — Báo cáo trạng thái hệ thống

On-device cardiac-CT EAT pipeline — scaling run trên NVIDIA DGX Spark (GB10 Grace-Blackwell) · Phase 1 (EAT) · cohort 1000 ca
📅 2026-07-09 🖥 DGX Spark · GB10 Grace-Blackwell · ARM64 (aarch64) 📦 ~/works/vc-eat-edge 🔬 Dataset: ImageCAS ×1000

Pipeline phân tích cardiac CT tại chỗ theo nguyên tắc ML định vị ROI pericardium, phép tính HU deterministic ra con số (model không bao giờ regress ra số — mọi giá trị đều audit được). Đợt này scale silver-label lên 1000 ca + retrain trên DGX Spark GB10.

Image GB10/arm64
Xong
NGC 26.06 · torch nv26.06
Data 1000 ca
Xong
giải nén · 0 corrupt
Smoke 5 ca
Xong
đạt tiêu chí
Silver batch 1000
Xong
1000/1000 · 0 lỗi
Đính chính phần cứng (trung thực): đợt chạy này giả định ban đầu là x86 DGX với A100/H100, nhưng máy thực tế là NVIDIA DGX Spark — GB10 Grace-Blackwell, kiến trúc ARM64 (aarch64), GPU Blackwell compute cap 12.1 (sm_121), unified memory. Không phải x86, không phải A100/H100, cũng không phải Jetson/Tegra. Pipeline đã được điều chỉnh cho đúng nền tảng (xem mục 1) — trực tiếp verify torch chạy thật trên GB10.

1Môi trường thực thi — DGX Spark GB10

Thành phầnGiá trịGhi chú
Board / SoCNVIDIA DGX Spark — GB10 Grace-BlackwellCPU ARM Cortex-X925 + A725; unified memory
Kiến trúcaarch64 (ARM64)KHÔNG phải x86 — Docker kéo image bản linux/arm64
GPU computeBlackwell, compute cap 12.1 (sm_121)verify matmul chạy thật trên GB10
CUDA / driverCUDA 13.3 (container) · driver 580.159.03 (kernel)CUDA forward-compat mode ENABLED
Container GPUnvcr.io/nvidia/pytorch:26.06-py3voriacare-dgx:eattorch 2.13.0a0+nv26.06, CUDA=True, device "NVIDIA GB10"
Deps (image)TotalSegmentator 2.15.0 · nnunetv2 2.8.1 · SimpleITK 2.5.5 · scikit-image 0.26 · nibabel 5.4.2torch NGC giữ nguyên (không bị pip thay)
Flags container--gpus all · --ipc=host · -v $IMG_DIR:/data:ronnUNet_compile=0 (an toàn trên aarch64)

Khác Jetson: dùng NGC pytorch (không l4t-pytorch) và --gpus all (không --runtime nvidia). Tag 24.08 trong runbook gốc không hỗ trợ Blackwell GB10 → chọn 26.06 (tag mới nhất, có bản arm64, sm_121).

2Dataset — ImageCAS ×1000 Giải nén xong

Volumes
1000
0 corrupt (gzip -t)
Nguồn
split-zip
5 range · recombine
Dung lượng
~90 GB
ổ 2.7TB (còn 2.3TB)
Layout
flat
<id>.img.nii.gz

Giải nén từ 1-200 … 801-1000 (mỗi range = split-zip .z01..z04 + segment cuối) bằng recombine zip -s 0 --out rồi unzip chỉ lấy *.img.nii.gz. Kiểm tra toàn vẹn gzip 0 lỗi. IMG_DIR=/media/hientm/data_NDGD/ImageCAS/extracted/all. ImageCAS = CTA cản quang + label lòng vành (label không dùng cho EAT).

3Smoke test — 5 ca Đạt

Chạy run_eat_batch.py --limit 5 --fast để kiểm chứng end-to-end trên GB10 trước khi scale.

Cases
5/5
0 lỗi · GPU
EAT range
74–152 mL
tiêu chí 50–200
mean HU
−79…−83
≈ −80 (đúng mỡ)
Tốc độ
~24 s/ca
fast mode

4Silver batch — 1000 ca trên GB10 Xong · 1000/1000

TotalSegmentator whole-heart → ROI pericardium proxy (convex-hull per-slice + dilation EDT 3mm) → EAT deterministic. Container eat-batch chạy nền, resumable (CSV ghi tăng dần, skip ca đã xong).

Tiến độ
1000/1000
0 lỗi · xong · 7.05h
EAT median
98.0 mL
IQR 77–121 · [21–198]
mean HU
−81.0
−98…−70 (đúng mỡ)
ROI / heart
1.61×
hệ số phình proxy

Cập nhật (auto): 2026-07-09 17:341000/1000 ca, ~25.9 s/ca (tổng 7.05h). Output: out/eat_1000.csv + silver masks masks/<id>/{heart,pericardium_roi}.nii.gz (trên ổ 2.7TB). Con số cập nhật khi sinh lại báo cáo.

EAT là proxy over-inclusive. ROI ≈ 1.6× thể tích tim (hull bắc cầu qua các lõm ở mạch lớn + dilation 3mm đồng nhất). Đây là nhãn silver để bootstrap segmenter — chưa dùng lâm sàng cho tới khi validate với nhãn pericardium vàng.

5Deterministic measure (nền tảng, đã chứng minh chính xác)

Trong ROI pericardium: đếm voxel HU ∈ [−190, −30] × thể tích voxel → EAT (mL) + mean HU. Không có model regress số. Test phantom: chính xác tuyệt đối (1000 voxel × 0.25 mm³ = đúng 0.25 mL; window loại đúng biên).

vc_eat/measure.pyvc_eat/harness.pyvc_eat/postprocess.py — keep-largest-CCtests/test_measure_eat.py ✓

6nnU-Net pericardium — training Xong · early-stop @604

3d_fullres, fold 0, nnUNet_compile=0 (nnUNet dirs trên ổ 2.7TB). Dừng sớm ở epoch 604/1000 vì EMA pseudo-Dice đã plateau (12 lần cải thiện cuối chỉ bò 0.9714→0.9747, mỗi lần ~0.0001–0.0003) — chạy hết 1000 epoch không đáng cho nhãn silver. Dùng checkpoint_best (best-EMA) làm model cuối. Đang chạy validation để lấy Dice held-out thật.

Trạng thái
Early-stop
epoch 604 → validating
Config
3d_fullres
1000 epochs · fold 0
Epoch
/1000
Pseudo dice
held-out (EMA)

Cập nhật train (auto): . Nguồn: nnU-Net training_log trong results/…/fold_0/ (đọc trực tiếp từ file, không phụ thuộc stdout buffer).

7TensorRT — export & verify Xong · parity 99.98%

export_onnx.py (checkpoint_final=best-EMA) → ONNX opset-18 (external-data, 123MB) → trtexecverify_trt.py trên GB10 Blackwell. Engine per-GPU (ONNX portable, .plan gắn GPU).

Trạng thái
Xong
engine + parity ✓
Argmax parity
99.984%
min 99.963% (TRT vs torch)
Max |logit Δ|
2.2e−2
mask = cái feed EAT
Engine
~63 MB
strongly-typed
Trung thực về precision: TensorRT 11.0 (trong NGC 26.06) bỏ cờ --fp16 — mạng mặc định strongly-typed, precision lấy từ kiểu trong ONNX. Nên engine này là FP32/TF32 (không phải FP16 như tên file pericardium_fp16.plan giữ lại cho tương thích script). Trên GB10, TF32 tensor-core vẫn nhanh; parity với torch gần tuyệt đối. Muốn FP16 thật trên TRT11 cần export ONNX kiểu FP16 (ghi nhận là bước sau).

Validation — TRT model vs silver hull n=50 held-out

Chạy test_trt_vs_hull.py trên 50 ca held-out (fold_0 val, model không thấy khi train): so ROI của model TRT (đã clean keep-largest-CC) với ROI silver hull, và EAT hai bên.

Dice ROI (model↔hull)
0.959
median 0.962 · min 0.886
EAT MAE
4.74 mL
MAPE 4.5%
EAT bias
−3.4 mL
model thấp hơn hull
Pearson r
0.983
EAT_trt vs EAT_hull
Metric (n=50)Giá trịDiễn giải
Dice ROI mean / median / min0.959 / 0.962 / 0.886model tái tạo hull rất trung thực trên ca chưa thấy
EAT MAE / MAPE4.74 mL / 4.5%sai lệch EAT nhỏ (tốt hơn baseline Jetson 6.86 mL)
EAT bias−3.4 mLmodel hơi thấp hơn hull — do clean_pericardium bỏ island → ROI nhỏ lại
Pearson r0.983tương quan EAT rất cao
EAT median (trt / hull)98.4 / 104.3 mL
Tốc độ~187 s/ca3d_fullres nặng; muốn nhanh cần 3d_lowres

Chi tiết từng ca — 50 ca held-out (sắp theo EAT_trt)

Màu Dice: ≥0.95 · 0.90–0.95 · <0.90. ΔEAT = EAT_trt − EAT_hull.

#Ca (held-out)EAT_trt (mL)EAT_hull (mL)ΔEATDice ROImeanHU
128150.9753.37-2.40.9557-84.0
219951.3256.92-5.60.95-91.5
31958.9660.44-1.470.9622-77.6
42761.6263.83-2.20.9599-89.1
524068.5870.99-2.410.9628-86.1
623668.9170.95-2.040.9561-87.8
725473.977.33-3.430.9577-82.3
824675.2376.46-1.230.9622-82.5
920379.0583.59-4.530.9667-75.8
1010180.176.333.770.9532-83.9
1126682.2689.24-6.980.9693-78.3
1231382.4782.96-0.490.9692-88.6
1315782.7185.02-2.310.9632-81.7
1426183.4987.27-3.780.9546-86.1
15100084.291.47-7.270.9693-80.7
1615285.489.16-3.760.9572-82.5
1710788.4290.46-2.040.9604-78.4
1822888.6887.041.640.9673-86.9
1929990.0997.02-6.930.9592-81.4
2022091.6199.34-7.730.9608-79.5
212295.396.52-1.230.9734-76.9
2220196.74103.95-7.210.9677-74.8
2314097.7499.96-2.220.953-76.0
2413598.2497.410.830.8932-96.3
2519498.39110.13-11.740.9576-72.3
2623398.49106.19-7.710.97-76.4
27278100.77110.86-10.10.9543-81.2
28192101.83104.59-2.750.9739-77.6
29164101.98112.94-10.970.9632-78.4
30197102.19104.71-2.520.9695-80.0
31212105.21108.67-3.470.9721-73.9
32113105.84100.215.630.9282-78.4
3318110.21116.74-6.530.9618-88.3
34285111.57116.65-5.080.9696-76.8
35275116.7117.45-0.750.9616-80.3
36297117.35126.19-8.850.9606-75.7
37312117.59122.68-5.090.9617-76.3
38128120.25123.21-2.950.9611-85.2
39239122.87125.73-2.860.9665-81.6
40149127.71129.93-2.220.9665-77.5
41215129.56132.55-2.990.9725-78.3
42218132.79149.39-16.60.9593-78.4
43244134.22130.044.180.9655-78.5
44146136.18138.49-2.310.959-80.4
45267136.51144.87-8.360.9417-78.3
46293145.11129.3615.750.8862-76.9
47222147.5146.441.060.9639-87.7
481147.93152.28-4.350.9639-79.1
49277148.3154.47-6.170.9565-79.8
5025149.43152.12-2.690.9734-82.5
Hiểu đúng (trung thực): đây đo độ trung thành model ↔ nhãn silver hull — KHÔNG phải độ đúng lâm sàng. Dice 0.96 nghĩa model học lại đúng hull proxy; cleanup còn kéo EAT xuống ~3.4 mL (bỏ island giả). Cả hai vẫn thừa hưởng over-inclusion ~1.6× của hull. EAT đúng lâm sàng vẫn cần gold pericardium label. Artifacts: out/test50_trt_vs_hull.csv.

8Baseline lịch sử — Jetson AGX Orin (200 ca) (tham chiếu, KHÔNG phải kết quả run DGX này)

Bối cảnh: pipeline đã hoàn tất một vòng trên Jetson Orin với 200 ca ở đợt trước (commit gốc). Những con số dưới đây là kết quả Jetson cũ, đưa vào để so sánh — đợt DGX 1000 ca đang tái lập lại từ đầu (train/TRT ở mục 6–7 còn pending).
Hạng mục (Jetson, 200 ca)Kết quảGhi chú
Silver batch 200 ca98.2 mL median0 lỗi · 4.40h · ROI/heart 1.62×
nnU-Net 3d_fullres (250ep)Dice 0.9596held-out 40 ca · epoch ~338s
nnU-Net 3d_lowres (100ep)Dice 0.9716inference ~32s/ca · ~3× nhanh
TensorRT FP16 parityDice 0.9997ΔEAT < 0.11 mL · argmax 99.996%
Hiểu đúng: Dice cao nghĩa là model học lại hull proxykhông sửa over-inclusion (sai lệch nằm trong silver label). Giá trị: thay chuỗi TotalSegmentator+hull+EDT bằng 1 forward pass exportable. EAT đúng lâm sàng vẫn cần gold pericardium label.

9Gotcha đã xử lý ở đợt DGX

Vấn đềTriệu chứng / nguyên nhânFix
Nhầm nền tảnggiả định x86 A100/H100 → thực tế GB10 ARM64 Blackwellverify uname -m+torch.cuda, điều chỉnh toàn bộ lệnh
NGC tag quá cũpytorch:24.08 ra trước Blackwell → không có kernel sm_121dùng tag mới 26.06-py3 (bản arm64)
Split-zip không unzip thẳngfile vắt qua ranh giới part 4.3GB → member không đọc đượcrecombine zip -s 0 --out trước rồi unzip
Docker /dev/shmmặc định 64MB → nnUNet dataloader "No space left"--ipc=host
Triton (aarch64)torch.compile có thể crash trên ARMnnUNet_compile=0
ngrok kiến trúcrunbook ghi "linux amd64" nhưng máy là ARM64cài ngrok linux arm64
Đĩa / hạn chế/ chỉ 173GB — không đủ cho 1000 ca + nnUNetdata + masks + nnUNet → ổ 2.7TB (bind-mount)

10Dòng thời gian (đợt DGX)

11Cổng report

Đang phục vụ

https://research.bvndgd.ngrok.io vc-report :80 (docker) ngrok arm64 report/ bind-mount live

Trang: index/status (trang này) · pipeline · gallery · algorithms · models (so sánh kiến trúc). Gallery hiện dùng figures của model trước; figures 2D+3D từ model DGX sẽ sinh lại sau TRT.

12Giới hạn & bước tiếp

Giới hạn trung thực

  • EAT hiện là proxy over-inclusive (ROI/heart ~1.6×) — chưa validate lâm sàng.
  • Batch 1000 đang chạy; train/TRT trên DGX chưa chạy (mục 6–7 pending).
  • Con số Dice/TRT ở mục 8 là baseline Jetson cũ, không phải run DGX này.
  • Chưa có ground-truth EAT thật để đo độ đúng.

Ưu tiên tiếp

  • Hoàn tất batch 1000 → tự launch train 3d_fullres → theo dõi Dice held-out.
  • Export TRT FP16 cho GB10 → verify parity → run_eat_trt.py.
  • Sinh lại figures 2D+3D (VC_STEP=4 VC_CLEAN=1) từ model mới → refresh gallery.
  • Chất lượng: gold pericardium label để refine + validate — đòn bẩy chính.