中国工业设计在线官网点击精灵seo
中国工业设计在线官网,点击精灵seo,永久免费企业网站申请,网站开发需求分析中性能需求注#xff1a;博主是初学者#xff0c;有些内容描述可能有误#xff0c;请见谅#xff01;本文内容使用jupyter notebook实现。
在代码实现前#xff0c;先简单介绍一下基础知识。
线性回归 线性回归是一种用于建立自变量#xff08;特征#xff09;与因变量#xff…注博主是初学者有些内容描述可能有误请见谅本文内容使用jupyter notebook实现。在代码实现前先简单介绍一下基础知识。线性回归线性回归是一种用于建立自变量特征与因变量目标之间线性关系的统计模型。它通过寻找一条最佳拟合直线在多元情况下是一个超平面来最小化预测值与实际值之间的误差平方和。这个模型可以表示为 y β₀ β₁x₁ β₂x₂ ... βₙxₙ ε其中 y 是因变量x 是自变量β 是需要估计的系数ε 是误差项。线性回归的核心思想是找到一组系数使得模型能最好地描述数据中的线性趋势常用于预测和因果关系分析。平方损失平方损失又称L2损失或均方误差是机器学习中最常用的损失函数之一它通过计算预测值与真实值之差的平方来衡量模型的误差大小。具体公式为 L(y, ŷ) (y - ŷ)²其中y是真实值ŷ是预测值。平方损失的核心特性是对较大误差给予更严重的惩罚因为平方放大了大误差的影响这使得模型会更积极地避免产生大的预测偏差。在线性回归中最小化平方损失等价于最小二乘法能给出最优的线性拟合。不过平方损失对异常值比较敏感因为异常值会产生巨大的平方误差可能过度影响模型参数。梯度下降梯度下降是机器学习中用来优化模型参数比如线性回归中的权重和偏置的核心算法。它的目标是最小化一个损失函数比如刚提到的平方损失函数。梯度下降的工作流程如下1初始化随机选择一个起点随机初始化模型参数。2计算梯度在当前位置计算损失函数的梯度。梯度是一个向量它指向山坡最陡峭的上升方向。那么它的反方向负梯度方向就是当前点最陡峭的下降方向。3更新参数沿着负梯度方向迈出一步。这一步的大小由一个关键参数控制叫做学习率lr。4更新公式对于参数 ww_new w_old - 学习率 * 梯度不断重复第2和第3步计算新位置的梯度并更新直到梯度变得非常小接近零意味着已经到了平地/谷底或达到预设的迭代次数。它的核心思想就是通过迭代一步步朝着使损失函数值减少最快的方向调整参数最终逼近最优解学习率的选择十分重要学习率太大步子迈得太大会直接“跨过”最优点导致损失值在最优值两侧剧烈震荡、甚至发散损失值不降反增最终变成NaN优化彻底失败。学习率太小损失函数虽然会稳定下降但速度极慢。这不仅需要极长的训练时间还可能陷入局部最优点或鞍点而无法逃脱因为每次更新的“力量”太微弱。固定不变的学习率并非最优在整个训练过程中模型的需求是变化的。初期我们希望大步快速接近目标区域后期则希望小步精调稳定收敛到最优点。一个固定的学习率难以同时满足这两个阶段的需求。技巧方法1粗略搜索与可视化在正式训练前进行学习率扫描是至关重要的一步。具体做法是选择一系列呈指数级增长的学习率候选值如0.0001、0.001、0.01、0.1、1每个值仅训练几个周期同时记录并绘制损失曲线。通过观察这些曲线可以直观判断学习率的合适程度理想的学习率会使损失在初期快速且平稳下降曲线呈现漂亮的下降趋势过大的学习率会导致损失剧烈震荡甚至爆炸式上升过小的学习率则表现为损失下降极其缓慢几乎呈水平线。这个方法被业界称为LR Range Test它能快速排除明显不合适的学习率为后续精细调参确定一个合理范围是确定初始学习率最实用的经验法则。2自适应优化器现代深度学习中手动调整固定学习率的做法已经基本被淘汰取而代之的是自适应优化器。这类优化器能够为每个参数动态调整学习步长考虑到了梯度的一阶矩均值和二阶矩方差从而在不同参数、不同训练阶段使用不同的有效学习率。最典型的代表是Adam优化器它巧妙融合了动量法Momentum的方向稳定性和RMSProp的自适应学习率特性在大多数任务上都能取得不错的默认表现大大降低了调参门槛。对于更复杂的场景AdamW作为改进版本通过修正权重衰减的实现方式解决了Adam在权重正则化上的缺陷在训练Transformer等现代架构时表现尤为出色已成为当前许多SOTA模型的标准配置。但是使用自适应优化器不代表学习率可以随便设置只是大大放宽了对学习率设置的精确度要求提供了更宽的“安全区间”简化调参。3学习率调度器学习率调度器是管理学习率动态变化的核心工具它定义了学习率随训练进程变化的策略。一个精心设计的调度策略能显著提升模型性能和训练效率。最基本的策略包括热身阶段——训练初期使用极小学习率使梯度统计稳定然后线性增加到预设值warmup衰减阶段则是在训练后期逐步降低学习率以实现精细收敛。更高级的策略如余弦退火将学习率变化模拟为半个余弦周期从最大值平滑衰减到零有时还会结合周期性重启在衰减到最小值后突然跳回较高值这种重启机制能帮助模型跳出局部最优探索更好的解空间。实践表明合理的调度策略往往比单纯寻找一个完美固定学习率带来更大收益。为什么要使用梯度下降要解决这个问题首先要介绍一下解析解显示解、闭式解。1有解析解的情况以简单线性回归为例对于最基本的线性回归使用平方损失函数可以通过严格的数学公式如求导并令导数为零直接解出一组最优参数 (w*, b*)。这组解是一个明确的数学表达式一步计算就能得到这就是解析解。优点精确、一步到位、计算高效对于数据量不是特别大的情况。缺点有严格前提。它要求损失函数是凸的且可导并且求解过程如计算矩阵的逆在数据特征维度很高或数据量极大时会变得计算量巨大、甚至不可行矩阵可能不可逆或求逆的计算复杂度为O(n³)代价过高。2没有解析解或解析解不可行的情况模型复杂。当模型不再是简单的线性回归而是像神经网络这样极其复杂的非线性模型时其损失函数会变成一个非常复杂、非凸的函数根本无法通过解方程 梯度0 来求得全局最优解。数据量大。即使对于线性模型当数据有百万甚至上亿条时计算解析解所需的矩阵运算在内存和计算时间上都是噩梦。损失函数不可导。有些模型的损失函数本身不具备处处可导的性质无法用求导的方法找解析解。这时梯度下降的优势就体现出来了。梯度下降是一种“数值优化方法”。它不试图去直接“解方程”找到那个精确的数学解而是像蒙眼下山的登山者一样采用一种迭代逼近的策略。梯度下降几乎适用于任何可微的损失函数和模型结构是训练复杂模型如深度学习的基石。可以与随机梯度下降或小批量梯度下降结合。不需要对整个庞大的数据集计算梯度那计算量也很大而可以每次只用一个或一小批数据来估计梯度。这大大降低了每次迭代的计算成本使得处理海量数据成为可能。所以在面对没有解析解或求解解析解不现实的复杂问题时梯度下降提供了一条切实可行的寻优路径。随机梯度下降SGD随机梯度下降是梯度下降的一种高效变体它不再每次迭代都计算整个数据集的梯度计算成本极高而是每次随机抽取一个样本来计算梯度并更新模型参数。这种做法的核心优势在于极大地提高了计算效率使得在海量数据集上训练模型成为可能同时由于引入的随机噪声它有助于模型跳出局部最优解增加找到全局最优的机会。不过单个样本的梯度估计方差较大会导致优化路径剧烈震荡因此现代实践中更常采用折衷的小批量随机梯度下降即每次使用一小批数据来计算梯度在效率、稳定性和收敛性之间取得了最佳平衡。线性回归代码实现首先打开Anaconda Prompt输入jupyter notebook。可以复制网址浏览器打开。创建新的notebook进行代码编写因为jupyter notebook方便编写代码同时可视化所以现在使用这个。1定义一个函数 synthetic_data用于生成简单的人工数据带噪声的线性数据。import numpy as np import torch from torch.utils import data def synthetic_data(true_w, true_b, num_examples): 生成合成的线性回归数据集 参数: true_w: 真实权重 (list 或 torch.Tensor) true_b: 真实偏置 (float) num_examples: 样本数量 (int) 返回: features: 特征矩阵 (torch.Tensor, shape: [num_examples, len(true_w)]) labels: 标签向量 (torch.Tensor, shape: [num_examples]) # 安全地将 true_w 转换为不带梯度的 Tensor if isinstance(true_w, torch.Tensor): w true_w.clone().detach() else: w torch.tensor(true_w, dtypetorch.float32) num_inputs w.numel() # 元素个数即特征维度 features torch.randn(num_examples, num_inputs) labels features w true_b # 使用 运算符更简洁 labels torch.normal(0, 0.01, sizelabels.shape) return features, labels.unsqueeze(1)参数true_w真实的权重向量可以是 Python 列表或 PyTorch 张量例如 [2.0, -3.4]。true_b真实的偏置标量浮点数例如 4.2。num_examples要生成的样本数量例如 1000。处理权重 true_wif isinstance(true_w, torch.Tensor): w true_w.clone().detach() else: w torch.tensor(true_w, dtypetorch.float32)安全地将 true_w 转换为一个不带梯度、不参与计算图的张量。如果输入是 torch.Tensor就用 .clone().detach() 复制一份避免意外修改原张量或保留梯度。如果是列表如 [2, -3.4]就转成 torch.Tensor并指定数据类型为 float32PyTorch 默认训练类型。生成特征 featuresnum_inputs w.numel() # 元素个数即特征维度 features torch.randn(num_examples, num_inputs)w.numel()获取权重中元素个数即输入特征的维度例如 w [2, -3.4] → num_inputs 2。torch.randn(...)从标准正态分布均值 0标准差 1中随机生成 num_examples × num_inputs 的矩阵。1000 个样本每个有 2 个特征→ features.shape (1000, 2)生成标签 labels带噪声labels features w true_bfeatures w矩阵乘法等价于 torch.matmul(features, w)。features: [1000, 2]结果[1000] —— 每个样本的线性预测值 true_b加上偏置项得到“真实”标签无噪声。labels torch.normal(0, 0.01, sizelabels.shape)添加高斯噪声均值为 0标准差为 0.01。模拟现实数据中的测量误差或随机扰动。使问题更贴近真实场景否则模型会过拟合“完美”数据。生成数据查看数据。2定义一个 load_array 的函数将 PyTorch 张量封装成可批量迭代的数据加载器DataLoader。参数data_arrays一个元组包含多个张量通常是 (features, labels)。batch_size每个批次batch包含多少样本例如 10。is_train布尔值控制是否打乱数据顺序训练时通常打乱测试时不打乱。def load_array(data_arrays, batch_size, is_trainTrue): 构造一个PyTorch数据迭代器。 dataset data.TensorDataset(*data_arrays) return data.DataLoader(dataset, batch_size, shuffleis_train) batch_size 10 data_iter load_array((features, labels), batch_size) next(iter(data_iter))创建 Datasetdataset data.TensorDataset(*data_arrays)data 是 torch.utils.data 的别名需提前导入from torch.utils import data。TensorDataset 是 PyTorch 内置类用于将多个张量打包成一个数据集。*data_arrays 是 Python 的“解包”操作如果传入 (features, labels)那么 *data_arrays 相当于 features, labels所以这行等价于dataset data.TensorDataset(features, labels)TensorDataset 的作用当用 dataset[i] 时会返回 (features[i], labels[i]) 这个样本对。创建 DataLoaderreturn data.DataLoader(dataset, batch_size, shuffleis_train)DataLoader 是 PyTorch 的核心工具用于按批次加载数据支持多线程、打乱顺序等。返回的是一个可迭代对象DataLoader 实例可以用 for X, y in data_iter: 遍历。参数dataset上面创建的 TensorDataset。batch_size10每次迭代返回 10 个样本。shuffleis_train如果 is_trainTrue默认每个 epoch 开始前打乱样本顺序防止模型记住顺序提升泛化。如果 is_trainFalse如验证/测试则保持原始顺序。注data_iter 就是 torch.utils.data.DataLoader 的一个实例用于按批次batch_size自动加载和打乱数据每次迭代返回一个 (features, labels) 元组供模型训练使用。3定义网络随机初始参数、损失函数from torch import nn net nn.Sequential(nn.Linear(2, 1)) net[0].weight.data.normal_(0, 0.01) net[0].bias.data.fill_(0) loss nn.MSELoss() trainer torch.optim.SGD(net.parameters(), lr0.03)from torch import nn导入 PyTorch 的神经网络模块。nn 是 torch.nn 的别名包含所有层如 Linear, Conv2d、损失函数如 MSELoss和优化器等。使用 nn.Sequential 可以方便地堆叠多个层。net nn.Sequential(nn.Linear(2, 1))创建一个简单的神经网络模型。nn.Linear(2, 1)全连接层线性层输入维度为 2输出维度为 1。适用于二特征 → 一标签的线性回归任务。数学形式 yWxb。nn.Sequential(...)将层按顺序封装成一个网络。这里只有一个层所以 net[0] 就是这个 Linear 层。net[0].weight.data.normal_(0, 0.01)初始化权重矩阵 W。net[0]访问第一个也是唯一一个层。.weight获取该层的权重参数张量。.data获取参数的底层数据不带梯度信息。.normal_(0, 0.01)原地操作将权重初始化为均值为 0、标准差为 0.01 的正态分布随机数。避免初始值过大导致训练不稳定。是常见的初始化方式。W 被设为类似 [ [0.012, -0.008] ] 的小数值。net[0].bias.data.fill_(0)初始化偏置项 b。.bias获取偏置参数。.fill_(0)原地操作将偏置设为 0。初始时假设没有偏移由训练过程自动学习。b 0.0loss nn.MSELoss()定义损失函数均方误差Mean Squared Error。常用于回归任务。输入要求预测值 net(X) 和真实值 y 形状必须一致例如都是 [batch_size, 1]。trainer torch.optim.SGD(net.parameters(), lr0.03)创建优化器随机梯度下降SGD。net.parameters()返回模型中所有可训练参数包括 weight 和 bias。lr0.03学习率控制每次更新步长大小。太大容易震荡太小收敛慢。0.03 是常见选择适合简单问题。每次调用 trainer.step() 会根据梯度更新 W 和 b。4训练代码num_epochs 3 for epoch in range(num_epochs): for X, y in data_iter: l loss(net(X), y) trainer.zero_grad() l.backward() trainer.step() # 计算整个数据集上的损失用于监控 with torch.no_grad(): l loss(net(features), labels) print(fepoch {epoch 1}, loss {l:.6f}) # 最终结果对比 print(f真实权重: {true_w}, 学习到的权重: {net[0].weight.data.reshape(-1)}) print(f真实偏置: {true_b:.2f}, 学习到的偏置: {net[0].bias.data.item():.2f})num_epochs 3设置训练轮数为 3 次。每个 epoch 表示遍历完整个数据集一次。for epoch in range(num_epochs):外层循环执行 3 轮训练。for X, y in data_iter:内层循环。遍历 data_iter一个 DataLoader 对象每次取出一个批次batch_size的数据其中 X 是该批次的输入特征y 是对应的标签。data_iter 是由 DataLoader 创建的迭代器每次返回X: 特征张量形状如 [batch_size, 2]y: 标签张量形状如 [batch_size, 1]l loss(net(X), y)前向传播net(X)将输入 X 输入模型得到预测值形状同 y。loss(...)计算预测值与真实值之间的均方误差MSE。l 是当前 batch 的损失值标量张量。trainer.zero_grad()清空上一轮的梯度。因为 PyTorch 默认会累加梯度grad所以每轮前必须手动清零。必须在 backward() 之前调用l.backward()反向传播。自动计算损失对所有可训练参数W, b的梯度。使用链式法则递归求导。此时 net[0].weight.grad 和 net[0].bias.grad 被填充了梯度值。trainer.step()更新模型参数。使用优化器SGD根据梯度更新 W 和 b。这一步是“学习”的核心。with torch.no_grad():上下文管理器。进入无梯度模式。避免在计算验证损失时记录梯度节省内存防止误更新。l loss(net(features), labels)计算整个数据集上的损失不是单个 batch。用于监控训练效果。这里 features 和 labels 是完整的原始数据1000 个样本。print(fepoch {epoch 1}, loss {l:.6f})打印当前 epoch 的损失。{l:.6f}保留 6 位小数便于观察收敛情况。