展示型网站设计案例,苏州网站开发的企业,开发网页的公司,政和县建设局网站公告目录
1 小批量梯度下降法 1.0 展开聊一聊~ 1.1 数据分组 1.2 用DataLoader进行封装 1.3 模型构建 1.4 完善Runner类 1.5 模型训练 1.6 模型评价 1.7 模型预测
思考
总结
参考文献 首先基础知识铺垫~
继续使用第三章中的鸢尾花分类任务#xff0c;将Softm…目录
1 小批量梯度下降法 1.0 展开聊一聊~ 1.1 数据分组 1.2 用DataLoader进行封装 1.3 模型构建 1.4 完善Runner类 1.5 模型训练 1.6 模型评价 1.7 模型预测
思考
总结
参考文献 首先基础知识铺垫~
继续使用第三章中的鸢尾花分类任务将Softmax分类器替换为前馈神经网络。
损失函数交叉熵损失优化器随机梯度下降法评价指标准确率
1 小批量梯度下降法 1.0 展开聊一聊~ 在梯度下降法中目标函数是整个训练集上的风险函数这种方式称为批量梯度下降法Batch Gradient DescentBGD。批量梯度下降法在每次迭代时需要计算每个样本上损失函数的梯度并求和。为了减少每次迭代的计算复杂度我们可以在每次迭代时只采集一小部分样本计算在这组样本上损失函数的梯度并更新参数这种优化方式称为小批量梯度下降法Mini-Batch Gradient DescentMini-Batch GD。 梯度下降算法一般情况下主要说的是三种批量梯度下降、随机梯度下降、小批量梯度下降。 知道大家跟我一样不爱看一大段一大段的定义巴拉巴拉一堆的所以我大概总结了一下快拿出你们的小本本 首先要明确梯度下降算法都是优化算法用于求解目标函数的最优参数: 批量梯度下降Batch Gradient DescentBGD随机梯度下降Stochastic Gradient DescentSGD小批量梯度下降Mini-Batch Gradient DescentMBGD 批量梯度下降BGD最早出现的梯度下降方法是批量梯度下降。BGD在每一次迭代中使用所有训练样本来计算梯度并更新模型参数,步骤如下: 对于每个训练样本计算梯度。将所有梯度求平均得到一个全局梯度。根据学习率和全局梯度更新模型参数。 优点 收敛性较好能够达到全局最优目标函数是凸函数。梯度计算相对准确参数更新稳定。收敛速度最快可以保证每一步都是准确地向着极值点的方向趋近所需要的迭代次数最少。 缺点 计算梯度时需要处理大量数据计算开销较大。参数更新只能在整个训练集上进行但大规模数据集通常会有大量冗余数据所以不适用于大规模数据集。容易陷入局部最优目标函数是非凸函数。 这里需要提一下~对所有样本的计算可以利用向量运算进行并行计算来提升运算速度。 随机梯度下降SGD为了解决批量梯度下降在处理大规模数据集时的计算开销问题随机梯度下降方法被提出。SGD在每一次迭代中仅使用一个训练样本来计算梯度并更新模型参数。具体步骤如下 随机选择一个训练样本。计算该样本的梯度。根据学习率和该样本的梯度更新模型参数。 优点 计算开销较小适用于大规模数据集。参数更新频繁可能更容易逃离局部最优。 缺点 每次迭代只使用一个样本但是单个样本计算出的梯度不能够很好的体现全体样本的梯度。参数更新的方向较不稳定可能会产生参数震荡。参数更新非常的频繁在最优点附近晃来晃去收敛速度大大降低。 小批量梯度下降MBGD为了兼顾批量梯度下降和随机梯度下降的优点小批量梯度下降方法被引入。小批量梯度下降算法又被叫做小批量随机梯度下降算法。MBGD在每一次迭代中使用一小部分训练样本通常称为mini-batch来计算梯度并更新模型参数。具体步骤如下 随机选择一小部分训练样本mini-batch。计算这些样本的梯度。根据学习率和这些样本的梯度更新模型参数。 优点 兼具BGD和SGD的优点计算开销适中参数更新相对稳定。可以利用矩阵运算的高效性提高计算效率。较容易并行化处理适用于大规模数据集。 缺点 学习率选择较为敏感需要进行合适的调参。 总结:三种梯度下降方法各有优劣。批量梯度下降收敛性好但计算开销大随机梯度下降计算开销小但更新不稳定小批量梯度下降在两者之间取得平衡并且对于大规模数据集有较好的适应性。在实际应用中根据具体问题的规模和特点选择合适的梯度下降方法。 1.1 数据分组 为了小批量梯度下降法我们需要对数据进行随机分组。目前机器学习中通常做法是构建一个数据迭代器每个迭代过程中从全部数据集中获取一批指定数量的数据。原理图展示一下: 首先将数据集封装为Dataset类传入一组索引值根据索引从数据集合中获取数据 其次构建DataLoader类需要指定数据批量的大小和是否需要对数据进行乱序通过该类即可批量获取数据。
import torch.utils.data as Dataclass IrisDataset(Data.Dataset):def __init__(self, modetrain, num_train120, num_dev15):super(IrisDataset, self).__init__()# 调用第三章中的数据读取函数其中不需要将标签转成one-hot类型X, y load_data(shuffleTrue)if mode train:self.X, self.y X[:num_train], y[:num_train]elif mode dev:self.X, self.y X[num_train:num_train num_dev], y[num_train:num_train num_dev]else:self.X, self.y X[num_train num_dev:], y[num_train num_dev:]def __getitem__(self, idx):return self.X[idx], self.y[idx]def __len__(self):return len(self.y) __getitem__根据给定索引获取数据集中指定样本并对样本进行数据处理 __len__返回数据集样本个数。 train_dataset IrisDataset(modetrain)
dev_dataset IrisDataset(modedev)
test_dataset IrisDataset(modetest)print(length of train set: , len(train_dataset)) 1.2 用DataLoader进行封装
batch_size 16# 加载数据
train_loader Data.DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue)
dev_loader Data.DataLoader(dev_dataset, batch_sizebatch_size)
test_loader Data.DataLoader(test_dataset, batch_sizebatch_size) 1.3 模型构建
class Model_MLP_L2_V3(nn.Module):def __init__(self, input_size, output_size, hidden_size):super(Model_MLP_L2_V3, self).__init__()# 构建第一个全连接层self.fc1 nn.Linear(input_size, hidden_size)# 构建第二全连接层self.fc2 nn.Linear(hidden_size, output_size)# 定义网络使用的激活函数self.act nn.Sigmoid()nn.init.normal_(self.fc1.weight, mean0., std0.01)nn.init.constant_(self.fc1.bias, 1.0)nn.init.normal_(self.fc2.weight, mean0., std0.01)nn.init.constant_(self.fc2.bias, 1.0)def forward(self, inputs):outputs self.fc1(inputs)outputs self.act(outputs)outputs self.fc2(outputs)return outputsfnn_model Model_MLP_L2_V3(input_size4, output_size3, hidden_size6) 1.4 完善Runner类
class Accuracy(object):def __init__(self, is_logistTrue):输入- is_logist: outputs是logist还是激活后的值# 用于统计正确的样本个数self.num_correct 0# 用于统计样本的总数self.num_count 0self.is_logist is_logistdef update(self, outputs, labels):输入- outputs: 预测值, shape[N,class_num]- labels: 标签值, shape[N,1]# 判断是二分类任务还是多分类任务shape[1]1时为二分类任务shape[1]1时为多分类任务if outputs.shape[1] 1: # 二分类outputs torch.squeeze(outputs, axis-1)if self.is_logist:# logist判断是否大于0preds (outputs 0).to(torch.float32)else:# 如果不是logist判断每个概率值是否大于0.5当大于0.5时类别为1否则类别为0preds (outputs 0.5).to(torch.float32)else:# 多分类时使用paddle.argmax计算最大元素索引作为类别preds torch.argmax(outputs, dim1).int()# 获取本批数据中预测正确的样本个数labels torch.squeeze(labels, dim-1)batch_correct float((preds labels).sum())# batch_correct torch.sum(torch.tensor(preds labels, dtypetorch.float32)).numpy()batch_count len(labels)# 更新num_correct 和 num_countself.num_correct batch_correctself.num_count batch_countdef accumulate(self):# 使用累计的数据计算总的指标if self.num_count 0:return 0return self.num_correct / self.num_countdef reset(self):# 重置正确的数目和总数self.num_correct 0self.num_count 0def name(self):return Accuracy 完善RunnerV3类
import torchclass RunnerV3(object):def __init__(self, model, optimizer, loss_fn, metric, **kwargs):self.model modelself.optimizer optimizerself.loss_fn loss_fnself.metric metric # 只用于计算评价指标# 记录训练过程中的评价指标变化情况self.dev_scores []# 记录训练过程中的损失函数变化情况self.train_epoch_losses [] # 一个epoch记录一次lossself.train_step_losses [] # 一个step记录一次lossself.dev_losses []# 记录全局最优指标self.best_score 0def train(self, train_loader, dev_loaderNone, **kwargs):# 将模型切换为训练模式self.model.train()# 传入训练轮数如果没有传入值则默认为0num_epochs kwargs.get(num_epochs, 0)# 传入log打印频率如果没有传入值则默认为100log_steps kwargs.get(log_steps, 100)# 评价频率eval_steps kwargs.get(eval_steps, 0)# 传入模型保存路径如果没有传入值则默认为best_model.pdparamssave_path kwargs.get(save_path, best_model.pdparams)custom_print_log kwargs.get(custom_print_log, None)# 训练总的步数num_training_steps num_epochs * len(train_loader)if eval_steps:if self.metric is None:raise RuntimeError(Error: Metric can not be None!)if dev_loader is None:raise RuntimeError(Error: dev_loader can not be None!)# 运行的step数目global_step 0# 进行num_epochs轮训练for epoch in range(num_epochs):# 用于统计训练集的损失total_loss 0for step, data in enumerate(train_loader):X, y data# 获取模型预测logits self.model(X)loss self.loss_fn(logits, y) # 默认求meantotal_loss loss# 训练过程中每个step的loss进行保存self.train_step_losses.append((global_step, loss.item()))if log_steps and global_step % log_steps 0:print(f[Train] epoch: {epoch}/{num_epochs}, step: {global_step}/{num_training_steps}, loss: {loss.item():.5f})# 梯度反向传播计算每个参数的梯度值loss.backward()if custom_print_log:custom_print_log(self)# 小批量梯度下降进行参数更新self.optimizer.step()# 梯度归零self.optimizer.zero_grad() #无clear_grad# 判断是否需要评价if eval_steps 0 and global_step 0 and \(global_step % eval_steps 0 or global_step (num_training_steps - 1)):dev_score, dev_loss self.evaluate(dev_loader, global_stepglobal_step)print(f[Evaluate] dev score: {dev_score:.5f}, dev loss: {dev_loss:.5f})# 将模型切换为训练模式self.model.train()# 如果当前指标为最优指标保存该模型if dev_score self.best_score:self.save_model(save_path)print(f[Evaluate] best accuracy performence has been updated: {self.best_score:.5f} -- {dev_score:.5f})self.best_score dev_scoreglobal_step 1# 当前epoch 训练loss累计值trn_loss (total_loss / len(train_loader)).item()# epoch粒度的训练loss保存self.train_epoch_losses.append(trn_loss)print([Train] Training done!)# 模型评估阶段使用paddle.no_grad()控制不计算和存储梯度torch.no_grad()def evaluate(self, dev_loader, **kwargs):assert self.metric is not None# 将模型设置为评估模式self.model.eval()global_step kwargs.get(global_step, -1)# 用于统计训练集的损失total_loss 0# 重置评价self.metric.reset()# 遍历验证集每个批次for batch_id, data in enumerate(dev_loader):X, y data# 计算模型输出logits self.model(X)# 计算损失函数loss self.loss_fn(logits, y).item()# 累积损失total_loss loss# 累积评价self.metric.update(logits, y)dev_loss (total_loss / len(dev_loader))dev_score self.metric.accumulate()# 记录验证集lossif global_step ! -1:self.dev_losses.append((global_step, dev_loss))self.dev_scores.append(dev_score)return dev_score, dev_loss# 模型评估阶段使用paddle.no_grad()控制不计算和存储梯度torch.no_grad()def predict(self, x, **kwargs):# 将模型设置为评估模式self.model.eval()# 运行模型前向计算得到预测值logits self.model(x)return logitsdef save_model(self, save_path):torch.save(self.model.state_dict(), save_path)def load_model(self, model_path):model_state_dict torch.load(model_path)self.model.load_state_dict(model_state_dict) 注意torch环境中没有clear_grad方法这儿需要调用zero_grad方法。 1.5 模型训练 这里把RunnerV3放入runner.py存储在nndl文件夹中
import torch.optim as opt
from nndl.runner import RunnerV3
import torch.nn.functional as Flr 0.2
# 定义网络
model fnn_model
# 定义优化器
optimizer opt.SGD(model.parameters(), lrlr)
# 定义损失函数。softmax交叉熵
loss_fn F.cross_entropy# 定义评价指标
metric Accuracy(is_logistTrue)runner RunnerV3(model, optimizer, loss_fn, metric) 使用训练集和验证集进行模型训练共训练150个epoch。在实验中保存准确率最高的模型作为最佳模型。
# 启动训练
log_steps 100
eval_steps 50
runner.train(train_loader, dev_loader,num_epochs150, log_stepslog_steps, eval_stepseval_steps,save_pathbest_model.pdparams) 可视化观察训练集损失和训练集loss变化情况,代码如下:
import matplotlib.pyplot as plt# 绘制训练集和验证集的损失变化以及验证集上的准确率变化曲线
def plot_training_loss_acc(runner, fig_name,fig_size(16, 6),sample_step20,loss_legend_locupper right,acc_legend_loclower right,train_color#e4007f,dev_color#f19ec2,fontsizelarge,train_linestyle-,dev_linestyle--):global dev_stepsplt.figure(figsizefig_size)plt.subplot(1, 2, 1)train_items runner.train_step_losses[::sample_step]train_steps [x[0] for x in train_items]train_losses [x[1] for x in train_items]plt.plot(train_steps, train_losses, colortrain_color, linestyletrain_linestyle, labelTrain loss)if len(runner.dev_losses) 0:dev_steps [x[0] for x in runner.dev_losses]dev_losses [x[1] for x in runner.dev_losses]plt.plot(dev_steps, dev_losses, colordev_color, linestyledev_linestyle, labelDev loss)# 绘制坐标轴和图例plt.ylabel(loss, fontsizefontsize)plt.xlabel(step, fontsizefontsize)plt.legend(locloss_legend_loc, fontsizex-large)# 绘制评价准确率变化曲线if len(runner.dev_scores) 0:plt.subplot(1, 2, 2)plt.plot(dev_steps, runner.dev_scores,colordev_color, linestyledev_linestyle, labelDev accuracy)# 绘制坐标轴和图例plt.ylabel(score, fontsizefontsize)plt.xlabel(step, fontsizefontsize)plt.legend(locacc_legend_loc, fontsizex-large)plt.savefig(fig_name)plt.show()plot_training_loss_acc(runner, fw-loss.pdf) 1.6 模型评价 使用测试数据对在训练过程中保存的最佳模型进行评价观察模型在测试集上的准确率以及Loss情况代码如下:
# 加载最优模型
runner.load_model(best_model.pdparams)
# 模型评价
score, loss runner.evaluate(test_loader)
print([Test] accuracy/loss: {:.4f}/{:.4f}.format(score, loss)) 1.7 模型预测 同样地也可以使用保存好的模型对测试集中的某一个数据进行模型预测观察模型效果。代码如下
# 获取测试集中第一条数据
X, label train_dataset[0]
logits runner.predict(X)pred_class torch.argmax(logits[0]).numpy()
label label.numpy()# 输出真实类别与预测类别
print(The true category is {} and the predicted category is {}.format(label, pred_class)) 思考
softmax、svm、前馈神经网络三种进行比较svm代码如下:
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import accuracy_score
def SVC_split(x_train, y_train, x_test, y_test):# 定义SVM分类器svm SVC()# 定义参数空间param_grid {C: [0.01, 0.1, 1, 10],kernel: [linear, rbf, poly],gamma: [scale, auto]}# 使用GridSearchCV进行交叉验证和参数选择grid_search GridSearchCV(svm, param_gridparam_grid, cv5)grid_search.fit(x_train, y_train.ravel())# 在测试集上评估模型性能y_pred grid_search.predict(x_test)accuracy accuracy_score(y_test, y_pred)print(Accuracy on test set: {:.2f}%.format(accuracy * 100))SVC_split(train_dataset.X,train_dataset.y ,test_dataset.X, test_dataset.y) 调用实验四的softmax函数的结果如下 很明显我们发现softmax回归的准确率远远低于前馈神经网络和svm简单总结一下都有什么原因吧 softmax回归是一个线性模型其只能学习到线性关系。对于复杂的非线性分类问题Softmax回归的表达能力可能不足以捕捉到数据中的更复杂模式。相比之下前馈神经网络具有更强大的非线性建模能力可以通过多个隐藏层和非线性激活函数来学习到更复杂的特征表示。SVM也可以通过核函数将低维输入映射到高维空间从而进行非线性分类。 由此得出结论但需要注意的是Softmax回归在所有二分类任务上表现都会远远低于前馈神经网络和SVM。对于一些简单的线性可分问题或数据分布较为简单的情况下Softmax回归可能表现得很好。然而对于更复杂的问题和数据集使用更复杂的模型如前馈神经网络和SVM通常能够获得更好的性能。 但是有个疑问前馈神经网络和SVM究竟哪个更好一点 简而言之神经网络是个“黑匣子”优化目标是基于经验风险最小化易陷入局部最优训练结果不太稳定一般需要大样本 而支持向量机有严格的理论和数学基础基于结构风险最小化原则, 泛化能力优于前者算法具有全局最优性, 是针对小样本统计的理论。 就目前我的理论知识好像想搞明白哪个好哪个坏可能有点难而且模型好像很难说哪个好哪个坏可能针对不同的数据集表现也会不一样害浅浅插个眼等之后对深度学习有了一定程度的了解的时候再回来看看有没有一个答案吧。 总结 到此为止前馈神经网络结束啦有了一点搭建神经网络的经验了吧大概流程如下: 定义网络结构首先需要确定网络的结构包括输入层、隐藏层和输出层的大小和数量。 初始化参数对于每个神经元需要初始化权重和偏置值。权重和偏置值通常是随机初始化的以避免初始状态过于相似导致模型收敛缓慢。 定义损失函数损失函数用来衡量预测值和真实值之间的误差。二分类问题通常使用交叉熵损失函数回归问题可以使用均方误差损失函数。 定义优化器优化器用于更新模型的参数使损失函数最小化。常见的优化器包括随机梯度下降 (SGD)、Adam等。 训练模型通过传递数据进行前向传播和反向传播更新模型的参数。在训练过程中需要将数据分为训练集、验证集和测试集。 模型评价在训练完成之后可以通过输入新数据并进行前向传播来得到预测结果。也可以进行可视化等等。 本次实验对前馈神经网络的应用有更为明确的理解同时针对softmaxsvm,CNN的对比在实验和搜索资料的过程中也明白了什么模型更适合应用在什么范围内softmax和CNN的具体的应用区别还没弄明白算是个小小的遗憾吧等有更多深度学习经验的时候看看能不能再回来解答这个问题吧~ 参考文献
torch.nn.Module所有方法总结及其使用举例_torch.nn.module cuda-CSDN博客torch.nn — PyTorch master documentation
NNDL 实验五 前馈神经网络3鸢尾花分类-CSDN博客神经网络 VS SVM_svm和神经网络的区别-CSDN博客