[Pytorch] CIFAR-10数据集的训练和模型优化

news2024/9/24 3:29:22

本篇文章借鉴了我的朋友Jc的报告,他是一个十分优秀的人。
本篇文章记录了第一次完整训练优化的过程

0 关于数据集

在CIFAR-10 dataset的介绍中,cifar-10数据集一共10类图片,每一类有6000张图片,加起来就是60000张图片,每张图片的尺寸是32x32,图片是彩色图,整个数据集被分为5个训练批次和1个测试批次,每一批10000张图片。测试批次包含10000张图片,是由每一类图片随机抽取出1000张组成的集合。剩下的50000张图片每一类的图片数量都是5000张,训练批次是由剩下的50000张图片打乱顺序,然后随机分成5份,所以可能某个训练批次中10个种类的图片数量不是对等的,会出现一个类的图片数量比另一类多的情况。

1数据处理

1.1 加载数据集和归一化

transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))的作用
使用Normalize()函数,将数据转换为标准正太分布,使得模型更加容易收敛,其中 mean 和 std 的3个值分表表示图像的3个通道。对于单通道的灰度图,可以写成 transforms.Normalize(mean=[0.5], std=[0.5])。

## 加载数据集归一化
transform = transforms.Compose(
    [transforms.ToTensor(),
     # transforms.Normalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225])# 66.98
     transforms.Normalize(mean=[0.5, 0.5, 0.5],std=[0.5, 0.5, 0.5])
     ]
)

PyTorch 中我们经常看到 mean = [0.485, 0.456, 0.406], std = [0.229, 0.224, 0.225] ,是从 ImageNet 数据集的数百万张图片中随机抽样计算得到的。

train_data = torchvision.datasets.CIFAR10("dataset", train=True, transform=transform,
                                          download=True)
test_data = torchvision.datasets.CIFAR10("dataset", train=False, transform=transform,
                                         download=True)

1.2 把训练的数据二八分成 训练集和验证集

【深度学习】训练集、测试集和验证集的相关概念

train_size = int(0.8 * len(train_data))
val_size = len(train_data) - train_size
train_data, val_data = torch.utils.data.random_split(train_data, [train_size, val_size]
                                                     , generator=torch.Generator().manual_seed(123))
                                                     

1.3利用DataLoader来加载数据集

获得图片数据集后,我们就可以利用torch.utils.data.DataLoader将数据集包装成一个数据加载器

train_dataloader = DataLoader(train_data, shuffle=True, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)
val_dataloader = DataLoader(val_data, batch_size=64)

2 模型的搭建

2.1 神经网络模型构建

在这里插入图片描述
在Pytorch中,可以选择使用Sequential来进行贯序模型的搭建。分析目标神经网络的网络结构,可以得出神经网络各层的具体情况如下表所示。
在这里插入图片描述
值得注意的是,通道数为3的32×32的图像,在经过5×5的卷积核时,默认值的情况下输出的图像大小应该为28×28,若想图片的大小仍让为32×32,我们需要计算padding进行填补。
pytorch的conv2d卷积操作有公式可以进行计算:
在这里插入图片描述
使用默认的dilation=1,stride=1,计算得出padding为2,同理宽也一样。
在经过三轮的卷积、最大池化的操作后,需要 Flatten 层作为卷积层与全连接层的过渡,处理后的数据从多维变成一维,尺寸为 1×1024。最后通过两个全连接层,将输出个数从 1024 个降到 64 个再到 10 个并实现十分类的概率输出。

    def __init__(self):
        super(Model_CIFAR10, self).__init__()
        self.model = nn.Sequential(OrderedDict([
            ("conv1", nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, padding=2)),
            ("maxPool1", nn.MaxPool2d(2)),
            ("conv2", nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding=2)),
            ("maxPool2", nn.MaxPool2d(2)),
            ("conv3", nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding=2)),
            ("maxPool3", nn.MaxPool2d(2)),
            ("Flatten", nn.Flatten()),
            ("Linear1", nn.Linear(1024, 64)),
            ("Linear2", nn.Linear(64, 10))
        ]))

