《深度学习》——调整学习率和保存使用最优模型

调整学习率

在使用 PyTorch 进行深度学习训练时,调整学习率是一个重要的技巧,合适的学习率调整策略可以帮助模型更好地收敛。
PyTorch 提供了多种调整学习率的方法,下面将详细介绍几种常见的学习率调整策略及实例代码:

  • torch.optim.lr_scheduler.StepLR(固定步长学习率调度器)
    StepLR 是一种简单的学习率调整策略,它会每隔一定的训练步数(epoch)将学习率乘以一个固定的衰减因子。

    import torch
    import torch.nn as nn
    import torch.optim as optim
    from torch.optim.lr_scheduler import StepLR# 定义一个简单的模型
    class SimpleModel(nn.Module):def __init__(self):super(SimpleModel, self).__init__()self.fc = nn.Linear(10, 1)def forward(self, x):return self.fc(x)model = SimpleModel()
    optimizer = optim.SGD(model.parameters(), lr=0.1)# 定义 StepLR 调度器,每 3 个 epoch 将学习率乘以 0.1
    scheduler = StepLR(optimizer, step_size=3, gamma=0.1)# 模拟训练过程
    for epoch in range(10):# 训练代码...print(f'Epoch {epoch}: Learning rate = {optimizer.param_groups[0]["lr"]}')optimizer.step()scheduler.step()
    

在这里插入图片描述

  • torch.optim.lr_scheduler.MultiStepLR(多步学习率调度器)
    MultiStepLR 允许你在指定的训练步数(epoch)处将学习率乘以一个固定的衰减因子。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import MultiStepLRmodel = SimpleModel()
optimizer = optim.SGD(model.parameters(), lr=0.1)# 定义 MultiStepLR 调度器,在 epoch 为 3 和 7 时将学习率乘以 0.1
milestones = [3, 7]
scheduler = MultiStepLR(optimizer, milestones=milestones, gamma=0.1)# 模拟训练过程
for epoch in range(10):# 训练代码...print(f'Epoch {epoch}: Learning rate = {optimizer.param_groups[0]["lr"]}')optimizer.step()scheduler.step()

在这里插入图片描述

  • torch.optim.lr_scheduler.ExponentialLR(指数学习率调度器)
    ExponentialLR 会在每个训练步数(epoch)将学习率乘以一个固定的衰减因子。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import ExponentialLRmodel = SimpleModel()
optimizer = optim.SGD(model.parameters(), lr=0.1)# 定义 ExponentialLR 调度器,每个 epoch 将学习率乘以 0.9
scheduler = ExponentialLR(optimizer, gamma=0.9)# 模拟训练过程
for epoch in range(10):# 训练代码...print(f'Epoch {epoch}: Learning rate = {optimizer.param_groups[0]["lr"]}')optimizer.step()scheduler.step()

在这里插入图片描述

  • torch.optim.lr_scheduler.ReduceLROnPlateau(自适应学习率调度器)
    ReduceLROnPlateau 会根据验证集上的指标(如损失值)来动态调整学习率。当指标在一定的训练步数内没有改善时,它会将学习率乘以一个固定的衰减因子。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import ReduceLROnPlateaumodel = SimpleModel()
optimizer = optim.SGD(model.parameters(), lr=0.1)# 定义 ReduceLROnPlateau 调度器,当验证损失在 2 个 epoch 内没有改善时,将学习率乘以 0.1
scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=2)# 模拟训练过程
for epoch in range(10):# 训练代码...# 假设这是验证集上的损失val_loss = torch.rand(1).item()print(f'Epoch {epoch}: Learning rate = {optimizer.param_groups[0]["lr"]}')optimizer.step()scheduler.step(val_loss)

在这里插入图片描述

保存最优模型

在深度学习训练过程中,保存最优模型是一个常见的需求,这样可以在训练结束后使用表现最好的模型进行预测或评估。通常,我们会根据验证集上的某个指标(如准确率、损失值等)来判断模型是否为最优。

  • 保存模型的状态字典(state_dict)到文件 best.pth 中。
  • 保存整个模型对象到文件 best1.pt 中。
