网站 后台 设计,wordpress回复显示插件,企业信用信息查询系统,南部县网站建设DAY 54 Inception网络及其思考 知识点回顾#xff1a; 传统计算机视觉发展史#xff1a;LeNet--AlexNet--VGGNet--inceptionNet--ResNet 之所以说传统#xff0c;是因为现在主要是针对backbone-neck-head这样的范式做文章 inception模块和网络特征融合方法… DAY 54 Inception网络及其思考 知识点回顾 传统计算机视觉发展史LeNet--AlexNet--VGGNet--inceptionNet--ResNet 之所以说传统是因为现在主要是针对backbone-neck-head这样的范式做文章 inception模块和网络特征融合方法阶段性总结逐元素相加、逐元素相乘、concat通道数增加等感受野与卷积核变体深入理解不同模块和类的设计初衷 作业一次稍微有点学术感觉的作业 对inception网络在cifar10上观察精度消融实验引入残差机制和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], axis1)
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_size0.2, random_state42, stratifyy)
# stratifyy 确保训练集和测试集中目标变量的比例与原始数据集相同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_state42, solverliblinear) # solverliblinear 对小数据集表现好
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_dimz_dim))model.add(layers.LeakyReLU(alpha0.2))model.add(layers.BatchNormalization(momentum0.8)) # 批归一化有助于训练稳定model.add(layers.Dense(512))model.add(layers.LeakyReLU(alpha0.2))model.add(layers.BatchNormalization(momentum0.8))model.add(layers.Dense(data_dim, activationtanh)) # tanh激活函数使输出在[-1, 1]范围内与MinMaxScaler对应return model# --- 定义判别器 Discriminator ---
def build_discriminator(data_dim):model models.Sequential()model.add(layers.Dense(512, input_dimdata_dim))model.add(layers.LeakyReLU(alpha0.2))model.add(layers.Dropout(0.3)) # Dropout有助于防止过拟合model.add(layers.Dense(256))model.add(layers.LeakyReLU(alpha0.2))model.add(layers.Dropout(0.3))model.add(layers.Dense(1, activationsigmoid)) # sigmoid激活函数输出0到1之间的概率return model# 构建并编译判别器
discriminator build_discriminator(data_dim)
discriminator.compile(lossbinary_crossentropy, optimizeroptimizers.Adam(learning_rate0.0002, beta_10.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(lossbinary_crossentropy, optimizeroptimizers.Adam(learning_rate0.0002, beta_10.5))print(\n--- 开始训练GAN ---)
print(fGAN 将生成 {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(fEpoch {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) # 它们都是target1# 将生成的样本添加到少数类训练数据中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_state42, solverliblinear)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, labelDiscriminator Loss)
plt.plot(g_losses, labelGenerator 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, padding4),# 随机水平翻转图像概率0.5transforms.RandomHorizontalFlip(),# 随机颜色抖动亮度、对比度、饱和度和色调随机变化transforms.ColorJitter(brightness0.2, contrast0.2, saturation0.2, hue0.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,trainTrue,downloadTrue,transformtrain_transform # 使用增强后的预处理
)test_dataset datasets.CIFAR10(root./data,trainFalse,transformtest_transform # 测试集不使用增强
)# 3. 创建数据加载器
batch_size 128 #优化调参点 由64 ————》128
train_loader DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue)
test_loader DataLoader(test_dataset, batch_sizebatch_size, shuffleFalse)# 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_size1), # 降维至64通道nn.ReLU() # 引入非线性激活)# 3x3卷积分支通过1x1卷积降维后使用3x3卷积捕捉中等尺度特征# 先降维减少计算量再进行空间特征提取self.branch3x3 nn.Sequential(nn.Conv2d(in_channels, 96, kernel_size1), # 降维至96通道nn.ReLU(),nn.Conv2d(96, 128, kernel_size3, padding1), # 3x3卷积保持空间尺寸不变nn.ReLU())# 5x5卷积分支通过1x1卷积降维后使用5x5卷积捕捉大尺度特征# 较大的感受野用于提取更全局的结构信息self.branch5x5 nn.Sequential(nn.Conv2d(in_channels, 16, kernel_size1), # 大幅降维至16通道nn.ReLU(),nn.Conv2d(16, 32, kernel_size5, padding2), # 5x5卷积保持空间尺寸不变nn.ReLU())# 池化分支通过池化操作保留全局信息并降维# 增强特征的平移不变性self.branch_pool nn.Sequential(nn.MaxPool2d(kernel_size3, stride1, padding1), # 3x3最大池化保持尺寸nn.Conv2d(in_channels, 32, kernel_size1), # 降维至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]# 在通道维度(dim1)拼接四个分支的输出# 总通道数: 64 128 32 32 256outputs [branch1x1, branch3x3, branch5x5, branch_pool]return torch.cat(outputs, dim1)class InceptionNet(nn.Module):def __init__(self, num_classes10):super(InceptionNet, self).__init__()self.conv1 nn.Sequential(nn.Conv2d(3, 64, kernel_size7, stride2, padding3),nn.ReLU(),nn.MaxPool2d(kernel_size3, stride2, padding1))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(), lr0.001)# 引入学习率调度器在训练过程中动态调整学习率--训练初期使用较大的 LR 快速降低损失训练后期使用较小的 LR 更精细地逼近全局最优解。
# 在每个 epoch 结束后需要手动调用调度器来更新学习率可以在训练过程中调用 scheduler.step()
scheduler optim.lr_scheduler.ReduceLROnPlateau(optimizer, # 指定要控制的优化器这里是Adammodemin, # 监测的指标是最小化如损失函数patience3, # 如果连续3个epoch指标没有改善才降低LRfactor0.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(fEpoch: {epoch1}/{epochs} | Batch: {batch_idx1}/{len(train_loader)} f| 单Batch损失: {iter_loss:.4f} | 累计平均损失: {running_loss/(batch_idx1):.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(fEpoch {epoch1}/{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-, alpha0.7, labelIteration Loss)plt.xlabel(IterationBatch序号)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, padding4),transforms.RandomHorizontalFlip(),transforms.ColorJitter(brightness0.2, contrast0.2, saturation0.2, hue0.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, trainTrue, downloadTrue, transformtrain_transform)
test_dataset datasets.CIFAR10(root./data, trainFalse, transformtest_transform)# 数据加载器
batch_size 128
train_loader DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue)
test_loader DataLoader(test_dataset, batch_sizebatch_size, shuffleFalse)# 原始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, padding1), nn.ReLU())self.branch5x5 nn.Sequential(nn.Conv2d(in_channels, 16, 1), nn.ReLU(),nn.Conv2d(16, 32, 5, padding2), nn.ReLU())self.branch_pool nn.Sequential(nn.MaxPool2d(3, stride1, padding1),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, reduction16):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, padding3)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, dim1, keepdimTrue)max_out, _ torch.max(x, dim1, keepdimTrue)spatial torch.cat([avg_out, max_out], dim1)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, stride2, padding3), nn.ReLU(),nn.MaxPool2d(3, stride2, padding1))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, stride2, padding3), nn.ReLU(),nn.MaxPool2d(3, stride2, padding1))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, stride2, padding3), nn.ReLU(),nn.MaxPool2d(3, stride2, padding1))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, epochs20):model model.to(device)criterion nn.CrossEntropyLoss()optimizer optim.Adam(model.parameters(), lr0.001)scheduler optim.lr_scheduler.ReduceLROnPlateau(optimizer, min, patience3, factor0.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 {epoch1}/{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], labelname)
plt.title(训练损失对比)
plt.xlabel(Epoch)
plt.ylabel(Loss)
plt.legend()plt.subplot(1,2,2)
for name in models:plt.plot(results[name][1], labelname)
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博客