深度学习实验十三 卷积神经网络(4)——使用预训练resnet18实现CIFAR-10分类

news2024/12/26 22:41:57

目录

一、数据加载

二、数据集类构建

三、模型构建

四、模型训练

五、模型评价及预测

附完整可运行代码:

实验大体步骤:

注:

在自己电脑的CPU跑代码×

连接远程服务器跑代码√

本次实验由于数据量巨大,我的笔记本上还没有GPU,跑代码一直跑不出来,一直停在如下这个位置不动:

于是我想到了连接远程服务器来跑代码。

 如果你的电脑上有GPU,那么可以参考学长的博客跑:学长本次实验的博客

我这里使用的是AutoDL算力云,租个3080的服务器,跑个七八分钟就能出来,而且租一小时才1块多!安利!

我在这里也附上如何使用远程服务器的方法

进入AutoDL官网后,点击算力市场:

随便租个就可以

基础镜像这边选个Pytorch的某个版本就行

接下来就跟着这个视频做吧:Pycharm连接远程GPU服务器跑深度学习_哔哩哔哩_bilibili

有几点需要注意的地方:

1.pycharm必须是专业版,社区版没有连接远程服务器的功能。pycharm专业版参考这个链接:​​​​​​​Pycharm专业版​​​​​​​

2.连接成功之后,可能会遇到一些安装包安装不上的问题,比如我在import torch的这里一直报错,显示安装错误,多安装几次就好了,安装的时候尽量不要连hbu的校园网,不是很稳定,容易下载出错。

3.在自己笔记本就能运行,也没有报错,为什么连接个远程服务器会出现size不匹配的错误?还有numpy也会出错?

第一个问题,这个错误是因为模型中的输入和权重在不同的设备上进行计算,导致了类型不匹配。我的模型使用了GPU(torch.cuda.FloatTensor),而输入数据却是CPU上的张量(torch.FloatTensor)。PyTorch要求输入和模型的权重在相同的设备上,才能进行有效的计算。所以,需要时时刻刻确保输入数据和模型在同一个设备上。

于是要多处添加如下的代码:

第二个问题,出现在 nndl_3.py 文件中的 self.metric.update(logits, y) 这一行,具体是因为尝试将一个在 GPU 上的 tensor 转换为 NumPy 数组。由于 NumPy 不支持在 GPU 上的 tensor,所以必须先将其移动到 CPU 上。代码改成如下:

一、数据加载

本实验的数据集使用计算机视觉领域的经典数据集:CIFAR-10数据集,数据集下载位置:数据集下载

代码如下:

def load_cifar10_batch(folder_path, batch_id=1, mode='train'):
    if mode == 'test':
        file_path = os.path.join(folder_path, 'test_batch')
    else:
        file_path = os.path.join(folder_path, 'data_batch_' + str(batch_id))

    # 加载数据集文件
    with open(file_path, 'rb') as batch_file:
        batch = pickle.load(batch_file, encoding='latin1')

    imgs = batch['data'].reshape((len(batch['data']), 3, 32, 32)) / 255.
    labels = batch['labels']

    return np.array(imgs, dtype='float32'), np.array(labels)


imgs_batch, labels_batch = load_cifar10_batch(folder_path=r'cifar-10-batches-py',
                                              batch_id=1, mode='train')
# 打印一下每个batch中X和y的维度
print("batch of imgs shape: ", imgs_batch.shape, "batch of labels shape: ", labels_batch.shape)
print(torch.__version__)
print(torch.cuda.is_available())
# ==========可视化观察其中的一张样本图像和对应的标签=================================
import matplotlib.pyplot as plt

image, label = imgs_batch[1], labels_batch[1]
print("The label in the picture is {}".format(label))
plt.figure(figsize=(2, 2))
plt.imshow(image.transpose(1, 2, 0))
plt.show()

运行结果:

 

二、数据集类构建

代码如下:

# =====构建Dataset类======================================================
import torch
from torch.utils.data import Dataset, DataLoader
import torchvision.transforms as transforms


