PyTorch技术和深度学习——四、神经网络训练与优化

文章目录

      • 1.神经网络迭代概念
        • 1)训练误差与泛化误差
        • 2)训练集、验证集和测试集划分
        • 3)偏差与方差
      • 2.正则化方法
        • 1)提前终止
        • 2)L2正则化
        • 3)Dropout
      • 3.优化算法
        • 1)梯度下降
        • 2)Momentum算法
        • 3)RMSprop算法
        • 4)Adam算法
      • 4.PyTorch的初始化函数
        • 1)普通初始化
        • 2)Xavier 初始化
        • 3)He初始化

1.神经网络迭代概念

超参数包括神经网络的层数、每层神经元的个数、学习率以及合适的激活函数。需要多次循环往复地进行“设置超参数》编码》检查实验结果”这一过程,才能设置最合适的超参数。数据样本的划分也很关键。

1)训练误差与泛化误差

机器学习在训练数据集上表现出的误差叫做训练误差,在任意一个测试数据样本上的误差的期望值叫做泛化误差。

2)训练集、验证集和测试集划分

训练集:用来训练模型内参数的数据集

验证集:用于在训练过程中检验模型的状态,收敛情况。验证集通常用于调整超参数,根据几组模型验证集上的表现决定哪组超参数拥有最好的性能。

同时验证集在训练过程中还可以用来监控模型是否发生过拟合,一般来说验证集表现稳定后,若继续训练,训练集表现还会继续上升,但是验证集会出现不升反降的情况,这样一般就发生了过拟合。所以验证集也用来判断何时停止训练

测试集:用来评价模型泛化能力,即之前模型使用验证集确定了超参数,使用训练集调整了参数,最后使用一个从没有见过的数据集来判断这个模型是否Work。

区别:形象上来说训练集就像是学生的课本,学生 根据课本里的内容来掌握知识,验证集就像是作业,通过作业可以知道 不同学生学习情况、进步的速度快慢,而最终的测试集就像是考试,考的题是平常都没有见过,考察学生举一反三的能力。

交叉验证法的作用就是尝试利用不同的训练集/测试集划分来对模型做多组不同的训练/测试,来应对单词测试结果过于片面以及训练数据不足的问题。

3)偏差与方差

偏差欠拟合;方差过拟合。

2.正则化方法

过拟合的解决方式有两种:一是收集更多数据,标注更多标签;二是正则化。

1)提前终止

基本思想:神经网络出现过拟合苗头时,提前终止。

方法:绘制训练和严重准确率及损失曲线;找到最佳次数;修改n_epochs为最佳次数。

另一种方式是记录每一轮的准确率,保存对应的参数。然后加载最佳网络参数。

创建文件mnist_early_stopping.py
添加代码如下:

