"""
演示
    自动微分模块 如何 计算梯度/导数
介绍：
    梯度：损失函数对模型参数的导数/梯度，针对某个确定的模型参数，损失函数的导函数的数值，模型参数就是权重w,偏置b
    损失函数对模型参数的梯度不需要手动计算，是loss.backward反向传播过程中pytorch调用自动微分模块来自动计算的
    梯度下降法的参数更新公式：
        w新 = w旧 - 学习率 * 梯度

过程：
    1.定义模型权重参数
    2.定义一个损失函数
    3.backward()反向传播计算导数/梯度
    4.w.grad获取导数值/梯度
    5.更新参数：w新 = w旧 - 学习率 * 梯度

"""

# 导包
import torch

# 1.定义变量,模拟模型权重参数w
w = torch.tensor([10,20],requires_grad=True,dtype=torch.float32)
print(f"w:{w}, requires_grad: {w.requires_grad}")
# 2.定义函数，模拟损失函数
loss = w**2 + 10    # [110,410]
print(f"loss:{loss}")   # 1D: (2,)
# 打印导函数
print(f"loss.grad_fn:{loss.grad_fn}")
loss_mean = loss.mean()
print(f"loss_mean:{loss_mean}")
# loss' = 2*w = [2*w1,2*w2]
# loss_mean' = 2*w/2 = [w1,w2]
# 3.需要执行反向传播来调用自动微分模块
# 反向传播的张量必须是标量
loss.mean().backward()
# 4.打印loss_mean对w的梯度
print(f"w.grad:{w.grad}")   # [w1,w2]=[10.0,20.0]
# 5.更新参数：w新 = w旧 - 学习率 * 梯度
w.data = w.data - 0.01 * w.grad.data
# 10 - 0.01*20=9.8
# [10,20] - 0.01*[10.,20.]=[9.9,19.8]
print(f"w:{w}")