深度学习作为一项强大的技术,已经在多个基础研究领域中找到了应用。尽管神经网络和深度学习已经存在一段时间,但由于数据不足,长期以来并没有受到太多关注。ImageNet的创建成为了深度学习和卷积神经网络进一步发展的主导力量。
在本文中,将采取实践的方法来学习并训练一个简单的CNN模型。将使用一个名为“胸部X光图像(肺炎)”的数据集,可以在Kaggle上找到这个数据集。在进行分析之前,让先了解一下肺炎是什么。
肺炎是一种可能发生在任一侧肺部的感染。这种感染可能由多种原因引起,如细菌、病毒或真菌。感染导致肺泡充满脓液或液体,从而导致患者呼吸困难。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import cv2
import random
import os
import glob
from tqdm.notebook import tqdm
import albumentations as A
from tensorflow.keras.layers import Conv2D, Flatten, MaxPooling2D, Dense
from tensorflow.keras.models import Sequential
from tensorflow.keras.preprocessing.image import ImageDataGenerator
将使用glob模块来加载训练、测试和验证数据集。
train_data = glob.glob('../input/chest-xray-pneumonia/chest_xray/train/**/*.jpeg')
test_data = glob.glob('../input/chest-xray-pneumonia/chest_xray/test/**/*.jpeg')
val_data = glob.glob('../input/chest-xray-pneumonia/chest_xray/val/**/*.jpeg')
创建一个函数来同时可视化多张图片,这将有助于后续的探索性数据分析(EDA)。
def plot_multiple_img(img_matrix_list, title_list, ncols, main_title=""):
fig, myaxes = plt.subplots(figsize=(20, 15), nrows=3, ncols=ncols, squeeze=False)
fig.suptitle(main_title, fontsize = 30)
fig.subplots_adjust(wspace=0.3)
fig.subplots_adjust(hspace=0.3)
for i, (img, title) in enumerate(zip(img_matrix_list, title_list)):
myaxes[i // ncols][i % ncols].imshow(img)
myaxes[i // ncols][i % ncols].set_title(title, fontsize=15)
plt.show()
在开始EDA之前,让先看看数据中所有类别的分布情况。
DIR = "../input/chest-xray-pneumonia/chest_xray/"
sets = ["train", "test", "val"]
all_pneumonia = []
all_normal = []
for cat in sets:
path = os.path.join(DIR, cat)
norm = glob.glob(os.path.join(path, "NORMAL/*.jpeg"))
pneu = glob.glob(os.path.join(path, "PNEUMONIA/*.jpeg"))
all_normal.extend(norm)
all_pneumonia.extend(pneu)
可以看到肺炎图像和正常图像之间存在明显的不平衡。如果在早期阶段没有检测到这个问题,模型将无法高效地执行。现在让继续进行EDA。
随机打乱图像顺序。
random.shuffle(all_normal)
random.shuffle(all_pneumonia)
images = all_normal[:50] + all_pneumonia[:50]
查看X光图像。
fig=plt.figure(figsize=(15, 10))
columns = 4; rows = 5
for i in range(1, columns*rows +1):
img = cv2.imread(images[i])
img = cv2.resize(img, (128, 128))
fig.add_subplot(rows, columns, i)
plt.imshow(img)
plt.axis(False)
现在尝试Ben Graham的方法。首先,将图像转换为灰度,然后应用高斯模糊。
fig=plt.figure(figsize=(15, 10))
columns = 4; rows = 2
for i in range(1, columns*rows +1):
img = cv2.imread(images[i])
img = cv2.resize(img, (512, 512))
img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
img = cv2.addWeighted (img, 4, cv2.GaussianBlur(img, (0,0), 512/10), -4, 128)
fig.add_subplot(rows, columns, i)
plt.imshow(img)
plt.axis(False)
现在,来研究像素分布。将为此使用傅里叶方法。
fig=plt.figure(figsize=(15, 10))
columns = 4; rows = 2
for i in range(1, columns*rows +1):
img = cv2.imread(images[i])
img = cv2.resize(img, (512, 512))
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))
fig.add_subplot(rows, columns, i)
plt.imshow(magnitude_spectrum)
plt.axis(False)
所有这些图像可能看起来像是蓝色背景上的一堆绿点,但并非仅此而已。这些图像本质上是幅度谱,告诉大部分增长在哪里。
图像腐蚀:
fig=plt.figure(figsize=(15, 10))
columns = 5; rows = 2
for i in range(1, columns*rows +1):
img = cv2.imread(images[i])
img = cv2.resize(img, (512, 512))
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
kernel = np.ones((5, 5), np.uint8)
img_erosion = cv2.erode(img, kernel, iterations=3)
fig.add_subplot(rows, columns, i)
plt.imshow(img_erosion)
plt.axis(False)
图像膨胀:
fig=plt.figure(figsize=(15, 10))
columns = 5; rows = 2
for i in range(1, columns*rows +1):
img = cv2.imread(images[i])
img = cv2.resize(img, (512, 512))
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
kernel = np.ones((5, 5), np.uint8)
img_erosion = cv2.dilate(img, kernel, iterations=3)
fig.add_subplot(rows, columns, i)
plt.imshow(img_erosion)
plt.axis(False)
现在让使用OpenCV的Canny边缘检测:
fig=plt.figure(figsize=(15, 10))
columns = 5; rows = 2
for i in range(1, columns*rows +1):
img = cv2.imread(images[i])
img = cv2.resize(img, (512, 512))
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(img, 80, 100)
fig.add_subplot(rows, columns, i)
plt.imshow(edges)
plt.axis(False)
首先,使用Keras Image DataGenerator将数据分为训练集和验证集。
train_gen = ImageDataGenerator(
rescale=1/255.,
horizontal_flip=True,
vertical_flip=True,
rotation_range=0.4,
zoom_range=0.4
)
val_gen = ImageDataGenerator(
rescale=1/255.,
)
Train = train_gen.flow_from_directory(
"../input/chest-xray-pneumonia/chest_xray/train",
target_size=(224, 224),
batch_size=16
)
Test = train_gen.flow_from_directory(
"../input/chest-xray-pneumonia/chest_xray/test",
target_size=(224, 224),
batch_size=8
)
现在是最有趣的部分。开始使用Keras Sequential API构建模型。这将是一个简单的CNN。将使用Rectifier Linear Unit作为激活函数。
model = Sequential()
model.add(Conv2D(filters=128, kernel_size=(3,3), activation='relu', input_shape=(224, 224, 3)))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters=128, kernel_size=(3,3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters=64, kernel_size=(3,3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters=32, kernel_size=(3,3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dense(128, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(2, activation='softmax'))
编译模型以查看其结构和参数。
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()
现在模型已经准备好了!让训练它20个周期,看看它的性能如何。将添加最后5个周期的截图:
hist = model.fit_generator(
Train,
epochs=20,
validation_data=Test
)
model.save("best_model.hdf5")
现在,让可视化模型的性能:
plt.style.use("classic")
plt.figure(figsize=(16, 9))
plt.plot(hist.history['loss'], label="Train Loss")
plt.plot(hist.history['val_loss'], label="Valid Loss")
plt.legend()
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.title("Loss over the Epochs")
plt.show()
plt.style.use("ggplot")
plt.figure(figsize=(16, 9))
plt.plot(hist.history['accuracy'], label="Train Accuracy")
plt.plot(hist.history['val_accuracy'], label="Valid Accuracy")
plt.legend()
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.title("Accuracy over the Epochs")
plt.show()
如所见,模型可以提供近86%的准确率,这是相当可观的。因此,可以自信地在现实世界案例中使用这个模型来预测肺炎。
在本文中,学习了如何使用Keras库创建一个简单的CNN。在探索性数据分析中,主要使用了OpenCV库。首先,看到了数据在两个类别中的分布,并发现肺炎肺部的图像比正常图像多得多。首先随机打乱图像,以抵消拥有更多一种类型数据的影响。