挑战杯 基于卷积神经网络的乳腺癌分类 深度学习 医学图像

文章目录

  • 1 前言
  • 2 前言
  • 3 数据集
    • 3.1 良性样本
    • 3.2 病变样本
  • 4 开发环境
  • 5 代码实现
    • 5.1 实现流程
    • 5.2 部分代码实现
      • 5.2.1 导入库
      • 5.2.2 图像加载
      • 5.2.3 标记
      • 5.2.4 分组
      • 5.2.5 构建模型训练
  • 6 分析指标
    • 6.1 精度,召回率和F1度量
    • 6.2 混淆矩阵
  • 7 结果和结论
  • 8 最后

1 前言

🔥 优质竞赛项目系列,今天要分享的是

基于卷积神经网络的乳腺癌分类

该项目较为新颖,适合作为竞赛课题方向,学长非常推荐!

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

2 前言

乳腺癌是全球第二常见的女性癌症。2012年,它占所有新癌症病例的12%,占所有女性癌症病例的25%。

当乳腺细胞生长失控时,乳腺癌就开始了。这些细胞通常形成一个肿瘤,通常可以在x光片上直接看到或感觉到有一个肿块。如果癌细胞能生长到周围组织或扩散到身体的其他地方,那么这个肿瘤就是恶性的。

以下是报告:

  • 大约八分之一的美国女性(约12%)将在其一生中患上浸润性乳腺癌。
  • 2019年,美国预计将有268,600例新的侵袭性乳腺癌病例,以及62,930例新的非侵袭性乳腺癌。
  • 大约85%的乳腺癌发生在没有乳腺癌家族史的女性身上。这些发生是由于基因突变,而不是遗传突变
  • 如果一名女性的一级亲属(母亲、姐妹、女儿)被诊断出患有乳腺癌,那么她患乳腺癌的风险几乎会增加一倍。在患乳腺癌的女性中,只有不到15%的人的家人被诊断出患有乳腺癌。

3 数据集

该数据集为学长实验室数据集。

搜先这是图像二分类问题。我把数据拆分如图所示

    dataset train
      benign
       b1.jpg
       b2.jpg
       //
      malignant
       m1.jpg
       m2.jpg
       //  validation
       benign
        b1.jpg
        b2.jpg
        //
       malignant
        m1.jpg
        m2.jpg
        //...

训练文件夹在每个类别中有1000个图像,而验证文件夹在每个类别中有250个图像。

3.1 良性样本

在这里插入图片描述
在这里插入图片描述

3.2 病变样本

在这里插入图片描述
在这里插入图片描述

4 开发环境

  • scikit-learn
  • keras
  • numpy
  • pandas
  • matplotlib
  • tensorflow

5 代码实现

5.1 实现流程

完整的图像分类流程可以形式化如下:

我们的输入是一个由N个图像组成的训练数据集,每个图像都有相应的标签。

然后,我们使用这个训练集来训练分类器,来学习每个类。

最后,我们通过让分类器预测一组从未见过的新图像的标签来评估分类器的质量。然后我们将这些图像的真实标签与分类器预测的标签进行比较。

5.2 部分代码实现

5.2.1 导入库

  
    import json
    import math
    import os
    import cv2
    from PIL import Image
    import numpy as np
    from keras import layers
    from keras.applications import DenseNet201
    from keras.callbacks import Callback, ModelCheckpoint, ReduceLROnPlateau, TensorBoard
    from keras.preprocessing.image import ImageDataGenerator
    from keras.utils.np_utils import to_categorical
    from keras.models import Sequential
    from keras.optimizers import Adam
    import matplotlib.pyplot as plt
    import pandas as pd
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import cohen_kappa_score, accuracy_score
    import scipy
    from tqdm import tqdm
    import tensorflow as tf
    from keras import backend as K
    import gc
    from functools import partial
    from sklearn import metrics
    from collections import Counter
    import json
    import itertools

5.2.2 图像加载