class CIFAR10Dataset(Dataset):
    def __init__(self, folder_path=r'cifar-10-batches-py', mode='train', device=None):
        if mode == 'train':
            self.imgs, self.labels = load_cifar10_batch(folder_path=folder_path, batch_id=1, mode='train')
            for i in range(2, 5):
                imgs_batch, labels_batch = load_cifar10_batch(folder_path=folder_path, batch_id=i, mode='train')
                self.imgs, self.labels = np.concatenate([self.imgs, imgs_batch]), np.concatenate(
                    [self.labels, labels_batch])
        elif mode == 'dev':
            self.imgs, self.labels = load_cifar10_batch(folder_path=folder_path, batch_id=5, mode='dev')
        elif mode == 'test':
            self.imgs, self.labels = load_cifar10_batch(folder_path=folder_path, mode='test')

        self.transforms = transforms.Compose([transforms.Resize(32), transforms.ToTensor(),
                                              transforms.Normalize(mean=[0.4914, 0.4822, 0.4465],
                                                                   std=[0.2023, 0.1994, 0.2010])])
        self.device = device  # 保存设备信息

    def __getitem__(self, idx):
        img, label = self.imgs[idx], self.labels[idx]
        img, label = torch.tensor(img).float(), torch.tensor(label).long()  # 转为Tensor
        if self.device:
            img, label = img.to(self.device), label.to(self.device)  # 将数据传输到目标设备
        return img, label

    def __len__(self):
        return len(self.imgs)


device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)
# 创建数据集时传递设备信息
train_dataset = CIFAR10Dataset(folder_path=r'cifar-10-batches-py', mode='train', device=device)
dev_dataset = CIFAR10Dataset(folder_path=r'cifar-10-batches-py', mode='dev', device=device)
test_dataset = CIFAR10Dataset(folder_path=r'cifar-10-batches-py', mode='test', device=device)

三、模型构建

使用PyTorch API中的Resnet18进行图像分类实验。

代码如下:

# =======模型构建========================================
from torchvision.models import resnet18
time1 = time.time()
resnet18_model = resnet18(pretrained=True)

四、模型训练

代码如下:

# =======模型训练================================================
import torch.nn.functional as F
import torch.optim as opt
from nndl_3 import RunnerV3, Accuracy

# 学习率大小
lr = 0.001
# 批次大小
batch_size = 64
# 加载数据
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
dev_loader = DataLoader(dev_dataset, batch_size=batch_size)
test_loader = DataLoader(test_dataset, batch_size=batch_size)
# 定义网络
model = resnet18_model.to(device)
# 定义优化器,这里使用Adam优化器以及l2正则化策略,相关内容在7.3.3.2和7.6.2中会进行详细介绍
optimizer = opt.Adam(lr=lr, params=model.parameters(), weight_decay=0.005)
# 定义损失函数
loss_fn = F.cross_entropy
loss_fn = loss_fn
# 定义评价指标
metric = Accuracy(is_logist=True)
# 在训练和评估时,将数据传输到设备上
for data, labels in train_loader:
    data, labels = data.to(device), labels.to(device)  # 将数据和标签都发送到相同的设备
    logits = model(data)  # 进行前向传播
    loss = loss_fn(logits, labels)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
# 实例化RunnerV3
runner = RunnerV3(model, optimizer, loss_fn, metric)
# 启动训练
log_steps = 3000
eval_steps = 3000
runner.train(train_loader, dev_loader, num_epochs=30, log_steps=log_steps,
             eval_steps=eval_steps, save_path="best_model.pdparams")

from nndl_3 import plot

plot(runner, fig_name='cnn-loss4.pdf')

运行结果:

五、模型评价及预测

代码如下:

# ========模型评价============================================
# 加载最优模型
runner.load_model('best_model.pdparams')
# 模型评价
score, loss = runner.evaluate(test_loader)
print("[Test] accuracy/loss: {:.4f}/{:.4f}".format(score, loss))

# ==========模型预测================================================
import matplotlib.pyplot as plt

# 获取测试集中的一个batch的数据
X, label = next(iter(test_loader))
X = X.to(device)
logits = runner.predict(X, dim=1)
# 多分类,使用softmax计算预测概率
pred = F.softmax(logits)
# print(pred)
# 获取概率最大的类别
pred_class = torch.argmax(pred[2][0]).cpu().numpy()
label = label[2].item()
# 输出真实类别与预测类别
print("The true category is {} and the predicted category is {}".format(label, pred_class))
# 可视化图片
plt.figure(figsize=(2, 2))
imgs, labels = load_cifar10_batch(folder_path=r'cifar-10-batches-py', mode='test')
plt.imshow(imgs[2].transpose(1, 2, 0))
plt.savefig('cnn-test-vis.pdf')
time2 = time.time()
print('使用预训练模型的训练时间:{}'.format(time2-time1))

 运行结果:

