一、实验目的
本实验的目的是基于卷积神经网络对猫狗图片进行分类,并通过调整优化器和学习率等参数,优化网络的训练效果。具体来说,实验的目标有以下几点:
1.图像分类问题:通过训练一个卷积神经网络模型,能够准确地将猫和狗的图片进行分类,使得模型能够正确地区分输入图像中的猫和狗。
2.过拟合问题:通过观察训练集和测试集的正确率差异,判断模型是否发生了过拟合现象。如果在训练集上的正确率高于测试集,即模型在训练集上表现良好但在新数据上表现较差,就需要采取措施减小过拟合问题。
3.优化器选择:选择合适的优化器来优化模型的训练过程。不同的优化器具有不同的优化策略,如梯度下降、动量、学习率衰减等。实验通过比较RMSprop、SGD、Nadam和Adam四种优化器的效果,找到适合该问题的最优优化器。
4.学习率选择:调整学习率来探索模型在不同学习率下的性能表现。学习率决定了参数更新的步幅,过小的学习率会导致收敛速度慢,而过大的学习率可能导致模型无法收敛或在最优点附近震荡。实验通过比较不同学习率下的正确率变化,确定适合该问题的最优学习率。
二、实验原理
1.数据处理
在本实验中,我们使用了Kaggle提供的猫狗数据集。数据预处理是指将原始数据转换为模型能够使用的格式。在本实验中,考虑到电脑内存和训练时间等因素,我们从下载的数据集中选择了部分数据作为训练集和验证集。
2.卷积神经网络
卷积神经网络(Convolutional Neural Network,CNN)是一种特别适用于图像处理任务的深度学习模型,通过多层卷积层和池化层提取图像的特征,并使用全连接层进行分类。
(1)卷积层
卷积层用于从图像中提取特征,它通过将一组卷积核与输入图像进行卷积操作来获取特征图。卷积核可以看作是一种滤波器,通过滑动在图像上进行卷积操作,可以识别出不同的特征,如边缘、纹理等。每个卷积核都会生成一个对应的特征图,这些特征图会捕捉到不同位置的相似特征。
(2)池化层
池化层用于降低特征图的空间大小和参数数量,从而减少计算量。最常见的池化操作是最大池化,它用一个滤波器扫描特征图,选择每个区域中的最大值作为输出。最大池化能够提取出图像的主要特征,同时具备一定的平移和旋转不变性。
(3)全连接层
在卷积层和池化层之后,通常会使用全连接层进行分类。全连接层将特征图展平为一维向量,并通过多个全连接层进行映射和分类。最后一层一般使用softmax函数将输出转换为概率分布,表示输入图像属于每个类别的概率。
3.模型优化
(1)数据增强
数据增强是一种常用的技术,通过在训练过程中对原始数据进行变换和扩充,以增加数据的多样性和数量,从而提高模型的泛化能力和鲁棒性。数据增强可以通过多种方式实现,包括平移、旋转、剪切、缩放、翻转、添加噪声等操作。
(2)优化器
在实验中,通过调整优化器和学习率等参数,可以进一步优化模型的训练效果。优化器是训练神经网络时使用的算法,用于自适应地调整模型中的参数,以减小损失函数的值。常见的优化器包括RMSprop、SGD、Nadam和Adam。不同的优化器具有不同的优化策略,如动量、学习率衰减等。下面是这些优化器的具体介绍:
①RMSprop(Root Mean Square Propagation):RMSprop是一种自适应学习率优化算法,通过考虑最近梯度的平方平均来调整学习率。它可以解决标准梯度下降算法中学习率设置不合理的问题,并减少参数更新的方差。RMSprop具有一种保守的更新策略,能更好地适应不同维度的梯度变化。
②SGD(Stochastic Gradient Descent):SGD是一种基本的优化算法,它在每次迭代中随机选择一个样本进行梯度计算和参数更新。SGD的优势是计算简单、易于理解,但由于每次只使用一个样本进行更新,可能会导致参数更新的方向不稳定,使优化过程较慢。
③Nadam:Nadam是一种整合了Nesterov动量(Nesterov Momentum)和Adam算法的优化算法。Nadam通过引入动量的思想,在更新参数时考虑了之前的动量信息,并结合Adam的自适应学习率方式。Nadam能够在处理非凸问题时更快地收敛,并具有较好的泛化性能。
④Adam(Adaptive Moment Estimation):Adam是一种自适应学习率优化算法,结合了Momentum和RMSprop的优点。Adam算法使用了一阶和二阶矩估计来自适应地调整学习率,能够更好地适应不同参数的梯度变化,并在训练过程中保持较低的学习率。Adam通常被认为是一种有效的优化算法,广泛应用于深度学习中。
(3)学习率
学习率是指每次参数更新时的调整幅度,它决定了模型在训练过程中的收敛速度和最终准确性。较小的学习率可能导致收敛速度慢,而较大的学习率可能导致模型无法收敛或在最优点附近震荡。因此,在实验中,通过尝试不同的学习率,可以找到最适合的学习率,以获得更好的模型性能。
在实验中,我们可以观察训练集和验证集的准确率和损失函数随轮次的变化情况,以评估模型的性能和训练效果。通过调整优化器和学习率等参数,可以进一步改善模型的准确性和泛化能力,提高对猫狗图片的分类效果。
三、实验数据收集
数据集选取自网站https://www.kaggle.com/c/dogs-vs-cats/data。该数据集有25000张猫和狗的图片,其中猫和狗各有12500张图片。
四、实验环境
在实验过程中,使用了以下工具和库:
Python编程语言
Jupyter Notebook环境
Numpy库:处理图像数据,进行图像读取、处理和预处理,以及将图像数据转换为卷积神经网络中的张量格式。
Matplotlib库:可视化分类效果(训练集和验证集的准确率和损失函数随轮次的变化情况等)。
TensorFlow:开源深度学习框架,用于构建和训练神经网络模型。在实验中,使用TensorFlow来定义卷积神经网络架构,并进行模型训练和评估。
Keras:深度学习API,用于在TensorFlow等后端上构建和训练深度学习模型。在实验中,使用Keras来构建卷积神经网络架构,并在TensorFlow后端上进行训练和评估。
五、实验步骤
1.数据处理和分析
数据预处理:从25000张图片中选取3000张猫和3000张狗的图像作为训练集,选取1000张猫和1000张狗的图像作为验证集。
# 原始目录所在的路径
original_dataset_dir = "C:\\Users\\Dell\\最优化——神经网络\\dogs_cats\\data\\train"
# # 数据集分类后的目录
base_dir = "C:\\Users\\Dell\\最优化——神经网络\\dogs_cats\\data\\train6"
os.mkdir(base_dir)
# # 训练、验证数据集的目录
train_dir = os.path.join(base_dir, 'train')
# os.mkdir(train_dir)
validation_dir = os.path.join(base_dir, 'validation')
os.mkdir(validation_dir)
# 猫训练图片所在目录
train_cats_dir = os.path.join(train_dir, 'cats')
os.mkdir(train_cats_dir)
# 狗训练图片所在目录
train_dogs_dir = os.path.join(train_dir, 'dogs')
os.mkdir(train_dogs_dir)
# 猫验证图片所在目录
validation_cats_dir = os.path.join(validation_dir, 'cats')
os.mkdir(validation_cats_dir)
# 狗验证数据集所在目录
validation_dogs_dir = os.path.join(validation_dir, 'dogs')
os.mkdir(validation_dogs_dir)
# 将前3000张猫图像复制到train_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(1,1001)]
for fname in fnames:
src = os.path.join(original_dataset_dir+"\\cats\\", fname)
# print(src)
dst = os.path.join(train_cats_dir, fname)
# print(dst)
shutil.copyfile(src, dst)
# 将下1000张猫图像复制到validation_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(1001, 1501)]
for fname in fnames:
src = os.path.join(original_dataset_dir+"\\cats\\", fname)
dst = os.path.join(validation_cats_dir, fname)
shutil.copyfile(src, dst)
# 将前1000张狗图像复制到train_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(1,1001)]
for fname in fnames:
src = os.path.join(original_dataset_dir+"\\dogs\\", fname)
dst = os.path.join(train_dogs_dir, fname)
shutil.copyfile(src, dst)
# 将下1000张狗图像复制到validation_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(1001, 1501)]
for fname in fnames:
src = os.path.join(original_dataset_dir+"\\dogs\\", fname)
dst = os.path.join(validation_dogs_dir, fname)
shutil.copyfile(src, dst)
部分图像可视化如下:
2.卷积神经网络
(1)构建卷积神经网络模型
我们采用Keras深度学习框架搭建模型,构建了四个卷积层,四个池化层,一个展平层,两个全连接层,其中,卷积层和池化层用于提取特征,展平层为了方便连接全连接层,relu激活函数和sigmoid激活函数用于增加非线性性,全连接层用于输出预测结果。该卷积神经网络结构及该模型的具体参数如下:
#网络模型构建
#keras的序贯模型
model = Sequential()
#卷积层,卷积核是3*3,激活函数relu
model.add(layers.Conv2D(32, (3, 3), activation='relu',
input_shape=(150, 150, 3)))
#最大池化层
model.add(layers.MaxPooling2D((2, 2)))
#卷积层,卷积核2*2,激活函数relu
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
#最大池化层
model.add(layers.MaxPooling2D((2, 2)))
#卷积层,卷积核是3*3,激活函数relu
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
#最大池化层
model.add(layers.MaxPooling2D((2, 2)))
#卷积层,卷积核是3*3,激活函数relu
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
#最大池化层
model.add(layers.MaxPooling2D((2, 2)))
#flatten层,用于将多维的输入一维化,用于卷积层和全连接层的过渡
model.add(layers.Flatten())
#全连接,激活函数relu
model.add(layers.Dense(512, activation='relu'))
#全连接,激活函数sigmoid
model.add(layers.Dense(1, activation='sigmoid'))
由于每一层的结点数都非常多,因此我们以训练集中的一张图片为例,输入模型后经过第一个卷积层后得到的部分输出进行了可视化:
(2)训练卷积神经网络模型
在训练之前我们设置神经网络模型的编译参数,主要包括损失函数、优化器和评估指标。因为猫狗分类为二分类任务,因此我们选择的是二分类交叉熵损失函数,优化器随机选择的是RMSprop优化器,学习率设置为1e-4。对图像进行预处理,所有图像将按1/255重新缩放,对图像的大小(150x150),每个批次的图像数(20)和类别的模式(二进制标签)进行设定,并创建了训练数据生成器和验证数据生成器,然后训练模型,训练步数为100,同时验证步数为50,训练了30轮。然后对训练集和验证集的正确率和损失进行了可视化:
从图中我们可以看出当训练集的正确率达到100%时验证集的正确率只有80%左右,说明该模型出现了过拟合,因此我们需要采取措施减少过拟合,提高模型的泛化能力。
3.优化
(1)数据增强
为了减少网络的过拟合,我们对训练集的图片进行数据增强,包括对图片进行随机旋转,剪切,随机缩放,平移等操作。
下图是对一张训练集图片做出的转换的示例:
然后将数据增强后的训练集和未数据增强的验证集重新建立模型,训练了30轮,得出了训练集和验证集的正确率和损失:
经过数据增强后训练集正确率为78%验证集正确率为80%左右,可以很明显的观察到曲线没有过度拟合了,训练曲线紧密地跟踪验证曲线。
(2)优化器
进行数据增强后,虽然没有过度拟合,但是正确率还是只有80%,为了进一步提高正确率,我们选择不同的优化器训练模型,包括RMSprop、SGD、Nadam和Adam,并将训练轮数提高到100轮,此时的学习率均为1e-4,观察各优化器的性能。
从图中我们可以看出Nadam优化器的效果最好,此时验证集正确率已经达到了90%。而SGD优化器的性能最差,正确率只有55%左右,可能是因为优化算法在参数更新的方式和收敛性上存在差异,Nadam通常更容易找到更优的局部极小值。
(3)学习率
通过(2)我们确定了最有优化器,但是模型的正确率与学习率这个超参数也息息相关,因此我们选用了四个常用的学习率,和最优的Nadam优化器进行训练,每次扩大10倍,可视化如下:
从图中我们可以看出当学习率为1e-3时模型的泛化性能最好,验证集正确率达到了95%左右。而步长为1e-2或1e-1时正确率只有50%,模型的预测效果非常差。代码如下:
# 不同的学习率
learning_rates = [1e-4,1e-3,1e-2,1e-1]
# 针对每个学习率创建模型并编译
new_models = []
new_histories = []
for learning_rate in learning_rates:
optimizer = optimizers.Nadam(learning_rate=learning_rate)
model = create_new_model() # 创建新的模型对象
model.compile(loss='binary_crossentropy',
optimizer=optimizer,
metrics=['acc'])
new_models.append(model)
from keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
train_datagen = ImageDataGenerator(
rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,)
# Note that the validation data should not be augmented!
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
# This is the target directory
train_dir,
# All images will be resized to 150x150
target_size=(150, 150),
batch_size=32,
# Since we use binary_crossentropy loss, we need binary labels
class_mode='binary')
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(150, 150),
batch_size=32,
class_mode='binary')
steps_per_epoch = len(train_generator)
validation_steps = len(validation_generator)
history = model.fit(
train_generator,
steps_per_epoch=steps_per_epoch,
epochs=100,
validation_data=validation_generator,
validation_steps=validation_steps
)
# 保存历史纪录
new_histories.append(history)
六、实验结果分析
本次实验我们利用卷积神经网络对猫狗进行了分类,在实验得出了以下结论:
1.过拟合问题
原始的卷积神经网络在训练集上表现出很高的正确率(100%),但在测试集上的正确率却较低(80%),这表明出现了过拟合问题。为了解决这个问题,我们进行了数据增强操作。通过对训练集图像进行旋转、缩放、平移等增强操作,增加了训练数据的多样性,从而缓解了过拟合问题。经过数据增强后,模型在训练集和测试集上的正确率都变成了80%,这是一个可接受的折中结果,但是我们需要更好的模型去优化该问题。
2.优化器的选择
在本次实验中,我们尝试了不同的优化器,包括RMSprop、SGD、Nadam和Adam。结果显示,Nadam优化器在测试集上达到了最好的性能,测试集正确率达到了90%。而SGD优化器表现最差,测试集正确率只有55%。这说明不同的优化器对模型的性能有显著影响,Nadam是一种结合了Nesterov动量和Adam优化器的优化算法。相比于SGD优化器,Nadam具有更快的收敛速度和更好的稳定性。因此,通常在训练深度神经网络时,Nadam优化器可以帮助模型更快地达到更好的性能,选择合适的优化器可以提高模型在测试集上的准确率。
3.学习率的选择
我们进一步分析了不同的学习率对模型性能的影响。通过尝试4个不同的学习率(1e-4、1e-3、1e-2、1e-1),发现最优的学习率是1e-3,模型在测试集上的正确率达到了95%左右。但当学习率为1e-2或1e-1时,模型的测试集正确率一直在50%附近震荡。这表明较大的学习率可能导致模型在参数空间中跳跃过大,进而导致模型无法充分学习,无法有效地收敛到全局最优解或降低训练误差,从而影响了模型在测试集上的准确性。而较小的学习率可能会导致收敛速度过慢,在有限的训练时间内无法充分收敛,导致准确率较低。因此选择合适的学习率,对模型在训练过程中平衡收敛速度和性能表现具有重要作用。
七、总结
综上所述,通过对模型架构、数据增强、优化器和学习率的优化,我们成功提高了猫狗识别模型在测试集上的正确率。这些结论为进一步优化模型性能提供了指导,同时也表明模型优化是一个复杂的过程,需要综合考虑多个因素的影响。在未来的研究中,可以继续探索其他优化方法,以进一步提高模型的性能和泛化能力。