if correct > best_acc:# 如果当前正确预测的样本数量大于之前记录的最优值best_acc = correct# 更新最优准确率记录为当前的正确样本数量print(model.state_dict().keys())# 打印模型状态字典中的所有键,这些键代表了模型中可学习参数的名称,# 例如各个层的权重(weight)和偏置(bias)等torch.save(model.state_dict(), 'best.pth')# 将模型的状态字典保存到名为 'best.pth' 的文件中。# 状态字典包含了模型中所有可学习参数的值,这种保存方式只保存参数,不保存模型结构,# 后续加载时需要先定义相同结构的模型,再加载参数torch.save(model, 'best1.pt')# 将整个模型对象保存到名为 'best1.pt' 的文件中。# 这种保存方式不仅保存了模型的参数,还保存了模型的结构信息,# 后续加载时可以直接加载整个模型对象

注意

    1. 保存状态字典与保存整个模型的区别
    • 保存状态字典(torch.save(model.state_dict(), ‘best.pth’)):
      • 优点:文件体积相对较小,适合在不同环境下共享模型参数,因为只需要模型结构定义代码一致,就可以加载参数。
      • 缺点:需要手动定义模型结构,再加载参数。如果模型结构发生变化,可能会导致加载失败。
    • 保存整个模型(torch.save(model, ‘best1.pt’)):
      • 优点:加载方便,直接加载整个模型对象,不需要重新定义模型结构。
      • 缺点:文件体积较大,并且依赖于保存时的 Python 环境和 PyTorch 版本,在不同环境下加载可能会出现兼容性问题。
    1. 准确率指标的选择
      代码中使用 correct(正确预测的样本数量)作为判断模型优劣的指标,在实际应用中,更常见的做法是使用准确率(correct / total),因为 correct 的数值会受到验证集样本数量的影响,而准确率是一个相对稳定的指标。
    1. 文件路径管理
      代码中直接使用相对路径保存模型文件,在实际项目中,建议使用绝对路径或者更规范的文件路径管理方式,避免文件保存位置混乱。

使用最优模型

  • 使用best.pth 中的状态字典(state_dict) 。
  • 使用best1.pt 中的模型对象 。
# 尝试从 'best.pth' 文件中加载模型的状态字典(state_dict),
# 状态字典包含了模型中所有可学习参数(如权重、偏置)的值,
# 但不包含模型的结构信息。所以在使用此方式加载前,
# 必须先定义好与保存时结构一致的模型实例。
# torch.load('best.pth') 用于从文件中读取状态字典数据,
# model.load_state_dict() 方法将读取到的状态字典数据赋值给当前的 model 实例。
model.load_state_dict(torch.load('best.pth'))# 这行代码会直接从 'best.pt' 文件中加载整个模型对象,
# 该文件保存时使用了 torch.save(model, 'best.pt') 方式,
# 这种保存方式不仅保存了模型的参数,还保存了模型的结构信息。
# 加载后,model 变量将指向一个完整的、可直接使用的模型对象。
# 不过需要注意的是,如果之前使用的 Python 环境、PyTorch 版本不同,
# 或者模型定义代码发生了变化,可能会导致加载失败或出现兼容性问题。
# 并且这行代码与上一行 'model.load_state_dict(...)' 存在冲突,
# 因为这里会覆盖掉上一行代码对 model 实例参数的加载结果,
# 通常在实际使用中只会选择其中一种加载方式。
model = torch.load('best.pt')# 将模型设置为评估模式。在评估模式下,
# 一些在训练时起作用的特殊层(如 Dropout、BatchNorm 等)
# 会改变其行为。例如,Dropout 层在训练时会随机丢弃部分神经元以防止过拟合,
# 但在评估时会正常使用所有神经元;BatchNorm 层在训练时会根据当前批次的数据
# 计算均值和方差,而在评估时会使用训练过程中统计的全局均值和方差。
# 因此,在进行模型推理、验证或测试时,需要将模型设置为评估模式,
# 以确保得到准确的结果。
model.eval()

