PyTorch 神经网络基础:Variable 与 Tensor 的梯度计算

本文介绍了 PyTorch 中 Variable 和 Tensor 的基本使用方法,重点解析了如何在计算中使用它们完成自动求导和梯度计算。文章通过实例展示了从早期的 Variable 到 Tensor 的演进,以及在 PyTorch 中对计算图和自动求导的支持。此外,文中详细解释了张量梯度的计算公式与结果,同时展示了如何从 Variable 和 Tensor 中提取数据,并转换为 NumPy 格式。内容旨在帮助读者理解 PyTorch 的核心概念,掌握张量计算的基础技能,为深度学习模型的构建打下坚实基础。

一 导入依赖

import torch
from torch.autograd import Variable  # 导入 PyTorch 中的 Variable

二 Variable 介绍

在早期的 PyTorch 版本中,Variable 是一个用于封装 Tensor 的数据结构,它提供了额外的功能,例如自动求导和计算图管理。然而,从 PyTorch 0.4.0 开始,Variable 已经被弃用,其功能被完全合并到 Tensor 中。Variable 是基于张量构建的结构,支持与张量相同的操作,并通过设置 requires_grad=True 实现自动梯度计算和计算图记录。

# 创建一个 Float 类型的张量
tensor = torch.FloatTensor([[1, 2], [3, 4]])
# 使用 Variable 封装张量并设置 requires_grad=True
variable = Variable(tensor, requires_grad=True)
print("Tensor:", tensor)  # 输出张量
print("Variable:", variable)  # 输出 Variable

自 PyTorch 0.4.0 起,Variable 被废弃,所有张量(Tensor)均支持自动求导功能,不需要显式地使用 Variable ,可以直接这样写:

# 直接创建一个支持梯度计算的张量
tensor = torch.tensor([[1.0, 2.0], [3.0, 4.0]], requires_grad=True)
print("Data:", tensor)  # 输出张量的值

三 梯度计算

1)使用 Variable 计算
# 计算 x^2 的均值
v_out = torch.mean(variable * variable)  # x^2
print("Output:", v_out)  # 输出结果: 7.5

# 进行反向传播,计算梯度
v_out.backward()
print("Gradient of Variable:", variable.grad)  # 输出初始 Variable 的梯度
2)使用 Tensor 计算
# 创建支持梯度计算的张量
tensor = torch.tensor([[1.0, 2.0], [3.0, 4.0]], requires_grad=True)
print("Data:", tensor)  # 输出张量的值

# 定义一个计算过程 (均值平方)
output = torch.mean(tensor * tensor)  # 相当于 x^2 的均值

# 输出计算结果
print("Output of mean(square):", output.item())  # 输出标量值

# 进行反向传播,计算梯度
output.backward()

# 查看梯度
print("Gradient of Tensor:", tensor.grad)  # 输出梯度
3)划重点 - 梯度公式释义

假设 tensor = [[1.0, 2.0], [3.0, 4.0]]

  • 计算过程
    output = 1 n ∑ ( x 2 ) = 1 4 ( 1 2 + 2 2 + 3 2 + 4 2 ) = 7.5 \text{output} = \frac{1}{n} \sum (x^2) = \frac{1}{4} (1^2 + 2^2 + 3^2 + 4^2) = 7.5 output=n1(x2)=41(12+22+32+42)=7.5

  • 梯度公式: 对于
    output = 1 4 ∑ ( x 2 ) \text{output} = \frac{1}{4} \sum (x^2) output=41(x2)
    梯度为:
    ∂ output ∂ x = 1 4 ⋅ 2 x = x 2 \frac{\partial \text{output}}{\partial x} = \frac{1}{4} \cdot 2x = \frac{x}{2} xoutput=412x=2x

  • 张量的梯度: 每个元素的梯度为:
    tensor.grad = tensor 2 = [ 0.5 1.0 1.5 2.0 ] \text{tensor.grad} = \frac{\text{tensor}}{2} = \begin{bmatrix} 0.5 & 1.0 \\ 1.5 & 2.0 \end{bmatrix} tensor.grad=2tensor=[0.51.51.02.0]

四 获取数据