对于神经网络可以通俗地理解为一个函数近似器,它需要近似一个输入x到输入y的映射函数。我们要训练的网络参数其实就是在拟合这个映射函数的未知量。神经网络的训练可以分为两个步骤,一个是前向传播,另外一个是反向传播。
同时,由于该模型为贯序模型,因此可以直接使用Mudule默认的前向传播函数forward(),可以不进行forward函数的重定义。

    def forward(self, x):
        x = self.model(x)
        return x

前向传播计算出了输出值(也即预测值),就可以根据输出值与目标值的差别来计算损失loss。
而反向传播就是根据损失函数loss来反方向地计算每一层的偏导数,从最后一层逐层向前去改变每一层的权重,也就是更新参数,核心就是损失函数对每一网络层的每一个参数求偏导的链式求导法则。
步骤可以概括为:
1.根据模型的输出与真实的target标签计算误差
2.调动反向传播,得到每个要更新参数的梯度
3.调动优化器,对卷积的一些参数进行调整

这里我们选用的损失函数为交叉熵损失函数 CrossEntropyLoss() ,其结合了nn.LogSoftmax() 和
nn.NLLLoss() 两个函数,在做分类(具体几类)训练的时候是非常有用的。

loss_fn = nn.CrossEntropyLoss()

损失函数上,分别对神经网络参数的常见优化器SGD(stochastic gradient descent 随机梯度下降)、和Adam(Adaptive Moment Estimation 自适应矩估计)两种优化器进行了挑选,在实际效果上,发现SGD随机梯度下降对本实验的优化更好。

# optimizer = torch.optim.Momentum(model_u.parameters(), lr=learning_rate)
optimizer = torch.optim.SGD(model_u.parameters(), lr=learning_rate)

在训练过程中使用反向传播优化网络参数。
在使用pytorch的backward()函数进行计算,网络参数进行反馈,梯度是被积累而不是被替换掉,训练时每一个batch只需要更新网络参数,并不需要将上一个batch的梯度继续叠加到下一个batch。因此在每一轮batch中都需要设置optimizer.zero_grad()对梯度初始化为0,把loss关于weight的导数变为0。

outputs = model_u(imgs)
loss = loss_fn(outputs, targets)
optimizer.zero_grad()
loss.backward()
optimizer.step()

2.2 TensorBoard 模型的可视化

我们可以通过安装TensorBoard来进行神经网络结构的可视化。
(1)安装TensorBoard可视化工具
本文在anaconda prompt环境下安装tensorboard,分为两步:

1)激活虚拟环境 activate pytorch-gpu(我自己的环境名)
2)安装tensorboard工具包 pip install tensorboard

(2)利用TensorBoard可视化构建好的模型,生成该卷积网络的图像

1)建立SummaryWriter。用于在log_dir中创建事件文件,将条目直接写入事件文件以供 TensorBoard 使用。
2)模型的数据流和结构的保存。利用SummaryWriter.add_graph()函数来进行模型以及数据流的保存,可视化模型的网络结构图。
pycharm的命令行输入:tensorboard --logdir=log。随后点击超链接访问,得到网络结构图。
在这里插入图片描述
我们可以通过writer.add_graph里添加模型以及模型的输入,来检测模型的正确与否。

    writer = SummaryWriter('log')
    model = Model_CIFAR10()
    input = torch.rand(20, 3, 32, 32)

    writer.add_graph(model, input_to_model=input)
    writer.close()

在这里插入图片描述

实验中输入模型的torch.rand(20, 3, 32, 32),其torch.Size为[20,3,32,32]
即20个通道数为3的大小为32*32的图像。
那么根据我们的网络结构,输出应该是20个十分类的概率输出,torch.Size为[20.10]

    input = torch.rand(20, 3, 32, 32)
    print(input.size())
    output = model(input)
    print(output.size())

在这里插入图片描述
TensorBoard的数据流也显示了正确的结果:

在这里插入图片描述

3 模型的训练

3.1 定义训练设备

训练模型是个时间较长的过程,如果电脑中有cuda的支持,将可以使用GPU进行训练,减少一定的时间。
在神经网络中,有三个部分可以放到GPU中
分别是在模型、损失函数以及数据上。

