一.导包
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import pathlib
二.数据处理:
我的数据集一共是10个不同的面部数据
先对数据进行读取
data_dir = r'C:\Users\hao\rgzn21sdxx\sjwl\数据集\face_data' # 文件夹的路径
data_dir = pathlib.Path(data_dir) # Path类是pathlib模块中的主要类,用于表示和操作文件和文件夹路径
img_count = len(list(data_dir.glob('./*/*.jpg'))) # 使用Path对象的glob()方法来查找特定类型的文件
print(img_count)
img_count是总的数据量(电脑硬件不行,没有GPU)
获取标签名
all_images_paths = list(data_dir.glob('*')) # 查找data_dir文件夹中的所有文件和文件夹
all_images_paths = [str(path) for path in all_images_paths]
all_label_names = [path.split("\\")[7].split(".")[0] for path in all_images_paths] # 获得最后一个标签名
print(all_label_names)
拿到的所有文件夹标签名和我实际的文件标签是一样的
三.正文开始
一.设置超参数
height = 224 # 图片高度
width = 224 # 图片宽度
epochs =100 # 训练次数
batch_size = 128 # 每个训练批次中包含的样本数量为128
二.创建一个图像数据增强生成器对象
train_data_gen = tf.keras.preprocessing.image.ImageDataGenerator(
rescale=1./255, # 数据归一化
rotation_range=45, # 随机旋转图像的角度范围为 -45 度到 +45 度。模拟图像在不同角度下的变化
shear_range=0.2, # 随机剪切图像的错切变换范围为 -0.2 到 +0.2。模拟图像在不同错切程度下的变化
zoom_range=0.2, # 随机缩放图像的尺度范围为 0.8 到 1.2。模拟图像在不同缩放程度下的变化
validation_split=0.2, # 将数据集划分为训练集和验证集 训练与验证[8:2]
horizontal_flip=True # 随机水平翻转图像。模拟图像在水平方向上的镜像变换
)
数据增强是一种通过对训练数据进行随机变换来扩充数据集的技术。它可以帮助模型更好地学习到数据的特征,提高模型的泛化能力和鲁棒性。
三.使用train_data_gen自动生成训练集与验证集
train_ds = train_data_gen.flow_from_directory(
directory=data_dir, # 数据集所在的目录
target_size=(height,width), # 图像的大小
batch_size=batch_size, # 每次训练批次数据的大小
shuffle=True, # 在每次训练时打乱数据
class_mode='categorical', # 标签类型 categorical:表示标签是一个多元分类问题,即有多个类别
subset='training' # 生成训练子集
)
test_ds = train_data_gen.flow_from_directory(
directory=data_dir,
target_size=(height,width),
batch_size=batch_size,
shuffle=True,
class_mode='categorical',
subset='validation'
)
可以看到,程序自己将数据集分为了两个。训练数据集一共有49张图片,验证数据集一共有10张图片。(总共59张图片)
四.查看图片
plt.figure(figsize=(15, 10)) # 图形的宽为15高为10
for images, labels in train_ds:
for i in range(8):
ax = plt.subplot(5, 8, i + 1)
plt.imshow(images[i])
plt.title(all_label_names[np.argmax(labels[i])])
plt.axis("off")
break
plt.show()
五.使用Xception预训练
base_model = tf.keras.applications.Xception(weights = 'imagenet',include_top = False,pooling = 'max',input_shape = (height,width,3))
# weights='imagenet':表示使用预训练的 Xception 模型的权重
# include_top=False:表示不包括模型的顶部(全连接层)。这样做的目的是将 Xception 模型作为特征提取器使用,而不是作为一个完整的分类模型
# pooling='max':表示使用最大池化操作来汇集特征
# input_shape=(height, width, 3):表示输入图像的尺寸,其中 height 和 width 是图像的高度和宽度,3 表示图像的通道数(RGB 图像)
base_model.trainable = False#前面的参数设置为不可训练
input = base_model.input # 获取 Xception 模型的输出张量
x = tf.keras.layers.Dense(256,activation='relu')(base_model.output) # 将Xception模型的输出张量连接到一个全连接层
x = tf.keras.layers.Dense(128,activation='relu')(x)
output = tf.keras.layers.Dense(10,activation='sigmoid')(x)
model = tf.keras.models.Model(inputs = input,outputs = output) # input:利用Xception提取图像特征 output:输出自己训练的模型
六.利用Adam指定学习速率
# 设置初始学习率
initial_learning_rate = 1e-4 # 指定初始学习率
lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
initial_learning_rate, # 开始训练时的学习率
decay_steps=300, # 学习步长
decay_rate=0.96, # 更新速率
staircase=True) # 阶梯状的衰减
# 将指数衰减学习率送入优化器
optimizer = tf.keras.optimizers.Adam(learning_rate=lr_schedule)
七.编译模型
model.compile(
optimizer = optimizer, # 优化器
loss = "categorical_crossentropy", # 使用交叉熵损失函数 用于多分类问题
metrics = ['accuracy'] # 评估指标
)
8.训练模型
history = model.fit(
train_ds, # 训练集
validation_data = test_ds, # 验证集
epochs = epochs # 训练次数
)
loss:模型在训练数据集上的损失函数值
accuracy:模型在训练数据集上的正确率
val_loss:模型在验证数据集上的损失函数值
val_accuracy:模型在验证数据集上的准确率
9.打印
plt.plot(history.history.get("loss"),label='loss')
plt.plot(history.history.get('val_loss'),label='val_loss')
plt.legend()
plt.plot(history.history.get("accuracy"),label='acc')
plt.plot(history.history.get('val_accuracy'),label='val_acc')
plt.legend()
可以看到图像一直在震荡,这可能是数据量过小导致产生了过拟合
解决方法:在编译自己的Dense层时增加dropout层
四.模型验证
plt.figure(figsize=(50,50)) # 创建一个大小为 (50, 50) 的图像窗口,能够容纳更多的子图。
num = 0
for images,labels in train_ds:
for i in range(49):
ax = plt.subplot(8,8,i+1)
plt.imshow(images[i])
img_array = tf.expand_dims(images[i],0)
pre = model.predict(img_array) # 预测
if np.argmax(pre) == np.argmax(labels[i]): # 如果预测的和真值相同
plt.title(all_label_names[np.argmax(pre)], fontsize=50)
else:
plt.title("False :"+str(all_label_names[np.argmax(pre)]), fontsize=50)
if np.argmax(pre) == np.argmax(labels[i]):
num += 1
plt.axis("off")
break
plt.suptitle("The Acc rating is:{}".format(num / 50), fontsize=100)
plt.show()
可以看到最后验证准确率为96%,出现了False
结语:
总结一下深度学习的一般步骤为:
1.创建模型
2.编译模型
3.训练模型
4.验证模型
本博客仅作一个基于预训练网络进行图片分类识别的参考。就我自己而言:在进行训练前,一定要对数据进行处理,分清楚这是一个二分类还是多分类问题。激活函数应该使用哪一个,输出函数,以及超参数的设置等等。