接下来,我将图像加载到相应的文件夹中。


    def Dataset_loader(DIR, RESIZE, sigmaX=10):
        IMG = []
        read = lambda imname: np.asarray(Image.open(imname).convert("RGB"))
        for IMAGE_NAME in tqdm(os.listdir(DIR)):
            PATH = os.path.join(DIR,IMAGE_NAME)
            _, ftype = os.path.splitext(PATH)
            if ftype == ".png":
                img = read(PATH)
               

                img = cv2.resize(img, (RESIZE,RESIZE))
               
                IMG.append(np.array(img))
        return IMG
    
    benign_train = np.array(Dataset_loader('data/train/benign',224))
    malign_train = np.array(Dataset_loader('data/train/malignant',224))
    benign_test = np.array(Dataset_loader('data/validation/benign',224))
    malign_test = np.array(Dataset_loader('data/validation/malignant',224))

5.2.3 标记

之后,我创建了一个全0的numpy数组,用于标记良性图像,以及全1的numpy数组,用于标记恶性图像。我还重新整理了数据集,并将标签转换为分类格式。


    benign_train_label = np.zeros(len(benign_train))
    malign_train_label = np.ones(len(malign_train))
    benign_test_label = np.zeros(len(benign_test))
    malign_test_label = np.ones(len(malign_test))
    

    X_train = np.concatenate((benign_train, malign_train), axis = 0)
    Y_train = np.concatenate((benign_train_label, malign_train_label), axis = 0)
    X_test = np.concatenate((benign_test, malign_test), axis = 0)
    Y_test = np.concatenate((benign_test_label, malign_test_label), axis = 0)
    
    s = np.arange(X_train.shape[0])
    np.random.shuffle(s)
    X_train = X_train[s]
    Y_train = Y_train[s]
    
    s = np.arange(X_test.shape[0])
    np.random.shuffle(s)
    X_test = X_test[s]
    Y_test = Y_test[s]
    
    Y_train = to_categorical(Y_train, num_classes= 2)
    Y_test = to_categorical(Y_test, num_classes= 2)

5.2.4 分组

然后我将数据集分成两组,分别具有80%和20%图像的训练集和测试集。让我们看一些样本良性和恶性图像


    x_train, x_val, y_train, y_val = train_test_split(
        X_train, Y_train, 
        test_size=0.2, 
        random_state=11
    )
    

    w=60
    h=40
    fig=plt.figure(figsize=(15, 15))
    columns = 4
    rows = 3
    
    for i in range(1, columns*rows +1):
        ax = fig.add_subplot(rows, columns, i)
        if np.argmax(Y_train[i]) == 0:
            ax.title.set_text('Benign')
        else:
            ax.title.set_text('Malignant')
        plt.imshow(x_train[i], interpolation='nearest')
    plt.show()

在这里插入图片描述

5.2.5 构建模型训练

我使用的batch值为16。batch是深度学习中最重要的超参数之一。我更喜欢使用更大的batch来训练我的模型,因为它允许从gpu的并行性中提高计算速度。但是,众所周知,batch太大会导致泛化效果不好。在一个极端下,使用一个等于整个数据集的batch将保证收敛到目标函数的全局最优。但是这是以收敛到最优值较慢为代价的。另一方面,使用更小的batch已被证明能够更快的收敛到好的结果。这可以直观地解释为,较小的batch允许模型在必须查看所有数据之前就开始学习。使用较小的batch的缺点是不能保证模型收敛到全局最优。因此,通常建议从小batch开始,通过训练慢慢增加batch大小来加快收敛速度。

我还做了一些数据扩充。数据扩充的实践是增加训练集规模的一种有效方式。训练实例的扩充使网络在训练过程中可以看到更加多样化,仍然具有代表性的数据点。

然后,我创建了一个数据生成器,自动从文件夹中获取数据。Keras为此提供了方便的python生成器函数。


    BATCH_SIZE = 16

    train_generator = ImageDataGenerator(
            zoom_range=2,  # 设置范围为随机缩放
            rotation_range = 90,
            horizontal_flip=True,  # 随机翻转图片
            vertical_flip=True,  # 随机翻转图片
        )

