正则化

正则化(Regularization)是一种在训练机器学习模型过程中,在损失函数中添加额外项,来惩罚过大的参数,进而限制模型复杂度、避免过拟合,提高模型泛化能力的技术。

正则化最常用的两种技术方法是L1和L2正则化

L1正则化(Lasso回归): L1正则化在损失函数中加入参数的绝对值之和。
在这里插入图片描述

L1正则化通过惩罚模型参数的绝对值,使得部分权重趋近0甚至变为0。这会导致特征选择,即模型会自动“丢弃”一些不重要的特征。
L1正则化有助于创建稀疏模型(即许多参数为0)。
在解决回归问题时,使用L1正则化也被称为“Lasso回归”,其超参数λ控制着正则化的强度。一句话简单理解:超参数λ取较大的值意味着强烈的正则化,会使模型更简单,可能导致欠拟合;而较小的值则会使模型更复杂,可能导致过拟合。

L2正则化(Ridge回归):L2正则化在损失函数中加入参数的平方之和
在这里插入图片描述
L2正则化通过惩罚模型参数的平方,使得所有参数都变得更小,但不会将参数强行压缩为0。它会使得模型尽量平滑,从而防止过拟合。在解决回归问题时,使用L2正则化也被称为“Ridge回归”或者“岭回归”

上述正则化技术方法中,关于超参数(本文中是惩罚系数λ)的理解:在机器学习中,超参数是模型训练前预设的、不能从数据中直接学习的配置参数(如学习率、网络层数、正则化强度),它们控制着模型的结构、训练过程与复杂度优化,其选择直接影响模型的性能与泛化能力,通常需要通过经验、网格搜索或贝叶斯优化等方法进行调优,是连接算法设计与实际应用效果的关键环节。

"""
	L1正则化,权重可以变为0,相当于降维
	L2正则化,权重可以无限接近0
	DropOut,随机失活,每批次样本训练时,随机让一部分神经元死亡,防止一些特征对结果影响较大(防止过拟合)
	
"""
def dm01():
	# 1.创建隐藏层输出结果
	t1 = torch.randint(0,10,size=(1,4)).float()

	# 2.进行下一层,加权求和、激活函数计算
	linear1 = nn.Linear(4,4)

	l1 = linear1(t1) # 加权求和

	# 激活函数
	output = torch.relu(l1)

	# 3.对激活值进行随机失活dropout处理->,只有训练阶段有,测试阶段没有
	dropout = nn.Dropout(p=0.4) # 每个神经元只有40%的概率被kill

	d1 = dropout(output)
	print(f'd1(随机失活后的数据):{d1}')

在这里插入图片描述

"""
批量归一化属于正则化的一种,用于缓解模型过拟合

思路:
	先对数据标准化(会丢失一些信息),然后再对数据缩放(γ,理解为:w权重)和平移(β,理解为:b偏置),补回一些信息
	
应用场景:
	批量归一化在计算机视觉领域使用较多

BatchNorm1d 主要用于全连接层或处理一维数据的网络,例如文本处理,接受形状为(N,num_features)的张量作为输入
BatchNorm2d 主要用于卷积神经网络,处理二维图像数或特征图,接受形状为(N,C,H,W)的张量作为输入
BatchNorm3d 主要用于三维卷积神经网络(3D CNN),处理三维数据,例如视频或医学图像,接受形状(N,C,D,H,W)作为收入
"""
import torch
import torch.nn

def dm01():
	# 1.创建图像样本,1张图片,2个通道,3行4列(像素点)
	input_2d = torch.randn(size=(1,2,3,4))
	print(f'input_2d:{input_2d}')

	# 2.创建批量归一化(BN层)
	# 参数:输入特征数=图片图倒数  噪声值(小常数,默认1e-5)  动量值(用于计算移动平局统计量的)  
	bn2d = nn.BatchNorm2d(num_features=2,eps=1e-5,momentum=0.1,affine=True)

	# 3.对数据进行批量归一化处理
	output_2d = bn2d(input_2d)
	print(f'output_2d:{output_2d}')

