病灶变化预测 vs 分类:医学影像 AI 中更有价值的问题是什么?

一、前言:医学影像 AI,真的只是"分类"吗?

目前在医学影像领域,90% 的深度学习项目都停留在分类阶段

  • 良性 / 恶性

  • 有病灶 / 无病灶

  • 高风险 / 低风险

但在真实临床场景中,医生更关心的问题往往是:

病灶 有没有变大?

生长速度 快还是慢?

下一阶段 可能发展到什么程度?

这类问题,本质上已经不再是"分类问题",而是变化预测(Change Prediction)问题

本文将从建模思路 出发,并结合完整可运行的代码示例,讲清楚医学影像中"变化预测"到底应该怎么做。


二、分类任务 vs 变化预测:从数据结构就已经不同

1️⃣ 传统分类任务的数据形式

Image → Label

对应代码通常是:

image, label

模型只关心:

👉 这一刻是什么状态


2️⃣ 变化预测任务的数据形式(关键差异)

Image(t1), Image(t2) → Change

也就是:

image_t1, image_t2, delta_label

模型关心的是:

👉 从 t1 到 t2,发生了什么变化

这是后续所有建模差异的根源。


三、变化预测数据集:完整 Dataset 代码示例

下面是一个标准的变化预测 Dataset 实现(PyTorch)

python 复制代码
import torch
from torch.utils.data import Dataset
import numpy as np

class LesionChangeDataset(Dataset):
    def __init__(self, data_list):
        """
        data_list: [
            {
                't1': 'path/to/image_t1.npy',
                't2': 'path/to/image_t2.npy',
                'delta': 2.3
            },
            ...
        ]
        """
        self.data_list = data_list

    def __len__(self):
        return len(self.data_list)

    def __getitem__(self, idx):
        img_t1 = np.load(self.data_list[idx]['t1'])
        img_t2 = np.load(self.data_list[idx]['t2'])
        delta = self.data_list[idx]['delta']

        img_t1 = torch.tensor(img_t1).float().unsqueeze(0)
        img_t2 = torch.tensor(img_t2).float().unsqueeze(0)
        delta = torch.tensor(delta).float()

        return img_t1, img_t2, delta

📌 注意

变化预测不是"一个 image + 一个 label",

而是一对影像 + 一个变化标签


四、共享 CNN 特征提取器(变化预测的核心原则)

在变化预测中,有一个非常重要但经常被忽略的原则

不同时间点的影像,必须使用同一个 CNN(共享权重)

否则模型学到的是网络差异 ,而不是病灶变化


CNN 特征提取器实现

python 复制代码
import torch.nn as nn

class FeatureCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.features = nn.Sequential(
            nn.Conv2d(1, 16, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),

            nn.Conv2d(16, 32, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )

        self.fc = nn.Linear(32 * 32 * 32, 128)

    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size(0), -1)
        return self.fc(x)

五、变化建模方式一:特征差分(最推荐)

这是医学影像变化预测中最直观、最稳定的方法

1️⃣ 特征差分函数

python 复制代码
def feature_difference(f1, f2):
    return f2 - f1

2️⃣ 变化回归模型

python 复制代码
class ChangeRegressor(nn.Module):
    def __init__(self):
        super().__init__()
        self.regressor = nn.Sequential(
            nn.Linear(128, 64),
            nn.ReLU(),
            nn.Linear(64, 1)
        )

    def forward(self, x):
        return self.regressor(x)

3️⃣ 前向传播逻辑(完整)

python 复制代码
cnn = FeatureCNN()
regressor = ChangeRegressor()

f1 = cnn(img_t1)
f2 = cnn(img_t2)

diff_feature = feature_difference(f1, f2)
pred_delta = regressor(diff_feature)

📌 核心思想

模型不再"猜类别",而是直接学习变化本身


六、对比方案:特征拼接(不推荐但常见)