# -*- coding: utf-8 -*-
"""
MNIST数据集分类示例
提前终止
"""import torch
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import torch.nn as nn
from torchvision import datasets
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
from torch.utils.data.sampler import SubsetRandomSampler# 防止plt汉字乱码
mpl.rcParams[u'font.sans-serif'] = ['simhei']
mpl.rcParams['axes.unicode_minus'] = False# 是否使用GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 超参数
batch_size = 256
n_epochs = 50       # 将原来的训练轮次从50改为14
# n_epochs = 50       # 将原来的训练轮次从50改为14
init_best_acc = 0.975    # 初始最佳验证准确率
checkpoint = "best_mnist_early_stopping.pt"
valid_ratio = 0.2       # 验证集划分比例def load_mnist_datasets():""" 加载MNIST数据集 """# 简单数据转换transform = transforms.ToTensor()# 选择训练集和测试集train_data = datasets.MNIST(root='../datasets/mnist/', train=True, download=True, transform=transform)test_data = datasets.MNIST(root='../datasets/mnist/', train=False, download=True, transform=transform)# 训练集和验证集划分num_train = len(train_data)indices = list(range(num_train))np.random.shuffle(indices)split = int(np.floor(valid_ratio * num_train))train_idx, valid_idx = indices[split:], indices[:split]# 定义获取训练及验证批数据的抽样器train_sampler = SubsetRandomSampler(train_idx)valid_sampler = SubsetRandomSampler(valid_idx)# 加载训练集、验证集和测试集train_loader = DataLoader(train_data, batch_size=batch_size, sampler=train_sampler, num_workers=0)val_loader = DataLoader(train_data, batch_size=batch_size, sampler=valid_sampler, num_workers=0)test_loader = DataLoader(test_data, batch_size=batch_size, num_workers=0)return train_loader, val_loader, test_loaderclass MLPModel(nn.Module):""" 三层简单全连接网络 """def __init__(self):super(MLPModel, self).__init__()self.fc1 = nn.Linear(28 * 28, 128)self.fc2 = nn.Linear(128, 128)self.fc3 = nn.Linear(128, 10)self.relu = nn.ReLU()def forward(self, x):x = x.view(-1, 28 * 28)x = self.relu(self.fc1(x))x = self.relu(self.fc2(x))x = self.fc3(x)return xdef train_model(model, epochs, train_loader, val_loader, optimizer, criterion):""" 训练模型 """# 一轮训练的损失train_loss = 0.val_loss = 0.# 多轮训练的损失历史train_losses_history = []val_losses_history = []# 多轮训练的准确率历史train_acc_history = []val_acc_history = []# 当前最佳准确率best_acc = init_best_accfor epoch in range(1, epochs + 1):model.train()  # 训练模式num_correct = 0num_samples = 0for batch, (data, target) in enumerate(train_loader, 1):data, target = data.to(device), target.to(device)# 梯度清零optimizer.zero_grad()# 前向传播output = model(data)# 计算损失loss = criterion(output, target)# 反向传播loss.backward()# 更新参数optimizer.step()# 记录损失train_loss += loss.item() * target.size(0)# 将概率最高的类别作为预测类_, predicted = torch.max(output.data, dim=1)num_samples += target.size(0)num_correct += (predicted == target).int().sum()# 训练准确率train_acc = 1.0 * num_correct / num_samplestrain_acc_history.append(train_acc)# 验证模型with torch.no_grad():model.eval()  # 验证模式num_correct = 0num_samples = 0for data, target in val_loader:data, target = data.to(device), target.to(device)# 前向传播output = model(data)# 计算损失loss = criterion(output, target)# 记录验证损失val_loss += loss.item() * target.size(0)# 将概率最高的类别作为预测类_, predicted = torch.max(output.data, dim=1)num_samples += target.size(0)num_correct += (predicted == target).int().sum()# 验证准确率val_acc = 1.0 * num_correct / num_samplesval_acc_history.append(val_acc)# 计算一轮训练后的损失train_loss = train_loss / num_samplesval_loss = val_loss / num_samplestrain_losses_history.append(train_loss)val_losses_history.append(val_loss)# 打印统计信息epoch_len = len(str(epochs))print(f'[{epoch:>{epoch_len}}/{epochs:>{epoch_len}}] ' +f'训练准确率:{train_acc:.3%} ' +f'验证准确率:{val_acc:.3%} ' +f'训练损失:{train_loss:.5f} ' +f'验证损失:{val_loss:.5f}')# 记录最佳测试准确率if val_acc > best_acc:best_acc = val_accprint("保存模型......")torch.save(model.state_dict(), checkpoint)# 为下一轮训练清除统计数据train_loss = 0val_loss = 0# 加载最佳模型model.load_state_dict(torch.load(checkpoint))return model, train_acc_history, val_acc_history, train_losses_history, val_losses_historydef plot_metrics_curves(train_acc, val_acc, train_loss, val_loss):""" 绘制性能曲线 """# 训练和验证准确率plt.figure(figsize=(10, 8))plt.plot(range(1, len(train_acc) + 1), train_acc, label=u'训练准确率')plt.plot(range(1, len(val_acc) + 1), val_acc, label=u'验证准确率')max_position = np.argmin(val_acc)+1# max_position = val_acc.index(max(val_acc)) + 1plt.axvline(max_position, linestyle='--', color='r', label=u'提前终止检查点')plt.xlabel(u'轮次')plt.ylabel(u'准确率')plt.ylim(0, 1.2)plt.xlim(0, len(train_acc) + 1)plt.grid(True)plt.title(u'训练和验证准确率')plt.legend()plt.tight_layout()plt.show()# 训练和验证损失plt.figure(figsize=(10, 8))plt.plot(range(1, len(train_loss) + 1), train_loss, label=u'训练损失')plt.plot(range(1, len(val_loss) + 1), val_loss, label=u'验证损失')min_position = np.argmin(val_loss)+1# min_position = val_loss.index(min(val_loss)) + 1plt.axvline(min_position, linestyle='--', color='r', label=u'提前终止检查点')plt.xlabel(u'轮次')plt.ylabel(u'损失')plt.ylim(0, 0.5)plt.xlim(0, len(train_loss) + 1)plt.grid(True)plt.title(u'训练和验证损失')plt.legend()plt.tight_layout()plt.show()def test_model(model, test_loader, criterion):""" 模型测试 """test_loss = 0.0total_correct = 0total_examples = 0model.eval()  # 评估模式for data, target in test_loader:data, target = data.to(device), target.to(device)output = model(data)loss = criterion(output, target)test_loss += loss.item() * data.size(0)_, pred = torch.max(output, dim=1)correct = np.squeeze(pred.eq(target.data.view_as(pred)))total_correct += correct.sum()total_examples += target.size(0)test_loss = test_loss / len(test_loader.dataset)print('测试损失:{:.6f}\n'.format(test_loss))total_acc = 1.0 * total_correct / total_examplesprint(f'\n总体测试准确率: {total_acc:.3%}({total_correct}/{total_examples})')def main():""" 主函数 """# 实例化MLP模型model = MLPModel().to(device)print(model)# 交叉熵损失函数criterion = nn.CrossEntropyLoss()# 优化器optimizer = torch.optim.Adam(model.parameters())# 加载数据集train_loader, val_loader, test_loader = load_mnist_datasets()# 模型训练model, train_acc, val_acc, train_loss, val_loss = \train_model(model, n_epochs, train_loader, val_loader, optimizer, criterion)# 绘制性能曲线# train_acc2 = train_acc.to(device='cpu')# val_acc2 = val_acc.to(device='cpu')# train_loss2 = train_loss.to(device='cpu')# val_loss2 = val_loss.to(device='cpu')# plot_metrics_curves(train_acc2, val_acc2, train_loss2, val_loss2)train_acc2 = torch.tensor(train_acc).detach().cpu().clone().numpy()val_acc2 = torch.tensor(val_acc).cpu().clone().numpy()train_loss2 = torch.tensor(train_loss).cpu().clone().numpy()val_loss2 = torch.tensor(val_loss).cpu().clone().numpy()plot_metrics_curves(train_acc2, val_acc2, train_loss2, val_loss2)# plot_metrics_curves(train_acc, val_acc, train_loss, val_loss)# 模型测试test_model(model, test_loader, criterion)if __name__ == '__main__':main()

运行结果:

总体测试准确率: 97.630%(9763/10000)

