import torch

x_data = torch.tensor([1.0, 2.0, 3.0])
y_data = torch.tensor([2.0, 4.0, 6.0]) # 张量

w = torch.tensor([1.0])  # 将权重w封装为PyTorch张量,是一个形状为 [1] 的一维张量(本质是标量)
w.requires_grad_(True)  # ☆在运算时,Python标量 1.0 会被广播。相当于告诉PyTorch:“请跟踪w的所有运算,以便后续计算梯度”

def forward(x):
    return x * w  # w是张量,返回值也是张量

def loss(x, y):
    y_pred = forward(x)
    return (y_pred - y) ** 2  # 返回的l是一个包含计算历史的张量

print("predict (before training)", 4, forward(4).item())

learning_rate = 0.01

for epoch in range(100):
    for x, y in zip(x_data, y_data):
        l = loss(x, y) # 1. 前向传播,计算损失(构建计算图)
        l.backward()  # 2.☆自动反向传播,计算梯度并存入w.grad
        print('\tgrad:', x, y, w.grad.item()) # 3. 查看计算出的梯度
        #1.如果不使用torch.no_grad():
        # 后果:这个减法操作 -= 会被PyTorch的Autograd引擎记录到计算图中。因为w是requires_grad = True的张量,任何对它的操作都会被跟踪。
        # 这会导致:计算图无限膨胀:每次更新都会在图中添加新节点,训练几百次后,图会变得巨大,可能内存泄漏。
        # 逻辑错误:你本意是“用梯度修正参数”,但这个“修正动作”本身又被记录下来等待求导,这毫无意义且浪费资源。
        with torch.no_grad():           # 4.☆在更新参数时禁用梯度跟踪
            w.data -= learning_rate * w.grad.data  # 5. 执行梯度下降更新
        #2. 如果不使用 zero_grad():
        # 后果:PyTorch 的 backward() 函数计算出的梯度是累积到 .grad 属性中的,而不是覆盖。如果不清零,下一次的梯度会与上一次的梯度相加,导致更新方向错误。
        # 梯度值爆炸:梯度会随着迭代次数不断累加,数值异常增大。
        # 更新方向完全错误:参数会朝着一个混乱的合成方向更新,模型无法收敛。
        w.grad.data.zero_() # 6.☆将w的梯度清零,防止累积
    print("progress:", epoch, l.item()) # 7. 打印当前损失(.item()从张量提取数值)
print("predict (after training)", 4, forward(4).item())

更多推荐