Chuyển đến nội dung chính

醫療領域的AI:從診斷到治療的全面革命

Duy Tran35 分鐘
醫療領域的AI:從診斷到治療的全面革命

1. 概覽:AI如何重塑醫療產業

全球醫療體系面臨一個悖論:人口老化、疾病日趨複雜,而專科醫師的供應卻跟不上需求。美國預計到2034年將短缺12萬4,000名醫師。越南的每萬人醫師比約為9人——遠低於WHO建議的25人。

AI不是要取代醫師——AI是醫師的能力放大器。

1.1. 市場規模

年份全球醫療AI市場規模
2023192億7,000萬美元
2024266億9,000萬美元
2026約450億美元
20301,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 Inception0.991與21位皮膚科醫師相當
糖尿病視網膜病變DeepMind0.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 5Intuitive力回饋、組織追蹤
Hugo RASMedtronic雲端連接、效能數據
VersiusCMR Surgical小型化、模組化
MakoStryker術前規劃、即時引導
TouchSurgeryJ&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 ResearchVinDr-CXR(AI胸部X光)在MICCAI發表,18種病變AUC 0.88,現用於Vinmec
VinBrainDrAid™獲CE標誌的放射AI,部署於越南40+家醫院 + 出口
VNPT HealthConnect遠端醫療 + AI分診200萬用戶
百邁醫院AI心電圖判讀與CardioAI合作,心房顫動偵測
FPT SoftwareAI病理與Roche合作,組織樣本分析
Zalo AIPhoBERT 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 2Google文本(醫療問答)5,400億參數,USMLE 86.5%
GPT-4V for RadiologyOpenAI影像 + 文本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年。