显示Mnist训练和验证准确率及损失曲线
在这里插入图片描述

在这里插入图片描述

验证 损失最小值处就是提前终止检查点。

2)L2正则化

通过对权重参数施加惩罚达到。它是一个减少方差的策略,也就是减少高方差。

误差可分解为:偏差,方差与噪声之和。即误差 = 偏差 + 方差 + 噪声

偏差度量了学习算法的期望预测与真实结果的偏离程度, 即刻画了学习算法本身的拟合能力
方差度量了同样大小的训练集的变动所导致的学习性能的变化,即刻画了数据扰动所造成的影响
噪声则表达了在当前任务上任何学习算法所能达到的期望泛化误差的下界。

L1 正则化的特点:

  • 不容易计算, 在零点连续但不可导, 需要分段求导
  • L1 模型可以将 一些权值缩小到零(稀疏)
  • 执行隐式变量选择。这意味着一些变量值对结果的影响降为 0, 就像删除它们一样
  • 其中一些预测因子对应较大的权值, 而其余的(几乎归零)
  • 由于它可以提供稀疏的解决方案, 因此通常是建模特征数量巨大时的首选模型
  • 它任意选择高度相关特征中的任何一个,并将其余特征对应的系数减少到 0**
  • L1 范数对于异常值更具提抗力

L2 正则化的特点:

  • 容易计算, 可导, 适合基于梯度的方法
  • 将一些权值缩小到接近 0
  • 相关的预测特征对应的系数值相似
  • 当特征数量巨大时, 计算量会比较大
  • 对于有相关特征存在的情况,它会包含所有这些相关的特征, 但是相关特征的权值分布取决于相关性。
  • 对异常值非常敏感
  • 相对于 L1 正则会更加准确

创建文件mnist_regularization.py
添加代码如下:

# -*- coding: utf-8 -*-
"""
MNIST数据集分类示例
L2正则化
"""import torch
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import torch.nn as nn
from torchvision import datasets
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
from torch.utils.data.sampler import SubsetRandomSampler# 防止plt汉字乱码
mpl.rcParams[u'font.sans-serif'] = ['simhei']
mpl.rcParams['axes.unicode_minus'] = False# 是否使用GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 超参数
batch_size = 256
n_epochs = 50
init_best_acc = 0.975    # 初始最佳验证准确率
checkpoint = "best_mnist_early_stopping.pt"
valid_ratio = 0.2       # 验证集划分比例def load_mnist_datasets():""" 加载MNIST数据集 """# 简单数据转换transform = transforms.ToTensor()# 选择训练集和测试集train_data = datasets.MNIST(root='../datasets/mnist/', train=True, download=True, transform=transform)test_data = datasets.MNIST(root='../datasets/mnist/', train=False, download=True, transform=transform)# 训练集和验证集划分num_train = len(train_data)indices = list(range(num_train))np.random.shuffle(indices)split = int(np.floor(valid_ratio * num_train))train_idx, valid_idx = indices[split:], indices[:split]# 定义获取训练及验证批数据的抽样器train_sampler = SubsetRandomSampler(train_idx)valid_sampler = SubsetRandomSampler(valid_idx)# 加载训练集、验证集和测试集train_loader = DataLoader(train_data, batch_size=batch_size, sampler=train_sampler, num_workers=0)val_loader = DataLoader(train_data, batch_size=batch_size, sampler=valid_sampler, num_workers=0)test_loader = DataLoader(test_data, batch_size=batch_size, num_workers=0)return train_loader, val_loader, test_loaderclass MLPModel(nn.Module):""" 三层简单全连接网络 """def __init__(self):super(MLPModel, self).__init__()self.fc1 = nn.Linear(28 * 28, 128)self.fc2 = nn.Linear(128, 128)self.fc3 = nn.Linear(128, 10)self.relu = nn.ReLU()def forward(self, x):x = x.view(-1, 28 * 28)x = self.relu(self.fc1(x))x = self.relu(self.fc2(x))x = self.fc3(x)return xdef train_model(model, epochs, train_loader, val_loader, optimizer, criterion):""" 训练模型 """# 一轮训练的损失train_loss = 0.val_loss = 0.# 多轮训练的损失历史train_losses_history = []val_losses_history = []# 多轮训练的准确率历史train_acc_history = []val_acc_history = []# 当前最佳准确率best_acc = init_best_accfor epoch in range(1, epochs + 1):model.train()  # 训练模式num_correct = 0num_samples = 0for batch, (data, target) in enumerate(train_loader, 1):data, target = data.to(device), target.to(device)# 梯度清零optimizer.zero_grad()# 前向传播output = model(data)# 计算损失loss = criterion(output, target)# 反向传播loss.backward()# 更新参数optimizer.step()# 记录损失train_loss += loss.item() * target.size(0)# 将概率最高的类别作为预测类_, predicted = torch.max(output.data, dim=1)num_samples += target.size(0)num_correct += (predicted == target).int().sum()# 训练准确率train_acc = 1.0 * num_correct / num_samplestrain_acc_history.append(train_acc)# 验证模型with torch.no_grad():model.eval()  # 验证模式num_correct = 0num_samples = 0for data, target in val_loader:data, target = data.to(device), target.to(device)# 前向传播output = model(data)# 计算损失loss = criterion(output, target)# 记录验证损失val_loss += loss.item() * target.size(0)# 将概率最高的类别作为预测类_, predicted = torch.max(output.data, dim=1)num_samples += target.size(0)num_correct += (predicted == target).int().sum()# 验证准确率val_acc = 1.0 * num_correct / num_samplesval_acc_history.append(val_acc)# 计算一轮训练后的损失train_loss = train_loss / num_samplesval_loss = val_loss / num_samplestrain_losses_history.append(train_loss)val_losses_history.append(val_loss)# 打印统计信息epoch_len = len(str(epochs))print(f'[{epoch:>{epoch_len}}/{epochs:>{epoch_len}}] ' +f'训练准确率:{train_acc:.3%} ' +f'验证准确率:{val_acc:.3%} ' +f'训练损失:{train_loss:.5f} ' +f'验证损失:{val_loss:.5f}')# 记录最佳测试准确率if val_acc > best_acc:best_acc = val_accprint("保存模型......")torch.save(model.state_dict(), checkpoint)# 为下一轮训练清除统计数据train_loss = 0val_loss = 0# 加载最佳模型model.load_state_dict(torch.load(checkpoint))return model, train_acc_history, val_acc_history, train_losses_history, val_losses_historydef plot_metrics_curves(train_acc, val_acc, train_loss, val_loss):""" 绘制性能曲线 """# 训练和验证准确率plt.figure(figsize=(10, 8))plt.plot(range(1, len(train_acc) + 1), train_acc, label=u'训练准确率')plt.plot(range(1, len(val_acc) + 1), val_acc, label=u'验证准确率')max_position = val_acc.index(max(val_acc)) + 1plt.axvline(max_position, linestyle='--', color='r', label=u'提前终止检查点')plt.xlabel(u'轮次')plt.ylabel(u'准确率')plt.ylim(0, 1.2)plt.xlim(0, len(train_acc) + 1)plt.grid(True)plt.title(u'训练和验证准确率')plt.legend()plt.tight_layout()plt.show()# 训练和验证损失plt.figure(figsize=(10, 8))plt.plot(range(1, len(train_loss) + 1), train_loss, label=u'训练损失')plt.plot(range(1, len(val_loss) + 1), val_loss, label=u'验证损失')min_position = val_loss.index(min(val_loss)) + 1plt.axvline(min_position, linestyle='--', color='r', label=u'提前终止检查点')plt.xlabel(u'轮次')plt.ylabel(u'损失')plt.ylim(0, 0.5)plt.xlim(0, len(train_loss) + 1)plt.grid(True)plt.title(u'训练和验证损失')plt.legend()plt.tight_layout()plt.show()def test_model(model, test_loader, criterion):""" 模型测试 """test_loss = 0.0total_correct = 0total_examples = 0model.eval()  # 评估模式for data, target in test_loader:data, target = data.to(device), target.to(device)output = model(data)loss = criterion(output, target)test_loss += loss.item() * data.size(0)_, pred = torch.max(output, dim=1)correct = np.squeeze(pred.eq(target.data.view_as(pred)))total_correct += correct.sum()total_examples += target.size(0)test_loss = test_loss / len(test_loader.dataset)print('测试损失:{:.6f}\n'.format(test_loss))total_acc = 1.0 * total_correct / total_examplesprint(f'\n总体测试准确率: {total_acc:.3%}({total_correct}/{total_examples})')def main():""" 主函数 """# 实例化MLP模型model = MLPModel().to(device)print(model)# 交叉熵损失函数criterion = nn.CrossEntropyLoss()# 优化器optimizer = torch.optim.Adam(model.parameters(), weight_decay=0.0001)# 加载数据集train_loader, val_loader, test_loader = load_mnist_datasets()# 模型训练model, train_acc, val_acc, train_loss, val_loss = \train_model(model, n_epochs, train_loader, val_loader, optimizer, criterion)# 绘制性能曲线plot_metrics_curves(train_acc, val_acc, train_loss, val_loss)# 模型测试test_model(model, test_loader, criterion)if __name__ == '__main__':main()
3)Dropout

