当前位置: 首页 > news >正文

Python打卡训练营Day54

DAY 54 Inception网络及其思考

知识点回顾:

  1. 传统计算机视觉发展史:LeNet-->AlexNet-->VGGNet-->inceptionNet-->ResNet

之所以说传统,是因为现在主要是针对backbone-neck-head这样的范式做文章

  1. inception模块和网络
  2. 特征融合方法阶段性总结:逐元素相加、逐元素相乘、concat通道数增加等
  3. 感受野与卷积核变体:深入理解不同模块和类的设计初衷

作业:一次稍微有点学术感觉的作业:

  1. 对inception网络在cifar10上观察精度
  2. 消融实验:引入残差机制和cbam模块分别进行消融

昨天GAN代码补充

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, f1_score
import tensorflow as tf
from tensorflow.keras import layers, models, optimizers# 设置中文显示和负号
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False# 加载数据
dt = pd.read_csv('heart.csv')print("--- 原始数据信息 ---")
dt.info()
print("\n")
print("--- 原始数据前5行 ---")
print(dt.head())
print("\n")# 检查目标变量分布
print("--- 原始目标变量分布 ---")
print(dt['target'].value_counts())
print("\n")# 分离特征和目标
X = dt.drop(['target'], axis=1)
y = dt['target']# 数据缩放到 [-1, 1]
# 注意:MinMaxScaler的fit_transform应该在X上进行,以确保所有特征都被正确缩放
# 如果在X_scaled上fit,可能导致数据泄露
scaler = MinMaxScaler(feature_range=(-1, 1))
X_scaled = scaler.fit_transform(X)# 划分数据集 (使用缩放后的数据进行划分)
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42, stratify=y)
# stratify=y 确保训练集和测试集中目标变量的比例与原始数据集相同print("--- 训练集和测试集划分后目标变量分布 ---")
print("训练集 target 分布:\n", y_train.value_counts())
print("测试集 target 分布:\n", y_test.value_counts())
print("\n")# --- 1. 不使用GAN的原始模型表现 ---
print("--- 1. 不使用GAN增强数据的模型表现 ---")
model_original = LogisticRegression(random_state=42, solver='liblinear') # solver='liblinear' 对小数据集表现好
model_original.fit(X_train, y_train)y_pred_original = model_original.predict(X_test)accuracy_original = accuracy_score(y_test, y_pred_original)
f1_original = f1_score(y_test, y_pred_original)print(f'原始数据 (不使用GAN) 准确率: {accuracy_original:.4f}')
print(f'原始数据 (不使用GAN) F1分数: {f1_original:.4f}')
print("\n")# --- 2. 使用GAN增强少数类数据 ---# 提取训练集中的少数类数据 (target = 1)
X_train_minority = X_train[y_train == 1]
print(f"训练集中少数类样本数量: {X_train_minority.shape[0]}")# 定义GAN参数
z_dim = 100  # 噪声向量维度
data_dim = X_train.shape[1] # 数据特征维度
epochs = 1000 # GAN训练轮次,可能需要调整
batch_size = 32 # GAN训练批次大小# --- 定义生成器 Generator ---
def build_generator(z_dim, data_dim):model = models.Sequential()model.add(layers.Dense(256, input_dim=z_dim))model.add(layers.LeakyReLU(alpha=0.2))model.add(layers.BatchNormalization(momentum=0.8)) # 批归一化有助于训练稳定model.add(layers.Dense(512))model.add(layers.LeakyReLU(alpha=0.2))model.add(layers.BatchNormalization(momentum=0.8))model.add(layers.Dense(data_dim, activation='tanh')) # tanh激活函数使输出在[-1, 1]范围内,与MinMaxScaler对应return model# --- 定义判别器 Discriminator ---
def build_discriminator(data_dim):model = models.Sequential()model.add(layers.Dense(512, input_dim=data_dim))model.add(layers.LeakyReLU(alpha=0.2))model.add(layers.Dropout(0.3)) # Dropout有助于防止过拟合model.add(layers.Dense(256))model.add(layers.LeakyReLU(alpha=0.2))model.add(layers.Dropout(0.3))model.add(layers.Dense(1, activation='sigmoid')) # sigmoid激活函数输出0到1之间的概率return model# 构建并编译判别器
discriminator = build_discriminator(data_dim)
discriminator.compile(loss='binary_crossentropy', optimizer=optimizers.Adam(learning_rate=0.0002, beta_1=0.5), metrics=['accuracy'])# 构建生成器
generator = build_generator(z_dim, data_dim)# 构建GAN (生成器 + 判别器)
# 训练生成器时,判别器的权重不更新
discriminator.trainable = False
gan_input = layers.Input(shape=(z_dim,))
fake_data = generator(gan_input)
gan_output = discriminator(fake_data)
gan = models.Model(gan_input, gan_output)
gan.compile(loss='binary_crossentropy', optimizer=optimizers.Adam(learning_rate=0.0002, beta_1=0.5))print("\n--- 开始训练GAN ---")
print(f"GAN 将生成 {X_train_minority.shape[0]} 个少数类样本作为真实样本进行学习。")d_losses = []
g_losses = []for epoch in range(epochs):# --- 训练判别器 ---# 随机选择真实少数类样本批次idx = np.random.randint(0, X_train_minority.shape[0], batch_size)real_data_batch = X_train_minority[idx]# 生成噪声向量noise = np.random.normal(0, 1, size=(batch_size, z_dim))# 生成虚假样本fake_data_batch = generator.predict(noise)# 判别器训练标签# 对真实样本使用平滑标签 (0.9) 以提高稳定性real_labels = np.ones((batch_size, 1)) * 0.9fake_labels = np.zeros((batch_size, 1))# 训练判别器d_loss_real = discriminator.train_on_batch(real_data_batch, real_labels)d_loss_fake = discriminator.train_on_batch(fake_data_batch, fake_labels)d_loss = 0.5 * np.add(d_loss_real, d_loss_fake) # 平均损失# --- 训练生成器 ---# 生成噪声向量作为生成器输入noise = np.random.normal(0, 1, size=(batch_size, z_dim))# 生成器希望判别器将其生成的数据识别为真实 (标签为1)misleading_targets = np.ones((batch_size, 1))# 训练GAN (通过gan模型训练生成器)g_loss = gan.train_on_batch(noise, misleading_targets)# 记录损失d_losses.append(d_loss[0])g_losses.append(g_loss)# 打印进度if epoch % 500 == 0:print(f"Epoch {epoch}/{epochs} | D_loss: {d_loss[0]:.4f}, D_acc: {d_loss[1]:.4f} | G_loss: {g_loss:.4f}")print("\n--- GAN训练完成 ---")# --- 3. 生成新的少数类样本并进行数据增强 ---# 计算需要生成的少数类样本数量
count_majority = (y_train == 0).sum()
count_minority_original = (y_train == 1).sum()
num_samples_to_generate = count_majority - count_minority_originalif num_samples_to_generate > 0:print(f"\n需要生成 {num_samples_to_generate} 个新的少数类样本以平衡训练集。")# 生成足够数量的噪声noise_for_generation = np.random.normal(0, 1, size=(num_samples_to_generate, z_dim))# 使用训练好的生成器生成新样本generated_X_minority = generator.predict(noise_for_generation)generated_y_minority = np.ones(num_samples_to_generate) # 它们都是target=1# 将生成的样本添加到少数类训练数据中X_train_minority_augmented = np.vstack((X_train_minority, generated_X_minority))y_train_minority_augmented = np.concatenate((y_train[y_train == 1].values, generated_y_minority))# 获取多数类数据X_train_majority = X_train[y_train == 0]y_train_majority = y_train[y_train == 0].values# 合并增强后的少数类数据和原始多数类数据X_train_augmented = np.vstack((X_train_majority, X_train_minority_augmented))y_train_augmented = np.concatenate((y_train_majority, y_train_minority_augmented))print("--- 增强后训练集目标变量分布 ---")print("增强后训练集 target 0 数量:", (y_train_augmented == 0).sum())print("增强后训练集 target 1 数量:", (y_train_augmented == 1).sum())print("\n")# --- 4. 使用增强数据重新训练模型并评估 ---print("--- 2. 使用GAN增强数据后的模型表现 ---")model_augmented = LogisticRegression(random_state=42, solver='liblinear')model_augmented.fit(X_train_augmented, y_train_augmented)y_pred_augmented = model_augmented.predict(X_test)accuracy_augmented = accuracy_score(y_test, y_pred_augmented)f1_augmented = f1_score(y_test, y_pred_augmented)print(f'增强数据 (使用GAN) 准确率: {accuracy_augmented:.4f}')print(f'增强数据 (使用GAN) F1分数: {f1_augmented:.4f}')else:print("\n多数类和少数类已平衡或少数类更多,无需生成样本。")accuracy_augmented = accuracy_originalf1_augmented = f1_originalprint("模型表现与原始数据模型表现相同。")# --- 结果对比 ---
print("\n--- F1分数对比 ---")
print(f'原始数据 (不使用GAN) F1分数: {f1_original:.4f}')
print(f'增强数据 (使用GAN) F1分数: {f1_augmented:.4f}')# 可视化GAN训练损失 (可选)
plt.figure(figsize=(10, 5))
plt.plot(d_losses, label='Discriminator Loss')
plt.plot(g_losses, label='Generator Loss')
plt.title('GAN Training Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.grid(True)
plt.show()

数据集选择不太好哈哈,如果强行使用只会越来越拉。

今日代码:

# !!! inception网络在cifar10上观察精度 !!!import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np# 设置中文字体支持
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题# 检查GPU是否可用
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"使用设备: {device}")# 1. 数据预处理
# 训练集:使用多种数据增强方法提高模型泛化能力
train_transform = transforms.Compose([# 随机裁剪图像,从原图中随机截取32x32大小的区域transforms.RandomCrop(32, padding=4),# 随机水平翻转图像(概率0.5)transforms.RandomHorizontalFlip(),# 随机颜色抖动:亮度、对比度、饱和度和色调随机变化transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),# 随机旋转图像(最大角度15度)transforms.RandomRotation(15),# 将PIL图像或numpy数组转换为张量transforms.ToTensor(),# 标准化处理:每个通道的均值和标准差,使数据分布更合理transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])# 测试集:仅进行必要的标准化,保持数据原始特性,标准化不损失数据信息,可还原
test_transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])# 2. 加载CIFAR-10数据集
train_dataset = datasets.CIFAR10(root='./data',train=True,download=True,transform=train_transform  # 使用增强后的预处理
)test_dataset = datasets.CIFAR10(root='./data',train=False,transform=test_transform  # 测试集不使用增强
)# 3. 创建数据加载器
batch_size = 128 #优化调参点 由64 ————》128
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)# 4. 定义inceptionnet
class Inception(nn.Module):def __init__(self, in_channels):"""Inception模块初始化,实现多尺度特征并行提取与融合参数:in_channels: 输入特征图的通道数"""super(Inception, self).__init__()# 1x1卷积分支:降维并提取通道间特征关系# 减少后续卷积的计算量,同时保留局部特征信息self.branch1x1 = nn.Sequential(nn.Conv2d(in_channels, 64, kernel_size=1),  # 降维至64通道nn.ReLU()  # 引入非线性激活)# 3x3卷积分支:通过1x1卷积降维后使用3x3卷积捕捉中等尺度特征# 先降维减少计算量,再进行空间特征提取self.branch3x3 = nn.Sequential(nn.Conv2d(in_channels, 96, kernel_size=1),  # 降维至96通道nn.ReLU(),nn.Conv2d(96, 128, kernel_size=3, padding=1),  # 3x3卷积,保持空间尺寸不变nn.ReLU())# 5x5卷积分支:通过1x1卷积降维后使用5x5卷积捕捉大尺度特征# 较大的感受野用于提取更全局的结构信息self.branch5x5 = nn.Sequential(nn.Conv2d(in_channels, 16, kernel_size=1),  # 大幅降维至16通道nn.ReLU(),nn.Conv2d(16, 32, kernel_size=5, padding=2),  # 5x5卷积,保持空间尺寸不变nn.ReLU())# 池化分支:通过池化操作保留全局信息并降维# 增强特征的平移不变性self.branch_pool = nn.Sequential(nn.MaxPool2d(kernel_size=3, stride=1, padding=1),  # 3x3最大池化,保持尺寸nn.Conv2d(in_channels, 32, kernel_size=1),  # 降维至32通道nn.ReLU())def forward(self, x):"""前向传播函数,并行计算四个分支并在通道维度拼接参数:x: 输入特征图,形状为[batch_size, in_channels, height, width]返回:拼接后的特征图,形状为[batch_size, 256, height, width]"""# 注意,这里是并行计算四个分支branch1x1 = self.branch1x1(x)  # 输出形状: [batch_size, 64, height, width]branch3x3 = self.branch3x3(x)  # 输出形状: [batch_size, 128, height, width]branch5x5 = self.branch5x5(x)  # 输出形状: [batch_size, 32, height, width]branch_pool = self.branch_pool(x)  # 输出形状: [batch_size, 32, height, width]# 在通道维度(dim=1)拼接四个分支的输出# 总通道数: 64 + 128 + 32 + 32 = 256outputs = [branch1x1, branch3x3, branch5x5, branch_pool]return torch.cat(outputs, dim=1)class InceptionNet(nn.Module):def __init__(self, num_classes=10):super(InceptionNet, self).__init__()self.conv1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2, padding=1))self.inception1 = Inception(64)self.inception2 = Inception(256)self.avgpool = nn.AdaptiveAvgPool2d((1, 1))self.fc = nn.Linear(256, num_classes)def forward(self, x):x = self.conv1(x)x = self.inception1(x)x = self.inception2(x)x = self.avgpool(x)x = torch.flatten(x, 1)x = self.fc(x)return x# 实例化
model = InceptionNet()
model = model.to(device)  # 将模型移至GPU(如果可用)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)# 引入学习率调度器,在训练过程中动态调整学习率--训练初期使用较大的 LR 快速降低损失,训练后期使用较小的 LR 更精细地逼近全局最优解。
# 在每个 epoch 结束后,需要手动调用调度器来更新学习率,可以在训练过程中调用 scheduler.step()
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer,        # 指定要控制的优化器(这里是Adam)mode='min',       # 监测的指标是"最小化"(如损失函数)patience=3,       # 如果连续3个epoch指标没有改善,才降低LRfactor=0.5       # 降低LR的比例(新LR = 旧LR × 0.5)
)# 5. 训练模型(记录每个 iteration 的损失)
def train(model, train_loader, test_loader, criterion, optimizer, scheduler, device, epochs):model.train()  # 设置为训练模式# 记录每个 iteration 的损失all_iter_losses = []  # 存储所有 batch 的损失iter_indices = []     # 存储 iteration 序号# 记录每个 epoch 的准确率和损失train_acc_history = []test_acc_history = []train_loss_history = []test_loss_history = []for epoch in range(epochs):running_loss = 0.0correct = 0total = 0for batch_idx, (data, target) in enumerate(train_loader):data, target = data.to(device), target.to(device)  # 移至GPUoptimizer.zero_grad()  # 梯度清零output = model(data)  # 前向传播loss = criterion(output, target)  # 计算损失loss.backward()  # 反向传播optimizer.step()  # 更新参数# 记录当前 iteration 的损失iter_loss = loss.item()all_iter_losses.append(iter_loss)iter_indices.append(epoch * len(train_loader) + batch_idx + 1)# 统计准确率和损失running_loss += iter_loss_, predicted = output.max(1)total += target.size(0)correct += predicted.eq(target).sum().item()# 每100个批次打印一次训练信息if (batch_idx + 1) % 100 == 0:print(f'Epoch: {epoch+1}/{epochs} | Batch: {batch_idx+1}/{len(train_loader)} 'f'| 单Batch损失: {iter_loss:.4f} | 累计平均损失: {running_loss/(batch_idx+1):.4f}')# 计算当前epoch的平均训练损失和准确率epoch_train_loss = running_loss / len(train_loader)epoch_train_acc = 100. * correct / totaltrain_acc_history.append(epoch_train_acc)train_loss_history.append(epoch_train_loss)# 测试阶段model.eval()  # 设置为评估模式test_loss = 0correct_test = 0total_test = 0with torch.no_grad():for data, target in test_loader:data, target = data.to(device), target.to(device)output = model(data)test_loss += criterion(output, target).item()_, predicted = output.max(1)total_test += target.size(0)correct_test += predicted.eq(target).sum().item()epoch_test_loss = test_loss / len(test_loader)epoch_test_acc = 100. * correct_test / total_testtest_acc_history.append(epoch_test_acc)test_loss_history.append(epoch_test_loss)# 更新学习率调度器scheduler.step(epoch_test_loss)print(f'Epoch {epoch+1}/{epochs} 完成 | 训练准确率: {epoch_train_acc:.2f}% | 测试准确率: {epoch_test_acc:.2f}%')# 绘制所有 iteration 的损失曲线plot_iter_losses(all_iter_losses, iter_indices)# 绘制每个 epoch 的准确率和损失曲线plot_epoch_metrics(train_acc_history, test_acc_history, train_loss_history, test_loss_history)return epoch_test_acc  # 返回最终测试准确率# 6. 绘制每个 iteration 的损失曲线
def plot_iter_losses(losses, indices):plt.figure(figsize=(10, 4))plt.plot(indices, losses, 'b-', alpha=0.7, label='Iteration Loss')plt.xlabel('Iteration(Batch序号)')plt.ylabel('损失值')plt.title('每个 Iteration 的训练损失')plt.legend()plt.grid(True)plt.tight_layout()plt.show()# 7. 绘制每个 epoch 的准确率和损失曲线
def plot_epoch_metrics(train_acc, test_acc, train_loss, test_loss):epochs = range(1, len(train_acc) + 1)plt.figure(figsize=(12, 4))# 绘制准确率曲线plt.subplot(1, 2, 1)plt.plot(epochs, train_acc, 'b-', label='训练准确率')plt.plot(epochs, test_acc, 'r-', label='测试准确率')plt.xlabel('Epoch')plt.ylabel('准确率 (%)')plt.title('训练和测试准确率')plt.legend()plt.grid(True)# 绘制损失曲线plt.subplot(1, 2, 2)plt.plot(epochs, train_loss, 'b-', label='训练损失')plt.plot(epochs, test_loss, 'r-', label='测试损失')plt.xlabel('Epoch')plt.ylabel('损失值')plt.title('训练和测试损失')plt.legend()plt.grid(True)plt.tight_layout()plt.show()# 8. 执行训练和测试
epochs = 30  # 增加训练轮次以获得更好效果 优化调参 20 ————》30
print("开始使用inception网络训练模型...")
final_accuracy = train(model, train_loader, test_loader, criterion, optimizer, scheduler, device, epochs)
print(f"训练完成!最终测试准确率: {final_accuracy:.2f}%")# # 保存模型
# torch.save(model.state_dict(), 'cifar10_cnn_model.pth')
# print("模型已保存为: cifar10_cnn_model.pth")
Epoch 30/30 完成 | 训练准确率: 78.89% | 测试准确率: 79.53%