下一步是构建模型。这可以通过以下3个步骤来描述:

  • 我使用DenseNet201作为训练前的权重,它已经在Imagenet比赛中训练过了。设置学习率为0.0001。

  • 在此基础上,我使用了globalaveragepooling层和50%的dropout来减少过拟合。

  • 我使用batch标准化和一个以softmax为激活函数的含有2个神经元的全连接层,用于2个输出类的良恶性。

  • 我使用Adam作为优化器,使用二元交叉熵作为损失函数。

    
    
    def build_model(backbone, lr=1e-4):
        model = Sequential()
        model.add(backbone)
        model.add(layers.GlobalAveragePooling2D())
        model.add(layers.Dropout(0.5))
        model.add(layers.BatchNormalization())
        model.add(layers.Dense(2, activation='softmax'))
        
    
        model.compile(
            loss='binary_crossentropy',
            optimizer=Adam(lr=lr),
            metrics=['accuracy']
        )
        return model
    
    resnet = DenseNet201(
        weights='imagenet',
        include_top=False,
        input_shape=(224,224,3)
    )
    
    model = build_model(resnet ,lr = 1e-4)
    model.summary()
    

让我们看看每个层中的输出形状和参数。

在这里插入图片描述
在训练模型之前,定义一个或多个回调函数很有用。非常方便的是:ModelCheckpoint和ReduceLROnPlateau。

  • ModelCheckpoint:当训练通常需要多次迭代并且需要大量的时间来达到一个好的结果时,在这种情况下,ModelCheckpoint保存训练过程中的最佳模型。

  • ReduceLROnPlateau:当度量停止改进时,降低学习率。一旦学习停滞不前,模型通常会从将学习率降低2-10倍。这个回调函数会进行监视,如果在’patience’(耐心)次数下,模型没有任何优化的话,学习率就会降低。

在这里插入图片描述

该模型我训练了60个epoch。


    learn_control = ReduceLROnPlateau(monitor='val_acc', patience=5,
                                      verbose=1,factor=0.2, min_lr=1e-7)
    

    filepath="weights.best.hdf5"
    checkpoint = ModelCheckpoint(filepath, monitor='val_acc', verbose=1, save_best_only=True, mode='max')
    
    history = model.fit_generator(
        train_generator.flow(x_train, y_train, batch_size=BATCH_SIZE),
        steps_per_epoch=x_train.shape[0] / BATCH_SIZE,
        epochs=20,
        validation_data=(x_val, y_val),
        callbacks=[learn_control, checkpoint]
    )

6 分析指标

评价模型性能最常用的指标是精度。然而,当您的数据集中只有2%属于一个类(恶性),98%属于其他类(良性)时,错误分类的分数就没有意义了。你可以有98%的准确率,但仍然没有发现恶性病例,即预测的时候全部打上良性的标签,这是一个不好的分类器。


    history_df = pd.DataFrame(history.history)
    history_df[['loss', 'val_loss']].plot()
    

    history_df = pd.DataFrame(history.history)
    history_df[['acc', 'val_acc']].plot()

在这里插入图片描述

6.1 精度,召回率和F1度量

为了更好地理解错误分类,我们经常使用以下度量来更好地理解真正例(TP)、真负例(TN)、假正例(FP)和假负例(FN)。

精度反映了被分类器判定的正例中真正的正例样本的比重。

召回率反映了所有真正为正例的样本中被分类器判定出来为正例的比例。

F1度量是准确率和召回率的调和平均值。

在这里插入图片描述

6.2 混淆矩阵

混淆矩阵是分析误分类的一个重要指标。矩阵的每一行表示预测类中的实例,而每一列表示实际类中的实例。对角线表示已正确分类的类。这很有帮助,因为我们不仅知道哪些类被错误分类,还知道它们为什么被错误分类。


    from sklearn.metrics import classification_report
    classification_report( np.argmax(Y_test, axis=1), np.argmax(Y_pred_tta, axis=1))
    

    from sklearn.metrics import confusion_matrix
    
    def plot_confusion_matrix(cm, classes,
                              normalize=False,
                              title='Confusion matrix',
                              cmap=plt.cm.Blues):
        if normalize:
            cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
            print("Normalized confusion matrix")
        else:
            print('Confusion matrix, without normalization')
    
        print(cm)
    
        plt.imshow(cm, interpolation='nearest', cmap=cmap)
        plt.title(title)
        plt.colorbar()
        tick_marks = np.arange(len(classes))
        plt.xticks(tick_marks, classes, rotation=55)
        plt.yticks(tick_marks, classes)
        fmt = '.2f' if normalize else 'd'
        thresh = cm.max() / 2.
        for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
            plt.text(j, i, format(cm[i, j], fmt),
                     horizontalalignment="center",
                     color="white" if cm[i, j] > thresh else "black")
    
        plt.ylabel('True label')
        plt.xlabel('Predicted label')
        plt.tight_layout()
    
    cm = confusion_matrix(np.argmax(Y_test, axis=1), np.argmax(Y_pred, axis=1))
    
    cm_plot_label =['benign', 'malignant']
    plot_confusion_matrix(cm, cm_plot_label, title ='Confusion Metrix for Skin Cancer')


