损失函数对权重求导数-->上升方向

导数负方向-->最小值所在方向-->w=w-alpha*(\partial cost)/(\partial w)    alpha为学习率

不一定得到全局最优,局部最优解-----需注意鞍点:gradient=0  无法继续迭代

学习率过大可能导致学习失败

针对同样的回归任务,梯度下降法实现如下

import matplotlib.pyplot as plt
import numpy as np  # 导入 numpy 用于生成平滑的线条

# 1. 原始数据
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]

# 2. 初始化模型参数
w = 1.0
w_initial = w  # 保存初始权重,用于后续可视化比较


# 3. 模型、损失函数、梯度函数定义
def forward(x):
    """模型的前向传播"""
    return x * w


def cost(xs, ys):
    """计算均方误差损失 (Mean Squared Error)"""
    cost_val = 0
    for x, y in zip(xs, ys):
        y_pred = forward(x)
        cost_val += (y_pred - y) ** 2
    return cost_val / len(xs)


def gradient(xs, ys):
    """计算损失函数关于权重 w 的梯度"""
    grad = 0
    # BUG修复:梯度需要累加所有样本的影响,而不是只用最后一个
    for x, y in zip(xs, ys):
        grad += 2 * x * (x * w - y)  # 使用 += 进行累加
    return grad / len(xs)


# 4. 训练过程
cost_list = []
epoch_list = []

print(f'Predict (before training) for x=4: {forward(4):.3f}')  # 格式化输出

# 学习率
learning_rate = 0.01

for epoch in range(100):
    # 计算损失并记录
    cost_val = cost(x_data, y_data)
    cost_list.append(cost_val)
    epoch_list.append(epoch)

    # 计算梯度并更新权重
    grad_val = gradient(x_data, y_data)
    w -= learning_rate * grad_val

    # 打印训练过程
    if epoch % 10 == 0:  # 每10次迭代打印一次
        print(f'Epoch: {epoch}, w = {w:.3f}, loss = {cost_val:.3f}')

print(f'Predict (after training) for x=4: {forward(4):.3f}')

# 5. 可视化
# 创建一个大画布,包含两个子图
plt.figure(figsize=(12, 5))

# --- 图 1: 损失随迭代次数的变化 ---
plt.subplot(1, 2, 1)  # 1行2列的第1个图
plt.plot(epoch_list, cost_list)
plt.title("Cost (Loss) vs. Epoch")
plt.xlabel("Epoch")
plt.ylabel("Cost (MSE Loss)")
plt.grid(True)

# --- 图 2: 模型拟合效果对比 ---
plt.subplot(1, 2, 2)  # 1行2列的第2个图
# 绘制原始数据点
plt.scatter(x_data, y_data, color='red', label='Actual Data')

# 绘制训练前的拟合线
x_range = np.linspace(0, 4, 100)  # 生成 0到4 之间的100个点来画平滑的线
y_pred_before = w_initial * x_range
plt.plot(x_range, y_pred_before, color='orange', linestyle='--', label=f'Prediction Before (w={w_initial:.2f})')

# 绘制训练后的拟合线
y_pred_after = w * x_range  # 使用最终训练好的w
plt.plot(x_range, y_pred_after, color='green', label=f'Prediction After (w={w:.2f})')

plt.title("Model Fit: Before vs. After Training")
plt.xlabel("x")
plt.ylabel("y")
plt.legend()  # 显示图例
plt.grid(True)

plt.tight_layout()  # 调整子图布局,防止重叠
plt.show()

梯度下降法-->随机梯度下降(stochastic gradient descent)w=w-alpha*(\partial loss)/(\partial w)

cost为所有loss的均值,随机梯度下降代表从N个loss里随机选一个  

(\partial cost)/(\partial w)=(\sum 2\cdot xn\cdot (xn\cdot w-yn))/N

(\partial loss)/(\partial w)=2\cdot xn\cdot (xn\cdot w-yn)

why? 对有鞍点的cost function,在鞍点位置梯度=0,无法继续学习

利用每个样本的随机噪声,可能可以继续推动跨越鞍点学习

import matplotlib.pyplot as plt
import numpy as np  # 导入 numpy 用于生成平滑的线条

# 1. 原始数据
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]

# 2. 初始化模型参数
w = 1.0
w_initial = w  # 保存初始权重,用于后续可视化比较


# 3. 模型、损失函数、梯度函数定义
def forward(x):
    """模型的前向传播"""
    return x * w
def loss(x,y):
    y_pred=forward(x)
    return (y_pred-y)**2

# def cost(xs, ys):
#     """计算均方误差损失 (Mean Squared Error)"""
#     cost_val = 0
#     for x, y in zip(xs, ys):
#         y_pred = forward(x)
#         cost_val += (y_pred - y) ** 2
#     return cost_val / len(xs)


# def gradient(xs, ys):
#     """计算损失函数关于权重 w 的梯度"""
#     grad = 0
#     # BUG修复:梯度需要累加所有样本的影响,而不是只用最后一个
#     for x, y in zip(xs, ys):
#         grad += 2 * x * (x * w - y)  # 使用 += 进行累加
#     return grad / len(xs)
def gradient(x,y):
    return 2*x*(x*w-y)

# 4. 训练过程
cost_list = []
epoch_list = []

print(f'Predict (before training) for x=4: {forward(4):.3f}')  # 格式化输出

# 学习率
learning_rate = 0.01

for epoch in range(100):
    # # 计算损失并记录
    # cost_val = cost(x_data, y_data)
    # cost_list.append(cost_val)
    # epoch_list.append(epoch)
    #
    # # 计算梯度并更新权重
    # grad_val = gradient(x_data, y_data)
    # w -= learning_rate * grad_val
    for x,y in zip(x_data,y_data):
        grad=gradient(x,y)
        w-=grad*learning_rate
        l=loss(x,y)
    print('epoch=',epoch,'w=',w,'loss=',l)

print(f'Predict (after training) for x=4: {forward(4):.3f}')  # 格式化输出

随机梯度下降每一次的w是由上一次的w计算来的-->无法进行并行计算

梯度下降可进行并行计算

如何折中?batch  进行批量的随机梯度下降,每次去batch size为一组求梯度,进行更新

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