# 处理一维数据
def dm02():
	input_id = torch.randn(size=(2,2))
	print(f'input_id:{input_id}')

	# 先进行线性处理
	linear1 = nn.Linear(2,4)

	l1 = linear(input_ld)
	print(f'l1:{l1}')

	bn1d = nn.BatchNorm1d(num_features=4)
	output_1d = bn1d(l1)
	print(f'output_1d:{output_1d}')

案例:使用多项式在 x∈[-3.5,3.5] 区间上,拟合sin(x)函数

分别使用不正则化、L1正则化和L2正则化技术进行拟合

说明:同简单的线性回归一样,L1正则化(Lasso回归)和L2正则化(Ridge回归)都封装在sklearn库中,通过sklearn库可以直接调用

import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression,Lasso,Ridge
from sklearn.metrics import mean_squared_error

# 全局设置,解决字体不显示问题
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

def polynomial(x, degree):
	return np.hstack([x**i for i in range(1, degree + 1)])

# 生成随机数据
X = np.linspace(-3.5, 3.5, 300).reshape(-1, 1)
y = np.sin(X) + np.random.uniform(-0.55, 0.55, X.size).reshape(-1, 1)
figs, ax = plt.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_test = train_test_split(X, y, test_size=0.25, random_state=22)
x_train1 = polynomial(x_train, 20)
x_test1 = polynomial(x_test, 20)

# 不使用正则化
model = LinearRegression()
model.fit(x_train1, y_train)
y_pred3 = model.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),color='r')  # 绘制所有的拟合系数
ax[1, 0].set_ylabel('各项拟合系数')

# L1正则化-Lasso回归
lasso = Lasso(alpha=0.01) # alpha就是λ超参数
lasso.fit(x_train1, y_train)  # 模型训练
y_pred3 = lasso.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_,color='r')  # 绘制所有拟合系数
ax[1, 1].set_ylabel('各项拟合系数')

# L2正则化-Ridge回归
ridge = Ridge(alpha=1)  # 同理,alpha就是λ超参数
ridge.fit(x_train1, y_train)  # 模型训练
y_pred3 = ridge.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_,color='r')  # 绘制所有系数
ax[1, 2 ].set_ylabel('各项拟合系数')
plt.savefig('G:/learning video/L1.jpg',dpi=400)
plt.show()

在这里插入图片描述

交叉验证

交叉验证(Cross-Validation)是一种评估模型泛化能力的方法,通过将数据集划分为多个子集,反复进行训练和验证,以减少因单次数据划分带来的随机性误差。
通过交叉验证能更可靠地估计模型在未知数据上的表现,亦能避免因单次数据划分不合理导致的模型过拟合或欠拟合

常用的数据划分方法包括简单交叉验证、K折交叉验证和留一交叉验证。其中,K折交叉验证是应用最为广泛的数据划分方法。

简单交叉验证(Hold-Out Validation):

只将数据划分为训练集和验证集(如70%训练,30%验证),其结果受单次划分影响较大,可能高估或低估模型性能

K折交叉验证(k-Fold Cross-Validation):

将数据均匀分为k个子集(称为“折”),每次用k−1折训练,剩余1折验证,重复k次后取平均性能
在这里插入图片描述

留一交叉验证(Leave-One-Out,LOO):

每次仅留一个样本作为验证集,其余全部用于训练,重复直到所有样本都被验证一次。适用于小数据集,计算成本极高。

关注梯度下降法

模型的求解评估策略:就是让结构化的经验风险最小,即让模型的损失函数值最小化,称为结构风险最小化(Structural Risk Minimization,SRM)
在这里插入图片描述

对于如上损失函数而言:本质就是求解一个最优化问题。代入训练集所有数据,要求最小值的目标函数就是模型中参数的函数,其具体求解的算法,可以利用数学公式直接计算解析解(解析法),也可以使用迭代算法(梯度下降法)。

解析法

如果模型损失函数的最小值可以通过数学公式进行严格推导,得到一个解析解,那么就直接得到了最优模型的全部参数,这种方法称作解析法。

  • 要求:目标函数必须可导,且导数方程有解析解
  • 对于上述的L2正则化-Ridge回归,咱们可以通过数学公式推导,求解出解析解
    在这里插入图片描述

梯度下降法

