机器学习笔记 - 使用Keras和深度学习进行乳腺癌分类
一、數據集簡介
????????乳腺組織病理學圖像
????????浸潤性導管癌 (IDC) 是所有乳腺癌中最常見的亞型。 為了給整個樣本分配侵襲性等級,病理學家通常關注包含 IDC 的區域。 因此,自動侵略性分級的常見預處理步驟之一是在整個安裝載玻片內描繪 IDC 的確切區域。
????????乳腺癌是女性最常見的癌癥形式,浸潤性導管癌 (IDC) 是最常見的乳腺癌形式。 準確識別和分類乳腺癌亞型是一項重要的臨床任務,可以使用自動化方法來節省時間和減少錯誤。
????????原始數據集包含 162 張以 40 倍掃描的乳腺癌 (BCa) 標本的整體載玻片圖像。從中提取了 277,524 個大小為 50 x 50 的圖像塊(198,738 個 IDC 陰性和 78,786 個 IDC 陽性)。
? ? ? ? 數據集是kaggle提供,下面是鏈接地址
Breast Histopathology Images | Kaggle198,738 IDC(-) image patches; 78,786 IDC(+) image patcheshttps://www.kaggle.com/datasets/paultimothymooney/breast-histopathology-images? ? ? ? 下面是部分圖片示例
????????????????kaggle乳腺組織病理學圖像數據集由Janowczyk、Madabhushi和Roa 等人策劃。???????
?????????數據集中的每個圖像都有一個特定的文件名結構。數據集中的圖像文件名示例如下所示:
????????10253_idx5_x1351_y1101_class0.png
????????我們可以將此文件名解釋為:
????????患者編號: 10253_idx5
????????x - 坐標: 1,351
????????y -坐標: 1,101
????????類標簽: 0(0表示無IDC,1表示IDC)
二、編寫代碼
1、配置文件
? ? ? ? 創建config.py文件
import os# 初始化圖像的原始目錄的路徑 ORIG_INPUT_DATASET = "datasets/orig"# 在計算訓練和測試拆分后,初始化新目錄的基本路徑,該目錄將包含我們的圖像 BASE_PATH = "datasets/idc"# 訓練、驗證和測試目錄 TRAIN_PATH = os.path.sep.join([BASE_PATH, "training"]) VAL_PATH = os.path.sep.join([BASE_PATH, "validation"]) TEST_PATH = os.path.sep.join([BASE_PATH, "testing"])# 定義將用于訓練的數據量 TRAIN_SPLIT = 0.8# 驗證數據量將是訓練數據的百分比 VAL_SPLIT = 0.12、構建數據集
? ? ? ? 創建名為build_dataset.py的文件,執行該腳本將會劃分訓練、驗證、測試數據集。
import config from imutils import paths import random import shutil import os# 獲取原始輸入目錄中所有輸入圖像的路徑并將它們打亂 imagePaths = list(paths.list_images(config.ORIG_INPUT_DATASET)) random.seed(42) random.shuffle(imagePaths)# 計算訓練和測試分割 i = int(len(imagePaths) * config.TRAIN_SPLIT) trainPaths = imagePaths[:i] testPaths = imagePaths[i:]# 我們將使用部分訓練數據進行驗證 i = int(len(trainPaths) * config.VAL_SPLIT) valPaths = trainPaths[:i] trainPaths = trainPaths[i:]# 定義我們將要構建的數據集 datasets = [("training", trainPaths, config.TRAIN_PATH),("validation", valPaths, config.VAL_PATH),("testing", testPaths, config.TEST_PATH) ]# 循環數據集 for (dType, imagePaths, baseOutput) in datasets:# 打印我們正在創建的數據拆分print("[INFO] building '{}' split".format(dType))# 如果輸出基本輸出目錄不存在,則創建它if not os.path.exists(baseOutput):print("[INFO] 'creating {}' directory".format(baseOutput))os.makedirs(baseOutput)# 循環輸入圖像路徑for inputPath in imagePaths:# 提取輸入圖像的文件名并提取類標簽(“0”表示“負”,“1”表示“正”)filename = inputPath.split(os.path.sep)[-1]label = filename[-5:-4]# 構建標簽目錄的路徑labelPath = os.path.sep.join([baseOutput, label])# 如果標簽輸出目錄不存在,則創建它if not os.path.exists(labelPath):print("[INFO] 'creating {}' directory".format(labelPath))os.makedirs(labelPath)# 構建目標圖像的路徑,然后復制圖像本身p = os.path.sep.join([labelPath, filename])shutil.copy2(inputPath, p)3、創建模型
? ? ? ? 這里使用了SeparableConv2D,看過 MobileNet 架構的人都會遇到可分離卷積的概念??煞蛛x卷積主要有兩種類型:空間可分離卷積和深度可分離卷積。可分離卷積可以減少了卷積中的參數數量。
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import BatchNormalization from tensorflow.keras.layers import SeparableConv2D from tensorflow.keras.layers import MaxPooling2D from tensorflow.keras.layers import Activation from tensorflow.keras.layers import Flatten from tensorflow.keras.layers import Dropout from tensorflow.keras.layers import Dense from tensorflow.keras import backend as K class CancerNet:@staticmethoddef build(width, height, depth, classes):# 將模型與輸入形狀一起初始化為“通道最后”和通道尺寸本身model = Sequential()inputShape = (height, width, depth)chanDim = -1# 如果我們使用“通道優先”,更新輸入形狀和通道維度if K.image_data_format() == "channels_first":inputShape = (depth, height, width)chanDim = 1# CONV => RELU => POOLmodel.add(SeparableConv2D(32, (3, 3), padding="same",input_shape=inputShape))model.add(Activation("relu"))model.add(BatchNormalization(axis=chanDim))model.add(MaxPooling2D(pool_size=(2, 2)))model.add(Dropout(0.25))# (CONV => RELU => POOL) * 2model.add(SeparableConv2D(64, (3, 3), padding="same"))model.add(Activation("relu"))model.add(BatchNormalization(axis=chanDim))model.add(SeparableConv2D(64, (3, 3), padding="same"))model.add(Activation("relu"))model.add(BatchNormalization(axis=chanDim))model.add(MaxPooling2D(pool_size=(2, 2)))model.add(Dropout(0.25))# (CONV => RELU => POOL) * 3model.add(SeparableConv2D(128, (3, 3), padding="same"))model.add(Activation("relu"))model.add(BatchNormalization(axis=chanDim))model.add(SeparableConv2D(128, (3, 3), padding="same"))model.add(Activation("relu"))model.add(BatchNormalization(axis=chanDim))model.add(SeparableConv2D(128, (3, 3), padding="same"))model.add(Activation("relu"))model.add(BatchNormalization(axis=chanDim))model.add(MaxPooling2D(pool_size=(2, 2)))model.add(Dropout(0.25))# first (and only) set of FC => RELU layersmodel.add(Flatten())model.add(Dense(256))model.add(Activation("relu"))model.add(BatchNormalization())model.add(Dropout(0.5))# softmax classifiermodel.add(Dense(classes))model.add(Activation("softmax"))# return the constructed network architecturereturn model4、訓練模型
? ? ? ? 創建train_model.py文件。
import matplotlib matplotlib.use("Agg")from tensorflow.keras.preprocessing.image import ImageDataGenerator from tensorflow.keras.callbacks import LearningRateScheduler from tensorflow.keras.optimizers import Adagrad from tensorflow.keras.utils import to_categorical from sklearn.metrics import classification_report from sklearn.metrics import confusion_matrix from pyimagesearch.cancernet import CancerNet from pyimagesearch import config from imutils import paths import matplotlib.pyplot as plt import numpy as np import argparse import os# 構造參數解析器并解析參數 ap = argparse.ArgumentParser() ap.add_argument("-p", "--plot", type=str, default="plot.png", help="path to output loss/accuracy plot") args = vars(ap.parse_args())# 初始化我們的時期數、初始學習率和批量大小 NUM_EPOCHS = 40 INIT_LR = 1e-2 BS = 32 # 確定訓練、驗證和測試目錄中的圖像路徑總數 trainPaths = list(paths.list_images(config.TRAIN_PATH)) totalTrain = len(trainPaths) totalVal = len(list(paths.list_images(config.VAL_PATH))) totalTest = len(list(paths.list_images(config.TEST_PATH))) # 計算每個類中訓練圖像的總數并初始化一個字典來存儲類權重 trainLabels = [int(p.split(os.path.sep)[-2]) for p in trainPaths] trainLabels = to_categorical(trainLabels) classTotals = trainLabels.sum(axis=0) classWeight = dict() # 遍歷所有類并計算類權重 for i in range(0, len(classTotals)):classWeight[i] = classTotals.max() / classTotals[i]# 初始化訓練數據增強對象 trainAug = ImageDataGenerator(rescale=1 / 255.0,rotation_range=20,zoom_range=0.05,width_shift_range=0.1,height_shift_range=0.1,shear_range=0.05,horizontal_flip=True,vertical_flip=True,fill_mode="nearest") # 初始化驗證(和測試)數據增強對象 valAug = ImageDataGenerator(rescale=1 / 255.0)# initialize the training generator trainGen = trainAug.flow_from_directory(config.TRAIN_PATH,class_mode="categorical",target_size=(48, 48),color_mode="rgb",shuffle=True,batch_size=BS)# initialize the validation generator valGen = valAug.flow_from_directory(config.VAL_PATH,class_mode="categorical",target_size=(48, 48),color_mode="rgb",shuffle=False,batch_size=BS)# initialize the testing generator testGen = valAug.flow_from_directory(config.TEST_PATH,class_mode="categorical",target_size=(48, 48),color_mode="rgb",shuffle=False,batch_size=BS)# 初始化我們的模型并編譯它 model = CancerNet.build(width=48, height=48, depth=3, classes=2) opt = Adagrad(lr=INIT_LR, decay=INIT_LR / NUM_EPOCHS) model.compile(loss="binary_crossentropy", optimizer=opt, metrics=["accuracy"]) # fit the model H = model.fit(x=trainGen,steps_per_epoch=totalTrain,validation_data=valGen,validation_steps=totalVal,class_weight=classWeight,epochs=NUM_EPOCHS)# 重置測試生成器,然后使用我們經過訓練的模型對數據進行預測 print("[INFO] evaluating network...") testGen.reset() predIdxs = model.predict(x=testGen, steps=(totalTest // BS) + 1) # 對于測試集中的每張圖像,我們需要找到具有對應最大預測概率的標簽的索引 predIdxs = np.argmax(predIdxs, axis=1) # 顯示格式化的分類報告 print(classification_report(testGen.classes, predIdxs, target_names=testGen.class_indices.keys()))# 計算混淆矩陣并使用它來推導原始準確度、靈敏度和特異性 cm = confusion_matrix(testGen.classes, predIdxs) total = sum(sum(cm)) acc = (cm[0, 0] + cm[1, 1]) / total sensitivity = cm[0, 0] / (cm[0, 0] + cm[0, 1]) specificity = cm[1, 1] / (cm[1, 0] + cm[1, 1]) # 顯示混淆矩陣、準確性、敏感性和特異性 print(cm) print("acc: {:.4f}".format(acc)) print("sensitivity: {:.4f}".format(sensitivity)) print("specificity: {:.4f}".format(specificity))# 繪制訓練損失和準確率 N = NUM_EPOCHS plt.style.use("ggplot") plt.figure() plt.plot(np.arange(0, N), H.history["loss"], label="train_loss") plt.plot(np.arange(0, N), H.history["val_loss"], label="val_loss") plt.plot(np.arange(0, N), H.history["accuracy"], label="train_acc") plt.plot(np.arange(0, N), H.history["val_accuracy"], label="val_acc") plt.title("Training Loss and Accuracy on Dataset") plt.xlabel("Epoch #") plt.ylabel("Loss/Accuracy") plt.legend(loc="lower left") plt.savefig(args["plot"])總結
以上是生活随笔為你收集整理的机器学习笔记 - 使用Keras和深度学习进行乳腺癌分类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 给飞机叶片穿戴上3D打印传感器
- 下一篇: 深度学习,提高前列腺癌诊断正确率