如何用Python基于损失函数实现线性回归的w与b求解及模型构建
线性回归模型构建学习笔记与问题解答
我的目标
创建一个ipynb文件,学习线性回归模型(Linear Regression Model)的构建方法。
技术疑问
- 线性回归模型的初始w和b应如何设置?是否需要随机初始化?
- 迭代过程中何时调整w或b?
- 每次迭代时w或b的更新幅度应为多少?
预期实现效果
- 构建一个包含
__init__和fit方法的Model类; fit方法需在每次迭代中对w或b进行增减调整。
已完成的工作
1. 数据可视化图表绘制
plt.xlim(-2, 11) plt.ylim(-2, 11) x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] y = [-1, 2, 1, 4, 3, 6, 5, 8, 7, 10, 9] plt.plot(x, y, 'ro') # y = x x = [0,10] y = [0,10] plt.plot(x, y) # fill_between x = [0, 10] y1 = [-1, 9] y2 = [1, 11] plt.fill_between(x, y1, y2, alpha=0.2) del x, y
2. 损失函数实现
# Dots x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] y = [-1, 2, 1, 4, 3, 6, 5, 8, 7, 10, 9] # calculated from y = 1x + 0 ŷ = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 线性回归的损失函数为(ŷ - y)²,也叫残差平方 def calculate_linear_regression_loss_function(ŷ: list[int], y: list[int]) -> list[int]: # 转换为numpy数组简化计算 np_ŷ = np.array(ŷ) np_y = np.array(y) # 计算预测值与真实值的差值 distances = np_ŷ - np_y # 差值平方 squares = distances ** 2 # 返回平方和 return squares.sum() print(calculate_linear_regression_loss_function(ŷ, y)) del x, ŷ, y
3. 训练数据生成及拆分函数实现
生成训练数据
def generate_training_data(n: int) -> list[list[int]]: training_data: list[list[int]] = [] for _ in range(n): x = randrange(0, 1000) / 100 y = randrange(0, 1000) / 100 training_data.append([x, y]) return training_data generate_training_data(n=10)
拆分训练数据为x和y
def separate_training_data_into_x_y(training_data: list[list[int]]) -> tuple[list[int], list[int]]: array = np.array(training_data) return array[:,0], array[:, 1] training_data = generate_training_data(n=10) print("training_data", training_data) x_training, y_training = separate_training_data_into_x_y(training_data=training_data) print("x_training", x_training)
可视化生成的训练数据
training_data = generate_training_data(10) x_training, y_training = separate_training_data_into_x_y(training_data=training_data) plt.plot(x_training, y_training, 'ro')
示例疑问:如何估算下图中线性回归模型的初始w和b

待完善代码
目前Model类尚未完成,需先理解线性回归核心逻辑再完善:
# 深度学习的目标是最小化损失函数的值 # 以线性回归y = w*x + b为例,权重w和偏置b会在训练过程中调整 # 损失函数为(ŷ - y)²,其中ŷ是预测值,y是真实值 from typing import Callable class Model: x_train: list[list[int]] loss_function: Callable[[int, int], int] def __init__(self, loss_function: Callable[[int, int], int]): self.loss_function = loss_function def fit(self, x_training: list[list[int]], y_training: list[int]): self.x_training = x_training self.y_training = y_training print(self.loss_function(3,1)) loss_function: Callable[[int, int], int] = lambda ŷ, y: (ŷ - y)**2 model = Model(loss_function) model.fit([[1], [1]], [1])
技术疑问解答
1. 初始w和b的设置方式
线性回归的参数初始化分两种场景:
- 若使用批量梯度下降(BGD)或最小二乘法解析解:无需随机初始化,直接设为0即可,因为线性回归的损失函数是凸函数,不会陷入局部最优;
- 若使用随机/小批量梯度下降(SGD/MBGD):可以从[-0.1, 0.1]的均匀分布随机采样初始化,也可以直接设为0,随机初始化仅在极少数情况下能加快收敛。
针对你提供的数据分布图,也可以通过可视化粗略估算:比如数据整体斜率接近1,截距接近0,用这个值作为初始参数能大幅加快收敛速度。
2. 迭代过程中何时调整w或b
每次计算完损失函数的梯度后,就需要调整w和b。梯度代表当前参数下损失函数增大的方向,我们要朝着梯度的反方向更新参数,才能让损失函数持续减小:
- 批量梯度下降:遍历完所有训练数据,计算一次全局梯度,更新一次参数;
- 随机梯度下降:每遍历一个样本,计算一次梯度并更新参数;
- 小批量梯度下降:每遍历一小批样本,计算梯度并更新参数。
3. w和b的更新幅度
更新幅度由学习率(learning rate)和梯度值共同决定,公式为:
w = w - learning_rate * dL/dw b = b - learning_rate * dL/db
其中dL/dw是损失函数对w的偏导数,dL/db是对b的偏导数:
- 学习率是手动调整的超参数:太小会导致收敛过慢,太大可能导致损失函数震荡甚至发散,通常从0.001、0.01、0.1这类值开始尝试;
- 梯度值反映参数对损失的影响程度:梯度越大,说明参数对损失的影响越强,更新幅度也会越大。
完善后的线性回归Model类
结合上述逻辑,完善后的Model类包含参数初始化、梯度计算、迭代更新逻辑:
import numpy as np from typing import Callable class LinearRegressionModel: def __init__(self, loss_function: Callable[[np.ndarray, np.ndarray], float], learning_rate: float = 0.01): self.loss_function = loss_function self.learning_rate = learning_rate self.w = None # 权重参数 self.b = None # 偏置参数 def _predict(self, x: np.ndarray) -> np.ndarray: # 线性回归预测公式:ŷ = w*x + b return self.w * x + self.b def _compute_gradients(self, x: np.ndarray, y: np.ndarray) -> tuple[float, float]: # 计算损失函数对w和b的梯度(基于均方误差损失) ŷ = self._predict(x) error = ŷ - y dw = (2 / len(x)) * np.sum(error * x) db = (2 / len(x)) * np.sum(error) return dw, db def fit(self, x_training: np.ndarray, y_training: np.ndarray, epochs: int = 1000): # 初始化参数:这里设为0,也可以随机初始化 self.w = 0.0 self.b = 0.0 # 转换为numpy数组方便计算 x_train = np.array(x_training) y_train = np.array(y_training) for epoch in range(epochs): # 计算梯度 dw, db = self._compute_gradients(x_train, y_train) # 更新参数 self.w -= self.learning_rate * dw self.b -= self.learning_rate * db # 每100轮打印一次损失,监控训练过程 if epoch % 100 == 0: ŷ = self._predict(x_train) loss = self.loss_function(ŷ, y_train) print(f"Epoch {epoch}: Loss = {loss:.4f}, w = {self.w:.4f}, b = {self.b:.4f}") # 定义均方误差损失函数 def mean_squared_error(ŷ: np.ndarray, y: np.ndarray) -> float: return np.mean((ŷ - y)**2) # 测试模型 if __name__ == "__main__": # 示例数据 x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) y = np.array([-1, 2, 1, 4, 3, 6, 5, 8, 7, 10, 9]) # 创建模型 model = LinearRegressionModel(loss_function=mean_squared_error, learning_rate=0.01) # 训练模型 model.fit(x, y, epochs=2000) # 测试预测 print(f"\n预测x=11的值:{model._predict(11):.4f}")
内容的提问来源于stack exchange,提问作者Jason Rich Darmawan
相关产品推荐
相关产品推荐