运行时间:

以上是使用预训练的结果,对比不适用预训练,只需要修改这一行代码:

resnet18_model = resnet18(pretrained=True)

把True改为False即可。

不使用预训练的结果如下:

对比可以看出:使用预训练运行时间变短了,准确率变高了,那么这是为什么呢?

首先来说,什么是预训练?什么是迁移学习呢?

预训练:      

  “预训练”的做法一般是将大量低成本收集的训练数据放在一起,经过某种预训方法去学习其中的共性,然后将其中的共性“移植”到特定任务的模型中,再使用相关特定领域的少量标注数据进行“微调”,这样的话,模型只需要从“共性”出发,去学习该特定任务的“特殊”部分即可。
        因为预训练模型已经在大规模数据集上学到了一般性的特征表示(如边缘、纹理、颜色等),所以参数已经初始化为较优值,只需对少部分参数进行调整,模型无需从零开始学习,因而训练过程更快。

迁移学习:

迁移学习主要思想:

迁移学习的核心思想是:在一个任务上训练得到的模型包含的知识可以部分或全部地转移到另一个任务上。这通常涉及以下两个主要步骤:

·源任务学习: 在源任务上训练模型,这个任务通常有大量的数据可用。

·知识迁移: 将从源任务学到的知识(如网络参数、特征表示等)应用到目标任务上。
迁移学习通过重复利用已有的知识,不仅提高了学习效率和模型性能,还降低了对标注数据的需求和整体训练成本。它在小数据集、跨领域应用和解决复杂问题方面展现了显著的优势。
普通训练、预训练、迁移学习的对比:

 实验过程中,使用的优化器不是SGD了,而是换成了Adam,那么Adam优化器和SGD优化器有什么区别呢?

Adam是一种常用的自适应优化算法,它结合了动量和自适应学习率机制。Adam是基于梯度下降法的,它通过调整每个参数的学习率来加速训练并避免一些常见问题(如梯度消失或爆炸)。
Adam优化器和SGD的对比:


Adam优化器自动调整每个参数的学习率,尤其适合大规模的深度学习任务。所以本次实验选择了Adam优化器。

本次实验中还用到了权重衰减,用来防止过拟合,那么它的原理是什么呢?

权重衰减是一种正则化方法,旨在防止模型的过拟合。它通过在损失函数中添加一个项,使得模型的参数保持较小的值,从而避免模型过度依赖某些特征,导致过拟合。

权重衰减的公式:

对于一个损失函数J(θ),在应用权重衰减后,损失函数变为:


λ 是权重衰减的超参数(通常称为正则化强度),决定了对权重的惩罚程度。

是模型权重的L2范数,即权重的平方和。
L2正则化和权重衰减本质上是相同的,区别在于在实现时是否将其明确作为正则化项添加到损失函数中。通常,现代优化器(如Adam、SGD)会通过直接修改损失函数来实现这一点,从而形成权重衰减。

附完整可运行代码:

主程序:

import os
import pickle
import time

import numpy as np
import torch


def load_cifar10_batch(folder_path, batch_id=1, mode='train'):
    if mode == 'test':
        file_path = os.path.join(folder_path, 'test_batch')
    else:
        file_path = os.path.join(folder_path, 'data_batch_' + str(batch_id))

    # 加载数据集文件
    with open(file_path, 'rb') as batch_file:
        batch = pickle.load(batch_file, encoding='latin1')

    imgs = batch['data'].reshape((len(batch['data']), 3, 32, 32)) / 255.
    labels = batch['labels']

    return np.array(imgs, dtype='float32'), np.array(labels)


imgs_batch, labels_batch = load_cifar10_batch(folder_path=r'cifar-10-batches-py',
                                              batch_id=1, mode='train')
# 打印一下每个batch中X和y的维度
print("batch of imgs shape: ", imgs_batch.shape, "batch of labels shape: ", labels_batch.shape)
print(torch.__version__)
print(torch.cuda.is_available())
# ==========可视化观察其中的一张样本图像和对应的标签=================================
import matplotlib.pyplot as plt

