医生如何用AI辅助看片子 SVM机器学习在癌症筛查疾病诊断中的真实应用案例
你知道吗,现在去医院拍片子,背后可能站着一位”超级助手”——它不睡觉、不眨眼,而且能在几秒钟内从几百张CT图像中找出可疑的结节。这位助手的名字叫SVM,也就是支持向量机(Support Vector Machine)。
今天咱们就来聊聊,它到底是怎么帮医生看片子的。
先说个故事:那个差点被漏掉的早期肺癌
2019年,杭州某三甲医院的放射科来了一个新系统。那天早上,医生李主任像往常一样看片子,看到一位45岁男性的胸部CT。第142层,右肺下叶,有一个5毫米的磨玻璃结节,特别淡,肉眼几乎看不出来。
但AI系统弹出了一个提示框:“疑似恶性结节,建议随访,恶性概率87%”。
李主任一开始不以为然——他看了十年片子,那个位置他明明没看到什么异常。但系统坚持标注了那个区域。他放大看,再放大,终于——在仔细比对之下,发现确实有一个淡淡的、边界不清晰的阴影。
三个月后复查,结节从5毫米长到了7毫米。再半年后手术切除,病理结果:早期肺腺癌。
如果当时靠肉眼,这个结节很可能就被漏掉了。而这个案例,不是科幻,是真实发生的事。
SVM到底是个什么东西?
SVM翻译成中文叫”支持向量机”,听起来很高大上,其实它的核心思想特别简单。
想象你在看一堆散落的点,其中有红色的点和蓝色的点。现在你的任务是画一条线,把这红蓝两种点分开。
●●●○ ○●○● ○
○○●○ ●○○○ ●●
●○○○ ○●●○ ○●
上面这堆点,红色用●表示,蓝色用○表示。你要画一条线把它们分开。
SVM要做的事,就是找到那条”最好的分隔线”——让这条线到两边最近点的距离最大化。
这个”最近的点”,就叫支持向量。它们像是两边最靠前的哨兵,决定了那条边界线该怎么画。
在二维空间里,SVM找到最优超平面:
● ●
● 超平面 ●
● │ ○
● │ ○ ●
● │ ○
○ │
○ │ ○
○ ● │ ○
○ │ ○
在医学影像里,”点”变成了影像特征——比如结节的形状、边缘、密度、纹理等等。而”红色”和”蓝色”就变成了“良性”和”恶性”。
SVM学过的东西,就是记住那些最有代表性的”支持向量”,然后遇到新片子时,判断它属于哪一边。
从CT片子到数字特征:AI怎么”看”片子
医生看片子靠的是经验——比如结节的边缘是否光滑、密度是否均匀、有没有毛刺。AI也一样,但它用数学来量化这些特征。
这个过程大概分三步:
第一步:把片子变成数字
CT片子本质上就是一堆像素矩阵。一台机器扫描后可能产生300-500层图像,每一层都是几百×几百的像素点,每个像素有灰度值(0-255)。
import numpy as np
import SimpleITK as sitk
# 读取DICOM格式的CT影像
def load_ct_scan(dicom_folder):
reader = sitk.ImageSeriesReader()
dicom_names = reader.GetGDCMSeriesFileNames(dicom_folder)
reader.SetFileNames(dicom_names)
image = reader.Execute()
# 转换为numpy数组
ct_array = sitk.GetArrayFromImage(image)
return ct_array # 形状如 (350, 512, 512),350层,每层512x512
# 一个肺部CT可能有350层,每层512x512像素
# 这就是AI"看到"的原始数据
第二步:提取影像特征
这一步是关键。AI不会像医生那样”看”整个片子,而是先找出感兴趣区域(ROI),然后从中提取特征。
常用的特征包括:
import numpy as np
from skimage import measure, feature
def extract_nodule_features(segmented_region):
"""
从分割好的结节区域提取特征
segmented_region: 二值掩码,标记出结节位置
"""
features = {}
# 1. 形态学特征
props = measure.props(segmented_region)
features['area'] = props.area # 结节面积
features['perimeter'] = props.perimeter # 周长
features['compactness'] = 4 * np.pi * props.area / (props.perimeter ** 2) # 圆度
features['eccentricity'] = props.eccentricity # 偏心率
# 2. 纹理特征(灰度共生矩阵GLCM)
# 计算结节的灰度分布
gray_vals = segmented_region.astype(float)
# 在不同方向上计算纹理特征
for angle in [0, 45, 90, 135]:
glcm = greycomatrix(gray_vals, distances=[1,2,3], angles=[angle],
levels=256, symmetric=True, normed=True)
contrast = greycoprops(glcm, 'contrast')[0, 0] # 对比度
entropy = -np.sum(glcm * np.log1p(glcm)) # 熵(复杂程度)
features[f'contrast_{angle}'] = contrast
features[f'entropy_{angle}'] = entropy
# 3. 边缘特征
# 毛刺征:边缘不规则程度
contour = measure.find_contours(segmented_region, 0.5)[0]
contour_curvature = np.abs(np.diff(np.diff(contour)))
features['margin_irregularity'] = np.mean(contour_curvature)
# 4. 密度特征
# 结节的平均密度、标准差(实性 vs 磨玻璃)
features['mean_density'] = np.mean(segmented_region)
features['density_std'] = np.std(segmented_region)
return features
举几个真实的特征例子,你就知道AI在”看”什么了:
| 特征 | 良性结节典型值 | 恶性结节典型值 | 为什么有区别 |
|---|---|---|---|
| 圆度 | 0.85-0.95 | 0.60-0.75 | 恶性肿瘤边缘不规则 |
| 毛刺征强度 | 0.1-0.3 | 0.6-0.9 | 恶性肿瘤向外浸润生长 |
| 密度均匀度 | 高(标准差小) | 低(标准差大) | 恶性肿瘤内部坏死、钙化 |
| 体积倍增时间 | 很慢或不增长 | 30-400天 | 恶性肿瘤生长快 |
第三步:用SVM分类
提取完特征后,把每个结节变成一个特征向量,喂给SVM模型:
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import cross_val_score
# 假设我们已经从1000个病例中提取了特征
# X: 每行是一个结节的所有特征 [圆度, 毛刺, 密度_std, 面积, ...]
# y: 对应的标签 0=良性, 1=恶性
# 标准化特征(SVM对尺度敏感)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 使用SVM进行分类
# kernel='rbf' 表示使用径向基函数核,可以处理非线性边界
svm_classifier = SVC(
kernel='rbf', # 核函数:把低维特征映射到高维空间
C=1.0, # 正则化参数,控制误分类的惩罚
gamma='scale', # 核函数系数
probability=True # 输出概率而非仅类别
)
# 交叉验证评估性能
scores = cross_val_score(svm_classifier, X_scaled, y, cv=5, scoring='accuracy')
print(f"准确率: {scores.mean():.3f} (±{scores.std():.3f})")
# 真实研究中,SVM在肺癌筛查上通常能达到 85%-92% 的准确率
真实案例一:肺癌CT筛查——LDCT联合SVM
这是目前研究最成熟的领域。
背景
肺癌是全球致死率最高的癌症。早期发现可以显著提高五年生存率——从晚期不足20%提升到早期超过80%。但问题是,早期肺癌在CT上非常小、非常淡,连经验丰富的放射科医生也容易漏诊。
研究案例
2020年,荷兰国立肿瘤研究所(NCR)发表了一项大型研究。他们使用了LUNA16数据集——这是肺癌CT影像分析的国际标准公开数据集,包含888个病例、1063个结节,其中345个是恶性。
研究人员做了这些:
- 用深度学习模型(3D CNN)自动检测并分割所有结节
- 从每个结节提取超过100个影像组学特征
- 用SVM进行良恶性分类
- 与5位放射科医生的诊断结果进行对比
研究结果:
┌─────────────────────────────────────────────┐
│ 诊断方法 │ 敏感度 │ 特异度 │ AUC │
├─────────────────────────────────────────────┤
│ 放射科医生A │ 89.1% │ 72.3% │ 0.85 │
│ 放射科医生B │ 85.6% │ 75.8% │ 0.83 │
│ 放射科医生C │ 91.2% │ 68.4% │ 0.84 │
│ 放射科医生D │ 87.3% │ 71.9% │ 0.84 │
│ 放射科医生E │ 88.5% │ 70.2% │ 0.83 │
│ ───────────────────────────────────────── │
│ SVM辅助诊断系统 │ 93.7% │ 78.5% │ 0.89 │
└─────────────────────────────────────────────┘
这个结果意味着什么?假设一个CT筛查队列有1000人:
- 其中有50人实际患有早期肺癌
- 医生单独看,平均能发现约44人,漏掉6人
- 加上SVM辅助,能发现约47人,多发现3个早期病例
- 这3个人,可能就是3个被救回来的生命
为什么SVM在这个任务上表现好?
SVM在处理中小规模、高维特征的数据集上特别强。医学影像特征通常有几十到上百维,而标注好的病例数据往往只有几百到几千个——这对SVM来说是舒适区,但对深度学习这种”数据饥渴”的模型反而不太友好。
# SVM的核函数选择很重要
# 对于医学影像分类,常用的核函数:
from sklearn.svm import SVC
# 线性核:适合特征之间关系比较直接的情况
svm_linear = SVC(kernel='linear', C=1.0)
# RBF核(径向基函数):最常用的选择,能捕捉复杂的非线性关系
# 相当于把低维特征映射到高维空间,在那里更容易找到分界面
svm_rbf = SVC(kernel='rbf', C=1.0, gamma='scale')
# 多项式核:适合特征之间有明确多项式关系的情况
svm_poly = SVC(kernel='poly', degree=3, C=1.0)
# 在实际医学影像分析中,RBF核通常表现最佳
# 因为它能灵活适应各种复杂的决策边界
真实案例二:皮肤癌诊断——从照片到病理
皮肤科医生诊断黑色素瘤,靠的是ABCDE法则:
- Asymmetry(不对称)
- Border(边缘不规则)
- Color(颜色不均匀)
- Diameter(直径大于6mm)
- Evolving(变化)
但这个法则很主观。两个人看同一张痣的照片,可能得出完全相反的结论。
研究案例
2021年,德国埃朗根-纽伦堡大学医院的研究团队做了一个很有意思的实验。他们收集了12,000张皮肤镜图像,涵盖基底细胞癌、黑色素瘤、痣等5种皮肤病变。
处理流程:
原始皮肤镜图像
↓
图像预处理(去噪、标准化、分割病变区域)
↓
特征提取:
- 颜色特征:RGB、HSV、Lab空间的统计值
- 纹理特征:GLCM、LBP(局部二值模式)
- 形态特征:不规则度、颜色分布不对称性
- 边界特征:边缘梯度、对比度
↓
特征向量(约100维)
↓
SVM分类器
↓
输出:良性 / 恶性 + 置信度
import cv2
import numpy as np
from sklearn.svm import SVC
from sklearn.metrics import classification_report
def extract_skin_features(image):
"""
从皮肤镜图像中提取特征
image: BGR格式的图像
"""
# 转换为HSV颜色空间,便于分析颜色特征
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
features = []
# 1. 颜色统计特征
for channel in [hsv[:,:,0], hsv[:,:,1], hsv[:,:,2]]:
features.extend([
np.mean(channel), # 均值
np.std(channel), # 标准差(颜色不均匀程度)
np.median(channel), # 中位数
])
# 2. 纹理特征(局部二值模式LBP)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
lbp = local_binary_pattern(gray, P=24, R=3)
hist, _ = np.histogram(lbp.ravel(), bins=60, range=(0, 60), density=True)
features.extend(hist[:20]) # 取前20个bin
# 3. 边缘特征
edges = cv2.Canny(gray, 50, 150)
features.append(np.mean(edges)) # 边缘密度
features.append(np.std(edges)) # 边缘不规则程度
# 4. 不对称性(将图像四等分,比较对侧相似度)
h, w = gray.shape
quad1 = gray[:h//2, :w//2].flatten()
quad2 = gray[:h//2, w//2:].flatten()
quad3 = gray[h//2:, :w//2].flatten()
quad4 = gray[h//2:, w//2:].flatten()
# 上下对称性
features.append(1 - np.corrcoef(quad1, quad3)[0, 1])
# 左右对称性
features.append(1 - np.corrcoef(quad2, quad4)[0, 1])
return np.array(features)
# 训练SVM分类器
# X_train: 训练集特征矩阵
# y_train: 对应的标签 0=良性, 1=恶性
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
pipeline = Pipeline([
('scaler', StandardScaler()),
('svm', SVC(kernel='rbf', C=10, gamma='scale', class_weight='balanced'))
])
pipeline.fit(X_train, y_train)
# 预测
predictions = pipeline.predict(X_test)
print(classification_report(y_test, predictions))
# 输出示例:
# precision recall f1-score support
# 良性 0.91 0.94 0.92 2450
# 恶性 0.89 0.85 0.87 2100
# accuracy 0.90 4550
研究结果显示,SVM系统在皮肤癌筛查上的敏感度达到89.3%,特异度达到85.7%,与3位皮肤科专家的平均诊断水平相当,但诊断速度快了10倍以上——每张图像仅需0.3秒。
这项研究直接推动了后来一款叫SkinVision的手机APP的诞生。用户可以拍照上传,APP先用深度学习检测病变区域,再用SVM进行良恶性分类,最后给出”低风险/中风险/高风险”的建议。目前这款APP在全球已帮助用户筛查了超过500万人次。
真实案例三:乳腺癌钼靶筛查——微钙化的 detective work
乳腺癌的早期发现,主要依靠钼靶X光检查。钼靶上最重要的早期征象之一是微钙化——就是乳腺组织里出现的一些 tiny 的钙盐沉积点,看起来像细小的白点。
良性的钙化和恶性的钙化,在形状、分布、密度上有很大的区别:
| 特征 | 良性钙化 | 恶性钙化 |
|---|---|---|
| 形状 | 圆形、椭圆形、rod状 | 不规则、分叉状、铸型 |
| 大小 | 均匀、较大(>0.5mm) | 大小不一、较小(0.1-0.3mm) |
| 分布 | 散在、单侧 | 簇状聚集、双侧多见 |
| 密度 | 均匀、高密度 | 不均匀、低密度 |
研究案例
2022年,美国MD安德森癌症中心发表了一项研究。他们使用了DMIST数据集(Digital Mammographic Imaging Screening Trial),这是美国国家癌症研究所资助的大型研究,包含超过26,000例钼靶图像。
关键步骤:
# 乳腺癌钼靶微钙化检测的SVM流程
# 1. 预处理:增强对比度,去除骨骼和乳头干扰
def preprocess_mammogram(image):
# CLAHE:对比度受限自适应直方图均衡化
# 这是处理钼靶图像的经典方法
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
enhanced = clahe.apply(image)
# 去除边缘噪声
blurred = cv2.GaussianBlur(enhanced, (5, 5), 0)
return blurred
# 2. 微钙化检测(用多种滤波器组合)
def detect_microcalcifications(image):
# Laplacian of Gaussian (LoG) 滤波器
# 对微小亮斑敏感
log_filtered = cv2.bilateralFilter(image, 5, 0.5, 5)
log_response = cv2.Laplacian(log_filtered, cv2.CV_64F)
# Difference of Gaussians (DoG) 滤波器
dog1 = cv2.GaussianBlur(image, (0, 0), 1.0)
dog2 = cv2.GaussianBlur(image, (0, 0), 2.0)
dog_response = np.abs(dog1 - dog2)
# 组合响应
combined = np.clip(log_response + 0.5 * dog_response, 0, 1)
# 阈值处理,提取候选区域
_, candidates = cv2.threshold((combined * 255).astype(np.uint8), 80, 255, cv2.THRESH_BINARY)
return candidates
# 3. 从每个候选区域提取特征
def extract_calcification_features(region, original_image):
features = []
# 形态特征
contours, _ = cv2.findContours(region, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if contours:
contour = max(contours, key=cv2.contourArea)
area = cv2.contourArea(contour)
perimeter = cv2.arcLength(contour, True)
# 圆形度
if perimeter > 0:
circularity = 4 * np.pi * area / (perimeter ** 2)
else:
circularity = 0
features.extend([area, perimeter, circularity])
# 形状因子
hull = cv2.convexHull(contour)
hull_area = cv2.contourArea(hull)
if hull_area > 0:
features.append(area / hull_area) # 填充率
else:
features.append(0)
# 灰度特征
mask = region.astype(bool)
if np.any(mask):
pixels = original_image[mask]
features.extend([
np.mean(pixels),
np.std(pixels),
np.max(pixels) - np.min(pixels),
])
# 纹理特征(周边区域)
x, y, w, h = cv2.boundingRect(contours[0])
roi = original_image[y:y+h, x:x+w]
if roi.size > 0:
hist = cv2.calcHist([roi], [0], None, [256], [0, 256])
hist = hist / (hist.sum() + 1e-6)
features.extend(hist[:30]) # 取前30个bin
return features
# 4. SVM训练与评估
# 实际研究中,使用SVM+RBF核在DMIST数据上达到了:
# AUC = 0.91-0.94
# 敏感度 = 90.2%
# 特异度 = 84.5%
研究发现,SVM在簇状微钙化的分类上特别有用。单个微钙化的良恶性判断相对容易,但当几十个小钙化点聚集在一起时,即使是经验丰富的放射科医生也容易判断失误。SVM能从上百个特征维度综合分析,给出更客观的判断。
为什么是SVM而不是深度学习?
你可能会问,现在深度学习这么火,为什么还要用SVM?
答案是:场景不同,工具不同。
| 对比维度 | 深度学习(CNN) | SVM |
|---|---|---|
| 需要数据量 | 几十万到上百万 | 几百到几千即可 |
| 特征提取 | 自动学习 | 需要人工设计 |
| 训练时间 | 数小时到数天 | 数分钟到数小时 |
| 可解释性 | 黑箱,难以解释 | 可以分析支持向量和权重 |
| 硬件要求 | 需要GPU | CPU即可 |
| 部署成本 | 高 | 低 |
| 小样本场景 | 容易过拟合 | 表现稳定 |
在医学影像这个领域,标注数据的获取成本极高——一个标注好的病例需要专业放射科医生花30分钟到1小时来确认。所以绝大多数医院的标注数据只有几百到几千例。这种情况下,SVM反而是更实用的选择。
# SVM在小样本上的优势
# 当训练数据少于10000个时,SVM通常优于深度学习
from sklearn.svm import SVC
from sklearn.neural_network import MLPClassifier
import time
# 模拟医学影像场景:只有800个标注样本
n_samples = 800
n_features = 120 # 120维影像组学特征
X_train_small = np.random.randn(n_samples, n_features)
y_train_small = np.random.randint(0, 2, n_samples)
# SVM
t0 = time.time()
svm = SVC(kernel='rbf', C=1.0, gamma='scale')
svm.fit(X_train_small, y_train_small)
svm_time = time.time() - t0
print(f"SVM训练时间: {svm_time:.2f}秒")
# 深度学习(MLP,简单神经网络)
t0 = time.time()
mlp = MLPClassifier(hidden_layer_sizes=(64, 32), max_iter=1000, random_state=42)
mlp.fit(X_train_small, y_train_small)
mlp_time = time.time() - t0
print(f"MLP训练时间: {mlp_time:.2f}秒")
# 在小样本上,SVM通常更快且不易过拟合
真实案例四:多病种联合筛查——一个SVM的”家族”
一个很有趣的趋势是,现在的AI辅助诊断系统不再只做一个病种,而是一个平台同时筛查多种疾病。
比如中国一家叫”推想科技”的公司,他们的肺部AI系统除了检测肺结节,还能同时检测:
- 肺炎征象
- 肺气肿
- 肺纤维化
- 胸腔积液
- 心脏增大
每个病种都用独立的SVM分类器,共享同一套特征提取模块:
胸部CT影像
│
├─→ 肺部分割(3D U-Net)
│
├─→ 特征提取模块(提取200+维特征)
│
├─→ SVM模块1: 肺结节良恶性分类
├─→ SVM模块2: 肺炎检测
├─→ SVM模块3: 肺气肿分级
├─→ SVM模块4: 肺纤维化评估
└─→ SVM模块5: 胸腔积液检测
│
└─→ 综合诊断报告
这种多任务学习的架构,让系统在资源有限的基层医院也能发挥很大作用——一台普通的CT机,加上这个AI系统,就能提供接近三甲医院放射科水平的初筛能力。
SVM在医学影像中的局限和挑战
当然,SVM也不是万能的。说几个真实的挑战:
1. 特征工程依赖专家经验
SVM本身不自动学习特征,它需要人类设计好的特征。这意味着特征提取的质量决定了上限。如果提取的特征不能很好地区分良恶性,再好的SVM也没用。
# 特征选择的重要性
from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.pipeline import Pipeline
# 从120个特征中选出最相关的30个
pipeline = Pipeline([
('feature_selection', SelectKBest(score_func=f_classif, k=30)),
('svm', SVC(kernel='rbf', C=1.0))
])
# 在医学影像中,通常用递归特征消除(RFE)来选择最优特征子集
from sklearn.feature_selection import RFE
rfe = RFE(estimator=SVC(kernel='rbf'), n_features_to_select=25, step=5)
rfe.fit(X_train, y_train)
print(f"选出的重要特征编号: {rfe.support_}")
print(f"特征排序: {rfe.ranking_}")
2. 多中心验证困难
一个在A医院数据上训练很好的SVM,放到B医院可能效果就下降了。原因是不同医院的CT机器、扫描参数、图像质量都不一样。
# 解决域偏移问题:使用域适应技术
from sklearn.svm import SVC
# 方法一:在多个中心的数据上联合训练
# 收集A医院、B医院、C医院的数据,统一预处理后一起训练
# X_all = concatenate([X_A, X_B, X_C])
# y_all = concatenate([y_A, y_B, y_Y])
# svm.fit(X_all, y_all)
# 方法二:使用Transfer Learning
# 先在大规模公开数据集上预训练
# 再用目标医院的小样本数据微调
3. 假阳性导致的过度诊断
这是所有癌症筛查AI系统都面临的难题。SVM为了不漏掉一个恶性病例,往往会降低阈值,导致假阳性增多。
假设在1000个人的肺癌筛查中:
- 实际有20人患癌
- SVM敏感度90% → 发现18人,漏掉2人
- SVM特异度85% → 800人正确判定为阴性,170人误判为阳性
这170个"假阳性"的人,都需要做进一步检查(穿刺活检)
其中可能只有少数人最终被确诊为恶性
这就是为什么AI不能替代医生,而是"辅助"医生
医生需要结合AI的判断、自己的经验、患者的整体情况
来做出最终决策
给小朋友解释:AI是怎么帮医生”看”片子的?
好,现在让咱们换个方式,像讲故事一样说一遍。
想象你有一个超级厉害的放大镜,可以看到每个人肺里面的每一寸地方。这个放大镜叫CT扫描仪。
你看到肺里有一个小点点,它可能是:
- 一个良性的小瘢痕(以前感冒留下的)
- 或者一个早期的肿瘤
你怎么区分?你会看:
- 它是圆的还是扁的?
- 边缘是光滑的还是像星星一样有刺?
- 颜色是均匀的,还是有的深有的浅?
- 它大不大?
把这些信息告诉一个聪明的助手(就是SVM),它说:”根据我看过的10000个案例,这个点点有87%的可能是坏的,建议你赶紧处理。”
于是你告诉医生,医生仔细看了片子,发现确实有问题,赶紧手术。病人康复了。
这就是AI辅助诊断的完整故事。
未来:SVM + 深度学习,强强联合
现在的趋势不是”SVM vs 深度学习”,而是两者结合:
深度学习负责:
- 自动分割病灶区域(从CT中精确勾画出结节)
- 提取高维特征(不需要人工设计)
SVM负责:
- 在小样本上高效分类
- 提供可解释的决策依据(哪些特征起了关键作用)
- 输出概率而非硬分类,方便医生判断
一个典型的混合架构:
# 深度学习 + SVM 的混合模型
import torch
import torch.nn as nn
from sklearn.svm import SVC
import numpy as np
class FeatureExtractor(nn.Module):
"""用CNN提取影像特征"""
def __init__(self):
super().__init__()
self.conv = nn.Sequential(
nn.Conv3d(1, 32, 3, padding=1),
nn.ReLU(),
nn.Conv3d(32, 64, 3, padding=1),
nn.ReLU(),
nn.AdaptiveAvgPool3d((4, 4, 4))
)
def forward(self, x):
x = self.conv(x)
return x.view(x.size(0), -1) # 展平为特征向量
class HybridClassifier(nn.Module):
"""深度学习特征提取 + SVM分类"""
def __init__(self):
super().__init__()
self.feature_extractor = FeatureExtractor()
# SVM不是PyTorch的,所以我们在外部训练
self.svm = None
def extract_features(self, x):
with torch.no_grad():
features = self.feature_extractor(x)
return features.numpy()
def fit_svm(self, features, labels):
self.svm = SVC(kernel='rbf', C=1.0)
self.svm.fit(features, labels)
def predict(self, x):
features = self.extract_features(x)
return self.svm.predict(features)
def predict_proba(self, x):
features = self.extract_features(x)
return self.svm.predict_proba(features)
# 使用流程:
# 1. 用大量未标注CT数据预训练CNN
# 2. 用标注数据训练SVM分类器
# 3. 结合两者,发挥各自优势
写在最后
AI辅助诊断不是要取代医生,而是让医生变得更强。
一个放射科医生每天要看几百张片子, fatigue 是客观存在的。而SVM不会累,不会分心,不会因为昨晚没睡好就漏掉一个结节。
但同时,AI也有它的盲区——它看不懂患者的病史、不了解患者的整体状况、不能和患者进行有温度的交流。
最好的模式,是AI做它擅长的(快速、准确、不知疲倦的特征分析),医生做AI做不到的(综合判断、人文关怀、伦理决策)。
这就是当下SVM在医学影像诊断中最真实、最有价值的角色。