Advertisement

毕设项目分享 基于卷积神经网络的乳腺癌分类 深度学习 医学图像

阅读量:

文章目录

  • 1 前言
  • 2 前言
  • 3 数据集
    • 3.1 良性样本
    • 3.2 病变样本

开发环境部分
代码实现模块
流程设计
详细代码解析
库的导入步骤
图像数据读取
数据标注过程
数据分类管理
模型构建与训练方案设计

  • 6 分析指标

    • 6.1 精度,召回率和F1度量
    • 6.2 混淆矩阵
  • 7 结果和结论

  • 8 最后

1 前言

Hi,大家好,今天向大家介绍 基于卷积神经网络的乳腺癌分类,

这是 深度学习 在 医学图像分类上的课题

大家可以用于毕业设计

2 前言

乳腺癌在全球范围内是最常见的女性癌症类型之一。在该年份的数据中显示,在所有新发癌症病例中约有12%与乳腺癌相关,在所有女性癌症病例中则占到了约25%的比例。

当乳腺细胞发生异常增殖时,在x光片上能够观察到明显的肿块,并认为这样的肿瘤被认为是恶性的

以下是报告:

约占美国女性的八分之一(约12%)在其一生期间内将患上浸润型乳腺癌。
预计出现268,600例新的侵袭性乳腺癌病例及62,930例新的非侵袭性乳腺癌症。
占大多数 breast cancer cases occur in women without a family history of breast cancer.这些病例的发生归因于基因突变而非遗传突变.
一名女性若有一级亲属患病,则患病风险显著提升;仅约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
    //...

每个分类目录下的训练数据集共包含1,000张图片,在测试用例中则为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 标记

之后,在完成上述操作后(即生成一个全部为零的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 构建模型训练

我的批处理大小设为16。批次大小被视为深度学习中一个至关重要的超参数。相比之下,较大的批次大小通常有助于提升模型的训练效率。然而,在极端情况下(例如当批次大小等于整个数据集时),这种做法可能会导致模型泛化能力的下降甚至完全失效。具体而言,在极端情况下(例如当批次大小等于整个数据集时),这种做法可能会导致模型无法有效泛化到新的数据样本上)。在这种极端情况下(即当批次大小等于整个数据集时),模型实际上是在一次性优化全局目标函数的一个单一实例点上进行梯度更新(即全局最小值)。然而,在这种情况下(即当批次大小等于整个数据集时),虽然能够保证找到全局最优解(即全局最小值),但这种方法通常会导致收敛速度显著变慢。相反地,在较小的批次设置下(即较小的批量处理大小),通常能够更快地达到较好的收敛效果(即较快地接近目标函数的极小值)。这可以从以下角度理解:较小的批量处理会使模型能够在仅遍历部分训练样本后就开始进行参数更新和学习过程(即快速开始学习)。然而,在较小批量设置下(即较小的批量处理大小),由于信息更新不够充分完整(仅有部分样本参与梯度计算),因此无法保证能够达到全局最优解(即全局最小值)。基于此,在实践应用中通常建议从较小的批量设置开始逐步增加批量处理大小以加快整体训练速度

我进行了额外的数据增强工作。这种方法有助于扩大训练数据集的规模。通过增加多样化的训练实例,网络在学习过程中能够呈现出更加多样的特征,并且依然能捕捉到具有代表性的样本信息。

随后, 我开发了一个数据生成器, 并让其自动从文件夹中提取所需的数据. 为此, Keras特意提供了便捷的Python生成器函数库.

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

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

我采用DenseNet201模型作为初始权重参数。该模型经过Imagenet大规模数据集的训练。设定学习率 learning_rate 为 0.0001。

基于此,在该基础上,我应用了全局平均池化操作和50%的dropout技术来降低模型过拟合现象。

通过批次归一化技术和运用softmax函数作为激活函数的设计方案,在一个包含两个神经元节点的全连接层中进行分类任务处理。

我使用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用于在完成长期且耗时较多的训练周期后保存能够取得良好效果的最佳模型

ReduceLROnPlateau:当监控的指标在一定时期内未见改善时( patience ), 学习率将被相应地降低。该回调机制会持续监督, 当 patience 周期结束后, 如果模型在该周期内没有任何优化表现, 学习率就会被缩小至当前值的2至10倍(通常是当前值的1/2至1/10)。

在这里插入图片描述

该模型我训练了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%的准确率(accuracy),但仍然无法有效识别出所有的恶性病例(false negatives),即预测时所有案例都被归类为良性——这样的分类器效果并不理想。

复制代码
    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/yaa-dc/warehouse-1/blob/master/python/README.md

全部评论 (0)

还没有任何评论哟~