机器学习回归模型代码理解——三阶多项式拟合y = sin(x)
先上代码:
# -*- coding: utf-8 -*-
import numpy as np
import math# 创建随机输入值和输出数据
x = np.linspace(-math.pi, math.pi, 2000)
y = np.sin(x)# 随机初始化权重
a = np.random.randn()
b = np.random.randn()
c = np.random.randn()
d = np.random.randn()learning_rate = 1e-6
for t in range(2000):# 前向传递: 计算y的预测值# y = a + b x + c x^2 + d x^3y_pred = a + b * x + c * x ** 2 + d * x ** 3# 计算并输出损失loss = np.square(y_pred - y).sum()if t % 100 == 99:print(t, loss)# 反向传播来计算相对于损失的a, b, c, d的梯度grad_y_pred = 2.0 * (y_pred - y)grad_a = grad_y_pred.sum()grad_b = (grad_y_pred * x).sum()grad_c = (grad_y_pred * x ** 2).sum()grad_d = (grad_y_pred * x ** 3).sum()# 更新权重a -= learning_rate * grad_ab -= learning_rate * grad_bc -= learning_rate * grad_cd -= learning_rate * grad_dprint(f'Result: y = {a} + {b} x + {c} x^2 + {d} x^3')
这段代码实现了一个简单的多项式回归模型,使用梯度下降算法来拟合正弦函数的数据。让我逐步解释代码的原理:
-
创建随机输入值和输出数据:
x = np.linspace(-math.pi, math.pi, 2000) y = np.sin(x)
这里通过
np.linspace
创建了一个包含2000个点的输入x
,范围是从-π
到π
。然后,根据sin(x)
创建了相应的输出数据y
。 -
随机初始化权重:
a = np.random.randn() b = np.random.randn() c = np.random.randn() d = np.random.randn()
这里使用
np.random.randn()
函数随机初始化了四个权重参数a
、b
、c
、d
。 -
设置学习率和训练循环:
learning_rate = 1e-6 for t in range(2000):
设置了学习率
learning_rate
为1e-6
,然后进行了 2000 次的训练循环。 -
前向传播和计算损失:
y_pred = a + b * x + c * x ** 2 + d * x ** 3 loss = np.square(y_pred - y).sum()
在每次训练迭代中,首先进行前向传播,计算模型对输入数据的预测值
y_pred
,然后计算预测值与真实值之间的平方损失。 -
反向传播计算梯度并更新权重:
grad_y_pred = 2.0 * (y_pred - y) grad_a = grad_y_pred.sum() grad_b = (grad_y_pred * x).sum() grad_c = (grad_y_pred * x ** 2).sum() grad_d = (grad_y_pred * x ** 3).sum()a -= learning_rate * grad_a b -= learning_rate * grad_b c -= learning_rate * grad_c d -= learning_rate * grad_d
这里通过反向传播计算了损失相对于权重
a
、b
、c
、d
的梯度,然后使用梯度下降算法更新了权重参数。 -
输出最终结果:
print(f'Result: y = {a} + {b} x + {c} x^2 + {d} x^3')
输出训练后得到的多项式回归模型的结果,包括最终拟合出的参数
a
、b
、c
、d
。
反向传播计算梯度并更新权重理解:
当我们使用梯度下降等优化算法来训练模型时,我们需要计算损失函数对模型参数的梯度,以便更新参数来最小化损失函数。反向传播(Backpropagation)是一种有效的方法,用于计算神经网络或其他模型中参数的梯度。
在这段代码中,反向传播的计算步骤如下:
-
计算损失函数关于预测值的梯度 (
grad_y_pred
):grad_y_pred = 2.0 * (y_pred - y)
这里使用了损失函数关于预测值的导数。对于均方误差损失函数,它的导数是误差乘以2,即
2 * (y_pred - y)
。 -
计算损失函数关于每个参数的梯度 (
grad_a
,grad_b
,grad_c
,grad_d
):grad_a = grad_y_pred.sum() grad_b = (grad_y_pred * x).sum() grad_c = (grad_y_pred * x ** 2).sum() grad_d = (grad_y_pred * x ** 3).sum()
这里利用了链式法则,将损失函数关于预测值的梯度传播到每个参数。通过求和操作,得到了损失函数关于每个参数的梯度。
-
更新参数:
a -= learning_rate * grad_a b -= learning_rate * grad_b c -= learning_rate * grad_c d -= learning_rate * grad_d
最后,利用梯度下降算法,通过将参数沿着梯度的反方向移动一小步(由学习率
learning_rate
控制),来更新模型的参数。
这样,通过反向传播计算参数的梯度,并利用梯度下降更新参数,模型就能够逐渐拟合出较好的函数形式,从而实现对给定数据的拟合。
grad_y_pred.sum() 为什么这里要用 .sum()?
在这段代码中,grad_y_pred
是损失函数关于预测值的梯度,它是一个包含了每个数据点的梯度值的数组。每个数据点对应一个梯度值,而这些梯度值的总和就代表了对整个损失函数的梯度。
在反向传播中,我们通常希望得到的是整个损失函数关于参数的梯度,而不仅仅是对单个数据点的梯度。因此,为了得到整个损失函数关于参数的梯度,我们需要将每个数据点的梯度值相加,即对 grad_y_pred
进行求和操作。
所以,在这里使用 .sum()
函数是为了将每个数据点的梯度值相加,得到整个损失函数关于预测值的梯度。