梯度下降法是迭代算法,基本思路就是先选取一个适当的初始值,然后沿着负梯度方向,不停地更新参数,最终取到极小值。
在这里插入图片描述
这里的▽L(θn)是参数取值为θn 时损失函数的梯度;α是每次迭代的“步长”,称为“学习率”。学习率是一个常见的超参数,需要手动设置,选择不当会导致收敛失败。

  • 梯度方向: 函数变化增长最快的方向(变量沿此方向变化时函数增长最快)
  • 负梯度方向:函数变化减少最快的方向(变量沿此方向变化时函数减少最快)
  • 损失函数是模型参数的函数,那么参数沿着损失函数的负梯度方向变化,此时损失函数减少最快,能够以最快速度下降到极小值

在这里插入图片描述

在梯度下降法中,可以更细致的分为三类:

  • 批量梯度下降(Batch Gradient Descent,BGD),每次迭代使用全部训练数据计算梯度。其优势为稳定收敛,劣势为计算复杂、开销大
  • 随机梯度下降(Stochastic Gradient Descent,SGD),每次迭代随机选取一个样本计算梯度。很明显,优势为速度快、参数更新快,劣势为梯度更新方向不稳定,优化过程震荡幅度较大,可能难以收敛
  • 小批量梯度下降(Mini-batch Gradient Descent,MBGD),每次迭代使用一小批样本计算梯度。该方法平衡了上述两种方法,是后续学习中最常使用的梯度下降算法

在这里插入图片描述

案例:以一个单变量函数为例,介绍梯度下降法的代码实现

import numpy as np
import matplotlib.pyplot as plt

# 1. 定义损失函数与梯度
def J(x):
	return (x**2 - 5)**2

def grad_J(x):
    return 4 * x * (x**2 - 5)

# 2. 梯度下降过程
lr = 0.058          # 学习率(超参数,手动调节)
n_iter = 8
x0 = 1.40          # 初始点
x_history = [x0]
x = x0
for _ in range(n_iter):
    x = x - lr * grad_J(x)
    x_history.append(x)
x_history = np.array(x_history)
J_history = J(x_history)

# 3. 绘制损失函数曲线
x_plot = np.linspace(1.3, 3, 400)
J_plot = J(x_plot)
plt.figure(figsize=(6, 4))
# 3.1 损失函数
plt.plot(x_plot, J_plot, color="black", linewidth=1)
# 3.2 梯度下降轨迹
plt.plot(x_history, J_history,
         color="red",
         marker="o",
         markersize=6,
         linewidth=1.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',dpi=600,bbox_inches="tight")
plt.show()

在这里插入图片描述

指数加权平均
在这里插入图片描述

"""
	指数移动加权平均,演示进30天,天气分布情况
	针对于β(调节权重系数)来讲,其值越大,越依赖指数加权平均,越不依赖本地的梯度值,数据越平缓
"""
import torch
import matplotlib.pyplot as plt

ELEMENT_NUMBER = 30

# 1.实际平均问题
def dm01():
	torch.manual_seed(0)
	# 产生30天的随机温度
	temperature = torch.randn(size=[ELEMENT_NUMBER,]) * 10
	print(temperature)

	# 绘制平均温度
	days = torch.arange(1,ELEMENT_NUMBER + 1,1)
	plt.plot(days,temperature,color='r')
	plt.scatter(days,temperature)
	plt.show()

# 指数加权平均温度
def dm02():
	torch.manual_seed(0)
	temperature = torch.randn(size=[ELEMENT_NUMBER,]) * 10

	exp_weight_avg = []
	for idx,temp in enumerate(temperature,1):
		# 第一个元素的EWA值等于自身
		if idx == 1:
			exp_weight_avg.append(temp)
			continue
		# 第二个元素的EWA等于上一个EMA乘以β + 当前气温乘以(1-β)
		new_temp = exp_weight_avg[idx - 2] * beta + (1 - beta) * temp
		exp_weight_avg.append(new_temp)

	days = torch.arange(1,ELEMENT_NUMBER + 1,1)
	plt.plot(days,exp_weight_avg,color = 'r')
	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],lr=0.01,momentum=0.9) 默认moment=0 只考虑本次梯度