在神经网络训练时,随机把一些神经单元去除,“瘦身”后的神经网络继续训练,最后的模型,是保留所有神经单元,但是神经的连接权重w乘上了一个刚才随机去除指数p.

# -*- coding: utf-8 -*-
"""
MNIST数据集分类示例
Dropout 
"""import torch
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import torch.nn as nn
from torchvision import datasets
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
from torch.utils.data.sampler import SubsetRandomSampler# 防止plt汉字乱码
mpl.rcParams[u'font.sans-serif'] = ['simhei']
mpl.rcParams['axes.unicode_minus'] = False# 是否使用GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 超参数
batch_size = 256
n_epochs = 50
init_best_acc = 0.975    # 初始最佳验证准确率
checkpoint = "best_mnist_dropout.pt"
valid_ratio = 0.2       # 验证集划分比例def load_mnist_datasets():""" 加载MNIST数据集 """# 简单数据转换transform = transforms.ToTensor()# 选择训练集和测试集train_data = datasets.MNIST(root='../datasets/mnist/', train=True, download=True, transform=transform)test_data = datasets.MNIST(root='../datasets/mnist/', train=False, download=True, transform=transform)# 训练集和验证集划分num_train = len(train_data)indices = list(range(num_train))np.random.shuffle(indices)split = int(np.floor(valid_ratio * num_train))train_idx, valid_idx = indices[split:], indices[:split]# 定义获取训练及验证批数据的抽样器train_sampler = SubsetRandomSampler(train_idx)valid_sampler = SubsetRandomSampler(valid_idx)# 加载训练集、验证集和测试集train_loader = DataLoader(train_data, batch_size=batch_size, sampler=train_sampler, num_workers=0)val_loader = DataLoader(train_data, batch_size=batch_size, sampler=valid_sampler, num_workers=0)test_loader = DataLoader(test_data, batch_size=batch_size, num_workers=0)return train_loader, val_loader, test_loaderclass MLPModel(nn.Module):""" 三层简单全连接网络 """def __init__(self):super(MLPModel, self).__init__()self.fc1 = nn.Linear(28 * 28, 128)self.fc2 = nn.Linear(128, 128)self.fc3 = nn.Linear(128, 10)self.relu = nn.ReLU()self.dropout = nn.Dropout(0.4)  # 随机丢弃的概率def forward(self, x):x = x.view(-1, 28 * 28)x = self.relu(self.fc1(x))x = self.dropout(x)x = self.relu(self.fc2(x))x = self.dropout(x)x = self.fc3(x)return xdef train_model(model, epochs, train_loader, val_loader, optimizer, criterion):""" 训练模型 """# 一轮训练的损失train_loss = 0.val_loss = 0.# 多轮训练的损失历史train_losses_history = []val_losses_history = []# 多轮训练的准确率历史train_acc_history = []val_acc_history = []# 当前最佳准确率best_acc = init_best_accfor epoch in range(1, epochs + 1):model.train()  # 训练模式num_correct = 0num_samples = 0for batch, (data, target) in enumerate(train_loader, 1):data, target = data.to(device), target.to(device)# 梯度清零optimizer.zero_grad()# 前向传播output = model(data)# 计算损失loss = criterion(output, target)# 反向传播loss.backward()# 更新参数optimizer.step()# 记录损失train_loss += loss.item() * target.size(0)# 将概率最高的类别作为预测类_, predicted = torch.max(output.data, dim=1)num_samples += target.size(0)num_correct += (predicted == target).int().sum()# 训练准确率train_acc = 1.0 * num_correct / num_samplestrain_acc_history.append(train_acc)# 验证模型with torch.no_grad():model.eval()  # 验证模式num_correct = 0num_samples = 0for data, target in val_loader:data, target = data.to(device), target.to(device)# 前向传播output = model(data)# 计算损失loss = criterion(output, target)# 记录验证损失val_loss += loss.item() * target.size(0)# 将概率最高的类别作为预测类_, predicted = torch.max(output.data, dim=1)num_samples += target.size(0)num_correct += (predicted == target).int().sum()# 验证准确率val_acc = 1.0 * num_correct / num_samplesval_acc_history.append(val_acc)# 计算一轮训练后的损失train_loss = train_loss / num_samplesval_loss = val_loss / num_samplestrain_losses_history.append(train_loss)val_losses_history.append(val_loss)# 打印统计信息epoch_len = len(str(epochs))print(f'[{epoch:>{epoch_len}}/{epochs:>{epoch_len}}] ' +f'训练准确率:{train_acc:.3%} ' +f'验证准确率:{val_acc:.3%} ' +f'训练损失:{train_loss:.5f} ' +f'验证损失:{val_loss:.5f}')# 记录最佳测试准确率if val_acc > best_acc:best_acc = val_accprint("保存模型......")torch.save(model.state_dict(), checkpoint)# 为下一轮训练清除统计数据train_loss = 0val_loss = 0# 加载最佳模型model.load_state_dict(torch.load(checkpoint))return model, train_acc_history, val_acc_history, train_losses_history, val_losses_historydef plot_metrics_curves(train_acc, val_acc, train_loss, val_loss):""" 绘制性能曲线 """# 训练和验证准确率plt.figure(figsize=(10, 8))plt.plot(range(1, len(train_acc) + 1), train_acc, label=u'训练准确率')plt.plot(range(1, len(val_acc) + 1), val_acc, label=u'验证准确率')max_position = val_acc.index(max(val_acc)) + 1plt.axvline(max_position, linestyle='--', color='r', label=u'提前终止检查点')plt.xlabel(u'轮次')plt.ylabel(u'准确率')plt.ylim(0, 1.2)plt.xlim(0, len(train_acc) + 1)plt.grid(True)plt.title(u'训练和验证准确率')plt.legend()plt.tight_layout()plt.show()# 训练和验证损失plt.figure(figsize=(10, 8))plt.plot(range(1, len(train_loss) + 1), train_loss, label=u'训练损失')plt.plot(range(1, len(val_loss) + 1), val_loss, label=u'验证损失')min_position = val_loss.index(min(val_loss)) + 1plt.axvline(min_position, linestyle='--', color='r', label=u'提前终止检查点')plt.xlabel(u'轮次')plt.ylabel(u'损失')plt.ylim(0, 1.0)plt.xlim(0, len(train_loss) + 1)plt.grid(True)plt.title(u'训练和验证损失')plt.legend()plt.tight_layout()plt.show()def test_model(model, test_loader, criterion):""" 模型测试 """test_loss = 0.0total_correct = 0total_examples = 0model.eval()  # 评估模式for data, target in test_loader:data, target = data.to(device), target.to(device)output = model(data)loss = criterion(output, target)test_loss += loss.item() * data.size(0)_, pred = torch.max(output, dim=1)correct = np.squeeze(pred.eq(target.data.view_as(pred)))total_correct += correct.sum()total_examples += target.size(0)test_loss = test_loss / len(test_loader.dataset)print('测试损失:{:.6f}\n'.format(test_loss))total_acc = 1.0 * total_correct / total_examplesprint(f'\n总体测试准确率: {total_acc:.3%}({total_correct}/{total_examples})')def main():""" 主函数 """# 实例化MLP模型model = MLPModel().to(device)print(model)# 交叉熵损失函数criterion = nn.CrossEntropyLoss()# 优化器optimizer = torch.optim.Adam(model.parameters())# 加载数据集train_loader, val_loader, test_loader = load_mnist_datasets()# 模型训练model, train_acc, val_acc, train_loss, val_loss = \train_model(model, n_epochs, train_loader, val_loader, optimizer, criterion)# 绘制性能曲线plot_metrics_curves(train_acc, val_acc, train_loss, val_loss)# 模型测试test_model(model, test_loader, criterion)if __name__ == '__main__':main()

