猫狗数据集分类VGG16(TensorFlow实现)

import random
import os
import tensorflow as tf
from tensorflow import keras
from shutil import copyfile
from tensorflow.keras import layers
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from PIL import Image
import datetime

# from tensorflow_addons.optimizers import AdamW
print('TensorFlow版本:' + tf.__version__)
print('CUDA设备:' + tf.test.gpu_device_name())

TensorFlow版本:2.6.0
CUDA设备:/device:GPU:0
def walk_through_dir(directory_name):
    for dirpaths, dirnames, filenames in os.walk(directory_name):
        print(f"There are {len(dirnames)} directories and {len(filenames)} images in '{dirpaths}'")
input_data_dir = '../PetImages'
print('目录结构:')
!tree ../PetImages
walk_through_dir(input_data_dir)
目录结构:
卷 新加卷 的文件夹 PATH 列表
卷序列号为 44A6-CC9A
D:\DOCUMENTS\PYTORCH深度学习实战\PETIMAGES
├─Cat
└─Dog
There are 2 directories and 0 images in '../PetImages'
There are 0 directories and 12501 images in '../PetImages\Cat'
There are 0 directories and 12501 images in '../PetImages\Dog'
os.mkdir('./data')  # 创建目录来存放训练数据和测试数据
os.mkdir('./data/train')
os.mkdir('./data/test')
for folder in os.listdir(input_data_dir):  # 遍历cat和dog目录
    files = os.listdir(os.path.join(input_data_dir, folder))  # 拼接得到图像文件的父目录
    images = []  # 创建列表来存储图像路径
    for f in files:  # 遍历Dog/Cat目录下的图像
        try:
            img = Image.open(os.path.join(input_data_dir, folder, f)).convert("RGB")  # 如果图像能够打开则添加到路径列表
            images.append(f)
        except IOError:  # 如果发生输入输出错误则输出发生错误的文件,并跳过该文件
            print(f'fail on {f}')
            pass

    random.shuffle(images)  # 将列表中的路径打乱
    count = len(images)  # Cat/Dog目录下的总图片数
    split = int(0.8 * count)  # 选取其中80%作为训练集
    os.mkdir(os.path.join('./data/train', folder))  # 创建训练集下的Dog/Cat目录
    os.mkdir(os.path.join('./data/test', folder))  # 创建测试集下的Dog/Cat目录

    for c in range(split):
        source_file = os.path.join(input_data_dir, folder, images[c])  # 得到训练集源文件的路径
        distination = os.path.join('./data/train', folder, images[c])  # 创建目标路径
        copyfile(source_file, distination)  # 将训练集路径下的文件放到训练集中
    for c in range(split, count):
        source_file = os.path.join(input_data_dir, folder, images[c])  # 得到测试集源文件的路径
        distination = os.path.join('./data/test', folder, images[c])  # 创建目标存放路径
        copyfile(source_file, distination)  # 将测试集路径下的文件放到测试集中
train_dir = './data/train'  # 生成的训练集文件目录
walk_through_dir(train_dir)  # 查看训练集目录
test_dir = './data/test'  # 生成的测试集文件目录
walk_through_dir(test_dir)  # 查看测试集目录
There are 2 directories and 0 images in './data/train'
There are 0 directories and 9999 images in './data/train\Cat'
There are 0 directories and 9999 images in './data/train\Dog'
There are 2 directories and 0 images in './data/test'
There are 0 directories and 2500 images in './data/test\Cat'
There are 0 directories and 2500 images in './data/test\Dog'
train_datagen = ImageDataGenerator(rescale=1. / 255, horizontal_flip=0.5, vertical_flip=0.5)  # 构建训练集图像迭代器
test_datagen = ImageDataGenerator(rescale=1. / 255)  # 构建测试集图像迭代器
# 从目录获取图像,并设置类模式
train_dataset = train_datagen.flow_from_directory(train_dir, target_size=(224, 224), batch_size=128, class_mode='binary',
                                                  shuffle=True)
test_dataset = test_datagen.flow_from_directory(test_dir, target_size=(224, 224), batch_size=128, class_mode='binary')
Found 19998 images belonging to 2 classes.
Found 5000 images belonging to 2 classes.
# 查看类的映射
train_dataset.class_indices
{'Cat': 0, 'Dog': 1}
# 设置二分类的评价指标
METRICS = [
    keras.metrics.TruePositives(name='tp'),
    keras.metrics.FalsePositives(name='fp'),
    keras.metrics.TrueNegatives(name='tn'),
    keras.metrics.FalseNegatives(name='fn'),
    keras.metrics.BinaryAccuracy(name='accuracy'),
    keras.metrics.Precision(name='precision'),
    keras.metrics.Recall(name='recall'),
    keras.metrics.AUC(name='auc'),
    keras.metrics.AUC(name='prc', curve='PR'),
]
def build_model():  # 设置函数来创建模型
    model = keras.Sequential()
    # 使用VGG16作为模型的基本框架,加载在ImageNet上训练的权重,并去除输出层
    base_model = tf.keras.applications.VGG16(include_top=False, weights='imagenet', input_shape=(224, 224, 3))
    base_model.trainable = False # 冻结VGG16的权重,只训练输出层
    model.add(base_model)
    model.add(layers.Flatten())
    model.add(layers.Dense(1, activation='sigmoid'))  # 二分类,使用sigmoid映射到[0.0,1.0]
    return model
timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')  # 获取当前时间来作为写入的路径
# 设置回调函数来写入训练情况
tf_callback = tf.keras.callbacks.TensorBoard(log_dir='./runs/dogvscat_trainer_{}'.format(timestamp))
model = build_model()
model.compile(
    loss=keras.losses.binary_crossentropy,  # 二分类交叉熵损失
    optimizer=keras.optimizers.Adam(lr=1e-3),  # 使用Adam优化器
    metrics=METRICS  # 设置评价函数
)
print(model.summary())  # 输出模型的形状
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
vgg16 (Functional)           (None, 7, 7, 512)         14714688  
_________________________________________________________________
flatten (Flatten)            (None, 25088)             0         
_________________________________________________________________
dense (Dense)                (None, 1)                 25089     
=================================================================
Total params: 14,739,777
Trainable params: 25,089
Non-trainable params: 14,714,688
_________________________________________________________________
None


C:\Users\reion\miniconda3\envs\tf2\lib\site-packages\keras\optimizer_v2\optimizer_v2.py:355: UserWarning: The `lr` argument is deprecated, use `learning_rate` instead.
  warnings.warn(
EPOCHS = 5 # 训练5轮
history = model.fit(
    train_dataset, epochs=5, validation_data=test_dataset, callbacks=[tf_callback]
)
Epoch 1/5
157/157 [==============================] - ETA: 0s - loss: 0.3822 - tp: 8125.0000 - fp: 1558.0000 - tn: 8441.0000 - fn: 1874.0000 - accuracy: 0.8284 - precision: 0.8391 - recall: 0.8126 - auc: 0.9095 - prc: 0.9141

C:\Users\reion\miniconda3\envs\tf2\lib\site-packages\PIL\TiffImagePlugin.py:845: UserWarning: Truncated File Read
  warnings.warn(str(msg))


157/157 [==============================] - 85s 459ms/step - loss: 0.3822 - tp: 8125.0000 - fp: 1558.0000 - tn: 8441.0000 - fn: 1874.0000 - accuracy: 0.8284 - precision: 0.8391 - recall: 0.8126 - auc: 0.9095 - prc: 0.9141 - val_loss: 0.2288 - val_tp: 2142.0000 - val_fp: 131.0000 - val_tn: 2369.0000 - val_fn: 358.0000 - val_accuracy: 0.9022 - val_precision: 0.9424 - val_recall: 0.8568 - val_auc: 0.9735 - val_prc: 0.9729
Epoch 2/5
157/157 [==============================] - 73s 466ms/step - loss: 0.2533 - tp: 8888.0000 - fp: 908.0000 - tn: 9091.0000 - fn: 1111.0000 - accuracy: 0.8990 - precision: 0.9073 - recall: 0.8889 - auc: 0.9628 - prc: 0.9643 - val_loss: 0.1962 - val_tp: 2300.0000 - val_fp: 191.0000 - val_tn: 2309.0000 - val_fn: 200.0000 - val_accuracy: 0.9218 - val_precision: 0.9233 - val_recall: 0.9200 - val_auc: 0.9782 - val_prc: 0.9779
Epoch 3/5
157/157 [==============================] - 75s 478ms/step - loss: 0.2302 - tp: 8969.0000 - fp: 826.0000 - tn: 9173.0000 - fn: 1030.0000 - accuracy: 0.9072 - precision: 0.9157 - recall: 0.8970 - auc: 0.9686 - prc: 0.9694 - val_loss: 0.2223 - val_tp: 2078.0000 - val_fp: 70.0000 - val_tn: 2430.0000 - val_fn: 422.0000 - val_accuracy: 0.9016 - val_precision: 0.9674 - val_recall: 0.8312 - val_auc: 0.9791 - val_prc: 0.9789
Epoch 4/5
157/157 [==============================] - 77s 487ms/step - loss: 0.2148 - tp: 9040.0000 - fp: 786.0000 - tn: 9213.0000 - fn: 959.0000 - accuracy: 0.9127 - precision: 0.9200 - recall: 0.9041 - auc: 0.9723 - prc: 0.9733 - val_loss: 0.1851 - val_tp: 2329.0000 - val_fp: 220.0000 - val_tn: 2280.0000 - val_fn: 171.0000 - val_accuracy: 0.9218 - val_precision: 0.9137 - val_recall: 0.9316 - val_auc: 0.9802 - val_prc: 0.9802
Epoch 5/5
157/157 [==============================] - 78s 493ms/step - loss: 0.1997 - tp: 9144.0000 - fp: 710.0000 - tn: 9289.0000 - fn: 855.0000 - accuracy: 0.9217 - precision: 0.9279 - recall: 0.9145 - auc: 0.9763 - prc: 0.9770 - val_loss: 0.1807 - val_tp: 2271.0000 - val_fp: 147.0000 - val_tn: 2353.0000 - val_fn: 229.0000 - val_accuracy: 0.9248 - val_precision: 0.9392 - val_recall: 0.9084 - val_auc: 0.9806 - val_prc: 0.9806

每轮损失(红色:训练集,蓝色:测试集)

每轮查准率

posted @ 2022-05-18 19:33  里列昂遗失的记事本  阅读(289)  评论(0编辑  收藏  举报