python 复制代码
combined_feature = torch.cat([f1, f2], dim=1)
python 复制代码
class ChangeConcatModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc = nn.Sequential(
            nn.Linear(256, 128),
            nn.ReLU(),
            nn.Linear(128, 1)
        )

    def forward(self, f1, f2):
        x = torch.cat([f1, f2], dim=1)
        return self.fc(x)

📌 实践中发现:

  • 拼接模型能学

  • 但对"变化"的表达不如差分明确


七、多时间点变化预测(进阶工程版)

真实医学随访往往是:

t1 → t2 → t3 → t4

这时可以引入 CNN + LSTM


LSTM 变化趋势模型

python 复制代码
class ChangeLSTM(nn.Module):
    def __init__(self):
        super().__init__()
        self.lstm = nn.LSTM(
            input_size=128,
            hidden_size=64,
            batch_first=True
        )
        self.fc = nn.Linear(64, 1)

    def forward(self, feature_seq):
        _, (h_n, _) = self.lstm(feature_seq)
        return self.fc(h_n[-1])

构造时间序列特征

python 复制代码
features = []
for img in images:  # 多时间点影像
    features.append(cnn(img))

feature_seq = torch.stack(features, dim=1)
pred = lstm_model(feature_seq)

📌 到这一步,模型已经能学习病灶生长趋势


八、训练代码:变化预测该怎么训?

损失函数(回归,而不是分类)

criterion = nn.MSELoss()


训练循环(完整示例)

python 复制代码
optimizer = torch.optim.Adam(
    list(cnn.parameters()) + list(regressor.parameters()),
    lr=1e-3
)

for img_t1, img_t2, delta in dataloader:
    optimizer.zero_grad()

    f1 = cnn(img_t1)
    f2 = cnn(img_t2)

    diff = f2 - f1
    pred = regressor(diff)

    loss = criterion(pred.squeeze(), delta)
    loss.backward()
    optimizer.step()

📌 如果你在这里用的是 CrossEntropyLoss

那本质上还是分类思维。


九、评估指标:为什么 Accuracy 不适合?

变化预测更适合以下指标:

python 复制代码
mae = torch.mean(torch.abs(pred - target))
rmse = torch.sqrt(torch.mean((pred - target) ** 2))
  • MAE:平均变化误差

  • RMSE:对极端增长更敏感

这比 Accuracy 更符合医学意义


十、总结:变化预测不是"高级分类"

当真正把代码写完整后会发现:

变化预测 ≠ 分类 + 换个模型

而是:

  • 数据结构不同

  • 建模思路不同

  • 评估方式不同

这一步,正是医学影像 AI 从"能跑"走向"有用"的关键

相关推荐
Sui_Network2 小时前
Walrus 2025 年度回顾
大数据·前端·人工智能·深度学习·区块链
说私域2 小时前
开源悬赏活动报名AI智能名片链动2+1模式商城小程序的应用与价值
人工智能·微信·小程序·开源
yuniko-n2 小时前
【AI】基于 LLaMa-Factory 和 LoRA 算法的大模型微调
人工智能
张彦峰ZYF2 小时前
大模型是如何工作的?从原理到通义生态的落地实践
人工智能·大模型是如何工作的?·从原理到通义生态的落地实践·大模型价值是与真实业务深度融合
jimmyleeee2 小时前
人工智能基础知识笔记三十一:Langfuse
人工智能·笔记
桂花饼2 小时前
小镜AI开放平台:Sora 2 API 低价高并发解决方案评测整理
人工智能·qwen3-next·sora2·nano banana 2·gemini-3-pro·gpt-5.2·glm-4.7
skywalk81632 小时前
小米大模型mimo-v2-flash简单接触
人工智能·小米
争不过朝夕,又念着往昔2 小时前
C++AI
开发语言·c++·人工智能
Rui_Freely2 小时前
Vins-Fusion之 TrackImage-Lukas-Kanade光流法(四)
人工智能