首先定义训练设备device

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

然后在程序中模型、损失函数、和数据上使用to函数加入到GPU中。

# 模型
model_u = model_u.to(device)
# 损失函数
loss_fn = loss_fn.to(device)
# 数据
imgs, targets = data
imgs = imgs.to(device)
targets = targets.to(device)

3.2划分数据集

如果只划分训练集和测试集,那么使用测试集对模型进行测试并观察指标,根据在测试集上获得的效果调整模型,这会导致测试集参与了人工调参的过程,会出现过拟合测试集的问题,因此在训练集中分出一部分作为验证集,用于调整模型的超参数,根据模型在验证集上的表现,决定哪组超参数拥有最好的性能。
测试集只用来评估模型的泛化能力,即之前的模型使用验证集确定了超参数,最后使用一个完全没有见过的新的数据集来判断这个模型是否准确。
在本实验中,将训练集划分成80%的训练集和20%的验证集,即最终训练的样本数为40000,验证集的样本数为10000,测试集样本数为10000。
本实验使用的CIFAR-10数据集是均衡分布的数据集,因此没有样本不平衡的问题。
因此本次实验可以采用了data.random_split()随机划分的方式便可以完成训练集和验证集的划分工作。

# 把训练的数据二八分成 训练集和验证集
train_size = int(0.8 * len(train_data))
val_size = len(train_data) - train_size
train_data, val_data = torch.utils.data.random_split(train_data, [train_size, val_size]
                                                     , generator=torch.Generator().manual_seed(1))

在这里插入图片描述
 torch.utils.data.Dataset是代表这一数据的抽象类,而DataLoader是Pytorch中用来处理模型输入数据的一个工具类。组合了数据集(dataset) + 采样器(sampler),并在数据集上提供单线程或多线程(num_workers)的可迭代对象

# 利用DataLoader来加载数据集
train_dataloader = DataLoader(train_data, shuffle=True, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)
val_dataloader = DataLoader(val_data, batch_size=64)

本实验将加载器批次大小设为64,同时为了增强模型的泛化能力,将训练集数据加载器的 shuffle 设为True,使得每一次迭代时都对数据集重新进行洗牌以尽可能地避免模型过拟合现象。

3.3 训练集训练

Epoch训练轮数,一个epoch表示所有的数据送入到网络中,完成依次前向计算+反向传播的过程,在本次实验中设置训练轮数为50。
由于一个epoch数据常常太大,因此分成多分batch,在本实验中batch_size设置为64。
先将训练集数据读出,并将数据加载到模型中。利用 model 进行前向传播
计算。利用定义好的损失函数 loss_fn()进行损失的计算。

for i in range(epoch):
    # 训练步骤开始
    model_u.train()
    total_train_accuracy = 0
    total_train_loss = 0
    for data in train_dataloader:
        imgs, targets = data
        imgs = imgs.to(device)
        targets = targets.to(device)
        outputs = model_u(imgs)
        loss = loss_fn(outputs, targets)
        total_train_loss += loss.item()

3.3.1 使用优化器优化模型

在使用pytorch的backward()函数进行计算,网络参数进行反馈,梯度是被积累而不是被替换掉,训练时每一个batch只需要更新网络参数,并不需要将上一个batch的梯度继续叠加到下一个batch。因此在每一轮batch中都需要设置optimizer.zero_grad()对梯度初始化为0,把loss关于weight的导数变为0。

        # 优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

3.4 验证集验证

正常情况下,测试集是未知的数据集,对模型泛化能力的测试。因此人们在只有训练集的情况下,需要设置一部分的验证集,来人为地调参,获得模型泛化能力的超参数。
然而在本实验中,已知了测试集,因此我们要想获得测试集的高准确率,只需对测试集的结果进行参数的调整,获得超参数,因此训练集中划分出验证集是没有必要的。
///正常情况下

    with torch.no_grad():
       for data in val_dataloader:
           imgs, targets = data
           imgs = imgs.to(device)
           targets = targets.to(device)
           outputs = model_u(imgs)
           loss = loss_fn(outputs, targets)
           total_val_loss += loss.item()
           val_accuracy = (outputs.argmax(1) == targets).sum()
           total_val_accuracy += val_accuracy

