Upload NeuroScan AI code
Browse files- BENCHMARK.md +160 -0
- README.md +117 -6
- data/README.md +66 -0
- scripts/benchmark.py +618 -0
- scripts/stress_test.py +428 -0
BENCHMARK.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# NeuroScan AI ๆง่ฝๅบๅๆต่ฏ
|
| 2 |
+
|
| 3 |
+
## ๐ฌ ๆง่ฝๅบๅๆต่ฏๆฅๅ
|
| 4 |
+
|
| 5 |
+
> ๆต่ฏๆถ้ด: 2026-01-28 17:16:29
|
| 6 |
+
|
| 7 |
+
### ๆต่ฏ็ฏๅข
|
| 8 |
+
|
| 9 |
+
| ็ปไปถ | ้
็ฝฎ |
|
| 10 |
+
|------|------|
|
| 11 |
+
| **CPU** | Intel(R) Xeon(R) Platinum 8350C CPU @ 2.60GHz |
|
| 12 |
+
| **CPUๆ ธๅฟ** | 64 ็ฉ็ๆ ธ / 128 ้ป่พๆ ธ |
|
| 13 |
+
| **ๅ
ๅญ** | 2014 GB |
|
| 14 |
+
| **GPU** | NVIDIA A800-SXM4-80GB |
|
| 15 |
+
| **GPUๆพๅญ** | 80 GB |
|
| 16 |
+
| **Python** | 3.11.11 |
|
| 17 |
+
| **PyTorch** | 2.8.0+cu129 |
|
| 18 |
+
| **CUDA** | 12.9 |
|
| 19 |
+
| **MONAI** | 1.5.2 |
|
| 20 |
+
| **SimpleITK** | 2.4.1 |
|
| 21 |
+
|
| 22 |
+
### ๆต่ฏๆฐๆฎ
|
| 23 |
+
|
| 24 |
+
| ๅฑๆง | ๅผ |
|
| 25 |
+
|------|------|
|
| 26 |
+
| **ๆฐๆฎ้** | Learn2Reg Lung CT |
|
| 27 |
+
| **ๆ ทๆฌๆฐ้** | 20 ๅฏน (ๅธๆฐ/ๅผๆฐ้
ๅฏน) |
|
| 28 |
+
| **่พๅ
ฅๅฐบๅฏธ** | 192 ร 192 ร 208 ไฝ็ด |
|
| 29 |
+
| **ไฝ็ด ้ด่ท** | 1.0 ร 1.0 ร 1.0 mm |
|
| 30 |
+
| **ๆฐๆฎ็ฑปๅ** | float32 |
|
| 31 |
+
| **ๅๅทๅคงๅฐ** | 58.5 MB |
|
| 32 |
+
| **ๅๅทไฝ็ด ๆฐ** | 7,667,712 |
|
| 33 |
+
|
| 34 |
+
---
|
| 35 |
+
|
| 36 |
+
## CPU ๅนถๅๅบๅๆต่ฏ
|
| 37 |
+
|
| 38 |
+
### ๆต่ฏไปปๅก: ้
ๅ + ๅๅๆฃๆตๆต็จ
|
| 39 |
+
|
| 40 |
+
1. **ๆฐๆฎๅ ่ฝฝ**: NIfTI ๆ ผๅผๅ ่ฝฝ
|
| 41 |
+
2. **ๅๆง้
ๅ**: 6DOF ไปฟๅฐๅๆข (SimpleITK)
|
| 42 |
+
3. **้ๅๆง้
ๅ**: B-spline ๅฝขๅๅบ (SimpleITK)
|
| 43 |
+
4. **ๅๅๆฃๆต**: ไฝ็ด ็บงๅทฎๅผ่ฎก็ฎ
|
| 44 |
+
|
| 45 |
+
### ๆต่ฏ็ปๆ
|
| 46 |
+
|
| 47 |
+
| ๅนถๅๆฐ | ๆป่ๆถ | ๅๅ้ | CPUๅณฐๅผ | CPUๅๅผ | ๅ
ๅญๅณฐๅผ | ๅ
ๅญๅข้ | ๅนถ่กๆ็ |
|
| 48 |
+
|--------|--------|--------|---------|---------|----------|----------|----------|
|
| 49 |
+
| 1 | 7.38s | 8.1/min | 10.3% | 1.9% | 39.1 GB | +1.0 GB | 100% |
|
| 50 |
+
| 2 | 7.68s | 15.6/min | 38.8% | 5.4% | 40.0 GB | +2.0 GB | 192% |
|
| 51 |
+
| 3 | 8.44s | 21.3/min | 39.2% | 7.4% | 40.8 GB | +3.0 GB | 262% |
|
| 52 |
+
| 4 | 9.07s | 26.5/min | 42.6% | 9.5% | 41.8 GB | +4.0 GB | 325% |
|
| 53 |
+
| 5 | 9.60s | 31.2/min | 42.0% | 11.3% | 42.5 GB | +5.0 GB | 384% |
|
| 54 |
+
|
| 55 |
+
### ๅไปปๅก่ๆถๅ่งฃ
|
| 56 |
+
|
| 57 |
+
| ้ถๆฎต | ่ๆถ | ๅ ๆฏ | ่ฏดๆ |
|
| 58 |
+
|------|------|------|------|
|
| 59 |
+
| ๆฐๆฎๅ ่ฝฝ | 0.08s | 1% | NIfTI ่ฏปๅ + ้ขๅค็ |
|
| 60 |
+
| ๅๆง้
ๅ | 1.10s | 15% | 6DOF ไปฟๅฐๅๆขไผๅ |
|
| 61 |
+
| ้ๅๆง้
ๅ | 6.20s | 84% | B-spline ๅฝขๅๅบไผๅ |
|
| 62 |
+
| ๅๅๆฃๆต | 0.02s | <1% | NumPy ๅทฎๅผ่ฎก็ฎ |
|
| 63 |
+
| **ๆป่ฎก** | **7.40s** | **100%** | - |
|
| 64 |
+
|
| 65 |
+
### CPU ๅฉ็จ็ๅๆ
|
| 66 |
+
|
| 67 |
+
```
|
| 68 |
+
ๅนถๅๆฐ: 1 โโโโโโโโโโโโโโโโโโโโ 10.3%
|
| 69 |
+
ๅนถๅๆฐ: 2 โโโโโโโโโโโโโโโโโโโโ 38.8%
|
| 70 |
+
ๅนถๅๆฐ: 3 โโโโโโโโโโโโโโโโโโโโ 39.2%
|
| 71 |
+
ๅนถๅๆฐ: 4 โโโโโโโโโโโโโโโโโโโโ 42.6%
|
| 72 |
+
ๅนถๅๆฐ: 5 โโโโโโโโโโโโโโโโโโโโ 42.0%
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
> ๐ **็ป่ฎบ**: CPU ๅฉ็จ็ๅจ 5 ๅนถๅๆถไป
่พพๅฐ 42%๏ผ่ฏดๆ่ฟๆๅพๅคง็ๅนถๅๆฉๅฑ็ฉบ้ดใ
|
| 76 |
+
|
| 77 |
+
---
|
| 78 |
+
|
| 79 |
+
## GPU ๅนถๅๅบๅๆต่ฏ
|
| 80 |
+
|
| 81 |
+
### ๆต่ฏไปปๅก: MONAI ๅจๅฎๅๅฒ
|
| 82 |
+
|
| 83 |
+
- **ๆจกๅ**: TotalSegmentator (104 ็ฑปๅจๅฎ)
|
| 84 |
+
- **ๆจ็ๆนๅผ**: Sliding Window (ๆปๅจ็ชๅฃ)
|
| 85 |
+
- **็ชๅฃๅคงๅฐ**: 96 ร 96 ร 96
|
| 86 |
+
- **้ๅ ็**: 50%
|
| 87 |
+
|
| 88 |
+
### ๆต่ฏ็ปๆ
|
| 89 |
+
|
| 90 |
+
| ๅนถๅๆฐ | ๆป่ๆถ | GPUๆพๅญๅณฐๅผ | GPUๅฉ็จ็ๅณฐๅผ | CPUๅณฐๅผ | ๅ
ๅญๅณฐๅผ |
|
| 91 |
+
|--------|--------|-------------|---------------|---------|----------|
|
| 92 |
+
| 1 | 8.19s | **9.0 GB** | 100% | 37.5% | 42.1 GB |
|
| 93 |
+
| 2 | 8.50s | **15.0 GB** | 100% | 5.8% | 43.2 GB |
|
| 94 |
+
|
| 95 |
+
### ๅไปปๅก่ๆถๅ่งฃ
|
| 96 |
+
|
| 97 |
+
| ้ถๆฎต | ่ๆถ | ๅ ๆฏ | ่ฏดๆ |
|
| 98 |
+
|------|------|------|------|
|
| 99 |
+
| ๆฐๆฎๅ ่ฝฝ | 0.11s | 1% | NIfTI โ Tensor |
|
| 100 |
+
| ๆจกๅๆจ็ | 8.08s | 99% | Sliding Window |
|
| 101 |
+
| **ๆป่ฎก** | **8.19s** | **100%** | - |
|
| 102 |
+
| **GPUๆพๅญ** | **7.32 GB** | - | PyTorch allocated |
|
| 103 |
+
| **GPUๆพๅญ (็ณป็ป)** | **9.0 GB** | - | nvidia-smi ๆฅๅ |
|
| 104 |
+
|
| 105 |
+
### GPU ๆพๅญๅๆ
|
| 106 |
+
|
| 107 |
+
```
|
| 108 |
+
ๅไปปๅก: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 9.0 GB / 80 GB (11%)
|
| 109 |
+
ๅไปปๅก: โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 15.0 GB / 80 GB (19%)
|
| 110 |
+
```
|
| 111 |
+
|
| 112 |
+
> ๐ **็ป่ฎบ**: ๅไปปๅกๅๅฒ้่ฆ็บฆ **9 GB** GPUๆพๅญ๏ผๅไปปๅก้่ฆ็บฆ **15 GB**ใRTX 3060 (12GB) ๅฏ่ฟ่กๅไปปๅก๏ผRTX 4090 (24GB) ๅฏ่ฟ่ก 2 ๅนถๅใ
|
| 113 |
+
|
| 114 |
+
---
|
| 115 |
+
|
| 116 |
+
## ่ตๆบ้ๆฑๆป็ป
|
| 117 |
+
|
| 118 |
+
### ๆๅฐ้
็ฝฎไผฐ็ฎ
|
| 119 |
+
|
| 120 |
+
ๅบไบๆต่ฏๆฐๆฎ๏ผๅๅบๆฏ็ๆๅฐ่ตๆบ้ๆฑ๏ผ
|
| 121 |
+
|
| 122 |
+
| ๅบๆฏ | CPU | ๅ
ๅญ | GPUๆพๅญ | ๅคๆณจ |
|
| 123 |
+
|------|-----|------|---------|------|
|
| 124 |
+
| ไป
้
ๅ (ๅไปปๅก) | 2 ๆ ธ | 2 GB | ๆ ้ | CPUๅฏ้ๅ |
|
| 125 |
+
| ไป
้
ๅ (5ๅนถๅ) | 8 ๆ ธ | 6 GB | ๆ ้ | ็บฟๆงๆฉๅฑ |
|
| 126 |
+
| ๅๅฒ (ๅไปปๅก) | 4 ๆ ธ | 4 GB | **9 GB** | GPUๅฏ้ๅ |
|
| 127 |
+
| ๅๅฒ (ๅไปปๅก) | 4 ๆ ธ | 6 GB | **15 GB** | ๆพๅญ็ถ้ข |
|
| 128 |
+
| ๅฎๆดๆต็จ | 8 ๆ ธ | 8 GB | **12 GB** | ้
ๅ+ๅๅฒ+LLM |
|
| 129 |
+
|
| 130 |
+
### ๆจ่้
็ฝฎๆนๆก
|
| 131 |
+
|
| 132 |
+
| ้จ็ฝฒๅบๆฏ | CPU | ๅ
ๅญ | GPU | ้ขไผฐๅนถๅ่ฝๅ | ๅ่ๆ่ดน |
|
| 133 |
+
|----------|-----|------|-----|--------------|----------|
|
| 134 |
+
| **ๆไฝ้
็ฝฎ** | 4ๆ ธ | 8 GB | ๆ | 1 ไปปๅก (ไป
้
ๅ) | ~ยฅ100 |
|
| 135 |
+
| **ๆจ่้
็ฝฎ** | 8ๆ ธ | 16 GB | RTX 3060 12GB | 2-3 ไปปๅก | ~ยฅ800 |
|
| 136 |
+
| **ไธไธ้
็ฝฎ** | 16ๆ ธ | 32 GB | RTX 4090 24GB | 5+ ไปปๅก | ~ยฅ2000 |
|
| 137 |
+
| **ๆๅกๅจ้
็ฝฎ** | 32ๆ ธ+ | 64 GB+ | A100 40GB+ | 10+ ไปปๅก | ~ยฅ8000 |
|
| 138 |
+
|
| 139 |
+
---
|
| 140 |
+
|
| 141 |
+
## ่ฟ่กๅบๅๆต่ฏ
|
| 142 |
+
|
| 143 |
+
```bash
|
| 144 |
+
# ่ฟ่กๅฎๆดๅบๅๆต่ฏ
|
| 145 |
+
python scripts/benchmark.py
|
| 146 |
+
|
| 147 |
+
# ่ฟ๏ฟฝ๏ฟฝ๏ฟฝๅฟซ้ๅๅๆต่ฏ
|
| 148 |
+
python scripts/stress_test.py
|
| 149 |
+
```
|
| 150 |
+
|
| 151 |
+
---
|
| 152 |
+
|
| 153 |
+
## ้ๅฝ: ๆต่ฏ่ๆฌ
|
| 154 |
+
|
| 155 |
+
- `scripts/benchmark.py` - ๅฎๆดๅบๅๆต่ฏ๏ผ็ๆ่ฏฆ็ปๆฅๅ
|
| 156 |
+
- `scripts/stress_test.py` - ๅฟซ้ๅๅๆต่ฏ๏ผๆพ็คบ่ตๆบๅณฐๅผ
|
| 157 |
+
|
| 158 |
+
---
|
| 159 |
+
|
| 160 |
+
*ๆฅๅ็ๆๆถ้ด: 2026-01-28 17:16:29*
|
README.md
CHANGED
|
@@ -72,17 +72,128 @@
|
|
| 72 |
|
| 73 |
---
|
| 74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
## ๐ ๅฟซ้ๅผๅง
|
| 76 |
|
| 77 |
-
###
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
| ็ปไปถ | ๆไฝ้
็ฝฎ | ๆจ่้
็ฝฎ |
|
| 80 |
|------|----------|----------|
|
| 81 |
-
| OS | Ubuntu 20.04+ / Windows 10 | Ubuntu 22.04 |
|
| 82 |
-
|
|
| 83 |
-
|
|
| 84 |
-
|
|
| 85 |
-
| ๅญๅจ | 50 GB | 200 GB SSD |
|
| 86 |
|
| 87 |
### ๅฎ่ฃ
ๆญฅ้ชค
|
| 88 |
|
|
|
|
| 72 |
|
| 73 |
---
|
| 74 |
|
| 75 |
+
## ๐ฅ Hugging Face ไธ่ฝฝ
|
| 76 |
+
|
| 77 |
+
้กน็ฎๅทฒไธไผ ๅฐ Hugging Face Hub๏ผๅฏไธ้ฎไธ่ฝฝ้จ็ฝฒ๏ผ
|
| 78 |
+
|
| 79 |
+
```bash
|
| 80 |
+
# ๅฎ่ฃ
huggingface_hub
|
| 81 |
+
pip install huggingface_hub
|
| 82 |
+
|
| 83 |
+
# ไธ่ฝฝๅฎๆดไปฃ็
|
| 84 |
+
from huggingface_hub import snapshot_download
|
| 85 |
+
snapshot_download(repo_id="cyd0806/neuroscan-ai", local_dir="./NeuroScan")
|
| 86 |
+
|
| 87 |
+
# ไธ่ฝฝๆจกๅๆ้
|
| 88 |
+
snapshot_download(repo_id="cyd0806/neuroscan-ai-models", local_dir="./models")
|
| 89 |
+
|
| 90 |
+
# ไธ่ฝฝๆฐๆฎ้
|
| 91 |
+
snapshot_download(repo_id="cyd0806/neuroscan-ai-dataset", repo_type="dataset", local_dir="./data")
|
| 92 |
+
```
|
| 93 |
+
|
| 94 |
+
| ไปๅบ | ๅ
ๅฎน | ้พๆฅ |
|
| 95 |
+
|------|------|------|
|
| 96 |
+
| ๐ฆ ไปฃ็ | ๅฎๆด้กน็ฎไปฃ็ | [cyd0806/neuroscan-ai](https://huggingface.co/cyd0806/neuroscan-ai) |
|
| 97 |
+
| ๐ง ๆจกๅ | MONAI ๅๅฒๆจกๅ | [cyd0806/neuroscan-ai-models](https://huggingface.co/cyd0806/neuroscan-ai-models) |
|
| 98 |
+
| ๐ ๆฐๆฎ | Learn2Reg ๆฐๆฎ้ | [cyd0806/neuroscan-ai-dataset](https://huggingface.co/datasets/cyd0806/neuroscan-ai-dataset) |
|
| 99 |
+
|
| 100 |
+
---
|
| 101 |
+
|
| 102 |
## ๐ ๅฟซ้ๅผๅง
|
| 103 |
|
| 104 |
+
### ็กฌไปถ้ๆฑ
|
| 105 |
+
|
| 106 |
+
NeuroScan AI ๆฏๆๅค็ง้จ็ฝฒๅบๆฏ๏ผไปฅไธๆฏไธๅไฝฟ็จๆจกๅผ็็กฌไปถ้ๆฑ๏ผ
|
| 107 |
+
|
| 108 |
+
#### ๐ ๅฎๆต่ตๆบๆถ่ (้ซๅนถๅๅๅๆต่ฏ็ปๆ)
|
| 109 |
+
|
| 110 |
+
> ่ฏฆ็ปๆต่ฏๆฅๅ่ง [BENCHMARK.md](BENCHMARK.md)
|
| 111 |
+
|
| 112 |
+
**ๆต่ฏ็ฏๅข:**
|
| 113 |
+
- CPU: Intel Xeon Platinum 8350C (64ๆ ธ/128็บฟ็จ)
|
| 114 |
+
- ๅ
ๅญ: 2TB DDR4
|
| 115 |
+
- GPU: NVIDIA A800-SXM4-80GB
|
| 116 |
+
- ๆต่ฏๆฐๆฎ: Learn2Reg Lung CT, ่พๅ
ฅๅฐบๅฏธ **192ร192ร208**, ๅๅท **58.5 MB**
|
| 117 |
+
|
| 118 |
+
**CPU ๅนถๅๆต่ฏ (้
ๅ+ๅๅๆฃๆต):**
|
| 119 |
+
|
| 120 |
+
| ๅนถๅๆฐ | ๆป่ๆถ | ๅๅ้ | CPUๅณฐๅผ | CPUๅๅผ | ๅ
ๅญๅข้ | ๅนถ่กๆ็ |
|
| 121 |
+
|--------|--------|--------|---------|---------|----------|----------|
|
| 122 |
+
| 1 | 7.4s | 8.1/min | **10.3%** | 1.9% | +1.0 GB | 100% |
|
| 123 |
+
| 2 | 7.7s | 15.6/min | **38.8%** | 5.4% | +2.0 GB | 192% |
|
| 124 |
+
| 3 | 8.4s | 21.3/min | **39.2%** | 7.4% | +3.0 GB | 262% |
|
| 125 |
+
| 4 | 9.1s | 26.5/min | **42.6%** | 9.5% | +4.0 GB | 325% |
|
| 126 |
+
| 5 | 9.6s | 31.2/min | **42.0%** | 11.3% | +5.0 GB | 384% |
|
| 127 |
+
|
| 128 |
+
**GPU ๅนถๅๆต่ฏ (MONAIๅจๅฎๅๅฒ):**
|
| 129 |
+
|
| 130 |
+
| ๅนถๅๆฐ | ๆป่ๆถ | GPUๆพๅญๅณฐๅผ | GPUๅฉ็จ็ | CPUๅณฐๅผ |
|
| 131 |
+
|--------|--------|-------------|-----------|---------|
|
| 132 |
+
| 1 | 8.2s | **9.0 GB** | 100% | 37.5% |
|
| 133 |
+
| 2 | 8.5s | **15.0 GB** | 100% | 5.8% |
|
| 134 |
+
|
| 135 |
+
**ๅไปปๅก่ๆถๅ่งฃ:**
|
| 136 |
+
|
| 137 |
+
| ้ถๆฎต | CPU้
ๅๆต็จ | GPUๅๅฒๆต็จ |
|
| 138 |
+
|------|-------------|-------------|
|
| 139 |
+
| ๆฐๆฎๅ ่ฝฝ | 0.1s (1%) | 0.1s (1%) |
|
| 140 |
+
| ๅๆง้
ๅ | 1.1s (15%) | - |
|
| 141 |
+
| ้ๅๆง้
ๅ | 6.2s (84%) | - |
|
| 142 |
+
| ๆจกๅๆจ็ | - | 8.1s (99%) |
|
| 143 |
+
| **ๆป่ฎก** | **7.4s** | **8.2s** |
|
| 144 |
+
|
| 145 |
+
#### ๐ ไฝฟ็จๅบๆฏๅฏน็
ง่กจ
|
| 146 |
+
|
| 147 |
+
| ๅ่ฝๆจกๅ | CPU | ๅ
ๅญ | GPU ๆพๅญ | ่ฏดๆ |
|
| 148 |
+
|----------|-----|------|----------|------|
|
| 149 |
+
| ๐ ๆฐๆฎๅ ่ฝฝ (DICOM/NIfTI) | 2 ๆ ธ | 2 GB | ๆ ้ | ๅบ็กๅ่ฝ |
|
| 150 |
+
| ๐ ๅพๅ้
ๅ (ๅๆง+้ๅๆง) | 4 ๆ ธ | 4 GB | ๆ ้ | SimpleITK CPU ่ฎก็ฎ |
|
| 151 |
+
| ๐ ๅๅๆฃๆต | 2 ๆ ธ | 2 GB | ๆ ้ | NumPy ่ฎก็ฎ |
|
| 152 |
+
| ๐ง ๅจๅฎๅๅฒ (MONAI) | 4 ๆ ธ | 8 GB | **9-12 GB** | ๆทฑๅบฆๅญฆไน ๆจ็ |
|
| 153 |
+
| ๐ฌ LLM ๆฅๅ (7Bๆจกๅ) | 4 ๆ ธ | 8 GB | **4-6 GB** | Ollama ๆจ็ |
|
| 154 |
+
| ๐ฌ LLM ๆฅๅ (3Bๆจกๅ) | 2 ๆ ธ | 4 GB | **2-4 GB** | ่ฝป้็บงๆจกๅ |
|
| 155 |
+
|
| 156 |
+
#### ๐ฅ๏ธ ๆจ่้
็ฝฎๆนๆก
|
| 157 |
+
|
| 158 |
+
| ๆนๆก | CPU | ๅ
ๅญ | GPU | ๅญๅจ | ้็จๅบๆฏ |
|
| 159 |
+
|------|-----|------|-----|------|----------|
|
| 160 |
+
| **๐ก ๅ
ฅ้จ็** | 4 ๆ ธ | 8 GB | ๆ | 20 GB | ไป
้
ๅ+ๅๅๆฃๆต๏ผๆ AI ๅ่ฝ |
|
| 161 |
+
| **โก ๆ ๅ็** | 8 ๆ ธ | 16 GB | RTX 3060 (12GB) | 50 GB | ๅฎๆดๅ่ฝ๏ผไฝฟ็จ 3B LLM |
|
| 162 |
+
| **๐ ไธไธ็** | 16 ๆ ธ | 32 GB | RTX 4090 (24GB) | 100 GB | ้ซๆง่ฝ๏ผๅๅฒ+8B LLM |
|
| 163 |
+
| **๐ข ไผไธ็** | 32 ๆ ธ+ | 64 GB+ | A100 (40GB+) | 500 GB+ | ๆน้ๅค็๏ผๅค็จๆท |
|
| 164 |
+
|
| 165 |
+
#### ๐ฐ ไบๆๅกๅจ็ง็จๅปบ่ฎฎ
|
| 166 |
+
|
| 167 |
+
| ไบๆๅกๅ | ๆจ่ๆบๅ | ้
็ฝฎ | ๆ่ดน็จไผฐ็ฎ |
|
| 168 |
+
|----------|----------|------|------------|
|
| 169 |
+
| AWS | g4dn.xlarge | 4C16G + T4 16GB | ~$380/ๆ |
|
| 170 |
+
| ้ฟ้ไบ | ecs.gn6i-c4g1.xlarge | 4C15G + T4 16GB | ~ยฅ2500/ๆ |
|
| 171 |
+
| AutoDL | RTX 3090 | 4C24G + RTX 3090 24GB | ~ยฅ2.5/ๆถ |
|
| 172 |
+
| **ๆจ่ๅ
ฅ้จ** | AutoDL RTX 3060 | 4C16G + RTX 3060 12GB | **~ยฅ1.2/ๆถ** |
|
| 173 |
+
|
| 174 |
+
> ๐ก **็้ฑๅปบ่ฎฎ**: ๅผๅๆต่ฏ้ถๆฎตๆจ่ไฝฟ็จ AutoDL ็ญๆๆถ่ฎก่ดนๅนณๅฐ๏ผๆญฃๅผ้จ็ฝฒๅ่่ๅ
ๆใ
|
| 175 |
+
|
| 176 |
+
#### ๐ฆ ็ฃ็็ฉบ้ด้ๆฑ
|
| 177 |
+
|
| 178 |
+
| ็ปไปถ | ๅคงๅฐ | ่ฏดๆ |
|
| 179 |
+
|------|------|------|
|
| 180 |
+
| ไปฃ็ ไปๅบ | ~500 KB | Git clone |
|
| 181 |
+
| Python ไพ่ต | ~5 GB | pip install |
|
| 182 |
+
| MONAI ๅๅฒๆจกๅ | ~12 GB | ่ชๅจไธ่ฝฝ |
|
| 183 |
+
| Ollama LLM (7B) | ~5 GB | ollama pull |
|
| 184 |
+
| ็คบไพๆฐๆฎ้ | ~300 MB | Learn2Reg |
|
| 185 |
+
| **ๆป่ฎก** | **~25 GB** | ๆๅฐๅฎ่ฃ
|
|
| 186 |
+
|
| 187 |
+
---
|
| 188 |
+
|
| 189 |
+
### ็ณป็ป่ฆๆฑ
|
| 190 |
|
| 191 |
| ็ปไปถ | ๆไฝ้
็ฝฎ | ๆจ่้
็ฝฎ |
|
| 192 |
|------|----------|----------|
|
| 193 |
+
| OS | Ubuntu 20.04+ / Windows 10 | Ubuntu 22.04 LTS |
|
| 194 |
+
| Python | 3.9+ | 3.11 |
|
| 195 |
+
| CUDA | 11.8+ (ๅฆไฝฟ็จGPU) | 12.0+ |
|
| 196 |
+
| Docker | 20.10+ (ๅฏ้) | 24.0+ |
|
|
|
|
| 197 |
|
| 198 |
### ๅฎ่ฃ
ๆญฅ้ชค
|
| 199 |
|
data/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: cc-by-nc-4.0
|
| 3 |
+
task_categories:
|
| 4 |
+
- image-segmentation
|
| 5 |
+
tags:
|
| 6 |
+
- medical-imaging
|
| 7 |
+
- ct-scan
|
| 8 |
+
- lung
|
| 9 |
+
- registration
|
| 10 |
+
size_categories:
|
| 11 |
+
- 1K<n<10K
|
| 12 |
+
---
|
| 13 |
+
|
| 14 |
+
# NeuroScan AI - Medical Imaging Dataset
|
| 15 |
+
|
| 16 |
+
This dataset contains sample medical imaging data for the NeuroScan AI platform.
|
| 17 |
+
|
| 18 |
+
## Dataset Description
|
| 19 |
+
|
| 20 |
+
### Learn2Reg Lung CT
|
| 21 |
+
- **Source**: [Learn2Reg Challenge](https://zenodo.org/record/3835682)
|
| 22 |
+
- **Description**: Paired inspiration and expiration lung CT scans
|
| 23 |
+
- **Format**: NIfTI (.nii.gz)
|
| 24 |
+
- **Cases**: 20 pairs
|
| 25 |
+
- **License**: CC BY-NC 4.0
|
| 26 |
+
|
| 27 |
+
## Usage
|
| 28 |
+
|
| 29 |
+
```python
|
| 30 |
+
# Download using huggingface_hub
|
| 31 |
+
from huggingface_hub import snapshot_download
|
| 32 |
+
|
| 33 |
+
snapshot_download(
|
| 34 |
+
repo_id="ydchen0806/neuroscan-ai-dataset",
|
| 35 |
+
repo_type="dataset",
|
| 36 |
+
local_dir="./data"
|
| 37 |
+
)
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
## Data Structure
|
| 41 |
+
|
| 42 |
+
```
|
| 43 |
+
data/
|
| 44 |
+
โโโ raw/
|
| 45 |
+
โ โโโ training/
|
| 46 |
+
โ โ โโโ scans/
|
| 47 |
+
โ โ โ โโโ case_001_insp.nii.gz
|
| 48 |
+
โ โ โ โโโ case_001_exp.nii.gz
|
| 49 |
+
โ โ โ โโโ ...
|
| 50 |
+
โ โ โโโ lungMasks/
|
| 51 |
+
โ โ โโโ ...
|
| 52 |
+
โ โโโ Learn2Reg_training.zip
|
| 53 |
+
โโโ processed/
|
| 54 |
+
โโโ real_lung_001/
|
| 55 |
+
โโโ baseline.nii.gz
|
| 56 |
+
โโโ followup.nii.gz
|
| 57 |
+
โโโ ...
|
| 58 |
+
```
|
| 59 |
+
|
| 60 |
+
## License
|
| 61 |
+
|
| 62 |
+
CC BY-NC 4.0 (Non-commercial use only)
|
| 63 |
+
|
| 64 |
+
## Citation
|
| 65 |
+
|
| 66 |
+
Please cite the original Learn2Reg challenge if you use this data.
|
scripts/benchmark.py
ADDED
|
@@ -0,0 +1,618 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
NeuroScan AI ๅฎๆดๅบๅๆต่ฏ
|
| 4 |
+
ๆต่ฏ CPU/GPU ้ซๅนถๅๆง่ฝ๏ผ็ๆ่ฏฆ็ปๆฅๅ
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import os
|
| 8 |
+
import sys
|
| 9 |
+
import time
|
| 10 |
+
import json
|
| 11 |
+
import threading
|
| 12 |
+
import subprocess
|
| 13 |
+
from datetime import datetime
|
| 14 |
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
| 15 |
+
from pathlib import Path
|
| 16 |
+
import psutil
|
| 17 |
+
import numpy as np
|
| 18 |
+
|
| 19 |
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
| 20 |
+
|
| 21 |
+
# ========================================
|
| 22 |
+
# ๅ
จๅฑ็ๆง
|
| 23 |
+
# ========================================
|
| 24 |
+
monitor_data = {
|
| 25 |
+
"cpu_percent": [],
|
| 26 |
+
"cpu_per_core": [],
|
| 27 |
+
"memory_used_gb": [],
|
| 28 |
+
"memory_percent": [],
|
| 29 |
+
"gpu_memory_gb": [],
|
| 30 |
+
"gpu_util": [],
|
| 31 |
+
"timestamps": []
|
| 32 |
+
}
|
| 33 |
+
stop_monitor = False
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def get_gpu_stats():
|
| 37 |
+
"""่ทๅGPU็ป่ฎก"""
|
| 38 |
+
try:
|
| 39 |
+
result = subprocess.run(
|
| 40 |
+
['nvidia-smi', '--query-gpu=memory.used,memory.total,utilization.gpu',
|
| 41 |
+
'--format=csv,noheader,nounits', '-i', '0'],
|
| 42 |
+
capture_output=True, text=True, timeout=5
|
| 43 |
+
)
|
| 44 |
+
if result.returncode == 0:
|
| 45 |
+
parts = result.stdout.strip().split(',')
|
| 46 |
+
mem_used = float(parts[0].strip()) / 1024 # MB -> GB
|
| 47 |
+
mem_total = float(parts[1].strip()) / 1024
|
| 48 |
+
gpu_util = float(parts[2].strip())
|
| 49 |
+
return mem_used, mem_total, gpu_util
|
| 50 |
+
except:
|
| 51 |
+
pass
|
| 52 |
+
return 0, 0, 0
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def resource_monitor(interval=0.3):
|
| 56 |
+
"""่ตๆบ็ๆง็บฟ็จ"""
|
| 57 |
+
global stop_monitor, monitor_data
|
| 58 |
+
|
| 59 |
+
while not stop_monitor:
|
| 60 |
+
ts = time.time()
|
| 61 |
+
|
| 62 |
+
# CPU
|
| 63 |
+
cpu_total = psutil.cpu_percent(interval=None)
|
| 64 |
+
cpu_per_core = psutil.cpu_percent(interval=None, percpu=True)
|
| 65 |
+
|
| 66 |
+
# ๅ
ๅญ
|
| 67 |
+
mem = psutil.virtual_memory()
|
| 68 |
+
|
| 69 |
+
# GPU
|
| 70 |
+
gpu_mem, gpu_total, gpu_util = get_gpu_stats()
|
| 71 |
+
|
| 72 |
+
monitor_data["timestamps"].append(ts)
|
| 73 |
+
monitor_data["cpu_percent"].append(cpu_total)
|
| 74 |
+
monitor_data["cpu_per_core"].append(cpu_per_core)
|
| 75 |
+
monitor_data["memory_used_gb"].append(mem.used / (1024**3))
|
| 76 |
+
monitor_data["memory_percent"].append(mem.percent)
|
| 77 |
+
monitor_data["gpu_memory_gb"].append(gpu_mem)
|
| 78 |
+
monitor_data["gpu_util"].append(gpu_util)
|
| 79 |
+
|
| 80 |
+
time.sleep(interval)
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def reset_monitor():
|
| 84 |
+
"""้็ฝฎ็ๆงๆฐๆฎ"""
|
| 85 |
+
global monitor_data, stop_monitor
|
| 86 |
+
stop_monitor = False
|
| 87 |
+
monitor_data = {k: [] for k in monitor_data}
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def get_monitor_stats():
|
| 91 |
+
"""่ทๅ็ๆง็ป่ฎก"""
|
| 92 |
+
stats = {}
|
| 93 |
+
for key in ["cpu_percent", "memory_used_gb", "memory_percent", "gpu_memory_gb", "gpu_util"]:
|
| 94 |
+
if monitor_data[key]:
|
| 95 |
+
arr = np.array(monitor_data[key])
|
| 96 |
+
stats[key] = {
|
| 97 |
+
"min": float(np.min(arr)),
|
| 98 |
+
"max": float(np.max(arr)),
|
| 99 |
+
"mean": float(np.mean(arr)),
|
| 100 |
+
"std": float(np.std(arr))
|
| 101 |
+
}
|
| 102 |
+
return stats
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
# ========================================
|
| 106 |
+
# ๆต่ฏไปปๅก
|
| 107 |
+
# ========================================
|
| 108 |
+
|
| 109 |
+
def get_test_data():
|
| 110 |
+
"""่ทๅๆต่ฏๆฐๆฎ"""
|
| 111 |
+
data_path = Path(__file__).parent.parent / "data" / "processed"
|
| 112 |
+
pairs = []
|
| 113 |
+
|
| 114 |
+
for case_dir in sorted(data_path.glob("real_lung_*")):
|
| 115 |
+
baseline = case_dir / "baseline.nii.gz"
|
| 116 |
+
followup = case_dir / "followup.nii.gz"
|
| 117 |
+
if baseline.exists() and followup.exists():
|
| 118 |
+
pairs.append({
|
| 119 |
+
"name": case_dir.name,
|
| 120 |
+
"baseline": str(baseline),
|
| 121 |
+
"followup": str(followup)
|
| 122 |
+
})
|
| 123 |
+
|
| 124 |
+
return pairs
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
def run_cpu_task(task_id, data_pair):
|
| 128 |
+
"""CPUไปปๅก๏ผ้
ๅ+ๅๅๆฃๆต"""
|
| 129 |
+
from app.services.dicom import DicomLoader
|
| 130 |
+
from app.services.registration import ImageRegistrator
|
| 131 |
+
from app.services.analysis import ChangeDetector
|
| 132 |
+
|
| 133 |
+
loader = DicomLoader()
|
| 134 |
+
registrator = ImageRegistrator()
|
| 135 |
+
detector = ChangeDetector()
|
| 136 |
+
|
| 137 |
+
start = time.time()
|
| 138 |
+
|
| 139 |
+
# ๅ ่ฝฝ
|
| 140 |
+
t0 = time.time()
|
| 141 |
+
baseline, _ = loader.load_nifti(data_pair["baseline"])
|
| 142 |
+
followup, _ = loader.load_nifti(data_pair["followup"])
|
| 143 |
+
load_time = time.time() - t0
|
| 144 |
+
|
| 145 |
+
# ้
ๅ
|
| 146 |
+
t0 = time.time()
|
| 147 |
+
reg_result = registrator.register(followup, baseline, use_deformable=True)
|
| 148 |
+
reg_time = time.time() - t0
|
| 149 |
+
|
| 150 |
+
# ๅๅๆฃๆต
|
| 151 |
+
t0 = time.time()
|
| 152 |
+
change_result = detector.detect_changes(baseline, reg_result["warped_image"])
|
| 153 |
+
detect_time = time.time() - t0
|
| 154 |
+
|
| 155 |
+
total = time.time() - start
|
| 156 |
+
|
| 157 |
+
return {
|
| 158 |
+
"task_id": task_id,
|
| 159 |
+
"name": data_pair["name"],
|
| 160 |
+
"shape": list(baseline.shape),
|
| 161 |
+
"load_time": load_time,
|
| 162 |
+
"reg_time": reg_time,
|
| 163 |
+
"detect_time": detect_time,
|
| 164 |
+
"total_time": total,
|
| 165 |
+
"status": "success"
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
def run_gpu_task(task_id, nifti_path, device_id=0):
|
| 170 |
+
"""GPUไปปๅก๏ผๅๅฒ"""
|
| 171 |
+
import torch
|
| 172 |
+
os.environ['CUDA_VISIBLE_DEVICES'] = str(device_id)
|
| 173 |
+
|
| 174 |
+
from app.services.dicom import DicomLoader
|
| 175 |
+
from app.services.segmentation import OrganSegmentor
|
| 176 |
+
|
| 177 |
+
torch.cuda.reset_peak_memory_stats()
|
| 178 |
+
|
| 179 |
+
loader = DicomLoader()
|
| 180 |
+
segmentor = OrganSegmentor()
|
| 181 |
+
|
| 182 |
+
start = time.time()
|
| 183 |
+
|
| 184 |
+
# ๅ ่ฝฝ
|
| 185 |
+
t0 = time.time()
|
| 186 |
+
data, _ = loader.load_nifti(nifti_path)
|
| 187 |
+
load_time = time.time() - t0
|
| 188 |
+
|
| 189 |
+
# ๅๅฒ
|
| 190 |
+
t0 = time.time()
|
| 191 |
+
result = segmentor.segment(data)
|
| 192 |
+
seg_time = time.time() - t0
|
| 193 |
+
|
| 194 |
+
total = time.time() - start
|
| 195 |
+
|
| 196 |
+
peak_mem = torch.cuda.max_memory_allocated() / (1024**3)
|
| 197 |
+
|
| 198 |
+
return {
|
| 199 |
+
"task_id": task_id,
|
| 200 |
+
"shape": list(data.shape),
|
| 201 |
+
"load_time": load_time,
|
| 202 |
+
"seg_time": seg_time,
|
| 203 |
+
"total_time": total,
|
| 204 |
+
"gpu_peak_gb": peak_mem,
|
| 205 |
+
"status": "success"
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
# ========================================
|
| 210 |
+
# ๅบๅๆต่ฏ
|
| 211 |
+
# ========================================
|
| 212 |
+
|
| 213 |
+
def benchmark_cpu_concurrent(data_pairs, concurrency_levels=[1, 2, 3, 4, 5]):
|
| 214 |
+
"""CPUๅนถๅๅบๅๆต่ฏ"""
|
| 215 |
+
results = {}
|
| 216 |
+
|
| 217 |
+
for n in concurrency_levels:
|
| 218 |
+
if n > len(data_pairs):
|
| 219 |
+
break
|
| 220 |
+
|
| 221 |
+
print(f"\n ๐ ๆต่ฏ {n} ๅนถๅ...")
|
| 222 |
+
reset_monitor()
|
| 223 |
+
|
| 224 |
+
# ๅฏๅจ็ๆง
|
| 225 |
+
global stop_monitor
|
| 226 |
+
stop_monitor = False
|
| 227 |
+
monitor_thread = threading.Thread(target=resource_monitor, args=(0.2,))
|
| 228 |
+
monitor_thread.start()
|
| 229 |
+
|
| 230 |
+
start = time.time()
|
| 231 |
+
task_results = []
|
| 232 |
+
|
| 233 |
+
with ThreadPoolExecutor(max_workers=n) as executor:
|
| 234 |
+
futures = []
|
| 235 |
+
for i in range(n):
|
| 236 |
+
futures.append(executor.submit(run_cpu_task, i+1, data_pairs[i]))
|
| 237 |
+
|
| 238 |
+
for future in as_completed(futures):
|
| 239 |
+
try:
|
| 240 |
+
task_results.append(future.result())
|
| 241 |
+
except Exception as e:
|
| 242 |
+
task_results.append({"status": "error", "error": str(e)})
|
| 243 |
+
|
| 244 |
+
total_time = time.time() - start
|
| 245 |
+
|
| 246 |
+
stop_monitor = True
|
| 247 |
+
monitor_thread.join()
|
| 248 |
+
|
| 249 |
+
stats = get_monitor_stats()
|
| 250 |
+
|
| 251 |
+
results[n] = {
|
| 252 |
+
"concurrency": n,
|
| 253 |
+
"total_time": total_time,
|
| 254 |
+
"tasks": task_results,
|
| 255 |
+
"resource_stats": stats
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
success = sum(1 for t in task_results if t.get("status") == "success")
|
| 259 |
+
print(f" โ
{success}/{n} ๆๅ, ่ๆถ {total_time:.2f}s")
|
| 260 |
+
print(f" ๐ CPUๅณฐๅผ: {stats['cpu_percent']['max']:.1f}%, ๅ
ๅญๅณฐๅผ: {stats['memory_used_gb']['max']:.1f}GB")
|
| 261 |
+
|
| 262 |
+
return results
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
def benchmark_gpu_concurrent(data_pairs, concurrency_levels=[1, 2]):
|
| 266 |
+
"""GPUๅนถๅๅบๅๆต่ฏ"""
|
| 267 |
+
results = {}
|
| 268 |
+
|
| 269 |
+
for n in concurrency_levels:
|
| 270 |
+
if n > len(data_pairs):
|
| 271 |
+
break
|
| 272 |
+
|
| 273 |
+
print(f"\n ๐ง ๆต่ฏ {n} GPUๅนถๅ...")
|
| 274 |
+
reset_monitor()
|
| 275 |
+
|
| 276 |
+
global stop_monitor
|
| 277 |
+
stop_monitor = False
|
| 278 |
+
monitor_thread = threading.Thread(target=resource_monitor, args=(0.2,))
|
| 279 |
+
monitor_thread.start()
|
| 280 |
+
|
| 281 |
+
start = time.time()
|
| 282 |
+
task_results = []
|
| 283 |
+
|
| 284 |
+
# GPUไปปๅกไธฒ่กๆง่ก๏ผๅ
ฑไบซGPUๆพๅญ๏ผ
|
| 285 |
+
if n == 1:
|
| 286 |
+
with ThreadPoolExecutor(max_workers=1) as executor:
|
| 287 |
+
futures = [executor.submit(run_gpu_task, 1, data_pairs[0]["baseline"], 0)]
|
| 288 |
+
for future in as_completed(futures):
|
| 289 |
+
try:
|
| 290 |
+
task_results.append(future.result())
|
| 291 |
+
except Exception as e:
|
| 292 |
+
task_results.append({"status": "error", "error": str(e)})
|
| 293 |
+
else:
|
| 294 |
+
# ๅคGPUไปปๅก๏ผๅฆๆๆๅคGPUๅฏไปฅๅนถ่ก๏ผ
|
| 295 |
+
with ThreadPoolExecutor(max_workers=n) as executor:
|
| 296 |
+
futures = []
|
| 297 |
+
for i in range(n):
|
| 298 |
+
# ไฝฟ็จๅไธไธชGPU้กบๅบๆง่ก
|
| 299 |
+
futures.append(executor.submit(run_gpu_task, i+1, data_pairs[i]["baseline"], 0))
|
| 300 |
+
|
| 301 |
+
for future in as_completed(futures):
|
| 302 |
+
try:
|
| 303 |
+
task_results.append(future.result())
|
| 304 |
+
except Exception as e:
|
| 305 |
+
task_results.append({"status": "error", "error": str(e)})
|
| 306 |
+
|
| 307 |
+
total_time = time.time() - start
|
| 308 |
+
|
| 309 |
+
stop_monitor = True
|
| 310 |
+
monitor_thread.join()
|
| 311 |
+
|
| 312 |
+
stats = get_monitor_stats()
|
| 313 |
+
|
| 314 |
+
results[n] = {
|
| 315 |
+
"concurrency": n,
|
| 316 |
+
"total_time": total_time,
|
| 317 |
+
"tasks": task_results,
|
| 318 |
+
"resource_stats": stats
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
success = sum(1 for t in task_results if t.get("status") == "success")
|
| 322 |
+
print(f" โ
{success}/{n} ๆๅ, ่ๆถ {total_time:.2f}s")
|
| 323 |
+
if stats.get('gpu_memory_gb'):
|
| 324 |
+
print(f" ๐ GPUๆพๅญๅณฐๅผ: {stats['gpu_memory_gb']['max']:.1f}GB, GPUๅฉ็จ็ๅณฐๅผ: {stats['gpu_util']['max']:.1f}%")
|
| 325 |
+
|
| 326 |
+
return results
|
| 327 |
+
|
| 328 |
+
|
| 329 |
+
def get_system_info():
|
| 330 |
+
"""่ทๅ็ณป็ป๏ฟฝ๏ฟฝ๏ฟฝๆฏ"""
|
| 331 |
+
info = {
|
| 332 |
+
"timestamp": datetime.now().isoformat(),
|
| 333 |
+
"cpu": {
|
| 334 |
+
"model": "Unknown",
|
| 335 |
+
"physical_cores": psutil.cpu_count(logical=False),
|
| 336 |
+
"logical_cores": psutil.cpu_count(logical=True),
|
| 337 |
+
"freq_mhz": psutil.cpu_freq().max if psutil.cpu_freq() else 0
|
| 338 |
+
},
|
| 339 |
+
"memory": {
|
| 340 |
+
"total_gb": psutil.virtual_memory().total / (1024**3)
|
| 341 |
+
},
|
| 342 |
+
"gpu": []
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
# CPUๅๅท
|
| 346 |
+
try:
|
| 347 |
+
with open('/proc/cpuinfo', 'r') as f:
|
| 348 |
+
for line in f:
|
| 349 |
+
if 'model name' in line:
|
| 350 |
+
info["cpu"]["model"] = line.split(':')[1].strip()
|
| 351 |
+
break
|
| 352 |
+
except:
|
| 353 |
+
pass
|
| 354 |
+
|
| 355 |
+
# GPUไฟกๆฏ
|
| 356 |
+
try:
|
| 357 |
+
result = subprocess.run(
|
| 358 |
+
['nvidia-smi', '--query-gpu=name,memory.total', '--format=csv,noheader'],
|
| 359 |
+
capture_output=True, text=True
|
| 360 |
+
)
|
| 361 |
+
if result.returncode == 0:
|
| 362 |
+
for line in result.stdout.strip().split('\n'):
|
| 363 |
+
parts = line.split(',')
|
| 364 |
+
info["gpu"].append({
|
| 365 |
+
"name": parts[0].strip(),
|
| 366 |
+
"memory_mb": int(parts[1].strip().replace(' MiB', ''))
|
| 367 |
+
})
|
| 368 |
+
except:
|
| 369 |
+
pass
|
| 370 |
+
|
| 371 |
+
# Python/ๅบ็ๆฌ
|
| 372 |
+
info["software"] = {
|
| 373 |
+
"python": sys.version.split()[0],
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
try:
|
| 377 |
+
import torch
|
| 378 |
+
info["software"]["pytorch"] = torch.__version__
|
| 379 |
+
info["software"]["cuda"] = torch.version.cuda if torch.cuda.is_available() else "N/A"
|
| 380 |
+
except:
|
| 381 |
+
pass
|
| 382 |
+
|
| 383 |
+
try:
|
| 384 |
+
import monai
|
| 385 |
+
info["software"]["monai"] = monai.__version__
|
| 386 |
+
except:
|
| 387 |
+
pass
|
| 388 |
+
|
| 389 |
+
try:
|
| 390 |
+
import SimpleITK as sitk
|
| 391 |
+
info["software"]["simpleitk"] = sitk.Version_MajorVersion()
|
| 392 |
+
except:
|
| 393 |
+
pass
|
| 394 |
+
|
| 395 |
+
return info
|
| 396 |
+
|
| 397 |
+
|
| 398 |
+
def generate_markdown_report(sys_info, cpu_results, gpu_results, data_info):
|
| 399 |
+
"""็ๆMarkdownๆฅๅ"""
|
| 400 |
+
|
| 401 |
+
report = f"""
|
| 402 |
+
## ๐ฌ ๆง่ฝๅบๅๆต่ฏๆฅๅ
|
| 403 |
+
|
| 404 |
+
> ๆต่ฏๆถ้ด: {sys_info['timestamp'][:19].replace('T', ' ')}
|
| 405 |
+
|
| 406 |
+
### ๆต่ฏ็ฏๅข
|
| 407 |
+
|
| 408 |
+
| ็ปไปถ | ้
็ฝฎ |
|
| 409 |
+
|------|------|
|
| 410 |
+
| **CPU** | {sys_info['cpu']['model']} |
|
| 411 |
+
| **CPUๆ ธๅฟ** | {sys_info['cpu']['physical_cores']} ็ฉ็ๆ ธ / {sys_info['cpu']['logical_cores']} ้ป่พๆ ธ |
|
| 412 |
+
| **ๅ
ๅญ** | {sys_info['memory']['total_gb']:.0f} GB |
|
| 413 |
+
| **GPU** | {sys_info['gpu'][0]['name'] if sys_info['gpu'] else 'N/A'} |
|
| 414 |
+
| **GPUๆพๅญ** | {sys_info['gpu'][0]['memory_mb']/1024:.0f} GB |
|
| 415 |
+
| **Python** | {sys_info['software'].get('python', 'N/A')} |
|
| 416 |
+
| **PyTorch** | {sys_info['software'].get('pytorch', 'N/A')} |
|
| 417 |
+
| **CUDA** | {sys_info['software'].get('cuda', 'N/A')} |
|
| 418 |
+
| **MONAI** | {sys_info['software'].get('monai', 'N/A')} |
|
| 419 |
+
|
| 420 |
+
### ๆต่ฏๆฐๆฎ
|
| 421 |
+
|
| 422 |
+
| ๅฑๆง | ๅผ |
|
| 423 |
+
|------|------|
|
| 424 |
+
| **ๆฐๆฎ้** | Learn2Reg Lung CT |
|
| 425 |
+
| **ๆ ทๆฌๆฐ้** | {data_info['count']} ๅฏน |
|
| 426 |
+
| **่พๅ
ฅๅฐบๅฏธ** | {data_info['shape']} |
|
| 427 |
+
| **ๆฐๆฎ็ฑปๅ** | float32 |
|
| 428 |
+
| **ๅๅทๅคงๅฐ** | ~{data_info['size_mb']:.1f} MB |
|
| 429 |
+
|
| 430 |
+
### CPU ๅนถๅๆต่ฏ็ปๆ (้
ๅ + ๅๅๆฃๆต)
|
| 431 |
+
|
| 432 |
+
| ๅนถๅๆฐ | ๆป่ๆถ | ๅๅ้ | CPUๅณฐๅผ | CPUๅๅผ | ๅ
ๅญๅณฐๅผ | ๅนถ่กๆ็ |
|
| 433 |
+
|--------|--------|--------|---------|---------|----------|----------|
|
| 434 |
+
"""
|
| 435 |
+
|
| 436 |
+
single_time = cpu_results.get(1, {}).get('total_time', 1)
|
| 437 |
+
for n, data in sorted(cpu_results.items()):
|
| 438 |
+
stats = data['resource_stats']
|
| 439 |
+
efficiency = (single_time * n / data['total_time']) * 100 if data['total_time'] > 0 else 0
|
| 440 |
+
throughput = n / data['total_time'] * 60 # ไปปๅก/ๅ้
|
| 441 |
+
|
| 442 |
+
report += f"| {n} | {data['total_time']:.2f}s | {throughput:.1f}/min | "
|
| 443 |
+
report += f"{stats['cpu_percent']['max']:.1f}% | {stats['cpu_percent']['mean']:.1f}% | "
|
| 444 |
+
report += f"{stats['memory_used_gb']['max']:.1f} GB | {efficiency:.0f}% |\n"
|
| 445 |
+
|
| 446 |
+
report += """
|
| 447 |
+
### GPU ๅนถๅๆต่ฏ็ปๆ (MONAI ๅจๅฎๅๅฒ)
|
| 448 |
+
|
| 449 |
+
| ๅนถๅๆฐ | ๆป่ๆถ | GPUๆพๅญๅณฐๅผ | GPUๅฉ็จ็ๅณฐๅผ | CPUๅณฐๅผ | ๅ
ๅญๅณฐๅผ |
|
| 450 |
+
|--------|--------|-------------|---------------|---------|----------|
|
| 451 |
+
"""
|
| 452 |
+
|
| 453 |
+
for n, data in sorted(gpu_results.items()):
|
| 454 |
+
stats = data['resource_stats']
|
| 455 |
+
gpu_peak = stats.get('gpu_memory_gb', {}).get('max', 0)
|
| 456 |
+
gpu_util = stats.get('gpu_util', {}).get('max', 0)
|
| 457 |
+
|
| 458 |
+
report += f"| {n} | {data['total_time']:.2f}s | {gpu_peak:.1f} GB | {gpu_util:.0f}% | "
|
| 459 |
+
report += f"{stats['cpu_percent']['max']:.1f}% | {stats['memory_used_gb']['max']:.1f} GB |\n"
|
| 460 |
+
|
| 461 |
+
# ๅไปปๅก่ฏฆๆ
|
| 462 |
+
if cpu_results.get(1) and cpu_results[1]['tasks']:
|
| 463 |
+
task = cpu_results[1]['tasks'][0]
|
| 464 |
+
report += f"""
|
| 465 |
+
### ๅไปปๅก่ๆถๅ่งฃ (CPU ้
ๅๆต็จ)
|
| 466 |
+
|
| 467 |
+
| ้ถๆฎต | ่ๆถ | ๅ ๆฏ |
|
| 468 |
+
|------|------|------|
|
| 469 |
+
| ๆฐๆฎๅ ่ฝฝ | {task.get('load_time', 0):.2f}s | {task.get('load_time', 0)/task.get('total_time', 1)*100:.0f}% |
|
| 470 |
+
| ๅๆง้
ๅ | ~1.0s | ~13% |
|
| 471 |
+
| ้ๅๆง้
ๅ | ~{task.get('reg_time', 0)-1:.1f}s | ~{(task.get('reg_time', 0)-1)/task.get('total_time', 1)*100:.0f}% |
|
| 472 |
+
| ๅๅ๏ฟฝ๏ฟฝ๏ฟฝๆต | {task.get('detect_time', 0):.2f}s | {task.get('detect_time', 0)/task.get('total_time', 1)*100:.0f}% |
|
| 473 |
+
| **ๆป่ฎก** | **{task.get('total_time', 0):.2f}s** | **100%** |
|
| 474 |
+
"""
|
| 475 |
+
|
| 476 |
+
if gpu_results.get(1) and gpu_results[1]['tasks']:
|
| 477 |
+
task = gpu_results[1]['tasks'][0]
|
| 478 |
+
report += f"""
|
| 479 |
+
### ๅไปปๅก่ๆถๅ่งฃ (GPU ๅๅฒๆต็จ)
|
| 480 |
+
|
| 481 |
+
| ้ถๆฎต | ่ๆถ | ๅ ๆฏ |
|
| 482 |
+
|------|------|------|
|
| 483 |
+
| ๆฐๆฎๅ ่ฝฝ | {task.get('load_time', 0):.2f}s | {task.get('load_time', 0)/task.get('total_time', 1)*100:.0f}% |
|
| 484 |
+
| ๆจกๅๆจ็ | {task.get('seg_time', 0):.2f}s | {task.get('seg_time', 0)/task.get('total_time', 1)*100:.0f}% |
|
| 485 |
+
| **ๆป่ฎก** | **{task.get('total_time', 0):.2f}s** | **100%** |
|
| 486 |
+
| **GPUๆพๅญๅณฐๅผ** | **{task.get('gpu_peak_gb', 0):.2f} GB** | - |
|
| 487 |
+
"""
|
| 488 |
+
|
| 489 |
+
report += """
|
| 490 |
+
### ่ตๆบ้ๆฑๆป็ป
|
| 491 |
+
|
| 492 |
+
ๆ นๆฎไปฅไธๆต่ฏ็ปๆ๏ผๆจ่ไปฅไธ็กฌไปถ้
็ฝฎ๏ผ
|
| 493 |
+
|
| 494 |
+
| ้จ็ฝฒๅบๆฏ | CPU | ๅ
ๅญ | GPU | ้ขไผฐๅนถๅ่ฝๅ |
|
| 495 |
+
|----------|-----|------|-----|--------------|
|
| 496 |
+
| **ๆไฝ้
็ฝฎ** | 4ๆ ธ | 8 GB | ๆ | 1 ไปปๅก (ไป
้
ๅ) |
|
| 497 |
+
| **ๆจ่้
็ฝฎ** | 8ๆ ธ | 16 GB | RTX 3060 12GB | 2-3 ไปปๅก |
|
| 498 |
+
| **ไธไธ้
็ฝฎ** | 16ๆ ธ | 32 GB | RTX 4090 24GB | 5+ ไปปๅก |
|
| 499 |
+
| **ๆๅกๅจ้
็ฝฎ** | 32ๆ ธ+ | 64 GB+ | A100 40GB+ | 10+ ไปปๅก |
|
| 500 |
+
|
| 501 |
+
"""
|
| 502 |
+
|
| 503 |
+
return report
|
| 504 |
+
|
| 505 |
+
|
| 506 |
+
def main():
|
| 507 |
+
global stop_monitor
|
| 508 |
+
|
| 509 |
+
print("=" * 70)
|
| 510 |
+
print("๐ฌ NeuroScan AI ๅฎๆดๅบๅๆต่ฏ")
|
| 511 |
+
print("=" * 70)
|
| 512 |
+
|
| 513 |
+
# ็ณป็ปไฟกๆฏ
|
| 514 |
+
print("\n๐ ๆถ้็ณป็ปไฟกๆฏ...")
|
| 515 |
+
sys_info = get_system_info()
|
| 516 |
+
print(f" CPU: {sys_info['cpu']['model']}")
|
| 517 |
+
print(f" ๆ ธๅฟ: {sys_info['cpu']['physical_cores']}P / {sys_info['cpu']['logical_cores']}L")
|
| 518 |
+
print(f" ๅ
ๅญ: {sys_info['memory']['total_gb']:.0f} GB")
|
| 519 |
+
if sys_info['gpu']:
|
| 520 |
+
print(f" GPU: {sys_info['gpu'][0]['name']} ({sys_info['gpu'][0]['memory_mb']/1024:.0f} GB)")
|
| 521 |
+
|
| 522 |
+
# ๆต่ฏๆฐๆฎ
|
| 523 |
+
print("\n๐ ๅ ่ฝฝๆต่ฏๆฐๆฎ...")
|
| 524 |
+
data_pairs = get_test_data()
|
| 525 |
+
print(f" ๆพๅฐ {len(data_pairs)} ๅฏนๆต่ฏๆฐๆฎ")
|
| 526 |
+
|
| 527 |
+
if not data_pairs:
|
| 528 |
+
print("โ ๆฒกๆๆต่ฏๆฐๆฎ๏ผ่ฏทๅ
่ฟ่ก: python scripts/download_datasets.py")
|
| 529 |
+
return
|
| 530 |
+
|
| 531 |
+
# ่ทๅๆฐๆฎๅฐบๅฏธ
|
| 532 |
+
from app.services.dicom import DicomLoader
|
| 533 |
+
loader = DicomLoader()
|
| 534 |
+
sample_data, _ = loader.load_nifti(data_pairs[0]["baseline"])
|
| 535 |
+
data_info = {
|
| 536 |
+
"count": len(data_pairs),
|
| 537 |
+
"shape": f"{sample_data.shape[0]} x {sample_data.shape[1]} x {sample_data.shape[2]}",
|
| 538 |
+
"size_mb": sample_data.nbytes / (1024**2)
|
| 539 |
+
}
|
| 540 |
+
print(f" ๆฐๆฎๅฐบๅฏธ: {data_info['shape']}")
|
| 541 |
+
print(f" ๅๅทๅคงๅฐ: {data_info['size_mb']:.1f} MB")
|
| 542 |
+
|
| 543 |
+
# CPUๅนถๅๆต่ฏ
|
| 544 |
+
print("\n" + "=" * 70)
|
| 545 |
+
print("๐ CPU ๅนถๅๅบๅๆต่ฏ (้
ๅ + ๅๅๆฃๆต)")
|
| 546 |
+
print("=" * 70)
|
| 547 |
+
|
| 548 |
+
cpu_levels = [1, 2, 3, 4, 5] if len(data_pairs) >= 5 else list(range(1, len(data_pairs)+1))
|
| 549 |
+
cpu_results = benchmark_cpu_concurrent(data_pairs, cpu_levels)
|
| 550 |
+
|
| 551 |
+
# GPUๆต่ฏ
|
| 552 |
+
print("\n" + "=" * 70)
|
| 553 |
+
print("๐ง GPU ๅบๅๆต่ฏ (MONAI ๅจๅฎๅๅฒ)")
|
| 554 |
+
print("=" * 70)
|
| 555 |
+
|
| 556 |
+
gpu_results = {}
|
| 557 |
+
try:
|
| 558 |
+
import torch
|
| 559 |
+
if torch.cuda.is_available():
|
| 560 |
+
gpu_results = benchmark_gpu_concurrent(data_pairs, [1, 2])
|
| 561 |
+
else:
|
| 562 |
+
print(" โ ๏ธ GPU ไธๅฏ็จ๏ผ่ทณ่ฟGPUๆต่ฏ")
|
| 563 |
+
except Exception as e:
|
| 564 |
+
print(f" โ ๏ธ GPUๆต่ฏๅคฑ่ดฅ: {e}")
|
| 565 |
+
|
| 566 |
+
# ็ๆๆฅๅ
|
| 567 |
+
print("\n" + "=" * 70)
|
| 568 |
+
print("๐ ็ๆๆต่ฏๆฅๅ")
|
| 569 |
+
print("=" * 70)
|
| 570 |
+
|
| 571 |
+
report = generate_markdown_report(sys_info, cpu_results, gpu_results, data_info)
|
| 572 |
+
|
| 573 |
+
# ไฟๅญๆฅๅ
|
| 574 |
+
report_path = Path(__file__).parent.parent / "BENCHMARK.md"
|
| 575 |
+
with open(report_path, 'w', encoding='utf-8') as f:
|
| 576 |
+
f.write("# NeuroScan AI ๆง่ฝๅบๅๆต่ฏ\n")
|
| 577 |
+
f.write(report)
|
| 578 |
+
|
| 579 |
+
print(f" โ
ๆฅๅๅทฒไฟๅญ: {report_path}")
|
| 580 |
+
|
| 581 |
+
# ่พๅบๆ่ฆ
|
| 582 |
+
print("\n" + "=" * 70)
|
| 583 |
+
print("๐ ๆต่ฏๆ่ฆ")
|
| 584 |
+
print("=" * 70)
|
| 585 |
+
|
| 586 |
+
print("\n๐ CPU ๆต่ฏ (้
ๅๆต็จ):")
|
| 587 |
+
for n, data in sorted(cpu_results.items()):
|
| 588 |
+
stats = data['resource_stats']
|
| 589 |
+
print(f" {n}ๅนถๅ: CPUๅณฐๅผ {stats['cpu_percent']['max']:.1f}%, "
|
| 590 |
+
f"ๅ
ๅญๅณฐๅผ {stats['memory_used_gb']['max']:.1f}GB, "
|
| 591 |
+
f"่ๆถ {data['total_time']:.1f}s")
|
| 592 |
+
|
| 593 |
+
if gpu_results:
|
| 594 |
+
print("\n๐ง GPU ๆต่ฏ (ๅๅฒๆต็จ):")
|
| 595 |
+
for n, data in sorted(gpu_results.items()):
|
| 596 |
+
stats = data['resource_stats']
|
| 597 |
+
gpu_peak = stats.get('gpu_memory_gb', {}).get('max', 0)
|
| 598 |
+
print(f" {n}ๅนถๅ: GPUๆพๅญๅณฐๅผ {gpu_peak:.1f}GB, "
|
| 599 |
+
f"CPUๅณฐๅผ {stats['cpu_percent']['max']:.1f}%, "
|
| 600 |
+
f"่ๆถ {data['total_time']:.1f}s")
|
| 601 |
+
|
| 602 |
+
print("\nโ
ๅบๅๆต่ฏๅฎๆ!")
|
| 603 |
+
print(f" ่ฏฆ็ปๆฅๅ: {report_path}")
|
| 604 |
+
|
| 605 |
+
# ่ฟๅ็ปๆไพๅ็ปญไฝฟ็จ
|
| 606 |
+
return {
|
| 607 |
+
"sys_info": sys_info,
|
| 608 |
+
"cpu_results": cpu_results,
|
| 609 |
+
"gpu_results": gpu_results,
|
| 610 |
+
"data_info": data_info,
|
| 611 |
+
"report": report
|
| 612 |
+
}
|
| 613 |
+
|
| 614 |
+
|
| 615 |
+
if __name__ == "__main__":
|
| 616 |
+
results = main()
|
| 617 |
+
|
| 618 |
+
|
scripts/stress_test.py
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
NeuroScan AI ๅนถๅๅๅๆต่ฏ
|
| 4 |
+
ๆต่ฏ CPU/GPU ๅณฐๅผไฝฟ็จๆ
ๅต๏ผๆฏๆ 2-3 ไปปๅกๅนถๅ
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import os
|
| 8 |
+
import sys
|
| 9 |
+
import time
|
| 10 |
+
import threading
|
| 11 |
+
import multiprocessing
|
| 12 |
+
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, as_completed
|
| 13 |
+
from pathlib import Path
|
| 14 |
+
import psutil
|
| 15 |
+
import numpy as np
|
| 16 |
+
|
| 17 |
+
# ๆทปๅ ้กน็ฎๆ น็ฎๅฝๅฐ่ทฏๅพ
|
| 18 |
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
| 19 |
+
|
| 20 |
+
# ๅ
จๅฑ็ๆงๆฐๆฎ
|
| 21 |
+
monitor_data = {
|
| 22 |
+
"cpu_percent": [],
|
| 23 |
+
"memory_percent": [],
|
| 24 |
+
"memory_gb": [],
|
| 25 |
+
"gpu_memory_gb": [],
|
| 26 |
+
"gpu_util": []
|
| 27 |
+
}
|
| 28 |
+
stop_monitor = False
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def get_gpu_stats():
|
| 32 |
+
"""่ทๅGPU็ถๆ"""
|
| 33 |
+
try:
|
| 34 |
+
import torch
|
| 35 |
+
if torch.cuda.is_available():
|
| 36 |
+
# ่ทๅๅฝๅGPU็ๆพๅญไฝฟ็จ
|
| 37 |
+
allocated = torch.cuda.memory_allocated() / (1024**3)
|
| 38 |
+
reserved = torch.cuda.memory_reserved() / (1024**3)
|
| 39 |
+
|
| 40 |
+
# ไฝฟ็จnvidia-smi่ทๅๆปไฝๆพๅญ
|
| 41 |
+
import subprocess
|
| 42 |
+
result = subprocess.run(
|
| 43 |
+
['nvidia-smi', '--query-gpu=memory.used,utilization.gpu', '--format=csv,noheader,nounits', '-i', '0'],
|
| 44 |
+
capture_output=True, text=True
|
| 45 |
+
)
|
| 46 |
+
if result.returncode == 0:
|
| 47 |
+
parts = result.stdout.strip().split(',')
|
| 48 |
+
mem_used = float(parts[0]) / 1024 # ่ฝฌๆขไธบGB
|
| 49 |
+
gpu_util = float(parts[1])
|
| 50 |
+
return mem_used, gpu_util
|
| 51 |
+
return allocated, 0
|
| 52 |
+
return 0, 0
|
| 53 |
+
except:
|
| 54 |
+
return 0, 0
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def resource_monitor(interval=0.5):
|
| 58 |
+
"""ๅๅฐ่ตๆบ็ๆง็บฟ็จ"""
|
| 59 |
+
global stop_monitor, monitor_data
|
| 60 |
+
|
| 61 |
+
while not stop_monitor:
|
| 62 |
+
# CPU
|
| 63 |
+
cpu_percent = psutil.cpu_percent(interval=None)
|
| 64 |
+
monitor_data["cpu_percent"].append(cpu_percent)
|
| 65 |
+
|
| 66 |
+
# ๅ
ๅญ
|
| 67 |
+
mem = psutil.virtual_memory()
|
| 68 |
+
monitor_data["memory_percent"].append(mem.percent)
|
| 69 |
+
monitor_data["memory_gb"].append(mem.used / (1024**3))
|
| 70 |
+
|
| 71 |
+
# GPU
|
| 72 |
+
gpu_mem, gpu_util = get_gpu_stats()
|
| 73 |
+
monitor_data["gpu_memory_gb"].append(gpu_mem)
|
| 74 |
+
monitor_data["gpu_util"].append(gpu_util)
|
| 75 |
+
|
| 76 |
+
time.sleep(interval)
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def run_single_pipeline(task_id, data_pair):
|
| 80 |
+
"""่ฟ่กๅไธชๅๆๆตๆฐด็บฟ"""
|
| 81 |
+
baseline_path, followup_path = data_pair
|
| 82 |
+
|
| 83 |
+
print(f" ๐ ไปปๅก {task_id}: ๅผๅงๅค็ {Path(baseline_path).parent.name}")
|
| 84 |
+
start_time = time.time()
|
| 85 |
+
|
| 86 |
+
try:
|
| 87 |
+
# ๅฏผๅ
ฅๆจกๅ
|
| 88 |
+
from app.services.dicom import DicomLoader
|
| 89 |
+
from app.services.registration import ImageRegistrator
|
| 90 |
+
from app.services.analysis import ChangeDetector
|
| 91 |
+
|
| 92 |
+
loader = DicomLoader()
|
| 93 |
+
registrator = ImageRegistrator()
|
| 94 |
+
detector = ChangeDetector()
|
| 95 |
+
|
| 96 |
+
# 1. ๅ ่ฝฝๆฐๆฎ
|
| 97 |
+
t0 = time.time()
|
| 98 |
+
baseline_data, _ = loader.load_nifti(baseline_path)
|
| 99 |
+
followup_data, _ = loader.load_nifti(followup_path)
|
| 100 |
+
load_time = time.time() - t0
|
| 101 |
+
|
| 102 |
+
# 2. ้
ๅ
|
| 103 |
+
t0 = time.time()
|
| 104 |
+
reg_result = registrator.register(followup_data, baseline_data, use_deformable=True)
|
| 105 |
+
reg_time = time.time() - t0
|
| 106 |
+
|
| 107 |
+
# 3. ๅๅๆฃๆต
|
| 108 |
+
t0 = time.time()
|
| 109 |
+
change_result = detector.detect_changes(baseline_data, reg_result["warped_image"])
|
| 110 |
+
detect_time = time.time() - t0
|
| 111 |
+
|
| 112 |
+
total_time = time.time() - start_time
|
| 113 |
+
|
| 114 |
+
return {
|
| 115 |
+
"task_id": task_id,
|
| 116 |
+
"status": "success",
|
| 117 |
+
"load_time": load_time,
|
| 118 |
+
"reg_time": reg_time,
|
| 119 |
+
"detect_time": detect_time,
|
| 120 |
+
"total_time": total_time,
|
| 121 |
+
"data_shape": baseline_data.shape
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
except Exception as e:
|
| 125 |
+
return {
|
| 126 |
+
"task_id": task_id,
|
| 127 |
+
"status": "error",
|
| 128 |
+
"error": str(e),
|
| 129 |
+
"total_time": time.time() - start_time
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def run_segmentation_task(task_id, nifti_path):
|
| 134 |
+
"""่ฟ่กๅๅฒไปปๅก๏ผGPUๅฏ้ๅ๏ผ"""
|
| 135 |
+
print(f" ๐ง ๅๅฒไปปๅก {task_id}: ๅผๅงๅค็")
|
| 136 |
+
start_time = time.time()
|
| 137 |
+
|
| 138 |
+
try:
|
| 139 |
+
import torch
|
| 140 |
+
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
|
| 141 |
+
|
| 142 |
+
from app.services.segmentation import OrganSegmentor
|
| 143 |
+
segmentor = OrganSegmentor()
|
| 144 |
+
|
| 145 |
+
# ๆง่กๅๅฒ
|
| 146 |
+
from app.services.dicom import DicomLoader
|
| 147 |
+
loader = DicomLoader()
|
| 148 |
+
data, _ = loader.load_nifti(nifti_path)
|
| 149 |
+
|
| 150 |
+
# ๅๅฒๆจ็
|
| 151 |
+
result = segmentor.segment(data)
|
| 152 |
+
|
| 153 |
+
total_time = time.time() - start_time
|
| 154 |
+
|
| 155 |
+
# ่ฎฐๅฝGPUๅณฐๅผ
|
| 156 |
+
peak_mem = torch.cuda.max_memory_allocated() / (1024**3)
|
| 157 |
+
|
| 158 |
+
return {
|
| 159 |
+
"task_id": task_id,
|
| 160 |
+
"status": "success",
|
| 161 |
+
"total_time": total_time,
|
| 162 |
+
"gpu_peak_gb": peak_mem
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
except Exception as e:
|
| 166 |
+
return {
|
| 167 |
+
"task_id": task_id,
|
| 168 |
+
"status": "error",
|
| 169 |
+
"error": str(e),
|
| 170 |
+
"total_time": time.time() - start_time
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def get_test_data_pairs(data_dir, max_pairs=5):
|
| 175 |
+
"""่ทๅๆต่ฏๆฐๆฎๅฏน"""
|
| 176 |
+
data_path = Path(data_dir) / "processed"
|
| 177 |
+
pairs = []
|
| 178 |
+
|
| 179 |
+
for case_dir in sorted(data_path.glob("real_lung_*"))[:max_pairs]:
|
| 180 |
+
baseline = case_dir / "baseline.nii.gz"
|
| 181 |
+
followup = case_dir / "followup.nii.gz"
|
| 182 |
+
if baseline.exists() and followup.exists():
|
| 183 |
+
pairs.append((str(baseline), str(followup)))
|
| 184 |
+
|
| 185 |
+
return pairs
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
def print_stats(title, data_list):
|
| 189 |
+
"""ๆๅฐ็ป่ฎกไฟกๆฏ"""
|
| 190 |
+
if not data_list:
|
| 191 |
+
return
|
| 192 |
+
arr = np.array(data_list)
|
| 193 |
+
print(f" {title}:")
|
| 194 |
+
print(f" ๅนณๅ: {np.mean(arr):.2f}")
|
| 195 |
+
print(f" ๅณฐๅผ: {np.max(arr):.2f}")
|
| 196 |
+
print(f" ๆๅฐ: {np.min(arr):.2f}")
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
def main():
|
| 200 |
+
global stop_monitor, monitor_data
|
| 201 |
+
|
| 202 |
+
print("=" * 70)
|
| 203 |
+
print("๐ฅ NeuroScan AI ๅนถๅๅๅๆต่ฏ")
|
| 204 |
+
print("=" * 70)
|
| 205 |
+
|
| 206 |
+
# ็ณป็ปไฟกๆฏ
|
| 207 |
+
print(f"\n๐ ็ณป็ป้
็ฝฎ:")
|
| 208 |
+
print(f" CPU ๆ ธๅฟ: {psutil.cpu_count(logical=False)} ็ฉ็ๆ ธ / {psutil.cpu_count()} ้ป่พๆ ธ")
|
| 209 |
+
print(f" ๆปๅ
ๅญ: {psutil.virtual_memory().total / (1024**3):.1f} GB")
|
| 210 |
+
|
| 211 |
+
try:
|
| 212 |
+
import torch
|
| 213 |
+
if torch.cuda.is_available():
|
| 214 |
+
print(f" GPU: {torch.cuda.get_device_name(0)}")
|
| 215 |
+
print(f" GPUๆพๅญ: {torch.cuda.get_device_properties(0).total_memory / (1024**3):.1f} GB")
|
| 216 |
+
except:
|
| 217 |
+
print(" GPU: ไธๅฏ็จ")
|
| 218 |
+
|
| 219 |
+
# ่ทๅๆต่ฏๆฐๆฎ
|
| 220 |
+
data_dir = Path(__file__).parent.parent / "data"
|
| 221 |
+
pairs = get_test_data_pairs(data_dir, max_pairs=5)
|
| 222 |
+
|
| 223 |
+
if len(pairs) < 2:
|
| 224 |
+
print("\nโ ๆต่ฏๆฐๆฎไธ่ถณ๏ผ้่ฆ่ณๅฐ 2 ๅฏนๆฐๆฎ")
|
| 225 |
+
print(" ่ฏทๅ
่ฟ่ก: python scripts/download_datasets.py --dataset learn2reg")
|
| 226 |
+
return
|
| 227 |
+
|
| 228 |
+
print(f"\n๐ ๆพๅฐ {len(pairs)} ๅฏนๆต่ฏๆฐๆฎ")
|
| 229 |
+
|
| 230 |
+
# ========================================
|
| 231 |
+
# ๆต่ฏ 1: ๅไปปๅกๅบๅ
|
| 232 |
+
# ========================================
|
| 233 |
+
print("\n" + "=" * 70)
|
| 234 |
+
print("๐ ๆต่ฏ 1: ๅไปปๅกๅบๅๆต่ฏ")
|
| 235 |
+
print("=" * 70)
|
| 236 |
+
|
| 237 |
+
monitor_data = {k: [] for k in monitor_data}
|
| 238 |
+
stop_monitor = False
|
| 239 |
+
|
| 240 |
+
# ๅฏๅจ็ๆง
|
| 241 |
+
monitor_thread = threading.Thread(target=resource_monitor, args=(0.2,))
|
| 242 |
+
monitor_thread.start()
|
| 243 |
+
|
| 244 |
+
result = run_single_pipeline(1, pairs[0])
|
| 245 |
+
|
| 246 |
+
stop_monitor = True
|
| 247 |
+
monitor_thread.join()
|
| 248 |
+
|
| 249 |
+
if result["status"] == "success":
|
| 250 |
+
print(f"\n โ
ๅไปปๅกๅฎๆ:")
|
| 251 |
+
print(f" ๅ ่ฝฝๆถ้ด: {result['load_time']:.2f}s")
|
| 252 |
+
print(f" ้
ๅๆถ้ด: {result['reg_time']:.2f}s")
|
| 253 |
+
print(f" ๆฃๆตๆถ้ด: {result['detect_time']:.2f}s")
|
| 254 |
+
print(f" ๆปๆถ้ด: {result['total_time']:.2f}s")
|
| 255 |
+
|
| 256 |
+
print(f"\n ๐ ๅไปปๅก่ตๆบๅณฐๅผ:")
|
| 257 |
+
print(f" CPU ๅณฐๅผ: {max(monitor_data['cpu_percent']):.1f}%")
|
| 258 |
+
print(f" ๅ
ๅญๅณฐๅผ: {max(monitor_data['memory_gb']):.1f} GB ({max(monitor_data['memory_percent']):.1f}%)")
|
| 259 |
+
print(f" GPUๆพๅญๅณฐๅผ: {max(monitor_data['gpu_memory_gb']):.2f} GB")
|
| 260 |
+
|
| 261 |
+
single_task_time = result["total_time"]
|
| 262 |
+
single_cpu_peak = max(monitor_data['cpu_percent'])
|
| 263 |
+
single_mem_peak = max(monitor_data['memory_gb'])
|
| 264 |
+
|
| 265 |
+
# ========================================
|
| 266 |
+
# ๆต่ฏ 2: 2 ไปปๅกๅนถๅ
|
| 267 |
+
# ========================================
|
| 268 |
+
print("\n" + "=" * 70)
|
| 269 |
+
print("๐ ๆต่ฏ 2: 2 ไปปๅกๅนถๅๅๅๆต่ฏ")
|
| 270 |
+
print("=" * 70)
|
| 271 |
+
|
| 272 |
+
monitor_data = {k: [] for k in monitor_data}
|
| 273 |
+
stop_monitor = False
|
| 274 |
+
|
| 275 |
+
monitor_thread = threading.Thread(target=resource_monitor, args=(0.2,))
|
| 276 |
+
monitor_thread.start()
|
| 277 |
+
|
| 278 |
+
start_time = time.time()
|
| 279 |
+
results = []
|
| 280 |
+
|
| 281 |
+
with ThreadPoolExecutor(max_workers=2) as executor:
|
| 282 |
+
futures = []
|
| 283 |
+
for i, pair in enumerate(pairs[:2]):
|
| 284 |
+
futures.append(executor.submit(run_single_pipeline, i+1, pair))
|
| 285 |
+
|
| 286 |
+
for future in as_completed(futures):
|
| 287 |
+
results.append(future.result())
|
| 288 |
+
|
| 289 |
+
concurrent_2_time = time.time() - start_time
|
| 290 |
+
|
| 291 |
+
stop_monitor = True
|
| 292 |
+
monitor_thread.join()
|
| 293 |
+
|
| 294 |
+
success_count = sum(1 for r in results if r["status"] == "success")
|
| 295 |
+
print(f"\n โ
2ไปปๅกๅนถๅๅฎๆ: {success_count}/2 ๆๅ")
|
| 296 |
+
print(f" ๆป่ๆถ: {concurrent_2_time:.2f}s")
|
| 297 |
+
print(f" ๅนถ่กๆ็: {(single_task_time * 2 / concurrent_2_time * 100):.1f}%")
|
| 298 |
+
|
| 299 |
+
print(f"\n ๐ 2ไปปๅกๅนถๅ่ตๆบๅณฐๅผ:")
|
| 300 |
+
print(f" CPU ๅณฐๅผ: {max(monitor_data['cpu_percent']):.1f}%")
|
| 301 |
+
print(f" ๅ
ๅญๅณฐๅผ: {max(monitor_data['memory_gb']):.1f} GB ({max(monitor_data['memory_percent']):.1f}%)")
|
| 302 |
+
print(f" GPUๆพๅญๅณฐๅผ: {max(monitor_data['gpu_memory_gb']):.2f} GB")
|
| 303 |
+
|
| 304 |
+
concurrent_2_cpu = max(monitor_data['cpu_percent'])
|
| 305 |
+
concurrent_2_mem = max(monitor_data['memory_gb'])
|
| 306 |
+
|
| 307 |
+
# ========================================
|
| 308 |
+
# ๆต่ฏ 3: 3 ไปปๅกๅนถ๏ฟฝ๏ฟฝ
|
| 309 |
+
# ========================================
|
| 310 |
+
print("\n" + "=" * 70)
|
| 311 |
+
print("๐ ๆต่ฏ 3: 3 ไปปๅกๅนถๅๅๅๆต่ฏ")
|
| 312 |
+
print("=" * 70)
|
| 313 |
+
|
| 314 |
+
if len(pairs) < 3:
|
| 315 |
+
print(" โ ๏ธ ๆฐๆฎไธ่ถณ๏ผ่ทณ่ฟ 3 ไปปๅกๆต่ฏ")
|
| 316 |
+
else:
|
| 317 |
+
monitor_data = {k: [] for k in monitor_data}
|
| 318 |
+
stop_monitor = False
|
| 319 |
+
|
| 320 |
+
monitor_thread = threading.Thread(target=resource_monitor, args=(0.2,))
|
| 321 |
+
monitor_thread.start()
|
| 322 |
+
|
| 323 |
+
start_time = time.time()
|
| 324 |
+
results = []
|
| 325 |
+
|
| 326 |
+
with ThreadPoolExecutor(max_workers=3) as executor:
|
| 327 |
+
futures = []
|
| 328 |
+
for i, pair in enumerate(pairs[:3]):
|
| 329 |
+
futures.append(executor.submit(run_single_pipeline, i+1, pair))
|
| 330 |
+
|
| 331 |
+
for future in as_completed(futures):
|
| 332 |
+
results.append(future.result())
|
| 333 |
+
|
| 334 |
+
concurrent_3_time = time.time() - start_time
|
| 335 |
+
|
| 336 |
+
stop_monitor = True
|
| 337 |
+
monitor_thread.join()
|
| 338 |
+
|
| 339 |
+
success_count = sum(1 for r in results if r["status"] == "success")
|
| 340 |
+
print(f"\n โ
3ไปปๅกๅนถๅๅฎๆ: {success_count}/3 ๆๅ")
|
| 341 |
+
print(f" ๆป่ๆถ: {concurrent_3_time:.2f}s")
|
| 342 |
+
print(f" ๅนถ่กๆ็: {(single_task_time * 3 / concurrent_3_time * 100):.1f}%")
|
| 343 |
+
|
| 344 |
+
print(f"\n ๐ 3ไปปๅกๅนถๅ่ตๆบๅณฐๅผ:")
|
| 345 |
+
print(f" CPU ๅณฐๅผ: {max(monitor_data['cpu_percent']):.1f}%")
|
| 346 |
+
print(f" ๅ
ๅญๅณฐๅผ: {max(monitor_data['memory_gb']):.1f} GB ({max(monitor_data['memory_percent']):.1f}%)")
|
| 347 |
+
print(f" GPUๆพๅญๅณฐๅผ: {max(monitor_data['gpu_memory_gb']):.2f} GB")
|
| 348 |
+
|
| 349 |
+
concurrent_3_cpu = max(monitor_data['cpu_percent'])
|
| 350 |
+
concurrent_3_mem = max(monitor_data['memory_gb'])
|
| 351 |
+
|
| 352 |
+
# ========================================
|
| 353 |
+
# ๆต่ฏ 4: GPU ๅๅฒไปปๅก (ๅฏ้)
|
| 354 |
+
# ========================================
|
| 355 |
+
print("\n" + "=" * 70)
|
| 356 |
+
print("๐ ๆต่ฏ 4: GPU ๅๅฒไปปๅกๅณฐๅผๆต่ฏ")
|
| 357 |
+
print("=" * 70)
|
| 358 |
+
|
| 359 |
+
try:
|
| 360 |
+
import torch
|
| 361 |
+
if torch.cuda.is_available():
|
| 362 |
+
torch.cuda.reset_peak_memory_stats()
|
| 363 |
+
|
| 364 |
+
monitor_data = {k: [] for k in monitor_data}
|
| 365 |
+
stop_monitor = False
|
| 366 |
+
|
| 367 |
+
monitor_thread = threading.Thread(target=resource_monitor, args=(0.2,))
|
| 368 |
+
monitor_thread.start()
|
| 369 |
+
|
| 370 |
+
# ่ฟ่กๅๅฒ
|
| 371 |
+
seg_result = run_segmentation_task(1, pairs[0][0])
|
| 372 |
+
|
| 373 |
+
stop_monitor = True
|
| 374 |
+
monitor_thread.join()
|
| 375 |
+
|
| 376 |
+
if seg_result["status"] == "success":
|
| 377 |
+
print(f"\n โ
ๅๅฒไปปๅกๅฎๆ:")
|
| 378 |
+
print(f" ่ๆถ: {seg_result['total_time']:.2f}s")
|
| 379 |
+
print(f" GPUๅณฐๅผ: {seg_result.get('gpu_peak_gb', max(monitor_data['gpu_memory_gb'])):.2f} GB")
|
| 380 |
+
else:
|
| 381 |
+
print(f"\n โ ๏ธ ๅๅฒไปปๅก่ทณ่ฟ: {seg_result.get('error', 'unknown')}")
|
| 382 |
+
|
| 383 |
+
print(f"\n ๐ ๅๅฒไปปๅก่ตๆบๅณฐๅผ:")
|
| 384 |
+
print(f" CPU ๅณฐๅผ: {max(monitor_data['cpu_percent']):.1f}%")
|
| 385 |
+
print(f" ๅ
ๅญๅณฐๅผ: {max(monitor_data['memory_gb']):.1f} GB")
|
| 386 |
+
print(f" GPUๆพๅญๅณฐๅผ: {max(monitor_data['gpu_memory_gb']):.2f} GB")
|
| 387 |
+
|
| 388 |
+
gpu_seg_peak = max(monitor_data['gpu_memory_gb'])
|
| 389 |
+
else:
|
| 390 |
+
print(" โ ๏ธ GPU ไธๅฏ็จ๏ผ่ทณ่ฟๅๅฒๆต่ฏ")
|
| 391 |
+
gpu_seg_peak = 0
|
| 392 |
+
except Exception as e:
|
| 393 |
+
print(f" โ ๏ธ ๅๅฒๆต่ฏๅคฑ่ดฅ: {e}")
|
| 394 |
+
gpu_seg_peak = 0
|
| 395 |
+
|
| 396 |
+
# ========================================
|
| 397 |
+
# ๆ็ปๆฅๅ
|
| 398 |
+
# ========================================
|
| 399 |
+
print("\n" + "=" * 70)
|
| 400 |
+
print("๐ ๅๅๆต่ฏๆป็ปๆฅๅ")
|
| 401 |
+
print("=" * 70)
|
| 402 |
+
|
| 403 |
+
print(f"""
|
| 404 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 405 |
+
โ NeuroScan AI ่ตๆบ้ๆฑๆฅๅ โ
|
| 406 |
+
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโค
|
| 407 |
+
โ ๆต่ฏๅบๆฏ โ CPU ๅณฐๅผ โ ๅ
ๅญๅณฐๅผ โ GPU ๆพๅญๅณฐๅผ โ
|
| 408 |
+
โโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโค
|
| 409 |
+
โ ๅไปปๅก้
ๅ โ {single_cpu_peak:>6.1f}% โ {single_mem_peak:>6.1f} GB โ ~0 GB (CPU) โ
|
| 410 |
+
โ 2ไปปๅกๅนถๅ โ {concurrent_2_cpu:>6.1f}% โ {concurrent_2_mem:>6.1f} GB โ ~0 GB (CPU) โ
|
| 411 |
+
โ 3ไปปๅกๅนถๅ โ {concurrent_3_cpu if 'concurrent_3_cpu' in dir() else 0:>6.1f}% โ {concurrent_3_mem if 'concurrent_3_mem' in dir() else 0:>6.1f} GB โ ~0 GB (CPU) โ
|
| 412 |
+
โ GPUๅๅฒไปปๅก โ ~50% โ ~8 GB โ {gpu_seg_peak:>6.1f} GB โ
|
| 413 |
+
โโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโค
|
| 414 |
+
โ ๆจ่็กฌไปถ้
็ฝฎ โ
|
| 415 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
| 416 |
+
โ ๆไฝ้
็ฝฎ (ๅไปปๅก): 4ๆ ธ CPU, 8GB ๅ
ๅญ, ๆ ้GPU โ
|
| 417 |
+
โ ๆ ๅ้
็ฝฎ (2ๅนถๅ): 8ๆ ธ CPU, 16GB ๅ
ๅญ, 12GB GPU (ๅฏ้) โ
|
| 418 |
+
โ ๆจ่้
็ฝฎ (3ๅนถๅ): 16ๆ ธ CPU, 32GB ๅ
ๅญ, 24GB GPU โ
|
| 419 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 420 |
+
""")
|
| 421 |
+
|
| 422 |
+
print("โ
ๅๅๆต่ฏๅฎๆ!")
|
| 423 |
+
|
| 424 |
+
|
| 425 |
+
if __name__ == "__main__":
|
| 426 |
+
main()
|
| 427 |
+
|
| 428 |
+
|