vgg16识别咖啡豆

 我的环境:

🍺 要求:

  1. 自己搭建VGG-16网络框架(✔)
  2. 调用官方的VGG-16网络框架(✔)

🍻 拔高(可选):

  1. 验证集准确率达到100%(✔)
  2. 使用PPT画出VGG-16算法框架图(发论文需要这项技能)(✔)

🔎 探索(难度有点大)

  1. 在不影响准确率的前提下轻量化模型(✔)
    ○ 目前VGG16的Total params是134,276,932

目录

一 前期工作

1.设置GPU或者cpu

2.导入数据

3.查看数据

二 数据预处理

1.加载数据

2.可视化数据

3.再次检查数据

4.配置数据集

三 搭建网络

四 训练模型

1.设置动态学习率

2.早期与保存最佳模型参数

3.模型训练

五 模型评估

1.Loss和Accuracy图

 2.指定图片进行预测

 3.总结


一 前期工作

环境:python3.7,1080ti,tensorflow2.5(网上租的环境😂😂)

由于电脑问题,现在在jupytr上跑了,所以代码风格发生变化。

1.设置GPU或者cpu

设置cpu(电脑gpu跑不动就用这个将就一下)

from tensorflow import keras
from tensorflow.keras import layers, models
import os, PIL, pathlib
import matplotlib.pyplot as plt
import tensorflow as tf
import numpy as np
import tensorflow as tf
import tensorflow as tf
import os,PIL
# os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
#os.environ['CUDA_VISIBLE_DEVICES']='0'
os.environ['CUDA_VISIBLE_DEVICES']='2'
# os.environ['TF_CPP_MIN_LOG_LEVEL']='2'#屏蔽通知和警告信息
import os,PIL
os.environ['TF_XLA_FLAGS'] = '--tf_xla_enable_xla_devices'
from tensorflow import keras
keras.backend.clear_session()

设置gpu

from tensorflow       import keras
from tensorflow.keras import layers,models
import os, PIL, pathlib
import matplotlib.pyplot as plt
import tensorflow        as tf
import numpy             as np
 
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")
    
gpus

2.导入数据

data_dir = "./49-data/"
data_dir = pathlib.Path(data_dir)

3.查看数据

image_count = len(list(data_dir.glob('*/*.png')))

print("图片总数为:",image_count)

二 数据预处理

1.加载数据

设置数据尺寸

batch_size = 32
img_height = 224
img_width = 224

设置dataset

"""
关于image_dataset_from_directory()的详细介绍可以参考文章:https://mtyjkh.blog.csdn.net/article/details/117018789
"""
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
    data_dir,
    validation_split=0.2,
    subset="training",
    seed=123,
    image_size=(img_height, img_width),
    batch_size=batch_size)
"""
关于image_dataset_from_directory()的详细介绍可以参考文章:https://mtyjkh.blog.csdn.net/article/details/117018789
"""
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    data_dir,
    validation_split=0.2,
    subset="validation",
    seed=123,
    image_size=(img_height, img_width),
    batch_size=batch_size)

关于image_dataset_from_directory()的详细介绍可以参考文章:(58条消息) tf.keras.preprocessing.image_dataset_from_directory() 简介_K同学啊的博客-CSDN博客_tf.keras.preprocessing.image

 

  输出经过image_dataset_from_directory()分类后的标签

class_names = train_ds.class_names
print(class_names)

2.可视化数据

打印部分图片

plt.figure(figsize=(10, 4))  # 图形的宽为10高为5

for images, labels in train_ds.take(1):
    for i in range(10):
        
        ax = plt.subplot(2, 5, i + 1)  

        plt.imshow(images[i].numpy().astype("uint8"))
        plt.title(class_names[labels[i]])
        
        plt.axis("off")

3.再次检查数据

输出数据的尺寸

for image_batch, labels_batch in train_ds:
    print(image_batch.shape)
    print(labels_batch.shape)
    break

4.配置数据集

shuffle:打乱数据集

prefetch:加速处理

AUTOTUNE = tf.data.AUTOTUNE

train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds   = val_ds.cache().prefetch(buffer_size=AUTOTUNE)

三 搭建网络

本文神经网络为官方vgg16模型,我们需要做的是对最后一层按我们的类别进行分类即可。

调用官方

model = keras.applications.VGG16(include_top=False,weights='imagenet')
global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
prediction_layer1 = tf.keras.layers.Dense(1024,activation='relu')
prediction_layer2 = tf.keras.layers.Dense(512,activation='relu')
prediction_layer3 = tf.keras.layers.Dense(len(class_names),activation='softmax')

model = tf.keras.Sequential([
  model,
  global_average_layer,
  prediction_layer1,
  prediction_layer2,
  prediction_layer3
])
model.summary()

 

关于VGG16函数参考下面文章

(58条消息) keras 自带VGG16 net 参数分析_vola9527的博客-CSDN博客

我们对vgg16前部分卷积层没有改变,而是不选择官方的dense层,因为我们需要根据自己的数据进行输出,官方输出为1000种分类,我们只有4种,因此按照这个写法即可。

 自己搭建

