第45步 深度学习图像识别:Nasnet建模(Tensorflow)

news/2025/1/23 14:48:15/

基于WIN10的64位系统演示

一、写在前面

(1)Nasnet

NASNet是由Google Brain团队在2017年提出的一种神经网络架构搜索(Neural Architecture Search,简称NAS)的结果。NAS是一种用于自动化设计深度学习模型的技术。在NAS中,机器学习算法通过搜索和优化一系列可能的神经网络架构,然后挑选出性能最好的那一个。

NASNet的全称是"Neural Architecture Search Network",是一种基于卷积神经网络(Convolutional Neural Network,CNN)的模型。它主要包括两种重复的模块,分别称为Normal Cell和Reduction Cell。Normal Cell用于保持特征图的尺寸不变,而Reduction Cell则用于减半特征图的尺寸。

需要注意的是,NASNet的训练过程非常耗时耗力。虽然在许多任务上表现出色,但其高昂的计算成本使得这种方法并不适合所有的应用场景。为了解决这个问题,Google团队还开发了一种轻量级的NASNet版本,称为NASNet-Mobile,适用于移动设备和其他计算资源有限的环境。

(2)Nasnet的预训练版本

Keras有Nasnet的预训练模型,包括NASNet-Mobile和NASNet-Large,省事:

 

由于我的显卡不行,这里我就测试NASNet-Mobile版本了。

二、Nasnet迁移学习代码实战

我们继续胸片的数据集:肺结核病人和健康人的胸片的识别。其中,肺结核病人700张,健康人900张,分别存入单独的文件夹中。

(a)导入包

from tensorflow import keras
import tensorflow as tf
from tensorflow.python.keras.layers import Dense, Flatten, Conv2D, MaxPool2D, Dropout, Activation, Reshape, Softmax, GlobalAveragePooling2D
from tensorflow.python.keras.layers.convolutional import Convolution2D, MaxPooling2D
from tensorflow.python.keras import Sequential
from tensorflow.python.keras import Model
from tensorflow.python.keras.optimizers import adam_v2
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.python.keras.preprocessing.image import ImageDataGenerator, image_dataset_from_directory
from tensorflow.python.keras.layers.preprocessing.image_preprocessing import RandomFlip, RandomRotation, RandomContrast, RandomZoom, RandomTranslation
import os,PIL,pathlib
import warnings
#设置GPU
gpus = tf.config.list_physical_devices("GPU")if gpus:gpu0 = gpus[0] #如果有多个GPU,仅使用第0个GPUtf.config.experimental.set_memory_growth(gpu0, True) #设置GPU显存用量按需使用tf.config.set_visible_devices([gpu0],"GPU")warnings.filterwarnings("ignore")             #忽略警告信息
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False    # 用来正常显示负号

(b)导入数据集

#1.导入数据
data_dir = "./cat_dog"
data_dir = pathlib.Path(data_dir)
image_count = len(list(data_dir.glob('*/*')))
print("图片总数为:",image_count)batch_size = 32
img_height = 224
img_width  = 224train_ds = image_dataset_from_directory(data_dir,validation_split=0.2,subset="training",seed=12,image_size=(img_height, img_width),batch_size=batch_size)val_ds = image_dataset_from_directory(data_dir,validation_split=0.2,subset="validation",seed=12,image_size=(img_height, img_width),batch_size=batch_size)class_names = train_ds.class_names
print(class_names)
print(train_ds)#2.检查数据
for image_batch, labels_batch in train_ds:print(image_batch.shape)print(labels_batch.shape)break#3.配置数据
AUTOTUNE = tf.data.AUTOTUNEdef train_preprocessing(image,label):return (image/255.0,label)train_ds = (train_ds.cache().shuffle(800).map(train_preprocessing).prefetch(buffer_size=AUTOTUNE)
)val_ds = (val_ds.cache()
.map(train_preprocessing).prefetch(buffer_size=AUTOTUNE)
)#4. 数据可视化
plt.figure(figsize=(10, 8))  
plt.suptitle("数据展示")class_names = ["Dog","Cat"]for images, labels in train_ds.take(1):for i in range(15):plt.subplot(4, 5, i + 1)plt.xticks([])plt.yticks([])plt.grid(False)plt.imshow(images[i])plt.xlabel(class_names[labels[i]-1])plt.show()

这里注意,NASNetMobile模型的默认输入尺寸是224x224。改成其他的,会直接报错:

ValueError: Dimensions must be equal, but are 12 and 13 for '{{node NASNet/normal_add_1_0/add}} = AddV2[T=DT_FLOAT](NASNet/separable_conv_2_bn_normal_left1_0/FusedBatchNormV3, NASNet/separable_conv_2_bn_normal_right1_0/FusedBatchNormV3)' with input shapes: [?,12,12,44], [?,13,13,44].