思路二:基于AdaGrad(自适应学习率)
optimizer = optim.Adagrad(params=[w],lr=0.01)

思路三:基于RMSProp(自适应学习率)
optimizer = optim.RMSprop(params=[w],lr=0.01,alpha=0.99)

思路四:基于Adam(自适应估计)
optimizer = optim.Adam(params=[w],lr=0.01,betas=(0.9,0.999))
在这里插入图片描述

"""
梯度下降优化方法:结合本次损失函数的导数(作为梯度)基于学习率更新权重
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通过引入衰减系数β,控制历史梯度对历史梯度信息获取多少
	
	综合测量Adam(Adaptive Moment Estimation)
		既优化学习率,又优化梯度
		一阶距:算均值
			Mt = β1 * Mt - 1 + (1 - β1) * Gt  充当梯度
			St = β2 * St - 1 + (1 - β2) * Gt * Gt  充当学习率
		二阶距:梯度的方差
			Mt^ = Mt / (1 - β1^ t)
			St^ = St / (1 - β2^ t)
		权重更新公式:
			W新 = W旧 - 学习率 / (sqrt(St^)) * Mt^
	
"""
import torch
import torch.nn as nn

# 定义函数:梯度下降优化方法——动量法(Momentum)
def dm01_moment():
	# 1.初始化权重参数
	w = torch.tensor([1.0],requires_grad=True,dtype=float)

	# 2.定义损失函数
	criterion = ((w ** 2)/2.0)

	# 3.创建优化器(函数对象)->基于SGD(随机梯度下降) 加入参数momentum,就是动量法
	# 参数一:待优化的参数列表   参数二:学习率   参数三:动量参数
	optimizer = optim.SGD(params=[w],lr=0.01,momentum=0.9)

	# 4.计算梯度值:梯度清零+反向传播+参数更新
	optimizer.zero_grad()
	criterion.sum().backward()
	optimizer.step()
	print(f'w:{w},w.grad:{w.grad}')

	# 5.重复上述步骤
	criterion = ((w ** 2)/2.0)
	optimizer.zero_grad()
	criterion.sum().backward()
	optimizer.step()
	print(f'w:{w},w.grad:{w.grad}')

# 定义函数:梯度下降优化方法——自适应学习率(AdaGrad)
def dm02_adagrad():
	# 1.初始化权重参数
	w = torch.tensor([1.0],requires_grad=True,dtype=float)

	# 2.定义损失函数
	criterion = ((w ** 2)/2.0)

	# 3.创建优化器(函数对象)->基于SGD(随机梯度下降) 加入参数momentum,就是动量法
	# 参数一:待优化的参数列表   参数二:学习率   参数三:动量参数
	optimizer = optim.Adagrad(params=[w],lr=0.01)

	# 4.计算梯度值:梯度清零+反向传播+参数更新
	optimizer.zero_grad()
	criterion.sum().backward()
	optimizer.step()
	print(f'w:{w},w.grad:{w.grad}')

	# 5.重复上述步骤
	criterion = ((w ** 2)/2.0)
	optimizer.zero_grad()
	criterion.sum().backward()
	optimizer.step()
	print(f'w:{w},w.grad:{w.grad}')

# 定义函数:梯度下降优化方法RMSProp
def dm03_rmsprop():
	# 1.初始化权重参数
	w = torch.tensor([1.0],requires_grad=True,dtype=float)

	# 2.定义损失函数
	criterion = ((w ** 2)/2.0)

	# 3.创建优化器
	optimizer = optim.RMSporp(params=[w],lr=0.01,alpha=0.99)

	# 4.计算梯度值:梯度清零+反向传播+参数更新
	optimizer.zero_grad()
	criterion.sum().backward()
	optimizer.step()
	print(f'w:{w},w.grad:{w.grad}')

	criterion = ((w ** 2)/2.0)
	optimizer.zero_grad()
	criterion.sum().backward()
	optimizer.step()
	print(f'w:{w},w.grad:{w.grad}')