测试集带入训练好的模型进行测试

与之前的训练套路相同,均是先将训练集数据读出,并将数据加载到模型中。利用 model 进行前向传播计算。利用定义好的损失函数 loss_fn()进行损失的计算。
在前面训练的过程中,需要通过训练的损失函数loss来计算每一层的偏导数,再调用优化器逐一改变每一层的权重,来达到模型参数优化的目的,而测试集并不需要反向传播,优化模型,只是起到检验模型泛化能力,因此无需反向传播。
因此使用torch.no_grad()表面当前计算不需要反向传播,使用之后,强制后面的内容不进行计算图的构建。

with torch.no_grad():
    for data in test_dataloader:
        imgs, targets = data
        imgs = imgs.to(device)
        targets = targets.to(device)
        outputs = model_u(imgs)
        loss = loss_fn(outputs, targets)
        total_test_loss += loss.item()
        test_accuracy = (outputs.argmax(1) == targets).sum()
        total_test_accuracy += test_accuracy

3.5 模型的评估

本实验将每一次迭代过程中的测试集下的模型准确率、模型损失函数值以及每个类别的准确率记录下来并通过tensorboard 进行可视化,以便在训练过程中对模型的泛化能力、是否存在过拟合现象等做出更加精准的判断。
在每一轮epoch下,模型的输出调用argmax(1)函数返回数组中每一行中最大值的索引值,从而获得20张照片十分类下预测最大概率的类别,与真实的标签进行比较,获得预测正确的标签的数量。

3.5.1 计算准确率

计算整体训练集的准确率:

        train_accuracy = (outputs.argmax(1) == targets).sum()
        total_train_accuracy += train_accuracy

所有预测正确的数量除以训练集的总数量即为本轮训练的准确率

    train_accuracy_list.append(float(total_train_accuracy / 40000))
    print(total_train_step, "   train:", total_train_accuracy / 40000)

计算每个类别的准确率:

        c = (outputs.argmax(1) == targets).squeeze()

        for ind in range(len(targets)):
            _label = targets[ind]
            train_class_correct[_label] += c[ind].item()
            train_class_total[_label] += 1

通过(outputs.argmax(1) == targets).squeeze()可以获得每一张图片与对应图片标签预测正确与否,再通过一个for循环记录该标签下预测正确的数量与预测的总数量。

在测试集下的总体准确率:

max_acc = total_test_accuracy / 10000
test_loss = total_test_loss

3.5.2 模型的总体损失值

在每个batch都调用损失函数,并且累加

loss = loss_fn(outputs, targets)
total_train_loss += loss.item()

3.5.3 训练时间

训练开始:

start_time = time.time()

训练结束:

end_time = time.time()
print(end_time - start_time)

3.5.4 tensorboard进行可视化

