基于cifar10数据集CNN卷积网络的实现

1.CNN简介

CNN是卷积神经网络的简称,是深度学习的算法之一,目前在图像的分割领域有着广泛的应用。因为卷积神经网络概念很多可以参考如下的博客:
1、CNN笔记:通俗理解卷积神经网络:https://blog.csdn.net/v_JULY_v/article/details/51812459
2、卷积神经网络(CNN)详解https://zhuanlan.zhihu.com/p/47184529

2.环境配置

采用Anaconda3配置的python环境,选择TensorFlow-CPU2.1版本(本人TensorFlow-GPU测试不成功),需要额外导入matplotlib库。具体可以参照:【北京大学】Tensorflow2.0
项目工程文件

3. 数据集准备

这里我们使用cifar10数据集,下面对cifar10数据集做个简单介绍,参考博客为:https://blog.csdn.net/DaVinciL/article/details/78793067

3.1 CIFAR-10数据集

CIFAR-10数据集由10类32x32的彩色图片组成,一共包含60000张图片,每一类包含6000图片。其中50000张图片作为训练集,10000张图片作为测试集。CIFAR-10数据集被划分成了5个训练的batch和1个测试的batch,每个batch均包含10000张图片。测试集batch的图片是从每个类别中随机挑选的1000张图片组成的,训练集batch以随机的顺序包含剩下的50000张图片。不过一些训练集batch可能出现包含某一类图片比其他类的图片数量多的情况。训练集batch包含来自每一类的5000张图片,一共50000张训练图片。下图显示的是数据集的类,以及每一类中随机挑选的10张图片,如图 1 CIFAR-10数据集:
在这里插入图片描述

图 1 CIFAR-10数据集

3.2 tensorflow2.0下载

tensorflow2.0下载数据集准备,使用如下代码即可完成下载。

cifar10 = tf.keras.datasets.cifar10

但是需要科学上网,官方给出了多个CIFAR-10数据集的版本,如表格 1 CIFAR-10数据集的版本以下是链接:
表格 1 CIFAR-10数据集的版本

VersionSizemd5sum
CIFAR-10 python version163 MBc58f30108f718f92721af3b95e74349a
CIFAR-10 Matlab version175 MB70270af85842c9e89bb428ec9976c926
CIFAR-10 binary version (suitable for C programs)162MBc32a1d4ab5d03f1284b67883e8d87530

此处我们下载python版本。下载完成后,解压,放到我截图中的位置即可,如图 2 数据集路径。
在这里插入图片描述
图 2 数据集路径

4 tensenflow2.0中关于卷积相关函数简介
4.1 数据集加载函数
cifar10 = tf.keras.datasets.cifar10
(x_train,y_trian),(x_test,y_test) = cifar10.load_data()

这里我们使用tf中keras模块加载数据集,最后会返回两个元组,一个为训练集,一个为测试集,函数为load_data()

4.2 Conv2D
tf.keras.layers.Conv2D(
    filters, kernel_size, strides=(1, 1), padding='valid', data_format=None,
    dilation_rate=(1, 1), activation=None, use_bias=True,
    kernel_initializer='glorot_uniform', bias_initializer='zeros',
    kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None,
    kernel_constraint=None, bias_constraint=None, **kwargs
)

该函数将创建一个卷积核,这里我只使用filters(卷积核),kerel_size(卷积核大小),strides(步长),padding(全零填充,valid表示不使用全零填充,same表示使用全零填充)

4.3 BatchNormalization
tf.keras.layers.BatchNormalization(
    axis=-1, momentum=0.99, epsilon=0.001, center=True, scale=True,
    beta_initializer='zeros', gamma_initializer='ones',
    moving_mean_initializer='zeros', moving_variance_initializer='ones',
    beta_regularizer=None, gamma_regularizer=None, beta_constraint=None,
    gamma_constraint=None, renorm=False, renorm_clipping=None, renorm_momentum=0.99,
    fused=None, trainable=True, virtual_batch_size=None, adjustment=None, name=None,
    **kwargs
)