# 定义函数,梯度下降优化方法-自适应宇哥(Adam)
def dm04_adam():
	# 1.初始化权重参数
	w = torch.tensor([1.0],requires_grad=True,dtype=float)

	# 2.定义损失函数
	criterion = ((w ** 2)/2.0)

	# 3.创建优化器
	optimizer = optim.Adam(params=[w],lr=0.01,betas=(0.9,0.999))#betas=(梯度用的衰减系数,学习率用的衰减系数)

	# 4.计算梯度值:梯度清零+反向传播+参数更新
	optimizer.zero_grad()
	criterion.sum().backward()
	optimizer.step()
	print(f'w:{w},w.grad:{w.grad}')

	criterion = ((w ** 2)/2.0)
	optimizer.zero_grad()
	criterion.sum().backward()
	optimizer.step()
	print(f'w:{w},w.grad:{w.grad}')

总结:如何选择梯度下降优化方法

  • 简单任务和较小模型:SGD 动量法
  • 复杂任务或者有大量数据:Adam
  • 需要处理稀疏矩阵或者文本数据:AdaGrad RMSProp

3. 📉 学习率衰减(StepLR)

通俗理解:学开车的过程

学习率 = 方向盘的转动幅度

刚开始学车(训练初期):

🎯 大学习率:方向盘猛打猛转

✅ 优点:快速找到感觉,进步明显

❌ 缺点:容易过头,左右摇摆

成为老司机(训练后期):

🎯 小学习率:方向盘微调,精细修正

✅ 优点:平稳精准,优化细节

❌ 缺点:进步缓慢

# 就像驾校教练的教学策略:1-10节课:大胆尝试,多转方向盘    # 学习率=1e-411-20节课:小幅修正,精细调整    # 学习率=1e-5(衰减到0.1倍)

self.scheduler = StepLR(
	self.optimizer,
	step_size = self.config.step_size, # 每10个epoch衰减一次
	gamma = self.config.gamma # 学习率乘以0.5
)

学习率衰减优化方法

"""
学习率对梯度(权重优化)的影响

学习率越小,梯度下降越慢
学习率越大,梯度下降越快,可能会越过最小值;造成震荡,甚至不收敛(梯度爆炸)
"""
# x看成是权重,y看成是loss
def func():
	return torch.pow(2*x_t,2) # y = 4 x ^2

def dm01():
	x = torch.tensor([2.],requires_grad=True)
	# 记录loss迭代次数,画曲线
	ite_rec,loss_rec,x_rec = list(),list(),list()

	"""
		实验学习率:0.01,0.02,0.03,0.1,0.2,0.3,0.4
		lr=0.1 正常梯度下降
		lr=0.125 当学习率设置0.125,一下子求出一个最优解,当x=0 y=0  在x=0处梯度等于0 
		lr
		lr
	"""
	max_iteration = 4
	for i in range(max_iteration):
		y = func(x) # 得出loss的值
		y.backward() # 计算x的梯度
		print("")
		x_rec.append(x.item()) # 计算梯度下降点
		# 更新参数
		x.data.sub_(lr * x.grad)
		x.grad.zero_()
		iter_rec.append(i)
		loss_rec.append(y.item())
	
	plt.subplot(121).plot(iter_rec,loss_rec,'-ro')
	plt.grid()
	plt.xlabel("Iteration X")
	plt.ylabel("Loss value Y")
	# 函数曲线-下降轨迹 显示图
	x_t = torch.linspace(-3,3,100)
	y = func(x_t)
	plt.subplot(122).plot(x_t.detach().numpy(),y.detach().numpy(),label="y=x*x^2")
	y_rec = [func(torch.tensor(i)).item() for i in x_rec]
	print('x_rec-->',x_rec)
	print('y_rec-->',y_rec)
	# 制定线的颜色和样式
	plt.subplot(122).plot(x_rec,y_rec,'-ro')
	plt.grid()
	plt.legend()
	plt.show()
		

在这里插入图片描述

方法一:等间隔学习率衰减
在这里插入图片描述

方法二:指定间隔学习率衰减
在这里插入图片描述

方法三:指数间隔学习率衰减
在这里插入图片描述

"""
	学习率衰减策略
	较之于AdaGrad、RMSProp、Adam方式,可以通过等间隔、指定间隔、指数等方式来手动控制学习率
"""
import torch
from torch import optim
import matplotlib.pyplot as plt