image, label = imgs_batch[1], labels_batch[1]
print("The label in the picture is {}".format(label))
plt.figure(figsize=(2, 2))
plt.imshow(image.transpose(1, 2, 0))
plt.show()

# =====构建Dataset类======================================================
import torch
from torch.utils.data import Dataset, DataLoader
import torchvision.transforms as transforms


class CIFAR10Dataset(Dataset):
    def __init__(self, folder_path=r'cifar-10-batches-py', mode='train', device=None):
        if mode == 'train':
            self.imgs, self.labels = load_cifar10_batch(folder_path=folder_path, batch_id=1, mode='train')
            for i in range(2, 5):
                imgs_batch, labels_batch = load_cifar10_batch(folder_path=folder_path, batch_id=i, mode='train')
                self.imgs, self.labels = np.concatenate([self.imgs, imgs_batch]), np.concatenate(
                    [self.labels, labels_batch])
        elif mode == 'dev':
            self.imgs, self.labels = load_cifar10_batch(folder_path=folder_path, batch_id=5, mode='dev')
        elif mode == 'test':
            self.imgs, self.labels = load_cifar10_batch(folder_path=folder_path, mode='test')

        self.transforms = transforms.Compose([transforms.Resize(32), transforms.ToTensor(),
                                              transforms.Normalize(mean=[0.4914, 0.4822, 0.4465],
                                                                   std=[0.2023, 0.1994, 0.2010])])
        self.device = device  # 保存设备信息

    def __getitem__(self, idx):
        img, label = self.imgs[idx], self.labels[idx]
        img, label = torch.tensor(img).float(), torch.tensor(label).long()  # 转为Tensor
        if self.device:
            img, label = img.to(self.device), label.to(self.device)  # 将数据传输到目标设备
        return img, label

    def __len__(self):
        return len(self.imgs)


device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)
# 创建数据集时传递设备信息
train_dataset = CIFAR10Dataset(folder_path=r'cifar-10-batches-py', mode='train', device=device)
dev_dataset = CIFAR10Dataset(folder_path=r'cifar-10-batches-py', mode='dev', device=device)
test_dataset = CIFAR10Dataset(folder_path=r'cifar-10-batches-py', mode='test', device=device)

# =======模型构建========================================
from torchvision.models import resnet18
time1 = time.time()
resnet18_model = resnet18(pretrained=True)

# =======模型训练================================================
import torch.nn.functional as F
import torch.optim as opt
from nndl_3 import RunnerV3, Accuracy

# 学习率大小
lr = 0.001
# 批次大小
batch_size = 64
# 加载数据
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
dev_loader = DataLoader(dev_dataset, batch_size=batch_size)
test_loader = DataLoader(test_dataset, batch_size=batch_size)
# 定义网络
model = resnet18_model.to(device)
# 定义优化器,这里使用Adam优化器以及l2正则化策略,相关内容在7.3.3.2和7.6.2中会进行详细介绍
optimizer = opt.Adam(lr=lr, params=model.parameters(), weight_decay=0.005)
# 定义损失函数
loss_fn = F.cross_entropy
loss_fn = loss_fn
# 定义评价指标
metric = Accuracy(is_logist=True)
# 在训练和评估时,将数据传输到设备上
for data, labels in train_loader:
    data, labels = data.to(device), labels.to(device)  # 将数据和标签都发送到相同的设备
    logits = model(data)  # 进行前向传播
    loss = loss_fn(logits, labels)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
# 实例化RunnerV3
runner = RunnerV3(model, optimizer, loss_fn, metric)
# 启动训练
log_steps = 3000
eval_steps = 3000
runner.train(train_loader, dev_loader, num_epochs=30, log_steps=log_steps,
             eval_steps=eval_steps, save_path="best_model.pdparams")

from nndl_3 import plot

plot(runner, fig_name='cnn-loss4.pdf')

# ========模型评价============================================
# 加载最优模型
runner.load_model('best_model.pdparams')
# 模型评价
score, loss = runner.evaluate(test_loader)
print("[Test] accuracy/loss: {:.4f}/{:.4f}".format(score, loss))

# ==========模型预测================================================
import matplotlib.pyplot as plt