实例

数据集:照片文件:在这里插入图片描述
在这里插入图片描述

test.txt:
在这里插入图片描述

train.txt:
在这里插入图片描述

test_true.txt:
在这里插入图片描述

保存最优模型

对食物分类中food dataset2目录下的test、train中的照片进行卷积神经训练,进行食物分类并保存最优模型,并调整学习率。
代码:

import os
from PIL import Image# 定义函数用于生成训练集和测试集的文件列表及对应的标签
def train_test_file(root, dir):# 打开一个以dir命名的txt文件,用于写入图像路径和标签file_txt = open(dir + '.txt', 'w')# 拼接完整的路径path = os.path.join(root, dir)# 遍历指定路径下的所有文件和文件夹for roots, directories, files in os.walk(path):  # os.list_dir()# 如果存在子文件夹,将子文件夹名称存储在dirs列表中if len(directories) != 0:dirs = directorieselse:# 获取当前文件夹的名称now_dir = roots.split('\\')# 遍历当前文件夹下的所有文件for file in files:# 拼接图像文件的完整路径path_1 = os.path.join(roots, file)print(path_1)# 将图像路径和对应的标签写入txt文件,标签为当前文件夹在dirs列表中的索引file_txt.write(path_1 + ' ' + str(dirs.index(now_dir[-1])) + '\n')# 关闭文件file_txt.close()# 数据集根目录
root = r'.\食物分类\food_dataset'
# 训练集文件夹名称
train_dir = 'train'
# 测试集文件夹名称
test_dir = 'test'
# 生成训练集的文件列表及标签
train_test_file(root, train_dir)
# 生成测试集的文件列表及标签
train_test_file(root, test_dir)# 自定义类,用于演示__getitem__和__len__方法
class USE_getitem():def __init__(self, text):# 初始化传入的文本self.text = textdef __getitem__(self, index):# 获取指定索引位置的字符并转换为大写result = self.text[index].upper()return resultdef __len__(self):# 返回文本的长度return len(self.text)# 创建USE_getitem类的实例
p = USE_getitem('pytorch')
# 打印索引为0和1的字符
print(p[0], p[1])
# 调用__len__方法获取文本长度
len(p)import torch
from torch.utils.data import Dataset, DataLoader
import numpy as np
from torchvision import transforms
from torch import nn# 定义训练集和验证集的数据预处理转换
data_transforms = {'train':transforms.Compose([# 将图像大小调整为300x300transforms.Resize([300, 300]),# 随机旋转图像,旋转角度范围为-45到45度transforms.RandomRotation(45),# 从图像中心裁剪出256x256的区域transforms.CenterCrop(256),# 以0.5的概率随机水平翻转图像transforms.RandomHorizontalFlip(p=0.5),# 以0.5的概率随机垂直翻转图像transforms.RandomVerticalFlip(p=0.5),# 随机调整图像的亮度、对比度、饱和度和色相transforms.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.1, hue=0.1),# 以0.1的概率将图像转换为灰度图transforms.RandomGrayscale(p=0.1),# 将图像转换为Tensortransforms.ToTensor(),# 对图像进行归一化处理transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),'valid':transforms.Compose([# 将图像大小调整为256x256transforms.Resize([256, 256]),# 将图像转换为Tensortransforms.ToTensor(),# 对图像进行归一化处理transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
}# 自定义数据集类,继承自torch.utils.data.Dataset
class food_dataset(Dataset):def __init__(self, file_path, transform=None):# 初始化文件路径self.file_path = file_path# 用于存储图像路径的列表self.imgs = []# 用于存储图像标签的列表self.labels = []# 初始化数据预处理转换self.transform = transform# 打开文件并读取每一行with open(self.file_path) as f:# 将每一行按空格分割成图像路径和标签samples = [x.strip().split(' ') for x in f.readlines()]for img_path, label in samples:# 将图像路径添加到imgs列表中self.imgs.append(img_path)  # 图像路径# 将标签添加到labels列表中self.labels.append(label)  # 标签def __len__(self):# 返回图像的数量return len(self.imgs)def __getitem__(self, idx):# 打开指定索引位置的图像image = Image.open(self.imgs[idx])# 如果存在数据预处理转换,对图像进行转换if self.transform:image = self.transform(image)# 获取指定索引位置的标签label = self.labels[idx]# 将标签转换为torch.Tensor类型label = torch.from_numpy(np.array(label, dtype=np.int64))return image, label# 创建训练集数据集对象
training_data = food_dataset(file_path='./train.txt', transform=data_transforms['train'])
# 创建测试集数据集对象
test_data = food_dataset(file_path='./test.txt', transform=data_transforms['valid'])# 创建训练集数据加载器,批量大小为64,数据打乱
train_dataloader = DataLoader(training_data, batch_size=64, shuffle=True)
# 创建测试集数据加载器,批量大小为64,数据打乱
test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)# 判断是否支持GPU或MPS,如果支持则使用,否则使用CPU
device = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'
print(f'Using {device} device')# 定义卷积神经网络类,继承自torch.nn.Module
class CNN(nn.Module):def __init__(self):super(CNN, self).__init__()# 第一个卷积块self.conv_block1 = nn.Sequential(# 输入通道数为3,输出通道数为32,卷积核大小为3,填充为1nn.Conv2d(3, 32, kernel_size=3, padding=1),# 批量归一化nn.BatchNorm2d(32),# ReLU激活函数nn.ReLU(inplace=True),# 最大池化层,池化核大小为2nn.MaxPool2d(2))# 第二个卷积块self.conv_block2 = nn.Sequential(nn.Conv2d(32, 64, kernel_size=3, padding=1),nn.BatchNorm2d(64),nn.ReLU(inplace=True),nn.MaxPool2d(2))# 第三个卷积块self.conv_block3 = nn.Sequential(nn.Conv2d(64, 128, kernel_size=3, padding=1),nn.BatchNorm2d(128),nn.ReLU(inplace=True),nn.MaxPool2d(2))# 第四个卷积块self.conv_block4 = nn.Sequential(nn.Conv2d(128, 256, kernel_size=3, padding=1),nn.BatchNorm2d(256),nn.ReLU(inplace=True),nn.MaxPool2d(2))# 第五个卷积块self.conv_block5 = nn.Sequential(nn.Conv2d(256, 512, kernel_size=3, padding=1),nn.BatchNorm2d(512),nn.ReLU(inplace=True),nn.MaxPool2d(2))# 计算经过卷积和池化后特征图的尺寸# 每次池化操作将尺寸缩小一半,经过5次池化,256 / 2^5 = 8self.fc1 = nn.Linear(512 * 8 * 8, 2048)self.relu = nn.ReLU(inplace=True)# 随机丢弃50%的神经元,防止过拟合self.dropout = nn.Dropout(0.5)# 输出层,输出20个类别self.fc2 = nn.Linear(2048, 20)def forward(self, x):# 前向传播,依次通过各个卷积块x = self.conv_block1(x)x = self.conv_block2(x)x = self.conv_block3(x)x = self.conv_block4(x)x = self.conv_block5(x)# 将多维的特征图展平为一维向量x = x.view(-1, 512 * 8 * 8)# 通过第一个全连接层x = self.fc1(x)x = self.relu(x)x = self.dropout(x)# 通过输出层output = self.fc2(x)return output# 创建CNN模型实例并将其移动到指定设备上
model = CNN().to(device)# 定义训练函数
def train(dataloader, model, loss_fn, optimizer):# 将模型设置为训练模式model.train()  # 记录当前批次的编号batch_size_num = 1# 遍历数据加载器中的每个批次for x, y in dataloader:  # 其中batch为每一个数据的编号# 将训练数据和标签移动到指定设备上x, y = x.to(device), y.to(device)  # 前向传播,计算模型的预测结果pred = model.forward(x)  # 通过交叉熵损失函数计算损失值loss = loss_fn(pred, y)  # 梯度值清零optimizer.zero_grad()  # 反向传播计算每一个参数的梯度值loss.backward()  # 根据梯度更新网络参数optimizer.step()  # 从tensor数据中提取损失值loss_value = loss.item()  # 每10个批次打印一次损失值if batch_size_num % 10 == 0:print(f'loss:{loss_value:7f}  [number:{batch_size_num}]')# 批次编号加1batch_size_num += 1# 记录最佳准确率
best_acc = 0# 定义测试函数
def test(dataloader, model, loss_fn):global best_acc# 数据集的总样本数size = len(dataloader.dataset)  # 数据加载器中的批次数量num_batches = len(dataloader)  # 将模型设置为评估模式model.eval()  # 初始化测试损失和正确预测的样本数test_loss, correct = 0, 0# 关闭梯度计算with torch.no_grad():  for x, y in dataloader:# 将测试数据和标签移动到指定设备上x, y = x.to(device), y.to(device)# 前向传播,计算模型的预测结果pred = model.forward(x)# 累加每个批次的损失值test_loss += loss_fn(pred, y).item()  # 计算正确预测的样本数correct += (pred.argmax(1) == y).type(torch.float).sum().item()a = (pred.argmax(1) == y)  # dim=1表示每一行中的最大值对应的索引号,dim=0表示每一列中的最大值对应的索引号b = (pred.argmax(1) == y).type(torch.float)# 计算平均测试损失test_loss /= num_batches  # 计算平均准确率correct /= size  # 如果当前准确率高于最佳准确率,更新最佳准确率并保存模型if correct > best_acc:best_acc = correctprint(model.state_dict().keys())# 保存模型的参数torch.save(model.state_dict(), 'best.pth')# 保存整个模型torch.save(model, 'best1.pt')print(f'Test result: \n Accuracy:{(100 * correct)}%,Avg loss:{test_loss}')# 创建交叉熵损失函数对象
loss_fn = nn.CrossEntropyLoss()  
# 创建Adam优化器,用于更新模型参数
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)  # 训练的轮数
epochs = 150
# 循环训练多个轮次
for t in range(epochs):print(f'epoch{t + 1}\n--------------------')# 训练模型train(train_dataloader, model, loss_fn, optimizer)# 测试模型test(test_dataloader, model, loss_fn)
print('Done!')

