深度学习基础相关知识(3.18)

一、mnist_pytorch运行结果

二、loss and acc 图+理论

说明:

train loss(训练损失):随着训练的进行,训练损失应该逐渐下降,表明模型在训练数据上的拟合能力增强。

test loss(测试损失):测试损失也应该逐渐下降,但如果模型过拟合,测试损失可能会在某个点开始上升。

train accuracy(训练准确率):训练准确率应该逐渐上升,表明模型在训练数据上的预测能力提高。

test accuracy(测试准确率):测试准确率也应该逐渐上升,但如果模型过拟合,测试准确率可能会停滞甚至下降。

1. 损失(Loss)

理论

a.定义:损失函数(Loss Function)用于衡量模型预测值与真实值之间的差异。在分类任务中,常用的损失函数是交叉熵损失(Cross-Entropy Loss)

b.作用:

        损失值越小,说明模型的预测结果与真实值越接近。

        训练过程中,优化器(如 SGD、Adam)的目标是最小化损失函数。

c.变化趋势:

        在训练初期,损失值通常较高,随着训练的进行,损失值逐渐下降。

        如果损失值在训练集上下降但在验证集上上升,可能是过拟合的迹象。


2. 准确率(Accuracy)

理论

a.定义:准确率是模型预测正确的样本数占总样本数的比例。

Number of Correct Predictions:模型预测正确的样本数。

Total Number of Predictions:总样本数。

b.作用:

        准确率越高,说明模型的预测能力越强。

        在分类任务中,准确率是最直观的评估指标。

c.变化趋势:

        在训练初期,准确率通常较低,随着训练的进行,准确率逐渐上升。

        如果训练集准确率持续上升但验证集准确率停滞或下降,可能是过拟合的迹象。

三、其他分类指标运算

机器学习

  • 准确率(Accuracy)

    • 定义与公式:预测正确的样本数占总样本数的比例,公式为Accuracy=TP+TN+FP+FNTP+TN​。例如,在一个手写数字识别任务中,共有 1000 张数字图片,模型正确识别出了 900 张,那么准确率就是1000900​=0.9。

    • 适用场景与局限性:适用于样本分布较为均衡的情况,能直观地反映模型的整体分类性能。但当正负样本比例悬殊时,如正样本占比 99%,模型即使全部预测为正样本,准确率也会很高,却不能说明模型有效,此时准确率就具有一定的误导性。

  • 精确率(Precision)

    • 定义与公式:预测为正例的样本中,真正例的比例,公式为Precision=TP\TP+FP。例如,在一个疾病检测模型中,模型预测有 100 人患病,其中实际患病的有 80 人,那么精确率就是80\100=0.8。

    • 适用场景与局限性:在一些对误判为正例代价较高的场景中非常重要,如金融诈骗检测,较高的精确率可以减少对正常交易的误判,降低不必要的调查成本。但如果召回率很低,即使精确率高,也可能遗漏很多真正的正例。

  • 召回率(Recall)

    • 定义与公式:实际为正例的样本中,被预测为正例的比例,公式为Recall=TP\TP+FN​。例如,在一个癌症早期筛查模型中,实际有 100 名癌症患者,模型检测出了 60 名,召回率就是60\100​=0.6。

    • 适用场景与局限性:对于那些需要尽可能找出所有正例的场景至关重要,如疾病防控中的病例筛查,高召回率能确保大部分患者被及时发现。但如果只追求召回率,可能会导致大量误判,使精确率降低。

  • F1 值

    • 定义与公式:精确率和召回率的调和平均数,公式为F1=2×(Precision×Recall)\(Precision+Recal)​。例如,当精确率为 0.8,召回率为 0.6 时,F1=2×(0.8×0.6​)\(0.8+0.6)≈0.69。

    • 适用场景与局限性:综合了精确率和召回率,在样本不均衡、精确率和召回率此消彼长的情况下,能更全面地评估模型性能。但如果精确率和召回率都很低,F1 值也会较低,不能很好地反映模型在某些特定情况下的优势。

  • 混淆矩阵

    • 定义:是一个n×n的矩阵(n为类别数),用于展示分类模型的预测结果与真实标签之间的关系。矩阵的行表示真实类别,列表示预测类别。例如,在一个三分类问题中,混淆矩阵可能如下所示:

真实类别 \ 预测类别

类别 1

类别 2

类别 3

类别 1

80

10

10

类别 2

5

75

20

类别 3

3

12

85

  • 适用场景与局限性:能清晰地展示出各类别的预测情况,包括正确分类和错误分类的样本数,帮助分析模型在不同类别上的性能表现,进而发现模型的优势和不足。但对于多类别问题,矩阵可能会比较复杂,难以直观地看出整体趋势。

深度学习

  • 1.准确率、精确率、召回率、F1 值、ROC 曲线和 AUC

    • 定义与计算方式:这些指标在深度学习中的定义与机器学习中基本相同。例如,在图像分类任务中,计算准确率时,同样是用正确分类的图像数量除以总图像数量。在计算 ROC 曲线时,通过不断调整分类阈值,得到不同阈值下的真正率(TPR)和假正率(FPR),从而绘制出曲线,AUC 则是曲线下的面积。

    • 适用场景与特点:在深度学习的各种应用中广泛使用,如在医学图像分类中,通过 AUC 值可以评估模型对疾病类型判断的准确性;在自然语言处理的文本分类任务中,F1 值可以综合衡量模型对不同类别文本的分类效果。由于深度学习模型通常处理大规模、复杂的数据,这些指标能帮助评估模型在不同数据分布和特征情况下的性能。

  • 对数损失(Log Loss)

    • 定义与公式:也称为交叉熵损失,用于衡量模型预测的概率分布与真实标签的概率分布之间的差异。对于二分类问题,公式为,其中y为真实标签(0 或 1),p为模型预测为正例的概率。对于多分类问题,公式为,其中yi​表示第i个类别对应的真实标签(0 或 1),pi​表示模型预测第i个类别为正例的概率。

    • 适用场景与特点:是深度学习中分类任务常用的损失函数,在训练模型时,通过最小化对数损失来调整模型的参数。它对预测概率与真实标签之间的差异非常敏感,能有效地引导模型学习到正确的概率分布,尤其适用于需要对类别进行概率估计的场景。

  • Hinge 损失

    • 定义与公式:常用于支持向量机(SVM)等深度学习模型中,特别是在二分类问题中。公式为,其中y为真实标签(+1或−1),f(x)为模型的预测得分。

    • 适用场景与特点:它的目标是使正确分类的样本距离决策边界尽可能远,而错误分类的样本受到惩罚。Hinge 损失对于离群点相对不敏感,能有效防止模型过拟合,在一些对模型泛化能力要求较高的场景中表现较好,如在处理具有复杂边界的分类问题时,能使模型学习到更鲁棒的决策边界。

在原有的基础上添加更多的分类指标,如精确率(Precision)、召回率(Recall)和 F1 值。代码如下

import os
import torch
import torchvision
import torch.nn as nn
from torchvision import datasets, transforms
import torch.nn.functional as F
from sklearn.metrics import precision_score, recall_score, f1_score
import numpy as np


# 数据预处理
transformation = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))  # MNIST是单通道图像,均值和标准差为(0.5,)
])

# 加载MNIST数据集
train_dataset = torchvision.datasets.MNIST('data',
                                           train=True,
                                           transform=transformation,
                                           download=True)

test_dataset = torchvision.datasets.MNIST('data',
                                          train=False,
                                          transform=transformation,
                                          download=True)

# 创建数据加载器
train_dl = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dl = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=True)

# 构建CNN模型
class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, 5)  # 输入通道1,输出通道6,卷积核大小5x5
        self.conv2 = nn.Conv2d(6, 16, 3)  # 输入通道6,输出通道16,卷积核大小3x3
        self.pool = nn.MaxPool2d((2, 2))  # 最大池化层,2x2
        self.linear_1 = nn.Linear(16 * 5 * 5, 256)  # 全连接层,输入16*5*5,输出256
        self.linear_2 = nn.Linear(256, 10)  # 全连接层,输入256,输出10(10个类别)

    def forward(self, input):
        x = F.relu(self.conv1(input))  # 卷积层1 + ReLU激活
        x = self.pool(x)  # 池化层
        x = F.relu(self.conv2(x))  # 卷积层2 + ReLU激活
        x = self.pool(x)  # 池化层
        x = x.view(x.size(0), -1)  # 展平操作,将多维张量展平为一维
        x = F.relu(self.linear_1(x))  # 全连接层1 + ReLU激活
        x = self.linear_2(x)  # 全连接层2
        return x


