正则化正则化Regularization是一种在训练机器学习模型过程中在损失函数中添加额外项来惩罚过大的参数进而限制模型复杂度、避免过拟合提高模型泛化能力的技术。正则化最常用的两种技术方法是L1和L2正则化L1正则化Lasso回归: L1正则化在损失函数中加入参数的绝对值之和。L1正则化通过惩罚模型参数的绝对值使得部分权重趋近0甚至变为0。这会导致特征选择即模型会自动“丢弃”一些不重要的特征。L1正则化有助于创建稀疏模型即许多参数为0。在解决回归问题时使用L1正则化也被称为“Lasso回归”其超参数λ控制着正则化的强度。一句话简单理解超参数λ取较大的值意味着强烈的正则化会使模型更简单可能导致欠拟合而较小的值则会使模型更复杂可能导致过拟合。L2正则化Ridge回归L2正则化在损失函数中加入参数的平方之和L2正则化通过惩罚模型参数的平方使得所有参数都变得更小但不会将参数强行压缩为0。它会使得模型尽量平滑从而防止过拟合。在解决回归问题时使用L2正则化也被称为“Ridge回归”或者“岭回归”上述正则化技术方法中关于超参数本文中是惩罚系数λ的理解在机器学习中超参数是模型训练前预设的、不能从数据中直接学习的配置参数如学习率、网络层数、正则化强度它们控制着模型的结构、训练过程与复杂度优化其选择直接影响模型的性能与泛化能力通常需要通过经验、网格搜索或贝叶斯优化等方法进行调优是连接算法设计与实际应用效果的关键环节。案例使用多项式在 x∈[-3.5,3.5] 区间上拟合sin(x)函数分别使用不正则化、L1正则化和L2正则化技术进行拟合说明同简单的线性回归一样L1正则化Lasso回归和L2正则化Ridge回归都封装在sklearn库中通过sklearn库可以直接调用importnumpyasnpimportmatplotlib.pyplotaspltfromsklearn.model_selectionimporttrain_test_splitfromsklearn.linear_modelimportLinearRegression,Lasso,Ridgefromsklearn.metricsimportmean_squared_error# 全局设置解决字体不显示问题plt.rcParams[font.sans-serif][SimHei]plt.rcParams[axes.unicode_minus]Falsedefpolynomial(x,degree):returnnp.hstack([x**iforiinrange(1,degree1)])# 生成随机数据Xnp.linspace(-3.5,3.5,300).reshape(-1,1)ynp.sin(X)np.random.uniform(-0.55,0.55,X.size).reshape(-1,1)figs,axplt.subplots(2,3,figsize(15,8))ax[0,0].plot(X,y,go)ax[0,1].plot(X,y,go)ax[0,2].plot(X,y,go)# 划分训练集和测试集x_train,x_test,y_train,y_testtrain_test_split(X,y,test_size0.25,random_state22)x_train1polynomial(x_train,20)x_test1polynomial(x_test,20)# 不使用正则化modelLinearRegression()model.fit(x_train1,y_train)y_pred3model.predict(x_test1)# 预测ax[0,0].plot(X,model.predict(polynomial(X,20)),r)# 绘制曲线ax[0,0].text(-3.4,1,f测试集均方误差{mean_squared_error(y_test,y_pred3):.4f})ax[0,0].text(-3.4,1.2,不使用正则化拟合)ax[1,0].bar(np.arange(20),model.coef_.reshape(-1),colorr)# 绘制所有的拟合系数ax[1,0].set_ylabel(各项拟合系数)# L1正则化-Lasso回归lassoLasso(alpha0.01)# alpha就是λ超参数lasso.fit(x_train1,y_train)# 模型训练y_pred3lasso.predict(x_test1)# 预测ax[0,1].plot(X,lasso.predict(polynomial(X,20)),r)# 绘制曲线ax[0,1].text(-3.4,1,f测试集均方误差{mean_squared_error(y_test,y_pred3):.4f})ax[0,1].text(-3.4,1.2,Lasso回归)ax[1,1].bar(np.arange(20),lasso.coef_,colorr)# 绘制所有拟合系数ax[1,1].set_ylabel(各项拟合系数)# L2正则化-Ridge回归ridgeRidge(alpha1)# 同理alpha就是λ超参数ridge.fit(x_train1,y_train)# 模型训练y_pred3ridge.predict(x_test1)# 预测ax[0,2].plot(X,ridge.predict(polynomial(X,20)),r)# 绘制曲线ax[0,2].text(-3.4,1,f测试集均方误差{mean_squared_error(y_test,y_pred3):.4f})ax[0,2].text(-3.4,1.2,Ridge回归)ax[1,2].bar(np.arange(20),ridge.coef_,colorr)# 绘制所有系数ax[1,2].set_ylabel(各项拟合系数)plt.savefig(G:/learning video/L1.jpg,dpi400)plt.show()交叉验证交叉验证Cross-Validation是一种评估模型泛化能力的方法通过将数据集划分为多个子集反复进行训练和验证以减少因单次数据划分带来的随机性误差。通过交叉验证能更可靠地估计模型在未知数据上的表现亦能避免因单次数据划分不合理导致的模型过拟合或欠拟合常用的数据划分方法包括简单交叉验证、K折交叉验证和留一交叉验证。其中K折交叉验证是应用最为广泛的数据划分方法。简单交叉验证Hold-Out Validation只将数据划分为训练集和验证集如70%训练30%验证其结果受单次划分影响较大可能高估或低估模型性能K折交叉验证k-Fold Cross-Validation将数据均匀分为k个子集称为“折”每次用k−1折训练剩余1折验证重复k次后取平均性能留一交叉验证Leave-One-OutLOO每次仅留一个样本作为验证集其余全部用于训练重复直到所有样本都被验证一次。适用于小数据集计算成本极高。关注梯度下降法模型的求解评估策略就是让结构化的经验风险最小即让模型的损失函数值最小化称为结构风险最小化Structural Risk MinimizationSRM对于如上损失函数而言本质就是求解一个最优化问题。代入训练集所有数据要求最小值的目标函数就是模型中参数的函数其具体求解的算法可以利用数学公式直接计算解析解解析法也可以使用迭代算法梯度下降法。解析法如果模型损失函数的最小值可以通过数学公式进行严格推导得到一个解析解那么就直接得到了最优模型的全部参数这种方法称作解析法。要求目标函数必须可导且导数方程有解析解对于上述的L2正则化-Ridge回归咱们可以通过数学公式推导求解出解析解梯度下降法梯度下降法是迭代算法基本思路就是先选取一个适当的初始值然后沿着负梯度方向不停地更新参数最终取到极小值。这里的▽L(θn)是参数取值为θn 时损失函数的梯度α是每次迭代的“步长”称为“学习率”。学习率是一个常见的超参数需要手动设置选择不当会导致收敛失败。梯度方向 函数变化增长最快的方向变量沿此方向变化时函数增长最快负梯度方向函数变化减少最快的方向变量沿此方向变化时函数减少最快损失函数是模型参数的函数那么参数沿着损失函数的负梯度方向变化此时损失函数减少最快能够以最快速度下降到极小值在梯度下降法中可以更细致的分为三类批量梯度下降Batch Gradient DescentBGD每次迭代使用全部训练数据计算梯度。其优势为稳定收敛劣势为计算复杂、开销大随机梯度下降Stochastic Gradient DescentSGD每次迭代随机选取一个样本计算梯度。很明显优势为速度快、参数更新快劣势为梯度更新方向不稳定优化过程震荡幅度较大可能难以收敛小批量梯度下降Mini-batch Gradient DescentMBGD每次迭代使用一小批样本计算梯度。该方法平衡了上述两种方法是后续学习中最常使用的梯度下降算法案例以一个单变量函数为例介绍梯度下降法的代码实现importnumpyasnpimportmatplotlib.pyplotasplt# 1. 定义损失函数与梯度defJ(x):return(x**2-5)**2defgrad_J(x):return4*x*(x**2-5)# 2. 梯度下降过程lr0.058# 学习率超参数手动调节n_iter8x01.40# 初始点x_history[x0]xx0for_inrange(n_iter):xx-lr*grad_J(x)x_history.append(x)x_historynp.array(x_history)J_historyJ(x_history)# 3. 绘制损失函数曲线x_plotnp.linspace(1.3,3,400)J_plotJ(x_plot)plt.figure(figsize(6,4))# 3.1 损失函数plt.plot(x_plot,J_plot,colorblack,linewidth1)# 3.2 梯度下降轨迹plt.plot(x_history,J_history,colorred,markero,markersize6,linewidth1.8)# 3.3 绘图细节plt.xlabel(x)plt.ylabel(J(x))plt.title(Gradient Descent Trajectory on J(x))plt.grid(False)plt.tight_layout()plt.savefig(gradient.png,dpi600,bbox_inchestight)plt.show()指数加权平均 指数移动加权平均演示进30天天气分布情况 针对于β调节权重系数来讲其值越大越依赖指数加权平均越不依赖本地的梯度值数据越平缓 importtorchimportmatplotlib.pyplotasplt ELEMENT_NUMBER30# 1.实际平均问题defdm01():torch.manual_seed(0)# 产生30天的随机温度temperaturetorch.randn(size[ELEMENT_NUMBER,])*10print(temperature)# 绘制平均温度daystorch.arange(1,ELEMENT_NUMBER1,1)plt.plot(days,temperature,colorr)plt.scatter(days,temperature)plt.show()# 指数加权平均温度defdm02():torch.manual_seed(0)temperaturetorch.randn(size[ELEMENT_NUMBER,])*10exp_weight_avg[]foridx,tempinenumerate(temperature,1):# 第一个元素的EWA值等于自身ifidx1:exp_weight_avg.append(temp)continue# 第二个元素的EWA等于上一个EMA乘以β 当前气温乘以1-βnew_tempexp_weight_avg[idx-2]*beta(1-beta)*temp exp_weight_avg.append(new_temp)daystorch.arange(1,ELEMENT_NUMBER1,1)plt.plot(days,exp_weight_avg,colorr)plt.scatter(days,temperature)plt.show()if__name____main__:dm01()# 不考虑权重系数每个值的权重都一致dm02(0.5)# 考虑权重系数值越小数据越陡dm02(0.9)# 考虑权重系数值越大数据越平缓思路一基于SGD随机梯度下降加入参数Momentum就是动量法参数1 待优化的参数列表 参数2 学习率 参数3 动量参数optimizer optim.SGD(params[w],lr0.01,momentum0.9) 默认moment0 只考虑本次梯度思路二基于AdaGrad(自适应学习率)optimizer optim.Adagrad(params[w],lr0.01)思路三基于RMSProp自适应学习率optimizer - optim.RMSprop(params[w],lr0.01,alpha0.99) 梯度下降优化方法结合本次损失函数的导数作为梯度基于学习率更新权重 W新 W旧 - 学习率 * 梯度 存在问题 1.遇到平缓区域梯度下降权重更新可能会慢 2.可能会遇到鞍点梯度为0 3.可能会遇到局部最小值 解决方案 动量法Momentum St β * St - 1 (1 - β) * Gt 加入动量法后的梯度公式W新 W旧 - 学习率 * St St 本次的指数移动加权平均结果 β 调节权重系数越大数据越平稳历史指数移动加权平均比重越大本次梯度权重越小 St - 1 历史的指数移动加权平均结果 Gt 本次计算出的梯度不考虑历史梯度 自适应学习率AdaGrad St St - 1 Gt * Gt St 累计平方梯度 St-1 历史累计平方梯度 Gt 本次的梯度 学习率 学习率/(sqrt(St) 小常数) 小常熟1e-10 目的是防止分母变为0 梯度下降公式W新 W旧 - 调整后的学习率 * Gt 缺点可能导致学习率过早过量的降低导致模型后期学习率太小较难找到最优解 自适应学习率RMSProp——对AdaGrad做的优化加入调和权重系数 St β * St - 1 (1 - β) * Gt * Gt St 累计平方梯度 St - 1 历史累计平方梯度 Gt 本次梯度 β 调和权重系数 学习率 学习率/(sqrt(St) 小常数) 小常熟1e-10 目的是防止分母变为0 梯度下降公式W新 W旧 - 调整后的学习率 * Gt 优点RMSProp通过引入衰减系数β控制历史梯度对历史梯度信息获取多少 综合测量AdamAdaptive Moment Estimation 既优化学习率又优化梯度 一阶距Mt β1 * 二阶距 importtorchimporttorch.nnasnn# 定义函数梯度下降优化方法——动量法Momentumdefdm01_moment():# 1.初始化权重参数wtorch.tensor([1.0],requires_gradTrue,dtypefloat)# 2.定义损失函数criterion((w**2)/2.0)# 3.创建优化器函数对象-基于SGD随机梯度下降 加入参数momentum,就是动量法# 参数一待优化的参数列表 参数二学习率 参数三动量参数optimizeroptim.SGD(params[w],lr0.01,momentum0.9)# 4.计算梯度值梯度清零反向传播参数更新optimizer.zero_grad()criterion.sum().backward()optimizer.step()print(fw:{w},w.grad:{w.grad})# 5.重复上述步骤criterion((w**2)/2.0)optimizer.zero_grad()criterion.sum().backward()optimizer.step()print(fw:{w},w.grad:{w.grad})# 定义函数梯度下降优化方法——自适应学习率AdaGraddefdm02_adagrad():# 1.初始化权重参数wtorch.tensor([1.0],requires_gradTrue,dtypefloat)# 2.定义损失函数criterion((w**2)/2.0)# 3.创建优化器函数对象-基于SGD随机梯度下降 加入参数momentum,就是动量法# 参数一待优化的参数列表 参数二学习率 参数三动量参数optimizeroptim.Adagrad(params[w],lr0.01)# 4.计算梯度值梯度清零反向传播参数更新optimizer.zero_grad()criterion.sum().backward()optimizer.step()print(fw:{w},w.grad:{w.grad})# 5.重复上述步骤criterion((w**2)/2.0)optimizer.zero_grad()criterion.sum().backward()optimizer.step()print(fw:{w},w.grad:{w.grad})# 定义函数梯度下降优化方法RMSPropdefdm03_rmsprop():# 1.初始化权重参数wtorch.tensor([1.0],requires_gradTrue,dtypefloat)# 2.定义损失函数criterion((w**2)/2.0)# 3.创建优化器optimizeroptim.RMSporp(params[w],lr0.01,alpha0.99)# 4.计算梯度值梯度清零反向传播参数更新optimizer.zero_grad()criterion.sum().backward()optimizer.step()print(fw:{w},w.grad:{w.grad})criterion((w**2)/2.0)optimizer.zero_grad()criterion.sum().backward()optimizer.step()print(fw:{w},w.grad:{w.grad})