3.优化算法

寻找最优参数

1)梯度下降

批量梯度下降算法(BGD):计算全部样本平均梯度;

随机梯度下降算法(SGD):计算一个样本;

小批量梯度下降算法(MBGD):

2)Momentum算法

动量是一个能够对抗鞍点和局部最小值的技术。其运算速度较快。

结合当前梯度与上一次更新信息,用于当前更新;

动量,他的作用是尽量保持当前梯度的变化方向。没有动量的网络可以视为一个质量很轻的棉花团,风往哪里吹就往哪里走,一点风吹草动都影响他,四处跳动不容易学习到更好的局部最优。没有动力来源的时候可能又不动了。加了动量就像是棉花变成了铁球,咕噜咕噜的滚在参数空间里,很容易闯过鞍点,直到最低点。可以参照指数滑动平均。优化效果是梯度二阶导数不会过大,优化更稳定,也可以看做效果接近二阶方法,但是计算容易的多。

其实本质应该是对参数加了约束。

创建文件gradient_descent.py,演示梯度下降算法的缺点
添加代码如下:

import numpy as np
from matplotlib import pyplot as plt# 尝试修改学习率为0.43和0.55,看看效果
learning_rate = 0.43def f_2d(w, b):""" 待优化的函数 """return 0.1 * w ** 2 + 2 * b ** 2def gd_2d(w, b):""" 优化一步 """return w - learning_rate * 0.2 * w, b - learning_rate * 4 * bdef train_2d(optimizer):""" 使用定制优化器optimizer来训练二维目标函数 """w, b = -7, 4  # 初始值history = [(w, b)]epochs = 20  # 训练轮次for i in range(epochs):w, b = optimizer(w, b)history.append((w, b))print('经过轮次:%d,最终的w:%f,b:%f' % (epochs, w, b))return historydef trace_2d(f, hist):""" 追踪训练二维目标函数的过程 """w, b = zip(*hist)plt.rcParams['figure.figsize'] = (5, 3)plt.plot(w, b, '-o', color='blue')w = np.arange(-7.5, 7.5, 0.1)b = np.arange(min(-4.0, min(b) - 1), max(4.0, max(b) + 1), 0.1)w, b = np.meshgrid(w, b)plt.contour(w, b, f(w, b), colors='green')plt.xlabel('w')plt.ylabel('b')plt.show()def main():history = train_2d(gd_2d)trace_2d(f_2d, history)if __name__ == '__main__':main()

