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

news2024/11/25 12:29:01

基于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个GPU
    tf.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  = 224

train_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.AUTOTUNE

def 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, LearningRateScheduler

NO_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 plt

loss = 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)
    # 将矩阵转化为 DataFrame
    conf_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 math

def 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.coloradmin.cn/o/702726.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

oracle字符集

1、查看oracle字符集 如果操作系统或者客户端的字符集设置和数据库设置不一样就会出现乱码 查询NLS_LANG即操作系统环境变量要设为 NLS_LANGUAGE_NLS_TERRITORY**.NLS_CHARACTERSET**,如: export NLS_LANG“AMERICAN_AMERICA.AL32UTF8”

Spring MVC处理响应附案例详解

目录 一、配置视图解析器 二、控制器方法的返回值 2.1 返回值为void 2.1.1 控制器方法 2.1.2 jsp页面 2.1.3 测试结果 2.2 返回值为String 2.2.1 控制器方法 2.2.2 测试结果 2.3 返回值为ModelAndView 2.3.1 控制器方法 2.3.2 JSP页面 2.3.3 测试结果 三、某些会…

基于蒙特卡罗法评估智能电网可靠性研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

python爬虫_django+vue+echarts可视化查询所有CSDN用户质量分

文章目录 ⭐前言⭐ 效果⭐django简介⭐vue3简介⭐vue引入echarts ⭐前后分离实现💖 django代码层💖 vue3代码层结束 ⭐前言 大家好,我是yma16,本文分享关于前后分离djangovueecharts可视化查询CSDN用户质量分。 该系列文章&#…

一种基于linux内核双向链表的移植

1.简介 双向链表(Doubly Linked List)是一种常见的数据结构,由一系列的节点组成,每个节点都包含两个指针,分别指向前一个节点和后一个节点。与单向链表不同,双向链表可以在 O(1) 的时间复杂度内向前或向后遍…

【Unity编辑器扩展】(三)PSD转UGUI Prefab, 一键拼UI解放美术/程序(完结)

工具效果: 第一步,把psd图层转换为可编辑的节点树,并自动解析UI类型、自动绑定UI子元素: 第二步, 点击“生成UIForm"按钮生成UI预制体 (若有UI类型遗漏可在下拉菜单手动点选UI类型): 验证一键生成UI效果: 书接上…

idea双击打不开怎么办?

今天在敲代码的时候,突然出现了一个bug,idea打不开了,这个问题怎么解决? 只要找到C:\Users\Administrator .IntelliJIdea2019.3这个文件把所有文件都给删了就可以重启了 哈哈,重启成功

Bayes贝叶斯定理

问题的关键在于:人们是否考虑过大背景/先验/问题的前提,从而做出一个大致的估计。这就引出了我们关于理性的探讨,理性不是说知道事实,而是认识到哪些因素是有关的。 x.1 一个关于贝叶斯定理的例子 引入一个steve假设。我们已知大…

开源进展 | WeIdentity v3.1.1发布,提供无存储依赖的纯功能接口

作为连接实体对象(人或物)的现实身份与链上身份的可信映射,实现实体对象之间安全可信的数据授权与交换,分布式身份技术解决方案在推动区块链应用繁荣及可信数据流转的过程中扮演着重要角色。 WeIdentity是由微众银行自主研发并完全…

parcel打包工具搭建热开发项目环境

parcel是一款WEB端打包工具 能够提供热开发的项目环境 使用了的话不然Webpack 但相对搭建项目会更快一些 我们现在本地创建一个目录 然后 用编辑器打开我们创建的目录 运行终端 在终端中输入 npm init 初始化一个项目 运行完毕之后 我们就会得到一个package.json文件 然后…

Spring Boot 中的 RedisCacheManager 是什么,原理,如何使用

Spring Boot 中的 RedisCacheManager 是什么,原理,如何使用 介绍 在现代应用程序中,缓存是提高应用程序性能的重要组成部分。Spring Boot 提供了一个强大的缓存框架,它支持多种缓存提供程序,包括 Redis、Ehcache、Ca…

国金QMT量化交易系统的Bug及应对策略

国金QMT量化交易系统中的 账号成交状态变化主推 deal_callback() , 当账号成交状态有变化时,这个函数被客户端调用。 我的策略是,在handlebar()里面挂单,等待成交,而判断成交的方式是根据系统主推deal_callback()通知…

数据结构与算法:查找、排序、动态规划、数学

1 查找表 查找表是同一数据类型构成的集合。只进行查找操作的称为静态查找表;在查找的同时进行插入和删除操作的称为动态查找表。 查找算法衡量好坏的依据为:查找成功时,查找的关键字和查找表中比较过的数据元素的个数的平均值,…

MKS SERVO4257D 闭环步进电机_系列10 arduino 例程

第1部分 产品介绍 MKS SERVO 28D/35D/42D/57D 系列闭环步进电机是创客基地为满足市场需求而自主研发的一款产品。具备脉冲接口和RS485/CAN串行接口,支持MODBUS-RTU通讯协议,内置高效FOC矢量算法,采用高精度编码器,通过位置反馈&a…

HiEV独家|余承东力推L3标准,华为ADS更高阶产品将至

作者 | 张祥威 编辑 | 德新 L3标准出台提速,智驾江湖的厮杀将更加惨烈。 近日,多位接近华为的人士告诉HiEV,余承东正在力推自动驾驶L3标准尽快出台,华为的多位技术专家深度参与了L3标准制定。 本月稍早前,余承东在重庆…

计算机网络-数据链路层下篇

目录 计算机网络 七、MAC地址,IP地址及ARP地址 (一)MAC地址 (二)IP地址 (三)ARP地址 八、集线器和交换机的区别 九、以太网交换机自学习和转发帧的流程 十、以太网交换机的生成树协议ST…

一步一步学OAK之十三:实现RGB相机上的空间对象跟踪

前面我们实现了在RGB相机上进行物体的对象跟踪,能够实时跟踪我们想要追踪的物探,但是,如果我们要想知道这个物体的三维空间坐标,该如何实现呢?要想实现这个功能,我们需要用到DepthAI API提供的MobileNetSpa…

无人机动力测试台-50公斤级-Flight Stand 50

Flight Stand 50测试台通过测量电机和螺旋桨的拉力、扭矩、转速、电流、电压、温度、螺旋桨效率和电机效率来精准地描述和评估无人机动力系统的性能。 产品应用 Flight Stand 50测试台可以用于以下方向: 实时动态测试 FS50 Pro的1000 Hz采样率使测试成为可能&am…

使用 OAT 工具替换 OceanBase 云平台节点

OceanBase 环境基本都会先安装 OCP 来部署、监控、运维数据库集群。但如果有机器过保等问题,就需要有平稳的 OCP 节点的替换方案。 作者:张瑞远 上海某公司 DBA,曾经从事银行、证券数仓设计、开发、优化类工作,现主要从事电信级 I…

android:DataPicker控件使用

一、前言:我真的服了,刚开始再发布运行的时候一直报这个错误“ Attempt to invoke virtual method void android.widget.TextView.setText(java.lang.CharSequence) on a null object reference”说空指针。我也上网查了,网上说在这个错误不是…