本实验对模型在训练集和测试集下的准确度变化曲线以及相应的模型损失曲线来对模型的泛化能力进行初步评估。
使用add_scalar函数进行可视化
tag (string): Data identifier图像的名字
scalar_value (float or string/blobname): Value to save y轴的描述
global_step (int): Global step value to record x轴的描述
本次采用的优化器为SGD随机梯度优化器,学习率为0.005,训练轮数为80,设备为RTX 3060。
首先对训练集下模型的准确度和损失函数值进行曲线绘制:
在这里插入图片描述
在 80 次迭代训练的情况下,模型在训练集下的准确度不断地升高,只是增
长的趋势放缓,由于学习率的设置为 0.005,因此收敛的速度较慢,未出现训练
集的准确度达到 95%以上的情况(最高只达到了 94.82%)。而每一轮模型的损
失函数值也随着迭代的次数逐步降低,第 80 次迭代完成的模型函数的损失值为
119.20。
接着实验对每一个类别的准确率进行了绘制。
在这里插入图片描述
基本趋势与训练集整体的模型相同,值得注意的是,在训练轮数较少时,由
于每一轮的网络参数的优化会有一定的偏向,因此会出现较大的波动,在随着训
练轮数的增加,模型的整体网络参数的优化趋于平衡,因此抖动较小。与训练集
最后的准确度仅为 94%类似,10 个类别单独的类别的准确率,最低达到了 87.02%,
最好的一组识别准确率则达到了 96.47%。
实验对验证集的准确率曲线以及损失函数值曲线如下图所示。
在这里插入图片描述
与训练集模型的准确率不断上升不同,在 80 次迭代训练的情况下,验证集
在迭代了 30 轮之后,模型在验证集下的准确度就处在不断的波动,查看
tensorborad 绘制的曲线,验证集的最高准确率达到了 67.33%,而波动的最低准
确率仅仅 65.06%。这种抖动无法收敛的情况可能与设置的学习率 0.005 有关,导
致在网络参数的更改较大,无法收敛。从损失函数也可以看出,测试集的每轮损
失函数值并没有随着迭代的轮数而降低,而是在 30-40 轮之间时损失函数值达到
最低,然后逐步上升。
验证集的十个类别最终的准确率如下表:
在这里插入图片描述
十个类别的准确率曲线类似,因此选取其中一个曲线进行说明:
在这里插入图片描述
与验证集的整体抖动类似,类别 9 的准确率曲线波动几乎从头到尾,每一轮
反向传播的参数调整对各个类别单独的准确率影响较大。
最终在测试集的准确率为 65.33%。

3.5.5 ROC 曲线的绘制

ROC 曲线将灵敏度与特异性以图示方法结合在一起,可准确反映某分析方
法特异性和敏感性的关系,是试验准确性的综合代表。
AUC 值:AUC(Area Under Curve)被定义为 ROC 曲线下与坐标轴围成的
面积,显然这个面积的数值不会大于 1。又由于 ROC 曲线一般都处于 y=x 这条
直线的上方,所以 AUC 的取值范围在 0.5 和 1 之间。AUC 越接近 1.0,检测方
法真实性越高;等于 0.5 时,则真实性最低,无应用价值。

    # 需要先进行热独编码,以便分别绘制ROC曲线
    y_test1 = y_test1[10000:]
    prediction = prediction[10000:]
    prediction1 = DataFrame(prediction.reshape((10000, 10)))
    y_test11 = pd.get_dummies(y_test1[:])

    for i in range(len(n_classes)):
        fpr[i], tpr[i], _ = roc_curve(y_test11.iloc[:, i], prediction1.iloc[:, i])
        roc_auc[i] = auc(fpr[i], tpr[i])
    plt.rcParams['font.family'] = ['calibri']
    plt.figure()
    lw = 1
    colors = ['dimgray', 'rosybrown', 'lightcoral', 'tomato', 'peru',
              'burlywood', 'steelblue', 'olive', 'lawngreen', 'lightseagreen']
    for i, color in zip(range(len(n_classes)), colors):
        plt.plot(fpr[i], tpr[i], color=color, lw=lw,
                 label='ROC curve of class {0} (AUC = {1:0.3f})'
                       ''.format(i, roc_auc[i]))

    plt.plot([0, 1], [0, 1], 'k--', lw=lw)
    plt.xlim([-0.05, 1.0])
    plt.ylim([0.0, 1.05])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title('Receiver operating characteristic for multi-class data')
    plt.legend(loc="lower right")
    plt.show()

绘制 ROC 曲线:
在这里插入图片描述
如上图 ROC 曲线以及 AUC 值来看,模型整体的 AUC 值突破 0.8,因此
该模型对数据集的各个类别都有较好的分类性能。但是不同类别的 AUC 也有较
大的差距,在类别 airplane、automobile、frog、horse、ship、truck 的 AUC 值突
破 0.92。相比而言 bird、cat、deer、dog 而言 AUC 值则 0.89 都没有达到,由于
是 cat 类别的 AUC 值仅有 0.811。这可能与不同类别提取特征的难度有关,因此
模型的整体分类器的性能较为不错,但是在不同的类别存在较大的差异。

3.6 模型保存与加载

本次实验使用model.save()的方法,同时保存模型的结构以及网路参数
以训练学习率、优化器、以及训练轮数三者进行命名。