# 选择设备
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = Model().to(device)
loss_fn = torch.nn.CrossEntropyLoss()  # 交叉熵损失函数
opt = torch.optim.SGD(model.parameters(), lr=0.001)  # 随机梯度下降优化器


# 训练函数
def train(dl, model, loss_fn, optimizer):
    size = len(dl.dataset)  # 数据集的大小
    num_batches = len(dl)

    train_loss, correct = 0, 0
    all_preds = []
    all_labels = []

    for x, y in dl:
        x, y = x.to(device), y.to(device)
        pred = model(x)
        loss = loss_fn(pred, y)
        optimizer.zero_grad()  # 梯度清零
        loss.backward()
        optimizer.step()
        with torch.no_grad():
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()
            train_loss += loss.item()
            all_preds.extend(pred.argmax(1).cpu().numpy())
            all_labels.extend(y.cpu().numpy())

    correct /= size
    train_loss /= num_batches

    precision = precision_score(all_labels, all_preds, average='macro')
    recall = recall_score(all_labels, all_preds, average='macro')
    f1 = f1_score(all_labels, all_preds, average='macro')

    return correct, train_loss, precision, recall, f1


# 测试函数
def test(test_dl, model, loss_fn):
    size = len(test_dl.dataset)  # 数据集的大小
    num_batches = len(test_dl)

    test_loss, correct = 0, 0
    all_preds = []
    all_labels = []

    with torch.no_grad():
        for x, y in test_dl:
            x, y = x.to(device), y.to(device)
            pred = model(x)
            loss = loss_fn(pred, y)
            test_loss += loss.item()
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()
            all_preds.extend(pred.argmax(1).cpu().numpy())
            all_labels.extend(y.cpu().numpy())

    correct /= size
    test_loss /= num_batches

    precision = precision_score(all_labels, all_preds, average='macro')
    recall = recall_score(all_labels, all_preds, average='macro')
    f1 = f1_score(all_labels, all_preds, average='macro')

    return correct, test_loss, precision, recall, f1


# 创建保存模型的目录
if not os.path.exists('saved_models'):
    os.makedirs('saved_models')

# 创建保存训练数据的目录
if not os.path.exists('saved_data'):
    os.makedirs('saved_data')


# 训练和测试循环
def fit(epochs, train_dl, test_dl, model, loss_fn, opt):
    train_losses = []
    train_accs = []
    train_precisions = []
    train_recalls = []
    train_f1s = []

    test_losses = []
    test_accs = []
    test_precisions = []
    test_recalls = []
    test_f1s = []

    for epoch in range(epochs):
        epoch_acc, epoch_loss, epoch_train_precision, epoch_train_recall, epoch_train_f1 = train(
            train_dl, model, loss_fn, opt)
        epoch_test_acc, epoch_test_loss, epoch_test_precision, epoch_test_recall, epoch_test_f1 = test(
            test_dl, model, loss_fn)

        train_losses.append(epoch_loss)
        train_accs.append(epoch_acc)
        train_precisions.append(epoch_train_precision)
        train_recalls.append(epoch_train_recall)
        train_f1s.append(epoch_train_f1)

        test_losses.append(epoch_test_loss)
        test_accs.append(epoch_test_acc)
        test_precisions.append(epoch_test_precision)
        test_recalls.append(epoch_test_recall)
        test_f1s.append(epoch_test_f1)

        template = ("epoch:{:2d}, train_loss:{:.5f}, train_acc:{:.1f}%, train_precision:{:.1f}%, train_recall:{:.1f}%, train_f1:{:.1f}%, "
                    "test_loss:{:.5f}, test_acc:{:.1f}%, test_precision:{:.1f}%, test_recall:{:.1f}%, test_f1:{:.1f}%")
        print(template.format(epoch, epoch_loss, epoch_acc * 100, epoch_train_precision * 100,
                              epoch_train_recall * 100, epoch_train_f1 * 100,
                              epoch_test_loss, epoch_test_acc * 100, epoch_test_precision * 100,
                              epoch_test_recall * 100, epoch_test_f1 * 100))

    # 保存模型
    model_path = 'saved_models/mnist_cnn_model.pth'
    torch.save(model.state_dict(), model_path)
    print(f"Model saved to {model_path}")

    # 保存训练数据
    train_data = {
        'train_loss': train_losses,
        'train_acc': train_accs,
        'train_precision': train_precisions,
        'train_recall': train_recalls,
        'train_f1': train_f1s,
        'test_loss': test_losses,
        'test_acc': test_accs,
        'test_precision': test_precisions,
        'test_recall': test_recalls,
        'test_f1': test_f1s
    }
    data_path = 'saved_data/training_data.pth'
    torch.save(train_data, data_path)
    print(f"Training data saved to {data_path}")

    print("=============Done===============")
    return train_losses, train_accs, train_precisions, train_recalls, train_f1s, \
        test_losses, test_accs, test_precisions, test_recalls, test_f1s