model = models.Sequential([
    layers.experimental.preprocessing.Rescaling( 1. ,input_shape=(img_height, img_width, 3)),
    layers.Conv2D(filters=64, kernel_size=(3, 3), padding='same'),  # 卷积层1
    #layers.BatchNormalization(),  # BN层1
    layers.Activation('relu'),  # 激活层1
    layers.Conv2D(filters=64, kernel_size=(3, 3), padding='same', ),
    #layers.BatchNormalization(),  # BN层1
    layers.Activation('relu') , # 激活层1
    layers.MaxPool2D(pool_size=(2, 2), strides=2, padding='same'),
    #layers.Dropout(0.2),  # dropout层
    #
    layers.Conv2D(filters=128, kernel_size=(3, 3), padding='same'),
    #layers.BatchNormalization(),  # BN层1
    layers.Activation('relu'),  # 激活层1
    layers.Conv2D(filters=128, kernel_size=(3, 3), padding='same'),
    #layers.BatchNormalization(),  # BN层1
    layers.Activation('relu'),  # 激活层1
    layers.MaxPool2D(pool_size=(2, 2), strides=2, padding='same'),
    #layers.Dropout(0.2),  # dropout层
    #
    layers.Conv2D(filters=256, kernel_size=(3, 3), padding='same'),
    #layers.BatchNormalization() , # BN层1
    layers.Activation('relu'),  # 激活层1
    layers.Conv2D(filters=256, kernel_size=(3, 3), padding='same'),
    #layers.BatchNormalization() , # BN层1
    layers.Activation('relu') , # 激活层1
    layers.Conv2D(filters=256, kernel_size=(3, 3), padding='same'),
   # layers.BatchNormalization(),
    layers.Activation('relu'),
    layers.MaxPool2D(pool_size=(2, 2), strides=2, padding='same'),
    #layers.Dropout(0.2),
    #
    layers.Conv2D(filters=512, kernel_size=(3, 3), padding='same'),
   # layers.BatchNormalization() , # BN层1
    layers.Activation('relu') , # 激活层1
    layers.Conv2D(filters=512, kernel_size=(3, 3), padding='same'),
    #layers.BatchNormalization() , # BN层1
    layers.Activation('relu'),  # 激活层1
    layers.Conv2D(filters=512, kernel_size=(3, 3), padding='same'),
    #layers.BatchNormalization(),
    layers.Activation('relu'),
    layers.MaxPool2D(pool_size=(2, 2), strides=2, padding='same'),
    #layers.Dropout(0.2),
    #
    layers.Conv2D(filters=512, kernel_size=(3, 3), padding='same'),
   # layers.BatchNormalization() , # BN层1
    layers.Activation('relu'),  # 激活层1
    layers.Conv2D(filters=512, kernel_size=(3, 3), padding='same'),
    #layers.BatchNormalization(),  # BN层1
    layers.Activation('relu'),  # 激活层1
    layers.Conv2D(filters=512, kernel_size=(3, 3), padding='same'),
   # layers.BatchNormalization(),
    layers.Activation('relu'),
    layers.MaxPool2D(pool_size=(2, 2), strides=2, padding='same'),
    #layers.Dropout(0.2),

 
    layers.Flatten(),  # Flatten层,连接卷积层与全连接层
    layers.Dense(4096, activation='relu'),  # 全连接层,特征进一步提取
    layers.Dense(4096, activation='relu'),  # 全连接层,特征进一步提取
    layers.Dense(len(class_names),activation='softmax')  # 输出层,输出预期结果
])
model.summary()

四 训练模型

模型训练时,需要完成如下设置

损失函数(loss):衡量模型准确率

优化器(optimizer):根据损失函数进行优化更新

指标(metrics):监控训练过程,保存最优模型

1.设置动态学习率

initial_learning_rate = 1e-4

lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
        initial_learning_rate, 
        decay_steps=30,      # 敲黑板!!!这里是指 steps,不是指epochs
        decay_rate=0.99,     # lr经过一次衰减就会变成 decay_rate*lr
        staircase=True)

# 设置优化器
opt = tf.keras.optimizers.Adam(learning_rate=initial_learning_rate)

model.compile(optimizer=opt,
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

注意损失函数不要用错了!

对于损失函数可以参考下面文章

(8条消息) tensorflow损失函数详解_重邮研究森的博客-CSDN博客

此外,需要注意在dataset设置中label_model的设置会影响loss

2.早期与保存最佳模型参数

关于ModelCheckpoint参考下面文章(8条消息) ModelCheckpoint 讲解【TensorFlow2入门手册】_K同学啊的博客-CSDN博客_modelcheckpoint函数

from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
 
epochs = 100
 
# 保存最佳模型参数
checkpointer = ModelCheckpoint('best_model.h5',
                                monitor='val_accuracy',
                                verbose=1,
                                save_best_only=True,
                                save_weights_only=True)
 
# 设置早停
earlystopper = EarlyStopping(monitor='val_accuracy', 
                             min_delta=0.001,
                             patience=20, 
                             verbose=1)

3.模型训练

history = model.fit(train_ds,
                    validation_data=val_ds,
                    epochs=epochs,
                    callbacks=[checkpointer, earlystopper])

 可以看到在第三轮模型准确率到了100%

五 模型评估

1.Loss和Accuracy图

 2.指定图片进行预测

# 加载效果最好的模型权重
model.load_weights('best_model.h5')
from PIL import Image
import numpy as np
 
img = Image.open("./49-data/Dark/dark (100).png")  #这里选择你需要预测的图片

img=np.array(img)
image = tf.image.resize(img, [img_height, img_width])
 
img_array = tf.expand_dims(image, 0) 
 
predictions = model.predict(img_array) # 这里选用你已经训练好的模型
print("预测结果为:",class_names[np.argmax(predictions)])

 3.总结

1.在调用官方模型时,改变最后dense层分别为1024,512,4这样的形式。

准确率:100%(第三轮),模型参数:15,766,852

2.在使用自己搭建的官方模型时(完全按照官方搭建)

准确率:0.99167,模型参数:134,276,932

2.在使用自己搭建的官方模型时(加入BN层和drouput)

准确率:0.95,模型参数:134,290,756

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值