该函数为披标准化函数,作用为:加速收敛、控制过拟合,可以少用或不用Dropout和正则、降低网络对初始化权重不敏感、允许使用较大的学习率。

4.4 Activation
tf.keras.layers.Activation(
    activation, **kwargs
)

指定当前神经网络层激活函数,这里我们使用relu激活函数,

4.5 MaxPool2D
tf.keras.layers.MaxPool2D(
    pool_size=(2, 2), strides=None, padding='valid', data_format=None, **kwargs
)

最大池化函数,pool_size(池化层大小),strides(步长),padding(是否使用全零填充,valid表示不使用全零填充,same表示使用全零填充)

4.6 Dropout
tf.keras.layers.Dropout(
    rate, noise_shape=None, seed=None, **kwargs
)

该函数用来随机舍弃神经元,防止训练过程中出现过拟合情况,我们只用rate
总结:在搭建卷积神经网络过程中我们使用到了如下的口诀,CBAPD,分别对应tf函数为Conv2D,BatchNormalization,Activation,MaxPool2D,Dropout,请记住,卷积就是特征提取器,在下边的代码中我们会遵循CBAPD来实现一个卷积神经网络

5 基础卷积神经网络实现

这里我们要搭建一个这样结构的卷积神经网络,CBAPD,CBA,CBAPD,全连接层(12812810)
在这里插入图片描述

5.1 加载数据集
cifar10 = tf.keras.datasets.cifar10
(x_train,y_trian),(x_test,y_test) = cifar10.load_data()
5.2 归一化处理

运用归一化处理能够加快神经网络收敛速度

x_train,x_test = x_train/255.0,x_test/255.0
5.3 搭建卷积模型(重点)

这里我们不同于我之前的博客,我们使用类的方式来搭建CNN,随后的博客中也只需要更改3中的卷积模块即可实现功能。
这里我们指定一个类,继承自tf.keras.Model

class Baseline(Model):

然后弄一个初始化函数

def __init__(self):

再实现父类的init方法

super(Baseline,self).__init__()

完整代码如下

class Baseline(Model):
    def __init__(self):
        super(Baseline,self).__init__()
        self.c1 = Conv2D(filters=6,kernel_size=(5,5),padding="same")#卷积层
        self.b1 = BatchNormalization()#BN层
        self.a1 = Activation("relu")
        self.p1 = MaxPool2D(pool_size=(2,2),strides=2,padding="same")#池化层
        self.d1 = Dropout(0.2)
        self.c2 = Conv2D(filters=12,kernel_size=(5,5),padding="same")
        self.b2 = BatchNormalization()
        self.a2 = Activation("relu")
        self.c3 = Conv2D(filters=24,kernel_size=(5,5),padding="same")
        self.b3 = BatchNormalization()
        self.a3 = Activation("relu")
        self.p3 = MaxPool2D(pool_size=(2,2),strides=2,padding="same")
        self.d3 = Dropout(0.2)
        self.flatten = Flatten()
        self.f1 = Dense(128,activation="relu")
        self.d4 = Dropout(0.2)
        self.f2 = Dense(128,activation="relu")
        self.d5  =Dropout(0.2)
        self.f3 = Dense(10,activation="softmax")

结合CBAPD是不是显得很清晰呢,到这里我们完成了网络结构的搭建,现在我们还要过一遍前向传播
我们使用call函数来表示

def call(self,x):
    x = self.c1(x)
    x = self.b1(x)
    x = self.a1(x)
    x = self.p1(x)
    x = self.d1(x)
    x = self.c2(x)
    x = self.b2(x)
    x = self.a2(x)
    x = self.c3(x)
    x = self.b3(x)
    x = self.a3(x)
    x = self.p3(x)
    x = self.d3(x)
    x = self.flatten(x)
    x = self.f1(x)
    x = self.d4(x)
    x = self.f2(x)
    x = self.d5(x)
    y = self.f3(x)
    return y
