ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于卷积神经网络的肝脏肿瘤CT检测:从数据预处理到工程部署

基于卷积神经网络的肝脏肿瘤CT检测:从数据预处理到工程部署 简介一份关于基于卷积神经网络的肝脏肿瘤检测算法及应用研究的PDF文献面向深度学习、医学图像处理方向的科研人员与算法工程师。内容聚焦VGG16网络结构的改进通过4个卷积层、4个池化层和1个全连接层的设计结合空间金字塔池化实现多尺度特征输出并给出模型参数表、算法步骤与两组实验结果检测准确率达90%以上为临床辅助诊断提供参考。资源为单个PDF文件大小948KB便于下载阅读已有243人学习。文件完整涵盖引言、算法模型设计、特征融合影响分析、实验数据与结论适合快速掌握CNN在肝脏肿瘤检测中的建模思路、参数调整方法和效果验证手段。1. 肝脏肿瘤检测算法为什么绕不开卷积神经网络CT影像的问题和答案3毫米的肝转移灶在CT上是什么样子它和周围肝实质的灰度差不到20个HU边界模糊到放射科医生需要翻看连续三个窗位才能确认传统阈值分割和形态学方法在这种输入上基本第一步就失效。这就是基于卷积神经网络的肝脏肿瘤检测算法要解决的核心矛盾用卷积核自动堆叠出多尺度、多对比度的特征表达把检测从“找边界”变成“学模式”。这篇笔记不打算复现任何一篇论文而是把这类检测算法落地成工程方案的完整路径讲清楚——数据怎么备、网络怎么选、参数怎么调、推理怎么验证。适合正在做医学影像AI方向、手头有CT数据、或者准备从分类任务转向检测任务的从业者。后面的方案尽量按2D3D折中路线展开显存有限的团队也能跟上。2. 训练数据从哪来CT序列预处理、标注转检测框的完整流程2.1 数据来源与标注形式公开集、医院数据各自的坑肝脏肿瘤检测的数据来源常见就两条路公开数据集和医院合作数据。公开集里LiTS和DeepLesion是起步阶段最常被提起的两个前者带肝脏和肿瘤的分割掩码后者是CT断层上的病灶检测框两者都是研究界验证算法的主流选择。医院合作数据的优势是贴近真实临床分布——设备型号、扫描协议、层厚、增强期相都和你最终部署环境一致但伦理审批、脱敏、标注人力成本都是实打实的坎没有想象的那么容易。不管数据从哪来落地前先确认标注形式。常见三种分割掩码每个像素标类别、检测框xyxy坐标、医生勾画的多边形。如果是后者转检测框时别直接拿多边形外接矩形草草了事——多边形往往贴着病灶边缘画外接矩形会带进大片正常组织导致训练时正样本里混入过多背景模型学到的特征被稀释。我一般会先把多边形栅格化成掩码再做连通域分析取外接框顺便能过滤掉标注面积过小的噪声点。数据量方面给个底线参考做检测任务训练集至少需要300例以上有标注的CT序列每例平均包含1-3个病灶。低于这个量级模型容易在验证集上虚高、换一批数据就崩。如果实在凑不够先别急着上检测网络用分类网络做切片级“有无肿瘤”判断或者用预训练模型做迁移学习都比硬train一个检测器靠谱。2.2 窗宽窗位与体素重采样预处理细节决定模型上限CT图像存的是HU值范围从-1024到3071直接归一化到0-1丢给卷积网络等于把肝脏实质和肿瘤之间那几十个HU的差异压到零点零几的数值差里梯度根本没力气学。所以第一步永远是窗宽窗位截断。肝脏肿瘤检测常见做法是窗位50、窗宽300也就是把HU值从-100到200做线性映射小于-100全部置0大于200全部置255。为什么是这个范围肝脏实质典型值在40-60HU肿瘤因为血供和坏死通常比肝实质低10-30HU把窗中心对准肝实质、窗宽覆盖到大多数病灶的分布区间对比度才拉得开。第二步是体素重采样。原始CT的层内分辨率通常是512x512但层厚可能是2.5mm、3mm甚至5mm直接按切片喂网络训练等于把各向异性的数据当作各向同性来处理。常见做法是重采样到各向同性1mm也就是层内和层间都统一到1mm体素。这一步对后续的3D网络尤其重要因为卷积核的感受野在各方向一致时学习到的空间特征才是旋转不变、尺度一致的。重采样用线性插值即可标签掩码用最近邻插值别把类别标签插出中间值。归一化放在截断和重采样之后。常见做法是减均值除标准差均值方差从训练集全量统计而不是逐张切片单独计算。逐张计算会让同一患者不同切片的输入分布不一致模型学到的就不是病灶特征而是切片间的亮度差异了。import numpy as np import SimpleITK as sitk def load_and_preprocess_ct(path, target_spacing1.0, level50, width300): # 读取原始DICOM序列或NIfTI文件 img sitk.ReadImage(path) origin_spacing img.GetSpacing() origin_direction img.GetDirection() origin_origin img.GetOrigin() # 1. 重采样到各向同性体素保留物理空间信息 resampler sitk.ResampleImageFilter() resampler.SetOutputSpacing([target_spacing, target_spacing, target_spacing]) resampler.SetSize([int(round(img.GetSize()[i] * origin_spacing[i] / target_spacing)) for i in range(3)]) resampler.SetOutputDirection(origin_direction) resampler.SetOutputOrigin(origin_origin) resampler.SetInterpolator(sitk.sitkLinear) img_resampled resampler.Execute(img) arr sitk.GetArrayFromImage(img_resampled).astype(np.float32) # shape: [D, H, W] # 2. 窗宽窗位截断映射到[0, 255] lower level - width / 2.0 upper level width / 2.0 arr_clipped np.clip(arr, lower, upper) arr_normalized (arr_clipped - lower) / (upper - lower) * 255.0 return arr_normalized这段代码有三个关键点。重采样目标spacing传1.0mm如果原始数据层厚已经是1mm就跳过重采样节省时间窗宽窗位截断放在重采样之后避免插值过程把窗外的背景值混进来返回的数组保持D,H,W顺序和SimpleITK的GetArrayFromImage默认顺序一致后面切slice、裁patch都不会搞错维度。注意重采样后要用最近邻插值单独处理掩码不能用上面的线性插值否则边界会糊掉。2.3 把分割掩码转成检测框连通域分析与转坐标的Python代码拿到的是分割掩码而不是检测框时需要做一次标注转换。掩码是每个像素一个类别标签的体数据检测框需要的是每个病灶一个xyxy坐标。直接遍历所有像素找边界一是慢二是没法区分多个相邻病灶连在一起的情况需要用连通域分析把每个独立病灶拆开。import numpy as np from scipy.ndimage import label, find_objects def mask_to_bboxes(mask, min_voxel_threshold50): 将分割掩码转为检测框列表 mask: [D, H, W] 的0/1数组1表示肿瘤区域 min_voxel_threshold: 小于该体素数的连通域视为标注噪声丢弃 返回: list of dict, 每个dict包含bbox(np数组xyxy)和体积信息 # 1. 连通域标记相邻的肿瘤体素归为同一个病灶 structure np.ones((3, 3, 3), dtypeint) # 26邻域连通 labeled_mask, num_features label(mask, structurestructure) bboxes [] for i in range(1, num_features 1): # 提取单个连通域的坐标 coords np.argwhere(labeled_mask i) # [N, 3] 格式的体素坐标 if len(coords) min_voxel_threshold: continue # 计算三维外接框 z_min, y_min, x_min coords.min(axis0) z_max, y_max, x_max coords.max(axis0) # 存储为xyxy格式z轴信息单独记录切片检测时要用 bboxes.append({ bbox_3d: [x_min, y_min, z_min, x_max, y_max, z_max], volume_voxels: len(coords), center: coords.mean(axis0).astype(int) }) return bboxes连通域结构元素用的是3x3x3的26邻域这样同一病灶只要在任意方向上相邻就会被归到一起避免模型把同一肿瘤当成多个小目标。min_voxel_threshold设50体素在1mm各向同性分辨率下对应约50立方毫米也就是直径不到5mm的微小病灶这些病灶不是不能检测而是标注时本身就不稳定强转成检测框只会给训练集注入噪声。如果你明确要检测微小病灶这个阈值可以调到10但需要人工复核一遍转换结果。3. 网络结构怎么选2D检测、3D分割还是two-stage方案3.1 从任务反推结构病灶尺寸、对比度与标注形式决定网络类型选网络结构之前先回答三个问题病灶在CT里是什么尺寸、病灶和周围组织灰度差多少、你手里的标注是框还是掩码。肝脏肿瘤的典型情况是直径从3mm到10cm对比度在10-30HU之间标注形式取决于数据来源。这三个条件直接决定了不同网络结构的适用边界。只用分类网络ResNet、DenseNet等解决不了定位问题它只能告诉你“这张切片有没有肿瘤”不能告诉你“肿瘤在哪、多大”。检测网络YOLO、Faster R-CNN在2D切片上找框适合处理尺寸跨度大的病灶但对z轴上下文敏感度低——一个在单张切片上很小的病灶在连续三张切片上可能是明显的高亮团块2D检测器看不到这个信息。3D分割网络3D U-Net、nnU-Net直接对体数据分割能吃满z轴上下文同时对显存和训练数据量的要求也直线上升。我的建议很直接团队第一次做、显存不超过24GB、数据量在300-500例先走2D检测路线数据量超过800例、且病灶以微小多发为主再考虑patch-based 3D。two-stage方案先检测候选区域再精细分类在肝脏肿瘤上收益没那么明显因为病灶和背景的类间差异本身不大two-stage的第二阶段分类网络吃到的候选框如果定位偏差太大反而会把正常组织误判成肿瘤。3.2 2D检测路线在CT切片上用YOLO找病灶的工程操作2D路线把CT体数据按轴向切成slice每张切片当作一张普通图像喂给检测器。具体实现上YOLO系比Faster R-CNN更常用原因不是精度更高而是推理速度快、部署简单小团队的迭代效率决定了最终能调几轮参数。输入尺寸建议用512x512原始分辨率别resize到416或640——肝脏肿瘤的CT切片本来就是512x512resize只会丢掉小病灶的像素信息。YOLO最需要改的是anchor。默认anchor是COCO数据集上聚类出来的COCO的物体占图像比例普遍比较大而肝脏肿瘤在512x512切片上10mm病灶也就占20x20像素左右。常见做法是用训练集自己的标注框重新聚类anchork-means距离用box IoU而不是欧氏距离。# yolov8 训练配置示例关键参数按肝脏肿瘤场景调整 train: ./data/train.txt val: ./data/val.txt # 输入尺寸保持512x512不降到640以下 imgsz: 512 # 重新聚类后的anchor尺寸单位像素 # 10mm肿瘤约20x2030mm约60x6080mm以上约150x150 anchors: - [10, 10, 20, 15, 15, 30] # 小目标 - [30, 30, 60, 45, 45, 60] # 中目标 - [80, 80, 120, 120, 160, 160] # 大目标 # 医学影像数据量小关闭mosaic避免窗宽窗位语义被拼坏 mosaic: 0.0 mixup: 0.0 # 正样本分配阈值适当放宽 anchor_t: 4.0 # 训练轮次放长配合早停 epochs: 300 patience: 30anchor分三档覆盖从10px到160px的尺度范围聚类时如果发现小目标样本占比过低需要单独对小尺寸标注框做一次过采样再聚类否则聚类结果会被大肿瘤拉偏。mosaic增强在自然图像上好用但在CT上会把不同患者的窗宽窗位拼到同一张图里模型被迫去学“拼接缝”特征这里直接关掉。anchor_t从默认值放宽到4.0让更多低IoU的预测框参与正样本分配对边界模糊的小病灶更友好。标注方式有个容易被忽略的细节同一病灶会出现在连续多张切片上每张切片都要标一个框但框的id要共享。这样才能在训练时让网络看到“同一目标在不同切片上的形态变化”推理阶段也方便沿z轴合并。3.3 3D折中方案patch式三维卷积怎么在显存受限时落地真3D网络不是不能训是一张完整的512x512x300体数据直接喂进去单卡A100都吃力。常见做法是patch-based训练从体数据里随机裁剪64x64x32的patch按“是否包含肿瘤中心点”来平衡正负样本。正样本以肿瘤中心为基准裁负样本在远离任何标注框的区域随机裁。这样批量大小可以开到8-16显存占用可控。3D U-Net的输出是逐体素的分割概率图推理时做连通域分析就能得到病灶列表。和2D检测相比它天然利用z轴上下文——一个在单层切片上只有5个像素的病灶在16层连续切片上可能是清晰的团块。代价是推理速度慢一个数量级一个全肝扫描滑窗推理要几分钟。如果科室的MRI、CT机器同时连着多台工作站这个延迟可能无法接受。折中方案是把2D检测和3D分割串起来先用2D检测器快速筛出疑似切片区间只在这些区间上跑3D patch既保住3D的上下文优势又把推理时间压到30秒内。这个方案的小坑是要保证2D检测器的召回率足够高——召回率低于95%时漏掉的切片区间直接导致3D确认阶段根本看不到病灶整体灵敏度反而不如纯2D。所以串行方案上线前2D部分的漏检分析必须单独做一轮。4. 训练与评估参数让检测模型在肝脏CT上收敛的实操配置4.1 损失函数与采样策略把正负样本比例失衡压下去肝脏CT切片上肿瘤区域通常占整张图像面积的1%以下检测器默认的损失函数在这种极端正负比例下会被负样本主导模型学到的就是“全部预测为背景”。YOLO系损失函数本身已经分成了box_loss、cls_loss、dfl_loss三个部分其中cls_loss建议换成focal loss变体。focal loss的核心思想是让模型把注意力放在“难分样本”上对那些已经预测得很准的样本降权对预测概率在0.5附近摇摆的样本加权重公式为FL(p_t) -α_t(1-p_t)^γ log(p_t)其中γ取2.0、α取0.25是分类问题常用的起点。采样策略比损失函数的影响更直接。常见做法是每张切片限制负样本数量YOLO在训练时会为每个gt框分配正样本剩下的anchor都算负样本。在肝脏CT场景下可以做一次统计——记录每张切片上anchor的负正比例把超过500:1的样本丢弃或者降采样。另一个实用操作是离线难例挖掘先拿一个训练好的模型跑一遍训练集把误报最多的切片挑出来单独加大这些切片在训练数据流中的出现频率。sampler的batch组织也要注意。按患者为单位组织batch每个batch内尽量来自同一个患者的不同切片区间而不是随机混搭。这样batch内部的图像分布更一致梯度方向更稳定训练收敛快且不容易震荡。4.2 评价指标Dice、IOU与FROC各自在看什么医学影像检测的评价指标和自然图像mAP不完全是一回事写论文和做工程选指标的逻辑也不一样。分割掩码任务看Dice它衡量两个区域的重叠程度Dice 2×|A∩B| / (|A||B|)对边界的分割质量敏感但容易被大面积背景拉高所以只看Dice会骗人。检测框任务看IOU在0.5和0.75两个阈值下分别统计mAP0.75阈值更严格对定位精度的要求更高。做临床应用时FROC曲线比mAP更有参考价值。FROC的横轴是平均每例假阳性数FP/scan纵轴是灵敏度允许同一个病灶被预测多次只算一次命中。这意味着它衡量的是“在这个误报率下你能找到多少真病灶”而不是“每个框找得多准”。临床上接受的标准通常是每例假阳性不超过2个时灵敏度达到90%以上达不到这个数医生不会愿意在系统上花时间看结果。训练过程中我一般同时盯两个指标验证集的mAP0.5判断定位精度FROC判断临床可用性如果mAP提升但FROC下降多半是模型在重复预测同一病灶这时候要做的是改进NMS而不是继续训练。4.3 一张参数表带走输入尺寸、学习率、批量大小与训练轮次以下参数基于2D YOLO方案在512x512 CT切片上的经验值3D patch方案在batch size和学习率上需要另行调整。参数推荐值说明输入尺寸512x512保持CT原始分辨率不resizeBatch size8-16单卡24GB显存可跑16小于8时BN不稳定优化器AdamW比SGD收敛快配合weight decay5e-4初始学习率1e-4迁移学习场景可降到5e-5学习率调度Cosine Annealing避免训练后期lr过大在局部最优附近震荡训练轮次300轮早停医学小数据100轮前很难收敛数据增强旋转±10°、水平翻转、亮度对比度、弹性形变禁用mosaic和mixupEMA开启decay0.999减小验证集指标波动学习率是这里面最容易翻车的参数。1e-4是AdamW在检测任务上的保险值如果batch size只有4-8学习率要降到5e-5——batch越小梯度噪声越大学习率不降就会在训练中期loss震荡。弹性形变是医学影像增强里收益最高的操作之一肝脏肿瘤形态不规则、边缘模糊弹性形变让模型看到更多形态变异但幅度不要太大sigma取5-8个像素过强会产生不符合解剖结构的伪影。5. 训练与部署避坑5个让肝脏肿瘤检测模型原地翻车的问题5.1 数据泄漏同一患者的相邻切片同时出现在训练集和验证集现象是训练集loss降得很漂亮验证集mAP也异常高但换到一批新患者数据上检测率掉一半以上。原因是划分数据集时按切片随机划分同一个患者的几百张连续切片被分到了训练集和验证集。相邻切片在解剖结构上高度相似验证集里出现的“新数据”其实只是同一患者不同切片的微小平移模型相当于开了卷考试。解决方式是按患者ID划分数据集确保训练集、验证集、测试集的patient_id完全不重叠而不是按切片文件划分。划分后写一段代码检查集合交集并打印每个集合的患者数量防止排序错误导致id混在一起。5.2 窗宽窗位不一致训练正常、推理漏检的经典原因现象是模型在本地测试集上表现正常部署到医生工作站后原本能检出的病灶大量漏检。原因在于推理环境的图像显示或预处理代码使用了不同的窗宽窗位。DICOM查看器通常允许医生手动调节窗宽窗位如果推理应用直接读取了查看器当前的显示参数输入分布就和训练时完全不一致。解决方式是把窗宽窗位参数固化到推理服务配置里设置为和训练时一致的level50、width300。另外要注意如果训练数据里有静脉期和动脉期混合的CT两个期相的肝实质和病灶HU值分布差异很大建议按期相分别训练模型或者在预处理里加一个期相分类分支。5.3 小肿瘤被下采样丢掉网络看得见但梯度学不到现象是模型对10mm以上肿瘤检测效果不错对5mm以下病灶几乎零检出。原因有两层第一是把512x512切片resize到416或更小尺寸时小肿瘤只剩几个像素卷积下采样两层后特征直接消失第二是anchor聚类时小尺寸样本占比太低聚类结果被大肿瘤主导小目标没有匹配的anchor。解决方式是推理和训练都保持原始512x512分辨率不做全局resize。anchor聚类前按病灶尺寸分层统计如果小目标占数据集比例低于5%考虑用小目标过采样或单独为小目标设置一组anchor。滑窗推理也是备选方案把512x512切成四个256x256带重叠的patch分别推理后再合并但推理时间翻四倍需权衡。5.4 过拟合假象训练loss下降、验证指标纹丝不动现象是训练loss持续走低验证集mAP在某个值附近不再动弹看起来像模型还在学、但验证已经饱和。原因通常是数据增强过强把CT窗宽窗位分布扭曲到了偏离真实范围的程度模型在增强后的数据上学到的特征和真实数据对不上。解决方式是做增强强度的消融先关掉所有增强跑20轮看验证集baseline再逐个开启增强项并观察验证集变化。如果开启某一项增强后验证指标不升反降说明该项增强不适合你的数据分布。另外验证集本身太小也会导致这个现象——验证集只有3-5例患者随机抽样的波动就足以掩盖真实的指标变化把验证集扩充到至少10例患者才能看到可靠曲线。5.5 推理管线与训练管线不一致归一化参数和预处理顺序都要固定现象是最隐蔽的训练代码里跑测试一切正常封装成推理服务后结果变差但差得不多让人怀疑是模型加载问题而不是管线问题。原因几乎总是预处理顺序不一致。比如训练时归一化的均值和方差是从训练集统计的固定值推理时如果重新对当前图像计算了均值和方差输入分布就会偏移再比如训练时先resize后clip推理时先clip后resize像素分布完全不同。解决方式是把预处理写成独立模块训练、验证、推理共用同一个函数并且对输入输出写单测断言——同一张CT图训练脚本预处理后的数组和推理服务的预处理数组必须逐位相等。我在项目里会用一组固定的10张切片做管线一致性测试每次部署前跑一遍这个习惯帮你省掉至少两轮“线上结果不对”的排查时间。6. 从检测框到临床应用把模型输出变成医生能用的辅助判断6.1 Grad-CAM热力图让检测框的决策依据可见检测框告诉医生“这里有问题”但没说“为什么”。实际临床场景中医生很难信任一个说不清依据的黑匣子这时需要用Grad-CAM生成热力图让模型决策的注意力区域可视化叠加到CT原图上给医生复核。Grad-CAM的思路是把最后一层卷积的特征图取出来用类别得分对这些特征图的梯度做全局平均池化得到权重再对特征图加权求和后过ReLU激活得到的就是模型关注的区域。import torch import torch.nn.functional as F def generate_gradcam(model, image_tensor, target_layer): image_tensor: [1, 3, 512, 512] 的输入切片 target_layer: 最后一层卷积层模块 返回: [512, 512] 的热力图数组0~1范围 gradients [] activations [] def forward_hook(module, input, output): activations.append(output.detach()) def backward_hook(module, grad_input, grad_output): gradients.append(grad_output[0].detach()) # 注册hook捕获前向特征和反向梯度 forward_handle target_layer.register_forward_hook(forward_hook) backward_handle target_layer.register_backward_hook(backward_hook) output model(image_tensor) # 前向推理 target_score output[0, 0] # 取肿瘤类别的得分假设二分类 model.zero_grad() target_score.backward() # 反向传播计算梯度 # 对梯度做全局平均池化得到权重 weights torch.mean(gradients[0], dim(2, 3), keepdimTrue) cam F.relu(torch.sum(activations[0] * weights, dim1, keepdimTrue)) # 上采样到原图尺寸并归一化 cam F.interpolate(cam, size(512, 512), modebilinear, align_cornersFalse) cam cam.squeeze().cpu().numpy() cam (cam - cam.min()) / (cam.max() - cam.min() 1e-8) forward_handle.remove() backward_handle.remove() return camgrad-cam里有几个工程细节。target_layer选择最后一层卷积而不是全连接层因为卷积特征保住了空间位置信息全连接层会把位置信息抹平。backward_hook取grad_output[0]而不是grad_input前者是输出侧梯度尺寸和特征图一致后者是输入侧梯度会多一层维度。归一化时加1e-8防止除零叠加到CT图上时用Jet colormap或透明度混合让医生一眼看出模型聚焦的区域是不是病灶本身。6.2 切片检测合并成病例级结论3D NMS与体积估算2D路线在每张切片上输出一堆检测框但临床诊断需要的是“这个患者有几个病灶、每个在哪、多大”。所以切片级结果合并成一个病例级病灶列表是必须做的事不能简单对所有框跑全局NMS。同一病灶在连续切片上出现相邻切片的框在xy平面上高度重叠但z轴坐标逐步移动全局NMS按2D框的平面IOU做抑制会把相邻切片的同一病灶误判成多个不同病灶。常见做法是沿z轴做聚类按切片序号排序连续的切片上如果框的中心点在xy平面距离小于阈值比如10mm并且z轴间距不超过连续3张切片就归为同一个病灶。聚类完成后每个病灶记录中心坐标、最大直径和体积估计。体积估计的做法是把该病灶覆盖的连续切片厚度乘以每张切片上的平面面积求和即V Σ(A_i × slice_thickness)A_i是第i张切片上检测框的面积。合并结果要给医生展示结构化信息不能只给一张标记图。病灶编号、最大径、体积、所在肝段根据Couinaud分段需要额外配准逐项列出。这些信息直接对接PACS和报告系统医生确认后才算完成闭环。6.3 独立测试集验证用20例重新勾画的数据给模型兜底模型训练时用的验证集在调试过程中被反复看过指标再高也说明不了最终效果。我会在项目后期找合作医生对20例全新数据做独立标注这20例不参与训练也不参与调参只做一次最终评估。评估指标看三样病灶级灵敏度100个标注病灶里检出几个、每例假阳性数平均每例几个误报、以及最大径测量误差模型预测直径和医生标注直径的绝对差值。这三项指标决定了模型能不能进临床试用。灵敏度至少90%否则漏检比误报更让医生反感每例假阳性不超过2个超过的话医生看报告的时间成本高于收益最大径测量误差在10mm以内因为肿瘤大小直接决定TNM分期和治疗方案选择。达不到这些指标要么调模型阈值、要么改方案不要硬上线。说一个我自己的教训第一次做肝转移瘤检测模型时验证集mAP有0.72信心满满进入独立测试结果灵敏度只有71%。后来查到原因是训练集里增强期CT占了80%独立测试数据一半是平扫平扫的病灶对比度更低模型完全没见过。从那以后我做的每个医学影像项目都会先把期相分布统计表拉出来训练集和独立测试集时期相比例严格对齐。这一条也希望帮到你——数据分布比模型结构更值得花时间。本文还有配套的精品资源点击获取
返回列表