运行结果:
在这里插入图片描述

创建文件momentum.py,演示Momentum算法
添加代码如下:

# -*- coding: utf-8 -*-
"""
演示Momentum算法
"""
import numpy as np
from matplotlib import pyplot as plt# 尝试修改学习率为0.43和0.55,看看效果
learning_rate = 0.55
gamma = 0.5def f_2d(w, b):""" 待优化的函数 """return 0.1 * w ** 2 + 2 * b ** 2def momentum_2d(w, b, vw, vb, nesterov=False):""" 优化一步 """if nesterov:vw = gamma * vw + (1 - gamma) * 0.2 * wvb = gamma * vb + (1 - gamma) * 4 * breturn w - learning_rate * vw, b - learning_rate * vb, vw, vbelse:vw = gamma * vw + learning_rate * (1 - gamma) * 0.2 * wvb = gamma * vb + learning_rate * (1 - gamma) * 4 * breturn w - vw, b - vb, vw, vbdef train_2d(optimizer):""" 使用定制优化器optimizer来训练二维目标函数 """w, b, vw, vb = -7, 4, 0, 0  # 初始值history = [(w, b)]epochs = 20  # 训练轮次for i in range(epochs):w, b, vw, vb = optimizer(w, b, vw, vb, True)history.append((w, b))print('经过轮次:%d,最终的w:%f,b:%f' % (epochs, w, b))return historydef trace_2d(f, hist):""" 追踪训练二维目标函数的过程 """w, b = zip(*hist)plt.rcParams['figure.figsize'] = (5, 3)plt.plot(w, b, '-o', color='blue')w = np.arange(-7.5, 7.5, 0.1)b = np.arange(min(-4.0, min(b) - 1), max(4.0, max(b) + 1), 0.1)w, b = np.meshgrid(w, b)plt.contour(w, b, f(w, b), colors='green')plt.xlabel('w')plt.ylabel('b')plt.show()def main():history = train_2d(momentum_2d)trace_2d(f_2d, history)if __name__ == '__main__':main()

运行结果:
在这里插入图片描述

3)RMSprop算法

与动量梯度下降一样,都是消除梯度下降过程中的摆动来加速梯度下降的方法。

创建文件rmsprop.py
添加代码如下:

