AI 实验六(人工智能 软工课)

  1. 内核寄掉了

    解决方法:

    在导包的时候加上这个

    import os 
    os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"

画图的时候报错:

问题原因:画图的列表中有空的列表

解决方法:把训练过程的代码跑一遍, 报错了就debug就行了。

问题1:您能将上述的CNN结构,修改为SNN结构吗?

有三个卷积层

第一层 有一个输入, 32个输出, 卷积核是(3,3)的矩阵

第二层有32个输入, 64个输出, 卷积核为(3,3)的矩阵

第三层有64个输入, 64个输出, 卷积核为(3,3)的矩阵

每个卷积层后面都跟着一个ReLU的激活函数

nn.Flatten(), 扁平化, 把卷积层的输出, 变成一维的, 以便后面线性层的输入

线性层接收一维的数据, 然后映射成10个类别

为什么 -6?

因为每次卷积, 会模糊边缘的两个像素, 卷积了3层就是 2 * 3 = 6, 所以 -6

然后定义了正向传播函数

修改为SNN结构的代码如下:

​
class DigitClassifier(nn.Module): 
    def __init__(self):
        super().__init__()
        self.model = nn.Sequential(
            nn.Linear(28 * 28, 1024), 
            nn.ReLU(),
            nn.Conv2d(1024, 512), 
            nn.ReLU(),
            nn.Linear(512, 10)  
        )
​
    def forward(self, x): 
        return self.model(x)

clf = DigitClassifier().to(device)
opt = Adam(clf.parameters(), lr=1e-3)  # 指定优化算法
loss_fn = nn.CrossEntropyLoss()
问题2:您能将上述的Adam优化算法替换为其他优化算法吗?能做个对比吗?
使用SGD优化算法:
​
opt_sgd = torch.optim.SGD(clf.parameters(), lr=1e-3, momentum=0.9)  # 使用SGD优化算法

SGD是一种经典的优化算法,它通过计算梯度并沿着梯度的负方向更新参数。SGD还可以使用动量(momentum)来帮助加速学习过程,防止陷入局部极小值。

使用RMSprop优化算法:
​
opt_rmsprop = torch.optim.RMSprop(clf.parameters(), lr=1e-3, alpha=0.9)  # 使用RMSprop优化算法

RMSprop是一种自适应学习率的优化算法,它能够自动调整不同参数的学习率,从而加速收敛过程。RMSprop通过平均平方梯度来缩放每个参数的学习率。

对比:
  1. SGD vs. Adam:

    • SGD通常比较简单,容易实现。它在学习率较小、数据较大的情况下效果较好,特别是在使用动量的情况下(momentum参数设置为一个较大的值,比如0.9)。

    • Adam结合了动量和自适应学习率的特性,通常在深度学习中表现较好。Adam适用于大多数情况,因为它能够自适应地调整学习率,并且通常比SGD更快地收敛。

  2. RMSprop vs. Adam:

    • RMSprop也是一种自适应学习率的方法,与Adam类似。RMSprop在某些情况下可能比Adam更稳定,尤其是在处理非平稳目标函数时。

    • Adam在实践中通常表现得更好,因为它考虑了梯度的一阶矩估计(动量)和二阶矩估计(自适应学习率),这使得它在不同类型的数据和网络架构上都有很好的表现。

问题3:能搞定nn.CrossEntropyLoss()这个损失函数的计算公式吗?

公式如下

$$
L(x, y) = -\frac{1}{N} \sum_{n=1}^{N} \log\left(\frac{\exp(x_{n, y_{n}})}{\sum_{c=0}^{C-1} \exp(x_{n, c})}\right)
$$

问题4:你能修改上述代码,记录每一代之后的模型准确率吗?
%%time
​
losses = []
epochs = []
total_count = 0
correct_count = 0
for epoch in range(10): # 训练10代
    for batch in dataset: 
        X,y = batch 
        X, y = X.to(device), y.to(device) 
        yhat = clf(X)  # 正向传播
        loss = loss_fn(yhat, y)  # 损失函数
        total_count += len(y)
        correct_count += (yhat.argmax(1) == y).sum().item()
        accuracy = correct_count / total_count
        
        # 反向传播 
        opt.zero_grad()  # 这一步不能省,每次反向传播前,设置优化算法的梯度参数
        loss.backward()  # 反向传播,计算梯度
        opt.step()   # 基于优化算法的梯度更新
    epochs.append(epoch+1)  # 计算代数
    losses.append(loss.item())  # 保存损失函数值
​
    print(f"Epoch:{epoch} loss is {loss.item()}  Accuracy:{accuracy}")  # 显示每一代训练后的损失值
训练集和验证集上的对比曲线。

再损失函数下面加上三行代码即可

        total_count += len(y)
        correct_count += (yhat.argmax(1) == y).sum().item()
        accuracy = correct_count / total_count
