深度学习概述
- 1. 线性回归
- 1.1 线性回归一般表达式
- 1.2 线性回归内积表达方式:
- 1.3 多个样本时,线性回归的进一步表达:
- 1.4 线性回归方程的解析
- 1.5 线性回归就是求loss函数的最小值
- 2. 如何求函数最小值
- 2.1 一个例子
- 2.2 求导法——求最小值
- 2.3 求导法存在的问题
- 2.4 迭代法——求最小值
- 3. 代码实现
- 3.1 手动求函数最小值
- 3.2 使用pytorch求函数最小值
原文: https://blog.csdn.net/Deadwalk/article/details/139606252?spm=1001.2014.3001.5502
1. 线性回归
1.1 线性回归一般表达式
- y = f ( x ) = x 1 w 1 + x 2 w 2 + . . . + x n w n + b y = f(x) = x_1w_1 + x_2w_2 + ... + x_nw_n + b y=f(x)=x1w1+x2w2+...+xnwn+b
- ( x 1 、 x 2 、 x n ) :输入特征向量 ( x ) 的各个特征值,代表输入数据的特征。 (x_1、x_2、x_n):输入特征向量 ( x ) 的各个特征值,代表输入数据的特征。 (x1、x2、xn):输入特征向量(x)的各个特征值,代表输入数据的特征。
- ( w 1 、 w 2 、 w n ) :权重向量 ( w ) 的各个权重值,用来衡量每个特征对输出的影响程度。 (w_1、w_2、w_n):权重向量 ( w ) 的各个权重值,用来衡量每个特征对输出的影响程度。 (w1、w2、wn):权重向量(w)的各个权重值,用来衡量每个特征对输出的影响程度。
- ( b ) :偏置项,也称为截距项,用来调整模型的输出值,即在没有特征输入时的输出值。 ( b ):偏置项,也称为截距项,用来调整模型的输出值,即在没有特征输入时的输出值。 (b):偏置项,也称为截距项,用来调整模型的输出值,即在没有特征输入时的输出值。
- ( y ) :模型的输出值,即线性回归模型对输入特征的预测值。 ( y ):模型的输出值,即线性回归模型对输入特征的预测值。 (y):模型的输出值,即线性回归模型对输入特征的预测值。
1.2 线性回归内积表达方式:
- y = f ( x ) = x @ w + b y = f(x) = x@w+ b y=f(x)=x@w+b
- x @ w :特征向量 ( x ) 与权重向量 ( w ) 的内积 x@w:特征向量 ( x ) 与 权重向量( w ) 的内积 x@w:特征向量(x)与权重向量(w)的内积
1.3 多个样本时,线性回归的进一步表达:
- y = f ( X ) = X @ w + b y = f(X) = X@w+ b y=f(X)=X@w+b
- X :特征矩阵,矩阵的行是一条一条的样本,矩阵的列是多个特征向量。 X:特征矩阵,矩阵的行是一条一条的样本,矩阵的列是多个特征向量。 X:特征矩阵,矩阵的行是一条一条的样本,矩阵的列是多个特征向量。
1.4 线性回归方程的解析
- 在训练时,x和y是训练集中的特征和标签,看作是常量;w和b是待优化的参数值,看作是变量。
- 在推理时,w和b已经找到了比较合适的值固定下来,看作常量;此时x是待预测的样本的特征,是变量;
- 预测的本质:把x带入,求解y。
1.5 线性回归就是求loss函数的最小值
- 训练过程
- 从训练集中取出一对x 和y
- 把x带入模型,求解预测结果y_pred
- 找到一种方法,度量y和y_pred的误差loss
- 由此推导:
- loss是y和y_pred的函数;
- y_pred是模型预测的结果,是w和b的函数;
- 所以简单来说,loss也是w和b的函数
- 训练的本质
由上图推导结果可知,训练的本质就是求解loss什么时候是最小值。当w和b取得什么值的时候,loss最小。
2. 如何求函数最小值
2.1 一个例子
- y = 2 x 2 y= 2x^2 y=2x2
- 上述这个示例中,求y最小值是比较简单的,从图形中可以看到x=0时,y=0为最小值。但是实际工程中,并不是所有的函数y=f(x)都能画出来,简单地找到最小值,此时就需要使用导数求最小值。
2.2 求导法——求最小值
- 通过回归导数求极值的方法,我们知道大致步骤如下:
- 第一步:求函数的导数
- 第二步:令导数等于零
- 第三步:解方程,求出疑似极值点
- 第四步:验证该点是否是极值点以及是什么极值点
2.3 求导法存在的问题
- 求导的方法是有一定前提条件的,即:
- 第一步的求(偏)导数是可以求得的;
- 第三步(偏)导数为零后,方程(组)是可以解的。
- 实际工程中,上述方法是不可行的。以Llama3-8B模型为例,其有80亿个输入参数 x,按照上述的求解方法是几乎无法求得最小值的!
- 由此可知,通过推导公式期望一次性求得最小值是不现实的;而我们可以借鉴人工智能中一个重要的思想:迭代法来逐步求解最小值。
2.4 迭代法——求最小值
- 原理如下图:
- 随机选择一个出生点 x 0 : 随机选择一个出生点x_0: 随机选择一个出生点x0:
- 当 x 0 在最小值的左侧时: x 0 + 正数(一个非常小的正数),向右侧移动,而最小值左侧的导数是负数,所以可以看作 x 0 − 导数 当x_0在最小值的左侧时:x_0 + 正数(一个非常小的正数),向右侧移动,而最小值左侧的导数是负数,所以可以看作 x_0 - 导数 当x0在最小值的左侧时:x0+正数(一个非常小的正数),向右侧移动,而最小值左侧的导数是负数,所以可以看作x0−导数
- 当 x 0 在最小值的右侧时: x 0 − 正数(一个非常小的正数),向左侧移动,而最小值右侧的导数是正数,所以也可以看作 x 0 − 导数 当x_0在最小值的右侧时:x_0 - 正数(一个非常小的正数),向左侧移动,而最小值右侧的导数是正数,所以也可以看作 x_0 - 导数 当x0在最小值的右侧时:x0−正数(一个非常小的正数),向左侧移动,而最小值右侧的导数是正数,所以也可以看作x0−导数
- 当 x 0 是最小值时: x 0 不需要移动,而此处的导数也正是 0 ,所以依然可以看作 x 0 − 导数 当x_0是最小值时:x_0不需要移动,而此处的导数也正是0,所以依然可以看作 x_0 - 导数 当x0是最小值时:x0不需要移动,而此处的导数也正是0,所以依然可以看作x0−导数
- 梯度下降的概念
- 在一元函数中,求函数f(x)在某一点的斜率为导数;在多元函数中,称为偏导数,也就是梯度。
- 减去导数也就是减去梯度,这就是梯度下降法!
3. 代码实现
3.1 手动求函数最小值
- 以 y = 2 x 2 y= 2x^2 y=2x2
import numpy as npdef fn(x):"""原始函数"""return 2 * x ** 2def dfn(x):"""导函数"""return 4 * xdef gradient_descent(x0, learning_rate, dfn, epochs):"""使用梯度下降法求函数的最小值Parameters:x0 (float): 初始点的位置learning_rate (float): 学习率dfn (function): 导函数epochs (int): 迭代次数Returns:x_min (float): 最小值点的位置"""for _ in range(epochs):x0 = x0 - learning_rate * dfn(x0)return x0# 随机选择一个出生点
x0 = np.random.randint(low=-1000, high=1000, size=1)# 迭代次数
epochs = 1000# 学习率
learning_rate = 1e-2# 使用梯度下降法求最小值
x_min = gradient_descent(x0, learning_rate, dfn, epochs)# 输出最小值
print("最小值点的位置:", x_min)
- f ( x , y , z ) = x 2 + y 2 + z 2 f ( x , y , z ) = x^2 + y^2 + z^2 f(x,y,z)=x2+y2+z2
import numpy as npdef df_x(x, y, z):"""f 对 x 求偏导"""return 2 * xdef df_y(x, y, z):"""f 对 y 求偏导"""return 2 * ydef df_z(x, y, z):"""f 对 z 求偏导"""return 2 * z# 随机选择出生点
x0 = np.random.randint(low=-1000, high=1000, size=(1,))
y0 = np.random.randint(low=-1000, high=1000, size=(1,))
z0 = np.random.randint(low=-1000, high=1000, size=(1,))# 迭代次数
epochs = 1000# 学习率
learning_rate = 1e-2for _ in range(epochs):# 求解每个变量的偏导fx = df_x(x0, y0, z0)fy = df_y(x0, y0, z0)fz = df_z(x0, y0, z0)# 每个变量都减去自己的偏导x0 = x0 - learning_rate * fxy0 = y0 - learning_rate * fyz0 = z0 - learning_rate * fz# 输出更新后的变量值
print("更新后的 x 值:", x0)
print("更新后的 y 值:", y0)
print("更新后的 z 值:", z0)
3.2 使用pytorch求函数最小值
- 以 y = 2 x 2 y= 2x^2 y=2x2
import torch# 定义原始函数和导函数
def fn(x):return 2 * x ** 2# 说明:pytorch可以通过grad函数求导,所以可以省去写导函数
# def dfn(x):
# return 4 * x# 随机选择出生点
# requires_grad=True用来告诉框架该变量是一个张量,需要计算梯度。
x0 = torch.randint(low=-1000, high=1001, size=(1,), dtype=torch.float32, requires_grad=True)# 迭代次数
epochs = 1000# 学习率
learning_rate = 1e-2# 使用 PyTorch 进行梯度下降
for _ in range(epochs):# 正向传播计算损失loss = fn(x0)# 反向传播计算梯度loss.backward()# 获取梯度并更新参数with torch.no_grad():grad = x0.gradx0 -= learning_rate * grad# 梯度清零x0.grad.zero_()# 输出最小值点的位置
print("最小值点的位置:", x0.item())
- 以 f ( x , y , z ) = x 2 + y 2 + z 2 f ( x , y , z ) = x^2 + y^2 + z^2 f(x,y,z)=x2+y2+z2 为例
import torchdef fn(x, y, z):"""函数定义"""return x**2 + y**2 + z**2# 说明:pytorch可以通过grad函数求导,所以可以省去写导函数
# def df_x(x, y, z):
# return 2 * x# def df_y(x, y, z):
# return 2 * y# def df_z(x, y, z):
# return 2 * z# 随机选择出生点
x0 = torch.randint(low=-1000, high=1001, size=(1,), dtype=torch.float32, requires_grad=True)
y0 = torch.randint(low=-1000, high=1001, size=(1,), dtype=torch.float32, requires_grad=True)
z0 = torch.randint(low=-1000, high=1001, size=(1,), dtype=torch.float32, requires_grad=True)# 迭代次数
epochs = 1000# 学习率
learning_rate = 1e-2# 使用 PyTorch 进行梯度下降
for _ in range(epochs):# 正向传播计算损失loss = fn(x0, y0, z0)# 反向传播计算梯度loss.backward()# 获取梯度并更新参数# 在测试阶段或者不需要计算梯度的情况下使用 torch.no_grad()# 以提高计算效率并避免不必要的梯度计算。with torch.no_grad():x0 -= learning_rate * x0.grady0 -= learning_rate * y0.gradz0 -= learning_rate * z0.grad# 梯度清零x0.grad.zero_()y0.grad.zero_()z0.grad.zero_()# 输出更新后的变量值
print("更新后的 x 值:", x0.item())
print("更新后的 y 值:", y0.item())
print("更新后的 z 值:", z0.item())