# -*- coding: utf-8 -*-
"""
演示RMSprop算法
"""
import numpy as np
from matplotlib import pyplot as plt# 尝试修改学习率为0.43和0.55,看看效果
learning_rate = 0.55
gamma = 0.9def f_2d(w, b):""" 待优化的函数 """return 0.1 * w ** 2 + 2 * b ** 2def rmsprop_2d(w, b, sw, sb):""" 优化一步 """dw, db, eps = 0.2 * w, 4 * b, 1e-8sw = gamma * sw + (1 - gamma) * dw ** 2sb = gamma * sb + (1 - gamma) * db ** 2return (w - learning_rate * dw / (np.sqrt(sw) + eps),b - learning_rate * db / (np.sqrt(sb) + eps), sw, sb)def train_2d(optimizer):""" 使用定制优化器optimizer来训练二维目标函数 """w, b, sw, sb = -7, 4, 0, 0  # 初始值history = [(w, b)]epochs = 20  # 训练轮次for i in range(epochs):w, b, sw, sb = optimizer(w, b, sw, sb)history.append((w, b))print('经过轮次:%d,最终的w:%f,b:%f' % (epochs, w, b))return historydef trace_2d(f, hist):""" 追踪训练二维目标函数的过程 """w, b = zip(*hist)plt.rcParams['figure.figsize'] = (5, 3)plt.plot(w, b, '-o', color='blue')w = np.arange(-7.5, 7.5, 0.1)b = np.arange(min(-4.0, min(b) - 1), max(4.0, max(b) + 1), 0.1)w, b = np.meshgrid(w, b)plt.contour(w, b, f(w, b), colors='green')plt.xlabel('w')plt.ylabel('b')plt.show()def main():history = train_2d(rmsprop_2d)trace_2d(f_2d, history)if __name__ == '__main__':main()

运行结果:
在这里插入图片描述

4)Adam算法

是RMSProp的更新版本

Adam中动量直接并入了梯度一阶矩(指数加权)的估计。其次,相比于缺少修正因子导致二阶矩估计可能在训练初期具有很高偏置的RMSProp,Adam包括偏置修正,修正从原点初始化的一阶矩(动量项)和(非中心的)二阶矩估计。

创建文件adam.py
添加代码如下:

# -*- coding: utf-8 -*-
"""
演示Adam算法
"""
import numpy as np
from matplotlib import pyplot as plt# 尝试修改学习率为0.43和0.55,看看效果
learning_rate = 0.43
beta1 = 0.9
beta2 = 0.999def f_2d(w, b):""" 待优化的函数 """return 0.1 * w ** 2 + 2 * b ** 2def adam_2d(w, b, vw, vb, sw, sb, t):""" 优化一步 """dw, db, eps = 0.2 * w, 4 * b, 1e-8vw = beta1 * vw + (1 - beta1) * dwvb = beta1 * vb + (1 - beta1) * dbsw = beta2 * sw + (1 - beta2) * dw ** 2sb = beta2 * sb + (1 - beta2) * db ** 2vwc = vw / (1 - beta1 ** t)vbc = vb / (1 - beta1 ** t)swc = sw / (1 - beta2 ** t)sbc = sb / (1 - beta2 ** t)return (w - learning_rate * vwc / np.sqrt(swc + eps),b - learning_rate * vbc / np.sqrt(sbc + eps), vw, vb, sw, sb)def train_2d(optimizer):""" 使用定制优化器optimizer来训练二维目标函数 """w, b, vw, vb, sw, sb = -7, 4, 0, 0, 0, 0  # 初始值history = [(w, b)]epochs = 20  # 训练轮次for t in range(epochs):w, b, vw, vb, sw, sb = optimizer(w, b, vw, vb, sw, sb, t + 1)history.append((w, b))print('经过轮次:%d,最终的w:%f,b:%f' % (epochs, w, b))return historydef trace_2d(f, hist):""" 追踪训练二维目标函数的过程 """w, b = zip(*hist)plt.rcParams['figure.figsize'] = (5, 3)plt.plot(w, b, '-o', color='blue')w = np.arange(-7.5, 7.5, 0.1)b = np.arange(min(-4.0, min(b) - 1), max(4.0, max(b) + 1), 0.1)w, b = np.meshgrid(w, b)plt.contour(w, b, f(w, b), colors='green')plt.xlabel('w')plt.ylabel('b')plt.show()def main():history = train_2d(adam_2d)trace_2d(f_2d, history)if __name__ == '__main__':main()

运行结果:
在这里插入图片描述

4.PyTorch的初始化函数

训练需要给参数赋初始值。torch.nn.init模块定义了多种初始化函数。

1)普通初始化

常数初始化;

均匀分布初始化;

正态分布

初始化为1;

初始化为0;

初始化为对角阵

初始化为狄拉克函数

2)Xavier 初始化

均匀分布初始化

高斯分布;

gain的计算

3)He初始化

均匀分布初始化

高斯分布;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/192557.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

​软考-高级-系统架构设计师教程(清华第2版)【第4章 信息安全技术基础知识(P160~189)-思维导图】​

软考-高级-系统架构设计师教程(清华第2版)【第4章 信息安全技术基础知识(P160~189)-思维导图】 课本里章节里所有蓝色字体的思维导图

LeetCode(10)跳跃游戏 II【数组/字符串】【中等】

目录 1.题目2.答案3.提交结果截图 链接: 45. 跳跃游戏 II 1.题目 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nu…

机器学习-搜索技术:从技术发展到应用实战的全面指南

在本文中,我们全面探讨了人工智能中搜索技术的发展,从基础算法如DFS和BFS,到高级搜索技术如CSP和优化问题的解决方案,进而探索了机器学习与搜索的融合,最后展望了未来的趋势和挑战,提供了对AI搜索技术深刻的…

表单提交是

首先&#xff0c;确保你已经安装了Vue 3、Element UI和axios&#xff08;用于发送HTTP请求&#xff09;。你可以使用以下命令进行安装&#xff1a; bash复制代码 npm install vuenext element-ui axios --save <template> <el-form :model"form" :rules&q…

Java Stream 的常用API