# 获取测试集中的一个batch的数据
X, label = next(iter(test_loader))
X = X.to(device)
logits = runner.predict(X, dim=1)
# 多分类,使用softmax计算预测概率
pred = F.softmax(logits)
# print(pred)
# 获取概率最大的类别
pred_class = torch.argmax(pred[2][0]).cpu().numpy()
label = label[2].item()
# 输出真实类别与预测类别
print("The true category is {} and the predicted category is {}".format(label, pred_class))
# 可视化图片
plt.figure(figsize=(2, 2))
imgs, labels = load_cifar10_batch(folder_path=r'cifar-10-batches-py', mode='test')
plt.imshow(imgs[2].transpose(1, 2, 0))
plt.savefig('cnn-test-vis.pdf')
time2 = time.time()
print('使用预训练模型的训练时间:{}'.format(time2-time1))

nndl_3的代码:

import torch
from matplotlib import pyplot as plt
from torch import nn


class Op(object):
    def __init__(self):
        pass

    def __call__(self, inputs):
        return self.forward(inputs)

    def forward(self, inputs):
        raise NotImplementedError

    def backward(self, inputs):
        raise NotImplementedError


# 实现一个两层前馈神经网络
class Model_MLP_L2_V3(torch.nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(Model_MLP_L2_V3, self).__init__()
        self.fc1 = torch.nn.Linear(input_size, hidden_size)
        w_ = torch.normal(0, 0.01, size=(hidden_size, input_size), requires_grad=True)
        self.fc1.weight = torch.nn.Parameter(w_)
        self.fc1.bias = torch.nn.init.constant_(self.fc1.bias, val=1.0)
        self.fc2 = torch.nn.Linear(hidden_size, output_size)
        w2 = torch.normal(0, 0.01, size=(output_size, hidden_size), requires_grad=True)
        self.fc2.weight = nn.Parameter(w2)
        self.fc2.bias = torch.nn.init.constant_(self.fc2.bias, val=1.0)
        self.act = torch.sigmoid

    def forward(self, inputs):
        outputs = self.fc1(inputs)
        outputs = self.act(outputs)
        outputs = self.fc2(outputs)
        return outputs


class RunnerV3(object):
    def __init__(self, model, optimizer, loss_fn, metric, **kwargs):
        self.model = model
        self.optimizer = optimizer
        self.loss_fn = loss_fn
        self.metric = metric  # 只用于计算评价指标

        # 记录训练过程中的评价指标变化情况
        self.dev_scores = []

        # 记录训练过程中的损失函数变化情况
        self.train_epoch_losses = []  # 一个epoch记录一次loss
        self.train_step_losses = []  # 一个step记录一次loss
        self.dev_losses = []

        # 记录全局最优指标
        self.best_score = 0

    def train(self, train_loader, dev_loader=None, **kwargs):
        # 将模型切换为训练模式
        self.model.train()

        # 传入训练轮数,如果没有传入值则默认为0
        num_epochs = kwargs.get("num_epochs", 0)
        # 传入log打印频率,如果没有传入值则默认为100
        log_steps = kwargs.get("log_steps", 100)
        # 评价频率
        eval_steps = kwargs.get("eval_steps", 0)

        # 传入模型保存路径,如果没有传入值则默认为"best_model.pdparams"
        save_path = kwargs.get("save_path", "best_model.pdparams")

        custom_print_log = kwargs.get("custom_print_log", None)

        # 训练总的步数
        num_training_steps = num_epochs * len(train_loader)

        if eval_steps:
            if self.metric is None:
                raise RuntimeError('Error: Metric can not be None!')
            if dev_loader is None:
                raise RuntimeError('Error: dev_loader can not be None!')

        # 运行的step数目
        global_step = 0

        # 进行num_epochs轮训练
        for epoch in range(num_epochs):
            # 用于统计训练集的损失
            total_loss = 0
            for step, data in enumerate(train_loader):
                X, y = data
                # 获取模型预测
                logits = self.model(X)
                loss = self.loss_fn(logits, y.long())  # 默认求mean
                total_loss += loss

                # 训练过程中,每个step的loss进行保存
                self.train_step_losses.append((global_step, loss.item()))

                if log_steps and global_step % log_steps == 0:
                    print(
                        f"[Train] epoch: {epoch}/{num_epochs}, step: {global_step}/{num_training_steps}, loss: {loss.item():.5f}")

                # 梯度反向传播,计算每个参数的梯度值
                loss.backward()

                if custom_print_log:
                    custom_print_log(self)

                # 小批量梯度下降进行参数更新
                self.optimizer.step()
                # 梯度归零
                self.optimizer.zero_grad()

                # 判断是否需要评价
                if eval_steps > 0 and global_step > 0 and \
                        (global_step % eval_steps == 0 or global_step == (num_training_steps - 1)):

                    dev_score, dev_loss = self.evaluate(dev_loader, global_step=global_step)
                    print(f"[Evaluate]  dev score: {dev_score:.5f}, dev loss: {dev_loss:.5f}")

                    # 将模型切换为训练模式
                    self.model.train()

                    # 如果当前指标为最优指标,保存该模型
                    if dev_score > self.best_score:
                        self.save_model(save_path)
                        print(
                            f"[Evaluate] best accuracy performence has been updated: {self.best_score:.5f} --> {dev_score:.5f}")
                        self.best_score = dev_score

                global_step += 1

            # 当前epoch 训练loss累计值
            trn_loss = (total_loss / len(train_loader)).item()
            # epoch粒度的训练loss保存
            self.train_epoch_losses.append(trn_loss)

        print("[Train] Training done!")

    # 模型评估阶段,使用'torch.no_grad()'控制不计算和存储梯度
    @torch.no_grad()
    def evaluate(self, dev_loader, **kwargs):
        assert self.metric is not None

        # 将模型设置为评估模式
        self.model.eval()

        global_step = kwargs.get("global_step", -1)

        # 用于统计训练集的损失
        total_loss = 0

        # 重置评价
        self.metric.reset()

        # 遍历验证集每个批次
        for batch_id, data in enumerate(dev_loader):
            X, y = data

            # 计算模型输出
            logits = self.model(X)

            # 计算损失函数
            loss = self.loss_fn(logits, y).item()
            # 累积损失
            total_loss += loss

            # 累积评价
            self.metric.update(logits, y)

        dev_loss = (total_loss / len(dev_loader))
        dev_score = self.metric.accumulate()

        # 记录验证集loss
        if global_step != -1:
            self.dev_losses.append((global_step, dev_loss))
            self.dev_scores.append(dev_score)

        return dev_score, dev_loss

    # 模型评估阶段,使用'torch.no_grad()'控制不计算和存储梯度
    @torch.no_grad()
    def predict(self, x, **kwargs):
        # 将模型设置为评估模式
        self.model.eval()
        # 运行模型前向计算,得到预测值
        logits = self.model(x)
        return logits

    def save_model(self, save_path):
        torch.save(self.model.state_dict(), save_path)

    def load_model(self, model_path):
        model_state_dict = torch.load(model_path)
        self.model.load_state_dict(model_state_dict)


class Accuracy():
    def __init__(self, is_logist=True):
        # 用于统计正确的样本个数
        self.num_correct = 0
        # 用于统计样本的总数
        self.num_count = 0

        self.is_logist = is_logist

    def update(self, outputs, labels):
        if outputs.shape[1] == 1:  # 二分类
            outputs = torch.squeeze(outputs, dim=-1)
            if self.is_logist:
                # logist判断是否大于0
                preds = torch.tensor((outputs >= 0), dtype=torch.float32)
            else:
                # 如果不是logist,判断每个概率值是否大于0.5,当大于0.5时,类别为1,否则类别为0
                preds = torch.tensor((outputs >= 0.5), dtype=torch.float32)
        else:
            # 多分类时,使用'torch.argmax'计算最大元素索引作为类别
            preds = torch.argmax(outputs, dim=1)

        # 获取本批数据中预测正确的样本个数
        labels = torch.squeeze(labels, dim=-1)
        batch_correct = torch.sum(torch.tensor(preds == labels, dtype=torch.float32)).cpu().numpy()
        batch_count = len(labels)

        # 更新num_correct 和 num_count
        self.num_correct += batch_correct
        self.num_count += batch_count

    def accumulate(self):
        # 使用累计的数据,计算总的指标
        if self.num_count == 0:
            return 0
        return self.num_correct / self.num_count

    def reset(self):
        # 重置正确的数目和总数
        self.num_correct = 0
        self.num_count = 0

    def name(self):
        return "Accuracy"


# 可视化
def plot(runner, fig_name):
    plt.figure(figsize=(10, 5))

    plt.subplot(1, 2, 1)
    train_items = runner.train_step_losses[::30]
    train_steps = [x[0] for x in train_items]
    train_losses = [x[1] for x in train_items]

    plt.plot(train_steps, train_losses, color='#8E004D', label="Train loss")
    if runner.dev_losses[0][0] != -1:
        dev_steps = [x[0] for x in runner.dev_losses]
        dev_losses = [x[1] for x in runner.dev_losses]
        plt.plot(dev_steps, dev_losses, color='#E20079', linestyle='--', label="Dev loss")
    # 绘制坐标轴和图例
    plt.ylabel("loss", fontsize='x-large')
    plt.xlabel("step", fontsize='x-large')
    plt.legend(loc='upper right', fontsize='x-large')

    plt.subplot(1, 2, 2)
    # 绘制评价准确率变化曲线
    if runner.dev_losses[0][0] != -1:
        plt.plot(dev_steps, runner.dev_scores,
                 color='#E20079', linestyle="--", label="Dev accuracy")
    else:
        plt.plot(list(range(len(runner.dev_scores))), runner.dev_scores,
                 color='#E20079', linestyle="--", label="Dev accuracy")
    # 绘制坐标轴和图例
    plt.ylabel("score", fontsize='x-large')
    plt.xlabel("step", fontsize='x-large')
    plt.legend(loc='lower right', fontsize='x-large')

    plt.savefig(fig_name)
    plt.show()

今天的分享就到这里,下次再见~

 

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

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

相关文章

【Maven Helper】分析依赖冲突案例

目录 Maven Helper实际案例java文件pom.xml文件运行抛出异常分析 参考资料 《咏鹅》骆宾王 鹅,鹅,鹅,曲项向天歌。 白毛浮绿水,红掌拨清波。 骆宾王是在自己7岁的时候就写下了这首杂言 Maven Helper A must have plugin for wor…

Android 桌面窗口新功能推进,聊一聊 Android 桌面化的未来

Android 桌面化支持可以说是 Android 15 里被多次提及的 new features,例如在 Android 15 QPR1 Beta 2 里就提到为 Pixel 平板引入了桌面窗口支持,桌面窗口允许用户在自由窗口同时运行多个应用,同时可以像在传统 PC 平台上一样调整这些窗口的…

【深度学习】四大图像分类网络之VGGNet

2014年,牛津大学计算机视觉组(Visual Geometry Group)和Google DeepMind公司一起研发了新的卷积神经网络,并命名为VGGNet。VGGNet是比AlexNet更深的深度卷积神经网络,该模型获得了2014年ILSVRC竞赛的第二名&#xff0c…

Pytest框架学习20--conftest.py

conftest.py作用 正常情况下,如果多个py文件之间需要共享数据,如一个变量,或者调用一个方法 需要先在一个新文件中编写函数等,然后在使用的文件中导入,然后使用 pytest中定义个conftest.py来实现数据,参…

【力扣】389.找不同

问题描述 思路解析 只有小写字母,这种设计参数小的,直接桶排序我最开始的想法是使用两个不同的数组,分别存入他们单个字符转换后的值,然后比较是否相同。也确实通过了 看了题解后,发现可以优化,首先因为t相…

HarmonyOS4+NEXT星河版入门与项目实战(23)------组件转场动画

文章目录 1、控件图解2、案例实现1、代码实现2、代码解释3、实现效果4、总结1、控件图解 这里我们用一张完整的图来汇整 组件转场动画的用法格式、属性和事件,如下所示: 2、案例实现 这里我们对上一节小鱼游戏进行改造,让小鱼在游戏开始的时候增加一个转场动画,让小鱼自…

Wireshark常用功能使用说明

此处用于记录下本人所使用 wireshark 所可能用到的小技巧。Wireshark是一款强大的数据包分析工具,此处仅介绍常用功能。 Wireshark常用功能使用说明 1.相关介绍1.1.工具栏功能介绍1.1.1.时间戳/分组列表概况等设置 1.2.Windows抓包 2.wireshark过滤器规则2.1.wiresh…

Vue3 开源UI 框架推荐 (大全)

一 、前言 💥这篇文章主要推荐了支持 Vue3 的开源 UI 框架,包括 web 端和移动端的多个框架,如 Element-Plus、Ant Design Vue 等 web 端框架,以及 Vant、NutUI 等移动端框架,并分别介绍了它们的特性和资源地址。&#…

探索Python词云库WordCloud的奥秘

文章目录 探索Python词云库WordCloud的奥秘1. 背景介绍:为何选择WordCloud?2. WordCloud库简介3. 安装WordCloud库4. 简单函数使用方法5. 应用场景示例6. 常见Bug及解决方案7. 总结 探索Python词云库WordCloud的奥秘 1. 背景介绍:为何选择Wo…

Kali Linux系统一键汉化中文版及基础使用详细教程

Kali Linux系统一键汉化中文版及基础使用详细教程 引言 Kali Linux是一款基于Debian的Linux发行版,专为渗透测试和网络安全而设计。由于其强大的功能和丰富的工具,Kali Linux在安全领域得到了广泛应用。然而,许多用户在使用Kali Linux时会遇…

网络安全(三):网路安全协议

网络安全协议设计的要求是实现协议过程中的认证性、机密性与不可否认性。网络安全协议涉及网络层、传输层与应用层。 1、网络层安全与IPSec协议、IPSec VPN 1.1、IPSec安全体系结构 IP协议本质上是不安全的额,伪造一个IP分组、篡改IP分组的内容、窥探传输中的IP分…

2. STM32_中断

中断 中断是什么: 打断CPU执行正常的程序,转而处理紧急程序,然后返回原暂停的程序继续运行,就叫中断。 中断的意义: 中断可以高效处理紧急程序,不会一直占用CPU资源。如实时控制、故障处理、处理不确定…

【聚类】主成分分析 和 t-SNE 降维

1 主成分分析PCA PCA 是一种线性降维技术,旨在通过选择具有最大方差的特征方向(称为主成分)来压缩数据,同时尽可能减少信息损失。 1.1 原理 1.2 优缺点 from sklearn.decomposition import PCA import matplotlib.pyplot as plt…

ARM 嵌入式处理器内核与架构深度剖析:解锁底层技术逻辑

目录 一、ARM架构概述 1.1. 优势与特点 1.2. 应用领域 二、ARM内核的主要系列及特点 2.1. ARM内核与架构的关系 2.2. Cortex-A系列 2.2.1. 应用场景 2.2.2. 特点 2.3. Cortex-R系列 2.3.1. 应用场景 2.3.2. 特点 2.4. Cortex-M系列 2.4.1. 应用场景 2.4.2. 特点 …

数据结构 (21)树、森林和二叉树的关系

一、树 定义:树是由一个集合以及在该集合上定义的一种关系构成的。集合中的元素称为树的结点,所定义的关系称为父子关系。当集合为空时,是一棵空树;当集合非空时,有且仅有一个特定的称为根的结点。树中的每个结点可以有…

探索温度计的数字化设计:一个可视化温度数据的Web图表案例

随着科技的发展,数据可视化在各个领域中的应用越来越广泛。在温度监控和展示方面,传统的温度计已逐渐被数字化温度计所取代。本文将介绍一个使用Echarts库创建的温度计Web图表,该图表通过动态数据可视化展示了温度值,并通过渐变色…

计算机网络——数据链路层Mac帧详解

目录 前言 一、以太网 二、Mac帧 三、MTU——最大传输单元 四、Mac帧的传输过程 1.ARP协议 2.RARP协议 前言 在之前,我们学习过网络层的IP协议,了解到IP协议解决了从哪里来,到哪里去的问题,也就是提供了将数据从A到B的能力…

LabVIEW将TXT文本转换为CSV格式(多行多列)

在LabVIEW中,将TXT格式的文本文件内容转换为Excel格式(即CSV文件)是一项常见的数据处理任务,适用于将以制表符、空格或其他分隔符分隔的数据格式化为可用于电子表格分析的形式。以下是将TXT文件转换为Excel(CSV&#x…

响应式编程一、Reactor核心

目录 一、前置知识1、Lambda表达式2、函数式接口 Function3、StreamAPI4、Reactive-Stream1)几个实际的问题2)Reactive-Stream是什么?3)核心接口4)处理器 Processor5)总结 二、Reactor核心1、Reactor1&…

Vue3之弹窗

文章目录 第一步、引入JS第二步、弹框 在前端开发语言Vue3&#xff0c;在管理端如何进行弹窗&#xff1f;下面根据API实现效果。 Element API文档&#xff1a; Element-plus文档 搭建环境可参考博客【 初探Vue3环境搭建与nvm使用】 第一步、引入JS <script lang"ts&…