# 开始训练
train_losses, train_accs, train_precisions, train_recalls, train_f1s, \
    test_losses, test_accs, test_precisions, test_recalls, test_f1s = fit(50, train_dl, test_dl, model, loss_fn, opt)
    

运行结果和图形绘制 

绘制结果代码

import os
import torch
import matplotlib.pyplot as plt  # 用于绘图

# 从文件中加载训练数据
data_path ='saved_data/training_data.pth'  # 训练数据文件路径
# 添加安全全局变量,这里假设你的数据中没有自定义的特殊对象,如果有需要根据实际情况添加
torch.serialization.add_safe_globals({})
train_data = torch.load(data_path)

# 提取训练和测试的损失、准确率、精确率、召回率和 F1 值
train_loss = train_data['train_loss']
train_acc = train_data['train_acc']
train_precision = train_data['train_precision']
train_recall = train_data['train_recall']
train_f1 = train_data['train_f1']

test_loss = train_data['test_loss']
test_acc = train_data['test_acc']
test_precision = train_data['test_precision']
test_recall = train_data['test_recall']
test_f1 = train_data['test_f1']

# 获取训练的 epoch 数量
epochs = len(train_loss)

# 绘制损失、准确率、精确率、召回率和 F1 值曲线
plt.figure(figsize=(15, 10))  # 设置图表大小

# 绘制损失曲线
plt.subplot(2, 3, 1)
plt.plot(range(epochs), train_loss, label='Train Loss', color='blue', linestyle='-')
plt.plot(range(epochs), test_loss, label='Test Loss', color='red', linestyle='-')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training and Testing Loss')
plt.legend(loc='upper right')
plt.grid(True)

# 绘制准确率曲线
plt.subplot(2, 3, 2)
plt.plot(range(epochs), train_acc, label='Train Accuracy', color='green', linestyle='--')
plt.plot(range(epochs), test_acc, label='Test Accuracy', color='orange', linestyle='--')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Training and Testing Accuracy')
plt.legend(loc='lower right')
plt.grid(True)

# 绘制精确率曲线
plt.subplot(2, 3, 3)
plt.plot(range(epochs), train_precision, label='Train Precision', color='purple', linestyle='-')
plt.plot(range(epochs), test_precision, label='Test Precision', color='brown', linestyle='-')
plt.xlabel('Epoch')
plt.ylabel('Precision')
plt.title('Training and Testing Precision')
plt.legend(loc='lower right')
plt.grid(True)

# 绘制召回率曲线
plt.subplot(2, 3, 4)
plt.plot(range(epochs), train_recall, label='Train Recall', color='cyan', linestyle='--')
plt.plot(range(epochs), test_recall, label='Test Recall', color='magenta', linestyle='--')
plt.xlabel('Epoch')
plt.ylabel('Recall')
plt.title('Training and Testing Recall')
plt.legend(loc='lower right')
plt.grid(True)

# 绘制 F1 值曲线
plt.subplot(2, 3, 5)
plt.plot(range(epochs), train_f1, label='Train F1', color='lime', linestyle='-')
plt.plot(range(epochs), test_f1, label='Test F1', color='olive', linestyle='-')
plt.xlabel('Epoch')
plt.ylabel('F1 Score')
plt.title('Training and Testing F1 Score')
plt.legend(loc='lower right')
plt.grid(True)

plt.tight_layout()  # 调整布局
plt.show()