5.4 训练过程参数配置

这里可以参考我之前的这篇博客,细节讲解全在里边了https://blog.csdn.net/JohnLeeK/article/details/106423634

5.4.1 指定学习率,优化器等
model.compile(optimizer = tf.keras.optimizers.Adam(
    learning_rate = 0.001,beta_1 = 0.9,beta_2 = 0.999#自定义动量,adam和学习率,也是为了提高准确率
),
              loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
              metrics = ["sparse_categorical_accuracy"]
              )
5.4.2 断点续训:
checkpoint_save = "./checkpoinCNNBase/Baseline.ckpt"
if os.path.exists(checkpoint_save+".index"):
    print("---------------load the model----------------------")
    model.load_weights(checkpoint_save)
cp_callback = tf.keras.callbacks.ModelCheckpoint(
    filepath = checkpoint_save,
    save_weights_only = True,
    save_best_only = True
)
5.4.3 将数据喂入神经网络
history = model.fit(
    x_train,y_trian,batch_size = 2048,epochs = 300,validation_data = (x_test,y_test),
    validation_freq = 1,callbacks = [cp_callback]
)
5.4.4 打印网络结构
model.summary()
5.4.5 保存权重
file = open("./cifar10_weights.txt","w")
for v in model.trainable_variables:
    file.write(str(v.name)+"\n")
    file.write(str(v.shape)+"\n")
    file.write(str(v.numpy())+"\n")
file.close()
5.4.6 绘制准确率和损失函数并保存
acc = history.history["sparse_categorical_accuracy"]
val_acc = history.history["val_sparse_categorical_accuracy"]
loss = history.history["loss"]
val_loss = history.history["val_loss"]
plt.subplot(1,2,1)
plt.plot(acc,label = "Training Acc")
plt.plot(val_acc,label = "Validation Acc")
plt.title("Training and Validation Acc")
plt.legend()
plt.subplot(1,2,2)
plt.plot(loss,label = "Training Loss")
plt.plot(val_loss,label = "Validation Loss")
plt.title("Trainning and Validation Loss")
plt.legend()
plt.savefig("./day4_cifar1_baseline")

6 结果展示

训练结果如图 3 训练结果acc和loss可视化
在这里插入图片描述

图 3 训练结果acc和loss可视化
这里可以看到在经过300轮的训练之后我们的神经网络,对cifar10数据集的分类准确率能达到80%以上,但是我们还可以发现80%并不是最优的结果,从图中观察可以发现准确率曲线没有趋于平滑,还有上升的趋势,原因如下:
1.我训练次数偏少只训练了300轮,对于当前网络模型并未达到最优解
2.我并未对神经网络结构进行优化,卷积层数较少,特征提取能力较弱
3.全连接层偏少分类预测率较低

参考文献