1)获取 Variable 里的数据
print("Variable:", variable)  # 输出 Variable 形式
print("Variable data:", variable.data)  # 获取 Variable 中的张量数据
print("Variable data as NumPy:", variable.data.numpy())  # 转换为 NumPy 数据
2)获取 Tensor 里的数据
# 直接获取 Tensor 的数据
print("Tensor:", tensor)

# 去除梯度信息,获取纯数据
print("Tensor data (no grad):", tensor.detach())

# 转换为 NumPy 数据
print("Tensor as NumPy array:", tensor.detach().numpy())

五 完整代码示例

# This is a sample Python script.

# Press ⌃R to execute it or replace it with your code.
# Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings.
import torch
from torch.autograd import Variable  # torch 中 Variable 模块


def variable_old():
    # 创建一个 Float 类型的张量
    tensor = torch.FloatTensor([[1, 2], [3, 4]])
    # 使用 Variable 封装张量并设置 requires_grad=True
    variable = Variable(tensor, requires_grad=True)
    print("Tensor:", tensor)  # 输出张量
    print("Variable:", variable)  # 输出 Variable

    # 计算 x^2 的均值
    v_out = torch.mean(variable * variable)  # x^2
    print("Output:", v_out)  # 输出结果: 7.5

    # 进行反向传播,计算梯度
    v_out.backward()
    print("Gradient of Variable:", variable.grad)  # 输出初始 Variable 的梯度

    print("Variable:", variable)  # 输出 Variable 形式
    print("Variable data:", variable.data)  # 获取 Variable 中的张量数据
    print("Variable data as NumPy:", variable.data.numpy())  # 转换为 NumPy 数据


def tensor_new():
    # 创建支持梯度计算的张量
    tensor = torch.tensor([[1.0, 2.0], [3.0, 4.0]], requires_grad=True)
    print("Data:", tensor)  # 输出张量的值

    # 定义一个计算过程 (均值平方)
    output = torch.mean(tensor * tensor)  # 相当于 x^2 的均值

    # 输出计算结果
    print("Output of mean(square):", output.item())  # 输出标量值

    # 进行反向传播,计算梯度
    output.backward()

    # 查看梯度
    print("Gradient of Tensor:", tensor.grad)  # 输出梯度

    # 直接获取 Tensor 的数据
    print("Tensor:", tensor)

    # 去除梯度信息,获取纯数据
    print("Tensor data (no grad):", tensor.detach())

    # 转换为 NumPy 数据
    print("Tensor as NumPy array:", tensor.detach().numpy())


def print_hi(name):
    # Use a breakpoint in the code line below to debug your script.
    print(f'Hi, {name}')  # Press ⌘F8 to toggle the breakpoint.

    # 老的写法
    variable_old()

    # 新的写法
    tensor_new()


# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    print_hi('变量 Variable 和 Tensor')

# See PyCharm help at https://www.jetbrains.com/help/pycharm/

复制粘贴并覆盖到你的 main.py 中运行,运行结果如下。

Hi, 变量 Variable 和 Tensor
Tensor: tensor([[1., 2.],
        [3., 4.]])
Variable: tensor([[1., 2.],
        [3., 4.]], requires_grad=True)
Output: tensor(7.5000, grad_fn=<MeanBackward0>)
Gradient of Variable: tensor([[0.5000, 1.0000],
        [1.5000, 2.0000]])
Variable: tensor([[1., 2.],
        [3., 4.]], requires_grad=True)
Variable data: tensor([[1., 2.],
        [3., 4.]])
Variable data as NumPy: [[1. 2.]
 [3. 4.]]
Data: tensor([[1., 2.],
        [3., 4.]], requires_grad=True)
Output of mean(square): 7.5
Gradient of Tensor: tensor([[0.5000, 1.0000],
        [1.5000, 2.0000]])
Tensor: tensor([[1., 2.],
        [3., 4.]], requires_grad=True)
Tensor data (no grad): tensor([[1., 2.],
        [3., 4.]])
Tensor as NumPy array: [[1. 2.]
 [3. 4.]]

六 源码地址

代码地址,GitHub变量 Variable 和 Tensor.py

七 参考

[1] PyTorch 官方文档

[2] 莫烦 Python

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