torch.save(model_u, r"trainmodel\test_{}.pth".format(str(learning_rate)+"_SGD_"+str(epoch)))

在这里插入图片描述
此时,在模型的测试之前,我们只需要对训练好的模型加载即可,无需再重复训练,可以节省我们大量的时间。

3.7 不同超参数组合下模型性能评估

3.7.1 学习率与迭代次数对模型的影响

(1)学习率
训练模型输出误差反向传播给网络参数,以此来拟合样本的输出。本质上是一个优化的过程,但每次更新参数参数利用多少误差,就需要通过一个参数来控制,也就是学习率(Learning rate),也称为步长。
通常情况下,学习率的大小有着这样的特点:
在这里插入图片描述
(2)迭代次数
一个epoch等于训练集中的全部样本训练一次,完整的数据集在同样的神经网络中传递多次,随着epoch数量的增加,神经网络中的权重的更新次数也在增加,曲线从欠拟合变得过拟合。

3.7.2 不同超参数组合下模型性能的比较

在之前对CIFAR数据集分类模型进行初步分析,本实验将从模型的训练轮数epoch和模型的学习率两方面进行组合,以此研究不同超参数组合对模型性能的影响。
本次实验通过改变模型的训练轮数以及模型的学习率来探究两者不同组合
下对模型性能的影响,此处设置的迭代次数分别为20、40、60、80、100以及
120。设置学习率分别为0.001、0.005、0.010以及0.015。实验将从错误率、准
确率、时间(训练+测试)三个维度评估不同超参设置下的模型泛化性能,并
进行分析总结。
本次采用的优化器为同一个优化器 SGD 随机梯度优化器,设备均为 RTX
3060。
模型训练集下准确率曲线:
在这里插入图片描述
训练集在学习率与训练轮数组合下准确率数据如下:
在这里插入图片描述
从以上两表可以看出,当学习率相同,迭代的轮数越多,模型的准确率越高,
相应的模型的错误率就越低。当训练轮数相同,那么训练轮数越少,模型的准确
率、错误率差别就越大,而当训练到一定次数,学习率大的模型对于准确率已经
达到 1,没有上升空间,且学习率越大,达到准确率 1 的训练轮数就越少。
为了便于观察,实验在每一轮训练后使用测试集进行测验。训练 120 轮四个
不同学习率的测试集集准确率曲线为:
在这里插入图片描述
在 Tensorboard 可以下载整个曲线的数据。
在这里插入图片描述
测试集在学习率与训练轮数组合下准确率数据如下:
在这里插入图片描述
从表 3 可以简单分析看出,当学习率等于 0.001 时,模型测试集的准确率随
着训练轮数的增加而不断地提升。而学习率 0.005、0.010、0.015 三者则均呈现出
了达到高的准确率之后不断下降趋于平缓的情况,并且学习率越大,则越早到达
测试集准确率的最高峰,三者最终完成 120 轮训练后的准确率基本相同,但高于
学习率等于 0.001 时的准确率。因此结合学习率的特点,我们可以合理猜测,学
习率等于 0.001 的模型还并未收敛。因此实验又增加了 80 轮的训练轮数,最终
的准确率为 0.6702。

在这里插入图片描述
从模型训练和测试时间来看,学习率于总的花费时间成正比关系,即学习率
越大,花费的时间越多。
结合以上所有,得出在学习率和训练轮数24种组合下,学习率为0.005,训
练轮数为60时,模型测试集的准确率达到67.34%,错误率为32.66%,但是我们
发现该情况下,模型训练集的准确率还并未达到100%,仅为88.32%,因此可
以认为此时的模型在训练集上并未收敛,测试集上的高准确率和低错误率,可
能时模型未稳定而导致的异常结果,因此暂时无法认为其对模型泛化能力好的
表现。
因此实验重新对模型设置相同的超参,即设置学习率为0.005,训练轮数为
60。在经过十次重复训练之后,模型测试集的准确率平均值为67.20%,相差无
几,因此本实验认为该超参组合训练下的网络参数对模型泛化能力是稳定且较
为优秀的。

3.7.3 学习率衰减策略进行模型优化

在这里插入图片描述
模板如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.7.4 防止过拟合