四、feature map图

feature map(特征图):在cnn的每个卷积层,数据都是以三维形式存在的。你可以把它看成许多个二维图片叠在一起(像豆腐皮一样),其中每一个称为一个feature map。

输入层:在输入层,如果是灰度图片,那就只有一个feature map;

如果是彩色图片,一般就是3个feature map(红绿蓝)。

其它层:层与层之间会有若干个卷积核(kernel)(也称为过滤器),上一层每个feature map跟每个卷积核做卷积,都会产生下一层的一个feature map,有N个卷积核,下层就会产生N个feather map。

如何计算?

主要由卷积和池化层

  • 卷积层计算
    • 卷积核滑动:在卷积层中,通过将卷积核在输入数据上进行滑动,对每个位置进行卷积操作。卷积核的大小通常为奇数,如\(3\times3\)、\(5\times5\)等,它代表了在输入数据的局部区域上进行特征提取的窗口。
    • 计算方式:对于输入的二维图像数据(假设通道数为C),卷积核的通道数也为C,且具有一定的深度K(即卷积核的个数)。在滑动过程中,卷积核与输入数据对应位置的元素相乘并求和,得到输出特征图上的一个像素值。具体来说,对于输入特征图X,卷积核W,输出特征图Y,在位置(i,j)处的计算为,其中m和n是卷积核内元素的坐标,c是通道索引。
    • 偏置与激活:在完成上述计算后,通常会为每个卷积核添加一个偏置项b,然后将结果通过一个激活函数,如 ReLU(Rectified Linear Unit)函数\(f(x)=\max(0, x)\),得到最终的特征图。即。
    • 池化层计算
      • 作用与方式:池化层主要用于对卷积层得到的特征图进行下采样,以减少数据量和计算量,同时保留主要的特征信息。常见的池化方式有最大池化(Max Pooling)和平均池化(Average Pooling)。
      • 最大池化计算:最大池化是在一个固定大小的池化窗口内取最大值作为输出。例如,池化窗口大小为\(2\times2\),步长为2,则将特征图划分为若干个\(2\times2\)的小块,每个小块中取最大值作为该区域池化后的结果,从而得到下采样后的特征图。
      • 平均池化计算:平均池化则是在池化窗口内计算平均值作为输出。同样以\(2\times2\)的池化窗口为例,将每个小块内的元素值求平均,得到池化后的特征图。

示例代码

import os
import torch
import torchvision
import torch.nn as nn
from torchvision import datasets, transforms
import torch.nn.functional as F
import matplotlib.pyplot as plt


# 数据预处理
transformation = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))  # MNIST是单通道图像,均值和标准差为(0.5,)
])

# 加载MNIST数据集
train_dataset = torchvision.datasets.MNIST('data',
                                           train=True,
                                           transform=transformation,
                                           download=True)

test_dataset = torchvision.datasets.MNIST('data',
                                          train=False,
                                          transform=transformation,
                                          download=True)

# 创建数据加载器
train_dl = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dl = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=True)

# 构建CNN模型
class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, 5)  # 输入通道1,输出通道6,卷积核大小5x5
        self.conv2 = nn.Conv2d(6, 16, 3)  # 输入通道6,输出通道16,卷积核大小3x3
        self.pool = nn.MaxPool2d((2, 2))  # 最大池化层,2x2
        self.linear_1 = nn.Linear(16 * 5 * 5, 256)  # 全连接层,输入16*5*5,输出256
        self.linear_2 = nn.Linear(256, 10)  # 全连接层,输入256,输出10(10个类别)

    def forward(self, input):
        x = F.relu(self.conv1(input))  # 卷积层1 + ReLU激活
        conv1_output = x
        x = self.pool(x)  # 池化层
        x = F.relu(self.conv2(x))  # 卷积层2 + ReLU激活
        conv2_output = x
        x = self.pool(x)  # 池化层
        x = x.view(x.size(0), -1)  # 展平操作,将多维张量展平为一维
        x = F.relu(self.linear_1(x))  # 全连接层1 + ReLU激活
        x = self.linear_2(x)  # 全连接层2
        return x, conv1_output, conv2_output