(c)数据增强

data_augmentation = Sequential([RandomFlip("horizontal_and_vertical"),RandomRotation(0.2),RandomContrast(1.0),RandomZoom(0.5,0.2),RandomTranslation(0.3,0.5),
])def prepare(ds):ds = ds.map(lambda x, y: (data_augmentation(x, training=True), y), num_parallel_calls=AUTOTUNE)return ds
train_ds = prepare(train_ds)

(d)导入Nasnet

#获取预训练模型对输入的预处理方法
from tensorflow.python.keras.applications import nasnet
from tensorflow.python.keras import Input
IMG_SIZE = (img_height, img_width, 3)
base_model = nasnet.NASNetMobile(include_top=False, #是否包含顶层的全连接层weights='imagenet')inputs = Input(shape=IMG_SIZE)
#模型
x = base_model(inputs, training=False) #参数不变化
#全局池化
x = GlobalAveragePooling2D()(x)
#BatchNormalization
x = BatchNormalization()(x)
#Dropout
x = Dropout(0.8)(x)
#Dense
x = Dense(128, kernel_regularizer=regularizers.l2(0.3))(x)  # 全连接层减少到128,添加 L2 正则化
#BatchNormalization
x = BatchNormalization()(x)
#激活函数
x = Activation('relu')(x)
#输出层
outputs = Dense(2, kernel_regularizer=regularizers.l2(0.3))(x)  # 添加 L2 正则化
#BatchNormalization
outputs = BatchNormalization()(outputs)
#激活函数
outputs = Activation('sigmoid')(outputs)
#整体封装
model = Model(inputs, outputs)
#打印模型结构
print(model.summary())

然后打印出模型的结构:

 (e)编译模型

#定义优化器
from tensorflow.python.keras.optimizers import adam_v2, rmsprop_v2
#from tensorflow.python.keras.optimizer_v2.gradient_descent import SGD
optimizer = adam_v2.Adam()
#optimizer = SGD(learning_rate=0.001)
#optimizer = rmsprop_v2.RMSprop()
#编译模型
model.compile(optimizer=optimizer,loss='sparse_categorical_crossentropy',metrics=['accuracy'])#训练模型
from tensorflow.python.keras.callbacks import ModelCheckpoint, Callback, EarlyStopping, ReduceLROnPlateau, LearningRateSchedulerNO_EPOCHS = 100
PATIENCE  = 10
VERBOSE   = 1# 设置动态学习率
annealer = LearningRateScheduler(lambda x: 1e-5 * 0.99 ** (x+NO_EPOCHS))# 设置早停
earlystopper = EarlyStopping(monitor='loss', patience=PATIENCE, verbose=VERBOSE)# 
checkpointer = ModelCheckpoint('mtb_jet_best_model_ResNet50.h5',monitor='val_accuracy',verbose=VERBOSE,save_best_only=True,save_weights_only=True)train_model  = model.fit(train_ds,epochs=NO_EPOCHS,verbose=1,validation_data=val_ds,callbacks=[earlystopper, checkpointer, annealer])#保存模型
model.save('mtb_jet_best_model_ResNet50.h5')
print("The trained model has been saved.")

模型训练速度也比较慢,一个迭代需要48s。然而,准确率波动比较比较小:

(f)Accuracy和Loss可视化

import matplotlib.pyplot as pltloss = train_model.history['loss']
acc = train_model.history['accuracy']
val_loss = train_model.history['val_loss']
val_acc = train_model.history['val_accuracy']
epoch = range(1, len(loss)+1)fig, ax = plt.subplots(1, 2, figsize=(10,4))
ax[0].plot(epoch, loss, label='Train loss')
ax[0].plot(epoch, val_loss, label='Validation loss')
ax[0].set_xlabel('Epochs')
ax[0].set_ylabel('Loss')
ax[0].legend()
ax[1].plot(epoch, acc, label='Train acc')
ax[1].plot(epoch, val_acc, label='Validation acc')
ax[1].set_xlabel('Epochs')
ax[1].set_ylabel('Accuracy')
ax[1].legend()
plt.show()

通过这个图,观察模型训练情况:

 蓝色为训练集,橙色为验证集。可以看到loss还是总体呈现下降趋势,验证集的loss几乎没有波动,跟训练集完全重合。准确度曲线,验证集的波动也是比较小,跟训练集差不多。

(g)混淆矩阵可视化以及模型参数

import numpy as np
import matplotlib.pyplot as plt
from tensorflow.python.keras.models import load_model
from matplotlib.pyplot import imshow
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
import pandas as pd
import math
# 定义一个绘制混淆矩阵图的函数
def plot_cm(labels, predictions):# 生成混淆矩阵conf_numpy = confusion_matrix(labels, predictions)# 将矩阵转化为 DataFrameconf_df = pd.DataFrame(conf_numpy, index=class_names ,columns=class_names)  plt.figure(figsize=(8,7))sns.heatmap(conf_df, annot=True, fmt="d", cmap="BuPu")plt.title('混淆矩阵',fontsize=15)plt.ylabel('真实值',fontsize=14)plt.xlabel('预测值',fontsize=14)val_pre   = []
val_label = []for images, labels in val_ds:#这里可以取部分验证数据(.take(1))生成混淆矩阵for image, label in zip(images, labels):# 需要给图片增加一个维度img_array = tf.expand_dims(image, 0) # 使用模型预测图片中的人物prediction = model.predict(img_array)val_pre.append(np.argmax(prediction))val_label.append(label)plot_cm(val_label, val_pre)cm_val = confusion_matrix(val_label, val_pre)    
a_val = cm_val[0,0]
b_val = cm_val[0,1]
c_val = cm_val[1,0]
d_val = cm_val[1,1]
acc_val = (a_val+d_val)/(a_val+b_val+c_val+d_val) #准确率:就是被分对的样本数除以所有的样本数
error_rate_val = 1 - acc_val #错误率:与准确率相反,描述被分类器错分的比例
sen_val = d_val/(d_val+c_val) #灵敏度:表示的是所有正例中被分对的比例,衡量了分类器对正例的识别能力
sep_val = a_val/(a_val+b_val) #特异度:表示的是所有负例中被分对的比例,衡量了分类器对负例的识别能力
precision_val = d_val/(b_val+d_val) #精确度:表示被分为正例的示例中实际为正例的比例
F1_val = (2*precision_val*sen_val)/(precision_val+sen_val) #F1值:P和R指标有时候会出现的矛盾的情况,这样就需要综合考虑他们,最常见的方法就是F-Measure(又称为F-Score)
MCC_val = (d_val*a_val-b_val*c_val) / (math.sqrt((d_val+b_val)*(d_val+c_val)*(a_val+b_val)*(a_val+c_val))) #马修斯相关系数(Matthews correlation coefficient):当两个类别具有非常不同的大小时,可以使用MCC
print("验证集的灵敏度为:",sen_val, "验证集的特异度为:",sep_val,"验证集的准确率为:",acc_val, "验证集的错误率为:",error_rate_val,"验证集的精确度为:",precision_val, "验证集的F1为:",F1_val,"验证集的MCC为:",MCC_val)train_pre   = []
train_label = []
for images, labels in train_ds:#这里可以取部分验证数据(.take(1))生成混淆矩阵for image, label in zip(images, labels):# 需要给图片增加一个维度img_array = tf.expand_dims(image, 0)# 使用模型预测图片中的人物prediction = model.predict(img_array)train_pre.append(np.argmax(prediction))train_label.append(label)plot_cm(train_label, train_pre)cm_train = confusion_matrix(train_label, train_pre)  
a_train = cm_train[0,0]
b_train = cm_train[0,1]
c_train = cm_train[1,0]
d_train = cm_train[1,1]
acc_train = (a_train+d_train)/(a_train+b_train+c_train+d_train)
error_rate_train = 1 - acc_train
sen_train = d_train/(d_train+c_train)
sep_train = a_train/(a_train+b_train)
precision_train = d_train/(b_train+d_train)
F1_train = (2*precision_train*sen_train)/(precision_train+sen_train)
MCC_train = (d_train*a_train-b_train*c_train) / (math.sqrt((d_train+b_train)*(d_train+c_train)*(a_train+b_train)*(a_train+c_train))) 
print("训练集的灵敏度为:",sen_train, "训练集的特异度为:",sep_train,"训练集的准确率为:",acc_train, "训练集的错误率为:",error_rate_train,"训练集的精确度为:",precision_train, "训练集的F1为:",F1_train,"训练集的MCC为:",MCC_train)

效果好不错,就是验证集的灵敏度还没到0.8,可以通过调整阈值来改善:

 (g)AUC曲线绘制

from sklearn import metrics
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.python.keras.models import load_model
from matplotlib.pyplot import imshow
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
import pandas as pd
import mathdef plot_roc(name, labels, predictions, **kwargs):fp, tp, _ = metrics.roc_curve(labels, predictions)plt.plot(fp, tp, label=name, linewidth=2, **kwargs)plt.plot([0, 1], [0, 1], color='orange', linestyle='--')plt.xlabel('False positives rate')plt.ylabel('True positives rate')ax = plt.gca()ax.set_aspect('equal')val_pre_auc   = []
val_label_auc = []for images, labels in val_ds:for image, label in zip(images, labels):      img_array = tf.expand_dims(image, 0) prediction_auc = model.predict(img_array)val_pre_auc.append((prediction_auc)[:,1])val_label_auc.append(label)
auc_score_val = metrics.roc_auc_score(val_label_auc, val_pre_auc)train_pre_auc   = []
train_label_auc = []for images, labels in train_ds:for image, label in zip(images, labels):img_array_train = tf.expand_dims(image, 0) prediction_auc = model.predict(img_array_train)train_pre_auc.append((prediction_auc)[:,1])#输出概率而不是标签!train_label_auc.append(label)
auc_score_train = metrics.roc_auc_score(train_label_auc, train_pre_auc)plot_roc('validation AUC: {0:.4f}'.format(auc_score_val), val_label_auc , val_pre_auc , color="red", linestyle='--')
plot_roc('training AUC: {0:.4f}'.format(auc_score_train), train_label_auc, train_pre_auc, color="blue", linestyle='--')
plt.legend(loc='lower right')
#plt.savefig("roc.pdf", dpi=300,format="pdf")print("训练集的AUC值为:",auc_score_train, "验证集的AUC值为:",auc_score_val)

ROC曲线如下:

 很完美的ROC曲线!

三、调整过程

几乎没有什么调整,Nasnet在这个数据集上的表现堪称完美,唯一的缺点就是训练的比较慢罢了。

四、Nasnet、ResNet50、InceptionResnetV2、Mobilenet、Efficientnet、DenseNet201、Inception V3和VGG19的对比

 

五、数据

链接:https://pan.baidu.com/s/15vSVhz1rQBtqNkNp2GQyVw?pwd=x3jf

提取码:x3jf


http://www.ppmy.cn/news/702098.html

相关文章

数学建模概论

1、从现实对象到数学模型 我们常见的模型 玩具、照片......~实物模型水箱中的舰艇、风洞中的飞机......~物理模型地图、电路图、分子结构图......~符号模型 模型是为了一定目的,对客观事物的一部分进行简缩、抽象、提炼出来的原型的替代物,集中反映了原型…

python开发对电脑配置要求_学python最电脑配置有要求么

python对于电脑硬件基本没什么要求,下载python安装程序的时候,注意看下自己电脑属性是64位系统还是32位系统,再下载对应的python安装程序。 单纯学Python的话普通电脑就ok了,机器学习几大基础算法都ok,学深度学习的话台式无脑上1080ti或者泰坦xp,其他配置留下升级空间。笔…

台式计算机如何升级,老电脑如何升级 老电脑升级方法【详细介绍】

数码产品都不可避免的有一定的使用周期,一旦过了这个周期,要么是被替代要么接受升级,这个特点在PC产品上尤为明显。无论是笔记本还是台式机,电脑升级分为硬件和软件两方面,升级软件的前提必须是硬件过硬才行&#xff0…

计算机硬件升级的说法有哪些,客户让我给他的电脑升级,看到电脑配置后:看来升级又凉凉了!...

原标题:客户让我给他的电脑升级,看到电脑配置后:看来升级又凉凉了! 电脑升级指的是通过增加或者替换硬件的方式提高电脑的性能,电脑升级常见的就是升级硬盘与内存条,因为这两个硬件适用于所有的电脑&#x…

计算机硬件有哪些升级空间等级查询,你的电脑要不要升级内存?怎么升级?答案都在这里~...

之前给大家介绍了固态硬盘的选购攻略(戳这里复习),小可爱们看完纷纷表示,固态硬盘加装必须安排上,要感受如德芙巧克力一样丝般顺滑的电脑使用体验! 不过事实是,只固态还不够哟~ 除硬盘外,还有另一类存储同样直接影响到电脑的性能,那就是“内存”。今天S姐就跟大家分享下…

旧电脑装html5,5年以上旧电脑如何升级

5年以上旧电脑如何升级 2019年10月14日 13:55作者:王伟铭编辑:王伟铭文章出处:泡泡网原创 分享 首先需要考虑的是需求问题,一般5年以上的电脑即便是拿到现在来说,也能够基本满足办公、上网、影音的需要,不用…

VScode安装和C++配置 - 升级版

上次我发了一篇配置教程,一开始觉得没问题,后来发现我好像把问题搞麻烦了,所以今天我特地卸载了VScode来重写一篇教程…… 开玩笑,我这么怕麻烦的人咋会没事重装软件呢。 主要是因为我的电脑元旦的时候没法启动,于是…

计算机硬件有哪些升级空间等级查询,怎么判断电脑哪些硬件需要升级?

电脑作为如今的生产力工具,要保持在较高的性能状态,但是电脑也如其他的电器产品一样,因为新的技术出现,新的芯片发布,在每隔一段时间新的配件在性能上的升级可以说是很大的,那么我们怎么判断我们的硬件需要…