"""
演示
    梯度下降法 求损失函数的最小值
    循环实现，计算梯度，更新参数w
题目：
    # 求 loss = w**2 + 20 的极小值点 并打印loss是最小值时 w的值(梯度)
计算过程：
    # 1 定义点 w=10, requires_grad=True, dtype=torch.float32
    # 2 定义函数 loss = w**2 + 20
    # 3 利用梯度下降法 循环迭代 求最优解/最小值
        # 3.1 前向传播,计算损失
        # 3.2 梯度清零 w.grad.zero_()
        # 3.3 反向传播 loss.backward()
        # 3.4 更新参数 w.data = w.data - 0.01 * w.grad
"""

# 导包
import torch
import matplotlib.pyplot as plt
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 微软雅黑
plt.rcParams['axes.unicode_minus'] = False            # 解决负号显示问题

# 1 定义点 w=10, requires_grad=True, dtype=torch.float32
w = torch.tensor([10.0],requires_grad=True,dtype=torch.float32)
# 2 定义函数 loss = w**2 + 20
loss = w**2 + 20    # 120.0
# 3 利用梯度下降法 循环迭代 求最优解/最小值
print(f"初始值：w:{w.data}, w.grad: {w.grad}, loss.mean():{loss.mean()}")
# 记录损失均值
loss_list = []
for i in range(500):
    # 3.1 前向传播, 计算损失
    loss = w**2 + 20
    # 3.2 梯度清零 w.grad.zero_()
    if w.grad is not None:
        w.grad.zero_()
    # 3.3 反向传播 loss.backward()
    loss.mean().backward()
    print(f"w.grad:{w.grad.data}")
    # loss_mean' = 2*w
    # 3.4 更新参数 w.data = w.data - 0.01 * w.grad
    w.data = w.data - 0.01 * w.grad.data
    # loss_mean' = 2*w = w = [2*w1]
    print(f"第{i+1}次迭代：w:{w.data}, w.grad:{w.grad.data}, loss.mean():{loss.mean()}")
    # 添加到loss_list
    loss_list.append(loss.mean().item())

# 绘制损失曲线
iterations = range(500)
plt.figure(figsize=(12,8))
plt.plot(iterations,loss_list)
plt.xlabel("迭代次数")
plt.ylabel("损失均值loss.mean")
plt.grid()
plt.show()