相比简单CNN好像没有很大的提升。

# !!! 引入cbam模块和残差网络并分别做消融实验 !!!
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt# 设备配置
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"使用设备: {device}")# 数据预处理
train_transform = transforms.Compose([transforms.RandomCrop(32, padding=4),transforms.RandomHorizontalFlip(),transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),transforms.RandomRotation(15),transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])test_transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])# 加载数据集
train_dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=train_transform)
test_dataset = datasets.CIFAR10(root='./data', train=False, transform=test_transform)# 数据加载器
batch_size = 128
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)# 原始Inception模块
class Inception(nn.Module):def __init__(self, in_channels):super(Inception, self).__init__()self.branch1x1 = nn.Sequential(nn.Conv2d(in_channels, 64, 1), nn.ReLU())self.branch3x3 = nn.Sequential(nn.Conv2d(in_channels, 96, 1), nn.ReLU(),nn.Conv2d(96, 128, 3, padding=1), nn.ReLU())self.branch5x5 = nn.Sequential(nn.Conv2d(in_channels, 16, 1), nn.ReLU(),nn.Conv2d(16, 32, 5, padding=2), nn.ReLU())self.branch_pool = nn.Sequential(nn.MaxPool2d(3, stride=1, padding=1),nn.Conv2d(in_channels, 32, 1), nn.ReLU())def forward(self, x):return torch.cat([self.branch1x1(x),self.branch3x3(x),self.branch5x5(x),self.branch_pool(x)], 1)# 残差Inception模块
class ResInception(nn.Module):def __init__(self, in_channels):super().__init__()self.inception = Inception(in_channels)self.res_conv = nn.Conv2d(in_channels, 256, 1) if in_channels != 256 else nn.Identity()self.relu = nn.ReLU()def forward(self, x):residual = self.res_conv(x)out = self.inception(x) + residualreturn self.relu(out)# CBAM模块
class CBAM(nn.Module):def __init__(self, channel, reduction=16):super().__init__()# 通道注意力self.avg_pool = nn.AdaptiveAvgPool2d(1)self.max_pool = nn.AdaptiveMaxPool2d(1)self.mlp = nn.Sequential(nn.Linear(channel, channel // reduction),nn.ReLU(),nn.Linear(channel // reduction, channel))# 空间注意力self.conv = nn.Conv2d(2, 1, 7, padding=3)def forward(self, x):# 通道注意力avg_out = self.mlp(self.avg_pool(x).squeeze())max_out = self.mlp(self.max_pool(x).squeeze())channel_att = torch.sigmoid(avg_out + max_out).unsqueeze(2).unsqueeze(3)x = x * channel_att.expand_as(x)# 空间注意力avg_out = torch.mean(x, dim=1, keepdim=True)max_out, _ = torch.max(x, dim=1, keepdim=True)spatial = torch.cat([avg_out, max_out], dim=1)spatial_att = torch.sigmoid(self.conv(spatial))return x * spatial_att# 带CBAM的Inception模块
class CBAMInception(nn.Module):def __init__(self, in_channels):super().__init__()self.inception = Inception(in_channels)self.cbam = CBAM(256)  # Inception输出256通道def forward(self, x):x = self.inception(x)return self.cbam(x)# 原始网络
class InceptionNet(nn.Module):def __init__(self):super().__init__()self.conv1 = nn.Sequential(nn.Conv2d(3, 64, 7, stride=2, padding=3), nn.ReLU(),nn.MaxPool2d(3, stride=2, padding=1))self.inception1 = Inception(64)self.inception2 = Inception(256)self.avgpool = nn.AdaptiveAvgPool2d((1,1))self.fc = nn.Linear(256, 10)def forward(self, x):x = self.conv1(x)x = self.inception1(x)x = self.inception2(x)x = self.avgpool(x)return self.fc(x.flatten(1))# 残差网络
class ResInceptionNet(nn.Module):def __init__(self):super().__init__()self.conv1 = nn.Sequential(nn.Conv2d(3, 64, 7, stride=2, padding=3), nn.ReLU(),nn.MaxPool2d(3, stride=2, padding=1))self.inception1 = ResInception(64)self.inception2 = ResInception(256)self.avgpool = nn.AdaptiveAvgPool2d((1,1))self.fc = nn.Linear(256, 10)def forward(self, x):x = self.conv1(x)x = self.inception1(x)x = self.inception2(x)x = self.avgpool(x)return self.fc(x.flatten(1))# CBAM网络
class CBAMInceptionNet(nn.Module):def __init__(self):super().__init__()self.conv1 = nn.Sequential(nn.Conv2d(3, 64, 7, stride=2, padding=3), nn.ReLU(),nn.MaxPool2d(3, stride=2, padding=1))self.inception1 = CBAMInception(64)self.inception2 = CBAMInception(256)self.avgpool = nn.AdaptiveAvgPool2d((1,1))self.fc = nn.Linear(256, 10)def forward(self, x):x = self.conv1(x)x = self.inception1(x)x = self.inception2(x)x = self.avgpool(x)return self.fc(x.flatten(1))# 训练函数
def train_model(model, name, epochs=20):model = model.to(device)criterion = nn.CrossEntropyLoss()optimizer = optim.Adam(model.parameters(), lr=0.001)scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min', patience=3, factor=0.5)train_loss = []test_acc = []for epoch in range(epochs):model.train()epoch_loss = 0for inputs, labels in train_loader:inputs, labels = inputs.to(device), labels.to(device)optimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()epoch_loss += loss.item()# 验证model.eval()total, correct = 0, 0with torch.no_grad():for inputs, labels in test_loader:inputs, labels = inputs.to(device), labels.to(device)outputs = model(inputs)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()avg_loss = epoch_loss / len(train_loader)acc = 100 * correct / totaltrain_loss.append(avg_loss)test_acc.append(acc)scheduler.step(avg_loss)print(f"{name} Epoch {epoch+1}/{epochs} | Loss: {avg_loss:.4f} | Acc: {acc:.2f}%")return train_loss, test_acc# 训练并比较三个模型
epochs = 20
models = {"原始模型": InceptionNet(),"残差模型": ResInceptionNet(),"CBAM模型": CBAMInceptionNet()
}results = {}
for name, model in models.items():print(f"\n开始训练 {name}")train_loss, test_acc = train_model(model, name, epochs)results[name] = (train_loss, test_acc)# 可视化结果
plt.figure(figsize=(12, 5))
plt.subplot(1,2,1)
for name in models:plt.plot(results[name][0], label=name)
plt.title('训练损失对比')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()plt.subplot(1,2,2)
for name in models:plt.plot(results[name][1], label=name)
plt.title('测试准确率对比')
plt.xlabel('Epoch')
plt.ylabel('Accuracy (%)')
plt.legend()plt.tight_layout()
plt.show()
原始模型 Epoch 20/20 | Loss: 0.7455 | Acc: 76.24%
残差模型 Epoch 20/20 | Loss: 0.7608 | Acc: 74.16%
CBAM模型 Epoch 20/20 | Loss: 0.7564 | Acc: 75.57%