问题5:你能绘制出模型训练过程中的准确率曲线吗?

代码如下:

plt.plot(epochs, accuracys, 'o--') # 改成正确率的那个数组就行了
plt.xlabel('Epoch')
plt.ylabel('accuracy')
plt.title('Accuracy per epoch')  
plt.show()

问题6:如何绘制训练图形,才能有效观察模型是否过拟合?模型泛化能力如何?是否有进一步改善的余地?

绘图观察模型是否过拟合, 以及他的泛化能力

  1. 添加验证集数据: 在训练过程中,保留一部分数据作为验证集。通常,会将训练集分成训练集和验证集,然后使用训练集来训练模型,验证集来评估模型性能。

  2. 在每个epoch结束后计算验证集的损失值和准确率: 在每个epoch结束后,用模型在验证集上进行前向传播,计算损失值并记录准确率。

  3. 绘制损失值和准确率曲线: 使用Matplotlib或其他绘图库,绘制训练集和验证集的损失值和准确率曲线。

改善的余地:

可以添加验证集进行进一步的验证, 如果不通过验证就让他回炉重造啦

切片的时候, 先测试用什么大小的切片训练模型比较合适, 然后用合适大小的切片进行训练大模型

梯度下降的步长, 可以先做小测试, 测试出合适的步长, 然后用这个步长去训练大模型, 这样效率会高一点

绘制曲线的代码

添加验证集

test = datasets.MNIST(root="data", train=False, download=True, transform=ToTensor())
data_test = DataLoader(test, 32)

训练过程的代码修改:

添加了验证集的损失函数计算, 还有正确率的计算, 并将他们放到一个列表中, 方便下面画图使用

%%time
​
losses = []
epochs = []
steps = []
accuracys = []
total_count = 0
correct_count = 0
​
val_losses = []
val_accuracies = []
​
for epoch in range(10): # 训练10代
    for batch in dataset: 
        X,y = batch 
        X, y = X.to(device), y.to(device) 
        yhat = clf(X)  # 正向传播
        loss = loss_fn(yhat, y)  # 损失函数
        
        total_count += len(y)
        correct_count += (yhat.argmax(1) == y).sum().item()
        accuracy = correct_count / total_count
        
        # 反向传播 
        opt.zero_grad()  # 这一步不能省,每次反向传播前,设置优化算法的梯度参数
        loss.backward()  # 反向传播,计算梯度
        opt.step()   # 基于优化算法的梯度更新
        
       
     # 在验证集上进行评估
    val_total_count = 0
    val_correct_count = 0
    val_loss = 0.0
    with torch.no_grad():  # 在验证过程中不需要计算梯度
        for val_batch in data_test:
            val_X, val_y = val_batch 
            val_X, val_y = val_X.to(device), val_y.to(device) 
            val_yhat = clf(val_X)  # 正向传播
            val_loss += loss_fn(val_yhat, val_y).item()  # 损失函数
            val_total_count += len(val_y)
            val_correct_count += (val_yhat.argmax(1) == val_y).sum().item()    
    val_accuracy = val_correct_count / val_total_count
    val_losses.append(val_loss / len(data_test))  # 平均损失值
    val_accuracies.append(val_accuracy)
    
    epochs.append(epoch+1)  # 计算代数
    accuracys.append(accuracy)
    losses.append(loss.item())  # 保存损失函数值
​
    print(f"Epoch:{epoch} loss is {loss.item()}  Accuracy:{accuracy}")  # 显示每一代训练后的损失值

绘制曲线的代码

朴素版本

plt.plot(epochs, losses, 'o--')
plt.plot(epochs, val_losses,'o--')
plt.xlabel('Epoch')
​
plt.ylabel('Loss')
plt.title('Loss per epoch')  # 也可以按照每个batch绘制图形
plt.show()
​
plt.plot(epochs, accuracys, 'o--') # 改成正确率的那个数组就行了
plt.plot(epochs, val_accuracies,'o--')
plt.xlabel('Epoch')
plt.ylabel('accuracy')
plt.title('Accuracy per epoch')  
plt.show()

视觉优化:

代码:

import matplotlib.pyplot as plt
​
plt.figure(figsize=(12, 4))
​
# 绘制损失值曲线
plt.subplot(1, 2, 1)
plt.plot(epochs, losses, marker='o', color='b', label='Training Loss')
plt.plot(epochs, val_losses, marker='o', color='r', label='Validation Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.title('Training and Validation Loss')
plt.legend()
​
# 绘制准确率曲线
plt.subplot(1, 2, 2)
plt.plot(epochs, accuracys, marker='o', color='b', label='Training Accuracy')
plt.plot(epochs, val_accuracies, marker='o', color='r', label='Validation Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()
​
plt.tight_layout()
plt.show()
​

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值