1. 概覽:AI如何重塑醫療產業
全球醫療體系面臨一個悖論:人口老化、疾病日趨複雜,而專科醫師的供應卻跟不上需求。美國預計到2034年將短缺12萬4,000名醫師。越南的每萬人醫師比約為9人——遠低於WHO建議的25人。
AI不是要取代醫師——AI是醫師的能力放大器。
1.1. 市場規模
| 年份 | 全球醫療AI市場規模 |
|---|---|
| 2023 | 192億7,000萬美元 |
| 2024 | 266億9,000萬美元 |
| 2026 | 約450億美元 |
| 2030 | 1,879億5,000萬美元 |
年複合成長率約38.5%——是科技業成長率最高的領域之一。
1.2. 主要應用類別
醫療AI
├── 診斷
│ ├── 醫療影像(X光、CT、MRI、病理)
│ ├── 臨床決策支援
│ └── 症狀檢查
├── 治療
│ ├── 治療計畫
│ ├── 機器人手術
│ └── 放射治療計畫
├── 新藥研發
│ ├── 靶點識別
│ ├── 分子生成
│ └── 臨床試驗優化
├── 基因組學與精準醫療
│ ├── 變異體分析
│ ├── 基因表達分析
│ └── 藥物基因組學
├── 患者管理
│ ├── EHR分析(NLP)
│ ├── 遠端患者監測
│ └── 再入院預測
└── 行政管理
├── 醫療編碼(ICD-10/11)
├── 保險理賠處理
└── 預約排程
2. 醫療影像AI
2.1. 為什麼醫療影像是深度學習的「黃金問題」
醫療影像具備CNNs的理想特性:
- 需要模式識別的非結構化數據——深度學習的核心優勢
- 數據量龐大:500床醫院每天產生約50GB的DICOM影像
- 相對明確的標準答案:組織病理學結果與手術提供確定性標籤
- 可量化的專家錯誤率:約4%的胸部X光被誤讀;28%的皮膚癌最初被誤診
2.2. 醫療影像的CNN架構
ResNet / DenseNet是醫療影像中最常見的骨幹網路,原因如下:
- 跳躍連接解決深層網路的梯度消失問題
- 具有特徵重用的DenseNet在數據有限時表現尤為出色
import torch
import torch.nn as nn
from torchvision import models
class ChestXRayClassifier(nn.Module):
"""
胸部X光分類模型,針對14種病變
(肺炎、胸腔積液、肺不張等)
"""
def __init__(self, num_classes=14, pretrained=True):
super().__init__()
# 從ImageNet遷移學習——減少80%所需數據
self.backbone = models.densenet121(pretrained=pretrained)
# 替換最終分類器
in_features = self.backbone.classifier.in_features
self.backbone.classifier = nn.Sequential(
nn.Dropout(p=0.5),
nn.Linear(in_features, 512),
nn.ReLU(),
nn.Dropout(p=0.3),
nn.Linear(512, num_classes),
nn.Sigmoid() # 多標籤:患者可能同時患有多種疾病
)
def forward(self, x):
return self.backbone(x)
# 多標籤分類的損失函數
# 加權BCELoss處理類別不平衡(罕見的疝氣 vs 常見的無異常發現)
class WeightedBCELoss(nn.Module):
def __init__(self, pos_weights):
super().__init__()
self.pos_weights = pos_weights
def forward(self, pred, target):
return nn.functional.binary_cross_entropy(
pred, target,
weight=self.pos_weights.unsqueeze(0).expand_as(target)
)
數據增強尤為重要——醫療數據集通常小且不平衡:
from torchvision import transforms
import albumentations as A
from albumentations.pytorch import ToTensorV2
# 增強必須「醫學上合理」——切勿垂直翻轉胸部X光!
train_transform = A.Compose([
A.RandomRotate90(p=0.0), # 不進行90°旋轉(心臟不在右側)
A.Rotate(limit=10, p=0.5), # 僅小幅度±10°旋轉
A.HorizontalFlip(p=0.5), # 可行:胸部水平翻轉
A.RandomBrightness(limit=0.2),
A.RandomContrast(limit=0.2),
A.GaussNoise(var_limit=(0, 25)),
A.Resize(224, 224),
A.Normalize(
mean=[0.485, 0.456, 0.406], # ImageNet均值(灰階→3通道)
std=[0.229, 0.224, 0.225]
),
ToTensorV2()
])
2.3. 醫療影像AI的真實世界成果
| 應用場景 | 模型 | AUC | 與醫師比較 |
|---|---|---|---|
| 胸部X光(14種病變) | CheXNet(史丹佛) | 0.90 | 超越4位放射科醫師 |
| 皮膚癌(黑色素瘤) | Google Inception | 0.991 | 與21位皮膚科醫師相當 |
| 糖尿病視網膜病變 | DeepMind | 0.997 | 與專科醫師相當 |
| 大腸息肉(大腸鏡) | GI Genius | +14%檢出率 | 輔助而非取代 |
| 腦部MRI判讀 | AI Radiology | 約95%準確率 | 快40倍 |
2.4. 分割——腫瘤邊界描繪
偵測腫瘤只是第一步。分割(精確描繪邊界)對放射治療和手術至關重要:
# U-Net——醫療影像分割的黃金標準架構
class UNet(nn.Module):
"""
具有跳躍連接的U-Net,用於腫瘤分割
輸入:512x512 CT影像,輸出:512x512遮罩(0=背景,1=腫瘤)
"""
def __init__(self, in_channels=1, out_channels=1, features=[64, 128, 256, 512]):
super().__init__()
self.encoder = nn.ModuleList()
self.decoder = nn.ModuleList()
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
# 編碼器(收縮路徑)
for feature in features:
self.encoder.append(self._double_conv(in_channels, feature))
in_channels = feature
# 瓶頸層
self.bottleneck = self._double_conv(features[-1], features[-1] * 2)
# 解碼器(擴張路徑)與跳躍連接
for feature in reversed(features):
self.decoder.append(
nn.ConvTranspose2d(feature * 2, feature, kernel_size=2, stride=2)
)
self.decoder.append(self._double_conv(feature * 2, feature))
self.final_conv = nn.Conv2d(features[0], out_channels, kernel_size=1)
def _double_conv(self, in_ch, out_ch):
return nn.Sequential(
nn.Conv2d(in_ch, out_ch, 3, padding=1, bias=False),
nn.BatchNorm2d(out_ch),
nn.ReLU(inplace=True),
nn.Conv2d(out_ch, out_ch, 3, padding=1, bias=False),
nn.BatchNorm2d(out_ch),
nn.ReLU(inplace=True),
)
指標:Dice係數是醫療分割的標準指標(具有空間感知能力的F1分數)。Dice ≥ 0.85是腫瘤分割臨床上可接受的門檻。
3. AI與電子健康記錄(EHR / EMR)
3.1. 從醫療文本中提取資訊的NLP
90%的臨床資訊存在於非結構化文本中——醫師的病歷記錄、敘述性檢查結果、出院摘要。NLP將這些文本轉換為結構化數據:
import spacy
from transformers import AutoTokenizer, AutoModelForTokenClassification
import torch
# BioBERT / ClinicalBERT——在PubMed + MIMIC-III上預訓練的BERT
# 理解醫療術語的能力比標準BERT強40–60%
model_name = "dmis-lab/biobert-base-cased-v1.2"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForTokenClassification.from_pretrained(
model_name,
num_labels=9 # B/I/O for: 疾病、藥物、劑量、症狀
)
def extract_medical_entities(clinical_note: str) -> dict:
"""
從臨床記錄中提取:疾病、藥物、劑量、症狀
輸入: 「患者有高血壓,服用氨氯地平5mg/日,
訴頭痛和頭暈。」
輸出: {
"diseases": ["高血壓"],
"drugs": ["氨氯地平"],
"dosages": ["5mg/日"],
"symptoms": ["頭痛", "頭暈"]
}
"""
inputs = tokenizer(
clinical_note,
return_tensors="pt",
truncation=True,
max_length=512
)
with torch.no_grad():
outputs = model(**inputs)
predictions = torch.argmax(outputs.logits, dim=2)
tokens = tokenizer.convert_ids_to_tokens(inputs["input_ids"][0])
# 合併子詞tokens並提取實體
entities = {"diseases": [], "drugs": [], "dosages": [], "symptoms": []}
# ... (NER後處理邏輯)
return entities
3.2. 30天再入院預測
30天再入院率是重要的醫院品質指標。AI預測哪些患者處於高風險,以便進行主動干預:
import pandas as pd
from sklearn.ensemble import GradientBoostingClassifier, RandomForestClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
import xgboost as xgb
# 從EHR進行特徵工程
def create_readmission_features(patient_df: pd.DataFrame) -> pd.DataFrame:
features = pd.DataFrame()
# 人口統計特徵
features["age"] = patient_df["age"]
features["age_squared"] = patient_df["age"] ** 2 # 非線性年齡效應
# 臨床嚴重程度
features["num_diagnoses"] = patient_df["diagnoses"].apply(len)
features["num_procedures"] = patient_df["procedures"].apply(len)
features["icu_days"] = patient_df["icu_stay_days"]
features["los_days"] = patient_df["length_of_stay"]
# 檢驗值(趨勢比絕對值更重要)
features["hba1c_latest"] = patient_df["hba1c"].apply(lambda x: x[-1] if x else None)
features["hba1c_trend"] = patient_df["hba1c"].apply(
lambda x: (x[-1] - x[-2]) if len(x) >= 2 else 0
)
# 健康的社會決定因素(SDOH)——日益重要
features["insurance_type"] = patient_df["insurance"].map({
"Medicare": 2, "Medicaid": 3, "Private": 0, "Uninsured": 4
})
features["discharge_to_home"] = (patient_df["discharge_destination"] == "Home").astype(int)
# 過往就醫記錄
features["prior_admissions_1yr"] = patient_df["admissions_12m"]
features["prior_er_visits"] = patient_df["er_visits_12m"]
return features
# 集成模型
readmission_model = Pipeline([
("scaler", StandardScaler()),
("xgb", xgb.XGBClassifier(
n_estimators=500,
max_depth=6,
learning_rate=0.05,
subsample=0.8,
colsample_bytree=0.8,
scale_pos_weight=3, # 處理類別不平衡(10-20%再入院)
eval_metric="aucpr",
random_state=42
))
])
真實世界結果:UCSF部署了類似模型,將心臟病患者30天再入院率降低30%——每位患者節省約4,500美元。
3.3. 敗血症早期偵測
敗血症每年在美國奪走27萬人的生命。提早1小時偵測可將存活率提升7%:
import numpy as np
from typing import List, Dict
# 用於即時生命徵象時間序列分析的LSTM
import torch.nn as nn
class SepsisEarlyWarning(nn.Module):
"""
分析即時生命徵象序列的LSTM模型
每小時輸入:心率、血壓(收縮壓/舒張壓)、體溫、呼吸率、SpO2、WBC、乳酸、肌酐
輸出:未來6小時內發生敗血症的概率
"""
def __init__(self, input_size=8, hidden_size=128, num_layers=2):
super().__init__()
self.lstm = nn.LSTM(
input_size=input_size,
hidden_size=hidden_size,
num_layers=num_layers,
batch_first=True,
dropout=0.3,
bidirectional=False # 因果性:僅使用過去數據
)
self.attention = nn.MultiheadAttention(
embed_dim=hidden_size,
num_heads=8,
dropout=0.1
)
self.classifier = nn.Sequential(
nn.Linear(hidden_size, 64),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(64, 1),
nn.Sigmoid()
)
def forward(self, x, mask=None):
# x: [批次, 時間步, 特徵]
lstm_out, _ = self.lstm(x)
# 注意力機制,聚焦於最重要的時間步
attn_out, _ = self.attention(
lstm_out.transpose(0, 1),
lstm_out.transpose(0, 1),
lstm_out.transpose(0, 1),
key_padding_mask=mask
)
# 使用最終輸出
output = self.classifier(attn_out[-1])
return output
Epic敗血症模型(部署於美國170多家醫院)的AUC約為0.76,能提前9–12小時偵測敗血症。
4. AI在新藥研發領域的應用
4.1. 問題:龐大的成本與時間
傳統新藥研發流程:
靶點識別 → 苗頭化合物發現 → 先導化合物優化 →
臨床前研究 → I期臨床 → II期臨床 → III期臨床 → FDA核准
時程:12–15年
成本:13–26億美元
成功率:約0.01%(10,000個化合物中有1個)
AI將早期階段從4–6年壓縮至12–18個月。
4.2. AlphaFold 2——蛋白質折疊的革命
蛋白質折疊問題存在了50年:給定氨基酸序列→預測3D結構。
3D結構決定了蛋白質功能以及藥物分子的結合能力。
# 透過ColabFold使用AlphaFold2
from colabfold.batch import get_queries, run
# 目標蛋白質序列(例:SARS-CoV-2刺突蛋白)
sequence = """
MFVFLVLLPLVSSQCVNLTTRTQLPPAYTNSFTRGVYYPDKVFRSSVLHSTQDLFLPFFSNVTWFHAIHVSGTNG
TKRFDNPVLPFNDGVYFASTEKSNIIRGWIFGTTLDSKTQSLLIVNNATNVVIKVCEFQFCNDPFLGVYYHKNNK
SWMESEFRVYSSANNCTFEYVSQPFLMDLEGKQGNFKNLREFVFKNIDGYFKIYSKHTPINLVRDLPQGFSALEP
"""
queries = [("SARSCoV2_Spike", sequence, None)]
results = run(
queries=queries,
result_dir="./alphafold_results",
use_templates=False,
num_recycles=3, # 提升準確度的循環步數
model_type="alphafold2_ptm",
num_models=5
)
# 輸出:含3D座標的PDB文件 + 每個殘基的置信度(pLDDT分數)
# pLDDT > 90:非常高的置信度——適合藥物設計使用
AlphaFold 2以中位數TM分數0.92預測結構——幾乎與X射線晶體學的實驗結果相當,但快了10萬倍。
4.3. 用於新藥分子設計的生成式AI
獲得靶點結構後,下一步是生成能與靶點結合的藥物分子:
import torch
from rdkit import Chem
from rdkit.Chem import AllChem, Descriptors
# 用於分子表示的圖神經網路
# 原子 = 節點,化學鍵 = 邊
class MoleculeGNN(nn.Module):
"""
預測藥物-靶點結合親和力(pIC50)
結合分子圖 + 蛋白質口袋指紋
"""
def __init__(self, atom_features=74, bond_features=12, hidden_dim=256):
super().__init__()
# 訊息傳遞神經網路
self.conv1 = nn.Linear(atom_features, hidden_dim)
self.conv2 = nn.Linear(hidden_dim, hidden_dim)
self.conv3 = nn.Linear(hidden_dim, hidden_dim)
# 蛋白質結合位點編碼器
self.protein_encoder = nn.Sequential(
nn.Linear(1000, 512), # 蛋白質序列特徵
nn.ReLU(),
nn.Linear(512, 256)
)
# 結合親和力預測器
self.predictor = nn.Sequential(
nn.Linear(hidden_dim + 256, 512),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(512, 1) # 預測pIC50
)
def forward(self, molecule_graph, protein_features):
# 圖卷積學習分子表示
mol_repr = self.graph_conv(molecule_graph)
# 蛋白質結合位點表示
protein_repr = self.protein_encoder(protein_features)
# 組合並預測
combined = torch.cat([mol_repr, protein_repr], dim=-1)
return self.predictor(combined)
# 目標導向的分子設計
# 使用強化學習:同時優化多個目標
def multi_objective_drug_design():
"""
同時優化:
- 對靶蛋白的高結合親和力
- 良好的ADMET(吸收、分布、代謝、排泄、毒性)
- 藥物相似性(Lipinski的五規則)
- 可合成性(實驗室合成的難易度)
"""
objectives = {
"binding_affinity": lambda mol: predict_binding(mol), # 最大化
"toxicity": lambda mol: predict_toxicity(mol), # 最小化
"solubility": lambda mol: predict_logS(mol), # 優化
"synthetic_accessibility": lambda mol: SAscore(mol), # 最小化
"drug_likeness": lambda mol: QEDscore(mol), # 最大化
}
return objectives
4.4. 案例研究:Insilico Medicine
- 2019年:Insilico Medicine使用AI設計針對特發性肺纖維化(IPF)的INS018_055
- 2021年:從啟動算起僅18個月即進入I期臨床試驗
- 2023年:II期臨床顯示有希望的結果——這是第一個99%由AI設計、進入臨床試驗的藥物
相比之下,傳統方式達到相同階段通常需要4–6年。
5. 基因組學與精準醫療
5.1. 單核苷酸多態性(SNP)與疾病
每個人的DNA在約300萬個位置(SNP)上存在差異。特定SNP與以下情況直接相關:
- 疾病風險:BRCA1/2突變→乳腺癌風險70–80%
- 藥物反應:CYP2C19變異體→影響氯吡格雷的代謝
- 最適劑量:VKORC1變異體→決定安全的華法林劑量
import numpy as np
from sklearn.linear_model import LassoCV
from sklearn.preprocessing import StandardScaler
# 多基因風險評分(PRS)——將數百萬個小SNP匯總成整體風險
def compute_polygenic_risk_score(
genotype_matrix: np.ndarray, # 形狀:[個體數, SNP數]
effect_sizes: np.ndarray, # 來自GWAS的Beta係數
allele_frequencies: np.ndarray
) -> np.ndarray:
"""
PRS = Σ (effect_size_i × genotype_i)
心血管疾病PRS示例(基於約660萬個SNP)
PRS前1%的個體比平均水平高出3倍的心臟病發作風險
"""
# 標準化基因型
scaler = StandardScaler()
standardized = scaler.fit_transform(genotype_matrix)
# 加權求和
prs = standardized @ effect_sizes
# 轉換為百分位數
percentile = (np.argsort(np.argsort(prs)) / len(prs)) * 100
return prs, percentile
# 藥物基因組學:個人化用藥
def warfarin_dosing_recommendation(patient_data: dict) -> float:
"""
結合ML與臨床因素的IWPC演算法
輸入:年齡、身高、體重、適應症,
CYP2C9基因型(*1/*1、*1/*2、*1/*3、*2/*2、*2/*3、*3/*3),
VKORC1基因型(-1639G>A)
輸出:建議的華法林劑量 mg/週
"""
# VKORC1 -1639 G>A:AA降低劑量35%,GA降低20%
vkorc1_factor = {
"GG": 1.0,
"GA": 0.80,
"AA": 0.65
}.get(patient_data["vkorc1"], 1.0)
# CYP2C9:*2、*3變異體降低代謝→需要更低劑量
cyp2c9_factor = {
"*1/*1": 1.0, "*1/*2": 0.75, "*1/*3": 0.50,
"*2/*2": 0.50, "*2/*3": 0.30, "*3/*3": 0.15
}.get(patient_data["cyp2c9"], 1.0)
# ML模型的基礎劑量
base_dose = predict_base_dose(patient_data)
return base_dose * vkorc1_factor * cyp2c9_factor
5.2. 用於基因組序列的Transformer
# DNA BERT——在人類全基因組上預訓練的BERT
# 標記化:6-mer(ATCGGA、TCGGAT、...)
from transformers import AutoTokenizer, AutoModel
dna_bert = AutoModel.from_pretrained("zhihan1996/DNA_bert_6")
dna_tokenizer = AutoTokenizer.from_pretrained("zhihan1996/DNA_bert_6")
def analyze_regulatory_sequence(dna_sequence: str) -> dict:
"""
預測基因組DNA序列中的啟動子區域、增強子、剪接位點
"""
# 標記化為重疊的6-mer
kmers = [
dna_sequence[i:i+6]
for i in range(0, len(dna_sequence) - 5)
]
kmer_sentence = " ".join(kmers)
inputs = dna_tokenizer(
kmer_sentence,
return_tensors="pt",
max_length=512,
truncation=True
)
with torch.no_grad():
outputs = dna_bert(**inputs)
# 序列級別表示
sequence_embedding = outputs.last_hidden_state[:, 0, :]
return {
"embedding": sequence_embedding,
# 下游:分類啟動子、外顯子/內含子、轉座子...
}
6. 醫療NLP:從文本到知識
6.1. 完整的臨床NLP流程
原始臨床文本
↓
句子分割(比標準NLP更複雜:
「pt c/o SOB, DOE x 3d. PMH: HTN, DM2.」——專業縮寫!)
↓
命名實體識別(NER)
→ 疾病(UMLS代碼)
→ 藥物(RxNorm代碼)
→ 手術操作(CPT/ICD代碼)
→ 檢驗值 + 單位
→ 解剖(身體部位)
↓
關係提取
→ 藥物-疾病(治療、禁忌症)
→ 藥物相互作用
→ 發現-解剖
↓
時間推理
→ 事件時間線(發作、持續時間、消退)
→ 疾病進展
↓
結構化知識圖譜
6.2. 使用LLM的醫療問答
from openai import OpenAI
client = OpenAI()
MEDICAL_SYSTEM_PROMPT = """您是協助醫師進行資訊查詢的醫療助手。
重要事項:
- 僅基於循證醫學(RCT、系統性回顧、臨床指南)回答
- 始終引用來源(UpToDate、PubMed、ACC/AHA指南...)
- 按照ACC/AHA分級明確區分「證據等級A/B/C」
- 不得直接診斷特定患者
- 不確定時說「我不確定」並建議諮詢專科醫師
醫師使用此工具:查詢指南、計算臨床評分(CHADS2、Wells評分...)、藥物相互作用、治療方案。"""
def clinical_decision_support(
clinical_question: str,
patient_context: str = None
) -> str:
messages = [
{"role": "system", "content": MEDICAL_SYSTEM_PROMPT}
]
if patient_context:
messages.append({
"role": "user",
"content": f"臨床脈絡:{patient_context}\n\n問題:{clinical_question}"
})
else:
messages.append({"role": "user", "content": clinical_question})
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
temperature=0.1, # 低溫以避免幻覺——在醫療領域極為重要
max_tokens=2000
)
return response.choices[0].message.content
# 使用示例
answer = clinical_decision_support(
clinical_question="非瓣膜性心房顫動的抗凝治療方案?",
patient_context="68歲男性,CrCl 45 mL/分,HAS-BLED評分2,CHADS2-VASc評分4"
)
關於醫療領域LLM的重要注意事項:GPT-4在USMLE第1–3步達到90%以上,但仍可能「幻覺」醫療資訊。任何臨床應用都需要人工審核和嚴格驗證。
7. 遠端患者監測(RPM)
7.1. RPM系統架構
IoT穿戴式設備(Apple Watch、CGM、智慧貼片)
↓ (BLE/WiFi)
邊緣處理(手機/集線器) ← AI:去噪、心律不整偵測
↓ (HTTPS/MQTT)
雲端接入(Kafka/Kinesis)
↓
串流處理(Flink/Spark Streaming) ← AI:異常偵測
↓
├── 警報引擎(規則型 + ML混合)
│ → 簡訊/推播/電話通知醫師
├── 趨勢分析
│ → 每週/每月報告給醫師
└── 預測模型
→ 提前24–48小時預測病情惡化
7.2. 從PPG偵測心房顫動
傳統上,診斷心房顫動需要12導聯心電圖。AI可以從PPG(光電容積描記法)——智慧手錶上的心率感測器——偵測心房顫動:
import numpy as np
from scipy.signal import butter, filtfilt
import torch.nn as nn
class AFibDetectorFromPPG(nn.Module):
"""
從PPG(光電容積描記法)訊號偵測心房顫動
輸入:100Hz的30秒PPG訊號 = 3,000個樣本
輸出:心房顫動概率
FDA 510(k)清關——Apple Watch Series 9使用類似架構
"""
def __init__(self):
super().__init__()
# 用於從時間序列提取特徵的1D CNN
self.feature_extractor = nn.Sequential(
nn.Conv1d(1, 32, kernel_size=7, stride=1, padding=3),
nn.BatchNorm1d(32),
nn.ReLU(),
nn.MaxPool1d(2),
nn.Conv1d(32, 64, kernel_size=5, padding=2),
nn.BatchNorm1d(64),
nn.ReLU(),
nn.MaxPool1d(2),
nn.Conv1d(64, 128, kernel_size=3, padding=1),
nn.BatchNorm1d(128),
nn.ReLU(),
nn.AdaptiveAvgPool1d(32)
)
# 用於長程依賴的Transformer編碼器
encoder_layer = nn.TransformerEncoderLayer(
d_model=128, nhead=8, dropout=0.1, batch_first=True
)
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=4)
self.classifier = nn.Sequential(
nn.Linear(128 * 32, 256),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(256, 1),
nn.Sigmoid()
)
def forward(self, ppg_signal):
# ppg_signal: [批次, 1, 3000]
features = self.feature_extractor(ppg_signal)
# 為Transformer重塑:[批次, 序列, 特徵]
features = features.permute(0, 2, 1)
attended = self.transformer(features)
flat = attended.reshape(attended.size(0), -1)
return self.classifier(flat)
def preprocess_ppg(raw_ppg: np.ndarray, fs: int = 100) -> np.ndarray:
"""帶通濾波器:保留0.5–4 Hz(心率30–240 bpm)"""
b, a = butter(4, [0.5/(fs/2), 4.0/(fs/2)], btype='band')
filtered = filtfilt(b, a, raw_ppg)
# 標準化
return (filtered - filtered.mean()) / filtered.std()
結果:Apple Watch Series 9 / Series Ultra達到心房顫動偵測靈敏度98.3%、特異性99.6%——符合FDA II類醫療器材標準。
8. 機器人手術與AI輔助
8.1. 機器人手術系統
達文西手術系統(Intuitive Surgical)——部署最廣泛的手術機器人:
- 1999年至今超過700萬台手術
- 用於攝護腺、婦科、心臟、大腸直腸手術
- AI整合:顫抖過濾、力回饋、動作縮放
最新趨勢:
| 系統 | 公司 | AI功能 |
|---|---|---|
| da Vinci 5 | Intuitive | 力回饋、組織追蹤 |
| Hugo RAS | Medtronic | 雲端連接、效能數據 |
| Versius | CMR Surgical | 小型化、模組化 |
| Mako | Stryker | 術前規劃、即時引導 |
| TouchSurgery | J&J | 手術模擬 + AI教學輔導 |
8.2. 手術階段辨識
AI監控手術影片以識別當前階段,支援教學輔導和錯誤偵測:
# 腹腔鏡膽囊切除術有7個標準階段
CHOLEC_PHASES = [
"準備", "卡洛三角解剖",
"夾閉切斷", "膽囊解剖",
"膽囊包裝", "清潔凝血",
"膽囊取出"
]
class SurgicalPhaseRecognizer(nn.Module):
"""
基於影片的手術階段辨識
輸入:25fps手術影片
輸出:當前階段 + 置信度
"""
def __init__(self, num_phases=7):
super().__init__()
# ResNet50提取影格特徵
backbone = models.resnet50(pretrained=True)
self.frame_encoder = nn.Sequential(*list(backbone.children())[:-1])
# LSTM對時間脈絡建模(30秒滑動窗口)
self.temporal_model = nn.LSTM(
input_size=2048, # ResNet50輸出
hidden_size=512,
num_layers=2,
batch_first=True,
dropout=0.3
)
self.classifier = nn.Linear(512, num_phases)
def forward(self, video_frames):
# video_frames: [批次, 影格, C, H, W]
batch, frames = video_frames.shape[:2]
# 編碼每一影格
frame_features = []
for i in range(frames):
feat = self.frame_encoder(video_frames[:, i])
frame_features.append(feat.squeeze())
frame_features = torch.stack(frame_features, dim=1)
# 時間建模
lstm_out, _ = self.temporal_model(frame_features)
phase_logits = self.classifier(lstm_out)
return phase_logits # [批次, 影格, num_phases]
9. 技術挑戰與倫理議題
9.1. 數據挑戰
醫療數據是「黃金數據」,但極難取得:
| 挑戰 | 具體問題 | 解決方案 |
|---|---|---|
| 隱私 | HIPAA(美國)、GDPR(歐盟)、第13/2023號法令(越南) | 去識別化、聯邦學習 |
| 類別不平衡 | 罕見疾病:1:1,000,甚至1:100,000 | 過採樣(SMOTE)、代價敏感學習、單樣本學習 |
| 標籤雜訊 | 不同醫師對X光有不同解讀 | 評分者間信賴度、軟標籤 |
| 分布偏移 | 在美國訓練的模型→在越南部署效果不同 | 域適應、定期重新訓練 |
| 小數據集 | 罕見疾病可能只有幾百個案例 | 遷移學習、數據增強、合成數據(GAN) |
| 多模態 | 結合影像 + 文本 + 結構化數據 | 多模態融合架構 |
聯邦學習——保護隱私的訓練解決方案:
"""
聯邦學習:每家醫院訓練本地模型,
將梯度(非數據)發送到中央伺服器進行匯聚。
患者數據永遠不會離開醫院。
"""
# FedAvg演算法(McMahan et al., 2017)
def federated_averaging(
global_model_weights: dict,
client_updates: list[dict],
client_sample_counts: list[int]
) -> dict:
"""
客戶端模型更新的加權平均
權重 = 每個客戶端的樣本數
"""
total_samples = sum(client_sample_counts)
avg_weights = {}
for key in global_model_weights.keys():
# 加權平均
avg_weights[key] = sum(
client_update[key] * (n / total_samples)
for client_update, n in zip(client_updates, client_sample_counts)
)
return avg_weights
9.2. 醫療AI中的偏見
偏見在醫療領域是更嚴重的問題,因為它直接影響健康結果:
- 脈搏血氧儀偏見:設備對黑人患者的準確度低3倍——導致COVID-19期間氧氣治療不足
- 皮膚科AI偏見:主要在較淺膚色上訓練的CheXNet→對黑人/棕色皮膚準確度較低
- 疼痛評估AI偏見:NIH疼痛聯盟發現AI低估了女性的疼痛
- 風險評分偏見:OPTUM敗血症模型對黑人患者的效能低4.5%
# 醫療AI中需要測量的公平性指標
from fairlearn.metrics import (
demographic_parity_difference,
equalized_odds_difference,
MetricFrame
)
import pandas as pd
def evaluate_fairness(
model_predictions: np.ndarray,
true_labels: np.ndarray,
sensitive_attributes: pd.DataFrame # 種族、性別、年齡組、保險
):
"""
評估多個人口統計群體間的公平性
目標:
- 人口統計均等差異 < 0.05
- 均等化勝算差異 < 0.05
- 各群體間的AUC差距 < 0.02
"""
metrics = {
"accuracy": lambda y, pred: (pred.round() == y).mean(),
"false_negative_rate": lambda y, pred: ((pred.round() == 0) & (y == 1)).sum() / y.sum(),
# 醫療中FNR很重要:漏診比誤診更危險
}
mf = MetricFrame(
metrics=metrics,
y_true=true_labels,
y_pred=model_predictions,
sensitive_features=sensitive_attributes
)
print("各群體效能:")
print(mf.by_group)
print(f"\n人口統計均等差異:{demographic_parity_difference(true_labels, model_predictions, sensitive_features=sensitive_attributes['race']):.4f}")
print(f"均等化勝算差異:{equalized_odds_difference(true_labels, model_predictions, sensitive_features=sensitive_attributes['race']):.4f}")
return mf
9.3. 醫療AI的可解釋性
黑盒問題:醫師無法接受無法解釋的決策——「AI說患者有癌症,但為什麼?」
import shap
import numpy as np
# SHAP(SHapley加法解釋)——解釋局部預測
def explain_readmission_prediction(
model,
patient_features: pd.DataFrame,
feature_names: list
):
"""
解釋為什麼模型預測這位患者的再入院風險高
輸出:「高風險原因:
- 肌酐 2.8 mg/dL(+0.23風險評分)
- 過去一年3次住院記錄(+0.18)
- 回家無家庭照護者(+0.12)
- 年齡78歲(+0.09)」
"""
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(patient_features)
# 每位特定患者的瀑布圖
shap.waterfall_plot(
shap.Explanation(
values=shap_values[0],
base_values=explainer.expected_value,
data=patient_features.iloc[0],
feature_names=feature_names
)
)
# 前5個最具影響力的因素
feature_importance = sorted(
zip(feature_names, shap_values[0]),
key=lambda x: abs(x[1]),
reverse=True
)
return feature_importance[:5]
9.4. 監管框架
| 地區 | 法規 | AI醫療器材要求 |
|---|---|---|
| 美國 | FDA 510(k) / De Novo / PMA | 軟體即醫療器材(SaMD)分類、臨床驗證 |
| 歐盟 | EU AI法案 + MDR 2017/745 | 高風險AI:合格評估、CE標誌、上市後監督 |
| 越南 | 第98/2021號法令 + 第46/2017號通知 | 醫療器材分類A/B/C/D、衛生部登記 |
10. 越南的醫療AI
10.1. 現況
越南特有的挑戰:
- 公立醫院系統數位化不足:不足30%的省級醫院擁有完整的HIS
- 數據碎片化、非標準化:各醫院使用不同軟體
- 缺乏標記的越南語醫療NLP數據
- 醫療工作者缺乏數位技能
優勢:
- 年輕人口,智慧型手機普及率高(>70%)
- 醫療成本低→高AI投資報酬率
- 主要醫院(百邁、朱萊)患者量龐大→豐富數據
10.2. 值得關注的項目與新創企業
| 機構 | 項目 | 成果 |
|---|---|---|
| VinAI Research | VinDr-CXR(AI胸部X光) | 在MICCAI發表,18種病變AUC 0.88,現用於Vinmec |
| VinBrain | DrAid™ | 獲CE標誌的放射AI,部署於越南40+家醫院 + 出口 |
| VNPT HealthConnect | 遠端醫療 + AI分診 | 200萬用戶 |
| 百邁醫院 | AI心電圖判讀 | 與CardioAI合作,心房顫動偵測 |
| FPT Software | AI病理 | 與Roche合作,組織樣本分析 |
| Zalo AI | PhoBERT for Healthcare | 醫療記錄的越南語NLP |
10.3. VinDr-CXR——詳細案例研究
# VinDr-CXR數據集:18,000張胸部X光,由17位放射科醫師標注
# 發布於:https://www.nature.com/articles/s41597-022-01498-w
VINDR_FINDINGS = [
"主動脈擴張", "肺不張", "鈣化",
"心臟擴大", "鎖骨骨折", "實變",
"水腫", "肺氣腫", "肺動脈擴張", "間質性肺病",
"浸潤", "肺部混濁", "結節/腫塊",
"其他病灶", "胸腔積液", "胸膜增厚",
"氣胸", "肺纖維化"
]
import torch
from torch.utils.data import Dataset
from PIL import Image
import pydicom
class VinDrDataset(Dataset):
def __init__(self, df, dicom_dir, transform=None):
self.df = df
self.dicom_dir = dicom_dir
self.transform = transform
def __getitem__(self, idx):
row = self.df.iloc[idx]
# 載入DICOM文件
dicom = pydicom.dcmread(f"{self.dicom_dir}/{row['image_id']}.dicom")
image = dicom.pixel_array.astype(np.float32)
# DICOM特定的前處理
image = self._apply_windowing(image, row.get("window_center"), row.get("window_width"))
image = Image.fromarray((image * 255).astype(np.uint8)).convert("RGB")
if self.transform:
image = self.transform(image)
# 多標籤目標
labels = torch.zeros(len(VINDR_FINDINGS))
for finding in row["findings"]:
if finding in VINDR_FINDINGS:
labels[VINDR_FINDINGS.index(finding)] = 1.0
return image, labels
def _apply_windowing(self, image, window_center=None, window_width=None):
"""DICOM視窗化:標準化Hounsfield單位"""
if window_center is None:
window_center = image.mean()
if window_width is None:
window_width = image.std() * 4
lower = window_center - window_width / 2
upper = window_center + window_width / 2
image = np.clip(image, lower, upper)
return (image - lower) / (upper - lower)
10.4. 越南醫療AI部署路線圖
第一階段(2024–2025年):基礎建設
├── 數據標準化:HIS的HL7 FHIR
├── 建立國家健康數據湖
└── 培訓5,000名數位健康專業人才
第二階段(2025–2027年):應用落地
├── 大規模AI篩查:X光、眼底攝影、子宮頸抹片
├── AI輔助EMR:自動編碼、臨床記錄
└── 地區醫院的遠端病理AI
第三階段(2027–2030年):全面整合
├── 精準醫療:藥物基因組學試點
├── AI賦能罕見疾病診斷
└── 越南健康AI基準數據集
11. 基礎模型與醫療AI的未來
11.1. 醫療基礎模型
新世代:不再訓練許多專業模型,而是訓練一個在所有醫療數據上預訓練的大型模型,然後針對每個任務進行微調:
| 模型 | 機構 | 模態 | 規模 |
|---|---|---|---|
| Med-PaLM 2 | 文本(醫療問答) | 5,400億參數,USMLE 86.5% | |
| GPT-4V for Radiology | OpenAI | 影像 + 文本 | GPT-4基礎 |
| BioMedLM | 史丹佛 | 文本(生物醫學) | 27億參數,開源 |
| CheXagent | 史丹佛 | 胸部X光 + 文本 | 放射科基礎模型 |
| Segment Anything Medical(SAM-Med) | Meta基礎 | 通用分割 | 零樣本醫療分割 |
| UniMedI | 研究 | 統一醫療影像 | 一個模型處理CT/MRI/X光 |
11.2. 多模態醫療AI
# 未來:一個模型處理所有模態
# 「患者65歲,給我所有影像 + 檢驗值 + 病史→診斷」
class MultimodalMedicalAI(nn.Module):
"""
結合:
- 醫療影像(X光、CT、MRI、病理切片)
- 結構化數據(檢驗值、生命徵象、人口統計)
- 臨床文本(醫師記錄、出院摘要)
- 基因組學(SNP陣列、全基因組定序)
- 穿戴式數據(心電圖、持續血糖監測)
"""
def __init__(self):
super().__init__()
# 醫療影像的視覺編碼器
self.image_encoder = MedicalImageEncoder() # 基於ViT
# 臨床記錄的文本編碼器
self.text_encoder = ClinicalBertEncoder() # BioClinicalBERT
# 結構化數據編碼器
self.tabular_encoder = TabTransformer() # Tab Transformer
# 用於融合的跨模態注意力
self.cross_attention = CrossModalAttention(
hidden_dim=768,
num_heads=12
)
# 任務特定的輸出頭
self.diagnosis_head = nn.Linear(768, num_diagnosis_codes)
self.prognosis_head = nn.Linear(768, 1) # 生存概率
self.treatment_head = nn.Linear(768, num_treatment_options)
def forward(self, images=None, text=None, structured=None, genomics=None):
embeddings = []
if images is not None:
embeddings.append(self.image_encoder(images))
if text is not None:
embeddings.append(self.text_encoder(text))
if structured is not None:
embeddings.append(self.tabular_encoder(structured))
# 跨模態融合
fused = self.cross_attention(embeddings)
return {
"diagnosis": self.diagnosis_head(fused),
"prognosis": self.prognosis_head(fused),
"treatment": self.treatment_head(fused)
}
11.3. 醫療中的數位孿生
患者數位孿生——特定患者身體的數位生理模擬:
- 心臟模擬:在手術前預測干預結果
- 個人化藥物動力學:用特定患者的藥代動力學參數模擬藥物代謝
- 腫瘤虛擬活檢:從影像數據模擬腫瘤對化療的反應
Dassault Systèmes和Siemens Healthineers正在試驗規模上部署。展望2030年。