在这里插入图片描述

optimizer = torch.optim.SGD(model_u.parameters(), lr=learning_rate)
scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.95,last_epoch=-1)
scheduler.step()
class Model_CIFAR10(nn.Module):
    def __init__(self):
        super(Model_CIFAR10, self).__init__()
        self.model = nn.Sequential(OrderedDict([
            ("conv1", nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, padding=2)),
            ("relu1",nn.ReLU()),
            ("maxPool1", nn.MaxPool2d(2)),
            ("conv2", nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding=2)),
            ("relu2", nn.ReLU()),
            ("maxPool2", nn.MaxPool2d(2)),
            ("conv3", nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding=2)),
            ("relu3", nn.ReLU()),
            ("maxPool3", nn.MaxPool2d(2)),
            ("Flatten", nn.Flatten()),
            ("Linear1", nn.Linear(1024, 64)),
            ("dropout", nn.Dropout(p=0.2)),
            ("Linear2", nn.Linear(64, 10))
        ]))

    def forward(self, x):
        x = self.model(x)
        return x

在修改后的网络结构,测试集的准确率为 69.78%,高于修改前的
67.33%。因此在原先神经网络模型结构中加入激活函数以及 dropout 层能够
一定程度上提高模型的准确率,增强模型的泛化能力,起到一定的优化作用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/187921.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度卷积对抗神经网络 基础 第五部分 Inception-v3 architecture GANs

深度卷积对抗神经网络 基础 第五部分 Inception-v3 architecture GANs 对抗神经网络能够产生不存在的图片,换脸或者生成一些艺术品,这些有趣和强大的对抗神经网络的能力不仅能够创造价值,还能够用来犯罪。With Great Power , Comes With Res…

3.1.1 类和对象

文章目录1.类2.对象3.类和对象的关系4.类的创建使用5.对象在内存中的存储过程6.对象创建过程分析1.类 java最基本的单位就是类,可以理解为类型类是一类事物的抽象可以理解为模板或者设计图纸 注意:类在现实世界并不存在,它只是一种对象的数据类型。例如乌鸦&#…

如何使用DevExpress WPF组件实现异步加载TreeList节点?建议收藏

DevExpress WPF拥有120个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。在本文中,我…

PADS Layout封装创建时批量放置焊盘的方法

批量放置焊盘一般是在BGA封装的是用的比较多,当然对于一些普通贴片焊盘也是挺常用的。 1、第一步:打开PCB封装编辑器,进入到封装编辑界面,放置焊盘后,点击焊盘右键“分步与重复”既可。2、第二步:点击以后弹…

常见的锁策略和synchronized的锁机制

文章目录一. 常见的锁策略1. 乐观锁和悲观锁2. 轻量级锁和重量级锁3. 自旋锁和挂起等待锁4. 普通互斥锁和读写锁5. 公平锁和非公平锁6. 可重入锁和不可重入锁二. synchronized的锁机制1. 锁升级/锁膨胀2. 锁消除3. 锁粗化一. 常见的锁策略 1. 乐观锁和悲观锁 乐观锁和悲观锁主…

C++ | 数据结构与算法 | 最小生成树算法讲解 | Kruskal Prim

文章目录前言Kruskal算法Prim算法前言 讲解之前,我们需要先明白连通图是指什么?连通图具有以一个顶点为起点可以到达该图中的任意一个顶点的特性,就算它们不直接相连,但是它们之间至少有一条可以递达的路径。并且连通图是针对无向…

劳务派遣协议范本整理版模板范本

