目录
在本系列文章中,我们将应用深度学习(DL)网络ResNet50来诊断胸部X射线图像中的Covid-19。我们将使用Python的TensorFlow库在Jupyter Notebook上训练神经网络。
该项目所需的工具和库是:
IDE:
库:
我们假设您熟悉Python和Jupyter笔记本的深度学习。如果您不熟悉Python,请从本教程开始。如果您还不熟悉Jupyter,请从这里开始。
在上一篇文章中,我们重构了ResNet50模型以适应新的分类任务——COVID-19与正常胸部X射线之间的区别。在本文中,我们将微调模型以提供预期的性能和准确性。
训练模型
在该项目中,转移学习被用于在一个新的分类任务(COVID-19的检测)中利用ResNet50的知识。转移学习包括两个阶段:冻结和微调。
在冻结阶段,预训练模型的公共可用权重和学习到的参数将被冻结并“按原样”使用。通过移除ResNet50的完全连接层(FC)并将其重新配置为三个完全连接层,开始微调,在输出层有两个输出神经元对应于COVID-19和正常胸部X射线。请注意,FC层的权重是在训练过程中随机启动的。其余图层的权重被冻结,以确保它们充当输入图像高抽象级别的强大特征提取器,因为它们已经在ImageNet数据集中的数百万个图像上进行了训练。
该网络使用梯度下降优化的随机方法在1,590张图像上进行训练,每次迭代的批处理大小为64张图像。本系列的第二篇文章讨论了读取训练数据以及数据选择的代码。
为了使训练过程中的成本函数最小化,将完全连接层的初始学习率和减小因子分别设置为0.0001和0.1。选择时期数是一项复杂的任务:它与训练过程中的优化次数直接相关。如果时期数很多,则网络可能会过拟合并表现不佳。
为避免过度拟合,我们在验证图像上监控了错误和性能。发现ResNet50在第3阶段达到了最高的训练精度以及最佳的泛化能力。表1显示了在3个时期之后,网络的良好训练性能——准确率为98.7%(图6)。
tf.keras.callbacks.EarlyStopping(
monitor='val_loss', min_delta=0, patience=0, verbose=0,
mode='auto', baseline=None, restore_best_weights=False
)
model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy'])
history = model.fit_generator(generator = train_generator, steps_per_epoch=train_generator.n//train_generator.batch_size, epochs = 3)
图6:网络的培训过程
为了评估训练期间的模型性能,让我们在时期数上绘制准确性和损失(图7和8):
acc = history.history['accuracy']
loss = history.history['loss']
plt.figure()
plt.plot(acc, label='Training Accuracy')
plt.ylabel('Accuracy')
plt.title('Training Accuracy')
plt.figure()
plt.plot(loss, label='Training Loss')
plt.ylabel('Loss')
plt.title('Training Loss')
plt.xlabel('epoch')
plt.show()
图7:训练精度与时期数
图8:损失与时期数
如图7和8所示,训练精度随着时期数的增加而增加,而训练损失则随着每个时期的减少而减少。这是运行梯度下降优化时应该期望的。换句话说,每次迭代都应减少误差。
评估模型
一旦对模型进行了正确的训练,我们就可以开始在我们的测试数据集上对其进行测试,该测试数据集包含895个不属于训练集的图像。测试集已在系列的第二篇文章中加载为test_generator。
为了测试我们的模型,让我们使用model.evaluate函数。此函数根据您传递给它的输入数据来计算损耗和准确性。我们通过了所有输入的测试数据test_generator,并评估了模型。
Testresults = model.evaluate(test_generator)
print("test loss, test acc:", Testresults)
图9:测试准确性的快照
如您在上面看到的(图9),我们的模型在将新图像分类到COVID-19或Normal中显示出良好的泛化能力,准确度为95%,测试损失为0.108。
我们还可以使用model.predict函数评估模型。此函数与model.evaluate相似,除了它生成给定输入的预测输出。要获得对测试数据的所有预测,请使用model.predict:
predictions = model.predict(test_generator, batch_size=None, verbose=0, steps=None, callbacks=None)
print(predictions)
在获得由Softmax函数生成的预测作为概率之后,我们将这些预测取整为0s或1s。舍入后的输出将存储在类中,而实际输出将存储在test_generator.Labels中。
# Generate arg maxes for predictions
classes = np.argmax(predictions, axis = 1)
print(classes)
print(test_generator.labels)
我们还用model.predict来对一张图像的类别进行分类。我们首先使用以下命令打印所有测试图像的类
print(test_generator.labels)
然后,我们选择了一个属于类别0(COVID-19)的图像并将其提供给model.predict:
x=test_generator[5]
predictions = model.predict(x)
print('First prediction:', predictions[0])
category = np.argmax(predictions[0], axis = 0)
print("the image class is:", category)
渐变权重类激活映射(Grad-Cam)
为了更好地解释和评估所采用的模型,我们可以采用许多参数和度量,例如Grad-Cam。我们可视化了一些正确分类的COVID-19和Normal测试图像的Grad-Cam。
Grad-Cam是一种方法,可用于可视化网络集中用于对特定图像进行分类的区域中的激活。通过热图突出显示与预测类别相关的可疑区域,其中最高的激活区域以深红色显示,而最低的激活区域以深蓝色显示。
图10显示了由ResNet50正确分类的一些测试图像的Grad-Cam。上排显示“普通”示例,下排显示COVID-19图像。请注意,除了TensorFlow之外,我们还使用OpenCV(CV2)来计算和绘制热图,因此必须导入CV2。
我们选择了一些测试图像并计算了它们的Grad_Cam。要处理其他图像,只需在IMAGE_PATH中更改图像名称。重要的是选择最后一个卷积层LAYER_NAME,以调查模型在最终卷积层中的可视化效果,这有助于做出最终决策。Class_INDEX表示给定图像的类别,在此示例中为COVID-19(0)。
import cv2
IMAGE_PATH = r'C:\Users\abdul\Desktop\ContentLab\P1\archive\COVID-19 Radiography Database\test\NORMAL\NORMAL (2).png'
LAYER_NAME = 'conv5_block3_out'
CLASS_INDEX = 0
img = tf.keras.preprocessing.image.load_img(IMAGE_PATH, target_size=(224, 224))
img = tf.keras.preprocessing.image.img_to_array(img)
# Load initial model
model = model
# Create a graph that outputs target convolution and output
grad_model = tf.keras.models.Model([model.inputs], [model.get_layer(LAYER_NAME).output, model.output])
# Get the score for target class
with tf.GradientTape() as tape:
conv_outputs, predictions = grad_model(np.array([img]))
loss = predictions[:, CLASS_INDEX]
# Extract filters and gradients
output = conv_outputs[0]
grads = tape.gradient(loss, conv_outputs)[0]
# Average gradients spatially
weights = tf.reduce_mean(grads, axis=(0, 1))
# Build a ponderated map of filters according to gradients importance
cam = np.ones(output.shape[0:2], dtype=np.float32)
for index, w in enumerate(weights):
cam += w * output[:, :, index]
# Heatmap visualization
cam = cv2.resize(cam.numpy(), (224, 224))
cam = np.maximum(cam, 0)
heatmap = (cam - cam.min()) / (cam.max() - cam.min())
cam = cv2.applyColorMap(np.uint8(255*heatmap), cv2.COLORMAP_JET)
output_image = cv2.addWeighted(cv2.cvtColor(img.astype('uint8'), cv2.COLOR_RGB2BGR), 0.5, cam, 1, 0)
plt.imshow(output_image, cmap='rainbow')
图10:测试图像的热图
下一步
在下一篇文章中,我们将讨论通过我们的模型获得的COVID-19检测结果,并将这些结果与其他模型的结果进行比较。敬请关注!
https://www.codeproject.com/Articles/5294464/Fine-tuning-ResNet50-to-Diagnose-COVID-19