在这里插入图片描述

7 结果和结论

在这里插入图片描述
在这个博客中,学长我演示了如何使用卷积神经网络和迁移学习从一组显微图像中对良性和恶性乳腺癌进行分类,希望对大家有所帮助。

8 最后

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/406283.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数字滚动实现

介绍 vue-countup-v3 插件是一个基于 Vue3 的数字动画插件,用于在网站或应用程序中创建带有数字动画效果的计数器。通过该插件,我们可以轻松地实现数字的递增或递减动画,并自定义其样式和动画效果。该插件可以用于许多场景,例如展…

nginx 配置文件详细介绍

一, nginx 配置文件架构 上一篇 已对 main 全局配置做了详细介绍 本章对剩下的配置文件部分做介绍 二,event 设置 (一)event 相关的配置文件为 配置工作模式以及连接数 (二)具体表现 1&#xff…

抖音数据抓取工具|视频内容提取软件

引言部分: 介绍针对抖音视频下载需求开发的强大工具突出解决用户获取抖音视频繁琐问题的初衷 工具功能介绍: 详细描述工具功能,包括关键词搜索、自动批量抓取、选择性批量下载等提及基于C#开发的优势以及支持通过分享链接进行单个视频抓取…

k8s的svc流量通过iptables和ipvs转发到pod的流程解析

文章目录 1. k8s的svc流量转发1.1 service 说明1.2 endpoints说明1.3 pod 说明1.4 svc流量转发的主要工作 2. iptables规则解析2.1 svc涉及的iptables链流程说明2.2 svc涉及的iptables规则实例2.2.1 KUBE-SERVICES规则链2.2.2 KUBE-SVC-EFPSQH5654KMWHJ5规则链2.2.3 KUBE-SEP-L…

axios是如何实现的(源码解析)

1 axios的实例与请求流程 在阅读源码之前,先大概了解一下axios实例的属性和请求整体流程,带着这些概念,阅读源码可以轻松不少! 下图是axios实例属性的简图。 可以看到axios的实例上,其实主要就这三个东西&#xff1a…

自定义悬浮气泡组件

