欢迎光临
我们一直在努力

自动微分模块

介绍 

        训练神经网络时,最常用的算法就是反向传播。在该算法中,参数(模型权重)会根据损失函数关于对应参数的梯度进行调整。为了计算这些梯度,PyTorch内置了名为 torch.autograd 的微分模块。它支持任意计算图的自动梯度计算:

        总的来说,自动微分模块的工作就是:对损失函数进行求导,结合反向传播,更新权重参数w,b(自动微分 = 求导)

        接下来我们使用这个结构进行自动微分模块的介绍。我们使用 backward 方法、grad 属性来实现梯度的计算和访问。(grad:梯度、backward:自动计算梯度)

案例——更新一次参数

        PyTorch不支持向量张量对向量张量的求导,只支持标量张量对向量张量的求导(x如果是张量,y必须是标量(一个值)才可以进行求导)

        计算梯度: y.backward(), y是一个标量

        获取x点的梯度值: x.grad, 会累加上一次的梯度值

"""
案例:
演示自动微分模块, 具体如何求导.

回顾:
权重更新公式:
W新 = W旧 – 学习率 * 梯度

梯度 = 损失函数的导数

关于损失函数的导数, 无需我们手动计算, 因为非常常用, 所以 PyTorch模块内置有 自动微分模块, 专门实现针对于 不同的损失函数求导,
从而实现 结合 反向传播, 更新 权重参数w 和 偏置参数b

细节:
只有标量张量才能求导, 且大多数底层操作的都是 浮点型, 记得转型.
"""

# 导包
import torch

# 1. 定义变量, 记录: 初始的权重w(旧)
# 参1: 初始值, 参2: 是否自动微分(求导), 参3: 数据类型 requires_grad=True: 自动求导, 默认为False
w = torch.tensor(10, requires_grad=True, dtype=torch.float)

# 2. 定义loss变量, 表示损失函数.
loss = 2 * w ** 2 # loss = 2w² -> 求导: 4w

# 3. 打印梯度函数类型(了解)
# print(f'梯度函数类型: {type(loss.grad_fn)}') # <class 'MulBackward0'>
# print(loss.sum())

# 4. 计算梯度, 梯度 = 损失函数的导数, 计算完毕后, 会记录到 w.grad属性中.
loss.sum().backward() # 保证loss是1个标量.
# loss.backward() # 这里因为y本身就是标量, 可以不写sum()

# 5. 代入 权重更新公式: W新 = W旧 – 学习率 * 梯度
w.data = w.data – 0.01 * w.grad

# 6. 打印最终结果.
print(f'更新后的权重: {w}') # 9.6

案例——循环更新参数

"""
案例:
演示自动微分模块, 循环实现 计算梯度, 更新参数.

需求:
求 y = x**2 + 20 的极小值点 并打印y是最小值时 w的值(梯度)

解题步骤:
1. 定义点 w=10 requires_grad=True dtlosspe=torch.float32
2. 定义函数 loss = w**2 + 20
3. 利用梯度下降法 循环迭代1000 求最优解
3.1 正向计算(前向传播)
3.2 梯度清零 w.grad.zero_()
3.3 反向传播
3.4 梯度更新 w.data = w.data – 0.01 * w.grad

回顾:
W新 = W旧 – 学习率 * 梯度
"""
# 导包
import torch

# 1. 定义点 w=10 requires_grad=True dtlosspe=torch.float32
# 参1: 初始值, 参2: 自动微分(求导), 参3: 数据类型, 浮点型.
w = torch.tensor(10, requires_grad=True, dtype=torch.float32)

# 2. 定义函数 loss = w**2 + 20
loss = w ** 2 + 20 # 求导: loss' = 2w

# 3. 利用梯度下降法 循环迭代100 求最优解
print(f'开始 权重初始值: {w}, (0.01 * w.grad): 无, loss: {loss}') # 10, 无, 120

# 迭代100次, 求最优解.
for i in range(1, 101):
# 3.1 正向计算(前向传播)
loss = w ** 2 + 20

# 3.2 梯度清零 w.grad.zero_() 默认梯度会累加.
# 至此(第一次的时候), 还没有计算梯度, 所以w.grad = None, 要做非空判断.
if w.grad is not None:
w.grad.zero_()

# 3.3 反向传播
loss.sum().backward()

# 3.4 梯度更新 w.data = w.data – 0.01 * w.grad
# print(f'梯度值为: {w.grad}')
w.data = w.data – 0.01 * w.grad

# 3.5 打印本次 梯度更新后的 权重参数结果.
print(f'第 {i} 次, 权重初始值: {w}, (0.01 * w.grad): {0.01 * w.grad:.5f}, loss: {loss:.5f}')

# 4. 打印最终结果.
print(f'最终结果 权重: {w}, 梯度: {w.grad:.5f}, loss: {loss:.5f}')

赞(0)
未经允许不得转载:171主机测评 » 自动微分模块
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址