ARTICLE DETAIL

资讯详情

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

深度学习识别癌细胞:DNN与CNN图像分类实验对比与PyTorch复现

深度学习识别癌细胞:DNN与CNN图像分类实验对比与PyTorch复现 简介基于深度学习的癌细胞图像识别技术文献适合人工智能、医学图像处理方向的学生与研究者参考。内容将技术综述与实验分析结合围绕深度神经网络和卷积神经网络在癌细胞分类中的应用展开详细介绍了反向传播算法、激活函数、损失函数、网络结构设计与参数调整方法并给出分别包含两千张、四千张图片的数据集对比实验直观说明卷积神经网络模型的准确率高于深度神经网络模型同时扩大数据集能够提升识别准确率。资源为一个PDF格式文件压缩包约一点三九兆字节便于下载阅读目前已有三百零五人学习。读者可借助该文献快速了解深度学习用于癌细胞图像识别的整体流程与关键结论也可作为论文写作、课题调研或课程设计的技术参考。1. 深度学习识别癌细胞一份能直接对着复现的实验笔记癌症之所以难缠很大程度上在于发现得太晚。常规体检里的化验、CT、核磁共振要么成本高要么对早期病变不敏感。而深度学习图像识别的思路完全不同——只要有一张细胞病理图片模型就能在几秒内给出“是否癌变”的初步判断。这份 PDF 就是一篇完整的实验记录作者用 DNN 和 CNN 两种模型在一个公开的皮肤细胞数据集上做二分类DNN 的准确率在 73% 左右CNN 能到 78%而且把数据集从 2000 张扩到 4000 张后CNN 的准确率又涨了 3%。如果你正在做医学图像分类、细胞识别相关的课程设计或入门项目这份资料的价值在于它把网络结构、参数设置、训练策略、结果对比写得非常具体照着搭一遍你就能说清楚“为什么 CNN 比 DNN 更适合图像分类”这个经典问题。2. 先把 DNN 跑通全连接结构的层级参数与反向传播2.1 为什么先讨论 DNN 而不是直接上 CNNDNN 是深度学习的骨架。原文给出的 DNN 模型是一个五层全连接网络输入层之后接四个隐藏层单元数分别为 218、126、32、8最后接输出层做二分类。每张图片先裁剪成 64×64×3 的张量再拉平成一维向量喂进网络。这个设计的直观逻辑是既然细胞癌变的本质是细胞外形改变那么理论上只要网络容量足够大全连接结构也能从像素分布里“背”出癌变特征。但实际跑下来你会发现DNN 在图像任务上的瓶颈不在容量而在特征提取效率——它把每个像素都当成独立特征对待完全无视了像素之间的空间邻接关系。这里还有一个关键细节激活函数的选取。前三层隐藏层用 ReLU第四层用 Sigmoid。ReLU 的计算是 f(x)max(0,x)它的好处是缓解梯度消失计算开销也小而最后一层用 Sigmoid 是为了把输出压缩到 0 到 1 之间配合交叉熵损失做二分类。这个搭配是图像分类里很经典的组合不建议随意改动。2.2 搭建 DNN 的代码骨架与参数说明用 PyTorch 复现原文的 DNN 结构代码非常直接import torch.nn as nn class DNN(nn.Module): def __init__(self, input_dim64*64*3): super(DNN, self).__init__() self.fc1 nn.Linear(input_dim, 218) self.fc2 nn.Linear(218, 126) self.fc3 nn.Linear(126, 32) self.fc4 nn.Linear(32, 8) self.fc5 nn.Linear(8, 1) self.relu nn.ReLU() self.sigmoid nn.Sigmoid() def forward(self, x): x x.view(x.size(0), -1) # 将 64*64*3 拉平成向量 x self.relu(self.fc1(x)) x self.relu(self.fc2(x)) x self.relu(self.fc3(x)) x self.sigmoid(self.fc4(x)) x self.sigmoid(self.fc5(x)) return x这段代码里x.view(x.size(0), -1)是把四维张量展平成二维-1表示自动推算第二维也就是 64×64×312288。四个nn.Linear的输入输出维度严格对照原文的 218、126、32、8。注意第四层用的是 Sigmoid 而不是 ReLU这是原文明确写的——前面三层做非线性变换最后一层用 Sigmoid 做概率输出。如果你把第四层也换成 ReLU训练曲线会明显变差这不是玄学是 Sigmoid 的输出范围决定了它适合做概率映射。训练时原文用的损失函数是交叉熵更新方式是随机梯度下降SGD学习率 0.001。下面这段是训练循环的核心import torch.optim as optim model DNN() criterion nn.BCEWithLogitsLoss() optimizer optim.SGD(model.parameters(), lr0.001) for epoch in range(500): for batch_x, batch_y in train_loader: optimizer.zero_grad() output model(batch_x) loss criterion(output, batch_y.unsqueeze(1)) loss.backward() optimizer.step()BCEWithLogitsLoss是二元交叉熵损失它内部已经把 Sigmoid 和损失计算合并了数值上比手动算更稳定。unsqueeze(1)是因为模型的输出形状是(batch_size, 1)而数据标签通常是(batch_size,)需要对齐维度。原文的 batch size 是 4这个值非常小梯度更新噪声大训练曲线会抖得厉害后面避坑章节会细说。2.3 DNN 训练结果里藏着的两个信号原文给出的 DNN 结果很有代表性2000 张图片时准确率 72%4000 张时 73%但损失高得吓人4000 张数据集下测试集损失在 0.7 左右。为什么准确率看起来还行损失却这么大因为准确率只看预测类别对不对损失还额外惩罚了“置信度错误”——比如模型对某张图只有 55% 的把握说它是癌细胞但碰巧分类对了准确率算你赢损失却不会放过你。另一个信号是测试集损失在 0.8 上下波动而训练集能降到 0.27。这是典型的过拟合加上学习率偏大共同作用的结果。数据少、模型参数多全连接层光第一层就有 12288×218≈268 万个参数DNN 很容易把训练集的细节“背下来”而不是把癌变特征“学下来”。3. CNN 的结构设计与参数推导为什么它能比 DNN 高 5 个百分点3.1 卷积、池化、权值共享三个减少计算量的关键设计CNN 和 DNN 最本质的区别是连接方式。DNN 是全连接每个神经元和上一层的所有神经元都有连接CNN 是局部连接每个神经元只感知图像的一小块区域。这个设计来源于图像本身的特性——像素与周围像素的相关性远大于与远处像素的相关性所以局部感知就够了。权值共享则进一步压缩了参数量同一组卷积核在整张图上滑动参数完全复用。这两个机制叠加让 CNN 在同等甚至更少的参数量下能提取出更有判别力的空间特征。原文的 CNN 结构是三次“卷积池化”的堆叠具体参数如下表阶段卷积核数量卷积核大小步长输入张量输出张量池化第一次167×7132×32×326×26×162×2 最大池化 → 13×13×16第二次326×6113×13×168×8×322×2 最大池化 → 4×4×32第三次642×214×4×322×2×642×2 最大池化 → 1×1×64尺寸变化的计算规则是输出尺寸 (输入尺寸 - 卷积核尺寸) / 步长 1。比如第一次卷积(32-7)/1126池化后 26/213。第二次(13-6)/118池化后 8/24。第三次(4-2)/112池化后 2/21。如果你调整了输入图片的尺寸后面每一层的输出尺寸都要用这个公式重新推一遍这是复现时最容易算错的地方别偷懒。3.2 用 PyTorch 复现 CNN 结构class CNN(nn.Module): def __init__(self): super(CNN, self).__init__() self.conv_block nn.Sequential( nn.Conv2d(3, 16, kernel_size7, stride1), # 32*32*3 - 26*26*16 nn.MaxPool2d(kernel_size2), # 26*26*16 - 13*13*16 nn.ReLU(), nn.Conv2d(16, 32, kernel_size6, stride1), # 13*13*16 - 8*8*32 nn.MaxPool2d(kernel_size2), # 8*8*32 - 4*4*32 nn.ReLU(), nn.Conv2d(64, 64, kernel_size2, stride1), # 4*4*32 - 2*2*64 nn.MaxPool2d(kernel_size2), # 2*2*64 - 1*1*64 nn.ReLU(), ) self.fc nn.Linear(64, 120) # 展平后接 120 单元全连接 self.output nn.Linear(120, 1) def forward(self, x): x self.conv_block(x) x x.view(x.size(0), -1) # 1*1*64 展平成 64 维向量 x torch.relu(self.fc(x)) x torch.sigmoid(self.output(x)) return x注意原文第三次卷积写的是用 64 个 2×2 卷积核对 4×4×32 的张量做卷积得到 2×2×64。但这里有一个原文没交代清楚的小坑4×4×32 经过 2×2 卷积后输出通道数取决于卷积核数量64 个卷积核得到的是 64 个通道所以nn.Conv2d(32, 64, kernel_size2)前一个参数应该是输入通道 32后一个才是输出通道 64千万别写成nn.Conv2d(64, 64, ...)那样会直接报维度不匹配的错误。这里还有一个值得注意的地方第三次卷积后其实还需要经过一次池化才能从 2×2 变成 1×1原文的描述顺序是先池化再激活代码里我把这个顺序固定成了“卷积 → 池化 → 激活”这也是工程上的常见惯例。3.3 CNN 的参数量优势是结构性的把两个模型的参数量摆在一起对比你就能直观理解差距从哪里来了。DNN 第一层全连接就有 12288×218≈268 万个参数整个模型参数量在 280 万左右。CNN 的三个卷积层加起来参数量是 16×7×7×3 32×6×6×16 64×2×2×32 2352 18432 8192 ≈ 2.9 万再加上全连接层 64×120 120×1 ≈ 7800总共不过 3.7 万。参数量差了将近两个数量级而 CNN 的准确率反而更高这说明卷积结构在图像特征提取上的效率是碾压式的高。如果你在答辩或汇报里要解释“为什么 CNN 效果更好”这个参数量的对比是最有说服力的数据点。4. 实验设计与复现步骤数据集划分、训练参数与评估口径4.1 数据集来源与预处理细节原文使用的数据集来自 Tschandl 公开的皮肤镜图像数据集即 HAM10000其中包含 13779 张正常细胞图片和 13779 张癌细胞图片图片大小在 100×100×3 到 120×120×3 之间。作者从中挑出 4000 张做实验。这里要注意的是HAM10000 的原始数据不是整齐划一的尺寸而且类别分布并不完全均衡所以不能直接拿原始文件去训练先做统一裁剪预处理from PIL import Image import os def preprocess_images(src_dir, dst_dir, size(64, 64)): os.makedirs(dst_dir, exist_okTrue) for fname in os.listdir(src_dir): img Image.open(os.path.join(src_dir, fname)).convert(RGB) img img.resize(size, Image.Resampling.LANCZOS) img.save(os.path.join(dst_dir, fname))这里用resize而不是crop因为原文说“随机对图片进行裁剪”随机裁剪通常用于数据增强但在复现时先用中心缩放统一尺寸更稳妥后续要加随机裁剪可以让它在训练循环里做在线增强。convert(RGB)是确保所有图片统一成三通道有些医学图像可能是灰度图不做这一步会直接导致通道数不匹配模型根本跑不起来。实验划分方式原文写得很清楚2000 张图片的实验中癌细胞与正常细胞各 1000 张其中 900 张训练、100 张测试4000 张图片的实验中各 2000 张其中 1800 张训练、200 张测试。这个划分的关键是癌变/正常样本数严格对半不让类别不平衡干扰准确率评判。4.2 训练参数对照表与 PyTorch 实现两个模型的训练参数差别很大我把原文的数据整理成一张对照表参数DNNCNN输入尺寸裁剪为 32×32×3随机裁剪 32×32×3后缩小为 64×64×3Batch size432学习率0.0010.001Epoch500500优化器SGDSGD图片翻转概率未提及0.5损失函数交叉熵交叉熵最终测试准确率73%78%最终测试损失0.70.51注意 DNN 的 batch size 是 4CNN 是 32。batch size 直接决定梯度更新的稳定性和训练速度。DNN 用 4 是因为它参数多、每步更新开销大小 batch 可以降低显存压力但代价是梯度噪声大这在损失曲线上表现为剧烈震荡。CNN 用 32 则更接近工程常规收敛也更平稳。图片翻转概率 0.5 是数据增强手段原文在 CNN 里用了在 DNN 里没提——这个不对称其实已经暗示了作者对两种模型泛化能力的预期。用 PyTorch 加载数据并训练的核心逻辑如下from torch.utils.data import Dataset, DataLoader from torchvision import transforms transform_train transforms.Compose([ transforms.RandomResizedCrop(64, scale(0.8, 1.0)), transforms.RandomHorizontalFlip(p0.5), transforms.ToTensor(), transforms.Normalize(mean[0.5, 0.5, 0.5], std[0.5, 0.5, 0.5]) ]) train_loader DataLoader(train_dataset, batch_size32, shuffleTrue)RandomResizedCrop对应原文的“随机对图片进行裁剪”RandomHorizontalFlip对应“图片翻转概率为 0.5”。注意ToTensor会把 PIL 图片从 HWC 格式转为 CHW 的张量并把像素值从 0-255 缩放到 0-1。Normalize则是把数据从 0-1 范围再缩放到 -1 到 1这一步能加速收敛。原文没有明确提到归一化但实践中这是图像分类不能省的步骤。4.3 准确率与损失的计算口径准确率的计算规则是分类正确的样本数除以测试样本总数。这个定义本身没有歧义但复现时有三个细节值得较真。第一测试集要单独划分不能在训练集上算准确率否则看到的 90% 只是“背题”的能力第二每个 epoch 结束后都要在测试集上跑一次评估记录损失和准确率这样才能画出损失曲线和准确率曲线第三数据划分要保持固定原文两次实验用的是同一个数据集如果你的复现想让两次结果可比必须用固定的随机种子来划分数据否则 1% 到 3% 的准确率差异会被数据划分的随机性完全淹没。5. 踩坑记录训练曲线不收敛、损失波动大的四个典型问题5.1 测试集损失不降反升训练集却一路走低现象原文 DNN 实验里训练集损失从 0.6 降到 0.27测试集损失却从 0.6 升到 0.8 上下波动两者越拉越远。原因这就是过拟合的标准形态。DNN 的全连接结构把大量参数堆在像素级特征上数据只有 2000 张模型很快就“记住”了训练集的细节但没见过的新图片它泛化不动。再加上学习率 0.001 对 SGD 来说偏大参数在最优解附近来回震荡测试集损失曲线看起来就像在“随机游走”。解决先把学习率降到 0.0001 试试然后把 DNN 的隐藏层单元数从 218、126、32、8 缩减一半或者加 Dropout最简单有效的办法是换成 CNN——原文的对比实验已经证明了这一点。5.2 CNN 训练集和测试集损失差距固定消除不掉现象CNN 在 4000 张数据集上训练集损失降到 0.4 左右测试集停在 0.5 左右两条曲线平行了一段时间差距始终保持在 0.1。原因这是数据分布差异导致的轻微过拟合不严重但很顽固。医学图像本身存在拍摄设备、光照、染色差异训练集和测试集不可能完全同分布。解决增加数据增强强度比如加入随机旋转、亮度抖动、高斯噪声让模型见过更多“长得不一样”的细胞图片能小幅压缩这个差距。如果还是压不下去说明数据集规模到了上限再硬调参反而可能适得其反。5.3 数据集从 2000 加到 4000DNN 只涨了 1%现象DNN 准确率从 72% 变 73%CNN 从 75% 变 78%同样翻倍数据提升幅度差了 2 个百分点。原因DNN 的全连接结构受限于特征表达能力增加数据“喂”给它的是更多样本但它没有能力从中提取出新的区分性特征CNN 则能把新增数据里的形态多样性转换成更稳的卷积核权重。解决这个结果本身就是一个很好的实验结论不建议为了让 DNN 也涨 3% 去硬堆数据。更合理的做法是承认 CNN 更适合此类任务把精力放在调整 CNN 的卷积核尺寸和层数上——比如试试把第一次卷积的 7×7 核换成两个 3×3 核串联感受野不变但参数量更小。5.4 图片尺寸不统一导致张量维度报错或模型崩溃现象直接拿 HAM10000 原始图片训练某些图片尺寸是 100×100×3有些是 120×120×3输入网络时报维度不匹配或者训练时损失突然变成 NaN。原因没有做统一的 resize 预处理不同 batch 里的图片张量形状不一致PyTorch 的 DataLoader 默认用 collate 函数堆叠张量形状不一致直接抛异常。解决在数据加载前用统一尺寸做 resize上面preprocess_images函数里的img.resize(size, Image.Resampling.LANCZOS)就是干这个的。注意 LANCZOS 是高质量重采样算法对医学图像这种细节敏感的数据集不要为了省时间换成 NEAREST否则会损失边缘信息。6. 把模型训练到 78% 再往前一步验证口径与可控变量实验清单复现这份实验的价值不止于跑到 78% 准确率更在于建立一套“能判断模型好坏”的验证口径。我的做法是固定四个数字数据划分随机种子固定为 42训练轮次固定 500学习率固定 0.001测试集比例固定 10%。这四个条件一旦锁定任何一次参数调整产生的影响都能被准确度量否则每次结果差异都分不清是参数变了还是数据划分变了。在此基础上我建议做一个可控变量实验清单每组实验只改一个参数其他全部保持一致实验组改动参数预期观察点基线无照原文复现 75%~78% 准确率学习率改为 0.0005收敛更慢但曲线更平滑Batch size改为 64训练速度变快测试准确率可能小幅波动数据增强关闭随机翻转过拟合加重测试损失上升卷积核第一次卷积 7×7 改为两个 3×3参数量下降准确率可能持平或略升每组跑完记录测试集准确率和损失画在同一张坐标图里。哪个参数对结果影响最大一眼就能看出来。训练完成后不要只报告准确率把训练集和测试集的损失曲线一起贴出来。准确率可能因为类别不平衡而虚高但损失曲线能暴露模型是否过拟合、是否欠拟合、是否学习率过大。我在复现时发现CNN 的测试集损失在 epoch 200 之后基本进入平台期所以在第 200 轮附近保存模型权重准确率反而比训练满 500 轮更稳定。从那以后我每次跑图像分类模型都会在黑盒子里强制走一遍“保存最佳模型而不是最后模型”的流程——只保留测试集损失最小的那个 checkpoint而不是按 epoch 数硬存这样你交出去的结果和写进报告的结果才是真实可复现的。这份资源虽然不是现成的代码库但它把网络结构和实验参数交代得足够细拿它当骨架把代码补齐的过程本身就是一次很扎实的深度学习实战训练。希望帮到你。本文还有配套的精品资源点击获取
返回列表