承德市网站建设_网站建设公司_代码压缩_seo优化
2026/1/8 21:48:51 网站建设 项目流程

@浙大疏锦行

import torch import torch.nn as nn import torch.nn.functional as F import torchvision import torchvision.transforms as transforms from torch.utils.data import DataLoader import matplotlib.pyplot as plt import numpy as np # 设置随机种子保证可重复性 torch.manual_seed(42) # 简单数据预处理 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ]) # 加载CIFAR-10数据集 trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform) trainloader = DataLoader(trainset, batch_size=64, shuffle=True) testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform) testloader = DataLoader(testset, batch_size=64, shuffle=False) # CIFAR-10类别 classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') # 带残差的Inception模块 class ResidualInceptionModule(nn.Module): def __init__(self, in_channels, use_residual=True): super(ResidualInceptionModule, self).__init__() self.use_residual = use_residual # 四个并行分支 # 1x1卷积分支 self.branch1x1 = nn.Conv2d(in_channels, 64, kernel_size=1) # 3x3卷积分支 self.branch3x3 = nn.Sequential( nn.Conv2d(in_channels, 48, kernel_size=1), nn.Conv2d(48, 64, kernel_size=3, padding=1) ) # 5x5卷积分支 self.branch5x5 = nn.Sequential( nn.Conv2d(in_channels, 32, kernel_size=1), nn.Conv2d(32, 32, kernel_size=3, padding=1), nn.Conv2d(32, 64, kernel_size=3, padding=1) ) # 池化分支 self.branch_pool = nn.Sequential( nn.MaxPool2d(kernel_size=3, stride=1, padding=1), nn.Conv2d(in_channels, 32, kernel_size=1) ) # 残差连接(如果需要调整通道数) if self.use_residual: if in_channels != 224: # 输出通道是64+64+64+32=224 self.residual_conv = nn.Conv2d(in_channels, 224, kernel_size=1) else: self.residual_conv = nn.Identity() else: self.residual_conv = None def forward(self, x): branch1 = self.branch1x1(x) branch2 = self.branch3x3(x) branch3 = self.branch5x5(x) branch4 = self.branch_pool(x) # 在通道维度上拼接 inception_output = torch.cat([branch1, branch2, branch3, branch4], 1) if self.use_residual and self.residual_conv is not None: # 残差连接 residual = self.residual_conv(x) output = inception_output + residual else: output = inception_output return F.relu(output, inplace=True) class SimpleInceptionNet(nn.Module): def __init__(self, num_classes=10, use_residual=True): super(SimpleInceptionNet, self).__init__() self.use_residual = use_residual print(f"构建{'带残差' if use_residual else '无残差'}的简化版Inception网络...") # 第一层:基础卷积 self.conv1 = nn.Sequential( nn.Conv2d(3, 32, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(32, 64, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2) ) # 第一个Inception模块(带残差选项) self.inception1 = ResidualInceptionModule(64, use_residual=use_residual) print(f"Inception模块1: 输入64通道 -> 输出224通道 (64+64+64+32), 残差连接: {use_residual}") # 过渡层 self.transition1 = nn.Sequential( nn.Conv2d(224, 128, kernel_size=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2) ) # 第二个Inception模块(带残差选项) self.inception2 = ResidualInceptionModule(128, use_residual=use_residual) print(f"Inception模块2: 输入128通道 -> 输出224通道, 残差连接: {use_residual}") # 全局平均池化和全连接 self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) self.fc = nn.Linear(224, num_classes) print(f"全连接层: 224 -> {num_classes}") print(f"网络构建完成! 残差连接: {use_residual}\n") def forward(self, x): x = self.conv1(x) x = self.inception1(x) x = self.transition1(x) x = self.inception2(x) x = self.avgpool(x) x = x.view(x.size(0), -1) x = self.fc(x) return x # 初始化设备 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print(f"使用设备: {device}")
# # 创建模型 # model = SimpleInceptionNet().to(device) # # 打印模型参数数量 # total_params = sum(p.numel() for p in model.parameters()) # print(f"模型总参数量: {total_params:,}") # print("-" * 50) # # 损失函数和优化器 # criterion = nn.CrossEntropyLoss() # optimizer = torch.optim.Adam(model.parameters(), lr=0.001) def test_model(model, testloader): """通用的测试函数""" model.eval() correct = 0 total = 0 print("\n开始测试...") with torch.no_grad(): for inputs, labels in testloader: inputs, labels = inputs.to(device), labels.to(device) outputs = model(inputs) _, predicted = outputs.max(1) total += labels.size(0) correct += predicted.eq(labels).sum().item() accuracy = 100. * correct / total print(f'测试准确率: {accuracy:.2f}%\n') # 打印每个类别的准确率 class_correct = [0] * 10 class_total = [0] * 10 with torch.no_grad(): for inputs, labels in testloader: inputs, labels = inputs.to(device), labels.to(device) outputs = model(inputs) _, predicted = outputs.max(1) c = predicted.eq(labels) for i in range(len(labels)): label = labels[i] class_correct[label] += c[i].item() class_total[label] += 1 print("各类别准确率:") for i in range(10): acc = 100 * class_correct[i] / class_total[i] if class_total[i] > 0 else 0 print(f' {classes[i]:10s}: {acc:.1f}% ({class_correct[i]}/{class_total[i]})') return accuracy def ablation_experiment(): """残差连接消融实验""" print("\n" + "="*60) print("残差连接消融实验 - 对比有/无残差连接的性能") print("="*60) num_epochs = 10 # 为了快速实验,减少epoch数 results = [] # 实验配置 experiments = [ {'name': '无残差连接', 'use_residual': False, 'color': 'red'}, {'name': '有残差连接', 'use_residual': True, 'color': 'blue'} ] for exp in experiments: print(f"\n{'='*50}") print(f"实验: {exp['name']}") print(f"{'='*50}") # 创建模型 model = SimpleInceptionNet(use_residual=exp['use_residual']).to(device) # 打印模型参数数量 total_params = sum(p.numel() for p in model.parameters()) print(f"模型总参数量: {total_params:,}") # 训练模型 criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) train_accs = [] test_accs = [] train_losses = [] for epoch in range(num_epochs): # 训练 model.train() train_correct = 0 train_total = 0 epoch_loss = 0.0 for i, (inputs, labels) in enumerate(trainloader): 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() _, predicted = outputs.max(1) train_total += labels.size(0) train_correct += predicted.eq(labels).sum().item() avg_loss = epoch_loss / len(trainloader) train_acc = 100. * train_correct / train_total train_accs.append(train_acc) train_losses.append(avg_loss) # 测试 model.eval() test_correct = 0 test_total = 0 with torch.no_grad(): for inputs, labels in testloader: inputs, labels = inputs.to(device), labels.to(device) outputs = model(inputs) _, predicted = outputs.max(1) test_total += labels.size(0) test_correct += predicted.eq(labels).sum().item() test_acc = 100. * test_correct / test_total test_accs.append(test_acc) if (epoch + 1) % 2 == 0: print(f' Epoch [{epoch+1}/{num_epochs}], Loss: {avg_loss:.3f}, Train Acc: {train_acc:.1f}%, Test Acc: {test_acc:.1f}%') # 保存结果 results.append({ 'name': exp['name'], 'color': exp['color'], 'final_train_acc': train_accs[-1], 'final_test_acc': test_accs[-1], 'train_accs': train_accs, 'test_accs': test_accs, 'train_losses': train_losses }) # 绘制对比图 plot_ablation_results(results, num_epochs) # 打印实验结果对比 print_results_summary(results) return results def plot_ablation_results(results, num_epochs): """绘制消融实验结果对比图""" plt.figure(figsize=(15, 4)) epochs = list(range(1, num_epochs + 1)) # 1. 训练损失对比 plt.subplot(1, 3, 1) for result in results: plt.plot(epochs, result['train_losses'], label=result['name'], color=result['color'], linewidth=2) plt.xlabel('Epoch') plt.ylabel('Training Loss') plt.title('Training Loss Comparison') plt.legend() plt.grid(True, alpha=0.3) plt.tight_layout() # 2. 训练准确率对比 plt.subplot(1, 3, 2) for result in results: plt.plot(epochs, result['train_accs'], label=result['name'], color=result['color'], linewidth=2) plt.xlabel('Epoch') plt.ylabel('Training Accuracy (%)') plt.title('Training Accuracy Comparison') plt.legend() plt.grid(True, alpha=0.3) plt.tight_layout() # 3. 测试准确率对比 plt.subplot(1, 3, 3) for result in results: plt.plot(epochs, result['test_accs'], label=result['name'], color=result['color'], linewidth=2) plt.xlabel('Epoch') plt.ylabel('Test Accuracy (%)') plt.title('Test Accuracy Comparison') plt.legend() plt.grid(True, alpha=0.3) plt.tight_layout() plt.suptitle('Residual Connection Ablation Study on Inception Network', fontsize=14, fontweight='bold') plt.tight_layout() plt.show() # 绘制柱状图对比最终结果 plt.figure(figsize=(10, 5)) x = np.arange(len(results)) width = 0.35 final_train_accs = [r['final_train_acc'] for r in results] final_test_accs = [r['final_test_acc'] for r in results] colors = [r['color'] for r in results] names = [r['name'] for r in results] plt.bar(x - width/2, final_train_accs, width, label='Training Accuracy', color='lightblue', edgecolor='black') plt.bar(x + width/2, final_test_accs, width, label='Test Accuracy', color='lightcoral', edgecolor='black') plt.xlabel('Model Configuration') plt.ylabel('Accuracy (%)') plt.title('Final Accuracy Comparison') plt.xticks(x, names) plt.legend() plt.grid(True, alpha=0.3, axis='y') # 在柱子上添加数值标签 for i, (train_acc, test_acc) in enumerate(zip(final_train_accs, final_test_accs)): plt.text(i - width/2, train_acc + 0.5, f'{train_acc:.1f}%', ha='center') plt.text(i + width/2, test_acc + 0.5, f'{test_acc:.1f}%', ha='center') plt.tight_layout() plt.show() def print_results_summary(results): """打印实验结果总结""" print("\n" + "="*60) print("消融实验结果总结") print("="*60) print("\n对比项\t\t\t无残差连接\t有残差连接\t提升") print("-"*60) if len(results) >= 2: no_res = results[0] with_res = results[1] # 最终准确率对比 train_improve = with_res['final_train_acc'] - no_res['final_train_acc'] test_improve = with_res['final_test_acc'] - no_res['final_test_acc'] print(f"最终训练准确率\t\t{no_res['final_train_acc']:.1f}%\t\t{with_res['final_train_acc']:.1f}%\t\t+{train_improve:.1f}%") print(f"最终测试准确率\t\t{no_res['final_test_acc']:.1f}%\t\t{with_res['final_test_acc']:.1f}%\t\t+{test_improve:.1f}%") # 收敛速度对比(达到指定准确率的epoch) for threshold in [70, 75, 80]: no_res_epoch = get_convergence_epoch(no_res['test_accs'], threshold) with_res_epoch = get_convergence_epoch(with_res['test_accs'], threshold) if no_res_epoch and with_res_epoch: speedup = no_res_epoch - with_res_epoch print(f"达到{threshold}%准确率\t{no_res_epoch} epoch\t\t{with_res_epoch} epoch\t\t{'+' if speedup > 0 else ''}{speedup} epoch") elif with_res_epoch and not no_res_epoch: print(f"达到{threshold}%准确率\t未达到\t\t{with_res_epoch} epoch\t\t-") elif no_res_epoch and not with_res_epoch: print(f"达到{threshold}%准确率\t{no_res_epoch} epoch\t\t未达到\t\t-") else: print(f"达到{threshold}%准确率\t未达到\t\t未达到\t\t-") print("-"*60) print("\n实验结论:") print("1. 残差连接是否提升了模型性能?") print("2. 残差连接是否加速了模型收敛?") print("3. 残差连接对训练稳定性有何影响?") print("4. 残差机制在Inception网络中的有效性验证") def get_convergence_epoch(acc_list, threshold): """获取达到指定准确率的epoch""" for i, acc in enumerate(acc_list): if acc >= threshold: return i + 1 return None def main(): print("=" * 60) print("Inception网络消融实验 - 残差连接的影响") print("=" * 60) print("\n注意:程序将显示两张可视化图表:") print("1. 训练曲线对比图(包含损失、训练准确率、测试准确率)") print("2. 最终准确率柱状对比图") print("-" * 60) # 运行消融实验(会自动显示图表) results = ablation_experiment() print("\n" + "=" * 60) print("实验完成!") print("=" * 60) # 分析可视化结果 print("\n从可视化图表中可以看出:") print("1. 蓝色曲线代表有残差连接,红色曲线代表无残差连接") print("2. 观察训练损失曲线:残差连接是否使训练更稳定?") print("3. 观察准确率曲线:残差连接是否提升收敛速度和最终性能?") print("4. 柱状图直观展示最终性能对比") # 运行 if __name__ == '__main__': main()

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询