在这里插入图片描述
保存模型: 在这里插入图片描述

使用最优模型

对数据中的测试数据进行测试训练,路径文件为test_true.txt。

from PIL import Image
import torch
from torch.utils.data import Dataset, DataLoader
import numpy as np
from torchvision import transforms
from torch import nn# 定义数据预处理转换,这里只定义了验证集的转换
data_transforms = {'valid':transforms.Compose([# 将图像调整为 256x256 的大小transforms.Resize([256, 256]),# 将图像转换为 PyTorch 的张量transforms.ToTensor(),# 对图像进行归一化处理,使用 ImageNet 的均值和标准差transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
}# 自定义食物数据集类,继承自 torch.utils.data.Dataset
class food_dataset(Dataset):def __init__(self, file_path, transform=None):# 保存数据集文件路径self.file_path = file_path# 用于存储图像路径的列表self.imgs = []# 用于存储图像标签的列表self.labels = []# 保存数据预处理转换self.transform = transform# 打开数据集文件with open(self.file_path) as f:# 读取文件的每一行,并按空格分割成图像路径和标签samples = [x.strip().split(' ') for x in f.readlines()]for img_path, label in samples:# 将图像路径添加到 imgs 列表中self.imgs.append(img_path)# 将标签添加到 labels 列表中self.labels.append(label)def __len__(self):# 返回数据集的长度,即图像的数量return len(self.imgs)def __getitem__(self, idx):# 打开指定索引的图像image = Image.open(self.imgs[idx])# 如果存在数据预处理转换,则对图像进行转换if self.transform:image = self.transform(image)# 获取指定索引的标签label = self.labels[idx]# 将标签转换为 PyTorch 的张量label = torch.from_numpy(np.array(label, dtype=np.int64))# 返回图像和标签return image, label# 判断是否支持 GPU 或 MPS,如果支持则使用,否则使用 CPU
device = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'
print(f'Using {device} device')# 定义卷积神经网络类,继承自 torch.nn.Module
class CNN(nn.Module):def __init__(self):super(CNN, self).__init__()# 第一个卷积块self.conv_block1 = nn.Sequential(# 输入通道数为 3,输出通道数为 32,卷积核大小为 3,填充为 1nn.Conv2d(3, 32, kernel_size=3, padding=1),# 批量归一化层nn.BatchNorm2d(32),# ReLU 激活函数nn.ReLU(inplace=True),# 最大池化层,池化核大小为 2nn.MaxPool2d(2))# 第二个卷积块self.conv_block2 = nn.Sequential(nn.Conv2d(32, 64, kernel_size=3, padding=1),nn.BatchNorm2d(64),nn.ReLU(inplace=True),nn.MaxPool2d(2))# 第三个卷积块self.conv_block3 = nn.Sequential(nn.Conv2d(64, 128, kernel_size=3, padding=1),nn.BatchNorm2d(128),nn.ReLU(inplace=True),nn.MaxPool2d(2))# 第四个卷积块self.conv_block4 = nn.Sequential(nn.Conv2d(128, 256, kernel_size=3, padding=1),nn.BatchNorm2d(256),nn.ReLU(inplace=True),nn.MaxPool2d(2))# 第五个卷积块self.conv_block5 = nn.Sequential(nn.Conv2d(256, 512, kernel_size=3, padding=1),nn.BatchNorm2d(512),nn.ReLU(inplace=True),nn.MaxPool2d(2))# 全连接层的输入维度,经过 5 次池化后,特征图大小为 8x8,通道数为 512self.fc1 = nn.Linear(512 * 8 * 8, 2048)# ReLU 激活函数self.relu = nn.ReLU(inplace=True)# Dropout 层,防止过拟合self.dropout = nn.Dropout(0.5)# 输出层,输出 20 个类别self.fc2 = nn.Linear(2048, 20)def forward(self, x):# 依次通过各个卷积块x = self.conv_block1(x)x = self.conv_block2(x)x = self.conv_block3(x)x = self.conv_block4(x)x = self.conv_block5(x)# 将多维的特征图展平为一维向量x = x.view(-1, 512 * 8 * 8)# 通过第一个全连接层x = self.fc1(x)# 通过 ReLU 激活函数x = self.relu(x)# 通过 Dropout 层x = self.dropout(x)# 通过输出层output = self.fc2(x)return output# 创建 CNN 模型实例,并将其移动到指定设备上
model = CNN().to(device)# 加载之前保存的模型参数
model.load_state_dict(torch.load('best.pth'))
# 也可以直接加载整个模型
# model = torch.load('best.pt')
# 将模型设置为评估模式
model.eval()# 创建测试数据集实例
test_data = food_dataset(file_path='test_true.txt', transform=data_transforms['valid'])
# 创建测试数据加载器,批量大小为 1,数据打乱
test_dataloader = DataLoader(test_data, batch_size=1, shuffle=True)
# 用于存储模型的预测结果
result = []
# 用于存储真实标签
lables = []# 定义测试函数,用于获取每个样本的预测结果和真实标签
def test_true(dataloader, model):# 关闭梯度计算,减少内存消耗with torch.no_grad():for x, y in dataloader:# 将输入数据和标签移动到指定设备上x, y = x.to(device), y.to(device)# 进行前向传播,得到模型的预测结果pred = model.forward(x)# 获取预测结果中概率最大的类别索引,并添加到 result 列表中result.append(pred.argmax(1).item())# 获取真实标签,并添加到 lables 列表中lables.append(y.item())# 调用测试函数
test_true(test_dataloader, model)
# 打印模型的预测结果
print('预测值:\t', result)
# 打印真实标签
print('真实值:\t', lables)# 定义测试函数,用于计算模型的准确率和平均损失
def test(dataloader, model, loss_fn):global best_acc# 数据集的总样本数size = len(dataloader.dataset)# 数据加载器中的批次数量num_batches = len(dataloader)# 将模型设置为评估模式model.eval()# 初始化测试损失和正确预测的样本数test_loss, correct = 0, 0# 关闭梯度计算,减少内存消耗with torch.no_grad():for x, y in dataloader:# 将输入数据和标签移动到指定设备上x, y = x.to(device), y.to(device)# 进行前向传播,得到模型的预测结果pred = model.forward(x)# 计算当前批次的损失,并累加到 test_loss 中test_loss += loss_fn(pred, y).item()# 统计正确预测的样本数correct += (pred.argmax(1) == y).type(torch.float).sum().item()a = (pred.argmax(1) == y)  # dim=1 表示每一行中的最大值对应的索引号,dim=0 表示每一列中的最大值对应的索引号b = (pred.argmax(1) == y).type(torch.float)# 计算平均测试损失test_loss /= num_batches# 计算准确率correct /= size# 打印测试结果print(f'Test result: \n Accuracy:{(100 * correct)}%,Avg loss:{test_loss}')# 创建交叉熵损失函数实例
loss_fn = nn.CrossEntropyLoss()
# 创建 Adam 优化器实例
optimizer = torch.optim.Adam(model.parameters(), lr=0.0001)
# 调用测试函数,计算模型的准确率和平均损失
test(test_dataloader, model, loss_fn)

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot+微信小程序+数据可视化的宠物到家喂宠服务(程序+论文+讲解+安装+调试+售后等)

感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,我会一一回复,希望帮助更多的人。 系统介绍 在经济高速发展、物质生活极大丰富的当下,人们的精神需求愈发凸显&#xff0…

《仙台有树》追剧疑问与DeepSeek解答

本篇形式:直接以两段对话直接呈现,有删减 本篇背景:看过太多逻辑bug,有些bug无药可救直接弃剧,有些bug情有可原包容理解。想到最近大火的DeepSeek,就与时俱进,简单直接点吧,也许自己…

Java版企业电子招标采购系统源业码Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis

功能描述 1、门户管理:所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含:招标公告、非招标公告、系统通知、政策法规。 2、立项管理:企业用户可对需要采购的项目进行立项申请,并提交审批,查看所…

txt文件批量转PDF

需要使用acrobat DC软件。 工具 – 创建 PDF – 多个文件(可以选择多个TXT文件,过多可能内存溢出)。

学习笔记之debian的thonny开发(尚未验证)--从stm32裸机到linux嵌入式系统

这应该算 stm32裸机用户 转 linux嵌入式系统 的入门学习笔记。 【鲁班猫】39-vnc远程桌面连接鲁班猫_哔哩哔哩_bilibili 本集的鲁班猫的视频介绍中,没有清晰明确指出需要linux开发板接入网络,接入网络可以使用有线网口或者wifi路由,有些提示…

PVE使用一个物理网卡采用VLAN为管理IP和VM分配网络的问题

问题描述: 部署PVE后, 想着在上面部署多个不同VLAN的VM (类似于VMwarere ESXi),但有人反馈无法使用VLAN,只能配置部署PVE时使用的网段。 问题分析: 在PVE的主机节点网络配置中,默认…

15.3.10 窗体下使用多线程

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 从.Net FrameWork2.0开始,为了加强了程序安全,防止跨线程调用导致不可预知的结果。微软将窗体主线程&#x…

ASP.NET Core SixLabors.ImageSharp v3.x 的图像实用程序类

使用用 C# 编写的 asp.net core web 应用程序示例在 Windows 和 Linux web 服务器上处理图像,包括创建散点图和直方图,以及根据需要旋转图像以便正确显示。 这个小型实用程序库需要将 NuGet SixLabors.ImageSharp包(版本 3.1.x)添…

【leetcode】200.岛屿数量(DFS入门)

实战总结 用char型接收整形int转化为的对应字符要小心 int res; char res 0; 其中 res 的上限是127。 在下面这道题中,笔者一开始想将遍历过的位置更新值为 res ‘0’,但当岛屿数过多的时候就溢出了,所以还是应该将遍历过的位置更新为‘…

CES Asia 2025“科技+文旅”融合计划:开启文旅新篇

CES Asia 2025第七届亚洲消费电子技术贸易展(赛逸展)将在首都北京盛大举行,其亮点十三“‘科技文旅’融合计划”备受瞩目,为科技与文旅产业的深度融合带来了新的契机与活力。 在“科技文旅”融合计划中,景区智能设备租…

【Git版本控制器】第三弹——版本回退,撤销修改,删除文件

🎁个人主页:我们的五年 🔍系列专栏:Linux网络编程 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 ​ 相关笔记: https://blog.csdn.net/djd…

DeepSeek ,银行营销会被 AIGC 颠覆吗?

AI 让银行营销更智能,但更重要的是“懂客户” AI 在银行营销中的应用已经不仅仅局限于文案生成,而是渗透到了整个营销流程。 据悉,中国银行已经开始利用 AI 大模型构建智能营销助手系统,结合知识图谱和 AI 技术,实现…

【产品推介】可驱动5A负载的降压型DC/DC转换器XBL1663

一、产品简介 采用ESOP-8封装的XBL1663最大可输出5A电流 芯伯乐XBL1663是一款专为降压型DC/DC转换器设计的单片集成电路,具有高转换效率、恒定开关频率工作的特点。内置功率 MOSFET可在 4.5 V-40V 输入电源上实现 5A 峰值输出电流,并具有出色的负载和线…

Rust编程语言入门教程(四)猜数游戏:一次猜测

目录 引言猜数游戏——目标一、创建项目二、编写代码三、运行代码四、代码解释总结 引言 猜数游戏是一个经典的编程练习,它不仅能够帮助开发者熟悉基本的输入输出操作,还能深入理解条件判断和用户交互的逻辑。在 Rust 中,通过标准库提供的 s…

.NET版PDF处理控件Aspose.PDF教程:在 C# 中将 TIFF 文件转换为 PDF

将TIFF文件转换为PDF文档在各个行业中都是必不可少的。许多企业需要将文档转换为存档、共享或打印。TIFF 文件通常用于图像,而 PDF 是文档共享的标准。将 TIFF 文件转换为 PDF 可确保跨不同平台的兼容性和易用性。在这篇博文中,我们将探讨如何使用 Aspos…

DeepSeek视角下学术论文创新点探索干货分享!

学术论文的创新性是推动知识进步和科学发展的关键因素。它不仅是学术研究的基本要求,也是研究者专业能力的重要体现。本文将探讨学术论文创新的重要性,并分析DeepSeek在促进学术论文创新方面可能发挥的独特作用。 1.创新为啥这么重要? 1. 探…

EasyRTC智能硬件:实时畅联、沉浸互动、消音护航

在当今智能硬件迅猛发展的时代,音视频通讯技术已成为设备与用户、设备与设备间不可或缺的沟通纽带。而EasyRTC,凭借其无可比拟的实时性能、卓越的互动感受以及强大的交互实力,正逐步演变为智能硬件领域的“超级动力”核心。特别是其倾力打造的…

matlab汽车动力学半车垂向振动模型

1、内容简介 matlab141-半车垂向振动模型 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略

重生之我在异世界学编程之C语言:深入预处理篇(上)

大家好,这里是小编的博客频道 小编的博客:就爱学编程 很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!! 本文目录 引言正文一、预处理的作用与流程&#xf…

观察者模式说明(C语言版本)

观察者模式主要是为了实现一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。下面使用C语言实现了一个具体的应用示例,有需要的可以参考…