# 选择设备
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = Model().to(device)
loss_fn = torch.nn.CrossEntropyLoss()  # 交叉熵损失函数
opt = torch.optim.SGD(model.parameters(), lr=0.001)  # 随机梯度下降优化器

# 训练函数
def train(dl, model, loss_fn, optimizer):
    size = len(dl.dataset)  # 数据集的大小
    num_batches = len(dl)

    train_loss, correct = 0, 0

    for x, y in dl:
        x, y = x.to(device), y.to(device)
        pred, _, _ = model(x)
        loss = loss_fn(pred, y)
        optimizer.zero_grad()  # 梯度清零
        loss.backward()
        optimizer.step()
        with torch.no_grad():
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()
            train_loss += loss.item()
    correct /= size
    train_loss /= num_batches
    return correct, train_loss


# 测试函数
def test(test_dl, model, loss_fn):
    size = len(test_dl.dataset)  # 数据集的大小
    num_batches = len(test_dl)

    test_loss, correct = 0, 0

    with torch.no_grad():
        for x, y in test_dl:
            x, y = x.to(device), y.to(device)
            pred, _, _ = model(x)
            loss = loss_fn(pred, y)
            test_loss += loss.item()
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()
        correct /= size
        test_loss /= num_batches
        return correct, test_loss


# 创建保存模型的目录
if not os.path.exists('saved_models'):
    os.makedirs('saved_models')

# 创建保存训练数据的目录
if not os.path.exists('saved_data'):
    os.makedirs('saved_data')

# 训练和测试循环
def fit(epochs, train_dl, test_dl, model, loss_fn, opt):
    train_loss = []
    train_acc = []
    test_loss = []
    test_acc = []
    for epoch in range(epochs):
        epoch_acc, epoch_loss = train(train_dl, model, loss_fn, opt)
        epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)

        train_loss.append(epoch_loss)
        train_acc.append(epoch_acc)

        test_loss.append(epoch_test_loss)
        test_acc.append(epoch_test_acc)

        template = ("epoch:{:2d},train_loss:{:.5f},train_acc:{:.1f},test_loss:{:.5f},test_acc:{:.1f}")
        print(template.format(epoch, epoch_loss, epoch_acc * 100, epoch_test_loss, epoch_test_acc * 100))

    # 保存模型
    model_path = 'saved_models/mnist_cnn_model.pth'
    torch.save(model.state_dict(), model_path)
    print(f"Model saved to {model_path}")

    # 保存训练数据
    train_data = {
        'train_loss': train_loss,
        'train_acc': train_acc,
        'test_loss': test_loss,
        'test_acc': test_acc
    }
    data_path = 'saved_data/training_data.pth'
    torch.save(train_data, data_path)
    print(f"Training data saved to {data_path}")

    print("=============Done===============")
    return train_loss, train_acc, test_loss, test_acc


# 生成特征图
def generate_feature_maps(model, test_dl, device):
    with torch.no_grad():
        for x, y in test_dl:
            x, y = x.to(device), y.to(device)
            _, conv1_output, conv2_output = model(x)

            # 选择第一个样本的特征图
            conv1_output = conv1_output[0].cpu().numpy()
            conv2_output = conv2_output[0].cpu().numpy()

            # 绘制第一个卷积层的特征图
            num_filters_conv1 = conv1_output.shape[0]
            fig, axes = plt.subplots(1, num_filters_conv1, figsize=(num_filters_conv1, 1))
            for i in range(num_filters_conv1):
                axes[i].imshow(conv1_output[i], cmap='gray')
                axes[i].axis('off')
            plt.savefig('saved_data/conv1_feature_maps.png')
            plt.close()

            # 绘制第二个卷积层的特征图
            num_filters_conv2 = conv2_output.shape[0]
            fig, axes = plt.subplots(2, num_filters_conv2 // 2, figsize=(num_filters_conv2 // 2, 2))
            axes = axes.flatten()
            for i in range(num_filters_conv2):
                axes[i].imshow(conv2_output[i], cmap='gray')
                axes[i].axis('off')
            plt.savefig('saved_data/conv2_feature_maps.png')
            plt.close()
            break


# 开始训练
train_loss, train_acc, test_loss, test_acc = fit(50, train_dl, test_dl, model, loss_fn, opt)

# 生成特征图
generate_feature_maps(model, test_dl, device)
    

结果:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值