绷不住了,结果没有像预想的那样。

实验报告小结:

浙大疏锦行-CSDN博客

相关文章:

  • 《仿盒马》app开发技术分享-- 回收金提现记录查询(端云一体)
  • C++题解(35) 2025年顺德区中小学生程序设计展示活动(初中组C++) 换位(一)
  • 1.1、WDM基础
  • pyhton基础【9】容器介绍四
  • 解析Buildroot
  • 自增id用完怎么办?
  • Oracle21cR3之客户端安装错误及处理方法
  • 京东API接口最新指南:店铺所有商品接口的接入与使用
  • Axure应用交互设计:多种类型元件实现新增中继器数据
  • 一个应用程序或移动网站项目提供最佳UI解决方案
  • UnityDots学习(六)
  • 【unitrix】 1.9 Z0与其它类型的算术运算(arith_ops.rs)
  • 李沐--动手学深度学习 LSTM
  • 前端错误捕获
  • 模板方法模式Template Method Pattern
  • 移动应用开发实验室web组大一下期末考核题解
  • Vela sensor uORB 框架学习
  • 适配器模式Adapter Pattern
  • Java中如何使用lambda表达式分类groupby
  • STL容器分类总结
  • 无锡做网站品牌公司/四川seo多少钱
  • 95资料库/南京seo代理
  • 小企业如何优化网站建设/seo基础教程
  • 做嫒嫒网站/网站设计制作在哪里找
  • 阿里云可以做电影网站/培训心得体会模板
  • 网站建设空间多大/网络营销的主要传播渠道