### 回答1: PyTorch可以使用CNN来训练CIFAR10数据集。首先,需要导入必要的库和数据集。然后,定义CNN模型和优化器。接下来,使用训练数据集对模型进行训练,并使用测试数据集对模型进行评估。最后,可以保存训练好的模型以备后续使用。 ### 回答2: 使用 PyTorch 训练 CIFAR10 的过程主要包括数据准备、模型搭建、模型训练和结果评估等 4 个步骤。 1. 数据准备 CIFAR10 是一个常用的图像分类数据集,包含了 10 个分类,共计 60000 张 32x32 像素的彩色图片。我们首先需要用 PyTorch 加载 CIFAR10 数据集,并进行数据预处理。PyTorch 提供了 torchvision.datasets 模块,其中包含了 CIFAR10 数据集的加载函数。 ``` import torchvision.datasets as dset import torchvision.transforms as transforms transform = transforms.Compose([ transforms.Resize(32), transforms.RandomHorizontalFlip(), transforms.RandomCrop(32, padding=4), transforms.ToTensor(), transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) ]) train_set = dset.CIFAR10(root='./data', train=True, download=True, transform=transform) test_set = dset.CIFAR10(root='./data', train=False, download=True, transform=transform) ``` 其中 transform 参数表示对数据进行的预处理操作,包括图像大小调整、随机水平翻转、随机裁剪等,可以有效提升模型的鲁棒性。train_set 和 test_set 分别表示训练集和测试集。 2. 模型搭建 本文采用的是卷积神经网络CNN)进行 CIFAR10 分类。我们可以用 PyTorch 构建卷积神经网络,也可以使用 PyTorch 提供的深度学习框架 ResNet,该框架在 ImageNet 分类任务上获得了很好的成绩。这里我们使用 PyTorch 构建一个简单的 CNN 模型: ``` import torch.nn as nn class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1) self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) self.pool = nn.MaxPool2d(2, 2) self.fc1 = nn.Linear(64 * 8 * 8, 512) self.fc2 = nn.Linear(512, 10) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = x.view(-1, 64 * 8 * 8) x = F.relu(self.fc1(x)) x = self.fc2(x) return x net = Net() ``` 其中 Conv2d 表示卷积层,MaxPool2d 表示最大池化层,Linear 表示全连接层。损失函数可以使用交叉熵(CrossEntropy)等常见的分类损失函数,优化器可以使用梯度下降法(SGD)等常见的优化算法。 3. 模型训练 在模型和数据准备好后,我们可以利用 PyTorch 提供的深度学习训练框架进行模型训练。训练时需要设定一些超参数,如学习率、批量大小等。具体代码如下: ``` import torch.optim as optim criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9) for epoch in range(10): running_loss = 0.0 for i, data in enumerate(trainloader, 0): inputs, labels = data optimizer.zero_grad() outputs = net(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() if i % 2000 == 1999: print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000)) running_loss = 0.0 print('Finished Training') ``` 其中 criterion 表示损失函数,optimizer 表示优化器。我们将训练数据分为若干批次,每次从数据集中随机取出一批数据进行训练。 4. 结果评估 训练完成后,我们需要对模型进行测试来评估其分类性能。测试的代码如下: ``` correct = 0 total = 0 with torch.no_grad(): for data in testloader: images, labels = data outputs = net(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total)) ``` 其中,我们遍历测试集,计算分类正确的样本数和总样本数,用正确分类的比例即可评估模型的分类性能。 总之,利用 PyTorch 训练 CIFAR10 就是这样一个基本的过程,其中会涉及到 PyTorch 中的模型搭建、数据准备、模型训练、模型测试等内容。需要不断地进行实践和调试,才能提升模型性能并实现更加优秀的结果。 ### 回答3: PyTorch是一种开源的深度学习框架,支持动态图计算,能够帮助开发人员快速高效地构建、训练深度神经网络。而卷积神经网络CNN)则是深度学习中最常用的一种网络结构,它能够有效地处理图像、语音和自然语言等复杂数据,因此在图像分类、目标检测、人脸识别等领域有着广泛应用。本文将介绍如何使用PyTorch训练一个CNN来对CIFAR10数据集中的图像进行分类。 CIFAR10是一个包含60000张32x32像素的RGB图像的数据集,其中50000张用于训练,10000张用于测试,共有10个类别,即飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船和卡车。我们的目标是使用PyTorch训练一个CNN来识别这些图像,并对测试集中的图像进行分类。 首先,我们需要下载和加载CIFAR10数据集。PyTorch提供了一个内置的数据加载器,可以方便地加载CIFAR10数据集。代码如下: ``` import torchvision import torchvision.transforms as transforms # 定义数据预处理方式 transform = transforms.Compose( [transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) # 加载训练集和测试集 trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform) trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2) testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform) testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2) # 定义10个类别的名称 classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') ``` 在这个例子中,我们定义了一个数据预处理方式,包括随机水平翻转、转换为张量和归一化。然后使用`torchvision.datasets.CIFAR10`方法加载训练集和测试集,并使用`torch.utils.data.DataLoader`方法将它们封装为批量的迭代器。最后定义10个类别的名称。 接下来,我们需要定义CNN模型。在这个例子中,我们使用4个卷积层和3个全连接层来构建CNN模型。首先定义`__init__()`方法以定义网络结构,然后定义`forward()`方法以实现前向传播。代码如下: ``` import torch.nn as nn import torch.nn.functional as F # 定义CNN模型 class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(3, 64, kernel_size=3, padding=1) self.conv2 = nn.Conv2d(64, 128, kernel_size=3, padding=1) self.conv3 = nn.Conv2d(128, 256, kernel_size=3, padding=1) self.conv4 = nn.Conv2d(256, 512, kernel_size=3, padding=1) self.pool = nn.MaxPool2d(2, 2) self.fc1 = nn.Linear(512 * 4 * 4, 1024) self.fc2 = nn.Linear(1024, 512) self.fc3 = nn.Linear(512, 10) # 定义前向传播 def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = self.pool(F.relu(self.conv3(x))) x = self.pool(F.relu(self.conv4(x))) x = x.view(-1, 512 * 4 * 4) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x net = Net() # 实例化网络 ``` 在这个例子中,我们使用`nn.Module`方法来创建一个新的模型类,包含4个卷积层和3个全连接层。在`__init__()`方法中,我们定义了每个卷积层的输入通道数、输出通道数、卷积核大小和填充大小,以及每个全连接层的输入和输出大小。在`forward()`方法中,我们定义了CNN的前向传播过程,包括卷积、池化和全连接等操作。 接下来,我们需要定义损失函数和优化器。这里我们使用交叉熵损失函数和随机梯度下降优化器。 ``` import torch.optim as optim criterion = nn.CrossEntropyLoss() # 定义损失函数 optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9) # 定义优化器 ``` 在训练过程中,我们需要对网络进行多次迭代,每次迭代称为一个epoch。在每个epoch中,我们将输入数据馈送到CNN模型中进行前向传播得到输出,根据输出计算损失函数,然后根据损失函数调整模型中的参数来最小化损失。训练的代码如下: ``` # 定义训练函数 def train(net, epoch): running_loss = 0.0 for i, data in enumerate(trainloader, 0): inputs, labels = data optimizer.zero_grad() outputs = net(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() if i % 2000 == 1999: print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000)) running_loss = 0.0 # 开始训练 for epoch in range(10): # 数据集迭代10次 train(net, epoch) print('Finished Training') ``` 在这个例子中,我们定义了一个`train()`函数,接受CNN模型和epoch数作为输入,然后对训练集中的所有图像进行迭代,计算损失并调整模型参数。在每个epoch中,我们将训练损失打印出来,以便跟踪训练进度。最后,我们使用一个简单的循环来执行多个epoch的训练。 在训练完成后,我们需要对测试集进行分类并计算分类准确率。这里我们需要使用`torch.no_grad()`方法来取消梯度计算,以便在测试过程中节省内存。测试的代码如下: ``` # 定义测试函数 def test(net): correct = 0 total = 0 with torch.no_grad(): for data in testloader: images, labels = data outputs = net(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print('Accuracy of the network on the 10000 test images: %d %%' % ( 100 * correct / total)) # 对测试集进行分类 test(net) ``` 在这个例子中,我们定义了一个`test()`函数,接受CNN模型作为输入,然后对测试集中的所有图像进行分类。在分类过程中,我们使用`torch.no_grad()`方法取消梯度计算,以避免内存浪费。最后,我们计算分类准确率并将其打印出来。 综上所述,以上就是使用PyTorch训练CNNCIFAR10数据集进行分类的步骤。需要注意的是,在实际应用中,我们可能需要对模型进行调试和优化,例如增加或减少网络层数、调整超参数等,以达到更好的分类效果。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2345VOR

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值