省城三甲医院的放射科主任林医生,被派到一家县医院组建胸片诊断科室。院长给她的任务不是“立刻达到三甲水准”,而是“先定一套人人能复制的标准流程”——先有基线,再谈超越。林医生的方案有四步:招一批肯共享笔记的医生,每个医生把自己的完整发现传给后面所有同事;一张片子按 14 种常见病逐项打钩;让大家在各种光线和角度下反复练读片;把省城积累的十年经验直接带过来用。这套思路,和 DenseNet-121 在 NIH ChestXray14 胸片数据集上建立基线模型的过程几乎一模一样:密集连接复用特征、多标签逐病分类、数据增强提升鲁棒性、迁移学习继承 ImageNet 经验。本文就用这个“建科室”的故事,带你零基础看懂 DenseNet-121 胸片基线模型的每一个环节。
学完你将理解:DenseNet-121 为何成为医学影像 AI 最常用的基线骨架——从架构原理、多标签训练到评估复现,你能独立搭建并复现一份胸片疾病分类基线,为后续模型对比与论文实验打底。
可视化演示
本节配有交互动效(进入视口后自动加载,约 3KB)。
密集连接架构 每层接收前面所有层输出拼接 特征复用减少参数量 x_l = H_l([x_0, x_1, ..., x_{l-1}]) 121层密集连接
影像基线概述
林医生到县医院的第一件事,不是引进最先进的设备,而是定下统一阅片标准:先保证“任何一位医生按这套流程读片,结果都稳定可复现”。这就是基线的本质——它不是最佳方案,而是所有人必须超越的起跑线。在医学影像 AI 里,NIH ChestXray14 就是那批“标准教学片”:3 万多张胸片,标注了 14 种常见疾病。在这个数据集上,DenseNet-121 常被用作基线模型——任何新方法想证明自己有效,先跟它对打。
基线模型要有两样东西:稳定的架构和统一的评价标准。DenseNet-121 在架构上结构公开、预训练权重现成;在评价上,最常用的指标是 AUC。和准确率不同,AUC 只看模型给“有病样本”打的分数是否高于“无病样本”,完全不依赖你选哪个阈值,这对胸片这种疾病稀疏、正负样本极不平衡的数据特别友好——就像标准考试只排名次,不受“及格线定在哪”的影响。
1. 正负样本配对:先不算单个样本,而是把每一张有病片子和每一张无病片子都配成一对,共得到 M×N 对。
2. 打分比较:模型给每张片子打出一个“有病概率”得分 s,然后比较这一对里谁的分高。
3. 指示函数:若有病片的得分更高,计 1 分,否则计 0 分。它像一个“裁判”,只记输赢不记分数差。
4. 取平均:把所有配对上的"1"加起来,除以总配对数 M×N,得到的就是 AUC。
就像林医生用统一阅片标准给科室定基线,AUC 就是那套“标准考试题”——任何医生来考试,分数都能横向比较。基线先立住,后面所有的优化才有参照物。
DenseNet架构
林医生的团队有个特殊规矩:每个医生读完片,必须把自己的发现完整写进共享笔记,后面每一位同事在写结论前,都要先翻阅前面所有人的笔记。乍一听很累,但这样一来,任何一个早期发现的细微线索都不会在传递中丢失——这就是 DenseNet 的“密集连接”机制。
在普通卷积网络里,信息像传话游戏一样逐层传递,传到后面往往已经失真;而 DenseNet 让第 l 层直接拼接前面所有层的输出特征图,再一起处理。数学上写作:
1. 拼接符号:方括号表示把所有特征图在通道维度上拼成一大摞,像把所有笔记叠成一本书。
2. 特征图集合:每一张 x 都是一层输出的“读片笔记”,其中 x_0 是原始输入的图像。
3. 组合函数:H_l 是本层自己的处理流程,通常是一串“批归一化→ReLU→卷积”的复合操作。
4. 本层输出:拼接后的厚笔记经过 H_l 提炼,得到第 l 层的新笔记 x_l,继续传给后面所有人。
那 121 层是怎么来的?DenseNet-121 由 4 个 Dense Block 组成,密集层数分别为 6、12、24、16,块与块之间用“过渡层”压缩通道数。每个密集层内部采用瓶颈层设计:先用 1×1 卷积把通道数压缩到原来的 1/4,再用 3×3 卷积提取特征,就像把厚笔记先画重点再精读。增长率 k=32 则决定每层新增 32 张特征图——笔记越写越厚,但每页都经过浓缩,所以团队虽老练却依旧敏捷。
多标签分类
胸片和普通照片最大的不同:一张片子上往往同时有好几种病。肺不张合并心脏肥大、积液伴肺炎,都是临床常事。所以林医生不让团队做“单选”,而是人手一张 14 项疾病清单,逐项独立打钩——这也正是多标签分类与多分类的根本区别。
多分类任务(比如区分猫狗鸟)用 softmax 让所有类别概率和为 1,类别之间互相竞争;而多标签任务里,14 种疾病互不排斥,每种病都有“有”或“无”两种可能。因此 DenseNet-121 的最后一层不做 softmax,而是让全局平均池化后的特征接一个 14 输出的全连接层,每个输出独立通过 sigmoid 函数映射到 0 到 1 之间的概率,再各自与 0.5 这个“打钩线”比较。
1. 线性得分:z_k 是网络对第 k 种疾病打出的原始分,可以是任意实数,负的表示“不像”,正的表示“像”。
2. Sigmoid 压缩:把任意实数缩到 0 到 1 之间,分数越高概率越接近 1,这就像把“像不像”的直觉换算成百分比。
3. 阈值判正:用 0.5 作分界线,超过就打钩,否则不打钩。每个类别独立判决,互不干扰。
逐项打钩对应逐类独立输出概率,sigmoid 让每种疾病的判断都保留自己的“主权”。第一版清单可能打错几项,但没关系——基线的作用就是先跑起来,后面再逐项纠偏。
数据增强
林医生给团队下了一条硬性要求:平时练读片,不能只看标准正位片,还要练“歪着头看、在偏暗的灯箱下看、把片子左右倒过来看”。练多了,真到了设备型号不同、曝光参数各异的一线,团队照样认得病。这就是数据增强的思路——训练时不看“原片”,只看“变化过的片子”。
从数学上看,数据增强就是对输入图像做随机几何与光度变换,让同一张 X 光变成“多个视角的样本”。胸片有天然的左右对称性,所以水平翻转几乎无损;拍摄时患者体位略有偏差,因此 ±10° 的随机旋转能模拟这种误差;不同设备的曝光差异,则用随机的亮度、对比度抖动来模拟。
1. 旋转:R_θ 是旋转矩阵,θ 是随机角度。它模拟患者体位轻微偏斜的情况。
2. 水平翻转:flip 把图像左右镜像。人体胸腔大致左右对称,翻转后的胸片仍是有意义的样本。
3. 亮度与对比度:α 控制对比度(乘性缩放),β 控制亮度(加性平移),模拟不同曝光条件。
4. 组合输出:先几何变换、再光度变换,得到增强样本 x_aug,送进网络训练。
注意一个重要细节:增强只在训练阶段使用,验证和测试时只做统一的缩放与归一化,就像考试时必须用标准试卷,不能用练习时的小改动版本。多视角训练让团队在任何灯箱下都认得病,这就是模型的“鲁棒性”。
迁移学习
林医生在省城积累了十年读片经验。来县医院,她不是从零学起——把省城那套“看肺纹理、找结节、辨纵隔”的通用基本功直接搬过来,只需要花几天熟悉县医院的设备特性和常见病分布。迁移学习的逻辑与此完全一致:把在 ImageNet 1000 类自然图像上学到的通用特征提取能力,搬运到医学影像任务上。
为什么能搬?因为卷积网络的浅层学的是“边缘、纹理、形状”这些通用视觉元素,自然图像和胸片都适用。DenseNet-121 在 ImageNet 上预训练好的权重,就是林医生的“十年经验底座”。使用时,把最后的 1000 类分类头替换成 14 输出的新分类头,其余骨干结构原样保留:
1. 预训练骨干:θ 上标 pre 表示从 ImageNet 学来的权重,包含丰富的通用视觉特征。
2. 随机分类头:替换成的新分类头没有先验知识,用随机数初始化,上标 rand 表示“待训练”。
3. 整体拼接:方括号表示把两部分权重组合成完整的网络。训练时通常先冻结 backbone,只更新分类头。
具体操作上,胸片是灰度图,预处理时要复制成 3 通道喂给网络;训练初期冻结骨干只训练分类头,收敛后再用更小的学习率(比如 1e-4)微调深层部分。经验底座 + 快速熟悉新设备,让林医生的团队几天内就能上岗,这正是迁移学习让 DenseNet-121 在小规模医学数据集上也能训练稳定的原因。
训练配置
新科室的规章制度要定清楚:每张片子都按标准流程判读,出了问题能追溯到具体环节。对模型来说,训练配置就是它的“规章制度”——损失函数规定“错得多严重”,优化器决定“如何改进”,数据供给则保证“喂饭节奏稳定”。
损失函数上,多标签胸片分类最常用的是 BCE(二元交叉熵)损失。PyTorch 里推荐直接用 BCEWithLogitsLoss,它把 sigmoid 和 BCE 合并计算,数值上更稳定。优化器常选 Adam,初始学习率 1e-3,配合余弦退火或按步长衰减;如果想更贴近经典实验,也可以选带动量的 SGD。数据方面,batch size 取 32、输入尺寸 224×224 是性价比很高的默认配置。
1. 逐类二分类:对第 k 种疾病,真实标签 y_k 是 0 或 1。N 是疾病类别数(这里为 14)。
2. 正样本项:当 y_k=1(真有这种病)时,若模型概率 p_k 小,−log p_k 就大,惩罚重。
3. 负样本项:当 y_k=0(没有这种病)时,若模型概率 p_k 大,−log(1−p_k) 就大,同样受罚。
4. 求和平均:把所有类别的两项惩罚加起来再除以 N,得到该样本的损失,训练时不断让它下降。
规矩清晰、追责合理,团队就能稳定进步。同理,BCE 让每个疾病类别都受到监督,任何一个类别的判断失误都会反映在损失上,模型也因此被逼着对 14 种病“全面发展”。
基线评估
三个月后院长来验收,林医生没有让个别医生自夸,而是组织了一场全科“标准考试”:14 类疾病的片子混在一起,看团队整体平均分和每一类的单项分。在 DenseNet-121 基线上,这场“考试”就是计算 14 类疾病各自的 AUC,然后取平均。
NIH ChestXray14 官方报告里,DenseNet-121 基线的平均 AUC 大约在 0.76 到 0.80 之间。逐病种看,肺不张、心脏肥大等样本充足、影像特征明显的疾病 AUC 较高;而疝气(Hernia)这类样本极少、特征隐蔽的疾病,AUC 明显偏低——就像班里有一门课只有三个学生选,平均分再高也说明不了教学水平。
1. 单类 AUC:AUC_k 是第 k 种疾病的单独成绩,计算方式就是“有病 vs 无病”配对比分。
2. 求和:把 14 类疾病的成绩全部累加。
3. 取平均:除以类别数 14,得到平均 AUC,也就是基线的“总评分”。
基线评估最关键的心态是“正视局限”:ChestXray14 的标签是从放射科报告里用文本挖掘自动生成的,含有不少噪声;模型是在切片级图像上训练的,不等于能直接判断病灶的精确位置。AUC 高不代表临床可用——就像考试高分不等于临床妙手。基线之所以是基线,就是因为它被设计成边界清晰、可复现,供后来者逐项超越。
AI 应用场景
医院影像科的 AI 初筛分诊
阶段:模型部署与辅助诊断
解决的问题:放射科医生每天要读几百张胸片,疲劳导致漏诊。传统方式全靠人工按顺序读片,危急病例可能排在队尾。用 DenseNet-121 基线模型做“初筛分诊”,先自动把所有片子按 14 类疾病的阳性概率排序,把最可能有问题的片子置顶,医生优先读。基线 AUC 排序能力已经能显著缩短危急病例的等待时间。
具体案例:某三甲医院影像科接入一套 DenseNet-121 分诊系统:胸片拍完 30 秒内,系统给出“气胸高度疑似”的红色提示,值班医生优先调阅并复核,确认后立刻通知急诊。周末夜班时段,分诊系统把危急病例的平均报告时间从 45 分钟压缩到 12 分钟。
科研团队的基线对比实验
阶段:模型开发与论文评估
解决的问题:研究新模型时,如果不用统一基线,实验结果无法横向比较。传统做法是各跑各的模型,指标口径不一。在 ChestXray14 上,DenseNet-121 作为社区公认基线,任何新模型(如注意力网络、Transformer 变体)都要和它同数据、同指标对比,论文才有说服力。
具体案例:某高校医学影像课题组想验证“加入解剖先验注意力能提升胸片分类”,他们先用官方 DenseNet-121 基线复现平均 AUC 0.77,再在完全相同的训练配置下替换为新模型,得到平均 AUC 0.80。由于基线可复现,审稿人认可了这份对比的公平性,论文顺利发表。
基层体检车的移动读片筛查
阶段:边缘端推理与公共卫生筛查
解决的问题:偏远地区体检车拍完胸片,当地没有放射科医生,片子要传回县城等几天才有报告。传统方式诊断周期长、随访率低。用迁移学习得到的 DenseNet-121 轻量模型部署在车载设备上,现场就能给出肺结核、气胸等疾病的概率提示,帮助现场医护决定是否转诊。
具体案例:某省结核病防治所的两台移动体检车加载 DenseNet-121 基线模型,每车每天在 6 个乡镇巡回筛查约 200 人。模型圈出“疑似结核”的片子由车载医生复核,转诊率提升 3 倍,确诊患者的平均就诊时间缩短了 9 天。
Python 演示
import osimport numpy as npimport torchimport torch.nn as nnimport torchvisionfrom torch.utils.data import Dataset, DataLoaderfrom torchvision import transforms # 14 类胸部疾病,顺序与 NIH ChestXray14 的 CSV 列一致DISEASES = [ 'Atelectasis', 'Cardiomegaly', 'Effusion', 'Infiltration', 'Mass', 'Nodule', 'Pneumonia', 'Pneumothorax', 'Consolidation', 'Edema', 'Emphysema', 'Fibrosis', 'Pleural_Thickening', 'Hernia']NUM_CLASSES = len(DISEASES) class ChestXrayDataset(Dataset): """读取 NIH ChestXray14 标注 CSV,返回图像和 14 维多标签向量。""" def __init__(self, root, csv_path, transform=None): import pandas as pd self.root = root self.transform = transform df = pd.read_csv(csv_path) self.files = df['Image Index'].tolist() self.labels = df[DISEASES].values.astype(np.float32) def __len__(self): return len(self.files) def __getitem__(self, idx): from PIL import Image img = Image.open(os.path.join(self.root, self.files[idx])).convert('RGB') if self.transform: img = self.transform(img) return img, torch.from_numpy(self.labels[idx]) def build_model(freeze_backbone=True): model = torchvision.models.densenet121(pretrained=True) model.classifier = nn.Linear(model.classifier.in_features, NUM_CLASSES) if freeze_backbone: for p in model.features.parameters(): p.requires_grad = False return model def train_one_epoch(model, loader, criterion, optimizer, device): model.train() total_loss = 0.0 for images, labels in loader: images, labels = images.to(device), labels.to(device) logits = model(images) loss = criterion(logits, labels) optimizer.zero_grad() loss.backward() optimizer.step() total_loss += loss.item() * images.size(0) return total_loss / len(loader.dataset) def evaluate_auc(model, loader, device): model.eval() y_true_list, y_score_list = [], [] with torch.no_grad(): for images, labels in loader: logits = model(images.to(device)) y_true_list.append(labels.numpy()) y_score_list.append(torch.sigmoid(logits).cpu().numpy()) y_true = np.concatenate(y_true_list) y_score = np.concatenate(y_score_list) from sklearn.metrics import roc_auc_score return roc_auc_score(y_true, y_score, average='macro') def main(): device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') train_transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomHorizontalFlip(), transforms.RandomRotation(10), transforms.ColorJitter(brightness=0.2, contrast=0.2), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), ]) val_transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), ]) train_set = ChestXrayDataset('images', 'train_val.csv', train_transform) val_set = ChestXrayDataset('images', 'test.csv', val_transform) train_loader = DataLoader(train_set, batch_size=32, shuffle=True) val_loader = DataLoader(val_set, batch_size=32, shuffle=False) model = build_model(freeze_backbone=True).to(device) criterion = nn.BCEWithLogitsLoss() optimizer = torch.optim.Adam(model.classifier.parameters(), lr=1e-3) for epoch in range(5): loss = train_one_epoch(model, train_loader, criterion, optimizer, device) auc = evaluate_auc(model, val_loader, device) print('epoch %d loss %.4f mean_auc %.4f' % (epoch + 1, loss, auc)) if __name__ == '__main__': main()
model = torchvision.models.densenet121(pretrained=True)加载 ImageNet 预训练权重,省下从头训练几个月的时间。model.classifier = nn.Linear(model.classifier.in_features, NUM_CLASSES)把 1000 类分类头换成 14 类,对应 14 种疾病。for p in model.features.parameters(): p.requires_grad = False冻结骨干,只训练分类头,先让新头学会“打分”。self.labels = df[DISEASES].values.astype(np.float32)读出 CSV 中 14 列的 0/1 标注,形成多标签向量。transforms.RandomRotation(10)训练时随机旋转 ±10°,模拟患者体位偏差。criterion = nn.BCEWithLogitsLoss()多标签损失,内部合并 sigmoid 与 BCE,数值更稳定。roc_auc_score(y_true, y_score, average='macro')按 14 类分别算 AUC 再平均,对应文中 Mean AUC。torch.optim.Adam(model.classifier.parameters(), lr=1e-3)只优化分类头参数,冻结部分不更新。
常见误区
误区DenseNet 每个层都连到所有后续层,那应该是所有层共用同一套卷积参数吧?不然参数量不得爆炸?
正解密集连接共享的是“特征图”而不是“参数”。每一层仍然有自己独立的卷积核,只是它的输入拼接了前面所有层的输出。就像共享笔记的团队里,每个医生都有自己的专业判断,只是下结论前都要参考前面所有人的笔记——笔记共享,判断独立。DenseNet 参数少,是因为它靠特征复用避免了大量冗余卷积核,而不是靠参数共享。
为何常见:看到“连接所有层”很容易联想到“共享权重”,加上 DenseNet 确实以参数高效著称,初学者容易把两个概念混在一起。
误区分类任务不都应该在最后一层加 softmax 吗?把 14 个疾病的概率归一化,加起来等于 1,多好看。
正解softmax 强制所有类别概率之和为 1,意味着“此消彼长”——肺炎概率高了,心脏肥大就必须降低。但胸片上这两种病完全可以同时存在。多标签任务必须对每个类别独立使用 sigmoid,各自在 0 到 1 之间取值、各自与 0.5 比较。这就像 14 张独立的打钩清单,每张都只回答“有”或“没有”,而不是 14 个选项里只能选一个。
为何常见:大多数入门教材以单标签分类为例,softmax 的“标准答案”印象太深,遇到多标签场景很容易惯性照搬。
误区数据增强能提升泛化能力,那验证集、测试集也做同样的随机翻转旋转,效果肯定更好。
正解数据增强是为了让模型在训练时看到更多“变体”,从而学到不变的本质特征。但评估时必须用固定、标准的输入,才能公平比较不同模型。想象考试时给每个学生发不同的试卷,分数就失去可比性了。验证集只做统一的 resize 和归一化,任何随机性都会让评估结果有噪声,AUC 忽高忽低无法复现。
为何常见:初学者觉得“增强是样本多样化的万金油”,忽略了评估环节对确定性和可复现性的要求。
误区迁移学习就是加载预训练权重后把所有层冻结,只训练最后的分类头,这样又快又稳。
正解冻结骨干只是训练的第一阶段策略。因为 ImageNet 和胸片图像差异不小,分类头训练几轮后,骨干的特征可能仍不够贴近医学影像域。常规做法是:先冻结骨干训分类头,待损失平稳后,解冻部分深层(或全部)骨干,用小学习率(如 1e-4)微调。就像林医生先熟悉设备再调整自己的读片习惯——经验底座要保留,但细节必须因地制宜。
为何常见:教材里“冻结 backbone”是降低训练成本的经典做法,初学者容易把它当成唯一且永远正确的方案。
误区DenseNet-121 在 ChestXray14 上平均 AUC 0.78,那它就可以直接替代放射科医生下诊断了。
正解AUC 高只说明模型“排序能力强”——有病的得分普遍高于没病的,但它不告诉你病灶在哪、不保证阈值选得准,更不能处理临床中复杂的影像检查序列。ChestXray14 的标签来自文本挖掘自动生成,存在错误标注,模型的成绩是在这些噪声标签上算的。考试高分不等于临床妙手,基线模型的价值是作为对比基准,而不是作为最终诊断工具。
为何常见:媒体常把“AI 检测准确率 90%+”当成“AI 取代医生”,数字本身又让非专业人士产生不切实际的信任。
面试题
Q1. DenseNet 相比 ResNet,最核心的创新是什么?
- A.残差跳跃连接只连接相邻层
- B.每一层都与后续所有层密集相连← 正确答案
- C.用注意力机制增强特征表达
- D.单纯堆叠更深更宽的卷积层
答案:B。ResNet 是“每一层只跳过一层”的残差连接,而 DenseNet 把第 l 层的输入改为前面所有层输出的拼接,形成“每层都与后续所有层相连”的密集连接。这就像共享笔记团队里每个成员都参考前面所有人的笔记,而不是只看上一位同事的结论。A 说的是 ResNet 的近似描述,C 是注意力网络,D 是传统加深思路。
Q2. DenseNet-121 做胸片 14 种疾病多标签分类,输出层应该用什么?
- A.Sigmoid 对每个疾病独立输出概率← 正确答案
- B.Softmax 输出单一的疾病类别
- C.不加激活函数直接线性输出
- D.用 Tanh 将输出映射到负一到一
答案:A。多标签任务中各类别互不排斥,须对每个疾病独立用 sigmoid 输出 0 到 1 的概率,各自与 0.5 比较。softmax 会让概率总和为 1,导致“此消彼长”,与胸片可同时患多种病的事实矛盾。C 缺少概率语义,D 的 Tanh 输出范围含负值,都不适合做概率判断。
Q3. DenseNet 中“增长率”(growth rate)参数 k 指的是什么?
- A.网络卷积层的总数量
- B.每层新增的特征图数量← 正确答案
- C.学习率随训练步数增长
- D.数据集中样本数量增长
答案:B。增长率 k 决定每个密集层向共享笔记中新增多少张特征图,典型值为 32。k 越大,拼接后的特征越多,网络容量越大但计算量也越大。A 是网络深度,C 是学习率调度,D 是数据规模,都与增长率无关。
Q4. 关于 DenseNet 瓶颈层(BN-ReLU-1x1-3x3)的作用,下列说法正确的有?
- A.用 1x1 卷积压缩通道数量← 正确答案
- B.瓶颈层可以显著降低计算量← 正确答案
- C.使梯度消失问题变得更严重
- D.改变密集连接的方向与方式
答案:AB。瓶颈层先用 1×1 卷积把通道压缩到 1/4,再用 3×3 卷积提取特征。通道数变少,后续 3×3 卷积的乘加运算随之减少,因此 A、B 正确。密集连接加瓶颈层恰恰缓解了梯度消失,C 说反了;D 无中生有,密集连接的方向始终是“前层到后层”。
Q5. ChestXray14 基线评估中“平均 AUC”表示什么?
- A.十四种疾病 AUC 的平均值← 正确答案
- B.全部测试样本分类准确率
- C.模型全部参数取平均
- D.训练过程所有损失平均值
答案:A。平均 AUC 是 AUC_k 逐类计算后求和再除以 14,是模型整体排序能力的平均分。B 是准确率,与阈值相关且不适合不平衡数据;C 是参数均值,与模型质量无关;D 是训练损失,只能反映拟合程度,不能衡量判别能力。
Q6. 用迁移学习训练 DenseNet-121 胸片基线,常见的正确做法有哪些?
- A.用 ImageNet 预训练权重初始化骨干← 正确答案
- B.把所有层参数全部随机初始化
- C.用较小学习率微调深层网络← 正确答案
- D.新分类头训练而骨干先冻结← 正确答案
答案:ACD。迁移学习的核心是复用 ImageNet 预训练权重,A 正确;先冻结骨干训练分类头、再小学习率微调是标准两阶段策略,C、D 正确。B 完全随机初始化等于抛弃预训练经验,从头训练既慢又难收敛,是典型错误做法。
Q7. 训练时对胸片做随机旋转、水平翻转等数据增强,主要作用是什么?
- A.直接减小模型的参数量
- B.显著加快单次推理的速度
- C.增加样本多样性提升模型鲁棒性← 正确答案
- D.改变损失函数对样本的权重
答案:C。数据增强通过对同一张片子做各种合法变换,让模型看到更多“变体”,学会忽略旋转、翻转等无关变化,从而提升泛化鲁棒性。它不改变参数数量(A)、不改变推理速度(B)、不改损失函数(D),本质是等效扩大训练数据。
Q8. 关于多标签胸片训练中的 BCE 损失,正确的描述有哪些?
- A.每个类别都算独立的二分类损失← 正确答案
- B.训练时需要对输出做 softmax 归一
- C.正负样本不平衡时也可以加权← 正确答案
- D.标签必须是一维的单个标量
答案:AC。BCE 对每个类别单独计算“有/无”的二分类交叉熵再取平均,A 正确;类别不平衡时可通过 pos_weight 给正样本更高权重,C 正确。B 错误,BCE 配合 sigmoid 而非 softmax;D 错误,多标签的标签是 14 维多热向量。
Q9. DenseNet 的特征复用(feature reuse)带来的一个直接后果是什么?
- A.每层参数量更大但层数更少
- B.后续层输入的特征图数量更多← 正确答案
- C.完全不再需要批归一化层
- D.网络只能处理固定尺寸的输入
答案:B。因为第 l 层拼接了 0 到 l-1 层所有输出,越靠后的层输入特征图数量越多(随层数线性增长),这正是“特征复用”的直接体现。A 说反了——DenseNet 靠复用减少了冗余参数;C 错误,批归一化仍是标准组件;D 错误,DenseNet 可用全局池化适应不同输入尺寸。
Q10. DenseNet-121 中的"121"表示什么?
- A.网络总数一百二十一层← 正确答案
- B.参数量为一点二一亿
- C.识别疾病类别达到一百二十一
- D.输入图像尺寸为一百二十一
答案:A。DenseNet-121 的 121 指网络总层数:4 个 DenseBlock 的密集层 6+12+24+16 共 58 层,加上过渡层、初始卷积和分类层等合计 121 层。B 是参数量、C 是疾病数(14)、D 是图像尺寸(224),都不是 121 的含义。