day41

# 原始模型(2层卷积)
class OriginalCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 16, 3)
        self.conv2 = nn.Conv2d(16, 32, 3)
        self.fc = nn.Linear(32*5*5, 10)
    def forward(self, x):
        x = torch.relu(self.conv1(x))
        x = torch.max_pool2d(x, 2)
        x = torch.relu(self.conv2(x))
        x = torch.max_pool2d(x, 2)
        return self.fc(x.flatten(1))

# 修改1:减少卷积层(1层卷积)
class ReducedCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 32, 3)  # 通道数翻倍补偿层数减少
        self.fc = nn.Linear(32*13*13, 10)
    def forward(self, x):
        x = torch.relu(self.conv1(x))
        x = torch.max_pool2d(x, 2)
        return self.fc(x.flatten(1))

# 修改2:增加注意力(简单通道注意力)
class SECNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 16, 3)
        self.conv2 = nn.Conv2d(16, 32, 3)
        self.se = nn.Sequential(nn.AdaptiveAvgPool2d(1), nn.Flatten(),
                               nn.Linear(32, 8), nn.ReLU(),
                               nn.Linear(8, 32), nn.Sigmoid(), nn.Unflatten(1, (32,1,1)))
        self.fc = nn.Linear(32*5*5, 10)
    def forward(self, x):
        x = torch.relu(self.conv1(x))
        x = torch.max_pool2d(x, 2)
        x = torch.relu(self.conv2(x))
        x = x * self.se(x)  # 应用注意力
        x = torch.max_pool2d(x, 2)
        return self.fc(x.flatten(1))

# 训练函数(支持不同调度器)
def train(model, scheduler_type, epochs=5):
    model = model.to(device)
    opt = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
    
    # 调度器
    if scheduler_type == 'cosine':
        scheduler = optim.lr_scheduler.CosineAnnealingLR(opt, T_max=epochs)
    elif scheduler_type == 'step':
        scheduler = optim.lr_scheduler.StepLR(opt, step_size=2, gamma=0.5)
    else:
        scheduler = None
    
    loss_list = []
    for e in range(epochs):
        model.train()
        loss_sum = 0
        for x, y in loader:
            x, y = x.to(device), y.to(device)
            opt.zero_grad()
            loss = nn.CrossEntropyLoss()(model(x), y)
            loss.backward()
            opt.step()
            loss_sum += loss.item()
        loss_list.append(loss_sum / len(loader))
        if scheduler: scheduler.step()
        print(f"Epoch {e+1}, Loss: {loss_list[-1]:.4f}")
    return loss_list

# 对比实验
def compare():
    models = {'Original': OriginalCNN(), 'Reduced': ReducedCNN(), 'SE': SECNN()}
    schedulers = ['cosine', 'step', None]
    
    results = {}
    for name, model in models.items():
        results[name] = {}
        for sched in schedulers:
            s_name = 'Cosine' if sched=='cosine' else 'StepLR' if sched=='step' else 'None'
            print(f"\n=== {name} + {s_name} ===")
            results[name][s_name] = train(model, sched, epochs=5)
    
    # 可视化
    plt.figure(figsize=(10, 6))
    for name, scheds in results.items():
        for s_name, loss in scheds.items():
            plt.plot(loss, label=f"{name} + {s_name}")
    plt.title("Loss Comparison")
    plt.legend()
    plt.grid(True)
    plt.show()

if __name__ == "__main__":
    compare()
@浙大疏锦行https://blog.csdn.net/weixin_45655710

你可能感兴趣的:(python训练营,python)