劳务派遣协议范本整理版 甲方(用工单位):______ 法定代表人:____________ 地址:__________________ 电话:__________________ 传真:__________________ 乙方(派遣单位&#xf…

【Java】一文彻底弄懂访问修饰符(public/protected/默认/private)--建议收藏

博主简介:努力学习的预备程序媛一枚~博主主页: 是瑶瑶子啦所属专栏: Java岛冒险记【从小白到大佬之路】 前言 OOP(Object Oriented Programing),即面向对象编程,最重要的功能/特点之一就是封装,这点在该专栏开篇博客【…

WebPack面试题汇总

1,Webpack有什么作用,谈谈你对它的理解 现在的前端网页功能丰富,特别是SPA(single page web application 单页应用)技术流行后,JavaScript的复杂度增加和需要一大堆依赖包,还需要解决Scss、Les…

记录--这样封装列表 hooks,一天可以开发 20 个页面

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 这样封装列表 hooks,一天可以开发 20 个页面 前言 在做移动端的需求时,我们经常会开发一些列表页,这些列表页大多数有着相似的功能:分页获取列表、上拉加载、下拉刷…

【Java 面试题合集】ThreadPoolExecutor 线程池面试题

文章目录自定义的线程池的 7 个参数如何合理设置核心线程数 corePoolSize 的大小《JAVA 并发编程实战》中的方案java 开发手册中为什么不允许使用 Executors 默认的实现?一个线程池中的线程异常了,那么线程池会怎么处理这个线程?线程池被创建后里面有线…

OpenCV——总结《图像处理-1》

1.HSV H - 色调(主波长)。S - 饱和度(纯度/颜色的阴影)。V值(强度) hsvcv2.cvtColor(img,cv2.COLOR_BGR2HSV)2.图像阈值 函数介绍: ret, dst cv2.threshold(src, thresh, maxval, type) sr…

嵌入式Linux从入门到精通之第九节:系统编程

系统编程概述 在讲解系统编程之前,先了解几个概念: 操作系统的作用: 操作系统用来管理所有的资源,并将不同的设备和不同的程序关联起来。 什么是Linux系统编程? 在有操作系统的环境下编程,并使用操作系统提供的系统调用及各种库,对系统资源进行访问。 学会了C语言再知…

Grafana9.3.x在windows上的安装及使用

Grafana9.3.x的安装及使用1. Grafana install1.1 Download1.2 Install2. User Guide1.1 Document1.2 Table视图背景色渲染3.Awakening1. Grafana install 1.1 Download 下载地址 Grafana Website: https://grafana.com/. 1.2 Install 直接点击安装就好了 进入conf目录复制一…

python集合语法与应用

python集合语法与应用 文章目录python集合语法与应用一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤1.创建2.增加3.删除4.集合运算5.拓展知识一6.拓展知识二总结一、实验目的 掌握集合的用法 二、实验原理 集合中只能包含数字、字符串、元组等不可变的类型的…

规则引擎,实现业务低代码开发的重要工具

规则引擎,是将业务执行抽象化的配置,通过其定义的数据结构、算法和流程来实现应用程序功能的普适化。 规则引擎可以帮助企业提高业务开发效率,提高运营的灵活性,降低运营成本与开发成本,让系统更加智能化灵活化。这里以…

【Rust】5. 所有权

5. 所有权 5.1 什么是所有权 5.1.1 栈(Stack)与堆(Heap) 5.1.2 所有权规则 5.1.3 变量作用域 5.1.4 String 类型 String 类型可进行修改,而字符串字面值是不可以的!(区别在于二者对内存的处理…

OAuth2

目录一、什么是OAuth2.0二、OAuth2中的角色三、认证流程四、生活中的Oauth2思维5. 令牌的特点6.OAuth2授权方式6.1 授权码6.2 隐藏方式6.3 密码方式6.4 凭证方式一、什么是OAuth2.0 OAuth2.0是目前使用非常广泛的授权机制,用于授权第三方应用获取用户的数据。 举例…

PythonWeb Django框架学习笔记

文章目录Django一、初步了解Django1.1 创建项目1.2 文件介绍1.3 APP的创建和说明添加新的app注册app创建页面1.4 templates模板templates语法单一变量列表循环【列表】字典循环【字典】列表套字典条件判断templates小结1.5 请求和响应案例:用户管理二、数据库操作2.…

前言技术之mybatis-plus 01

目录 1.什么是mybatis-plus 2.初体验 3.日志 4.主键生成策略 5.更新 6.自动填充 1.什么是mybatis-plus 升级版的mybatis,目的是让mybatis更易于使用, 用官方的话说“为简化而生” 官网: MyBatis-Plus 2.初体验 1.准备数据库脚本 数据…