Java Stream 的常用API 遍历&#xff08;forEach&#xff09; package com.liudashuai;import java.util.ArrayList; import java.util.List;public class Test {public static void main(String[] args) {List<Person> userList new ArrayList<>();userList.ad…

可视化技术专栏100例教程导航帖—学习可视化技术的指南宝典

&#x1f389;&#x1f38a;&#x1f389; 你的技术旅程将在这里启航&#xff01; &#x1f680;&#x1f680; 本文专栏&#xff1a;可视化技术专栏100例 可视化技术专栏100例领略各种先进的可视化技术&#xff0c;包括但不限于大屏可视化、图表可视化等等。订阅专栏用户在文章…

Stable Diffusion 是否使用 GPU?

在线工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 3D数字孪生场景编辑器 Stable Diffusion 已迅速成为最流行的生成式 AI 工具之一&#xff0c;用于通过文本到图像扩散模型创建图像。但是&#xff0c;它需…

解决:element ui表格表头自定义输入框单元格el-input不能输入问题

表格表头如图所示&#xff0c;有 40-45&#xff0c;45-50 数据&#xff0c;且以输入框形式呈现&#xff0c;现想修改其数据或点击右侧加号增加新数据编辑。结果不能输入&#xff0c;部分代码如下 <template v-if"columnData.length > 0"><el-table-colu…

一则DNS被重定向导致无法获取MySQL连接处理

同事反馈xwik应用端报java exception 获取MySQL连接超时无法连接到数据库实例 经过告警日志发现访问进来的IP地址数据库端无法被解析&#xff0c;这里可以知道问题出现在Dns配置上了 通过以上报错检查/etc/resolve.conf 发现namesever 被重定向设置成了114.114.114.114 域名 …

GoF之代理模式

2023.11.12 代理模式是GoF23种设计模式之一&#xff0c;其作用是&#xff1a;为其他对象提供一种代理以控制对这个对象的访问。在某些情况下&#xff0c;一个客户不想或者不能直接引用一个对象&#xff0c;此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以…

Linux组调度

为什么引入组调度可以参考这篇文章的讨论。核心原因是基础的调度算法都是基于任务的&#xff0c;如果用户A有10个任务&#xff0c;用户B只有1个任务&#xff0c;假设这些任务的优先级都相同&#xff0c;那么用户A得到的CPU时间将是用户B的10倍&#xff0c;这样从任务的角度看虽…

Zigbee智能家居方案设计

背景 目前智能家居物联网中最流行的三种通信协议&#xff0c;Zigbee、WiFi以及BLE&#xff08;蓝牙&#xff09;。这三种协议各有各的优势和劣势。本方案基于CC2530芯片来设计&#xff0c;CC2530是TI的Zigbee芯片。 网关使用了ESP8266CC2530。 硬件实物 节点板子上带有继电器…

java,springboot钉钉开发连接器,自定义连接器配合流程使用,流程加入连接器,连接器发送参数,然后你本地处理修改值,返回给流程

1.绘制连接器&#xff0c;注意出餐入参的格式&#xff0c; 2.绘制流程&#xff0c;绑定连接器&#xff0c;是提交后出发还是表单值变化后 3.编写本地接口&#xff08;内网穿透&#xff09;&#xff0c;绑定连接器 钉钉开发连接器&#xff0c;自定义连接器配合流程使用&#x…

学【Java多态】-- 写高质量代码

多态的实现条件 在java中要实现&#xff0c;必须要满足如下几个条件&#xff0c;缺一不可。 1.必须在继承体系下2.子类必须要对父类中的方法进行重写3.通过父类的引用调用冲写的方法。 想要真正的学好多态需要去学习一些前置知识&#xff0c;那我们直接开始吧&#xff01; …

Sealos 云操作系统一键集成 runwasi,解锁 Wasm 的无限潜力

WebAssembly (通常缩写为 Wasm) 是一种为网络浏览器设计的低级编程语言。它旨在提供一种比传统的 JavaScript 更快、更高效的方式来执行代码&#xff0c;以弥补 JavaScript 在性能方面的不足。通过使用二进制格式&#xff0c;WebAssembly 能够提供比传统 JavaScript 更快的解析…

基于态、势、感、知的人机协同机理

基于态、势、感、知的人机协同机理是一种以人类的状态、动机、感觉和知觉为基础&#xff0c;与机器系统进行协同合作的机理。这种机理将人类的主观算计能力与机器系统的客观计算功能相结合&#xff0c;以实现更加智能、自适应和人性化的人机协同。下面是对基于态、势、感、知的…

防爆五参数气象仪的科技力量

WX-FBQ2 随着科技的不断进步&#xff0c;气象监测设备也在不断升级和完善。 防爆五参数气象仪是一种可以同时监测温度、湿度、压力、风速和风向五个基本气象参数的仪器。它采用了气象监测技术&#xff0c;不仅可以实时监测气象数据&#xff0c;还可以对数据进行分析和处理。 …

深入理解JVM虚拟机第二十四篇:详解JVM当中的动态链接和常量池的作用

大神链接&#xff1a;作者有幸结识技术大神孙哥为好友&#xff0c;获益匪浅。现在把孙哥视频分享给大家。 孙哥链接&#xff1a;孙哥个人主页 作者简介&#xff1a;一个颜值99分&#xff0c;只比孙哥差一点的程序员 本专栏简介&#xff1a;话不多说&#xff0c;让我们一起干翻J…

【linux】centos7 yum安装nginx

查看系统中是否已安装 nginx 服务 yum list | grep nginx查看nginx运行进程 ps -ef | grep nginx添加源 rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm 安装Nginx yum install -y nginx 查看nginx安装目录 find …