# 等间隔学习率衰减
def dm01():
	# 初始学习率,训练轮数,每轮训练的批次数
	lr,eptchs,iteration = 0.1,200,10
	
	# 创建数据集,真实值、输入特征、权重参数w
	y_true = torch.tensor([0])
	x = torch.tensor([1.0],dtype=torch.float32)
	w = torch.tensor([1.0],requires_grad=True,dtype=torch.float32)

	# 创建优化器对象,动量法->
	optimizer = optim.SGD([w],lr=lr,momentum=0.9)
	
	scheduler = optim.lr_scheduler.StepLR(optimizer,step_size=50,gamma=0.5)

	lr_list,epoch_list = [],[]

	# 循环遍历训练轮数,进行具体的训练
	for epoch in range(epochs):
		epoch_list.append(epoch)
		lr_list.append(scheduler.get_last_lr())

		for batch in range(iteration):
			y_pred = w * x
			loss = (y_pred - y_true) **2 # 最小二乘法计算损失
			# 梯度清零+反向传播+优化器更新参数
			optimizer.zero_grad()
			loss.backward()
			optimizer.step()
			# 更新学习率
			scheduler.step()
	print(f'lr_list:{lr_list}')

	# 可视化
	plt.plot('eopch_list',lr_list)
	plt.xlabel('Epoch')
	plt.y_label('learning Rate')
	plt.legend()
	plt.show()
		
		

# 指定间隔学习率衰减
def dm02():
	# 初始学习率,训练轮数,每轮训练的批次数
	lr,eptchs,iteration = 0.1,200,10
	
	# 创建数据集,真实值、输入特征、权重参数w
	y_true = torch.tensor([0])
	x = torch.tensor([1.0],dtype=torch.float32)
	w = torch.tensor([1.0],requires_grad=True,dtype=torch.float32)

	# 创建优化器对象,动量法->
	optimizer = optim.SGD([w],lr=lr,momentum=0.9)
	
	milestones = [50,125,160]
	scheduler = optim.lr_scheduler.MultiStepLR(optimizer,milestones,gamma=0.5)

	lr_list,epoch_list = [],[]

	# 循环遍历训练轮数,进行具体的训练
	for epoch in range(epochs):
		epoch_list.append(epoch)
		lr_list.append(scheduler.get_last_lr())

		for batch in range(iteration):
			y_pred = w * x
			loss = (y_pred - y_true) **2 # 最小二乘法计算损失
			# 梯度清零+反向传播+优化器更新参数
			optimizer.zero_grad()
			loss.backward()
			optimizer.step()
			# 更新学习率
			scheduler.step()
	print(f'lr_list:{lr_list}')

	# 可视化
	plt.plot('eopch_list',lr_list)
	plt.xlabel('Epoch')
	plt.y_label('learning Rate')
	plt.legend()
	plt.show()


# 指数学习率衰减
def dm03():
	# 初始学习率,训练轮数,每轮训练的批次数
	lr,eptchs,iteration = 0.1,200,10
	
	# 创建数据集,真实值、输入特征、权重参数w
	y_true = torch.tensor([0])
	x = torch.tensor([1.0],dtype=torch.float32)
	w = torch.tensor([1.0],requires_grad=True,dtype=torch.float32)

	# 创建优化器对象,动量法->
	optimizer = optim.SGD([w],lr=lr,momentum=0.9)
	
	scheduler = optim.lr_scheduler.ExponentialLR(optimizer,gamma=0.95)

	lr_list,epoch_list = [],[]

	# 循环遍历训练轮数,进行具体的训练
	for epoch in range(epochs):
		epoch_list.append(epoch)
		lr_list.append(scheduler.get_last_lr())

		for batch in range(iteration):
			y_pred = w * x
			loss = (y_pred - y_true) **2 # 最小二乘法计算损失
			# 梯度清零+反向传播+优化器更新参数
			optimizer.zero_grad()
			loss.backward()
			optimizer.step()
			# 更新学习率
			scheduler.step()
	print(f'lr_list:{lr_list}')

	# 可视化
	plt.plot('eopch_list',lr_list)
	plt.xlabel('Epoch')
	plt.y_label('learning Rate')
	plt.legend()
	plt.show()


在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