一.常用悬浮气泡展示 在一个项目中,常常会使用点悬浮展示,而市面上悬浮tooltip的组件非常多 例如常用的antd提供的Tooltip 用法如下(来自于官方文档示例): import React from react; import { Button, Tooltip, Con…

129 Linux 系统编程7 ,make 的编写和解析

前文中,我们有多少个.c文件,就需要build 出来多少个.o文件 假设我们的项目很大,怎么管理这些 .c文件呢? 这里就要学习一个make文件的编写了。 makefile 本质上是一个脚本语言 脚本语言实际上就是将一系列命令放在一起执行 mak…

服务器被黑该如何查找入侵痕迹以及如何防御攻击

当公司的网站服务器被黑,被入侵导致整个网站,以及业务系统瘫痪,给企业带来的损失无法估量,但是当发生服务器被攻击的情况,作为服务器的维护人员应当在第一时间做好安全响应,对服务器以及网站应以最快的时间…

程序环境和预处理(1)

文章目录 目录1. 程序的翻译环境和执行环境2. 详解编译链接2.1 翻译环境2.2 编译本身也分为几个阶段2.3 运行环境 3. 预处理详解3.1 预定义符号3.2 #define3.2.1 #define 定义标识符3.2.2 #define 定义宏3.2.3 #define 替换规则3.2.4 #和##3.2.5 带副作用的宏参数3.2.6 宏和函数…

HAT论文详解:Activating More Pixels in Image Super-Resolution Transformer

code:https://github.com/XPixelGroup/HAT paper: https://arxiv.org/abs/2309.05239 1. 概述 本文是对Swinir的改进,目前很多图像超分Benchmark的SOTA。相对于SwinIR的改进主要有三个地方:1. 引入Channel Attention,以获得更好的全局能力&…

【Linux】 login命令使用

login命令 在 Linux 中用于创建一个新的会话,并在新会话中登录用户。这个命令通常在终端中自动执行,当你打开一个新的终端会话或者通过 SSH 远程连接到 Linux 服务器时。 在命令后面附加欲登入的用户名称,它会直接询问密码,等待…

探索水下低光照图像检测性能,基于YOLOv3全系列【yolov3tiny/yolov3/yolov3spp】参数模型开发构建海底生物检测识别分析系统

海底这类特殊数据场景下的检测模型开发相对来说比较少,在前面的博文中也有一些涉及,感兴趣的话可以自行移步阅读即可: 《尝试探索水下目标检测,基于yolov5轻量级系列模型n/s/m开发构建海底生物检测系统》 《基于YOLOv5C3CBAMCBA…

Element table 实现表格行、列拖拽功能

安装包 npm install sortablejs --save <template><div class"draggable" style"padding: 20px"><el-table row-key"id" :data"tableData" style"width: 100%" border><el-table-columnv-for"(it…

【Linux】 faillock 命令使用

faillock 命令 faillock 命令是 PAM (Pluggable Authentication Modules) 的一部分&#xff0c;它被设计用来跟踪失败的登录尝试&#xff0c;并在连续失败尝试超过某个阈值时锁定账户。这个功能可以帮助系统管理员识别和防止暴力破解攻击。当一个用户连续多次输入错误的密码后&…

如何开发自己的npm包并上传到npm官网可以下载

目录 搭建文件结构 开始编写 发布到npm 如何下载我们发布的npm包 搭建文件结构 先创建新文件夹,按照下面的样子布局 .├── README.md //说明文档 ├── index.js //主入口 ├── lib //功能文件 └── tests //测试用例 然后再此根目录下初始化package包 npm init…

Cartographer 构建约束优化问题

计算优化的思路&#xff0c;需要两种坐标变换&#xff0c;用两种坐标变化的残差求解。 第一种残差 将节点与子图原点在global坐标系下的相对位姿与约束的差值作为残差项 第一种坐标变换&#xff1a;节点与子图原点在global坐标系下的坐标变换 第二种坐标变换&#xff1a;子图内…

NXP实战笔记(八):S32K3xx基于RTD-SDK在S32DS上配置LCU实现ABZ解码

目录 1、概述 2、SDK配置 2.1、IO配置 2.2、TRGMUX配置 2.3、LCU配置 2.4、Trgmux配置 2.5、Emios配置 2.6、代码实现 1、概述 碰到光电编码器、磁编码器等,有时候传出来的位置信息为ABZ的方式,在S32K3里面通过TRGMUX、LCU、Emios结合的方式可以实现ABZ解码。 官方…

【Pytorch】从MoCo看无监督对比学习;从SupCon看有监督对比学习

目录 无监督对比学习&#xff1a;Moco文章内容理解代码解释 有监督对比学习&#xff1a;Supervised Contrastive Learning文章内容理解 无监督对比学习&#xff1a;Moco 文章内容理解 以下内容全部来自于&#xff1a;自监督学习-MoCo-论文笔记. 侵删 论文&#xff1a;Momentu…

vue : 无法加载文件 C:\Program Files\nodejs\node_global\vue.ps1,因为在此系统上禁止运行脚本。

解决方法&#xff1a; 打开PowerShell&#xff0c;在命令框输入set-ExecutionPolicy RemoteSigned 在PowerShell中输入会出现如下图&#xff0c;输入y即可。

【MATLAB】 RLMD信号分解+FFT傅里叶频谱变换组合算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 展示出图效果 1 RLMD分解算法 RLMD&#xff08;Robust Local Mode Decomposition&#xff09;是一种鲁棒的局部模态分解方法。它是通过在局部区间内对信号进行多项式拟合&#xff0c;提取局部特征&#xff0c;进而分解信…